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

Generated by: LCOV version 1.14