LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dp-core - vr_nexthop.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 1145 2579 44.4 %
Date: 2026-11-09 02:10:49 Functions: 60 84 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_nexthop.c -- data path nexthop management
       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_types.h>
       9             : #include <vr_packet.h>
      10             : #include <vr_interface.h>
      11             : #include <vr_nexthop.h>
      12             : #include <vr_vxlan.h>
      13             : 
      14             : #include "vr_message.h"
      15             : #include "vr_sandesh.h"
      16             : #include "vr_bridge.h"
      17             : #include "vr_btable.h"
      18             : #include "vr_datapath.h"
      19             : #include "vr_route.h"
      20             : #include "vr_hash.h"
      21             : #include "vr_mirror.h"
      22             : #include "vr_offloads_dp.h"
      23             : 
      24             : extern bool vr_has_to_fragment(struct vr_interface *, struct vr_packet *,
      25             :         unsigned int);
      26             : extern struct vr_vrf_stats *(*vr_inet_vrf_stats)(unsigned short, unsigned int);
      27             : extern struct vr_nexthop *vr_inet6_ip_lookup(unsigned short, uint8_t *);
      28             : extern struct vr_nexthop *vr_inet_ip_lookup(unsigned short, uint32_t);
      29             : extern struct vr_nexthop *vr_inet_src_lookup(unsigned short,
      30             :         struct vr_packet *);
      31             : extern l4_pkt_type_t vr_ip6_well_known_packet(struct vr_packet *);
      32             : extern l4_pkt_type_t vr_ip_well_known_packet(struct vr_packet *);
      33             : 
      34             : 
      35             : struct vr_nexthop *ip4_default_nh;
      36             : struct vr_nexthop *ip6_default_nh;
      37             : 
      38             : unsigned int vr_nexthops = VR_DEF_NEXTHOPS;
      39             : 
      40             : struct vr_nexthop *
      41    27894586 : __vrouter_get_nexthop(struct vrouter *router, unsigned int index)
      42             : {
      43    27894586 :     if (!router || index >= router->vr_max_nexthops)
      44           0 :         return NULL;
      45             : 
      46    27894586 :     return *(struct vr_nexthop **)vr_btable_get(router->vr_nexthops, index);
      47             : }
      48             : 
      49             : struct vr_nexthop *
      50      106621 : vrouter_get_nexthop(unsigned int rid, unsigned int index)
      51             : {
      52             :     struct vr_nexthop *nh;
      53             :     struct vrouter *router;
      54             : 
      55      106621 :     router = vrouter_get(rid);
      56      106621 :     nh = __vrouter_get_nexthop(router, index);
      57      106621 :     if (nh)
      58      106237 :         (void)vr_sync_add_and_fetch_32u(&nh->nh_users, 1);
      59             : 
      60      106621 :     return nh;
      61             : }
      62             : 
      63             : static int
      64         635 : __vrouter_set_nexthop(struct vrouter *router, unsigned int index,
      65             :         struct vr_nexthop *nh)
      66             : {
      67             :     struct vr_nexthop **nh_p;
      68             : 
      69         635 :     nh_p = (struct vr_nexthop **)vr_btable_get(router->vr_nexthops, index);
      70         635 :     if (!nh_p)
      71           0 :         return -EINVAL;
      72             : 
      73         635 :     *nh_p = nh;
      74         635 :     return 0;
      75             : }
      76             : 
      77             : static bool
      78           2 : vr_l2_control_data_add(struct vr_packet **pkt)
      79             : {
      80             : 
      81             :     unsigned int *data;
      82             :     struct vr_packet *tmp_pkt;
      83             : 
      84           2 :     if (pkt_head_space(*pkt) < VR_L2_CTRL_DATA_LEN) {
      85           0 :         tmp_pkt = vr_pexpand_head(*pkt, VR_L2_CTRL_DATA_LEN -
      86           0 :                                                 pkt_head_space(*pkt));
      87           0 :         if (!tmp_pkt)
      88           0 :             return false;
      89           0 :         *pkt = tmp_pkt;
      90             :     }
      91             : 
      92           2 :     data = (unsigned int *)pkt_push(*pkt, VR_L2_CTRL_DATA_LEN);
      93           2 :     if (!data)
      94           0 :         return false;
      95             : 
      96           2 :     *data = VR_L2_CTRL_DATA;
      97           2 :     return true;
      98             : }
      99             : 
     100             : 
     101             : static void
     102         309 : vrouter_free_nexthop(struct vr_nexthop *nh)
     103             : {
     104             :     int i;
     105             : 
     106         309 :     if (nh->nh_type == NH_COMPOSITE) {
     107           5 :         if (nh->nh_component_nh) {
     108           5 :             vr_free(nh->nh_component_nh, VR_NEXTHOP_COMPONENT_OBJECT);
     109           5 :             nh->nh_component_nh = NULL;
     110             :         }
     111             : 
     112           5 :         if (nh->nh_component_ecmp) {
     113           4 :             nh->nh_component_ecmp_cnt = 0;
     114           4 :             vr_free(nh->nh_component_ecmp, VR_NEXTHOP_COMPONENT_OBJECT);
     115           4 :             nh->nh_component_ecmp = NULL;
     116             :         }
     117             : 
     118         304 :     } else if ((nh->nh_type == NH_TUNNEL) &&
     119          52 :             (nh->nh_flags & NH_FLAG_TUNNEL_UDP) &&
     120           1 :             (nh->nh_family == AF_INET6)) {
     121           0 :         if (nh->nh_udp_tun6_sip) {
     122           0 :             vr_free(nh->nh_udp_tun6_sip, VR_NETWORK_ADDRESS_OBJECT);
     123           0 :             nh->nh_udp_tun6_sip = NULL;
     124             :         }
     125             : 
     126           0 :         if (nh->nh_udp_tun6_dip) {
     127           0 :             vr_free(nh->nh_udp_tun6_dip, VR_NETWORK_ADDRESS_OBJECT);
     128           0 :             nh->nh_udp_tun6_dip = NULL;
     129             :         }
     130             :     }
     131             : 
     132        1236 :     for (i = 0; i < VR_MAX_PHY_INF; i++) {
     133         927 :         if (nh->nh_dev_arr[i]) {
     134         237 :             vrouter_put_interface(nh->nh_dev_arr[i]);
     135             :         }
     136             :     }
     137             : 
     138         309 :     vr_free(nh, VR_NEXTHOP_OBJECT);
     139         309 :     return;
     140             : }
     141             : 
     142             : static void
     143         179 : vrouter_free_nexthop_cb(struct vrouter *router, void *data)
     144             : {
     145         179 :     struct vr_defer_data *vdd = (struct vr_defer_data *)data;
     146             : 
     147         179 :     if (!vdd)
     148           0 :         return;
     149             : 
     150         179 :     vrouter_free_nexthop((struct vr_nexthop *)vdd->vdd_data);
     151         179 :     return;
     152             : }
     153             : 
     154             : static int
     155         179 : vrouter_free_nexthop_defer(struct vr_nexthop *nh)
     156             : {
     157             :     struct vr_defer_data *defer;
     158             : 
     159         179 :     defer = vr_get_defer_data(sizeof(*defer));
     160         179 :     if (!defer)
     161           0 :         return -ENOMEM;
     162             : 
     163         179 :     defer->vdd_data = nh;
     164         179 :     vr_defer(nh->nh_router, vrouter_free_nexthop_cb, (void *)defer);
     165             : 
     166         179 :     return 0;
     167             : }
     168             : 
     169             : void
     170      106543 : vrouter_put_nexthop(struct vr_nexthop *nh)
     171             : {
     172             :     int i, component_cnt;
     173             :     struct vr_nexthop *cnh;
     174             :     unsigned int ref_cnt;
     175             : 
     176      106543 :     if (!nh)
     177           0 :         return;
     178             : 
     179             :     /* This function might get invoked with zero ref_cnt */
     180      106543 :     ref_cnt = nh->nh_users;
     181      106543 :     if (ref_cnt) {
     182      106542 :         ref_cnt = vr_sync_sub_and_fetch_32u(&nh->nh_users, 1);
     183             :     }
     184             : 
     185      106543 :     if (!ref_cnt ) {
     186             : 
     187             :         /* If indirect, lets de-ref the direct nh too */
     188         309 :         if ((nh->nh_flags & NH_FLAG_INDIRECT) && nh->nh_direct_nh) {
     189           0 :             cnh = nh->nh_direct_nh;
     190           0 :             nh->nh_direct_nh = NULL;
     191           0 :             vrouter_put_nexthop(cnh);
     192             :         }
     193             : 
     194             :         /* If composite de-ref the internal nexthops */
     195         309 :         if (nh->nh_type == NH_COMPOSITE) {
     196           5 :             component_cnt = nh->nh_component_cnt;
     197           5 :             nh->nh_component_cnt = 0;
     198          14 :             for (i = 0; i < component_cnt; i++) {
     199           9 :                 if (nh->nh_component_nh[i].cnh) {
     200           9 :                     cnh = nh->nh_component_nh[i].cnh;
     201           9 :                     nh->nh_component_nh[i].cnh = NULL;
     202           9 :                     vrouter_put_nexthop(cnh);
     203             :                 }
     204             :             }
     205             :         }
     206             : 
     207         309 :         if (vr_not_ready) {
     208         130 :             vrouter_free_nexthop(nh);
     209             :         } else {
     210         179 :             if (vrouter_free_nexthop_defer(nh)) {
     211           0 :                 vr_delay_op();
     212           0 :                 vrouter_free_nexthop(nh);
     213             :             }
     214             :         }
     215             :     }
     216             : 
     217      106543 :     return;
     218             : }
     219             : 
     220             : static int
     221         329 : vrouter_add_nexthop(struct vr_nexthop *nh)
     222             : {
     223         329 :     struct vrouter *router = vrouter_get(nh->nh_rid);
     224             : 
     225         329 :     if (!router || nh->nh_id >= router->vr_max_nexthops)
     226           0 :         return -EINVAL;
     227             : 
     228             :     /*
     229             :      * NH change just copies the field
     230             :      * over to nexthop, incase of change
     231             :      * just return
     232             :      */
     233         329 :     if (__vrouter_get_nexthop(router, nh->nh_id))
     234          12 :         return 0;
     235             : 
     236         317 :     nh->nh_users++;
     237         317 :     return __vrouter_set_nexthop(router, nh->nh_id, nh);
     238             : }
     239             : 
     240             : static void
     241         318 : nh_del(struct vr_nexthop *nh)
     242             : {
     243         318 :     struct vrouter *router = vrouter_get(nh->nh_rid);
     244             : 
     245         318 :     if (!router || nh->nh_id >= router->vr_max_nexthops)
     246           0 :         return;
     247             : 
     248         318 :     __vrouter_set_nexthop(router, nh->nh_id, NULL);
     249         318 :     vrouter_put_nexthop(nh);
     250             : 
     251         318 :     return;
     252             : }
     253             : 
     254             : bool
     255          44 : vr_gateway_nexthop(struct vr_nexthop *nh)
     256             : {
     257          44 :     if (nh) {
     258          44 :         if (!nh->nh_dev)
     259           2 :             return false;
     260             : 
     261          42 :         if ((nh->nh_type == NH_ENCAP) &&
     262          27 :                 (nh->nh_dev->vif_type == VIF_TYPE_AGENT))
     263           0 :             return true;
     264             :     }
     265             : 
     266          42 :     return false;
     267             : }
     268             : 
     269             : 
     270             : bool
     271           0 : vr_hosted_nexthop(struct vr_nexthop *nh)
     272             : {
     273           0 :     if (nh) {
     274           0 :         if (!nh->nh_dev)
     275           0 :             return false;
     276             : 
     277           0 :         if ((nh->nh_type == NH_ENCAP) && vif_is_virtual(nh->nh_dev))
     278           0 :             return true;
     279             :     }
     280             : 
     281           0 :     return false;
     282             : }
     283             : 
     284             : static int
     285          63 : nh_tunnel_loop_detect_handle(struct vr_packet *pkt, struct vr_nexthop *nh,
     286             :                                     struct vr_forwarding_md *fmd, uint32_t dip)
     287             : {
     288          63 :     if (!pkt || !nh || !fmd || !dip)
     289           0 :         return 0;
     290             : 
     291          63 :     if ((!fmd->fmd_outer_src_ip) || !vif_is_fabric(pkt->vp_if))
     292          63 :         return 0;
     293             : 
     294           0 :     if (nh->nh_type != NH_TUNNEL)
     295           0 :         return 0;
     296             : 
     297           0 :     if (fmd->fmd_outer_src_ip == dip) {
     298           0 :         PKT_LOG(VP_DROP_PKT_LOOP, pkt, 0, VR_NEXTHOP_C, __LINE__);
     299           0 :         vr_pfree(pkt, VP_DROP_PKT_LOOP);
     300           0 :         return 1;
     301             :     }
     302             : 
     303           0 :     return 0;
     304             : }
     305             : 
     306             : static struct vr_interface *
     307           8 : nh_underlay_tunnel_vif_selection(struct vr_packet *pkt, struct
     308             :     vr_forwarding_md *fmd, struct vr_nexthop *nh, unsigned short *drop_reason)
     309             : {
     310           8 :     struct vr_interface *vif = NULL;
     311             :     uint32_t hash;
     312             :     int index;
     313             : 
     314             :     /* flow mode: check for underlay ecmp index */
     315           8 :     if (fmd->fmd_underlay_ecmp_index >= 0) {
     316             :         /* If true, then assign that index to vif */
     317           1 :         if (nh->nh_encap_valid[fmd->fmd_underlay_ecmp_index])
     318           1 :             vif = nh->nh_dev_arr[fmd->fmd_underlay_ecmp_index];
     319             :         else {
     320           0 :             *drop_reason = VP_DROP_INVALID_UNDERLAY_ECMP;
     321           0 :             return vif;
     322             :         }
     323             :     } else {
     324             :         /* packet mode: compute 5 tuple hash and assign interface */
     325           7 :         hash = vr_get_pkt_hash(pkt);
     326           7 :         index = hash % VR_MAX_PHY_INF;
     327           7 :         if (!nh->nh_encap_valid[index]) {
     328           4 :             if (!nh->nh_valid_underlay_dev_count) {
     329           0 :                 *drop_reason = VP_DROP_INVALID_UNDERLAY_ECMP;
     330           0 :                 return vif;
     331             :             }
     332           4 :             hash = hash % nh->nh_valid_underlay_dev_count;
     333           4 :             vif = nh->nh_valid_underlay_dev[hash];
     334             :         } else
     335           3 :             vif = nh->nh_dev_arr[index];
     336             :     }
     337             : 
     338           8 :     return vif;
     339             : }
     340             : 
     341             : 
     342             : static nh_processing_t
     343           0 : nh_resolve(struct vr_packet *pkt, struct vr_nexthop *nh,
     344             :            struct vr_forwarding_md *fmd)
     345             : {
     346           0 :     struct vr_vrf_stats *stats = NULL;
     347             :     struct vr_packet *pkt_clone;
     348             : 
     349           0 :     if (vr_inet_vrf_stats) {
     350           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
     351           0 :         if (stats)
     352           0 :             stats->vrf_resolves++;
     353             :     }
     354             : 
     355             :     /*
     356             :         * bridge is set only for vhost/physical interface, and this
     357             :         * path will be hit only for packets from vhost, in which case
     358             :         * we already know everything that has to be known i.e. we know
     359             :         * the outgoing device and the mac address (which was already
     360             :         * resolved as part of the arp request from host
     361             :         */
     362           0 :     pkt_clone = vr_pclone(pkt);
     363           0 :     if (pkt_clone) {
     364             :         /* xconnect the original pkt */
     365           0 :         vr_preset(pkt);
     366           0 :         vif_xconnect(pkt->vp_if, pkt, fmd);
     367             :         /* will trap the packet to agent to create a route */
     368           0 :         vr_trap(pkt_clone, fmd->fmd_dvrf, AGENT_TRAP_RESOLVE, NULL);
     369           0 :         return NH_PROCESSING_COMPLETE;
     370             :     }
     371             : 
     372             :     /* will trap the packet to agent to create a route */
     373           0 :     vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_RESOLVE, NULL);
     374             : 
     375           0 :     return NH_PROCESSING_COMPLETE;
     376             : }
     377             : 
     378             : static nh_processing_t
     379           1 : nh_vrf_translate(struct vr_packet *pkt, struct vr_nexthop *nh,
     380             :                  struct vr_forwarding_md *fmd)
     381             : {
     382           1 :     struct vr_vrf_stats *stats = NULL;
     383             : 
     384           1 :     if (vr_inet_vrf_stats) {
     385           1 :         stats = vr_inet_vrf_stats(nh->nh_vrf, pkt->vp_cpu);
     386           1 :         if (stats)
     387           1 :             stats->vrf_vrf_translates++;
     388             :     }
     389             : 
     390           1 :     fmd->fmd_dvrf = nh->nh_vrf;
     391           1 :     if (nh->nh_family == AF_INET)
     392           0 :         return vr_forward(nh->nh_router, pkt, fmd);
     393             : 
     394           1 :     if (pkt->vp_type == VP_TYPE_PBB) {
     395           0 :         if (vr_pbb_decode(pkt, fmd))
     396           0 :             return 0;
     397             :     }
     398             : 
     399           1 :     vr_bridge_input(nh->nh_router, pkt, fmd);
     400             : 
     401           1 :     return NH_PROCESSING_COMPLETE;
     402             : }
     403             : 
     404             : static nh_processing_t
     405          29 : nh_l2_rcv(struct vr_packet *pkt, struct vr_nexthop *nh,
     406             :           struct vr_forwarding_md *fmd)
     407             : {
     408             :     unsigned char eth_dmac[VR_ETHER_ALEN], *data;
     409          29 :     int pull_len, handled = 0;
     410          29 :     struct vr_vrf_stats *stats = NULL;
     411             : 
     412          29 :     if (vr_inet_vrf_stats) {
     413          29 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
     414          29 :         if (stats)
     415          29 :             stats->vrf_l2_receives++;
     416             :     }
     417             : 
     418          29 :     data = pkt_data(pkt);
     419          29 :     fmd->fmd_to_me = 1;
     420          29 :     pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
     421          29 :     if (!pkt_pull(pkt, pull_len)) {
     422           0 :         PKT_LOG(VP_DROP_PULL, pkt, 0, VR_NEXTHOP_C, __LINE__);
     423           0 :         vr_pfree(pkt, VP_DROP_PULL);
     424           0 :         return NH_PROCESSING_COMPLETE;
     425             :     }
     426             : 
     427             :     /*
     428             :      * there should not be any unicast ARP requests destined to "my mac".
     429             :      * The ARP response destined to "my mac" incase of ARP request being
     430             :      * generated by Agent for some features
     431             :      */
     432          29 :     if (pkt->vp_type == VP_TYPE_IP6) {
     433           0 :         VR_MAC_COPY(eth_dmac, data);
     434           0 :         handled = vr_neighbor_input(pkt, fmd, eth_dmac);
     435           0 :         if (!handled)
     436           0 :             handled = vr_l3_input(pkt, fmd);
     437          29 :     } else if (pkt->vp_type == VP_TYPE_IP) {
     438          29 :         handled = vr_l3_input(pkt, fmd);
     439           0 :     } else if (pkt->vp_type == VP_TYPE_ARP) {
     440           0 :         VR_MAC_COPY(eth_dmac, data);
     441           0 :         handled = vr_arp_input(pkt, fmd, eth_dmac);
     442             :     }
     443             : 
     444          29 :     if (!handled){
     445           0 :         PKT_LOG(VP_DROP_INVALID_PROTOCOL, pkt, 0, VR_NEXTHOP_C, __LINE__);
     446           0 :         vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL);
     447             :     }
     448          29 :     return NH_PROCESSING_COMPLETE;
     449             : }
     450             : 
     451             : static nh_processing_t
     452          11 : nh_l3_rcv(struct vr_packet *pkt, struct vr_nexthop *nh,
     453             :           struct vr_forwarding_md *fmd)
     454             : {
     455          11 :     struct vr_vrf_stats *stats = NULL;
     456             : 
     457          11 :     if (vr_inet_vrf_stats) {
     458          11 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
     459          11 :         if (stats)
     460          11 :             stats->vrf_receives++;
     461             :     }
     462             : 
     463          11 :     if (nh->nh_family == AF_INET)
     464          11 :         return vr_ip_rcv(nh->nh_router, pkt, fmd);
     465             :     else {
     466           0 :         PKT_LOG(VP_DROP_INVALID_PROTOCOL, pkt, 0, VR_NEXTHOP_C, __LINE__);
     467           0 :         vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL);
     468             :     }
     469           0 :     return NH_PROCESSING_COMPLETE;
     470             : }
     471             : 
     472             : static int
     473          57 : nh_push_mpls_header(struct vr_packet *pkt, unsigned int label,
     474             :         struct vr_forwarding_class_qos *qos, bool is_bottom_label)
     475             : {
     476          57 :     uint32_t exp_qos = 0;
     477             :     unsigned int *lbl;
     478             :     unsigned int ttl;
     479          57 :     unsigned int label_pos = 0;
     480             : 
     481          57 :     lbl = (unsigned int *)pkt_push(pkt, sizeof(unsigned int));
     482          57 :     if (!lbl)
     483           0 :         return -ENOSPC;
     484             : 
     485             :     /* Use the ttl from packet. If not ttl,
     486             :      * initialise to some arbitrary value */
     487          57 :     ttl = pkt->vp_ttl;
     488          57 :     if (!ttl) {
     489           0 :         ttl = 64;
     490             :     }
     491             : 
     492          57 :     if (qos) {
     493           0 :         exp_qos = qos->vfcq_mpls_qos;
     494           0 :         exp_qos <<= VR_MPLS_EXP_QOS_SHIFT;
     495             :     }
     496          57 :     if (is_bottom_label) {
     497          57 :         label_pos = 1;
     498             :     }
     499          57 :     *lbl = htonl((label << VR_MPLS_LABEL_SHIFT) | exp_qos |
     500          57 :             (label_pos << 8) | ttl);
     501             : 
     502          57 :     return 0;
     503             : }
     504             : 
     505             : /*
     506             :  * nh_udp_tunnel_helper - helper function to use for UDP tunneling. Used
     507             :  * by mirroring and MPLS over UDP. Returns true on success, false otherwise.
     508             :  */
     509             : static bool
     510          60 : nh_udp_tunnel_helper(struct vr_packet *pkt, unsigned short sport,
     511             :         unsigned short dport, unsigned int sip,
     512             :         unsigned int dip, struct vr_forwarding_class_qos *qos)
     513             : {
     514             :     struct vr_ip *ip;
     515             :     struct vr_udp *udp;
     516             : 
     517             :     /* Udp Header */
     518          60 :     udp = (struct vr_udp *)pkt_push(pkt, sizeof(struct vr_udp));
     519          60 :     if (!udp) {
     520           0 :         return false;
     521             :     }
     522             : 
     523          60 :     udp->udp_sport = sport;
     524          60 :     udp->udp_dport = dport;
     525          60 :     udp->udp_length = htons(pkt_len(pkt));
     526          60 :     udp->udp_csum = 0;
     527             : 
     528             :     /* And now the IP header */
     529          60 :     ip = (struct vr_ip *)pkt_push(pkt, sizeof(struct vr_ip));
     530          60 :     if (!ip) {
     531           0 :         return false;
     532             :     }
     533             : 
     534          60 :     ip->ip_version = 4;
     535          60 :     ip->ip_hl = 5;
     536          60 :     if (qos) {
     537           0 :         ip->ip_tos = VR_IP_DSCP(qos->vfcq_dscp);
     538           0 :         pkt->vp_queue = qos->vfcq_queue_id;
     539           0 :         pkt->vp_priority = qos->vfcq_dotonep_qos;
     540             :     } else {
     541          60 :         ip->ip_tos = 0;
     542             :     }
     543          60 :     ip->ip_id = htons(vr_generate_unique_ip_id());
     544          60 :     ip->ip_frag_off = 0;
     545             : 
     546          60 :     if (vr_pkt_is_diag(pkt)) {
     547           0 :         ip->ip_ttl = pkt->vp_ttl;
     548             :     } else {
     549          60 :         ip->ip_ttl = 64;
     550             :     }
     551             : 
     552          60 :     ip->ip_proto = VR_IP_PROTO_UDP;
     553          60 :     ip->ip_saddr = sip;
     554          60 :     ip->ip_daddr = dip;
     555          60 :     ip->ip_len = htons(pkt_len(pkt));
     556             : 
     557             :     /*
     558             :      * header checksum
     559             :      */
     560          60 :     ip->ip_csum = 0;
     561          60 :     ip->ip_csum = vr_ip_csum(ip);
     562             : 
     563          60 :     return true;
     564             : }
     565             : 
     566             : static bool
     567           0 : nh_udp_tunnel6_helper(struct vr_packet *pkt, struct vr_nexthop *nh,
     568             :                         uint8_t *sip, uint16_t sport, uint16_t dport)
     569             : {
     570             :     struct vr_ip6 *ip6;
     571             :     struct vr_udp *udp;
     572             : 
     573           0 :     if (!sip)
     574           0 :         sip = nh->nh_udp_tun6_sip;
     575             : 
     576             :     /* udp Header */
     577           0 :     udp = (struct vr_udp *)pkt_push(pkt, sizeof(struct vr_udp));
     578           0 :     if (!udp) {
     579           0 :         return false;
     580             :     }
     581             : 
     582           0 :     udp->udp_sport = sport;
     583           0 :     udp->udp_dport = dport;
     584           0 :     udp->udp_length = htons(pkt_len(pkt));
     585           0 :     udp->udp_csum = 0;
     586             : 
     587             :     /* And now the IP6 header */
     588           0 :     ip6 = (struct vr_ip6 *)pkt_push(pkt, sizeof(struct vr_ip6));
     589           0 :     if (!ip6) {
     590           0 :         return false;
     591             :     }
     592             : 
     593           0 :     ip6->ip6_version = 6;
     594           0 :     ip6->ip6_priority_l = 0;
     595           0 :     ip6->ip6_priority_h = 0;
     596           0 :     ip6->ip6_flow_l = 0;
     597           0 :     ip6->ip6_flow_h = 0;
     598           0 :     ip6->ip6_plen = htons(pkt_len(pkt) - sizeof(struct vr_ip6));
     599           0 :     ip6->ip6_nxt = VR_IP_PROTO_UDP;
     600           0 :     ip6->ip6_hlim = 64;
     601             : 
     602           0 :     memcpy(ip6->ip6_src, sip, VR_IP6_ADDRESS_LEN);
     603           0 :     memcpy(ip6->ip6_dst, nh->nh_udp_tun6_dip, VR_IP6_ADDRESS_LEN);
     604             : 
     605             : 
     606           0 :     return true;
     607             : }
     608             : 
     609             : static bool
     610           0 : nh_pbb_tunnel_helper(struct vrouter *router, struct vr_packet **pkt,
     611             :         struct vr_forwarding_md *fmd, uint8_t *dmac, uint8_t *smac,
     612             :         uint32_t isid)
     613             : {
     614             :     int pbb_head_space;
     615             :     struct vr_pbb_itag *pbb_itag;
     616             :     struct vr_eth *eth;
     617             :     struct vr_packet *expanded_pkt;
     618             : 
     619           0 :     pbb_head_space = sizeof(struct vr_pbb_itag) + VR_ETHER_HLEN;
     620             : 
     621           0 :     if (pkt_head_space(*pkt) < pbb_head_space) {
     622           0 :         expanded_pkt = vr_pexpand_head(*pkt, pbb_head_space - pkt_head_space(*pkt));
     623           0 :         if (!expanded_pkt)
     624           0 :             return false;
     625           0 :         *pkt = expanded_pkt;
     626             :     }
     627             : 
     628           0 :     pbb_itag = (struct vr_pbb_itag *)pkt_push(*pkt, sizeof(*pbb_itag));
     629           0 :     if (!pbb_itag)
     630           0 :         return false;
     631           0 :     pbb_itag->pbbi_pcp = pbb_itag->pbbi_dei = 0;
     632           0 :     pbb_itag->pbbi_uca = pbb_itag->pbbi_res = 0;
     633           0 :     pbb_itag->pbbi_isid = (htonl(isid) >> 8) & 0xFFFFFF;
     634             : 
     635           0 :     eth = (struct vr_eth *)pkt_push(*pkt, VR_ETHER_HLEN);
     636           0 :     if(!eth)
     637           0 :         return false;
     638             : 
     639           0 :     VR_MAC_COPY(eth->eth_dmac, dmac);
     640           0 :     VR_MAC_COPY(eth->eth_smac, smac);
     641           0 :     eth->eth_proto = htons(VR_ETH_PROTO_PBB);
     642             : 
     643           0 :     return true;
     644             : }
     645             : 
     646             : static bool
     647           8 : nh_vxlan_tunnel_helper(struct vrouter *router, struct vr_packet **pkt,
     648             :         struct vr_forwarding_md *fmd, unsigned int sip, unsigned int dip)
     649             : {
     650           8 :     unsigned short udp_src_port = VR_VXLAN_UDP_SRC_PORT;
     651             : 
     652             :     struct vr_vxlan *vxlanh;
     653             :     struct vr_packet *expanded_pkt;
     654             :     struct vr_forwarding_class_qos *qos;
     655             : 
     656           8 :     if (pkt_head_space(*pkt) < VR_VXLAN_HDR_LEN) {
     657           0 :         expanded_pkt = vr_pexpand_head(*pkt, VR_VXLAN_HDR_LEN - pkt_head_space(*pkt));
     658           0 :         if (!expanded_pkt) {
     659           0 :             return false;
     660             :         }
     661           0 :         *pkt = expanded_pkt;
     662             :     }
     663             : 
     664           8 :     if (fmd->fmd_udp_src_port)
     665           2 :         udp_src_port = fmd->fmd_udp_src_port;
     666             : 
     667             :     /*
     668             :      * The UDP source port is a hash of the inner headers
     669             :      */
     670           8 :     if ((!fmd->fmd_udp_src_port) && vr_get_udp_src_port) {
     671           6 :         udp_src_port = vr_get_udp_src_port(*pkt, fmd, fmd->fmd_dvrf);
     672           6 :         if (udp_src_port == 0) {
     673           0 :          return false;
     674             :         }
     675             :     }
     676             : 
     677           8 :     vr_fmd_update_label_type(fmd, VR_LABEL_TYPE_VXLAN_ID);
     678             : 
     679             :     /* Add the vxlan header */
     680           8 :     vxlanh = (struct vr_vxlan *)pkt_push(*pkt, sizeof(struct vr_vxlan));
     681           8 :     vxlanh->vxlan_vnid = htonl(fmd->fmd_label << VR_VXLAN_VNID_SHIFT);
     682           8 :     vxlanh->vxlan_flags = htonl(VR_VXLAN_IBIT);
     683             : 
     684           8 :     qos = vr_qos_get_forwarding_class(router, *pkt, fmd);
     685           8 :     return nh_udp_tunnel_helper(*pkt, htons(udp_src_port),
     686           8 :             htons(VR_VXLAN_UDP_DST_PORT), sip, dip, qos);
     687             : }
     688             : 
     689             : static struct vr_packet *
     690           2 : nh_mcast_clone(struct vr_packet *pkt, unsigned short head_room)
     691             : {
     692             :     struct vr_packet *clone_pkt;
     693             : 
     694             :     /* Clone the packet */
     695           2 :     clone_pkt = vr_pclone(pkt);
     696           2 :     if (!clone_pkt) {
     697           0 :         return NULL;
     698             :     }
     699             : 
     700             :     /* Increase the head space by the head_room */
     701           2 :     if (vr_pcow(&clone_pkt, head_room)) {
     702           0 :         PKT_LOG(VP_DROP_PCOW_FAIL, pkt, 0, VR_NEXTHOP_C, __LINE__);
     703           0 :         vr_pfree(clone_pkt, VP_DROP_PCOW_FAIL);
     704           0 :         return NULL;
     705             :     }
     706             : 
     707             :     /* Copy the ttl from old packet */
     708           2 :     clone_pkt->vp_ttl = pkt->vp_ttl;
     709             : 
     710           2 :     return clone_pkt;
     711             : }
     712             : 
     713             : static int
     714           0 : nh_composite_ecmp_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
     715             :                                struct vr_forwarding_md *fmd, void *ret_data)
     716             : {
     717             :     int i;
     718           0 :     int status = NH_SOURCE_INVALID;
     719           0 :     unsigned int inner_ecmp_index = -1;/* reset to invalid */
     720           0 :     struct vr_nexthop *cnh = NULL;
     721             : 
     722             :     /* the first few checks are straight forward */
     723           0 :     if (!fmd)
     724           0 :         return NH_SOURCE_INVALID;
     725             : 
     726           0 :     if ((fmd->fmd_ecmp_src_nh_index >= 0) &&
     727           0 :             (fmd->fmd_ecmp_src_nh_index < nh->nh_component_cnt)) {
     728           0 :         cnh = nh->nh_component_nh[fmd->fmd_ecmp_src_nh_index].cnh;
     729             :     }
     730             : 
     731             :     /*
     732             :      * when the 'supposed' source goes down, cnh is null, in which
     733             :      * case validate the source against other present nexthops. follow
     734             :      * the same logic if the component validate source returns invalid
     735             :      * source, which could mean that source has moved
     736             :      */
     737           0 :     if (!cnh || (!cnh->nh_validate_src) ||
     738           0 :             (NH_SOURCE_INVALID == cnh->nh_validate_src(pkt, cnh, fmd, NULL))) {
     739           0 :         for (i = 0; i < nh->nh_component_cnt; i++) {
     740           0 :             if (i == fmd->fmd_ecmp_src_nh_index)
     741           0 :                 continue;
     742             : 
     743           0 :             cnh = nh->nh_component_nh[i].cnh;
     744             :             /* If direct nexthop is not valid, dont process it */
     745           0 :             if (!cnh || !(cnh->nh_flags & NH_FLAG_VALID) ||
     746           0 :                                             !cnh->nh_validate_src)
     747           0 :                 continue;
     748             : 
     749             :             /*
     750             :              * if the source has moved to a present and valid source,
     751             :              * return mismatch
     752             :              */
     753           0 :             status = cnh->nh_validate_src(pkt, cnh, fmd, &inner_ecmp_index);
     754           0 :             if (status == NH_SOURCE_VALID) {
     755           0 :                 if (ret_data) {
     756           0 :                     *(unsigned int *)ret_data = i;
     757             :                 }
     758           0 :                 return NH_SOURCE_MISMATCH;
     759             :             }
     760             :             /*
     761             :              * Handle multi level ECMP,
     762             :              * inner ecmp returns NH_SOURCE_MISMATCH, return the
     763             :              * same error. copy inner_ecmp_value for NH mismatch case only.
     764             :              */
     765           0 :             if (status == NH_SOURCE_MISMATCH) {
     766           0 :                 if (ret_data) {
     767           0 :                     *(unsigned int *)ret_data = inner_ecmp_index;
     768             :                 }
     769           0 :                 return NH_SOURCE_MISMATCH;
     770             :             }
     771             :         }
     772             : 
     773             :         /* if everything else fails, source is indeed invalid */
     774           0 :         return NH_SOURCE_INVALID;
     775             :     }
     776             : 
     777             :     /* source is validated by validate_src */
     778           0 :     return NH_SOURCE_VALID;
     779             : }
     780             : 
     781             : /*
     782             :  * nh_ecmp_config_hash is two byte value. The configurable hash as such is
     783             :  * 5 bit field. We store agent added configurable hash values in the first
     784             :  * byte and convert them to Flow flags and store them in second byte
     785             :  */
     786             : static void
     787           4 : nh_ecmp_store_ecmp_config_hash(vr_nexthop_req *req, struct vr_nexthop *nh)
     788             : {
     789             :     unsigned char hash;
     790             :     unsigned short flow_hash;
     791             :     int i;
     792             : 
     793           4 :     if (!nh || (nh->nh_type != NH_COMPOSITE) ||
     794           4 :        (!(nh->nh_flags & NH_FLAG_COMPOSITE_ECMP))) {
     795           0 :         return;
     796             :     }
     797             : 
     798           4 :     if (!req || !req->nhr_ecmp_config_hash) {
     799           4 :         nh->nh_ecmp_config_hash = ((VR_FLOW_KEY_ALL << 8) & 0xFF00);
     800           4 :         return;
     801             :     }
     802             : 
     803           0 :     flow_hash = 0;
     804           0 :     hash = req->nhr_ecmp_config_hash & NH_ECMP_CONFIG_HASH_MASK;
     805             : 
     806           0 :     for (i = 0; i < NH_ECMP_CONFIG_HASH_BITS; i++) {
     807           0 :         switch (hash & (1 << i)) {
     808           0 :         case NH_ECMP_CONFIG_HASH_PROTO:
     809           0 :             flow_hash |= VR_FLOW_KEY_PROTO;
     810           0 :             break;
     811           0 :         case NH_ECMP_CONFIG_HASH_SRC_IP:
     812           0 :             flow_hash |= VR_FLOW_KEY_SRC_IP;
     813           0 :             break;
     814           0 :         case NH_ECMP_CONFIG_HASH_SRC_PORT:
     815           0 :             flow_hash |= VR_FLOW_KEY_SRC_PORT;
     816           0 :             break;
     817           0 :         case NH_ECMP_CONFIG_HASH_DST_IP:
     818           0 :             flow_hash |= VR_FLOW_KEY_DST_IP;
     819           0 :             break;
     820           0 :         case NH_ECMP_CONFIG_HASH_DST_PORT:
     821           0 :             flow_hash |= VR_FLOW_KEY_DST_PORT;
     822           0 :             break;
     823           0 :         default:
     824           0 :             break;
     825             :         }
     826             :     }
     827             : 
     828             :     /* In the nh, store flow hash values in the second byte */
     829           0 :     nh->nh_ecmp_config_hash = hash | ((flow_hash << 8) & 0xFF00);
     830             : 
     831           0 :     return;
     832             : }
     833             : 
     834             : 
     835             : /*
     836             :  * Returns the ecmp nh index based on the reverse flows information. If
     837             :  * the reverse flow is created because of a packet on Fabric,
     838             :  * rflow_src_info contains tunnel's source IP, if created because of a
     839             :  * packet on VMI, it contains VMI's index. The ecmp nh is chosen in such
     840             :  * a way that packet is given to same reverse flow source
     841             :  */
     842             : static int
     843           1 : nh_composite_ecmp_select_by_rflow(struct vr_packet *pkt,
     844             :         struct vr_nexthop *nh, struct vr_forwarding_md *fmd,
     845             :         uint32_t rflow_src_info)
     846             : {
     847             :     int index;
     848             :     uint32_t ip;
     849             :     struct vr_nexthop *cnh;
     850             : 
     851           1 :     ip = fmd->fmd_outer_src_ip;
     852           1 :     fmd->fmd_outer_src_ip = rflow_src_info;
     853           3 :     for (index = 0; index < nh->nh_component_cnt; index++) {
     854           2 :         cnh = nh->nh_component_nh[index].cnh;
     855           2 :         if (!cnh || !(cnh->nh_flags & NH_FLAG_VALID))
     856           0 :             continue;
     857             : 
     858             :         /*
     859             :          * Make use of tunnel's nh_validate_src as it validates the
     860             :          * tunnel source
     861             :          */
     862           2 :         if ((cnh->nh_type == NH_TUNNEL) && cnh->nh_validate_src) {
     863           2 :             if (NH_SOURCE_VALID == cnh->nh_validate_src(pkt, cnh, fmd, NULL))
     864           0 :                 break;
     865             :         }
     866             : 
     867             :         /*
     868             :          * nh_validate_src cant be used as it compares VIF pointer for
     869             :          * encap. Validate the index explicitly
     870             :          */
     871           2 :         if (cnh->nh_type == NH_ENCAP) {
     872           0 :             if (cnh->nh_dev->vif_idx == rflow_src_info)
     873           0 :                 break;
     874             :         }
     875             :     }
     876             : 
     877           1 :     fmd->fmd_outer_src_ip = ip;
     878           1 :     if (index == nh->nh_component_cnt)
     879           1 :        index = -1;
     880             : 
     881           1 :     return index;
     882             : }
     883             : 
     884             : static int
     885          20 : nh_composite_ecmp_select_nh(struct vr_packet *pkt, struct vr_nexthop *nh,
     886             :         struct vr_forwarding_md *fmd)
     887             : {
     888          20 :     bool hash_computed = false;
     889          20 :     int ret = -1, ecmp_index = -1;
     890             :     unsigned int hash, hash_ecmp, count, rflow_src_info;
     891             : 
     892          20 :     struct vr_flow flow, *flowp = &flow;
     893          20 :     struct vr_flow_entry *fe = NULL;
     894          20 :     struct vr_nexthop *cnh = NULL;
     895          20 :     struct vr_component_nh *cnhp = nh->nh_component_nh;
     896             :     struct vr_ip *ip;
     897             :     struct vr_ip6 *ip6;
     898             :     struct vr_packet *pkt_c;
     899             : 
     900          20 :     if (!nh || !fmd || (!nh->nh_component_cnt))
     901           0 :         return ret;
     902             : 
     903          20 :     count = nh->nh_component_cnt;
     904             : 
     905          20 :     if (fmd->fmd_flow_index >= 0) {
     906           1 :         fe = vr_flow_get_entry(nh->nh_router, fmd->fmd_flow_index);
     907           1 :         if (fe) {
     908           1 :             flowp = &fe->fe_key;
     909             :             /*
     910             :              * If the ecmp index is explicitly configured as -1, the
     911             :              * index need to be chosen as the one matchig with reverse
     912             :              * flow's source.
     913             :              */
     914           1 :             if (fmd->fmd_ecmp_nh_index == -1) {
     915           1 :                 rflow_src_info = vr_flow_get_rflow_src_info(nh->nh_router, fe);
     916           1 :                 if (rflow_src_info != (unsigned int)-1) {
     917           1 :                     ecmp_index = nh_composite_ecmp_select_by_rflow(pkt,
     918             :                             nh, fmd, rflow_src_info);
     919             :                 }
     920             :             }
     921             :         }
     922             :     }
     923             : 
     924          20 :     if (!fe) {
     925             :         /*
     926             :          * If the flow entry does not exist, apply the configured
     927             :          * hash parameters to select candidate nexthop
     928             :          */
     929          19 :         hash = (nh->nh_ecmp_config_hash >> 8) & NH_ECMP_CONFIG_HASH_MASK;
     930          19 :         if (pkt->vp_type == VP_TYPE_IP) {
     931          19 :             ip = (struct vr_ip *)pkt_network_header(pkt);
     932          19 :             ret = vr_inet_get_flow_key(nh->nh_router, pkt, fmd,
     933             :                                          flowp, hash, VR_FRAG_FLAG_NONE);
     934          19 :             switch (ret) {
     935          11 :                 case 0:
     936             :                     /*
     937             :                      * Handle head fragmented packets
     938             :                      * - If this is a head fragment, clone it and enqueue it to the assembler
     939             :                      *   which would result in flushing of non-head fragments which
     940             :                      *   were queued earlier. The addition of head fragment to the fragment
     941             :                      *   hash table is taken care of in the get_flow_key().
     942             :                      */
     943          11 :                     if (vr_ip_fragment_head(ip) && vr_enqueue_to_assembler) {
     944           2 :                         pkt_c = vr_pclone(pkt);
     945           2 :                         if (pkt_c) {
     946           2 :                             vr_enqueue_to_assembler(nh->nh_router, pkt_c, fmd);
     947             :                         } else {
     948           0 :                             pkt_drop_stats(pkt->vp_if, VP_DROP_CLONE_FAIL, pkt->vp_cpu);
     949             :                         }
     950             :                     }
     951          11 :                     break;
     952             : 
     953           8 :                 case -VP_DROP_NO_FRAG_ENTRY:
     954             :                     /*
     955             :                      * Handle non-head fragmented packets
     956             :                      * - If the head fragment has not yet arrived, the fragment hash table
     957             :                      *   will not have any entry for it. In such cases, we cannot form
     958             :                      *   the flow key and get_flow_key() will fail. Such packets need to be
     959             :                      *   enqueued to the assembler. Once head fragment arrives, these
     960             :                      *   packets would be reinjected by the assembler.
     961             :                      */
     962           8 :                     if (!vr_ip_transport_header_valid(ip) && vr_enqueue_to_assembler) {
     963           8 :                         vr_enqueue_to_assembler(nh->nh_router, pkt, fmd);
     964           8 :                         return NH_ECMP_PACKET_HELD;
     965             :                     }
     966           0 :                     break;
     967           0 :                 case -VP_DROP_ICMP_ERROR:
     968             :                 case -VP_DROP_NO_MEMORY:
     969             :                 default:
     970           0 :                     return ret;
     971             : 
     972             :             }
     973           0 :         } else if (pkt->vp_type == VP_TYPE_IP6) {
     974           0 :             ip6 = (struct vr_ip6 *)pkt_network_header(pkt);
     975           0 :             ret = vr_inet6_get_flow_key(nh->nh_router, fmd->fmd_dvrf, pkt,
     976           0 :                                      fmd->fmd_vlan, flowp, hash, 0);
     977           0 :             switch (ret) {
     978           0 :                 case 0:
     979           0 :                     if (vr_ip6_fragment_head(ip6) && vr_enqueue_to_assembler) {
     980           0 :                         pkt_c = vr_pclone(pkt);
     981           0 :                         if (pkt_c) {
     982           0 :                             vr_enqueue_to_assembler(nh->nh_router, pkt_c, fmd);
     983             :                         } else {
     984           0 :                             pkt_drop_stats(pkt->vp_if, VP_DROP_CLONE_FAIL, pkt->vp_cpu);
     985             :                         }
     986             :                     }
     987           0 :                     break;
     988             : 
     989           0 :                 case -VP_DROP_NO_FRAG_ENTRY:
     990           0 :                     if (!vr_ip6_transport_header_valid(ip6) && vr_enqueue_to_assembler) {
     991           0 :                         vr_enqueue_to_assembler(nh->nh_router, pkt, fmd);
     992           0 :                         return NH_ECMP_PACKET_HELD;
     993             :                     }
     994           0 :                     break;
     995           0 :                 case -VP_DROP_ICMP_ERROR:
     996             :                 case -VP_DROP_NO_MEMORY:
     997             :                 default:
     998           0 :                     return ret;
     999             : 
    1000             :             }
    1001             :         } else {
    1002             :             /*
    1003             :              * packet can be hashed on ethernet header and VRF to identify
    1004             :              * the component
    1005             :              */
    1006           0 :             hash_ecmp = vr_hash(pkt_data(pkt), VR_ETHER_HLEN, 0);
    1007           0 :             hash_ecmp = vr_hash_2words(hash_ecmp, fmd->fmd_dvrf, 0);
    1008           0 :             hash_computed = true;
    1009             :         }
    1010             :     }
    1011             : 
    1012             : 
    1013          12 :     if (ecmp_index == -1) {
    1014          12 :         if (!hash_computed)
    1015          12 :             hash_ecmp = vr_hash(flowp, flowp->flow_key_len, 0);
    1016          12 :         hash = hash_ecmp % count;
    1017          12 :         ecmp_index = cnhp[hash].cnh_ecmp_index;
    1018          12 :         cnh = cnhp[hash].cnh;
    1019          12 :         if (!cnh) {
    1020           0 :             if (nh->nh_component_ecmp_cnt) {
    1021           0 :                 cnhp = nh->nh_component_ecmp;
    1022           0 :                 hash_ecmp %= nh->nh_component_ecmp_cnt;
    1023           0 :                 ecmp_index = cnhp[hash_ecmp].cnh_ecmp_index;
    1024           0 :                 if (!(cnh = cnhp[hash_ecmp].cnh))
    1025           0 :                     return -1;
    1026             :             }
    1027             :         }
    1028             :     }
    1029             : 
    1030          12 :     if (fe)
    1031           1 :         return vr_flow_update_ecmp_index(nh->nh_router, fe, ecmp_index, fmd);
    1032             : 
    1033          11 :     fmd->fmd_ecmp_nh_index = ecmp_index;
    1034             : 
    1035          11 :     return 0;
    1036             : }
    1037             : 
    1038             : static nh_processing_t
    1039          24 : nh_composite_ecmp(struct vr_packet *pkt, struct vr_nexthop *nh,
    1040             :                   struct vr_forwarding_md *fmd)
    1041             : {
    1042          24 :     int ret = 0, drop_reason = VP_DROP_INVALID_NH;
    1043          24 :     struct vr_nexthop *member_nh = NULL;
    1044          24 :     struct vr_vrf_stats *stats = NULL;
    1045             : 
    1046          24 :     if (!fmd) {
    1047           0 :         drop_reason = VP_DROP_NO_FMD;
    1048           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1049           0 :         goto drop;
    1050             :     }
    1051             : 
    1052          24 :     if (vr_inet_vrf_stats) {
    1053          24 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    1054          24 :         if (stats)
    1055          24 :             stats->vrf_ecmp_composites++;
    1056             :     }
    1057             : 
    1058          24 :     if ((fmd->fmd_ecmp_nh_index >= 0) &&
    1059           4 :             (fmd->fmd_ecmp_nh_index < nh->nh_component_cnt)) {
    1060           4 :         member_nh = nh->nh_component_nh[fmd->fmd_ecmp_nh_index].cnh;
    1061             :     }
    1062             : 
    1063          24 :     if (!member_nh) {
    1064          20 :         ret = nh_composite_ecmp_select_nh(pkt, nh, fmd);
    1065          20 :         switch (ret) {
    1066          12 :             case 0:
    1067          12 :                 break;
    1068           8 :             case NH_ECMP_PACKET_HELD:
    1069           8 :                 return 0; /* packet was consumed */
    1070           0 :             case -VP_DROP_ICMP_ERROR:
    1071             :             case -VP_DROP_NO_MEMORY:
    1072             :             case -VP_DROP_NO_FRAG_ENTRY:
    1073           0 :                  drop_reason = -ret;
    1074           0 :                  PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1075           0 :                  goto drop;
    1076           0 :             default:
    1077           0 :                  goto drop;
    1078             :         }
    1079             : 
    1080          12 :         member_nh = nh->nh_component_nh[fmd->fmd_ecmp_nh_index].cnh;
    1081          12 :         if (!member_nh)
    1082           0 :             goto drop;
    1083             :     }
    1084             :     /*
    1085             :      * this composite nh does not have vpn mpls label which should be
    1086             :      * derived from routelook only, so not overriding label retrieved from
    1087             :      * route lookup for label unicast composite nh case
    1088             :      */
    1089          16 :     if (!(nh->nh_flags & NH_FLAG_COMPOSITE_LU_ECMP)) {
    1090          16 :         vr_fmd_set_label(fmd, nh->nh_component_nh[fmd->fmd_ecmp_nh_index].cnh_label,
    1091             :                VR_LABEL_TYPE_UNKNOWN);
    1092             :     }
    1093          16 :     nh_output(pkt, member_nh, fmd);
    1094          16 :     return NH_PROCESSING_COMPLETE;
    1095             : 
    1096           0 : drop:
    1097           0 :     vr_pfree(pkt, drop_reason);
    1098           0 :     return NH_PROCESSING_COMPLETE;
    1099             : }
    1100             : 
    1101             : 
    1102             : /*
    1103             :  * This function validate the source  of the tunnel incase of L2
    1104             :  * multicast
    1105             :  */
    1106             : 
    1107             : static int
    1108           0 : nh_composite_mcast_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
    1109             :                                 struct vr_forwarding_md *fmd, void *ret_flags)
    1110             : {
    1111             :     int i, j;
    1112             :     struct vr_nexthop *dir_nh, *fabric_nh;
    1113             :     unsigned int tun_dip;
    1114             : 
    1115             :     /*
    1116             :      * If multicast packet is received on fabric interface, we need to
    1117             :      * validate whether the source of this packet is in the distribution
    1118             :      * tree. If source is not in the list, packet needs to be dropped.
    1119             :      */
    1120             : 
    1121             :     /* Valid if source is VM */
    1122           0 :     if (pkt->vp_if->vif_type != VIF_TYPE_PHYSICAL)
    1123           0 :         return NH_SOURCE_VALID;
    1124             : 
    1125             :     /* If there is no source IP to compare treat it as invalid source */
    1126           0 :     if (!fmd->fmd_outer_src_ip)
    1127           0 :         return NH_SOURCE_INVALID;
    1128             : 
    1129           0 :     for(j = 0; j < nh->nh_component_cnt; j++) {
    1130           0 :         fabric_nh = nh->nh_component_nh[j].cnh;
    1131             : 
    1132           0 :         if (!fabric_nh || !(fabric_nh->nh_flags & NH_FLAG_VALID))
    1133           0 :             continue;
    1134             : 
    1135           0 :         if (fabric_nh->nh_type != NH_COMPOSITE ||
    1136           0 :             !(fabric_nh->nh_flags & (NH_FLAG_COMPOSITE_FABRIC |
    1137             :               NH_FLAG_COMPOSITE_EVPN | NH_FLAG_COMPOSITE_TOR)))
    1138           0 :             continue;
    1139             : 
    1140           0 :         for (i = 0; i < fabric_nh->nh_component_cnt; i++) {
    1141           0 :             dir_nh = fabric_nh->nh_component_nh[i].cnh;
    1142             : 
    1143             :             /* If direct nexthop is not valid, dont process it */
    1144           0 :             if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
    1145           0 :                 continue;
    1146             : 
    1147           0 :             if (dir_nh->nh_type != NH_TUNNEL)
    1148           0 :                 continue;
    1149             : 
    1150           0 :             tun_dip = 0;
    1151           0 :             if (dir_nh->nh_flags & NH_FLAG_TUNNEL_GRE)
    1152           0 :                 tun_dip = dir_nh->nh_gre_tun_dip;
    1153           0 :             else if (dir_nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS)
    1154           0 :                 tun_dip = dir_nh->nh_udp_tun_dip;
    1155           0 :             else if (dir_nh->nh_flags & NH_FLAG_TUNNEL_VXLAN)
    1156           0 :                 tun_dip = dir_nh->nh_vxlan_tun_dip;
    1157             : 
    1158             :             /* If source is in districution tree, it is valid */
    1159           0 :             if (tun_dip && fmd->fmd_outer_src_ip &&
    1160           0 :                       fmd->fmd_outer_src_ip == tun_dip) {
    1161             : 
    1162           0 :                 if (ret_flags)
    1163           0 :                     *((unsigned int *)ret_flags) = fabric_nh->nh_flags;
    1164             : 
    1165           0 :                 return NH_SOURCE_VALID;
    1166             :             }
    1167             :         }
    1168             :     }
    1169             : 
    1170           0 :     if (!(nh->nh_flags & NH_FLAG_VALIDATE_MCAST_SRC)) {
    1171           0 :         *((unsigned int *)ret_flags) = NH_FLAG_VALIDATE_MCAST_SRC;
    1172           0 :         return NH_SOURCE_VALID;
    1173             :     }
    1174             : 
    1175           0 :     return NH_SOURCE_INVALID;
    1176             : }
    1177             : 
    1178             : static int
    1179           0 : nh_handle_unknown_unicast(struct vr_packet *pkt, struct vr_eth *eth,
    1180             :         struct vr_forwarding_md *fmd, unsigned int pkt_src)
    1181             : {
    1182           0 :     int handled = 1, pull_len;
    1183             :     struct vr_route_req rt;
    1184             :     struct vr_nexthop *nh;
    1185             : 
    1186             :     /*
    1187             :      * If packet is from VM or from TOR, we must have done a look up
    1188             :      * already in bridge before coming to this processing
    1189             :      */
    1190           0 :     if (!pkt_src || (pkt_src == PKT_SRC_TOR_REPL_TREE))
    1191           0 :         return !handled;
    1192             : 
    1193           0 :     rt.rtr_req.rtr_label_flags = 0;
    1194           0 :     rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX;
    1195           0 :     rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN;
    1196           0 :     rt.rtr_req.rtr_mac = eth->eth_dmac;
    1197           0 :     rt.rtr_req.rtr_vrf_id = fmd->fmd_dvrf;
    1198             : 
    1199           0 :     nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt);
    1200           0 :     if (!nh || nh->nh_type != NH_ENCAP)
    1201           0 :         return !handled;
    1202             : 
    1203             :     /* Get the packet to eth header */
    1204           0 :     pull_len = (uintptr_t)eth - (uintptr_t)pkt_data(pkt);
    1205           0 :     if (pull_len)
    1206           0 :         pkt_pull(pkt, pull_len);
    1207             : 
    1208           0 :     nh_output(pkt, nh, fmd);
    1209             : 
    1210           0 :     return handled;
    1211             : }
    1212             : 
    1213             : static int
    1214           0 : nh_handle_mcast_control_pkt(struct vr_packet *pkt, struct vr_eth *eth,
    1215             :         struct vr_forwarding_md *fmd, unsigned int pkt_src, bool *flood_to_vms)
    1216             : {
    1217           0 :     int handled = 1;
    1218             :     unsigned char eth_dmac[VR_ETHER_ALEN];
    1219           0 :     bool flood = false;
    1220           0 :     unsigned short trap, rt_flags, drop_reason, pull_len  = 0;
    1221           0 :     l4_pkt_type_t l4_type = L4_TYPE_UNKNOWN;
    1222             :     struct vr_arp *sarp;
    1223             :     struct vr_nexthop *src_nh;
    1224             :     struct vr_ip6 *ip6;
    1225             : 
    1226           0 :     struct vr_packet *pkt_c = NULL;
    1227             : 
    1228             :     /*
    1229             :      * The vlan tagged packets are meant to be handled only by VM's
    1230             :      */
    1231           0 :     if (fmd->fmd_vlan != VLAN_ID_INVALID)
    1232           0 :         return !handled;
    1233             : 
    1234           0 :     pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt);
    1235           0 :     if (!pkt_pull(pkt, pull_len)) {
    1236           0 :         drop_reason = VP_DROP_PULL;
    1237           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1238           0 :         goto drop;
    1239             :     }
    1240             : 
    1241           0 :     rt_flags = vr_bridge_route_flags(fmd->fmd_dvrf, eth->eth_smac);
    1242             : 
    1243           0 :     if (pkt->vp_type == VP_TYPE_ARP) {
    1244             : 
    1245           0 :         if ((pkt_src == PKT_SRC_INGRESS_REPL_TREE) &&
    1246           0 :                 (rt_flags & VR_BE_EVPN_CONTROL_PROCESSING_FLAG)) {
    1247           0 :             fmd->fmd_src = TOR_EVPN_SOURCE;
    1248             :         }
    1249             : 
    1250           0 :         VR_MAC_COPY(eth_dmac, eth->eth_dmac);
    1251           0 :         handled = vr_arp_input(pkt, fmd, eth_dmac);
    1252           0 :         if (handled)
    1253           0 :             return handled;
    1254             : 
    1255             :         /*
    1256             :          * If not handled, packet needs to be flooded. If the ARP is
    1257             :          * from MX, VM's should not see this ARP as VM's always need to
    1258             :          * see Agent as gateway
    1259             :          */
    1260             : 
    1261           0 :         if (pkt_src) {
    1262           0 :             sarp = (struct vr_arp *)pkt_data(pkt);
    1263           0 :             src_nh = vr_inet_ip_lookup(fmd->fmd_dvrf, sarp->arp_spa);
    1264           0 :             if (vr_gateway_nexthop(src_nh)) {
    1265           0 :                 *flood_to_vms = false;
    1266             :             }
    1267             :         }
    1268             : 
    1269           0 :         goto unhandled;
    1270             :     }
    1271             : 
    1272           0 :     if ((pkt->vp_type != VP_TYPE_IP) && (pkt->vp_type != VP_TYPE_IP6))
    1273           0 :         goto unhandled;
    1274             : 
    1275             :     /*
    1276             :      * V6 Ndisc, router solictation packets are ICMP packets. So we need
    1277             :      * to parse to identify the type, unlike V4 ARP
    1278             :      */
    1279           0 :     if (pkt->vp_type == VP_TYPE_IP6) {
    1280           0 :         l4_type = vr_ip6_well_known_packet(pkt);
    1281           0 :     } else if (pkt_src == (PKT_SRC_TOR_REPL_TREE) ||
    1282             :                 (pkt_src == PKT_SRC_INGRESS_REPL_TREE)) {
    1283           0 :         l4_type = vr_ip_well_known_packet(pkt);
    1284             :     }
    1285             : 
    1286             :     /*
    1287             :      * Special control packets need to be handled only if VM or BMS
    1288             :      * behind OvsDB Tor or BMS behind Evpn Tor(which will have
    1289             :      * VR_BE_EVPN_CONTROL_PROCESSING_FLAG)
    1290             :      */
    1291           0 :     if ((!pkt_src) || (pkt_src == PKT_SRC_TOR_REPL_TREE) ||
    1292           0 :             ((pkt_src == PKT_SRC_INGRESS_REPL_TREE) &&
    1293           0 :              (rt_flags & VR_BE_EVPN_CONTROL_PROCESSING_FLAG))) {
    1294             : 
    1295             :         /*
    1296             :          * If packet is identified as known packet, we always trap
    1297             :          * it to agent with the exception of DHCP. DHCP can be flooded
    1298             :          * depending on the configuration on VMI or L2 route flags
    1299             :          */
    1300           0 :         if (l4_type != L4_TYPE_UNKNOWN) {
    1301             : 
    1302           0 :             trap = true;
    1303             : 
    1304           0 :             if (l4_type == L4_TYPE_DHCP_REQUEST) {
    1305           0 :                 if (rt_flags & VR_BE_FLOOD_DHCP_FLAG)
    1306           0 :                     trap = false;
    1307           0 :             } else if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) {
    1308           0 :                 trap = false;
    1309           0 :             } else if (l4_type == L4_TYPE_NEIGHBOUR_ADVERTISEMENT) {
    1310           0 :                 flood = true;
    1311             :             }
    1312             : 
    1313           0 :             if (trap && flood) {
    1314           0 :                 pkt_c = nh_mcast_clone(pkt, AGENT_PKT_HEAD_SPACE);
    1315           0 :                 if (!pkt_c) {
    1316           0 :                     trap = false;
    1317             :                 }
    1318             :             }
    1319             : 
    1320           0 :             if (trap) {
    1321           0 :                 if (flood) {
    1322           0 :                     vr_trap(pkt_c, fmd->fmd_dvrf,
    1323             :                             AGENT_TRAP_L3_PROTOCOLS, NULL);
    1324           0 :                     goto unhandled;
    1325             :                 } else {
    1326           0 :                     vr_trap(pkt, fmd->fmd_dvrf,
    1327             :                             AGENT_TRAP_L3_PROTOCOLS, NULL);
    1328           0 :                     return handled;
    1329             :                 }
    1330             :             }
    1331             :         }
    1332             :     }
    1333             : 
    1334           0 :     if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) {
    1335           0 :         VR_MAC_COPY(eth_dmac, eth->eth_dmac);
    1336           0 :         handled = vr_neighbor_input(pkt, fmd, eth_dmac);
    1337           0 :         if (handled)
    1338           0 :             return handled;
    1339             : 
    1340           0 :         if (pkt_src) {
    1341           0 :             ip6 = (struct vr_ip6 *)pkt_data(pkt);
    1342           0 :             src_nh = vr_inet6_ip_lookup(fmd->fmd_dvrf, ip6->ip6_src);
    1343           0 :             if (vr_gateway_nexthop(src_nh))
    1344           0 :                 *flood_to_vms = false;
    1345             :         }
    1346             :     }
    1347             : 
    1348           0 : unhandled:
    1349           0 :     if (pull_len)
    1350           0 :         pkt_push(pkt, pull_len);
    1351           0 :     return 0;
    1352             : 
    1353           0 : drop:
    1354           0 :     vr_pfree(pkt, drop_reason);
    1355           0 :     return 1;
    1356             : }
    1357             : 
    1358             : static nh_processing_t
    1359           0 : nh_composite_mcast(struct vr_packet *pkt, struct vr_nexthop *nh,
    1360             :                      struct vr_forwarding_md *fmd)
    1361             : {
    1362             : 
    1363             :     int i, clone_size;
    1364           0 :     bool flood_to_vms = true, l2_control_data = false;
    1365           0 :     unsigned short drop_reason, label, pkt_vrf, pull_len = 0,
    1366           0 :                    pbb_pull_len = 0;
    1367             :     unsigned int tun_src, pkt_src, hashval, port_range, handled;
    1368             :     mac_learn_t ml_res;
    1369           0 :     struct vr_eth *eth = NULL;
    1370             :     struct vr_nexthop *dir_nh;
    1371             :     struct vr_packet *new_pkt;
    1372           0 :     struct vr_vrf_stats *stats = NULL;
    1373             :     // Context for the flag:
    1374             :     // For 5.1, mcast source is outside contrail and only <*,G> is supported.
    1375             :     // Until such a time when source can be inside contrail, multicast data
    1376             :     // packets sourced from inside contrail has to be dropped.
    1377             :     // Also, packets originating outside of contrail has pkt->vp_data pointing
    1378             :     // to inner ethernet header (in case of VxLan tunneled packet).
    1379           0 :     bool pull_header = true;
    1380             : 
    1381           0 :     if (!fmd) {
    1382           0 :         drop_reason = VP_DROP_NO_FMD;
    1383           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1384           0 :         goto drop;
    1385             :     }
    1386             : 
    1387           0 :     if (vr_inet_vrf_stats) {
    1388           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    1389           0 :         if (stats)
    1390           0 :             stats->vrf_l2_mcast_composites++;
    1391             :     }
    1392             : 
    1393           0 :     pkt_vrf = fmd->fmd_dvrf;
    1394           0 :     drop_reason = VP_DROP_CLONED_ORIGINAL;
    1395             : 
    1396             :     /*
    1397             :      * nh_validate_src identifies the format of the packet and source of
    1398             :      * the packet too. Without this callback being defined we will not
    1399             :      * be able to replicate the packet
    1400             :      */
    1401           0 :     if (!nh->nh_validate_src) {
    1402           0 :         drop_reason = VP_DROP_MISC;
    1403           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1404           0 :         goto drop;
    1405             :     }
    1406             : 
    1407           0 :     tun_src = pkt_src = 0;
    1408           0 :     if (nh->nh_validate_src(pkt, nh, fmd, &tun_src) == NH_SOURCE_INVALID) {
    1409           0 :         drop_reason = VP_DROP_INVALID_MCAST_SOURCE;
    1410           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1411           0 :         goto drop;
    1412             :     }
    1413             : 
    1414           0 :     if (tun_src & NH_FLAG_COMPOSITE_EVPN)
    1415           0 :         pkt_src = PKT_SRC_INGRESS_REPL_TREE;
    1416             : 
    1417           0 :     if (tun_src & NH_FLAG_COMPOSITE_FABRIC) {
    1418           0 :         pkt_src = PKT_SRC_EDGE_REPL_TREE;
    1419           0 :         if (nh->nh_family == AF_BRIDGE)
    1420           0 :             pull_len = VR_VXLAN_HDR_LEN;
    1421             :     }
    1422             : 
    1423           0 :     if (tun_src & NH_FLAG_VALIDATE_MCAST_SRC) {
    1424             :         // Since source check is relaxed, tunnel source is hard-coded to
    1425             :         // fabric.
    1426           0 :         tun_src = NH_FLAG_COMPOSITE_FABRIC;
    1427           0 :         pkt_src = PKT_SRC_EDGE_REPL_TREE;
    1428             :         // In this case ethernet header pointer need not be adjusted.
    1429           0 :         pull_header = false;
    1430             :     }
    1431             : 
    1432           0 :     if (tun_src & NH_FLAG_COMPOSITE_TOR) {
    1433           0 :         pkt_src = PKT_SRC_TOR_REPL_TREE;
    1434           0 :         fmd->fmd_src = TOR_SOURCE;
    1435             :     }
    1436             : 
    1437           0 :     if (nh->nh_family == AF_BRIDGE) {
    1438           0 :         eth = (struct vr_eth *)pkt_data_at_offset(pkt,
    1439           0 :                                 pkt->vp_data + pull_len);
    1440             : 
    1441           0 :         if (ntohs(eth->eth_proto) == VR_ETH_PROTO_PBB) {
    1442           0 :             pbb_pull_len = __vr_pbb_decode(eth, pkt_head_len(pkt) - pull_len, fmd);
    1443           0 :             if (pbb_pull_len <= 0) {
    1444           0 :                 drop_reason = VP_DROP_INVALID_PACKET;
    1445           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1446           0 :                 goto drop;
    1447             :             }
    1448             : 
    1449           0 :             if (vr_pkt_type(pkt, pbb_pull_len + pull_len, fmd) < 0) {
    1450           0 :                 drop_reason = VP_DROP_INVALID_PACKET;
    1451           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1452           0 :                 goto drop;
    1453             :             }
    1454             : 
    1455           0 :             eth = (struct vr_eth *)(((char *)eth) + pbb_pull_len);
    1456           0 :             if (nh->nh_flags & NH_FLAG_MAC_LEARN) {
    1457           0 :                 ml_res = vr_bridge_learn(nh->nh_router, pkt, eth, fmd);
    1458           0 :                 if (ml_res == MAC_TRAPPED)
    1459           0 :                     return NH_PROCESSING_COMPLETE;
    1460             :             }
    1461             :         }
    1462             : 
    1463           0 :         handled = nh_handle_mcast_control_pkt(pkt, eth, fmd,
    1464             :                                         pkt_src, &flood_to_vms);
    1465           0 :         if (handled)
    1466           0 :             return NH_PROCESSING_COMPLETE;
    1467             : 
    1468           0 :         if (flood_to_vms && !IS_MAC_BMCAST(eth->eth_dmac)) {
    1469           0 :             handled = nh_handle_unknown_unicast(pkt, eth, fmd, pkt_src);
    1470           0 :             if (handled)
    1471           0 :                 return NH_PROCESSING_COMPLETE;
    1472             :         }
    1473             : 
    1474             : 
    1475             :         /*
    1476             :          * The packet can come to this nexthp either from Fabric or from VM.
    1477             :          * Incase of Fabric, the packet would contain the Vxlan header and
    1478             :          * control information. From VM, it contains neither of them
    1479             :          */
    1480             : 
    1481           0 :         if (!fmd->fmd_udp_src_port) {
    1482           0 :             if (hashrnd_inited == 0) {
    1483           0 :                 get_random_bytes(&vr_hashrnd, sizeof(vr_hashrnd));
    1484           0 :                 hashrnd_inited = 1;
    1485             :             }
    1486           0 :             hashval = vr_hash(eth, sizeof(struct vr_eth), vr_hashrnd);
    1487             :             /* Include the VRF to calculate the hash */
    1488           0 :             hashval = vr_hash_2words(hashval, fmd->fmd_dvrf, vr_hashrnd);
    1489             : 
    1490             :             /*
    1491             :              * Convert the hash value to a value in the port range that we want
    1492             :              * for dynamic UDP ports
    1493             :              */
    1494           0 :             port_range = VR_MUDP_PORT_RANGE_END - VR_MUDP_PORT_RANGE_START;
    1495           0 :             fmd->fmd_udp_src_port = (uint16_t) (((uint64_t) hashval * port_range) >> 32);
    1496             : 
    1497           0 :             if (fmd->fmd_udp_src_port > port_range) {
    1498             :                /*
    1499             :                 * Shouldn't happen...
    1500             :                 */
    1501           0 :                 fmd->fmd_udp_src_port = 0;
    1502             :             }
    1503             : 
    1504           0 :             fmd->fmd_udp_src_port += VR_MUDP_PORT_RANGE_START;
    1505             :         }
    1506             : 
    1507           0 :         if (vr_fmd_l2_control_data_is_enabled(fmd))
    1508           0 :             l2_control_data = true;
    1509             :     }
    1510             : 
    1511           0 :     if (!nh->nh_component_cnt) {
    1512           0 :         drop_reason = VP_DROP_DISCARD;
    1513           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1514           0 :         goto drop;
    1515             :     }
    1516             : 
    1517           0 :     label = fmd->fmd_label;
    1518             : 
    1519           0 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    1520           0 :         clone_size = 0;
    1521           0 :         dir_nh = nh->nh_component_nh[i].cnh;
    1522             : 
    1523             :         /* We need to copy back the original label from Bridge lookaup
    1524             :          * as previous iteration would have manipulated that
    1525             :          */
    1526           0 :         vr_fmd_set_label(fmd, label, VR_LABEL_TYPE_UNKNOWN);
    1527           0 :         fmd->fmd_dvrf = pkt_vrf;
    1528           0 :         vr_fmd_update_l2_control_data(fmd, false);
    1529             : 
    1530             :         /* If direct nexthop is not valid, dont process it */
    1531           0 :         if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID) ||
    1532           0 :                                 (dir_nh->nh_type != NH_COMPOSITE))
    1533           0 :             continue;
    1534             : 
    1535           0 :         if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_ENCAP) {
    1536           0 :             if (!flood_to_vms)
    1537           0 :                 continue;
    1538             : 
    1539           0 :             if (!(new_pkt = nh_mcast_clone(pkt, 0))) {
    1540           0 :                 drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1541           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1542           0 :                 break;
    1543             :             }
    1544             : 
    1545           0 :             pull_len = pbb_pull_len;
    1546           0 :             if (nh->nh_family == AF_BRIDGE &&
    1547             :                     (pkt_src == PKT_SRC_EDGE_REPL_TREE)) {
    1548           0 :                 if (pull_header) {
    1549           0 :                     pull_len += VR_VXLAN_HDR_LEN;
    1550             :                 }
    1551             :             }
    1552             : 
    1553           0 :             if (pull_len && !pkt_pull(new_pkt, pull_len)) {
    1554           0 :                 vr_pfree(new_pkt, VP_DROP_PULL);
    1555           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1556           0 :                 break;
    1557             :             }
    1558           0 :         } else if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_FABRIC) {
    1559           0 :             if (pkt_src == PKT_SRC_INGRESS_REPL_TREE)
    1560           0 :                 continue;
    1561             : 
    1562           0 :             if (pkt_src != PKT_SRC_EDGE_REPL_TREE) {
    1563           0 :                 if (nh->nh_family == AF_BRIDGE) {
    1564           0 :                     clone_size += VR_L2_MCAST_PKT_HEAD_SPACE;
    1565           0 :                     if (dir_nh->nh_flags & NH_FLAG_TUNNEL_PBB)
    1566           0 :                         clone_size += VR_ETHER_HLEN + sizeof(struct vr_pbb_itag);
    1567             :                 } else {
    1568           0 :                     clone_size += VR_L3_MCAST_PKT_HEAD_SPACE;
    1569             :                 }
    1570             :             }
    1571             : 
    1572             :             /* Create head space for L2 Mcast header */
    1573           0 :             if (!(new_pkt = nh_mcast_clone(pkt, clone_size))) {
    1574           0 :                 drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1575           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1576           0 :                 break;
    1577             :             }
    1578           0 :             if (!pull_header) {
    1579             :                 // Recover header space to write tunnel header when sending to
    1580             :                 // other computes. Assumption is that multicast data packet was
    1581             :                 // received from outside contrail using vxlan header.
    1582           0 :                 pkt_push(new_pkt, VR_VXLAN_HDR_LEN);
    1583             :             }
    1584           0 :             fmd->fmd_dvrf = dir_nh->nh_vrf;
    1585             : 
    1586           0 :         } else if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_EVPN) {
    1587             : 
    1588             :             /* We replicate only if received from VM and Ovs TOR*/
    1589           0 :             if ((!pkt_src)|| (pkt_src == PKT_SRC_TOR_REPL_TREE)) {
    1590             : 
    1591             :                 /* Create head space for non Vxlan header */
    1592           0 :                 clone_size = VR_L3_MCAST_PKT_HEAD_SPACE;
    1593           0 :                 if (nh->nh_flags & NH_FLAG_L2_CONTROL_DATA)
    1594           0 :                     clone_size += VR_L2_CTRL_DATA_LEN;
    1595           0 :                 if (dir_nh->nh_flags & NH_FLAG_TUNNEL_PBB)
    1596           0 :                     clone_size += VR_ETHER_HLEN + sizeof(struct vr_pbb_itag);
    1597             : 
    1598           0 :                 if (!(new_pkt = nh_mcast_clone(pkt, clone_size))) {
    1599           0 :                     drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1600           0 :                     PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1601           0 :                     break;
    1602             :                 }
    1603           0 :                 fmd->fmd_dvrf = dir_nh->nh_vrf;
    1604             :             } else {
    1605           0 :                 continue;
    1606             :             }
    1607             : 
    1608           0 :             if (l2_control_data)
    1609           0 :                 vr_fmd_update_l2_control_data(fmd, true);
    1610             : 
    1611           0 :         } else if (dir_nh->nh_flags & NH_FLAG_COMPOSITE_TOR) {
    1612             : 
    1613             :             /* Create head space for Vxlan header */
    1614           0 :             clone_size = VR_L2_MCAST_PKT_HEAD_SPACE - VR_L2_CTRL_DATA_LEN;
    1615           0 :             if (!(new_pkt = nh_mcast_clone(pkt, clone_size))) {
    1616           0 :                 drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1617           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1618           0 :                 break;
    1619             :             }
    1620             : 
    1621           0 :             if (pkt_src == PKT_SRC_EDGE_REPL_TREE) {
    1622             : 
    1623           0 :                 pull_len = VR_VXLAN_HDR_LEN + pbb_pull_len;
    1624           0 :                 if (!pkt_pull(new_pkt, pull_len)) {
    1625           0 :                     vr_pfree(new_pkt, VP_DROP_PULL);
    1626           0 :                     PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1627           0 :                     break;
    1628             :                 }
    1629             :             }
    1630           0 :             fmd->fmd_dvrf = dir_nh->nh_vrf;
    1631             : 
    1632             :         } else {
    1633           0 :             continue;
    1634             :         }
    1635             : 
    1636           0 :         nh_output(new_pkt, dir_nh, fmd);
    1637             :     }
    1638             : 
    1639             :     /* Original packet needs to be unconditionally dropped */
    1640           0 : drop:
    1641           0 :     vr_pfree(pkt, drop_reason);
    1642           0 :     return NH_PROCESSING_COMPLETE;
    1643             : }
    1644             : 
    1645             : 
    1646             : static nh_processing_t
    1647           0 : nh_composite_encap(struct vr_packet *pkt, struct vr_nexthop *nh,
    1648             :                    struct vr_forwarding_md *fmd)
    1649             : {
    1650             :     int i, j;
    1651           0 :     struct vr_vrf_stats *stats = NULL;
    1652             :     struct vr_nexthop *dir_nh;
    1653             :     unsigned short drop_reason;
    1654             :     struct vr_packet *new_pkt;
    1655             : 
    1656           0 :     if (!fmd) {
    1657           0 :         drop_reason = VP_DROP_NO_FMD;
    1658           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1659           0 :         goto drop;
    1660             :     }
    1661             : 
    1662           0 :     drop_reason = VP_DROP_CLONED_ORIGINAL;
    1663           0 :     if (vr_inet_vrf_stats) {
    1664           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    1665           0 :         if (stats)
    1666           0 :             stats->vrf_encap_composites++;
    1667             :     }
    1668             : 
    1669           0 :     if (!nh->nh_component_cnt) {
    1670           0 :         drop_reason = VP_DROP_DISCARD;
    1671           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1672           0 :         goto drop;
    1673             :     }
    1674             : 
    1675           0 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    1676           0 :        dir_nh = nh->nh_component_nh[i].cnh;
    1677             : 
    1678             :         /* If direct nexthop is not valid, dont process it */
    1679           0 :         if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
    1680           0 :             continue;
    1681             : 
    1682             :         /* Dont give back the packet to same VM */
    1683           0 :         if (dir_nh->nh_dev == pkt->vp_if)
    1684           0 :             continue;
    1685             : 
    1686             :         /* There would be enought head space to clone it with zero size */
    1687           0 :         if (!(new_pkt = nh_mcast_clone(pkt, 0))) {
    1688           0 :             drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1689           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1690           0 :             break;
    1691             :         }
    1692             : 
    1693           0 :         for (j = 0; j < VR_MAX_PHY_INF; j++) {
    1694           0 :             if (dir_nh->nh_dev_arr[j] != NULL) {
    1695           0 :                 fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
    1696           0 :                 break;
    1697             :             }
    1698             :         }
    1699           0 :         nh_output(new_pkt, dir_nh, fmd);
    1700             :     }
    1701             : 
    1702             :     /* Original packet needs to be unconditionally dropped */
    1703           0 : drop:
    1704           0 :     vr_pfree(pkt, drop_reason);
    1705           0 :     return NH_PROCESSING_COMPLETE;
    1706             : }
    1707             : 
    1708             : static nh_processing_t
    1709           0 : nh_composite_tor(struct vr_packet *pkt, struct vr_nexthop *nh,
    1710             :                  struct vr_forwarding_md *fmd)
    1711             : {
    1712             :     int i, j;
    1713           0 :     struct vr_vrf_stats *stats = NULL;
    1714             :     struct vr_nexthop *dir_nh;
    1715             :     unsigned short drop_reason;
    1716             :     struct vr_packet *new_pkt;
    1717             : 
    1718           0 :     if (!fmd) {
    1719           0 :         drop_reason = VP_DROP_NO_FMD;
    1720           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1721           0 :         goto drop;
    1722             :     }
    1723             : 
    1724           0 :     drop_reason = VP_DROP_CLONED_ORIGINAL;
    1725           0 :     if (vr_inet_vrf_stats) {
    1726           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    1727           0 :         if (stats)
    1728           0 :             stats->vrf_evpn_composites++;
    1729             :     }
    1730             : 
    1731           0 :     if (!nh->nh_component_cnt) {
    1732           0 :         drop_reason = VP_DROP_DISCARD;
    1733           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1734           0 :         goto drop;
    1735             :     }
    1736             : 
    1737           0 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    1738           0 :         dir_nh = nh->nh_component_nh[i].cnh;
    1739             : 
    1740             :         /* If direct nexthop is not valid, dont process it */
    1741           0 :         if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
    1742           0 :             continue;
    1743             : 
    1744           0 :         if (dir_nh->nh_type != NH_TUNNEL)
    1745           0 :             continue;
    1746             : 
    1747             :         /* Dont forward to same source */
    1748           0 :         if (fmd->fmd_outer_src_ip && fmd->fmd_outer_src_ip ==
    1749           0 :             dir_nh->nh_udp_tun_dip)
    1750           0 :             continue;
    1751             : 
    1752             :         /*
    1753             :          * Enough head spaces are created in the previous nexthop
    1754             :          * handling. Just cow the packet with zero size to get different
    1755             :          * buffer space
    1756             :          */
    1757           0 :         new_pkt = nh_mcast_clone(pkt, 0);
    1758           0 :         if (!new_pkt) {
    1759           0 :             drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1760           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1761           0 :             break;
    1762             :         }
    1763             : 
    1764           0 :         vr_fmd_set_label(fmd, nh->nh_component_nh[i].cnh_label,
    1765             :                 VR_LABEL_TYPE_UNKNOWN);
    1766           0 :         for (j = 0; j < VR_MAX_PHY_INF; j++) {
    1767           0 :             if (dir_nh->nh_dev_arr[j] != NULL) {
    1768           0 :                 fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
    1769           0 :                 break;
    1770             :             }
    1771             :         }
    1772           0 :         nh_output(new_pkt, dir_nh, fmd);
    1773             :     }
    1774             : 
    1775             :     /* Original packet needs to be unconditionally dropped */
    1776           0 : drop:
    1777           0 :     vr_pfree(pkt, drop_reason);
    1778           0 :     return NH_PROCESSING_COMPLETE;
    1779             : }
    1780             : 
    1781             : static nh_processing_t
    1782           0 : nh_composite_evpn(struct vr_packet *pkt, struct vr_nexthop *nh,
    1783             :                   struct vr_forwarding_md *fmd)
    1784             : {
    1785             :     int i, j;
    1786           0 :     bool l2_control_data = false;
    1787           0 :     struct vr_vrf_stats *stats = NULL;
    1788             :     struct vr_nexthop *dir_nh;
    1789             :     unsigned short drop_reason;
    1790             :     struct vr_packet *new_pkt;
    1791             :     uint8_t eth_mac[VR_ETHER_ALEN];
    1792             : 
    1793           0 :     if (!fmd) {
    1794           0 :         drop_reason = VP_DROP_NO_FMD;
    1795           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1796           0 :         goto drop;
    1797             :     }
    1798             : 
    1799           0 :     drop_reason = VP_DROP_CLONED_ORIGINAL;
    1800           0 :     if (vr_inet_vrf_stats) {
    1801           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    1802           0 :         if (stats)
    1803           0 :             stats->vrf_evpn_composites++;
    1804             :     }
    1805             : 
    1806           0 :     if (!nh->nh_component_cnt) {
    1807           0 :         drop_reason = VP_DROP_DISCARD;
    1808           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1809           0 :         goto drop;
    1810             :     }
    1811             : 
    1812           0 :     if (nh->nh_flags & NH_FLAG_TUNNEL_PBB)
    1813           0 :         vr_mcast_mac_from_isid(pkt->vp_if->vif_isid, eth_mac);
    1814             : 
    1815           0 :     if (vr_fmd_l2_control_data_is_enabled(fmd)) {
    1816           0 :         l2_control_data = true;
    1817           0 :         vr_fmd_update_l2_control_data(fmd, false);
    1818             :     }
    1819             : 
    1820           0 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    1821           0 :         dir_nh = nh->nh_component_nh[i].cnh;
    1822             : 
    1823             :         /* If direct nexthop is not valid, dont process it */
    1824           0 :         if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
    1825           0 :             continue;
    1826             : 
    1827           0 :         if (dir_nh->nh_type != NH_TUNNEL)
    1828           0 :             continue;
    1829             : 
    1830             :         /*
    1831             :          * Enough head spaces are created in the previous nexthop
    1832             :          * handling. Just cow the packet with zero size to get different
    1833             :          * buffer space
    1834             :          */
    1835           0 :         new_pkt = nh_mcast_clone(pkt, 0);
    1836           0 :         if (!new_pkt) {
    1837           0 :             drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1838           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1839           0 :             break;
    1840             :         }
    1841             : 
    1842           0 :         if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
    1843           0 :             if (!nh_pbb_tunnel_helper(nh->nh_router, &new_pkt, fmd,
    1844           0 :                     eth_mac, pkt->vp_if->vif_pbb_mac, pkt->vp_if->vif_isid)) {
    1845           0 :                 PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1846           0 :                 vr_pfree(new_pkt, VP_DROP_PUSH);
    1847           0 :                 continue;
    1848             :             }
    1849             :         }
    1850             : 
    1851           0 :         if (l2_control_data && !vr_l2_control_data_add(&new_pkt)) {
    1852           0 :             drop_reason = VP_DROP_PULL;
    1853           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1854           0 :             break;
    1855             :         }
    1856             : 
    1857           0 :         vr_fmd_set_label(fmd, nh->nh_component_nh[i].cnh_label,
    1858             :                 VR_LABEL_TYPE_UNKNOWN);
    1859           0 :         for (j = 0; j < VR_MAX_PHY_INF; j++) {
    1860           0 :             if (dir_nh->nh_dev_arr[j] != NULL) {
    1861           0 :                 fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
    1862           0 :                 break;
    1863             :             }
    1864             :         }
    1865           0 :         nh_output(new_pkt, dir_nh, fmd);
    1866             :     }
    1867             : 
    1868             :     /* Original packet needs to be unconditionally dropped */
    1869           0 : drop:
    1870           0 :     vr_pfree(pkt, drop_reason);
    1871           0 :     return NH_PROCESSING_COMPLETE;
    1872             : }
    1873             : 
    1874             : static nh_processing_t
    1875           2 : nh_composite_fabric(struct vr_packet *pkt, struct vr_nexthop *nh,
    1876             :                     struct vr_forwarding_md *fmd)
    1877             : {
    1878           2 :     int i, j, flag = 0;
    1879             :     int32_t label;
    1880             :     unsigned int dip, sip;
    1881             :     int8_t eth_mac[VR_ETHER_ALEN];
    1882           2 :     struct vr_vrf_stats *stats = NULL;
    1883             :     struct vr_nexthop *dir_nh;
    1884             :     unsigned short drop_reason, pkt_vrf;
    1885             :     struct vr_packet *new_pkt;
    1886             : 
    1887           2 :     if (!fmd) {
    1888           0 :         drop_reason = VP_DROP_NO_FMD;
    1889           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1890           0 :         goto drop;
    1891             :     }
    1892             : 
    1893           2 :     drop_reason = VP_DROP_CLONED_ORIGINAL;
    1894           2 :     if (vr_inet_vrf_stats) {
    1895           2 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    1896           2 :         if (stats)
    1897           2 :             stats->vrf_fabric_composites++;
    1898             :     }
    1899             : 
    1900           2 :     if (!nh->nh_component_cnt) {
    1901           0 :         drop_reason = VP_DROP_DISCARD;
    1902           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1903           0 :         goto drop;
    1904             :     }
    1905             : 
    1906             :     /*
    1907             :      * Packet can be L2 or L3 with or without control information. It is
    1908             :      * always ensured before coming to this nexthop that packet headers
    1909             :      * along with control inforation is in first buffer. So it can be
    1910             :      * safely cow'd for the required length
    1911             :      */
    1912             : 
    1913           2 :     label = fmd->fmd_label;
    1914           2 :     pkt_vrf = fmd->fmd_dvrf;
    1915           2 :     if (nh->nh_flags & NH_FLAG_TUNNEL_PBB)
    1916           0 :         vr_mcast_mac_from_isid(pkt->vp_if->vif_isid, eth_mac);
    1917             : 
    1918           4 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    1919           2 :         dir_nh = nh->nh_component_nh[i].cnh;
    1920           2 :         flag = 0;
    1921           2 :         fmd->fmd_dvrf = pkt_vrf;
    1922             : 
    1923             :         /* If direct nexthop is not valid, dont process it */
    1924           2 :         if ((!dir_nh) || !(dir_nh->nh_flags & NH_FLAG_VALID))
    1925           0 :             continue;
    1926             : 
    1927           2 :         if (dir_nh->nh_type != NH_TUNNEL)
    1928           0 :             continue;
    1929             : 
    1930             :         /*
    1931             :          * Take the right tunnel source. The dst is also our own
    1932             :          * address
    1933             :          */
    1934           2 :         sip = dip = 0;
    1935           2 :         if (dir_nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
    1936           0 :             sip = dir_nh->nh_gre_tun_sip;
    1937           0 :             dip = dir_nh->nh_gre_tun_dip;
    1938           2 :         } else if (dir_nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
    1939           2 :             sip = dir_nh->nh_udp_tun_sip;
    1940           2 :             dip = dir_nh->nh_udp_tun_dip;
    1941             :         } else {
    1942           0 :             drop_reason = VP_DROP_INVALID_NH;
    1943           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1944           0 :             break;
    1945             :         }
    1946             : 
    1947             :         /* Dont forward to same source */
    1948           2 :         if (fmd->fmd_outer_src_ip && fmd->fmd_outer_src_ip == dip)
    1949           0 :             continue;
    1950             : 
    1951             :         /* Dont flood back on ingress physical interface on the fabric. */
    1952           2 :         if (vif_is_vlan(pkt->vp_if)) {
    1953           0 :             for (j = 0; j < VR_MAX_PHY_INF; j++) {
    1954           0 :                 if (dir_nh->nh_dev_arr[j] != NULL) {
    1955           0 :                     if (vif_is_vlan(dir_nh->nh_dev_arr[j]) &&
    1956           0 :                         pkt->vp_if->vif_parent == dir_nh->nh_dev_arr[j]->vif_parent) {
    1957           0 :                         flag = 1;
    1958           0 :                         break;
    1959           0 :                     } else if (pkt->vp_if->vif_parent == dir_nh->nh_dev_arr[j]) {
    1960           0 :                         flag = 1;
    1961           0 :                         break;
    1962             :                     }
    1963             :                 }
    1964             :             }
    1965           0 :             if (flag == 1)
    1966           0 :                 continue;
    1967             :         }
    1968             : 
    1969             :         /*
    1970             :          * Enough head spaces are created in the previous nexthop
    1971             :          * handling. Just cow the packet with zero size to get different
    1972             :          * buffer space
    1973             :          */
    1974           2 :         new_pkt = nh_mcast_clone(pkt, 0);
    1975           2 :         if (!new_pkt) {
    1976           0 :             drop_reason = VP_DROP_MCAST_CLONE_FAIL;
    1977           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1978           0 :             break;
    1979             :         }
    1980             : 
    1981             :         /* If from VM or Tor add vxlan header */
    1982           2 :         if (vif_is_virtual(new_pkt->vp_if) ||
    1983           0 :                         (fmd->fmd_src == TOR_SOURCE)) {
    1984             :             /*
    1985             :              * The L2 multicast bridge entry will have VNID as label. If fmd
    1986             :              * does not valid label/vnid, skip the processing
    1987             :              */
    1988           2 :             if (label < 0) {
    1989           0 :                 PKT_LOG(VP_DROP_INVALID_LABEL, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1990           0 :                 vr_pfree(new_pkt, VP_DROP_INVALID_LABEL);
    1991           0 :                 break;
    1992             :             }
    1993             : 
    1994           2 :             if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
    1995           0 :                 if (!nh_pbb_tunnel_helper(nh->nh_router, &new_pkt, fmd, eth_mac,
    1996           0 :                               pkt->vp_if->vif_pbb_mac, pkt->vp_if->vif_isid)) {
    1997           0 :                     PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    1998           0 :                     vr_pfree(new_pkt, VP_DROP_PUSH);
    1999           0 :                     continue;
    2000             :                 }
    2001             :             }
    2002             : 
    2003           2 :             if (nh->nh_family == AF_BRIDGE) {
    2004             :                 /*
    2005             :                  * Add vxlan encapsulation. The vxlan id need to be taken
    2006             :                  * from Bridge entry
    2007             :                  */
    2008           2 :                 vr_fmd_set_label(fmd, label, VR_LABEL_TYPE_UNKNOWN);
    2009           3 :                 for (j = 0; j < VR_MAX_PHY_INF; j++) {
    2010           3 :                     if (dir_nh->nh_dev_arr[j] != NULL) {
    2011           2 :                         fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
    2012           2 :                         break;
    2013             :                     }
    2014             :                 }
    2015           2 :                 if (nh_vxlan_tunnel_helper(nh->nh_router, &new_pkt,
    2016           2 :                                         fmd, sip, dip) == false) {
    2017           0 :                     PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2018           0 :                     vr_pfree(new_pkt, VP_DROP_PUSH);
    2019           0 :                     break;
    2020             :                 }
    2021             :             }
    2022             :         }
    2023             : 
    2024           2 :         if (nh->nh_family == AF_BRIDGE) {
    2025           2 :             if (vr_l2_control_data_add(&new_pkt) == false) {
    2026           0 :                 PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2027           0 :                 vr_pfree(new_pkt, VP_DROP_PUSH);
    2028           0 :                 break;
    2029             :             }
    2030           2 :             vr_fmd_update_l2_control_data(fmd, false);
    2031             :         }
    2032             : 
    2033             :         /* MPLS label for outer header encapsulation */
    2034           2 :         vr_fmd_set_label(fmd, nh->nh_component_nh[i].cnh_label,
    2035             :                 VR_LABEL_TYPE_UNKNOWN);
    2036           3 :         for (j = 0; j < VR_MAX_PHY_INF; j++) {
    2037           3 :             if (dir_nh->nh_dev_arr[j] != NULL) {
    2038           2 :                 fmd->fmd_dvrf = dir_nh->nh_dev_arr[j]->vif_vrf;
    2039           2 :                 break;
    2040             :             }
    2041             :         }
    2042           2 :         nh_output(new_pkt, dir_nh, fmd);
    2043             :     }
    2044             : 
    2045             :     /* Original packet needs to be unconditionally dropped */
    2046           2 : drop:
    2047           2 :     vr_pfree(pkt, drop_reason);
    2048           2 :     return NH_PROCESSING_COMPLETE;
    2049             : }
    2050             : 
    2051             : nh_processing_t
    2052           1 : nh_discard(struct vr_packet *pkt, struct vr_nexthop *nh,
    2053             :            struct vr_forwarding_md *fmd)
    2054             : {
    2055           1 :     struct vr_vrf_stats *stats = NULL;
    2056             : 
    2057           1 :     if (vr_inet_vrf_stats) {
    2058           1 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    2059           1 :         if (stats)
    2060           1 :             stats->vrf_discards++;
    2061             :     }
    2062             : 
    2063           1 :     PKT_LOG(VP_DROP_DISCARD, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2064           1 :     vr_pfree(pkt, VP_DROP_DISCARD);
    2065           1 :     return NH_PROCESSING_COMPLETE;
    2066             : }
    2067             : 
    2068             : static uint8_t *
    2069           0 : nh_generate_mirroring_sip(struct vr_nexthop *nh,
    2070             :         struct vr_packet *pkt, struct vr_forwarding_md *fmd)
    2071             : {
    2072             :     uint16_t intf_id;
    2073             :     mirror_type_t mtype;
    2074           0 :     struct vr_interface *vif = NULL;
    2075             : 
    2076           0 :     mtype = vr_fmd_get_mirror_type(fmd);
    2077             : 
    2078           0 :     if (mtype == MIRROR_TYPE_PORT_RX) {
    2079           0 :         vif = pkt->vp_if;
    2080           0 :     } else if (mtype == MIRROR_TYPE_PORT_TX) {
    2081           0 :         intf_id = vr_fmd_get_mirror_if_id(fmd);
    2082           0 :         if (intf_id != FMD_MIRROR_INVALID_DATA)
    2083           0 :             vif = __vrouter_get_interface(vrouter_get(nh->nh_rid), intf_id);
    2084             :     }
    2085             : 
    2086           0 :     if (!vif)
    2087           0 :         return NULL;
    2088             : 
    2089           0 :     if (nh->nh_family == AF_INET)
    2090           0 :         return (uint8_t *)&vif->vif_ip;
    2091           0 :     else if (nh->nh_family == AF_INET6)
    2092           0 :         return vif->vif_ip6;
    2093             : 
    2094           0 :     return NULL;
    2095             : }
    2096             : 
    2097             : static nh_processing_t
    2098           1 : nh_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
    2099             :               struct vr_forwarding_md *fmd)
    2100             : {
    2101           1 :     int ret = -1;
    2102           1 :     uint8_t *vif_ip = NULL;
    2103           1 :     uint16_t sport = 0;
    2104             :     unsigned int head_space, hash;
    2105           1 :     uint32_t sip = 0, port_range;
    2106             :     struct vr_packet *tmp;
    2107             :     struct vr_ip *ip;
    2108             :     struct vr_ip6 *ip6;
    2109             :     struct vr_udp *udp;
    2110           1 :     struct vr_vrf_stats *stats = NULL;
    2111             :     struct vr_forwarding_class_qos *qos;
    2112           1 :     struct vr_flow flow, *flowp = &flow;
    2113             : 
    2114           1 :     if (!fmd) {
    2115           0 :         PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
    2116           0 :         goto send_fail;
    2117             :     }
    2118             : 
    2119           1 :     head_space = sizeof(struct vr_udp) + VR_ETHER_HLEN;
    2120             : 
    2121           1 :     if (nh->nh_family == AF_INET)
    2122           1 :         head_space += sizeof(struct vr_ip);
    2123           0 :     else if (nh->nh_family == AF_INET6)
    2124           0 :         head_space += sizeof(struct vr_ip6);
    2125             :     else {
    2126           0 :         PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
    2127           0 :         goto send_fail;
    2128             :     }
    2129             : 
    2130           1 :     if (pkt_head_space(pkt) < head_space) {
    2131           0 :         tmp = vr_pexpand_head(pkt, head_space - pkt_head_space(pkt));
    2132           0 :         if (!tmp) {
    2133           0 :             PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
    2134           0 :             goto send_fail;
    2135             :         }
    2136           0 :         pkt = tmp;
    2137             :     }
    2138             : 
    2139           1 :     if (pkt->vp_type == VP_TYPE_IP) {
    2140           1 :         ret = vr_inet_get_flow_key(nh->nh_router, pkt, fmd,
    2141             :                                      flowp, VR_FLOW_KEY_ALL,
    2142             :                                      VR_FRAG_FLAG_MIRROR);
    2143           0 :     } else if (pkt->vp_type == VP_TYPE_IP6) {
    2144           0 :         ret = vr_inet6_get_flow_key(nh->nh_router, fmd->fmd_dvrf, pkt,
    2145           0 :                                  fmd->fmd_vlan, flowp, VR_FLOW_KEY_ALL,
    2146             :                                  VR_FRAG_FLAG_MIRROR);
    2147             :     }
    2148             : 
    2149           1 :     if (!ret) {
    2150           1 :         hash = vr_hash(flowp, flowp->flow_key_len, 0);
    2151           1 :         port_range = VR_UDP_PORT_RANGE_END - VR_UDP_PORT_RANGE_START;
    2152           1 :         sport = (uint16_t)
    2153           1 :             (((uint64_t ) hash * port_range) >> 32);
    2154           1 :         sport += VR_UDP_PORT_RANGE_START;
    2155             :     }
    2156             : 
    2157           1 :     if (nh->nh_flags & NH_FLAG_TUNNEL_SIP_COPY) {
    2158           0 :         vif_ip = nh_generate_mirroring_sip(nh, pkt, fmd);
    2159             :     }
    2160             : 
    2161           1 :     if (nh->nh_family == AF_INET) {
    2162             : 
    2163           1 :         if (vif_ip)
    2164           0 :             sip = *(uint32_t *)vif_ip;
    2165             : 
    2166           1 :         if (!sip)
    2167           1 :             sip = nh->nh_udp_tun_sip;
    2168             : 
    2169           1 :         if (!sport)
    2170           0 :             sport = ntohs(nh->nh_udp_tun_sport);
    2171             : 
    2172           1 :         qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
    2173           2 :         if (nh_udp_tunnel_helper(pkt, htons(sport),
    2174           1 :                     nh->nh_udp_tun_dport, sip,
    2175           1 :                     nh->nh_udp_tun_dip, qos) == false) {
    2176           0 :             PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
    2177           0 :             goto send_fail;
    2178             :         }
    2179             : 
    2180           1 :         if (pkt_len(pkt) > ((1 << sizeof(ip->ip_len) * 8))) {
    2181           0 :             PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
    2182           0 :             goto send_fail;
    2183             :         }
    2184             : 
    2185           1 :         ip = (struct vr_ip *)(pkt_data(pkt));
    2186           1 :         udp = (struct vr_udp *)((char *)ip + ip->ip_hl * 4);
    2187           1 :         udp->udp_csum = vr_ip_partial_csum(ip);
    2188           1 :         pkt->vp_flags |= VP_FLAG_CSUM_PARTIAL;
    2189             : 
    2190           1 :         pkt->vp_type = VP_TYPE_IP;
    2191             : 
    2192           0 :     } else if (nh->nh_family == AF_INET6) {
    2193             : 
    2194           0 :         if (!sport)
    2195           0 :             sport = ntohs(nh->nh_udp_tun6_sport);
    2196             : 
    2197           0 :         if (nh_udp_tunnel6_helper(pkt, nh, vif_ip, htons(sport),
    2198           0 :                    nh->nh_udp_tun6_dport) == false) {
    2199           0 :             PKT_LOG(VP_DROP_PUSH, pkt, flowp, VR_NEXTHOP_C, __LINE__);
    2200           0 :             goto send_fail;
    2201             :         }
    2202             : 
    2203           0 :         ip6 = (struct vr_ip6 *)(pkt_data(pkt));
    2204           0 :         udp = (struct vr_udp *)((char *)ip6 + sizeof(struct vr_ip6));
    2205           0 :         udp->udp_csum = vr_ip6_partial_csum(ip6);
    2206           0 :         pkt->vp_flags |= VP_FLAG_CSUM_PARTIAL;
    2207             : 
    2208           0 :         pkt->vp_type = VP_TYPE_IP6;
    2209             :     }
    2210             : 
    2211           1 :     fmd->fmd_udp_src_port = sport;
    2212             : 
    2213           1 :     pkt_set_network_header(pkt, pkt->vp_data);
    2214             : 
    2215             :     /*
    2216             :      * Incase of mirroring set the inner network header to the newly added
    2217             :      * header so that this is fragmented and checksummed
    2218             :      */
    2219           1 :     pkt_set_inner_network_header(pkt, pkt->vp_data);
    2220             : 
    2221           1 :     if (vr_inet_vrf_stats) {
    2222           1 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    2223           1 :         if (stats)
    2224           1 :             stats->vrf_udp_tunnels++;
    2225             :     }
    2226             : 
    2227           1 :     vr_forward(vrouter_get(nh->nh_rid), pkt, fmd);
    2228             : 
    2229           1 :     return NH_PROCESSING_COMPLETE;
    2230             : 
    2231           0 : send_fail:
    2232           0 :     vr_pfree(pkt, VP_DROP_PUSH);
    2233           0 :     return NH_PROCESSING_COMPLETE;
    2234             : }
    2235             : 
    2236             : /*
    2237             :  * nh_vxlan_tunnel - tunnel packet with VXLAN header
    2238             :  */
    2239             : static nh_processing_t
    2240           6 : nh_vxlan_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
    2241             :                 struct vr_forwarding_md *fmd)
    2242             : {
    2243             :     struct vr_interface *vif;
    2244           6 :     struct vr_vrf_stats *stats = NULL;
    2245           6 :     unsigned short reason = VP_DROP_PUSH;
    2246             :     struct vr_packet *tmp_pkt;
    2247             :     struct vr_df_trap_arg trap_arg;
    2248             :     unsigned short overhead_len;
    2249             : 
    2250           6 :     if (!fmd) {
    2251           0 :         reason = VP_DROP_NO_FMD;
    2252           0 :         PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2253           0 :         goto send_fail;
    2254             :     }
    2255             : 
    2256           6 :     if (fmd->fmd_label < 0) {
    2257           0 :         reason = VP_DROP_INVALID_LABEL;
    2258           0 :         PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2259           0 :         goto send_fail;
    2260             :     }
    2261             : 
    2262           6 :     if (vr_inet_vrf_stats) {
    2263           6 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    2264           6 :         if (stats)
    2265           6 :             stats->vrf_vxlan_tunnels++;
    2266             :     }
    2267             : 
    2268           6 :     if (nh_tunnel_loop_detect_handle(pkt, nh, fmd, nh->nh_vxlan_tun_dip))
    2269           0 :         return NH_PROCESSING_COMPLETE;
    2270             : 
    2271           6 :     if (vr_perfs)
    2272           6 :         pkt->vp_flags |= VP_FLAG_GSO;
    2273             : 
    2274             :     /* Assigning the vif */
    2275           6 :     if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    2276           1 :         vif = nh_underlay_tunnel_vif_selection(pkt, fmd, nh, &reason);
    2277           1 :         if (reason == VP_DROP_INVALID_UNDERLAY_ECMP && !vif) {
    2278           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2279           0 :             goto send_fail;
    2280             :         }
    2281             :     } else
    2282           5 :         vif = nh->nh_dev;
    2283             : 
    2284           6 :     if (nh->nh_flags & NH_FLAG_L3_VXLAN) {
    2285             :         struct vr_eth *eth;
    2286             : 
    2287             :         /* Preset the pkt to make it point to L2 header */
    2288           0 :         vr_preset(pkt);
    2289             : 
    2290           0 :         if (!vif || IS_MAC_ZERO(vif->vif_mac)) {
    2291           0 :             reason = VP_DROP_INTERFACE_DROP;
    2292           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2293           0 :             goto send_fail;
    2294             :         }
    2295             : 
    2296           0 :         eth = (struct vr_eth *)pkt_data(pkt);
    2297           0 :         VR_MAC_COPY(eth->eth_dmac, nh->nh_vxlan_tun_l3_mac);
    2298           0 :         VR_MAC_COPY(eth->eth_smac, vif->vif_mac);
    2299             :     }
    2300             : 
    2301           6 :     overhead_len = VR_VXLAN_HDR_LEN;
    2302           6 :     if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
    2303           6 :         if (vr_has_to_fragment(vif, pkt, overhead_len) &&
    2304           0 :                 vr_ip_dont_fragment_set(pkt)) {
    2305           0 :             if (pkt->vp_flags & VP_FLAG_MULTICAST) {
    2306           0 :                 reason = VP_DROP_MCAST_DF_BIT;
    2307           0 :                 PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2308           0 :                 goto send_fail;
    2309             :             }
    2310             : 
    2311           0 :             trap_arg.df_mtu = vif_get_mtu(vif) -
    2312           0 :                 (overhead_len + pkt_get_network_header_off(pkt) - pkt->vp_data);
    2313           0 :             trap_arg.df_flow_index = fmd->fmd_flow_index;
    2314           0 :             vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_HANDLE_DF, (void *)&trap_arg);
    2315           0 :             return NH_PROCESSING_COMPLETE;
    2316             :         }
    2317             :     }
    2318             : 
    2319           6 :     if (nh_vxlan_tunnel_helper(nh->nh_router, &pkt, fmd, nh->nh_vxlan_tun_sip,
    2320           6 :                 nh->nh_vxlan_tun_dip) == false)
    2321           0 :         goto send_fail;
    2322             : 
    2323           6 :     pkt_set_network_header(pkt, pkt->vp_data);
    2324             : 
    2325           6 :     if (pkt->vp_type == VP_TYPE_IPOIP)
    2326           0 :         pkt->vp_type = VP_TYPE_IP;
    2327           6 :     else if (pkt->vp_type == VP_TYPE_IP6OIP)
    2328           0 :         pkt->vp_type = VP_TYPE_IP6;
    2329             : 
    2330             :     /*
    2331             :      * Change the packet type
    2332             :      */
    2333           6 :     if (pkt->vp_type == VP_TYPE_IP6)
    2334           3 :         pkt->vp_type = VP_TYPE_IP6OIP;
    2335           3 :     else if (pkt->vp_type == VP_TYPE_IP)
    2336           3 :         pkt->vp_type = VP_TYPE_IPOIP;
    2337             :     else
    2338           0 :         pkt->vp_type = VP_TYPE_IP;
    2339             : 
    2340           6 :     if (pkt_head_space(pkt) < nh->nh_vxlan_tun_encap_len) {
    2341           0 :         tmp_pkt = vr_pexpand_head(pkt, nh->nh_vxlan_tun_encap_len - pkt_head_space(pkt));
    2342           0 :         if (!tmp_pkt) {
    2343           0 :             goto send_fail;
    2344             :         }
    2345           0 :         pkt = tmp_pkt;
    2346             :     }
    2347             : 
    2348             :     /* slap l2 header */
    2349           6 :     if (nh->nh_flags & NH_FLAG_CRYPT_TRAFFIC) {
    2350           0 :         if (!nh->nh_crypt_dev) {
    2351           0 :             reason = VP_DROP_NO_CRYPT_PATH;
    2352           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2353           0 :             goto send_fail;
    2354             :         }
    2355           0 :         vif = nh->nh_crypt_dev;
    2356             :     }
    2357             :     /*
    2358             :      * during l3 multihoming, the nh_data passed can contain encap data from
    2359             :      * multiple gateways. To ensure that the right data is passed, the nh_data
    2360             :      * pointer is shifted to the relevant encap data address using the product
    2361             :      * of len of data and the vif_idx which the physical interface corresponding
    2362             :      * to the encap data. Since physical interfaces will always have the Id 0, 1
    2363             :      * or 2, vif_idx can directly be used.
    2364             :      */
    2365           6 :     if (vif_is_fabric(vif) && (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP)) {
    2366           1 :         if (vif->vif_set_rewrite(vif, &pkt, fmd,
    2367           1 :                     (nh->nh_data +(nh->nh_vxlan_tun_encap_len * vif->vif_idx)),
    2368           1 :                     nh->nh_vxlan_tun_encap_len) < 0) {
    2369           0 :             goto send_fail;
    2370             :         }
    2371             :     } else {
    2372           5 :         if (vif->vif_set_rewrite(vif, &pkt, fmd,
    2373           5 :                     nh->nh_data, nh->nh_vxlan_tun_encap_len) < 0) {
    2374           0 :             goto send_fail;
    2375             :         }
    2376             :     }
    2377             : 
    2378           6 :     vif->vif_tx(vif, pkt, fmd);
    2379             : 
    2380           6 :     return NH_PROCESSING_COMPLETE;
    2381             : 
    2382           0 : send_fail:
    2383           0 :     vr_pfree(pkt, reason);
    2384           0 :     return NH_PROCESSING_COMPLETE;
    2385             : 
    2386             : }
    2387             : 
    2388             : static nh_processing_t
    2389           0 : nh_pbb_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
    2390             :         struct vr_forwarding_md *fmd)
    2391             : {
    2392           0 :     struct vr_vrf_stats *stats = NULL;
    2393             : 
    2394           0 :     if (vr_fmd_etree_is_enabled(fmd)) {
    2395           0 :         if ((!vr_fmd_etree_is_root(fmd)) &&
    2396           0 :                     (!(nh->nh_flags & NH_FLAG_ETREE_ROOT))) {
    2397           0 :             PKT_LOG(VP_DROP_LEAF_TO_LEAF, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2398           0 :             vr_pfree(pkt, VP_DROP_LEAF_TO_LEAF);
    2399           0 :             return NH_PROCESSING_COMPLETE;
    2400             :         }
    2401             :     }
    2402             : 
    2403           0 :     if (vr_inet_vrf_stats) {
    2404           0 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    2405           0 :         if (stats)
    2406           0 :             stats->vrf_pbb_tunnels++;
    2407             :     }
    2408             : 
    2409           0 :     if (!nh_pbb_tunnel_helper(nh->nh_router, &pkt, fmd, nh->nh_pbb_mac,
    2410           0 :             pkt->vp_if->vif_pbb_mac, pkt->vp_if->vif_isid)) {
    2411           0 :             PKT_LOG(VP_DROP_PUSH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2412           0 :             vr_pfree(pkt, VP_DROP_PUSH);
    2413           0 :         return NH_PROCESSING_COMPLETE;
    2414             :     }
    2415           0 :     vr_fmd_set_label(fmd, nh->nh_pbb_label, VR_LABEL_TYPE_UNKNOWN);
    2416             : 
    2417           0 :     return NH_PROCESSING_INCOMPLETE;
    2418             : }
    2419             : 
    2420             : static int
    2421           0 : nh_pbb_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
    2422             :         struct vr_forwarding_md *fmd, void *ret_data)
    2423             : {
    2424           0 :     bool root = false;
    2425             : 
    2426           0 :     if (nh->nh_flags & NH_FLAG_ETREE_ROOT)
    2427           0 :         root = true;
    2428           0 :     vr_fmd_update_etree_root(fmd,root);
    2429             : 
    2430           0 :     if (VR_MAC_CMP(nh->nh_pbb_mac, fmd->fmd_smac)) {
    2431           0 :         return NH_SOURCE_VALID;
    2432             :     }
    2433             : 
    2434           0 :     return NH_SOURCE_INVALID;
    2435             : }
    2436             : 
    2437             : static int
    2438           7 : nh_mpls_udp_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
    2439             :                                 struct vr_forwarding_md *fmd, void *ret_data)
    2440             : {
    2441           7 :     if (fmd->fmd_outer_src_ip == nh->nh_udp_tun_dip)
    2442           5 :         return NH_SOURCE_VALID;
    2443             : 
    2444           2 :     return NH_SOURCE_INVALID;
    2445             : }
    2446             : 
    2447             : static int
    2448           0 : nh_vxlan_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
    2449             :                                 struct vr_forwarding_md *fmd, void *ret_data)
    2450             : {
    2451           0 :     if (fmd->fmd_outer_src_ip == nh->nh_udp_tun_dip)
    2452           0 :         return NH_SOURCE_VALID;
    2453             : 
    2454           0 :     return NH_SOURCE_INVALID;
    2455             : }
    2456             : 
    2457             : 
    2458             : /*
    2459             :  * nh_mpls_udp_tunnel - tunnel packet with MPLS label in UDP.
    2460             :  */
    2461             : static nh_processing_t
    2462          51 : nh_mpls_udp_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
    2463             :                    struct vr_forwarding_md *fmd)
    2464             : {
    2465             :     unsigned int tun_sip, tun_dip, overhead_len, mudp_head_space;
    2466          51 :     uint16_t tun_encap_len, udp_src_port = VR_MPLS_OVER_UDP_SRC_PORT;
    2467          51 :     unsigned short reason = VP_DROP_PUSH;
    2468             : 
    2469             :     int tun_encap_rewrite;
    2470             :     struct vr_forwarding_class_qos *qos;
    2471             :     struct vr_interface *vif;
    2472          51 :     struct vr_vrf_stats *stats = NULL;
    2473             :     struct vr_packet *tmp_pkt;
    2474             :     struct vr_df_trap_arg trap_arg;
    2475          51 :     unsigned int label_count = 0;
    2476          51 :     uint32_t transport_label = 0;
    2477             : 
    2478             :     /*
    2479             :      * If we are testing MPLS over UDP using the vr_mudp sysctl, use the
    2480             :      * values from the GRE tunnel nexthop below. Otherwise, use the values
    2481             :      * from the UDP tunnel nexthop.
    2482             :      */
    2483          51 :     if (vr_mudp) {
    2484           0 :         tun_sip = nh->nh_gre_tun_sip;
    2485           0 :         tun_dip = nh->nh_gre_tun_dip;
    2486           0 :         tun_encap_len = nh->nh_gre_tun_encap_len;
    2487             :     } else {
    2488          51 :         tun_sip = nh->nh_udp_tun_sip;
    2489          51 :         tun_dip = nh->nh_udp_tun_dip;
    2490          51 :         tun_encap_len = nh->nh_udp_tun_encap_len;
    2491          51 :         transport_label = nh->nh_udp_tun_label;
    2492             :     }
    2493             : 
    2494          51 :     if (vr_inet_vrf_stats) {
    2495          51 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    2496          51 :         if (stats) {
    2497          51 :             if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    2498           0 :                 stats->vrf_udp_mpls_over_mpls_tunnels++;
    2499             :             } else {
    2500          51 :                 stats->vrf_udp_mpls_tunnels++;
    2501             :             }
    2502             :         }
    2503             :     }
    2504             : 
    2505          51 :     if (!fmd || fmd->fmd_label < 0) {
    2506           0 :         vr_forward(nh->nh_router, pkt, fmd);
    2507           0 :         return NH_PROCESSING_COMPLETE;
    2508             :     }
    2509             : 
    2510          51 :     vr_fmd_update_label_type(fmd, VR_LABEL_TYPE_MPLS);
    2511             : 
    2512          51 :     if (nh_tunnel_loop_detect_handle(pkt, nh, fmd, tun_dip))
    2513           0 :         return NH_PROCESSING_COMPLETE;
    2514             : 
    2515          51 :     if (fmd->fmd_udp_src_port)
    2516          19 :         udp_src_port = fmd->fmd_udp_src_port;
    2517             : 
    2518             :     /*
    2519             :      * The UDP source port is a hash of the inner IP src/dst address and
    2520             :      * vrf.
    2521             :      */
    2522          51 :     if ((!fmd->fmd_udp_src_port)  && vr_get_udp_src_port) {
    2523          32 :         udp_src_port = vr_get_udp_src_port(pkt, fmd, fmd->fmd_dvrf);
    2524          32 :         if (udp_src_port == 0) {
    2525           0 :             reason = VP_DROP_PULL;
    2526           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2527           0 :             goto send_fail;
    2528             :         }
    2529             :     }
    2530             : 
    2531          51 :     if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    2532           0 :         label_count = 2;
    2533             :     } else {
    2534          51 :         label_count = 1;
    2535             :     }
    2536             :     /* Calculate the head space for mpls,udp ip and eth */
    2537          51 :     mudp_head_space = (label_count*VR_MPLS_HDR_LEN) +
    2538          51 :                 sizeof(struct vr_ip) + sizeof(struct vr_udp);
    2539          51 :     if (vr_fmd_l2_control_data_is_enabled(fmd))
    2540           0 :         mudp_head_space += VR_L2_CTRL_DATA_LEN;
    2541             : 
    2542             :     /* Assigning the vif */
    2543          51 :     if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    2544           5 :         vif = nh_underlay_tunnel_vif_selection(pkt, fmd, nh, &reason);
    2545           5 :         if (reason == VP_DROP_INVALID_UNDERLAY_ECMP && !vif) {
    2546           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2547           0 :             goto send_fail;
    2548             :         }
    2549             :     } else
    2550          46 :         vif = nh->nh_dev;
    2551             : 
    2552          51 :     if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
    2553          49 :         overhead_len = mudp_head_space;
    2554          50 :         if (vr_has_to_fragment(vif, pkt, overhead_len) &&
    2555           1 :                 vr_ip_dont_fragment_set(pkt)) {
    2556           0 :             if (pkt->vp_flags & VP_FLAG_MULTICAST) {
    2557           0 :                 reason = VP_DROP_MCAST_DF_BIT;
    2558           0 :                 PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2559           0 :                 goto send_fail;
    2560             :             }
    2561           0 :             trap_arg.df_mtu = vif_get_mtu(vif) -
    2562           0 :                 (overhead_len + pkt_get_network_header_off(pkt) - pkt->vp_data);
    2563           0 :             trap_arg.df_flow_index = fmd->fmd_flow_index;
    2564           0 :             vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_HANDLE_DF, (void *)&trap_arg);
    2565           0 :             return NH_PROCESSING_COMPLETE;
    2566             :         }
    2567             :     }
    2568             : 
    2569          51 :     mudp_head_space += tun_encap_len;
    2570             : 
    2571          51 :     if (pkt_head_space(pkt) < mudp_head_space) {
    2572           0 :         tmp_pkt = vr_pexpand_head(pkt, mudp_head_space - pkt_head_space(pkt));
    2573           0 :         if (!tmp_pkt)
    2574           0 :             goto send_fail;
    2575             : 
    2576           0 :         pkt = tmp_pkt;
    2577             :     }
    2578             : 
    2579          51 :     if (vr_fmd_l2_control_data_is_enabled(fmd)) {
    2580           0 :         if (!vr_l2_control_data_add(&pkt))
    2581           0 :             goto send_fail;
    2582             :     }
    2583             : 
    2584          51 :     qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
    2585          51 :     if (nh_push_mpls_header(pkt, fmd->fmd_label, qos, true) < 0) {
    2586           0 :         PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2587           0 :         goto send_fail;
    2588             :     }
    2589          51 :     if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    2590             :         /* insert outer label (transport label) */
    2591           0 :         if (nh_push_mpls_header(pkt, transport_label, qos, false) < 0) {
    2592           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2593           0 :             goto send_fail;
    2594             :         }
    2595             :     }
    2596             : 
    2597             : 
    2598          51 :     if (vr_perfs)
    2599          51 :         pkt->vp_flags |= VP_FLAG_GSO;
    2600             : 
    2601             : 
    2602          51 :     if (pkt->vp_type == VP_TYPE_IPOIP)
    2603           0 :         pkt->vp_type = VP_TYPE_IP;
    2604          51 :     else if (pkt->vp_type == VP_TYPE_IP6OIP)
    2605           0 :         pkt->vp_type = VP_TYPE_IP6;
    2606             : 
    2607             :     /*
    2608             :      * Change the packet type
    2609             :      */
    2610          51 :     if (pkt->vp_type == VP_TYPE_IP6)
    2611           2 :         pkt->vp_type = VP_TYPE_IP6OIP;
    2612          49 :     else if (pkt->vp_type == VP_TYPE_IP)
    2613          47 :         pkt->vp_type = VP_TYPE_IPOIP;
    2614             :     else
    2615           2 :         pkt->vp_type = VP_TYPE_IP;
    2616             : 
    2617         102 :     if (nh_udp_tunnel_helper(pkt, htons(udp_src_port),
    2618          51 :                              htons(VR_MPLS_OVER_UDP_DST_PORT),
    2619          51 :                              tun_sip, tun_dip, qos) == false) {
    2620           0 :         PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2621           0 :         goto send_fail;
    2622             :     }
    2623             : 
    2624          51 :     pkt_set_network_header(pkt, pkt->vp_data);
    2625             : 
    2626             :     /* slap l2 header */
    2627          51 :     if (nh->nh_flags & NH_FLAG_CRYPT_TRAFFIC) {
    2628           0 :         if (!nh->nh_crypt_dev) {
    2629           0 :             reason = VP_DROP_NO_CRYPT_PATH;
    2630           0 :             PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2631           0 :             goto send_fail;
    2632             :         }
    2633           0 :         vif = nh->nh_crypt_dev;
    2634             :     }
    2635             :     /*
    2636             :      * during l3 multihoming, the nh_data passed can contain encap data from
    2637             :      * multiple gateways. To ensure that the right data is passed, the nh_data
    2638             :      * pointer is shifted to the relevant encap data address using the product
    2639             :      * of len of data and the vif_idx which the physical interface corresponding
    2640             :      * to the encap data. Since physical interfaces will always have the Id 0,
    2641             :      * 1 or 2, vif_idx can directly be used.
    2642             :      */
    2643          51 :     if (vif_is_fabric(vif) && (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP)) {
    2644           5 :         tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
    2645           5 :                 (nh->nh_data + (tun_encap_len * vif->vif_idx)), tun_encap_len);
    2646             :     } else {
    2647          46 :         tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
    2648          46 :                 nh->nh_data, tun_encap_len);
    2649             :     }
    2650          51 :     if (tun_encap_rewrite < 0) {
    2651           0 :         reason = VP_DROP_REWRITE_FAIL;
    2652           0 :         PKT_LOG(reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2653           0 :         goto send_fail;
    2654             :     }
    2655             : 
    2656          51 :     vif->vif_tx(vif, pkt, fmd);
    2657             : 
    2658          51 :     return NH_PROCESSING_COMPLETE;
    2659             : 
    2660           0 : send_fail:
    2661           0 :     vr_pfree(pkt, reason);
    2662           0 :     return NH_PROCESSING_COMPLETE;
    2663             : 
    2664             : }
    2665             : 
    2666             : static int
    2667           0 : nh_gre_tunnel_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
    2668             :                            struct vr_forwarding_md *fmd, void *ret_data)
    2669             : {
    2670           0 :     if (fmd->fmd_outer_src_ip == nh->nh_gre_tun_dip)
    2671           0 :         return NH_SOURCE_VALID;
    2672             : 
    2673           0 :     return NH_SOURCE_INVALID;
    2674             : }
    2675             : 
    2676             : static nh_processing_t
    2677           6 : nh_gre_tunnel(struct vr_packet *pkt, struct vr_nexthop *nh,
    2678             :               struct vr_forwarding_md *fmd)
    2679             : {
    2680             :     int overhead_len, gre_head_space;
    2681           6 :     unsigned short drop_reason = VP_DROP_INVALID_NH;
    2682             :     unsigned int id;
    2683             : 
    2684             :     int tun_encap_rewrite;
    2685             :     struct vr_forwarding_class_qos *qos;
    2686             :     struct vr_gre *gre_hdr;
    2687             :     struct vr_ip *ip;
    2688             :     struct vr_interface *vif;
    2689           6 :     struct vr_vrf_stats *stats = NULL;
    2690             :     struct vr_packet *tmp_pkt;
    2691             :     struct vr_df_trap_arg trap_arg;
    2692           6 :     unsigned int label_count = 0;
    2693             : 
    2694           6 :     if (vr_mudp && vr_perfs) {
    2695           0 :         return nh_mpls_udp_tunnel(pkt, nh, fmd);
    2696             :     }
    2697             : 
    2698           6 :     if (vr_inet_vrf_stats) {
    2699           6 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    2700           6 :         if (stats) {
    2701           6 :             if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    2702           0 :                 stats->vrf_udp_mpls_over_mpls_tunnels++;
    2703             :             } else {
    2704           6 :                 stats->vrf_gre_mpls_tunnels++;
    2705             :             }
    2706             :         }
    2707             :     }
    2708             : 
    2709             :     /*
    2710             :      * When the packet encounters a tunnel nexthop with policy enabled,
    2711             :      * the forwarding metadata (and hence the label filled up by vr_forward)
    2712             :      * is lost as packets are queued in the flow entry. Note also the fact
    2713             :      * that nh_output sets pkt->vp_nh to the looked up NH. So, once the
    2714             :      * flow queue is flushed, we will not do vr_forward again and hence we
    2715             :      * will not have label information. For those packets, we need to do
    2716             :      * vr_forward again. One practical example of where this can happen is
    2717             :      * when ECMP source initiates traffic to a target in a remote (not in
    2718             :      * the same) server. vr_forward->tunnel_nh->nh_output sets pkt->vp_nh
    2719             :      * (source is ECMP)->pass through flow lookup->
    2720             :      */
    2721           6 :     if (!fmd || fmd->fmd_label < 0) {
    2722           0 :         vr_forward(nh->nh_router, pkt, fmd);
    2723           0 :         return NH_PROCESSING_COMPLETE;
    2724             :     }
    2725             : 
    2726           6 :     vr_fmd_update_label_type(fmd, VR_LABEL_TYPE_MPLS);
    2727             : 
    2728           6 :     if (nh_tunnel_loop_detect_handle(pkt, nh, fmd, nh->nh_gre_tun_dip))
    2729           0 :         return NH_PROCESSING_COMPLETE;
    2730             : 
    2731           6 :     if (vr_perfs)
    2732           6 :         pkt->vp_flags |= VP_FLAG_GSO;
    2733             : 
    2734           6 :     if (pkt->vp_type == VP_TYPE_IP) {
    2735           4 :         ip = (struct vr_ip *)pkt_network_header(pkt);
    2736           4 :         id = ip->ip_id;
    2737             :     } else {
    2738           2 :         id = htons(vr_generate_unique_ip_id());
    2739             :     }
    2740             : 
    2741           6 :     if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    2742           0 :         label_count = 2;
    2743             :     } else {
    2744           6 :         label_count = 1;
    2745             :     }
    2746             : 
    2747           6 :     gre_head_space = (label_count *VR_MPLS_HDR_LEN) + sizeof(struct vr_ip) +
    2748             :         sizeof(struct vr_gre);
    2749           6 :     if (vr_fmd_l2_control_data_is_enabled(fmd))
    2750           0 :         gre_head_space += VR_L2_CTRL_DATA_LEN;
    2751             : 
    2752             :     /* Assigning the vif */
    2753           6 :     if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    2754           2 :         vif = nh_underlay_tunnel_vif_selection(pkt, fmd, nh, &drop_reason);
    2755           2 :         if (drop_reason == VP_DROP_INVALID_UNDERLAY_ECMP && !vif) {
    2756           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2757           0 :             goto send_fail;
    2758             :         }
    2759             :     } else
    2760           4 :         vif = nh->nh_dev;
    2761             : 
    2762           6 :     if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
    2763             :         /*
    2764             :          * If there are any L2 headers lets add those as well. For L3
    2765             :          * unicast, following will add no extra overhead
    2766             :          */
    2767           6 :         overhead_len = gre_head_space;
    2768           6 :         if (vr_has_to_fragment(vif, pkt, overhead_len) &&
    2769           0 :                 vr_ip_dont_fragment_set(pkt)) {
    2770           0 :             if (pkt->vp_flags & VP_FLAG_MULTICAST) {
    2771           0 :                 drop_reason = VP_DROP_MCAST_DF_BIT;
    2772           0 :                 PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2773           0 :                 goto send_fail;
    2774             :             }
    2775             : 
    2776           0 :             trap_arg.df_mtu = vif_get_mtu(vif) -
    2777           0 :                 (overhead_len + pkt_get_network_header_off(pkt) - pkt->vp_data);
    2778           0 :             trap_arg.df_flow_index = fmd->fmd_flow_index;
    2779           0 :             vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_HANDLE_DF, (void *)&trap_arg);
    2780           0 :             return NH_PROCESSING_COMPLETE;
    2781             :         }
    2782             :     }
    2783             : 
    2784           6 :     gre_head_space += nh->nh_gre_tun_encap_len;
    2785             : 
    2786           6 :     if (pkt_head_space(pkt) < gre_head_space) {
    2787           0 :         tmp_pkt = vr_pexpand_head(pkt, gre_head_space - pkt_head_space(pkt));
    2788           0 :         if (!tmp_pkt) {
    2789           0 :             drop_reason = VP_DROP_HEAD_ALLOC_FAIL;
    2790           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2791           0 :             goto send_fail;
    2792             :         }
    2793           0 :         pkt = tmp_pkt;
    2794             :     }
    2795             : 
    2796           6 :     if (vr_fmd_l2_control_data_is_enabled(fmd)) {
    2797           0 :         if (!vr_l2_control_data_add(&pkt))
    2798           0 :             goto send_fail;
    2799             :     }
    2800             : 
    2801           6 :     qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
    2802           6 :     if (nh_push_mpls_header(pkt, fmd->fmd_label, qos, true) < 0)
    2803           0 :         goto send_fail;
    2804           6 :     if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    2805             :         /* insert outer label (transport label) */
    2806           0 :         if (nh_push_mpls_header(pkt, nh->nh_gre_tun_label, qos, false) < 0)
    2807           0 :             goto send_fail;
    2808             :     }
    2809             : 
    2810           6 :     gre_hdr = (struct vr_gre *)pkt_push(pkt, sizeof(struct vr_gre));
    2811           6 :     if (!gre_hdr) {
    2812           0 :         drop_reason = VP_DROP_PUSH;
    2813           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2814           0 :         goto send_fail;
    2815             :     }
    2816             : 
    2817           6 :     gre_hdr->gre_flags = 0;
    2818           6 :     gre_hdr->gre_proto = VR_GRE_PROTO_MPLS_NO;
    2819             : 
    2820           6 :     ip = (struct vr_ip *)pkt_push(pkt, sizeof(struct vr_ip));
    2821           6 :     if (!ip) {
    2822           0 :         drop_reason = VP_DROP_PUSH;
    2823           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2824           0 :         goto send_fail;
    2825             :     }
    2826           6 :     pkt_set_network_header(pkt, pkt->vp_data);
    2827             : 
    2828           6 :     if (pkt->vp_type == VP_TYPE_IPOIP)
    2829           0 :         pkt->vp_type = VP_TYPE_IP;
    2830           6 :     else if (pkt->vp_type == VP_TYPE_IP6OIP)
    2831           0 :         pkt->vp_type = VP_TYPE_IP6;
    2832             : 
    2833           6 :     if (pkt->vp_type == VP_TYPE_IP6)
    2834           2 :         pkt->vp_type = VP_TYPE_IP6OIP;
    2835           4 :     else  if (pkt->vp_type == VP_TYPE_IP)
    2836           4 :         pkt->vp_type = VP_TYPE_IPOIP;
    2837             :     else
    2838           0 :         pkt->vp_type = VP_TYPE_IP;
    2839             : 
    2840           6 :     ip->ip_version = 4;
    2841           6 :     ip->ip_hl = 5;
    2842           6 :     if (qos) {
    2843           0 :         ip->ip_tos = VR_IP_DSCP(qos->vfcq_dscp);
    2844           0 :         pkt->vp_queue = qos->vfcq_queue_id;
    2845           0 :         pkt->vp_priority = qos->vfcq_dotonep_qos;
    2846             :     } else {
    2847           6 :         ip->ip_tos = 0;
    2848             :     }
    2849             : 
    2850           6 :     ip->ip_id = id;
    2851           6 :     ip->ip_frag_off = 0;
    2852             : 
    2853           6 :     if (vr_pkt_is_diag(pkt)) {
    2854           0 :         ip->ip_ttl = pkt->vp_ttl;
    2855             :     } else {
    2856           6 :         ip->ip_ttl = 64;
    2857             :     }
    2858             : 
    2859           6 :     ip->ip_proto = VR_IP_PROTO_GRE;
    2860           6 :     ip->ip_saddr = nh->nh_gre_tun_sip;
    2861           6 :     ip->ip_daddr = nh->nh_gre_tun_dip;
    2862           6 :     ip->ip_len = htons(pkt_len(pkt));
    2863             :     /* checksum will be calculated for tunneled packet in linux_xmit_segment */
    2864           6 :     if (!vr_pkt_type_is_overlay(pkt->vp_type)) {
    2865           0 :         ip->ip_csum = 0;
    2866           0 :         ip->ip_csum = vr_ip_csum(ip);
    2867             :     }
    2868             : 
    2869             :     /* slap l2 header */
    2870           6 :     if (nh->nh_flags & NH_FLAG_CRYPT_TRAFFIC) {
    2871           0 :         if (!nh->nh_crypt_dev) {
    2872           0 :             drop_reason = VP_DROP_NO_CRYPT_PATH;
    2873           0 :             PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2874           0 :             goto send_fail;
    2875             :         }
    2876           0 :         vif = nh->nh_crypt_dev;
    2877             :     }
    2878             :     /*
    2879             :      * during l3 multihoming, the nh_data passed can contain encap data from
    2880             :      * multiple gateways. To ensure that the right data is passed, the nh_data
    2881             :      * pointer is shifted to the relevant encap data address using the product
    2882             :      * of len of data and the vif_idx which the physical interface corresponding
    2883             :      * to the encap data. Since physical interfaces will always have the Id 0,
    2884             :      * 1 or 2, vif_idx can directly be used.
    2885             :      */
    2886           6 :     if (vif_is_fabric(vif) && (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP)) {
    2887           2 :         tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
    2888           2 :                 (nh->nh_data + (nh->nh_gre_tun_encap_len * vif->vif_idx)),
    2889           2 :                 nh->nh_gre_tun_encap_len);
    2890             :     } else {
    2891           4 :         tun_encap_rewrite = vif->vif_set_rewrite(vif, &pkt, fmd,
    2892           4 :                 nh->nh_data, nh->nh_gre_tun_encap_len);
    2893             :     }
    2894           6 :     if (tun_encap_rewrite < 0) {
    2895           0 :         drop_reason = VP_DROP_REWRITE_FAIL;
    2896           0 :         PKT_LOG(drop_reason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2897           0 :         goto send_fail;
    2898             :     }
    2899           6 :     vif->vif_tx(vif, pkt, fmd);
    2900           6 :     return NH_PROCESSING_COMPLETE;
    2901             : 
    2902           0 : send_fail:
    2903           0 :     vr_pfree(pkt, drop_reason);
    2904           0 :     return NH_PROCESSING_COMPLETE;
    2905             : }
    2906             : 
    2907             : 
    2908             : /*
    2909             :  * Returns 0 - Completion of pkt handling
    2910             :  *        <0 - Error in pkt handling
    2911             :  */
    2912             : int
    2913         180 : nh_output(struct vr_packet *pkt, struct vr_nexthop *nh,
    2914             :           struct vr_forwarding_md *fmd)
    2915             : {
    2916         180 :     bool need_flow_lookup = false;
    2917             :     nh_processing_t res;
    2918             : 
    2919         180 :     if (!pkt->vp_ttl) {
    2920           0 :         vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_ZERO_TTL, NULL);
    2921           0 :         return 0;
    2922             :     }
    2923             : 
    2924         180 :     pkt->vp_nh = nh;
    2925             : 
    2926             : 
    2927             :     /* If nexthop does not have valid data, drop it */
    2928         180 :     if (!(nh->nh_flags & NH_FLAG_VALID)) {
    2929           0 :         PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2930           0 :         vr_pfree(pkt, VP_DROP_INVALID_NH);
    2931           0 :         return 0;
    2932             :     }
    2933             : 
    2934         180 :     if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) {
    2935             :         /*
    2936             :          * If the packet has not gone through flow lookup once
    2937             :          * (!VP_FLAG_FLOW_SET), we need to determine whether it has to undergo
    2938             :          * flow lookup now or not. There are two cases:
    2939             :          *
    2940             :          * 1. when policy flag is set in the nexthop, and
    2941             :          * 2. when the source is an ECMP (For bridged packets this ECMP
    2942             :          *      is avoided)
    2943             :          *
    2944             :          * When the source is an ECMP, we would like the packet to reach the
    2945             :          * same place from where it came from, and hence a flow has to be setup
    2946             :          * so that DP knows where to send the packet to (from an ECMP NH).
    2947             :          * Typical example for this situation is when the packet reaches the
    2948             :          * target VM's server from an ECMP-ed service chain.
    2949             :          */
    2950         177 :          if (!(pkt->vp_flags & VP_FLAG_FLOW_SET)) {
    2951          97 :              if (nh->nh_flags & (NH_FLAG_POLICY_ENABLED |
    2952             :                          NH_FLAG_FLOW_LOOKUP)) {
    2953          14 :                  need_flow_lookup = true;
    2954             :              }
    2955             : 
    2956          97 :              if (need_flow_lookup) {
    2957          14 :                  pkt->vp_flags |= VP_FLAG_FLOW_GET;
    2958             :                  /*
    2959             :                   * after vr_flow_forward returns, pkt->vp_nh could have changed
    2960             :                   * since in NAT cases the new destination should have been
    2961             :                   * looked up.
    2962             :                   */
    2963          14 :                  if (!vr_flow_forward(nh->nh_router, pkt, fmd))
    2964           4 :                      return 0;
    2965             : 
    2966             :                  /* pkt->vp_nh could have changed after vr_flow_forward */
    2967          10 :                  if (!pkt->vp_nh) {
    2968           0 :                      PKT_LOG(VP_DROP_INVALID_NH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    2969           0 :                      vr_pfree(pkt, VP_DROP_INVALID_NH);
    2970           0 :                      return 0;
    2971             :                  }
    2972             : 
    2973          10 :                  if (nh != pkt->vp_nh) {
    2974           0 :                      return nh_output(pkt, pkt->vp_nh, fmd);
    2975             :                  }
    2976             :              }
    2977             :         }
    2978             :     }
    2979             : 
    2980         176 :     res = nh->nh_reach_nh(pkt, nh, fmd);
    2981         176 :     if (res == NH_PROCESSING_COMPLETE)
    2982         176 :         return 0;
    2983             : 
    2984           0 :     if ((nh->nh_flags & NH_FLAG_INDIRECT) && nh->nh_direct_nh)
    2985           0 :         return nh_output(pkt, nh->nh_direct_nh, fmd);
    2986             :     else
    2987           0 :         vr_pfree(pkt, VP_DROP_INVALID_NH);
    2988             : 
    2989           0 :     return 0;
    2990             : }
    2991             : 
    2992             : static nh_processing_t
    2993          14 : nh_encap_l2(struct vr_packet *pkt, struct vr_nexthop *nh,
    2994             :             struct vr_forwarding_md *fmd)
    2995             : {
    2996          14 :     int8_t eth_mac[VR_ETHER_ALEN], *pbb_self_mac = eth_mac;
    2997             :     struct vr_interface *vif;
    2998          14 :     struct vr_vrf_stats *stats = NULL;
    2999             :     struct vr_forwarding_class_qos *qos;
    3000             : 
    3001          14 :     if (vr_fmd_etree_is_enabled(fmd)) {
    3002           0 :         if ((!vr_fmd_etree_is_root(fmd)) &&
    3003           0 :                     (!(nh->nh_flags & NH_FLAG_ETREE_ROOT))) {
    3004           0 :             PKT_LOG(VP_DROP_LEAF_TO_LEAF, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3005           0 :             vr_pfree(pkt, VP_DROP_LEAF_TO_LEAF);
    3006           0 :             return NH_PROCESSING_COMPLETE;
    3007             :         }
    3008             :     }
    3009             : 
    3010             :     /* No GRO for multicast and user packets */
    3011          14 :     if ((pkt->vp_flags & VP_FLAG_MULTICAST) ||
    3012          14 :             (fmd->fmd_vlan != VLAN_ID_INVALID)) {
    3013           5 :         vr_pkt_unset_gro(pkt);
    3014             :     }
    3015             : 
    3016          14 :     vif = nh->nh_dev;
    3017          14 :     if (!vif) {
    3018           0 :         PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3019           0 :         vr_pfree(pkt, VP_DROP_INVALID_IF);
    3020           0 :         return NH_PROCESSING_COMPLETE;
    3021             :     }
    3022             : 
    3023          14 :     if (!IS_MAC_ZERO(fmd->fmd_dmac) &&
    3024           0 :             !IS_MAC_ZERO(vif->vif_pbb_mac)) {
    3025             : 
    3026           0 :         if (IS_MAC_BMCAST(fmd->fmd_dmac))
    3027           0 :             vr_mcast_mac_from_isid(vif->vif_isid, pbb_self_mac);
    3028             :         else
    3029           0 :             pbb_self_mac = vif->vif_pbb_mac;
    3030             : 
    3031           0 :         if (!VR_MAC_CMP(fmd->fmd_dmac, pbb_self_mac)) {
    3032           0 :             PKT_LOG(VP_DROP_BMAC_ISID_MISMATCH, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3033           0 :             vr_pfree(pkt, VP_DROP_BMAC_ISID_MISMATCH);
    3034           0 :             return NH_PROCESSING_COMPLETE;
    3035             :         }
    3036             :     }
    3037             : 
    3038          14 :     if (vr_inet_vrf_stats)
    3039          14 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    3040             : 
    3041          14 :     if (vif_is_fabric(vif)) {
    3042           0 :         if (!(pkt->vp_flags & VP_FLAG_GROED)) {
    3043           0 :             qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
    3044           0 :             if (qos) {
    3045           0 :                 if (pkt->vp_type == VP_TYPE_IP) {
    3046           0 :                     vr_inet_set_tos((struct vr_ip *)pkt_network_header(pkt),
    3047           0 :                             VR_IP_DSCP(qos->vfcq_dscp));
    3048           0 :                 } else if (pkt->vp_type == VP_TYPE_IP6) {
    3049           0 :                     vr_inet6_set_tos((struct vr_ip6 *)pkt_network_header(pkt),
    3050           0 :                             qos->vfcq_dscp);
    3051             :                 }
    3052           0 :                 pkt->vp_queue = qos->vfcq_queue_id;
    3053           0 :                 pkt->vp_priority = qos->vfcq_dotonep_qos;
    3054             :             }
    3055             :         }
    3056             :     }
    3057             : 
    3058          14 :     if (vr_pkt_is_gro(pkt) && vif_is_virtual(vif) &&
    3059           1 :             (!(vif->vif_flags & VIF_FLAG_MIRROR_TX))) {
    3060           1 :         if (vr_gro_input(pkt, nh)) {
    3061           0 :             if (stats)
    3062           0 :                 stats->vrf_gros++;
    3063           0 :             return NH_PROCESSING_COMPLETE;
    3064             :         }
    3065             :     }
    3066             : 
    3067             :     /*
    3068             :      * If for some reason, we have GRO flag set and we have not invoked
    3069             :      * the GRO, we need to unset
    3070             :      */
    3071          14 :     vr_pkt_unset_gro(pkt);
    3072             : 
    3073          14 :     if (stats)
    3074          14 :         stats->vrf_l2_encaps++;
    3075             : 
    3076          14 :     vif->vif_tx(vif, pkt, fmd);
    3077             : 
    3078          14 :     return NH_PROCESSING_COMPLETE;
    3079             : }
    3080             : 
    3081             : static int
    3082          55 : nh_encap_validate_src(struct vr_packet *pkt, struct vr_nexthop *nh,
    3083             :                          struct vr_forwarding_md *fmd, void *ret_data)
    3084             : {
    3085          55 :     bool root = false;
    3086             : 
    3087          55 :     if (nh->nh_flags & NH_FLAG_ETREE_ROOT)
    3088          35 :         root = true;
    3089          55 :     vr_fmd_update_etree_root(fmd,root);
    3090             : 
    3091          55 :     if (pkt->vp_if == nh->nh_dev)
    3092          55 :         return NH_SOURCE_VALID;
    3093             : 
    3094           0 :     return NH_SOURCE_INVALID;
    3095             : }
    3096             : 
    3097             : static nh_processing_t
    3098           0 : nh_encap_l3_mcast(struct vr_packet *pkt, struct vr_nexthop *nh,
    3099             :                     struct vr_forwarding_md *fmd)
    3100             : {
    3101             :     uint8_t *ptr;
    3102           0 :     unsigned short dreason = VP_DROP_INVALID_IF;
    3103             :     struct vr_interface *vif;
    3104             :     struct vr_ip *ip;
    3105             :     struct vr_eth *eth;
    3106             : 
    3107           0 :     vif = nh->nh_dev;
    3108           0 :     if (!vif)
    3109           0 :         goto drop;
    3110             : 
    3111           0 :     ip = (struct vr_ip *)pkt_network_header(pkt);
    3112           0 :     if (vr_ip_is_ip4(ip)) {
    3113           0 :         pkt->vp_type = VP_TYPE_IP;
    3114           0 :         eth = (struct vr_eth *)pkt_push(pkt, sizeof(struct vr_eth));
    3115           0 :         if (!eth) {
    3116           0 :             dreason = VP_DROP_PUSH;
    3117           0 :             PKT_LOG(dreason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3118           0 :             goto drop;
    3119             :         }
    3120             : 
    3121           0 :         VR_MAC_COPY(eth->eth_smac, vif->vif_mac);
    3122           0 :         eth->eth_proto = htons(VR_ETH_PROTO_IP);
    3123           0 :         ptr = (uint8_t *)eth->eth_dmac;
    3124           0 :         *(unsigned int *)(ptr + 2) = ip->ip_daddr;
    3125             : 
    3126           0 :         ptr[0] = 1;
    3127           0 :         ptr[1] = 0;
    3128           0 :         ptr[2] = 0x5E;
    3129           0 :         ptr[3] = 0x07F & ptr[3];
    3130             : 
    3131             : 
    3132           0 :         vif->vif_tx(vif, pkt, fmd);
    3133             : 
    3134             :     } else {
    3135           0 :         dreason = VP_DROP_INVALID_PROTOCOL;
    3136           0 :         PKT_LOG(dreason, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3137           0 :         goto drop;
    3138             :     }
    3139             : 
    3140           0 :     return NH_PROCESSING_COMPLETE;
    3141             : 
    3142           0 : drop:
    3143           0 :     vr_pfree(pkt, dreason);
    3144           0 :     return NH_PROCESSING_COMPLETE;
    3145             : }
    3146             : 
    3147             : static nh_processing_t
    3148          31 : nh_encap_l3(struct vr_packet *pkt, struct vr_nexthop *nh,
    3149             :                     struct vr_forwarding_md *fmd)
    3150             : {
    3151             :     int rewrite_len;
    3152             :     unsigned short *proto_p;
    3153             : 
    3154             :     struct vr_ip *ip;
    3155             :     struct vr_interface *vif;
    3156          31 :     struct vr_vrf_stats *stats = NULL;
    3157          31 :     struct vr_forwarding_class_qos *qos = NULL;
    3158             : 
    3159          31 :     if (vr_inet_vrf_stats)
    3160          31 :         stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu);
    3161             : 
    3162          31 :     vif = nh->nh_dev;
    3163          31 :     if (!vif) {
    3164           0 :         PKT_LOG(VP_DROP_INVALID_IF, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3165           0 :         vr_pfree(pkt, VP_DROP_INVALID_IF);
    3166           0 :         return NH_PROCESSING_COMPLETE;
    3167             :     }
    3168             : 
    3169          31 :     if (vif_is_fabric(vif)) {
    3170           1 :         if (!(pkt->vp_flags & VP_FLAG_GROED)) {
    3171           1 :             qos = vr_qos_get_forwarding_class(nh->nh_router, pkt, fmd);
    3172           1 :             if (qos) {
    3173           0 :                 pkt->vp_queue = qos->vfcq_queue_id;
    3174           0 :                 pkt->vp_priority = qos->vfcq_dotonep_qos;
    3175             :             }
    3176             :         }
    3177             :     }
    3178             : 
    3179          31 :     ip = (struct vr_ip *)pkt_network_header(pkt);
    3180          31 :     if (vr_ip_is_ip6(ip)) {
    3181           2 :         pkt->vp_type = VP_TYPE_IP6;
    3182           2 :         if (qos)
    3183           0 :             vr_inet6_set_tos((struct vr_ip6 *)ip, qos->vfcq_dscp);
    3184          29 :     } else if (vr_ip_is_ip4(ip)) {
    3185          28 :         pkt->vp_type = VP_TYPE_IP;
    3186          28 :         if (qos)
    3187           0 :             vr_inet_set_tos(ip, VR_IP_DSCP(qos->vfcq_dscp));
    3188             :     } else {
    3189           1 :         PKT_LOG(VP_DROP_INVALID_PROTOCOL, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3190           1 :         vr_pfree(pkt, VP_DROP_INVALID_PROTOCOL);
    3191           1 :         return NH_PROCESSING_COMPLETE;
    3192             :     }
    3193             : 
    3194          30 :     if (vr_pkt_is_diag(pkt)) {
    3195           0 :         vr_pkt_unset_gro(pkt);
    3196           0 :         if (stats)
    3197           0 :             stats->vrf_diags++;
    3198             :     }
    3199             : 
    3200          30 :     if (vr_pkt_is_gro(pkt) && vif_is_virtual(vif) &&
    3201           3 :             (!(vif->vif_flags & VIF_FLAG_MIRROR_TX))) {
    3202           3 :         if (vr_gro_input(pkt, nh)) {
    3203           0 :             if (stats) {
    3204           0 :                 stats->vrf_gros++;
    3205             :             }
    3206           0 :             return NH_PROCESSING_COMPLETE;
    3207             :         }
    3208             :     }
    3209             : 
    3210             :     /*
    3211             :      * If for some reason, we have GRO flag set and we have not invoked
    3212             :      * the GRO, we need to unset
    3213             :      */
    3214          30 :     vr_pkt_unset_gro(pkt);
    3215             : 
    3216          30 :     rewrite_len = vif->vif_set_rewrite(vif, &pkt, fmd, nh->nh_data, nh->nh_encap_len);
    3217          30 :     if (rewrite_len < 0) {
    3218           0 :         PKT_LOG(VP_DROP_REWRITE_FAIL, pkt, 0, VR_NEXTHOP_C, __LINE__);
    3219           0 :         vr_pfree(pkt, VP_DROP_REWRITE_FAIL);
    3220           0 :         return NH_PROCESSING_COMPLETE;
    3221             :     }
    3222             : 
    3223          30 :     if (rewrite_len) {
    3224          29 :         proto_p = (unsigned short *)(pkt_data(pkt) + nh->nh_encap_len - 2);
    3225          29 :         if (pkt->vp_type == VP_TYPE_IP6)
    3226           2 :             *proto_p = htons(VR_ETH_PROTO_IP6);
    3227             :         else
    3228          27 :             *proto_p = htons(VR_ETH_PROTO_IP);
    3229             :     }
    3230             : 
    3231             :     /*
    3232             :      * Look if this is the Diag packet to trap to agent
    3233             :      */
    3234          30 :     if (vr_pkt_is_diag(pkt)) {
    3235           0 :         pkt->vp_if = vif;
    3236           0 :         vr_pset_data(pkt, pkt->vp_data);
    3237           0 :         vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_DIAG, &vif->vif_idx);
    3238           0 :         return NH_PROCESSING_COMPLETE;
    3239             :     }
    3240             : 
    3241          30 :     if (stats) {
    3242          30 :         stats->vrf_encaps++;
    3243             :     }
    3244             : 
    3245          30 :     vif->vif_tx(vif, pkt, fmd);
    3246             : 
    3247          30 :     return NH_PROCESSING_COMPLETE;
    3248             : }
    3249             : 
    3250             : static int
    3251         267 : vr_nexthop_delete(vr_nexthop_req *req)
    3252             : {
    3253             :     struct vr_nexthop *nh;
    3254         267 :     int ret = 0;
    3255             : 
    3256         267 :     nh = vrouter_get_nexthop(req->nhr_rid, req->nhr_id);
    3257         267 :     if (!nh) {
    3258           4 :         ret = -EINVAL;
    3259             :     } else {
    3260         263 :         vr_offload_nexthop_del(nh);
    3261         263 :         vrouter_put_nexthop(nh);
    3262         263 :         nh->nh_destructor(nh);
    3263             :     }
    3264             : 
    3265         267 :     ret = vr_send_response(ret);
    3266             : 
    3267         267 :     return ret;
    3268             : }
    3269             : 
    3270             : static int
    3271           0 : nh_resolve_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3272             : {
    3273           0 :     nh->nh_reach_nh = nh_resolve;
    3274           0 :     return 0;
    3275             : }
    3276             : 
    3277             : static int
    3278          16 : nh_l2_rcv_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3279             : {
    3280          16 :     nh->nh_reach_nh = nh_l2_rcv;
    3281          16 :     return 0;
    3282             : }
    3283             : 
    3284             : static int
    3285          23 : nh_rcv_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3286             : {
    3287          23 :     int ret = 0;
    3288             :     struct vr_interface *vif, *old_vif;
    3289             : 
    3290          23 :     old_vif = nh->nh_dev;
    3291             : 
    3292          23 :     vif = vrouter_get_interface(nh->nh_rid, req->nhr_encap_oif_id[0]);
    3293          23 :     if (!vif) {
    3294           0 :         ret = -ENODEV;
    3295           0 :         goto exit_add;
    3296             :     }
    3297             : 
    3298             :     /*
    3299             :      * We need to delete the reference to old_vif only after new vif is
    3300             :      * added to NH
    3301             :      */
    3302          23 :     nh->nh_dev = vif;
    3303          23 :     if (old_vif)
    3304           0 :         vrouter_put_interface(old_vif);
    3305             : 
    3306          23 : exit_add:
    3307          23 :     if (nh->nh_dev) {
    3308          23 :         nh->nh_reach_nh = nh_l3_rcv;
    3309             :     }
    3310             : 
    3311          23 :     return ret;
    3312             : }
    3313             : 
    3314             : static int
    3315           1 : nh_vrf_translate_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3316             : {
    3317           1 :     nh->nh_reach_nh = nh_vrf_translate;
    3318           1 :     return 0;
    3319             : }
    3320             : 
    3321             : static int
    3322           5 : nh_composite_mcast_validate(struct vr_component_nh *component_nh,
    3323             :         vr_nexthop_req *req)
    3324             : {
    3325             :     unsigned int i;
    3326           5 :     bool l2_seen = false, l3_seen = false;
    3327             :     struct vr_nexthop *tmp_nh;
    3328             : 
    3329           5 :     if (req->nhr_family == AF_INET)
    3330           4 :         l3_seen = true;
    3331           1 :     else if (req->nhr_family == AF_BRIDGE)
    3332           1 :         l2_seen = true;
    3333             : 
    3334             :     /* Fabric and EVPN nexthop*/
    3335           5 :     if (req->nhr_flags & (NH_FLAG_COMPOSITE_FABRIC |
    3336             :                 NH_FLAG_COMPOSITE_EVPN | NH_FLAG_COMPOSITE_TOR)) {
    3337             : 
    3338           1 :         if (!l3_seen && !l2_seen)
    3339           0 :             return -1;
    3340             : 
    3341           2 :         for (i = 0; i < req->nhr_nh_list_size; i++) {
    3342           1 :             tmp_nh = component_nh[i].cnh;
    3343           1 :             if (!tmp_nh)
    3344           0 :                 continue;
    3345           1 :             if (tmp_nh->nh_type != NH_TUNNEL)
    3346           0 :                 return -1;
    3347           1 :             if (tmp_nh->nh_flags & NH_FLAG_TUNNEL_UDP)
    3348           0 :                 return -1;
    3349             : 
    3350             :             /* Tor nexthop can only have Vxlan encap tunnels */
    3351           1 :             if (req->nhr_flags & NH_FLAG_COMPOSITE_TOR) {
    3352           0 :                 if ((tmp_nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) == 0)
    3353           0 :                     return -1;
    3354             :             }
    3355             :         }
    3356             :     }
    3357             : 
    3358             :     /* Composite Encap */
    3359           5 :     if (req->nhr_flags & NH_FLAG_COMPOSITE_ENCAP) {
    3360             : 
    3361           0 :         for (i = 0; i < req->nhr_nh_list_size; i++) {
    3362           0 :             tmp_nh = component_nh[i].cnh;
    3363           0 :             if (!tmp_nh)
    3364           0 :                 continue;
    3365             : 
    3366           0 :             if (tmp_nh->nh_type != NH_ENCAP)
    3367           0 :                 return -1;
    3368             : 
    3369           0 :             if (tmp_nh->nh_family == AF_INET) {
    3370           0 :                 if (l2_seen)
    3371           0 :                     return -1;
    3372             : 
    3373           0 :                 if (!(tmp_nh->nh_flags & NH_FLAG_MCAST))
    3374           0 :                     return -1;
    3375           0 :             } else if (tmp_nh->nh_family == AF_BRIDGE) {
    3376           0 :                 if (l3_seen)
    3377           0 :                     return -1;
    3378             : 
    3379           0 :                 if (tmp_nh->nh_flags & NH_FLAG_MCAST)
    3380           0 :                     return -1;
    3381             :             } else {
    3382           0 :                 return -1;
    3383             :             }
    3384             :         }
    3385             :     }
    3386             : 
    3387             :     /* L2 and L3 multicast */
    3388           5 :     if (req->nhr_flags & NH_FLAG_MCAST) {
    3389             : 
    3390           0 :         if (!l3_seen && !l2_seen)
    3391           0 :             return -1;
    3392             : 
    3393           0 :         for (i = 0; i < req->nhr_nh_list_size; i++) {
    3394           0 :             tmp_nh = component_nh[i].cnh;
    3395             :             /* NULL component NH is valid */
    3396           0 :             if (!tmp_nh)
    3397           0 :                 continue;
    3398             : 
    3399             :             /* IT can contain only Fabric and L2ENCAP composite */
    3400           0 :             if (tmp_nh->nh_type != NH_COMPOSITE)
    3401           0 :                 return -1;
    3402             : 
    3403           0 :             if (!(tmp_nh->nh_flags &
    3404             :                    (NH_FLAG_COMPOSITE_FABRIC | NH_FLAG_COMPOSITE_EVPN |
    3405             :                     NH_FLAG_COMPOSITE_TOR | NH_FLAG_COMPOSITE_ENCAP))) {
    3406           0 :                 return -1;
    3407             :             }
    3408             : 
    3409             :         }
    3410             :     }
    3411             : 
    3412           5 :     return 0;
    3413             : }
    3414             : 
    3415             : static int
    3416           5 : nh_composite_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3417             : {
    3418           5 :     int ret = 0;
    3419           5 :     unsigned int i, j = 0, active = 0;
    3420             :     struct vr_nexthop *tmp_nh;
    3421           5 :     struct vr_component_nh *component_nh = NULL, *component_ecmp = NULL;
    3422             : 
    3423           5 :     if (req->nhr_nh_list_size != req->nhr_label_list_size) {
    3424           0 :         ret = -EINVAL;
    3425           0 :         goto exit_add;
    3426             :     }
    3427             : 
    3428           5 :     if (req->nhr_nh_list_size) {
    3429           5 :         component_nh = vr_zalloc(req->nhr_nh_list_size *
    3430             :                 sizeof(struct vr_component_nh), VR_NEXTHOP_COMPONENT_OBJECT);
    3431           5 :         if (!component_nh) {
    3432           0 :             ret = -ENOMEM;
    3433           0 :             goto exit_add;
    3434             :         }
    3435             : 
    3436          14 :         for (i = 0; i < req->nhr_nh_list_size; i++) {
    3437          18 :             component_nh[i].cnh = vrouter_get_nexthop(req->nhr_rid,
    3438           9 :                     req->nhr_nh_list[i]);
    3439           9 :             component_nh[i].cnh_label = req->nhr_label_list[i];
    3440           9 :             if (component_nh[i].cnh)
    3441           9 :                 active++;
    3442             : 
    3443           9 :             if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
    3444           8 :                 component_nh[i].cnh_ecmp_index = i;
    3445             :             } else {
    3446           1 :                 component_nh[i].cnh_ecmp_index = -1;
    3447             :             }
    3448             :         }
    3449             : 
    3450           5 :         if (nh_composite_mcast_validate(component_nh, req)) {
    3451           0 :             ret = -EINVAL;
    3452           0 :             goto exit_add;
    3453             :         }
    3454             : 
    3455           5 :         if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
    3456           4 :             if (active) {
    3457             :                 component_ecmp =
    3458           4 :                     vr_zalloc(active * sizeof(struct vr_component_nh),
    3459             :                             VR_NEXTHOP_COMPONENT_OBJECT);
    3460           4 :                 if (!component_ecmp) {
    3461           0 :                     ret = -ENOMEM;
    3462           0 :                     goto exit_add;
    3463             :                 }
    3464             :             }
    3465             : 
    3466          12 :             for (i = 0; i < req->nhr_nh_list_size; i++) {
    3467           8 :                 if (component_nh[i].cnh) {
    3468           8 :                     memcpy(&component_ecmp[j++], &component_nh[i],
    3469             :                             sizeof(struct vr_component_nh));
    3470             :                     /* this happens implicitly */
    3471             :                     /* nh->nh_component_ecmp[j++].cnh_ecmp_index = i */
    3472             :                 }
    3473             :             }
    3474             :         }
    3475             :     }
    3476             : 
    3477           5 :     nh->nh_validate_src = NULL;
    3478             :     /* Delete the old nexthops first */
    3479           5 :     if (nh->nh_component_cnt && nh->nh_component_nh) {
    3480           0 :         for (i = 0; i < nh->nh_component_cnt; i++) {
    3481           0 :             if (nh->nh_component_nh[i].cnh)
    3482           0 :                 vrouter_put_nexthop(nh->nh_component_nh[i].cnh);
    3483             :         }
    3484           0 :         vr_free(nh->nh_component_nh, VR_NEXTHOP_COMPONENT_OBJECT);
    3485           0 :         nh->nh_component_nh = NULL;
    3486           0 :         nh->nh_component_cnt = 0;
    3487             : 
    3488           0 :         if (nh->nh_component_ecmp) {
    3489           0 :             vr_free(nh->nh_component_ecmp, VR_NEXTHOP_COMPONENT_OBJECT);
    3490           0 :             nh->nh_component_ecmp = NULL;
    3491           0 :             nh->nh_component_ecmp_cnt = 0;
    3492             :         }
    3493             :     }
    3494             : 
    3495             :     /* Nh list of size 0 is valid */
    3496           5 :     if (req->nhr_nh_list_size == 0)
    3497           0 :         goto exit_add;
    3498             : 
    3499           5 :     nh->nh_component_nh = component_nh;
    3500           5 :     if (component_ecmp) {
    3501           4 :         nh->nh_component_ecmp = component_ecmp;
    3502             :     }
    3503           5 :     nh->nh_component_cnt = req->nhr_nh_list_size;
    3504             : 
    3505           5 : exit_add:
    3506             :     /* This needs to be the last */
    3507           5 :     if (req->nhr_flags & NH_FLAG_MCAST) {
    3508           0 :         nh->nh_reach_nh = nh_composite_mcast;
    3509           0 :         nh->nh_validate_src = nh_composite_mcast_validate_src;
    3510           5 :     } else if (req->nhr_flags & NH_FLAG_COMPOSITE_ECMP) {
    3511           4 :         nh->nh_reach_nh = nh_composite_ecmp;
    3512           4 :         nh->nh_validate_src = nh_composite_ecmp_validate_src;
    3513           4 :         if (!ret) {
    3514           4 :             nh_ecmp_store_ecmp_config_hash(req, nh);
    3515           4 :             nh->nh_component_ecmp_cnt = j;
    3516             :         }
    3517           1 :     } else if (req->nhr_flags & NH_FLAG_COMPOSITE_FABRIC) {
    3518           1 :         nh->nh_reach_nh = nh_composite_fabric;
    3519           0 :     } else if (req->nhr_flags & NH_FLAG_COMPOSITE_EVPN) {
    3520           0 :         nh->nh_reach_nh = nh_composite_evpn;
    3521           0 :     } else if (req->nhr_flags & NH_FLAG_COMPOSITE_ENCAP) {
    3522           0 :         nh->nh_reach_nh = nh_composite_encap;
    3523           0 :     } else if (req->nhr_flags & NH_FLAG_COMPOSITE_TOR) {
    3524           0 :         nh->nh_reach_nh = nh_composite_tor;
    3525             :     }
    3526             : 
    3527           5 :     if (ret) {
    3528           0 :         if (component_nh) {
    3529           0 :             for (i = 0; i < req->nhr_nh_list_size; i++) {
    3530           0 :                 tmp_nh = component_nh[i].cnh;
    3531           0 :                 if (tmp_nh)
    3532           0 :                     vrouter_put_nexthop(tmp_nh);
    3533             :             }
    3534             : 
    3535           0 :             vr_free(component_nh, VR_NEXTHOP_COMPONENT_OBJECT);
    3536             :         }
    3537             : 
    3538           0 :         if (component_ecmp) {
    3539           0 :             vr_free(component_ecmp, VR_NEXTHOP_COMPONENT_OBJECT);
    3540             :         }
    3541             :     }
    3542             : 
    3543           5 :     return ret;
    3544             : }
    3545             : 
    3546             : static inline void
    3547          54 : nh_tunnel_set_reach_nh(struct vr_nexthop *nh)
    3548             : {
    3549          54 :     bool dev = false;
    3550             :     int i;
    3551             : 
    3552          54 :     if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    3553          36 :         for (i = 0; i < VR_MAX_PHY_INF; i++)
    3554          27 :             if (nh->nh_encap_valid[i])
    3555          15 :                 dev = true;
    3556             :     } else {
    3557          45 :         if (nh->nh_dev)
    3558          44 :             dev = true;
    3559             :     }
    3560             : 
    3561          54 :     if (nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
    3562           6 :         if (dev) {
    3563           6 :             nh->nh_reach_nh = nh_gre_tunnel;
    3564             :         }
    3565          48 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP) {
    3566           1 :         nh->nh_reach_nh = nh_udp_tunnel;
    3567          47 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
    3568          40 :         if (dev) {
    3569          39 :             nh->nh_reach_nh = nh_mpls_udp_tunnel;
    3570             :         }
    3571           7 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) {
    3572           7 :         if (dev) {
    3573           7 :             nh->nh_reach_nh = nh_vxlan_tunnel;
    3574             :         }
    3575           0 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
    3576           0 :         nh->nh_reach_nh = nh_pbb_tunnel;
    3577             :     }
    3578             : 
    3579          54 :     return;
    3580             : }
    3581             : 
    3582             : static int
    3583          54 : nh_tunnel_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3584             : {
    3585          54 :     int i, ret = 0;
    3586          54 :     struct vr_interface *vif[VR_MAX_PHY_INF]     = {NULL};
    3587          54 :     struct vr_interface *old_vif[VR_MAX_PHY_INF] = {NULL};
    3588          54 :     struct vr_interface *crypt_vif = NULL, *old_crypt_vif = NULL;
    3589             : 
    3590          54 :     if (req->nhr_family == AF_INET6) {
    3591           0 :         if (!req->nhr_tun_sip6 || !req->nhr_tun_dip6) {
    3592           0 :             ret = -EINVAL;
    3593           0 :             goto exit_add;
    3594             :         }
    3595          54 :     } else if (req->nhr_family == AF_INET) {
    3596          54 :         if (!req->nhr_tun_sip || !req->nhr_tun_dip) {
    3597           0 :             ret = -EINVAL;
    3598           0 :             goto exit_add;
    3599             :         }
    3600             :     }
    3601             : 
    3602         216 :     for (i = 0; i < VR_MAX_PHY_INF; i++)
    3603         162 :         old_vif[i] = nh->nh_dev_arr[i];
    3604             : 
    3605             :     /* Reset the nh valid underlay vif count on every add or update*/
    3606          54 :     nh->nh_valid_underlay_dev_count = 0;
    3607             : 
    3608          54 :     if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    3609          36 :         for (i = 0; i < VR_MAX_PHY_INF; i++) {
    3610          27 :             nh->nh_valid_underlay_dev[i] = NULL;
    3611          27 :             nh->nh_encap_valid[i] = req->nhr_encap_valid[i];
    3612          27 :             if (nh->nh_encap_valid[i]) {
    3613          30 :                 vif[i] = vrouter_get_interface(nh->nh_rid,
    3614          15 :                                 req->nhr_encap_oif_id[i]);
    3615          15 :                 nh->nh_valid_underlay_dev[nh->nh_valid_underlay_dev_count]
    3616          15 :                     = vif[i];
    3617          15 :                 nh->nh_valid_underlay_dev_count += 1;
    3618             :             } else
    3619          12 :                 vif[i] = NULL;
    3620             :         }
    3621             :     } else {
    3622          45 :         vif[0] = vrouter_get_interface(nh->nh_rid, req->nhr_encap_oif_id[0]);
    3623             :     }
    3624             : 
    3625          54 :     old_crypt_vif = nh->nh_crypt_dev;
    3626          54 :     crypt_vif = vrouter_get_interface(nh->nh_rid, req->nhr_encap_crypt_oif_id);
    3627          54 :     nh->nh_crypt_dev = crypt_vif;
    3628          54 :     if (old_crypt_vif) {
    3629           2 :         vrouter_put_interface(old_crypt_vif);
    3630             :     }
    3631             : 
    3632          54 :     if (nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
    3633           6 :         if (!(vif[0] || vif[1] || vif[2])) {
    3634           0 :             ret = -ENODEV;
    3635           0 :             goto exit_add;
    3636             :         }
    3637             : 
    3638           6 :         nh->nh_gre_tun_sip = req->nhr_tun_sip;
    3639           6 :         nh->nh_gre_tun_dip = req->nhr_tun_dip;
    3640           6 :         nh->nh_validate_src = nh_gre_tunnel_validate_src;
    3641           6 :         if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    3642           2 :             nh->nh_gre_tun_encap_len = req->nhr_encap_len;
    3643           8 :             for (i = 0; i < VR_MAX_PHY_INF; i++) {
    3644           6 :                 if (nh->nh_encap_valid[i])
    3645           6 :                     nh->nh_dev_arr[i] = vif[i];
    3646             :                 else
    3647           0 :                     nh->nh_dev_arr[i] = NULL;
    3648             :             }
    3649             :         } else {
    3650           4 :             nh->nh_gre_tun_encap_len = req->nhr_encap_size;
    3651           4 :             nh->nh_dev = vif[0];
    3652             :         }
    3653             : 
    3654           6 :         if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    3655           0 :             nh->nh_gre_tun_label = req->nhr_transport_label;
    3656             :         }
    3657          48 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP) {
    3658           1 :         if (req->nhr_family == AF_INET) {
    3659           1 :             nh->nh_udp_tun_sip = req->nhr_tun_sip;
    3660           1 :             nh->nh_udp_tun_dip = req->nhr_tun_dip;
    3661           1 :             nh->nh_udp_tun_sport = req->nhr_tun_sport;
    3662           1 :             nh->nh_udp_tun_dport = req->nhr_tun_dport;
    3663           1 :             nh->nh_udp_tun_encap_len = req->nhr_encap_size;
    3664           0 :         } else if (req->nhr_family == AF_INET6) {
    3665           0 :             if (!nh->nh_udp_tun6_sip) {
    3666           0 :                 nh->nh_udp_tun6_sip = vr_malloc(VR_IP6_ADDRESS_LEN,
    3667             :                         VR_NETWORK_ADDRESS_OBJECT);
    3668           0 :                 if (!nh->nh_udp_tun6_sip) {
    3669           0 :                     ret = -ENOMEM;
    3670           0 :                     goto exit_error;
    3671             :                 }
    3672             :             }
    3673           0 :             memcpy(nh->nh_udp_tun6_sip, req->nhr_tun_sip6, VR_IP6_ADDRESS_LEN);
    3674             : 
    3675           0 :             if (!nh->nh_udp_tun6_dip) {
    3676           0 :                 nh->nh_udp_tun6_dip = vr_malloc(VR_IP6_ADDRESS_LEN,
    3677             :                         VR_NETWORK_ADDRESS_OBJECT);
    3678           0 :                 if (!nh->nh_udp_tun6_dip) {
    3679           0 :                     ret = -ENOMEM;
    3680           0 :                     goto exit_error;
    3681             :                 }
    3682             :             }
    3683           0 :             memcpy(nh->nh_udp_tun6_dip, req->nhr_tun_dip6,
    3684             :                     VR_IP6_ADDRESS_LEN);
    3685           0 :             nh->nh_udp_tun6_sport = req->nhr_tun_sport;
    3686           0 :             nh->nh_udp_tun6_dport = req->nhr_tun_dport;
    3687           0 :             nh->nh_udp_tun6_encap_len = req->nhr_encap_size;
    3688             :         } else {
    3689           0 :             ret = -EINVAL;
    3690           0 :             goto exit_error;
    3691             :         }
    3692             :         /* VIFs should be null, but lets clean if one is found */
    3693           4 :         for (i = 0; i < VR_MAX_PHY_INF; i++) {
    3694           3 :             if (vif[i])
    3695           1 :                 vrouter_put_interface(vif[i]);
    3696             :         }
    3697          47 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
    3698          40 :         if (!(vif[0] || vif[1] || vif[2])) {
    3699           1 :             ret = -ENODEV;
    3700           1 :             goto exit_add;
    3701             :         }
    3702             : 
    3703          39 :         nh->nh_udp_tun_sip = req->nhr_tun_sip;
    3704          39 :         nh->nh_udp_tun_dip = req->nhr_tun_dip;
    3705          39 :         nh->nh_validate_src = nh_mpls_udp_tunnel_validate_src;
    3706          39 :         if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    3707           5 :             nh->nh_udp_tun_encap_len = req->nhr_encap_len;
    3708          20 :             for (i = 0; i < VR_MAX_PHY_INF; i++) {
    3709          15 :                 if (nh->nh_encap_valid[i])
    3710           7 :                     nh->nh_dev_arr[i] = vif[i];
    3711             :                 else
    3712           8 :                     nh->nh_dev_arr[i] = NULL;
    3713             :             }
    3714             :         } else {
    3715          34 :             nh->nh_udp_tun_encap_len = req->nhr_encap_size;
    3716          34 :             nh->nh_dev = vif[0];
    3717             :         }
    3718             : 
    3719          39 :         if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    3720           0 :             nh->nh_udp_tun_label = req->nhr_transport_label;
    3721             :         }
    3722           7 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) {
    3723           7 :         if (!(vif[0] || vif[1] || vif[2])) {
    3724           0 :             ret = -ENODEV;
    3725           0 :             goto exit_add;
    3726             :         }
    3727             : 
    3728           7 :         nh->nh_vxlan_tun_sip = req->nhr_tun_sip;
    3729           7 :         nh->nh_vxlan_tun_dip = req->nhr_tun_dip;
    3730           7 :         nh->nh_validate_src = nh_vxlan_tunnel_validate_src;
    3731           7 :         if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    3732           1 :             nh->nh_vxlan_tun_encap_len = req->nhr_encap_len;
    3733           4 :             for (i = 0; i < VR_MAX_PHY_INF; i++) {
    3734           3 :                 if (nh->nh_encap_valid[i])
    3735           2 :                     nh->nh_dev_arr[i] = vif[i];
    3736             :                 else
    3737           1 :                     nh->nh_dev_arr[i] = NULL;
    3738             :             }
    3739             :         } else {
    3740           6 :             nh->nh_udp_tun_encap_len = req->nhr_encap_size;
    3741           6 :             nh->nh_dev = vif[0];
    3742             :         }
    3743             : 
    3744           7 :         if (nh->nh_flags & NH_FLAG_L3_VXLAN) {
    3745           0 :             if ((req->nhr_rw_dst_mac_size != VR_ETHER_ALEN) ||
    3746           0 :                     (IS_MAC_ZERO(req->nhr_rw_dst_mac))) {
    3747           0 :                 ret = -EINVAL;
    3748           0 :                 goto exit_add;
    3749             :             }
    3750           0 :             VR_MAC_COPY(nh->nh_vxlan_tun_l3_mac, req->nhr_rw_dst_mac);
    3751             :         }
    3752           0 :     } else if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
    3753           0 :         if (!(nh->nh_flags & NH_FLAG_INDIRECT)) {
    3754           0 :             ret = -EINVAL;
    3755           0 :             goto exit_add;
    3756             :         }
    3757             : 
    3758           0 :         if ((req->nhr_pbb_mac_size != VR_ETHER_ALEN) ||
    3759           0 :                 (IS_MAC_ZERO(req->nhr_pbb_mac))) {
    3760           0 :             ret = -EINVAL;
    3761           0 :             goto exit_add;
    3762             :         }
    3763             : 
    3764           0 :         nh->nh_pbb_label = -1;
    3765           0 :         if (req->nhr_label_list_size)
    3766           0 :             nh->nh_pbb_label = req->nhr_label_list[0];
    3767             : 
    3768           0 :         VR_MAC_COPY(nh->nh_pbb_mac, req->nhr_pbb_mac);
    3769           0 :         nh->nh_validate_src = nh_pbb_tunnel_validate_src;
    3770           0 :         for (i = 0; i < VR_MAX_PHY_INF; i++) {
    3771           0 :             if (vif[i])
    3772           0 :                 vrouter_put_interface(vif[i]);
    3773             :         }
    3774             :     } else {
    3775             :         /* Reference to VIf should be cleaned */
    3776           0 :         for (i = 0; i < VR_MAX_PHY_INF; i++)
    3777           0 :             if (vif[i])
    3778           0 :                 vrouter_put_interface(vif[i]);
    3779           0 :         if (crypt_vif)
    3780           0 :             vrouter_put_interface(crypt_vif);
    3781             : 
    3782           0 :         return -EINVAL;
    3783             :     }
    3784             : 
    3785          53 :     memcpy(nh->nh_data, req->nhr_encap, req->nhr_encap_size);
    3786         212 :     for (i =0; i < VR_MAX_PHY_INF; i++) {
    3787         159 :         if (old_vif[i])
    3788           4 :             vrouter_put_interface(old_vif[i]);
    3789             :     }
    3790             : 
    3791          53 : exit_add:
    3792          54 :     nh_tunnel_set_reach_nh(nh);
    3793             : 
    3794          54 : exit_error:
    3795          54 :     return ret;
    3796             : }
    3797             : 
    3798             : static int
    3799           0 : nh_indirect_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3800             : {
    3801           0 :     struct vr_nexthop *old_nh, *direct_nh = NULL;
    3802             : 
    3803             :     /*
    3804             :      * Following check needs to be enahnced every time we make a new
    3805             :      * indirect nexthop
    3806             :      */
    3807           0 :     if ((nh->nh_type != NH_TUNNEL) ||
    3808           0 :             (!(nh->nh_flags & NH_FLAG_TUNNEL_PBB)))
    3809           0 :         return -EINVAL;
    3810             : 
    3811             :     /*
    3812             :      * Lets allow without direct nh for greater convenience of adds,
    3813             :      * changes, but only one direct nh
    3814             :      */
    3815           0 :     if ((unsigned int)req->nhr_nh_list_size > 1)
    3816           0 :         return -EINVAL;
    3817             : 
    3818           0 :     if (req->nhr_nh_list_size) {
    3819           0 :         direct_nh = vrouter_get_nexthop(req->nhr_rid, req->nhr_nh_list[0]);
    3820           0 :         if (!direct_nh)
    3821           0 :             return -EINVAL;
    3822             :     }
    3823             : 
    3824             :     /* Remove the old nh */
    3825           0 :     old_nh = nh->nh_direct_nh;
    3826           0 :     nh->nh_direct_nh = direct_nh;
    3827           0 :     if (old_nh)
    3828           0 :         vrouter_put_nexthop(old_nh);
    3829             : 
    3830           0 :     return 0;
    3831             : }
    3832             : 
    3833             : static int
    3834         178 : nh_encap_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3835             : {
    3836         178 :     int ret = 0;
    3837             :     struct vr_interface *vif, *old_vif;
    3838             : 
    3839         178 :     old_vif = nh->nh_dev;
    3840             : 
    3841         178 :     if ((req->nhr_family != AF_INET) && (req->nhr_family != AF_BRIDGE)) {
    3842           0 :         ret = -EINVAL;
    3843           0 :         goto exit_add;
    3844             :     }
    3845             : 
    3846         178 :     if ((req->nhr_family == AF_BRIDGE) && (req->nhr_flags & NH_FLAG_MCAST)) {
    3847           0 :         ret = -EINVAL;
    3848           0 :         goto exit_add;
    3849             :     }
    3850             : 
    3851         178 :     if ((req->nhr_family == AF_INET) && !(req->nhr_flags & NH_FLAG_MCAST)) {
    3852         145 :         if (req->nhr_encap_size < VR_ETHER_ALEN) {
    3853           0 :             ret = -EINVAL;
    3854           0 :             goto exit_add;
    3855             :         }
    3856             :     }
    3857             : 
    3858         178 :     vif = vrouter_get_interface(nh->nh_rid, req->nhr_encap_oif_id[0]);
    3859         178 :     if (!vif) {
    3860           0 :         ret = -EINVAL;
    3861           0 :         goto exit_add;
    3862             :     }
    3863             : 
    3864         178 :     nh->nh_encap_family = req->nhr_encap_family;
    3865         178 :     nh->nh_encap_len = req->nhr_encap_size;
    3866         178 :     if (nh->nh_encap_len) {
    3867         177 :         memcpy(nh->nh_data, req->nhr_encap, nh->nh_encap_len);
    3868             :     }
    3869             : 
    3870         178 :     nh->nh_dev = vif;
    3871         178 :     if (old_vif)
    3872          10 :         vrouter_put_interface(old_vif);
    3873             : 
    3874         168 : exit_add:
    3875         178 :     if (nh->nh_dev) {
    3876         178 :         nh->nh_validate_src = nh_encap_validate_src;
    3877         178 :         if (req->nhr_family == AF_BRIDGE) {
    3878          33 :             nh->nh_reach_nh = nh_encap_l2;
    3879         145 :         } else if (nh->nh_flags & NH_FLAG_MCAST) {
    3880           0 :             nh->nh_reach_nh = nh_encap_l3_mcast;
    3881             :         } else {
    3882         145 :             nh->nh_reach_nh = nh_encap_l3;
    3883             :         }
    3884             :     }
    3885             : 
    3886         178 :     return ret;
    3887             : }
    3888             : 
    3889             : static int
    3890           0 : nh_discard_add(struct vr_nexthop *nh, vr_nexthop_req *req)
    3891             : {
    3892           0 :     nh->nh_family = req->nhr_family;
    3893           0 :     nh->nh_type = NH_DISCARD;
    3894           0 :     nh->nh_router = vrouter_get(0);
    3895           0 :     nh->nh_reach_nh = nh_discard;
    3896           0 :     return 0;
    3897             : }
    3898             : 
    3899             : static bool
    3900         277 : vr_nexthop_valid_request(vr_nexthop_req *req)
    3901             : {
    3902         277 :     struct vrouter *router = vrouter_get(req->nhr_rid);
    3903             : 
    3904         277 :     if (!router)
    3905           0 :         return false;
    3906             : 
    3907         277 :     if ((unsigned int)req->nhr_id >= router->vr_max_nexthops)
    3908           0 :         return false;
    3909             : 
    3910         277 :     if ((unsigned int)req->nhr_type >= NH_MAX)
    3911           0 :         return false;
    3912             : 
    3913         277 :     return true;
    3914             : }
    3915             : 
    3916             : static int
    3917         265 : vr_nexthop_size(vr_nexthop_req *req)
    3918             : {
    3919         265 :     unsigned int size = sizeof(struct vr_nexthop);
    3920             : 
    3921         265 :     if ((req->nhr_type == NH_ENCAP) || (req->nhr_type == NH_TUNNEL))
    3922         220 :         if (req->nhr_encap)
    3923         220 :             size += req->nhr_encap_size;
    3924             : 
    3925         265 :     return size;
    3926             : }
    3927             : 
    3928             : static bool
    3929          12 : vr_nexthop_valid_change(vr_nexthop_req *req, struct vr_nexthop *nh)
    3930             : {
    3931             : 
    3932          12 :     if (!(req->nhr_flags & NH_FLAG_VALID))
    3933           0 :         return true;
    3934             : 
    3935          12 :     if (req->nhr_type != nh->nh_type)
    3936           0 :         return false;
    3937             : 
    3938          12 :     if (req->nhr_encap_size &&
    3939          11 :             req->nhr_encap_size != nh->nh_data_size)
    3940           0 :         return false;
    3941             : 
    3942             :     /* Indirect to non-indirect and other way is not allowed */
    3943          12 :     if ((req->nhr_flags & NH_FLAG_INDIRECT) ^
    3944          12 :             (nh->nh_flags & NH_FLAG_INDIRECT))
    3945           0 :         return false;
    3946             : 
    3947          12 :     return true;
    3948             : }
    3949             : 
    3950             : 
    3951             : int
    3952         277 : vr_nexthop_add(vr_nexthop_req *req)
    3953             : {
    3954         277 :     int ret = 0, len = 0;
    3955         277 :     bool invalid_to_valid = false, change = false;
    3956             :     struct vr_nexthop *nh;
    3957         277 :     struct vrouter *router = vrouter_get(req->nhr_rid);
    3958             : 
    3959         277 :     if (!vr_nexthop_valid_request(req) && (ret = -EINVAL))
    3960           0 :         goto generate_resp;
    3961             : 
    3962         277 :     nh = __vrouter_get_nexthop(router, req->nhr_id);
    3963         277 :     if (!nh) {
    3964         265 :         len = vr_nexthop_size(req);
    3965         265 :         if (len < 0) {
    3966           0 :             ret = -EINVAL;
    3967           0 :             goto generate_resp;
    3968             :         }
    3969             : 
    3970         265 :         nh = vr_zalloc(len, VR_NEXTHOP_OBJECT);
    3971         265 :         if (!nh) {
    3972           0 :             ret = -ENOMEM;
    3973           0 :             goto generate_resp;
    3974             :         }
    3975             : 
    3976         265 :         nh->nh_data_size = len - sizeof(struct vr_nexthop);
    3977             :     } else {
    3978          12 :         change = true;
    3979             :         /*
    3980             :          * If modification of old_nh change the action to discard and ensure
    3981             :          * everybody sees that
    3982             :          */
    3983          12 :         if (!vr_nexthop_valid_change(req, nh)) {
    3984           0 :             ret = -EINVAL;
    3985           0 :             goto generate_resp;
    3986             :         }
    3987             : 
    3988             :         /* Lets track if invalid to valid change */
    3989          12 :         if ((req->nhr_flags & NH_FLAG_VALID) &&
    3990          12 :                 !(nh->nh_flags & NH_FLAG_VALID))
    3991           0 :             invalid_to_valid = true;
    3992             : 
    3993             :         /* If valid to invalid lets propogate flags immediately */
    3994          12 :         if (!(req->nhr_flags & NH_FLAG_VALID) &&
    3995           0 :                 (nh->nh_flags & NH_FLAG_VALID))
    3996           0 :             nh->nh_flags = req->nhr_flags;
    3997             : 
    3998             :         /* For a change lets always point to discard */
    3999          12 :         nh->nh_reach_nh = nh_discard;
    4000          12 :         vr_delay_op();
    4001             :     }
    4002             : 
    4003         277 :     nh->nh_reach_nh = nh_discard;
    4004         277 :     nh->nh_destructor = nh_del;
    4005         277 :     nh->nh_type = req->nhr_type;
    4006         277 :     nh->nh_family = req->nhr_family;
    4007         277 :     nh->nh_id = req->nhr_id;
    4008         277 :     nh->nh_rid = req->nhr_rid;
    4009         277 :     nh->nh_router = vrouter_get(nh->nh_rid);
    4010         277 :     nh->nh_vrf = req->nhr_vrf;
    4011         277 :     nh->nh_direct_nh = NULL;
    4012             : 
    4013             :     /*
    4014             :      * If invalid to valid, lets make it valid after the whole nexthop
    4015             :      * is cookedup. For invalid to invalid, valid to valid, lets
    4016             :      * copy the flags as is
    4017             :      */
    4018         277 :     if (invalid_to_valid)
    4019           0 :         nh->nh_flags = (req->nhr_flags & ~NH_FLAG_VALID);
    4020             :     else
    4021         277 :         nh->nh_flags = req->nhr_flags;
    4022             : 
    4023         277 :     if (req->nhr_flags & NH_FLAG_VALID) {
    4024         277 :         if (nh->nh_flags & NH_FLAG_INDIRECT) {
    4025           0 :             ret = nh_indirect_add(nh, req);
    4026           0 :             if (ret)
    4027           0 :                 goto error;
    4028             :         }
    4029         277 :         switch (nh->nh_type) {
    4030         178 :         case NH_ENCAP:
    4031         178 :             ret = nh_encap_add(nh, req);
    4032         178 :             break;
    4033             : 
    4034          54 :         case NH_TUNNEL:
    4035          54 :             ret = nh_tunnel_add(nh, req);
    4036          54 :             break;
    4037             : 
    4038          23 :         case NH_RCV:
    4039          23 :             ret = nh_rcv_add(nh, req);
    4040          23 :             break;
    4041             : 
    4042          16 :         case NH_L2_RCV:
    4043          16 :             ret = nh_l2_rcv_add(nh, req);
    4044          16 :             break;
    4045             : 
    4046           0 :         case NH_RESOLVE:
    4047           0 :             ret = nh_resolve_add(nh, req);
    4048           0 :             break;
    4049             : 
    4050           0 :         case NH_DISCARD:
    4051           0 :             ret = nh_discard_add(nh, req);
    4052           0 :             break;
    4053             : 
    4054           5 :         case NH_COMPOSITE:
    4055           5 :             ret = nh_composite_add(nh, req);
    4056           5 :             break;
    4057             : 
    4058           1 :         case NH_VRF_TRANSLATE:
    4059           1 :             ret = nh_vrf_translate_add(nh, req);
    4060           1 :             break;
    4061             : 
    4062           0 :         default:
    4063           0 :             ret = -EINVAL;
    4064             :         }
    4065             : 
    4066             :     }
    4067             : 
    4068           0 : error:
    4069         277 :     if (ret) {
    4070           1 :         if (!change) {
    4071           1 :             if (nh->nh_destructor) {
    4072           1 :                 nh->nh_destructor(nh);
    4073             :             }
    4074             :         }
    4075             : 
    4076           1 :         goto generate_resp;
    4077             :     }
    4078             : 
    4079             :     /* Mark he nexthop valid after whole nexthop is cooked incase of
    4080             :      * invalid to valid transition
    4081             :      */
    4082         276 :     if (invalid_to_valid)
    4083           0 :         nh->nh_flags |= NH_FLAG_VALID;
    4084             : 
    4085         276 :     ret = vrouter_add_nexthop(nh);
    4086             : 
    4087         276 :     if (ret) {
    4088           0 :         nh->nh_destructor(nh);
    4089           0 :         goto generate_resp;
    4090             :     }
    4091             :     else /* notify hw offload of change, if enabled */
    4092         276 :         ret = vr_offload_nexthop_add(nh);
    4093             : 
    4094             :     /* if offload failed, delete kernel entry for consistency */
    4095         276 :     if (ret)
    4096           0 :         nh->nh_destructor(nh);
    4097             : 
    4098         276 : generate_resp:
    4099         277 :     ret = vr_send_response(ret);
    4100             : 
    4101         277 :     return ret;
    4102             : }
    4103             : 
    4104             : unsigned int
    4105          25 : vr_nexthop_req_get_size(void *req_p)
    4106             : {
    4107          25 :     int size = 4 * sizeof(vr_nexthop_req);
    4108          25 :     vr_nexthop_req *req = (vr_nexthop_req *)req_p;
    4109             : 
    4110          25 :     size += req->nhr_encap_size;
    4111             : 
    4112          25 :     if (req->nhr_nh_list_size)
    4113           0 :         size += (4 * req->nhr_nh_list_size);
    4114             : 
    4115          25 :     if (req->nhr_label_list_size)
    4116           0 :         size += (4 * req->nhr_label_list_size);
    4117             : 
    4118          25 :     if (req->nhr_encap_oif_id_size)
    4119          25 :         size += (4 * req->nhr_encap_oif_id_size);
    4120             : 
    4121          25 :     if (req->nhr_encap_valid_size)
    4122           4 :         size += (4 * req->nhr_encap_valid_size);
    4123             : 
    4124          25 :     size += req->nhr_pbb_mac_size;
    4125             : 
    4126          25 :     if ((req->nhr_type == NH_TUNNEL) &&
    4127           5 :             (req->nhr_flags & NH_FLAG_TUNNEL_UDP) &&
    4128           0 :             (req->nhr_family == AF_INET6))
    4129           0 :         size += (VR_IP6_ADDRESS_LEN * 2 * 4);
    4130             : 
    4131          25 :     return size;
    4132             : }
    4133             : 
    4134             : /* we expect the caller to bzero req, before sending it here */
    4135             : static int
    4136          25 : vr_nexthop_make_req(vr_nexthop_req *req, struct vr_nexthop *nh)
    4137             : {
    4138             :     unsigned int i;
    4139          25 :     unsigned char *encap = NULL;
    4140             :     struct vr_nexthop *cnh;
    4141             : 
    4142          25 :     bool dump = false;
    4143             : 
    4144          25 :     if (req->h_op == SANDESH_OP_DUMP)
    4145           0 :         dump = true;
    4146             : 
    4147          25 :     req->nhr_type = nh->nh_type;
    4148          25 :     req->nhr_family = nh->nh_family;
    4149          25 :     req->nhr_flags = nh->nh_flags;
    4150          25 :     req->nhr_id = nh->nh_id;
    4151          25 :     req->nhr_rid = nh->nh_rid;
    4152          25 :     req->nhr_ref_cnt = nh->nh_users;
    4153          25 :     req->nhr_nh_list_size = 0;
    4154          25 :     req->nhr_vrf = nh->nh_vrf;
    4155             : 
    4156          25 :     if ((nh->nh_flags & NH_FLAG_INDIRECT) && (cnh = nh->nh_direct_nh)) {
    4157           0 :         req->nhr_nh_list_size = 1;
    4158           0 :         req->nhr_nh_list =
    4159           0 :                 vr_zalloc(req->nhr_nh_list_size * sizeof(unsigned int),
    4160             :                         VR_NEXTHOP_REQ_LIST_OBJECT);
    4161           0 :         if (!req->nhr_nh_list)
    4162           0 :             return -ENOMEM;
    4163           0 :         req->nhr_nh_list[0] = cnh->nh_id;
    4164             :     }
    4165             : 
    4166          25 :     switch (nh->nh_type) {
    4167           0 :     case NH_RCV:
    4168           0 :         if (nh->nh_dev)
    4169           0 :            req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4170           0 :         break;
    4171             : 
    4172           0 :     case NH_L2_RCV:
    4173           0 :         if (nh->nh_dev)
    4174           0 :            req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4175           0 :         break;
    4176             : 
    4177          12 :     case NH_ENCAP:
    4178          12 :         if (nh->nh_dev)
    4179          12 :             req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4180          12 :         req->nhr_encap_size = nh->nh_encap_len;
    4181          12 :         req->nhr_encap_family = nh->nh_encap_family;
    4182          12 :         if (req->nhr_encap_size)
    4183          11 :             encap = nh->nh_data;
    4184          12 :         break;
    4185             : 
    4186           0 :     case NH_COMPOSITE:
    4187           0 :         req->nhr_nh_list_size = req->nhr_nh_count =  nh->nh_component_cnt;
    4188           0 :         if (dump && (req->nhr_nh_list_size > VR_NEXTHOP_COMPONENT_DUMP_LIMIT))
    4189           0 :             req->nhr_nh_list_size = VR_NEXTHOP_COMPONENT_DUMP_LIMIT;
    4190           0 :         req->nhr_ecmp_config_hash = nh->nh_ecmp_config_hash &
    4191             :                                          NH_ECMP_CONFIG_HASH_MASK;
    4192             : 
    4193           0 :         if (nh->nh_component_cnt) {
    4194           0 :             req->nhr_nh_list =
    4195           0 :                 vr_zalloc(req->nhr_nh_list_size * sizeof(unsigned int),
    4196             :                         VR_NEXTHOP_REQ_LIST_OBJECT);
    4197           0 :             if (!req->nhr_nh_list)
    4198           0 :                 return -ENOMEM;
    4199             : 
    4200           0 :             req->nhr_label_list_size = req->nhr_nh_list_size;
    4201           0 :             req->nhr_label_list =
    4202           0 :                 vr_zalloc(req->nhr_label_list_size * sizeof(unsigned int),
    4203             :                         VR_NEXTHOP_REQ_LIST_OBJECT);
    4204             :             /* don't bother about freeing. we will free it in req_destroy */
    4205           0 :             if (!req->nhr_label_list)
    4206           0 :                 return -ENOMEM;
    4207             : 
    4208           0 :             for (i = 0; i < req->nhr_nh_list_size; i++) {
    4209           0 :                 if (nh->nh_component_nh[i].cnh)
    4210           0 :                     req->nhr_nh_list[i] = nh->nh_component_nh[i].cnh->nh_id;
    4211             :                 else
    4212           0 :                     req->nhr_nh_list[i] = -1;
    4213             : 
    4214           0 :                 req->nhr_label_list[i] = nh->nh_component_nh[i].cnh_label;
    4215             :             }
    4216             :         }
    4217             : 
    4218           0 :         break;
    4219             : 
    4220           5 :     case NH_TUNNEL:
    4221           5 :         if (nh->nh_crypt_dev)
    4222           4 :             req->nhr_encap_crypt_oif_id = nh->nh_crypt_dev->vif_idx;
    4223           5 :         req->nhr_encap_family = nh->nh_encap_family;
    4224           5 :         if (nh->nh_flags & NH_FLAG_TUNNEL_GRE) {
    4225           0 :             req->nhr_tun_sip = nh->nh_gre_tun_sip;
    4226           0 :             req->nhr_tun_dip = nh->nh_gre_tun_dip;
    4227           0 :             req->nhr_encap_size = nh->nh_data_size;
    4228           0 :             if (req->nhr_encap_size)
    4229           0 :                 encap = nh->nh_data;
    4230           0 :             if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    4231           0 :                 for (i = 0; i < VR_MAX_PHY_INF; i++) {
    4232           0 :                     req->nhr_encap_valid[i] = nh->nh_encap_valid[i];
    4233           0 :                     if (nh->nh_encap_valid[i])
    4234           0 :                         req->nhr_encap_oif_id[i] = nh->nh_dev_arr[i]->vif_idx;
    4235             :                     else
    4236           0 :                         req->nhr_encap_oif_id[i] = -1;
    4237             :                 }
    4238             :             }
    4239             :             else {
    4240           0 :                 if (nh->nh_dev) {
    4241           0 :                     req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4242             :                 }
    4243             :             }
    4244           0 :             if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    4245           0 :                 req->nhr_transport_label = nh->nh_gre_tun_label;
    4246             :             }
    4247           5 :         } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP) {
    4248           0 :             if (nh->nh_family == AF_INET) {
    4249           0 :                 req->nhr_tun_sip = nh->nh_udp_tun_sip;
    4250           0 :                 req->nhr_tun_dip = nh->nh_udp_tun_dip;
    4251           0 :                 req->nhr_encap_size = nh->nh_udp_tun_encap_len;
    4252           0 :                 req->nhr_tun_sport = nh->nh_udp_tun_sport;
    4253           0 :                 req->nhr_tun_dport = nh->nh_udp_tun_dport;
    4254           0 :             } else if (nh->nh_family == AF_INET6) {
    4255           0 :                 if (req->nhr_tun_sip6_size && req->nhr_tun_sip6)
    4256           0 :                     memcpy(req->nhr_tun_sip6, nh->nh_udp_tun6_sip,
    4257             :                             VR_IP6_ADDRESS_LEN);
    4258           0 :                 if (req->nhr_tun_dip6_size && req->nhr_tun_dip6)
    4259           0 :                     memcpy(req->nhr_tun_dip6, nh->nh_udp_tun6_dip,
    4260             :                             VR_IP6_ADDRESS_LEN);
    4261           0 :                 req->nhr_encap_size = nh->nh_udp_tun6_encap_len;
    4262           0 :                 req->nhr_tun_sport = nh->nh_udp_tun6_sport;
    4263           0 :                 req->nhr_tun_dport = nh->nh_udp_tun6_dport;
    4264             :             }
    4265             : 
    4266           0 :             if (req->nhr_encap_size)
    4267           0 :                 encap = nh->nh_data;
    4268           0 :             if (nh->nh_dev) {
    4269           0 :                 req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4270             :             }
    4271           5 :         } else if (nh->nh_flags & NH_FLAG_TUNNEL_UDP_MPLS) {
    4272           4 :             req->nhr_tun_sip = nh->nh_udp_tun_sip;
    4273           4 :             req->nhr_tun_dip = nh->nh_udp_tun_dip;
    4274           4 :             req->nhr_encap_size = nh->nh_data_size;
    4275           4 :             if (req->nhr_encap_size)
    4276           4 :                 encap = nh->nh_data;
    4277           4 :             if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    4278          16 :                 for (i = 0; i < VR_MAX_PHY_INF; i++) {
    4279          12 :                     req->nhr_encap_valid[i] = nh->nh_encap_valid[i];
    4280          12 :                     if (nh->nh_encap_valid[i])
    4281           6 :                         req->nhr_encap_oif_id[i] = nh->nh_dev_arr[i]->vif_idx;
    4282             :                     else
    4283           6 :                         req->nhr_encap_oif_id[i] = -1;
    4284             :                 }
    4285             :             }
    4286             :             else {
    4287           0 :                 if (nh->nh_dev) {
    4288           0 :                     req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4289             :                 }
    4290             :             }
    4291           4 :             if (nh->nh_flags & NH_FLAG_TUNNEL_MPLS_O_MPLS) {
    4292           0 :                 req->nhr_transport_label = nh->nh_udp_tun_label;
    4293             :             }
    4294           1 :         } else if (nh->nh_flags & NH_FLAG_TUNNEL_VXLAN) {
    4295           1 :             req->nhr_tun_sip = nh->nh_vxlan_tun_sip;
    4296           1 :             req->nhr_tun_dip = nh->nh_vxlan_tun_dip;
    4297           1 :             req->nhr_encap_size = nh->nh_data_size;
    4298           1 :             if (req->nhr_encap_size)
    4299           1 :                 encap = nh->nh_data;
    4300           1 :             if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    4301           0 :                 for (i = 0; i < VR_MAX_PHY_INF; i++) {
    4302           0 :                     req->nhr_encap_valid[i] = nh->nh_encap_valid[i];
    4303           0 :                     if (nh->nh_encap_valid[i])
    4304           0 :                         req->nhr_encap_oif_id[i] = nh->nh_dev_arr[i]->vif_idx;
    4305             :                     else
    4306           0 :                         req->nhr_encap_oif_id[i] = -1;
    4307             :                 }
    4308             :             }
    4309             :             else {
    4310           1 :                 if (nh->nh_dev) {
    4311           1 :                     req->nhr_encap_oif_id[0] = nh->nh_dev->vif_idx;
    4312             :                 }
    4313             :             }
    4314           1 :             if (nh->nh_flags & NH_FLAG_L3_VXLAN) {
    4315           0 :                 req->nhr_rw_dst_mac_size = VR_ETHER_ALEN;
    4316           0 :                 req->nhr_rw_dst_mac = vr_zalloc(req->nhr_rw_dst_mac_size,
    4317             :                         VR_NEXTHOP_REQ_BMAC_OBJECT);
    4318           0 :                 if (!req->nhr_rw_dst_mac)
    4319           0 :                     return -ENOMEM;
    4320           0 :                 VR_MAC_COPY(req->nhr_rw_dst_mac, nh->nh_vxlan_tun_l3_mac);
    4321             :             }
    4322           0 :         } else if (nh->nh_flags & NH_FLAG_TUNNEL_PBB) {
    4323           0 :             if (nh->nh_pbb_label != -1) {
    4324           0 :                 req->nhr_label_list_size = 1;
    4325           0 :                 req->nhr_label_list =
    4326           0 :                     vr_zalloc(req->nhr_nh_list_size * sizeof(unsigned int),
    4327             :                                     VR_NEXTHOP_REQ_LIST_OBJECT);
    4328           0 :                 if (!req->nhr_label_list)
    4329           0 :                     return -ENOMEM;
    4330           0 :                 req->nhr_label_list[0] = nh->nh_pbb_label;
    4331             :             }
    4332             : 
    4333           0 :             req->nhr_pbb_mac_size = VR_ETHER_ALEN;
    4334           0 :             req->nhr_pbb_mac = vr_zalloc(req->nhr_pbb_mac_size,
    4335             :                     VR_NEXTHOP_REQ_BMAC_OBJECT);
    4336           0 :             if (!req->nhr_pbb_mac)
    4337           0 :                 return -ENOMEM;
    4338           0 :             VR_MAC_COPY(req->nhr_pbb_mac, nh->nh_pbb_mac);
    4339             :         }
    4340             : 
    4341           5 :         break;
    4342             :     }
    4343             : 
    4344          25 :     if (req->nhr_encap_size) {
    4345          16 :         req->nhr_encap_len = VR_ETHER_HLEN;
    4346          16 :         req->nhr_encap = vr_zalloc(req->nhr_encap_size,
    4347             :                 VR_NEXTHOP_REQ_ENCAP_OBJECT);
    4348          16 :         if (req->nhr_encap) {
    4349          16 :             memcpy(req->nhr_encap, encap,
    4350          16 :                     req->nhr_encap_size);
    4351             :         } else {
    4352           0 :             req->nhr_encap_size = 0;
    4353           0 :             req->nhr_encap_len = 0;
    4354           0 :             return -ENOMEM;
    4355             :         }
    4356             :     }
    4357             : 
    4358          25 :     return 0;
    4359             : }
    4360             : 
    4361             : static vr_nexthop_req *
    4362          25 : vr_nexthop_req_get(struct vr_nexthop *nh)
    4363             : {
    4364             :     vr_nexthop_req *nhr;
    4365             : 
    4366          25 :     nhr = vr_zalloc(sizeof(vr_nexthop_req), VR_NEXTHOP_REQ_OBJECT);
    4367          25 :     if (!nhr)
    4368           0 :         return NULL;
    4369             : 
    4370          25 :     if (nh->nh_flags & NH_FLAG_TUNNEL_UNDERLAY_ECMP) {
    4371           4 :         nhr->nhr_encap_oif_id_size = VR_MAX_PHY_INF;
    4372           4 :         nhr->nhr_encap_oif_id = vr_zalloc(nhr->nhr_encap_oif_id_size *
    4373             :                 sizeof(unsigned int), VR_NEXTHOP_REQ_LIST_OBJECT);
    4374           4 :         if (!nhr->nhr_encap_oif_id)
    4375           0 :             goto fail;
    4376             : 
    4377           4 :         nhr->nhr_encap_valid_size = VR_MAX_PHY_INF;
    4378           4 :         nhr->nhr_encap_valid = vr_zalloc(nhr->nhr_encap_valid_size *
    4379             :                 sizeof(unsigned int), VR_NEXTHOP_REQ_LIST_OBJECT);
    4380           4 :         if (!nhr->nhr_encap_valid)
    4381           0 :             goto fail;
    4382             :     } else {
    4383          21 :         nhr->nhr_encap_oif_id_size = 1;
    4384          21 :         nhr->nhr_encap_oif_id = vr_zalloc(nhr->nhr_encap_oif_id_size *
    4385             :                 sizeof(unsigned int), VR_NEXTHOP_REQ_LIST_OBJECT);
    4386          21 :         if (!nhr->nhr_encap_oif_id)
    4387           0 :             goto fail;
    4388             : 
    4389          21 :         nhr->nhr_encap_valid_size = 0;
    4390          21 :         nhr->nhr_encap_valid = NULL;
    4391             :     }
    4392          25 :     if ((nh->nh_type == NH_TUNNEL) &&
    4393           5 :             (nh->nh_flags & NH_FLAG_TUNNEL_UDP) &&
    4394           0 :             (nh->nh_family == AF_INET6)) {
    4395           0 :         nhr->nhr_tun_sip6 = vr_malloc(VR_IP6_ADDRESS_LEN,
    4396             :                 VR_NETWORK_ADDRESS_OBJECT);
    4397           0 :         if (!nhr->nhr_tun_sip6)
    4398           0 :             goto fail;
    4399           0 :         nhr->nhr_tun_sip6_size = VR_IP6_ADDRESS_LEN;
    4400             : 
    4401           0 :         nhr->nhr_tun_dip6 = vr_malloc(VR_IP6_ADDRESS_LEN,
    4402             :                 VR_NETWORK_ADDRESS_OBJECT);
    4403           0 :         if (!nhr->nhr_tun_dip6)
    4404           0 :             goto fail;
    4405           0 :         nhr->nhr_tun_dip6_size = VR_IP6_ADDRESS_LEN;
    4406             :     }
    4407             : 
    4408          25 :     return nhr;
    4409             : 
    4410           0 : fail:
    4411           0 :     if (nhr->nhr_encap_oif_id) {
    4412           0 :         vr_free(nhr->nhr_encap_oif_id, nhr->nhr_encap_oif_id_size *
    4413             :                 sizeof(unsigned int));
    4414           0 :         nhr->nhr_encap_oif_id = NULL;
    4415             :     }
    4416             : 
    4417           0 :     if (nhr->nhr_encap_valid) {
    4418           0 :         vr_free(nhr->nhr_encap_valid, nhr->nhr_encap_valid_size *
    4419             :                 sizeof(unsigned int));
    4420           0 :         nhr->nhr_encap_valid = NULL;
    4421             :     }
    4422             : 
    4423           0 :     if (nhr->nhr_tun_sip6) {
    4424           0 :         vr_free(nhr->nhr_tun_sip6, VR_IP6_ADDRESS_LEN);
    4425           0 :         nhr->nhr_tun_sip6 = NULL;
    4426             :     }
    4427             : 
    4428           0 :     if (nhr->nhr_tun_dip6) {
    4429           0 :         vr_free(nhr->nhr_tun_dip6, VR_IP6_ADDRESS_LEN);
    4430           0 :         nhr->nhr_tun_dip6 = NULL;
    4431             :     }
    4432             : 
    4433           0 :     if (nhr) {
    4434           0 :         vr_free(nhr, VR_NEXTHOP_REQ_OBJECT);
    4435           0 :         nhr = NULL;
    4436             :     }
    4437             : 
    4438           0 :     return nhr;
    4439             : }
    4440             : 
    4441             : static void
    4442          25 : vr_nexthop_req_destroy(vr_nexthop_req *req)
    4443             : {
    4444          25 :     if (!req)
    4445           0 :         return;
    4446             : 
    4447          25 :     if (req->nhr_encap_size && req->nhr_encap) {
    4448          16 :         vr_free(req->nhr_encap, VR_NEXTHOP_REQ_ENCAP_OBJECT);
    4449          16 :         req->nhr_encap_size = 0;
    4450          16 :         req->nhr_encap = NULL;
    4451             :     }
    4452             : 
    4453          25 :     if (req->nhr_nh_list_size && req->nhr_nh_list) {
    4454           0 :         vr_free(req->nhr_nh_list, VR_NEXTHOP_REQ_LIST_OBJECT);
    4455           0 :         req->nhr_nh_list_size = 0;
    4456           0 :         req->nhr_nh_list = NULL;
    4457             :     }
    4458             : 
    4459          25 :     if (req->nhr_label_list_size && req->nhr_label_list) {
    4460           0 :         vr_free(req->nhr_label_list, VR_NEXTHOP_REQ_LIST_OBJECT);
    4461           0 :         req->nhr_label_list = NULL;
    4462           0 :         req->nhr_label_list_size = 0;
    4463             :     }
    4464             : 
    4465          25 :     if (req->nhr_tun_sip6) {
    4466           0 :         vr_free(req->nhr_tun_sip6, VR_NETWORK_ADDRESS_OBJECT);
    4467           0 :         req->nhr_tun_sip6 = NULL;
    4468             :     }
    4469             : 
    4470          25 :     if (req->nhr_tun_dip6) {
    4471           0 :         vr_free(req->nhr_tun_dip6, VR_NETWORK_ADDRESS_OBJECT);
    4472           0 :         req->nhr_tun_dip6 = NULL;
    4473             :     }
    4474             : 
    4475          25 :     if (req->nhr_pbb_mac) {
    4476           0 :         vr_free(req->nhr_pbb_mac, VR_NEXTHOP_REQ_BMAC_OBJECT);
    4477           0 :         req->nhr_pbb_mac = NULL;
    4478           0 :         req->nhr_pbb_mac_size = 0;
    4479             :     }
    4480             : 
    4481          25 :     if (req->nhr_encap_oif_id_size && req->nhr_encap_oif_id) {
    4482          25 :         vr_free(req->nhr_encap_oif_id, VR_NEXTHOP_REQ_LIST_OBJECT);
    4483          25 :         req->nhr_encap_oif_id = NULL;
    4484          25 :         req->nhr_encap_oif_id_size = 0;
    4485             :     }
    4486             : 
    4487          25 :     if (req->nhr_encap_valid_size && req->nhr_encap_valid) {
    4488           4 :         vr_free(req->nhr_encap_valid, VR_NEXTHOP_REQ_LIST_OBJECT);
    4489           4 :         req->nhr_encap_valid = NULL;
    4490           4 :         req->nhr_encap_valid_size = 0;
    4491             :     }
    4492             : 
    4493          25 :     vr_free(req, VR_NEXTHOP_REQ_OBJECT);
    4494          25 :     return;
    4495             : }
    4496             : 
    4497             : int
    4498          25 : vr_nexthop_get(vr_nexthop_req *req)
    4499             : {
    4500          25 :     int ret = 0;
    4501          25 :     struct vr_nexthop *nh = NULL;
    4502             :     struct vrouter *router;
    4503          25 :     vr_nexthop_req *resp = NULL;
    4504             : 
    4505          25 :     router = vrouter_get(req->nhr_rid);
    4506          25 :     if (!router || (unsigned int)req->nhr_id >= router->vr_max_nexthops) {
    4507           0 :         ret = -ENODEV;
    4508           0 :         goto generate_response;
    4509             :     }
    4510             : 
    4511          25 :     nh = __vrouter_get_nexthop(router, req->nhr_id);
    4512          25 :     if (nh) {
    4513          25 :         resp = vr_nexthop_req_get(nh);
    4514          25 :         if (!resp) {
    4515           0 :             ret = -ENOMEM;
    4516           0 :             goto generate_response;
    4517             :         }
    4518             : 
    4519          25 :         resp->h_op = SANDESH_OP_GET;
    4520          25 :         if (resp)
    4521          25 :             ret = vr_nexthop_make_req(resp, nh);
    4522             :         else
    4523           0 :             ret = -ENOMEM;
    4524             :     } else
    4525           0 :         ret = -ENOENT;
    4526             : 
    4527             :     /* Debug comparison to check if matching entry is programmed on NIC */
    4528          25 :     if (!ret)
    4529          25 :         vr_offload_nexthop_get(nh, resp);
    4530             : 
    4531           0 : generate_response:
    4532          25 :     vr_message_response(VR_NEXTHOP_OBJECT_ID, ret < 0 ? NULL : resp, ret, false);
    4533          25 :     if (resp)
    4534          25 :         vr_nexthop_req_destroy(resp);
    4535             : 
    4536          25 :     return 0;
    4537             : }
    4538             : 
    4539             : int
    4540           0 : vr_nexthop_dump(vr_nexthop_req *r)
    4541             : {
    4542           0 :     int ret = 0;
    4543             :     unsigned int i;
    4544           0 :     vr_nexthop_req *resp = NULL;
    4545           0 :     struct vr_message_dumper *dumper = NULL;
    4546             :     struct vr_nexthop *nh;
    4547           0 :     struct vrouter *router = vrouter_get(0);
    4548             : 
    4549           0 :     if (!router && (ret = -ENODEV))
    4550           0 :         goto generate_response;
    4551             : 
    4552           0 :     if ((unsigned int)(r->nhr_marker) + 1 >= router->vr_max_nexthops)
    4553           0 :         goto generate_response;
    4554             : 
    4555           0 :     dumper = vr_message_dump_init(r);
    4556           0 :     if (!dumper && (ret = -ENOMEM))
    4557           0 :         goto generate_response;
    4558             : 
    4559           0 :     for (i = (unsigned int)(r->nhr_marker + 1);
    4560           0 :             i < router->vr_max_nexthops; i++) {
    4561           0 :         nh = __vrouter_get_nexthop(router, i);
    4562           0 :         if (nh) {
    4563           0 :             resp = vr_nexthop_req_get(nh);
    4564           0 :             if (!resp && (ret = -ENOMEM))
    4565           0 :                 goto generate_response;
    4566             : 
    4567           0 :             resp->h_op = SANDESH_OP_DUMP;
    4568           0 :             ret = vr_nexthop_make_req(resp, nh);
    4569             : 
    4570           0 :             if (!ret)
    4571           0 :                 vr_offload_nexthop_get(nh, resp);
    4572             : 
    4573           0 :             if ((ret < 0) || ((ret = vr_message_dump_object(dumper,
    4574             :                                 VR_NEXTHOP_OBJECT_ID, resp)) <= 0)) {
    4575           0 :                 vr_nexthop_req_destroy(resp);
    4576           0 :                 break;
    4577             :             }
    4578             : 
    4579           0 :             vr_nexthop_req_destroy(resp);
    4580             :         }
    4581             :     }
    4582             : 
    4583           0 : generate_response:
    4584           0 :     vr_message_dump_exit(dumper, ret);
    4585           0 :     return 0;
    4586             : }
    4587             : 
    4588             : /*
    4589             :  * called by sandesh_process based on type of the request
    4590             :  */
    4591             : void
    4592         569 : vr_nexthop_req_process(void *s_req)
    4593             : {
    4594             :     int ret;
    4595         569 :     vr_nexthop_req *req = (vr_nexthop_req *)s_req;
    4596             : 
    4597         569 :     switch (req->h_op) {
    4598         277 :     case SANDESH_OP_ADD:
    4599         277 :         ret = vr_nexthop_add(req);
    4600         277 :         break;
    4601             : 
    4602          25 :     case SANDESH_OP_GET:
    4603          25 :         ret = vr_nexthop_get(req);
    4604          25 :         break;
    4605             : 
    4606         267 :     case SANDESH_OP_DEL:
    4607         267 :         ret = vr_nexthop_delete(req);
    4608         267 :         break;
    4609             : 
    4610           0 :     case SANDESH_OP_DUMP:
    4611           0 :         ret = vr_nexthop_dump(req);
    4612           0 :         break;
    4613             : 
    4614           0 :     default:
    4615           0 :         ret = -EOPNOTSUPP;
    4616           0 :         vr_send_response(ret);
    4617           0 :         break;
    4618             :     }
    4619         569 : }
    4620             : 
    4621             : int
    4622           8 : vr_is_local_ecmp_nh (struct vr_nexthop *nh)
    4623             : {
    4624             :     int i;
    4625             : 
    4626           8 :     if (!nh || (nh->nh_type != NH_COMPOSITE) ||
    4627           0 :        (!(nh->nh_flags & NH_FLAG_COMPOSITE_ECMP))) {
    4628           8 :         return 0;
    4629             :     }
    4630           0 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    4631           0 :          if (nh->nh_component_nh && nh->nh_component_nh[i].cnh &&
    4632           0 :                  nh->nh_component_nh[i].cnh->nh_type != NH_ENCAP) {
    4633           0 :              return 0;
    4634             :          }
    4635             :     }
    4636           0 :     return 1;
    4637             : }
    4638             : 
    4639             : struct vr_interface *
    4640           0 : vr_get_ecmp_first_member_dev (struct vr_nexthop *nh)
    4641             : {
    4642             :     int i;
    4643           0 :     if (!nh || (nh->nh_type != NH_COMPOSITE) ||
    4644           0 :        (!(nh->nh_flags & NH_FLAG_COMPOSITE_ECMP))) {
    4645           0 :         return NULL;
    4646             :     }
    4647             : 
    4648           0 :     for (i = 0; i < nh->nh_component_cnt; i++) {
    4649           0 :         if (nh->nh_component_nh && nh->nh_component_nh[i].cnh) {
    4650           0 :             return nh->nh_component_nh[i].cnh ? nh->nh_component_nh[i].cnh->nh_dev : NULL;
    4651             :         }
    4652             :     }
    4653           0 :     return NULL;
    4654             : }
    4655             : 
    4656             : static void
    4657          53 : nh_table_exit(struct vrouter *router, bool soft_reset)
    4658             : {
    4659             :     unsigned int i;
    4660             :     struct vr_nexthop *nh;
    4661             : 
    4662          53 :     if (!router->vr_nexthops)
    4663           0 :         return;
    4664             : 
    4665    27787317 :     for (i = 0; i < router->vr_max_nexthops; i++) {
    4666    27787264 :         if (soft_reset && i == NH_DISCARD_ID)
    4667           0 :             continue;
    4668    27787264 :         nh = __vrouter_get_nexthop(router, i);
    4669    27787264 :         if (nh)
    4670          54 :             nh->nh_destructor(nh);
    4671             :     }
    4672             : 
    4673             : 
    4674          53 :     if (soft_reset == false) {
    4675             :         /* Make the default nh point to NULL */
    4676          53 :         ip4_default_nh = NULL;
    4677          53 :         vr_btable_free(router->vr_nexthops);
    4678          53 :         router->vr_max_nexthops = 0;
    4679          53 :         router->vr_nexthops = NULL;
    4680             :     }
    4681             : 
    4682          53 :     return;
    4683             : }
    4684             : 
    4685             : static int
    4686          53 : nh_allocate_discard(void)
    4687             : {
    4688          53 :     ip4_default_nh = vr_zalloc(sizeof(struct vr_nexthop), VR_NEXTHOP_OBJECT);
    4689          53 :     if (!ip4_default_nh)
    4690           0 :         return -ENOMEM;
    4691             : 
    4692          53 :     ip4_default_nh->nh_id = NH_DISCARD_ID;
    4693          53 :     ip4_default_nh->nh_type = NH_DISCARD;
    4694          53 :     ip4_default_nh->nh_router = vrouter_get(0);
    4695          53 :     ip4_default_nh->nh_reach_nh = nh_discard;
    4696          53 :     ip4_default_nh->nh_destructor = nh_del;
    4697          53 :     ip4_default_nh->nh_flags = NH_FLAG_VALID;
    4698          53 :     ip4_default_nh->nh_family = AF_INET;
    4699             : 
    4700          53 :     return vrouter_add_nexthop(ip4_default_nh);
    4701             : }
    4702             : 
    4703             : static int
    4704          53 : nh_table_init(struct vrouter *router)
    4705             : {
    4706             :     int ret;
    4707             :     unsigned int table_memory;
    4708             : 
    4709          53 :     if (!router->vr_max_nexthops) {
    4710          53 :         router->vr_max_nexthops = vr_nexthops;
    4711          53 :         table_memory = router->vr_max_nexthops * sizeof(struct vr_nexthop *);
    4712          53 :         router->vr_nexthops = vr_btable_alloc(router->vr_max_nexthops,
    4713             :                 sizeof(struct vr_nexthop *));
    4714          53 :         if (!router->vr_nexthops)
    4715           0 :             return vr_module_error(-ENOMEM, __FUNCTION__,
    4716             :                     __LINE__, table_memory);
    4717             :     }
    4718             : 
    4719          53 :     if (!ip4_default_nh) {
    4720          53 :         ret = nh_allocate_discard();
    4721          53 :         if (ret)
    4722           0 :             return vr_module_error(ret, __FUNCTION__, __LINE__, 0);
    4723             :     }
    4724             : 
    4725          53 :     return 0;
    4726             : }
    4727             : 
    4728             : void
    4729          53 : vr_nexthop_exit(struct vrouter *router, bool soft_reset)
    4730             : {
    4731          53 :     nh_table_exit(router, soft_reset);
    4732          53 :     return;
    4733             : }
    4734             : 
    4735             : int
    4736          53 : vr_nexthop_init(struct vrouter *router)
    4737             : {
    4738          53 :     return nh_table_init(router);
    4739             : }
    4740             : 
    4741             : /*
    4742             :  * Called by offload module to update vrfstats with packets which have been
    4743             :  * offloaded. Expect counters in host byte order.
    4744             :  */
    4745             : int
    4746           0 : vr_nexthop_update_offload_vrfstats(uint32_t vrfid, uint32_t num_cntrs,
    4747             :                                uint64_t *cntrs)
    4748             : {
    4749             :     uint64_t *dst_cntr;
    4750           0 :     struct vr_vrf_stats *stats = NULL;
    4751             : 
    4752           0 :     if (!vr_inet_vrf_stats)
    4753           0 :         return 0;
    4754             : 
    4755             :     /* hw offload stats always go to CPU 0 */
    4756           0 :     stats = vr_inet_vrf_stats(vrfid, 0);
    4757           0 :     if (stats && num_cntrs <= sizeof(struct vr_vrf_stats) / sizeof(uint64_t)) {
    4758           0 :         dst_cntr = (uint64_t *)stats;
    4759           0 :         while (num_cntrs-- > 0)
    4760           0 :             *dst_cntr++ += *cntrs++;
    4761             :     }
    4762             : 
    4763           0 :     return 0;
    4764             : }

Generated by: LCOV version 1.14