LCOV - code coverage report
Current view: top level - vnet/l2 - l2_learn.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 169 199 84.9 %
Date: 2023-10-26 01:39:38 Functions: 18 22 81.8 %

          Line data    Source code
       1             : /*
       2             :  * l2_learn.c : layer 2 learning using l2fib
       3             :  *
       4             :  * Copyright (c) 2013 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/vnet.h>
      20             : #include <vnet/ethernet/ethernet.h>
      21             : #include <vlib/cli.h>
      22             : 
      23             : #include <vnet/l2/l2_input.h>
      24             : #include <vnet/l2/feat_bitmap.h>
      25             : #include <vnet/l2/l2_fib.h>
      26             : #include <vnet/l2/l2_learn.h>
      27             : 
      28             : #include <vppinfra/error.h>
      29             : #include <vppinfra/hash.h>
      30             : 
      31             : #ifndef CLIB_MARCH_VARIANT
      32             : l2learn_main_t l2learn_main;
      33             : #endif
      34             : 
      35             : /**
      36             :  * @file
      37             :  * @brief Ethernet Bridge Learning.
      38             :  *
      39             :  * Populate the mac table with entries mapping the packet's source mac + bridge
      40             :  * domain ID to the input sw_if_index.
      41             :  *
      42             :  * Note that learning and forwarding are separate graph nodes. This means that
      43             :  * for a set of packets, all learning is performed first, then all nodes are
      44             :  * forwarded. The forwarding is done based on the end-state of the mac table,
      45             :  * instead of the state after each packet. Thus the forwarding results could
      46             :  * differ in certain cases (mac move tests), but this not expected to cause
      47             :  * problems in real-world networks. It is much simpler to separate learning
      48             :  * and forwarding into separate nodes.
      49             :  */
      50             : 
      51             : 
      52             : typedef struct
      53             : {
      54             :   u8 src[6];
      55             :   u8 dst[6];
      56             :   u32 sw_if_index;
      57             :   u16 bd_index;
      58             : } l2learn_trace_t;
      59             : 
      60             : 
      61             : /* packet trace format function */
      62             : static u8 *
      63        4830 : format_l2learn_trace (u8 * s, va_list * args)
      64             : {
      65        4830 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      66        4830 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      67        4830 :   l2learn_trace_t *t = va_arg (*args, l2learn_trace_t *);
      68             : 
      69        4830 :   s = format (s, "l2-learn: sw_if_index %d dst %U src %U bd_index %d",
      70             :               t->sw_if_index,
      71        4830 :               format_ethernet_address, t->dst,
      72        4830 :               format_ethernet_address, t->src, t->bd_index);
      73        4830 :   return s;
      74             : }
      75             : 
      76             : extern vlib_node_registration_t l2learn_node;
      77             : 
      78             : #define foreach_l2learn_error                           \
      79             : _(L2LEARN,           "L2 learn packets")              \
      80             : _(MISS,              "L2 learn misses")                       \
      81             : _(MAC_MOVE,          "L2 mac moves")                  \
      82             : _(MAC_MOVE_VIOLATE,  "L2 mac move violations")                \
      83             : _(LIMIT,             "L2 not learned due to limit")   \
      84             : _(HIT_UPDATE,        "L2 learn hit updates")          \
      85             : _(FILTER_DROP,       "L2 filter mac drops")
      86             : 
      87             : typedef enum
      88             : {
      89             : #define _(sym,str) L2LEARN_ERROR_##sym,
      90             :   foreach_l2learn_error
      91             : #undef _
      92             :     L2LEARN_N_ERROR,
      93             : } l2learn_error_t;
      94             : 
      95             : static char *l2learn_error_strings[] = {
      96             : #define _(sym,string) string,
      97             :   foreach_l2learn_error
      98             : #undef _
      99             : };
     100             : 
     101             : typedef enum
     102             : {
     103             :   L2LEARN_NEXT_L2FWD,
     104             :   L2LEARN_NEXT_DROP,
     105             :   L2LEARN_N_NEXT,
     106             : } l2learn_next_t;
     107             : 
     108             : 
     109             : /** Perform learning on one packet based on the mac table lookup result. */
     110             : 
     111             : static_always_inline void
     112    56207400 : l2learn_process (vlib_node_runtime_t * node,
     113             :                  l2learn_main_t * msm,
     114             :                  u64 * counter_base,
     115             :                  vlib_buffer_t * b0,
     116             :                  u32 sw_if_index0,
     117             :                  l2fib_entry_key_t * key0,
     118             :                  l2fib_entry_key_t * cached_key,
     119             :                  u32 * count,
     120             :                  l2fib_entry_result_t * result0, u16 * next0, u8 timestamp)
     121             : {
     122    56207400 :   l2_bridge_domain_t *bd_config =
     123    56207400 :     vec_elt_at_index (l2input_main.bd_configs, vnet_buffer (b0)->l2.bd_index);
     124             :   /* Set up the default next node (typically L2FWD) */
     125    56207400 :   *next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index,
     126             :                                  L2INPUT_FEAT_LEARN);
     127             : 
     128             :   /* Check mac table lookup result */
     129    56207400 :   if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0))
     130             :     {
     131             :       /* Entry in L2FIB with matching sw_if_index matched - normal fast path */
     132    56205700 :       u32 dtime = timestamp - result0->fields.timestamp;
     133    56205700 :       u32 dsn = (result0->fields.sn - vnet_buffer (b0)->l2.l2fib_sn);
     134    56205700 :       u32 check = (dtime && vnet_buffer (b0)->l2.bd_age) || dsn;
     135             : 
     136    56205700 :       if (PREDICT_TRUE (check == 0))
     137    56205700 :         return;                 /* MAC entry up to date */
     138           1 :       if (l2fib_entry_result_is_set_AGE_NOT (result0))
     139           0 :         return;                 /* Static MAC always age_not */
     140           1 :       if (msm->global_learn_count > msm->global_learn_limit)
     141           0 :         return;                 /* Above learn limit - do not update */
     142           1 :       if (bd_config->learn_count > bd_config->learn_limit)
     143           0 :         return; /* Above bridge domain learn limit - do not update */
     144             : 
     145             :       /* Limit updates per l2-learn node call to avoid prolonged update burst
     146             :        * as dtime advance over 1 minute mark, unless more than 1 min behind
     147             :        * or SN obsolete */
     148           1 :       if ((*count > 2) && (dtime == 1) && (dsn == 0))
     149           0 :         return;
     150             : 
     151           1 :       counter_base[L2LEARN_ERROR_HIT_UPDATE] += 1;
     152           1 :       *count += 1;
     153             :     }
     154        1754 :   else if (result0->raw == ~0)
     155             :     {
     156             :       /* Entry not in L2FIB - add it  */
     157        1671 :       counter_base[L2LEARN_ERROR_MISS] += 1;
     158             : 
     159        1671 :       if ((msm->global_learn_count >= msm->global_learn_limit) ||
     160        1660 :           (bd_config->learn_count >= bd_config->learn_limit))
     161             :         {
     162             :           /*
     163             :            * Global limit reached. Do not learn the mac but forward the packet.
     164             :            * In the future, limits could also be per-interface or bridge-domain.
     165             :            */
     166          42 :           counter_base[L2LEARN_ERROR_LIMIT] += 1;
     167          42 :           return;
     168             :         }
     169             : 
     170             :       /* Do not learn if mac is 0 */
     171        1629 :       l2fib_entry_key_t key = *key0;
     172        1629 :       key.fields.bd_index = 0;
     173        1629 :       if (key.raw == 0)
     174           0 :         return;
     175             : 
     176             :       /* It is ok to learn */
     177             :       /* learn_count variable may have little inaccuracy because they are not
     178             :        * incremented/decremented with atomic operations */
     179             :       /* l2fib_scan is call every 2sec fixing potential inaccuracy */
     180        1629 :       msm->global_learn_count++;
     181        1629 :       bd_config->learn_count++;
     182        1629 :       result0->raw = 0;              /* clear all fields */
     183        1629 :       result0->fields.sw_if_index = sw_if_index0;
     184        1629 :       if (msm->client_pid != 0)
     185         139 :         l2fib_entry_result_set_LRN_EVT (result0);
     186             :       else
     187        1490 :         l2fib_entry_result_clear_LRN_EVT (result0);
     188             :     }
     189             :   else
     190             :     {
     191             :       /* Entry in L2FIB with different sw_if_index - mac move or filter */
     192          83 :       if (l2fib_entry_result_is_set_FILTER (result0))
     193             :         {
     194           0 :           ASSERT (result0->fields.sw_if_index == ~0);
     195             :           /* drop packet because lookup matched a filter mac entry */
     196           0 :           b0->error = node->errors[L2LEARN_ERROR_FILTER_DROP];
     197           0 :           *next0 = L2LEARN_NEXT_DROP;
     198           0 :           return;
     199             :         }
     200             : 
     201          83 :       if (l2fib_entry_result_is_set_STATIC (result0))
     202             :         {
     203             :           /*
     204             :            * Don't overwrite a static mac
     205             :            * TODO: Check violation policy. For now drop the packet
     206             :            */
     207           0 :           b0->error = node->errors[L2LEARN_ERROR_MAC_MOVE_VIOLATE];
     208           0 :           *next0 = L2LEARN_NEXT_DROP;
     209           0 :           return;
     210             :         }
     211             : 
     212             :       /*
     213             :        * TODO: may want to rate limit mac moves
     214             :        * TODO: check global/bridge domain/interface learn limits
     215             :        */
     216          83 :       result0->fields.sw_if_index = sw_if_index0;
     217          83 :       if (l2fib_entry_result_is_set_AGE_NOT (result0))
     218             :         {
     219             :           /* The mac was provisioned */
     220             :           /* learn_count variable may have little inaccuracy because they are
     221             :            * not incremented/decremented with atomic operations */
     222             :           /* l2fib_scan is call every 2sec fixing potential inaccuracy */
     223           0 :           msm->global_learn_count++;
     224           0 :           bd_config->learn_count++;
     225             : 
     226           0 :           l2fib_entry_result_clear_AGE_NOT (result0);
     227             :         }
     228          83 :       if (msm->client_pid != 0)
     229           0 :         l2fib_entry_result_set_bits (result0,
     230             :                                      (L2FIB_ENTRY_RESULT_FLAG_LRN_EVT |
     231             :                                       L2FIB_ENTRY_RESULT_FLAG_LRN_MOV));
     232             :       else
     233          83 :         l2fib_entry_result_clear_bits (result0,
     234             :                                        (L2FIB_ENTRY_RESULT_FLAG_LRN_EVT |
     235             :                                         L2FIB_ENTRY_RESULT_FLAG_LRN_MOV));
     236          83 :       counter_base[L2LEARN_ERROR_MAC_MOVE] += 1;
     237             :     }
     238             : 
     239             :   /* Update the entry */
     240        1713 :   result0->fields.timestamp = timestamp;
     241        1713 :   result0->fields.sn = vnet_buffer (b0)->l2.l2fib_sn;
     242             : 
     243             :   BVT (clib_bihash_kv) kv;
     244        1713 :   kv.key = key0->raw;
     245        1713 :   kv.value = result0->raw;
     246        1713 :   BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ );
     247             : 
     248             :   /* Invalidate the cache */
     249        1713 :   cached_key->raw = ~0;
     250             : }
     251             : 
     252             : 
     253             : static_always_inline uword
     254     1071750 : l2learn_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
     255             :                      vlib_frame_t * frame, int do_trace)
     256             : {
     257             :   u32 n_left, *from;
     258     1071750 :   l2learn_main_t *msm = &l2learn_main;
     259     1071750 :   vlib_node_t *n = vlib_get_node (vm, l2learn_node.index);
     260     1071750 :   u32 node_counter_base_index = n->error_heap_index;
     261     1071750 :   vlib_error_main_t *em = &vm->error_main;
     262             :   l2fib_entry_key_t cached_key;
     263             :   l2fib_entry_result_t cached_result;
     264     1071750 :   u8 timestamp = (u8) (vlib_time_now (vm) / 60);
     265     1071750 :   u32 count = 0;
     266             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     267             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     268             : 
     269     1071750 :   from = vlib_frame_vector_args (frame);
     270     1071750 :   n_left = frame->n_vectors; /* number of packets to process */
     271     1071750 :   vlib_get_buffers (vm, from, bufs, n_left);
     272     1071750 :   next = nexts;
     273     1071750 :   b = bufs;
     274             : 
     275             :   /* Clear the one-entry cache in case mac table was updated */
     276     1071750 :   cached_key.raw = ~0;
     277     1071750 :   cached_result.raw = ~0;       /* warning be gone */
     278             : 
     279    13666500 :   while (n_left > 8)
     280             :     {
     281             :       u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
     282             :       const ethernet_header_t *h0, *h1, *h2, *h3;
     283             :       l2fib_entry_key_t key0, key1, key2, key3;
     284             :       l2fib_entry_result_t result0, result1, result2, result3;
     285             : 
     286             :       /* Prefetch next iteration. */
     287             :       {
     288             :         /* buffer header is read and written, so use LOAD
     289             :          * prefetch */
     290    12594800 :         vlib_prefetch_buffer_header (b[4], LOAD);
     291    12594800 :         vlib_prefetch_buffer_header (b[5], LOAD);
     292    12594800 :         vlib_prefetch_buffer_header (b[6], LOAD);
     293    12594800 :         vlib_prefetch_buffer_header (b[7], LOAD);
     294             : 
     295    12594800 :         clib_prefetch_load (b[4]->data);
     296    12594800 :         clib_prefetch_load (b[5]->data);
     297    12594800 :         clib_prefetch_load (b[6]->data);
     298    12594800 :         clib_prefetch_load (b[7]->data);
     299             :       }
     300             : 
     301             :       /* RX interface handles */
     302    12594800 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     303    12594800 :       sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
     304    12594800 :       sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
     305    12594800 :       sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
     306             : 
     307             :       /* Process 4 x pkts */
     308             : 
     309    12594800 :       h0 = vlib_buffer_get_current (b[0]);
     310    12594800 :       h1 = vlib_buffer_get_current (b[1]);
     311    12594800 :       h2 = vlib_buffer_get_current (b[2]);
     312    12594800 :       h3 = vlib_buffer_get_current (b[3]);
     313             : 
     314    12594800 :       if (do_trace)
     315             :         {
     316        1319 :           if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
     317             :             {
     318             :               l2learn_trace_t *t =
     319        1319 :                 vlib_add_trace (vm, node, b[0], sizeof (*t));
     320        1319 :               t->sw_if_index = sw_if_index0;
     321        1319 :               t->bd_index = vnet_buffer (b[0])->l2.bd_index;
     322        1319 :               clib_memcpy_fast (t->src, h0->src_address, 6);
     323        1319 :               clib_memcpy_fast (t->dst, h0->dst_address, 6);
     324             :             }
     325        1319 :           if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
     326             :             {
     327             :               l2learn_trace_t *t =
     328        1319 :                 vlib_add_trace (vm, node, b[1], sizeof (*t));
     329        1319 :               t->sw_if_index = sw_if_index1;
     330        1319 :               t->bd_index = vnet_buffer (b[1])->l2.bd_index;
     331        1319 :               clib_memcpy_fast (t->src, h1->src_address, 6);
     332        1319 :               clib_memcpy_fast (t->dst, h1->dst_address, 6);
     333             :             }
     334        1319 :           if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
     335             :             {
     336             :               l2learn_trace_t *t =
     337        1319 :                 vlib_add_trace (vm, node, b[2], sizeof (*t));
     338        1319 :               t->sw_if_index = sw_if_index2;
     339        1319 :               t->bd_index = vnet_buffer (b[2])->l2.bd_index;
     340        1319 :               clib_memcpy_fast (t->src, h2->src_address, 6);
     341        1319 :               clib_memcpy_fast (t->dst, h2->dst_address, 6);
     342             :             }
     343        1319 :           if (b[3]->flags & VLIB_BUFFER_IS_TRACED)
     344             :             {
     345             :               l2learn_trace_t *t =
     346        1319 :                 vlib_add_trace (vm, node, b[3], sizeof (*t));
     347        1319 :               t->sw_if_index = sw_if_index3;
     348        1319 :               t->bd_index = vnet_buffer (b[3])->l2.bd_index;
     349        1319 :               clib_memcpy_fast (t->src, h3->src_address, 6);
     350        1319 :               clib_memcpy_fast (t->dst, h3->dst_address, 6);
     351             :             }
     352             :         }
     353             : 
     354             :       /* process 4 pkts */
     355    12594800 :       vlib_node_increment_counter (vm, l2learn_node.index,
     356             :                                    L2LEARN_ERROR_L2LEARN, 4);
     357             : 
     358    12594800 :       l2fib_lookup_4 (msm->mac_table, &cached_key, &cached_result,
     359    12594800 :                       h0->src_address,
     360    12594800 :                       h1->src_address,
     361    12594800 :                       h2->src_address,
     362    12594800 :                       h3->src_address,
     363    12594800 :                       vnet_buffer (b[0])->l2.bd_index,
     364    12594800 :                       vnet_buffer (b[1])->l2.bd_index,
     365    12594800 :                       vnet_buffer (b[2])->l2.bd_index,
     366    12594800 :                       vnet_buffer (b[3])->l2.bd_index,
     367             :                       &key0, &key1, &key2, &key3,
     368             :                       &result0, &result1, &result2, &result3);
     369             : 
     370    12594800 :       l2learn_process (node, msm, &em->counters[node_counter_base_index],
     371             :                        b[0], sw_if_index0, &key0, &cached_key,
     372             :                        &count, &result0, next, timestamp);
     373             : 
     374    12594800 :       l2learn_process (node, msm, &em->counters[node_counter_base_index],
     375    12594800 :                        b[1], sw_if_index1, &key1, &cached_key,
     376             :                        &count, &result1, next + 1, timestamp);
     377             : 
     378    12594800 :       l2learn_process (node, msm, &em->counters[node_counter_base_index],
     379    12594800 :                        b[2], sw_if_index2, &key2, &cached_key,
     380             :                        &count, &result2, next + 2, timestamp);
     381             : 
     382    12594800 :       l2learn_process (node, msm, &em->counters[node_counter_base_index],
     383    12594800 :                        b[3], sw_if_index3, &key3, &cached_key,
     384             :                        &count, &result3, next + 3, timestamp);
     385             : 
     386    12594800 :       next += 4;
     387    12594800 :       b += 4;
     388    12594800 :       n_left -= 4;
     389             :     }
     390             : 
     391     6900120 :   while (n_left > 0)
     392             :     {
     393             :       u32 sw_if_index0;
     394             :       ethernet_header_t *h0;
     395             :       l2fib_entry_key_t key0;
     396             :       l2fib_entry_result_t result0;
     397             : 
     398     5828380 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     399             : 
     400     5828380 :       h0 = vlib_buffer_get_current (b[0]);
     401             : 
     402     5828380 :       if (do_trace && PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
     403             :         {
     404        1068 :           l2learn_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t));
     405        1068 :           t->sw_if_index = sw_if_index0;
     406        1068 :           t->bd_index = vnet_buffer (b[0])->l2.bd_index;
     407        1068 :           clib_memcpy_fast (t->src, h0->src_address, 6);
     408        1068 :           clib_memcpy_fast (t->dst, h0->dst_address, 6);
     409             :         }
     410             : 
     411             :       /* process 1 pkt */
     412     5828380 :       vlib_node_increment_counter (vm, l2learn_node.index,
     413             :                                    L2LEARN_ERROR_L2LEARN, 1);
     414             : 
     415             : 
     416     5828380 :       l2fib_lookup_1 (msm->mac_table, &cached_key, &cached_result,
     417     5828380 :                       h0->src_address, vnet_buffer (b[0])->l2.bd_index,
     418             :                       &key0, &result0);
     419             : 
     420     5828380 :       l2learn_process (node, msm, &em->counters[node_counter_base_index],
     421             :                        b[0], sw_if_index0, &key0, &cached_key,
     422             :                        &count, &result0, next, timestamp);
     423             : 
     424     5828380 :       next += 1;
     425     5828380 :       b += 1;
     426     5828380 :       n_left -= 1;
     427             :     }
     428             : 
     429     1071750 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     430             : 
     431     1071750 :   return frame->n_vectors;
     432             : }
     433             : 
     434     1074050 : VLIB_NODE_FN (l2learn_node) (vlib_main_t * vm,
     435             :                              vlib_node_runtime_t * node, vlib_frame_t * frame)
     436             : {
     437     1071750 :   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
     438         292 :     return l2learn_node_inline (vm, node, frame, 1 /* do_trace */ );
     439     1071450 :   return l2learn_node_inline (vm, node, frame, 0 /* do_trace */ );
     440             : }
     441             : 
     442             : /* *INDENT-OFF* */
     443      183788 : VLIB_REGISTER_NODE (l2learn_node) = {
     444             :   .name = "l2-learn",
     445             :   .vector_size = sizeof (u32),
     446             :   .format_trace = format_l2learn_trace,
     447             :   .type = VLIB_NODE_TYPE_INTERNAL,
     448             : 
     449             :   .n_errors = ARRAY_LEN(l2learn_error_strings),
     450             :   .error_strings = l2learn_error_strings,
     451             : 
     452             :   .n_next_nodes = L2LEARN_N_NEXT,
     453             : 
     454             :   /* edit / add dispositions here */
     455             :   .next_nodes = {
     456             :         [L2LEARN_NEXT_DROP] = "error-drop",
     457             :         [L2LEARN_NEXT_L2FWD] = "l2-fwd",
     458             :   },
     459             : };
     460             : /* *INDENT-ON* */
     461             : 
     462             : #ifndef CLIB_MARCH_VARIANT
     463             : clib_error_t *
     464         575 : l2learn_init (vlib_main_t * vm)
     465             : {
     466         575 :   l2learn_main_t *mp = &l2learn_main;
     467             : 
     468         575 :   mp->vlib_main = vm;
     469         575 :   mp->vnet_main = vnet_get_main ();
     470             : 
     471             :   /* Initialize the feature next-node indexes */
     472         575 :   feat_bitmap_init_next_nodes (vm,
     473             :                                l2learn_node.index,
     474             :                                L2INPUT_N_FEAT,
     475             :                                l2input_get_feat_names (),
     476         575 :                                mp->feat_next_node_index);
     477             : 
     478             :   /* init the hash table ptr */
     479         575 :   mp->mac_table = get_mac_table ();
     480             : 
     481             :   /*
     482             :    * Set the default number of dynamically learned macs to the number
     483             :    * of buckets.
     484             :    */
     485         575 :   mp->global_learn_limit = L2LEARN_DEFAULT_LIMIT;
     486             : 
     487             :   /*
     488             :    * Set the default number of dynamically learned macs to the number
     489             :    * of buckets.
     490             :    */
     491         575 :   mp->bd_default_learn_limit = L2LEARN_DEFAULT_LIMIT;
     492         575 :   return 0;
     493             : }
     494             : 
     495       21311 : VLIB_INIT_FUNCTION (l2learn_init);
     496             : 
     497             : 
     498             : /**
     499             :  * Set subinterface learn enable/disable.
     500             :  * The CLI format is:
     501             :  *    set interface l2 learn <interface> [disable]
     502             :  */
     503             : static clib_error_t *
     504           0 : int_learn (vlib_main_t * vm,
     505             :            unformat_input_t * input, vlib_cli_command_t * cmd)
     506             : {
     507           0 :   vnet_main_t *vnm = vnet_get_main ();
     508           0 :   clib_error_t *error = 0;
     509             :   u32 sw_if_index;
     510             :   u32 enable;
     511             : 
     512           0 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     513             :     {
     514           0 :       error = clib_error_return (0, "unknown interface `%U'",
     515             :                                  format_unformat_error, input);
     516           0 :       goto done;
     517             :     }
     518             : 
     519           0 :   enable = 1;
     520           0 :   if (unformat (input, "disable"))
     521             :     {
     522           0 :       enable = 0;
     523             :     }
     524             : 
     525             :   /* set the interface flag */
     526           0 :   l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_LEARN, enable);
     527             : 
     528           0 : done:
     529           0 :   return error;
     530             : }
     531             : 
     532             : /*?
     533             :  * Layer 2 learning can be enabled and disabled on each
     534             :  * interface and on each bridge-domain. Use this command to
     535             :  * manage interfaces. It is enabled by default.
     536             :  *
     537             :  * @cliexpar
     538             :  * Example of how to enable learning:
     539             :  * @cliexcmd{set interface l2 learn GigabitEthernet0/8/0}
     540             :  * Example of how to disable learning:
     541             :  * @cliexcmd{set interface l2 learn GigabitEthernet0/8/0 disable}
     542             : ?*/
     543             : /* *INDENT-OFF* */
     544      285289 : VLIB_CLI_COMMAND (int_learn_cli, static) = {
     545             :   .path = "set interface l2 learn",
     546             :   .short_help = "set interface l2 learn <interface> [disable]",
     547             :   .function = int_learn,
     548             : };
     549             : /* *INDENT-ON* */
     550             : 
     551             : 
     552             : static clib_error_t *
     553         575 : l2learn_config (vlib_main_t * vm, unformat_input_t * input)
     554             : {
     555         575 :   l2learn_main_t *mp = &l2learn_main;
     556             : 
     557         575 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     558             :     {
     559           0 :       if (unformat (input, "limit %d", &mp->global_learn_limit))
     560             :         ;
     561             : 
     562             :       else
     563           0 :         return clib_error_return (0, "unknown input `%U'",
     564             :                                   format_unformat_error, input);
     565             :     }
     566             : 
     567         575 :   return 0;
     568             : }
     569             : 
     570        7514 : VLIB_CONFIG_FUNCTION (l2learn_config, "l2learn");
     571             : 
     572             : #endif
     573             : 
     574             : 
     575             : /*
     576             :  * fd.io coding-style-patch-verification: ON
     577             :  *
     578             :  * Local Variables:
     579             :  * eval: (c-set-style "gnu")
     580             :  * End:
     581             :  */

Generated by: LCOV version 1.14