LCOV - code coverage report
Current view: top level - vnet/ipip - sixrd.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 169 188 89.9 %
Date: 2023-10-26 01:39:38 Functions: 21 24 87.5 %

          Line data    Source code
       1             : /*
       2             :  * sixrd.c - 6RD specific functions (RFC5969)
       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 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             : /**
      19             :  * This code supports the following sixrd modes:
      20             :  *
      21             :  * 32 EA bits (Complete IPv4 address is embedded):
      22             :  *   ea_bits_len = 32
      23             :  * IPv4 suffix is embedded:
      24             :  *   ea_bits_len = < 32
      25             :  * No embedded address bits (1:1 mode):
      26             :  *   ea_bits_len = 0
      27             :  */
      28             : 
      29             : #include "ipip.h"
      30             : #include <vlibapi/api.h>
      31             : #include <vlibmemory/api.h>
      32             : #include <vnet/adj/adj.h>
      33             : #include <vnet/adj/adj_delegate.h>
      34             : #include <vnet/adj/adj_midchain.h>
      35             : #include <vnet/dpo/lookup_dpo.h>
      36             : #include <vnet/fib/fib_table.h>
      37             : #include <vnet/fib/fib_entry_track.h>
      38             : #include <vnet/fib/ip6_fib.h>
      39             : #include <vnet/plugin/plugin.h>
      40             : 
      41             : extern vlib_node_registration_t ip4_sixrd_node;
      42             : 
      43             : /**
      44             :  * Adj delegate data
      45             :  */
      46             : typedef struct sixrd_adj_delegate_t_
      47             : {
      48             :   u32 adj_index;
      49             :   fib_node_t sixrd_node;
      50             :   fib_node_index_t sixrd_fib_entry_index;
      51             :   u32 sixrd_sibling;
      52             : } sixrd_adj_delegate_t;
      53             : 
      54             : /**
      55             :  * Pool of delegate structs
      56             :  */
      57             : static sixrd_adj_delegate_t *sixrd_adj_delegate_pool;
      58             : 
      59             : /**
      60             :  * Adj delegate registered type
      61             :  */
      62             : static adj_delegate_type_t sixrd_adj_delegate_type;
      63             : 
      64             : /**
      65             :  * FIB node registered type
      66             :  */
      67             : static fib_node_type_t sixrd_fib_node_type;
      68             : 
      69             : static inline sixrd_adj_delegate_t *
      70           2 : sixrd_adj_from_base (adj_delegate_t * ad)
      71             : {
      72           2 :   if (ad == NULL)
      73           1 :     return (NULL);
      74           1 :   return (pool_elt_at_index (sixrd_adj_delegate_pool, ad->ad_index));
      75             : }
      76             : 
      77             : static inline const sixrd_adj_delegate_t *
      78           0 : sixrd_adj_from_const_base (const adj_delegate_t * ad)
      79             : {
      80           0 :   if (ad == NULL)
      81             :     {
      82           0 :       return (NULL);
      83             :     }
      84           0 :   return (pool_elt_at_index (sixrd_adj_delegate_pool, ad->ad_index));
      85             : }
      86             : 
      87             : static void
      88          30 : sixrd_fixup (vlib_main_t * vm,
      89             :              const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
      90             : {
      91          30 :   ip4_header_t *ip4 = vlib_buffer_get_current (b0);
      92          30 :   ip6_header_t *ip6 = vlib_buffer_get_current (b0) + sizeof (ip4_header_t);
      93          30 :   const ipip_tunnel_t *t = data;
      94             : 
      95          30 :   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
      96          30 :   ip4->dst_address.as_u32 =
      97          30 :     sixrd_get_addr_net (t, ip6->dst_address.as_u64[0]);
      98          30 :   ip4->checksum = ip4_header_checksum (ip4);
      99          30 : }
     100             : 
     101             : static void
     102          10 : ip6ip_fixup (vlib_main_t * vm,
     103             :              const ip_adjacency_t * adj, vlib_buffer_t * b0, const void *data)
     104             : {
     105          10 :   const ipip_tunnel_t *t = data;
     106          10 :   ip4_header_t *ip4 = vlib_buffer_get_current (b0);
     107          10 :   ip4->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
     108          10 :   ip4->dst_address.as_u32 =
     109          10 :     sixrd_get_addr_net (t, adj->sub_type.nbr.next_hop.as_u64[0]);
     110          10 :   ip4->checksum = ip4_header_checksum (ip4);
     111          10 : }
     112             : 
     113             : static u8 *
     114          12 : sixrd_build_rewrite (vnet_main_t * vnm, u32 sw_if_index,
     115             :                      vnet_link_t link_type, const void *dst_address)
     116             : {
     117          12 :   u8 *rewrite = NULL;
     118             :   ipip_tunnel_t *t;
     119             : 
     120          12 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     121          12 :   if (!t)
     122           0 :     return 0;
     123             : 
     124          12 :   vec_validate (rewrite, sizeof (ip4_header_t) - 1);
     125          12 :   ip4_header_t *ip4 = (ip4_header_t *) rewrite;
     126          12 :   ip4->ip_version_and_header_length = 0x45;
     127          12 :   ip4->ttl = 64;
     128          12 :   ip4->protocol = IP_PROTOCOL_IPV6;
     129             :   /* fixup ip4 header length and checksum after-the-fact */
     130          12 :   ip4->src_address.as_u32 = t->tunnel_src.ip4.as_u32;
     131          12 :   ip4->dst_address.as_u32 = 0;
     132          12 :   ip4->checksum = ip4_header_checksum (ip4);
     133             : 
     134          12 :   return rewrite;
     135             : }
     136             : 
     137             : static void
     138           3 : ip6ip_tunnel_stack (adj_index_t ai, u32 fib_entry_index)
     139             : {
     140           3 :   ip_adjacency_t *adj = adj_get (ai);
     141             :   ipip_tunnel_t *t;
     142           3 :   u32 sw_if_index = adj->rewrite_header.sw_if_index;
     143             : 
     144           3 :   t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     145           3 :   if (!t)
     146           0 :     return;
     147             : 
     148             :   /*
     149             :    * find the adjacency that is contributed by the FIB entry
     150             :    * that this tunnel resolves via, and use it as the next adj
     151             :    * in the midchain
     152             :    */
     153           3 :   if (vnet_hw_interface_get_flags (vnet_get_main (), t->hw_if_index) &
     154             :       VNET_HW_INTERFACE_FLAG_LINK_UP)
     155             :     {
     156           3 :       adj_nbr_midchain_stack_on_fib_entry (ai,
     157             :                                            fib_entry_index,
     158             :                                            FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
     159             :     }
     160             :   else
     161             :     {
     162           0 :       adj_nbr_midchain_unstack (ai);
     163             :     }
     164             : }
     165             : 
     166             : static void
     167          11 : sixrd_tunnel_stack (adj_index_t ai, u32 fib_index)
     168             : {
     169          11 :   dpo_id_t dpo = DPO_INVALID;
     170          11 :   ip_adjacency_t *adj = adj_get (ai);
     171          11 :   u32 sw_if_index = adj->rewrite_header.sw_if_index;
     172             : 
     173          11 :   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     174          11 :   if (!t)
     175           0 :     return;
     176             : 
     177          11 :   lookup_dpo_add_or_lock_w_fib_index (fib_index, DPO_PROTO_IP4,
     178             :                                       LOOKUP_UNICAST, LOOKUP_INPUT_DST_ADDR,
     179             :                                       LOOKUP_TABLE_FROM_CONFIG, &dpo);
     180          11 :   adj_nbr_midchain_stack (ai, &dpo);
     181          11 :   dpo_reset (&dpo);
     182             : }
     183             : 
     184             : static void
     185          12 : sixrd_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
     186             : {
     187          12 :   ip_adjacency_t *adj = adj_get (ai);
     188          12 :   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     189             : 
     190             :   /* Not our tunnel */
     191          12 :   if (!t)
     192           0 :     return;
     193          12 :   if (IP_LOOKUP_NEXT_BCAST == adj->lookup_next_index)
     194             :     {
     195          11 :       adj_nbr_midchain_update_rewrite (ai, sixrd_fixup, t, ADJ_FLAG_NONE,
     196             :                                        sixrd_build_rewrite (vnm, sw_if_index,
     197          11 :                                                             adj_get_link_type
     198             :                                                             (ai), NULL));
     199          11 :       sixrd_tunnel_stack (ai, t->fib_index);
     200             :     }
     201             :   else
     202             :     {
     203             :       sixrd_adj_delegate_t *sixrd_ad;
     204             :       ip4_address_t da4;
     205             : 
     206           1 :       da4.as_u32 =
     207           1 :         sixrd_get_addr_net (t, adj->sub_type.nbr.next_hop.as_u64[0]);
     208             : 
     209           1 :       fib_prefix_t pfx = {
     210             :         .fp_proto = FIB_PROTOCOL_IP4,
     211             :         .fp_len = 32,
     212             :         .fp_addr = {
     213             :                     .ip4 = da4,
     214             :                     }
     215             :         ,
     216             :       };
     217             : 
     218           1 :       adj_nbr_midchain_update_rewrite (ai, ip6ip_fixup, t, ADJ_FLAG_NONE,
     219             :                                        sixrd_build_rewrite (vnm, sw_if_index,
     220           1 :                                                             adj_get_link_type
     221             :                                                             (ai), NULL));
     222             : 
     223           1 :       sixrd_ad =
     224           1 :         sixrd_adj_from_base (adj_delegate_get (adj, sixrd_adj_delegate_type));
     225           1 :       if (sixrd_ad == NULL)
     226             :         {
     227           1 :           pool_get (sixrd_adj_delegate_pool, sixrd_ad);
     228           1 :           fib_node_init (&sixrd_ad->sixrd_node, sixrd_fib_node_type);
     229           1 :           sixrd_ad->adj_index = ai;
     230           2 :           sixrd_ad->sixrd_fib_entry_index =
     231           1 :             fib_entry_track (t->fib_index, &pfx,
     232             :                              sixrd_fib_node_type,
     233           1 :                              sixrd_ad - sixrd_adj_delegate_pool,
     234           1 :                              &sixrd_ad->sixrd_sibling);
     235             : 
     236           1 :           adj_delegate_add (adj, sixrd_adj_delegate_type,
     237           1 :                             sixrd_ad - sixrd_adj_delegate_pool);
     238             : 
     239           1 :           ip6ip_tunnel_stack (ai, sixrd_ad->sixrd_fib_entry_index);
     240             :         }
     241             :     }
     242             : }
     243             : 
     244             : clib_error_t *
     245          22 : sixrd_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     246             : {
     247             :   /* Always up */
     248          22 :   vnet_hw_interface_set_flags (vnm, hw_if_index,
     249             :                                VNET_HW_INTERFACE_FLAG_LINK_UP);
     250          22 :   return /* no error */ 0;
     251             : }
     252             : 
     253             : /* *INDENT-OFF* */
     254        8063 : VNET_HW_INTERFACE_CLASS(sixrd_hw_interface_class) = {
     255             :     .name = "ip6ip-6rd",
     256             :     .build_rewrite = sixrd_build_rewrite,
     257             :     .update_adjacency = sixrd_update_adj,
     258             : };
     259             : 
     260       12095 : VNET_DEVICE_CLASS(sixrd_device_class) = {
     261             :     .name = "ip6ip-6rd",
     262             :     .admin_up_down_function = sixrd_interface_admin_up_down,
     263             : #ifdef SOON
     264             :     .clear counter = 0;
     265             : #endif
     266             : }
     267             : ;
     268             : /* *INDENT-ON* */
     269             : 
     270             : int
     271          11 : sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
     272             :                   ip4_address_t * ip4_prefix, u8 ip4_prefix_len,
     273             :                   ip4_address_t * ip4_src, bool security_check,
     274             :                   u32 ip4_fib_index, u32 ip6_fib_index, u32 * sw_if_index)
     275             : {
     276          11 :   ipip_main_t *gm = &ipip_main;
     277             :   ipip_tunnel_t *t;
     278             : 
     279          11 :   if ((ip6_prefix_len + 32 - ip4_prefix_len) > 64)
     280           0 :     return VNET_API_ERROR_INVALID_VALUE;
     281             : 
     282             :   /* Tunnel already configured */
     283          11 :   ip46_address_t src = ip46_address_initializer, dst =
     284             :     ip46_address_initializer;
     285          11 :   ip_set (&src, ip4_src, true);
     286             :   ipip_tunnel_key_t key;
     287             : 
     288          11 :   ipip_mk_key_i (IPIP_TRANSPORT_IP4, IPIP_MODE_6RD, &src, &dst, ip4_fib_index,
     289             :                  &key);
     290             : 
     291          11 :   t = ipip_tunnel_db_find (&key);
     292          11 :   if (t)
     293           0 :     return VNET_API_ERROR_IF_ALREADY_EXISTS;
     294             : 
     295             :   /* Get tunnel index */
     296          11 :   pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES);
     297          11 :   clib_memset (t, 0, sizeof (*t));
     298          11 :   u32 t_idx = t - gm->tunnels;       /* tunnel index (or instance) */
     299             : 
     300             :   /* Init tunnel struct */
     301          11 :   t->mode = IPIP_MODE_6RD;
     302          11 :   t->sixrd.ip4_prefix.as_u32 = ip4_prefix->as_u32;
     303          11 :   t->sixrd.ip4_prefix_len = ip4_prefix_len;
     304          11 :   t->sixrd.ip6_prefix = *ip6_prefix;
     305          11 :   t->sixrd.ip6_prefix_len = ip6_prefix_len;
     306          11 :   t->sixrd.ip6_fib_index = ip6_fib_index;
     307          11 :   t->tunnel_src = src;
     308          11 :   t->sixrd.security_check = security_check;
     309          11 :   t->sixrd.shift =
     310          11 :     (ip4_prefix_len < 32) ? 64 - ip6_prefix_len - (32 - ip4_prefix_len) : 0;
     311             : 
     312             :   /* Create interface */
     313             :   u32 hw_if_index =
     314          11 :     vnet_register_interface (vnet_get_main (), sixrd_device_class.index,
     315             :                              t_idx,
     316             :                              sixrd_hw_interface_class.index, t_idx);
     317             : 
     318             :   /* Default the interface to up and enable IPv6 (payload) */
     319             :   vnet_hw_interface_t *hi =
     320          11 :     vnet_get_hw_interface (vnet_get_main (), hw_if_index);
     321          11 :   t->hw_if_index = hw_if_index;
     322          11 :   t->fib_index = ip4_fib_index;
     323          11 :   t->sw_if_index = hi->sw_if_index;
     324          11 :   t->dev_instance = t_idx;
     325          11 :   t->user_instance = t_idx;
     326             : 
     327          11 :   vnet_sw_interface_set_mtu (vnet_get_main (), t->sw_if_index, 1480);
     328          11 :   vnet_set_interface_l3_output_node (gm->vlib_main, hi->sw_if_index,
     329             :                                      (u8 *) "tunnel-output");
     330             : 
     331          11 :   ipip_tunnel_db_add (t, &key);
     332             : 
     333          18 :   vec_validate_init_empty (gm->tunnel_index_by_sw_if_index, hi->sw_if_index,
     334             :                            ~0);
     335          11 :   gm->tunnel_index_by_sw_if_index[hi->sw_if_index] = t_idx;
     336             : 
     337          11 :   vnet_hw_interface_set_flags (vnet_get_main (), hw_if_index,
     338             :                                VNET_HW_INTERFACE_FLAG_LINK_UP);
     339          11 :   vnet_sw_interface_set_flags (vnet_get_main (), hi->sw_if_index,
     340             :                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     341          11 :   ip6_sw_interface_enable_disable (t->sw_if_index, true);
     342             : 
     343             :   /* Create IPv6 route/adjacency */
     344             :   /* *INDENT-OFF* */
     345          11 :   fib_prefix_t pfx6 = {
     346             :     .fp_proto = FIB_PROTOCOL_IP6,
     347          11 :     .fp_len = t->sixrd.ip6_prefix_len,
     348             :     .fp_addr = {
     349          11 :       .ip6 = t->sixrd.ip6_prefix,
     350             :     },
     351             :   };
     352             :   /* *INDENT-ON* */
     353             : 
     354          11 :   fib_table_lock (ip6_fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_6RD);
     355          11 :   fib_table_entry_update_one_path (ip6_fib_index, &pfx6, FIB_SOURCE_6RD,
     356             :                                    FIB_ENTRY_FLAG_ATTACHED, DPO_PROTO_IP6,
     357          11 :                                    &ADJ_BCAST_ADDR, t->sw_if_index, ~0, 1,
     358             :                                    NULL, FIB_ROUTE_PATH_FLAG_NONE);
     359             : 
     360          11 :   *sw_if_index = t->sw_if_index;
     361             : 
     362          11 :   if (!gm->ip4_protocol_registered)
     363             :     {
     364             :       vlib_node_t *ipip4_input =
     365          11 :         vlib_get_node_by_name (gm->vlib_main, (u8 *) "ipip4-input");
     366          11 :       ASSERT (ipip4_input);
     367          11 :       ip4_register_protocol (IP_PROTOCOL_IPV6, ipip4_input->index);
     368             :     }
     369          11 :   return 0;
     370             : }
     371             : 
     372             : /*
     373             :  * sixrd_del_tunnel
     374             :  */
     375             : int
     376          11 : sixrd_del_tunnel (u32 sw_if_index)
     377             : {
     378          11 :   ipip_main_t *gm = &ipip_main;
     379          11 :   ipip_tunnel_t *t = ipip_tunnel_db_find_by_sw_if_index (sw_if_index);
     380             :   ipip_tunnel_key_t key;
     381             : 
     382          11 :   if (!t)
     383             :     {
     384           0 :       clib_warning ("SIXRD tunnel delete: tunnel does not exist: %d",
     385             :                     sw_if_index);
     386           0 :       return -1;
     387             :     }
     388             : 
     389             :   /* *INDENT-OFF* */
     390          11 :   fib_prefix_t pfx6 = {
     391             :     .fp_proto = FIB_PROTOCOL_IP6,
     392          11 :     .fp_len = t->sixrd.ip6_prefix_len,
     393             :     .fp_addr = {
     394             :       .ip6 = t->sixrd.ip6_prefix,
     395             :     },
     396             :   };
     397             :   /* *INDENT-ON* */
     398             : 
     399          11 :   fib_table_entry_path_remove (t->sixrd.ip6_fib_index, &pfx6,
     400             :                                FIB_SOURCE_6RD,
     401             :                                DPO_PROTO_IP6,
     402             :                                &ADJ_BCAST_ADDR, t->sw_if_index, ~0, 1,
     403             :                                FIB_ROUTE_PATH_FLAG_NONE);
     404          11 :   fib_table_unlock (t->sixrd.ip6_fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_6RD);
     405             : 
     406          11 :   vnet_sw_interface_set_flags (vnet_get_main (), t->sw_if_index,
     407             :                                0 /* down */ );
     408          11 :   vnet_reset_interface_l3_output_node (gm->vlib_main, t->sw_if_index);
     409          11 :   ip6_sw_interface_enable_disable (t->sw_if_index, false);
     410          11 :   gm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
     411             : 
     412          11 :   vnet_delete_hw_interface (vnet_get_main (), t->hw_if_index);
     413          11 :   ipip_mk_key (t, &key);
     414          11 :   ipip_tunnel_db_remove (t, &key);
     415          11 :   pool_put (gm->tunnels, t);
     416             : 
     417          11 :   return 0;
     418             : }
     419             : 
     420             : static void
     421           1 : sixrd_adj_delegate_adj_deleted (adj_delegate_t * aed)
     422             : {
     423             :   sixrd_adj_delegate_t *sixrd_ad;
     424             : 
     425           1 :   sixrd_ad = sixrd_adj_from_base (aed);
     426           1 :   fib_entry_untrack (sixrd_ad->sixrd_fib_entry_index,
     427             :                      sixrd_ad->sixrd_sibling);
     428           1 :   pool_put (sixrd_adj_delegate_pool, sixrd_ad);
     429           1 : }
     430             : 
     431             : static u8 *
     432           0 : sixrd_adj_delegate_format (const adj_delegate_t * aed, u8 * s)
     433             : {
     434             :   const sixrd_adj_delegate_t *sixrd_ad;
     435             : 
     436           0 :   sixrd_ad = sixrd_adj_from_const_base (aed);
     437           0 :   s = format (s, "SIXRD:[fib-entry:%d]", sixrd_ad->sixrd_fib_entry_index);
     438             : 
     439           0 :   return (s);
     440             : }
     441             : 
     442             : static void
     443           0 : sixrd_fib_node_last_lock_gone (fib_node_t * node)
     444             : {
     445             :   /* top of the dependency tree, locks not managed here. */
     446           0 : }
     447             : 
     448             : static sixrd_adj_delegate_t *
     449           2 : sixrd_adj_delegate_from_fib_node (fib_node_t * node)
     450             : {
     451           2 :   return ((sixrd_adj_delegate_t *) (((char *) node) -
     452             :                                     STRUCT_OFFSET_OF (sixrd_adj_delegate_t,
     453             :                                                       sixrd_node)));
     454             : }
     455             : 
     456             : static fib_node_back_walk_rc_t
     457           2 : sixrd_fib_node_back_walk_notify (fib_node_t * node,
     458             :                                  fib_node_back_walk_ctx_t * ctx)
     459             : {
     460             :   sixrd_adj_delegate_t *sixrd_ad;
     461             : 
     462           2 :   sixrd_ad = sixrd_adj_delegate_from_fib_node (node);
     463           2 :   ip6ip_tunnel_stack (sixrd_ad->adj_index, sixrd_ad->sixrd_fib_entry_index);
     464             : 
     465           2 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     466             : }
     467             : 
     468             : /**
     469             :  * Function definition to get a FIB node from its index
     470             :  */
     471             : static fib_node_t *
     472           2 : sixrd_fib_node_get (fib_node_index_t index)
     473             : {
     474             :   sixrd_adj_delegate_t *sixrd_ad;
     475             : 
     476           2 :   sixrd_ad = pool_elt_at_index (sixrd_adj_delegate_pool, index);
     477             : 
     478           2 :   return (&sixrd_ad->sixrd_node);
     479             : }
     480             : 
     481             : /**
     482             :  * VFT registered with the adjacency delegate
     483             :  */
     484             : const static adj_delegate_vft_t sixrd_adj_delegate_vft = {
     485             :   .adv_adj_deleted = sixrd_adj_delegate_adj_deleted,
     486             :   .adv_format = sixrd_adj_delegate_format,
     487             : };
     488             : 
     489             : /**
     490             :  * VFT registered with the FIB node for the adj delegate
     491             :  */
     492             : const static fib_node_vft_t sixrd_fib_node_vft = {
     493             :   .fnv_get = sixrd_fib_node_get,
     494             :   .fnv_last_lock = sixrd_fib_node_last_lock_gone,
     495             :   .fnv_back_walk = sixrd_fib_node_back_walk_notify,
     496             : };
     497             : 
     498             : static clib_error_t *
     499         575 : sixrd_init (vlib_main_t * vm)
     500             : {
     501         575 :   clib_error_t *error = 0;
     502             : 
     503             :   /* Make sure the IPIP tunnel subsystem is initialised */
     504         575 :   error = vlib_call_init_function (vm, ipip_init);
     505             : 
     506         575 :   sixrd_adj_delegate_type =
     507         575 :     adj_delegate_register_new_type (&sixrd_adj_delegate_vft);
     508         575 :   sixrd_fib_node_type =
     509         575 :     fib_node_register_new_type ("sixrd", &sixrd_fib_node_vft);
     510             : 
     511         575 :   return error;
     512             : }
     513             : 
     514       62783 : VLIB_INIT_FUNCTION (sixrd_init);
     515             : 
     516             : /*
     517             :  * fd.io coding-style-patch-verification: ON
     518             :  *
     519             :  * Local Variables:
     520             :  * eval: (c-set-style "gnu")
     521             :  * End:
     522             :  */

Generated by: LCOV version 1.14