LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dp-core - vr_datapath.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 201 506 39.7 %
Date: 2026-11-09 02:10:49 Functions: 10 19 52.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_datapath.c -- data path inside the router
       3             :  *
       4             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       5             :  * Copyright Contributors to the OpenSDN project
       6             :  */
       7             : #include <vr_os.h>
       8             : #include <vr_bridge.h>
       9             : #include <vr_packet.h>
      10             : #include <vr_interface.h>
      11             : #include <vr_datapath.h>
      12             : #include <vr_mirror.h>
      13             : #include <vr_bridge.h>
      14             : #include <vr_packet.h>
      15             : 
      16             : #include "vr_ip_mtrie.h"
      17             : 
      18             : extern unsigned int vr_inet_route_flags(unsigned int, unsigned int);
      19             : extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short,
      20             :                                                  unsigned int);
      21             : extern struct vr_nexthop *
      22             : vr_inet_src_lookup(unsigned short vrf, struct vr_packet *pkt);
      23             : 
      24             : mac_response_t
      25           0 : vr_get_proxy_mac(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
      26             :         struct vr_route_req *rt, unsigned char *dmac)
      27             : {
      28             :     bool from_fabric, stitched, flood, over_lay, hosted_vm;
      29             :     bool to_gateway, no_proxy, to_vcp;
      30             : 
      31             :     unsigned char *resp_mac;
      32           0 :     struct vr_nexthop *nh = NULL, *l3_nh = NULL;
      33           0 :     struct vr_interface *vif = pkt->vp_if;
      34           0 :     struct vr_vrf_stats *stats = NULL;
      35             : 
      36           0 :     over_lay = true;
      37           0 :     from_fabric = stitched = flood = hosted_vm = false;
      38           0 :     to_gateway = to_vcp = no_proxy = false;
      39             : 
      40           0 :     if (vr_inet_vrf_stats)
      41           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
      42             :     /* here we will not check for stats, but will check before use */
      43             : 
      44           0 :     if (vif->vif_flags & VIF_FLAG_MAC_PROXY) {
      45           0 :         resp_mac = vif->vif_mac;
      46           0 :         goto proxy_selected;
      47             :     }
      48             : 
      49           0 :     if (vif->vif_type == VIF_TYPE_PHYSICAL)
      50           0 :         from_fabric = true;
      51             : 
      52           0 :     if (vif->vif_flags & VIF_FLAG_NO_ARP_PROXY)
      53           0 :         no_proxy = true;
      54             : 
      55           0 :     if (rt->rtr_req.rtr_label_flags & VR_RT_ARP_FLOOD_FLAG)
      56           0 :         flood = true;
      57             : 
      58           0 :     if (vif_is_vhost(vif) || (from_fabric && (fmd->fmd_label == -1) &&
      59           0 :                 (fmd->fmd_dvrf == vif->vif_vrf)))
      60           0 :         over_lay = false;
      61             : 
      62           0 :     if (vr_gateway_nexthop(rt->rtr_nh))
      63           0 :         to_gateway = true;
      64             : 
      65             :     /*
      66             :      * the no_proxy flag is set for the vcp ports. From such ports
      67             :      * vrouter should proxy only for the gateway ip.
      68             :      */
      69           0 :     if (no_proxy && !to_gateway)
      70           0 :         return MR_DROP;
      71             : 
      72           0 :     if (from_fabric) {
      73           0 :         if (vr_nexthop_is_vcp(rt->rtr_nh)) {
      74           0 :             to_vcp = true;
      75             :         }
      76             :     }
      77             : 
      78             : 
      79           0 :     l3_nh = rt->rtr_nh;
      80           0 :     resp_mac = vif->vif_mac;
      81           0 :     if (rt->rtr_req.rtr_index != VR_BE_INVALID_INDEX) {
      82           0 :         if ((nh = vr_bridge_lookup(fmd->fmd_dvrf, rt))) {
      83           0 :             resp_mac = rt->rtr_req.rtr_mac;
      84           0 :             stitched = true;
      85             :         }
      86             :     }
      87             : 
      88           0 :     if (!over_lay)
      89           0 :         nh = l3_nh;
      90             : 
      91           0 :     if (vr_hosted_nexthop(nh))
      92           0 :         hosted_vm = true;
      93             : 
      94             : 
      95             :     /*
      96             :      * situations that are handled here (from_fabric)
      97             :      *
      98             :      * . arp request from vm, but not proxied at the source because of lack
      99             :      *   of information at the source. only the compute that hosts the
     100             :      *   destination should respond, and that too only if the mac information
     101             :      *   is present (and hence the ENCAP check).
     102             :      *
     103             :      * . arp request from a baremetal arriving at a TSN, which if posesses the
     104             :      *   mac information for the destination vm, should proxy. If it does not
     105             :      *   hold the mac information, the request should be flooded
     106             :      *
     107             :      * . arp request from the uplink port of a vcp
     108             :      */
     109           0 :     if (from_fabric) {
     110           0 :         if (flood && !stitched) {
     111           0 :             if (stats)
     112           0 :                 stats->vrf_arp_physical_flood++;
     113           0 :             return MR_FLOOD;
     114             :         }
     115             : 
     116             :         /*
     117             :          * arp requests to gateway coming from the fabric should be dropped
     118             :          * unless the request was for the TSN DNS service (which appears as
     119             :          * the gateway, with the current set of checks). We should not respond
     120             :          * for gateway ip if we are TSN and the request came from baremetal.
     121             :          * TSN does not have gateway route and hence the to_gateway will be
     122             :          * true only for the DNS ip.
     123             :          */
     124           0 :         if (to_gateway) {
     125           0 :             if ((fmd->fmd_src != TOR_SOURCE) && (fmd->fmd_src !=
     126             :                         TOR_EVPN_SOURCE)) {
     127           0 :                 return MR_DROP;
     128             :             }
     129             :         }
     130             : 
     131             :         /*
     132             :          * we should proxy if the vm is hosted by us, in which case nh will be
     133             :          * of ENCAP type. we should also proxy for a host in vcp port. In all
     134             :          * other cases, we should proxy only if
     135             :          *
     136             :          * i am a TSN(fmd->fmd_src),
     137             :          * i amd the dns IP or
     138             :          * i have the mac information (nh - (mostly tunnel)) and
     139             :          * the originator is a bare metal (fmd->fmd_src)
     140             :          */
     141           0 :         if (to_vcp || to_gateway || hosted_vm ||
     142           0 :                 (fmd->fmd_src == TOR_SOURCE) ||
     143           0 :                 (fmd->fmd_src == TOR_EVPN_SOURCE)) {
     144           0 :             if (stats)
     145           0 :                 stats->vrf_arp_physical_stitch++;
     146             :         } else {
     147           0 :             if (stats)
     148           0 :                 stats->vrf_arp_physical_flood++;
     149             : 
     150           0 :             if (!over_lay)
     151           0 :                 return MR_XCONNECT;
     152             : 
     153           0 :             return MR_FLOOD;
     154             :         }
     155           0 :     } else if (!vif_is_vhost(vif)) {
     156             : 
     157           0 : proxy_selected:
     158           0 :         if (!stitched && flood) {
     159             :             /*
     160             :              * if there is no stitching information, but flood flag is set
     161             :              * we should flood
     162             :              */
     163           0 :             if (stats)
     164           0 :                 stats->vrf_arp_virtual_flood++;
     165           0 :             return MR_FLOOD;
     166             :         }
     167             : 
     168           0 :         if (stats) {
     169           0 :             if (stitched) {
     170           0 :                 stats->vrf_arp_virtual_stitch++;
     171             :             } else {
     172           0 :                 fmd->fmd_flags |= FMD_FLAG_MAC_IS_MY_MAC;
     173           0 :                 stats->vrf_arp_virtual_proxy++;
     174             :             }
     175             :         }
     176             :     }
     177             : 
     178           0 :     VR_MAC_COPY(dmac, resp_mac);
     179             : 
     180           0 :     return MR_PROXY;
     181             : }
     182             : 
     183             : static void
     184           0 : vr_arp_proxy(struct vr_arp *sarp, struct vr_packet *pkt,
     185             :         struct vr_forwarding_md *fmd, unsigned char *dmac)
     186             : {
     187             :     struct vr_eth *eth;
     188             :     struct vr_arp *arp;
     189             : 
     190           0 :     eth = (struct vr_eth *)pkt_push(pkt, sizeof(*eth));
     191           0 :     if (!eth) {
     192           0 :         PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_DATAPATH_C, __LINE__);
     193           0 :         vr_pfree(pkt, VP_DROP_PUSH);
     194           0 :         return;
     195             :     }
     196             : 
     197           0 :     memcpy(eth->eth_dmac, sarp->arp_sha, VR_ETHER_ALEN);
     198           0 :     memcpy(eth->eth_smac, dmac, VR_ETHER_ALEN);
     199           0 :     eth->eth_proto = htons(VR_ETH_PROTO_ARP);
     200             : 
     201           0 :     arp = (struct vr_arp *)(pkt_data(pkt) + sizeof(*eth));
     202           0 :     arp->arp_hw = htons(VR_ARP_HW_TYPE_ETHER);
     203           0 :     arp->arp_proto = htons(VR_ETH_PROTO_IP);
     204           0 :     arp->arp_hwlen = VR_ETHER_ALEN;
     205           0 :     arp->arp_protolen = VR_IP_ADDRESS_LEN;
     206           0 :     arp->arp_op = htons(VR_ARP_OP_REPLY);
     207           0 :     memcpy(arp->arp_sha, dmac, VR_ETHER_ALEN);
     208           0 :     memcpy(arp->arp_dha, sarp->arp_sha, VR_ETHER_ALEN);
     209           0 :     memcpy(&arp->arp_dpa, &sarp->arp_spa, sizeof(sarp->arp_spa));
     210           0 :     memcpy(&arp->arp_spa, &sarp->arp_dpa, sizeof(sarp->arp_dpa));
     211             : 
     212           0 :     vr_mac_reply_send(pkt, fmd);
     213             : 
     214           0 :     return;
     215             : }
     216             : 
     217             : static int
     218           6 : vr_handle_arp_request(struct vr_arp *sarp, struct vr_packet *pkt,
     219             :                       struct vr_forwarding_md *fmd, unsigned char *eth_dmac)
     220             : {
     221           6 :     int handled = true;
     222             :     unsigned char dmac[VR_ETHER_ALEN];
     223             :     mac_response_t arp_result;
     224             : 
     225             :     struct vr_packet *pkt_c;
     226           6 :     struct vr_interface *vif = pkt->vp_if;
     227           6 :     VR_MAC_COPY(dmac, eth_dmac);
     228             : 
     229           6 :     arp_result = vif->vif_mac_request(vif, pkt, fmd, dmac);
     230           6 :     switch (arp_result) {
     231           0 :     case MR_PROXY:
     232           0 :         vr_arp_proxy(sarp, pkt, fmd, dmac);
     233           0 :         break;
     234             : 
     235           3 :     case MR_XCONNECT:
     236           3 :         handled = vif_xconnect(pkt->vp_if, pkt, fmd);
     237           3 :         if (VR_RX_HANDLER_PASS != handled)
     238           3 :             handled = true;
     239           3 :         break;
     240             : 
     241           0 :     case MR_TRAP_X:
     242           0 :         pkt_c = vr_pclone(pkt);
     243           0 :         if (pkt_c) {
     244           0 :             vr_trap(pkt_c, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
     245           0 :             handled = vif_xconnect(pkt->vp_if, pkt, fmd);
     246           0 :             if (VR_RX_HANDLER_PASS != handled)
     247           0 :                 handled = true;
     248             :         } else {
     249           0 :             vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
     250             :         }
     251           0 :         break;
     252             : 
     253           0 :     case MR_MIRROR:
     254           0 :         pkt_c = vr_pclone(pkt);
     255           0 :         if (pkt_c)
     256           0 :             vr_trap(pkt_c, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
     257             : 
     258             :         /* Flood the original packet*/
     259           0 :         handled = false;
     260           0 :         break;
     261             : 
     262           0 :     case MR_DROP:
     263           0 :         PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
     264           0 :         vr_pfree(pkt, VP_DROP_INVALID_ARP);
     265           0 :         break;
     266             : 
     267           3 :     case MR_FLOOD:
     268             :     default:
     269             :         /*
     270             :          * If the packet is from Service Instance VM, we dont flood the
     271             :          * packet any where
     272             :          */
     273           3 :         if (!vif_is_service(pkt->vp_if)) {
     274           3 :             handled = false;
     275             :         } else {
     276           0 :             PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
     277           0 :             vr_pfree(pkt, VP_DROP_INVALID_ARP);
     278             :         }
     279           3 :         break;
     280             : 
     281             :     }
     282             : 
     283           6 :     return handled;
     284             : }
     285             : 
     286             : /*
     287             :  * ARP responses
     288             :  *    on fabric network: Both kernel and Agent are interested
     289             :  *    on fabric interface for VN : not handled
     290             :  *    from Virtual interface: If destined "to me" - trap to Agent
     291             :  *       else flood as well
     292             :  *
     293             :  */
     294             : static int
     295           0 : vr_handle_arp_reply(struct vr_arp *sarp, struct vr_packet *pkt,
     296             :                     struct vr_forwarding_md *fmd)
     297             : {
     298           0 :     struct vr_interface *vif = pkt->vp_if;
     299             :     struct vr_packet *cloned_pkt;
     300           0 :     int handled = 1;
     301             : 
     302             :     /*
     303             :      * If Vhost or fabric in cross connct mode, simply cross connect the
     304             :      * packet
     305             :      */
     306           0 :     if (vif_mode_xconnect(vif) || vif->vif_type == VIF_TYPE_HOST) {
     307           0 :         handled = vif_xconnect(vif, pkt, fmd);
     308           0 :         if (VR_RX_HANDLER_PASS != handled)
     309           0 :             handled = 1;
     310           0 :         return handled;
     311             :     }
     312             : 
     313           0 :     if (vif_is_virtual(vif)) {
     314             : 
     315             :         /*
     316             :          * If packet is destined "to me": packet is just trapped to
     317             :          * Agent. If multicast: paket would be Trapped and marked as
     318             :          * unhandled, so that caller continues to do original action. If
     319             :          * unicast, and not destined "to me" it is a case of unknown
     320             :          * unicast, and is not trapped to agent and caller takes the
     321             :          * aciton
     322             :          */
     323             : 
     324           0 :         if (fmd->fmd_to_me) {
     325           0 :             cloned_pkt = pkt;
     326           0 :         } else if (pkt->vp_flags & VP_FLAG_MULTICAST) {
     327           0 :             cloned_pkt = vr_pclone(pkt);
     328             : 
     329             :             /* If cloning fails, just trap original */
     330           0 :             if (cloned_pkt)
     331           0 :                 handled = 0;
     332             :             else
     333           0 :                 cloned_pkt = pkt;
     334             :         } else {
     335           0 :             return !handled;
     336             :         }
     337             : 
     338             :         /* If destined to me, Agent is interested in it */
     339           0 :         vr_preset(cloned_pkt);
     340           0 :         vr_trap(cloned_pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
     341           0 :         return handled;
     342             :     }
     343             : 
     344           0 :     if (vif_is_fabric(vif)) {
     345             : 
     346             :         /* If a tunneled packet, dont handle */
     347           0 :         if (fmd->fmd_label >= 0)
     348           0 :             return !handled;
     349             : 
     350             :         /*
     351             :          * in gro cases, fmd label won't be set. Hence, resort to the
     352             :          * following check to identify whether the packet was tunneled
     353             :          */
     354           0 :         if (fmd->fmd_dvrf != vif->vif_vrf)
     355           0 :             return !handled;
     356             : 
     357             :         /* If fabric: Agent and kernel are interested in it */
     358           0 :         cloned_pkt = pkt_cow(pkt, AGENT_PKT_HEAD_SPACE);
     359           0 :         if (cloned_pkt) {
     360           0 :             vr_preset(cloned_pkt);
     361           0 :             handled = vif_xconnect(vif, pkt, fmd);
     362           0 :             if (VR_RX_HANDLER_PASS != handled)
     363           0 :                 handled = 1;
     364           0 :             vr_trap(cloned_pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
     365             :         } else {
     366           0 :             vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ARP, NULL);
     367             :         }
     368             : 
     369           0 :         return handled;
     370             :     }
     371             : 
     372             :     /* Any other Response can be dropped */
     373           0 :     PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_DATAPATH_C, __LINE__);
     374           0 :     vr_pfree(pkt, VP_DROP_INVALID_IF);
     375             : 
     376           0 :     return handled;
     377             : }
     378             : 
     379             : /*
     380             :  * handle unicast arp requests and neighbor refreshes. In many cases,
     381             :  * we wouldn't like the unicast arp requests from gateway (such as MX)
     382             :  * to reach the VMs and change the gateway mac to ip(6) binding, since
     383             :  * for vms the gateway is always agent. We would like such requests
     384             :  * to go only if the mode is l2
     385             :  */
     386             : int
     387          60 : vif_plug_mac_request(struct vr_interface *vif, struct vr_packet *pkt,
     388             :         struct vr_forwarding_md *fmd)
     389             : {
     390          60 :     int nheader, handled = 1;
     391             :     unsigned char eth_dmac[VR_ETHER_ALEN];
     392             : 
     393          60 :     if (pkt->vp_flags & VP_FLAG_MULTICAST)
     394           0 :         goto unhandled;
     395             : 
     396          60 :     nheader = pkt_network_header(pkt) - pkt_data(pkt);
     397          60 :     if (nheader < 0 || (pkt->vp_data + nheader > pkt->vp_end))
     398           0 :         goto unhandled;
     399             : 
     400          60 :     VR_MAC_COPY(eth_dmac, pkt_data(pkt));
     401             : 
     402          60 :     if (pkt->vp_type == VP_TYPE_ARP) {
     403           0 :         if (pkt->vp_len < (nheader + sizeof(struct vr_arp)))
     404           0 :             goto unhandled;
     405             : 
     406           0 :         pkt_pull(pkt, nheader);
     407             : 
     408           0 :         handled = vr_arp_input(pkt, fmd, eth_dmac);
     409           0 :         if (!handled) {
     410           0 :             pkt_push(pkt, nheader);
     411             :         }
     412           0 :         return handled;
     413          60 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
     414           5 :         if (pkt->vp_len < (nheader + sizeof(struct vr_ip6) +
     415             :                     sizeof(struct vr_icmp) + VR_IP6_ADDRESS_LEN +
     416           5 :                     sizeof(struct vr_neighbor_option) + VR_ETHER_ALEN))
     417           5 :             goto unhandled;
     418             : 
     419           0 :         pkt_pull(pkt, nheader);
     420             : 
     421           0 :         handled = vr_neighbor_input(pkt, fmd, eth_dmac);
     422           0 :         if (!handled) {
     423           0 :             pkt_push(pkt, nheader);
     424             :         }
     425           0 :         return handled;
     426             :     }
     427             : 
     428          55 : unhandled:
     429          60 :     return !handled;
     430             : }
     431             : 
     432             : void
     433           0 : vr_mac_reply_send(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
     434             : {
     435           0 :     bool vif_tx = false;
     436             :     struct vr_forwarding_md fmd_new;
     437             :     struct vr_route_req rt;
     438           0 :     struct vr_nexthop *nh = NULL;
     439           0 :     struct vr_interface *vif = pkt->vp_if;
     440             : 
     441           0 :     vr_init_forwarding_md(&fmd_new);
     442           0 :     fmd_new.fmd_dvrf = fmd->fmd_dvrf;
     443           0 :     vr_pkt_type(pkt, 0, &fmd_new);
     444             : 
     445             :     /* Disable the flow processing for response packets */
     446           0 :     pkt->vp_flags |= VP_FLAG_FLOW_SET;
     447             : 
     448             :     /*
     449             :      * XXX: for vcp ports, there won't be bridge table entries. to avoid
     450             :      * doing vr_bridge_input, we check for the flag NO_ARP_PROXY and
     451             :      * and if set, directly send out on that interface
     452             :      * Incase of service instance with scaling of more than one, reply
     453             :      * can not be bridged as the destination mac address might point to
     454             :      * any of the primary/secondary. In this case, reply is forced
     455             :      * to go on the receiving VIF
     456             :      * If ARP request is received on fabric, reply on the same interface
     457             :      * only if vrf is 0 (underlay network)
     458             :      */
     459           0 :     if (vif_is_vhost(vif) || (vif_is_fabric(vif) && (fmd->fmd_dvrf == 0)) ||
     460           0 :             (vif->vif_flags & (VIF_FLAG_NO_ARP_PROXY | VIF_FLAG_MAC_PROXY))) {
     461           0 :         vif_tx = true;
     462             :     } else {
     463           0 :         rt.rtr_req.rtr_label_flags = 0;
     464           0 :         rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
     465           0 :         rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
     466           0 :         rt.rtr_req.rtr_mac = pkt_data(pkt);
     467           0 :         rt.rtr_req.rtr_vrf_id = fmd_new.fmd_dvrf;
     468           0 :         nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt);
     469           0 :         if (!nh || !(nh->nh_flags & NH_FLAG_VALID)) {
     470           0 :             PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_DATAPATH_C, __LINE__);
     471           0 :             vr_pfree(pkt, VP_DROP_INVALID_NH);
     472           0 :             return;
     473             :         }
     474           0 :         if (rt.rtr_req.rtr_label_flags & VR_BE_LABEL_VALID_FLAG)
     475           0 :             fmd_new.fmd_label = rt.rtr_req.rtr_label;
     476             : 
     477           0 :         if (vif_is_virtual(vif) && (nh->nh_dev != vif)) {
     478           0 :             vif_tx = true;
     479             :         }
     480             :     }
     481             : 
     482           0 :     if (vif_tx)
     483           0 :         vif->vif_tx(vif, pkt, &fmd_new);
     484             :     else
     485           0 :         nh_output(pkt, nh, &fmd_new);
     486             : 
     487           0 :     return;
     488             : }
     489             : 
     490             : 
     491             : /*
     492             :  * This funciton parses the ethernet packet and assigns the
     493             :  * pkt->vp_type, network protocol of the packet. The ethernet header can
     494             :  * start from an offset from vp_data
     495             :  */
     496             : int
     497         161 : vr_pkt_type(struct vr_packet *pkt, unsigned short offset,
     498             :             struct vr_forwarding_md *fmd)
     499             : {
     500         161 :     unsigned char *eth = pkt_data(pkt) + offset;
     501             :     unsigned short eth_proto;
     502         161 :     int pull_len, pkt_len = pkt_head_len(pkt) - offset;
     503             :     struct vr_vlan_hdr *vlan;
     504             : 
     505         161 :     pull_len = VR_ETHER_HLEN;
     506         161 :     if (pkt_len < pull_len)
     507           0 :         return -1;
     508             : 
     509         161 :     pkt->vp_flags &= ~(VP_FLAG_MULTICAST);
     510             : 
     511             :     /* L2 broadcast/multicast packets are multicast packets */
     512         161 :     if (IS_MAC_BMCAST(eth))
     513           9 :         pkt->vp_flags |= VP_FLAG_MULTICAST;
     514             : 
     515         161 :     eth_proto = ntohs(*(unsigned short *)(eth + VR_ETHER_PROTO_OFF));
     516         161 :     if (eth_proto == VR_ETH_PROTO_PBB) {
     517             : 
     518           0 :         if (pkt_len < (pull_len + sizeof(struct vr_pbb_itag)))
     519           0 :             return -1;
     520           0 :         pull_len += sizeof(struct vr_pbb_itag);
     521             : 
     522           0 :         if (pkt_len < (pull_len + VR_ETHER_HLEN))
     523           0 :             return -1;
     524             : 
     525           0 :         pkt->vp_type = vr_eth_proto_to_pkt_type(eth_proto);
     526           0 :         return 0;
     527             :     }
     528             : 
     529         161 :     while (eth_proto == VR_ETH_PROTO_VLAN) {
     530           0 :         if (pkt_len < (pull_len + sizeof(*vlan)))
     531           0 :             return -1;
     532           0 :         vlan = (struct vr_vlan_hdr *)(eth + pull_len);
     533             :         /*
     534             :          * consider the packet as vlan tagged only if it is provider
     535             :          * vlan tag. Customers vlan tag, Vrouter is not bothered off
     536             :          */
     537           0 :         if (fmd && (fmd->fmd_vlan == VLAN_ID_INVALID))
     538           0 :             fmd->fmd_vlan = ntohs(vlan->vlan_tag) & 0xFFF;
     539           0 :         eth_proto = ntohs(vlan->vlan_proto);
     540           0 :         pull_len += sizeof(*vlan);
     541             :     }
     542             : 
     543             : 
     544         161 :     pkt_set_network_header(pkt, pkt->vp_data + offset + pull_len);
     545         161 :     pkt_set_inner_network_header(pkt, pkt->vp_data + offset + pull_len);
     546         161 :     pkt->vp_type = vr_eth_proto_to_pkt_type(eth_proto);
     547             : 
     548         161 :     return 0;
     549             : }
     550             : 
     551             : int
     552           7 : vr_arp_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd,
     553             :         unsigned char *eth_dmac)
     554             : {
     555           7 :     int handled = 1;
     556             :     struct vr_arp sarp;
     557             : 
     558           7 :     if (pkt->vp_type != VP_TYPE_ARP)
     559           0 :         return !handled;
     560             : 
     561           7 :     if (pkt->vp_len < sizeof(struct vr_arp)) {
     562           1 :         PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
     563           1 :         vr_pfree(pkt, VP_DROP_INVALID_ARP);
     564           1 :         return handled;
     565             :     }
     566             : 
     567           6 :     memcpy(&sarp, pkt_data(pkt), sizeof(struct vr_arp));
     568             : 
     569             :     /* Validate the arp pkt */
     570           6 :     if (((htons(sarp.arp_hw) == VR_ARP_HW_TYPE_ETHER) &&
     571           6 :           (sarp.arp_hwlen != VR_ARP_HW_LEN)) ||
     572           6 :          ((htons(sarp.arp_proto) == VR_ETH_PROTO_IP) &&
     573           6 :           (sarp.arp_protolen != VR_ARP_PROTO_LEN_IPV4))) {
     574           0 :         PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
     575           0 :         vr_pfree(pkt, VP_DROP_INVALID_ARP);
     576           0 :         return handled;
     577             :     }
     578             : 
     579           6 :     switch (ntohs(sarp.arp_op)) {
     580           6 :     case VR_ARP_OP_REQUEST:
     581           6 :         return vr_handle_arp_request(&sarp, pkt, fmd, eth_dmac);
     582             : 
     583           0 :     case VR_ARP_OP_REPLY:
     584           0 :         return vr_handle_arp_reply(&sarp, pkt, fmd);
     585             :         break;
     586             : 
     587           0 :     default:
     588           0 :         PKT_LOG(VP_DROP_INVALID_ARP, pkt, 0, VR_DATAPATH_C, __LINE__);
     589           0 :         vr_pfree(pkt, VP_DROP_INVALID_ARP);
     590             :     }
     591             : 
     592           0 :     return handled;
     593             : }
     594             : 
     595             : int
     596          14 : vr_trap(struct vr_packet *pkt, unsigned short trap_vrf,
     597             :         unsigned short trap_reason, void *trap_param)
     598             : {
     599          14 :     struct vr_interface *vif = pkt->vp_if;
     600          14 :     struct vrouter *router = vif->vif_router;
     601             :     struct agent_send_params params;
     602             : 
     603          14 :     if (router->vr_agent_if && router->vr_agent_if->vif_send) {
     604          11 :         params.trap_vrf = trap_vrf;
     605          11 :         params.trap_reason = trap_reason;
     606          11 :         params.trap_param = trap_param;
     607          11 :         return router->vr_agent_if->vif_send(router->vr_agent_if, pkt,
     608             :                         &params);
     609             :     } else {
     610           3 :         PKT_LOG(VP_DROP_TRAP_NO_IF, pkt, 0, VR_DATAPATH_C, __LINE__);
     611           3 :         vr_pfree(pkt, VP_DROP_TRAP_NO_IF);
     612             :     }
     613             : 
     614           3 :     return 0;
     615             : }
     616             : 
     617             : unsigned int
     618           9 : vr_reinject_packet(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
     619             : {
     620           9 :     struct vr_interface *vif = pkt->vp_if;
     621             :     int handled;
     622             : 
     623           9 :     if (pkt->vp_nh) {
     624             :         /* If nexthop does not have valid data, drop it */
     625           1 :         if (!(pkt->vp_nh->nh_flags & NH_FLAG_VALID)) {
     626           0 :             PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_DATAPATH_C, __LINE__);
     627           0 :             vr_pfree(pkt, VP_DROP_INVALID_NH);
     628           0 :             return 0;
     629             :         }
     630             : 
     631           1 :         return pkt->vp_nh->nh_reach_nh(pkt, pkt->vp_nh, fmd);
     632             :     }
     633             : 
     634           8 :     if (vif_is_vhost(vif) ||
     635           8 :             (vif_is_fabric(vif) && (fmd->fmd_label < 0))) {
     636           0 :         handled = vr_l3_input(pkt, fmd);
     637           0 :         if (!handled)
     638           0 :             vif_drop_pkt(vif, pkt, 1);
     639           0 :         return 0;
     640             :     }
     641             : 
     642             : 
     643           8 :     return vr_bridge_input(vif->vif_router, pkt, fmd);
     644             : }
     645             : 
     646             : /*
     647             :  * vr_interface_input() is invoked if a packet ingresses an interface.
     648             :  * This function demultiplexes the packet to right input
     649             :  * function depending on the protocols enabled on the VIF
     650             :  */
     651             : unsigned int
     652         127 : vr_virtual_input(unsigned short vrf, struct vr_interface *vif,
     653             :                  struct vr_packet *pkt, struct vr_forwarding_md *fmd,
     654             :                  unsigned short vlan_id)
     655             : {
     656             :     struct vr_nexthop *nh;
     657             :     struct vr_eth *eth;
     658             :     struct vr_route_req vr_req;
     659         127 :     struct vr_rtable *rtable = NULL;
     660             :     uint32_t rt_prefix[4];
     661             :     struct vr_arp *arp;
     662             :     struct vrouter *router;
     663             :     uint8_t ip6_nxt;
     664             :     struct vr_ip6 *ip6;
     665             :     unsigned short *t_hdr;
     666             :     struct vr_icmp *icmph;
     667         127 :     bool check_trap_macipl = false;
     668         127 :     unsigned int ret = 0;
     669             : 
     670         127 :     fmd->fmd_vlan = vlan_id;
     671         127 :     fmd->fmd_dvrf = vrf;
     672         127 :     if (pkt->vp_priority != VP_PRIORITY_INVALID) {
     673           0 :         fmd->fmd_dotonep = pkt->vp_priority;
     674           0 :         pkt->vp_priority = VP_PRIORITY_INVALID;
     675             :     }
     676             : 
     677         127 :     if (vr_pkt_type(pkt, 0, fmd) < 0) {
     678           0 :         vif_drop_pkt(vif, pkt, 1);
     679           0 :         return 0;
     680             :     }
     681             : 
     682             :     /*
     683             :      * we really do not allow any broadcast packets from interfaces
     684             :      * that are part of transparent service chain, since transparent
     685             :      * service chain bridges packets across vrf (and hence loops can
     686             :      * happen)
     687             :      */
     688         127 :     if ((pkt->vp_flags & VP_FLAG_MULTICAST) &&
     689           1 :             (vif_is_service(vif)) && (pkt->vp_type != VP_TYPE_ARP)) {
     690           0 :         vif_drop_pkt(vif, pkt, 1);
     691           0 :         return 0;
     692             :     }
     693             : 
     694         127 :     if (!fmd->fmd_to_me) {
     695         127 :         eth = (struct vr_eth *)pkt_data(pkt);
     696         127 :         router = vrouter_get(0);
     697             : 
     698         127 :         if ((pkt->vp_if->vif_flags & VIF_FLAG_MAC_IP_LEARNING) &&
     699          12 :                 (pkt->vp_if->vif_flags & VIF_FLAG_L3_ENABLED) &&
     700          10 :                 (pkt->vp_if->vif_flags & VIF_FLAG_L2_ENABLED)){
     701             : 
     702          10 :             memset(&vr_req, 0, sizeof(struct vr_route_req));
     703          10 :             rtable = router->vr_inet_rtable;
     704          10 :             vr_req.rtr_req.rtr_prefix = (uint8_t*)&rt_prefix;
     705             : 
     706          10 :             if(pkt->vp_type == VP_TYPE_ARP) {
     707           5 :                 vr_req.rtr_req.rtr_prefix_size = 4;
     708           5 :                 vr_req.rtr_req.rtr_prefix_len = IP4_PREFIX_LEN;
     709           5 :                 vr_req.rtr_req.rtr_family = AF_INET;
     710           5 :                 arp = (struct vr_arp *)(pkt_data(pkt) + sizeof(struct vr_eth));
     711             : 
     712           5 :                 memcpy(vr_req.rtr_req.rtr_prefix, (uint8_t *)&arp->arp_spa,
     713             :                         sizeof(arp->arp_spa));
     714             : 
     715           5 :                 rtable->algo_get(fmd->fmd_dvrf, &vr_req);
     716           5 :                 check_trap_macipl = true;
     717             :             }
     718             : 
     719          10 :             if(pkt->vp_type == VP_TYPE_IP6){
     720           5 :                 ip6 = (struct vr_ip6 *)(pkt_data(pkt) + sizeof(struct vr_eth));
     721           5 :                 t_hdr = (unsigned short *)((char *)ip6 + sizeof(struct vr_ip6));
     722           5 :                 ip6_nxt = ip6->ip6_nxt;
     723           5 :                 if(ip6_nxt == VR_IP_PROTO_ICMP6) {
     724           5 :                     icmph = (struct vr_icmp *)t_hdr;
     725           5 :                     if((icmph->icmp_type == VR_ICMP6_TYPE_NEIGH_SOL) ||
     726           4 :                         (icmph->icmp_type == VR_ICMP6_TYPE_NEIGH_AD)){
     727           5 :                         vr_req.rtr_req.rtr_prefix_size = sizeof(ip6->ip6_src);
     728           5 :                         vr_req.rtr_req.rtr_prefix_len = IP6_PREFIX_LEN;
     729           5 :                         vr_req.rtr_req.rtr_family = AF_INET6;
     730           5 :                         memcpy(vr_req.rtr_req.rtr_prefix, ip6->ip6_src,
     731             :                                 sizeof(ip6->ip6_src));
     732           5 :                         rtable->algo_get(fmd->fmd_dvrf, &vr_req);
     733           5 :                         check_trap_macipl = true;
     734             :                     }
     735             :                 }
     736             :              }
     737             : 
     738          10 :              if(check_trap_macipl){
     739          10 :                  if(vr_req.rtr_nh && vr_req.rtr_nh->nh_id) {
     740           8 :                      if((pkt->vp_type == VP_TYPE_ARP &&
     741           4 :                           vr_req.rtr_req.rtr_prefix_len != IP4_PREFIX_LEN) ||
     742           8 :                         (pkt->vp_type == VP_TYPE_IP6 &&
     743           4 :                           vr_req.rtr_req.rtr_prefix_len != IP6_PREFIX_LEN) ||
     744           8 :                         ((vr_req.rtr_req.rtr_mac != NULL) &&
     745           4 :                           !(VR_MAC_CMP(eth->eth_smac, vr_req.rtr_req.rtr_mac)))) {
     746           2 :                          vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING,
     747             :                                    NULL);
     748           2 :                          return 0;
     749           6 :                      } else if (vr_req.rtr_req.rtr_mac == NULL) {
     750             :                         /* Incase of gatewayless forwarding, rtr_mac is NULL,
     751             :                          * So comparing source mac with nh encap data and trap
     752             :                          * to agent */
     753           4 :                          nh = vrouter_get_nexthop(0, vr_req.rtr_nh->nh_id);
     754           4 :                          if(nh && !(VR_MAC_CMP(eth->eth_smac, (nh->nh_data )))) {
     755           2 :                              vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING,
     756             :                                        NULL);
     757           2 :                              return 0;
     758             :                          }
     759             :                       }
     760             :                  } else {
     761           2 :                       vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING, NULL);
     762           2 :                       return 0;
     763             :                  }
     764             :              }
     765             :         }
     766             : 
     767         121 :         if ((pkt->vp_if->vif_flags & VIF_FLAG_MAC_IP_LEARNING) &&
     768           6 :                 (pkt->vp_if->vif_flags & VIF_FLAG_L2_ENABLED) &&
     769           6 :                 !(pkt->vp_if->vif_flags & VIF_FLAG_L3_ENABLED)) {
     770           2 :             if(pkt->vp_type == VP_TYPE_ARP) {
     771           2 :                 nh = __vrouter_bridge_lookup(fmd->fmd_dvrf, eth->eth_smac);
     772           2 :                 if(!nh) {
     773           1 :                     vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_MAC_IP_LEARNING, NULL);
     774           1 :                     return 0;
     775             :                 }
     776             :             }
     777             :         }
     778             : 
     779             :     }
     780             : 
     781         120 :     if (!vr_flow_forward(pkt->vp_if->vif_router, pkt, fmd))
     782          19 :         return 0;
     783             : 
     784         101 :     ret = vr_bridge_input(vif->vif_router, pkt, fmd);
     785             : 
     786         101 :     return ret;
     787             : }
     788             : 
     789             : unsigned int
     790          30 : vr_fabric_input(struct vr_interface *vif, struct vr_packet *pkt,
     791             :                 struct vr_forwarding_md *fmd, unsigned short vlan_id)
     792             : {
     793          30 :     int handled = 0;
     794          30 :     bool is_ipv6_nd_packet = false;
     795             :     unsigned short pull_len;
     796             :     unsigned char *data, eth_dmac[VR_ETHER_ALEN];
     797             : 
     798          30 :     if (vr_offload_prepare)
     799          30 :         vr_offload_prepare(pkt, fmd);
     800          30 :     fmd->fmd_vlan = vlan_id;
     801          30 :     fmd->fmd_dvrf = vif->vif_vrf;
     802             : 
     803          30 :     if (vr_pkt_type(pkt, 0, fmd) < 0) {
     804           0 :         vif_drop_pkt(vif, pkt, 1);
     805           0 :         return 0;
     806             :     }
     807             : 
     808          30 :     if ((pkt->vp_type == VP_TYPE_IP6) && !vr_is_ipv6_underlay_enabled())
     809           0 :         return vif_xconnect(vif, pkt, fmd);
     810             : 
     811          30 :     is_ipv6_nd_packet = vr_is_ipv6_nd_packet(pkt);
     812             :     /*
     813             :      * On Fabric ARP packets and IPv6 Neighbor Discovery packets are specially
     814             :      * handled. Rest all BUM traffic can be cross connected
     815             :      */
     816          30 :     if ((pkt->vp_type != VP_TYPE_ARP) && (!is_ipv6_nd_packet) &&
     817          17 :             (pkt->vp_flags & VP_FLAG_MULTICAST)) {
     818           2 :         return vif_xconnect(vif, pkt, fmd);
     819             :     }
     820             : 
     821          28 :     data = pkt_data(pkt);
     822          28 :     pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
     823          28 :     pkt_pull(pkt, pull_len);
     824             : 
     825          28 :     if (pkt->vp_type == VP_TYPE_IP) {
     826          14 :         handled = vr_l3_input(pkt, fmd);
     827          14 :     } else if (pkt->vp_type == VP_TYPE_ARP) {
     828           3 :         VR_MAC_COPY(eth_dmac, data);
     829           3 :         handled = vr_arp_input(pkt, fmd, eth_dmac);
     830           3 :         if(VR_RX_HANDLER_PASS == handled)
     831           0 :             return handled;
     832          11 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
     833          11 :         if (is_ipv6_nd_packet) {
     834          10 :             handled = vr_ipv6_nd_input(pkt, fmd);
     835             :         } else {
     836           1 :             handled = vr_l3_input(pkt, fmd);
     837             :         }
     838             :     }
     839             : 
     840          28 :     if (!handled) {
     841           4 :         pkt_push(pkt, pull_len);
     842           4 :         return vif_xconnect(vif, pkt, fmd);
     843             :     }
     844             : 
     845          24 :     return 0;
     846             : }
     847             : 
     848             : int
     849          45 : vr_l3_input(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
     850             : {
     851          45 :     struct vr_interface *vif = pkt->vp_if;
     852             : 
     853          45 :     if (pkt->vp_type == VP_TYPE_IP) {
     854          44 :         vr_ip_input(vif->vif_router, pkt, fmd);
     855          44 :         return 1;
     856           1 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
     857           1 :          vr_ip6_input(vif->vif_router, pkt, fmd);
     858           1 :          return 1;
     859             :     }
     860           0 :     return 0;
     861             : }
     862             : 
     863             : /*
     864             :  * Function to remove vlan from ethernet header. As it modifies vr_packet
     865             :  * structure and not skb, one is expected to invoke vr_pset_data() to
     866             :  * modify the data pointer of skb.
     867             :  */
     868             : 
     869             : int
     870           0 : vr_untag_pkt(struct vr_packet *pkt)
     871             : {
     872             :     struct vr_eth *eth;
     873             :     unsigned char *new_eth;
     874             : 
     875           0 :     eth = (struct vr_eth *)pkt_data(pkt);
     876           0 :     if (eth->eth_proto != htons(VR_ETH_PROTO_VLAN))
     877           0 :         return 0;
     878             : 
     879           0 :     new_eth = pkt_pull(pkt, VR_VLAN_HLEN);
     880           0 :     if (!new_eth)
     881           0 :         return -1;
     882             : 
     883           0 :     memmove(new_eth, eth, (2 * VR_ETHER_ALEN));
     884           0 :     return 0;
     885             : }
     886             : 
     887             : /*
     888             :  * Function to add vlan tag to ethernet header. As it modifies vr_packet
     889             :  * structure and not skb, one is expected to invoke vr_pset_data() to
     890             :  * modify the data pointer of skb
     891             :  */
     892             : int
     893           0 : vr_tag_pkt(struct vr_packet **pkt, unsigned short vlan_id, bool force_tag)
     894             : {
     895           0 :     uint8_t priority = 0;
     896             :     struct vr_packet *tmp_pkt;
     897             :     struct vr_eth *new_eth, *eth;
     898             :     unsigned short *vlan_tag;
     899             : 
     900           0 :     eth = (struct vr_eth *)pkt_data(*pkt);
     901           0 :     if (!force_tag) {
     902           0 :         if (eth->eth_proto == htons(VR_ETH_PROTO_VLAN))
     903           0 :             return 0;
     904             :     }
     905             : 
     906           0 :     if (pkt_head_space(*pkt) < VR_VLAN_HLEN) {
     907           0 :         tmp_pkt = vr_pexpand_head(*pkt, VR_VLAN_HLEN - pkt_head_space(*pkt));
     908           0 :         if (!tmp_pkt) {
     909           0 :             return -1;
     910             :         }
     911           0 :         *pkt = tmp_pkt;
     912             :     }
     913             : 
     914           0 :     new_eth = (struct vr_eth *)pkt_push(*pkt, VR_VLAN_HLEN);
     915           0 :     if (!new_eth)
     916           0 :         return -1;
     917             : 
     918           0 :     memmove(new_eth, eth, (2 * VR_ETHER_ALEN));
     919           0 :     new_eth->eth_proto = htons(VR_ETH_PROTO_VLAN);
     920           0 :     vlan_tag = (unsigned short *)(new_eth + 1);
     921           0 :     if ((*pkt)->vp_priority != VP_PRIORITY_INVALID)
     922           0 :         priority = (*pkt)->vp_priority;
     923             : 
     924           0 :     *vlan_tag = htons((priority << VR_VLAN_PRIORITY_SHIFT) | vlan_id);
     925             : 
     926           0 :     return 0;
     927             : }
     928             : 
     929             : void
     930           0 : vr_vlan_set_priority(struct vr_packet *pkt)
     931             : {
     932             :     struct vr_eth *eth;
     933             :     struct vr_vlan_hdr *vlan;
     934             : 
     935           0 :     eth = (struct vr_eth *)pkt_data(pkt);
     936           0 :     if (eth->eth_proto == htons(VR_ETH_PROTO_VLAN)) {
     937           0 :         vlan = (struct vr_vlan_hdr *)(eth + 1);
     938           0 :         if (pkt->vp_priority != VP_PRIORITY_INVALID) {
     939           0 :             vlan->vlan_tag |=
     940           0 :                 htons((pkt->vp_priority << VR_VLAN_PRIORITY_SHIFT));
     941             :         }
     942             :     }
     943             : 
     944           0 :     return;
     945             : }
     946             : 
     947             : int
     948           4 : vr_gro_input(struct vr_packet *pkt, struct vr_nexthop *nh)
     949             : {
     950           4 :     unsigned short push_len = 0;
     951           4 :     int handled = 1;
     952             :     struct vr_gro *gro;
     953             : 
     954           4 :     if (!vr_gro_process) {
     955           0 :         handled = 0;
     956           0 :         goto not_handled;
     957             :     }
     958             : 
     959           4 :     gro = (struct vr_gro *)pkt_push(pkt, sizeof(*gro));
     960           4 :     if (!gro) {
     961           0 :         handled = 0;
     962           0 :         goto not_handled;
     963             :     }
     964           4 :     push_len += sizeof(*gro);
     965             : 
     966           4 :     gro->vg_vif_id = pkt->vp_if->vif_idx;
     967           4 :     gro->pad = 0;
     968           4 :     gro->vg_nh_id = nh->nh_id;
     969             : 
     970           4 :     handled = vr_gro_process(pkt, nh->nh_dev, (nh->nh_family == AF_BRIDGE));
     971           4 : not_handled:
     972           4 :     if (!handled) {
     973           4 :         pkt_pull(pkt, push_len);
     974             :     }
     975             : 
     976           4 :     return handled;
     977             : }
     978             : 
     979             : int
     980           0 : __vr_pbb_decode(struct vr_eth *eth, int len, struct vr_forwarding_md *fmd)
     981             : {
     982           0 :     int pbb_size = sizeof(struct vr_eth) + sizeof(struct vr_pbb_itag);
     983             : 
     984           0 :     if (!eth || !fmd || (len < pbb_size))
     985           0 :         return -1;
     986             : 
     987           0 :     if (ntohs(eth->eth_proto) != VR_ETH_PROTO_PBB)
     988           0 :         return -1;
     989             : 
     990             :     /* Copy the PBB mac addresses to fmd */
     991           0 :     VR_MAC_COPY(fmd->fmd_smac, eth->eth_smac);
     992           0 :     VR_MAC_COPY(fmd->fmd_dmac, eth->eth_dmac);
     993             : 
     994           0 :     return pbb_size;
     995             : }
     996             : 
     997             : int
     998           0 : vr_pbb_decode(struct vr_packet *pkt, struct vr_forwarding_md *fmd)
     999             : {
    1000           0 :     int pbb_size, decode_error = 1;
    1001             : 
    1002           0 :     pbb_size = __vr_pbb_decode((struct vr_eth *)pkt_data(pkt),
    1003           0 :             pkt_head_len(pkt), fmd);
    1004           0 :     if (pbb_size <= 0) {
    1005           0 :         PKT_LOG(VP_DROP_INVALID_PACKET, pkt, 0, VR_DATAPATH_C, __LINE__);
    1006           0 :         vr_pfree(pkt, VP_DROP_INVALID_PACKET);
    1007           0 :         return decode_error;
    1008             :     }
    1009             : 
    1010           0 :     if (!pkt_pull(pkt, pbb_size)) {
    1011           0 :         PKT_LOG(VP_DROP_PULL, pkt, 0, VR_DATAPATH_C, __LINE__);
    1012           0 :         vr_pfree(pkt, VP_DROP_PULL);
    1013           0 :         return decode_error;
    1014             :     }
    1015             : 
    1016             :     /* Get the inner ether type and header pointers */
    1017           0 :     if (vr_pkt_type(pkt, 0, fmd) < 0) {
    1018           0 :         PKT_LOG(VP_DROP_INVALID_PACKET, pkt, 0, VR_DATAPATH_C, __LINE__);
    1019           0 :         vr_pfree(pkt, VP_DROP_INVALID_PACKET);
    1020           0 :         return decode_error;
    1021             :     }
    1022             : 
    1023           0 :     return !decode_error;
    1024             : }

Generated by: LCOV version 1.14