LCOV - code coverage report
Current view: top level - vnet/ip - ip6_ll_table.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 97 132 73.5 %
Date: 2023-10-26 01:39:38 Functions: 17 20 85.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 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 <vlib/vlib.h>
      17             : #include <vnet/dpo/drop_dpo.h>
      18             : #include <vnet/fib/ip6_fib.h>
      19             : 
      20             : #include <vnet/ip/ip6_ll_table.h>
      21             : 
      22             : /**
      23             :  * There's only one IP6 link local table
      24             :  */
      25             : static ip6_ll_table_t ip6_ll_table;
      26             : 
      27             : u32
      28        8295 : ip6_ll_fib_get (u32 sw_if_index)
      29             : {
      30        8295 :   ASSERT (vec_len (ip6_ll_table.ilt_fibs) > sw_if_index);
      31             : 
      32        8295 :   return (ip6_ll_table.ilt_fibs[sw_if_index]);
      33             : }
      34             : 
      35             : fib_node_index_t
      36           6 : ip6_ll_table_lookup (const ip6_ll_prefix_t * prefix)
      37             : {
      38           6 :   return (ip6_fib_table_lookup (ip6_ll_fib_get (prefix->ilp_sw_if_index),
      39             :                                 &prefix->ilp_addr, 128));
      40             : }
      41             : 
      42             : fib_node_index_t
      43        1949 : ip6_ll_table_lookup_exact_match (const ip6_ll_prefix_t * prefix)
      44             : {
      45        1949 :   return (ip6_fib_table_lookup_exact_match
      46             :           (ip6_ll_fib_get (prefix->ilp_sw_if_index), &prefix->ilp_addr, 128));
      47             : }
      48             : 
      49             : static void
      50        2115 : ip6_ll_fib_create (u32 sw_if_index)
      51             : {
      52        2115 :   vnet_main_t *vnm = vnet_get_main ();
      53             :   u8 *desc;
      54             : 
      55        2115 :   desc = format (NULL, "IP6-link-local:%U",
      56             :                  format_vnet_sw_interface_name,
      57             :                  vnm, vnet_get_sw_interface (vnm, sw_if_index));
      58             : 
      59        4230 :   ip6_ll_table.ilt_fibs[sw_if_index] =
      60        2115 :     ip6_fib_table_create_and_lock (FIB_SOURCE_IP6_ND,
      61             :                                    FIB_TABLE_FLAG_IP6_LL, desc);
      62             : 
      63             :   /*
      64             :    * leave the default route as a drop, but fix fe::/10 to be a glean
      65             :    * via the interface.
      66             :    */
      67             :     /* *INDENT-OFF* */
      68        2115 :     fib_prefix_t pfx = {
      69             :         .fp_proto = FIB_PROTOCOL_IP6,
      70             :         .fp_len = 10,
      71             :         .fp_addr = {
      72             :             .ip6 = {
      73             :                 .as_u8 = {
      74             :                     [0] = 0xFE,
      75             :                     [1] = 0x80,
      76             :                 }
      77             :             },
      78             :         }
      79             :     };
      80        2115 :     fib_table_entry_update_one_path(
      81        2115 :         ip6_ll_table.ilt_fibs[sw_if_index],
      82             :         &pfx,
      83             :         FIB_SOURCE_SPECIAL,
      84             :         (FIB_ENTRY_FLAG_ATTACHED |
      85             :          FIB_ENTRY_FLAG_NO_ATTACHED_EXPORT),
      86             :         DPO_PROTO_IP6,
      87             :         NULL,
      88             :         sw_if_index,
      89             :         ~0,
      90             :         1,
      91             :         NULL,
      92             :         FIB_ROUTE_PATH_FLAG_NONE);
      93             :     /* *INDENT-ON* */
      94        2115 : }
      95             : 
      96             : static void
      97        2121 : ip6_ll_prefix_to_fib (const ip6_ll_prefix_t * ilp, fib_prefix_t * fp)
      98             : {
      99        2121 :   fp->fp_proto = FIB_PROTOCOL_IP6;
     100        2121 :   fp->fp_len = 128;
     101        2121 :   fp->fp_addr.ip6 = ilp->ilp_addr;
     102        2121 :   fp->___fp___pad = 0;
     103        2121 : }
     104             : 
     105             : fib_node_index_t
     106        2121 : ip6_ll_table_entry_update (const ip6_ll_prefix_t * ilp,
     107             :                            fib_route_path_flags_t flags)
     108             : {
     109             :   fib_node_index_t ip6_ll_entry_index;
     110        2121 :   fib_route_path_t *rpaths, rpath = {
     111             :     .frp_flags = flags,
     112        2121 :     .frp_sw_if_index = ilp->ilp_sw_if_index,
     113             :     .frp_proto = DPO_PROTO_IP6,
     114             :     .frp_fib_index = ~0,
     115             :     .frp_weight = 1,
     116             :   };
     117        2121 :   fib_prefix_t fp = { 0 };
     118             : 
     119        2121 :   if (flags & FIB_ROUTE_PATH_LOCAL)
     120        2116 :     rpath.frp_addr.ip6 = ilp->ilp_addr;
     121             : 
     122        2121 :   vec_validate_init_empty (ip6_ll_table.ilt_fibs, ilp->ilp_sw_if_index, ~0);
     123             : 
     124        2121 :   if (~0 == ip6_ll_fib_get (ilp->ilp_sw_if_index))
     125             :     {
     126        2115 :       ip6_ll_fib_create (ilp->ilp_sw_if_index);
     127             :     }
     128             : 
     129        2121 :   rpaths = NULL;
     130        2121 :   vec_add1 (rpaths, rpath);
     131             : 
     132        2121 :   ip6_ll_prefix_to_fib (ilp, &fp);
     133             :   ip6_ll_entry_index =
     134        2121 :     fib_table_entry_update (ip6_ll_fib_get (ilp->ilp_sw_if_index), &fp,
     135             :                             FIB_SOURCE_IP6_ND,
     136             :                             (flags & FIB_ROUTE_PATH_LOCAL ?
     137        2121 :                              FIB_ENTRY_FLAG_LOCAL : FIB_ENTRY_FLAG_NONE),
     138             :                             rpaths);
     139        2121 :   vec_free (rpaths);
     140             : 
     141        2121 :   return (ip6_ll_entry_index);
     142             : }
     143             : 
     144             : void
     145        1949 : ip6_ll_table_entry_delete (const ip6_ll_prefix_t * ilp)
     146             : {
     147             :   fib_node_index_t ip6_ll_entry_index;
     148             :   u32 fib_index;
     149             : 
     150        1949 :   ip6_ll_entry_index = ip6_ll_table_lookup_exact_match (ilp);
     151             : 
     152        1949 :   if (FIB_NODE_INDEX_INVALID != ip6_ll_entry_index)
     153        1948 :     fib_table_entry_delete_index (ip6_ll_entry_index, FIB_SOURCE_IP6_ND);
     154             : 
     155             :   /*
     156             :    * if there are no ND sourced prefixes left, then we can clean up this FIB
     157             :    */
     158        1949 :   fib_index = ip6_ll_fib_get (ilp->ilp_sw_if_index);
     159        3897 :   if (~0 != fib_index &&
     160        1948 :       0 == fib_table_get_num_entries (fib_index, FIB_PROTOCOL_IP6,
     161             :                                       FIB_SOURCE_IP6_ND))
     162             :     {
     163        1943 :       fib_table_unlock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_IP6_ND);
     164        1943 :       ip6_ll_table.ilt_fibs[ilp->ilp_sw_if_index] = ~0;
     165             :     }
     166        1949 : }
     167             : 
     168             : static void
     169           6 : ip6_ll_table_show_one (vlib_main_t * vm, ip6_ll_prefix_t * ilp, int detail)
     170             : {
     171           6 :   vlib_cli_output (vm, "%U",
     172             :                    format_fib_entry,
     173             :                    ip6_ll_table_lookup (ilp),
     174             :                    (detail ?
     175             :                     FIB_ENTRY_FORMAT_DETAIL2 : FIB_ENTRY_FORMAT_DETAIL));
     176           6 : }
     177             : 
     178             : typedef struct ip6_ll_show_ctx_t_
     179             : {
     180             :   fib_node_index_t *entries;
     181             : } ip6_ll_show_ctx_t;
     182             : 
     183             : static fib_table_walk_rc_t
     184           0 : ip6_ll_table_show_walk (fib_node_index_t fib_entry_index, void *arg)
     185             : {
     186           0 :   ip6_ll_show_ctx_t *ctx = arg;
     187             : 
     188           0 :   vec_add1 (ctx->entries, fib_entry_index);
     189             : 
     190           0 :   return (FIB_TABLE_WALK_CONTINUE);
     191             : }
     192             : 
     193             : static void
     194           0 : ip6_ll_table_show_all (vlib_main_t * vm, u32 fib_index)
     195             : {
     196             :   fib_node_index_t *fib_entry_index;
     197           0 :   ip6_ll_show_ctx_t ctx = {
     198             :     .entries = NULL,
     199             :   };
     200             : 
     201           0 :   fib_table_walk (fib_index, FIB_PROTOCOL_IP6, ip6_ll_table_show_walk, &ctx);
     202           0 :   vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
     203             : 
     204           0 :   vec_foreach (fib_entry_index, ctx.entries)
     205             :   {
     206           0 :     vlib_cli_output (vm, "%U",
     207             :                      format_fib_entry,
     208             :                      *fib_entry_index, FIB_ENTRY_FORMAT_BRIEF);
     209             :   }
     210             : 
     211           0 :   vec_free (ctx.entries);
     212           0 : }
     213             : 
     214             : typedef struct
     215             : {
     216             :   u32 fib_index;
     217             :   u64 count_by_prefix_length[129];
     218             : } count_routes_in_fib_at_prefix_length_arg_t;
     219             : 
     220             : static int
     221           0 : count_routes_in_fib_at_prefix_length (clib_bihash_kv_24_8_t * kvp, void *arg)
     222             : {
     223           0 :   count_routes_in_fib_at_prefix_length_arg_t *ap = arg;
     224             :   int mask_width;
     225             : 
     226           0 :   if ((kvp->key[2] >> 32) != ap->fib_index)
     227           0 :     return (BIHASH_WALK_CONTINUE);
     228             : 
     229           0 :   mask_width = kvp->key[2] & 0xFF;
     230             : 
     231           0 :   ap->count_by_prefix_length[mask_width]++;
     232             : 
     233           0 :   return (BIHASH_WALK_CONTINUE);
     234             : }
     235             : 
     236             : static clib_error_t *
     237           2 : ip6_ll_show_fib (vlib_main_t * vm,
     238             :                  unformat_input_t * input, vlib_cli_command_t * cmd)
     239             : {
     240           2 :   count_routes_in_fib_at_prefix_length_arg_t _ca, *ca = &_ca;
     241             :   fib_table_t *fib_table;
     242             :   int verbose, matching;
     243             :   ip6_address_t matching_address;
     244           2 :   u32 mask_len = 128;
     245           2 :   u32 sw_if_index = ~0;
     246           2 :   int detail = 0;
     247           2 :   vnet_main_t *vnm = vnet_get_main ();
     248             :   u32 fib_index;
     249             : 
     250           2 :   verbose = 1;
     251           2 :   matching = 0;
     252             : 
     253           6 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     254             :     {
     255           8 :       if (unformat (input, "brief") ||
     256           8 :           unformat (input, "summary") || unformat (input, "sum"))
     257           0 :         verbose = 0;
     258             : 
     259           4 :       else if (unformat (input, "detail") || unformat (input, "det"))
     260           0 :         detail = 1;
     261             : 
     262           4 :       else if (unformat (input, "%U/%d",
     263             :                          unformat_ip6_address, &matching_address, &mask_len))
     264           0 :         matching = 1;
     265             : 
     266             :       else
     267           4 :         if (unformat (input, "%U", unformat_ip6_address, &matching_address))
     268           2 :         matching = 1;
     269           2 :       else if (unformat (input, "%U",
     270             :                          unformat_vnet_sw_interface, vnm, &sw_if_index))
     271             :         ;
     272             :       else
     273           0 :         break;
     274             :     }
     275             : 
     276          10 :   vec_foreach_index (sw_if_index, ip6_ll_table.ilt_fibs)
     277             :   {
     278             :     fib_source_t source;
     279           8 :     u8 *s = NULL;
     280             : 
     281           8 :     fib_index = ip6_ll_table.ilt_fibs[sw_if_index];
     282           8 :     if (~0 == fib_index)
     283           2 :       continue;
     284             : 
     285           6 :     fib_table = fib_table_get (fib_index, FIB_PROTOCOL_IP6);
     286             : 
     287           6 :     if (!(fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL))
     288           0 :       continue;
     289             : 
     290           6 :     s = format (s, "%U, fib_index:%d, locks:[",
     291             :                 format_fib_table_name, fib_index,
     292             :                 FIB_PROTOCOL_IP6, fib_index);
     293          96 :     vec_foreach_index (source, fib_table->ft_locks)
     294             :     {
     295          90 :       if (0 != fib_table->ft_locks[source])
     296             :         {
     297           6 :           s = format (s, "%U:%d, ",
     298           6 :                       format_fib_source, source, fib_table->ft_locks[source]);
     299             :         }
     300             :     }
     301           6 :     s = format (s, "]");
     302           6 :     vlib_cli_output (vm, "%v", s);
     303           6 :     vec_free (s);
     304             : 
     305             :     /* Show summary? */
     306           6 :     if (!verbose)
     307             :       {
     308           0 :         clib_bihash_24_8_t *h =
     309             :           &ip6_fib_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash;
     310             :         int len;
     311             : 
     312           0 :         vlib_cli_output (vm, "%=20s%=16s", "Prefix length", "Count");
     313             : 
     314           0 :         clib_memset (ca, 0, sizeof (*ca));
     315           0 :         ca->fib_index = fib_index;
     316             : 
     317           0 :         clib_bihash_foreach_key_value_pair_24_8
     318             :           (h, count_routes_in_fib_at_prefix_length, ca);
     319             : 
     320           0 :         for (len = 128; len >= 0; len--)
     321             :           {
     322           0 :             if (ca->count_by_prefix_length[len])
     323           0 :               vlib_cli_output (vm, "%=20d%=16lld",
     324             :                                len, ca->count_by_prefix_length[len]);
     325             :           }
     326           0 :         continue;
     327             :       }
     328             : 
     329           6 :     if (!matching)
     330             :       {
     331           0 :         ip6_ll_table_show_all (vm, fib_index);
     332             :       }
     333             :     else
     334             :       {
     335           6 :         if (~0 == sw_if_index)
     336             :           {
     337           0 :             vlib_cli_output (vm, "specify the interface");
     338             :           }
     339             :         else
     340             :           {
     341           6 :             ip6_ll_prefix_t ilp = {
     342             :               .ilp_addr = matching_address,
     343             :               .ilp_sw_if_index = sw_if_index,
     344             :             };
     345           6 :             ip6_ll_table_show_one (vm, &ilp, detail);
     346             :           }
     347             :       }
     348             :   };
     349             : 
     350           2 :   return 0;
     351             : }
     352             : 
     353             : /* *INDENT-OFF* */
     354      285289 : VLIB_CLI_COMMAND (ip6_show_fib_command, static) = {
     355             :     .path = "show ip6-ll",
     356             :     .short_help = "show ip6-ll [summary] [interface] [<ip6-addr>[/<width>]] [detail]",
     357             :     .function = ip6_ll_show_fib,
     358             : };
     359             : /* *INDENT-ON* */
     360             : 
     361             : static clib_error_t *
     362       11798 : ip6_ll_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
     363             : {
     364       15752 :   vec_validate_init_empty (ip6_ll_table.ilt_fibs, sw_if_index, ~0);
     365             : 
     366       11798 :   return (NULL);
     367             : }
     368             : 
     369        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (ip6_ll_sw_interface_add_del);
     370             : 
     371             : static clib_error_t *
     372         575 : ip6_ll_module_init (vlib_main_t * vm)
     373             : {
     374             :   clib_error_t *error;
     375             : 
     376         575 :   error = vlib_call_init_function (vm, ip6_lookup_init);
     377             : 
     378         575 :   return (error);
     379             : }
     380             : 
     381       40895 : VLIB_INIT_FUNCTION (ip6_ll_module_init);
     382             : 
     383             : /*
     384             :  * fd.io coding-style-patch-verification: ON
     385             :  *
     386             :  * Local Variables:
     387             :  * eval: (c-set-style "gnu")
     388             :  * End:
     389             :  */

Generated by: LCOV version 1.14