LCOV - code coverage report
Current view: top level - vnet/fib - mpls_fib.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 133 147 90.5 %
Date: 2023-10-26 01:39:38 Functions: 16 18 88.9 %

          Line data    Source code
       1             : /*
       2             :  * mpls_fib.h: The Label/MPLS FIB
       3             :  *
       4             :  * Copyright (c) 2012 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : /**
      18             :  * An MPLS_FIB table;
      19             :  *
      20             :  * The entries in the table are programmed wtih one or more MOIs. These MOIs
      21             :  * may result in different forwarding actions for end-of-stack (EOS) and non-EOS
      22             :  * packets. Whether the two actions are the same more often than they are
      23             :  * different, or vice versa, is a function of the deployment in which the router
      24             :  * is used and thus not predictable.
      25             :  * The design choice to make with an MPLS_FIB table is:
      26             :  *  1 - 20 bit key: label only.
      27             :  *      When the EOS and non-EOS actions differ the result is a 'EOS-choice' object.
      28             :  *  2 - 21 bit key: label and EOS-bit.
      29             :  *      The result is then the specific action based on EOS-bit.
      30             :  *
      31             :  * 20 bit key:
      32             :  *   Advantages:
      33             :  *    - lower memory overhead, since there are few DB entries.
      34             :  *   Disadvantages:
      35             :  *    - slower DP performance in the case the chains differ, as more objects are
      36             :  *      encountered in the switch path
      37             :  *
      38             :  * 21 bit key:
      39             :  *   Advantages:
      40             :  *    - faster DP performance
      41             :  *   Disadvantages
      42             :  *    - increased memory footprint.
      43             :  *
      44             :  * Switching between schemes based on observed/measured action similarity is not
      45             :  * considered on the grounds of complexity and flip-flopping.
      46             :  *
      47             :  * VPP mantra - favour performance over memory. We choose a 21 bit key.
      48             :  */
      49             : 
      50             : #include <vnet/fib/fib_table.h>
      51             : #include <vnet/fib/mpls_fib.h>
      52             : #include <vnet/dpo/load_balance.h>
      53             : #include <vnet/dpo/drop_dpo.h>
      54             : #include <vnet/dpo/punt_dpo.h>
      55             : #include <vnet/dpo/lookup_dpo.h>
      56             : #include <vnet/mpls/mpls.h>
      57             : 
      58             : /**
      59             :  * All lookups in an MPLS_FIB table must result in a DPO of type load-balance.
      60             :  * This is the default result which links to drop
      61             :  */
      62             : static index_t mpls_fib_drop_dpo_index = INDEX_INVALID;
      63             : 
      64             : static inline u32
      65        3587 : mpls_fib_entry_mk_key (mpls_label_t label,
      66             :                        mpls_eos_bit_t eos)
      67             : {
      68        3587 :     ASSERT(eos <= 1);
      69        3587 :     return (label << 1 | eos);
      70             : }
      71             : 
      72             : u32
      73        1212 : mpls_fib_index_from_table_id (u32 table_id)
      74             : {
      75        1212 :     mpls_main_t *mm = &mpls_main;
      76             :     uword * p;
      77             : 
      78        1212 :     p = hash_get (mm->fib_index_by_table_id, table_id);
      79        1212 :     if (!p)
      80          50 :         return FIB_NODE_INDEX_INVALID;
      81             : 
      82        1162 :     return p[0];
      83             : }
      84             : 
      85             : static u32
      86          49 : mpls_fib_create_with_table_id (u32 table_id,
      87             :                                fib_source_t src)
      88             : {
      89          49 :     dpo_id_t dpo = DPO_INVALID;
      90             :     fib_table_t *fib_table;
      91             :     mpls_eos_bit_t eos;
      92             :     mpls_fib_t *mf;
      93             :     int i;
      94             : 
      95          49 :     pool_get(mpls_main.fibs, fib_table);
      96          49 :     pool_get_aligned(mpls_main.mpls_fibs, mf, CLIB_CACHE_LINE_BYTES);
      97             : 
      98          49 :     ASSERT((fib_table - mpls_main.fibs) ==
      99             :            (mf - mpls_main.mpls_fibs));
     100             : 
     101          49 :     clib_memset(fib_table, 0, sizeof(*fib_table));
     102             : 
     103          49 :     fib_table->ft_proto = FIB_PROTOCOL_MPLS;
     104          49 :     fib_table->ft_index = (fib_table - mpls_main.fibs);
     105             : 
     106          49 :     hash_set (mpls_main.fib_index_by_table_id, table_id, fib_table->ft_index);
     107             : 
     108          49 :     fib_table->ft_table_id = table_id;
     109          49 :     fib_table->ft_flow_hash_config = MPLS_FLOW_HASH_DEFAULT;
     110             :     
     111          49 :     fib_table_lock(fib_table->ft_index, FIB_PROTOCOL_MPLS, src);
     112             : 
     113          49 :     if (INDEX_INVALID == mpls_fib_drop_dpo_index)
     114             :     {
     115          17 :         mpls_fib_drop_dpo_index = load_balance_create(1, DPO_PROTO_MPLS, 0);
     116          17 :         load_balance_set_bucket(mpls_fib_drop_dpo_index,
     117             :                                 0,
     118             :                                 drop_dpo_get(DPO_PROTO_MPLS));
     119             :     }
     120             : 
     121          49 :     mf->mf_entries = hash_create(0, sizeof(fib_node_index_t));
     122   102760000 :     for (i = 0; i < MPLS_FIB_DB_SIZE; i++)
     123             :     {
     124             :         /*
     125             :          * initialise each DPO in the data-path lookup table
     126             :          * to be the special MPLS drop
     127             :          */
     128   102760000 :         mf->mf_lbs[i] = mpls_fib_drop_dpo_index;
     129             :     }
     130             : 
     131             :     /*
     132             :      * non-default forwarding for the special labels.
     133             :      */
     134          49 :     fib_prefix_t prefix = {
     135             :         .fp_proto = FIB_PROTOCOL_MPLS,
     136             :         .fp_payload_proto = DPO_PROTO_MPLS,
     137             :     };
     138             : 
     139             :     /*
     140             :      * PUNT the router alert, both EOS and non-eos
     141             :      */
     142          49 :     prefix.fp_label = MPLS_IETF_ROUTER_ALERT_LABEL;
     143         147 :     FOR_EACH_MPLS_EOS_BIT(eos)
     144             :     {
     145          98 :         prefix.fp_eos = eos;
     146          98 :         fib_table_entry_special_dpo_add(fib_table->ft_index,
     147             :                                         &prefix,
     148             :                                         FIB_SOURCE_SPECIAL,
     149             :                                         FIB_ENTRY_FLAG_EXCLUSIVE,
     150             :                                         punt_dpo_get(DPO_PROTO_MPLS));
     151             :     }
     152             : 
     153             :     /*
     154             :      * IPv4 explicit NULL EOS lookup in the interface's IPv4 table
     155             :      */
     156          49 :     prefix.fp_label = MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL;
     157          49 :     prefix.fp_payload_proto = DPO_PROTO_IP4;
     158          49 :     prefix.fp_eos = MPLS_EOS;
     159             : 
     160          49 :     lookup_dpo_add_or_lock_w_fib_index(0, // unused
     161             :                                        DPO_PROTO_IP4,
     162             :                                        LOOKUP_UNICAST,
     163             :                                        LOOKUP_INPUT_DST_ADDR,
     164             :                                        LOOKUP_TABLE_FROM_INPUT_INTERFACE,
     165             :                                        &dpo);
     166          49 :     fib_table_entry_special_dpo_add(fib_table->ft_index,
     167             :                                     &prefix,
     168             :                                     FIB_SOURCE_SPECIAL,
     169             :                                     FIB_ENTRY_FLAG_EXCLUSIVE,
     170             :                                     &dpo);
     171             : 
     172          49 :     prefix.fp_payload_proto = DPO_PROTO_MPLS;
     173          49 :     prefix.fp_eos = MPLS_NON_EOS;
     174             : 
     175          49 :     lookup_dpo_add_or_lock_w_fib_index(0, //unsued
     176             :                                        DPO_PROTO_MPLS,
     177             :                                        LOOKUP_UNICAST,
     178             :                                        LOOKUP_INPUT_DST_ADDR,
     179             :                                        LOOKUP_TABLE_FROM_INPUT_INTERFACE,
     180             :                                        &dpo);
     181          49 :     fib_table_entry_special_dpo_add(fib_table->ft_index,
     182             :                                     &prefix,
     183             :                                     FIB_SOURCE_SPECIAL,
     184             :                                     FIB_ENTRY_FLAG_EXCLUSIVE,
     185             :                                     &dpo);
     186             : 
     187             :     /*
     188             :      * IPv6 explicit NULL EOS lookup in the interface's IPv6 table
     189             :      */
     190          49 :     prefix.fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL;
     191          49 :     prefix.fp_payload_proto = DPO_PROTO_IP6;
     192          49 :     prefix.fp_eos = MPLS_EOS;
     193             : 
     194          49 :     lookup_dpo_add_or_lock_w_fib_index(0, //unused
     195             :                                        DPO_PROTO_IP6,
     196             :                                        LOOKUP_UNICAST,
     197             :                                        LOOKUP_INPUT_DST_ADDR,
     198             :                                        LOOKUP_TABLE_FROM_INPUT_INTERFACE,
     199             :                                        &dpo);
     200          49 :     fib_table_entry_special_dpo_add(fib_table->ft_index,
     201             :                                     &prefix,
     202             :                                     FIB_SOURCE_SPECIAL,
     203             :                                     FIB_ENTRY_FLAG_EXCLUSIVE,
     204             :                                     &dpo);
     205             : 
     206          49 :     prefix.fp_payload_proto = DPO_PROTO_MPLS;
     207          49 :     prefix.fp_eos = MPLS_NON_EOS;
     208          49 :     lookup_dpo_add_or_lock_w_fib_index(0, // unsued
     209             :                                        DPO_PROTO_MPLS,
     210             :                                        LOOKUP_UNICAST,
     211             :                                        LOOKUP_INPUT_DST_ADDR,
     212             :                                        LOOKUP_TABLE_FROM_INPUT_INTERFACE,
     213             :                                        &dpo);
     214          49 :     fib_table_entry_special_dpo_add(fib_table->ft_index,
     215             :                                     &prefix,
     216             :                                     FIB_SOURCE_SPECIAL,
     217             :                                     FIB_ENTRY_FLAG_EXCLUSIVE,
     218             :                                     &dpo);
     219             : 
     220          49 :     return (fib_table->ft_index);
     221             : }
     222             : 
     223             : u32
     224         198 : mpls_fib_table_find_or_create_and_lock (u32 table_id,
     225             :                                         fib_source_t src)
     226             : {
     227             :     u32 index;
     228             : 
     229         198 :     index = mpls_fib_index_from_table_id(table_id);
     230         198 :     if (~0 == index)
     231          49 :         return mpls_fib_create_with_table_id(table_id, src);
     232             : 
     233         149 :     fib_table_lock(index, FIB_PROTOCOL_MPLS, src);
     234             : 
     235         149 :     return (index);
     236             : }
     237             : u32
     238           0 : mpls_fib_table_create_and_lock (fib_source_t src)
     239             : {
     240           0 :     return (mpls_fib_create_with_table_id(~0, src));
     241             : }
     242             : 
     243             : void
     244          49 : mpls_fib_table_destroy (u32 fib_index)
     245             : {
     246          49 :     fib_table_t *fib_table = pool_elt_at_index(mpls_main.fibs, fib_index);
     247          49 :     mpls_fib_t *mf = pool_elt_at_index(mpls_main.mpls_fibs, fib_index);
     248          49 :     fib_prefix_t prefix = {
     249             :         .fp_proto = FIB_PROTOCOL_MPLS,
     250             :     };
     251          49 :     mpls_label_t special_labels[] = {
     252             :         MPLS_IETF_ROUTER_ALERT_LABEL,
     253             :         MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
     254             :         MPLS_IETF_IPV4_EXPLICIT_NULL_LABEL,
     255             :     };
     256             :     mpls_eos_bit_t eos;
     257             :     u32 ii;
     258             : 
     259         196 :     for (ii = 0; ii < ARRAY_LEN(special_labels); ii++)
     260             :     {
     261         441 :         FOR_EACH_MPLS_EOS_BIT(eos)
     262             :         {
     263         294 :             prefix.fp_label = special_labels[ii];
     264         294 :             prefix.fp_eos   = eos;
     265             : 
     266         294 :             fib_table_entry_delete(fib_table->ft_index,
     267             :                                    &prefix,
     268             :                                    FIB_SOURCE_SPECIAL);
     269             :         }
     270             :     }
     271          49 :     if (~0 != fib_table->ft_table_id)
     272             :     {
     273          49 :         hash_unset(mpls_main.fib_index_by_table_id,
     274             :                    fib_table->ft_table_id);
     275             :     }
     276          49 :     hash_free(mf->mf_entries);
     277             : 
     278          49 :     vec_free (fib_table->ft_locks);
     279          49 :     vec_free(fib_table->ft_src_route_counts);
     280          49 :     pool_put(mpls_main.mpls_fibs, mf);
     281          49 :     pool_put(mpls_main.fibs, fib_table);
     282          49 : }
     283             : 
     284             : fib_node_index_t
     285        1058 : mpls_fib_table_lookup (const mpls_fib_t *mf,
     286             :                        mpls_label_t label,
     287             :                        mpls_eos_bit_t eos)
     288             : {
     289             :     uword *p;
     290             : 
     291        1058 :     p = hash_get(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
     292             : 
     293        1058 :     if (NULL == p)
     294         640 :         return FIB_NODE_INDEX_INVALID;
     295             : 
     296         418 :     return p[0];
     297             : }
     298             : 
     299             : void
     300         631 : mpls_fib_table_entry_insert (mpls_fib_t *mf,
     301             :                              mpls_label_t label,
     302             :                              mpls_eos_bit_t eos,
     303             :                              fib_node_index_t lfei)
     304             : {
     305         631 :     hash_set(mf->mf_entries, mpls_fib_entry_mk_key(label, eos), lfei);
     306         631 : }
     307             : 
     308             : void
     309         631 : mpls_fib_table_entry_remove (mpls_fib_t *mf,
     310             :                              mpls_label_t label,
     311             :                              mpls_eos_bit_t eos)
     312             : {
     313         631 :     hash_unset(mf->mf_entries, mpls_fib_entry_mk_key(label, eos));
     314         631 : }
     315             : 
     316             : void
     317         636 : mpls_fib_forwarding_table_update (mpls_fib_t *mf,
     318             :                                   mpls_label_t label,
     319             :                                   mpls_eos_bit_t eos,
     320             :                                   const dpo_id_t *dpo)
     321             : {
     322             :     mpls_label_t key;
     323             : 
     324         636 :     ASSERT((DPO_LOAD_BALANCE == dpo->dpoi_type) ||
     325             :            (DPO_REPLICATE == dpo->dpoi_type));
     326             :     if (CLIB_DEBUG > 0)
     327             :     {
     328         636 :         if (DPO_REPLICATE == dpo->dpoi_type)
     329           7 :             ASSERT(dpo->dpoi_index & MPLS_IS_REPLICATE);
     330         636 :         if (DPO_LOAD_BALANCE == dpo->dpoi_type)
     331         629 :             ASSERT(!(dpo->dpoi_index & MPLS_IS_REPLICATE));
     332             :     }
     333         636 :     key = mpls_fib_entry_mk_key(label, eos);
     334             : 
     335         636 :     mf->mf_lbs[key] = dpo->dpoi_index;
     336         636 : }
     337             : 
     338             : void
     339         631 : mpls_fib_forwarding_table_reset (mpls_fib_t *mf,
     340             :                                  mpls_label_t label,
     341             :                                  mpls_eos_bit_t eos)
     342             : {
     343             :     mpls_label_t key;
     344             : 
     345         631 :     key = mpls_fib_entry_mk_key(label, eos);
     346             : 
     347         631 :     mf->mf_lbs[key] = mpls_fib_drop_dpo_index;
     348         631 : }
     349             : 
     350             : void
     351         335 : mpls_fib_table_walk (mpls_fib_t *mpls_fib,
     352             :                      fib_table_walk_fn_t fn,
     353             :                      void *ctx)
     354             : {
     355             :     fib_node_index_t lfei;
     356             :     mpls_label_t key;
     357             : 
     358       78696 :     hash_foreach(key, lfei, mpls_fib->mf_entries,
     359             :     ({
     360             :         fn(lfei, ctx);
     361             :     }));
     362         335 : }
     363             : 
     364             : u8 *
     365           1 : format_mpls_fib_table_memory (u8 * s, va_list * args)
     366             : {
     367             :     u64 n_tables, mem;
     368             : 
     369           1 :     n_tables = pool_elts(mpls_main.fibs);
     370           1 :     mem = n_tables * sizeof(mpls_fib_t);
     371           1 :     s = format(s, "%=30s %=6ld %=12ld\n", "MPLS", n_tables, mem);
     372             : 
     373           1 :     return (s);
     374             : }
     375             : 
     376             : static void
     377           0 : mpls_fib_table_show_all (const mpls_fib_t *mpls_fib,
     378             :                          vlib_main_t * vm)
     379             : {
     380           0 :     fib_node_index_t lfei, *lfeip, *lfeis = NULL;
     381             :     mpls_label_t key;
     382             : 
     383           0 :     hash_foreach(key, lfei, mpls_fib->mf_entries,
     384             :     ({
     385             :         vec_add1(lfeis, lfei);
     386             :     }));
     387             : 
     388           0 :     vec_sort_with_function(lfeis, fib_entry_cmp_for_sort);
     389             : 
     390           0 :     vec_foreach(lfeip, lfeis)
     391             :     {
     392           0 :         vlib_cli_output (vm, "%U",
     393             :                          format_fib_entry, *lfeip,
     394             :                          FIB_ENTRY_FORMAT_DETAIL);
     395             :     }
     396           0 :     vec_free(lfeis);
     397           0 : }
     398             : 
     399             : static void
     400           2 : mpls_fib_table_show_one (const mpls_fib_t *mpls_fib,
     401             :                          mpls_label_t label,
     402             :                          vlib_main_t * vm)
     403             : {    
     404             :     fib_node_index_t lfei;
     405             :     mpls_eos_bit_t eos;
     406             : 
     407           6 :     FOR_EACH_MPLS_EOS_BIT(eos)
     408             :     {    
     409           4 :         lfei = mpls_fib_table_lookup(mpls_fib, label, eos);
     410             : 
     411           4 :         if (FIB_NODE_INDEX_INVALID != lfei)
     412             :         {
     413           2 :             vlib_cli_output (vm, "%U", 
     414             :                              format_fib_entry, lfei, FIB_ENTRY_FORMAT_DETAIL);
     415             :         }
     416             :     }
     417           2 : }
     418             : 
     419             : static clib_error_t *
     420           2 : mpls_fib_show (vlib_main_t * vm,
     421             :                unformat_input_t * input,
     422             :                vlib_cli_command_t * cmd)
     423             : {
     424             :     fib_table_t * fib_table;
     425             :     mpls_label_t label;
     426             :     int table_id;
     427             : 
     428           2 :     table_id = -1;
     429           2 :     label = MPLS_LABEL_INVALID;
     430             : 
     431           4 :     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     432             :     {
     433             :         /* if (unformat (input, "brief") || unformat (input, "summary") */
     434             :         /*     || unformat (input, "sum")) */
     435             :         /*     verbose = 0; */
     436             : 
     437           2 :         if (unformat (input, "%d", &label))
     438           2 :             continue;
     439           0 :         else if (unformat (input, "table %d", &table_id))
     440             :             ;
     441             :         else
     442           0 :             break;
     443             :     }
     444             : 
     445           4 :     pool_foreach (fib_table, mpls_main.fibs)
     446             :      {
     447             :         fib_source_t source;
     448           2 :         u8 *s = NULL;
     449             : 
     450           2 :         if (table_id >= 0 && table_id != fib_table->ft_table_id)
     451           0 :             continue;
     452             : 
     453           2 :         s = format (s, "%v, fib_index:%d locks:[",
     454           2 :                     fib_table->ft_desc, fib_table - mpls_main.fibs);
     455          30 :         vec_foreach_index(source, fib_table->ft_locks)
     456             :         {
     457          28 :             if (0 != fib_table->ft_locks[source])
     458             :             {
     459           5 :                 s = format(s, "%U:%d, ",
     460             :                            format_fib_source, source,
     461           5 :                            fib_table->ft_locks[source]);
     462             :             }
     463             :         }
     464           2 :         vlib_cli_output (vm, "%v]", s);
     465             : 
     466           2 :         if (MPLS_LABEL_INVALID == label)
     467             :         {
     468           0 :             mpls_fib_table_show_all(mpls_fib_get(fib_table->ft_index), vm);
     469             :         }
     470             :         else
     471             :         {
     472           2 :             mpls_fib_table_show_one(mpls_fib_get(fib_table->ft_index), label, vm);
     473             :         }
     474             :     }
     475             : 
     476           2 :     return 0;
     477             : }
     478             : 
     479      285289 : VLIB_CLI_COMMAND (mpls_fib_show_command, static) = {
     480             :     .path = "show mpls fib",
     481             :     .short_help = "show mpls fib [summary] [table <n>]",
     482             :     .function = mpls_fib_show,
     483             : };

Generated by: LCOV version 1.14