LCOV - code coverage report
Current view: top level - vnet/fib - fib_table.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 510 543 93.9 %
Date: 2023-07-05 22:20:52 Functions: 65 65 100.0 %

          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 <vlib/vlib.h>
      17             : #include <vnet/dpo/drop_dpo.h>
      18             : 
      19             : #include <vnet/fib/fib_table.h>
      20             : #include <vnet/fib/fib_entry_cover.h>
      21             : #include <vnet/fib/fib_internal.h>
      22             : #include <vnet/fib/ip4_fib.h>
      23             : #include <vnet/fib/ip6_fib.h>
      24             : #include <vnet/fib/mpls_fib.h>
      25             : 
      26             : const static char * fib_table_flags_strings[] = FIB_TABLE_ATTRIBUTES;
      27             : 
      28             : fib_table_t *
      29      638197 : fib_table_get (fib_node_index_t index,
      30             :                fib_protocol_t proto)
      31             : {
      32      638197 :     switch (proto)
      33             :     {
      34      477669 :     case FIB_PROTOCOL_IP4:
      35      477669 :         return (pool_elt_at_index(ip4_main.fibs, index));
      36      137567 :     case FIB_PROTOCOL_IP6:
      37      137567 :         return (pool_elt_at_index(ip6_main.fibs, index));
      38       22961 :     case FIB_PROTOCOL_MPLS:
      39       22961 :         return (pool_elt_at_index(mpls_main.fibs, index));
      40             :     }
      41           0 :     ASSERT(0);
      42           0 :     return (NULL);
      43             : }
      44             : 
      45             : static inline fib_node_index_t
      46      142810 : fib_table_lookup_i (fib_table_t *fib_table,
      47             :                     const fib_prefix_t *prefix)
      48             : {
      49      142810 :     switch (prefix->fp_proto)
      50             :     {
      51      113921 :     case FIB_PROTOCOL_IP4:
      52      113922 :         return (ip4_fib_table_lookup(ip4_fib_get(fib_table->ft_index),
      53             :                                      &prefix->fp_addr.ip4,
      54      113921 :                                      prefix->fp_len));
      55       28857 :     case FIB_PROTOCOL_IP6:
      56       28857 :         return (ip6_fib_table_lookup(fib_table->ft_index,
      57             :                                      &prefix->fp_addr.ip6,
      58       28857 :                                      prefix->fp_len));
      59          32 :     case FIB_PROTOCOL_MPLS:
      60          32 :         return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
      61             :                                       prefix->fp_label,
      62             :                                       prefix->fp_eos));
      63             :     }
      64           0 :     return (FIB_NODE_INDEX_INVALID);
      65             : }
      66             : 
      67             : fib_node_index_t
      68       67340 : fib_table_lookup (u32 fib_index,
      69             :                   const fib_prefix_t *prefix)
      70             : {
      71       67340 :     return (fib_table_lookup_i(fib_table_get(fib_index, prefix->fp_proto), prefix));
      72             : }
      73             : 
      74             : static inline fib_node_index_t
      75      245460 : fib_table_lookup_exact_match_i (const fib_table_t *fib_table,
      76             :                                 const fib_prefix_t *prefix)
      77             : {
      78      245460 :     switch (prefix->fp_proto)
      79             :     {
      80      190295 :     case FIB_PROTOCOL_IP4:
      81      190295 :         return (ip4_fib_table_lookup_exact_match(ip4_fib_get(fib_table->ft_index),
      82             :                                                  &prefix->fp_addr.ip4,
      83      190295 :                                                  prefix->fp_len));
      84       54143 :     case FIB_PROTOCOL_IP6:
      85       54143 :         return (ip6_fib_table_lookup_exact_match(fib_table->ft_index,
      86             :                                                  &prefix->fp_addr.ip6,
      87       54143 :                                                  prefix->fp_len));
      88        1022 :     case FIB_PROTOCOL_MPLS:
      89        1022 :         return (mpls_fib_table_lookup(mpls_fib_get(fib_table->ft_index),
      90             :                                       prefix->fp_label,
      91             :                                       prefix->fp_eos));
      92             :     }
      93           0 :     return (FIB_NODE_INDEX_INVALID);
      94             : }
      95             : 
      96             : fib_node_index_t
      97      178385 : fib_table_lookup_exact_match (u32 fib_index,
      98             :                               const fib_prefix_t *prefix)
      99             : {
     100      178385 :     return (fib_table_lookup_exact_match_i(fib_table_get(fib_index,
     101      178385 :                                                          prefix->fp_proto),
     102             :                                            prefix));
     103             : }
     104             : 
     105             : static fib_node_index_t
     106       75470 : fib_table_get_less_specific_i (fib_table_t *fib_table,
     107             :                                const fib_prefix_t *prefix)
     108             : {
     109             :     fib_prefix_t pfx;
     110             : 
     111       75470 :     pfx = *prefix;
     112             : 
     113       75470 :     if (FIB_PROTOCOL_MPLS == pfx.fp_proto)
     114             :     {
     115           0 :         return (FIB_NODE_INDEX_INVALID);
     116             :     }
     117             : 
     118             :     /*
     119             :      * in the absence of a tree structure for the table that allows for an O(1)
     120             :      * parent get, a cheeky way to find the cover is to LPM for the prefix with
     121             :      * mask-1.
     122             :      * there should always be a cover, though it may be the default route. the
     123             :      * default route's cover is the default route.
     124             :      */
     125       75470 :     if (pfx.fp_len != 0) {
     126       71647 :         pfx.fp_len -= 1;
     127             :     }
     128             : 
     129       75470 :     return (fib_table_lookup_i(fib_table, &pfx));    
     130             : }
     131             : 
     132             : fib_node_index_t
     133       36179 : fib_table_get_less_specific (u32 fib_index,
     134             :                              const fib_prefix_t *prefix)
     135             : {
     136       36179 :     return (fib_table_get_less_specific_i(fib_table_get(fib_index,
     137       36179 :                                                         prefix->fp_proto),
     138             :                                           prefix));
     139             : }
     140             : 
     141             : static void
     142       29967 : fib_table_entry_remove (fib_table_t *fib_table,
     143             :                         const fib_prefix_t *prefix,
     144             :                         fib_node_index_t fib_entry_index)
     145             : {
     146       29967 :     vlib_smp_unsafe_warning();
     147             : 
     148       29967 :     fib_table->ft_total_route_counts--;
     149             : 
     150       29967 :     switch (prefix->fp_proto)
     151             :     {
     152       15812 :     case FIB_PROTOCOL_IP4:
     153       15812 :         ip4_fib_table_entry_remove(ip4_fib_get(fib_table->ft_index),
     154             :                                    &prefix->fp_addr.ip4,
     155       15812 :                                    prefix->fp_len);
     156       15812 :         break;
     157       13524 :     case FIB_PROTOCOL_IP6:
     158       13524 :         ip6_fib_table_entry_remove(fib_table->ft_index,
     159             :                                    &prefix->fp_addr.ip6,
     160       13524 :                                    prefix->fp_len);
     161       13524 :         break;
     162         631 :     case FIB_PROTOCOL_MPLS:
     163         631 :         mpls_fib_table_entry_remove(mpls_fib_get(fib_table->ft_index),
     164             :                                     prefix->fp_label,
     165             :                                     prefix->fp_eos);
     166         631 :         break;
     167             :     }
     168             : 
     169       29967 :     fib_entry_unlock(fib_entry_index);
     170       29967 : }
     171             : 
     172             : static void
     173       39922 : fib_table_post_insert_actions (fib_table_t *fib_table,
     174             :                                const fib_prefix_t *prefix,
     175             :                                fib_node_index_t fib_entry_index)
     176             : {
     177             :     fib_node_index_t fib_entry_cover_index;
     178             : 
     179             :     /*
     180             :      * no cover relationships in the MPLS FIB
     181             :      */
     182       39922 :     if (FIB_PROTOCOL_MPLS == prefix->fp_proto)
     183         631 :         return;
     184             : 
     185             :     /*
     186             :      * find  the covering entry
     187             :      */
     188       39291 :     fib_entry_cover_index = fib_table_get_less_specific_i(fib_table, prefix);
     189             :     /*
     190             :      * the indicies are the same when the default route is first added
     191             :      */
     192       39291 :     if (fib_entry_cover_index != fib_entry_index)
     193             :     {
     194             :         /*
     195             :          * push any inherting sources from the cover onto the covered
     196             :          */
     197       35720 :         fib_entry_inherit(fib_entry_cover_index,
     198             :                           fib_entry_index);
     199             : 
     200             :         /*
     201             :          * inform the covering entry that a new more specific
     202             :          * has been inserted beneath it.
     203             :          * If the prefix that has been inserted is a host route
     204             :          * then it is not possible that it will be the cover for any
     205             :          * other entry, so we can elide the walk. This is particularly
     206             :          * beneficial since there are often many host entries sharing the
     207             :          * same cover (i.e. ADJ or RR sourced entries).
     208             :          */
     209       35720 :         if (!fib_entry_is_host(fib_entry_index))
     210             :         {
     211        9154 :             fib_entry_cover_change_notify(fib_entry_cover_index,
     212             :                                           fib_entry_index);
     213             :         }
     214             :     }
     215             : }
     216             : 
     217             : static void
     218       39922 : fib_table_entry_insert (fib_table_t *fib_table,
     219             :                         const fib_prefix_t *prefix,
     220             :                         fib_node_index_t fib_entry_index)
     221             : {
     222       39922 :     vlib_smp_unsafe_warning();
     223             : 
     224       39922 :     fib_entry_lock(fib_entry_index);
     225       39922 :     fib_table->ft_total_route_counts++;
     226             : 
     227       39922 :     switch (prefix->fp_proto)
     228             :     {
     229       21954 :     case FIB_PROTOCOL_IP4:
     230       21954 :         ip4_fib_table_entry_insert(ip4_fib_get(fib_table->ft_index),
     231             :                                    &prefix->fp_addr.ip4,
     232       21954 :                                    prefix->fp_len,
     233             :                                    fib_entry_index);
     234       21954 :         break;
     235       17337 :     case FIB_PROTOCOL_IP6:
     236       17337 :         ip6_fib_table_entry_insert(fib_table->ft_index,
     237             :                                    &prefix->fp_addr.ip6,
     238       17337 :                                    prefix->fp_len,
     239             :                                    fib_entry_index);
     240       17337 :         break;
     241         631 :     case FIB_PROTOCOL_MPLS:
     242         631 :         mpls_fib_table_entry_insert(mpls_fib_get(fib_table->ft_index),
     243             :                                     prefix->fp_label,
     244             :                                     prefix->fp_eos,
     245             :                                     fib_entry_index);
     246         631 :         break;
     247             :     }
     248             : 
     249       39922 :     fib_table_post_insert_actions(fib_table, prefix, fib_entry_index);
     250       39922 : }
     251             : 
     252             : void
     253       39656 : fib_table_fwding_dpo_update (u32 fib_index,
     254             :                              const fib_prefix_t *prefix,
     255             :                              const dpo_id_t *dpo)
     256             : {
     257       39656 :     vlib_smp_unsafe_warning();
     258             : 
     259       39656 :     switch (prefix->fp_proto)
     260             :     {
     261       21662 :     case FIB_PROTOCOL_IP4:
     262       21662 :         return (ip4_fib_table_fwding_dpo_update(ip4_fib_get(fib_index),
     263             :                                                 &prefix->fp_addr.ip4,
     264       21662 :                                                 prefix->fp_len,
     265             :                                                 dpo));
     266       17358 :     case FIB_PROTOCOL_IP6:
     267       17358 :         return (ip6_fib_table_fwding_dpo_update(fib_index,
     268             :                                                 &prefix->fp_addr.ip6,
     269       17358 :                                                 prefix->fp_len,
     270             :                                                 dpo));
     271         636 :     case FIB_PROTOCOL_MPLS:
     272         636 :         return (mpls_fib_forwarding_table_update(mpls_fib_get(fib_index),
     273             :                                                  prefix->fp_label,
     274             :                                                  prefix->fp_eos,
     275             :                                                  dpo));
     276             :     }
     277             : }
     278             : 
     279             : void
     280       29677 : fib_table_fwding_dpo_remove (u32 fib_index,
     281             :                              const fib_prefix_t *prefix,
     282             :                              const dpo_id_t *dpo)
     283             : {
     284       29677 :     vlib_smp_unsafe_warning();
     285             : 
     286       29677 :     switch (prefix->fp_proto)
     287             :     {
     288       15505 :     case FIB_PROTOCOL_IP4:
     289       31010 :         return (ip4_fib_table_fwding_dpo_remove(ip4_fib_get(fib_index),
     290             :                                                 &prefix->fp_addr.ip4,
     291       15505 :                                                 prefix->fp_len,
     292             :                                                 dpo,
     293             :                                                 fib_table_get_less_specific(fib_index,
     294             :                                                                             prefix)));
     295       13541 :     case FIB_PROTOCOL_IP6:
     296       13541 :         return (ip6_fib_table_fwding_dpo_remove(fib_index,
     297             :                                                 &prefix->fp_addr.ip6,
     298       13541 :                                                 prefix->fp_len,
     299             :                                                 dpo));
     300         631 :     case FIB_PROTOCOL_MPLS:
     301         631 :         return (mpls_fib_forwarding_table_reset(mpls_fib_get(fib_index),
     302             :                                                 prefix->fp_label,
     303             :                                                 prefix->fp_eos));
     304             :     }
     305             : }
     306             : 
     307             : static void
     308       44163 : fib_table_source_count_inc (fib_table_t *fib_table,
     309             :                             fib_source_t source)
     310             : {
     311       44163 :     vec_validate (fib_table->ft_src_route_counts, source);
     312       44163 :     fib_table->ft_src_route_counts[source]++;
     313       44163 : }
     314             : 
     315             : static void
     316       34158 : fib_table_source_count_dec (fib_table_t *fib_table,
     317             :                             fib_source_t source)
     318             : {
     319       34158 :     vec_validate (fib_table->ft_src_route_counts, source);
     320       34158 :     fib_table->ft_src_route_counts[source]--;
     321       34158 : }
     322             : 
     323             : fib_node_index_t
     324       21159 : fib_table_entry_special_dpo_add (u32 fib_index,
     325             :                                  const fib_prefix_t *prefix,
     326             :                                  fib_source_t source,
     327             :                                  fib_entry_flag_t flags,
     328             :                                  const dpo_id_t *dpo)
     329             : {
     330             :     fib_node_index_t fib_entry_index;
     331             :     fib_table_t *fib_table;
     332             : 
     333       21159 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     334       21159 :     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
     335             : 
     336       21159 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     337             :     {
     338       15408 :         fib_entry_index = fib_entry_create_special(fib_index, prefix,
     339             :                                                    source, flags,
     340             :                                                    dpo);
     341             : 
     342       15408 :         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
     343       15408 :         fib_table_source_count_inc(fib_table, source);
     344             :     }
     345             :     else
     346             :     {
     347             :         int was_sourced;
     348             : 
     349        5751 :         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     350        5751 :         fib_entry_special_add(fib_entry_index, source, flags, dpo);
     351             : 
     352        5751 :         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     353             :         {
     354        3982 :         fib_table_source_count_inc(fib_table, source);
     355             :         }
     356             :     }
     357             : 
     358             : 
     359       21159 :     return (fib_entry_index);
     360             : }
     361             : 
     362             : fib_node_index_t
     363          17 : fib_table_entry_special_dpo_update (u32 fib_index,
     364             :                                     const fib_prefix_t *prefix,
     365             :                                     fib_source_t source,
     366             :                                     fib_entry_flag_t flags,
     367             :                                     const dpo_id_t *dpo)
     368             : {
     369             :     fib_node_index_t fib_entry_index;
     370             :     fib_table_t *fib_table;
     371             : 
     372          17 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     373          17 :     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
     374             : 
     375          17 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     376             :     {
     377          12 :         fib_entry_index = fib_entry_create_special(fib_index, prefix,
     378             :                                                    source, flags,
     379             :                                                    dpo);
     380             : 
     381          12 :         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
     382          12 :         fib_table_source_count_inc(fib_table, source);
     383             :     }
     384             :     else
     385             :     {
     386             :         int was_sourced;
     387             : 
     388           5 :         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     389             : 
     390           5 :         if (was_sourced)
     391           1 :             fib_entry_special_update(fib_entry_index, source, flags, dpo);
     392             :         else
     393           4 :             fib_entry_special_add(fib_entry_index, source, flags, dpo);
     394             : 
     395           5 :         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     396             :         {
     397           4 :             fib_table_source_count_inc(fib_table, source);
     398             :         }
     399             :     }
     400             : 
     401          17 :     return (fib_entry_index);
     402             : }
     403             : 
     404             : fib_node_index_t
     405       17554 : fib_table_entry_special_add (u32 fib_index,
     406             :                              const fib_prefix_t *prefix,
     407             :                              fib_source_t source,
     408             :                              fib_entry_flag_t flags)
     409             : {
     410             :     fib_node_index_t fib_entry_index;
     411       17554 :     dpo_id_t tmp_dpo = DPO_INVALID;
     412             : 
     413       17554 :     dpo_copy(&tmp_dpo, drop_dpo_get(fib_proto_to_dpo(prefix->fp_proto)));
     414             :  
     415       17554 :     fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix, source,
     416             :                                                       flags, &tmp_dpo);
     417             : 
     418       17554 :     dpo_unlock(&tmp_dpo);
     419             : 
     420       17554 :     return (fib_entry_index);
     421             : }
     422             : 
     423             : void
     424       12285 : fib_table_entry_special_remove (u32 fib_index,
     425             :                                 const fib_prefix_t *prefix,
     426             :                                 fib_source_t source)
     427             : {
     428             :     /*
     429             :      * 1 is it present
     430             :      *   yes => remove source
     431             :      *    2 - is it still sourced?
     432             :      *      no => cover walk
     433             :      */
     434             :     fib_node_index_t fib_entry_index;
     435             :     fib_table_t *fib_table;
     436             : 
     437       12285 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     438       12285 :     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
     439             : 
     440       12285 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     441             :     {
     442             :         /*
     443             :          * removing an etry that does not exist. i'll allow it.
     444             :          */
     445             :     }
     446             :     else
     447             :     {
     448             :         fib_entry_src_flag_t src_flag;
     449             :         int was_sourced;
     450             : 
     451             :         /*
     452             :          * don't nobody go nowhere
     453             :          */
     454        9849 :         fib_entry_lock(fib_entry_index);
     455        9849 :         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     456             : 
     457        9849 :         src_flag = fib_entry_special_remove(fib_entry_index, source);
     458             : 
     459        9849 :         if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
     460             :         {
     461             :             /*
     462             :              * last source gone. remove from the table
     463             :              */
     464        7875 :             fib_table_entry_remove(fib_table, prefix, fib_entry_index);
     465             : 
     466             :             /*
     467             :              * now the entry is no longer in the table, we can
     468             :              * inform the entries that it covers to re-calculate their cover
     469             :              */
     470        7875 :             fib_entry_cover_change_notify(fib_entry_index,
     471             :                                           FIB_NODE_INDEX_INVALID);
     472             :         }
     473             :         /*
     474             :          * else
     475             :          *   still has sources, leave it be.
     476             :          */
     477        9849 :         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     478             :         {
     479        8161 :             fib_table_source_count_dec(fib_table, source);
     480             :         }
     481             : 
     482        9849 :         fib_entry_unlock(fib_entry_index);
     483             :     }
     484       12285 : }
     485             : 
     486             : /**
     487             :  * fib_table_route_path_fixup
     488             :  *
     489             :  * Convert attached hosts to attached next-hops.
     490             :  * 
     491             :  * This special case is required because an attached path will link to a
     492             :  * glean, and the FIB entry will have the interface or API/CLI source. When
     493             :  * the ARP/ND process is completes then that source (which will provide a
     494             :  * complete adjacency) will be lower priority and so the FIB entry will
     495             :  * remain linked to a glean and traffic will never reach the hosts. For
     496             :  * an ATTAHCED_HOST path we can link the path directly to the [incomplete]
     497             :  * adjacency.
     498             :  */
     499             : static void
     500       47826 : fib_table_route_path_fixup (const fib_prefix_t *prefix,
     501             :                             fib_entry_flag_t *eflags,
     502             :                             fib_route_path_t *path)
     503             : {
     504             :     /*
     505             :      * not all zeros next hop &&
     506             :      * is recursive path &&
     507             :      * nexthop is same as the route's address
     508             :      */
     509       47826 :     if ((!ip46_address_is_zero(&path->frp_addr)) &&
     510       44216 :         (~0 == path->frp_sw_if_index) &&
     511        3680 :         (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
     512             :     {
     513             :         /* Prefix recurses via itself */
     514           2 :         path->frp_flags |= FIB_ROUTE_PATH_DROP;
     515             :     }
     516       93600 :     if (!(path->frp_flags & FIB_ROUTE_PATH_LOCAL) &&
     517       84698 :         fib_prefix_is_host(prefix) &&
     518       38924 :         ip46_address_is_zero(&path->frp_addr) &&
     519         656 :         path->frp_sw_if_index != ~0 &&
     520         591 :         path->frp_proto != DPO_PROTO_ETHERNET)
     521             :     {
     522         588 :         path->frp_addr = prefix->fp_addr;
     523         588 :         path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
     524             :     }
     525       47238 :     else if ((*eflags & FIB_ENTRY_FLAG_CONNECTED) &&
     526        9112 :              !(*eflags & FIB_ENTRY_FLAG_LOCAL))
     527             :     {
     528        4518 :         if (ip46_address_is_zero(&path->frp_addr))
     529             :         {
     530        4518 :             path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
     531        4518 :             fib_prefix_normalize(prefix, &path->frp_connected);
     532             :         }
     533             :     }
     534       42720 :     else if (fib_route_path_is_attached(path))
     535             :     {
     536       14439 :         path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
     537       14439 :         fib_prefix_normalize(prefix, &path->frp_connected);
     538             :     }
     539       47826 :     if (*eflags & FIB_ENTRY_FLAG_DROP)
     540             :     {
     541           0 :         path->frp_flags |= FIB_ROUTE_PATH_DROP;
     542             :     }
     543       47826 :     if (*eflags & FIB_ENTRY_FLAG_LOCAL)
     544             :     {
     545        7126 :         path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
     546             :     }
     547       47826 :     if (*eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
     548             :     {
     549         476 :         path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
     550             :     }
     551       47826 :     if (path->frp_flags & FIB_ROUTE_PATH_LOCAL)
     552             :     {
     553        7129 :         *eflags |= FIB_ENTRY_FLAG_LOCAL;
     554             : 
     555        7129 :         if (path->frp_sw_if_index != ~0)
     556             :         {
     557        7127 :             *eflags |= FIB_ENTRY_FLAG_CONNECTED;
     558             :         }
     559             :     }
     560       47826 : }
     561             : 
     562             : fib_node_index_t
     563        9839 : fib_table_entry_path_add (u32 fib_index,
     564             :                           const fib_prefix_t *prefix,
     565             :                           fib_source_t source,
     566             :                           fib_entry_flag_t flags,
     567             :                           dpo_proto_t next_hop_proto,
     568             :                           const ip46_address_t *next_hop,
     569             :                           u32 next_hop_sw_if_index,
     570             :                           u32 next_hop_fib_index,
     571             :                           u32 next_hop_weight,
     572             :                           fib_mpls_label_t *next_hop_labels,
     573             :                           fib_route_path_flags_t path_flags)
     574             : {
     575        9839 :     fib_route_path_t path = {
     576             :         .frp_proto = next_hop_proto,
     577             :         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
     578             :         .frp_sw_if_index = next_hop_sw_if_index,
     579             :         .frp_fib_index = next_hop_fib_index,
     580             :         .frp_weight = next_hop_weight,
     581             :         .frp_flags = path_flags,
     582             :         .frp_rpf_id = INDEX_INVALID,
     583             :         .frp_label_stack = next_hop_labels,
     584             :     };
     585             :     fib_node_index_t fib_entry_index;
     586        9839 :     fib_route_path_t *paths = NULL;
     587             : 
     588        9839 :     vec_add1(paths, path);
     589             : 
     590        9839 :     fib_entry_index = fib_table_entry_path_add2(fib_index, prefix,
     591             :                                                 source, flags, paths);
     592             : 
     593        9839 :     vec_free(paths);
     594        9839 :     return (fib_entry_index);
     595             : }
     596             : 
     597             : static int
     598       80115 : fib_route_path_cmp_for_sort (void * v1,
     599             :                              void * v2)
     600             : {
     601       80115 :     return (fib_route_path_cmp(v1, v2));
     602             : }
     603             : 
     604             : fib_node_index_t
     605        9924 : fib_table_entry_path_add2 (u32 fib_index,
     606             :                            const fib_prefix_t *prefix,
     607             :                            fib_source_t source,
     608             :                            fib_entry_flag_t flags,
     609             :                            fib_route_path_t *rpaths)
     610             : {
     611             :     fib_node_index_t fib_entry_index;
     612             :     fib_table_t *fib_table;
     613             :     u32 ii;
     614             : 
     615        9924 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     616        9924 :     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
     617             : 
     618       19991 :     for (ii = 0; ii < vec_len(rpaths); ii++)
     619             :     {
     620       10067 :         fib_table_route_path_fixup(prefix, &flags, &rpaths[ii]);
     621             :     }
     622             :     /*
     623             :      * sort the paths provided by the control plane. this means
     624             :      * the paths and the extension on the entry will be sorted.
     625             :      */
     626        9924 :     vec_sort_with_function(rpaths, fib_route_path_cmp_for_sort);
     627             : 
     628        9924 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     629             :     {
     630        9572 :         fib_entry_index = fib_entry_create(fib_index, prefix,
     631             :                                            source, flags,
     632             :                                            rpaths);
     633             : 
     634        9572 :         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
     635        9572 :         fib_table_source_count_inc(fib_table, source);
     636             :     }
     637             :     else
     638             :     {
     639             :         int was_sourced;
     640             : 
     641         352 :         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     642         352 :         fib_entry_path_add(fib_entry_index, source, flags, rpaths);;
     643             : 
     644         352 :         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     645             :         {
     646          67 :             fib_table_source_count_inc(fib_table, source);
     647             :         }
     648             :     }
     649             : 
     650        9924 :     return (fib_entry_index);
     651             : }
     652             : 
     653             : void
     654        5455 : fib_table_entry_path_remove2 (u32 fib_index,
     655             :                               const fib_prefix_t *prefix,
     656             :                               fib_source_t source,
     657             :                               fib_route_path_t *rpaths)
     658             : {
     659             :     /*
     660             :      * 1 is it present
     661             :      *   yes => remove source
     662             :      *    2 - is it still sourced?
     663             :      *      no => cover walk
     664             :      */
     665             :     fib_node_index_t fib_entry_index;
     666             :     fib_route_path_t *rpath;
     667             :     fib_table_t *fib_table;
     668             : 
     669        5455 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     670        5455 :     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
     671             : 
     672        5455 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     673             :     {
     674             :         /*
     675             :          * removing an etry that does not exist. i'll allow it.
     676             :          */
     677             :     }
     678             :     else
     679             :     {
     680             :         fib_entry_src_flag_t src_flag;
     681             :         int was_sourced;
     682             : 
     683             :         /*
     684             :          * if it's not sourced, then there's nowt to remove
     685             :          */
     686        5454 :         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     687        5454 :         if (!was_sourced)
     688             :         {
     689           0 :             return;
     690             :         }
     691             : 
     692             :         /*
     693             :          * don't nobody go nowhere
     694             :          */
     695        5454 :         fib_entry_lock(fib_entry_index);
     696             : 
     697       10908 :         vec_foreach(rpath, rpaths)
     698             :         {
     699             :             fib_entry_flag_t eflags;
     700             : 
     701        5454 :             eflags = fib_entry_get_flags_for_source(fib_entry_index,
     702             :                                                     source);
     703        5454 :             fib_table_route_path_fixup(prefix, &eflags, rpath);
     704             :         }
     705             : 
     706        5454 :         src_flag = fib_entry_path_remove(fib_entry_index, source, rpaths);
     707             : 
     708        5454 :         if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
     709             :         {
     710             :             /*
     711             :              * last source gone. remove from the table
     712             :              */
     713        5331 :             fib_table_entry_remove(fib_table, prefix, fib_entry_index);
     714             : 
     715             :             /*
     716             :              * now the entry is no longer in the table, we can
     717             :              * inform the entries that it covers to re-calculate their cover
     718             :              */
     719        5331 :             fib_entry_cover_change_notify(fib_entry_index,
     720             :                                           FIB_NODE_INDEX_INVALID);
     721             :         }
     722             :         /*
     723             :          * else
     724             :          *   still has sources, leave it be.
     725             :          */
     726        5454 :         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     727             :         {
     728        5438 :             fib_table_source_count_dec(fib_table, source);
     729             :         }
     730             : 
     731        5454 :         fib_entry_unlock(fib_entry_index);
     732             :     }
     733             : }
     734             : 
     735             : void
     736        5444 : fib_table_entry_path_remove (u32 fib_index,
     737             :                              const fib_prefix_t *prefix,
     738             :                              fib_source_t source,
     739             :                              dpo_proto_t next_hop_proto,
     740             :                              const ip46_address_t *next_hop,
     741             :                              u32 next_hop_sw_if_index,
     742             :                              u32 next_hop_fib_index,
     743             :                              u32 next_hop_weight,
     744             :                              fib_route_path_flags_t path_flags)
     745             : {
     746             :     /*
     747             :      * 1 is it present
     748             :      *   yes => remove source
     749             :      *    2 - is it still sourced?
     750             :      *      no => cover walk
     751             :      */
     752        5444 :     fib_route_path_t path = {
     753             :         .frp_proto = next_hop_proto,
     754             :         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
     755             :         .frp_sw_if_index = next_hop_sw_if_index,
     756             :         .frp_fib_index = next_hop_fib_index,
     757             :         .frp_weight = next_hop_weight,
     758             :         .frp_flags = path_flags,
     759             :     };
     760        5444 :     fib_route_path_t *paths = NULL;
     761             : 
     762        5444 :     vec_add1(paths, path);
     763             : 
     764        5444 :     fib_table_entry_path_remove2(fib_index, prefix, source, paths);
     765             : 
     766        5444 :     vec_free(paths);
     767        5444 : }
     768             : 
     769             : fib_node_index_t
     770       18235 : fib_table_entry_update (u32 fib_index,
     771             :                         const fib_prefix_t *prefix,
     772             :                         fib_source_t source,
     773             :                         fib_entry_flag_t flags,
     774             :                         fib_route_path_t *paths)
     775             : {
     776             :     fib_node_index_t fib_entry_index;
     777             :     fib_table_t *fib_table;
     778             :     u32 ii;
     779             : 
     780       18235 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     781       18235 :     fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
     782             : 
     783       50540 :     for (ii = 0; ii < vec_len(paths); ii++)
     784             :     {
     785       32305 :         fib_table_route_path_fixup(prefix, &flags, &paths[ii]);
     786             :     }
     787             :     /*
     788             :      * sort the paths provided by the control plane. this means
     789             :      * the paths and the extension on the entry will be sorted.
     790             :      */
     791       18235 :     vec_sort_with_function(paths, fib_route_path_cmp_for_sort);
     792             : 
     793       18235 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     794             :     {
     795       14930 :         fib_entry_index = fib_entry_create(fib_index, prefix,
     796             :                                            source, flags,
     797             :                                            paths);
     798             : 
     799       14930 :         fib_table_entry_insert(fib_table, prefix, fib_entry_index);
     800       14930 :         fib_table_source_count_inc(fib_table, source);
     801             :     }
     802             :     else
     803             :     {
     804             :         int was_sourced;
     805             : 
     806        3305 :         was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     807        3305 :         fib_entry_update(fib_entry_index, source, flags, paths);
     808             : 
     809        3305 :         if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     810             :         {
     811         188 :             fib_table_source_count_inc(fib_table, source);
     812             :         }
     813             :     }
     814             : 
     815       18235 :     return (fib_entry_index);
     816             : }
     817             : 
     818             : fib_node_index_t
     819       11753 : fib_table_entry_update_one_path (u32 fib_index,
     820             :                                  const fib_prefix_t *prefix,
     821             :                                  fib_source_t source,
     822             :                                  fib_entry_flag_t flags,
     823             :                                  dpo_proto_t next_hop_proto,
     824             :                                  const ip46_address_t *next_hop,
     825             :                                  u32 next_hop_sw_if_index,
     826             :                                  u32 next_hop_fib_index,
     827             :                                  u32 next_hop_weight,
     828             :                                  fib_mpls_label_t *next_hop_labels,
     829             :                                  fib_route_path_flags_t path_flags)
     830             : {
     831             :     fib_node_index_t fib_entry_index;
     832       11753 :     fib_route_path_t path = {
     833             :         .frp_proto = next_hop_proto,
     834             :         .frp_addr = (NULL == next_hop? zero_addr : *next_hop),
     835             :         .frp_sw_if_index = next_hop_sw_if_index,
     836             :         .frp_fib_index = next_hop_fib_index,
     837             :         .frp_weight = next_hop_weight,
     838             :         .frp_flags = path_flags,
     839             :         .frp_label_stack = next_hop_labels,
     840             :     };
     841       11753 :     fib_route_path_t *paths = NULL;
     842             : 
     843       11753 :     vec_add1(paths, path);
     844             : 
     845             :     fib_entry_index = 
     846       11753 :         fib_table_entry_update(fib_index, prefix, source, flags, paths);
     847             : 
     848       11753 :     vec_free(paths);
     849             : 
     850       11753 :     return (fib_entry_index);
     851             : }
     852             : 
     853             : static void
     854       20601 : fib_table_entry_delete_i (u32 fib_index,
     855             :                           fib_node_index_t fib_entry_index,
     856             :                           const fib_prefix_t *prefix,
     857             :                           fib_source_t source)
     858             : {
     859             :     fib_entry_src_flag_t src_flag;
     860             :     fib_table_t *fib_table;
     861             :     int was_sourced;
     862             : 
     863       20601 :     fib_table = fib_table_get(fib_index, prefix->fp_proto);
     864       20601 :     was_sourced = fib_entry_is_sourced(fib_entry_index, source);
     865             : 
     866             :     /*
     867             :      * don't nobody go nowhere
     868             :      */
     869       20601 :     fib_entry_lock(fib_entry_index);
     870             : 
     871       20601 :     src_flag = fib_entry_delete(fib_entry_index, source);
     872             : 
     873       20601 :     if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
     874             :     {
     875             :         /*
     876             :          * last source gone. remove from the table
     877             :          */
     878       16761 :         fib_table_entry_remove(fib_table, prefix, fib_entry_index);
     879             : 
     880             :         /*
     881             :          * now the entry is no longer in the table, we can
     882             :          * inform the entries that it covers to re-calculate their cover
     883             :          */
     884       16761 :         fib_entry_cover_change_notify(fib_entry_index,
     885             :                                       FIB_NODE_INDEX_INVALID);
     886             :     }
     887             :     /*
     888             :      * else
     889             :      *   still has sources, leave it be.
     890             :      */
     891       20601 :     if (was_sourced != fib_entry_is_sourced(fib_entry_index, source))
     892             :     {
     893       20559 :         fib_table_source_count_dec(fib_table, source);
     894             :     }
     895             : 
     896       20601 :     fib_entry_unlock(fib_entry_index);
     897       20601 : }
     898             : 
     899             : void
     900       14457 : fib_table_entry_delete (u32 fib_index,
     901             :                         const fib_prefix_t *prefix,
     902             :                         fib_source_t source)
     903             : {
     904             :     fib_node_index_t fib_entry_index;
     905             : 
     906       14457 :     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
     907             : 
     908       14457 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     909             :     {
     910             :         /*
     911             :          * removing an etry that does not exist.
     912             :          * i'll allow it, but i won't like it.
     913             :          */
     914             :         if (0)
     915             :             clib_warning("%U not in FIB", format_fib_prefix, prefix);
     916             :     }
     917             :     else
     918             :     {
     919       14359 :         fib_table_entry_delete_i(fib_index, fib_entry_index, prefix, source);
     920             :     }
     921       14457 : }
     922             : 
     923             : void
     924        6242 : fib_table_entry_delete_index (fib_node_index_t fib_entry_index,
     925             :                               fib_source_t source)
     926             : {
     927             :     const fib_prefix_t *prefix;
     928             : 
     929        6242 :     prefix = fib_entry_get_prefix(fib_entry_index);
     930             : 
     931        6242 :     fib_table_entry_delete_i(fib_entry_get_fib_index(fib_entry_index),
     932             :                              fib_entry_index, prefix, source);
     933        6242 : }
     934             : 
     935             : u32
     936      158907 : fib_table_entry_get_stats_index (u32 fib_index,
     937             :                                  const fib_prefix_t *prefix)
     938             : {
     939      158907 :     return (fib_entry_get_stats_index(
     940             :                 fib_table_lookup_exact_match(fib_index, prefix)));
     941             : }
     942             : 
     943             : fib_node_index_t
     944         141 : fib_table_entry_local_label_add (u32 fib_index,
     945             :                                  const fib_prefix_t *prefix,
     946             :                                  mpls_label_t label)
     947             : {
     948             :     fib_node_index_t fib_entry_index;
     949             :  
     950         141 :     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
     951             : 
     952         282 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index ||
     953         141 :         !fib_entry_is_sourced(fib_entry_index, FIB_SOURCE_MPLS))
     954             :     {
     955             :         /*
     956             :          * only source the prefix once. this allows the label change
     957             :          * operation to work
     958             :          */
     959         140 :         fib_entry_index = fib_table_entry_special_dpo_add(fib_index, prefix,
     960             :                                                           FIB_SOURCE_MPLS,
     961             :                                                           FIB_ENTRY_FLAG_NONE,
     962             :                                                           NULL);
     963             :     }
     964             : 
     965         141 :     fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &label);
     966             : 
     967         141 :     return (fib_entry_index);
     968             : }
     969             : 
     970             : void
     971         140 : fib_table_entry_local_label_remove (u32 fib_index,
     972             :                                     const fib_prefix_t *prefix,
     973             :                                     mpls_label_t label)
     974             : {
     975             :     fib_node_index_t fib_entry_index;
     976             :     const void *data;
     977             :     mpls_label_t pl;
     978             : 
     979         140 :     fib_entry_index = fib_table_lookup_exact_match(fib_index, prefix);
     980             : 
     981         140 :     if (FIB_NODE_INDEX_INVALID == fib_entry_index)
     982           0 :         return;
     983             : 
     984         140 :     data = fib_entry_get_source_data(fib_entry_index, FIB_SOURCE_MPLS);
     985             : 
     986         140 :     if (NULL == data)
     987           0 :         return;
     988             : 
     989         140 :     pl = *(mpls_label_t*)data;
     990             : 
     991         140 :     if (pl != label)
     992           0 :         return;
     993             : 
     994         140 :     pl = MPLS_LABEL_INVALID;
     995             : 
     996         140 :     fib_entry_set_source_data(fib_entry_index, FIB_SOURCE_MPLS, &pl);
     997         140 :     fib_table_entry_special_remove(fib_index,
     998             :                                    prefix,
     999             :                                    FIB_SOURCE_MPLS);
    1000             : }
    1001             : 
    1002             : u32
    1003      106077 : fib_table_get_index_for_sw_if_index (fib_protocol_t proto,
    1004             :                                      u32 sw_if_index)
    1005             : {
    1006      106077 :     switch (proto)
    1007             :     {
    1008       92492 :     case FIB_PROTOCOL_IP4:
    1009       92492 :         return (ip4_fib_table_get_index_for_sw_if_index(sw_if_index));
    1010       13585 :     case FIB_PROTOCOL_IP6:
    1011       13585 :         return (ip6_fib_table_get_index_for_sw_if_index(sw_if_index));
    1012           0 :     case FIB_PROTOCOL_MPLS:
    1013           0 :         return (mpls_fib_table_get_index_for_sw_if_index(sw_if_index));
    1014             :     }
    1015           0 :     return (~0);
    1016             : }
    1017             : 
    1018             : flow_hash_config_t
    1019       39325 : fib_table_get_flow_hash_config (u32 fib_index,
    1020             :                                 fib_protocol_t proto)
    1021             : {
    1022             :     fib_table_t *fib;
    1023             : 
    1024       39325 :     fib = fib_table_get(fib_index, proto);
    1025             : 
    1026       39325 :     return (fib->ft_flow_hash_config);
    1027             : }
    1028             : 
    1029             : flow_hash_config_t
    1030         375 : fib_table_get_default_flow_hash_config (fib_protocol_t proto)
    1031             : {
    1032         375 :     switch (proto)
    1033             :     {
    1034          12 :     case FIB_PROTOCOL_IP4:
    1035             :     case FIB_PROTOCOL_IP6:
    1036          12 :         return (IP_FLOW_HASH_DEFAULT);
    1037             : 
    1038         363 :     case FIB_PROTOCOL_MPLS:
    1039         363 :         return (MPLS_FLOW_HASH_DEFAULT);
    1040             :     }
    1041             : 
    1042           0 :     ASSERT(0);
    1043           0 :     return (IP_FLOW_HASH_DEFAULT);
    1044             : }
    1045             : 
    1046             : /**
    1047             :  * @brief Table set flow hash config context.
    1048             :  */
    1049             : typedef struct fib_table_set_flow_hash_config_ctx_t_
    1050             : {
    1051             :     /**
    1052             :      * the flow hash config to set
    1053             :      */
    1054             :     flow_hash_config_t hash_config;
    1055             : } fib_table_set_flow_hash_config_ctx_t;
    1056             : 
    1057             : static fib_table_walk_rc_t
    1058         138 : fib_table_set_flow_hash_config_cb (fib_node_index_t fib_entry_index,
    1059             :                                    void *arg)
    1060             : {
    1061         138 :     fib_table_set_flow_hash_config_ctx_t *ctx = arg;
    1062             : 
    1063         138 :     fib_entry_set_flow_hash_config(fib_entry_index, ctx->hash_config);
    1064             : 
    1065         138 :     return (FIB_TABLE_WALK_CONTINUE);
    1066             : }
    1067             : 
    1068             : void
    1069           6 : fib_table_set_flow_hash_config (u32 fib_index,
    1070             :                                 fib_protocol_t proto,
    1071             :                                 flow_hash_config_t hash_config)
    1072             : {
    1073           6 :     fib_table_set_flow_hash_config_ctx_t ctx = {
    1074             :         .hash_config = hash_config,
    1075             :     };
    1076             :     fib_table_t *fib;
    1077             : 
    1078           6 :     fib = fib_table_get(fib_index, proto);
    1079           6 :     fib->ft_flow_hash_config = hash_config;
    1080             : 
    1081           6 :     fib_table_walk(fib_index, proto,
    1082             :                    fib_table_set_flow_hash_config_cb,
    1083             :                    &ctx);
    1084           6 : }
    1085             : 
    1086             : u32
    1087       10156 : fib_table_get_table_id_for_sw_if_index (fib_protocol_t proto,
    1088             :                                         u32 sw_if_index)
    1089             : {
    1090             :     fib_table_t *fib_table;
    1091             : 
    1092       10156 :     fib_table = fib_table_get(fib_table_get_index_for_sw_if_index(
    1093             :                                   proto, sw_if_index),
    1094             :                               proto);
    1095             : 
    1096       10156 :     return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
    1097             : }
    1098             : 
    1099             : u32
    1100      195681 : fib_table_get_table_id (u32 fib_index,
    1101             :                         fib_protocol_t proto)
    1102             : {
    1103             :     fib_table_t *fib_table;
    1104             : 
    1105      195681 :     fib_table = fib_table_get(fib_index, proto);
    1106             : 
    1107      195681 :     return ((NULL != fib_table ? fib_table->ft_table_id : ~0));
    1108             : }
    1109             : 
    1110             : u32
    1111       32046 : fib_table_find (fib_protocol_t proto,
    1112             :                 u32 table_id)
    1113             : {
    1114       32046 :     switch (proto)
    1115             :     {
    1116       20701 :     case FIB_PROTOCOL_IP4:
    1117       20701 :         return (ip4_fib_index_from_table_id(table_id));
    1118       10333 :     case FIB_PROTOCOL_IP6:
    1119       10333 :         return (ip6_fib_index_from_table_id(table_id));
    1120        1012 :     case FIB_PROTOCOL_MPLS:
    1121        1012 :         return (mpls_fib_index_from_table_id(table_id));
    1122             :     }
    1123           0 :     return (~0);
    1124             : }
    1125             : 
    1126             : static u32
    1127        2589 : fib_table_find_or_create_and_lock_i (fib_protocol_t proto,
    1128             :                                      u32 table_id,
    1129             :                                      fib_source_t src,
    1130             :                                      const u8 *name)
    1131             : {
    1132             :     fib_table_t *fib_table;
    1133             :     fib_node_index_t fi;
    1134             : 
    1135        2589 :     switch (proto)
    1136             :     {
    1137        1632 :     case FIB_PROTOCOL_IP4:
    1138        1632 :         fi = ip4_fib_table_find_or_create_and_lock(table_id, src);
    1139        1632 :         break;
    1140         759 :     case FIB_PROTOCOL_IP6:
    1141         759 :         fi = ip6_fib_table_find_or_create_and_lock(table_id, src);
    1142         759 :         break;
    1143         198 :     case FIB_PROTOCOL_MPLS:
    1144         198 :         fi = mpls_fib_table_find_or_create_and_lock(table_id, src);
    1145         198 :         break;
    1146           0 :     default:
    1147           0 :         return (~0);        
    1148             :     }
    1149             : 
    1150        2589 :     fib_table = fib_table_get(fi, proto);
    1151             : 
    1152        2589 :     if (NULL == fib_table->ft_desc)
    1153             :     {
    1154        1566 :         if (name && name[0])
    1155             :         {
    1156           0 :             fib_table->ft_desc = format(NULL, "%s", name);
    1157             :         }
    1158             :         else
    1159             :         {
    1160        1566 :             fib_table->ft_desc = format(NULL, "%U-VRF:%d",
    1161             :                                         format_fib_protocol, proto,
    1162             :                                         table_id);
    1163             :         }
    1164             :     }
    1165             : 
    1166        2589 :     return (fi);
    1167             : }
    1168             : 
    1169             : u32
    1170        2104 : fib_table_find_or_create_and_lock (fib_protocol_t proto,
    1171             :                                    u32 table_id,
    1172             :                                    fib_source_t src)
    1173             : {
    1174        2104 :     return (fib_table_find_or_create_and_lock_i(proto, table_id,
    1175             :                                                 src, NULL));
    1176             : }
    1177             : 
    1178             : u32
    1179         485 : fib_table_find_or_create_and_lock_w_name (fib_protocol_t proto,
    1180             :                                           u32 table_id,
    1181             :                                           fib_source_t src,
    1182             :                                           const u8 *name)
    1183             : {
    1184         485 :     return (fib_table_find_or_create_and_lock_i(proto, table_id,
    1185             :                                                 src, name));
    1186             : }
    1187             : 
    1188             : u32
    1189           6 : fib_table_create_and_lock (fib_protocol_t proto,
    1190             :                            fib_source_t src,
    1191             :                            const char *const fmt,
    1192             :                            ...)
    1193             : {
    1194             :     fib_table_t *fib_table;
    1195             :     fib_node_index_t fi;
    1196             :     va_list ap;
    1197             : 
    1198             : 
    1199           6 :     switch (proto)
    1200             :     {
    1201           0 :     case FIB_PROTOCOL_IP4:
    1202           0 :         fi = ip4_fib_table_create_and_lock(src);
    1203           0 :         break;
    1204           6 :     case FIB_PROTOCOL_IP6:
    1205           6 :         fi = ip6_fib_table_create_and_lock(src, FIB_TABLE_FLAG_NONE, NULL);
    1206           6 :         break;
    1207           0 :      case FIB_PROTOCOL_MPLS:
    1208           0 :         fi = mpls_fib_table_create_and_lock(src);
    1209           0 :         break;
    1210           0 :    default:
    1211           0 :         return (~0);        
    1212             :     }
    1213             : 
    1214           6 :     fib_table = fib_table_get(fi, proto);
    1215             : 
    1216           6 :     va_start(ap, fmt);
    1217             : 
    1218           6 :     fib_table->ft_desc = va_format(fib_table->ft_desc, fmt, &ap);
    1219             : 
    1220           6 :     va_end(ap);
    1221           6 :     return (fi);
    1222             : }
    1223             : 
    1224             : static void
    1225        2298 : fib_table_destroy (fib_table_t *fib_table)
    1226             : {
    1227        2298 :     vec_free(fib_table->ft_desc);
    1228             : 
    1229        2298 :     switch (fib_table->ft_proto)
    1230             :     {
    1231         252 :     case FIB_PROTOCOL_IP4:
    1232         252 :         ip4_fib_table_destroy(fib_table->ft_index);
    1233         252 :         break;
    1234        1997 :     case FIB_PROTOCOL_IP6:
    1235        1997 :         ip6_fib_table_destroy(fib_table->ft_index);
    1236        1997 :         break;
    1237          49 :     case FIB_PROTOCOL_MPLS:
    1238          49 :         mpls_fib_table_destroy(fib_table->ft_index);
    1239          49 :         break;
    1240             :     }
    1241        2298 : }
    1242             : 
    1243             : void
    1244        4462 : fib_table_walk (u32 fib_index,
    1245             :                 fib_protocol_t proto,
    1246             :                 fib_table_walk_fn_t fn,
    1247             :                 void *ctx)
    1248             : {
    1249        4462 :     switch (proto)
    1250             :     {
    1251        2936 :     case FIB_PROTOCOL_IP4:
    1252        2936 :         ip4_fib_table_walk(ip4_fib_get(fib_index), fn, ctx);
    1253        2936 :         break;
    1254        1191 :     case FIB_PROTOCOL_IP6:
    1255        1191 :         ip6_fib_table_walk(fib_index, fn, ctx);
    1256        1191 :         break;
    1257         335 :     case FIB_PROTOCOL_MPLS:
    1258         335 :         mpls_fib_table_walk(mpls_fib_get(fib_index), fn, ctx);
    1259         335 :         break;
    1260             :     }
    1261        4462 : }
    1262             : 
    1263             : typedef struct fib_table_walk_w_src_ctx_t_
    1264             : {
    1265             :     fib_table_walk_fn_t fn;
    1266             :     void *data;
    1267             :     fib_source_t src;
    1268             : } fib_table_walk_w_src_cxt_t;
    1269             : 
    1270             : static fib_table_walk_rc_t
    1271          40 : fib_table_walk_w_src_cb (fib_node_index_t fei,
    1272             :                          void *arg)
    1273             : {
    1274          40 :     fib_table_walk_w_src_cxt_t *ctx = arg;
    1275             : 
    1276          40 :     if (ctx->src == fib_entry_get_best_source(fei))
    1277             :     {
    1278          10 :         return (ctx->fn(fei, ctx->data));
    1279             :     }
    1280          30 :     return (FIB_TABLE_WALK_CONTINUE);
    1281             : }
    1282             : 
    1283             : void
    1284           4 : fib_table_walk_w_src (u32 fib_index,
    1285             :                       fib_protocol_t proto,
    1286             :                       fib_source_t src,
    1287             :                       fib_table_walk_fn_t fn,
    1288             :                       void *data)
    1289             : {
    1290           4 :     fib_table_walk_w_src_cxt_t ctx = {
    1291             :         .fn = fn,
    1292             :         .src = src,
    1293             :         .data = data,
    1294             :     };
    1295             : 
    1296           4 :     fib_table_walk(fib_index, proto, fib_table_walk_w_src_cb, &ctx);
    1297           4 : }
    1298             : 
    1299             : void
    1300          62 : fib_table_sub_tree_walk (u32 fib_index,
    1301             :                          fib_protocol_t proto,
    1302             :                          const fib_prefix_t *root,
    1303             :                          fib_table_walk_fn_t fn,
    1304             :                          void *ctx)
    1305             : {
    1306          62 :     switch (proto)
    1307             :     {
    1308          56 :     case FIB_PROTOCOL_IP4:
    1309          56 :         ip4_fib_table_sub_tree_walk(ip4_fib_get(fib_index), root, fn, ctx);
    1310          56 :         break;
    1311           6 :     case FIB_PROTOCOL_IP6:
    1312           6 :         ip6_fib_table_sub_tree_walk(fib_index, root, fn, ctx);
    1313           6 :         break;
    1314           0 :     case FIB_PROTOCOL_MPLS:
    1315           0 :         break;
    1316             :     }
    1317          62 : }
    1318             : 
    1319             : static void
    1320        6423 : fib_table_lock_dec (fib_table_t *fib_table,
    1321             :                     fib_source_t source)
    1322             : {
    1323        6423 :     vec_validate(fib_table->ft_locks, source);
    1324             : 
    1325        6423 :     ASSERT(fib_table->ft_locks[source] > 0);
    1326        6423 :     fib_table->ft_locks[source]--;
    1327        6423 :     fib_table->ft_total_locks--;
    1328        6423 : }
    1329             : 
    1330             : static void
    1331        8257 : fib_table_lock_inc (fib_table_t *fib_table,
    1332             :                     fib_source_t source)
    1333             : {
    1334        8257 :     vec_validate(fib_table->ft_locks, source);
    1335             : 
    1336        8257 :     ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
    1337        8257 :     fib_table->ft_locks[source]++;
    1338        8257 :     fib_table->ft_total_locks++;
    1339        8257 : }
    1340             : 
    1341             : 
    1342             : static void
    1343         421 : fib_table_lock_clear (fib_table_t *fib_table,
    1344             :                       fib_source_t source)
    1345             : {
    1346         421 :     vec_validate(fib_table->ft_locks, source);
    1347             : 
    1348         421 :     ASSERT(fib_table->ft_locks[source] <= 1);
    1349         421 :     if (fib_table->ft_locks[source])
    1350             :     {
    1351         421 :         fib_table->ft_locks[source]--;
    1352         421 :         fib_table->ft_total_locks--;
    1353             :     }
    1354         421 : }
    1355             : 
    1356             : static void
    1357         489 : fib_table_lock_set (fib_table_t *fib_table,
    1358             :                     fib_source_t source)
    1359             : {
    1360         489 :     vec_validate(fib_table->ft_locks, source);
    1361             : 
    1362         489 :     ASSERT(fib_table->ft_locks[source] <= 1);
    1363         489 :     ASSERT(fib_table->ft_total_locks < (0xffffffff - 1));
    1364         489 :     if (!fib_table->ft_locks[source])
    1365             :     {
    1366         439 :         fib_table->ft_locks[source]++;
    1367         439 :         fib_table->ft_total_locks++;
    1368             :     }
    1369         489 : }
    1370             : 
    1371             : void
    1372        6844 : fib_table_unlock (u32 fib_index,
    1373             :                   fib_protocol_t proto,
    1374             :                   fib_source_t source)
    1375             : {
    1376             :     fib_table_t *fib_table;
    1377             : 
    1378        6844 :     fib_table = fib_table_get(fib_index, proto);
    1379             : 
    1380        6844 :     if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
    1381         421 :         fib_table_lock_clear(fib_table, source);
    1382             :     else
    1383        6423 :         fib_table_lock_dec(fib_table, source);
    1384             : 
    1385        6844 :     if (0 == fib_table->ft_total_locks)
    1386             :     {
    1387             :         /*
    1388             :          * no more lock from any source - kill it
    1389             :          */
    1390        2298 :         fib_table_destroy(fib_table);
    1391             :     }
    1392        6844 : }
    1393             : 
    1394             : void
    1395        8746 : fib_table_lock (u32 fib_index,
    1396             :                 fib_protocol_t proto,
    1397             :                 fib_source_t source)
    1398             : {
    1399             :     fib_table_t *fib_table;
    1400             : 
    1401        8746 :     fib_table = fib_table_get(fib_index, proto);
    1402             : 
    1403        8746 :     if (source == FIB_SOURCE_API || source == FIB_SOURCE_CLI)
    1404         489 :         fib_table_lock_set(fib_table, source);
    1405             :     else
    1406        8257 :         fib_table_lock_inc(fib_table, source);
    1407        8746 : }
    1408             : 
    1409             : u32
    1410        1884 : fib_table_get_num_entries (u32 fib_index,
    1411             :                            fib_protocol_t proto,
    1412             :                            fib_source_t source)
    1413             : {
    1414             :     fib_table_t *fib_table;
    1415             : 
    1416        1884 :     fib_table = fib_table_get(fib_index, proto);
    1417             : 
    1418        1884 :     return (fib_table->ft_src_route_counts[source]);
    1419             : }
    1420             : 
    1421             : u8*
    1422         640 : format_fib_table_name (u8* s, va_list* ap)
    1423             : {
    1424         640 :     fib_node_index_t fib_index = va_arg(*ap, fib_node_index_t);
    1425         640 :     fib_protocol_t proto = va_arg(*ap, int); // int promotion
    1426             :     fib_table_t *fib_table;
    1427             : 
    1428         640 :     fib_table = fib_table_get(fib_index, proto);
    1429             : 
    1430         640 :     s = format(s, "%v", fib_table->ft_desc);
    1431             : 
    1432         640 :     return (s);
    1433             : }
    1434             : 
    1435             : u8*
    1436         572 : format_fib_table_flags (u8 *s, va_list *args)
    1437             : {
    1438         572 :     fib_table_flags_t flags = va_arg(*args, int);
    1439             :     fib_table_attribute_t attr;
    1440             : 
    1441         572 :     if (!flags)
    1442             :     {
    1443         572 :         return format(s, "none");
    1444             :     }
    1445             : 
    1446           0 :     FOR_EACH_FIB_TABLE_ATTRIBUTE(attr) {
    1447           0 :         if (1 << attr & flags) {
    1448           0 :             s = format(s, "%s", fib_table_flags_strings[attr]);
    1449             :         }
    1450             :     }
    1451             : 
    1452           0 :     return (s);
    1453             : }
    1454             : 
    1455             : /**
    1456             :  * @brief Table flush context. Store the indicies of matching FIB entries
    1457             :  * that need to be removed.
    1458             :  */
    1459             : typedef struct fib_table_flush_ctx_t_
    1460             : {
    1461             :     /**
    1462             :      * The list of entries to flush
    1463             :      */
    1464             :     fib_node_index_t *ftf_entries;
    1465             : 
    1466             :     /**
    1467             :      * The source we are flushing
    1468             :      */
    1469             :     fib_source_t ftf_source;
    1470             : } fib_table_flush_ctx_t;
    1471             : 
    1472             : static fib_table_walk_rc_t
    1473         269 : fib_table_flush_cb (fib_node_index_t fib_entry_index,
    1474             :                     void *arg)
    1475             : {
    1476         269 :     fib_table_flush_ctx_t *ctx = arg;
    1477             : 
    1478         269 :     if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
    1479             :     {
    1480         156 :         vec_add1(ctx->ftf_entries, fib_entry_index);
    1481             :     }
    1482         269 :     return (FIB_TABLE_WALK_CONTINUE);
    1483             : }
    1484             : 
    1485             : void
    1486          34 : fib_table_flush (u32 fib_index,
    1487             :                  fib_protocol_t proto,
    1488             :                  fib_source_t source)
    1489             : {
    1490             :     fib_node_index_t *fib_entry_index;
    1491          34 :     fib_table_flush_ctx_t ctx = {
    1492             :         .ftf_entries = NULL,
    1493             :         .ftf_source = source,
    1494             :     };
    1495             : 
    1496          34 :     fib_table_walk(fib_index, proto,
    1497             :                    fib_table_flush_cb,
    1498             :                    &ctx);
    1499             : 
    1500         190 :     vec_foreach(fib_entry_index, ctx.ftf_entries)
    1501             :     {
    1502         156 :         fib_table_entry_delete_index(*fib_entry_index, source);
    1503             :     }
    1504             : 
    1505          34 :     vec_free(ctx.ftf_entries);
    1506          34 : }
    1507             : 
    1508             : static fib_table_walk_rc_t
    1509         552 : fib_table_mark_cb (fib_node_index_t fib_entry_index,
    1510             :                    void *arg)
    1511             : {
    1512         552 :     fib_table_flush_ctx_t *ctx = arg;
    1513             : 
    1514         552 :     if (fib_entry_is_sourced(fib_entry_index, ctx->ftf_source))
    1515             :     {
    1516         468 :         fib_entry_mark(fib_entry_index, ctx->ftf_source);
    1517             :     }
    1518         552 :     return (FIB_TABLE_WALK_CONTINUE);
    1519             : }
    1520             : 
    1521             : void
    1522          24 : fib_table_mark (u32 fib_index,
    1523             :                 fib_protocol_t proto,
    1524             :                 fib_source_t source)
    1525             : {
    1526          24 :     fib_table_flush_ctx_t ctx = {
    1527             :         .ftf_source = source,
    1528             :     };
    1529             :     fib_table_t *fib_table;
    1530             : 
    1531          24 :     fib_table = fib_table_get(fib_index, proto);
    1532             : 
    1533          24 :     fib_table->ft_epoch++;
    1534          24 :     fib_table->ft_flags |= FIB_TABLE_FLAG_RESYNC;
    1535             : 
    1536          24 :     fib_table_walk(fib_index, proto,
    1537             :                    fib_table_mark_cb,
    1538             :                    &ctx);
    1539          24 : }
    1540             : 
    1541             : static fib_table_walk_rc_t
    1542         552 : fib_table_sweep_cb (fib_node_index_t fib_entry_index,
    1543             :                     void *arg)
    1544             : {
    1545         552 :     fib_table_flush_ctx_t *ctx = arg;
    1546             : 
    1547         552 :     if (fib_entry_is_marked(fib_entry_index, ctx->ftf_source))
    1548             :     {
    1549         228 :         vec_add1(ctx->ftf_entries, fib_entry_index);
    1550             :     }
    1551         552 :     return (FIB_TABLE_WALK_CONTINUE);
    1552             : }
    1553             : 
    1554             : void
    1555          24 : fib_table_sweep (u32 fib_index,
    1556             :                  fib_protocol_t proto,
    1557             :                  fib_source_t source)
    1558             : {
    1559          24 :     fib_table_flush_ctx_t ctx = {
    1560             :         .ftf_source = source,
    1561             :     };
    1562             :     fib_node_index_t *fib_entry_index;
    1563             :     fib_table_t *fib_table;
    1564             : 
    1565          24 :     fib_table = fib_table_get(fib_index, proto);
    1566             : 
    1567          24 :     fib_table->ft_flags &= ~FIB_TABLE_FLAG_RESYNC;
    1568             : 
    1569          24 :     fib_table_walk(fib_index, proto,
    1570             :                    fib_table_sweep_cb,
    1571             :                    &ctx);
    1572             : 
    1573         252 :     vec_foreach(fib_entry_index, ctx.ftf_entries)
    1574             :     {
    1575         228 :         fib_table_entry_delete_index(*fib_entry_index, source);
    1576             :     }
    1577             : 
    1578          24 :     vec_free(ctx.ftf_entries);
    1579          24 : }
    1580             : 
    1581             : u8 *
    1582           1 : format_fib_table_memory (u8 *s, va_list *args)
    1583             : {
    1584           1 :     s = format(s, "%U", format_ip4_fib_table_memory);
    1585           1 :     s = format(s, "%U", format_ip6_fib_table_memory);
    1586           1 :     s = format(s, "%U", format_mpls_fib_table_memory);
    1587             : 
    1588           1 :     return (s);
    1589             : }

Generated by: LCOV version 1.14