LCOV - code coverage report
Current view: top level - vnet/fib - ip6_fib.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 277 312 88.8 %
Date: 2023-10-26 01:39:38 Functions: 30 31 96.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/fib/ip6_fib.h>
      17             : #include <vnet/fib/fib_table.h>
      18             : #include <vnet/dpo/ip6_ll_dpo.h>
      19             : 
      20             : #include <vppinfra/bihash_24_8.h>
      21             : #include <vppinfra/bihash_template.c>
      22             : 
      23             : ip6_fib_table_instance_t ip6_fib_table[IP6_FIB_NUM_TABLES];
      24             : 
      25             : /* ip6 lookup table config parameters */
      26             : u32 ip6_fib_table_nbuckets;
      27             : uword ip6_fib_table_size;
      28             : 
      29             : static void
      30        2824 : vnet_ip6_fib_init (u32 fib_index)
      31             : {
      32        2824 :     fib_prefix_t pfx = {
      33             :         .fp_proto = FIB_PROTOCOL_IP6,
      34             :         .fp_len = 0,
      35             :         .fp_addr = {
      36             :             .ip6 = {
      37             :                 { 0, 0, },
      38             :             },
      39             :         }
      40             :     };
      41             : 
      42             :     /*
      43             :      * Add the default route.
      44             :      */
      45        2824 :     fib_table_entry_special_add(fib_index,
      46             :                                 &pfx,
      47             :                                 FIB_SOURCE_DEFAULT_ROUTE,
      48             :                                 FIB_ENTRY_FLAG_DROP);
      49             : 
      50             :     /*
      51             :      * all link local via the link local lookup DPO
      52             :      */
      53        2824 :     pfx.fp_addr.ip6.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
      54        2824 :     pfx.fp_addr.ip6.as_u64[1] = 0;
      55        2824 :     pfx.fp_len = 10;
      56        2824 :     fib_table_entry_special_dpo_add(fib_index,
      57             :                                     &pfx,
      58             :                                     FIB_SOURCE_SPECIAL,
      59             :                                     FIB_ENTRY_FLAG_NONE,
      60             :                                     ip6_ll_dpo_get());
      61        2824 : }
      62             : 
      63             : static u32
      64        2824 : create_fib_with_table_id (u32 table_id,
      65             :                           fib_source_t src,
      66             :                           fib_table_flags_t flags,
      67             :                           u8 *desc)
      68             : {
      69             :     fib_table_t *fib_table;
      70             :     ip6_fib_t *v6_fib;
      71             : 
      72        2824 :     pool_get(ip6_main.fibs, fib_table);
      73        2824 :     pool_get_aligned(ip6_main.v6_fibs, v6_fib, CLIB_CACHE_LINE_BYTES);
      74             : 
      75        2824 :     clib_memset(fib_table, 0, sizeof(*fib_table));
      76        2824 :     clib_memset(v6_fib, 0, sizeof(*v6_fib));
      77             : 
      78        2824 :     ASSERT((fib_table - ip6_main.fibs) ==
      79             :            (v6_fib - ip6_main.v6_fibs));
      80             :     
      81        2824 :     fib_table->ft_proto = FIB_PROTOCOL_IP6;
      82        2824 :     fib_table->ft_index =
      83        2824 :             v6_fib->index =
      84        2824 :                 (fib_table - ip6_main.fibs);
      85             : 
      86        2824 :     hash_set(ip6_main.fib_index_by_table_id, table_id, fib_table->ft_index);
      87             : 
      88        2824 :     fib_table->ft_table_id =
      89        2824 :         v6_fib->table_id =
      90             :             table_id;
      91        2824 :     fib_table->ft_flow_hash_config = IP_FLOW_HASH_DEFAULT;
      92        2824 :     fib_table->ft_flags = flags;
      93        2824 :     fib_table->ft_desc = desc;
      94             : 
      95        2824 :     vnet_ip6_fib_init(fib_table->ft_index);
      96        2824 :     fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_IP6, src);
      97             : 
      98        2824 :     return (fib_table->ft_index);
      99             : }
     100             : 
     101             : u32
     102         787 : ip6_fib_table_find_or_create_and_lock (u32 table_id,
     103             :                                        fib_source_t src)
     104             : {
     105             :     uword * p;
     106             : 
     107         787 :     p = hash_get (ip6_main.fib_index_by_table_id, table_id);
     108         787 :     if (NULL == p)
     109         703 :         return create_fib_with_table_id(table_id, src,
     110             :                                         FIB_TABLE_FLAG_NONE,
     111             :                                         NULL);
     112             : 
     113          84 :     fib_table_lock(p[0], FIB_PROTOCOL_IP6, src);
     114             : 
     115          84 :     return (p[0]);
     116             : }
     117             : 
     118             : u32
     119        2121 : ip6_fib_table_create_and_lock (fib_source_t src,
     120             :                                fib_table_flags_t flags,
     121             :                                u8 *desc)
     122             : {
     123        2121 :     return (create_fib_with_table_id(~0, src, flags, desc));
     124             : }
     125             : 
     126             : void
     127        2066 : ip6_fib_table_destroy (u32 fib_index)
     128             : {
     129             :     /*
     130             :      * all link local first ...
     131             :      */
     132        2066 :     fib_prefix_t pfx = {
     133             :         .fp_proto = FIB_PROTOCOL_IP6,
     134             :         .fp_len = 10,
     135             :         .fp_addr = {
     136             :             .ip6 = {
     137             :                 .as_u8 = {
     138             :                     [0] = 0xFE,
     139             :                     [1] = 0x80,
     140             :                 },
     141             :             },
     142             :         }
     143             :     };
     144        2066 :     fib_table_entry_delete(fib_index,
     145             :                            &pfx,
     146             :                            FIB_SOURCE_SPECIAL);
     147             : 
     148             :     /*
     149             :      * ... then the default route.
     150             :      */
     151        2066 :     pfx.fp_addr.ip6.as_u64[0] = 0;
     152        2066 :     pfx.fp_len = 00;
     153        2066 :     fib_table_entry_special_remove(fib_index,
     154             :                                    &pfx,
     155             :                                    FIB_SOURCE_DEFAULT_ROUTE);
     156             : 
     157        2066 :     fib_table_t *fib_table = fib_table_get(fib_index, FIB_PROTOCOL_IP6);
     158             :     fib_source_t source;
     159             : 
     160             :     /*
     161             :      * validate no more routes.
     162             :      */
     163             : #if CLIB_DEBUG > 0
     164        2066 :     if (0 != fib_table->ft_total_route_counts)
     165           0 :         fib_table_assert_empty(fib_table);
     166             : #endif
     167             : 
     168       45486 :     vec_foreach_index(source, fib_table->ft_src_route_counts)
     169             :     {
     170       43420 :         ASSERT(0 == fib_table->ft_src_route_counts[source]);
     171             :     }
     172             : 
     173        2066 :     if (~0 != fib_table->ft_table_id)
     174             :     {
     175         121 :         hash_unset (ip6_main.fib_index_by_table_id, fib_table->ft_table_id);
     176             :     }
     177        2066 :     vec_free (fib_table->ft_locks);
     178        2066 :     vec_free(fib_table->ft_src_route_counts);
     179        2066 :     pool_put_index(ip6_main.v6_fibs, fib_table->ft_index);
     180        2066 :     pool_put(ip6_main.fibs, fib_table);
     181        2066 : }
     182             : 
     183             : fib_node_index_t
     184       29773 : ip6_fib_table_lookup (u32 fib_index,
     185             :                       const ip6_address_t *addr,
     186             :                       u32 len)
     187             : {
     188             :     ip6_fib_table_instance_t *table;
     189             :     clib_bihash_kv_24_8_t kv, value;
     190             :     int i, n_p, rv;
     191             :     u64 fib;
     192             : 
     193       29773 :     table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
     194       29773 :     n_p = vec_len (table->prefix_lengths_in_search_order);
     195             : 
     196       29773 :     kv.key[0] = addr->as_u64[0];
     197       29773 :     kv.key[1] = addr->as_u64[1];
     198       29773 :     fib = ((u64)((fib_index))<<32);
     199             : 
     200             :     /*
     201             :      * start search from a mask length same length or shorter.
     202             :      * we don't want matches longer than the mask passed
     203             :      */
     204       29773 :     i = 0;
     205       67282 :     while (i < n_p && table->prefix_lengths_in_search_order[i] > len)
     206             :     {
     207       37509 :         i++;
     208             :     }
     209             : 
     210       44853 :     for (; i < n_p; i++)
     211             :     {
     212       44853 :         int dst_address_length = table->prefix_lengths_in_search_order[i];
     213       44853 :         ip6_address_t * mask = &ip6_main.fib_masks[dst_address_length];
     214             :       
     215       44853 :         ASSERT(dst_address_length >= 0 && dst_address_length <= 128);
     216             :         //As lengths are decreasing, masks are increasingly specific.
     217       44853 :         kv.key[0] &= mask->as_u64[0];
     218       44853 :         kv.key[1] &= mask->as_u64[1];
     219       44853 :         kv.key[2] = fib | dst_address_length;
     220             :       
     221       44853 :         rv = clib_bihash_search_inline_2_24_8(&table->ip6_hash, &kv, &value);
     222       44853 :         if (rv == 0)
     223       29773 :             return value.value;
     224             :     }
     225             : 
     226           0 :     return (FIB_NODE_INDEX_INVALID);
     227             : }
     228             : 
     229             : fib_node_index_t
     230       59433 : ip6_fib_table_lookup_exact_match (u32 fib_index,
     231             :                                   const ip6_address_t *addr,
     232             :                                   u32 len)
     233             : {
     234             :     ip6_fib_table_instance_t *table;
     235             :     clib_bihash_kv_24_8_t kv, value;
     236             :     ip6_address_t *mask;
     237             :     u64 fib;
     238             :     int rv;
     239             : 
     240       59433 :     table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
     241       59433 :     mask = &ip6_main.fib_masks[len];
     242       59433 :     fib = ((u64)((fib_index))<<32);
     243             : 
     244       59433 :     kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
     245       59433 :     kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
     246       59433 :     kv.key[2] = fib | len;
     247             :       
     248       59433 :     rv = clib_bihash_search_inline_2_24_8(&table->ip6_hash, &kv, &value);
     249       59433 :     if (rv == 0)
     250       41393 :         return value.value;
     251             : 
     252       18040 :     return (FIB_NODE_INDEX_INVALID);
     253             : }
     254             : 
     255             : static void
     256        7679 : compute_prefix_lengths_in_search_order (ip6_fib_table_instance_t *table)
     257             : {
     258        7679 :     u8 *old, *prefix_lengths_in_search_order = NULL;
     259             :     int i;
     260             : 
     261             :     /*
     262             :      * build the list in a scratch space then cutover so the workers
     263             :      * can continue uninterrupted.
     264             :      */
     265        7679 :     old = table->prefix_lengths_in_search_order;
     266             : 
     267             :     /* Note: bitmap reversed so this is in fact a longest prefix match */
     268       27836 :     clib_bitmap_foreach (i, table->non_empty_dst_address_length_bitmap)
     269             :      {
     270       20157 :         int dst_address_length = 128 - i;
     271       20157 :         vec_add1(prefix_lengths_in_search_order, dst_address_length);
     272             :     }
     273             : 
     274        7679 :     table->prefix_lengths_in_search_order = prefix_lengths_in_search_order;
     275             : 
     276             :     /*
     277             :      * let the workers go once round the track before we free the old set
     278             :      */
     279        7679 :     vlib_worker_wait_one_loop();
     280        7679 :     vec_free(old);
     281        7679 : }
     282             : 
     283             : void
     284       13990 : ip6_fib_table_entry_remove (u32 fib_index,
     285             :                             const ip6_address_t *addr,
     286             :                             u32 len)
     287             : {
     288             :     ip6_fib_table_instance_t *table;
     289             :     clib_bihash_kv_24_8_t kv;
     290             :     ip6_address_t *mask;
     291             :     u64 fib;
     292             : 
     293       13990 :     table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
     294       13990 :     mask = &ip6_main.fib_masks[len];
     295       13990 :     fib = ((u64)((fib_index))<<32);
     296             : 
     297       13990 :     kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
     298       13990 :     kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
     299       13990 :     kv.key[2] = fib | len;
     300             : 
     301       13990 :     clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 0);
     302             : 
     303             :     /* refcount accounting */
     304       13990 :     ASSERT (table->dst_address_length_refcounts[len] > 0);
     305       13990 :     if (--table->dst_address_length_refcounts[len] == 0)
     306             :     {
     307        1277 :         table->non_empty_dst_address_length_bitmap =
     308        1277 :             clib_bitmap_set (table->non_empty_dst_address_length_bitmap, 
     309        1277 :                              128 - len, 0);
     310        1277 :         compute_prefix_lengths_in_search_order (table);
     311             :     }
     312       13990 : }
     313             : 
     314             : void
     315       17827 : ip6_fib_table_entry_insert (u32 fib_index,
     316             :                             const ip6_address_t *addr,
     317             :                             u32 len,
     318             :                             fib_node_index_t fib_entry_index)
     319             : {
     320             :     ip6_fib_table_instance_t *table;
     321             :     clib_bihash_kv_24_8_t kv;
     322             :     ip6_address_t *mask;
     323             :     u64 fib;
     324             : 
     325       17827 :     table = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING];
     326       17827 :     mask = &ip6_main.fib_masks[len];
     327       17827 :     fib = ((u64)((fib_index))<<32);
     328             : 
     329       17827 :     kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
     330       17827 :     kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
     331       17827 :     kv.key[2] = fib | len;
     332       17827 :     kv.value = fib_entry_index;
     333             : 
     334       17827 :     clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 1);
     335             : 
     336       17827 :     if (0 == table->dst_address_length_refcounts[len]++)
     337             :     {
     338        2579 :         table->non_empty_dst_address_length_bitmap =
     339        2579 :             clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
     340        2579 :                              128 - len, 1);
     341        2579 :         compute_prefix_lengths_in_search_order (table);
     342             :     }
     343       17827 : }
     344             : 
     345        1758 : u32 ip6_fib_table_fwding_lookup_with_if_index (ip6_main_t * im,
     346             :                                                u32 sw_if_index,
     347             :                                                const ip6_address_t * dst)
     348             : {
     349        1758 :     u32 fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
     350        1758 :     return ip6_fib_table_fwding_lookup(fib_index, dst);
     351             : }
     352             : 
     353             : u32
     354       16239 : ip6_fib_table_get_index_for_sw_if_index (u32 sw_if_index)
     355             : {
     356       16239 :     if (sw_if_index >= vec_len(ip6_main.fib_index_by_sw_if_index))
     357             :     {
     358             :         /*
     359             :          * This is the case for interfaces that are not yet mapped to
     360             :          * a IP table
     361             :          */
     362           0 :         return (~0);
     363             :     }
     364       16239 :     return (ip6_main.fib_index_by_sw_if_index[sw_if_index]);
     365             : }
     366             : 
     367             : void
     368       17850 : ip6_fib_table_fwding_dpo_update (u32 fib_index,
     369             :                                  const ip6_address_t *addr,
     370             :                                  u32 len,
     371             :                                  const dpo_id_t *dpo)
     372             : {
     373             :     ip6_fib_table_instance_t *table;
     374             :     clib_bihash_kv_24_8_t kv;
     375             :     ip6_address_t *mask;
     376             :     u64 fib;
     377             : 
     378       17850 :     table = &ip6_fib_table[IP6_FIB_TABLE_FWDING];
     379       17850 :     mask = &ip6_main.fib_masks[len];
     380       17850 :     fib = ((u64)((fib_index))<<32);
     381             : 
     382       17850 :     kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
     383       17850 :     kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
     384       17850 :     kv.key[2] = fib | len;
     385       17850 :     kv.value = dpo->dpoi_index;
     386             : 
     387       17850 :     clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 1);
     388             : 
     389       17850 :     if (0 == table->dst_address_length_refcounts[len]++)
     390             :     {
     391        2564 :         table->non_empty_dst_address_length_bitmap =
     392        2564 :             clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
     393        2564 :                              128 - len, 1);
     394        2564 :         compute_prefix_lengths_in_search_order (table);
     395             :     }
     396       17850 : }
     397             : 
     398             : void
     399       14009 : ip6_fib_table_fwding_dpo_remove (u32 fib_index,
     400             :                                  const ip6_address_t *addr,
     401             :                                  u32 len,
     402             :                                  const dpo_id_t *dpo)
     403             : {
     404             :     ip6_fib_table_instance_t *table;
     405             :     clib_bihash_kv_24_8_t kv;
     406             :     ip6_address_t *mask;
     407             :     u64 fib;
     408             : 
     409       14009 :     table = &ip6_fib_table[IP6_FIB_TABLE_FWDING];
     410       14009 :     mask = &ip6_main.fib_masks[len];
     411       14009 :     fib = ((u64)((fib_index))<<32);
     412             : 
     413       14009 :     kv.key[0] = addr->as_u64[0] & mask->as_u64[0];
     414       14009 :     kv.key[1] = addr->as_u64[1] & mask->as_u64[1];
     415       14009 :     kv.key[2] = fib | len;
     416       14009 :     kv.value = dpo->dpoi_index;
     417             : 
     418       14009 :     clib_bihash_add_del_24_8(&table->ip6_hash, &kv, 0);
     419             : 
     420             :     /* refcount accounting */
     421       14009 :     ASSERT (table->dst_address_length_refcounts[len] > 0);
     422       14009 :     if (--table->dst_address_length_refcounts[len] == 0)
     423             :     {
     424        1259 :         table->non_empty_dst_address_length_bitmap =
     425        1259 :             clib_bitmap_set (table->non_empty_dst_address_length_bitmap,
     426        1259 :                              128 - len, 0);
     427        1259 :         compute_prefix_lengths_in_search_order (table);
     428             :     }
     429       14009 : }
     430             : 
     431             : /**
     432             :  * @brief Context when walking the IPv6 table. Since all VRFs are in the
     433             :  * same hash table, we need to filter only those we need as we walk
     434             :  */
     435             : typedef struct ip6_fib_walk_ctx_t_
     436             : {
     437             :     u32 i6w_fib_index;
     438             :     fib_table_walk_fn_t i6w_fn;
     439             :     void *i6w_ctx;
     440             :     fib_prefix_t i6w_root;
     441             :     fib_prefix_t *i6w_sub_trees;
     442             : } ip6_fib_walk_ctx_t;
     443             : 
     444             : static int
     445       47248 : ip6_fib_walk_cb (clib_bihash_kv_24_8_t * kvp,
     446             :                  void *arg)
     447             : {
     448       47248 :     ip6_fib_walk_ctx_t *ctx = arg;
     449             :     ip6_address_t key;
     450             : 
     451       47248 :     if ((kvp->key[2] >> 32) == ctx->i6w_fib_index)
     452             :     {
     453       17899 :         key.as_u64[0] = kvp->key[0];
     454       17899 :         key.as_u64[1] = kvp->key[1];
     455             : 
     456       17899 :         if (ip6_destination_matches_route(&ip6_main,
     457             :                                           &key,
     458       17899 :                                           &ctx->i6w_root.fp_addr.ip6,
     459       17899 :                                           ctx->i6w_root.fp_len))
     460             :         {
     461             :             const fib_prefix_t *sub_tree;
     462       17883 :             int skip = 0;
     463             : 
     464             :             /*
     465             :              * exclude sub-trees the walk does not want to explore
     466             :              */
     467       17885 :             vec_foreach(sub_tree, ctx->i6w_sub_trees)
     468             :             {
     469           3 :                 if (ip6_destination_matches_route(&ip6_main,
     470             :                                                   &key,
     471             :                                                   &sub_tree->fp_addr.ip6,
     472           3 :                                                   sub_tree->fp_len))
     473             :                 {
     474           1 :                     skip = 1;
     475           1 :                     break;
     476             :                 }
     477             :             }
     478             : 
     479       17883 :             if (!skip)
     480             :             {
     481       17882 :                 switch (ctx->i6w_fn(kvp->value, ctx->i6w_ctx))
     482             :                 {
     483       17880 :                 case FIB_TABLE_WALK_CONTINUE:
     484       17880 :                     break;
     485           2 :                 case FIB_TABLE_WALK_SUB_TREE_STOP: {
     486           2 :                     fib_prefix_t pfx = {
     487             :                         .fp_proto = FIB_PROTOCOL_IP6,
     488           2 :                         .fp_len = kvp->key[2] & 0xffffffff,
     489             :                         .fp_addr.ip6 = key,
     490             :                     };
     491           2 :                     vec_add1(ctx->i6w_sub_trees, pfx);
     492           2 :                     break;
     493             :                 }
     494           0 :                 case FIB_TABLE_WALK_STOP:
     495           0 :                     goto done;
     496             :                 }
     497             :             }
     498             :         }
     499             :     }
     500       29366 : done:
     501             : 
     502       47248 :     return (1);
     503             : }
     504             : 
     505             : void
     506        1402 : ip6_fib_table_walk (u32 fib_index,
     507             :                     fib_table_walk_fn_t fn,
     508             :                     void *arg)
     509             : {
     510        1402 :     ip6_fib_walk_ctx_t ctx = {
     511             :         .i6w_fib_index = fib_index,
     512             :         .i6w_fn = fn,
     513             :         .i6w_ctx = arg,
     514             :         .i6w_root = {
     515             :             .fp_proto = FIB_PROTOCOL_IP6,
     516             :         },
     517             :         .i6w_sub_trees = NULL,
     518             :     };
     519             : 
     520        1402 :     clib_bihash_foreach_key_value_pair_24_8(
     521             :         &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
     522             :         ip6_fib_walk_cb,
     523             :         &ctx);
     524             : 
     525        1402 :     vec_free(ctx.i6w_sub_trees);
     526        1402 : }
     527             : 
     528             : void
     529           6 : ip6_fib_table_sub_tree_walk (u32 fib_index,
     530             :                              const fib_prefix_t *root,
     531             :                              fib_table_walk_fn_t fn,
     532             :                              void *arg)
     533             : {
     534           6 :     ip6_fib_walk_ctx_t ctx = {
     535             :         .i6w_fib_index = fib_index,
     536             :         .i6w_fn = fn,
     537             :         .i6w_ctx = arg,
     538             :         .i6w_root = *root,
     539             :     };
     540             : 
     541           6 :     clib_bihash_foreach_key_value_pair_24_8(
     542             :         &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
     543             :         ip6_fib_walk_cb,
     544             :         &ctx);
     545           6 : }
     546             : 
     547             : typedef struct ip6_fib_show_ctx_t_ {
     548             :     fib_node_index_t *entries;
     549             : } ip6_fib_show_ctx_t;
     550             : 
     551             : static fib_table_walk_rc_t
     552        1742 : ip6_fib_table_show_walk (fib_node_index_t fib_entry_index,
     553             :                          void *arg)
     554             : {
     555        1742 :     ip6_fib_show_ctx_t *ctx = arg;
     556             : 
     557        1742 :     vec_add1(ctx->entries, fib_entry_index);
     558             : 
     559        1742 :     return (FIB_TABLE_WALK_CONTINUE);
     560             : }
     561             : 
     562             : static void
     563         199 : ip6_fib_table_show_all (ip6_fib_t *fib,
     564             :                         vlib_main_t * vm)
     565             : {
     566             :     fib_node_index_t *fib_entry_index;
     567         199 :     ip6_fib_show_ctx_t ctx = {
     568             :         .entries = NULL,
     569             :     };
     570             : 
     571         199 :     ip6_fib_table_walk(fib->index, ip6_fib_table_show_walk, &ctx);
     572         199 :     vec_sort_with_function(ctx.entries, fib_entry_cmp_for_sort);
     573             : 
     574        1941 :     vec_foreach(fib_entry_index, ctx.entries)
     575             :     {
     576        1742 :         vlib_cli_output(vm, "%U",
     577             :                         format_fib_entry,
     578             :                         *fib_entry_index,
     579             :                         FIB_ENTRY_FORMAT_BRIEF);
     580             :     }
     581             : 
     582         199 :     vec_free(ctx.entries);
     583         199 : }
     584             : 
     585             : static void
     586         135 : ip6_fib_table_show_one (ip6_fib_t *fib,
     587             :                         vlib_main_t * vm,
     588             :                         ip6_address_t *address,
     589             :                         u32 mask_len,
     590             :                         int detail)
     591             : {
     592         135 :     vlib_cli_output(vm, "%U",
     593             :                     format_fib_entry,
     594             :                     ip6_fib_table_lookup(fib->index, address, mask_len),
     595             :                     (detail ?
     596             :                      FIB_ENTRY_FORMAT_DETAIL2:
     597             :                      FIB_ENTRY_FORMAT_DETAIL));
     598         135 : }
     599             : 
     600             : u8 *
     601           1 : format_ip6_fib_table_memory (u8 * s, va_list * args)
     602             : {
     603             :     uword bytes_inuse;
     604             : 
     605           1 :     bytes_inuse = (alloc_arena_next(&(ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash)) +
     606           1 :                    alloc_arena_next(&(ip6_fib_table[IP6_FIB_TABLE_FWDING].ip6_hash)));
     607             : 
     608           1 :     s = format(s, "%=30s %=6d %=12ld\n",
     609             :                "IPv6 unicast",
     610           1 :                pool_elts(ip6_main.fibs),
     611             :                bytes_inuse);
     612           1 :     return (s);
     613             : }
     614             : 
     615             : typedef struct {
     616             :   u32 fib_index;
     617             :   u64 count_by_prefix_length[129];
     618             : } count_routes_in_fib_at_prefix_length_arg_t;
     619             : 
     620             : static int
     621           0 : count_routes_in_fib_at_prefix_length (clib_bihash_kv_24_8_t * kvp,
     622             :                                       void *arg)
     623             : {
     624           0 :   count_routes_in_fib_at_prefix_length_arg_t * ap = arg;
     625             :   int mask_width;
     626             : 
     627           0 :   if ((kvp->key[2]>>32) != ap->fib_index)
     628           0 :       return (BIHASH_WALK_CONTINUE);
     629             : 
     630           0 :   mask_width = kvp->key[2] & 0xFF;
     631             : 
     632           0 :   ap->count_by_prefix_length[mask_width]++;
     633             : 
     634           0 :   return (BIHASH_WALK_CONTINUE);
     635             : }
     636             : 
     637             : static clib_error_t *
     638         106 : ip6_show_fib (vlib_main_t * vm,
     639             :               unformat_input_t * input,
     640             :               vlib_cli_command_t * cmd)
     641             : {
     642         106 :     count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
     643         106 :     ip6_main_t * im6 = &ip6_main;
     644             :     fib_table_t *fib_table;
     645             :     ip6_fib_t * fib;
     646             :     int verbose, matching;
     647             :     ip6_address_t matching_address;
     648         106 :     u32 mask_len  = 128;
     649         106 :     int table_id = -1, fib_index = ~0;
     650         106 :     int detail = 0;
     651         106 :     int hash = 0;
     652             : 
     653         106 :     verbose = 1;
     654         106 :     matching = 0;
     655             : 
     656         174 :     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     657             :     {
     658         136 :         if (unformat (input, "brief")   ||
     659         136 :             unformat (input, "summary") ||
     660          68 :             unformat (input, "sum"))
     661           0 :             verbose = 0;
     662             :  
     663         136 :         else if (unformat (input, "detail")   ||
     664          68 :                  unformat (input, "det"))
     665           0 :             detail = 1;
     666             : 
     667         136 :         else if (unformat (input, "hash") ||
     668         136 :                  unformat (input, "mem") ||
     669          68 :                  unformat (input, "memory"))
     670           0 :             hash = 1;
     671             : 
     672          68 :         else if (unformat (input, "%U/%d",
     673             :                            unformat_ip6_address, &matching_address, &mask_len))
     674           0 :             matching = 1;
     675             : 
     676          68 :         else if (unformat (input, "%U", unformat_ip6_address, &matching_address))
     677          68 :             matching = 1;
     678             : 
     679           0 :         else if (unformat (input, "table %d", &table_id))
     680             :             ;
     681           0 :         else if (unformat (input, "index %d", &fib_index))
     682             :             ;
     683             :         else
     684           0 :             break;
     685             :     }
     686             : 
     687         106 :     if (hash)
     688             :     {
     689           0 :         vlib_cli_output (vm, "IPv6 Non-Forwarding Hash Table:\n%U\n",
     690             :                          BV (format_bihash),
     691             :                          &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
     692             :                          detail);
     693           0 :         vlib_cli_output (vm, "IPv6 Forwarding Hash Table:\n%U\n",
     694             :                          BV (format_bihash),
     695             :                          &ip6_fib_table[IP6_FIB_TABLE_FWDING].ip6_hash,
     696             :                          detail);
     697           0 :         return (NULL);
     698             :     }
     699             : 
     700         787 :     pool_foreach (fib_table, im6->fibs)
     701             :      {
     702             :         fib_source_t source;
     703         681 :         u8 *s = NULL;
     704             : 
     705         681 :         fib = pool_elt_at_index(im6->v6_fibs, fib_table->ft_index);
     706         681 :         if (table_id >= 0 && table_id != (int)fib->table_id)
     707         347 :             continue;
     708         681 :         if (fib_index != ~0 && fib_index != (int)fib->index)
     709           0 :             continue;
     710         681 :         if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
     711         347 :             continue;
     712             : 
     713         668 :         s = format(s, "%U, fib_index:%d, flow hash:[%U] epoch:%d flags:%U locks:[",
     714             :                    format_fib_table_name, fib->index,
     715             :                    FIB_PROTOCOL_IP6,
     716             :                    fib->index,
     717             :                    format_ip_flow_hash_config,
     718             :                    fib_table->ft_flow_hash_config,
     719             :                    fib_table->ft_epoch,
     720         334 :                    format_fib_table_flags, fib_table->ft_flags);
     721             : 
     722        6415 :         vec_foreach_index(source, fib_table->ft_locks)
     723             :         {
     724        6081 :             if (0 != fib_table->ft_locks[source])
     725             :             {
     726         682 :                 s = format(s, "%U:%d, ",
     727             :                            format_fib_source, source,
     728         682 :                            fib_table->ft_locks[source]);
     729             :             }
     730             :         }
     731         334 :         s = format (s, "]");
     732         334 :         vlib_cli_output (vm, "%v", s);
     733         334 :         vec_free(s);
     734             : 
     735             :         /* Show summary? */
     736         334 :         if (! verbose)
     737             :         {
     738           0 :             clib_bihash_24_8_t * h = &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
     739             :             int len;
     740             : 
     741           0 :             vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
     742             : 
     743           0 :             clib_memset (ca, 0, sizeof(*ca));
     744           0 :             ca->fib_index = fib->index;
     745             : 
     746           0 :             clib_bihash_foreach_key_value_pair_24_8
     747             :                 (h, count_routes_in_fib_at_prefix_length, ca);
     748             : 
     749           0 :             for (len = 128; len >= 0; len--)
     750             :             {
     751           0 :                 if (ca->count_by_prefix_length[len])
     752           0 :                     vlib_cli_output (vm, "%=20d%=16lld", 
     753             :                                      len, ca->count_by_prefix_length[len]);
     754             :             }
     755           0 :             continue;
     756             :         }
     757             : 
     758         334 :         if (!matching)
     759             :         {
     760         199 :             ip6_fib_table_show_all(fib, vm);
     761             :         }
     762             :         else
     763             :         {
     764         135 :             ip6_fib_table_show_one(fib, vm, &matching_address, mask_len, detail);
     765             :         }
     766             :     }
     767             : 
     768         106 :     return 0;
     769             : }
     770             : 
     771             : /*?
     772             :  * This command displays the IPv6 FIB Tables (VRF Tables) and the route
     773             :  * entries for each table.
     774             :  *
     775             :  * @note This command will run for a long time when the FIB tables are
     776             :  * comprised of millions of entries. For those scenarios, consider displaying
     777             :  * in summary mode.
     778             :  *
     779             :  * @cliexpar
     780             :  * @parblock
     781             :  * Example of how to display all the IPv6 FIB tables:
     782             :  * @cliexstart{show ip6 fib}
     783             :  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
     784             :  * @::/0
     785             :  *   unicast-ip6-chain
     786             :  *   [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
     787             :  *     [0] [@0]: dpo-drop ip6
     788             :  * fe80::/10
     789             :  *   unicast-ip6-chain
     790             :  *   [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
     791             :  *     [0] [@2]: dpo-receive
     792             :  * ff02::1/128
     793             :  *   unicast-ip6-chain
     794             :  *   [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
     795             :  *     [0] [@2]: dpo-receive
     796             :  * ff02::2/128
     797             :  *   unicast-ip6-chain
     798             :  *   [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
     799             :  *     [0] [@2]: dpo-receive
     800             :  * ff02::16/128
     801             :  *   unicast-ip6-chain
     802             :  *   [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
     803             :  *     [0] [@2]: dpo-receive
     804             :  * ff02::1:ff00:0/104
     805             :  *   unicast-ip6-chain
     806             :  *   [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
     807             :  *     [0] [@2]: dpo-receive
     808             :  * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto
     809             :  * @::/0
     810             :  *   unicast-ip6-chain
     811             :  *   [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
     812             :  *     [0] [@0]: dpo-drop ip6
     813             :  * @::a:1:1:0:4/126
     814             :  *   unicast-ip6-chain
     815             :  *   [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
     816             :  *     [0] [@4]: ipv6-glean: af_packet0
     817             :  * @::a:1:1:0:7/128
     818             :  *   unicast-ip6-chain
     819             :  *   [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
     820             :  *     [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
     821             :  * fe80::/10
     822             :  *   unicast-ip6-chain
     823             :  *   [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
     824             :  *     [0] [@2]: dpo-receive
     825             :  * fe80::fe:3eff:fe3e:9222/128
     826             :  *   unicast-ip6-chain
     827             :  *   [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
     828             :  *     [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
     829             :  * ff02::1/128
     830             :  *   unicast-ip6-chain
     831             :  *   [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
     832             :  *     [0] [@2]: dpo-receive
     833             :  * ff02::2/128
     834             :  *   unicast-ip6-chain
     835             :  *   [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
     836             :  *     [0] [@2]: dpo-receive
     837             :  * ff02::16/128
     838             :  *   unicast-ip6-chain
     839             :  *   [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
     840             :  *     [0] [@2]: dpo-receive
     841             :  * ff02::1:ff00:0/104
     842             :  *   unicast-ip6-chain
     843             :  *   [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
     844             :  *     [0] [@2]: dpo-receive
     845             :  * @cliexend
     846             :  *
     847             :  * Example of how to display a summary of all IPv6 FIB tables:
     848             :  * @cliexstart{show ip6 fib summary}
     849             :  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
     850             :  *     Prefix length         Count
     851             :  *          128                3
     852             :  *          104                1
     853             :  *          10                 1
     854             :  *           0                 1
     855             :  * ipv6-VRF:8, fib_index 1, flow hash: src dst sport dport proto
     856             :  *     Prefix length         Count
     857             :  *          128                5
     858             :  *          126                1
     859             :  *          104                1
     860             :  *          10                 1
     861             :  *           0                 1
     862             :  * @cliexend
     863             :  * @endparblock
     864             :  ?*/
     865             : /* *INDENT-OFF* */
     866      285289 : VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
     867             :     .path = "show ip6 fib",
     868             :     .short_help = "show ip6 fib [summary] [table <table-id>] [index <fib-id>] [<ip6-addr>[/<width>]] [detail]",
     869             :     .function = ip6_show_fib,
     870             : };
     871             : /* *INDENT-ON* */
     872             : 
     873             : static clib_error_t *
     874         575 : ip6_config (vlib_main_t * vm, unformat_input_t * input)
     875             : {
     876         575 :   uword heapsize = 0;
     877         575 :   u32 nbuckets = 0;
     878             : 
     879         575 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     880             :     {
     881           0 :       if (unformat (input, "hash-buckets %d", &nbuckets))
     882             :           ;
     883           0 :       else if (unformat (input, "heap-size %U",
     884             :                          unformat_memory_size, &heapsize))
     885             :         ;
     886             :       else
     887           0 :         return clib_error_return (0, "unknown input '%U'",
     888             :                                   format_unformat_error, input);
     889             :     }
     890             : 
     891         575 :   ip6_fib_table_nbuckets = nbuckets;
     892         575 :   ip6_fib_table_size = heapsize;
     893             : 
     894         575 :   return 0;
     895             : }
     896             : 
     897        7514 : VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
     898             : 
     899             : static clib_error_t *
     900         575 : ip6_fib_init (vlib_main_t * vm)
     901             : {
     902         575 :     if (ip6_fib_table_nbuckets == 0)
     903         575 :         ip6_fib_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
     904             : 
     905         575 :     ip6_fib_table_nbuckets = 1 << max_log2 (ip6_fib_table_nbuckets);
     906             : 
     907         575 :     if (ip6_fib_table_size == 0)
     908         575 :         ip6_fib_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
     909             : 
     910         575 :     clib_bihash_init_24_8 (&(ip6_fib_table[IP6_FIB_TABLE_FWDING].ip6_hash),
     911             :                            "ip6 FIB fwding table",
     912             :                            ip6_fib_table_nbuckets, ip6_fib_table_size);
     913         575 :     clib_bihash_init_24_8 (&ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
     914             :                            "ip6 FIB non-fwding table",
     915             :                            ip6_fib_table_nbuckets, ip6_fib_table_size);
     916             : 
     917         575 :     return (NULL);
     918             : }
     919             : 
     920       14399 : VLIB_INIT_FUNCTION (ip6_fib_init) =
     921             : {
     922             :   .runs_before = VLIB_INITS("ip6_lookup_init"),
     923             : };

Generated by: LCOV version 1.14