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

Generated by: LCOV version 1.14