LCOV - code coverage report
Current view: top level - vnet/l2 - l2_input.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 176 280 62.9 %
Date: 2023-10-26 01:39:38 Functions: 27 32 84.4 %

          Line data    Source code
       1             : /*
       2             :  * l2_input.c : layer 2 input packet processing
       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 <vnet/ethernet/packet.h>
      22             : #include <vnet/ip/ip_packet.h>
      23             : #include <vnet/ip/ip4_packet.h>
      24             : #include <vnet/ip/ip6_packet.h>
      25             : #include <vnet/fib/fib_node.h>
      26             : #include <vnet/ethernet/arp_packet.h>
      27             : #include <vlib/cli.h>
      28             : #include <vnet/l2/l2_input.h>
      29             : #include <vnet/l2/l2_output.h>
      30             : #include <vnet/l2/feat_bitmap.h>
      31             : #include <vnet/l2/l2_bvi.h>
      32             : #include <vnet/l2/l2_fib.h>
      33             : #include <vnet/l2/l2_bd.h>
      34             : 
      35             : #include <vppinfra/error.h>
      36             : #include <vppinfra/hash.h>
      37             : #include <vppinfra/cache.h>
      38             : 
      39             : /**
      40             :  * @file
      41             :  * @brief Interface Input Mode (Layer 2 Cross-Connect or Bridge / Layer 3).
      42             :  *
      43             :  * This file contains the CLI Commands that modify the input mode of an
      44             :  * interface. For interfaces in a Layer 2 cross-connect, all packets
      45             :  * received on one interface will be transmitted to the other. For
      46             :  * interfaces in a bridge-domain, packets will be forwarded to other
      47             :  * interfaces in the same bridge-domain based on destination mac address.
      48             :  * For interfaces in Layer 3 mode, the packets will be routed.
      49             :  */
      50             : 
      51             : /* Feature graph node names */
      52             : static char *l2input_feat_names[] = {
      53             : #define _(sym,name) name,
      54             :   foreach_l2input_feat
      55             : #undef _
      56             : };
      57             : 
      58             : char **
      59        9200 : l2input_get_feat_names (void)
      60             : {
      61        9200 :   return l2input_feat_names;
      62             : }
      63             : 
      64             : u8 *
      65       11466 : format_l2_input_feature_bitmap (u8 * s, va_list * args)
      66             : {
      67             :   static char *display_names[] = {
      68             : #define _(sym,name) #sym,
      69             :     foreach_l2input_feat
      70             : #undef _
      71             :   };
      72       11466 :   u32 feature_bitmap = va_arg (*args, u32);
      73       11466 :   u32 verbose = va_arg (*args, u32);
      74             : 
      75       11466 :   if (feature_bitmap == 0)
      76             :     {
      77          43 :       s = format (s, "  none configured");
      78          43 :       return s;
      79             :     }
      80             : 
      81       11423 :   feature_bitmap &= ~L2INPUT_FEAT_DROP;     /* Not a feature */
      82             :   int i;
      83      217037 :   for (i = L2INPUT_N_FEAT - 1; i >= 0; i--)
      84             :     {
      85      205614 :       if (feature_bitmap & (1 << i))
      86             :         {
      87       38481 :           if (verbose)
      88        3068 :             s = format (s, "%17s (%s)\n",
      89             :                         display_names[i], l2input_feat_names[i]);
      90             :           else
      91       35413 :             s = format (s, "%s ", l2input_feat_names[i]);
      92             :         }
      93             :     }
      94       11423 :   return s;
      95             : }
      96             : 
      97             : u8 *
      98           3 : format_l2_input_features (u8 * s, va_list * args)
      99             : {
     100           3 :   u32 sw_if_index = va_arg (*args, u32);
     101           3 :   u32 verbose = va_arg (*args, u32);
     102             : 
     103           3 :   l2_input_config_t *l2_input = l2input_intf_config (sw_if_index);
     104           3 :   u32 fb = l2_input->feature_bitmap;
     105             : 
     106             :   /* intf input features are masked by bridge domain */
     107           3 :   if (l2_input_is_bridge (l2_input))
     108           0 :     fb &= l2_input->bd_feature_bitmap;
     109             : 
     110             :   s =
     111           3 :     format (s, "\nl2-input:\n%U", format_l2_input_feature_bitmap, fb,
     112             :             verbose);
     113             : 
     114           3 :   return (s);
     115             : }
     116             : 
     117             : u8 *
     118        4111 : format_l2_input (u8 * s, va_list * args)
     119             : {
     120        4111 :   u32 sw_if_index = va_arg (*args, u32);
     121        4111 :   l2_input_config_t *l2_input = l2input_intf_config (sw_if_index);
     122             : 
     123             :   /* intf input features are masked by bridge domain */
     124        4111 :   if (l2_input_is_bridge (l2_input))
     125             :     {
     126         310 :       bd_main_t *bdm = &bd_main;
     127         310 :       u32 bd_id = l2input_main.bd_configs[l2_input->bd_index].bd_id;
     128             : 
     129         620 :       s = format (s, "  L2 bridge bd-id %d idx %d shg %d %s",
     130         310 :                   bd_id, bd_find_index (bdm, bd_id), l2_input->shg,
     131         310 :                   l2_input_is_bvi (l2_input) ? "bvi" : " ");
     132             :     }
     133        3801 :   else if (l2_input_is_xconnect (l2_input))
     134           0 :     s = format (s, "  L2 xconnect %U",
     135             :                 format_vnet_sw_if_index_name, vnet_get_main (),
     136             :                 l2_input->output_sw_if_index);
     137             : 
     138        4111 :   return (s);
     139             : }
     140             : 
     141             : clib_error_t *
     142         575 : l2input_init (vlib_main_t * vm)
     143             : {
     144         575 :   l2input_main_t *mp = &l2input_main;
     145             : 
     146         575 :   mp->vlib_main = vm;
     147         575 :   mp->vnet_main = vnet_get_main ();
     148             : 
     149             :   /* Get packets RX'd from L2 interfaces */
     150         575 :   ethernet_register_l2_input (vm, l2input_node.index);
     151             : 
     152             :   /* Initialize the feature next-node indexes */
     153         575 :   feat_bitmap_init_next_nodes (vm,
     154             :                                l2input_node.index,
     155             :                                L2INPUT_N_FEAT,
     156             :                                l2input_get_feat_names (),
     157         575 :                                mp->feat_next_node_index);
     158             : 
     159         575 :   return 0;
     160             : }
     161             : 
     162       19583 : VLIB_INIT_FUNCTION (l2input_init);
     163             : 
     164             : 
     165             : /** Get a pointer to the config for the given interface. */
     166             : l2_input_config_t *
     167       31467 : l2input_intf_config (u32 sw_if_index)
     168             : {
     169       31467 :   l2input_main_t *mp = &l2input_main;
     170             : 
     171       31467 :   vec_validate (mp->configs, sw_if_index);
     172       31467 :   return vec_elt_at_index (mp->configs, sw_if_index);
     173             : }
     174             : 
     175             : /** Enable (or disable) the feature in the bitmap for the given interface. */
     176             : u32
     177        1167 : l2input_intf_bitmap_enable (u32 sw_if_index,
     178             :                             l2input_feat_masks_t feature_bitmap, u32 enable)
     179             : {
     180        1167 :   l2_input_config_t *config = l2input_intf_config (sw_if_index);
     181             : 
     182        1167 :   if (enable)
     183         775 :     config->feature_bitmap |= feature_bitmap;
     184             :   else
     185         392 :     config->feature_bitmap &= ~feature_bitmap;
     186             : 
     187        1167 :   return config->feature_bitmap;
     188             : }
     189             : 
     190             : u32
     191           0 : l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value)
     192             : {
     193           0 :   l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);;
     194           0 :   bd_validate (bd_config);
     195           0 :   bd_config->feature_bitmap =
     196           0 :     (bd_config->feature_bitmap & ~feat_mask) | feat_value;
     197           0 :   return bd_config->feature_bitmap;
     198             : }
     199             : 
     200             : void
     201           1 : l2input_interface_mac_change (u32 sw_if_index,
     202             :                               const u8 * old_address, const u8 * new_address)
     203             : {
     204             :   /* check if the sw_if_index passed is a BVI in a BD */
     205             :   l2_input_config_t *intf_config;
     206             : 
     207           1 :   intf_config = l2input_intf_config (sw_if_index);
     208             : 
     209           1 :   if (l2_input_is_bridge (intf_config) && l2_input_is_bvi (intf_config))
     210             :     {
     211             :       /* delete and re-add l2fib entry for the bvi interface */
     212           1 :       l2fib_del_entry (old_address, intf_config->bd_index, sw_if_index);
     213           1 :       l2fib_add_entry (new_address,
     214           1 :                        intf_config->bd_index,
     215             :                        sw_if_index,
     216             :                        L2FIB_ENTRY_RESULT_FLAG_BVI |
     217             :                        L2FIB_ENTRY_RESULT_FLAG_STATIC);
     218             :     }
     219           1 : }
     220             : 
     221             : walk_rc_t
     222        8979 : l2input_recache (u32 bd_index, u32 sw_if_index)
     223             : {
     224             :   l2_input_config_t *input;
     225             :   l2_bridge_domain_t *bd;
     226             : 
     227        8979 :   bd = bd_get (bd_index);
     228        8979 :   input = l2input_intf_config (sw_if_index);
     229             : 
     230        8979 :   input->bd_mac_age = bd->mac_age;
     231        8979 :   input->bd_seq_num = bd->seq_num;
     232        8979 :   input->bd_feature_bitmap = bd->feature_bitmap;
     233             : 
     234        8979 :   return (WALK_CONTINUE);
     235             : }
     236             : 
     237             : void
     238        3288 : l2_input_seq_num_inc (u32 sw_if_index)
     239             : {
     240             :   l2_input_config_t *input;
     241             : 
     242        3288 :   input = vec_elt_at_index (l2input_main.configs, sw_if_index);
     243             : 
     244        3288 :   input->seq_num++;
     245        3288 : }
     246             : 
     247             : /**
     248             :  * Set the subinterface to run in l2 or l3 mode.
     249             :  * For L3 mode, just the sw_if_index is specified.
     250             :  * For bridged mode, the bd id and bvi flag are also specified.
     251             :  * For xconnect mode, the peer sw_if_index is also specified.
     252             :  * Return 0 if ok, or non-0 if there was an error.
     253             :  */
     254             : 
     255             : u32
     256        3553 : set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main,     /*           */
     257             :                  u32 mode,      /* One of L2 modes or back to L3 mode        */
     258             :                  u32 sw_if_index,       /* sw interface index                */
     259             :                  u32 bd_index,  /* for bridged interface                     */
     260             :                  l2_bd_port_type_t port_type,   /* port_type */
     261             :                  u32 shg,       /* the bridged interface split horizon group */
     262             :                  u32 xc_sw_if_index)    /* peer interface for xconnect       */
     263             : {
     264        3553 :   l2output_main_t *l2om = &l2output_main;
     265        3553 :   vnet_main_t *vnm = vnet_get_main ();
     266             :   vnet_hw_interface_t *hi;
     267             :   l2_output_config_t *out_config;
     268             :   l2_input_config_t *config;
     269             :   l2_bridge_domain_t *bd_config;
     270        3553 :   i32 l2_if_adjust = 0;
     271             :   vnet_device_class_t *dev_class;
     272             : 
     273        3553 :   hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index);
     274        3553 :   config = l2input_intf_config (sw_if_index);
     275             : 
     276        3553 :   if (l2fib_main.mac_table_initialized == 0)
     277          37 :     l2fib_table_init ();
     278             : 
     279        3553 :   if (l2_input_is_bridge (config))
     280             :     {
     281             :       /* Interface is already in bridge mode. Undo the existing config. */
     282        1136 :       bd_config = bd_get (config->bd_index);
     283             : 
     284             :       /* remove interface from flood vector */
     285        1136 :       bd_remove_member (bd_config, sw_if_index);
     286             : 
     287             :       /* undo any BVI-related config */
     288        1136 :       if (bd_config->bvi_sw_if_index == sw_if_index)
     289             :         {
     290             :           vnet_sw_interface_t *si;
     291             : 
     292           2 :           bd_config->bvi_sw_if_index = ~0;
     293           2 :           config->flags &= ~L2_INPUT_FLAG_BVI;
     294             : 
     295             :           /* delete the l2fib entry for the bvi interface */
     296           2 :           l2fib_del_entry (hi->hw_address, config->bd_index, sw_if_index);
     297             : 
     298             :           /* since this is a no longer BVI interface do not to flood to it */
     299           2 :           si = vnet_get_sw_interface (vnm, sw_if_index);
     300           2 :           si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
     301             :         }
     302        1136 :       if (bd_config->uu_fwd_sw_if_index == sw_if_index)
     303             :         {
     304           2 :           bd_config->uu_fwd_sw_if_index = ~0;
     305           2 :           bd_config->feature_bitmap &= ~L2INPUT_FEAT_UU_FWD;
     306             :         }
     307             : 
     308             :       /* Clear MACs learned on the interface */
     309        1136 :       if ((config->feature_bitmap & L2INPUT_FEAT_LEARN) ||
     310           2 :           (bd_config->feature_bitmap & L2INPUT_FEAT_LEARN))
     311        1136 :         l2fib_flush_int_mac (vm, sw_if_index);
     312             : 
     313        1136 :       bd_input_walk (config->bd_index, l2input_recache, NULL);
     314        1136 :       l2_if_adjust--;
     315             :     }
     316        2417 :   else if (l2_input_is_xconnect (config))
     317             :     {
     318          40 :       l2_if_adjust--;
     319             :     }
     320             : 
     321             :   /* Make sure vector is big enough */
     322        4595 :   vec_validate_init_empty (l2om->output_node_index_vec, sw_if_index,
     323             :                            L2OUTPUT_NEXT_DROP);
     324             : 
     325             :   /* Initialize the l2-input configuration for the interface */
     326        3553 :   if (mode == MODE_L3)
     327             :     {
     328             :       /* Set L2 config to BD index 0 so that if any packet accidentally
     329             :        * came in on L2 path, it will be dropped in BD 0 */
     330        2249 :       config->flags = L2_INPUT_FLAG_NONE;
     331        2249 :       config->shg = 0;
     332        2249 :       config->bd_index = 0;
     333        2249 :       config->feature_bitmap = L2INPUT_FEAT_DROP;
     334             : 
     335             :       /* Clear L2 output config */
     336        2249 :       out_config = l2output_intf_config (sw_if_index);
     337        2249 :       clib_memset (out_config, 0, sizeof (l2_output_config_t));
     338             : 
     339             :       /* Make sure any L2-output packet to this interface now in L3 mode is
     340             :        * dropped. This may happen if L2 FIB MAC entry is stale */
     341        2249 :       l2om->output_node_index_vec[sw_if_index] = L2OUTPUT_NEXT_BAD_INTF;
     342             :     }
     343             :   else
     344             :     {
     345             :       /* Add or update l2-output node next-arc and output_node_index_vec table
     346             :        * for the interface */
     347        1304 :       l2output_create_output_node_mapping (vm, vnet_main, sw_if_index);
     348             : 
     349        1304 :       if (mode == MODE_L2_BRIDGE)
     350             :         {
     351             :           u8 member_flags;
     352             : 
     353             :           /*
     354             :            * Remove a check that the interface must be an Ethernet.
     355             :            * Specifically so we can bridge to L3 tunnel interfaces.
     356             :            * Here's the check:
     357             :            * if (hi->hw_class_index != ethernet_hw_interface_class.index)
     358             :            *
     359             :            */
     360        1256 :           if (!hi)
     361           0 :             return MODE_ERROR_ETH;      /* non-ethernet */
     362             : 
     363        1256 :           config->flags = L2_INPUT_FLAG_BRIDGE;
     364        1256 :           config->bd_index = bd_index;
     365        1256 :           l2_input_seq_num_inc (sw_if_index);
     366             : 
     367             :           /*
     368             :            * Enable forwarding, flooding, learning and ARP termination by default
     369             :            * (note that ARP term is disabled on BD feature bitmap by default)
     370             :            */
     371        1256 :           config->feature_bitmap |= (L2INPUT_FEAT_FWD |
     372             :                                      L2INPUT_FEAT_UU_FLOOD |
     373             :                                      L2INPUT_FEAT_UU_FWD |
     374             :                                      L2INPUT_FEAT_FLOOD |
     375             :                                      L2INPUT_FEAT_LEARN |
     376             :                                      L2INPUT_FEAT_ARP_UFWD |
     377             :                                      L2INPUT_FEAT_ARP_TERM);
     378             : 
     379             :           /* Make sure last-chance drop is configured */
     380        1256 :           config->feature_bitmap |= L2INPUT_FEAT_DROP;
     381             : 
     382             :           /* Make sure xconnect is disabled */
     383        1256 :           config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT;
     384             : 
     385             :           /* Set up bridge domain */
     386        1256 :           bd_config = l2input_bd_config (bd_index);
     387        1256 :           bd_validate (bd_config);
     388             : 
     389             :           /* TODO: think: add l2fib entry even for non-bvi interface? */
     390             : 
     391             :           /* Do BVI interface initializations */
     392        1256 :           if (L2_BD_PORT_TYPE_BVI == port_type)
     393             :             {
     394             :               vnet_sw_interface_t *si;
     395             : 
     396             :               /* ensure BD has no bvi interface (or replace that one with this??) */
     397          11 :               if (bd_config->bvi_sw_if_index != ~0)
     398             :                 {
     399           0 :                   return MODE_ERROR_BVI_DEF;    /* bd already has a bvi interface */
     400             :                 }
     401          11 :               bd_config->bvi_sw_if_index = sw_if_index;
     402          11 :               config->flags |= L2_INPUT_FLAG_BVI;
     403             : 
     404             :               /* create the l2fib entry for the bvi interface */
     405          11 :               l2fib_add_entry (hi->hw_address, bd_index, sw_if_index,
     406             :                                L2FIB_ENTRY_RESULT_FLAG_BVI |
     407             :                                L2FIB_ENTRY_RESULT_FLAG_STATIC);
     408             : 
     409             :               /* Disable learning by default. no use since l2fib entry is static. */
     410          11 :               config->feature_bitmap &= ~L2INPUT_FEAT_LEARN;
     411             : 
     412             :               /* since this is a BVI interface we want to flood to it */
     413          11 :               si = vnet_get_sw_interface (vnm, sw_if_index);
     414          11 :               si->flood_class = VNET_FLOOD_CLASS_BVI;
     415          11 :               member_flags = L2_FLOOD_MEMBER_BVI;
     416             :             }
     417        1245 :           else if (L2_BD_PORT_TYPE_UU_FWD == port_type)
     418             :             {
     419           2 :               bd_config->uu_fwd_sw_if_index = sw_if_index;
     420           2 :               bd_config->feature_bitmap |= L2INPUT_FEAT_UU_FWD;
     421             :             }
     422             :           else
     423             :             {
     424        1243 :               member_flags = L2_FLOOD_MEMBER_NORMAL;
     425             :             }
     426             : 
     427        1256 :           if (L2_BD_PORT_TYPE_NORMAL == port_type ||
     428             :               L2_BD_PORT_TYPE_BVI == port_type)
     429             :             {
     430             :               /* Add interface to bridge-domain flood vector */
     431        1254 :               l2_flood_member_t member = {
     432             :                 .sw_if_index = sw_if_index,
     433             :                 .flags = member_flags,
     434             :                 .shg = shg,
     435             :               };
     436        1254 :               bd_add_member (bd_config, &member);
     437             :             }
     438             :         }
     439          48 :       else if (mode == MODE_L2_XC)
     440             :         {
     441          48 :           config->flags = L2_INPUT_FLAG_XCONNECT;
     442          48 :           config->output_sw_if_index = xc_sw_if_index;
     443             : 
     444             :           /* Make sure last-chance drop is configured */
     445          48 :           config->feature_bitmap |= L2INPUT_FEAT_DROP;
     446             : 
     447             :           /* Make sure bridging features are disabled */
     448          48 :           config->feature_bitmap &=
     449             :             ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);
     450             : 
     451          48 :           config->feature_bitmap |= L2INPUT_FEAT_XCONNECT;
     452          48 :           shg = 0;              /* not used in xconnect */
     453             :         }
     454           0 :       else if (mode == MODE_L2_CLASSIFY)
     455             :         {
     456           0 :           config->flags = L2_INPUT_FLAG_XCONNECT;
     457           0 :           config->output_sw_if_index = xc_sw_if_index;
     458             : 
     459             :           /* Make sure last-chance drop is configured */
     460           0 :           config->feature_bitmap |=
     461             :             L2INPUT_FEAT_DROP | L2INPUT_FEAT_INPUT_CLASSIFY;
     462             : 
     463             :           /* Make sure bridging features are disabled */
     464           0 :           config->feature_bitmap &=
     465             :             ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD);
     466           0 :           shg = 0;              /* not used in xconnect */
     467             :         }
     468             : 
     469             :       /* set up split-horizon group and set output feature bit */
     470        1304 :       config->shg = shg;
     471        1304 :       out_config = l2output_intf_config (sw_if_index);
     472        1304 :       out_config->shg = shg;
     473        1304 :       out_config->feature_bitmap |= L2OUTPUT_FEAT_OUTPUT;
     474             : 
     475             :       /*
     476             :        * Test: remove this when non-IP features can be configured.
     477             :        * Enable a non-IP feature to test IP feature masking
     478             :        * config->feature_bitmap |= L2INPUT_FEAT_CTRL_PKT;
     479             :        */
     480             : 
     481        1304 :       l2_if_adjust++;
     482             : 
     483        1304 :       bd_input_walk (bd_index, l2input_recache, NULL);
     484             :     }
     485             : 
     486             :   /* Adjust count of L2 interfaces */
     487        3553 :   hi->l2_if_count += l2_if_adjust;
     488             : 
     489        3553 :   if (hi->hw_class_index == ethernet_hw_interface_class.index)
     490             :     {
     491        3410 :       if ((hi->l2_if_count == 1) && (l2_if_adjust == 1))
     492             :         {
     493             :           /* Just added first L2 interface on this port
     494             :            * Set promiscuous mode on the l2 interface */
     495        1172 :           ethernet_set_flags (vnet_main, hi->hw_if_index,
     496             :                               ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
     497             :         }
     498        2238 :       else if ((hi->l2_if_count == 0) && (l2_if_adjust == -1))
     499             :         {
     500             :           /* Just removed only L2 subinterface on this port
     501             :            * Disable promiscuous mode on the l2 interface */
     502        1096 :           ethernet_set_flags (vnet_main, hi->hw_if_index,
     503             :                               /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);
     504             : 
     505             :         }
     506             :     }
     507             : 
     508             :   /* Set up the L2/L3 flag in the interface parsing tables */
     509        3553 :   ethernet_sw_interface_set_l2_mode (vnm, sw_if_index, (mode != MODE_L3));
     510             : 
     511        3553 :   dev_class = vnet_get_device_class (vnet_main, hi->dev_class_index);
     512        3553 :   if (dev_class->set_l2_mode_function)
     513             :     {
     514           0 :       dev_class->set_l2_mode_function (vnet_main, hi, l2_if_adjust);
     515             :     }
     516             : 
     517        3553 :   return 0;
     518             : }
     519             : 
     520             : static clib_error_t *
     521       11798 : l2_input_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
     522             : {
     523       11798 :   if (!is_add)
     524             :     {
     525        4251 :       vlib_main_t *vm = vlib_get_main ();
     526             :       l2_input_config_t *config;
     527             : 
     528        4251 :       if (sw_if_index < vec_len (l2input_main.configs))
     529             :         {
     530        4175 :           config = vec_elt_at_index (l2input_main.configs, sw_if_index);
     531        4175 :           if (l2_input_is_xconnect (config))
     532           3 :             set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0,
     533             :                              L2_BD_PORT_TYPE_NORMAL, 0, 0);
     534        4175 :           if (l2_input_is_xconnect (config) || l2_input_is_bridge (config))
     535         897 :             set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
     536             :                              L2_BD_PORT_TYPE_NORMAL, 0, 0);
     537             :         }
     538             :     }
     539             : 
     540       11798 :   return (NULL);
     541             : }
     542             : 
     543        3459 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (l2_input_interface_add_del);
     544             : 
     545             : /**
     546             :  * Set subinterface in bridging mode with a bridge-domain ID.
     547             :  * The CLI format is:
     548             :  *   set interface l2 bridge <interface> <bd> [bvi] [split-horizon-group]
     549             :  */
     550             : static clib_error_t *
     551           0 : int_l2_bridge (vlib_main_t * vm,
     552             :                unformat_input_t * input, vlib_cli_command_t * cmd)
     553             : {
     554           0 :   vnet_main_t *vnm = vnet_get_main ();
     555             :   l2_bd_port_type_t port_type;
     556           0 :   clib_error_t *error = 0;
     557             :   u32 bd_index, bd_id;
     558             :   u32 sw_if_index;
     559             :   u32 rc;
     560             :   u32 shg;
     561             : 
     562           0 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     563             :     {
     564           0 :       error = clib_error_return (0, "unknown interface `%U'",
     565             :                                  format_unformat_error, input);
     566           0 :       goto done;
     567             :     }
     568             : 
     569           0 :   if (!unformat (input, "%d", &bd_id))
     570             :     {
     571           0 :       error = clib_error_return (0, "expected bridge domain ID `%U'",
     572             :                                  format_unformat_error, input);
     573           0 :       goto done;
     574             :     }
     575             : 
     576           0 :   if (bd_id > L2_BD_ID_MAX)
     577             :     {
     578           0 :       error = clib_error_return (0, "bridge domain ID exceed 16M limit",
     579             :                                  format_unformat_error, input);
     580           0 :       goto done;
     581             :     }
     582           0 :   bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
     583             : 
     584             :   /* optional bvi  */
     585           0 :   port_type = L2_BD_PORT_TYPE_NORMAL;
     586           0 :   if (unformat (input, "bvi"))
     587           0 :     port_type = L2_BD_PORT_TYPE_BVI;
     588           0 :   if (unformat (input, "uu-fwd"))
     589           0 :     port_type = L2_BD_PORT_TYPE_UU_FWD;
     590             : 
     591             :   /* optional split horizon group */
     592           0 :   shg = 0;
     593           0 :   (void) unformat (input, "%d", &shg);
     594             : 
     595             :   /* set the interface mode */
     596           0 :   if ((rc =
     597           0 :        set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE, sw_if_index, bd_index,
     598             :                         port_type, shg, 0)))
     599             :     {
     600           0 :       if (rc == MODE_ERROR_ETH)
     601             :         {
     602           0 :           error = clib_error_return (0, "bridged interface must be ethernet",
     603             :                                      format_unformat_error, input);
     604             :         }
     605           0 :       else if (rc == MODE_ERROR_BVI_DEF)
     606             :         {
     607             :           error =
     608           0 :             clib_error_return (0, "bridge-domain already has a bvi interface",
     609             :                                format_unformat_error, input);
     610             :         }
     611             :       else
     612             :         {
     613           0 :           error = clib_error_return (0, "invalid configuration for interface",
     614             :                                      format_unformat_error, input);
     615             :         }
     616           0 :       goto done;
     617             :     }
     618             : 
     619           0 : done:
     620           0 :   return error;
     621             : }
     622             : 
     623             : /*?
     624             :  * Use this command put an interface into Layer 2 bridge domain. If a
     625             :  * bridge-domain with the provided bridge-domain-id does not exist, it
     626             :  * will be created. Interfaces in a bridge-domain forward packets to
     627             :  * other interfaces in the same bridge-domain based on destination mac
     628             :  * address. To remove an interface from a the Layer 2 bridge domain,
     629             :  * put the interface in a different mode, for example Layer 3 mode.
     630             :  *
     631             :  * Optionally, an interface can be added to a Layer 2 bridge-domain as
     632             :  * a Bridged Virtual Interface (bvi). Only one interface in a Layer 2
     633             :  * bridge-domain can be a bvi.
     634             :  *
     635             :  * Optionally, a split-horizon group can also be specified. This defaults
     636             :  * to 0 if not specified.
     637             :  *
     638             :  * @cliexpar
     639             :  * Example of how to configure a Layer 2 bridge-domain with three
     640             :  * interfaces (where 200 is the bridge-domain-id):
     641             :  * @cliexcmd{set interface l2 bridge GigabitEthernet0/8/0.200 200}
     642             :  * This interface is added a BVI interface:
     643             :  * @cliexcmd{set interface l2 bridge GigabitEthernet0/9/0.200 200 bvi}
     644             :  * This interface also has a split-horizon group of 1 specified:
     645             :  * @cliexcmd{set interface l2 bridge GigabitEthernet0/a/0.200 200 1}
     646             :  * Example of how to remove an interface from a Layer2 bridge-domain:
     647             :  * @cliexcmd{set interface l3 GigabitEthernet0/a/0.200}
     648             : ?*/
     649             : /* *INDENT-OFF* */
     650      285289 : VLIB_CLI_COMMAND (int_l2_bridge_cli, static) = {
     651             :   .path = "set interface l2 bridge",
     652             :   .short_help = "set interface l2 bridge <interface> <bridge-domain-id> [bvi|uu-fwd] [shg]",
     653             :   .function = int_l2_bridge,
     654             : };
     655             : /* *INDENT-ON* */
     656             : 
     657             : /**
     658             :  * Set subinterface in xconnect mode with another interface.
     659             :  * The CLI format is:
     660             :  *   set interface l2 xconnect <interface> <peer interface>
     661             :  */
     662             : static clib_error_t *
     663           0 : int_l2_xc (vlib_main_t * vm,
     664             :            unformat_input_t * input, vlib_cli_command_t * cmd)
     665             : {
     666           0 :   vnet_main_t *vnm = vnet_get_main ();
     667           0 :   clib_error_t *error = 0;
     668             :   u32 sw_if_index;
     669             :   u32 xc_sw_if_index;
     670             : 
     671           0 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     672             :     {
     673           0 :       error = clib_error_return (0, "unknown interface `%U'",
     674             :                                  format_unformat_error, input);
     675           0 :       goto done;
     676             :     }
     677             : 
     678           0 :   if (!unformat_user
     679             :       (input, unformat_vnet_sw_interface, vnm, &xc_sw_if_index))
     680             :     {
     681           0 :       error = clib_error_return (0, "unknown peer interface `%U'",
     682             :                                  format_unformat_error, input);
     683           0 :       goto done;
     684             :     }
     685             : 
     686             :   /* set the interface mode */
     687           0 :   if (set_int_l2_mode
     688             :       (vm, vnm, MODE_L2_XC, sw_if_index, 0, L2_BD_PORT_TYPE_NORMAL,
     689             :        0, xc_sw_if_index))
     690             :     {
     691           0 :       error = clib_error_return (0, "invalid configuration for interface",
     692             :                                  format_unformat_error, input);
     693           0 :       goto done;
     694             :     }
     695             : 
     696           0 : done:
     697           0 :   return error;
     698             : }
     699             : 
     700             : /*?
     701             :  * Use this command put an interface into Layer 2 cross-connect mode.
     702             :  * Both interfaces must be in this mode for bi-directional traffic. All
     703             :  * packets received on one interface will be transmitted to the other.
     704             :  * To remove the Layer 2 cross-connect, put the interface in a different
     705             :  * mode, for example Layer 3 mode.
     706             :  *
     707             :  * @cliexpar
     708             :  * Example of how to configure a Layer2 cross-connect between two interfaces:
     709             :  * @cliexcmd{set interface l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300}
     710             :  * @cliexcmd{set interface l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300}
     711             :  * Example of how to remove a Layer2 cross-connect:
     712             :  * @cliexcmd{set interface l3 GigabitEthernet0/8/0.300}
     713             :  * @cliexcmd{set interface l3 GigabitEthernet0/9/0.300}
     714             : ?*/
     715             : /* *INDENT-OFF* */
     716      285289 : VLIB_CLI_COMMAND (int_l2_xc_cli, static) = {
     717             :   .path = "set interface l2 xconnect",
     718             :   .short_help = "set interface l2 xconnect <interface> <peer interface>",
     719             :   .function = int_l2_xc,
     720             : };
     721             : /* *INDENT-ON* */
     722             : 
     723             : /**
     724             :  * Set subinterface in L3 mode.
     725             :  * The CLI format is:
     726             :  *   set interface l3 <interface>
     727             :  */
     728             : static clib_error_t *
     729           0 : int_l3 (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
     730             : {
     731           0 :   vnet_main_t *vnm = vnet_get_main ();
     732           0 :   clib_error_t *error = 0;
     733             :   u32 sw_if_index;
     734             : 
     735           0 :   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
     736             :     {
     737           0 :       error = clib_error_return (0, "unknown interface `%U'",
     738             :                                  format_unformat_error, input);
     739           0 :       goto done;
     740             :     }
     741             : 
     742             :   /* set the interface mode */
     743           0 :   if (set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
     744             :                        L2_BD_PORT_TYPE_NORMAL, 0, 0))
     745             :     {
     746           0 :       error = clib_error_return (0, "invalid configuration for interface",
     747             :                                  format_unformat_error, input);
     748           0 :       goto done;
     749             :     }
     750             : 
     751           0 : done:
     752           0 :   return error;
     753             : }
     754             : 
     755             : /*?
     756             :  * Modify the packet processing mode of the interface to Layer 3, which
     757             :  * implies packets will be routed. This is the default mode of an interface.
     758             :  * Use this command to remove an interface from a Layer 2 cross-connect or a
     759             :  * Layer 2 bridge.
     760             :  *
     761             :  * @cliexpar
     762             :  * Example of how to set the mode of an interface to Layer 3:
     763             :  * @cliexcmd{set interface l3 GigabitEthernet0/8/0.200}
     764             : ?*/
     765             : /* *INDENT-OFF* */
     766      285289 :      VLIB_CLI_COMMAND (int_l3_cli, static) = {
     767             :   .path = "set interface l3",
     768             :   .short_help = "set interface l3 <interface>",
     769             :   .function = int_l3,
     770             : };
     771             : /* *INDENT-ON* */
     772             : 
     773             : /**
     774             :  * Show interface mode.
     775             :  * The CLI format is:
     776             :  *    show mode [<if-name1> <if-name2> ...]
     777             :  */
     778             : static clib_error_t *
     779           0 : show_int_mode (vlib_main_t * vm,
     780             :                unformat_input_t * input, vlib_cli_command_t * cmd)
     781             : {
     782           0 :   vnet_main_t *vnm = vnet_get_main ();
     783           0 :   clib_error_t *error = 0;
     784             :   char *mode;
     785             :   u8 *args;
     786           0 :   vnet_interface_main_t *im = &vnm->interface_main;
     787             : 
     788           0 :   vnet_sw_interface_t *si, *sis = 0;
     789           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     790             :     {
     791             :       u32 sw_if_index;
     792             : 
     793             :       /* See if user wants to show specific interface */
     794           0 :       if (unformat
     795             :           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
     796             :         {
     797           0 :           si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
     798           0 :           vec_add1 (sis, si[0]);
     799             :         }
     800             :       else
     801             :         {
     802           0 :           error = clib_error_return (0, "unknown input `%U'",
     803             :                                      format_unformat_error, input);
     804           0 :           goto done;
     805             :         }
     806             :     }
     807             : 
     808           0 :   if (vec_len (sis) == 0)       /* Get all interfaces */
     809             :     {
     810             :       /* Gather interfaces. */
     811           0 :       sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
     812           0 :       vec_set_len (sis, 0);
     813             :       /* *INDENT-OFF* */
     814           0 :       pool_foreach (si, im->sw_interfaces) { vec_add1 (sis, si[0]); }
     815             :       /* *INDENT-ON* */
     816             :     }
     817             : 
     818           0 :   vec_foreach (si, sis)
     819             :   {
     820           0 :     l2_input_config_t *config = l2input_intf_config (si->sw_if_index);
     821           0 :     if (l2_input_is_bridge (config))
     822             :       {
     823             :         u32 bd_id;
     824           0 :         mode = "l2 bridge";
     825           0 :         bd_id = l2input_main.bd_configs[config->bd_index].bd_id;
     826             : 
     827           0 :         args = format (0, "bd_id %d%s shg %d", bd_id,
     828           0 :                        l2_input_is_bvi (config) ? " bvi" : "", config->shg);
     829             :       }
     830           0 :     else if (l2_input_is_xconnect (config))
     831             :       {
     832           0 :         mode = "l2 xconnect";
     833           0 :         args = format (0, "%U",
     834             :                        format_vnet_sw_if_index_name,
     835             :                        vnm, config->output_sw_if_index);
     836             :       }
     837             :     else
     838             :       {
     839           0 :         mode = "l3";
     840           0 :         args = format (0, " ");
     841             :       }
     842           0 :     vlib_cli_output (vm, "%s %U %v\n",
     843             :                      mode,
     844             :                      format_vnet_sw_if_index_name,
     845             :                      vnm, si->sw_if_index, args);
     846           0 :     vec_free (args);
     847             :   }
     848             : 
     849           0 : done:
     850           0 :   vec_free (sis);
     851             : 
     852           0 :   return error;
     853             : }
     854             : 
     855             : /*?
     856             :  * Show the packet processing mode (Layer2 cross-connect, Layer 2 bridge,
     857             :  * Layer 3 routed) of all interfaces and sub-interfaces, or limit the
     858             :  * output to just the provided list of interfaces and sub-interfaces.
     859             :  * The output shows the mode, the interface, and if the interface is
     860             :  * a member of a bridge, the bridge-domain-id and the split horizon group (shg).
     861             :  *
     862             :  * @cliexpar
     863             :  * Example of displaying the mode of all interfaces:
     864             :  * @cliexstart{show mode}
     865             :  * l3 local0
     866             :  * l3 GigabitEthernet0/8/0
     867             :  * l3 GigabitEthernet0/9/0
     868             :  * l3 GigabitEthernet0/a/0
     869             :  * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0
     870             :  * l2 bridge GigabitEthernet0/9/0.200 bd_id 200 shg 0
     871             :  * l2 bridge GigabitEthernet0/a/0.200 bd_id 200 shg 0
     872             :  * l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300
     873             :  * l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300
     874             :  * @cliexend
     875             :  * Example of displaying the mode of a selected list of interfaces:
     876             :  * @cliexstart{show mode GigabitEthernet0/8/0 GigabitEthernet0/8/0.200}
     877             :  * l3 GigabitEthernet0/8/0
     878             :  * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0
     879             :  * @cliexend
     880             : ?*/
     881             : /* *INDENT-OFF* */
     882      285289 : VLIB_CLI_COMMAND (show_l2_mode, static) = {
     883             :   .path = "show mode",
     884             :   .short_help = "show mode [<if-name1> <if-name2> ...]",
     885             :   .function = show_int_mode,
     886             : };
     887             : /* *INDENT-ON* */
     888             : 
     889             : #define foreach_l2_init_function                \
     890             : _(feat_bitmap_drop_init)                        \
     891             : _(l2fib_init)                                   \
     892             : _(l2_input_classify_init)                             \
     893             : _(l2bd_init)                                    \
     894             : _(l2fwd_init)                                   \
     895             : _(l2_in_out_acl_init)                           \
     896             : _(l2input_init)                                 \
     897             : _(l2_vtr_init)                                  \
     898             : _(l2_invtr_init)                                \
     899             : _(l2_efp_filter_init)                           \
     900             : _(l2learn_init)                                 \
     901             : _(l2flood_init)                                 \
     902             : _(l2output_init)                                \
     903             : _(l2_patch_init)                                \
     904             : _(l2_xcrw_init)
     905             : 
     906             : clib_error_t *
     907         575 : l2_init (vlib_main_t * vm)
     908             : {
     909             :   clib_error_t *error;
     910             : 
     911             : #define _(a) do {                                                       \
     912             :   if ((error = vlib_call_init_function (vm, a))) return error; }        \
     913             : while (0);
     914         575 :   foreach_l2_init_function;
     915             : #undef _
     916         575 :   return 0;
     917             : }
     918             : 
     919       11519 : VLIB_INIT_FUNCTION (l2_init);
     920             : 
     921             : /*
     922             :  * fd.io coding-style-patch-verification: ON
     923             :  *
     924             :  * Local Variables:
     925             :  * eval: (c-set-style "gnu")
     926             :  * End:
     927             :  */

Generated by: LCOV version 1.14