LCOV - code coverage report
Current view: top level - vnet/vxlan-gpe - vxlan_gpe.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 22 453 4.9 %
Date: 2023-07-05 22:20:52 Functions: 19 41 46.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       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             : /**
      16             :  *  @file
      17             :  *  @brief Common utility functions for IPv4 and IPv6 VXLAN GPE tunnels
      18             :  *
      19             : */
      20             : #include <vnet/vxlan-gpe/vxlan_gpe.h>
      21             : #include <vnet/fib/fib.h>
      22             : #include <vnet/ip/format.h>
      23             : #include <vnet/fib/fib_entry.h>
      24             : #include <vnet/fib/fib_table.h>
      25             : #include <vnet/fib/fib_entry_track.h>
      26             : #include <vnet/mfib/mfib_table.h>
      27             : #include <vnet/adj/adj_mcast.h>
      28             : #include <vnet/interface.h>
      29             : #include <vnet/udp/udp_local.h>
      30             : #include <vlib/vlib.h>
      31             : 
      32             : /**
      33             :  * @file
      34             :  * @brief VXLAN-GPE.
      35             :  *
      36             :  * VXLAN-GPE provides the features needed to allow L2 bridge domains (BDs)
      37             :  * to span multiple servers. This is done by building an L2 overlay on
      38             :  * top of an L3 network underlay using VXLAN-GPE tunnels.
      39             :  *
      40             :  * This makes it possible for servers to be co-located in the same data
      41             :  * center or be separated geographically as long as they are reachable
      42             :  * through the underlay L3 network.
      43             :  *
      44             :  * You can refer to this kind of L2 overlay bridge domain as a VXLAN-GPE segment.
      45             :  */
      46             : 
      47             : vxlan_gpe_main_t vxlan_gpe_main;
      48             : 
      49             : static u8 *
      50           0 : format_decap_next (u8 * s, va_list * args)
      51             : {
      52           0 :   vxlan_gpe_tunnel_t *t = va_arg (*args, vxlan_gpe_tunnel_t *);
      53             : 
      54           0 :   switch (t->protocol)
      55             :     {
      56           0 :     case VXLAN_GPE_PROTOCOL_IP4:
      57           0 :       s = format (s, "protocol ip4 fib-idx %d", t->decap_fib_index);
      58           0 :       break;
      59           0 :     case VXLAN_GPE_PROTOCOL_IP6:
      60           0 :       s = format (s, "protocol ip6 fib-idx %d", t->decap_fib_index);
      61           0 :       break;
      62           0 :     case VXLAN_GPE_PROTOCOL_ETHERNET:
      63           0 :       s = format (s, "protocol ethernet");
      64           0 :       break;
      65           0 :     case VXLAN_GPE_PROTOCOL_NSH:
      66           0 :       s = format (s, "protocol nsh");
      67           0 :       break;
      68           0 :     default:
      69           0 :       s = format (s, "protocol unknown %d", t->protocol);
      70             :     }
      71             : 
      72           0 :   return s;
      73             : }
      74             : 
      75             : /**
      76             :  * @brief Format function for VXLAN GPE tunnel
      77             :  *
      78             :  * @param *s formatting string
      79             :  * @param *args
      80             :  *
      81             :  * @return *s formatted string
      82             :  *
      83             :  */
      84             : u8 *
      85           0 : format_vxlan_gpe_tunnel (u8 * s, va_list * args)
      86             : {
      87           0 :   vxlan_gpe_tunnel_t *t = va_arg (*args, vxlan_gpe_tunnel_t *);
      88           0 :   vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
      89             : 
      90           0 :   s = format (s,
      91             :               "[%d] lcl %U rmt %U lcl_port %d rmt_port %d vni %d "
      92             :               "fib-idx %d sw-if-idx %d ",
      93           0 :               t - ngm->tunnels, format_ip46_address, &t->local, IP46_TYPE_ANY,
      94           0 :               format_ip46_address, &t->remote, IP46_TYPE_ANY, t->local_port,
      95           0 :               t->remote_port, t->vni, t->encap_fib_index, t->sw_if_index);
      96             : 
      97             : #if 0
      98             :   /* next_dpo not yet used by vxlan-gpe-encap node */
      99             :   s = format (s, "encap-dpo-idx %d ", t->next_dpo.dpoi_index);
     100             :   */
     101             : #endif
     102           0 :     s = format (s, "decap-next-%U ", format_decap_next, t);
     103             : 
     104           0 :   if (PREDICT_FALSE (ip46_address_is_multicast (&t->remote)))
     105           0 :     s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
     106             : 
     107           0 :   return s;
     108             : }
     109             : 
     110             : /**
     111             :  * @brief Naming for VXLAN GPE tunnel
     112             :  *
     113             :  * @param *s formatting string
     114             :  * @param *args
     115             :  *
     116             :  * @return *s formatted string
     117             :  *
     118             :  */
     119             : static u8 *
     120           0 : format_vxlan_gpe_name (u8 * s, va_list * args)
     121             : {
     122           0 :   u32 dev_instance = va_arg (*args, u32);
     123           0 :   return format (s, "vxlan_gpe_tunnel%d", dev_instance);
     124             : }
     125             : 
     126             : /**
     127             :  * @brief CLI function for VXLAN GPE admin up/down
     128             :  *
     129             :  * @param *vnm
     130             :  * @param hw_if_index
     131             :  * @param flag
     132             :  *
     133             :  * @return *rc
     134             :  *
     135             :  */
     136             : static clib_error_t *
     137           0 : vxlan_gpe_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     138             :                                    u32 flags)
     139             : {
     140           0 :   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
     141             :     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
     142           0 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     143             : 
     144           0 :   return 0;
     145             : }
     146             : 
     147             : /* *INDENT-OFF* */
     148       11199 : VNET_DEVICE_CLASS (vxlan_gpe_device_class,static) = {
     149             :   .name = "VXLAN_GPE",
     150             :   .format_device_name = format_vxlan_gpe_name,
     151             :   .format_tx_trace = format_vxlan_gpe_encap_trace,
     152             :   .admin_up_down_function = vxlan_gpe_interface_admin_up_down,
     153             : };
     154             : /* *INDENT-ON* */
     155             : 
     156             : 
     157             : /**
     158             :  * @brief Formatting function for tracing VXLAN GPE with length
     159             :  *
     160             :  * @param *s
     161             :  * @param *args
     162             :  *
     163             :  * @return *s
     164             :  *
     165             :  */
     166             : static u8 *
     167           0 : format_vxlan_gpe_header_with_length (u8 * s, va_list * args)
     168             : {
     169           0 :   u32 dev_instance = va_arg (*args, u32);
     170           0 :   s = format (s, "unimplemented dev %u", dev_instance);
     171           0 :   return s;
     172             : }
     173             : 
     174             : /* *INDENT-OFF* */
     175        7279 : VNET_HW_INTERFACE_CLASS (vxlan_gpe_hw_class) = {
     176             :   .name = "VXLAN_GPE",
     177             :   .format_header = format_vxlan_gpe_header_with_length,
     178             :   .build_rewrite = default_build_rewrite,
     179             : };
     180             : /* *INDENT-ON* */
     181             : 
     182             : static void
     183           0 : vxlan_gpe_tunnel_restack_dpo (vxlan_gpe_tunnel_t * t)
     184             : {
     185           0 :   dpo_id_t dpo = DPO_INVALID;
     186           0 :   u32 encap_index = vxlan_gpe_encap_node.index;
     187           0 :   fib_forward_chain_type_t forw_type = ip46_address_is_ip4 (&t->remote) ?
     188           0 :     FIB_FORW_CHAIN_TYPE_UNICAST_IP4 : FIB_FORW_CHAIN_TYPE_UNICAST_IP6;
     189             : 
     190           0 :   fib_entry_contribute_forwarding (t->fib_entry_index, forw_type, &dpo);
     191           0 :   dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
     192           0 :   dpo_reset (&dpo);
     193           0 : }
     194             : 
     195             : static vxlan_gpe_tunnel_t *
     196           0 : vxlan_gpe_tunnel_from_fib_node (fib_node_t * node)
     197             : {
     198           0 :   ASSERT (FIB_NODE_TYPE_VXLAN_GPE_TUNNEL == node->fn_type);
     199           0 :   return ((vxlan_gpe_tunnel_t *) (((char *) node) -
     200             :                                   STRUCT_OFFSET_OF (vxlan_gpe_tunnel_t,
     201             :                                                     node)));
     202             : }
     203             : 
     204             : /**
     205             :  * Function definition to backwalk a FIB node -
     206             :  * Here we will restack the new dpo of VXLAN_GPE DIP to encap node.
     207             :  */
     208             : static fib_node_back_walk_rc_t
     209           0 : vxlan_gpe_tunnel_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
     210             : {
     211           0 :   vxlan_gpe_tunnel_restack_dpo (vxlan_gpe_tunnel_from_fib_node (node));
     212           0 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     213             : }
     214             : 
     215             : /**
     216             :  * Function definition to get a FIB node from its index
     217             :  */
     218             : static fib_node_t *
     219           0 : vxlan_gpe_tunnel_fib_node_get (fib_node_index_t index)
     220             : {
     221             :   vxlan_gpe_tunnel_t *t;
     222           0 :   vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
     223             : 
     224           0 :   t = pool_elt_at_index (ngm->tunnels, index);
     225             : 
     226           0 :   return (&t->node);
     227             : }
     228             : 
     229             : /**
     230             :  * Function definition to inform the FIB node that its last lock has gone.
     231             :  */
     232             : static void
     233           0 : vxlan_gpe_tunnel_last_lock_gone (fib_node_t * node)
     234             : {
     235             :   /*
     236             :    * The VXLAN_GPE tunnel is a root of the graph. As such
     237             :    * it never has children and thus is never locked.
     238             :    */
     239           0 :   ASSERT (0);
     240           0 : }
     241             : 
     242             : /*
     243             :  * Virtual function table registered by VXLAN_GPE tunnels
     244             :  * for participation in the FIB object graph.
     245             :  */
     246             : const static fib_node_vft_t vxlan_gpe_vft = {
     247             :   .fnv_get = vxlan_gpe_tunnel_fib_node_get,
     248             :   .fnv_last_lock = vxlan_gpe_tunnel_last_lock_gone,
     249             :   .fnv_back_walk = vxlan_gpe_tunnel_back_walk,
     250             : };
     251             : 
     252             : #define foreach_gpe_copy_field                                                \
     253             :   _ (vni)                                                                     \
     254             :   _ (protocol)                                                                \
     255             :   _ (mcast_sw_if_index)                                                       \
     256             :   _ (encap_fib_index)                                                         \
     257             :   _ (decap_fib_index)                                                         \
     258             :   _ (local_port)                                                              \
     259             :   _ (remote_port)
     260             : 
     261             : #define foreach_copy_ipv4 {                     \
     262             :   _(local.ip4.as_u32)                           \
     263             :   _(remote.ip4.as_u32)                          \
     264             : }
     265             : 
     266             : #define foreach_copy_ipv6 {                     \
     267             :   _(local.ip6.as_u64[0])                        \
     268             :   _(local.ip6.as_u64[1])                        \
     269             :   _(remote.ip6.as_u64[0])                       \
     270             :   _(remote.ip6.as_u64[1])                       \
     271             : }
     272             : 
     273             : 
     274             : /**
     275             :  * @brief Calculate IPv4 VXLAN GPE rewrite header
     276             :  *
     277             :  * @param *t
     278             :  *
     279             :  * @return rc
     280             :  *
     281             :  */
     282             : int
     283           0 : vxlan4_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size,
     284             :                     u8 protocol_override, uword encap_next_node)
     285             : {
     286           0 :   u8 *rw = 0;
     287             :   ip4_header_t *ip0;
     288             :   ip4_vxlan_gpe_header_t *h0;
     289             :   int len;
     290             : 
     291           0 :   len = sizeof (*h0) + extension_size;
     292             : 
     293           0 :   vec_free (t->rewrite);
     294           0 :   vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
     295             : 
     296           0 :   h0 = (ip4_vxlan_gpe_header_t *) rw;
     297             : 
     298             :   /* Fixed portion of the (outer) ip4 header */
     299           0 :   ip0 = &h0->ip4;
     300           0 :   ip0->ip_version_and_header_length = 0x45;
     301           0 :   ip0->ttl = 254;
     302           0 :   ip0->protocol = IP_PROTOCOL_UDP;
     303             : 
     304             :   /* we fix up the ip4 header length and checksum after-the-fact */
     305           0 :   ip0->src_address.as_u32 = t->local.ip4.as_u32;
     306           0 :   ip0->dst_address.as_u32 = t->remote.ip4.as_u32;
     307           0 :   ip0->checksum = ip4_header_checksum (ip0);
     308             : 
     309             :   /* UDP header, randomize src port on something, maybe? */
     310           0 :   h0->udp.src_port = clib_host_to_net_u16 (t->local_port);
     311           0 :   h0->udp.dst_port = clib_host_to_net_u16 (t->remote_port);
     312             : 
     313             :   /* VXLAN header. Are we having fun yet? */
     314           0 :   h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
     315           0 :   h0->vxlan.ver_res = VXLAN_GPE_VERSION;
     316           0 :   if (protocol_override)
     317             :     {
     318           0 :       h0->vxlan.protocol = protocol_override;
     319             :     }
     320             :   else
     321             :     {
     322           0 :       h0->vxlan.protocol = t->protocol;
     323             :     }
     324           0 :   t->rewrite_size = sizeof (ip4_vxlan_gpe_header_t) + extension_size;
     325           0 :   h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni << 8);
     326             : 
     327           0 :   t->rewrite = rw;
     328           0 :   t->encap_next_node = encap_next_node;
     329           0 :   return (0);
     330             : }
     331             : 
     332             : /**
     333             :  * @brief Calculate IPv6 VXLAN GPE rewrite header
     334             :  *
     335             :  * @param *t
     336             :  *
     337             :  * @return rc
     338             :  *
     339             :  */
     340             : int
     341           0 : vxlan6_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size,
     342             :                     u8 protocol_override, uword encap_next_node)
     343             : {
     344           0 :   u8 *rw = 0;
     345             :   ip6_header_t *ip0;
     346             :   ip6_vxlan_gpe_header_t *h0;
     347             :   int len;
     348             : 
     349           0 :   len = sizeof (*h0) + extension_size;
     350             : 
     351           0 :   vec_free (t->rewrite);
     352           0 :   vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
     353             : 
     354           0 :   h0 = (ip6_vxlan_gpe_header_t *) rw;
     355             : 
     356             :   /* Fixed portion of the (outer) ip4 header */
     357           0 :   ip0 = &h0->ip6;
     358           0 :   ip0->ip_version_traffic_class_and_flow_label =
     359           0 :     clib_host_to_net_u32 (6 << 28);
     360           0 :   ip0->hop_limit = 255;
     361           0 :   ip0->protocol = IP_PROTOCOL_UDP;
     362             : 
     363           0 :   ip0->src_address.as_u64[0] = t->local.ip6.as_u64[0];
     364           0 :   ip0->src_address.as_u64[1] = t->local.ip6.as_u64[1];
     365           0 :   ip0->dst_address.as_u64[0] = t->remote.ip6.as_u64[0];
     366           0 :   ip0->dst_address.as_u64[1] = t->remote.ip6.as_u64[1];
     367             : 
     368             :   /* UDP header, randomize src port on something, maybe? */
     369           0 :   h0->udp.src_port = clib_host_to_net_u16 (t->local_port);
     370           0 :   h0->udp.dst_port = clib_host_to_net_u16 (t->remote_port);
     371             : 
     372             :   /* VXLAN header. Are we having fun yet? */
     373           0 :   h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P;
     374           0 :   h0->vxlan.ver_res = VXLAN_GPE_VERSION;
     375           0 :   if (protocol_override)
     376             :     {
     377           0 :       h0->vxlan.protocol = t->protocol;
     378             :     }
     379             :   else
     380             :     {
     381           0 :       h0->vxlan.protocol = protocol_override;
     382             :     }
     383           0 :   t->rewrite_size = sizeof (ip4_vxlan_gpe_header_t) + extension_size;
     384           0 :   h0->vxlan.vni_res = clib_host_to_net_u32 (t->vni << 8);
     385             : 
     386           0 :   t->rewrite = rw;
     387           0 :   t->encap_next_node = encap_next_node;
     388           0 :   return (0);
     389             : }
     390             : 
     391             : /* *INDENT-OFF* */
     392             : typedef CLIB_PACKED(union {
     393             :   struct {
     394             :     fib_node_index_t mfib_entry_index;
     395             :     adj_index_t mcast_adj_index;
     396             :   };
     397             :   u64 as_u64;
     398             : }) mcast_shared_t;
     399             : /* *INDENT-ON* */
     400             : 
     401             : static inline mcast_shared_t
     402           0 : mcast_shared_get (ip46_address_t * ip)
     403             : {
     404           0 :   ASSERT (ip46_address_is_multicast (ip));
     405           0 :   uword *p = hash_get_mem (vxlan_gpe_main.mcast_shared, ip);
     406           0 :   ALWAYS_ASSERT (p);
     407           0 :   return (mcast_shared_t)
     408             :   {
     409           0 :   .as_u64 = *p};
     410             : }
     411             : 
     412             : static inline void
     413           0 : mcast_shared_add (ip46_address_t * remote,
     414             :                   fib_node_index_t mfei, adj_index_t ai)
     415             : {
     416           0 :   mcast_shared_t new_ep = {
     417             :     .mcast_adj_index = ai,
     418             :     .mfib_entry_index = mfei,
     419             :   };
     420             : 
     421           0 :   hash_set_mem_alloc (&vxlan_gpe_main.mcast_shared, remote, new_ep.as_u64);
     422           0 : }
     423             : 
     424             : static inline void
     425           0 : mcast_shared_remove (ip46_address_t * remote)
     426             : {
     427           0 :   mcast_shared_t ep = mcast_shared_get (remote);
     428             : 
     429           0 :   adj_unlock (ep.mcast_adj_index);
     430           0 :   mfib_table_entry_delete_index (ep.mfib_entry_index, MFIB_SOURCE_VXLAN_GPE);
     431             : 
     432           0 :   hash_unset_mem_free (&vxlan_gpe_main.mcast_shared, remote);
     433           0 : }
     434             : 
     435             : /**
     436             :  * @brief Add or Del a VXLAN GPE tunnel
     437             :  *
     438             :  * @param *a
     439             :  * @param *sw_if_index
     440             :  *
     441             :  * @return rc
     442             :  *
     443             :  */
     444           0 : int vnet_vxlan_gpe_add_del_tunnel
     445             :   (vnet_vxlan_gpe_add_del_tunnel_args_t * a, u32 * sw_if_indexp)
     446             : {
     447           0 :   vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
     448           0 :   vxlan_gpe_tunnel_t *t = 0;
     449           0 :   vnet_main_t *vnm = ngm->vnet_main;
     450             :   vnet_hw_interface_t *hi;
     451             :   uword *p;
     452           0 :   u32 hw_if_index = ~0;
     453           0 :   u32 sw_if_index = ~0;
     454             :   int rv;
     455             :   vxlan4_gpe_tunnel_key_t key4, *key4_copy;
     456             :   vxlan6_gpe_tunnel_key_t key6, *key6_copy;
     457           0 :   u32 is_ip6 = a->is_ip6;
     458             : 
     459             :   /* Set udp-ports */
     460           0 :   if (a->local_port == 0)
     461           0 :     a->local_port = is_ip6 ? UDP_DST_PORT_VXLAN6_GPE : UDP_DST_PORT_VXLAN_GPE;
     462             : 
     463           0 :   if (a->remote_port == 0)
     464           0 :     a->remote_port = is_ip6 ? UDP_DST_PORT_VXLAN6_GPE : UDP_DST_PORT_VXLAN_GPE;
     465             : 
     466           0 :   if (!is_ip6)
     467             :     {
     468           0 :       key4.local = a->local.ip4.as_u32;
     469           0 :       key4.remote = a->remote.ip4.as_u32;
     470           0 :       key4.vni = clib_host_to_net_u32 (a->vni << 8);
     471           0 :       key4.port = (u32) clib_host_to_net_u16 (a->local_port);
     472             : 
     473           0 :       p = hash_get_mem (ngm->vxlan4_gpe_tunnel_by_key, &key4);
     474             :     }
     475             :   else
     476             :     {
     477           0 :       key6.local.as_u64[0] = a->local.ip6.as_u64[0];
     478           0 :       key6.local.as_u64[1] = a->local.ip6.as_u64[1];
     479           0 :       key6.remote.as_u64[0] = a->remote.ip6.as_u64[0];
     480           0 :       key6.remote.as_u64[1] = a->remote.ip6.as_u64[1];
     481           0 :       key6.vni = clib_host_to_net_u32 (a->vni << 8);
     482           0 :       key6.port = (u32) clib_host_to_net_u16 (a->local_port);
     483             : 
     484           0 :       p = hash_get_mem (ngm->vxlan6_gpe_tunnel_by_key, &key6);
     485             :     }
     486             : 
     487           0 :   if (a->is_add)
     488             :     {
     489           0 :       l2input_main_t *l2im = &l2input_main;
     490             : 
     491             :       /* adding a tunnel: tunnel must not already exist */
     492           0 :       if (p)
     493           0 :         return VNET_API_ERROR_TUNNEL_EXIST;
     494             : 
     495           0 :       pool_get_aligned (ngm->tunnels, t, CLIB_CACHE_LINE_BYTES);
     496           0 :       clib_memset (t, 0, sizeof (*t));
     497             : 
     498             :       /* copy from arg structure */
     499             : /* *INDENT-OFF* */
     500             : #define _(x) t->x = a->x;
     501           0 :       foreach_gpe_copy_field;
     502           0 :       if (!a->is_ip6)
     503           0 :         foreach_copy_ipv4
     504             :       else
     505           0 :         foreach_copy_ipv6
     506             : #undef _
     507             : /* *INDENT-ON* */
     508             : 
     509           0 :       if (!a->is_ip6)
     510           0 :         t->flags |= VXLAN_GPE_TUNNEL_IS_IPV4;
     511             : 
     512           0 :       if (!a->is_ip6)
     513             :         {
     514           0 :           rv = vxlan4_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP);
     515             :         }
     516             :       else
     517             :         {
     518           0 :           rv = vxlan6_gpe_rewrite (t, 0, 0, VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP);
     519             :         }
     520             : 
     521           0 :       if (rv)
     522             :         {
     523           0 :           pool_put (ngm->tunnels, t);
     524           0 :           return rv;
     525             :         }
     526             : 
     527           0 :       if (!is_ip6)
     528             :         {
     529           0 :           key4_copy = clib_mem_alloc (sizeof (*key4_copy));
     530           0 :           clib_memcpy_fast (key4_copy, &key4, sizeof (*key4_copy));
     531           0 :           hash_set_mem (ngm->vxlan4_gpe_tunnel_by_key, key4_copy,
     532             :                         t - ngm->tunnels);
     533             :         }
     534             :       else
     535             :         {
     536           0 :           key6_copy = clib_mem_alloc (sizeof (*key6_copy));
     537           0 :           clib_memcpy_fast (key6_copy, &key6, sizeof (*key6_copy));
     538           0 :           hash_set_mem (ngm->vxlan6_gpe_tunnel_by_key, key6_copy,
     539             :                         t - ngm->tunnels);
     540             :         }
     541             : 
     542           0 :       if (vec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices) > 0)
     543           0 :         {
     544           0 :           vnet_interface_main_t *im = &vnm->interface_main;
     545           0 :           hw_if_index = ngm->free_vxlan_gpe_tunnel_hw_if_indices
     546           0 :             [vec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices) - 1];
     547           0 :           vec_dec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices, 1);
     548             : 
     549           0 :           hi = vnet_get_hw_interface (vnm, hw_if_index);
     550           0 :           hi->dev_instance = t - ngm->tunnels;
     551           0 :           hi->hw_instance = hi->dev_instance;
     552             :           /* clear old stats of freed tunnel before reuse */
     553           0 :           sw_if_index = hi->sw_if_index;
     554           0 :           vnet_interface_counter_lock (im);
     555           0 :           vlib_zero_combined_counter
     556           0 :             (&im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
     557             :              sw_if_index);
     558           0 :           vlib_zero_combined_counter (&im->combined_sw_if_counters
     559             :                                       [VNET_INTERFACE_COUNTER_RX],
     560             :                                       sw_if_index);
     561           0 :           vlib_zero_simple_counter (&im->sw_if_counters
     562             :                                     [VNET_INTERFACE_COUNTER_DROP],
     563             :                                     sw_if_index);
     564           0 :           vnet_interface_counter_unlock (im);
     565             :         }
     566             :       else
     567             :         {
     568           0 :           hw_if_index = vnet_register_interface
     569           0 :             (vnm, vxlan_gpe_device_class.index, t - ngm->tunnels,
     570           0 :              vxlan_gpe_hw_class.index, t - ngm->tunnels);
     571           0 :           hi = vnet_get_hw_interface (vnm, hw_if_index);
     572             :         }
     573             : 
     574             :       /* Set vxlan-gpe tunnel output node */
     575           0 :       u32 encap_index = vxlan_gpe_encap_node.index;
     576           0 :       vnet_set_interface_output_node (vnm, hw_if_index, encap_index);
     577             : 
     578           0 :       t->hw_if_index = hw_if_index;
     579           0 :       t->sw_if_index = sw_if_index = hi->sw_if_index;
     580           0 :       vec_validate_init_empty (ngm->tunnel_index_by_sw_if_index, sw_if_index,
     581             :                                ~0);
     582           0 :       ngm->tunnel_index_by_sw_if_index[sw_if_index] = t - ngm->tunnels;
     583             : 
     584             :       /* setup l2 input config with l2 feature and bd 0 to drop packet */
     585           0 :       vec_validate (l2im->configs, sw_if_index);
     586           0 :       l2im->configs[sw_if_index].feature_bitmap = L2INPUT_FEAT_DROP;
     587           0 :       l2im->configs[sw_if_index].bd_index = 0;
     588             : 
     589           0 :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     590           0 :       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
     591           0 :       vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
     592             :                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     593           0 :       fib_node_init (&t->node, FIB_NODE_TYPE_VXLAN_GPE_TUNNEL);
     594             :       fib_prefix_t tun_remote_pfx;
     595           0 :       vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL;
     596             : 
     597           0 :       fib_protocol_t fp = fib_ip_proto (is_ip6);
     598           0 :       fib_prefix_from_ip46_addr (fp, &t->remote, &tun_remote_pfx);
     599           0 :       if (!ip46_address_is_multicast (&t->remote))
     600             :         {
     601             :           /* Unicast tunnel -
     602             :            * source the FIB entry for the tunnel's destination
     603             :            * and become a child thereof. The tunnel will then get poked
     604             :            * when the forwarding for the entry updates, and the tunnel can
     605             :            * re-stack accordingly
     606             :            */
     607           0 :           vtep_addr_ref (&ngm->vtep_table, t->encap_fib_index, &t->local);
     608           0 :           t->fib_entry_index = fib_entry_track (t->encap_fib_index,
     609             :                                                 &tun_remote_pfx,
     610             :                                                 FIB_NODE_TYPE_VXLAN_GPE_TUNNEL,
     611           0 :                                                 t - ngm->tunnels,
     612           0 :                                                 &t->sibling_index);
     613           0 :           vxlan_gpe_tunnel_restack_dpo (t);
     614             :         }
     615             :       else
     616             :         {
     617             :           /* Multicast tunnel -
     618             :            * as the same mcast group can be used for multiple mcast tunnels
     619             :            * with different VNIs, create the output fib adjacency only if
     620             :            * it does not already exist
     621             :            */
     622           0 :           if (vtep_addr_ref (&ngm->vtep_table,
     623           0 :                              t->encap_fib_index, &t->remote) == 1)
     624             :             {
     625             :               fib_node_index_t mfei;
     626             :               adj_index_t ai;
     627           0 :               fib_route_path_t path = {
     628           0 :                 .frp_proto = fib_proto_to_dpo (fp),
     629             :                 .frp_addr = zero_addr,
     630             :                 .frp_sw_if_index = 0xffffffff,
     631             :                 .frp_fib_index = ~0,
     632             :                 .frp_weight = 1,
     633             :                 .frp_flags = FIB_ROUTE_PATH_LOCAL,
     634             :                 .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
     635             :               };
     636           0 :               const mfib_prefix_t mpfx = {
     637             :                 .fp_proto = fp,
     638             :                 .fp_len = (is_ip6 ? 128 : 32),
     639             :                 .fp_grp_addr = tun_remote_pfx.fp_addr,
     640             :               };
     641             : 
     642             :               /*
     643             :                * Setup the (*,G) to receive traffic on the mcast group
     644             :                *  - the forwarding interface is for-us
     645             :                *  - the accepting interface is that from the API
     646             :                */
     647           0 :               mfib_table_entry_path_update (t->encap_fib_index, &mpfx,
     648             :                                             MFIB_SOURCE_VXLAN_GPE,
     649             :                                             MFIB_ENTRY_FLAG_NONE, &path);
     650             : 
     651           0 :               path.frp_sw_if_index = a->mcast_sw_if_index;
     652           0 :               path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
     653           0 :               path.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
     654           0 :               mfei = mfib_table_entry_path_update (
     655           0 :                 t->encap_fib_index, &mpfx, MFIB_SOURCE_VXLAN_GPE,
     656             :                 MFIB_ENTRY_FLAG_NONE, &path);
     657             : 
     658             :               /*
     659             :                * Create the mcast adjacency to send traffic to the group
     660             :                */
     661           0 :               ai = adj_mcast_add_or_lock (fp,
     662           0 :                                           fib_proto_to_link (fp),
     663             :                                           a->mcast_sw_if_index);
     664             : 
     665             :               /*
     666             :                * create a new end-point
     667             :                */
     668           0 :               mcast_shared_add (&t->remote, mfei, ai);
     669             :             }
     670             : 
     671           0 :           dpo_id_t dpo = DPO_INVALID;
     672           0 :           mcast_shared_t ep = mcast_shared_get (&t->remote);
     673             : 
     674             :           /* Stack shared mcast remote mac addr rewrite on encap */
     675           0 :           dpo_set (&dpo, DPO_ADJACENCY_MCAST,
     676           0 :                    fib_proto_to_dpo (fp), ep.mcast_adj_index);
     677             : 
     678           0 :           dpo_stack_from_node (encap_index, &t->next_dpo, &dpo);
     679           0 :           dpo_reset (&dpo);
     680           0 :           flood_class = VNET_FLOOD_CLASS_TUNNEL_MASTER;
     681             :         }
     682             : 
     683           0 :       vnet_get_sw_interface (vnet_get_main (), sw_if_index)->flood_class =
     684             :         flood_class;
     685             :     }
     686             :   else
     687             :     {
     688             :       /* deleting a tunnel: tunnel must exist */
     689           0 :       if (!p)
     690           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     691             : 
     692           0 :       t = pool_elt_at_index (ngm->tunnels, p[0]);
     693             : 
     694           0 :       sw_if_index = t->sw_if_index;
     695           0 :       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
     696           0 :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
     697           0 :       si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
     698           0 :       set_int_l2_mode (ngm->vlib_main, vnm, MODE_L3, t->sw_if_index, 0,
     699             :                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
     700           0 :       vec_add1 (ngm->free_vxlan_gpe_tunnel_hw_if_indices, t->hw_if_index);
     701             : 
     702           0 :       ngm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
     703             : 
     704           0 :       if (!is_ip6)
     705           0 :         hash_unset (ngm->vxlan4_gpe_tunnel_by_key, key4.as_u64);
     706             :       else
     707           0 :         hash_unset_mem_free (&ngm->vxlan6_gpe_tunnel_by_key, &key6);
     708             : 
     709           0 :       if (!ip46_address_is_multicast (&t->remote))
     710             :         {
     711           0 :           vtep_addr_unref (&ngm->vtep_table, t->encap_fib_index, &t->local);
     712           0 :           fib_entry_untrack (t->fib_entry_index, t->sibling_index);
     713             :         }
     714           0 :       else if (vtep_addr_unref (&ngm->vtep_table,
     715           0 :                                 t->encap_fib_index, &t->remote) == 0)
     716             :         {
     717           0 :           mcast_shared_remove (&t->remote);
     718             :         }
     719             : 
     720           0 :       fib_node_deinit (&t->node);
     721           0 :       vec_free (t->rewrite);
     722           0 :       pool_put (ngm->tunnels, t);
     723             :     }
     724             : 
     725           0 :   if (sw_if_indexp)
     726           0 :     *sw_if_indexp = sw_if_index;
     727             : 
     728           0 :   if (a->is_add)
     729             :     {
     730             :       /* register udp ports */
     731           0 :       if (!is_ip6 && !udp_is_valid_dst_port (a->local_port, 1))
     732           0 :         udp_register_dst_port (ngm->vlib_main, a->local_port,
     733             :                                vxlan4_gpe_input_node.index, 1 /* is_ip4 */);
     734           0 :       if (is_ip6 && !udp_is_valid_dst_port (a->remote_port, 0))
     735           0 :         udp_register_dst_port (ngm->vlib_main, a->remote_port,
     736             :                                vxlan6_gpe_input_node.index, 0 /* is_ip4 */);
     737             :     }
     738             : 
     739           0 :   return 0;
     740             : }
     741             : 
     742             : static clib_error_t *
     743           0 : vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm,
     744             :                                      unformat_input_t * input,
     745             :                                      vlib_cli_command_t * cmd)
     746             : {
     747           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     748           0 :   u8 is_add = 1;
     749             :   ip46_address_t local, remote;
     750           0 :   u8 local_set = 0;
     751           0 :   u8 remote_set = 0;
     752           0 :   u8 grp_set = 0;
     753           0 :   u8 ipv4_set = 0;
     754           0 :   u8 ipv6_set = 0;
     755           0 :   u32 mcast_sw_if_index = ~0;
     756           0 :   u32 encap_fib_index = 0;
     757           0 :   u32 decap_fib_index = 0;
     758           0 :   u8 protocol = VXLAN_GPE_PROTOCOL_IP4;
     759             :   u32 vni;
     760           0 :   u8 vni_set = 0;
     761           0 :   u32 local_port = 0;
     762           0 :   u32 remote_port = 0;
     763             :   int rv;
     764             :   u32 tmp;
     765           0 :   vnet_vxlan_gpe_add_del_tunnel_args_t _a, *a = &_a;
     766             :   u32 sw_if_index;
     767           0 :   clib_error_t *error = NULL;
     768             : 
     769             :   /* Get a line of input. */
     770           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     771           0 :     return 0;
     772             : 
     773           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     774             :     {
     775           0 :       if (unformat (line_input, "del"))
     776           0 :         is_add = 0;
     777           0 :       else if (unformat (line_input, "local %U",
     778             :                          unformat_ip4_address, &local.ip4))
     779             :         {
     780           0 :           local_set = 1;
     781           0 :           ipv4_set = 1;
     782             :         }
     783           0 :       else if (unformat (line_input, "remote %U",
     784             :                          unformat_ip4_address, &remote.ip4))
     785             :         {
     786           0 :           remote_set = 1;
     787           0 :           ipv4_set = 1;
     788             :         }
     789           0 :       else if (unformat (line_input, "local %U",
     790             :                          unformat_ip6_address, &local.ip6))
     791             :         {
     792           0 :           local_set = 1;
     793           0 :           ipv6_set = 1;
     794             :         }
     795           0 :       else if (unformat (line_input, "remote %U",
     796             :                          unformat_ip6_address, &remote.ip6))
     797             :         {
     798           0 :           remote_set = 1;
     799           0 :           ipv6_set = 1;
     800             :         }
     801           0 :       else if (unformat (line_input, "group %U %U",
     802             :                          unformat_ip4_address, &remote.ip4,
     803             :                          unformat_vnet_sw_interface,
     804             :                          vnet_get_main (), &mcast_sw_if_index))
     805             :         {
     806           0 :           grp_set = remote_set = 1;
     807           0 :           ipv4_set = 1;
     808             :         }
     809           0 :       else if (unformat (line_input, "group %U %U",
     810             :                          unformat_ip6_address, &remote.ip6,
     811             :                          unformat_vnet_sw_interface,
     812             :                          vnet_get_main (), &mcast_sw_if_index))
     813             :         {
     814           0 :           grp_set = remote_set = 1;
     815           0 :           ipv6_set = 1;
     816             :         }
     817           0 :       else if (unformat (line_input, "encap-vrf-id %d", &tmp))
     818             :         {
     819           0 :           if (ipv6_set)
     820           0 :             encap_fib_index = fib_table_find (FIB_PROTOCOL_IP6, tmp);
     821             :           else
     822           0 :             encap_fib_index = fib_table_find (FIB_PROTOCOL_IP4, tmp);
     823             : 
     824           0 :           if (encap_fib_index == ~0)
     825             :             {
     826             :               error =
     827           0 :                 clib_error_return (0, "nonexistent encap fib id %d", tmp);
     828           0 :               goto done;
     829             :             }
     830             :         }
     831           0 :       else if (unformat (line_input, "decap-vrf-id %d", &tmp))
     832             :         {
     833           0 :           if (ipv6_set)
     834           0 :             decap_fib_index = fib_table_find (FIB_PROTOCOL_IP6, tmp);
     835             :           else
     836           0 :             decap_fib_index = fib_table_find (FIB_PROTOCOL_IP4, tmp);
     837             : 
     838           0 :           if (decap_fib_index == ~0)
     839             :             {
     840             :               error =
     841           0 :                 clib_error_return (0, "nonexistent decap fib id %d", tmp);
     842           0 :               goto done;
     843             :             }
     844             :         }
     845           0 :       else if (unformat (line_input, "vni %d", &vni))
     846           0 :         vni_set = 1;
     847           0 :       else if (unformat (line_input, "local_port %d", &local_port))
     848             :         ;
     849           0 :       else if (unformat (line_input, "remote_port %d", &remote_port))
     850             :         ;
     851           0 :       else if (unformat (line_input, "next-ip4"))
     852           0 :         protocol = VXLAN_GPE_PROTOCOL_IP4;
     853           0 :       else if (unformat (line_input, "next-ip6"))
     854           0 :         protocol = VXLAN_GPE_PROTOCOL_IP6;
     855           0 :       else if (unformat (line_input, "next-ethernet"))
     856           0 :         protocol = VXLAN_GPE_PROTOCOL_ETHERNET;
     857           0 :       else if (unformat (line_input, "next-nsh"))
     858           0 :         protocol = VXLAN_GPE_PROTOCOL_NSH;
     859             :       else
     860             :         {
     861           0 :           error = clib_error_return (0, "parse error: '%U'",
     862             :                                      format_unformat_error, line_input);
     863           0 :           goto done;
     864             :         }
     865             :     }
     866             : 
     867           0 :   if (local_set == 0)
     868             :     {
     869           0 :       error = clib_error_return (0, "tunnel local address not specified");
     870           0 :       goto done;
     871             :     }
     872             : 
     873           0 :   if (remote_set == 0)
     874             :     {
     875           0 :       error = clib_error_return (0, "tunnel remote address not specified");
     876           0 :       goto done;
     877             :     }
     878             : 
     879           0 :   if (grp_set && !ip46_address_is_multicast (&remote))
     880             :     {
     881           0 :       error = clib_error_return (0, "tunnel group address not multicast");
     882           0 :       goto done;
     883             :     }
     884             : 
     885           0 :   if (grp_set == 0 && ip46_address_is_multicast (&remote))
     886             :     {
     887           0 :       error = clib_error_return (0, "remote address must be unicast");
     888           0 :       goto done;
     889             :     }
     890             : 
     891           0 :   if (grp_set && mcast_sw_if_index == ~0)
     892             :     {
     893           0 :       error = clib_error_return (0, "tunnel nonexistent multicast device");
     894           0 :       goto done;
     895             :     }
     896           0 :   if (ipv4_set && ipv6_set)
     897             :     {
     898           0 :       error = clib_error_return (0, "both IPv4 and IPv6 addresses specified");
     899           0 :       goto done;
     900             :     }
     901             : 
     902           0 :   if ((ipv4_set && memcmp (&local.ip4, &remote.ip4, sizeof (local.ip4)) == 0)
     903           0 :       || (ipv6_set
     904           0 :           && memcmp (&local.ip6, &remote.ip6, sizeof (local.ip6)) == 0))
     905             :     {
     906           0 :       error = clib_error_return (0, "src and remote addresses are identical");
     907           0 :       goto done;
     908             :     }
     909             : 
     910           0 :   if (vni_set == 0)
     911             :     {
     912           0 :       error = clib_error_return (0, "vni not specified");
     913           0 :       goto done;
     914             :     }
     915             : 
     916           0 :   clib_memset (a, 0, sizeof (*a));
     917             : 
     918           0 :   a->is_add = is_add;
     919           0 :   a->is_ip6 = ipv6_set;
     920             : 
     921             : /* *INDENT-OFF* */
     922             : #define _(x) a->x = x;
     923           0 :   foreach_gpe_copy_field;
     924           0 :   if (ipv4_set)
     925           0 :     foreach_copy_ipv4
     926             :   else
     927           0 :     foreach_copy_ipv6
     928             : #undef _
     929             : /* *INDENT-ON* */
     930             : 
     931           0 :   rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index);
     932             : 
     933           0 :   switch (rv)
     934             :     {
     935           0 :     case 0:
     936           0 :       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
     937             :                        vnet_get_main (), sw_if_index);
     938           0 :       break;
     939           0 :     case VNET_API_ERROR_INVALID_DECAP_NEXT:
     940           0 :       error = clib_error_return (0, "invalid decap-next...");
     941           0 :       goto done;
     942             : 
     943           0 :     case VNET_API_ERROR_TUNNEL_EXIST:
     944           0 :       error = clib_error_return (0, "tunnel already exists...");
     945           0 :       goto done;
     946             : 
     947           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     948           0 :       error = clib_error_return (0, "tunnel does not exist...");
     949           0 :       goto done;
     950             : 
     951           0 :     default:
     952           0 :       error = clib_error_return
     953             :         (0, "vnet_vxlan_gpe_add_del_tunnel returned %d", rv);
     954           0 :       goto done;
     955             :     }
     956             : 
     957           0 : done:
     958           0 :   unformat_free (line_input);
     959             : 
     960           0 :   return error;
     961             : }
     962             : 
     963             : /*?
     964             :  * Add or delete a VXLAN-GPE Tunnel.
     965             :  *
     966             :  * VXLAN-GPE provides the features needed to allow L2 bridge domains (BDs)
     967             :  * to span multiple servers. This is done by building an L2 overlay on
     968             :  * top of an L3 network underlay using VXLAN-GPE tunnels.
     969             :  *
     970             :  * This makes it possible for servers to be co-located in the same data
     971             :  * center or be separated geographically as long as they are reachable
     972             :  * through the underlay L3 network.
     973             :  *
     974             :  * You can refer to this kind of L2 overlay bridge domain as a VXLAN-GPE segment.
     975             :  *
     976             :  * @cliexpar
     977             :  * Example of how to create a VXLAN-GPE Tunnel:
     978             :  * @cliexcmd{create vxlan-gpe tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 encap-vrf-id 7}
     979             :  * Example of how to delete a VXLAN-GPE Tunnel:
     980             :  * @cliexcmd{create vxlan-gpe tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 del}
     981             :  ?*/
     982             : /* *INDENT-OFF* */
     983      272887 : VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = {
     984             :   .path = "create vxlan-gpe tunnel",
     985             :   .short_help =
     986             :   "create vxlan-gpe tunnel local <local-addr> "
     987             :   " {remote <remote-addr>|group <mcast-addr> <intf-name>}"
     988             :   " vni <nn> [next-ip4][next-ip6][next-ethernet][next-nsh]"
     989             :   " [encap-vrf-id <nn>] [decap-vrf-id <nn>] [del]\n",
     990             :   .function = vxlan_gpe_add_del_tunnel_command_fn,
     991             : };
     992             : /* *INDENT-ON* */
     993             : 
     994             : /**
     995             :  * @brief CLI function for showing VXLAN GPE tunnels
     996             :  *
     997             :  * @param *vm
     998             :  * @param *input
     999             :  * @param *cmd
    1000             :  *
    1001             :  * @return error
    1002             :  *
    1003             :  */
    1004             : static clib_error_t *
    1005           0 : show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm,
    1006             :                                   unformat_input_t * input,
    1007             :                                   vlib_cli_command_t * cmd)
    1008             : {
    1009           0 :   vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
    1010             :   vxlan_gpe_tunnel_t *t;
    1011             : 
    1012           0 :   if (pool_elts (ngm->tunnels) == 0)
    1013           0 :     vlib_cli_output (vm, "No vxlan-gpe tunnels configured.");
    1014             : 
    1015             :   /* *INDENT-OFF* */
    1016           0 :   pool_foreach (t, ngm->tunnels)
    1017             :    {
    1018           0 :     vlib_cli_output (vm, "%U", format_vxlan_gpe_tunnel, t);
    1019             :   }
    1020             :   /* *INDENT-ON* */
    1021             : 
    1022           0 :   return 0;
    1023             : }
    1024             : 
    1025             : /*?
    1026             :  * Display all the VXLAN-GPE Tunnel entries.
    1027             :  *
    1028             :  * @cliexpar
    1029             :  * Example of how to display the VXLAN-GPE Tunnel entries:
    1030             :  * @cliexstart{show vxlan-gpe tunnel}
    1031             :  * [0] local 10.0.3.1 remote 10.0.3.3 vni 13 encap_fib_index 0 sw_if_index 5 decap_next l2
    1032             :  * @cliexend
    1033             :  ?*/
    1034             : /* *INDENT-OFF* */
    1035      272887 : VLIB_CLI_COMMAND (show_vxlan_gpe_tunnel_command, static) = {
    1036             :     .path = "show vxlan-gpe",
    1037             :     .function = show_vxlan_gpe_tunnel_command_fn,
    1038             : };
    1039             : /* *INDENT-ON* */
    1040             : 
    1041             : void
    1042           0 : vnet_int_vxlan_gpe_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable)
    1043             : {
    1044           0 :   if (is_ip6)
    1045           0 :     vnet_feature_enable_disable ("ip6-unicast", "ip6-vxlan-gpe-bypass",
    1046             :                                  sw_if_index, is_enable, 0, 0);
    1047             :   else
    1048           0 :     vnet_feature_enable_disable ("ip4-unicast", "ip4-vxlan-gpe-bypass",
    1049             :                                  sw_if_index, is_enable, 0, 0);
    1050           0 : }
    1051             : 
    1052             : 
    1053             : static clib_error_t *
    1054           0 : set_ip_vxlan_gpe_bypass (u32 is_ip6,
    1055             :                          unformat_input_t * input, vlib_cli_command_t * cmd)
    1056             : {
    1057           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    1058           0 :   vnet_main_t *vnm = vnet_get_main ();
    1059           0 :   clib_error_t *error = 0;
    1060             :   u32 sw_if_index, is_enable;
    1061             : 
    1062           0 :   sw_if_index = ~0;
    1063           0 :   is_enable = 1;
    1064             : 
    1065           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    1066           0 :     return 0;
    1067             : 
    1068           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1069             :     {
    1070           0 :       if (unformat_user
    1071             :           (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index))
    1072             :         ;
    1073           0 :       else if (unformat (line_input, "del"))
    1074           0 :         is_enable = 0;
    1075             :       else
    1076             :         {
    1077           0 :           error = unformat_parse_error (line_input);
    1078           0 :           goto done;
    1079             :         }
    1080             :     }
    1081             : 
    1082           0 :   if (~0 == sw_if_index)
    1083             :     {
    1084           0 :       error = clib_error_return (0, "unknown interface `%U'",
    1085             :                                  format_unformat_error, line_input);
    1086           0 :       goto done;
    1087             :     }
    1088             : 
    1089           0 :   vnet_int_vxlan_gpe_bypass_mode (sw_if_index, is_ip6, is_enable);
    1090             : 
    1091           0 : done:
    1092           0 :   unformat_free (line_input);
    1093             : 
    1094           0 :   return error;
    1095             : }
    1096             : 
    1097             : static clib_error_t *
    1098           0 : set_ip4_vxlan_gpe_bypass (vlib_main_t * vm,
    1099             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
    1100             : {
    1101           0 :   return set_ip_vxlan_gpe_bypass (0, input, cmd);
    1102             : }
    1103             : 
    1104             : /*?
    1105             :  * This command adds the 'ip4-vxlan-gpe-bypass' graph node for a given
    1106             :  * interface. By adding the IPv4 vxlan-gpe-bypass graph node to an interface,
    1107             :  * the node checks for and validate input vxlan_gpe packet and bypass
    1108             :  * ip4-lookup, ip4-local, ip4-udp-lookup nodes to speedup vxlan_gpe packet
    1109             :  * forwarding. This node will cause extra overhead to for non-vxlan_gpe
    1110             :  * packets which is kept at a minimum.
    1111             :  *
    1112             :  * @cliexpar
    1113             :  * @parblock
    1114             :  * Example of graph node before ip4-vxlan-gpe-bypass is enabled:
    1115             :  * @cliexstart{show vlib graph ip4-vxlan-gpe-bypass}
    1116             :  *            Name                      Next                    Previous
    1117             :  * ip4-vxlan-gpe-bypass                error-drop [0]
    1118             :  *                                vxlan4-gpe-input [1]
    1119             :  *                                 ip4-lookup [2]
    1120             :  * @cliexend
    1121             :  *
    1122             :  * Example of how to enable ip4-vxlan-gpe-bypass on an interface:
    1123             :  * @cliexcmd{set interface ip vxlan-gpe-bypass GigabitEthernet2/0/0}
    1124             :  *
    1125             :  * Example of graph node after ip4-vxlan-gpe-bypass is enabled:
    1126             :  * @cliexstart{show vlib graph ip4-vxlan-gpe-bypass}
    1127             :  *            Name             Next                      Previous
    1128             :  * ip4-vxlan-gpe-bypass       error-drop [0]            ip4-input
    1129             :  *                       vxlan4-gpe-input [1]      ip4-input-no-checksum
    1130             :  *                        ip4-lookup [2]
    1131             :  * @cliexend
    1132             :  *
    1133             :  * Example of how to display the feature enabled on an interface:
    1134             :  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
    1135             :  * IP feature paths configured on GigabitEthernet2/0/0...
    1136             :  * ...
    1137             :  * ipv4 unicast:
    1138             :  *   ip4-vxlan-gpe-bypass
    1139             :  *   ip4-lookup
    1140             :  * ...
    1141             :  * @cliexend
    1142             :  *
    1143             :  * Example of how to disable ip4-vxlan-gpe-bypass on an interface:
    1144             :  * @cliexcmd{set interface ip vxlan-gpe-bypass GigabitEthernet2/0/0 del}
    1145             :  * @endparblock
    1146             : ?*/
    1147             : /* *INDENT-OFF* */
    1148      272887 : VLIB_CLI_COMMAND (set_interface_ip_vxlan_gpe_bypass_command, static) = {
    1149             :   .path = "set interface ip vxlan-gpe-bypass",
    1150             :   .function = set_ip4_vxlan_gpe_bypass,
    1151             :   .short_help = "set interface ip vxlan-gpe-bypass <interface> [del]",
    1152             : };
    1153             : /* *INDENT-ON* */
    1154             : 
    1155             : static clib_error_t *
    1156           0 : set_ip6_vxlan_gpe_bypass (vlib_main_t * vm,
    1157             :                           unformat_input_t * input, vlib_cli_command_t * cmd)
    1158             : {
    1159           0 :   return set_ip_vxlan_gpe_bypass (1, input, cmd);
    1160             : }
    1161             : 
    1162             : /*?
    1163             :  * This command adds the 'ip6-vxlan-gpe-bypass' graph node for a given
    1164             :  * interface. By adding the IPv6 vxlan-gpe-bypass graph node to an interface,
    1165             :  * the node checks for and validate input vxlan_gpe packet and bypass
    1166             :  * ip6-lookup, ip6-local, ip6-udp-lookup nodes to speedup vxlan_gpe packet
    1167             :  * forwarding. This node will cause extra overhead to for non-vxlan_gpe packets
    1168             :  * which is kept at a minimum.
    1169             :  *
    1170             :  * @cliexpar
    1171             :  * @parblock
    1172             :  * Example of graph node before ip6-vxlan-gpe-bypass is enabled:
    1173             :  * @cliexstart{show vlib graph ip6-vxlan-gpe-bypass}
    1174             :  *            Name                      Next                    Previous
    1175             :  * ip6-vxlan-gpe-bypass                error-drop [0]
    1176             :  *                                vxlan6-gpe-input [1]
    1177             :  *                                 ip6-lookup [2]
    1178             :  * @cliexend
    1179             :  *
    1180             :  * Example of how to enable ip6-vxlan-gpe-bypass on an interface:
    1181             :  * @cliexcmd{set interface ip6 vxlan-gpe-bypass GigabitEthernet2/0/0}
    1182             :  *
    1183             :  * Example of graph node after ip6-vxlan-gpe-bypass is enabled:
    1184             :  * @cliexstart{show vlib graph ip6-vxlan-gpe-bypass}
    1185             :  *            Name               Next                    Previous
    1186             :  * ip6-vxlan-gpe-bypass         error-drop [0]          ip6-input
    1187             :  *                         vxlan6-gpe-input [1]    ip4-input-no-checksum
    1188             :  *                          ip6-lookup [2]
    1189             :  * @cliexend
    1190             :  *
    1191             :  * Example of how to display the feature enabled on an interface:
    1192             :  * @cliexstart{show ip interface features GigabitEthernet2/0/0}
    1193             :  * IP feature paths configured on GigabitEthernet2/0/0...
    1194             :  * ...
    1195             :  * ipv6 unicast:
    1196             :  *   ip6-vxlan-gpe-bypass
    1197             :  *   ip6-lookup
    1198             :  * ...
    1199             :  * @cliexend
    1200             :  *
    1201             :  * Example of how to disable ip6-vxlan-gpe-bypass on an interface:
    1202             :  * @cliexcmd{set interface ip6 vxlan-gpe-bypass GigabitEthernet2/0/0 del}
    1203             :  * @endparblock
    1204             : ?*/
    1205             : /* *INDENT-OFF* */
    1206      272887 : VLIB_CLI_COMMAND (set_interface_ip6_vxlan_gpe_bypass_command, static) = {
    1207             :   .path = "set interface ip6 vxlan-gpe-bypass",
    1208             :   .function = set_ip6_vxlan_gpe_bypass,
    1209             :   .short_help = "set interface ip6 vxlan-gpe-bypass <interface> [del]",
    1210             : };
    1211             : /* *INDENT-ON* */
    1212             : 
    1213             : /* *INDENT-OFF* */
    1214       70583 : VNET_FEATURE_INIT (ip4_vxlan_gpe_bypass, static) =
    1215             : {
    1216             :   .arc_name = "ip4-unicast",
    1217             :   .node_name = "ip4-vxlan-gpe-bypass",
    1218             :   .runs_before = VNET_FEATURES ("ip4-lookup"),
    1219             : };
    1220             : 
    1221       70583 : VNET_FEATURE_INIT (ip6_vxlan_gpe_bypass, static) =
    1222             : {
    1223             :   .arc_name = "ip6-unicast",
    1224             :   .node_name = "ip6-vxlan-gpe-bypass",
    1225             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
    1226             : };
    1227             : /* *INDENT-ON* */
    1228             : 
    1229             : /**
    1230             :  * @brief Feature init function for VXLAN GPE
    1231             :  *
    1232             :  * @param *vm
    1233             :  *
    1234             :  * @return error
    1235             :  *
    1236             :  */
    1237             : clib_error_t *
    1238         559 : vxlan_gpe_init (vlib_main_t * vm)
    1239             : {
    1240         559 :   vxlan_gpe_main_t *ngm = &vxlan_gpe_main;
    1241             : 
    1242         559 :   ngm->vnet_main = vnet_get_main ();
    1243         559 :   ngm->vlib_main = vm;
    1244             : 
    1245             :   ngm->vxlan4_gpe_tunnel_by_key
    1246         559 :     = hash_create_mem (0, sizeof (vxlan4_gpe_tunnel_key_t), sizeof (uword));
    1247             : 
    1248             :   ngm->vxlan6_gpe_tunnel_by_key
    1249         559 :     = hash_create_mem (0, sizeof (vxlan6_gpe_tunnel_key_t), sizeof (uword));
    1250             : 
    1251             : 
    1252         559 :   ngm->mcast_shared = hash_create_mem (0,
    1253             :                                        sizeof (ip46_address_t),
    1254             :                                        sizeof (mcast_shared_t));
    1255         559 :   ngm->vtep_table = vtep_table_create ();
    1256             : 
    1257             :   /* Register the list of standard decap protocols supported */
    1258         559 :   vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IP4,
    1259             :                                      VXLAN_GPE_INPUT_NEXT_IP4_INPUT);
    1260         559 :   vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IP6,
    1261             :                                      VXLAN_GPE_INPUT_NEXT_IP6_INPUT);
    1262         559 :   vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_ETHERNET,
    1263             :                                      VXLAN_GPE_INPUT_NEXT_L2_INPUT);
    1264             : 
    1265         559 :   fib_node_register_type (FIB_NODE_TYPE_VXLAN_GPE_TUNNEL, &vxlan_gpe_vft);
    1266             : 
    1267         559 :   return 0;
    1268             : }
    1269             : 
    1270       64399 : VLIB_INIT_FUNCTION (vxlan_gpe_init);
    1271             : 
    1272             : 
    1273             : /*
    1274             :  * fd.io coding-style-patch-verification: ON
    1275             :  *
    1276             :  * Local Variables:
    1277             :  * eval: (c-set-style "gnu")
    1278             :  * End:
    1279             :  */

Generated by: LCOV version 1.14