LCOV - code coverage report
Current view: top level - plugins/gre - interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 233 368 63.3 %
Date: 2023-10-26 01:39:38 Functions: 22 28 78.6 %

          Line data    Source code
       1             : /*
       2             :  * gre_interface.c: gre interfaces
       3             :  *
       4             :  * Copyright (c) 2012 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vnet/vnet.h>
      19             : #include <gre/gre.h>
      20             : #include <vnet/ip/format.h>
      21             : #include <vnet/fib/fib_table.h>
      22             : #include <vnet/adj/adj_midchain.h>
      23             : #include <vnet/adj/adj_nbr.h>
      24             : #include <vnet/mpls/mpls.h>
      25             : #include <vnet/l2/l2_input.h>
      26             : #include <vnet/teib/teib.h>
      27             : 
      28             : u8 *
      29           0 : format_gre_tunnel_type (u8 *s, va_list *args)
      30             : {
      31           0 :   gre_tunnel_type_t type = va_arg (*args, int);
      32             : 
      33           0 :   switch (type)
      34             :     {
      35             : #define _(n, v)                                                               \
      36             :   case GRE_TUNNEL_TYPE_##n:                                                   \
      37             :     s = format (s, "%s", v);                                                  \
      38             :     break;
      39           0 :       foreach_gre_tunnel_type
      40             : #undef _
      41             :     }
      42             : 
      43           0 :   return (s);
      44             : }
      45             : 
      46             : static u8 *
      47           0 : format_gre_tunnel (u8 *s, va_list *args)
      48             : {
      49           0 :   gre_tunnel_t *t = va_arg (*args, gre_tunnel_t *);
      50             : 
      51           0 :   s = format (s, "[%d] instance %d src %U dst %U fib-idx %d sw-if-idx %d ",
      52             :               t->dev_instance, t->user_instance, format_ip46_address,
      53             :               &t->tunnel_src, IP46_TYPE_ANY, format_ip46_address,
      54             :               &t->tunnel_dst.fp_addr, IP46_TYPE_ANY, t->outer_fib_index,
      55             :               t->sw_if_index);
      56             : 
      57           0 :   s = format (s, "payload %U ", format_gre_tunnel_type, t->type);
      58           0 :   s = format (s, "%U ", format_tunnel_mode, t->mode);
      59             : 
      60           0 :   if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
      61           0 :     s = format (s, "session %d ", t->session_id);
      62             : 
      63           0 :   if (t->type != GRE_TUNNEL_TYPE_L3)
      64           0 :     s = format (s, "l2-adj-idx %d ", t->l2_adj_index);
      65             : 
      66           0 :   return s;
      67             : }
      68             : 
      69             : static gre_tunnel_t *
      70          95 : gre_tunnel_db_find (const vnet_gre_tunnel_add_del_args_t *a,
      71             :                     u32 outer_fib_index, gre_tunnel_key_t *key)
      72             : {
      73          95 :   gre_main_t *gm = &gre_main;
      74             :   uword *p;
      75             : 
      76          95 :   if (!a->is_ipv6)
      77             :     {
      78          79 :       gre_mk_key4 (a->src.ip4, a->dst.ip4, outer_fib_index, a->type, a->mode,
      79          79 :                    a->session_id, &key->gtk_v4);
      80         158 :       p = hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4);
      81             :     }
      82             :   else
      83             :     {
      84          16 :       gre_mk_key6 (&a->src.ip6, &a->dst.ip6, outer_fib_index, a->type, a->mode,
      85          16 :                    a->session_id, &key->gtk_v6);
      86          32 :       p = hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6);
      87             :     }
      88             : 
      89          95 :   if (NULL == p)
      90          47 :     return (NULL);
      91             : 
      92          48 :   return (pool_elt_at_index (gm->tunnels, p[0]));
      93             : }
      94             : 
      95             : static void
      96         120 : gre_tunnel_db_add (gre_tunnel_t *t, gre_tunnel_key_t *key)
      97             : {
      98         120 :   gre_main_t *gm = &gre_main;
      99             : 
     100         120 :   if (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6)
     101             :     {
     102          36 :       hash_set_mem_alloc (&gm->tunnel_by_key6, &key->gtk_v6, t->dev_instance);
     103             :     }
     104             :   else
     105             :     {
     106          84 :       hash_set_mem_alloc (&gm->tunnel_by_key4, &key->gtk_v4, t->dev_instance);
     107             :     }
     108         120 : }
     109             : 
     110             : static void
     111         120 : gre_tunnel_db_remove (gre_tunnel_t *t, gre_tunnel_key_t *key)
     112             : {
     113         120 :   gre_main_t *gm = &gre_main;
     114             : 
     115         120 :   if (t->tunnel_dst.fp_proto == FIB_PROTOCOL_IP6)
     116             :     {
     117          36 :       hash_unset_mem_free (&gm->tunnel_by_key6, &key->gtk_v6);
     118             :     }
     119             :   else
     120             :     {
     121          84 :       hash_unset_mem_free (&gm->tunnel_by_key4, &key->gtk_v4);
     122             :     }
     123         120 : }
     124             : 
     125             : /**
     126             :  * gre_tunnel_stack
     127             :  *
     128             :  * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
     129             :  */
     130             : void
     131          83 : gre_tunnel_stack (adj_index_t ai)
     132             : {
     133          83 :   gre_main_t *gm = &gre_main;
     134             :   ip_adjacency_t *adj;
     135             :   gre_tunnel_t *gt;
     136             :   u32 sw_if_index;
     137             : 
     138          83 :   adj = adj_get (ai);
     139          83 :   sw_if_index = adj->rewrite_header.sw_if_index;
     140             : 
     141          83 :   if ((vec_len (gm->tunnel_index_by_sw_if_index) <= sw_if_index) ||
     142          83 :       (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index]))
     143           0 :     return;
     144             : 
     145          83 :   gt = pool_elt_at_index (gm->tunnels,
     146             :                           gm->tunnel_index_by_sw_if_index[sw_if_index]);
     147             : 
     148          83 :   if ((vnet_hw_interface_get_flags (vnet_get_main (), gt->hw_if_index) &
     149             :        VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
     150             :     {
     151          36 :       adj_midchain_delegate_unstack (ai);
     152             :     }
     153             :   else
     154             :     {
     155          47 :       adj_midchain_delegate_stack (ai, gt->outer_fib_index, &gt->tunnel_dst);
     156             :     }
     157             : }
     158             : 
     159             : /**
     160             :  * mgre_tunnel_stack
     161             :  *
     162             :  * 'stack' (resolve the recursion for) the tunnel's midchain adjacency
     163             :  */
     164             : static void
     165          60 : mgre_tunnel_stack (adj_index_t ai)
     166             : {
     167          60 :   gre_main_t *gm = &gre_main;
     168             :   const ip_adjacency_t *adj;
     169             :   const gre_tunnel_t *gt;
     170             :   u32 sw_if_index;
     171             : 
     172          60 :   adj = adj_get (ai);
     173          60 :   sw_if_index = adj->rewrite_header.sw_if_index;
     174             : 
     175          60 :   if ((vec_len (gm->tunnel_index_by_sw_if_index) <= sw_if_index) ||
     176          60 :       (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index]))
     177           0 :     return;
     178             : 
     179          60 :   gt = pool_elt_at_index (gm->tunnels,
     180             :                           gm->tunnel_index_by_sw_if_index[sw_if_index]);
     181             : 
     182          60 :   if ((vnet_hw_interface_get_flags (vnet_get_main (), gt->hw_if_index) &
     183             :        VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
     184             :     {
     185          36 :       adj_midchain_delegate_unstack (ai);
     186             :     }
     187             :   else
     188             :     {
     189             :       const teib_entry_t *ne;
     190             : 
     191          24 :       ne = teib_entry_find_46 (sw_if_index, adj->ia_nh_proto,
     192             :                                &adj->sub_type.nbr.next_hop);
     193          24 :       if (NULL != ne)
     194          18 :         teib_entry_adj_stack (ne, ai);
     195             :     }
     196             : }
     197             : 
     198             : /**
     199             :  * @brief Call back when restacking all adjacencies on a GRE interface
     200             :  */
     201             : static adj_walk_rc_t
     202          36 : gre_adj_walk_cb (adj_index_t ai, void *ctx)
     203             : {
     204          36 :   gre_tunnel_stack (ai);
     205             : 
     206          36 :   return (ADJ_WALK_RC_CONTINUE);
     207             : }
     208             : static adj_walk_rc_t
     209          60 : mgre_adj_walk_cb (adj_index_t ai, void *ctx)
     210             : {
     211          60 :   mgre_tunnel_stack (ai);
     212             : 
     213          60 :   return (ADJ_WALK_RC_CONTINUE);
     214             : }
     215             : 
     216             : static void
     217         116 : gre_tunnel_restack (gre_tunnel_t *gt)
     218             : {
     219             :   fib_protocol_t proto;
     220             : 
     221             :   /*
     222             :    * walk all the adjacencies on th GRE interface and restack them
     223             :    */
     224         348 :   FOR_EACH_FIB_IP_PROTOCOL (proto)
     225             :   {
     226         232 :     switch (gt->mode)
     227             :       {
     228         156 :       case TUNNEL_MODE_P2P:
     229         156 :         adj_nbr_walk (gt->sw_if_index, proto, gre_adj_walk_cb, NULL);
     230         156 :         break;
     231          76 :       case TUNNEL_MODE_MP:
     232          76 :         adj_nbr_walk (gt->sw_if_index, proto, mgre_adj_walk_cb, NULL);
     233          76 :         break;
     234             :       }
     235         232 :   }
     236         116 : }
     237             : 
     238             : static void
     239         146 : gre_teib_mk_key (const gre_tunnel_t *t, const teib_entry_t *ne,
     240             :                  gre_tunnel_key_t *key)
     241             : {
     242             :   const fib_prefix_t *nh;
     243             : 
     244         146 :   nh = teib_entry_get_nh (ne);
     245             : 
     246             :   /* construct the key using mode P2P so it can be found in the DP */
     247         146 :   if (FIB_PROTOCOL_IP4 == nh->fp_proto)
     248          90 :     gre_mk_key4 (t->tunnel_src.ip4, nh->fp_addr.ip4,
     249          90 :                  teib_entry_get_fib_index (ne), t->type, TUNNEL_MODE_P2P, 0,
     250             :                  &key->gtk_v4);
     251             :   else
     252          56 :     gre_mk_key6 (&t->tunnel_src.ip6, &nh->fp_addr.ip6,
     253          56 :                  teib_entry_get_fib_index (ne), t->type, TUNNEL_MODE_P2P, 0,
     254             :                  &key->gtk_v6);
     255         146 : }
     256             : 
     257             : /**
     258             :  * An TEIB entry has been added
     259             :  */
     260             : static void
     261          85 : gre_teib_entry_added (const teib_entry_t *ne)
     262             : {
     263          85 :   gre_main_t *gm = &gre_main;
     264             :   const ip_address_t *nh;
     265             :   gre_tunnel_key_t key;
     266             :   gre_tunnel_t *t;
     267             :   u32 sw_if_index;
     268             :   u32 t_idx;
     269             : 
     270          85 :   sw_if_index = teib_entry_get_sw_if_index (ne);
     271          85 :   if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
     272          12 :     return;
     273             : 
     274          73 :   t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
     275             : 
     276          73 :   if (INDEX_INVALID == t_idx)
     277           0 :     return;
     278             : 
     279             :   /* entry has been added on an interface for which there is a GRE tunnel */
     280          73 :   t = pool_elt_at_index (gm->tunnels, t_idx);
     281             : 
     282          73 :   if (t->mode != TUNNEL_MODE_MP)
     283           0 :     return;
     284             : 
     285             :   /* the next-hop (underlay) of the NHRP entry will form part of the key for
     286             :    * ingress lookup to match packets to this interface */
     287          73 :   gre_teib_mk_key (t, ne, &key);
     288          73 :   gre_tunnel_db_add (t, &key);
     289             : 
     290             :   /* update the rewrites for each of the adjacencies for this peer (overlay)
     291             :    * using  the next-hop (underlay) */
     292          73 :   mgre_walk_ctx_t ctx = { .t = t, .ne = ne };
     293          73 :   nh = teib_entry_get_peer (ne);
     294          73 :   adj_nbr_walk_nh (
     295             :     teib_entry_get_sw_if_index (ne),
     296          73 :     (AF_IP4 == ip_addr_version (nh) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6),
     297             :     &ip_addr_46 (nh), mgre_mk_complete_walk, &ctx);
     298             : }
     299             : 
     300             : static void
     301          85 : gre_teib_entry_deleted (const teib_entry_t *ne)
     302             : {
     303          85 :   gre_main_t *gm = &gre_main;
     304             :   const ip_address_t *nh;
     305             :   gre_tunnel_key_t key;
     306             :   gre_tunnel_t *t;
     307             :   u32 sw_if_index;
     308             :   u32 t_idx;
     309             : 
     310          85 :   sw_if_index = teib_entry_get_sw_if_index (ne);
     311          85 :   if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
     312          12 :     return;
     313             : 
     314          73 :   t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
     315             : 
     316          73 :   if (INDEX_INVALID == t_idx)
     317           0 :     return;
     318             : 
     319          73 :   t = pool_elt_at_index (gm->tunnels, t_idx);
     320             : 
     321             :   /* remove the next-hop as an ingress lookup key */
     322          73 :   gre_teib_mk_key (t, ne, &key);
     323          73 :   gre_tunnel_db_remove (t, &key);
     324             : 
     325          73 :   nh = teib_entry_get_peer (ne);
     326             : 
     327             :   /* make all the adjacencies incomplete */
     328          73 :   adj_nbr_walk_nh (
     329             :     teib_entry_get_sw_if_index (ne),
     330          73 :     (AF_IP4 == ip_addr_version (nh) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6),
     331             :     &ip_addr_46 (nh), mgre_mk_incomplete_walk, t);
     332             : }
     333             : 
     334             : static walk_rc_t
     335           0 : gre_tunnel_delete_teib_walk (index_t nei, void *ctx)
     336             : {
     337           0 :   gre_tunnel_t *t = ctx;
     338             :   gre_tunnel_key_t key;
     339             : 
     340           0 :   gre_teib_mk_key (t, teib_entry_get (nei), &key);
     341           0 :   gre_tunnel_db_remove (t, &key);
     342             : 
     343           0 :   return (WALK_CONTINUE);
     344             : }
     345             : 
     346             : static walk_rc_t
     347           0 : gre_tunnel_add_teib_walk (index_t nei, void *ctx)
     348             : {
     349           0 :   gre_tunnel_t *t = ctx;
     350           0 :   gre_tunnel_key_t key = {};
     351             : 
     352           0 :   gre_teib_mk_key (t, teib_entry_get (nei), &key);
     353           0 :   gre_tunnel_db_add (t, &key);
     354             : 
     355           0 :   return (WALK_CONTINUE);
     356             : }
     357             : 
     358             : static int
     359          48 : vnet_gre_tunnel_add (vnet_gre_tunnel_add_del_args_t *a, u32 outer_fib_index,
     360             :                      u32 *sw_if_indexp)
     361             : {
     362          48 :   gre_main_t *gm = &gre_main;
     363          48 :   vnet_main_t *vnm = gm->vnet_main;
     364             :   gre_tunnel_t *t;
     365             :   vnet_hw_interface_t *hi;
     366             :   u32 hw_if_index, sw_if_index;
     367          48 :   u8 is_ipv6 = a->is_ipv6;
     368             :   gre_tunnel_key_t key;
     369             : 
     370          48 :   t = gre_tunnel_db_find (a, outer_fib_index, &key);
     371          48 :   if (NULL != t)
     372           1 :     return VNET_API_ERROR_IF_ALREADY_EXISTS;
     373             : 
     374          47 :   pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
     375          47 :   clib_memset (t, 0, sizeof (*t));
     376             : 
     377             :   /* Reconcile the real dev_instance and a possible requested instance */
     378          47 :   u32 t_idx = t - gm->tunnels; /* tunnel index (or instance) */
     379          47 :   u32 u_idx = a->instance;     /* user specified instance */
     380          47 :   if (u_idx == ~0)
     381          47 :     u_idx = t_idx;
     382          47 :   if (hash_get (gm->instance_used, u_idx))
     383             :     {
     384           0 :       pool_put (gm->tunnels, t);
     385           0 :       return VNET_API_ERROR_INSTANCE_IN_USE;
     386             :     }
     387          47 :   hash_set (gm->instance_used, u_idx, 1);
     388             : 
     389          47 :   t->dev_instance = t_idx;  /* actual */
     390          47 :   t->user_instance = u_idx; /* name */
     391             : 
     392          47 :   t->type = a->type;
     393          47 :   t->mode = a->mode;
     394          47 :   t->flags = a->flags;
     395          47 :   if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
     396           1 :     t->session_id = a->session_id;
     397             : 
     398          47 :   if (t->type == GRE_TUNNEL_TYPE_L3)
     399             :     {
     400          31 :       if (t->mode == TUNNEL_MODE_P2P)
     401             :         hw_if_index =
     402          24 :           vnet_register_interface (vnm, gre_device_class.index, t_idx,
     403             :                                    gre_hw_interface_class.index, t_idx);
     404             :       else
     405             :         hw_if_index =
     406           7 :           vnet_register_interface (vnm, gre_device_class.index, t_idx,
     407             :                                    mgre_hw_interface_class.index, t_idx);
     408             :     }
     409             :   else
     410             :     {
     411          16 :       vnet_eth_interface_registration_t eir = {};
     412             : 
     413             :       /* Default MAC address (d00b:eed0:0000 + sw_if_index) */
     414          16 :       u8 address[6] = {
     415          16 :         0xd0, 0x0b, 0xee, 0xd0, (u8) (t_idx >> 8), (u8) t_idx
     416             :       };
     417             : 
     418          16 :       eir.dev_class_index = gre_device_class.index;
     419          16 :       eir.dev_instance = t_idx;
     420          16 :       eir.address = address;
     421          16 :       hw_if_index = vnet_eth_register_interface (vnm, &eir);
     422             :     }
     423             : 
     424             :   /* Set GRE tunnel interface output node (not used for L3 payload) */
     425          47 :   if (GRE_TUNNEL_TYPE_ERSPAN == t->type)
     426           1 :     vnet_set_interface_output_node (vnm, hw_if_index,
     427             :                                     gre_erspan_encap_node.index);
     428             :   else
     429          46 :     vnet_set_interface_output_node (vnm, hw_if_index,
     430             :                                     gre_teb_encap_node.index);
     431             : 
     432          47 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     433          47 :   sw_if_index = hi->sw_if_index;
     434             : 
     435          47 :   t->hw_if_index = hw_if_index;
     436          47 :   t->outer_fib_index = outer_fib_index;
     437          47 :   t->sw_if_index = sw_if_index;
     438          47 :   t->l2_adj_index = ADJ_INDEX_INVALID;
     439             : 
     440         135 :   vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
     441          47 :   gm->tunnel_index_by_sw_if_index[sw_if_index] = t_idx;
     442             : 
     443          47 :   if (!is_ipv6)
     444             :     {
     445          39 :       hi->frame_overhead = sizeof (gre_header_t) + sizeof (ip4_header_t);
     446          39 :       hi->min_frame_size = hi->frame_overhead + 64;
     447             :     }
     448             :   else
     449             :     {
     450           8 :       hi->frame_overhead = sizeof (gre_header_t) + sizeof (ip6_header_t);
     451           8 :       hi->min_frame_size = hi->frame_overhead + 64;
     452             :     }
     453             : 
     454             :   /* Standard default gre MTU. */
     455          47 :   vnet_sw_interface_set_mtu (vnm, sw_if_index, 9000);
     456             : 
     457             :   /*
     458             :    * source the FIB entry for the tunnel's destination
     459             :    * and become a child thereof. The tunnel will then get poked
     460             :    * when the forwarding for the entry updates, and the tunnel can
     461             :    * re-stack accordingly
     462             :    */
     463             : 
     464          47 :   clib_memcpy (&t->tunnel_src, &a->src, sizeof (t->tunnel_src));
     465          47 :   t->tunnel_dst.fp_len = !is_ipv6 ? 32 : 128;
     466          47 :   t->tunnel_dst.fp_proto = !is_ipv6 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
     467          47 :   t->tunnel_dst.fp_addr = a->dst;
     468             : 
     469          47 :   gre_tunnel_db_add (t, &key);
     470             : 
     471          47 :   if (t->mode == TUNNEL_MODE_MP)
     472           7 :     teib_walk_itf (t->sw_if_index, gre_tunnel_add_teib_walk, t);
     473             : 
     474          47 :   if (t->type == GRE_TUNNEL_TYPE_ERSPAN)
     475             :     {
     476             :       gre_sn_key_t skey;
     477             :       gre_sn_t *gre_sn;
     478             : 
     479           1 :       gre_mk_sn_key (t, &skey);
     480           1 :       gre_sn = (gre_sn_t *) hash_get_mem (gm->seq_num_by_key, &skey);
     481           1 :       if (gre_sn != NULL)
     482             :         {
     483           0 :           gre_sn->ref_count++;
     484           0 :           t->gre_sn = gre_sn;
     485             :         }
     486             :       else
     487             :         {
     488           1 :           gre_sn = clib_mem_alloc (sizeof (gre_sn_t));
     489           1 :           gre_sn->seq_num = 0;
     490           1 :           gre_sn->ref_count = 1;
     491           1 :           t->gre_sn = gre_sn;
     492           1 :           hash_set_mem_alloc (&gm->seq_num_by_key, &skey, (uword) gre_sn);
     493             :         }
     494             :     }
     495             : 
     496          47 :   if (t->type != GRE_TUNNEL_TYPE_L3)
     497             :     {
     498          32 :       t->l2_adj_index = adj_nbr_add_or_lock (
     499          16 :         t->tunnel_dst.fp_proto, VNET_LINK_ETHERNET, &zero_addr, sw_if_index);
     500          16 :       vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
     501             :                                          (u8 *) "tunnel-output-no-count");
     502          16 :       gre_update_adj (vnm, t->sw_if_index, t->l2_adj_index);
     503             :     }
     504             :   else
     505             :     {
     506          31 :       vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
     507             :                                          (u8 *) "tunnel-output");
     508             :     }
     509          47 :   if (sw_if_indexp)
     510          47 :     *sw_if_indexp = sw_if_index;
     511             : 
     512             :   /* register gre46-input nodes */
     513          47 :   ip4_register_protocol (IP_PROTOCOL_GRE, gre4_input_node.index);
     514          47 :   ip6_register_protocol (IP_PROTOCOL_GRE, gre6_input_node.index);
     515             : 
     516          47 :   return 0;
     517             : }
     518             : 
     519             : static int
     520          47 : vnet_gre_tunnel_delete (vnet_gre_tunnel_add_del_args_t *a, u32 outer_fib_index,
     521             :                         u32 *sw_if_indexp)
     522             : {
     523          47 :   gre_main_t *gm = &gre_main;
     524          47 :   vnet_main_t *vnm = gm->vnet_main;
     525             :   gre_tunnel_t *t;
     526             :   gre_tunnel_key_t key;
     527             :   u32 sw_if_index;
     528             : 
     529          47 :   t = gre_tunnel_db_find (a, outer_fib_index, &key);
     530          47 :   if (NULL == t)
     531           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     532             : 
     533          47 :   if (t->mode == TUNNEL_MODE_MP)
     534           7 :     teib_walk_itf (t->sw_if_index, gre_tunnel_delete_teib_walk, t);
     535             : 
     536          47 :   sw_if_index = t->sw_if_index;
     537          47 :   vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */);
     538             : 
     539             :   /* make sure tunnel is removed from l2 bd or xconnect */
     540          47 :   set_int_l2_mode (gm->vlib_main, vnm, MODE_L3, sw_if_index, 0,
     541             :                    L2_BD_PORT_TYPE_NORMAL, 0, 0);
     542          47 :   gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
     543             : 
     544          47 :   if (t->type == GRE_TUNNEL_TYPE_L3)
     545          31 :     vnet_delete_hw_interface (vnm, t->hw_if_index);
     546             :   else
     547          16 :     ethernet_delete_interface (vnm, t->hw_if_index);
     548             : 
     549          47 :   if (t->l2_adj_index != ADJ_INDEX_INVALID)
     550             :     {
     551          16 :       adj_midchain_delegate_unstack (t->l2_adj_index);
     552          16 :       adj_unlock (t->l2_adj_index);
     553             :     }
     554             : 
     555          47 :   ASSERT ((t->type != GRE_TUNNEL_TYPE_ERSPAN) || (t->gre_sn != NULL));
     556          47 :   if ((t->type == GRE_TUNNEL_TYPE_ERSPAN) && (t->gre_sn->ref_count-- == 1))
     557             :     {
     558             :       gre_sn_key_t skey;
     559           1 :       gre_mk_sn_key (t, &skey);
     560           1 :       hash_unset_mem_free (&gm->seq_num_by_key, &skey);
     561           1 :       clib_mem_free (t->gre_sn);
     562             :     }
     563             : 
     564          47 :   vnet_reset_interface_l3_output_node (gm->vlib_main, sw_if_index);
     565          47 :   hash_unset (gm->instance_used, t->user_instance);
     566          47 :   gre_tunnel_db_remove (t, &key);
     567          47 :   pool_put (gm->tunnels, t);
     568             : 
     569          47 :   if (sw_if_indexp)
     570          47 :     *sw_if_indexp = sw_if_index;
     571             : 
     572          47 :   return 0;
     573             : }
     574             : 
     575             : int
     576          95 : vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t *a, u32 *sw_if_indexp)
     577             : {
     578             :   u32 outer_fib_index;
     579             : 
     580          95 :   outer_fib_index = fib_table_find (
     581          95 :     (a->is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4), a->outer_table_id);
     582             : 
     583          95 :   if (~0 == outer_fib_index)
     584           0 :     return VNET_API_ERROR_NO_SUCH_FIB;
     585             : 
     586          95 :   if (a->session_id > GTK_SESSION_ID_MAX)
     587           0 :     return VNET_API_ERROR_INVALID_SESSION_ID;
     588             : 
     589          95 :   if (a->mode == TUNNEL_MODE_MP && !ip46_address_is_zero (&a->dst))
     590           0 :     return (VNET_API_ERROR_INVALID_DST_ADDRESS);
     591             : 
     592          95 :   if (a->is_add)
     593          48 :     return (vnet_gre_tunnel_add (a, outer_fib_index, sw_if_indexp));
     594             :   else
     595          47 :     return (vnet_gre_tunnel_delete (a, outer_fib_index, sw_if_indexp));
     596             : }
     597             : 
     598             : clib_error_t *
     599         116 : gre_interface_admin_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
     600             : {
     601         116 :   gre_main_t *gm = &gre_main;
     602             :   vnet_hw_interface_t *hi;
     603             :   gre_tunnel_t *t;
     604             :   u32 ti;
     605             : 
     606         116 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     607             : 
     608         232 :   if (NULL == gm->tunnel_index_by_sw_if_index ||
     609         116 :       hi->sw_if_index >= vec_len (gm->tunnel_index_by_sw_if_index))
     610           0 :     return (NULL);
     611             : 
     612         116 :   ti = gm->tunnel_index_by_sw_if_index[hi->sw_if_index];
     613             : 
     614         116 :   if (~0 == ti)
     615             :     /* not one of ours */
     616           0 :     return (NULL);
     617             : 
     618         116 :   t = pool_elt_at_index (gm->tunnels, ti);
     619             : 
     620         116 :   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     621          58 :     vnet_hw_interface_set_flags (vnm, hw_if_index,
     622             :                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
     623             :   else
     624          58 :     vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
     625             : 
     626         116 :   gre_tunnel_restack (t);
     627             : 
     628         116 :   return /* no error */ 0;
     629             : }
     630             : 
     631             : static clib_error_t *
     632           0 : create_gre_tunnel_command_fn (vlib_main_t *vm, unformat_input_t *input,
     633             :                               vlib_cli_command_t *cmd)
     634             : {
     635           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     636           0 :   vnet_gre_tunnel_add_del_args_t _a, *a = &_a;
     637           0 :   ip46_address_t src = ip46_address_initializer,
     638           0 :                  dst = ip46_address_initializer;
     639           0 :   u32 instance = ~0;
     640           0 :   u32 outer_table_id = 0;
     641           0 :   gre_tunnel_type_t t_type = GRE_TUNNEL_TYPE_L3;
     642           0 :   tunnel_mode_t t_mode = TUNNEL_MODE_P2P;
     643           0 :   tunnel_encap_decap_flags_t flags = TUNNEL_ENCAP_DECAP_FLAG_NONE;
     644           0 :   u32 session_id = 0;
     645             :   int rv;
     646           0 :   u8 is_add = 1;
     647             :   u32 sw_if_index;
     648           0 :   clib_error_t *error = NULL;
     649             : 
     650             :   /* Get a line of input. */
     651           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     652           0 :     return 0;
     653             : 
     654           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     655             :     {
     656           0 :       if (unformat (line_input, "del"))
     657           0 :         is_add = 0;
     658           0 :       else if (unformat (line_input, "instance %d", &instance))
     659             :         ;
     660           0 :       else if (unformat (line_input, "src %U", unformat_ip46_address, &src))
     661             :         ;
     662           0 :       else if (unformat (line_input, "dst %U", unformat_ip46_address, &dst))
     663             :         ;
     664           0 :       else if (unformat (line_input, "outer-table-id %d", &outer_table_id))
     665             :         ;
     666           0 :       else if (unformat (line_input, "multipoint"))
     667           0 :         t_mode = TUNNEL_MODE_MP;
     668           0 :       else if (unformat (line_input, "teb"))
     669           0 :         t_type = GRE_TUNNEL_TYPE_TEB;
     670           0 :       else if (unformat (line_input, "erspan %d", &session_id))
     671           0 :         t_type = GRE_TUNNEL_TYPE_ERSPAN;
     672           0 :       else if (unformat (line_input, "flags %U",
     673             :                          unformat_tunnel_encap_decap_flags, &flags))
     674             :         ;
     675             :       else
     676             :         {
     677           0 :           error = clib_error_return (0, "unknown input `%U'",
     678             :                                      format_unformat_error, line_input);
     679           0 :           goto done;
     680             :         }
     681             :     }
     682             : 
     683           0 :   if (ip46_address_is_equal (&src, &dst))
     684             :     {
     685           0 :       error = clib_error_return (0, "src and dst are identical");
     686           0 :       goto done;
     687             :     }
     688             : 
     689           0 :   if (t_mode != TUNNEL_MODE_MP && ip46_address_is_zero (&dst))
     690             :     {
     691           0 :       error = clib_error_return (0, "destination address not specified");
     692           0 :       goto done;
     693             :     }
     694             : 
     695           0 :   if (ip46_address_is_zero (&src))
     696             :     {
     697           0 :       error = clib_error_return (0, "source address not specified");
     698           0 :       goto done;
     699             :     }
     700             : 
     701           0 :   if (ip46_address_is_ip4 (&src) != ip46_address_is_ip4 (&dst))
     702             :     {
     703           0 :       error = clib_error_return (0, "src and dst address must be the same AF");
     704           0 :       goto done;
     705             :     }
     706             : 
     707           0 :   clib_memset (a, 0, sizeof (*a));
     708           0 :   a->is_add = is_add;
     709           0 :   a->outer_table_id = outer_table_id;
     710           0 :   a->type = t_type;
     711           0 :   a->mode = t_mode;
     712           0 :   a->session_id = session_id;
     713           0 :   a->is_ipv6 = !ip46_address_is_ip4 (&src);
     714           0 :   a->instance = instance;
     715           0 :   a->flags = flags;
     716           0 :   clib_memcpy (&a->src, &src, sizeof (a->src));
     717           0 :   clib_memcpy (&a->dst, &dst, sizeof (a->dst));
     718             : 
     719           0 :   rv = vnet_gre_tunnel_add_del (a, &sw_if_index);
     720             : 
     721           0 :   switch (rv)
     722             :     {
     723           0 :     case 0:
     724           0 :       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
     725             :                        vnet_get_main (), sw_if_index);
     726           0 :       break;
     727           0 :     case VNET_API_ERROR_IF_ALREADY_EXISTS:
     728           0 :       error = clib_error_return (0, "GRE tunnel already exists...");
     729           0 :       goto done;
     730           0 :     case VNET_API_ERROR_NO_SUCH_FIB:
     731           0 :       error = clib_error_return (0, "outer table ID %d doesn't exist\n",
     732             :                                  outer_table_id);
     733           0 :       goto done;
     734           0 :     case VNET_API_ERROR_NO_SUCH_ENTRY:
     735           0 :       error = clib_error_return (0, "GRE tunnel doesn't exist");
     736           0 :       goto done;
     737           0 :     case VNET_API_ERROR_INVALID_SESSION_ID:
     738             :       error =
     739           0 :         clib_error_return (0, "session ID %d out of range\n", session_id);
     740           0 :       goto done;
     741           0 :     case VNET_API_ERROR_INSTANCE_IN_USE:
     742           0 :       error = clib_error_return (0, "Instance is in use");
     743           0 :       goto done;
     744           0 :     default:
     745           0 :       error = clib_error_return (0, "vnet_gre_tunnel_add_del returned %d", rv);
     746           0 :       goto done;
     747             :     }
     748             : 
     749           0 : done:
     750           0 :   unformat_free (line_input);
     751             : 
     752           0 :   return error;
     753             : }
     754             : 
     755             : /* *INDENT-OFF* */
     756      220777 : VLIB_CLI_COMMAND (create_gre_tunnel_command, static) = {
     757             :   .path = "create gre tunnel",
     758             :   .short_help = "create gre tunnel src <addr> dst <addr> [instance <n>] "
     759             :                 "[outer-fib-id <fib>] [teb | erspan <session-id>] [del] "
     760             :                 "[multipoint]",
     761             :   .function = create_gre_tunnel_command_fn,
     762             : };
     763             : /* *INDENT-ON* */
     764             : 
     765             : static clib_error_t *
     766           0 : show_gre_tunnel_command_fn (vlib_main_t *vm, unformat_input_t *input,
     767             :                             vlib_cli_command_t *cmd)
     768             : {
     769           0 :   gre_main_t *gm = &gre_main;
     770             :   gre_tunnel_t *t;
     771           0 :   u32 ti = ~0;
     772             : 
     773           0 :   if (pool_elts (gm->tunnels) == 0)
     774           0 :     vlib_cli_output (vm, "No GRE tunnels configured...");
     775             : 
     776           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     777             :     {
     778           0 :       if (unformat (input, "%d", &ti))
     779             :         ;
     780             :       else
     781           0 :         break;
     782             :     }
     783             : 
     784           0 :   if (~0 == ti)
     785             :     {
     786             :       /* *INDENT-OFF* */
     787           0 :       pool_foreach (t, gm->tunnels)
     788             :         {
     789           0 :           vlib_cli_output (vm, "%U", format_gre_tunnel, t);
     790             :         }
     791             :       /* *INDENT-ON* */
     792             :     }
     793             :   else
     794             :     {
     795           0 :       t = pool_elt_at_index (gm->tunnels, ti);
     796             : 
     797           0 :       vlib_cli_output (vm, "%U", format_gre_tunnel, t);
     798             :     }
     799             : 
     800           0 :   return 0;
     801             : }
     802             : 
     803             : /* *INDENT-OFF* */
     804      220777 : VLIB_CLI_COMMAND (show_gre_tunnel_command, static) = {
     805             :   .path = "show gre tunnel",
     806             :   .function = show_gre_tunnel_command_fn,
     807             : };
     808             : /* *INDENT-ON* */
     809             : 
     810             : const static teib_vft_t gre_teib_vft = {
     811             :   .nv_added = gre_teib_entry_added,
     812             :   .nv_deleted = gre_teib_entry_deleted,
     813             : };
     814             : 
     815             : /* force inclusion from application's main.c */
     816             : clib_error_t *
     817         575 : gre_interface_init (vlib_main_t *vm)
     818             : {
     819         575 :   teib_register (&gre_teib_vft);
     820             : 
     821         575 :   return (NULL);
     822             : }
     823             : 
     824        1727 : VLIB_INIT_FUNCTION (gre_interface_init);
     825             : 
     826             : /*
     827             :  * fd.io coding-style-patch-verification: ON
     828             :  *
     829             :  * Local Variables:
     830             :  * eval: (c-set-style "gnu")
     831             :  * End:
     832             :  */

Generated by: LCOV version 1.14