LCOV - code coverage report
Current view: top level - plugins/geneve - geneve.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 233 420 55.5 %
Date: 2023-10-26 01:39:38 Functions: 31 41 75.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 SUSE LLC.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : #include <geneve/geneve.h>
      16             : #include <vnet/ip/format.h>
      17             : #include <vnet/fib/fib_entry.h>
      18             : #include <vnet/fib/fib_table.h>
      19             : #include <vnet/fib/fib_entry_track.h>
      20             : #include <vnet/mfib/mfib_table.h>
      21             : #include <vnet/adj/adj_mcast.h>
      22             : #include <vnet/interface.h>
      23             : #include <vlib/vlib.h>
      24             : 
      25             : /**
      26             :  * @file
      27             :  * @brief GENEVE.
      28             :  *
      29             :  * GENEVE provides the features needed to allow L2 bridge domains (BDs)
      30             :  * to span multiple servers. This is done by building an L2 overlay on
      31             :  * top of an L3 network underlay using GENEVE tunnels.
      32             :  *
      33             :  * This makes it possible for servers to be co-located in the same data
      34             :  * center or be separated geographically as long as they are reachable
      35             :  * through the underlay L3 network.
      36             :  */
      37             : 
      38             : 
      39             : geneve_main_t geneve_main;
      40             : 
      41             : u8 *
      42          14 : format_geneve_encap_trace (u8 * s, va_list * args)
      43             : {
      44          14 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      45          14 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      46          14 :   geneve_encap_trace_t *t = va_arg (*args, geneve_encap_trace_t *);
      47             : 
      48          14 :   s = format (s, "GENEVE encap to geneve_tunnel%d vni %d",
      49             :               t->tunnel_index, t->vni);
      50          14 :   return s;
      51             : }
      52             : 
      53             : static u8 *
      54         110 : format_decap_next (u8 * s, va_list * args)
      55             : {
      56         110 :   u32 next_index = va_arg (*args, u32);
      57             : 
      58         110 :   switch (next_index)
      59             :     {
      60           0 :     case GENEVE_INPUT_NEXT_DROP:
      61           0 :       return format (s, "drop");
      62         110 :     case GENEVE_INPUT_NEXT_L2_INPUT:
      63         110 :       return format (s, "l2");
      64           0 :     default:
      65           0 :       return format (s, "index %d", next_index);
      66             :     }
      67             :   return s;
      68             : }
      69             : 
      70             : u8 *
      71         110 : format_geneve_tunnel (u8 * s, va_list * args)
      72             : {
      73         110 :   geneve_tunnel_t *t = va_arg (*args, geneve_tunnel_t *);
      74         110 :   geneve_main_t *ngm = &geneve_main;
      75             : 
      76         110 :   s = format (s, "[%d] lcl %U rmt %U vni %d fib-idx %d sw-if-idx %d ",
      77         110 :               t - ngm->tunnels,
      78             :               format_ip46_address, &t->local, IP46_TYPE_ANY,
      79             :               format_ip46_address, &t->remote, IP46_TYPE_ANY,
      80             :               t->vni, t->encap_fib_index, t->sw_if_index);
      81             : 
      82         110 :   s = format (s, "encap-dpo-idx %d ", t->next_dpo.dpoi_index);
      83         110 :   s = format (s, "decap-next-%U ", format_decap_next, t->decap_next_index);
      84         110 :   s = format (s, "l3-mode %u ", t->l3_mode);
      85             : 
      86         110 :   if (PREDICT_FALSE (ip46_address_is_multicast (&t->remote)))
      87           5 :     s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
      88             : 
      89         110 :   return s;
      90             : }
      91             : 
      92             : static u8 *
      93         153 : format_geneve_name (u8 * s, va_list * args)
      94             : {
      95         153 :   u32 dev_instance = va_arg (*args, u32);
      96         153 :   return format (s, "geneve_tunnel%d", dev_instance);
      97             : }
      98             : 
      99             : static clib_error_t *
     100          64 : geneve_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     101             : {
     102          64 :   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
     103             :     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
     104          64 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     105             : 
     106          64 :   return /* no error */ 0;
     107             : }
     108             : 
     109             : static clib_error_t *
     110           0 : geneve_mac_change (vnet_hw_interface_t * hi,
     111             :                    const u8 * old_address, const u8 * mac_address)
     112             : {
     113           0 :   l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
     114           0 :   return (NULL);
     115             : }
     116             : 
     117             : /* *INDENT-OFF* */
     118        9791 : VNET_DEVICE_CLASS (geneve_device_class, static) = {
     119             :   .name = "GENEVE",
     120             :   .format_device_name = format_geneve_name,
     121             :   .format_tx_trace = format_geneve_encap_trace,
     122             :   .admin_up_down_function = geneve_interface_admin_up_down,
     123             :   .mac_addr_change_function = geneve_mac_change,
     124             : };
     125             : /* *INDENT-ON* */
     126             : 
     127             : static u8 *
     128           0 : format_geneve_header_with_length (u8 * s, va_list * args)
     129             : {
     130           0 :   u32 dev_instance = va_arg (*args, u32);
     131           0 :   s = format (s, "unimplemented dev %u", dev_instance);
     132           0 :   return s;
     133             : }
     134             : 
     135             : /* *INDENT-OFF* */
     136        6911 : VNET_HW_INTERFACE_CLASS (geneve_hw_class) = {
     137             :   .name = "GENEVE",
     138             :   .format_header = format_geneve_header_with_length,
     139             :   .build_rewrite = default_build_rewrite,
     140             : };
     141             : /* *INDENT-ON* */
     142             : 
     143             : static void
     144          32 : geneve_tunnel_restack_dpo (geneve_tunnel_t * t)
     145             : {
     146          32 :   dpo_id_t dpo = DPO_INVALID;
     147          32 :   u32 encap_index = ip46_address_is_ip4 (&t->remote) ?
     148          32 :     geneve4_encap_node.index : geneve6_encap_node.index;
     149          32 :   fib_forward_chain_type_t forw_type = ip46_address_is_ip4 (&t->remote) ?
     150          32 :     FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6;
     151             : 
     152          32 :   fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo);
     153             : 
     154             :   /* geneve uses the flow hash as the udp source port
     155             :    * hence the packet's hash is unknown at this time.
     156             :    * However, we can still skip single bucket load balance dpo's */
     157          94 :   while (DPO_LOAD_BALANCE == dpo.dpoi_type)
     158             :     {
     159          62 :       load_balance_t *lb = load_balance_get (dpo.dpoi_index);
     160          62 :       if (lb->lb_n_buckets > 1)
     161           0 :         break;
     162             : 
     163          62 :       dpo_copy (&dpo, load_balance_get_bucket_i (lb, 0));
     164             :     }
     165          32 :   dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
     166          32 :   dpo_reset (&dpo);
     167          32 : }
     168             : 
     169             : static geneve_tunnel_t *
     170          10 : geneve_tunnel_from_fib_node (fib_node_t * node)
     171             : {
     172          10 :   ASSERT (FIB_NODE_TYPE_GENEVE_TUNNEL == node->fn_type);
     173          10 :   return ((geneve_tunnel_t *) (((char *) node) -
     174             :                                STRUCT_OFFSET_OF (geneve_tunnel_t, node)));
     175             : }
     176             : 
     177             : /**
     178             :  * Function definition to backwalk a FIB node -
     179             :  * Here we will restack the new dpo of GENEVE DIP to encap node.
     180             :  */
     181             : static fib_node_back_walk_rc_t
     182          10 : geneve_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
     183             : {
     184          10 :   geneve_tunnel_restack_dpo (geneve_tunnel_from_fib_node (node));
     185          10 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     186             : }
     187             : 
     188             : /**
     189             :  * Function definition to get a FIB node from its index
     190             :  */
     191             : static fib_node_t *
     192          10 : geneve_tunnel_fib_node_get (fib_node_index_t index)
     193             : {
     194             :   geneve_tunnel_t *t;
     195          10 :   geneve_main_t *vxm = &geneve_main;
     196             : 
     197          10 :   t = pool_elt_at_index (vxm->tunnels, index);
     198             : 
     199          10 :   return (&t->node);
     200             : }
     201             : 
     202             : /**
     203             :  * Function definition to inform the FIB node that its last lock has gone.
     204             :  */
     205             : static void
     206           0 : geneve_tunnel_last_lock_gone (fib_node_t * node)
     207             : {
     208             :   /*
     209             :    * The GENEVE tunnel is a root of the graph. As such
     210             :    * it never has children and thus is never locked.
     211             :    */
     212           0 :   ASSERT (0);
     213           0 : }
     214             : 
     215             : /*
     216             :  * Virtual function table registered by GENEVE tunnels
     217             :  * for participation in the FIB object graph.
     218             :  */
     219             : const static fib_node_vft_t geneve_vft = {
     220             :   .fnv_get = geneve_tunnel_fib_node_get,
     221             :   .fnv_last_lock = geneve_tunnel_last_lock_gone,
     222             :   .fnv_back_walk = geneve_tunnel_back_walk,
     223             : };
     224             : 
     225             : 
     226             : #define foreach_copy_field                      \
     227             : _(vni)                                          \
     228             : _(mcast_sw_if_index)                            \
     229             : _(encap_fib_index)                              \
     230             : _(decap_next_index)                             \
     231             : _(local)                                        \
     232             : _(remote)                                       \
     233             : _(l3_mode)
     234             : 
     235             : static int
     236          43 : geneve_rewrite (geneve_tunnel_t * t, bool is_ip6)
     237             : {
     238             :   union
     239             :   {
     240             :     ip4_geneve_header_t *h4;
     241             :     ip6_geneve_header_t *h6;
     242             :     u8 *rw;
     243          43 :   } r =
     244             :   {
     245             :   .rw = 0};
     246          43 :   int len = is_ip6 ? sizeof *r.h6 : sizeof *r.h4;
     247             : #if SUPPORT_OPTIONS_HEADER==1
     248             :   len += t->options_len;
     249             : #endif
     250             : 
     251          43 :   vec_validate_aligned (r.rw, len - 1, CLIB_CACHE_LINE_BYTES);
     252             : 
     253             :   udp_header_t *udp;
     254             :   geneve_header_t *geneve;
     255             :   /* Fixed portion of the (outer) ip header */
     256          43 :   if (!is_ip6)
     257             :     {
     258          43 :       ip4_header_t *ip = &r.h4->ip4;
     259          43 :       udp = &r.h4->udp, geneve = &r.h4->geneve;
     260          43 :       ip->ip_version_and_header_length = 0x45;
     261          43 :       ip->ttl = 254;
     262          43 :       ip->protocol = IP_PROTOCOL_UDP;
     263             : 
     264          43 :       ip->src_address = t->local.ip4;
     265          43 :       ip->dst_address = t->remote.ip4;
     266             : 
     267             :       /* we fix up the ip4 header length and checksum after-the-fact */
     268          43 :       ip->checksum = ip4_header_checksum (ip);
     269             :     }
     270             :   else
     271             :     {
     272           0 :       ip6_header_t *ip = &r.h6->ip6;
     273           0 :       udp = &r.h6->udp, geneve = &r.h6->geneve;
     274           0 :       ip->ip_version_traffic_class_and_flow_label =
     275           0 :         clib_host_to_net_u32 (6 << 28);
     276           0 :       ip->hop_limit = 255;
     277           0 :       ip->protocol = IP_PROTOCOL_UDP;
     278             : 
     279           0 :       ip->src_address = t->local.ip6;
     280           0 :       ip->dst_address = t->remote.ip6;
     281             :     }
     282             : 
     283             :   /* UDP header, randomize local port on something, maybe? */
     284          43 :   udp->src_port = clib_host_to_net_u16 (5251);
     285          43 :   udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_geneve);
     286             : 
     287             :   /* GENEVE header */
     288          43 :   vnet_set_geneve_version (geneve, GENEVE_VERSION);
     289             : #if SUPPORT_OPTIONS_HEADER==1
     290             :   vnet_set_geneve_options_len (geneve, t->options_len);
     291             : #else
     292          43 :   vnet_set_geneve_options_len (geneve, 0);
     293             : #endif
     294          43 :   vnet_set_geneve_oamframe_bit (geneve, 0);
     295          43 :   vnet_set_geneve_critical_bit (geneve, 0);
     296          43 :   vnet_set_geneve_protocol (geneve, GENEVE_ETH_PROTOCOL);
     297             : 
     298          43 :   vnet_geneve_hdr_1word_hton (geneve);
     299             : 
     300          43 :   vnet_set_geneve_vni (geneve, t->vni);
     301             : 
     302          43 :   t->rewrite = r.rw;
     303          43 :   return (0);
     304             : }
     305             : 
     306             : static bool
     307          43 : geneve_decap_next_is_valid (geneve_main_t * vxm, u32 is_ip6,
     308             :                             u32 decap_next_index)
     309             : {
     310          43 :   vlib_main_t *vm = vxm->vlib_main;
     311          43 :   u32 input_idx =
     312          43 :     (!is_ip6) ? geneve4_input_node.index : geneve6_input_node.index;
     313          43 :   vlib_node_runtime_t *r = vlib_node_get_runtime (vm, input_idx);
     314             : 
     315          43 :   return decap_next_index < r->n_next_nodes;
     316             : }
     317             : 
     318             : typedef union
     319             : {
     320             :   struct
     321             :   {
     322             :     fib_node_index_t mfib_entry_index;
     323             :     adj_index_t mcast_adj_index;
     324             :   };
     325             :   u64 as_u64;
     326             : } __clib_packed mcast_shared_t;
     327             : 
     328             : static inline mcast_shared_t
     329          31 : mcast_shared_get (ip46_address_t * ip)
     330             : {
     331          31 :   ASSERT (ip46_address_is_multicast (ip));
     332          31 :   uword *p = hash_get_mem (geneve_main.mcast_shared, ip);
     333          31 :   ALWAYS_ASSERT (p);
     334          62 :   return (mcast_shared_t)
     335             :   {
     336          31 :   .as_u64 = *p};
     337             : }
     338             : 
     339             : static inline void
     340          11 : mcast_shared_add (ip46_address_t * remote,
     341             :                   fib_node_index_t mfei, adj_index_t ai)
     342             : {
     343          11 :   mcast_shared_t new_ep = {
     344             :     .mcast_adj_index = ai,
     345             :     .mfib_entry_index = mfei,
     346             :   };
     347             : 
     348          11 :   hash_set_mem_alloc (&geneve_main.mcast_shared, remote, new_ep.as_u64);
     349          11 : }
     350             : 
     351             : static inline void
     352          10 : mcast_shared_remove (ip46_address_t * remote)
     353             : {
     354          10 :   mcast_shared_t ep = mcast_shared_get (remote);
     355             : 
     356          10 :   adj_unlock (ep.mcast_adj_index);
     357          10 :   mfib_table_entry_delete_index (ep.mfib_entry_index, MFIB_SOURCE_GENEVE);
     358             : 
     359          10 :   hash_unset_mem_free (&geneve_main.mcast_shared, remote);
     360          10 : }
     361             : 
     362          64 : int vnet_geneve_add_del_tunnel
     363             :   (vnet_geneve_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
     364             : {
     365          64 :   geneve_main_t *vxm = &geneve_main;
     366          64 :   geneve_tunnel_t *t = 0;
     367          64 :   vnet_main_t *vnm = vxm->vnet_main;
     368             :   uword *p;
     369          64 :   u32 hw_if_index = ~0;
     370          64 :   u32 sw_if_index = ~0;
     371             :   int rv;
     372             :   geneve4_tunnel_key_t key4;
     373             :   geneve6_tunnel_key_t key6;
     374          64 :   u32 is_ip6 = a->is_ip6;
     375             : 
     376          64 :   if (!is_ip6)
     377             :     {
     378          64 :       key4.remote = a->remote.ip4.as_u32;
     379          64 :       key4.vni = clib_host_to_net_u32 (a->vni << GENEVE_VNI_SHIFT);
     380          64 :       p = hash_get (vxm->geneve4_tunnel_by_key, key4.as_u64);
     381             :     }
     382             :   else
     383             :     {
     384           0 :       key6.remote = a->remote.ip6;
     385           0 :       key6.vni = clib_host_to_net_u32 (a->vni << GENEVE_VNI_SHIFT);
     386           0 :       p = hash_get_mem (vxm->geneve6_tunnel_by_key, &key6);
     387             :     }
     388             : 
     389          64 :   if (a->is_add)
     390             :     {
     391          43 :       l2input_main_t *l2im = &l2input_main;
     392             : 
     393             :       /* adding a tunnel: tunnel must not already exist */
     394          43 :       if (p)
     395           0 :         return VNET_API_ERROR_TUNNEL_EXIST;
     396             : 
     397             :       /*if not set explicitly, default to l2 */
     398          43 :       if (a->decap_next_index == ~0)
     399          42 :         a->decap_next_index = GENEVE_INPUT_NEXT_L2_INPUT;
     400          43 :       if (!geneve_decap_next_is_valid (vxm, is_ip6, a->decap_next_index))
     401           0 :         return VNET_API_ERROR_INVALID_DECAP_NEXT;
     402             : 
     403          43 :       pool_get_aligned (vxm->tunnels, t, CLIB_CACHE_LINE_BYTES);
     404          43 :       clib_memset (t, 0, sizeof (*t));
     405             : 
     406             :       /* copy from arg structure */
     407             : #define _(x) t->x = a->x;
     408          43 :       foreach_copy_field;
     409             : #undef _
     410             : 
     411          43 :       rv = geneve_rewrite (t, is_ip6);
     412          43 :       if (rv)
     413             :         {
     414           0 :           pool_put (vxm->tunnels, t);
     415           0 :           return rv;
     416             :         }
     417             : 
     418             :       /* copy the key */
     419          43 :       if (is_ip6)
     420           0 :         hash_set_mem_alloc (&vxm->geneve6_tunnel_by_key, &key6,
     421           0 :                             t - vxm->tunnels);
     422             :       else
     423          43 :         hash_set (vxm->geneve4_tunnel_by_key, key4.as_u64, t - vxm->tunnels);
     424             : 
     425             :       vnet_hw_interface_t *hi;
     426          43 :       if (a->l3_mode)
     427             :         {
     428           1 :           vnet_eth_interface_registration_t eir = {};
     429           1 :           u32 t_idx = t - vxm->tunnels;
     430           1 :           u8 address[6] =
     431           1 :             { 0xd0, 0x0b, 0xee, 0xd0, (u8) (t_idx >> 8), (u8) t_idx };
     432             : 
     433           1 :           eir.dev_class_index = geneve_device_class.index;
     434           1 :           eir.dev_instance = t_idx;
     435           1 :           eir.address = address;
     436           1 :           hw_if_index = vnet_eth_register_interface (vnm, &eir);
     437             :         }
     438             :       else
     439             :         {
     440          42 :           hw_if_index = vnet_register_interface
     441          42 :             (vnm, geneve_device_class.index, t - vxm->tunnels,
     442          42 :              geneve_hw_class.index, t - vxm->tunnels);
     443             :         }
     444             : 
     445          43 :       hi = vnet_get_hw_interface (vnm, hw_if_index);
     446             : 
     447             :       /* Set geneve tunnel output node */
     448          43 :       u32 encap_index = !is_ip6 ?
     449          43 :         geneve4_encap_node.index : geneve6_encap_node.index;
     450          43 :       vnet_set_interface_output_node (vnm, hw_if_index, encap_index);
     451             : 
     452          43 :       t->hw_if_index = hw_if_index;
     453          43 :       t->sw_if_index = sw_if_index = hi->sw_if_index;
     454             : 
     455          84 :       vec_validate_init_empty (vxm->tunnel_index_by_sw_if_index, sw_if_index,
     456             :                                ~0);
     457          43 :       vxm->tunnel_index_by_sw_if_index[sw_if_index] = t - vxm->tunnels;
     458             : 
     459             :       /* setup l2 input config with l2 feature and bd 0 to drop packet */
     460          43 :       vec_validate (l2im->configs, sw_if_index);
     461          43 :       l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
     462          43 :       l2im->configs[sw_if_index].bd_index = 0;
     463             : 
     464          43 :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     465          43 :       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
     466          43 :       vnet_sw_interface_set_flags (vnm, sw_if_index,
     467             :                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     468             : 
     469          43 :       fib_node_init (&t->node, FIB_NODE_TYPE_GENEVE_TUNNEL);
     470             :       fib_prefix_t tun_remote_pfx;
     471          43 :       vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL;
     472             : 
     473          43 :       fib_protocol_t fp = fib_ip_proto (is_ip6);
     474          43 :       fib_prefix_from_ip46_addr (fp, &t->remote, &tun_remote_pfx);
     475          43 :       if (!ip46_address_is_multicast (&t->remote))
     476             :         {
     477             :           /* Unicast tunnel -
     478             :            * source the FIB entry for the tunnel's destination
     479             :            * and become a child thereof. The tunnel will then get poked
     480             :            * when the forwarding for the entry updates, and the tunnel can
     481             :            * re-stack accordingly
     482             :            */
     483          22 :           vtep_addr_ref (&vxm->vtep_table, t->encap_fib_index, &t->local);
     484          44 :           t->fib_entry_index = fib_entry_track (t->encap_fib_index,
     485             :                                                 &tun_remote_pfx,
     486             :                                                 FIB_NODE_TYPE_GENEVE_TUNNEL,
     487          22 :                                                 t - vxm->tunnels,
     488          22 :                                                 &t->sibling_index);
     489          22 :           geneve_tunnel_restack_dpo (t);
     490             :         }
     491             :       else
     492             :         {
     493             :           /* Multicast tunnel -
     494             :            * as the same mcast group can be used for mutiple mcast tunnels
     495             :            * with different VNIs, create the output fib adjecency only if
     496             :            * it does not already exist
     497             :            */
     498          21 :           if (vtep_addr_ref (&vxm->vtep_table,
     499          21 :                              t->encap_fib_index, &t->remote) == 1)
     500             :             {
     501             :               fib_node_index_t mfei;
     502             :               adj_index_t ai;
     503          22 :               fib_route_path_t path = {
     504          11 :                 .frp_proto = fib_proto_to_dpo (fp),
     505             :                 .frp_addr = zero_addr,
     506             :                 .frp_sw_if_index = 0xffffffff,
     507             :                 .frp_fib_index = ~0,
     508             :                 .frp_weight = 1,
     509             :                 .frp_flags = FIB_ROUTE_PATH_LOCAL,
     510             :                 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
     511             :               };
     512          11 :               const mfib_prefix_t mpfx = {
     513             :                 .fp_proto = fp,
     514             :                 .fp_len = (is_ip6 ? 128 : 32),
     515             :                 .fp_grp_addr = tun_remote_pfx.fp_addr,
     516             :               };
     517             : 
     518             :               /*
     519             :                * Setup the (*,G) to receive traffic on the mcast group
     520             :                *  - the forwarding interface is for-us
     521             :                *  - the accepting interface is that from the API
     522             :                */
     523          11 :               mfib_table_entry_path_update (t->encap_fib_index, &mpfx,
     524             :                                             MFIB_SOURCE_GENEVE,
     525             :                                             MFIB_ENTRY_FLAG_NONE, &path);
     526             : 
     527          11 :               path.frp_sw_if_index = a->mcast_sw_if_index;
     528          11 :               path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
     529          11 :               path.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
     530          11 :               mfei = mfib_table_entry_path_update (
     531          11 :                 t->encap_fib_index, &mpfx, MFIB_SOURCE_GENEVE,
     532             :                 MFIB_ENTRY_FLAG_NONE, &path);
     533             : 
     534             :               /*
     535             :                * Create the mcast adjacency to send traffic to the group
     536             :                */
     537          11 :               ai = adj_mcast_add_or_lock (fp,
     538          11 :                                           fib_proto_to_link (fp),
     539             :                                           a->mcast_sw_if_index);
     540             : 
     541             :               /*
     542             :                * create a new end-point
     543             :                */
     544          11 :               mcast_shared_add (&t->remote, mfei, ai);
     545             :             }
     546             : 
     547          21 :           dpo_id_t dpo = DPO_INVALID;
     548          21 :           mcast_shared_t ep = mcast_shared_get (&t->remote);
     549             : 
     550             :           /* Stack shared mcast remote mac addr rewrite on encap */
     551          21 :           dpo_set (&dpo, DPO_ADJACENCY_MCAST,
     552          21 :                    fib_proto_to_dpo (fp), ep.mcast_adj_index);
     553             : 
     554          21 :           dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
     555          21 :           dpo_reset (&dpo);
     556          21 :           flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER;
     557             :         }
     558             : 
     559          43 :       vnet_get_sw_interface (vnet_get_main (), sw_if_index)->flood_class =
     560             :         flood_class;
     561             :     }
     562             :   else
     563             :     {
     564             :       /* deleting a tunnel: tunnel must exist */
     565          21 :       if (!p)
     566           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     567             : 
     568          21 :       t = pool_elt_at_index (vxm->tunnels, p[0]);
     569             : 
     570          21 :       sw_if_index = t->sw_if_index;
     571          21 :       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
     572          21 :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
     573          21 :       si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
     574             : 
     575             :       /* make sure tunnel is removed from l2 bd or xconnect */
     576          21 :       set_int_l2_mode (vxm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0,
     577             :                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
     578             : 
     579          21 :       if (t->l3_mode)
     580           1 :         ethernet_delete_interface (vnm, t->hw_if_index);
     581             :       else
     582          20 :         vnet_delete_hw_interface (vnm, t->hw_if_index);
     583             : 
     584          21 :       vxm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
     585             : 
     586          21 :       if (!is_ip6)
     587          21 :         hash_unset (vxm->geneve4_tunnel_by_key, key4.as_u64);
     588             :       else
     589           0 :         hash_unset_mem_free (&vxm->geneve6_tunnel_by_key, &key6);
     590             : 
     591          21 :       if (!ip46_address_is_multicast (&t->remote))
     592             :         {
     593           1 :           vtep_addr_unref (&vxm->vtep_table, t->encap_fib_index, &t->local);
     594           1 :           fib_entry_untrack (t->fib_entry_index, t->sibling_index);
     595             :         }
     596          20 :       else if (vtep_addr_unref (&vxm->vtep_table,
     597          20 :                                 t->encap_fib_index, &t->remote) == 0)
     598             :         {
     599          10 :           mcast_shared_remove (&t->remote);
     600             :         }
     601             : 
     602          21 :       fib_node_deinit (&t->node);
     603          21 :       vec_free (t->rewrite);
     604          21 :       pool_put (vxm->tunnels, t);
     605             :     }
     606             : 
     607          64 :   if (sw_if_indexp)
     608          64 :     *sw_if_indexp = sw_if_index;
     609             : 
     610          64 :   if (a->is_add)
     611             :     {
     612             :       /* register udp ports */
     613          43 :       if (!is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_geneve, 1))
     614           2 :         udp_register_dst_port (vxm->vlib_main, UDP_DST_PORT_geneve,
     615             :                                geneve4_input_node.index, 1);
     616          43 :       if (is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_geneve6, 0))
     617           0 :         udp_register_dst_port (vxm->vlib_main, UDP_DST_PORT_geneve6,
     618             :                                geneve6_input_node.index, 0);
     619             :     }
     620             : 
     621          64 :   return 0;
     622             : }
     623             : 
     624             : static uword
     625           0 : get_decap_next_for_node (u32 node_index, u32 ipv4_set)
     626             : {
     627           0 :   geneve_main_t *vxm = &geneve_main;
     628           0 :   vlib_main_t *vm = vxm->vlib_main;
     629           0 :   uword input_node = (ipv4_set) ? geneve4_input_node.index :
     630           0 :     geneve6_input_node.index;
     631             : 
     632           0 :   return vlib_node_add_next (vm, input_node, node_index);
     633             : }
     634             : 
     635             : static uword
     636           0 : unformat_decap_next (unformat_input_t * input, va_list * args)
     637             : {
     638           0 :   u32 *result = va_arg (*args, u32 *);
     639           0 :   u32 ipv4_set = va_arg (*args, int);
     640           0 :   geneve_main_t *vxm = &geneve_main;
     641           0 :   vlib_main_t *vm = vxm->vlib_main;
     642             :   u32 node_index;
     643             :   u32 tmp;
     644             : 
     645           0 :   if (unformat (input, "l2"))
     646           0 :     *result = GENEVE_INPUT_NEXT_L2_INPUT;
     647           0 :   else if (unformat (input, "node %U", unformat_vlib_node, vm, &node_index))
     648           0 :     *result = get_decap_next_for_node (node_index, ipv4_set);
     649           0 :   else if (unformat (input, "%d", &tmp))
     650           0 :     *result = tmp;
     651             :   else
     652           0 :     return 0;
     653           0 :   return 1;
     654             : }
     655             : 
     656             : static clib_error_t *
     657           0 : geneve_add_del_tunnel_command_fn (vlib_main_t * vm,
     658             :                                   unformat_input_t * input,
     659             :                                   vlib_cli_command_t * cmd)
     660             : {
     661           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     662             :   ip46_address_t local, remote;
     663           0 :   u8 is_add = 1;
     664           0 :   u8 local_set = 0;
     665           0 :   u8 remote_set = 0;
     666           0 :   u8 grp_set = 0;
     667           0 :   u8 ipv4_set = 0;
     668           0 :   u8 ipv6_set = 0;
     669           0 :   u8 l3_mode = 0;
     670           0 :   u32 encap_fib_index = 0;
     671           0 :   u32 mcast_sw_if_index = ~0;
     672           0 :   u32 decap_next_index = GENEVE_INPUT_NEXT_L2_INPUT;
     673           0 :   u32 vni = 0;
     674             :   u32 tmp;
     675             :   int rv;
     676           0 :   vnet_geneve_add_del_tunnel_args_t _a, *a = &_a;
     677             :   u32 tunnel_sw_if_index;
     678           0 :   clib_error_t *error = NULL;
     679             : 
     680             :   /* Cant "universally zero init" (={0}) due to GCC bug 53119 */
     681           0 :   clib_memset (&local, 0, sizeof local);
     682           0 :   clib_memset (&remote, 0, sizeof remote);
     683             : 
     684             :   /* Get a line of input. */
     685           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     686           0 :     return 0;
     687             : 
     688           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     689             :     {
     690           0 :       if (unformat (line_input, "del"))
     691             :         {
     692           0 :           is_add = 0;
     693             :         }
     694           0 :       else if (unformat (line_input, "local %U",
     695             :                          unformat_ip4_address, &local.ip4))
     696             :         {
     697           0 :           local_set = 1;
     698           0 :           ipv4_set = 1;
     699             :         }
     700           0 :       else if (unformat (line_input, "remote %U",
     701             :                          unformat_ip4_address, &remote.ip4))
     702             :         {
     703           0 :           remote_set = 1;
     704           0 :           ipv4_set = 1;
     705             :         }
     706           0 :       else if (unformat (line_input, "local %U",
     707             :                          unformat_ip6_address, &local.ip6))
     708             :         {
     709           0 :           local_set = 1;
     710           0 :           ipv6_set = 1;
     711             :         }
     712           0 :       else if (unformat (line_input, "remote %U",
     713             :                          unformat_ip6_address, &remote.ip6))
     714             :         {
     715           0 :           remote_set = 1;
     716           0 :           ipv6_set = 1;
     717             :         }
     718           0 :       else if (unformat (line_input, "group %U %U",
     719             :                          unformat_ip4_address, &remote.ip4,
     720             :                          unformat_vnet_sw_interface,
     721             :                          vnet_get_main (), &mcast_sw_if_index))
     722             :         {
     723           0 :           grp_set = remote_set = 1;
     724           0 :           ipv4_set = 1;
     725             :         }
     726           0 :       else if (unformat (line_input, "group %U %U",
     727             :                          unformat_ip6_address, &remote.ip6,
     728             :                          unformat_vnet_sw_interface,
     729             :                          vnet_get_main (), &mcast_sw_if_index))
     730             :         {
     731           0 :           grp_set = remote_set = 1;
     732           0 :           ipv6_set = 1;
     733             :         }
     734           0 :       else if (unformat (line_input, "encap-vrf-id %d", &tmp))
     735             :         {
     736           0 :           encap_fib_index = fib_table_find (fib_ip_proto (ipv6_set), tmp);
     737           0 :           if (encap_fib_index == ~0)
     738             :             {
     739             :               error =
     740           0 :                 clib_error_return (0, "nonexistent encap-vrf-id %d", tmp);
     741           0 :               goto done;
     742             :             }
     743             :         }
     744           0 :       else if (unformat (line_input, "decap-next %U", unformat_decap_next,
     745             :                          &decap_next_index, ipv4_set))
     746             :         ;
     747           0 :       else if (unformat (line_input, "vni %d", &vni))
     748             :         {
     749           0 :           if (vni >> 24)
     750             :             {
     751           0 :               error = clib_error_return (0, "vni %d out of range", vni);
     752           0 :               goto done;
     753             :             }
     754             :         }
     755           0 :       else if (unformat (line_input, "l3-mode"))
     756             :         {
     757           0 :           l3_mode = 1;
     758             :         }
     759             :       else
     760             :         {
     761           0 :           error = clib_error_return (0, "parse error: '%U'",
     762             :                                      format_unformat_error, line_input);
     763           0 :           goto done;
     764             :         }
     765             :     }
     766             : 
     767           0 :   if (local_set == 0)
     768             :     {
     769           0 :       error = clib_error_return (0, "tunnel local address not specified");
     770           0 :       goto done;
     771             :     }
     772             : 
     773           0 :   if (remote_set == 0)
     774             :     {
     775           0 :       error = clib_error_return (0, "tunnel remote address not specified");
     776           0 :       goto done;
     777             :     }
     778             : 
     779           0 :   if (grp_set && !ip46_address_is_multicast (&remote))
     780             :     {
     781           0 :       error = clib_error_return (0, "tunnel group address not multicast");
     782           0 :       goto done;
     783             :     }
     784             : 
     785           0 :   if (grp_set == 0 && ip46_address_is_multicast (&remote))
     786             :     {
     787           0 :       error = clib_error_return (0, "remote address must be unicast");
     788           0 :       goto done;
     789             :     }
     790             : 
     791           0 :   if (grp_set && mcast_sw_if_index == ~0)
     792             :     {
     793           0 :       error = clib_error_return (0, "tunnel nonexistent multicast device");
     794           0 :       goto done;
     795             :     }
     796             : 
     797           0 :   if (ipv4_set && ipv6_set)
     798             :     {
     799           0 :       error = clib_error_return (0, "both IPv4 and IPv6 addresses specified");
     800           0 :       goto done;
     801             :     }
     802             : 
     803           0 :   if (ip46_address_cmp (&local, &remote) == 0)
     804             :     {
     805             :       error =
     806           0 :         clib_error_return (0, "local and remote addresses are identical");
     807           0 :       goto done;
     808             :     }
     809             : 
     810           0 :   if (decap_next_index == ~0)
     811             :     {
     812           0 :       error = clib_error_return (0, "next node not found");
     813           0 :       goto done;
     814             :     }
     815             : 
     816           0 :   if (vni == 0)
     817             :     {
     818           0 :       error = clib_error_return (0, "vni not specified");
     819           0 :       goto done;
     820             :     }
     821             : 
     822           0 :   clib_memset (a, 0, sizeof (*a));
     823             : 
     824           0 :   a->is_add = is_add;
     825           0 :   a->is_ip6 = ipv6_set;
     826             : 
     827             : #define _(x) a->x = x;
     828           0 :   foreach_copy_field;
     829             : #undef _
     830             : 
     831           0 :   rv = vnet_geneve_add_del_tunnel (a, &tunnel_sw_if_index);
     832             : 
     833           0 :   switch (rv)
     834             :     {
     835           0 :     case 0:
     836           0 :       if (is_add)
     837           0 :         vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
     838             :                          vnet_get_main (), tunnel_sw_if_index);
     839           0 :       break;
     840             : 
     841           0 :     case VNET_API_ERROR_TUNNEL_EXIST:
     842           0 :       error = clib_error_return (0, "tunnel already exists...");
     843           0 :       goto done;
     844             : 
     845           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     846           0 :       error = clib_error_return (0, "tunnel does not exist...");
     847           0 :       goto done;
     848             : 
     849           0 :     default:
     850           0 :       error = clib_error_return
     851             :         (0, "vnet_geneve_add_del_tunnel returned %d", rv);
     852           0 :       goto done;
     853             :     }
     854             : 
     855           0 : done:
     856           0 :   unformat_free (line_input);
     857             : 
     858           0 :   return error;
     859             : }
     860             : 
     861             : /*?
     862             :  * Add or delete a GENEVE Tunnel.
     863             :  *
     864             :  * GENEVE provides the features needed to allow L2 bridge domains (BDs)
     865             :  * to span multiple servers. This is done by building an L2 overlay on
     866             :  * top of an L3 network underlay using GENEVE tunnels.
     867             :  *
     868             :  * This makes it possible for servers to be co-located in the same data
     869             :  * center or be separated geographically as long as they are reachable
     870             :  * through the underlay L3 network.
     871             :  *
     872             :  * You can refer to this kind of L2 overlay bridge domain as a GENEVE
     873             :  * segment.
     874             :  *
     875             :  * @cliexpar
     876             :  * Example of how to create a GENEVE Tunnel:
     877             :  * @cliexcmd{create geneve tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 encap-vrf-id 7}
     878             :  * Example of how to delete a GENEVE Tunnel:
     879             :  * @cliexcmd{create geneve tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 del}
     880             :  ?*/
     881             : /* *INDENT-OFF* */
     882      221929 : VLIB_CLI_COMMAND (create_geneve_tunnel_command, static) = {
     883             :   .path = "create geneve tunnel",
     884             :   .short_help =
     885             :   "create geneve tunnel local <local-vtep-addr>"
     886             :   " {remote <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>"
     887             :   " [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [l3-mode] [del]",
     888             :   .function = geneve_add_del_tunnel_command_fn,
     889             : };
     890             : /* *INDENT-ON* */
     891             : 
     892             : static clib_error_t *
     893           6 : show_geneve_tunnel_command_fn (vlib_main_t * vm,
     894             :                                unformat_input_t * input,
     895             :                                vlib_cli_command_t * cmd)
     896             : {
     897           6 :   geneve_main_t *vxm = &geneve_main;
     898             :   geneve_tunnel_t *t;
     899             : 
     900           6 :   if (pool_elts (vxm->tunnels) == 0)
     901           1 :     vlib_cli_output (vm, "No geneve tunnels configured...");
     902             : 
     903         116 :   pool_foreach (t, vxm->tunnels)
     904             :   {
     905         110 :     vlib_cli_output (vm, "%U", format_geneve_tunnel, t);
     906             :   }
     907             : 
     908           6 :   return 0;
     909             : }
     910             : 
     911             : /*?
     912             :  * Display all the GENEVE Tunnel entries.
     913             :  *
     914             :  * @cliexpar
     915             :  * Example of how to display the GENEVE Tunnel entries:
     916             :  * @cliexstart{show geneve tunnel}
     917             :  * [0] local 10.0.3.1 remote 10.0.3.3 vni 13 encap_fib_index 0 sw_if_index 5 decap_next l2
     918             :  * @cliexend
     919             :  ?*/
     920             : /* *INDENT-OFF* */
     921      221929 : VLIB_CLI_COMMAND (show_geneve_tunnel_command, static) = {
     922             :     .path = "show geneve tunnel",
     923             :     .short_help = "show geneve tunnel",
     924             :     .function = show_geneve_tunnel_command_fn,
     925             : };
     926             : /* *INDENT-ON* */
     927             : 
     928             : 
     929             : void
     930           0 : vnet_int_geneve_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable)
     931             : {
     932           0 :   if (is_ip6)
     933           0 :     vnet_feature_enable_disable ("ip6-unicast", "ip6-geneve-bypass",
     934             :                                  sw_if_index, is_enable, 0, 0);
     935             :   else
     936           0 :     vnet_feature_enable_disable ("ip4-unicast", "ip4-geneve-bypass",
     937             :                                  sw_if_index, is_enable, 0, 0);
     938           0 : }
     939             : 
     940             : 
     941             : static clib_error_t *
     942           0 : set_ip_geneve_bypass (u32 is_ip6,
     943             :                       unformat_input_t * input, vlib_cli_command_t * cmd)
     944             : {
     945           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     946           0 :   vnet_main_t *vnm = vnet_get_main ();
     947           0 :   clib_error_t *error = 0;
     948             :   u32 sw_if_index, is_enable;
     949             : 
     950           0 :   sw_if_index = ~0;
     951           0 :   is_enable = 1;
     952             : 
     953           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     954           0 :     return 0;
     955             : 
     956           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     957             :     {
     958           0 :       if (unformat_user
     959             :           (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     960             :         ;
     961           0 :       else if (unformat (line_input, "del"))
     962           0 :         is_enable = 0;
     963             :       else
     964             :         {
     965           0 :           error = unformat_parse_error (line_input);
     966           0 :           goto done;
     967             :         }
     968             :     }
     969             : 
     970           0 :   if (~0 == sw_if_index)
     971             :     {
     972           0 :       error = clib_error_return (0, "unknown interface `%U'",
     973             :                                  format_unformat_error, line_input);
     974           0 :       goto done;
     975             :     }
     976             : 
     977           0 :   vnet_int_geneve_bypass_mode (sw_if_index, is_ip6, is_enable);
     978             : 
     979           0 : done:
     980           0 :   unformat_free (line_input);
     981             : 
     982           0 :   return error;
     983             : }
     984             : 
     985             : static clib_error_t *
     986           0 : set_ip4_geneve_bypass (vlib_main_t * vm,
     987             :                        unformat_input_t * input, vlib_cli_command_t * cmd)
     988             : {
     989           0 :   return set_ip_geneve_bypass (0, input, cmd);
     990             : }
     991             : 
     992             : /*?
     993             :  * This command adds the 'ip4-geneve-bypass' graph node for a given interface.
     994             :  * By adding the IPv4 geneve-bypass graph node to an interface, the node checks
     995             :  * for and validate input geneve packet and bypass ip4-lookup, ip4-local,
     996             :  * ip4-udp-lookup nodes to speedup geneve packet forwarding. This node will
     997             :  * cause extra overhead to for non-geneve packets which is kept at a minimum.
     998             :  *
     999             :  * @cliexpar
    1000             :  * @parblock
    1001             :  * Example of graph node before ip4-geneve-bypass is enabled:
    1002             :  * @cliexstart{show vlib graph ip4-geneve-bypass}
    1003             :  *            Name                      Next                    Previous
    1004             :  * ip4-geneve-bypass                error-drop [0]
    1005             :  *                                geneve4-input [1]
    1006             :  *                                 ip4-lookup [2]
    1007             :  * @cliexend
    1008             :  *
    1009             :  * Example of how to enable ip4-geneve-bypass on an interface:
    1010             :  * @cliexcmd{set interface ip geneve-bypass GigabitEthernet2/0/0}
    1011             :  *
    1012             :  * Example of graph node after ip4-geneve-bypass is enabled:
    1013             :  * @cliexstart{show vlib graph ip4-geneve-bypass}
    1014             :  *            Name           Next                    Previous
    1015             :  * ip4-geneve-bypass     error-drop [0]              ip4-input
    1016             :  *                     geneve4-input [1]        ip4-input-no-checksum
    1017             :  *                      ip4-lookup [2]
    1018             :  * @cliexend
    1019             :  *
    1020             :  * Example of how to display the feature enabled on an interface:
    1021             :  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
    1022             :  * IP feature paths configured on GigabitEthernet2/0/0...
    1023             :  * ...
    1024             :  * ipv4 unicast:
    1025             :  *   ip4-geneve-bypass
    1026             :  *   ip4-lookup
    1027             :  * ...
    1028             :  * @cliexend
    1029             :  *
    1030             :  * Example of how to disable ip4-geneve-bypass on an interface:
    1031             :  * @cliexcmd{set interface ip geneve-bypass GigabitEthernet2/0/0 del}
    1032             :  * @endparblock
    1033             : ?*/
    1034             : /* *INDENT-OFF* */
    1035      221929 : VLIB_CLI_COMMAND (set_interface_ip_geneve_bypass_command, static) = {
    1036             :   .path = "set interface ip geneve-bypass",
    1037             :   .function = set_ip4_geneve_bypass,
    1038             :   .short_help = "set interface ip geneve-bypass <interface> [del]",
    1039             : };
    1040             : /* *INDENT-ON* */
    1041             : 
    1042             : static clib_error_t *
    1043           0 : set_ip6_geneve_bypass (vlib_main_t * vm,
    1044             :                        unformat_input_t * input, vlib_cli_command_t * cmd)
    1045             : {
    1046           0 :   return set_ip_geneve_bypass (1, input, cmd);
    1047             : }
    1048             : 
    1049             : /*?
    1050             :  * This command adds the 'ip6-geneve-bypass' graph node for a given interface.
    1051             :  * By adding the IPv6 geneve-bypass graph node to an interface, the node checks
    1052             :  * for and validate input geneve packet and bypass ip6-lookup, ip6-local,
    1053             :  * ip6-udp-lookup nodes to speedup geneve packet forwarding. This node will
    1054             :  * cause extra overhead to for non-geneve packets which is kept at a minimum.
    1055             :  *
    1056             :  * @cliexpar
    1057             :  * @parblock
    1058             :  * Example of graph node before ip6-geneve-bypass is enabled:
    1059             :  * @cliexstart{show vlib graph ip6-geneve-bypass}
    1060             :  *            Name                      Next                    Previous
    1061             :  * ip6-geneve-bypass                error-drop [0]
    1062             :  *                                geneve6-input [1]
    1063             :  *                                 ip6-lookup [2]
    1064             :  * @cliexend
    1065             :  *
    1066             :  * Example of how to enable ip6-geneve-bypass on an interface:
    1067             :  * @cliexcmd{set interface ip6 geneve-bypass GigabitEthernet2/0/0}
    1068             :  *
    1069             :  * Example of graph node after ip6-geneve-bypass is enabled:
    1070             :  * @cliexstart{show vlib graph ip6-geneve-bypass}
    1071             :  *      Name                      Next                    Previous
    1072             :  * ip6-geneve-bypass          error-drop [0]             ip6-input
    1073             :  *                          geneve6-input [1]       ip4-input-no-checksum
    1074             :  *                           ip6-lookup [2]
    1075             :  * @cliexend
    1076             :  *
    1077             :  * Example of how to display the feature enabled on an interface:
    1078             :  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
    1079             :  * IP feature paths configured on GigabitEthernet2/0/0...
    1080             :  * ...
    1081             :  * ipv6 unicast:
    1082             :  *   ip6-geneve-bypass
    1083             :  *   ip6-lookup
    1084             :  * ...
    1085             :  * @cliexend
    1086             :  *
    1087             :  * Example of how to disable ip6-geneve-bypass on an interface:
    1088             :  * @cliexcmd{set interface ip6 geneve-bypass GigabitEthernet2/0/0 del}
    1089             :  * @endparblock
    1090             : ?*/
    1091             : /* *INDENT-OFF* */
    1092      221929 : VLIB_CLI_COMMAND (set_interface_ip6_geneve_bypass_command, static) = {
    1093             :   .path = "set interface ip6 geneve-bypass",
    1094             :   .function = set_ip6_geneve_bypass,
    1095             :   .short_help = "set interface ip6 geneve-bypass <interface> [del]",
    1096             : };
    1097             : /* *INDENT-ON* */
    1098             : 
    1099             : clib_error_t *
    1100         575 : geneve_init (vlib_main_t * vm)
    1101             : {
    1102         575 :   geneve_main_t *vxm = &geneve_main;
    1103             : 
    1104         575 :   vxm->vnet_main = vnet_get_main ();
    1105         575 :   vxm->vlib_main = vm;
    1106             : 
    1107             :   /* initialize the ip6 hash */
    1108         575 :   vxm->geneve6_tunnel_by_key = hash_create_mem (0,
    1109             :                                                 sizeof (geneve6_tunnel_key_t),
    1110             :                                                 sizeof (uword));
    1111         575 :   vxm->vtep_table = vtep_table_create ();
    1112         575 :   vxm->mcast_shared = hash_create_mem (0,
    1113             :                                        sizeof (ip46_address_t),
    1114             :                                        sizeof (mcast_shared_t));
    1115             : 
    1116         575 :   fib_node_register_type (FIB_NODE_TYPE_GENEVE_TUNNEL, &geneve_vft);
    1117             : 
    1118         575 :   return 0;
    1119             : }
    1120             : 
    1121        1151 : VLIB_INIT_FUNCTION (geneve_init);
    1122             : 
    1123             : /*
    1124             :  * fd.io coding-style-patch-verification: ON
    1125             :  *
    1126             :  * Local Variables:
    1127             :  * eval: (c-set-style "gnu")
    1128             :  * End:
    1129             :  */

Generated by: LCOV version 1.14