LCOV - code coverage report
Current view: top level - vnet/ipip - ipip.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 352 392 89.8 %
Date: 2023-10-26 01:39:38 Functions: 39 42 92.9 %

          Line data    Source code
       1             : /*
       2             :  * ipip.c: ipip
       3             :  *
       4             :  * Copyright (c) 2018 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 aipiped 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 <stddef.h>
      19             : #include <vnet/adj/adj_midchain.h>
      20             : #include <vnet/ipip/ipip.h>
      21             : #include <vnet/vnet.h>
      22             : #include <vnet/adj/adj_nbr.h>
      23             : #include <vnet/adj/adj_midchain.h>
      24             : #include <vnet/fib/ip4_fib.h>
      25             : #include <vnet/fib/ip6_fib.h>
      26             : #include <vnet/ip/format.h>
      27             : #include <vnet/ipip/ipip.h>
      28             : #include <vnet/teib/teib.h>
      29             : #include <vnet/tunnel/tunnel_dp.h>
      30             : 
      31             : ipip_main_t ipip_main;
      32             : 
      33             : /* Packet trace structure */
      34             : typedef struct
      35             : {
      36             :   u32 tunnel_id;
      37             :   u32 length;
      38             :   ip46_address_t src;
      39             :   ip46_address_t dst;
      40             : } ipip_tx_trace_t;
      41             : 
      42             : u8 *
      43           0 : format_ipip_tx_trace (u8 * s, va_list * args)
      44             : {
      45           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      46           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      47           0 :   ipip_tx_trace_t *t = va_arg (*args, ipip_tx_trace_t *);
      48             : 
      49             :   s =
      50           0 :     format (s, "IPIP: tunnel %d len %d src %U dst %U", t->tunnel_id,
      51             :             t->length, format_ip46_address, &t->src, IP46_TYPE_ANY,
      52             :             format_ip46_address, &t->dst, IP46_TYPE_ANY);
      53           0 :   return s;
      54             : }
      55             : 
      56             : static u8 *
      57         210 : ipip_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
      58             :                     vnet_link_t link_type, const void *dst_address)
      59             : {
      60             :   const ip46_address_t *dst;
      61             :   ip4_header_t *ip4;
      62             :   ip6_header_t *ip6;
      63         210 :   u8 *rewrite = NULL;
      64             :   ipip_tunnel_t *t;
      65             : 
      66         210 :   dst = dst_address;
      67         210 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
      68             : 
      69         210 :   if (!t)
      70             :     /* not one of ours */
      71           0 :     return (0);
      72             : 
      73         210 :   switch (t->transport)
      74             :     {
      75         120 :     case IPIP_TRANSPORT_IP4:
      76         120 :       vec_validate (rewrite, sizeof (*ip4) - 1);
      77         120 :       ip4 = (ip4_header_t *) rewrite;
      78         120 :       ip4->ip_version_and_header_length = 0x45;
      79         120 :       ip4->ttl = 64;
      80             :       /* fixup ip4 header length, protocol and checksum after-the-fact */
      81         120 :       ip4->src_address.as_u32 = t->tunnel_src.ip4.as_u32;
      82         120 :       ip4->dst_address.as_u32 = dst->ip4.as_u32;
      83         120 :       if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP))
      84         116 :         ip4_header_set_dscp (ip4, t->dscp);
      85         120 :       if (t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_SET_DF)
      86           2 :         ip4_header_set_df (ip4);
      87             : 
      88         120 :       switch (link_type)
      89             :         {
      90          53 :         case VNET_LINK_IP6:
      91          53 :           ip4->protocol = IP_PROTOCOL_IPV6;
      92          53 :           break;
      93          66 :         case VNET_LINK_IP4:
      94          66 :           ip4->protocol = IP_PROTOCOL_IP_IN_IP;
      95          66 :           break;
      96           1 :         case VNET_LINK_MPLS:
      97           1 :           ip4->protocol = IP_PROTOCOL_MPLS_IN_IP;
      98           1 :           break;
      99           0 :         default:
     100           0 :           break;
     101             :         }
     102         120 :       ip4->checksum = ip4_header_checksum (ip4);
     103         120 :       break;
     104             : 
     105          90 :     case IPIP_TRANSPORT_IP6:
     106          90 :       vec_validate (rewrite, sizeof (*ip6) - 1);
     107          90 :       ip6 = (ip6_header_t *) rewrite;
     108          90 :       ip6->ip_version_traffic_class_and_flow_label =
     109          90 :         clib_host_to_net_u32 (6 << 28);
     110          90 :       ip6->hop_limit = 64;
     111             :       /* fixup ip6 header length and protocol after-the-fact */
     112          90 :       ip6->src_address.as_u64[0] = t->tunnel_src.ip6.as_u64[0];
     113          90 :       ip6->src_address.as_u64[1] = t->tunnel_src.ip6.as_u64[1];
     114          90 :       ip6->dst_address.as_u64[0] = dst->ip6.as_u64[0];
     115          90 :       ip6->dst_address.as_u64[1] = dst->ip6.as_u64[1];
     116          90 :       if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP))
     117          86 :         ip6_set_dscp_network_order (ip6, t->dscp);
     118             : 
     119          90 :       switch (link_type)
     120             :         {
     121          46 :         case VNET_LINK_IP6:
     122          46 :           ip6->protocol = IP_PROTOCOL_IPV6;
     123          46 :           break;
     124          43 :         case VNET_LINK_IP4:
     125          43 :           ip6->protocol = IP_PROTOCOL_IP_IN_IP;
     126          43 :           break;
     127           1 :         case VNET_LINK_MPLS:
     128           1 :           ip6->protocol = IP_PROTOCOL_MPLS_IN_IP;
     129           1 :           break;
     130           0 :         default:
     131           0 :           break;
     132             :         }
     133          90 :       break;
     134             :     }
     135         210 :   return (rewrite);
     136             : }
     137             : 
     138             : static void
     139        1444 : ipip64_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
     140             :               const void *data)
     141             : {
     142             :   tunnel_encap_decap_flags_t flags;
     143             :   ip4_header_t *ip4;
     144             : 
     145        1444 :   flags = pointer_to_uword (data);
     146             : 
     147        1444 :   ip4 = vlib_buffer_get_current (b);
     148        1444 :   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
     149        1444 :   tunnel_encap_fixup_6o4 (flags, ((ip6_header_t *) (ip4 + 1)), ip4);
     150             : 
     151        1444 :   ip4->checksum = ip4_header_checksum (ip4);
     152        1444 : }
     153             : 
     154             : static void
     155        1908 : ipip44_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
     156             :               const void *data)
     157             : {
     158             :   tunnel_encap_decap_flags_t flags;
     159             :   ip4_header_t *ip4;
     160             : 
     161        1908 :   flags = pointer_to_uword (data);
     162             : 
     163        1908 :   ip4 = vlib_buffer_get_current (b);
     164        1908 :   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b));
     165        1908 :   tunnel_encap_fixup_4o4 (flags, ip4 + 1, ip4);
     166             : 
     167        1908 :   ip4->checksum = ip4_header_checksum (ip4);
     168        1908 : }
     169             : 
     170             : static void
     171        1455 : ipip46_fixup (vlib_main_t * vm, const ip_adjacency_t * adj, vlib_buffer_t * b,
     172             :               const void *data)
     173             : {
     174             :   tunnel_encap_decap_flags_t flags;
     175             :   ip6_header_t *ip6;
     176             : 
     177        1455 :   flags = pointer_to_uword (data);
     178             : 
     179             :   /* Must set locally originated otherwise we're not allowed to
     180             :      fragment the packet later */
     181        1455 :   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     182             : 
     183        1455 :   ip6 = vlib_buffer_get_current (b);
     184        1455 :   ip6->payload_length =
     185        1455 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) -
     186             :                           sizeof (*ip6));
     187        1455 :   tunnel_encap_fixup_4o6 (flags, b, ((ip4_header_t *) (ip6 + 1)), ip6);
     188        1455 : }
     189             : 
     190             : static void
     191        4514 : ipip66_fixup (vlib_main_t * vm,
     192             :               const ip_adjacency_t * adj, vlib_buffer_t * b, const void *data)
     193             : {
     194             :   tunnel_encap_decap_flags_t flags;
     195             :   ip6_header_t *ip6;
     196             : 
     197        4514 :   flags = pointer_to_uword (data);
     198             : 
     199             :   /* Must set locally originated otherwise we're not allowed to
     200             :      fragment the packet later */
     201        4514 :   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     202             : 
     203        4514 :   ip6 = vlib_buffer_get_current (b);
     204        4514 :   ip6->payload_length =
     205        4514 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) -
     206             :                           sizeof (*ip6));
     207        4514 :   tunnel_encap_fixup_6o6 (flags, ip6 + 1, ip6);
     208        4514 : }
     209             : 
     210             : static void
     211          63 : ipipm6_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
     212             :               const void *data)
     213             : {
     214             :   tunnel_encap_decap_flags_t flags;
     215             :   ip6_header_t *ip6;
     216             : 
     217          63 :   flags = pointer_to_uword (data);
     218             : 
     219             :   /* Must set locally originated otherwise we're not allowed to
     220             :      fragment the packet later and we'll get an unwanted hop-limt
     221             :      decrement */
     222          63 :   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     223             : 
     224          63 :   ip6 = vlib_buffer_get_current (b);
     225          63 :   ip6->payload_length =
     226          63 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip6));
     227          63 :   tunnel_encap_fixup_mplso6 (flags, b, (mpls_unicast_header_t *) (ip6 + 1),
     228             :                              ip6);
     229          63 : }
     230             : 
     231             : static void
     232          63 : ipipm4_fixup (vlib_main_t *vm, const ip_adjacency_t *adj, vlib_buffer_t *b,
     233             :               const void *data)
     234             : {
     235             :   tunnel_encap_decap_flags_t flags;
     236             :   ip4_header_t *ip4;
     237             : 
     238          63 :   flags = pointer_to_uword (data);
     239             : 
     240             :   /* Must set locally originated otherwise we'll do a TTL decrement
     241             :    * during ip4-rewrite */
     242          63 :   b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     243             : 
     244          63 :   ip4 = vlib_buffer_get_current (b);
     245          63 :   ip4->length =
     246          63 :     clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b) - sizeof (*ip4));
     247          63 :   tunnel_encap_fixup_mplso4 (flags, (mpls_unicast_header_t *) (ip4 + 1), ip4);
     248          63 :   ip4->checksum = ip4_header_checksum (ip4);
     249          63 : }
     250             : 
     251             : static void
     252         365 : ipip_tunnel_stack (adj_index_t ai)
     253             : {
     254             :   ip_adjacency_t *adj;
     255             :   ipip_tunnel_t *t;
     256             :   u32 sw_if_index;
     257             : 
     258         365 :   adj = adj_get (ai);
     259         365 :   sw_if_index = adj->rewrite_header.sw_if_index;
     260             : 
     261         365 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     262         365 :   if (!t)
     263           0 :     return;
     264             : 
     265         365 :   if ((vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) &
     266             :        VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
     267             :     {
     268         165 :       adj_midchain_delegate_unstack (ai);
     269             :     }
     270             :   else
     271             :     {
     272             :       /* *INDENT-OFF* */
     273         200 :       fib_prefix_t dst = {
     274         200 :         .fp_len = t->transport == IPIP_TRANSPORT_IP6 ? 128 : 32,
     275         200 :         .fp_proto = (t->transport == IPIP_TRANSPORT_IP6 ?
     276         200 :                      FIB_PROTOCOL_IP6 :
     277             :                      FIB_PROTOCOL_IP4),
     278             :         .fp_addr = t->tunnel_dst
     279             :       };
     280             :       /* *INDENT-ON* */
     281             : 
     282         200 :       adj_midchain_delegate_stack (ai, t->fib_index, &dst);
     283             :     }
     284             : }
     285             : 
     286             : static adj_walk_rc_t
     287         167 : ipip_adj_walk_cb (adj_index_t ai, void *ctx)
     288             : {
     289         167 :   ipip_tunnel_stack (ai);
     290             : 
     291         167 :   return (ADJ_WALK_RC_CONTINUE);
     292             : }
     293             : 
     294             : static void
     295         206 : ipip_tunnel_restack (ipip_tunnel_t * gt)
     296             : {
     297             :   fib_protocol_t proto;
     298             : 
     299             :   /*
     300             :    * walk all the adjacencies on th IPIP interface and restack them
     301             :    */
     302         618 :   FOR_EACH_FIB_IP_PROTOCOL (proto)
     303             :   {
     304         412 :     adj_nbr_walk (gt->sw_if_index, proto, ipip_adj_walk_cb, NULL);
     305             :   }
     306         206 : }
     307             : 
     308             : static adj_midchain_fixup_t
     309         225 : ipip_get_fixup (const ipip_tunnel_t * t, vnet_link_t lt, adj_flags_t * aflags)
     310             : {
     311         225 :   if (t->transport == IPIP_TRANSPORT_IP6 && lt == VNET_LINK_IP6)
     312          46 :     return (ipip66_fixup);
     313         179 :   if (t->transport == IPIP_TRANSPORT_IP6 && lt == VNET_LINK_IP4)
     314          43 :     return (ipip46_fixup);
     315         136 :   if (t->transport == IPIP_TRANSPORT_IP6 && lt == VNET_LINK_MPLS)
     316           1 :     return (ipipm6_fixup);
     317         135 :   if (t->transport == IPIP_TRANSPORT_IP4 && lt == VNET_LINK_IP6)
     318          53 :     return (ipip64_fixup);
     319          82 :   if (t->transport == IPIP_TRANSPORT_IP4 && lt == VNET_LINK_MPLS)
     320           1 :     return (ipipm4_fixup);
     321          81 :   if (t->transport == IPIP_TRANSPORT_IP4 && lt == VNET_LINK_IP4)
     322             :     {
     323          81 :       *aflags = *aflags | ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR;
     324          81 :       return (ipip44_fixup);
     325             :     }
     326             : 
     327           0 :   ASSERT (0);
     328           0 :   return (ipip44_fixup);
     329             : }
     330             : 
     331             : void
     332         198 : ipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
     333             : {
     334             :   adj_midchain_fixup_t fixup;
     335             :   ipip_tunnel_t *t;
     336             :   adj_flags_t af;
     337             : 
     338         198 :   af = ADJ_FLAG_NONE;
     339         198 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     340         198 :   if (!t)
     341           0 :     return;
     342             : 
     343             :   /*
     344             :    * the user has not requested that the load-balancing be based on
     345             :    * a flow hash of the inner packet. so use the stacking to choose
     346             :    * a path.
     347             :    */
     348         198 :   if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
     349         198 :     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
     350             : 
     351         198 :   fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
     352         198 :   adj_nbr_midchain_update_rewrite
     353             :     (ai, fixup,
     354         198 :      uword_to_pointer (t->flags, void *), af,
     355             :      ipip_build_rewrite (vnm, sw_if_index,
     356         198 :                          adj_get_link_type (ai), &t->tunnel_dst));
     357         198 :   ipip_tunnel_stack (ai);
     358             : }
     359             : 
     360             : typedef struct mipip_walk_ctx_t_
     361             : {
     362             :   const ipip_tunnel_t *t;
     363             :   const teib_entry_t *ne;
     364             : } mipip_walk_ctx_t;
     365             : 
     366             : static adj_walk_rc_t
     367          12 : mipip_mk_complete_walk (adj_index_t ai, void *data)
     368             : {
     369             :   adj_midchain_fixup_t fixup;
     370          12 :   mipip_walk_ctx_t *ctx = data;
     371             :   adj_flags_t af;
     372             : 
     373          12 :   af = ADJ_FLAG_NONE;
     374          12 :   fixup = ipip_get_fixup (ctx->t, adj_get_link_type (ai), &af);
     375             : 
     376             :   /*
     377             :    * the user has not requested that the load-balancing be based on
     378             :    * a flow hash of the inner packet. so use the stacking to choose
     379             :    * a path.
     380             :    */
     381          12 :   if (!(ctx->t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
     382          12 :     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
     383             : 
     384          12 :   adj_nbr_midchain_update_rewrite
     385             :     (ai, fixup,
     386          12 :      uword_to_pointer (ctx->t->flags, void *),
     387             :      af, ipip_build_rewrite (vnet_get_main (),
     388          12 :                              ctx->t->sw_if_index,
     389          12 :                              adj_get_link_type (ai),
     390          12 :                              &teib_entry_get_nh (ctx->ne)->fp_addr));
     391             : 
     392          12 :   teib_entry_adj_stack (ctx->ne, ai);
     393             : 
     394          12 :   return (ADJ_WALK_RC_CONTINUE);
     395             : }
     396             : 
     397             : static adj_walk_rc_t
     398           9 : mipip_mk_incomplete_walk (adj_index_t ai, void *data)
     399             : {
     400             :   adj_midchain_fixup_t fixup;
     401           9 :   ipip_tunnel_t *t = data;
     402             :   adj_flags_t af;
     403             : 
     404           9 :   af = ADJ_FLAG_NONE;
     405           9 :   fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
     406             : 
     407           9 :   adj_nbr_midchain_update_rewrite (ai, fixup, NULL, ADJ_FLAG_NONE, NULL);
     408             : 
     409           9 :   adj_midchain_delegate_unstack (ai);
     410             : 
     411           9 :   return (ADJ_WALK_RC_CONTINUE);
     412             : }
     413             : 
     414             : void
     415           6 : mipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
     416             : {
     417           6 :   ipip_main_t *gm = &ipip_main;
     418             :   adj_midchain_fixup_t fixup;
     419             :   ip_adjacency_t *adj;
     420             :   teib_entry_t *ne;
     421             :   ipip_tunnel_t *t;
     422             :   adj_flags_t af;
     423             :   u32 ti;
     424             : 
     425           6 :   af = ADJ_FLAG_NONE;
     426           6 :   adj = adj_get (ai);
     427           6 :   ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
     428           6 :   t = pool_elt_at_index (gm->tunnels, ti);
     429             : 
     430           6 :   ne = teib_entry_find_46 (sw_if_index,
     431           6 :                            adj->ia_nh_proto, &adj->sub_type.nbr.next_hop);
     432             : 
     433           6 :   if (NULL == ne)
     434             :     {
     435             :       // no TEIB entry to provide the next-hop
     436           6 :       fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
     437           6 :       adj_nbr_midchain_update_rewrite
     438           6 :         (ai, fixup, uword_to_pointer (t->flags, void *), ADJ_FLAG_NONE, NULL);
     439           6 :       return;
     440             :     }
     441             : 
     442           0 :   mipip_walk_ctx_t ctx = {
     443             :     .t = t,
     444             :     .ne = ne
     445             :   };
     446           0 :   adj_nbr_walk_nh (sw_if_index,
     447           0 :                    adj->ia_nh_proto,
     448           0 :                    &adj->sub_type.nbr.next_hop, mipip_mk_complete_walk, &ctx);
     449             : }
     450             : 
     451             : static u8 *
     452         285 : format_ipip_tunnel_name (u8 * s, va_list * args)
     453             : {
     454         285 :   u32 dev_instance = va_arg (*args, u32);
     455         285 :   ipip_main_t *gm = &ipip_main;
     456             :   ipip_tunnel_t *t;
     457             : 
     458         285 :   if (dev_instance >= vec_len (gm->tunnels))
     459           0 :     return format (s, "<improperly-referenced>");
     460             : 
     461         285 :   t = pool_elt_at_index (gm->tunnels, dev_instance);
     462         285 :   return format (s, "ipip%d", t->user_instance);
     463             : }
     464             : 
     465             : static u8 *
     466         160 : format_ipip_device (u8 * s, va_list * args)
     467             : {
     468         160 :   u32 dev_instance = va_arg (*args, u32);
     469         160 :   CLIB_UNUSED (int verbose) = va_arg (*args, int);
     470             : 
     471         160 :   s = format (s, "IPIP tunnel: id %d\n", dev_instance);
     472         160 :   return s;
     473             : }
     474             : 
     475             : static clib_error_t *
     476         206 : ipip_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     477             : {
     478             :   vnet_hw_interface_t *hi;
     479             :   ipip_tunnel_t *t;
     480             : 
     481         206 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     482             : 
     483         206 :   t = ipip_tunnel_db_find_by_sw_if_index (hi->sw_if_index);
     484         206 :   if (!t)
     485           0 :     return 0;
     486             : 
     487         206 :   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     488         103 :     vnet_hw_interface_set_flags (vnm, hw_if_index,
     489             :                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
     490             :   else
     491         103 :     vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
     492             : 
     493         206 :   ipip_tunnel_restack (t);
     494             : 
     495         206 :   return /* no error */ 0;
     496             : }
     497             : 
     498             : static int
     499         103 : ipip_tunnel_desc (u32 sw_if_index,
     500             :                   ip46_address_t * src, ip46_address_t * dst, u8 * is_l2)
     501             : {
     502             :   ipip_tunnel_t *t;
     503             : 
     504         103 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     505         103 :   if (!t)
     506           0 :     return -1;
     507             : 
     508         103 :   *src = t->tunnel_src;
     509         103 :   *dst = t->tunnel_dst;
     510         103 :   *is_l2 = 0;
     511             : 
     512         103 :   return (0);
     513             : }
     514             : 
     515             : /* *INDENT-OFF* */
     516       12095 : VNET_DEVICE_CLASS(ipip_device_class) = {
     517             :     .name = "IPIP tunnel device",
     518             :     .format_device_name = format_ipip_tunnel_name,
     519             :     .format_device = format_ipip_device,
     520             :     .format_tx_trace = format_ipip_tx_trace,
     521             :     .admin_up_down_function = ipip_interface_admin_up_down,
     522             :     .ip_tun_desc = ipip_tunnel_desc,
     523             : #ifdef SOON
     524             :     .clear counter = 0;
     525             : #endif
     526             : };
     527             : 
     528        8063 : VNET_HW_INTERFACE_CLASS(ipip_hw_interface_class) = {
     529             :     .name = "IPIP",
     530             :     //.format_header = format_ipip_header_with_length,
     531             :     //.unformat_header = unformat_ipip_header,
     532             :     .build_rewrite = ipip_build_rewrite,
     533             :     .update_adjacency = ipip_update_adj,
     534             :     .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
     535             : };
     536             : 
     537        8063 : VNET_HW_INTERFACE_CLASS(mipip_hw_interface_class) = {
     538             :     .name = "mIPIP",
     539             :     //.format_header = format_ipip_header_with_length,
     540             :     //.unformat_header = unformat_ipip_header,
     541             :     .build_rewrite = ipip_build_rewrite,
     542             :     .update_adjacency = mipip_update_adj,
     543             :     .flags = VNET_HW_INTERFACE_CLASS_FLAG_NBMA,
     544             : };
     545             : /* *INDENT-ON* */
     546             : 
     547             : ipip_tunnel_t *
     548        6743 : ipip_tunnel_db_find (const ipip_tunnel_key_t * key)
     549             : {
     550        6743 :   ipip_main_t *gm = &ipip_main;
     551             :   uword *p;
     552             : 
     553        6743 :   p = hash_get_mem (gm->tunnel_by_key, key);
     554        6743 :   if (!p)
     555         972 :     return (NULL);
     556        5771 :   return (pool_elt_at_index (gm->tunnels, p[0]));
     557             : }
     558             : 
     559             : ipip_tunnel_t *
     560        1351 : ipip_tunnel_db_find_by_sw_if_index (u32 sw_if_index)
     561             : {
     562        1351 :   ipip_main_t *gm = &ipip_main;
     563        1351 :   if (vec_len (gm->tunnel_index_by_sw_if_index) <= sw_if_index)
     564           0 :     return NULL;
     565        1351 :   u32 ti = gm->tunnel_index_by_sw_if_index[sw_if_index];
     566        1351 :   if (ti == ~0)
     567           0 :     return NULL;
     568        1351 :   return pool_elt_at_index (gm->tunnels, ti);
     569             : }
     570             : 
     571             : void
     572         148 : ipip_tunnel_db_add (ipip_tunnel_t * t, const ipip_tunnel_key_t * key)
     573             : {
     574         148 :   ipip_main_t *gm = &ipip_main;
     575             : 
     576         148 :   hash_set_mem_alloc (&gm->tunnel_by_key, key, t->dev_instance);
     577         148 : }
     578             : 
     579             : void
     580         148 : ipip_tunnel_db_remove (ipip_tunnel_t * t, const ipip_tunnel_key_t * key)
     581             : {
     582         148 :   ipip_main_t *gm = &ipip_main;
     583             : 
     584         148 :   hash_unset_mem_free (&gm->tunnel_by_key, key);
     585         148 : }
     586             : 
     587             : void
     588         304 : ipip_mk_key_i (ipip_transport_t transport,
     589             :                ipip_mode_t mode,
     590             :                const ip46_address_t * src,
     591             :                const ip46_address_t * dst,
     592             :                u32 fib_index, ipip_tunnel_key_t * key)
     593             : {
     594         304 :   key->transport = transport;
     595         304 :   key->mode = mode;
     596         304 :   key->src = *src;
     597         304 :   key->dst = *dst;
     598         304 :   key->fib_index = fib_index;
     599         304 :   key->__pad = 0;;
     600         304 : }
     601             : 
     602             : void
     603         136 : ipip_mk_key (const ipip_tunnel_t * t, ipip_tunnel_key_t * key)
     604             : {
     605         136 :   ipip_mk_key_i (t->transport, t->mode,
     606             :                  &t->tunnel_src, &t->tunnel_dst, t->fib_index, key);
     607         136 : }
     608             : 
     609             : static void
     610          24 : ipip_teib_mk_key (const ipip_tunnel_t * t,
     611             :                   const teib_entry_t * ne, ipip_tunnel_key_t * key)
     612             : {
     613             :   const fib_prefix_t *nh;
     614             : 
     615          24 :   nh = teib_entry_get_nh (ne);
     616             : 
     617             :   /* construct the key using mode P2P so it can be found in the DP */
     618          24 :   ipip_mk_key_i (t->transport, IPIP_MODE_P2P,
     619             :                  &t->tunnel_src, &nh->fp_addr,
     620             :                  teib_entry_get_fib_index (ne), key);
     621          24 : }
     622             : 
     623             : static void
     624          85 : ipip_teib_entry_added (const teib_entry_t * ne)
     625             : {
     626          85 :   ipip_main_t *gm = &ipip_main;
     627             :   const ip_address_t *nh;
     628             :   ipip_tunnel_key_t key;
     629             :   ipip_tunnel_t *t;
     630             :   u32 sw_if_index;
     631             :   u32 t_idx;
     632             : 
     633          85 :   sw_if_index = teib_entry_get_sw_if_index (ne);
     634          85 :   if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
     635          73 :     return;
     636             : 
     637          12 :   t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
     638             : 
     639          12 :   if (INDEX_INVALID == t_idx)
     640           0 :     return;
     641             : 
     642          12 :   t = pool_elt_at_index (gm->tunnels, t_idx);
     643             : 
     644          12 :   ipip_teib_mk_key (t, ne, &key);
     645          12 :   ipip_tunnel_db_add (t, &key);
     646             : 
     647             :   // update the rewrites for each of the adjacencies for this next-hop
     648          12 :   mipip_walk_ctx_t ctx = {
     649             :     .t = t,
     650             :     .ne = ne
     651             :   };
     652          12 :   nh = teib_entry_get_peer (ne);
     653          12 :   adj_nbr_walk_nh (teib_entry_get_sw_if_index (ne),
     654          12 :                    (AF_IP4 == ip_addr_version (nh) ?
     655             :                     FIB_PROTOCOL_IP4 :
     656             :                     FIB_PROTOCOL_IP6),
     657             :                    &ip_addr_46 (nh), mipip_mk_complete_walk, &ctx);
     658             : }
     659             : 
     660             : static void
     661          85 : ipip_teib_entry_deleted (const teib_entry_t * ne)
     662             : {
     663          85 :   ipip_main_t *gm = &ipip_main;
     664             :   const ip_address_t *nh;
     665             :   ipip_tunnel_key_t key;
     666             :   ipip_tunnel_t *t;
     667             :   u32 sw_if_index;
     668             :   u32 t_idx;
     669             : 
     670          85 :   sw_if_index = teib_entry_get_sw_if_index (ne);
     671          85 :   if (vec_len (gm->tunnel_index_by_sw_if_index) < sw_if_index)
     672          73 :     return;
     673             : 
     674          12 :   t_idx = gm->tunnel_index_by_sw_if_index[sw_if_index];
     675             : 
     676          12 :   if (INDEX_INVALID == t_idx)
     677           0 :     return;
     678             : 
     679          12 :   t = pool_elt_at_index (gm->tunnels, t_idx);
     680             : 
     681          12 :   ipip_teib_mk_key (t, ne, &key);
     682          12 :   ipip_tunnel_db_remove (t, &key);
     683             : 
     684          12 :   nh = teib_entry_get_peer (ne);
     685             : 
     686             :   /* make all the adjacencies incomplete */
     687          12 :   adj_nbr_walk_nh (teib_entry_get_sw_if_index (ne),
     688          12 :                    (AF_IP4 == ip_addr_version (nh) ?
     689             :                     FIB_PROTOCOL_IP4 :
     690             :                     FIB_PROTOCOL_IP6),
     691             :                    &ip_addr_46 (nh), mipip_mk_incomplete_walk, t);
     692             : }
     693             : 
     694             : static walk_rc_t
     695           0 : ipip_tunnel_delete_teib_walk (index_t nei, void *ctx)
     696             : {
     697           0 :   ipip_tunnel_t *t = ctx;
     698             :   ipip_tunnel_key_t key;
     699             : 
     700           0 :   ipip_teib_mk_key (t, teib_entry_get (nei), &key);
     701           0 :   ipip_tunnel_db_remove (t, &key);
     702             : 
     703           0 :   return (WALK_CONTINUE);
     704             : }
     705             : 
     706             : static walk_rc_t
     707           0 : ipip_tunnel_add_teib_walk (index_t nei, void *ctx)
     708             : {
     709           0 :   ipip_tunnel_t *t = ctx;
     710             :   ipip_tunnel_key_t key;
     711             : 
     712           0 :   ipip_teib_mk_key (t, teib_entry_get (nei), &key);
     713           0 :   ipip_tunnel_db_add (t, &key);
     714             : 
     715           0 :   return (WALK_CONTINUE);
     716             : }
     717             : 
     718             : int
     719         133 : ipip_add_tunnel (ipip_transport_t transport,
     720             :                  u32 instance, ip46_address_t * src, ip46_address_t * dst,
     721             :                  u32 fib_index, tunnel_encap_decap_flags_t flags,
     722             :                  ip_dscp_t dscp, tunnel_mode_t tmode, u32 * sw_if_indexp)
     723             : {
     724         133 :   ipip_main_t *gm = &ipip_main;
     725         133 :   vnet_main_t *vnm = gm->vnet_main;
     726             :   ipip_tunnel_t *t;
     727             :   vnet_hw_interface_t *hi;
     728             :   u32 hw_if_index, sw_if_index;
     729             :   ipip_tunnel_key_t key;
     730             :   ipip_mode_t mode;
     731             : 
     732         133 :   if (tmode == TUNNEL_MODE_MP && !ip46_address_is_zero (dst))
     733           0 :     return (VNET_API_ERROR_INVALID_DST_ADDRESS);
     734             : 
     735         133 :   mode = (tmode == TUNNEL_MODE_P2P ? IPIP_MODE_P2P : IPIP_MODE_P2MP);
     736         133 :   ipip_mk_key_i (transport, mode, src, dst, fib_index, &key);
     737             : 
     738         133 :   t = ipip_tunnel_db_find (&key);
     739         133 :   if (t)
     740             :     {
     741           8 :       if (sw_if_indexp)
     742           8 :         sw_if_indexp[0] = t->sw_if_index;
     743           8 :       return VNET_API_ERROR_IF_ALREADY_EXISTS;
     744             :     }
     745             : 
     746         125 :   pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
     747         125 :   clib_memset (t, 0, sizeof (*t));
     748             : 
     749             :   /* Reconcile the real dev_instance and a possible requested instance */
     750         125 :   u32 t_idx = t - gm->tunnels;       /* tunnel index (or instance) */
     751         125 :   u32 u_idx = instance;         /* user specified instance */
     752         125 :   if (u_idx == ~0)
     753         125 :     u_idx = t_idx;
     754         125 :   if (hash_get (gm->instance_used, u_idx))
     755             :     {
     756           0 :       pool_put (gm->tunnels, t);
     757           0 :       return VNET_API_ERROR_INSTANCE_IN_USE;
     758             :     }
     759         125 :   hash_set (gm->instance_used, u_idx, 1);
     760             : 
     761         125 :   t->dev_instance = t_idx;   /* actual */
     762         125 :   t->user_instance = u_idx;  /* name */
     763             : 
     764         125 :   hw_if_index = vnet_register_interface (vnm, ipip_device_class.index, t_idx,
     765             :                                          (mode == IPIP_MODE_P2P ?
     766             :                                           ipip_hw_interface_class.index :
     767             :                                           mipip_hw_interface_class.index),
     768             :                                          t_idx);
     769             : 
     770         125 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     771         125 :   sw_if_index = hi->sw_if_index;
     772             : 
     773         125 :   t->mode = mode;
     774         125 :   t->hw_if_index = hw_if_index;
     775         125 :   t->fib_index = fib_index;
     776         125 :   t->sw_if_index = sw_if_index;
     777         125 :   t->dscp = dscp;
     778         125 :   t->flags = flags;
     779         125 :   t->transport = transport;
     780             : 
     781         363 :   vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, sw_if_index, ~0);
     782         125 :   gm->tunnel_index_by_sw_if_index[sw_if_index] = t_idx;
     783             : 
     784         125 :   if (t->transport == IPIP_TRANSPORT_IP4)
     785          79 :     hi->frame_overhead = sizeof (ip4_header_t);
     786             :   else
     787          46 :     hi->frame_overhead = sizeof (ip6_header_t);
     788             : 
     789         125 :   hi->min_frame_size = hi->frame_overhead + 64;
     790             : 
     791             :   /* Standard default ipip MTU. */
     792         125 :   vnet_sw_interface_set_mtu (vnm, sw_if_index, 9000);
     793         125 :   vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
     794             :                                      (u8 *) "tunnel-output");
     795             : 
     796         125 :   t->tunnel_src = *src;
     797         125 :   t->tunnel_dst = *dst;
     798             : 
     799         125 :   ipip_tunnel_db_add (t, &key);
     800             : 
     801         125 :   if (t->mode == IPIP_MODE_P2MP)
     802           2 :     teib_walk_itf (t->sw_if_index, ipip_tunnel_add_teib_walk, t);
     803             : 
     804         125 :   if (sw_if_indexp)
     805         125 :     *sw_if_indexp = sw_if_index;
     806             : 
     807         125 :   if (t->transport == IPIP_TRANSPORT_IP6 && !gm->ip6_protocol_registered)
     808             :     {
     809          13 :       ip6_register_protocol (IP_PROTOCOL_IP_IN_IP, ipip6_input_node.index);
     810          13 :       ip6_register_protocol (IP_PROTOCOL_MPLS_IN_IP, ipip6_input_node.index);
     811          13 :       ip6_register_protocol (IP_PROTOCOL_IPV6, ipip6_input_node.index);
     812          13 :       gm->ip6_protocol_registered = true;
     813             :     }
     814         112 :   else if (t->transport == IPIP_TRANSPORT_IP4 && !gm->ip4_protocol_registered)
     815             :     {
     816          37 :       ip4_register_protocol (IP_PROTOCOL_IP_IN_IP, ipip4_input_node.index);
     817          37 :       ip4_register_protocol (IP_PROTOCOL_MPLS_IN_IP, ipip4_input_node.index);
     818          37 :       ip4_register_protocol (IP_PROTOCOL_IPV6, ipip4_input_node.index);
     819          37 :       gm->ip4_protocol_registered = true;
     820             :     }
     821         125 :   return 0;
     822             : }
     823             : 
     824             : int
     825         125 : ipip_del_tunnel (u32 sw_if_index)
     826             : {
     827         125 :   ipip_main_t *gm = &ipip_main;
     828         125 :   vnet_main_t *vnm = gm->vnet_main;
     829             :   ipip_tunnel_t *t;
     830             :   ipip_tunnel_key_t key;
     831             : 
     832         125 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     833         125 :   if (t == NULL)
     834           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     835             : 
     836         125 :   if (t->mode == IPIP_MODE_P2MP)
     837           2 :     teib_walk_itf (t->sw_if_index, ipip_tunnel_delete_teib_walk, t);
     838             : 
     839         125 :   vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
     840         125 :   vnet_reset_interface_l3_output_node (gm->vlib_main, t->sw_if_index);
     841         125 :   gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
     842         125 :   vnet_delete_hw_interface (vnm, t->hw_if_index);
     843         125 :   hash_unset (gm->instance_used, t->user_instance);
     844             : 
     845         125 :   ipip_mk_key (t, &key);
     846         125 :   ipip_tunnel_db_remove (t, &key);
     847         125 :   pool_put (gm->tunnels, t);
     848             : 
     849         125 :   return 0;
     850             : }
     851             : 
     852             : const static teib_vft_t ipip_teib_vft = {
     853             :   .nv_added = ipip_teib_entry_added,
     854             :   .nv_deleted = ipip_teib_entry_deleted,
     855             : };
     856             : 
     857             : static clib_error_t *
     858         575 : ipip_init (vlib_main_t * vm)
     859             : {
     860         575 :   ipip_main_t *gm = &ipip_main;
     861             : 
     862         575 :   clib_memset (gm, 0, sizeof (gm[0]));
     863         575 :   gm->vlib_main = vm;
     864         575 :   gm->vnet_main = vnet_get_main ();
     865         575 :   gm->tunnel_by_key =
     866         575 :     hash_create_mem (0, sizeof (ipip_tunnel_key_t), sizeof (uword));
     867             : 
     868         575 :   teib_register (&ipip_teib_vft);
     869             : 
     870         575 :   return 0;
     871             : }
     872             : 
     873       62207 : VLIB_INIT_FUNCTION (ipip_init);
     874             : 
     875             : /*
     876             :  * fd.io coding-style-patch-verification: ON
     877             :  *
     878             :  * Local Variables:
     879             :  * eval: (c-set-style "gnu")
     880             :  * End:
     881             :  */

Generated by: LCOV version 1.14