LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - pkt_handler.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 480 900 53.3 %
Date: 2026-11-09 02:10:49 Functions: 49 60 81.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "base/os.h"
       7             : #include <sys/types.h>
       8             : #include <arpa/inet.h>
       9             : #include <netinet/in.h>
      10             : #include <netinet/ip6.h>
      11             : #include <netinet/icmp6.h>
      12             : 
      13             : #include "init/agent_param.h"
      14             : #include "cmn/agent_cmn.h"
      15             : #include "diag/diag.h"
      16             : #include "base/address_util.h"
      17             : #include "oper/ecmp_load_balance.h"
      18             : #include "oper/interface_common.h"
      19             : #include "oper/nexthop.h"
      20             : #include "oper/route_common.h"
      21             : #include "oper/vrf.h"
      22             : #include "oper/tunnel_nh.h"
      23             : #include "pkt/control_interface.h"
      24             : #include "pkt/pkt_handler.h"
      25             : #include "pkt/proto.h"
      26             : #include "pkt/flow_table.h"
      27             : #include "pkt/flow_proto.h"
      28             : #include "pkt/pkt_types.h"
      29             : #include "pkt/pkt_init.h"
      30             : #include "cmn/agent_stats.h"
      31             : #include "pkt/packet_buffer.h"
      32             : #include "vr_types.h"
      33             : #include "vr_defs.h"
      34             : #include "vr_mpls.h"
      35             : 
      36             : #define PKT_TRACE(obj, arg)                                              \
      37             : do {                                                                     \
      38             :     std::ostringstream _str;                                             \
      39             :     _str << arg;                                                         \
      40             :     Pkt##obj::TraceMsg(PacketTraceBuf, __FILE__, __LINE__, _str.str());  \
      41             : } while (false)                                                          \
      42             : 
      43             : const std::size_t PktTrace::kPktMaxTraceSize;
      44             : 
      45             : ////////////////////////////////////////////////////////////////////////////////
      46             : namespace {
      47          75 : inline bool IsBfdkeepalivePkt(const AgentHdr &hdr)
      48             : {
      49             :     // For the BFD traped packets, BFD state info is available in 'cmd_param'
      50          75 :     if ((hdr.cmd == AGENT_TRAP_BFD) && (hdr.cmd_param == 0xc0)) {
      51           0 :         return true;
      52             :     }
      53          75 :     return false;
      54             : }
      55             : 
      56             : } // namespace
      57             : 
      58           2 : PktHandler::PktHandler(Agent *agent, PktModule *pkt_module) :
      59           4 :     stats_(), agent_(agent), pkt_module_(pkt_module),
      60           2 :     work_queue_(TaskScheduler::GetInstance()->GetTaskId("Agent::PktHandler"), 0,
      61             :                 boost::bind(&PktHandler::ProcessPacket, this, _1)),
      62           2 :     work_queue_bfd_ka_(TaskScheduler::GetInstance()->GetTaskId("Agent::BFD_KA"), 0,
      63           2 :                 boost::bind(&PktHandler::ProcessBfdDataPacket, this, _1))
      64             :     {
      65           2 :     work_queue_.set_name("Packet Handler Queue");
      66           2 :     work_queue_.set_measure_busy_time(agent_->MeasureQueueDelay());
      67             :     // BFD keep alive packet processing
      68           2 :     work_queue_bfd_ka_.set_name("Packet BFD Data Queue");
      69           2 :     work_queue_bfd_ka_.set_measure_busy_time(agent_->MeasureQueueDelay());
      70          34 :     for (int i = 0; i < MAX_MODULES; ++i) {
      71          32 :         if (i == PktHandler::DHCP || i == PktHandler::DHCPV6 ||
      72             :             i == PktHandler::DNS)
      73           6 :             pkt_trace_.at(i).set_pkt_trace_size(512);
      74             :         else
      75          26 :             pkt_trace_.at(i).set_pkt_trace_size(128);
      76             :     }
      77           2 : }
      78             : 
      79           4 : PktHandler::~PktHandler() {
      80           2 :     work_queue_.Shutdown();
      81           4 : }
      82             : 
      83          26 : void PktHandler::Register(PktModuleName type, Proto *proto) {
      84          26 :     proto_list_.at(type) = proto;
      85          26 :     if (type == BFD) {
      86           2 :         bfd_keepalive_proto_ = proto;
      87             :     }
      88          26 : }
      89             : 
      90           0 : uint32_t PktHandler::EncapHeaderLen() const {
      91           0 :     return agent_->pkt()->control_interface()->EncapsulationLength();
      92             : }
      93             : 
      94             : // Send packet to tap interface
      95        2204 : void PktHandler::Send(const AgentHdr &hdr, const PacketBufferPtr &buff) {
      96        2204 :     stats_.PktSent(PktHandler::PktModuleName(buff->module()));
      97        2204 :     pkt_trace_.at(buff->module()).AddPktTrace(PktTrace::Out, buff->data_len(),
      98             :                                               buff->data(), &hdr);
      99        2204 :     if (agent_->pkt()->control_interface()->Send(hdr, buff) <= 0) {
     100           0 :         PKT_TRACE(Err, "Error sending packet");
     101             :     }
     102        2204 :     return;
     103             : }
     104             : 
     105          78 : void PktHandler::CalculatePortIP(PktInfo *pkt) {
     106          78 :     const Interface *in = NULL;
     107          78 :     const VmInterface *intf = NULL;
     108          78 :     const Interface *pkt_in_intf = NULL;
     109          78 :     bool ingress= false;
     110             :     VmInterface::FatFlowIgnoreAddressType ignore_addr;
     111             :     uint8_t protocol;
     112             : 
     113             :     const NextHop *nh =
     114          78 :         agent()->nexthop_table()->FindNextHop(pkt->agent_hdr.nh);
     115          78 :     if (!nh) {
     116          78 :         return;
     117             :     }
     118             : 
     119          78 :     if (nh->GetType() == NextHop::INTERFACE) {
     120          36 :         const InterfaceNH *intf_nh = static_cast<const InterfaceNH *>(nh);
     121          36 :         in = intf_nh->GetInterface();
     122          42 :     } else if (nh->GetType() == NextHop::VLAN) {
     123           0 :         const VlanNH *vlan_nh = static_cast<const VlanNH *>(nh);
     124           0 :         in = vlan_nh->GetInterface();
     125          42 :     } else if (nh->GetType() == NextHop::COMPOSITE) {
     126          37 :         const CompositeNH *comp_nh = static_cast<const CompositeNH *>(nh);
     127             : 
     128          37 :         if (comp_nh->composite_nh_type() == Composite::LOCAL_ECMP) {
     129          37 :             in = comp_nh->GetFirstLocalEcmpMemberInterface();
     130             :         }
     131             :     }
     132             : 
     133          78 :     if (in) {
     134          73 :         intf = dynamic_cast<const VmInterface *>(in);
     135             :     }
     136             : 
     137          78 :     if (!intf) {
     138           6 :         return;
     139             :     }
     140             : 
     141          72 :     if (intf->fat_flow_list().list_.size() == 0) {
     142          69 :         return;
     143             :     }
     144             : 
     145           3 :     if (intf->ExcludeFromFatFlow(pkt->family, pkt->ip_saddr, pkt->ip_daddr)) {
     146           0 :         return;
     147             :     }
     148           3 :     uint16_t sport = pkt->sport;
     149           3 :     if (pkt->ip_proto == IPPROTO_ICMP || pkt->ip_proto == IPPROTO_IGMP) {
     150           0 :         sport = 0;
     151             :     }
     152             : 
     153           3 :     protocol = pkt->ip_proto;
     154             :     /*
     155             :      * For ICMPv6 change the protocol to ICMP as the same value is used when it is
     156             :      * stored in the fat flow rule
     157             :      */
     158           3 :     if (pkt->ip_proto == IPPROTO_ICMPV6) {
     159           0 :         protocol = IPPROTO_ICMP;
     160             :     }
     161             : 
     162           3 :     pkt->is_fat_flow_src_prefix = false;
     163           3 :     pkt->is_fat_flow_dst_prefix = false;
     164             : 
     165           3 :     if (pkt->sport < pkt->dport) {
     166           2 :         if (intf->IsFatFlowPortBased(protocol, sport, &ignore_addr)) {
     167           2 :             pkt->dport = 0;
     168           2 :             pkt->ignore_address = ignore_addr;
     169           2 :             return;
     170             :         }
     171             : 
     172           0 :         if (intf->IsFatFlowPortBased(protocol, pkt->dport, &ignore_addr)) {
     173           0 :             pkt->sport = 0;
     174           0 :             pkt->ignore_address = ignore_addr;
     175           0 :             return;
     176             :         }
     177             :     } else {
     178           1 :         if (intf->IsFatFlowPortBased(protocol, pkt->dport, &ignore_addr)) {
     179           1 :             if (pkt->dport == pkt->sport) {
     180           0 :                 pkt->same_port_number = true;
     181             :             }
     182           1 :             pkt->sport = 0;
     183           1 :             pkt->ignore_address = ignore_addr;
     184           1 :             return;
     185             :         }
     186             : 
     187           0 :         if (intf->IsFatFlowPortBased(protocol, sport, &ignore_addr)) {
     188           0 :             pkt->dport = 0;
     189           0 :             pkt->ignore_address = ignore_addr;
     190           0 :             return;
     191             :         }
     192             :     }
     193             :     /* If Fat-flow port is 0, then both source and destination ports have to
     194             :      * be ignored */
     195           0 :     if (intf->IsFatFlowPortBased(protocol, 0, &ignore_addr)) {
     196           0 :         pkt->sport = 0;
     197           0 :         pkt->dport = 0;
     198           0 :         pkt->ignore_address = ignore_addr;
     199           0 :         return;
     200             :     }
     201             : 
     202             :     // Check for fat flow based on prefix aggregation
     203           0 :     pkt_in_intf = Agent::GetInstance()->interface_table()->FindInterface(
     204           0 :                                                        pkt->agent_hdr.ifindex);
     205           0 :     ingress = PktFlowInfo::ComputeDirection(pkt_in_intf);
     206             :     // set the src and dst prefix to src & dst ip to begin with
     207           0 :     pkt->ip_ff_src_prefix = pkt->ip_saddr;
     208           0 :     pkt->ip_ff_dst_prefix = pkt->ip_daddr;
     209           0 :     intf->IsFatFlowPrefixAggregation(ingress, protocol,
     210           0 :                                      (uint16_t *)&pkt->sport,
     211           0 :                                      (uint16_t *) &pkt->dport,
     212             :                                      &pkt->same_port_number,
     213             :                                      &pkt->ip_ff_src_prefix,
     214             :                                      &pkt->ip_ff_dst_prefix,
     215             :                                      &pkt->is_fat_flow_src_prefix,
     216             :                                      &pkt->is_fat_flow_dst_prefix,
     217             :                                      &pkt->ignore_address);
     218             : }
     219             : 
     220         111 : bool PktHandler::IsBFDHealthCheckPacket(const PktInfo *pkt_info,
     221             :                                         const Interface *intrface) {
     222         111 :     if (intrface->type() == Interface::VM_INTERFACE &&
     223         138 :         pkt_info->ip_proto == IPPROTO_UDP &&
     224          27 :         (pkt_info->dport == BFD_SINGLEHOP_CONTROL_PORT ||
     225          27 :          pkt_info->dport == BFD_MULTIHOP_CONTROL_PORT ||
     226          27 :          pkt_info->dport == BFD_ECHO_PORT)) {
     227           0 :         return true;
     228             :     }
     229             : 
     230         111 :     return false;
     231             : }
     232             : 
     233         111 : bool PktHandler::IsSegmentHealthCheckPacket(const PktInfo *pkt_info,
     234             :                                             const Interface *intrface) {
     235         155 :     if (intrface->type() == Interface::VM_INTERFACE &&
     236          44 :         pkt_info->ip_proto == IPPROTO_ICMP) {
     237          17 :         if (pkt_info->icmp_chksum == 0xffff) {
     238           0 :             return true;
     239             :         }
     240          17 :         return pkt_info->is_segment_hc_pkt;
     241             :     }
     242          94 :     return false;
     243             : }
     244             : 
     245             : // Validate the BFD Keepalive packet received
     246           0 : PktHandler::PktModuleName PktHandler::ParseBfdDataPacket(const AgentHdr &hdr,
     247             :                                                   PktInfo *pkt_info,
     248             :                                                   uint8_t *pkt) {
     249             : 
     250           0 :     PktType::Type pkt_type = PktType::INVALID;
     251           0 :     pkt_info->agent_hdr = hdr;
     252             : 
     253           0 :     int len = 0, ret = 0;
     254             :     
     255             :     // Parse packet before computing forwarding mode. Packet is parsed
     256             :     // independent of packet forwarding mode
     257           0 :     len += ParseEthernetHeader(pkt_info, (pkt + len));
     258           0 :     if (pkt_info->ether_type != ETHERTYPE_IP) {
     259           0 :         agent_->stats()->incr_pkt_drop_due_to_invalid_ethertype();
     260           0 :         return INVALID;
     261             :     }
     262             : 
     263             :     // IP Packets
     264           0 :     ret = ParseIpPacket(pkt_info, pkt_type, (pkt + len));
     265           0 :     if(ret == -1) {
     266           0 :         return INVALID;
     267             :     }
     268           0 :     len += ret;
     269             : 
     270             :     // Check if the BFD KA packet
     271           0 :     if (pkt_info->ip_proto == IPPROTO_UDP &&
     272           0 :             pkt_info->dport == BFD_SINGLEHOP_CONTROL_PORT &&
     273           0 :             (pkt_info->data[0] & 0x20)) {
     274           0 :         return BFD;
     275             :     }
     276             : 
     277           0 :     return INVALID;
     278             : }
     279             : 
     280             : // Process the packet received from tap interface
     281          78 : PktHandler::PktModuleName PktHandler::ParsePacket(const AgentHdr &hdr,
     282             :                                                   PktInfo *pkt_info,
     283             :                                                   uint8_t *pkt) {
     284          78 :     PktType::Type pkt_type = PktType::INVALID;
     285          78 :     Interface *intf = NULL;
     286             : 
     287          78 :     pkt_info->agent_hdr = hdr;
     288          78 :     if (!IsValidInterface(hdr.ifindex, &intf)) {
     289           0 :         return INVALID;
     290             :     }
     291             : 
     292             :     // Parse packet before computing forwarding mode. Packet is parsed
     293             :     // indepndent of packet forwarding mode
     294          78 :     if (ParseUserPkt(pkt_info, intf, pkt_type, pkt) < 0) {
     295           0 :         return INVALID;
     296             :     }
     297             : 
     298          78 :     if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_TOR_CONTROL_PKT) {
     299             :         // In case of a control packet from a TOR served by us, the ifindex
     300             :         // is modified to index of the VM interface; validate this interface.
     301           0 :         if (!IsValidInterface(pkt_info->agent_hdr.ifindex, &intf)) {
     302           0 :             return INVALID;
     303             :         }
     304             :     }
     305             : 
     306          78 :     pkt_info->vrf = pkt_info->agent_hdr.vrf;
     307             : 
     308             : 
     309          78 :     if (hdr.cmd == AgentHdr::TRAP_MAC_MOVE ||
     310          78 :         hdr.cmd == AgentHdr::TRAP_MAC_LEARN ||
     311          78 :         hdr.cmd == AgentHdr::TRAP_MAC_IP_LEARNING) {
     312           0 :         return MAC_LEARNING;
     313             :     }
     314             : 
     315          78 :     bool is_flow_packet = IsFlowPacket(pkt_info);
     316             :     // Look for DHCP packets if corresponding service is enabled
     317             :     // Service processing over-rides ACL/Flow and forwarding configuration
     318          78 :     if (!is_flow_packet && intf->dhcp_enabled() && (pkt_type == PktType::UDP)) {
     319           0 :         if (pkt_info->ip && (pkt_info->dport == DHCP_SERVER_PORT ||
     320           0 :                              pkt_info->sport == DHCP_CLIENT_PORT)) {
     321           0 :             return DHCP;
     322             :         }
     323             :     }
     324          78 :     if (!is_flow_packet && intf->dhcp_enabled_v6() && (pkt_type == PktType::UDP)) {
     325           0 :         if (pkt_info->ip6 && (pkt_info->dport == DHCPV6_SERVER_PORT ||
     326           0 :                               pkt_info->sport == DHCPV6_CLIENT_PORT)) {
     327           0 :             return DHCPV6;
     328             :         }
     329             :     }
     330             : 
     331             :     // Handle ARP packet
     332          78 :     if (pkt_type == PktType::ARP) {
     333           0 :         return ARP;
     334             :     }
     335             : 
     336             :     // Packets needing flow
     337          78 :     if (is_flow_packet) {
     338          78 :         CalculatePortIP(pkt_info);
     339          78 :         if ((pkt_info->ip && pkt_info->family == Address::INET) ||
     340           0 :             (pkt_info->ip6 && pkt_info->family == Address::INET6)) {
     341          78 :             return FLOW;
     342             :         } else {
     343           0 :             PKT_TRACE(Err, "Flow trap for non-IP packet for interface "
     344             :                       "index <" << hdr.ifindex << ">");
     345           0 :             agent_->stats()->pkt_drop_due_to_flow_trap();
     346           0 :             return INVALID;
     347             :         }
     348             :     }
     349             : 
     350             :     // Look for DNS packets if corresponding service is enabled
     351             :     // Service processing over-rides ACL/Flow
     352           0 :     if (intf->dns_enabled() && (pkt_type == PktType::UDP)) {
     353           0 :         if (pkt_info->dport == DNS_SERVER_PORT) {
     354           0 :             return DNS;
     355             :         }
     356             :     }
     357             : 
     358             :     // Look for IP packets that need ARP resolution
     359           0 :     if (pkt_info->ip && hdr.cmd == AgentHdr::TRAP_RESOLVE) {
     360           0 :         return ARP;
     361             :     }
     362             : 
     363             :     // send time exceeded ICMP messages to diag module
     364           0 :     if (IsDiagPacket(pkt_info)) {
     365           0 :         return DIAG;
     366             :     }
     367             : 
     368           0 :     if (IsBFDHealthCheckPacket(pkt_info, intf)) {
     369           0 :         return BFD;
     370             :     }
     371             : 
     372           0 :     if (pkt_type == PktType::ICMP && IsSegmentHealthCheckPacket(pkt_info,
     373             :                                                                 intf)) {
     374           0 :         return DIAG;
     375             :     }
     376             : 
     377           0 :     if (pkt_type == PktType::ICMP && IsGwPacket(intf, pkt_info->ip_daddr)) {
     378           0 :         return ICMP;
     379             :     }
     380             : 
     381             :     // Look for IP6 packets that need NDP resolution
     382           0 :     if (pkt_info->ip6 && hdr.cmd == AgentHdr::TRAP_RESOLVE) {
     383           0 :         return ICMPV6;
     384             :     }
     385             : 
     386           0 :     if (pkt_type == PktType::ICMPV6) {
     387           0 :         if (hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
     388           0 :             return ICMPV6_ERROR;
     389             :         }
     390           0 :         return ICMPV6;
     391             :     }
     392             : 
     393           0 :     if (pkt_type == PktType::IGMP) {
     394           0 :         return IGMP;
     395             :     }
     396             : 
     397           0 :     if(pkt_info->ip6 && hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
     398           0 :        return ICMPV6_ERROR;
     399             :     }
     400             : 
     401           0 :     if (pkt_info->ip && hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
     402           0 :         return ICMP_ERROR;
     403             :     }
     404             : 
     405           0 :     if (hdr.cmd == AgentHdr::TRAP_DIAG && (pkt_info->ip || pkt_info->ip6)) {
     406           0 :         return DIAG;
     407             :     }
     408             : 
     409           0 :     return INVALID;
     410             : }
     411             : 
     412          75 : void PktHandler::HandleRcvPkt(const AgentHdr &hdr, const PacketBufferPtr &buff){
     413             :     // Enqueue packets to a workqueue to decouple from ASIO and run in
     414             :     // exclusion with DB
     415             :     boost::shared_ptr<PacketBufferEnqueueItem>
     416          75 :         info(new PacketBufferEnqueueItem(hdr, buff));
     417             : 
     418             :     // BFD Keepalive packets are enqueued to a seperate work queue
     419             :     // so that its job run without dependence on dB tasks
     420          75 :     if (IsBfdkeepalivePkt(hdr)) {
     421           0 :         work_queue_bfd_ka_.Enqueue(info);
     422             :     } else {
     423          75 :         work_queue_.Enqueue(info);
     424             :     }
     425          75 : }
     426             : 
     427          75 : bool PktHandler::ProcessPacket(boost::shared_ptr<PacketBufferEnqueueItem> item) {
     428          75 :     agent_->stats()->incr_pkt_exceptions();
     429          75 :     const AgentHdr &hdr = item->hdr;
     430          75 :     const PacketBufferPtr &buff = item->buff;
     431          75 :     boost::shared_ptr<PktInfo> pkt_info (new PktInfo(buff));
     432          75 :     uint8_t *pkt = buff->data();
     433          75 :     PktModuleName mod = ParsePacket(hdr, pkt_info.get(), pkt);
     434          75 :     PktModuleEnqueue(mod, hdr, pkt_info, pkt);
     435          75 :     if (mod == INVALID) {
     436           0 :         pkt_info.reset();
     437             :     }
     438             : 
     439          75 :     return true;
     440          75 : }
     441             : // Process BFD keepalives (BFD packets with state 'UP') in a seperate task
     442             : // that is independent of Db Task
     443           0 : bool PktHandler::ProcessBfdDataPacket(boost::shared_ptr<PacketBufferEnqueueItem> item) {
     444           0 :     const AgentHdr &hdr = item->hdr;
     445           0 :     const PacketBufferPtr &buff = item->buff;
     446           0 :     uint8_t *pkt = buff->data();
     447             :     PktModuleName mod;
     448             : 
     449             :     // In certain Agent restart race condition, Agent would restart but
     450             :     // vrouter is not in sync yet with agent restart. In this condition
     451             :     // there could be BFD packets from the prior session could be trapped
     452             :     // in vrouter and injected to the Agent's PKT0 i/f So, don't process
     453             :     // BFD packets received, prior to agent init done.
     454           0 :     if (!bfd_keepalive_proto_ || (agent_->init_done() == false)) {
     455           0 :         PKT_TRACE(Err, "BFD proto_list is not Initialized. Ignoring");
     456           0 :         return true;
     457             :     }
     458             : 
     459           0 :     boost::shared_ptr<PktInfo> pkt_info (new PktInfo(buff));
     460           0 :     mod = ParseBfdDataPacket(hdr, pkt_info.get(), pkt);
     461           0 :     if (mod == BFD) {
     462           0 :         pkt_info->is_bfd_keepalive = true;
     463           0 :         pkt_info->packet_buffer()->set_module(mod);
     464           0 :         bfd_keepalive_proto_->Enqueue(pkt_info);
     465           0 :         proto_list_.at(BFD)->ProcessStats(PktStatsType::PKT_RX_ENQUEUE);
     466             :     } else {
     467           0 :         proto_list_.at(BFD)->ProcessStats(PktStatsType::PKT_RX_DROP_STATS);
     468           0 :         pkt_info.reset();
     469             :     }
     470           0 :     return true;
     471           0 : }
     472             : 
     473          75 : void PktHandler::PktModuleEnqueue(PktModuleName mod, const AgentHdr &hdr,
     474             :                                   boost::shared_ptr<PktInfo> pkt_info,
     475             :                                   uint8_t * pkt) {
     476          75 :     pkt_info->packet_buffer()->set_module(mod);
     477          75 :     stats_.PktRcvd(mod);
     478          75 :     if (mod == INVALID) {
     479           0 :         agent_->stats()->incr_pkt_dropped();
     480           0 :         pkt_trace_.at(mod).AddPktTrace(PktTrace::In, pkt_info->len, pkt, &hdr);
     481           0 :         return;
     482             :     }
     483          75 :     Enqueue(mod, pkt_info);
     484             : }
     485             : 
     486             : // Compute L2/L3 forwarding mode for pacekt.
     487             : // Forwarding mode is L3 if,
     488             : // - Packet uses L3 label
     489             : // - DMAC in packet is VRRP Mac or VHOST MAC or receiving physical interface MAC
     490             : // Else forwarding mode is L2
     491           0 : bool PktHandler::ComputeForwardingMode(PktInfo *pkt_info,
     492             :                                        const Interface *intf) const {
     493           0 :     if (pkt_info->tunnel.type.GetType() == TunnelType::MPLS_GRE ||
     494           0 :         pkt_info->tunnel.type.GetType() == TunnelType::MPLS_UDP) {
     495           0 :         return pkt_info->l3_label;
     496             :     }
     497             : 
     498           0 :     if (pkt_info->dmac == agent_->vrrp_mac()) {
     499           0 :         return true;
     500             :     }
     501             : 
     502           0 :     if (pkt_info->dmac == agent_->vhost_interface()->mac()) {
     503           0 :         return true;
     504             :     }
     505             : 
     506           0 :     if (intf && intf->type() == Interface::PHYSICAL &&
     507           0 :         pkt_info->dmac == intf->mac()) {
     508           0 :         return true;
     509             :     }
     510             : 
     511           0 :     return false;
     512             : }
     513             : 
     514          78 : void PktHandler::SetOuterIp(PktInfo *pkt_info, uint8_t *pkt) {
     515          78 :     if (pkt_info->ether_type != ETHERTYPE_IP) {
     516           0 :         return;
     517             :     }
     518          78 :     struct ip *ip_hdr = (struct ip *)pkt;
     519          78 :     pkt_info->tunnel.ip = ip_hdr;
     520          78 :     pkt_info->tunnel.ip_saddr = ntohl(ip_hdr->ip_src.s_addr);
     521          78 :     pkt_info->tunnel.ip_daddr = ntohl(ip_hdr->ip_dst.s_addr);
     522             : }
     523             : 
     524          78 : void PktHandler::SetOuterMac(PktInfo *pkt_info) {
     525          78 :     pkt_info->tunnel.eth = pkt_info->eth;
     526          78 : }
     527             : 
     528             : 
     529          93 : int PktHandler::ParseEthernetHeader(PktInfo *pkt_info, uint8_t *pkt) {
     530          93 :     int len = 0;
     531          93 :     pkt_info->eth = (struct ether_header *) (pkt + len);
     532          93 :     pkt_info->smac = MacAddress(pkt_info->eth->ether_shost);
     533          93 :     pkt_info->dmac = MacAddress(pkt_info->eth->ether_dhost);
     534          93 :     pkt_info->ether_type = ntohs(pkt_info->eth->ether_type);
     535          93 :     len += sizeof(struct ether_header);
     536             : 
     537             :     //strip service vlan and customer vlan in packet
     538          93 :     while (pkt_info->ether_type == ETHERTYPE_VLAN ||
     539          93 :            pkt_info->ether_type == ETHERTYPE_QINQ) {
     540           0 :         pkt_info->ether_type = ntohs(*((uint16_t *)(pkt + len + 2)));
     541           0 :         len += VLAN_HDR_LEN;
     542             :     }
     543             : 
     544          93 :     if (pkt_info->ether_type == ETHERTYPE_PBB) {
     545             :         //Parse inner payload
     546           0 :         pkt_info->pbb_header = (uint32_t *)(pkt + len);
     547           0 :         pkt_info->b_smac = pkt_info->smac;
     548           0 :         pkt_info->b_dmac = pkt_info->dmac;
     549           0 :         pkt_info->i_sid = ntohl(*(pkt_info->pbb_header)) & 0x00FFFFFF;
     550           0 :         len += ParseEthernetHeader(pkt_info, pkt + len + PBB_HEADER_LEN);
     551             :     }
     552             : 
     553          93 :     return len;
     554             : }
     555             : 
     556         131 : int PktHandler::ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type,
     557             :                               uint8_t *pkt) {
     558         131 :     int len = 0;
     559         131 :     uint16_t ip_payload_len = 0;
     560         131 :     if (pkt_info->ether_type == ETHERTYPE_IP) {
     561         131 :         struct ip *ip = (struct ip *)(pkt + len);
     562         131 :         pkt_info->ip = ip;
     563         131 :         pkt_info->family = Address::INET;
     564         131 :         pkt_info->ip_saddr = IpAddress(Ip4Address(ntohl(ip->ip_src.s_addr)));
     565         131 :         pkt_info->ip_daddr = IpAddress(Ip4Address(ntohl(ip->ip_dst.s_addr)));
     566         131 :         pkt_info->ip_proto = ip->ip_p;
     567         131 :         pkt_info->ttl      = ip->ip_ttl;
     568         131 :         uint8_t ip_header_len = (ip->ip_hl << 2);
     569         131 :         ip_payload_len = ip->ip_len - ip_header_len;
     570         131 :         len += ip_header_len;
     571           0 :     } else if (pkt_info->ether_type == ETHERTYPE_IPV6) {
     572           0 :         pkt_info->family = Address::INET6;
     573           0 :         ip6_hdr *ip = (ip6_hdr *)(pkt + len);
     574           0 :         pkt_info->ip6 = ip;
     575           0 :         pkt_info->ip = NULL;
     576             :         Ip6Address::bytes_type addr;
     577             : 
     578           0 :         for (int i = 0; i < 16; i++) {
     579           0 :             addr[i] = ip->ip6_src.s6_addr[i];
     580             :         }
     581           0 :         pkt_info->ip_saddr = IpAddress(Ip6Address(addr));
     582             : 
     583           0 :         for (int i = 0; i < 16; i++) {
     584           0 :             addr[i] = ip->ip6_dst.s6_addr[i];
     585             :         }
     586           0 :         pkt_info->ip_daddr = IpAddress(Ip6Address(addr));
     587           0 :         pkt_info->ttl      = ip->ip6_hlim;
     588             : 
     589           0 :         uint8_t proto = ip->ip6_ctlun.ip6_un1.ip6_un1_nxt;
     590           0 :         len += sizeof(ip6_hdr);
     591           0 :         if (proto == IPPROTO_FRAGMENT) {
     592           0 :             ip6_frag *nxt = (ip6_frag *)(pkt + len);
     593           0 :             proto = nxt->ip6f_nxt;
     594           0 :             len += sizeof(ip6_frag);
     595             :         }
     596             : 
     597           0 :         pkt_info->ip_proto = proto;
     598             :     } else {
     599           0 :         LOG(ERROR,
     600             :           "Error EthType = Non IP/IPv6. BackTrace: " << AgentBackTrace(1));
     601           0 :         agent_->stats()->incr_pkt_drop_due_to_invalid_ethertype();
     602           0 :         return -1;
     603             :      }
     604             : 
     605         131 :     switch (pkt_info->ip_proto) {
     606          61 :     case IPPROTO_UDP : {
     607          61 :         pkt_info->transp.udp = (udphdr *) (pkt + len);
     608          61 :         len += sizeof(udphdr);
     609          61 :         pkt_info->data = (pkt + len);
     610             : 
     611          61 :         pkt_info->dport = ntohs(pkt_info->transp.udp->uh_dport);
     612          61 :         pkt_info->sport = ntohs(pkt_info->transp.udp->uh_sport);
     613          61 :         pkt_type = PktType::UDP;
     614          61 :         break;
     615             :     }
     616             : 
     617           2 :     case IPPROTO_TCP : {
     618           2 :         pkt_info->transp.tcp = (tcphdr *) (pkt + len);
     619           2 :         len += sizeof(tcphdr);
     620           2 :         pkt_info->data = (pkt + len);
     621             : 
     622           2 :         pkt_info->dport = ntohs(pkt_info->transp.tcp->th_dport);
     623           2 :         pkt_info->sport = ntohs(pkt_info->transp.tcp->th_sport);
     624           2 :         pkt_info->tcp_ack = pkt_info->transp.tcp->th_flags & TH_ACK;
     625           2 :         pkt_type = PktType::TCP;
     626           2 :         break;
     627             :     }
     628             : 
     629           0 :     case IPPROTO_SCTP : {
     630           0 :         pkt_info->transp.sctp = (sctphdr *) (pkt + len);
     631           0 :         len += sizeof(sctphdr);
     632           0 :         pkt_info->data = (pkt + len);
     633           0 :         pkt_info->dport = ntohs(pkt_info->transp.sctp->th_dport);
     634           0 :         pkt_info->sport = ntohs(pkt_info->transp.sctp->th_sport);
     635           0 :         pkt_type = PktType::SCTP;
     636           0 :         break;
     637             :     }
     638             : 
     639          19 :     case IPPROTO_ICMP: {
     640          19 :         pkt_info->transp.icmp = (struct icmp *) (pkt + len);
     641          19 :         pkt_type = PktType::ICMP;
     642             : 
     643          19 :         struct icmp *icmp = (struct icmp *)(pkt + len);
     644          19 :         pkt_info->icmp_chksum = icmp->icmp_cksum;
     645          19 :         pkt_info->dport = htons(icmp->icmp_type);
     646          19 :         if (icmp->icmp_type == ICMP_ECHO || icmp->icmp_type == ICMP_ECHOREPLY) {
     647          19 :             pkt_info->dport = ICMP_ECHOREPLY;
     648          19 :             pkt_info->sport = htons(icmp->icmp_id);
     649          19 :             pkt_info->data = (pkt + len + ICMP_MINLEN);
     650          19 :             uint16_t icmp_payload_len = ip_payload_len - ICMP_MINLEN;
     651          19 :             if (icmp_payload_len >= sizeof(AgentDiagPktData)) {
     652          19 :                 AgentDiagPktData *ad = (AgentDiagPktData *)pkt_info->data;
     653          19 :                 string value(ad->data_, (sizeof(ad->data_) - 1));
     654          19 :                 if (value.compare(0, (sizeof(ad->data_) - 1),
     655          19 :                                   DiagTable::kDiagData) == 0) {
     656           0 :                     pkt_info->is_segment_hc_pkt = true;
     657             :                 }
     658          19 :             }
     659          19 :         } else if (IsFlowPacket(pkt_info) &&
     660           0 :                    ((icmp->icmp_type == ICMP_DEST_UNREACH) ||
     661           0 :                     (icmp->icmp_type == ICMP_TIME_EXCEEDED))) {
     662             :             //Agent has to look at inner payload
     663             :             //and recalculate the parameter
     664             :             //Handle this only for packets requiring flow miss
     665           0 :             if(ParseIpPacket(pkt_info, pkt_type, pkt + len + sizeof(icmp)) == -1) {
     666           0 :                 return -1;
     667             :             }
     668             :      //Swap the key parameter, which would be used as key
     669           0 :             IpAddress src_ip = pkt_info->ip_saddr;
     670           0 :             pkt_info->ip_saddr = pkt_info->ip_daddr;
     671           0 :             pkt_info->ip_daddr = src_ip;
     672           0 :             if (pkt_info->ip_proto != IPPROTO_ICMP) {
     673           0 :                 uint16_t port = pkt_info->sport;
     674           0 :                 pkt_info->sport = pkt_info->dport;
     675           0 :                 pkt_info->dport = port;
     676             :             }
     677             :         } else {
     678           0 :             pkt_info->sport = 0;
     679             :         }
     680          19 :         break;
     681             :     }
     682             : 
     683           0 :     case IPPROTO_ICMPV6: {
     684           0 :         pkt_type = PktType::ICMPV6;
     685           0 :         icmp6_hdr *icmp = (icmp6_hdr *)(pkt + len);
     686           0 :         pkt_info->transp.icmp6 = icmp;
     687             : 
     688           0 :         pkt_info->dport = htons(icmp->icmp6_type);
     689           0 :         if (icmp->icmp6_type == ICMP6_ECHO_REQUEST ||
     690           0 :             icmp->icmp6_type == ICMP6_ECHO_REPLY) {
     691           0 :             pkt_info->dport = ICMP6_ECHO_REPLY;
     692           0 :             pkt_info->sport = htons(icmp->icmp6_id);
     693           0 :         } else if (IsFlowPacket(pkt_info) &&
     694           0 :                 icmp->icmp6_type < ICMP6_ECHO_REQUEST) {
     695             :             //Agent has to look at inner payload
     696             :             //and recalculate the parameter
     697             :             //Handle this only for packets requiring flow miss
     698           0 :             if(ParseIpPacket(pkt_info, pkt_type, pkt + len + sizeof(icmp)) == -1) {
     699           0 :                 return -1;
     700             :             }
     701             :      //Swap the key parameter, which would be used as key
     702           0 :             IpAddress src_ip = pkt_info->ip_saddr;
     703           0 :             pkt_info->ip_saddr = pkt_info->ip_daddr;
     704           0 :             pkt_info->ip_daddr = src_ip;
     705           0 :             if (pkt_info->ip_proto != IPPROTO_ICMPV6) {
     706           0 :                 uint16_t port = pkt_info->sport;
     707           0 :                 pkt_info->sport = pkt_info->dport;
     708           0 :                 pkt_info->dport = port;
     709             :             }
     710             :         } else {
     711           0 :             pkt_info->sport = 0;
     712             :         }
     713           0 :         break;
     714             :     }
     715             : 
     716           0 :     case IPPROTO_IGMP: {
     717           0 :         pkt_info->transp.igmp = (struct igmp *) (pkt + len);
     718           0 :         pkt_type = PktType::IGMP;
     719             : 
     720           0 :         pkt_info->dport = 0;
     721           0 :         pkt_info->sport = 0;
     722           0 :         pkt_info->data = (pkt + len);
     723           0 :         break;
     724             :     }
     725             : 
     726          49 :     default: {
     727          49 :         pkt_type = PktType::IP;
     728          49 :         pkt_info->dport = 0;
     729          49 :         pkt_info->sport = 0;
     730          49 :         break;
     731             :     }
     732             :     }
     733             : 
     734         131 :     return len;
     735             : }
     736             : 
     737          49 : int PktHandler::ParseControlWord(PktInfo *pkt_info, uint8_t *pkt,
     738             :                                  const MplsLabel *mpls) {
     739          49 :     uint32_t ret = 0;
     740          49 :     if (mpls->IsFabricMulticastReservedLabel() == true) {
     741             :         //Check if there is a control word
     742           0 :         uint32_t *control_word = (uint32_t *)(pkt);
     743           0 :         if (*control_word == kMulticastControlWord) {
     744           0 :             pkt_info->l3_label = false;
     745           0 :             ret += kMulticastControlWordSize + sizeof(VxlanHdr) +
     746             :                    sizeof(udphdr) + sizeof(ip);
     747             :         }
     748          49 :     } else if (pkt_info->l3_label == false) {
     749           7 :         bool layer2_control_word = false;
     750             :         const InterfaceNH *intf_nh =
     751           7 :             dynamic_cast<const InterfaceNH *>(mpls->nexthop());
     752           7 :         if (intf_nh && intf_nh->layer2_control_word()) {
     753           0 :             layer2_control_word = true;
     754             :         }
     755             : 
     756             :         const CompositeNH *comp_nh =
     757           7 :             dynamic_cast<const CompositeNH *>(mpls->nexthop());
     758           7 :         if (comp_nh && comp_nh->layer2_control_word()) {
     759           0 :             layer2_control_word = true;
     760             :         }
     761             : 
     762             :         const VrfNH *vrf_nh =
     763           7 :             dynamic_cast<const VrfNH *>(mpls->nexthop());
     764           7 :         if (vrf_nh && vrf_nh->layer2_control_word()) {
     765           0 :             layer2_control_word = true;
     766             :         }
     767             : 
     768             :         //Check if there is a control word
     769           7 :         uint32_t *control_word = (uint32_t *)(pkt);
     770           7 :         if (layer2_control_word && *control_word == kMulticastControlWord) {
     771           0 :             ret += kMulticastControlWordSize;
     772             :         }
     773             :     }
     774             : 
     775          49 :     return ret;
     776             : }
     777             : 
     778          49 : int PktHandler::ParseMplsHdr(PktInfo *pkt_info, uint8_t *pkt) {
     779          49 :     MplsHdr *hdr = (MplsHdr *)(pkt);
     780             : 
     781             :     // MPLS Header validation. Check for,
     782             :     // - There is single label
     783          49 :     uint32_t mpls_host = ntohl(hdr->hdr);
     784          49 :     pkt_info->tunnel.label = (mpls_host & 0xFFFFF000) >> 12;
     785          49 :     uint32_t ret = sizeof(MplsHdr);
     786             : 
     787          49 :     if ((mpls_host & 0x100) == 0) {
     788             :         // interpret outer label 0xffffff as no label
     789           0 :         if (((mpls_host & 0xFFFFF000) >> 12) !=
     790             :                 MplsTable::kInvalidLabel) {
     791           0 :             pkt_info->tunnel.label = MplsTable::kInvalidLabel;
     792           0 :             PKT_TRACE(Err, "Unexpected MPLS Label Stack. Ignoring");
     793           0 :             return -1;
     794             :         }
     795           0 :         hdr = (MplsHdr *) (pkt + 4);
     796           0 :         mpls_host = ntohl(hdr->hdr);
     797           0 :         pkt_info->tunnel.label = (mpls_host & 0xFFFFF000) >> 12;
     798           0 :         if ((mpls_host & 0x100) == 0) {
     799           0 :             pkt_info->tunnel.label = MplsTable::kInvalidLabel;
     800           0 :             PKT_TRACE(Err, "Unexpected MPLS Label Stack. Ignoring");
     801           0 :             return  -1;
     802             :         }
     803           0 :         ret  += sizeof(MplsHdr);
     804             : 
     805             :     }
     806             : 
     807          49 :     uint32_t label = pkt_info->tunnel.label;
     808          49 :     MplsLabelKey mpls_key(label);
     809             : 
     810          49 :     const MplsLabel *mpls = static_cast<const MplsLabel *>(
     811          49 :             agent_->mpls_table()->FindActiveEntry(&mpls_key));
     812          49 :     if (mpls == NULL) {
     813           0 :         PKT_TRACE(Err, "Invalid MPLS Label <" << label << ">. Ignoring");
     814           0 :         pkt_info->tunnel.label = MplsTable::kInvalidLabel;
     815           0 :         return -1;
     816             :     }
     817             : 
     818          49 :     pkt_info->l3_label = true;
     819          49 :     const InterfaceNH *nh = dynamic_cast<const InterfaceNH *>(mpls->nexthop());
     820          49 :     if (nh && nh->IsBridge()) {
     821           7 :         pkt_info->l3_label = false;
     822             :     }
     823             : 
     824          49 :     const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(mpls->nexthop());
     825          49 :     if (cnh && cnh->composite_nh_type() != Composite::LOCAL_ECMP) {
     826           0 :         pkt_info->l3_label = false;
     827             :     }
     828             : 
     829          49 :     const VrfNH *vrf_nh = dynamic_cast<const VrfNH *>(mpls->nexthop());
     830          49 :     if (vrf_nh && vrf_nh->bridge_nh() == true) {
     831           0 :         pkt_info->l3_label = false;
     832             :     }
     833             : 
     834          49 :     ret += ParseControlWord(pkt_info, pkt + ret, mpls);
     835          49 :     return ret;
     836          49 : }
     837             : 
     838             : // Parse MPLSoGRE header
     839          49 : int PktHandler::ParseMPLSoGRE(PktInfo *pkt_info, uint8_t *pkt) {
     840          49 :     GreHdr *gre = (GreHdr *)(pkt);
     841          49 :     if (gre->protocol != ntohs(VR_GRE_PROTO_MPLS)) {
     842           0 :         PKT_TRACE(Err, "Non-MPLS protocol <" << ntohs(gre->protocol) <<
     843             :                   "> in GRE header");
     844           0 :         return -1;
     845             :     }
     846             : 
     847          49 :     int len = sizeof(GreHdr);
     848             : 
     849             :     int tmp;
     850          49 :     tmp = ParseMplsHdr(pkt_info, (pkt + len));
     851          49 :     if (tmp < 0) {
     852           0 :         return tmp;
     853             :     }
     854          49 :     len += tmp;
     855             : 
     856          49 :     if (pkt_info->l3_label == false) {
     857           7 :         tmp = ParseEthernetHeader(pkt_info, (pkt + len));
     858           7 :         if (tmp < 0)
     859           0 :             return tmp;
     860           7 :         len += tmp;
     861             :     }
     862             : 
     863          49 :     pkt_info->tunnel.type.SetType(TunnelType::MPLS_GRE);
     864          49 :     return (len);
     865             : }
     866             : 
     867           0 : int PktHandler::ParseMPLSoUDP(PktInfo *pkt_info, uint8_t *pkt) {
     868           0 :     int len = ParseMplsHdr(pkt_info, pkt);
     869           0 :     if (len < 0) {
     870           0 :         return len;
     871             :     }
     872             : 
     873           0 :     if (pkt_info->l3_label == false) {
     874           0 :         len += ParseEthernetHeader(pkt_info, (pkt + len));
     875             :     }
     876             : 
     877           0 :     pkt_info->tunnel.type.SetType(TunnelType::MPLS_UDP);
     878           0 :     return len;
     879             : }
     880             : 
     881           4 : int PktHandler::ParseVxlan(PktInfo *pkt_info, uint8_t *pkt) {
     882           4 :     VxlanHdr *vxlan = (VxlanHdr *)(pkt);
     883           4 :     pkt_info->tunnel.vxlan_id = htonl(vxlan->vxlan_id) >> 8;
     884             : 
     885           4 :     int len = sizeof(vxlan);
     886           4 :     len += ParseEthernetHeader(pkt_info, (pkt + len));
     887             : 
     888           4 :     pkt_info->tunnel.type.SetType(TunnelType::VXLAN);
     889           4 :     pkt_info->l3_label = false;
     890           4 :     return len;
     891             : }
     892             : 
     893           4 : int PktHandler::ParseUDPTunnels(PktInfo *pkt_info, uint8_t *pkt) {
     894           4 :     int len = 0;
     895           4 :     if (pkt_info->dport == VXLAN_UDP_DEST_PORT)
     896           4 :         len = ParseVxlan(pkt_info, (pkt + len));
     897           0 :     else if (pkt_info->dport == MPLS_OVER_UDP_DEST_PORT ||
     898           0 :              pkt_info->dport == IANA_MPLS_OVER_UDP_DEST_PORT)
     899           0 :         len = ParseMPLSoUDP(pkt_info, (pkt + len));
     900             : 
     901           4 :     return len;
     902             : }
     903             : 
     904         131 : bool PktHandler::ValidateIpPacket(PktInfo *pkt_info) {
     905             :     // For ICMP, IGMP, make sure IP is IPv4, else fail the parsing
     906             :     // so that we don't go ahead and access the ip header later
     907         131 :     if (((pkt_info->ip_proto == IPPROTO_ICMP) ||
     908         131 :          (pkt_info->ip_proto == IPPROTO_IGMP)) && (!pkt_info->ip)) {
     909           0 :         return false;
     910             :     }
     911             :     // If ip proto is ICMPv6, then make sure IP is IPv6, else fail
     912             :     // the parsing so that we don't go ahead and access the ip6 header
     913             :     // later
     914         131 :     if ((pkt_info->ip_proto == IPPROTO_ICMPV6) && (!pkt_info->ip6)) {
     915           0 :         return false;
     916             :     }
     917         131 :     return true;
     918             : }
     919             : 
     920          78 : int PktHandler::ParseUserPkt(PktInfo *pkt_info, Interface *intf,
     921             :                              PktType::Type &pkt_type, uint8_t *pkt) {
     922          78 :     int len = 0, ret = 0;
     923             :     bool pkt_ok;
     924             : 
     925             :     // get to the actual packet header
     926          78 :     len += ParseEthernetHeader(pkt_info, (pkt + len));
     927             : 
     928             :     // Parse payload
     929          78 :     if (pkt_info->ether_type == ETHERTYPE_ARP) {
     930           0 :         pkt_info->arp = (ether_arp *) (pkt + len);
     931           0 :         pkt_type = PktType::ARP;
     932             :         union {
     933             :             uint8_t data[sizeof(in_addr_t)];
     934             :             in_addr_t addr;
     935             :         } bytes;
     936           0 :         memcpy(bytes.data, pkt_info->arp->arp_spa, sizeof(in_addr_t));
     937           0 :         in_addr_t spa = ntohl(bytes.addr);
     938           0 :         pkt_info->ip_saddr = IpAddress(Ip4Address(spa));
     939           0 :         return len;
     940             :     }
     941             : 
     942             :     // Identify NON-IP Packets
     943          78 :     if (pkt_info->ether_type != ETHERTYPE_IP &&
     944           0 :         pkt_info->ether_type != ETHERTYPE_IPV6) {
     945           0 :         pkt_info->data = (pkt + len);
     946           0 :         pkt_type = PktType::NON_IP;
     947           0 :         return len;
     948             :     }
     949             :     // Copy IP fields from outer header assuming tunnel is present. If tunnel
     950             :     // is not present, the values here will be ignored
     951          78 :     SetOuterMac(pkt_info);
     952          78 :     SetOuterIp(pkt_info, (pkt + len));
     953             : 
     954             :     // IP Packets
     955          78 :     ret = ParseIpPacket(pkt_info, pkt_type, (pkt + len));
     956          78 :     if(ret == -1) {
     957           0 :         return -1;
     958             :     }
     959          78 :     len += ret;
     960             : 
     961          78 :     if (!ValidateIpPacket(pkt_info)) {
     962           0 :          agent_->stats()->incr_pkt_invalid_ip_pkt();
     963           0 :         return -1;
     964             :     }
     965             : 
     966             :     // If packet is an IP fragment and not flow trap, ignore it
     967          78 :     if (IgnoreFragmentedPacket(pkt_info)) {
     968           0 :         agent_->stats()->incr_pkt_fragments_dropped();
     969           0 :         return -1;
     970             :     }
     971             : 
     972             :     // If it is a packet from TOR that we serve, dont parse any further
     973          78 :     if (IsManagedTORPacket(intf, pkt_info, pkt_type, (pkt + len), &pkt_ok)) {
     974           0 :         return len;
     975          78 :     } else if (!pkt_ok) {
     976             :         // invalid pkt received from tor
     977           0 :        agent_->stats()->incr_pkt_invalid_frm_tor();
     978           0 :        return -1;
     979             :     }
     980             : 
     981          78 :     if (IsDiagPacket(pkt_info) &&
     982           0 :         (pkt_info->agent_hdr.cmd != AgentHdr::TRAP_ROUTER_ALERT)) {
     983           0 :         return len;
     984             :     }
     985             : 
     986             :     // If tunneling is not enabled on interface or if it is a DHCP packet,
     987             :     // dont parse any further
     988             : //    if (intf->IsTunnelEnabled() == false || IsDHCPPacket(pkt_info)) {
     989          78 :     if (intf->IsTunnelEnabled() == false) {
     990          25 :         agent_->stats()->incr_pkt_drop_due_to_disable_tnl();
     991          25 :         return len;
     992             :     }
     993          53 :     else if (IsDHCPPacket(pkt_info)) {
     994           0 :         return len;
     995             :     }
     996             : 
     997          53 :     int tunnel_len = 0;
     998             :     // Do tunnel processing only if IP-DA is ours
     999         106 :     if (pkt_info->family == Address::INET &&
    1000         106 :         pkt_info->ip_daddr.to_v4() == agent_->router_id()) {
    1001             :         // Look for supported headers
    1002          53 :         switch (pkt_info->ip_proto) {
    1003          49 :         case IPPROTO_GRE :
    1004             :             // Parse MPLSoGRE tunnel
    1005          49 :             tunnel_len = ParseMPLSoGRE(pkt_info, (pkt + len));
    1006          49 :             break;
    1007             : 
    1008           4 :         case IPPROTO_UDP:
    1009             :             // Parse MPLSoUDP tunnel
    1010           4 :             tunnel_len = ParseUDPTunnels(pkt_info, (pkt + len));
    1011           4 :             break;
    1012             : 
    1013           0 :         default:
    1014           0 :             break;
    1015             :         }
    1016             :     }
    1017             : 
    1018          53 :     if (tunnel_len < 0) {
    1019             :         // Found tunnel packet, but error in decoding
    1020           0 :         pkt_type = PktType::INVALID;
    1021           0 :         agent_->stats()->incr_pkt_drop_due_to_decode_error();
    1022           0 :         return tunnel_len;
    1023             :     }
    1024             : 
    1025          53 :     if (tunnel_len == 0) {
    1026           0 :         return len;
    1027             :     }
    1028             : 
    1029          53 :     len += tunnel_len;
    1030             : 
    1031             :     // Find IPv4/IPv6 Packet based on first nibble in payload
    1032          53 :     if (((pkt + len)[0] & 0x60) == 0x60) {
    1033           0 :         pkt_info->ether_type = ETHERTYPE_IPV6;
    1034             :     } else {
    1035          53 :         pkt_info->ether_type = ETHERTYPE_IP;
    1036             :     }
    1037             : 
    1038             : 
    1039          53 :     ret = ParseIpPacket(pkt_info, pkt_type, (pkt + len));
    1040          53 :     if(ret == -1) {
    1041           0 :         return -1;
    1042             :     }
    1043          53 :     len += ret;
    1044             : 
    1045             :     // validate inner iphdr
    1046          53 :     if (!ValidateIpPacket(pkt_info)) {
    1047           0 :         agent_->stats()->incr_pkt_invalid_ip_pkt();
    1048           0 :         return -1;
    1049             :     }
    1050             : 
    1051          53 :     return len;
    1052             : }
    1053             : 
    1054             : // Enqueue an inter-task message to the specified module
    1055        1074 : void PktHandler::SendMessage(PktModuleName mod, InterTaskMsg *msg) {
    1056        1074 :     if (mod < MAX_MODULES) {
    1057        1074 :         boost::shared_ptr<PktInfo> pkt_info(new PktInfo(mod, msg));
    1058        1074 :         if (!(proto_list_.at(mod)->Enqueue(pkt_info))) {
    1059           0 :             PKT_TRACE(Err, "Threshold exceeded while enqueuing IPC Message <" <<
    1060             :                       mod << ">");
    1061             :         }
    1062        1074 :     }
    1063        1074 : }
    1064             : 
    1065          78 : bool PktHandler::IgnoreFragmentedPacket(PktInfo *pkt_info) {
    1066          78 :     if (pkt_info->ip) {
    1067          78 :         uint16_t offset = htons(pkt_info->ip->ip_off);
    1068          78 :         if (((offset & IP_MF) || (offset & IP_OFFMASK)) &&
    1069           0 :             !IsFlowPacket(pkt_info))
    1070           0 :             return true;
    1071           0 :     } else if (pkt_info->ip6) {
    1072           0 :         uint8_t proto = pkt_info->ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
    1073           0 :         if (proto == IPPROTO_FRAGMENT) {
    1074           0 :             if (IsFlowPacket(pkt_info) ||
    1075           0 :                 pkt_info->agent_hdr.cmd == AgentHdr::TRAP_HANDLE_DF) {
    1076           0 :                 return false;
    1077             :             } else {
    1078           0 :                 return true;
    1079             :             }
    1080             :         }
    1081             :     }
    1082             : 
    1083          78 :     return false;
    1084             : }
    1085             : 
    1086          53 : bool PktHandler::IsDHCPPacket(PktInfo *pkt_info) {
    1087             :     // Do not consider source port in case we are looking at UDP tunnel header
    1088          53 :     if (pkt_info->dport == VXLAN_UDP_DEST_PORT ||
    1089          49 :         pkt_info->dport == MPLS_OVER_UDP_DEST_PORT ||
    1090          49 :         pkt_info->dport == IANA_MPLS_OVER_UDP_DEST_PORT) {
    1091           4 :         return false;
    1092             :     }
    1093             : 
    1094          49 :     if (pkt_info->dport == DHCP_SERVER_PORT ||
    1095          49 :         pkt_info->sport == DHCP_CLIENT_PORT) {
    1096             :         // we dont handle DHCPv6 coming from fabric
    1097           0 :         return true;
    1098             :     }
    1099          49 :     return false;
    1100             : }
    1101             : 
    1102           1 : bool PktHandler::IsToRDevice(uint32_t vrf_id, const IpAddress &ip) {
    1103           1 :     if (agent()->tsn_enabled() == false)
    1104           1 :         return false;
    1105             : 
    1106           0 :     if (ip.is_v4() == false)
    1107           0 :         return false;
    1108           0 :     Ip4Address ip4 = ip.to_v4();
    1109             : 
    1110           0 :     VrfEntry *vrf = agent()->vrf_table()->FindVrfFromId(vrf_id);
    1111           0 :     if (vrf == NULL)
    1112           0 :         return false;
    1113             : 
    1114             :     BridgeAgentRouteTable *table = static_cast<BridgeAgentRouteTable *>
    1115           0 :         (vrf->GetBridgeRouteTable());
    1116           0 :     if (table == NULL)
    1117           0 :         return false;
    1118             : 
    1119           0 :     BridgeRouteEntry *rt = table->FindRoute(MacAddress::BroadcastMac());
    1120           0 :     if (rt == NULL)
    1121           0 :         return false;
    1122             : 
    1123           0 :     const CompositeNH *nh = dynamic_cast<const CompositeNH *>
    1124           0 :         (rt->GetActiveNextHop());
    1125           0 :     if (nh == NULL)
    1126           0 :         return false;
    1127             : 
    1128           0 :     ComponentNHList::const_iterator it = nh->begin();
    1129           0 :     while (it != nh->end()) {
    1130           0 :         const CompositeNH *tor_nh = dynamic_cast<const CompositeNH *>
    1131           0 :             ((*it)->nh());
    1132           0 :         if (tor_nh == NULL) {
    1133           0 :             it++;
    1134           0 :             continue;
    1135             :         }
    1136             : 
    1137           0 :         if (tor_nh->composite_nh_type() != Composite::TOR &&
    1138           0 :             tor_nh->composite_nh_type() != Composite::EVPN) {
    1139           0 :             it++;
    1140           0 :             continue;
    1141             :         }
    1142             : 
    1143           0 :         ComponentNHList::const_iterator tor_it = tor_nh->begin();
    1144           0 :         while (tor_it != tor_nh->end()) {
    1145           0 :             const TunnelNH *tun_nh = dynamic_cast<const TunnelNH *>
    1146           0 :                 ((*tor_it)->nh());
    1147           0 :             if (tun_nh == NULL) {
    1148           0 :                 tor_it++;
    1149           0 :                 continue;
    1150             :             }
    1151           0 :             if (*tun_nh->GetDip() == ip4) {
    1152           0 :                 return true;
    1153             :             }
    1154           0 :             tor_it++;
    1155             :         }
    1156             : 
    1157           0 :         it++;
    1158             :     }
    1159             : 
    1160           0 :     return false;
    1161             : }
    1162             : 
    1163             : // We can receive DHCP / DNS packets on physical port from TOR ports managed
    1164             : // by a TOR services node. Check if the source mac is the mac address of a
    1165             : // VM interface available in the node.
    1166          78 : bool PktHandler::IsManagedTORPacket(Interface *intf, PktInfo *pkt_info,
    1167             :                                     PktType::Type &pkt_type, uint8_t *pkt, bool *pkt_ok) {
    1168          78 :     *pkt_ok = true;
    1169          78 :     if (intf->type() != Interface::PHYSICAL) {
    1170          25 :         return false;
    1171             :     }
    1172             : 
    1173          53 :     if (pkt_type != PktType::UDP || pkt_info->dport != VXLAN_UDP_DEST_PORT)
    1174          49 :         return false;
    1175             : 
    1176             :     // Get VXLAN id and point to original L2 frame after the VXLAN header
    1177           4 :     pkt += 8;
    1178             : 
    1179             :     // get to the actual packet header
    1180           4 :     pkt += ParseEthernetHeader(pkt_info, pkt);
    1181             : 
    1182             :     ether_addr addr;
    1183           4 :     memcpy(addr.ether_addr_octet, pkt_info->eth->ether_shost, ETH_ALEN);
    1184           4 :     MacAddress address(addr);
    1185           4 :     const VrfEntry *vrf = agent_->vrf_table()->
    1186           4 :         FindVrfFromId(pkt_info->agent_hdr.vrf);
    1187           4 :     if (vrf == NULL)
    1188           0 :         return false;
    1189             :    BridgeAgentRouteTable *bridge_table =
    1190           4 :         dynamic_cast<BridgeAgentRouteTable *>(vrf->GetBridgeRouteTable());
    1191           4 :     if(bridge_table == NULL) {
    1192           0 :         LOG(ERROR,
    1193             :            "Error bridge_table == NULL. BackTrace: " << AgentBackTrace(1));
    1194           0 :         _Exit(0);
    1195             :     }
    1196           4 :     const VmInterface *vm_intf = bridge_table->FindVmFromDhcpBinding(address);
    1197           4 :     if (vm_intf == NULL) {
    1198           3 :         return false;
    1199             :     }
    1200             : 
    1201           1 :     if (IsToRDevice(vm_intf->vrf_id(), pkt_info->ip_saddr) == false) {
    1202           1 :         return false;
    1203             :     }
    1204             : 
    1205             :     // update agent_hdr to reflect the VM interface data
    1206             :     // cmd_param is set to physical interface id
    1207           0 :     pkt_info->agent_hdr.cmd = AgentHdr::TRAP_TOR_CONTROL_PKT;
    1208           0 :     pkt_info->agent_hdr.cmd_param = pkt_info->agent_hdr.ifindex;
    1209           0 :     pkt_info->agent_hdr.ifindex = vm_intf->id();
    1210             : 
    1211             :     // Parse payload
    1212           0 :     if (pkt_info->ether_type == ETHERTYPE_ARP) {
    1213           0 :         pkt_info->arp = (ether_arp *) pkt;
    1214           0 :         pkt_type = PktType::ARP;
    1215           0 :         return true;
    1216             :     }
    1217             : 
    1218             :     // Identify NON-IP Packets
    1219           0 :     if (pkt_info->ether_type != ETHERTYPE_IP &&
    1220           0 :         pkt_info->ether_type != ETHERTYPE_IPV6) {
    1221           0 :         pkt_info->data = pkt;
    1222           0 :         pkt_type = PktType::NON_IP;
    1223           0 :         return true;
    1224             :     }
    1225             : 
    1226             :     // IP Packets
    1227           0 :     if(ParseIpPacket(pkt_info, pkt_type, pkt) == -1) {
    1228           0 :         *pkt_ok = false; //Don't process any further
    1229           0 :         return false;
    1230             :     }
    1231           0 :     if (!ValidateIpPacket(pkt_info)) {
    1232           0 :         *pkt_ok = false;
    1233           0 :         return false;
    1234             :     }
    1235           0 :     return true;
    1236             : }
    1237             : 
    1238          78 : bool PktHandler::IsFlowPacket(PktInfo *pkt_info) {
    1239          78 :     if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_FLOW_MISS ||
    1240           0 :         pkt_info->agent_hdr.cmd == AgentHdr::TRAP_FLOW_ACTION_HOLD) {
    1241          78 :         return true;
    1242             :     }
    1243           0 :     return false;
    1244             : }
    1245             : 
    1246           0 : bool PktHandler::IsFlowPacket(const AgentHdr &agent_hdr) {
    1247           0 :     if (agent_hdr.cmd == AgentHdr::TRAP_FLOW_MISS ||
    1248           0 :         agent_hdr.cmd == AgentHdr::TRAP_FLOW_ACTION_HOLD) {
    1249           0 :         return true;
    1250             :     }
    1251           0 :     return false;
    1252             : }
    1253             : 
    1254          78 : bool PktHandler::IsDiagPacket(PktInfo *pkt_info) {
    1255          78 :     if (pkt_info->agent_hdr.cmd == AgentHdr::TRAP_ZERO_TTL ||
    1256          78 :         pkt_info->agent_hdr.cmd == AgentHdr::TRAP_ICMP_ERROR
    1257          78 :         || pkt_info->agent_hdr.cmd == AgentHdr::TRAP_ROUTER_ALERT)
    1258           0 :         return true;
    1259          78 :     return false;
    1260             : }
    1261             : 
    1262             : // Check if the packet is destined to the VM's default GW
    1263           6 : bool PktHandler::IsGwPacket(const Interface *intf, const IpAddress &dst_ip) {
    1264           6 :     if (!intf || intf->type() != Interface::VM_INTERFACE)
    1265           0 :         return false;
    1266             : 
    1267           6 :     const VmInterface *vm_intf = static_cast<const VmInterface *>(intf);
    1268           6 :     if (vm_intf->vmi_type() != VmInterface::GATEWAY) {
    1269             :         //Gateway interface doesnt have IP address
    1270           6 :         if (dst_ip.is_v6() && vm_intf->primary_ip6_addr().is_unspecified())
    1271           0 :             return false;
    1272           6 :         else if (dst_ip.is_v4() && vm_intf->primary_ip_addr().is_unspecified())
    1273           0 :             return false;
    1274             :     }
    1275           6 :     const VnEntry *vn = vm_intf->vn();
    1276           6 :     if (vn) {
    1277           6 :         const std::vector<VnIpam> &ipam = vn->GetVnIpam();
    1278          18 :         for (unsigned int i = 0; i < ipam.size(); ++i) {
    1279          12 :             if (dst_ip.is_v4()) {
    1280          12 :                 if (!ipam[i].IsV4()) {
    1281           0 :                     continue;
    1282             :                 }
    1283          24 :                 if (ipam[i].default_gw == dst_ip ||
    1284          12 :                     ipam[i].dns_server == dst_ip) {
    1285           0 :                     return true;
    1286             :                 }
    1287             :             } else {
    1288           0 :                 if (!ipam[i].IsV6()) {
    1289           0 :                     continue;
    1290             :                 }
    1291           0 :                 if (ipam[i].default_gw == dst_ip ||
    1292           0 :                         ipam[i].dns_server == dst_ip) {
    1293           0 :                     return true;
    1294             :                 }
    1295             :             }
    1296             : 
    1297             :         }
    1298             :     }
    1299             : 
    1300           6 :     return false;
    1301             : }
    1302             : 
    1303          78 : bool PktHandler::IsValidInterface(uint32_t ifindex, Interface **intrface) {
    1304          78 :     Interface *intf = agent_->interface_table()->FindInterface(ifindex);
    1305          78 :     if (intf == NULL) {
    1306           0 :         PKT_TRACE(Err, "Invalid interface index <" << ifindex << ">");
    1307           0 :         agent_->stats()->incr_pkt_invalid_interface();
    1308           0 :         return false;
    1309             :     }
    1310             : 
    1311          78 :     *intrface = intf;
    1312          78 :     return true;
    1313             : }
    1314             : 
    1315           0 : void PktHandler::PktTraceIterate(PktModuleName mod, PktTraceCallback cb) {
    1316           0 :     if (!cb.empty()) {
    1317           0 :         PktTrace &pkt(pkt_trace_.at(mod));
    1318           0 :         pkt.Iterate(cb);
    1319             :     }
    1320           0 : }
    1321             : 
    1322          75 : void PktHandler::PktStats::PktRcvd(PktModuleName mod) {
    1323          75 :     if (mod < MAX_MODULES)
    1324          75 :         received[mod]++;
    1325          75 : }
    1326             : 
    1327        2204 : void PktHandler::PktStats::PktSent(PktModuleName mod) {
    1328        2204 :     if (mod < MAX_MODULES)
    1329        2204 :         sent[mod]++;
    1330        2204 : }
    1331             : 
    1332           0 : void PktHandler::PktStats::PktQThresholdExceeded(PktModuleName mod) {
    1333           0 :     if (mod < MAX_MODULES)
    1334           0 :         q_threshold_exceeded[mod]++;
    1335           0 : }
    1336             : 
    1337             : ///////////////////////////////////////////////////////////////////////////////
    1338             : 
    1339          78 : PktInfo::PktInfo(const PacketBufferPtr &buff) :
    1340          78 :     module(PktHandler::INVALID),
    1341          78 :     pkt(buff->data()), len(buff->data_len()), max_pkt_len(buff->buffer_len()),
    1342          78 :     data(), ipc(), family(Address::UNSPEC), type(PktType::INVALID), agent_hdr(),
    1343          78 :     ether_type(-1), ip_saddr(), ip_daddr(), ip_proto(), sport(), dport(),
    1344          78 :     ttl(0), icmp_chksum(0), tcp_ack(false), tunnel(),
    1345          78 :     l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
    1346          78 :     ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
    1347          78 :     is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
    1348          78 :     is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
    1349         312 :     eth(), arp(), ip(), ip6(), packet_buffer_(buff) {
    1350          78 :     transp.tcp = 0;
    1351          78 : }
    1352             : 
    1353           0 : PktInfo::PktInfo(const PacketBufferPtr &buff, const AgentHdr &hdr) :
    1354           0 :     pkt(buff->data()), len(buff->data_len()), max_pkt_len(buff->buffer_len()),
    1355           0 :     data(), ipc(), family(Address::UNSPEC), type(PktType::INVALID),
    1356           0 :     agent_hdr(hdr), ether_type(-1), ip_saddr(), ip_daddr(), ip_proto(), sport(),
    1357           0 :     dport(), ttl(0), icmp_chksum(0), tcp_ack(false), tunnel(),
    1358           0 :     l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
    1359           0 :     ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
    1360           0 :     is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
    1361           0 :     is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
    1362           0 :     eth(), arp(), ip(), ip6(), packet_buffer_(buff) {
    1363           0 :     transp.tcp = 0;
    1364           0 : }
    1365             : 
    1366        2432 : PktInfo::PktInfo(Agent *agent, uint32_t buff_len, PktHandler::PktModuleName mod,
    1367        2432 :                  uint32_t mdata) :
    1368        2432 :     module(mod),
    1369        2432 :     len(), max_pkt_len(), data(), ipc(), family(Address::UNSPEC),
    1370        2432 :     type(PktType::INVALID), agent_hdr(), ether_type(-1), ip_saddr(), ip_daddr(),
    1371        4864 :     ip_proto(), sport(), dport(), ttl(0), icmp_chksum(0), tcp_ack(false),
    1372        2432 :     tunnel(), l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
    1373        2432 :     ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
    1374        2432 :     is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
    1375        2432 :     is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
    1376        7296 :     eth(),arp(), ip(), ip6() {
    1377             : 
    1378             :     packet_buffer_ = agent->pkt()->packet_buffer_manager()->Allocate
    1379        2432 :         (module, buff_len, mdata);
    1380        2432 :     pkt = packet_buffer_->data();
    1381        2432 :     len = packet_buffer_->data_len();
    1382        2432 :     max_pkt_len = packet_buffer_->buffer_len();
    1383             : 
    1384        2432 :     transp.tcp = 0;
    1385        2432 : }
    1386             : 
    1387        1113 : PktInfo::PktInfo(PktHandler::PktModuleName mod, InterTaskMsg *msg) :
    1388        1113 :     module(mod),
    1389        1113 :     pkt(), len(), max_pkt_len(0), data(), ipc(msg), family(Address::UNSPEC),
    1390        1113 :     type(PktType::MESSAGE), agent_hdr(), ether_type(-1), ip_saddr(), ip_daddr(),
    1391        2226 :     ip_proto(), sport(), dport(), ttl(0), icmp_chksum(0), tcp_ack(false),
    1392        1113 :     tunnel(), l3_label(false), is_bfd_keepalive(false), is_segment_hc_pkt(false),
    1393        1113 :     ignore_address(VmInterface::IGNORE_NONE), same_port_number(false),
    1394        1113 :     is_fat_flow_src_prefix(false), ip_ff_src_prefix(),
    1395        1113 :     is_fat_flow_dst_prefix(false), ip_ff_dst_prefix(),
    1396        3339 :     eth(), arp(), ip(), ip6(), packet_buffer_() {
    1397        1113 :     transp.tcp = 0;
    1398        1113 : }
    1399             : 
    1400        7243 : PktInfo::~PktInfo() {
    1401        7243 : }
    1402             : 
    1403         336 : const AgentHdr &PktInfo::GetAgentHdr() const {
    1404         336 :     return agent_hdr;
    1405             : }
    1406             : 
    1407          75 : void PktInfo::reset_packet_buffer() {
    1408          75 :     packet_buffer_.reset();
    1409          75 : }
    1410             : 
    1411         113 : void PktInfo::AllocPacketBuffer(Agent *agent, uint32_t module, uint16_t len,
    1412             :                                 uint32_t mdata) {
    1413             :     packet_buffer_ = agent->pkt()->packet_buffer_manager()->Allocate
    1414         113 :         (module, len, mdata);
    1415         113 :     pkt = packet_buffer_->data();
    1416         113 :     len = packet_buffer_->data_len();
    1417         113 :     max_pkt_len = packet_buffer_->buffer_len();
    1418         113 : }
    1419             : 
    1420        2204 : void PktInfo::set_len(uint32_t x) {
    1421        2204 :     packet_buffer_->set_len(x);
    1422        2204 :     len = x;
    1423        2204 : }
    1424             : 
    1425           0 : void PktInfo::UpdateHeaderPtr() {
    1426           0 :     eth = (struct ether_header *)(pkt);
    1427           0 :     ip = (struct ip *)(eth + 1);
    1428           0 :     transp.tcp = (struct tcphdr *)(ip + 1);
    1429           0 : }
    1430             : 
    1431          62 : std::size_t PktInfo::hash(const Agent *agent,
    1432             :                           const EcmpLoadBalance &ecmp_load_balance) const {
    1433          62 :     std::size_t seed = 0;
    1434             :     // Bug: 1687879
    1435             :     // Consider that source compute has 2 member ECMP - compute-1 and compute-2
    1436             :     // Compute-1 is chosed in hash is even and Compute-2 is chosen if hash
    1437             :     // is add.
    1438             :     //
    1439             :     // On Compute-1, the hash computation uses same 5-tuple and will always
    1440             :     // result in even number. As a result, flows from Compute-1 will go to
    1441             :     // even-numbered ECMP members and never odd-numbered members.
    1442             :     // If Compute-2 happens to have only 2 members, all flows go to ecmp-index
    1443             :     // 0 and never to 1
    1444             :     //
    1445             :     // Solution:
    1446             :     // We need to ensure that hash computed in Compute-1 and Compute-2 are
    1447             :     // different. We also want to have same hash on agent restarts. So, include
    1448             :     // vhost-ip also to compute hash
    1449          62 :     if (agent->params()->flow_use_rid_in_hash()) {
    1450          62 :         boost::hash_combine(seed, agent->router_id().to_ulong());
    1451             :     }
    1452             : 
    1453          62 :     if (family == Address::INET) {
    1454          62 :         if (ecmp_load_balance.is_source_ip_set()) {
    1455          62 :             boost::hash_combine(seed, ip_saddr.to_v4().to_ulong());
    1456             :         }
    1457          62 :         if (ecmp_load_balance.is_destination_ip_set()) {
    1458          62 :             boost::hash_combine(seed, ip_daddr.to_v4().to_ulong());
    1459             :         }
    1460           0 :     } else if (family == Address::INET6) {
    1461           0 :         if (ecmp_load_balance.is_source_ip_set()) {
    1462             :             uint32_t words[4];
    1463           0 :             memcpy(words, ip_saddr.to_v6().to_bytes().data(), sizeof(words));
    1464           0 :             boost::hash_combine(seed, words[0]);
    1465           0 :             boost::hash_combine(seed, words[1]);
    1466           0 :             boost::hash_combine(seed, words[2]);
    1467           0 :             boost::hash_combine(seed, words[3]);
    1468             :         }
    1469             : 
    1470           0 :         if (ecmp_load_balance.is_destination_ip_set()) {
    1471             :             uint32_t words[4];
    1472           0 :             memcpy(words, ip_daddr.to_v6().to_bytes().data(), sizeof(words));
    1473           0 :             boost::hash_combine(seed, words[0]);
    1474           0 :             boost::hash_combine(seed, words[1]);
    1475           0 :             boost::hash_combine(seed, words[2]);
    1476           0 :             boost::hash_combine(seed, words[3]);
    1477             :         }
    1478             :     } else {
    1479           0 :         assert(0);
    1480             :     }
    1481          62 :     if (ecmp_load_balance.is_ip_protocol_set()) {
    1482          62 :         boost::hash_combine(seed, ip_proto);
    1483             :     }
    1484          62 :     if (ecmp_load_balance.is_source_port_set()) {
    1485          62 :         boost::hash_combine(seed, sport);
    1486             :     }
    1487          62 :     if (ecmp_load_balance.is_destination_port_set()) {
    1488          62 :         boost::hash_combine(seed, dport);
    1489             :     }
    1490             : 
    1491             :     // When only the sport changes by 2, its observed that only the lower 32
    1492             :     // bits of hash changes. Just hash combine upper and lower 32 bit numbers
    1493             :     // to randomize in case of incremental sport numbers
    1494          62 :     std::size_t hash = 0;
    1495          62 :     boost::hash_combine(hash, (seed & 0xFFFFFFFF));
    1496          62 :     boost::hash_combine(hash, (seed >> 16));
    1497          62 :     return hash;
    1498             : }
    1499             : 
    1500           0 : uint32_t PktInfo::GetUdpPayloadLength() const {
    1501           0 :     if (ip_proto == IPPROTO_UDP) {
    1502           0 :         return ntohs(transp.udp->uh_ulen) - sizeof(udphdr);
    1503             :     }
    1504           0 :     return 0;
    1505             : }
    1506             : 
    1507        1074 : void PktHandler::AddPktTrace(PktModuleName module, PktTrace::Direction dir,
    1508             :                              const PktInfo *pkt) {
    1509        1074 :     pkt_trace_.at(module).AddPktTrace(PktTrace::In, pkt->len, pkt->pkt,
    1510             :                                       &pkt->agent_hdr);
    1511        1074 : }
    1512             : 
    1513          75 : void PktHandler::Enqueue(PktModuleName module,
    1514             :                          boost::shared_ptr<PktInfo> pkt_info) {
    1515          75 :     if (!(proto_list_.at(module)->Enqueue(pkt_info))) {
    1516           0 :         stats_.PktQThresholdExceeded(module);
    1517             :     }
    1518          75 :     return;
    1519             : }
    1520             : 
    1521             : ///////////////////////////////////////////////////////////////////////////////
    1522        3278 : void PktTrace::Pkt::Copy(Direction d, std::size_t l, uint8_t *msg,
    1523             :                          std::size_t pkt_trace_size, const AgentHdr *hdr) {
    1524        3278 :     uint16_t hdr_len = sizeof(AgentHdr);
    1525        3278 :     dir = d;
    1526        3278 :     len = l + hdr_len;
    1527        3278 :     memcpy(pkt, hdr, hdr_len);
    1528        3278 :     memcpy(pkt + hdr_len, msg, std::min(l, (pkt_trace_size - hdr_len)));
    1529        3278 : }
    1530             : 
    1531        3278 : void PktTrace::AddPktTrace(Direction dir, std::size_t len, uint8_t *msg,
    1532             :                            const AgentHdr *hdr) {
    1533        3278 :     if (num_buffers_) {
    1534        3278 :         end_ = (end_ + 1) % num_buffers_;
    1535        3278 :         pkt_buffer_[end_].Copy(dir, len, msg, pkt_trace_size_, hdr);
    1536        3278 :         count_ = std::min((count_ + 1), (uint32_t) num_buffers_);
    1537             :     }
    1538        3278 : }

Generated by: LCOV version 1.14