LCOV - code coverage report
Current view: top level - vnet/l2 - l2_fwd.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 143 167 85.6 %
Date: 2023-07-05 22:20:52 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /*
       2             :  * l2_fwd.c : layer 2 forwarding 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/pg/pg.h>
      21             : #include <vnet/ethernet/ethernet.h>
      22             : #include <vlib/cli.h>
      23             : 
      24             : #include <vnet/l2/l2_input.h>
      25             : #include <vnet/l2/l2_bvi.h>
      26             : #include <vnet/l2/l2_fwd.h>
      27             : #include <vnet/l2/l2_fib.h>
      28             : #include <vnet/l2/feat_bitmap.h>
      29             : 
      30             : #include <vppinfra/error.h>
      31             : #include <vppinfra/hash.h>
      32             : #include <vppinfra/sparse_vec.h>
      33             : 
      34             : 
      35             : /**
      36             :  * @file
      37             :  * @brief Ethernet Forwarding.
      38             :  *
      39             :  * Code in this file handles forwarding Layer 2 packets. This file calls
      40             :  * the FIB lookup, packet learning and the packet flooding as necessary.
      41             :  * Packet is then sent to the next graph node.
      42             :  */
      43             : 
      44             : typedef struct
      45             : {
      46             : 
      47             :   /* Hash table */
      48             :   BVT (clib_bihash) * mac_table;
      49             : 
      50             :   /* next node index for the L3 input node of each ethertype */
      51             :   next_by_ethertype_t l3_next;
      52             : 
      53             :   /* Next nodes for each feature */
      54             :   u32 feat_next_node_index[32];
      55             : 
      56             :   /* convenience variables */
      57             :   vlib_main_t *vlib_main;
      58             :   vnet_main_t *vnet_main;
      59             : } l2fwd_main_t;
      60             : 
      61             : typedef struct
      62             : {
      63             :   /* per-pkt trace data */
      64             :   u8 dst_and_src[12];
      65             :   u32 sw_if_index;
      66             :   u16 bd_index;
      67             :   l2fib_entry_result_t result;
      68             : } l2fwd_trace_t;
      69             : 
      70             : /* packet trace format function */
      71             : static u8 *
      72        5297 : format_l2fwd_trace (u8 * s, va_list * args)
      73             : {
      74        5297 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      75        5297 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      76        5297 :   l2fwd_trace_t *t = va_arg (*args, l2fwd_trace_t *);
      77             : 
      78             :   s =
      79        5297 :     format (s,
      80             :             "l2-fwd:   sw_if_index %d dst %U src %U bd_index %d result [0x%llx, %d] %U",
      81        5297 :             t->sw_if_index, format_ethernet_address, t->dst_and_src,
      82        5297 :             format_ethernet_address, t->dst_and_src + 6,
      83        5297 :             t->bd_index, t->result.raw,
      84             :             t->result.fields.sw_if_index, format_l2fib_entry_result_flags,
      85        5297 :             t->result.fields.flags);
      86        5297 :   return s;
      87             : }
      88             : 
      89             : #ifndef CLIB_MARCH_VARIANT
      90             : l2fwd_main_t l2fwd_main;
      91             : #else
      92             : extern l2fwd_main_t l2fwd_main;
      93             : #endif
      94             : 
      95             : extern vlib_node_registration_t l2fwd_node;
      96             : 
      97             : #define foreach_l2fwd_error                             \
      98             : _(L2FWD,         "L2 forward packets")                        \
      99             : _(FLOOD,         "L2 forward misses")                 \
     100             : _(HIT,           "L2 forward hits")                   \
     101             : _(BVI_BAD_MAC,   "BVI L3 MAC mismatch")               \
     102             : _(BVI_ETHERTYPE, "BVI packet with unhandled ethertype")       \
     103             : _(FILTER_DROP,   "Filter Mac Drop")                   \
     104             : _(REFLECT_DROP,  "Reflection Drop")                   \
     105             : _(STALE_DROP,    "Stale entry Drop")
     106             : 
     107             : typedef enum
     108             : {
     109             : #define _(sym,str) L2FWD_ERROR_##sym,
     110             :   foreach_l2fwd_error
     111             : #undef _
     112             :     L2FWD_N_ERROR,
     113             : } l2fwd_error_t;
     114             : 
     115             : static char *l2fwd_error_strings[] = {
     116             : #define _(sym,string) string,
     117             :   foreach_l2fwd_error
     118             : #undef _
     119             : };
     120             : 
     121             : typedef enum
     122             : {
     123             :   L2FWD_NEXT_L2_OUTPUT,
     124             :   L2FWD_NEXT_DROP,
     125             :   L2FWD_N_NEXT,
     126             : } l2fwd_next_t;
     127             : 
     128             : /** Forward one packet based on the mac table lookup result. */
     129             : 
     130             : static_always_inline void
     131    52446600 : l2fwd_process (vlib_main_t * vm,
     132             :                vlib_node_runtime_t * node,
     133             :                l2fwd_main_t * msm,
     134             :                vlib_error_main_t * em,
     135             :                vlib_buffer_t * b0,
     136             :                u32 sw_if_index0, l2fib_entry_result_t * result0, u16 * next0)
     137             : {
     138    52446600 :   int try_flood = result0->raw == ~0;
     139             :   int flood_error;
     140             : 
     141    52446600 :   if (PREDICT_FALSE (try_flood))
     142             :     {
     143        3264 :       flood_error = L2FWD_ERROR_FLOOD;
     144             :     }
     145             :   else
     146             :     {
     147             :       /* lookup hit, forward packet  */
     148             : #ifdef COUNTERS
     149             :       em->counters[node_counter_base_index + L2FWD_ERROR_HIT] += 1;
     150             : #endif
     151             : 
     152    52443400 :       vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index;
     153    52443400 :       *next0 = L2FWD_NEXT_L2_OUTPUT;
     154    52443400 :       int l2fib_seq_num_valid = 1;
     155             : 
     156             :       /* check l2fib seq num for stale entries */
     157    52443400 :       if (!l2fib_entry_result_is_set_AGE_NOT (result0))
     158             :         {
     159    52439800 :           l2fib_seq_num_t in_sn = vnet_buffer (b0)->l2.l2fib_sn;
     160    52439800 :           l2fib_seq_num_t expected_sn = l2_fib_update_seq_num (in_sn,
     161    52439800 :                                                                l2_input_seq_num
     162             :                                                                (result0->fields.sw_if_index));
     163             : 
     164    52439800 :           l2fib_seq_num_valid = expected_sn == result0->fields.sn;
     165             :         }
     166             : 
     167    52443400 :       if (PREDICT_FALSE (!l2fib_seq_num_valid))
     168             :         {
     169         128 :           flood_error = L2FWD_ERROR_STALE_DROP;
     170         128 :           try_flood = 1;
     171             :         }
     172             :       /* perform reflection check */
     173    52443200 :       else if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index))
     174             :         {
     175           0 :           b0->error = node->errors[L2FWD_ERROR_REFLECT_DROP];
     176           0 :           *next0 = L2FWD_NEXT_DROP;
     177             :         }
     178             :       /* perform filter check */
     179    52443200 :       else if (PREDICT_FALSE (l2fib_entry_result_is_set_FILTER (result0)))
     180             :         {
     181           0 :           b0->error = node->errors[L2FWD_ERROR_FILTER_DROP];
     182           0 :           *next0 = L2FWD_NEXT_DROP;
     183             :         }
     184             :       /* perform BVI check */
     185    52443200 :       else if (PREDICT_FALSE (l2fib_entry_result_is_set_BVI (result0)))
     186             :         {
     187             :           u32 rc;
     188        1649 :           rc = l2_to_bvi (vm,
     189             :                           msm->vnet_main,
     190             :                           b0,
     191        1649 :                           vnet_buffer (b0)->sw_if_index[VLIB_TX],
     192             :                           &msm->l3_next, next0);
     193             : 
     194        1649 :           if (PREDICT_FALSE (rc))
     195             :             {
     196           0 :               if (rc == TO_BVI_ERR_BAD_MAC)
     197             :                 {
     198           0 :                   b0->error = node->errors[L2FWD_ERROR_BVI_BAD_MAC];
     199           0 :                   *next0 = L2FWD_NEXT_DROP;
     200             :                 }
     201           0 :               else if (rc == TO_BVI_ERR_ETHERTYPE)
     202             :                 {
     203           0 :                   b0->error = node->errors[L2FWD_ERROR_BVI_ETHERTYPE];
     204           0 :                   *next0 = L2FWD_NEXT_DROP;
     205             :                 }
     206             :             }
     207             :         }
     208             :     }
     209             : 
     210             :   /* flood */
     211    52446600 :   if (PREDICT_FALSE (try_flood))
     212             :     {
     213             :       /*
     214             :        * lookup miss, so flood which is typically the next feature
     215             :        * unless some other feature is inserted before uu_flood
     216             :        */
     217        3392 :       if (vnet_buffer (b0)->l2.feature_bitmap &
     218             :           (L2INPUT_FEAT_UU_FLOOD | L2INPUT_FEAT_UU_FWD))
     219             :         {
     220        3118 :           *next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index,
     221             :                                          L2INPUT_FEAT_FWD);
     222             :         }
     223             :       else
     224             :         {
     225             :           /* Flooding is disabled */
     226         274 :           b0->error = node->errors[flood_error];
     227         274 :           *next0 = L2FWD_NEXT_DROP;
     228             :         }
     229             :     }
     230    52446600 : }
     231             : 
     232             : 
     233             : static_always_inline uword
     234      971318 : l2fwd_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
     235             :                    vlib_frame_t * frame, int do_trace)
     236             : {
     237             :   u32 n_left, *from;
     238      971318 :   l2fwd_main_t *msm = &l2fwd_main;
     239      971318 :   vlib_node_t *n = vlib_get_node (vm, l2fwd_node.index);
     240      971318 :   CLIB_UNUSED (u32 node_counter_base_index) = n->error_heap_index;
     241      971318 :   vlib_error_main_t *em = &vm->error_main;
     242             :   l2fib_entry_key_t cached_key;
     243             :   l2fib_entry_result_t cached_result;
     244             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     245             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     246             : 
     247             :   /* Clear the one-entry cache in case mac table was updated */
     248      971318 :   cached_key.raw = ~0;
     249      971318 :   cached_result.raw = ~0;
     250             : 
     251      971318 :   from = vlib_frame_vector_args (frame);
     252      971318 :   n_left = frame->n_vectors; /* number of packets to process */
     253      971318 :   vlib_get_buffers (vm, from, bufs, n_left);
     254      971318 :   next = nexts;
     255      971318 :   b = bufs;
     256             : 
     257    12954700 :   while (n_left >= 8)
     258             :     {
     259             :       u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
     260             :       const ethernet_header_t *h0, *h1, *h2, *h3;
     261             :       l2fib_entry_key_t key0, key1, key2, key3;
     262             :       l2fib_entry_result_t result0, result1, result2, result3;
     263             : 
     264             :       /* Prefetch next iteration. */
     265             :       {
     266    11983400 :         vlib_prefetch_buffer_header (b[4], LOAD);
     267    11983400 :         vlib_prefetch_buffer_header (b[5], LOAD);
     268    11983400 :         vlib_prefetch_buffer_header (b[6], LOAD);
     269    11983400 :         vlib_prefetch_buffer_header (b[7], LOAD);
     270             : 
     271    11983400 :         clib_prefetch_load (b[4]->data);
     272    11983400 :         clib_prefetch_load (b[5]->data);
     273    11983400 :         clib_prefetch_load (b[6]->data);
     274    11983400 :         clib_prefetch_load (b[7]->data);
     275             :       }
     276             : 
     277             :       /* RX interface handles */
     278    11983400 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     279    11983400 :       sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
     280    11983400 :       sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
     281    11983400 :       sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
     282             : 
     283    11983400 :       h0 = vlib_buffer_get_current (b[0]);
     284    11983400 :       h1 = vlib_buffer_get_current (b[1]);
     285    11983400 :       h2 = vlib_buffer_get_current (b[2]);
     286    11983400 :       h3 = vlib_buffer_get_current (b[3]);
     287             : 
     288             : #ifdef COUNTERS
     289             :       em->counters[node_counter_base_index + L2FWD_ERROR_L2FWD] += 4;
     290             : #endif
     291             :       /* *INDENT-OFF* */
     292    11983400 :       l2fib_lookup_4 (msm->mac_table, &cached_key, &cached_result,
     293    11983400 :                       h0->dst_address, h1->dst_address,
     294    11983400 :                       h2->dst_address, h3->dst_address,
     295    11983400 :                       vnet_buffer (b[0])->l2.bd_index,
     296    11983400 :                       vnet_buffer (b[1])->l2.bd_index,
     297    11983400 :                       vnet_buffer (b[2])->l2.bd_index,
     298    11983400 :                       vnet_buffer (b[3])->l2.bd_index,
     299             :                       &key0,        /* not used */
     300             :                       &key1,        /* not used */
     301             :                       &key2,        /* not used */
     302             :                       &key3,        /* not used */
     303             :                       &result0,
     304             :                       &result1,
     305             :                       &result2,
     306             :                       &result3);
     307             :       /* *INDENT-ON* */
     308    11983400 :       l2fwd_process (vm, node, msm, em, b[0], sw_if_index0, &result0, next);
     309    11983400 :       l2fwd_process (vm, node, msm, em, b[1], sw_if_index1, &result1,
     310             :                      next + 1);
     311    11983400 :       l2fwd_process (vm, node, msm, em, b[2], sw_if_index2, &result2,
     312             :                      next + 2);
     313    11983400 :       l2fwd_process (vm, node, msm, em, b[3], sw_if_index3, &result3,
     314             :                      next + 3);
     315             : 
     316             :       /* verify speculative enqueues, maybe switch current next frame */
     317             :       /* if next0==next1==next_index then nothing special needs to be done */
     318    11983400 :       if (do_trace)
     319             :         {
     320        1437 :           if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
     321             :             {
     322        1437 :               l2fwd_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t));
     323        1437 :               t->sw_if_index = sw_if_index0;
     324        1437 :               t->bd_index = vnet_buffer (b[0])->l2.bd_index;
     325        1437 :               clib_memcpy_fast (t->dst_and_src, h0->dst_address,
     326             :                                 sizeof (h0->dst_address) +
     327             :                                 sizeof (h0->src_address));
     328        1437 :               t->result = result0;
     329             :             }
     330        1437 :           if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
     331             :             {
     332        1437 :               l2fwd_trace_t *t = vlib_add_trace (vm, node, b[1], sizeof (*t));
     333        1437 :               t->sw_if_index = sw_if_index1;
     334        1437 :               t->bd_index = vnet_buffer (b[1])->l2.bd_index;
     335        1437 :               clib_memcpy_fast (t->dst_and_src, h1->dst_address,
     336             :                                 sizeof (h1->dst_address) +
     337             :                                 sizeof (h1->src_address));
     338        1437 :               t->result = result1;
     339             :             }
     340        1437 :           if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
     341             :             {
     342        1437 :               l2fwd_trace_t *t = vlib_add_trace (vm, node, b[2], sizeof (*t));
     343        1437 :               t->sw_if_index = sw_if_index2;
     344        1437 :               t->bd_index = vnet_buffer (b[2])->l2.bd_index;
     345        1437 :               clib_memcpy_fast (t->dst_and_src, h2->dst_address,
     346             :                                 sizeof (h2->dst_address) +
     347             :                                 sizeof (h2->src_address));
     348        1437 :               t->result = result2;
     349             :             }
     350        1437 :           if (b[3]->flags & VLIB_BUFFER_IS_TRACED)
     351             :             {
     352        1437 :               l2fwd_trace_t *t = vlib_add_trace (vm, node, b[3], sizeof (*t));
     353        1437 :               t->sw_if_index = sw_if_index3;
     354        1437 :               t->bd_index = vnet_buffer (b[3])->l2.bd_index;
     355        1437 :               clib_memcpy_fast (t->dst_and_src, h3->dst_address,
     356             :                                 sizeof (h3->dst_address) +
     357             :                                 sizeof (h3->src_address));
     358        1437 :               t->result = result3;
     359             :             }
     360             :         }
     361             : 
     362    11983400 :       next += 4;
     363    11983400 :       b += 4;
     364    11983400 :       n_left -= 4;
     365             :     }
     366             : 
     367     5484420 :   while (n_left > 0)
     368             :     {
     369             :       u32 sw_if_index0;
     370             :       ethernet_header_t *h0;
     371             :       l2fib_entry_key_t key0;
     372             :       l2fib_entry_result_t result0;
     373             : 
     374     4513100 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
     375             : 
     376     4513100 :       h0 = vlib_buffer_get_current (b[0]);
     377             : 
     378             :       /* process 1 pkt */
     379             : #ifdef COUNTERS
     380             :       em->counters[node_counter_base_index + L2FWD_ERROR_L2FWD] += 1;
     381             : #endif
     382     4513100 :       l2fib_lookup_1 (msm->mac_table, &cached_key, &cached_result,
     383     4513100 :                       h0->dst_address, vnet_buffer (b[0])->l2.bd_index, &key0,
     384             :                       /* not used */ &result0);
     385     4513100 :       l2fwd_process (vm, node, msm, em, b[0], sw_if_index0, &result0, next);
     386             : 
     387     4513100 :       if (do_trace && PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
     388             :         {
     389         987 :           l2fwd_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t));
     390         987 :           t->sw_if_index = sw_if_index0;
     391         987 :           t->bd_index = vnet_buffer (b[0])->l2.bd_index;
     392         987 :           clib_memcpy_fast (t->dst_and_src, h0->dst_address,
     393             :                             sizeof (h0->dst_address) +
     394             :                             sizeof (h0->src_address));
     395         987 :           t->result = result0;
     396             :         }
     397             : 
     398             :       /* verify speculative enqueue, maybe switch current next frame */
     399     4513100 :       next += 1;
     400     4513100 :       b += 1;
     401     4513100 :       n_left -= 1;
     402             :     }
     403             : 
     404      971318 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     405             : 
     406      971318 :   return frame->n_vectors;
     407             : }
     408             : 
     409      973554 : VLIB_NODE_FN (l2fwd_node) (vlib_main_t * vm,
     410             :                            vlib_node_runtime_t * node, vlib_frame_t * frame)
     411             : {
     412      971318 :   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
     413         312 :     return l2fwd_node_inline (vm, node, frame, 1 /* do_trace */ );
     414      971006 :   return l2fwd_node_inline (vm, node, frame, 0 /* do_trace */ );
     415             : }
     416             : 
     417             : /* *INDENT-OFF* */
     418      178120 : VLIB_REGISTER_NODE (l2fwd_node) = {
     419             :   .name = "l2-fwd",
     420             :   .vector_size = sizeof (u32),
     421             :   .format_trace = format_l2fwd_trace,
     422             :   .type = VLIB_NODE_TYPE_INTERNAL,
     423             : 
     424             :   .n_errors = ARRAY_LEN(l2fwd_error_strings),
     425             :   .error_strings = l2fwd_error_strings,
     426             : 
     427             :   .n_next_nodes = L2FWD_N_NEXT,
     428             : 
     429             :   /* edit / add dispositions here */
     430             :   .next_nodes = {
     431             :     [L2FWD_NEXT_L2_OUTPUT] = "l2-output",
     432             :     [L2FWD_NEXT_DROP] = "error-drop",
     433             :   },
     434             : };
     435             : /* *INDENT-ON* */
     436             : 
     437             : #ifndef CLIB_MARCH_VARIANT
     438             : clib_error_t *
     439         559 : l2fwd_init (vlib_main_t * vm)
     440             : {
     441         559 :   l2fwd_main_t *mp = &l2fwd_main;
     442             : 
     443         559 :   mp->vlib_main = vm;
     444         559 :   mp->vnet_main = vnet_get_main ();
     445             : 
     446             :   /* Initialize the feature next-node indexes */
     447         559 :   feat_bitmap_init_next_nodes (vm,
     448             :                                l2fwd_node.index,
     449             :                                L2INPUT_N_FEAT,
     450             :                                l2input_get_feat_names (),
     451         559 :                                mp->feat_next_node_index);
     452             : 
     453             :   /* init the hash table ptr */
     454         559 :   mp->mac_table = get_mac_table ();
     455             : 
     456             :   /* Initialize the next nodes for each ethertype */
     457         559 :   next_by_ethertype_init (&mp->l3_next);
     458             : 
     459         559 :   return 0;
     460             : }
     461             : 
     462       19039 : VLIB_INIT_FUNCTION (l2fwd_init);
     463             : 
     464             : 
     465             : /** Add the L3 input node for this ethertype to the next nodes structure. */
     466             : void
     467        3917 : l2fwd_register_input_type (vlib_main_t * vm,
     468             :                            ethernet_type_t type, u32 node_index)
     469             : {
     470        3917 :   l2fwd_main_t *mp = &l2fwd_main;
     471             :   u32 next_index;
     472             : 
     473        3917 :   next_index = vlib_node_add_next (vm, l2fwd_node.index, node_index);
     474             : 
     475        3917 :   next_by_ethertype_register (&mp->l3_next, type, next_index);
     476        3917 : }
     477             : 
     478             : 
     479             : /**
     480             :  * Set subinterface forward enable/disable.
     481             :  * The CLI format is:
     482             :  *   set interface l2 forward <interface> [disable]
     483             :  */
     484             : static clib_error_t *
     485           0 : int_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
     486             : {
     487           0 :   vnet_main_t *vnm = vnet_get_main ();
     488           0 :   clib_error_t *error = 0;
     489             :   u32 sw_if_index;
     490             :   u32 enable;
     491             : 
     492           0 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     493             :     {
     494           0 :       error = clib_error_return (0, "unknown interface `%U'",
     495             :                                  format_unformat_error, input);
     496           0 :       goto done;
     497             :     }
     498             : 
     499           0 :   enable = 1;
     500           0 :   if (unformat (input, "disable"))
     501             :     {
     502           0 :       enable = 0;
     503             :     }
     504             : 
     505             :   /* set the interface flag */
     506           0 :   if (l2input_intf_config (sw_if_index))
     507             :     {
     508           0 :       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_XCONNECT, enable);
     509             :     }
     510             :   else
     511             :     {
     512           0 :       l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_FWD, enable);
     513             :     }
     514             : 
     515           0 : done:
     516           0 :   return error;
     517             : }
     518             : 
     519             : /*?
     520             :  * Layer 2 unicast forwarding can be enabled and disabled on each
     521             :  * interface and on each bridge-domain. Use this command to
     522             :  * manage interfaces. It is enabled by default.
     523             :  *
     524             :  * @cliexpar
     525             :  * Example of how to enable forwarding:
     526             :  * @cliexcmd{set interface l2 forward GigabitEthernet0/8/0}
     527             :  * Example of how to disable forwarding:
     528             :  * @cliexcmd{set interface l2 forward GigabitEthernet0/8/0 disable}
     529             : ?*/
     530             : /* *INDENT-OFF* */
     531      272887 : VLIB_CLI_COMMAND (int_fwd_cli, static) = {
     532             :   .path = "set interface l2 forward",
     533             :   .short_help = "set interface l2 forward <interface> [disable]",
     534             :   .function = int_fwd,
     535             : };
     536             : /* *INDENT-ON* */
     537             : 
     538             : #endif
     539             : 
     540             : /*
     541             :  * fd.io coding-style-patch-verification: ON
     542             :  *
     543             :  * Local Variables:
     544             :  * eval: (c-set-style "gnu")
     545             :  * End:
     546             :  */

Generated by: LCOV version 1.14