LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - pkt_handler.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 5 50 10.0 %
Date: 2026-06-22 02:21:21 Functions: 5 26 19.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef vnsw_agent_pkt_handler_hpp
       6             : #define vnsw_agent_pkt_handler_hpp
       7             : 
       8             : #include <net/if.h>
       9             : #include <sys/socket.h>
      10             : #include <netinet/if_ether.h>
      11             : #include <netinet/ip.h>
      12             : #include <netinet/ip6.h>
      13             : #include <netinet/ip_icmp.h>
      14             : #include <netinet/igmp.h>
      15             : 
      16             : #include <boost/array.hpp>
      17             : 
      18             : #include <base/address.h>
      19             : #include <net/mac_address.h>
      20             : #include <oper/mirror_table.h>
      21             : #include <oper/nexthop.h>
      22             : #include <pkt/pkt_trace.h>
      23             : #include <pkt/packet_buffer.h>
      24             : 
      25             : #include "vr_defs.h"
      26             : 
      27             : #define DNS_SERVER_PORT              53
      28             : #define DHCP_SERVER_PORT             67
      29             : #define DHCP_CLIENT_PORT             68
      30             : #define DHCPV6_SERVER_PORT           547
      31             : #define DHCPV6_CLIENT_PORT           546
      32             : #define BFD_SINGLEHOP_CONTROL_PORT   3784
      33             : #define BFD_ECHO_PORT                3785
      34             : #define BFD_MULTIHOP_CONTROL_PORT    4784
      35             : #define VXLAN_UDP_DEST_PORT          4789
      36             : #define IANA_MPLS_OVER_UDP_DEST_PORT 6635
      37             : #define MPLS_OVER_UDP_DEST_PORT      51234
      38             : 
      39             : #define IPv4_ALEN           4
      40             : #define ARP_TX_BUFF_LEN     128
      41             : #define IPC_HDR_LEN        (sizeof(struct ether_header) + sizeof(struct agent_hdr))
      42             : #define VLAN_PROTOCOL      0x8100
      43             : #define DEFAULT_IP_TTL     64
      44             : //Ideally VM is one hop away but traffic gets routed so use 2.
      45             : #define BGP_SERVICE_TTL_REV_FLOW 2
      46             : #define BGP_SERVICE_TTL_FWD_FLOW 255
      47             : #define DEFAULT_IP_ID      0
      48             : #define VLAN_HDR_LEN       4
      49             : 
      50             : #define ICMP_UNREACH_HDR_LEN 8
      51             : 
      52             : #define ETHERTYPE_QINQ    0x88A8
      53             : #define ETHERTYPE_PBB     0x88E7
      54             : #define PBB_HEADER_LEN    4
      55             : 
      56             : struct PktInfo;
      57             : struct agent_hdr;
      58             : class PacketBuffer;
      59             : class Proto;
      60             : class EcmpLoadBalance;
      61             : typedef boost::shared_ptr<PktInfo> PktInfoPtr;
      62             : 
      63             : struct InterTaskMsg {
      64           0 :     InterTaskMsg(uint16_t command): cmd(command) {}
      65           0 :     virtual ~InterTaskMsg() {}
      66             : 
      67             :     uint16_t cmd;
      68             : };
      69             : 
      70             : struct GreHdr {
      71             :     GreHdr() : flags(), protocol() {}
      72             :     ~GreHdr() {}
      73             : 
      74             :     uint16_t flags;
      75             :     uint16_t protocol;
      76             : };
      77             : 
      78             : struct MplsHdr {
      79             :     MplsHdr() : hdr() {}
      80             :     ~MplsHdr() {}
      81             : 
      82             :     uint32_t hdr;
      83             : };
      84             : 
      85             : struct VxlanHdr {
      86             :     VxlanHdr() : reserved(0), vxlan_id(0) { }
      87           6 :     VxlanHdr(uint32_t id) : reserved(0), vxlan_id((id) << 8) { }
      88           6 :     ~VxlanHdr() { }
      89             : 
      90             :     uint32_t reserved;
      91             :     uint32_t vxlan_id;
      92             : };
      93             : 
      94             : struct PktType {
      95             :     enum Type {
      96             :         INVALID,
      97             :         ARP,
      98             :         IP,
      99             :         UDP,
     100             :         TCP,
     101             :         ICMP,
     102             :         ICMPV6,
     103             :         NON_IP,
     104             :         MESSAGE,
     105             :         SCTP,
     106             :         IGMP,
     107             :     };
     108             : };
     109             : 
     110             : struct PktStatsType {
     111             :     enum Type {
     112             :         PKT_RX,
     113             :         PKT_RX_ENQUEUE,
     114             :         PKT_RX_DROP_STATS,
     115             :         PKT_TX,
     116             :         PKT_TX_ERROR,
     117             :     };
     118             : };
     119             : 
     120             : struct sctphdr {
     121             :     u_int16_t th_sport;
     122             :     u_int16_t th_dport;
     123             :     u_int32_t vtag;
     124             : };
     125             : 
     126             : struct AgentHdr {
     127             :     // Packet commands between agent and vrouter. The values must be in-sync
     128             :     // with vrouter/include/vr_defs.h
     129             :     enum PktCommand {
     130             :         TX_SWITCH = AGENT_CMD_SWITCH,
     131             :         TX_ROUTE = AGENT_CMD_ROUTE,
     132             :         TRAP_ARP = AGENT_TRAP_ARP,
     133             :         TRAP_L2_PROTOCOL = AGENT_TRAP_L2_PROTOCOLS,
     134             :         TRAP_NEXTHOP = AGENT_TRAP_NEXTHOP,
     135             :         TRAP_RESOLVE = AGENT_TRAP_RESOLVE,
     136             :         TRAP_FLOW_MISS = AGENT_TRAP_FLOW_MISS,
     137             :         TRAP_L3_PROTOCOLS = AGENT_TRAP_L3_PROTOCOLS,
     138             :         TRAP_DIAG = AGENT_TRAP_DIAG,
     139             :         TRAP_UNUSED_1,
     140             :         TRAP_SOURCE_MISMATCH = AGENT_TRAP_SOURCE_MISMATCH,
     141             :         TRAP_HANDLE_DF = AGENT_TRAP_HANDLE_DF,
     142             :         TRAP_TOR_CONTROL_PKT = AGENT_TRAP_TOR_CONTROL_PKT,
     143             :         TRAP_ZERO_TTL = AGENT_TRAP_ZERO_TTL,
     144             :         TRAP_ICMP_ERROR = AGENT_TRAP_ICMP_ERROR,
     145             :         TRAP_FLOW_ACTION_HOLD = AGENT_TRAP_FLOW_ACTION_HOLD,
     146             :         TRAP_ROUTER_ALERT = AGENT_TRAP_ROUTER_ALERT,
     147             :         TRAP_MAC_LEARN = AGENT_TRAP_MAC_LEARN,
     148             :         TRAP_MAC_MOVE = AGENT_TRAP_MAC_MOVE,
     149             :         TRAP_MAC_IP_LEARNING = AGENT_TRAP_MAC_IP_LEARNING,
     150             :         TRAP_BFD = AGENT_TRAP_BFD,
     151             :         INVALID = MAX_AGENT_HDR_COMMANDS
     152             :     };
     153             : 
     154             :     enum PktCommandParams {
     155             :         PACKET_CMD_PARAM_CTRL = CMD_PARAM_PACKET_CTRL,
     156             :         PACKET_CMD_PARAM_DIAG = CMD_PARAM_1_DIAG,
     157             :         MAX_PACKET_CMD_PARAM  = MAX_CMD_PARAMS,
     158             :     };
     159             : 
     160           0 :     AgentHdr() :
     161           0 :         ifindex(-1), vrf(-1), cmd(-1), cmd_param(-1), cmd_param_1(-1),
     162           0 :         cmd_param_2(0), cmd_param_3(0), cmd_param_4(0), cmd_param_5(0),
     163           0 :         nh(-1), flow_index(-1), mtu(0) {}
     164             : 
     165             :     AgentHdr(uint32_t ifindex_p, uint32_t vrf_p, uint16_t cmd_p) :
     166             :         ifindex(ifindex_p), vrf(vrf_p), cmd(cmd_p), cmd_param(-1),
     167             :         cmd_param_1(-1), cmd_param_2(0), cmd_param_3(0), cmd_param_4(0),
     168             :         cmd_param_5(0), nh(-1), flow_index(-1), mtu(0) {}
     169             : 
     170           0 :     AgentHdr(uint32_t ifindex_p, uint32_t vrf_p, uint16_t cmd_p,
     171           0 :              uint32_t param1, uint32_t param2) :
     172           0 :         ifindex(ifindex_p), vrf(vrf_p), cmd(cmd_p), cmd_param(param1),
     173           0 :         cmd_param_1(param2), cmd_param_2(0), cmd_param_3(0), cmd_param_4(0),
     174           0 :         cmd_param_5(0), nh(-1), flow_index(-1), mtu(0) {}
     175             : 
     176           0 :     ~AgentHdr() {}
     177             : 
     178             :     // Fields from agent_hdr
     179             :     uint32_t            ifindex;
     180             :     uint32_t            vrf;
     181             :     uint16_t            cmd;
     182             :     uint32_t            cmd_param;
     183             :     uint32_t            cmd_param_1;
     184             :     uint32_t            cmd_param_2;
     185             :     uint32_t            cmd_param_3;
     186             :     uint32_t            cmd_param_4;
     187             :     uint8_t             cmd_param_5;
     188             :     uint32_t            nh;
     189             :     uint32_t            flow_index;
     190             :     uint16_t            mtu;
     191             : };
     192             : 
     193             : // Tunnel header decoded from the MPLSoGRE/MPLSoUDP encapsulated packet on
     194             : // fabric. Supports only IPv4 addresses since only IPv4 is supported on fabric
     195             : struct TunnelInfo {
     196           0 :     TunnelInfo() : type(TunnelType::INVALID) { Reset(); }
     197           0 :     ~TunnelInfo() {}
     198             : 
     199           0 :     void Reset() {
     200           0 :         type = TunnelType::INVALID;
     201           0 :         label = -1;
     202           0 :         vxlan_id = -1;
     203           0 :         src_port = 0;
     204           0 :         ip_saddr = 0;
     205           0 :         ip_daddr = 0;
     206           0 :         eth = NULL;
     207           0 :         ip = NULL;
     208           0 :     }
     209             : 
     210             :     TunnelType          type;
     211             :     uint32_t            label;      // Valid only for MPLSoGRE and MPLSoUDP
     212             :     uint32_t            vxlan_id;   // Valid only for VXLAN
     213             :     uint16_t            src_port;   // Valid only for VXLAN and MPLSoUDP
     214             :     uint32_t            ip_saddr;
     215             :     uint32_t            ip_daddr;
     216             :     struct ether_header *eth;
     217             :     struct ip           *ip;
     218             : };
     219             : 
     220             : // Receive packets from the pkt0 (tap) interface, parse and send the packet to
     221             : // appropriate protocol task. Also, protocol tasks can send packets to pkt0
     222             : // or to other tasks.
     223             : class PktHandler {
     224             : public:
     225             :     typedef boost::function<bool(boost::shared_ptr<PktInfo>)> RcvQueueFunc;
     226             :     typedef boost::function<void(PktTrace::Pkt &)> PktTraceCallback;
     227             : 
     228             :     static const uint32_t kMulticastControlWord = 0;
     229             :     static const uint32_t kMulticastControlWordSize = 4;
     230             :     enum PktModuleName {
     231             :         INVALID,
     232             :         FLOW,
     233             :         ARP,
     234             :         DHCP,
     235             :         DHCPV6,
     236             :         DNS,
     237             :         ICMP,
     238             :         ICMPV6,
     239             :         DIAG,
     240             :         ICMP_ERROR,
     241             :         ICMPV6_ERROR,
     242             :         RX_PACKET,
     243             :         MAC_LEARNING,
     244             :         BFD,
     245             :         IGMP,
     246             :         MAC_IP_LEARNING,
     247             :         MAX_MODULES
     248             :     };
     249             : 
     250             :     struct PktStats {
     251             :         uint32_t sent[MAX_MODULES];
     252             :         uint32_t received[MAX_MODULES];
     253             :         uint32_t q_threshold_exceeded[MAX_MODULES];
     254             :         uint32_t dropped;
     255           0 :         void Reset() {
     256           0 :             for (int i = 0; i < MAX_MODULES; ++i) {
     257           0 :                 sent[i] = received[i] = q_threshold_exceeded[i] = 0;
     258             :             }
     259           0 :             dropped = 0;
     260           0 :         }
     261           0 :         PktStats() { Reset(); }
     262             :         void PktRcvd(PktModuleName mod);
     263             :         void PktSent(PktModuleName mod);
     264             :         void PktQThresholdExceeded(PktModuleName mod);
     265             :     };
     266             : 
     267             :     struct PacketBufferEnqueueItem {
     268             :         const AgentHdr hdr;
     269             :         const PacketBufferPtr buff;
     270             : 
     271           0 :         PacketBufferEnqueueItem(const AgentHdr &h, const PacketBufferPtr &b)
     272           0 :             : hdr(h), buff(b) {}
     273             :     };
     274             :     typedef WorkQueue<boost::shared_ptr<PacketBufferEnqueueItem> >
     275             :         PktHandlerQueue;
     276             : 
     277             :     PktHandler(Agent *, PktModule *pkt_module);
     278             :     virtual ~PktHandler();
     279             : 
     280             :     void Register(PktModuleName type, RcvQueueFunc cb);
     281             :     void Register(PktModuleName type, Proto *proto);
     282             : 
     283             :     void Send(const AgentHdr &hdr, const PacketBufferPtr &buff);
     284             : 
     285             :     PktModuleName ParsePacket(const AgentHdr &hdr, PktInfo *pkt_info,
     286             :                               uint8_t *pkt);
     287             :     PktModuleName ParseBfdDataPacket(const AgentHdr &hdr, PktInfo *pkt_info,
     288             :                               uint8_t *pkt);
     289             :     int ParseUserPkt(PktInfo *pkt_info, Interface *intf,
     290             :                      PktType::Type &pkt_type, uint8_t *pkt);
     291             :     bool ProcessPacket(boost::shared_ptr<PacketBufferEnqueueItem> item);
     292             :     bool ProcessBfdDataPacket(boost::shared_ptr<PacketBufferEnqueueItem> item);
     293             : // identify pkt type and send to the registered handler
     294             :     void HandleRcvPkt(const AgentHdr &hdr, const PacketBufferPtr &buff);
     295             :     void SendMessage(PktModuleName mod, InterTaskMsg *msg);
     296             : 
     297             :     bool IsGwPacket(const Interface *intf, const IpAddress &dst_ip);
     298             : 
     299          12 :     const PktStats &GetStats() const { return stats_; }
     300           0 :     void ClearStats() { stats_.Reset(); }
     301             :     void PktTraceIterate(PktModuleName mod, PktTraceCallback cb);
     302           0 :     void PktTraceClear(PktModuleName mod) { pkt_trace_.at(mod).Clear(); }
     303           0 :     void PktTraceBuffers(PktModuleName mod, uint32_t buffers) {
     304           0 :         pkt_trace_.at(mod).set_num_buffers(buffers);
     305           0 :     }
     306           0 :     uint32_t PktTraceBuffers(PktModuleName mod) const {
     307           0 :         return pkt_trace_.at(mod).num_buffers();
     308             :     }
     309           0 :     uint32_t PktTraceSize(PktModuleName mod) const {
     310           0 :         return pkt_trace_.at(mod).pkt_trace_size();
     311             :     }
     312             :     void AddPktTrace(PktModuleName module, PktTrace::Direction dir,
     313             :                      const PktInfo *pkt);
     314             : 
     315             :     uint32_t EncapHeaderLen() const;
     316           0 :     Agent *agent() const { return agent_; }
     317             :     PktModule *pkt_module() const { return pkt_module_; }
     318             :     void Enqueue(PktModuleName module, boost::shared_ptr<PktInfo> pkt_info);
     319             :     bool IsFlowPacket(PktInfo *pkt_info);
     320             :     void CalculatePortIP(PktInfo *pkt_info);
     321           0 :     const PktHandlerQueue *work_queue() const { return &work_queue_; }
     322             : 
     323             :     bool IsBFDHealthCheckPacket(const PktInfo *pkt_info,
     324             :                                 const Interface *interface);
     325             :     bool IsSegmentHealthCheckPacket(const PktInfo *pkt_info,
     326             :                                     const Interface *interface);
     327             : 
     328          12 :     uint64_t GetBfdKaEnqueueCount() {return work_queue_bfd_ka_.NumEnqueues(); }
     329          12 :     uint64_t GetPktEnqueueCount() {return work_queue_.NumEnqueues(); }
     330             : 
     331             : private:
     332             :     void PktModuleEnqueue(PktModuleName mod, const AgentHdr &hdr,
     333             :                           boost::shared_ptr<PktInfo> pkt_info, uint8_t *pkt);
     334             :     int ParseEthernetHeader(PktInfo *pkt_info, uint8_t *pkt);
     335             :     int ParseMplsHdr(PktInfo *pkt_info, uint8_t *pkt);
     336             :     int ParseIpPacket(PktInfo *pkt_info, PktType::Type &pkt_type,
     337             :                       uint8_t *ptr);
     338             : 
     339             :     int ParseMPLSoGRE(PktInfo *pkt_info, uint8_t *pkt);
     340             :     int ParseMPLSoUDP(PktInfo *pkt_info, uint8_t *pkt);
     341             :     int ParseControlWord(PktInfo *pkt_info, uint8_t *pkt,
     342             :                          const MplsLabel *mpls);
     343             :     int ParseUDPTunnels(PktInfo *pkt_info, uint8_t *pkt);
     344             :     int ParseVxlan(PktInfo *pkt_info, uint8_t *pkt);
     345             :     int ParseUdp(PktInfo *pkt_info, uint8_t *pkt);
     346             :     bool ComputeForwardingMode(PktInfo *pkt_info, const Interface *intf) const;
     347             : 
     348             :     void SetOuterIp(PktInfo *pkt_info, uint8_t *pkt);
     349             :     void SetOuterMac(PktInfo *pkt_info);
     350             :     bool IgnoreFragmentedPacket(PktInfo *pkt_info);
     351             :     bool IsDHCPPacket(PktInfo *pkt_info);
     352             :     bool IsValidInterface(uint32_t ifindex, Interface **interface);
     353             :     bool IsToRDevice(uint32_t vrf_id, const IpAddress &ip);
     354             :     bool IsManagedTORPacket(Interface *intf, PktInfo *pkt_info,
     355             :                             PktType::Type &pkt_type, uint8_t *pkt,
     356             :                             bool *pkt_ok);
     357             :     bool IsFlowPacket(const AgentHdr &agent_hdr);
     358             :     bool IsDiagPacket(PktInfo *pkt_info);
     359             :     bool ValidateIpPacket(PktInfo *pkt_info);
     360             : 
     361             :     boost::array<Proto *, MAX_MODULES> proto_list_;
     362             :     Proto *bfd_keepalive_proto_;
     363             : 
     364             :     PktStats stats_;
     365             :     boost::array<PktTrace, MAX_MODULES> pkt_trace_;
     366             :     DBTableBase::ListenerId iid_;
     367             : 
     368             :     Agent *agent_;
     369             :     PktModule *pkt_module_;
     370             :     PktHandlerQueue work_queue_;
     371             :     PktHandlerQueue work_queue_bfd_ka_;
     372             :     DISALLOW_COPY_AND_ASSIGN(PktHandler);
     373             : };
     374             : 
     375             : // Info from the parsed packet
     376             : struct PktInfo {
     377             :     PktHandler::PktModuleName module;
     378             :     uint8_t             *pkt;
     379             :     uint16_t            len;
     380             :     uint16_t            max_pkt_len;
     381             : 
     382             :     uint8_t             *data;
     383             :     InterTaskMsg        *ipc;
     384             : 
     385             :     Address::Family     family;
     386             :     PktType::Type       type;
     387             :     AgentHdr            agent_hdr;
     388             :     uint16_t            ether_type;
     389             :     // Fields extracted for processing in agent
     390             :     uint32_t            vrf;
     391             :     MacAddress          smac;
     392             :     MacAddress          dmac;
     393             :     IpAddress           ip_saddr;
     394             :     IpAddress           ip_daddr;
     395             :     uint8_t             ip_proto;
     396             :     uint32_t            sport;
     397             :     uint32_t            dport;
     398             :     uint32_t            ttl;
     399             :     uint16_t            icmp_chksum;
     400             : 
     401             :     MacAddress          b_smac;
     402             :     MacAddress          b_dmac;
     403             :     uint32_t            i_sid;
     404             : 
     405             :     bool                tcp_ack;
     406             :     TunnelInfo          tunnel;
     407             :     bool                l3_label;
     408             :     bool                multicast_label;
     409             :     bool                is_bfd_keepalive;  // bfd keepalive packet
     410             :     bool                is_segment_hc_pkt;
     411             :     VmInterface::FatFlowIgnoreAddressType ignore_address; //fat-flow config
     412             :     bool                same_port_number;
     413             :     bool                is_fat_flow_src_prefix; // indicates fat flow with src prefix
     414             :     IpAddress           ip_ff_src_prefix; // fat flow src prefix
     415             :     bool                is_fat_flow_dst_prefix; // indicates fat flow with dst prefix
     416             :     IpAddress           ip_ff_dst_prefix; // fat flow dst prefix
     417             : 
     418             :     // Pointer to different headers in user packet
     419             :     struct ether_header *eth;
     420             :     uint32_t            *pbb_header;
     421             :     struct ether_arp    *arp;
     422             :     struct ip           *ip;
     423             :     struct ip6_hdr      *ip6;
     424             :     union {
     425             :         struct tcphdr   *tcp;
     426             :         struct udphdr   *udp;
     427             :         struct icmp     *icmp;
     428             :         struct icmp6_hdr *icmp6;
     429             :         struct sctphdr *sctp;
     430             :         struct igmp     *igmp;
     431             :     } transp;
     432             : 
     433             :     PktInfo(Agent *agent, uint32_t buff_len, PktHandler::PktModuleName module,
     434             :             uint32_t mdata);
     435             :     PktInfo(const PacketBufferPtr &buff);
     436             :     PktInfo(const PacketBufferPtr &buff, const AgentHdr &hdr);
     437             :     PktInfo(PktHandler::PktModuleName module, InterTaskMsg *msg);
     438             :     virtual ~PktInfo();
     439             : 
     440             :     const AgentHdr &GetAgentHdr() const;
     441             :     void UpdateHeaderPtr();
     442             :     std::size_t hash(const Agent *agent,
     443             :              const EcmpLoadBalance &ecmp_has_fields_to_use) const;
     444             : 
     445           0 :     PacketBuffer *packet_buffer() const { return packet_buffer_.get(); }
     446           0 :     PacketBufferPtr packet_buffer_ptr() const { return packet_buffer_; }
     447             :     void AllocPacketBuffer(Agent *agent, uint32_t module, uint16_t len,
     448             :                            uint32_t mdata);
     449             :     void set_len(uint32_t len);
     450             :     void reset_packet_buffer();
     451             : 
     452             :     uint32_t GetUdpPayloadLength() const;
     453             : 
     454             : private:
     455             :     PacketBufferPtr     packet_buffer_;
     456             : };
     457             : 
     458             : #endif

Generated by: LCOV version 1.14