LCOV - code coverage report
Current view: top level - vnet/adj - adj.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 232 260 89.2 %
Date: 2023-07-05 22:20:52 Functions: 36 36 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 <vnet/adj/adj.h>
      17             : #include <vnet/adj/adj_internal.h>
      18             : #include <vnet/adj/adj_glean.h>
      19             : #include <vnet/adj/adj_midchain.h>
      20             : #include <vnet/adj/adj_mcast.h>
      21             : #include <vnet/adj/adj_delegate.h>
      22             : #include <vnet/fib/fib_node_list.h>
      23             : #include <vnet/fib/fib_walk.h>
      24             : 
      25             : /* Adjacency packet/byte counters indexed by adjacency index. */
      26             : vlib_combined_counter_main_t adjacency_counters = {
      27             :     .name = "adjacency",
      28             :     .stat_segment_name = "/net/adjacency",
      29             : };
      30             : 
      31             : /*
      32             :  * the single adj pool
      33             :  */
      34             : ip_adjacency_t *adj_pool;
      35             : 
      36             : /**
      37             :  * The adjacency logger
      38             :  */
      39             : vlib_log_class_t adj_logger;
      40             : 
      41             : /**
      42             :  * @brief Global Config for enabling per-adjacency counters.
      43             :  * By default these are disabled.
      44             :  */
      45             : int adj_per_adj_counters;
      46             : 
      47             : const ip46_address_t ADJ_BCAST_ADDR = {
      48             :     .ip6 = {
      49             :         .as_u64[0] = 0xffffffffffffffff,
      50             :         .as_u64[1] = 0xffffffffffffffff,
      51             :     },
      52             : };
      53             : 
      54             : /**
      55             :  * Adj flag names
      56             :  */
      57             : static const char *adj_attr_names[] = ADJ_ATTR_NAMES;
      58             : 
      59             : always_inline void
      60       22153 : adj_poison (ip_adjacency_t * adj)
      61             : {
      62             :     if (CLIB_DEBUG > 0)
      63             :     {
      64       22153 :         clib_memset (adj, 0xfe, sizeof (adj[0]));
      65             :     }
      66       22153 : }
      67             : 
      68             : ip_adjacency_t *
      69       22153 : adj_alloc (fib_protocol_t proto)
      70             : {
      71             :     ip_adjacency_t *adj;
      72       22153 :     u8 need_barrier_sync = pool_get_will_expand (adj_pool);
      73             :     vlib_main_t *vm;
      74       22153 :     vm = vlib_get_main();
      75             : 
      76       22153 :     ASSERT (vm->thread_index == 0);
      77             : 
      78             :     /* If the adj_pool will expand, stop the parade. */
      79       22153 :     if (need_barrier_sync)
      80        2627 :         vlib_worker_thread_barrier_sync (vm);
      81             : 
      82       22153 :     pool_get_aligned(adj_pool, adj, CLIB_CACHE_LINE_BYTES);
      83             : 
      84       22153 :     adj_poison(adj);
      85             : 
      86             :     /* Validate adjacency counters. */
      87       22153 :     if (need_barrier_sync == 0)
      88             :     {
      89             :         /* If the adj counter pool will expand, stop the parade */
      90       19526 :         need_barrier_sync = vlib_validate_combined_counter_will_expand
      91             :             (&adjacency_counters, adj_get_index (adj));
      92       19526 :         if (need_barrier_sync)
      93        1064 :             vlib_worker_thread_barrier_sync (vm);
      94             :     }
      95       22153 :     vlib_validate_combined_counter(&adjacency_counters,
      96             :                                    adj_get_index(adj));
      97             : 
      98             :     /* Make sure certain fields are always initialized. */
      99       22153 :     vlib_zero_combined_counter(&adjacency_counters,
     100             :                                adj_get_index(adj));
     101       22153 :     fib_node_init(&adj->ia_node,
     102             :                   FIB_NODE_TYPE_ADJ);
     103             : 
     104       22153 :     adj->ia_nh_proto = proto;
     105       22153 :     adj->ia_flags = 0;
     106       22153 :     adj->ia_cfg_index = 0;
     107       22153 :     adj->rewrite_header.sw_if_index = ~0;
     108       22153 :     adj->rewrite_header.flags = 0;
     109       22153 :     adj->lookup_next_index = 0;
     110       22153 :     adj->ia_delegates = NULL;
     111             : 
     112             :     /* lest it become a midchain in the future */
     113       22153 :     clib_memset(&adj->sub_type.midchain.next_dpo, 0,
     114             :            sizeof(adj->sub_type.midchain.next_dpo));
     115             : 
     116       22153 :     if (need_barrier_sync)
     117        3691 :         vlib_worker_thread_barrier_release (vm);
     118             : 
     119       22153 :     return (adj);
     120             : }
     121             : 
     122             : static int
     123      823424 : adj_index_is_special (adj_index_t adj_index)
     124             : {
     125      823424 :     if (ADJ_INDEX_INVALID == adj_index)
     126         167 :         return (!0);
     127             : 
     128      823257 :     return (0);
     129             : }
     130             : 
     131             : u8*
     132           7 : format_adj_flags (u8 * s, va_list * args)
     133             : {
     134             :     adj_flags_t af;
     135             :     adj_attr_t at;
     136             : 
     137           7 :     af = va_arg (*args, int);
     138             : 
     139           7 :     if (ADJ_FLAG_NONE == af)
     140             :     {
     141           5 :         return (format(s, "None"));
     142             :     }
     143          12 :     FOR_EACH_ADJ_ATTR(at)
     144             :     {
     145          10 :         if (af & (1 << at))
     146             :         {
     147           3 :             s = format(s, "%s ", adj_attr_names[at]);
     148             :         }
     149             :     }
     150           2 :     return (s);
     151             : }
     152             : 
     153             : /**
     154             :  * @brief Pretty print helper function for formatting specific adjacencies.
     155             :  * @param s - input string to format
     156             :  * @param args - other args passed to format function such as:
     157             :  *                 - vnet_main_t
     158             :  *                 - ip_lookup_main_t
     159             :  *                 - adj_index
     160             :  */
     161             : u8 *
     162      344757 : format_ip_adjacency (u8 * s, va_list * args)
     163             : {
     164             :     format_ip_adjacency_flags_t fiaf;
     165             :     ip_adjacency_t * adj;
     166             :     u32 adj_index;
     167             : 
     168      344757 :     adj_index = va_arg (*args, u32);
     169      344757 :     fiaf = va_arg (*args, format_ip_adjacency_flags_t);
     170             : 
     171      344757 :     if (!adj_is_valid(adj_index))
     172       19276 :       return format(s, "<invalid adjacency>");
     173             : 
     174      325481 :     adj = adj_get(adj_index);
     175             : 
     176      325481 :     switch (adj->lookup_next_index)
     177             :     {
     178      280870 :     case IP_LOOKUP_NEXT_REWRITE:
     179             :     case IP_LOOKUP_NEXT_BCAST:
     180      280870 :         s = format (s, "%U", format_adj_nbr, adj_index, 0);
     181      280870 :         break;
     182        2125 :     case IP_LOOKUP_NEXT_ARP:
     183        2125 :         s = format (s, "%U", format_adj_nbr_incomplete, adj_index, 0);
     184        2125 :         break;
     185         109 :     case IP_LOOKUP_NEXT_GLEAN:
     186         109 :         s = format (s, "%U", format_adj_glean, adj_index, 0);
     187         109 :         break;
     188       42057 :     case IP_LOOKUP_NEXT_MIDCHAIN:
     189       42057 :         s = format (s, "%U", format_adj_midchain, adj_index, 2);
     190       42057 :         break;
     191         320 :     case IP_LOOKUP_NEXT_MCAST:
     192         320 :         s = format (s, "%U", format_adj_mcast, adj_index, 0);
     193         320 :         break;
     194           0 :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     195           0 :         s = format (s, "%U", format_adj_mcast_midchain, adj_index, 0);
     196           0 :         break;
     197           0 :     case IP_LOOKUP_NEXT_DROP:
     198             :     case IP_LOOKUP_NEXT_PUNT:
     199             :     case IP_LOOKUP_NEXT_LOCAL:
     200             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
     201             :     case IP_LOOKUP_N_NEXT:
     202           0 :         break;
     203             :     }
     204             : 
     205      325481 :     if (fiaf & FORMAT_IP_ADJACENCY_DETAIL)
     206             :     {
     207             :         vlib_counter_t counts;
     208             : 
     209           7 :         vlib_get_combined_counter(&adjacency_counters, adj_index, &counts);
     210           7 :         s = format (s, "\n   flags:%U", format_adj_flags, adj->ia_flags);
     211           7 :         s = format (s, "\n   counts:[%Ld:%Ld]", counts.packets, counts.bytes);
     212           7 :         s = format (s, "\n   locks:%d", adj->ia_node.fn_locks);
     213           7 :         s = format(s, "\n delegates:");
     214           7 :         s = adj_delegate_format(s, adj);
     215             : 
     216           7 :         s = format(s, "\n children:");
     217           7 :         if (fib_node_list_get_size(adj->ia_node.fn_children))
     218             :         {
     219           5 :             s = format(s, "\n  ");
     220           5 :             s = fib_node_children_format(adj->ia_node.fn_children, s);
     221             :         }
     222             :     }
     223             : 
     224      325481 :     return s;
     225             : }
     226             : 
     227             : int
     228       66623 : adj_recursive_loop_detect (adj_index_t ai,
     229             :                            fib_node_index_t **entry_indicies)
     230             : {
     231             :     ip_adjacency_t * adj;
     232             : 
     233       66623 :     adj = adj_get(ai);
     234             : 
     235       66623 :     switch (adj->lookup_next_index)
     236             :     {
     237       64493 :     case IP_LOOKUP_NEXT_REWRITE:
     238             :     case IP_LOOKUP_NEXT_ARP:
     239             :     case IP_LOOKUP_NEXT_GLEAN:
     240             :     case IP_LOOKUP_NEXT_MCAST:
     241             :     case IP_LOOKUP_NEXT_BCAST:
     242             :     case IP_LOOKUP_NEXT_DROP:
     243             :     case IP_LOOKUP_NEXT_PUNT:
     244             :     case IP_LOOKUP_NEXT_LOCAL:
     245             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
     246             :     case IP_LOOKUP_N_NEXT:
     247             :         /*
     248             :          * these adjacency types are terminal graph nodes, so there's no
     249             :          * possibility of a loop down here.
     250             :          */
     251       64493 :         break;
     252        2130 :     case IP_LOOKUP_NEXT_MIDCHAIN:
     253             :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     254        2130 :         return (adj_ndr_midchain_recursive_loop_detect(ai, entry_indicies));
     255             :     }
     256             : 
     257       64493 :     return (0);
     258             : }
     259             : 
     260             : /*
     261             :  * adj_last_lock_gone
     262             :  *
     263             :  * last lock/reference to the adj has gone, we no longer need it.
     264             :  */
     265             : static void
     266       16972 : adj_last_lock_gone (ip_adjacency_t *adj)
     267             : {
     268       16972 :     vlib_main_t * vm = vlib_get_main();
     269             : 
     270       16972 :     ASSERT(0 == fib_node_list_get_size(adj->ia_node.fn_children));
     271       16972 :     ADJ_DBG(adj, "last-lock-gone");
     272             : 
     273       16972 :     adj_delegate_adj_deleted(adj);
     274             : 
     275       16972 :     vlib_worker_thread_barrier_sync (vm);
     276             : 
     277       16972 :     switch (adj->lookup_next_index)
     278             :     {
     279         477 :     case IP_LOOKUP_NEXT_MIDCHAIN:
     280         477 :         adj_midchain_teardown(adj);
     281             :         /* FALL THROUGH */
     282        6077 :     case IP_LOOKUP_NEXT_ARP:
     283             :     case IP_LOOKUP_NEXT_REWRITE:
     284             :     case IP_LOOKUP_NEXT_BCAST:
     285             :         /*
     286             :          * complete and incomplete nbr adjs
     287             :          */
     288        6077 :         adj_nbr_remove(adj_get_index(adj),
     289        6077 :                        adj->ia_nh_proto,
     290        6077 :                        adj->ia_link,
     291        6077 :                        &adj->sub_type.nbr.next_hop,
     292             :                        adj->rewrite_header.sw_if_index);
     293        6077 :         break;
     294        9134 :     case IP_LOOKUP_NEXT_GLEAN:
     295        9134 :         adj_glean_remove(adj);
     296        9134 :         break;
     297           0 :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     298           0 :         adj_midchain_teardown(adj);
     299             :         /* FALL THROUGH */
     300        1761 :     case IP_LOOKUP_NEXT_MCAST:
     301        1761 :         adj_mcast_remove(adj->ia_nh_proto,
     302             :                          adj->rewrite_header.sw_if_index);
     303        1761 :         break;
     304           0 :     case IP_LOOKUP_NEXT_DROP:
     305             :     case IP_LOOKUP_NEXT_PUNT:
     306             :     case IP_LOOKUP_NEXT_LOCAL:
     307             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
     308             :     case IP_LOOKUP_N_NEXT:
     309             :         /*
     310             :          * type not stored in any DB from which we need to remove it
     311             :          */
     312           0 :         break;
     313             :     }
     314             : 
     315             : 
     316       16972 :     fib_node_deinit(&adj->ia_node);
     317       16972 :     ASSERT(0 == vec_len(adj->ia_delegates));
     318       16972 :     vec_free(adj->ia_delegates);
     319       16972 :     pool_put(adj_pool, adj);
     320       16972 :     vlib_worker_thread_barrier_release(vm);
     321       16972 : }
     322             : 
     323             : u32
     324          16 : adj_dpo_get_urpf (const dpo_id_t *dpo)
     325             : {
     326             :     ip_adjacency_t *adj;
     327             : 
     328          16 :     adj = adj_get(dpo->dpoi_index);
     329             : 
     330          16 :     return (adj->rewrite_header.sw_if_index);
     331             : }
     332             : 
     333             : u16
     334           7 : adj_dpo_get_mtu (const dpo_id_t *dpo)
     335             : {
     336             :     ip_adjacency_t *adj;
     337             : 
     338           7 :     adj = adj_get(dpo->dpoi_index);
     339             : 
     340           7 :     return (adj->rewrite_header.max_l3_packet_bytes);
     341             : }
     342             : 
     343             : void
     344      375438 : adj_lock (adj_index_t adj_index)
     345             : {
     346             :     ip_adjacency_t *adj;
     347             : 
     348      375438 :     if (adj_index_is_special(adj_index))
     349             :     {
     350           5 :         return;
     351             :     }
     352             : 
     353      375433 :     adj = adj_get(adj_index);
     354      375433 :     ASSERT(adj);
     355             : 
     356      375433 :     fib_node_lock(&adj->ia_node);
     357             : }
     358             : 
     359             : void
     360      362086 : adj_unlock (adj_index_t adj_index)
     361             : {
     362             :     ip_adjacency_t *adj;
     363             : 
     364      362086 :     if (adj_index_is_special(adj_index))
     365             :     {
     366         162 :         return;
     367             :     }
     368             : 
     369      361924 :     adj = adj_get(adj_index);
     370      361924 :     ASSERT(adj);
     371             : 
     372      361924 :     fib_node_unlock(&adj->ia_node);
     373             : }
     374             : 
     375             : u32
     376       45830 : adj_child_add (adj_index_t adj_index,
     377             :                fib_node_type_t child_type,
     378             :                fib_node_index_t child_index)
     379             : {
     380       45830 :     ASSERT(ADJ_INDEX_INVALID != adj_index);
     381       45830 :     if (adj_index_is_special(adj_index))
     382             :     {
     383           0 :         return (~0);
     384             :     }
     385             : 
     386       45830 :     return (fib_node_child_add(FIB_NODE_TYPE_ADJ,
     387             :                                adj_index,
     388             :                                child_type,
     389             :                                child_index));
     390             : }
     391             : 
     392             : void
     393       40070 : adj_child_remove (adj_index_t adj_index,
     394             :                   u32 sibling_index)
     395             : {
     396       40070 :     if (adj_index_is_special(adj_index))
     397             :     {
     398           0 :         return;
     399             :     }
     400             : 
     401       40070 :     fib_node_child_remove(FIB_NODE_TYPE_ADJ,
     402             :                           adj_index,
     403             :                           sibling_index);
     404             : }
     405             : 
     406             : /*
     407             :  * Context for the walk to update the cached feature flags.
     408             :  */
     409             : typedef struct adj_feature_update_t_
     410             : {
     411             :     u8 arc;
     412             :     u8 enable;
     413             : } adj_feature_update_ctx_t;
     414             : 
     415             : static adj_walk_rc_t
     416       68597 : adj_feature_update_walk_cb (adj_index_t ai,
     417             :                             void *arg)
     418             : {
     419       68597 :     adj_feature_update_ctx_t *ctx = arg;
     420             :     ip_adjacency_t *adj;
     421             : 
     422       68597 :     adj = adj_get(ai);
     423             : 
     424             :     /*
     425             :      * this ugly mess matches the feature arc that is changing with affected
     426             :      * adjacencies
     427             :      */
     428       68597 :     if (((ctx->arc == ip6_main.lookup_main.output_feature_arc_index) &&
     429       10561 :          (VNET_LINK_IP6 == adj->ia_link)) ||
     430       61787 :         ((ctx->arc == ip4_main.lookup_main.output_feature_arc_index) &&
     431       10765 :          (VNET_LINK_IP4 == adj->ia_link)) ||
     432       57880 :         ((ctx->arc == mpls_main.output_feature_arc_index) &&
     433         745 :          (VNET_LINK_MPLS == adj->ia_link)))
     434             :     {
     435       10723 :         vnet_feature_main_t *fm = &feature_main;
     436             :         vnet_feature_config_main_t *cm;
     437             : 
     438       10723 :         cm = &fm->feature_config_mains[ctx->arc];
     439             : 
     440       10723 :         if (ctx->enable)
     441        5098 :             adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES;
     442             :         else
     443        5625 :             adj->rewrite_header.flags &= ~VNET_REWRITE_HAS_FEATURES;
     444             : 
     445       10723 :         adj->ia_cfg_index = vec_elt (cm->config_index_by_sw_if_index,
     446             :                                      adj->rewrite_header.sw_if_index);
     447             :     }
     448       68597 :     return (ADJ_WALK_RC_CONTINUE);
     449             : }
     450             : 
     451             : static void
     452      131439 : adj_feature_update (u32 sw_if_index,
     453             :                     u8 arc_index,
     454             :                     u8 is_enable,
     455             :                     void *data)
     456             : {
     457             :     /*
     458             :      * Walk all the adjacencies on the interface to update the cached
     459             :      * 'has-features' flag
     460             :      */
     461      131439 :     adj_feature_update_ctx_t ctx = {
     462             :         .arc = arc_index,
     463             :         .enable = is_enable,
     464             :     };
     465      131439 :     adj_walk (sw_if_index, adj_feature_update_walk_cb, &ctx);
     466      131439 : }
     467             : 
     468             : static adj_walk_rc_t
     469         158 : adj_mtu_update_walk_cb (adj_index_t ai,
     470             :                         void *arg)
     471             : {
     472             :     ip_adjacency_t *adj;
     473             : 
     474         158 :     adj = adj_get(ai);
     475             : 
     476         158 :     vnet_rewrite_update_mtu (vnet_get_main(), adj->ia_link,
     477             :                              &adj->rewrite_header);
     478         158 :     adj_delegate_adj_modified(adj);
     479             : 
     480             :     /**
     481             :      * Backwalk to all Path MTU trackers, casual like ..
     482             :      */
     483             :     {
     484         158 :         fib_node_back_walk_ctx_t bw_ctx = {
     485             :             .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_MTU,
     486             :         };
     487             : 
     488         158 :         fib_walk_async(FIB_NODE_TYPE_ADJ, ai,
     489             :                        FIB_WALK_PRIORITY_LOW, &bw_ctx);
     490             :     }
     491             : 
     492         158 :     return (ADJ_WALK_RC_CONTINUE);
     493             : }
     494             : 
     495             : static clib_error_t *
     496        5961 : adj_mtu_update (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
     497             : {
     498        5961 :   adj_walk (sw_if_index, adj_mtu_update_walk_cb, NULL);
     499             : 
     500        5961 :   return (NULL);
     501             : }
     502             : 
     503        1119 : VNET_SW_INTERFACE_MTU_CHANGE_FUNCTION(adj_mtu_update);
     504             : 
     505             : /**
     506             :  * @brief Walk the Adjacencies on a given interface
     507             :  */
     508             : void
     509      137400 : adj_walk (u32 sw_if_index,
     510             :           adj_walk_cb_t cb,
     511             :           void *ctx)
     512             : {
     513             :     /*
     514             :      * walk all the neighbor adjacencies
     515             :      */
     516             :     fib_protocol_t proto;
     517             : 
     518      412200 :     FOR_EACH_FIB_IP_PROTOCOL(proto)
     519             :     {
     520      274800 :         adj_nbr_walk(sw_if_index, proto, cb, ctx);
     521      274800 :         adj_mcast_walk(sw_if_index, proto, cb, ctx);
     522             :     }
     523      137400 : }
     524             : 
     525             : /**
     526             :  * @brief Return the link type of the adjacency
     527             :  */
     528             : vnet_link_t
     529       20610 : adj_get_link_type (adj_index_t ai)
     530             : {
     531             :     const ip_adjacency_t *adj;
     532             : 
     533       20610 :     adj = adj_get(ai);
     534             : 
     535       20610 :     return (adj->ia_link);
     536             : }
     537             : 
     538             : /**
     539             :  * @brief Return the sw interface index of the adjacency.
     540             :  */
     541             : u32
     542        1028 : adj_get_sw_if_index (adj_index_t ai)
     543             : {
     544             :     const ip_adjacency_t *adj;
     545             : 
     546        1028 :     adj = adj_get(ai);
     547             : 
     548        1028 :     return (adj->rewrite_header.sw_if_index);
     549             : }
     550             : 
     551             : /**
     552             :  * @brief Return true if the adjacency is 'UP', i.e. can be used for forwarding
     553             :  * 0 is down, !0 is up.
     554             :  */
     555             : int
     556       12861 : adj_is_up (adj_index_t ai)
     557             : {
     558       12861 :     return (adj_bfd_is_up(ai));
     559             : }
     560             : 
     561             : /**
     562             :  * @brief Return the rewrite string of the adjacency
     563             :  */
     564             : const u8*
     565         650 : adj_get_rewrite (adj_index_t ai)
     566             : {
     567             :     vnet_rewrite_header_t *rw;
     568             :     ip_adjacency_t *adj;
     569             : 
     570         650 :     adj = adj_get(ai);
     571         650 :     rw = &adj->rewrite_header;
     572             : 
     573         650 :     ASSERT (rw->data_bytes != 0xfefe);
     574             : 
     575         650 :     return (rw->data - rw->data_bytes);
     576             : }
     577             : 
     578             : static fib_node_t *
     579      176212 : adj_get_node (fib_node_index_t index)
     580             : {
     581             :     ip_adjacency_t *adj;
     582             : 
     583      176212 :     adj = adj_get(index);
     584             : 
     585      176212 :     return (&adj->ia_node);
     586             : }
     587             : 
     588             : #define ADJ_FROM_NODE(_node)                                            \
     589             :     ((ip_adjacency_t*)((char*)_node - STRUCT_OFFSET_OF(ip_adjacency_t, ia_node)))
     590             : 
     591             : static void
     592       16972 : adj_node_last_lock_gone (fib_node_t *node)
     593             : {
     594       16972 :     adj_last_lock_gone(ADJ_FROM_NODE(node));
     595       16972 : }
     596             : 
     597             : static fib_node_back_walk_rc_t
     598         263 : adj_back_walk_notify (fib_node_t *node,
     599             :                       fib_node_back_walk_ctx_t *ctx)
     600             : {
     601             :     ip_adjacency_t *adj;
     602             : 
     603         263 :     adj = ADJ_FROM_NODE(node);
     604             : 
     605         263 :     switch (adj->lookup_next_index)
     606             :     {
     607         263 :     case IP_LOOKUP_NEXT_MIDCHAIN:
     608         263 :         adj_midchain_delegate_restack(adj_get_index(adj));
     609         263 :         break;
     610           0 :     case IP_LOOKUP_NEXT_ARP:
     611             :     case IP_LOOKUP_NEXT_REWRITE:
     612             :     case IP_LOOKUP_NEXT_BCAST:
     613             :     case IP_LOOKUP_NEXT_GLEAN:
     614             :     case IP_LOOKUP_NEXT_MCAST:
     615             :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     616             :     case IP_LOOKUP_NEXT_DROP:
     617             :     case IP_LOOKUP_NEXT_PUNT:
     618             :     case IP_LOOKUP_NEXT_LOCAL:
     619             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
     620             :     case IP_LOOKUP_N_NEXT:
     621             :         /*
     622             :          * Que pasa. yo soj en el final!
     623             :          */
     624           0 :         ASSERT(0);
     625           0 :         break;
     626             :     }
     627             : 
     628         263 :     return (FIB_NODE_BACK_WALK_CONTINUE);
     629             : }
     630             : 
     631             : /*
     632             :  * Adjacency's graph node virtual function table
     633             :  */
     634             : static const fib_node_vft_t adj_vft = {
     635             :     .fnv_get = adj_get_node,
     636             :     .fnv_last_lock = adj_node_last_lock_gone,
     637             :     .fnv_back_walk = adj_back_walk_notify,
     638             : };
     639             : 
     640             : static clib_error_t *
     641         559 : adj_module_init (vlib_main_t * vm)
     642             : {
     643         559 :     fib_node_register_type(FIB_NODE_TYPE_ADJ, &adj_vft);
     644             : 
     645         559 :     adj_nbr_module_init();
     646         559 :     adj_glean_module_init();
     647         559 :     adj_midchain_module_init();
     648         559 :     adj_mcast_module_init();
     649             : 
     650         559 :     vnet_feature_register(adj_feature_update, NULL);
     651             : 
     652         559 :     adj_logger = vlib_log_register_class("adj", "adj");
     653             : 
     654         559 :     return (NULL);
     655             : }
     656             : 
     657       12879 : VLIB_INIT_FUNCTION (adj_module_init);
     658             : 
     659             : static clib_error_t *
     660          15 : adj_show (vlib_main_t * vm,
     661             :           unformat_input_t * input,
     662             :           vlib_cli_command_t * cmd)
     663             : {
     664          15 :     adj_index_t ai = ADJ_INDEX_INVALID;
     665          15 :     u32 sw_if_index = ~0;
     666          15 :     int summary = 0;
     667             : 
     668          22 :     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     669             :     {
     670           7 :         if (unformat (input, "%d", &ai))
     671             :             ;
     672           0 :         else if (unformat (input, "summary") || unformat (input, "sum"))
     673           0 :             summary = 1;
     674           0 :         else if (unformat (input, "%U",
     675             :                            unformat_vnet_sw_interface, vnet_get_main(),
     676             :                            &sw_if_index))
     677             :             ;
     678             :         else
     679           0 :             break;
     680             :     }
     681             : 
     682          15 :     if (summary)
     683             :     {
     684           0 :         vlib_cli_output (vm, "Number of adjacencies: %d", pool_elts(adj_pool));
     685           0 :         vlib_cli_output (vm, "Per-adjacency counters: %s",
     686           0 :                          (adj_are_counters_enabled() ?
     687             :                           "enabled":
     688             :                           "disabled"));
     689             :     }
     690             :     else
     691             :     {
     692          15 :         if (ADJ_INDEX_INVALID != ai)
     693             :         {
     694           7 :             if (pool_is_free_index(adj_pool, ai))
     695             :             {
     696           0 :                 vlib_cli_output (vm, "adjacency %d invalid", ai);
     697           0 :                 return 0;
     698             :             }
     699             : 
     700           7 :             vlib_cli_output (vm, "[@%d] %U",
     701             :                              ai,
     702             :                              format_ip_adjacency,  ai,
     703             :                              FORMAT_IP_ADJACENCY_DETAIL);
     704             :         }
     705             :         else
     706             :         {
     707             :             /* *INDENT-OFF* */
     708         205 :             pool_foreach_index (ai, adj_pool)
     709             :              {
     710         197 :                 if (~0 != sw_if_index &&
     711           0 :                     sw_if_index != adj_get_sw_if_index(ai))
     712             :                 {
     713             :                 }
     714             :                 else
     715             :                 {
     716         197 :                     vlib_cli_output (vm, "[@%d] %U",
     717             :                                      ai,
     718             :                                      format_ip_adjacency, ai,
     719             :                                      FORMAT_IP_ADJACENCY_NONE);
     720             :                 }
     721             :             }
     722             :             /* *INDENT-ON* */
     723             :         }
     724             :     }
     725          15 :     return 0;
     726             : }
     727             : 
     728             : /*?
     729             :  * Show all adjacencies.
     730             :  * @cliexpar
     731             :  * @cliexstart{sh adj}
     732             :  * [@0]
     733             :  * [@1]  glean: loop0
     734             :  * [@2] ipv4 via 1.0.0.2 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
     735             :  * [@3] mpls via 1.0.0.2 loop0: MPLS: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
     736             :  * [@4] ipv4 via 1.0.0.3 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
     737             :  * [@5] mpls via 1.0.0.3 loop0: MPLS: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
     738             :  * @cliexend
     739             :  ?*/
     740      272887 : VLIB_CLI_COMMAND (adj_show_command, static) = {
     741             :     .path = "show adj",
     742             :     .short_help = "show adj [<adj_index>] [interface] [summary]",
     743             :     .function = adj_show,
     744             : };
     745             : 
     746             : /**
     747             :  * @brief CLI invoked function to enable/disable per-adj counters
     748             :  */
     749             : static clib_error_t *
     750           4 : adj_cli_counters_set (vlib_main_t * vm,
     751             :                       unformat_input_t * input,
     752             :                       vlib_cli_command_t * cmd)
     753             : {
     754           4 :     clib_error_t *error = NULL;
     755           4 :     int enable = ~0;
     756             : 
     757           8 :     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     758             :     {
     759           4 :         if (unformat (input, "enable"))
     760           4 :             enable = 1;
     761           0 :         else if (unformat (input, "disable"))
     762           0 :             enable = 0;
     763             :         else
     764           0 :             break;
     765             :     }
     766             : 
     767           4 :     if (enable != ~0)
     768             :     {
     769             :         /* user requested something sensible */
     770           4 :         adj_per_adj_counters = enable;
     771             :     }
     772             :     else
     773             :     {
     774           0 :         error = clib_error_return (0, "specify 'enable' or 'disable'");
     775             :     }
     776             : 
     777           4 :     return (error);
     778             : }
     779             : 
     780             : /*?
     781             :  * Enable/disable per-adjacency counters. This is optional because it comes
     782             :  * with a non-negligible performance cost.
     783             :  ?*/
     784      272887 : VLIB_CLI_COMMAND (adj_cli_counters_set_command, static) = {
     785             :     .path = "adjacency counters",
     786             :     .short_help = "adjacency counters [enable|disable]",
     787             :     .function = adj_cli_counters_set,
     788             : };

Generated by: LCOV version 1.14