LCOV - code coverage report
Current view: top level - vnet/l2 - l2_bvi.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 45 103 43.7 %
Date: 2023-07-05 22:20:52 Functions: 12 16 75.0 %

          Line data    Source code
       1             : /*
       2             :  * l2_bvi.c : layer 2 Bridged Virtual Interface
       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/l2/l2_fwd.h>
      21             : #include <vnet/l2/l2_flood.h>
      22             : #include <vnet/l2/l2_bvi.h>
      23             : 
      24             : /* Allocated BVI instances */
      25             : static uword *l2_bvi_instances;
      26             : 
      27             : /* Call the L2 nodes that need the ethertype mapping */
      28             : void
      29        3917 : l2bvi_register_input_type (vlib_main_t * vm,
      30             :                            ethernet_type_t type, u32 node_index)
      31             : {
      32        3917 :   l2fwd_register_input_type (vm, type, node_index);
      33        3917 :   l2flood_register_input_type (vm, type, node_index);
      34        3917 : }
      35             : 
      36             : static u8 *
      37          12 : format_bvi_name (u8 * s, va_list * args)
      38             : {
      39          12 :   u32 dev_instance = va_arg (*args, u32);
      40          12 :   return format (s, "bvi%d", dev_instance);
      41             : }
      42             : 
      43             : static clib_error_t *
      44           7 : bvi_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
      45             : {
      46           7 :   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
      47             :     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
      48           7 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
      49           7 :   return 0;
      50             : }
      51             : 
      52             : static clib_error_t *
      53           1 : bvi_mac_change (vnet_hw_interface_t * hi,
      54             :                 const u8 * old_address, const u8 * mac_address)
      55             : {
      56           1 :   l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
      57             : 
      58           1 :   return (NULL);
      59             : }
      60             : 
      61             : /* *INDENT-OFF* */
      62       11199 : VNET_DEVICE_CLASS (bvi_device_class) = {
      63             :   .name = "BVI",
      64             :   .format_device_name = format_bvi_name,
      65             :   .admin_up_down_function = bvi_admin_up_down,
      66             :   .mac_addr_change_function = bvi_mac_change,
      67             : };
      68             : /* *INDENT-ON* */
      69             : 
      70             : /*
      71             :  * Maintain a bitmap of allocated bvi instance numbers.
      72             :  */
      73             : #define BVI_MAX_INSTANCE                (16 * 1024)
      74             : 
      75             : static u32
      76           4 : bvi_instance_alloc (u32 want)
      77             : {
      78             :   /*
      79             :    * Check for dynamically allocated instance number.
      80             :    */
      81           4 :   if (~0 == want)
      82             :     {
      83             :       u32 bit;
      84             : 
      85           4 :       bit = clib_bitmap_first_clear (l2_bvi_instances);
      86           4 :       if (bit >= BVI_MAX_INSTANCE)
      87             :         {
      88           0 :           return ~0;
      89             :         }
      90           4 :       l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, bit, 1);
      91           4 :       return bit;
      92             :     }
      93             : 
      94             :   /*
      95             :    * In range?
      96             :    */
      97           0 :   if (want >= BVI_MAX_INSTANCE)
      98             :     {
      99           0 :       return ~0;
     100             :     }
     101             : 
     102             :   /*
     103             :    * Already in use?
     104             :    */
     105           0 :   if (clib_bitmap_get (l2_bvi_instances, want))
     106             :     {
     107           0 :       return ~0;
     108             :     }
     109             : 
     110             :   /*
     111             :    * Grant allocation request.
     112             :    */
     113           0 :   l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, want, 1);
     114             : 
     115           0 :   return want;
     116             : }
     117             : 
     118             : static int
     119           0 : bvi_instance_free (u32 instance)
     120             : {
     121           0 :   if (instance >= BVI_MAX_INSTANCE)
     122             :     {
     123           0 :       return -1;
     124             :     }
     125             : 
     126           0 :   if (clib_bitmap_get (l2_bvi_instances, instance) == 0)
     127             :     {
     128           0 :       return -1;
     129             :     }
     130             : 
     131           0 :   l2_bvi_instances = clib_bitmap_set (l2_bvi_instances, instance, 0);
     132           0 :   return 0;
     133             : }
     134             : 
     135             : int
     136           4 : l2_bvi_create (u32 user_instance,
     137             :                const mac_address_t * mac_in, u32 * sw_if_indexp)
     138             : {
     139           4 :   vnet_main_t *vnm = vnet_get_main ();
     140           4 :   vlib_main_t *vm = vlib_get_main ();
     141           4 :   vnet_eth_interface_registration_t eir = {};
     142             :   u32 instance, hw_if_index, slot;
     143             :   vnet_hw_interface_t *hw_if;
     144             :   mac_address_t mac;
     145             : 
     146           4 :   ASSERT (sw_if_indexp);
     147             : 
     148           4 :   *sw_if_indexp = (u32) ~ 0;
     149             : 
     150             :   /*
     151             :    * Allocate a bvi instance.  Either select on dynamically
     152             :    * or try to use the desired user_instance number.
     153             :    */
     154           4 :   instance = bvi_instance_alloc (user_instance);
     155           4 :   if (instance == ~0)
     156             :     {
     157           0 :       return VNET_API_ERROR_INVALID_REGISTRATION;
     158             :     }
     159             : 
     160             :   /*
     161             :    * Default MAC address (b0b0:0000:0000 + instance) is allocated
     162             :    * if zero mac_address is configured. Otherwise, user-configurable MAC
     163             :    * address is programmed on the bvi interface.
     164             :    */
     165           4 :   if (mac_address_is_zero (mac_in))
     166             :     {
     167           4 :       u8 bytes[6] = {
     168             :         [0] = 0xb0,
     169             :         [1] = 0xb0,
     170             :         [5] = instance,
     171             :       };
     172           4 :       mac_address_from_bytes (&mac, bytes);
     173             :     }
     174             :   else
     175             :     {
     176           0 :       mac_address_copy (&mac, mac_in);
     177             :     }
     178             : 
     179           4 :   eir.dev_class_index = bvi_device_class.index;
     180           4 :   eir.dev_instance = instance;
     181           4 :   eir.address = mac.bytes;
     182           4 :   hw_if_index = vnet_eth_register_interface (vnm, &eir);
     183             : 
     184           4 :   hw_if = vnet_get_hw_interface (vnm, hw_if_index);
     185             : 
     186           4 :   slot = vlib_node_add_named_next_with_slot (vm, hw_if->tx_node_index,
     187             :                                              "l2-input", 0);
     188           4 :   ASSERT (slot == 0);
     189             : 
     190             :   {
     191           4 :     vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
     192           4 :     *sw_if_indexp = si->sw_if_index;
     193             : 
     194           4 :     si->flood_class = VNET_FLOOD_CLASS_BVI;
     195             :   }
     196             : 
     197           4 :   return 0;
     198             : }
     199             : 
     200             : int
     201           0 : l2_bvi_delete (u32 sw_if_index)
     202             : {
     203           0 :   vnet_main_t *vnm = vnet_get_main ();
     204             : 
     205           0 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
     206           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     207             : 
     208           0 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
     209           0 :   if (hw == 0 || hw->dev_class_index != bvi_device_class.index)
     210           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     211             : 
     212           0 :   if (bvi_instance_free (hw->dev_instance) < 0)
     213           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     214             : 
     215           0 :   ethernet_delete_interface (vnm, hw->hw_if_index);
     216             : 
     217           0 :   return 0;
     218             : }
     219             : 
     220             : static clib_error_t *
     221           0 : l2_bvi_create_cli (vlib_main_t * vm,
     222             :                    unformat_input_t * input, vlib_cli_command_t * cmd)
     223             : {
     224           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     225             :   u32 instance, sw_if_index;
     226             :   clib_error_t *error;
     227             :   mac_address_t mac;
     228             :   int rv;
     229             : 
     230           0 :   error = NULL;
     231           0 :   instance = sw_if_index = ~0;
     232           0 :   mac_address_set_zero (&mac);
     233             : 
     234           0 :   if (unformat_user (input, unformat_line_input, line_input))
     235             :     {
     236           0 :       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     237             :         {
     238           0 :           if (unformat (line_input, "mac %U", unformat_mac_address_t, &mac))
     239             :             ;
     240           0 :           else if (unformat (line_input, "instance %d", &instance))
     241             :             ;
     242             :           else
     243             :             {
     244           0 :               error = clib_error_return (0, "unknown input: %U",
     245             :                                          format_unformat_error, line_input);
     246           0 :               break;
     247             :             }
     248             :         }
     249             : 
     250           0 :       unformat_free (line_input);
     251             : 
     252           0 :       if (error)
     253           0 :         return error;
     254             :     }
     255             : 
     256           0 :   rv = l2_bvi_create (instance, &mac, &sw_if_index);
     257             : 
     258           0 :   if (rv)
     259           0 :     return clib_error_return (0, "BVI create failed");
     260             : 
     261           0 :   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
     262             :                    sw_if_index);
     263           0 :   return 0;
     264             : }
     265             : 
     266             : /*?
     267             :  * Create a BVI interface. Optionally, a MAC Address can be
     268             :  * provided. If not provided, 0b:0b::00:00:00:<instance> will be used.
     269             :  *
     270             :  * @cliexpar
     271             :  * The following two command syntaxes are equivalent:
     272             :  * @cliexcmd{bvi create [mac <mac-addr>] [instance <instance>]}
     273             :  * Example of how to create a bvi interface:
     274             :  * @cliexcmd{bvi create}
     275             : ?*/
     276             : /* *INDENT-OFF* */
     277      272887 : VLIB_CLI_COMMAND (l2_bvi_create_command, static) = {
     278             :   .path = "bvi create",
     279             :   .short_help = "bvi create [mac <mac-addr>] [instance <instance>]",
     280             :   .function = l2_bvi_create_cli,
     281             : };
     282             : /* *INDENT-ON* */
     283             : 
     284             : static clib_error_t *
     285           0 : l2_bvi_delete_cli (vlib_main_t * vm,
     286             :                    unformat_input_t * input, vlib_cli_command_t * cmd)
     287             : {
     288             :   vnet_main_t *vnm;
     289             :   u32 sw_if_index;
     290             :   int rv;
     291             : 
     292           0 :   vnm = vnet_get_main ();
     293           0 :   sw_if_index = ~0;
     294             : 
     295           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     296             :     {
     297           0 :       if (unformat
     298             :           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
     299             :         ;
     300             :       else
     301           0 :         break;
     302             :     }
     303             : 
     304           0 :   if (~0 != sw_if_index)
     305             :     {
     306           0 :       rv = l2_bvi_delete (sw_if_index);
     307             : 
     308           0 :       if (rv)
     309           0 :         return clib_error_return (0, "BVI delete failed");
     310             :     }
     311             :   else
     312           0 :     return clib_error_return (0, "no such interface: %U",
     313             :                               format_unformat_error, input);
     314             : 
     315           0 :   return 0;
     316             : }
     317             : 
     318             : /*?
     319             :  * Delete a BVI interface.
     320             :  *
     321             :  * @cliexpar
     322             :  * The following two command syntaxes are equivalent:
     323             :  * @cliexcmd{bvi delete <interface>}
     324             :  * Example of how to create a bvi interface:
     325             :  * @cliexcmd{bvi delete bvi0}
     326             : ?*/
     327             : /* *INDENT-OFF* */
     328      272887 : VLIB_CLI_COMMAND (l2_bvi_delete_command, static) = {
     329             :   .path = "bvi delete",
     330             :   .short_help = "bvi delete <interface>",
     331             :   .function = l2_bvi_delete_cli,
     332             : };
     333             : /* *INDENT-ON* */
     334             : 
     335             : 
     336             : /*
     337             :  * fd.io coding-style-patch-verification: ON
     338             :  *
     339             :  * Local Variables:
     340             :  * eval: (c-set-style "gnu")
     341             :  * End:
     342             :  */

Generated by: LCOV version 1.14