LCOV - code coverage report
Current view: top level - vnsw/agent/diag - diag_pkt_handler.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 420 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  *  * Copyright Contributors to the OpenSDN project
       4             :  *   */
       5             : 
       6             : #include <stdint.h>
       7             : #include "base/os.h"
       8             : #include <map>
       9             : #include "vr_defs.h"
      10             : #include "base/timer.h"
      11             : #include "cmn/agent_cmn.h"
      12             : #include "pkt/proto.h"
      13             : #include "pkt/proto_handler.h"
      14             : #include "diag/diag_pkt_handler.h"
      15             : #include "diag/diag.h"
      16             : #include "diag/diag_proto.h"
      17             : #include "diag/ping.h"
      18             : #include "diag/overlay_ping.h"
      19             : #include "diag/segment_health_check.h"
      20             : #include "oper/mirror_table.h"
      21             : #include <oper/bridge_route.h>
      22             : #include <oper/vxlan.h>
      23             : #include <netinet/icmp6.h>
      24             : #include "services/icmpv6_handler.h"
      25             : 
      26             : using namespace boost::posix_time;
      27           0 : void DiagPktHandler::SetReply() {
      28           0 :     AgentDiagPktData *ad = (AgentDiagPktData *)pkt_info_->data;
      29           0 :     ad->op_ = htonl(AgentDiagPktData::DIAG_REPLY);
      30           0 : }
      31             : 
      32           0 : void DiagPktHandler::SetDiagChkSum() {
      33             :     uint8_t proto;
      34           0 :     if (pkt_info_->ip) {
      35           0 :         proto = pkt_info_->ip->ip_p;
      36             :     } else {
      37           0 :         proto = pkt_info_->ip6->ip6_nxt;
      38             :     }
      39           0 :     switch(proto) {
      40           0 :         case IPPROTO_TCP:
      41           0 :             pkt_info_->transp.tcp->th_sum = 0xffff;
      42           0 :             break;
      43             : 
      44           0 :         case IPPROTO_UDP:
      45           0 :             pkt_info_->transp.udp->uh_sum = 0xffff;
      46           0 :             break;
      47             : 
      48           0 :         case IPPROTO_ICMP:
      49           0 :             pkt_info_->transp.icmp->icmp_cksum = 0xffff;
      50           0 :             break;
      51           0 :         case IPPROTO_ICMPV6:
      52           0 :             pkt_info_->transp.icmp6->icmp6_cksum = 0xffff;
      53           0 :             break;
      54             : 
      55           0 :         default:
      56           0 :             break;
      57             :     }
      58           0 : }
      59             : 
      60           0 : void DiagPktHandler::BuildReply() {
      61           0 :     SetReply();
      62           0 :     Swap();
      63           0 :     SetDiagChkSum();
      64           0 : }
      65             : 
      66           0 : void DiagPktHandler::Reply() {
      67           0 :     BuildReply();
      68           0 :     Send(GetInterfaceIndex(), GetVrfIndex(), AgentHdr::TX_ROUTE,
      69             :          CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
      70           0 : }
      71             : 
      72           0 : void DiagPktHandler::SegmentHealthCheckReply() {
      73           0 :     diag_table_->diag_proto()->IncrementDiagStats(GetInterfaceIndex(),
      74             :                                                   DiagProto::REQUESTS_RECEIVED);
      75           0 :     BuildReply();
      76           0 :     Send(GetInterfaceIndex(), GetVrfIndex(), AgentHdr::TX_SWITCH,
      77             :          CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
      78           0 :     diag_table_->diag_proto()->IncrementDiagStats(GetInterfaceIndex(),
      79             :                                                   DiagProto::REPLIES_SENT);
      80           0 : }
      81             : 
      82           0 : bool DiagPktHandler::IsTraceRoutePacket() {
      83           0 :     if (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_ZERO_TTL ||
      84           0 :         pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_ICMP_ERROR)
      85           0 :         return true;
      86             : 
      87           0 :     return false;
      88             : }
      89             : 
      90           0 : bool DiagPktHandler::IsOverlayPingPacket() {
      91           0 :     if (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_ROUTER_ALERT)
      92           0 :         return true;
      93           0 :     return false;
      94             : }
      95             : 
      96           0 : bool DiagPktHandler::HandleTraceRoutePacket() {
      97             : 
      98           0 :     uint32_t rabit = 0;
      99             :     uint8_t ttl;
     100           0 :     if (pkt_info_->ether_type == ETHERTYPE_IP) {
     101           0 :         ttl = pkt_info_->ip->ip_ttl;
     102           0 :     } else if (pkt_info_->ether_type == ETHERTYPE_IPV6) {
     103           0 :         ttl = pkt_info_->ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim;
     104             :     } else {
     105           0 :         return true;
     106             :     }
     107             : 
     108           0 :     if (ttl == 0 ) {
     109           0 :         if (pkt_info_->dport == VXLAN_UDP_DEST_PORT) {
     110           0 :             VxlanHdr *vxlan = (VxlanHdr *)(pkt_info_->transp.udp + 1);
     111           0 :             rabit = ntohl(vxlan->reserved) & OverlayPing::kVxlanRABit;
     112             :         }
     113             : 
     114           0 :         if (rabit) {
     115           0 :            SendOverlayResponse();
     116             :         } else {
     117           0 :             if (pkt_info_->ether_type == ETHERTYPE_IP) {
     118           0 :                 SendTimeExceededPacket();
     119             :             } else {
     120           0 :                 SendTimeExceededV6Packet();
     121             :             }
     122             :         }
     123           0 :         return true;
     124             :     }
     125           0 :     return HandleTraceRouteResponse();
     126             : }
     127             : 
     128             : // Send time exceeded ICMP packet
     129           0 : void DiagPktHandler::SendTimeExceededPacket() {
     130             :     // send IP header + 128 bytes from incoming pkt in the icmp response
     131           0 :     uint16_t icmp_len = pkt_info_->ip->ip_hl * 4 + 128;
     132           0 :     if (ntohs(pkt_info_->ip->ip_len) < icmp_len)
     133           0 :         icmp_len = ntohs(pkt_info_->ip->ip_len);
     134           0 :     boost::scoped_array<uint8_t> icmp_payload(new uint8_t[icmp_len]);
     135           0 :     memcpy(icmp_payload.get(), pkt_info_->ip, icmp_len);
     136           0 :     DiagEntry::DiagKey key = -1;
     137           0 :     if (!ParseIcmpData(icmp_payload.get(), icmp_len, (uint16_t *)&key, true))
     138           0 :         return;
     139             : 
     140           0 :     char *ptr = (char *)pkt_info_->pkt;
     141           0 :     uint16_t buf_len = pkt_info_->max_pkt_len;
     142             : 
     143             :     // Retain the agent-header before ethernet header
     144           0 :     uint16_t len = (char *)pkt_info_->eth - (char *)pkt_info_->pkt;
     145             : 
     146           0 :     Ip4Address src_ip(0);
     147           0 :     VmInterface *vm_itf = dynamic_cast<VmInterface *>
     148           0 :         (agent()->interface_table()->FindInterface(GetInterfaceIndex()));
     149           0 :     if (vm_itf == NULL) {
     150           0 :         src_ip = agent()->router_id();
     151             :     } else {
     152           0 :         if (vm_itf->vn() == NULL) {
     153           0 :             return;
     154             :         }
     155           0 :         const VnIpam *ipam = vm_itf->vn()->GetIpam(pkt_info_->ip_saddr.to_v4());
     156           0 :         if (ipam == NULL) {
     157           0 :             return;
     158             :         }
     159           0 :         src_ip = ipam->default_gw.to_v4();
     160             :     }
     161             : 
     162             :     // Form ICMP Packet with EthHdr - IP Header - ICMP Header
     163           0 :     len += EthHdr(ptr + len, buf_len - len, agent()->vhost_interface()->mac(),
     164           0 :                   MacAddress(pkt_info_->eth->ether_shost), ETHERTYPE_IP,
     165             :                   VmInterface::kInvalidVlanId);
     166             : 
     167           0 :     uint16_t ip_len = sizeof(iphdr) + 8 + icmp_len;
     168           0 :     len += IpHdr(ptr + len, buf_len - len, ip_len,
     169           0 :                  htonl(src_ip.to_ulong()),
     170           0 :                  htonl(pkt_info_->ip_saddr.to_v4().to_ulong()),
     171             :                  IPPROTO_ICMP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
     172             : 
     173           0 :     struct icmp *hdr = (struct icmp *) (ptr + len);
     174           0 :     memset((uint8_t *)hdr, 0, 8);
     175           0 :     hdr->icmp_type = ICMP_TIME_EXCEEDED;
     176           0 :     hdr->icmp_code = ICMP_EXC_TTL;
     177           0 :     memcpy(ptr + len + 8, icmp_payload.get(), icmp_len);
     178           0 :     IcmpChecksum((char *)hdr, 8 + icmp_len);
     179           0 :     len += 8 + icmp_len;
     180             : 
     181           0 :     pkt_info_->set_len(len);
     182             : 
     183           0 :     Send(GetInterfaceIndex(), pkt_info_->vrf, AgentHdr::TX_SWITCH,
     184             :          PktHandler::ICMP);
     185           0 : }
     186             : 
     187             : 
     188           0 : void DiagPktHandler::SendTimeExceededV6Packet() {
     189             :     uint8_t icmp_payload[icmp_payload_len];
     190           0 :     uint16_t  icmp_len = ntohs(pkt_info_->ip6->ip6_plen);
     191             : 
     192           0 :     if (icmp_len > icmp_payload_len)
     193           0 :         icmp_len = icmp_payload_len;
     194           0 :     memcpy(icmp_payload, pkt_info_->ip6, icmp_len);
     195             : 
     196           0 :     DiagEntry::DiagKey key = -1;
     197           0 :     if (!ParseIcmpData(icmp_payload, icmp_len, (uint16_t *)&key, false))
     198           0 :         return;
     199             : 
     200           0 :     char *buff = (char *)pkt_info_->pkt;
     201           0 :     uint16_t buff_len = pkt_info_->max_pkt_len;
     202             :     // Retain the agent-header before ethernet header
     203             : 
     204           0 :     uint16_t eth_len = EthHdr(buff, buff_len, GetInterfaceIndex(),
     205             :                               agent()->vhost_interface()->mac(),
     206           0 :                               MacAddress(pkt_info_->eth->ether_shost),
     207           0 :                               ETHERTYPE_IPV6);
     208             : 
     209           0 :     VmInterface *vm_itf = dynamic_cast<VmInterface *>
     210           0 :         (agent()->interface_table()->FindInterface(GetInterfaceIndex()));
     211           0 :     if (vm_itf == NULL || vm_itf->layer3_forwarding() == false ||
     212           0 :         vm_itf->vn() == NULL) {
     213           0 :         return;
     214             :     }
     215             : 
     216           0 :     const VnIpam *ipam = vm_itf->vn()->GetIpam(pkt_info_->ip_saddr.to_v6());
     217           0 :     if (ipam == NULL)
     218           0 :         return ;
     219             : 
     220           0 :     pkt_info_->ip6 = (struct ip6_hdr *)(buff + eth_len);
     221           0 :     Ip6Hdr(pkt_info_->ip6, icmp_len+ICMP_UNREACH_HDR_LEN, IPV6_ICMP_NEXT_HEADER,
     222           0 :            DEFAULT_IP_TTL, ipam->default_gw.to_v6().to_bytes().data(),
     223           0 :            pkt_info_->ip_saddr.to_v6().to_bytes().data());
     224             : 
     225           0 :     icmp6_hdr *icmp = pkt_info_->transp.icmp6 =
     226           0 :         (icmp6_hdr *)(pkt_info_->pkt + eth_len
     227           0 :                       + sizeof(ip6_hdr));
     228           0 :     icmp->icmp6_type = ICMP_TIME_EXCEEDED;
     229           0 :     icmp->icmp6_code = ICMP_EXC_TTL;
     230           0 :     icmp->icmp6_mtu = 0;
     231           0 :     icmp->icmp6_cksum = 0;
     232           0 :     icmp->icmp6_cksum =
     233           0 :         Icmpv6Csum(ipam->default_gw.to_v6().to_bytes().data(),
     234           0 :                    pkt_info_->ip_saddr.to_v6().to_bytes().data(),
     235             :                    icmp, icmp_len);
     236           0 :     memcpy(buff + sizeof(ip6_hdr) + eth_len+ICMP_UNREACH_HDR_LEN,
     237             :            icmp_payload, icmp_len);
     238           0 :     pkt_info_->set_len(icmp_len + sizeof(ip6_hdr) + eth_len+ICMP_UNREACH_HDR_LEN);
     239             : 
     240             :     uint16_t command =
     241           0 :         (pkt_info_->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) ?
     242           0 :         (uint16_t)AgentHdr::TX_ROUTE : AgentHdr::TX_SWITCH;
     243             : 
     244           0 :     Send(GetInterfaceIndex(), pkt_info_->vrf, command,
     245             :          PktHandler::ICMPV6);
     246             : 
     247             : }
     248             : 
     249           0 : bool DiagPktHandler::HandleTraceRouteResponse() {
     250           0 :     uint8_t *data = (uint8_t *)(pkt_info_->transp.icmp) + 8;
     251           0 :     uint16_t len = pkt_info_->len - (data - pkt_info_->pkt);
     252           0 :     bool is_v4 = pkt_info_->ether_type == ETHERTYPE_IP;
     253           0 :     DiagEntry::DiagKey key = -1;
     254             :     // if it is Overlay packet get the key from Oam data
     255           0 :     if (IsOverlayPingPacket()) {
     256           0 :         OverlayOamPktData *oamdata = (OverlayOamPktData *) pkt_info_->data;
     257           0 :         key = ntohs(oamdata->org_handle_);
     258             :     } else {
     259           0 :         if (!ParseIcmpData(data, len, (uint16_t *)&key, is_v4))
     260           0 :             return true;
     261             :     }
     262             : 
     263           0 :     DiagEntry *entry = diag_table_->Find(key);
     264           0 :     if (!entry) return true;
     265             : 
     266           0 :     if (is_v4)
     267           0 :         address_ = pkt_info_->ip_saddr.to_v4().to_string();
     268             :     else {
     269           0 :         address_ =  pkt_info_->ip_saddr.to_v6().to_string();
     270             :     }
     271           0 :     entry->HandleReply(this);
     272             : 
     273             :     DiagEntryOp *op;
     274           0 :     if (IsDone()) {
     275           0 :         op = new DiagEntryOp(DiagEntryOp::DEL, entry);
     276             :     } else {
     277           0 :         op = new DiagEntryOp(DiagEntryOp::RETRY, entry);
     278             :     }
     279           0 :     entry->diag_table()->Enqueue(op);
     280             : 
     281           0 :     return true;
     282             : }
     283             : 
     284           0 : bool DiagPktHandler::ParseIcmpData(const uint8_t *data, uint16_t data_len,
     285             :                                    uint16_t *key, bool is_v4) {
     286           0 :     if (data_len < sizeof(struct ip))
     287           0 :         return false;
     288           0 :     struct ip *ip_hdr = (struct ip *)(data);
     289           0 :     *key = ntohs(ip_hdr->ip_id);
     290           0 :     uint16_t len = sizeof(struct ip);
     291             :     uint8_t protocol;
     292             : 
     293           0 :     if (ip_hdr->ip_src.s_addr == htonl(agent()->router_id().to_ulong()) ||
     294           0 :         ip_hdr->ip_dst.s_addr == htonl(agent()->router_id().to_ulong())) {
     295             :         // Check inner header
     296           0 :         switch (ip_hdr->ip_p) {
     297           0 :             case IPPROTO_GRE : {
     298           0 :                 if (data_len < len + sizeof(GreHdr))
     299           0 :                     return true;
     300           0 :                 len += sizeof(GreHdr);
     301           0 :                 break;
     302             :             }
     303             : 
     304           0 :             case IPPROTO_UDP : {
     305           0 :                 if (data_len < len + sizeof(udphdr))
     306           0 :                     return true;
     307           0 :                 len += sizeof(udphdr);
     308           0 :                 break;
     309             :             }
     310             : 
     311           0 :             default: {
     312           0 :                 return true;
     313             :             }
     314             :         }
     315           0 :         len += sizeof(MplsHdr);
     316           0 :         if (is_v4) {
     317           0 :             if (data_len < len + sizeof(struct ip))
     318           0 :                 return true;
     319           0 :             ip_hdr = (struct ip *)(data + len);
     320           0 :             len += sizeof(struct ip);
     321           0 :             protocol = ip_hdr->ip_p;
     322             :         } else {
     323           0 :             if (data_len < len + sizeof(struct ip6_hdr))
     324           0 :                 return true;
     325           0 :             struct ip6_hdr *ip6_hdr = (struct ip6_hdr *)(data + len);
     326           0 :             len += sizeof(struct ip6_hdr);
     327           0 :             protocol = ip6_hdr->ip6_nxt;
     328             :         }
     329           0 :         switch (protocol) {
     330           0 :             case IPPROTO_TCP:
     331           0 :                 len += sizeof(tcphdr);
     332           0 :                 break;
     333             : 
     334           0 :             case IPPROTO_UDP:
     335           0 :                 len += sizeof(udphdr);
     336           0 :                 break;
     337             : 
     338           0 :             case IPPROTO_ICMP:
     339           0 :                 len += 8;
     340           0 :                 break;
     341           0 :             case IPPROTO_ICMPV6:
     342           0 :                 len += 8;
     343           0 :                 break;
     344           0 :             default:
     345           0 :                 return true;
     346             :         }
     347           0 :         if (data_len < len + sizeof(AgentDiagPktData))
     348           0 :             return true;
     349             : 
     350           0 :         AgentDiagPktData *agent_data = (AgentDiagPktData *)(data + len);
     351           0 :         if (ntohl(agent_data->op_) == AgentDiagPktData::DIAG_REQUEST) {
     352           0 :             agent_data->op_ = htonl(AgentDiagPktData::DIAG_REPLY);
     353           0 :         } else if (ntohl(agent_data->op_) == AgentDiagPktData::DIAG_REPLY) {
     354           0 :             *key = ntohs(agent_data->key_);
     355           0 :             done_ = true;
     356             :         }
     357             :     }
     358             : 
     359           0 :     return true;
     360             : }
     361             : 
     362           0 : bool DiagPktHandler::Run() {
     363           0 :     bool isoverlay_packet = IsOverlayPingPacket();
     364           0 :     AgentDiagPktData *ad = NULL;
     365           0 :     AgentDiagPktData tempdata;
     366             : 
     367           0 :     if (IsTraceRoutePacket()) {
     368           0 :         return HandleTraceRoutePacket();
     369             :     }
     370             : 
     371           0 :     if (isoverlay_packet) {
     372             :         // Process Overlay packet
     373             :         // papulate diag data AgentDiagPktData here
     374           0 :         memset((void*)&tempdata, 0, sizeof(AgentDiagPktData));
     375           0 :         ad = &tempdata;
     376           0 :         OverlayOamPktData *oamdata = (OverlayOamPktData *) pkt_info_->data;
     377           0 :         if (oamdata->msg_type_ == OverlayOamPktData::OVERLAY_ECHO_REQUEST) {
     378           0 :             ad->op_ = htonl(AgentDiagPktData::DIAG_REQUEST);
     379           0 :         } else if (oamdata->msg_type_ == OverlayOamPktData::OVERLAY_ECHO_REPLY) {
     380           0 :             ad->op_ = htonl(AgentDiagPktData::DIAG_REPLY);
     381             :         }
     382             : 
     383           0 :         ad->key_ = oamdata->org_handle_;
     384             :     } else {
     385           0 :         ad = (AgentDiagPktData *)pkt_info_->data;
     386             :     }
     387             : 
     388           0 :     if (!ad) {
     389             :         //Ignore if packet doesnt have proper L4 header
     390           0 :         return true;
     391             :     }
     392             : 
     393           0 :     SegmentHealthCheckPkt *segment_hc_pkt = NULL;
     394           0 :     DiagEntry::DiagKey key = ntohs(ad->key_);
     395           0 :     DiagEntry *entry = diag_table_->Find(key);
     396           0 :     if (entry) {
     397           0 :         segment_hc_pkt = dynamic_cast< SegmentHealthCheckPkt * >(entry);
     398             :     }
     399           0 :     if (ntohl(ad->op_) == AgentDiagPktData::DIAG_REQUEST) {
     400             :         //Request received swap the packet
     401             :         //and dump the packet back
     402           0 :         if (isoverlay_packet) {
     403             :             // Reply packet with after setting the TLV content.
     404           0 :             SendOverlayResponse();
     405           0 :             return true;
     406             :         }
     407           0 :         if (segment_hc_pkt) {
     408           0 :             SegmentHealthCheckReply();
     409             :         } else {
     410           0 :             Reply();
     411             :         }
     412           0 :         return true;
     413             :     }
     414             : 
     415           0 :     if (ntohl(ad->op_) != AgentDiagPktData::DIAG_REPLY) {
     416           0 :         return true;
     417             :     }
     418             :     //Reply for a query we sent
     419           0 :     if (!entry) {
     420           0 :         return true;
     421             :     }
     422           0 :     entry->HandleReply(this);
     423             : 
     424           0 :     if (segment_hc_pkt) {
     425             :         /* No further processing required for Segment Health check packet */
     426           0 :         return true;
     427             :     }
     428             : 
     429           0 :     if (entry->GetSeqNo() == entry->GetMaxAttempts()) {
     430             :         DiagEntryOp *op;
     431           0 :         op = new DiagEntryOp(DiagEntryOp::DEL, entry);
     432           0 :         entry->diag_table()->Enqueue(op);
     433             :     } else {
     434           0 :         entry->Retry();
     435             :     }
     436             : 
     437           0 :     return true;
     438             : }
     439             : 
     440           0 : void DiagPktHandler::TcpHdr(in_addr_t src, uint16_t sport, in_addr_t dst,
     441             :                             uint16_t dport, bool is_syn, uint32_t seq_no,
     442             :                             uint16_t len) {
     443           0 :     struct tcphdr *tcp = pkt_info_->transp.tcp;
     444           0 :     tcp->th_sport = htons(sport);
     445           0 :     tcp->th_dport = htons(dport);
     446             : 
     447           0 :     if (is_syn) {
     448           0 :         tcp->th_flags &= ~TH_ACK;
     449             :     } else {
     450             :         //If not sync, by default we are sending an ack
     451           0 :         tcp->th_flags &= ~TH_SYN;
     452             :     }
     453             : 
     454           0 :     tcp->th_seq = htons(seq_no);
     455           0 :     tcp->th_ack = htons(seq_no + 1);
     456             :     //Just a random number;
     457           0 :     tcp->th_win = htons(1000);
     458           0 :     tcp->th_off = 5;
     459           0 :     tcp->th_sum = 0;
     460           0 :     tcp->th_sum = TcpCsum(src, dst, len, tcp);
     461           0 : }
     462             : 
     463           0 : void DiagPktHandler::TcpHdr(uint16_t len, const uint8_t *src, uint16_t sport,
     464             :                             const uint8_t *dest, uint16_t dport, bool is_syn,
     465             :                             uint32_t seq_no, uint8_t next_hdr){
     466           0 :     struct tcphdr *tcp = pkt_info_->transp.tcp;
     467           0 :     tcp->th_sport = htons(sport);
     468           0 :     tcp->th_dport = htons(dport);
     469             : 
     470           0 :     if (is_syn) {
     471           0 :         tcp->th_flags &= ~TH_ACK;
     472             :     } else {
     473             :         //If not sync, by default we are sending an ack
     474           0 :         tcp->th_flags &= ~TH_SYN;
     475             :     }
     476             : 
     477           0 :     tcp->th_seq = htons(seq_no);
     478           0 :     tcp->th_ack = htons(seq_no + 1);
     479             :     //Just a random number;
     480           0 :     tcp->th_win = htons(1000);
     481           0 :     tcp->th_off = 5;
     482           0 :     tcp->th_sum = 0;
     483           0 :     tcp->th_sum = Ipv6Csum(src, dest, len, next_hdr, (uint16_t *)tcp);
     484           0 : }
     485             : 
     486           0 : uint16_t DiagPktHandler::TcpCsum(in_addr_t src, in_addr_t dest, uint16_t len,
     487             :                                  tcphdr *tcp) {
     488           0 :     uint32_t sum = 0;
     489           0 :     PseudoTcpHdr phdr(src, dest, htons(len));
     490           0 :     sum = Sum((uint16_t *)&phdr, sizeof(PseudoTcpHdr), sum);
     491           0 :     return Csum((uint16_t *)tcp, len, sum);
     492             : }
     493             : 
     494           0 : void DiagPktHandler::SwapL4() {
     495           0 :     if (pkt_info_->ip_proto == IPPROTO_TCP) {
     496           0 :         tcphdr *tcp = pkt_info_->transp.tcp;
     497           0 :         TcpHdr(htonl(pkt_info_->ip_daddr.to_v4().to_ulong()),
     498           0 :                 ntohs(tcp->th_dport),
     499           0 :                 htonl(pkt_info_->ip_saddr.to_v4().to_ulong()),
     500           0 :                 ntohs(tcp->th_sport), false, ntohs(tcp->th_ack),
     501           0 :                 ntohs(pkt_info_->ip->ip_len) - sizeof(struct ip));
     502           0 :     } else if (pkt_info_->ip_proto == IPPROTO_UDP) {
     503           0 :         udphdr *udp = pkt_info_->transp.udp;
     504           0 :         UdpHdr(ntohs(udp->uh_ulen), pkt_info_->ip_daddr.to_v4().to_ulong(),
     505           0 :                ntohs(udp->uh_dport), pkt_info_->ip_saddr.to_v4().to_ulong(),
     506           0 :                ntohs(udp->uh_sport));
     507           0 :     } else if (pkt_info_->ip_proto == IPPROTO_ICMP) {
     508           0 :         struct icmp *hdr = (struct icmp *) (pkt_info_->transp.icmp);
     509           0 :         if (hdr->icmp_type == ICMP_ECHO) {
     510           0 :             hdr->icmp_type = ICMP_ECHOREPLY;
     511           0 :             hdr->icmp_code = 0;
     512             :         }
     513             :         /* We do not change sequence and identifier fields of ICMP header */
     514             :     }
     515           0 : }
     516             : 
     517           0 : void DiagPktHandler::Swapv6L4() {
     518           0 :     if (pkt_info_->ip_proto == IPPROTO_TCP) {
     519           0 :         tcphdr *tcp = pkt_info_->transp.tcp;
     520           0 :         TcpHdr(ntohs(pkt_info_->ip6->ip6_ctlun.ip6_un1.ip6_un1_plen) - sizeof(struct ip6_hdr),
     521           0 :                pkt_info_->ip_daddr.to_v6().to_bytes().data(), ntohs(tcp->th_dport),
     522           0 :                pkt_info_->ip_saddr.to_v6().to_bytes().data(), ntohs(tcp->th_sport),
     523           0 :                false, ntohs(tcp->th_ack), IPPROTO_TCP);
     524           0 :     } else if (pkt_info_->ip_proto == IPPROTO_UDP) {
     525           0 :         udphdr *udp = pkt_info_->transp.udp;
     526           0 :         UdpHdr(ntohs(udp->uh_ulen), pkt_info_->ip_daddr.to_v6().to_bytes().data(),
     527           0 :                ntohs(udp->uh_dport), pkt_info_->ip_saddr.to_v6().to_bytes().data(),
     528           0 :                ntohs(udp->uh_sport), IPPROTO_UDP);
     529             :     }
     530           0 : }
     531             : 
     532           0 : void DiagPktHandler::SwapIpHdr() {
     533             :     //IpHdr expects IP address to be in network format
     534           0 :     struct ip *ip = pkt_info_->ip;
     535           0 :     IpHdr(ntohs(ip->ip_len), ip->ip_dst.s_addr,
     536           0 :           ip->ip_src.s_addr, ip->ip_p, DEFAULT_IP_ID, DEFAULT_IP_TTL);
     537           0 : }
     538             : 
     539           0 : void DiagPktHandler::SwapIp6Hdr() {
     540             :     //Ip6Hdr expects IPv6 address to be in network format
     541           0 :     struct ip6_hdr  *ip6 = pkt_info_->ip6;
     542           0 :     Ip6Hdr(ip6, ntohl(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen),
     543           0 :            ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt, DEFAULT_IP_TTL,
     544           0 :            pkt_info_->ip_daddr.to_v6().to_bytes().data(),
     545           0 :            pkt_info_->ip_saddr.to_v6().to_bytes().data());
     546           0 : }
     547             : 
     548           0 : void DiagPktHandler::SwapEthHdr() {
     549           0 :     struct ether_header *eth = pkt_info_->eth;
     550           0 :     EthHdr(MacAddress(eth->ether_dhost), MacAddress(eth->ether_shost), ntohs(eth->ether_type));
     551           0 : }
     552             : 
     553           0 : void DiagPktHandler::Swap() {
     554           0 :     if (pkt_info_->ether_type == ETHERTYPE_IPV6) {
     555           0 :         Swapv6L4();
     556           0 :         SwapIp6Hdr();
     557             :     } else {
     558           0 :         SwapL4();
     559           0 :         SwapIpHdr();
     560             :     }
     561           0 :     SwapEthHdr();
     562           0 : }
     563             : 
     564           0 : void DiagPktHandler::SetReturnCode(OverlayOamPktData *oamdata) {
     565           0 :     oamdata->return_code_ = OverlayOamPktData::OVERLAY_SEGMENT_NOT_PRESENT;
     566             : 
     567           0 :     uint16_t type  = ntohs(oamdata->oamtlv_.type_);
     568           0 :     if (type != OamTlv::VXLAN_PING_IPv4 && type != OamTlv::VXLAN_PING_IPv6) {
     569           0 :         return;
     570             :     }
     571             : 
     572           0 :     const int tlv_length = ntohs(oamdata->oamtlv_.length_);
     573             :     // VXLAN VNI and IPv4 / IPv6 sender address
     574           0 :     int parsed_tlv = (type == OamTlv::VXLAN_PING_IPv4) ? 8 : 20;
     575             : 
     576             :     VxLanId *vxlan =
     577           0 :         Agent::GetInstance()->vxlan_table()->Find(pkt_info_->tunnel.vxlan_id);
     578           0 :     if (!vxlan) {
     579           0 :         return;
     580             :     }
     581             : 
     582           0 :     const VrfNH *vrf_nh = dynamic_cast<const VrfNH *> (vxlan->nexthop());
     583           0 :     if (!vrf_nh) {
     584           0 :         return;
     585             :     }
     586             : 
     587           0 :     const VrfEntry *vrf = vrf_nh->GetVrf();
     588           0 :     if (!vrf || vrf->IsDeleted()) {
     589           0 :         return;
     590             :     }
     591             : 
     592           0 :     oamdata->return_code_ = OverlayOamPktData::RETURN_CODE_OK;
     593           0 :     while (tlv_length - parsed_tlv >= (int) sizeof(SubTlv)) {
     594           0 :         SubTlv *subtlv = (SubTlv *) (oamdata->oamtlv_.data_ + parsed_tlv);
     595           0 :         parsed_tlv += sizeof(SubTlv);
     596             : 
     597           0 :         const int subtlv_length = ntohs(subtlv->length_);
     598           0 :         if (ntohs(subtlv->type_) != SubTlv::END_SYSTEM_MAC) {
     599           0 :             parsed_tlv += subtlv_length;
     600           0 :             continue;
     601             :         }
     602             : 
     603           0 :         int parsed_subtlv = 0;
     604             :         // check that we have bytes for MAC (6) and return code (2)
     605           0 :         while (subtlv_length - parsed_subtlv >=
     606             :                (int) sizeof(SubTlv::EndSystemMac)) {
     607           0 :             SubTlv::EndSystemMac *end_system_mac =
     608             :                 (SubTlv::EndSystemMac *)
     609           0 :                 (oamdata->oamtlv_.data_ + parsed_tlv + parsed_subtlv);
     610           0 :             MacAddress mac(end_system_mac->mac);
     611             :             BridgeAgentRouteTable *table =
     612           0 :                 static_cast<BridgeAgentRouteTable *> (vrf->GetBridgeRouteTable());
     613           0 :             if (table->FindRoute(mac, Peer::EVPN_PEER) != NULL ||
     614           0 :                 table->FindRoute(mac, Peer::LOCAL_VM_PORT_PEER) != NULL ||
     615           0 :                 table->FindRoute(mac, Peer::LOCAL_VM_PEER) != NULL) {
     616           0 :                 end_system_mac->return_code = htons(SubTlv::END_SYSTEM_PRESENT);
     617             :             } else {
     618           0 :                 end_system_mac->return_code =
     619           0 :                     htons(SubTlv::END_SYSTEM_NOT_PRESENT);
     620             :             }
     621           0 :             parsed_subtlv += sizeof(SubTlv::EndSystemMac);
     622             :         }
     623           0 :         parsed_tlv += subtlv_length;
     624             :     }
     625             : }
     626             : 
     627           0 : void DiagPktHandler::TunnelHdrSwap() {
     628           0 :     struct ether_header *eth = pkt_info_->tunnel.eth;
     629           0 :     EthHdr((char *)eth, sizeof(struct ether_header), MacAddress(eth->ether_dhost),
     630           0 :            MacAddress(eth->ether_shost), ntohs(eth->ether_type),
     631             :            VmInterface::kInvalidVlanId);
     632           0 :     struct ip *ip = pkt_info_->tunnel.ip;
     633           0 :     IpHdr((char *)ip, sizeof(struct ip), ntohs(ip->ip_len),ip->ip_dst.s_addr,
     634           0 :             ip->ip_src.s_addr, ip->ip_p, DEFAULT_IP_ID, DEFAULT_IP_TTL);
     635           0 : }
     636             : 
     637           0 : void DiagPktHandler::SendOverlayResponse() {
     638           0 :     Agent *agent = Agent::GetInstance();
     639           0 :     TunnelHdrSwap();
     640             : 
     641           0 :     OverlayOamPktData *oamdata = (OverlayOamPktData *) pkt_info_->data;
     642           0 :     if (oamdata->reply_mode_ == OverlayOamPktData::DONT_REPLY) {
     643           0 :         return ;
     644             :     }
     645             : 
     646           0 :     SetReturnCode(oamdata);
     647             : 
     648           0 :     oamdata->msg_type_ = OverlayOamPktData::OVERLAY_ECHO_REPLY;
     649             :     boost::posix_time::ptime
     650           0 :         epoch(boost::gregorian::date(1970, boost::gregorian::Jan, 1));
     651           0 :     boost::posix_time::ptime time = microsec_clock::universal_time();
     652           0 :     boost::posix_time::time_duration td = time - epoch;
     653           0 :     oamdata->timerecv_sec_ = htonl(td.total_seconds());
     654           0 :     oamdata->timerecv_misec_ = htonl(td.total_microseconds() - 
     655           0 :                                  (td.total_seconds()*1000000));
     656             : 
     657           0 :     PhysicalInterfaceKey key1(agent->fabric_interface_name());
     658           0 :     Interface *intf = static_cast<Interface *>
     659           0 :                 (agent->interface_table()->Find(&key1, true));
     660           0 :     Send(intf->id(), agent->fabric_vrf()->vrf_id(),
     661             :          AgentHdr::TX_SWITCH, CMD_PARAM_PACKET_CTRL,
     662             :          CMD_PARAM_1_DIAG, PktHandler::DIAG);
     663           0 : }

Generated by: LCOV version 1.14