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

Generated by: LCOV version 1.14