LCOV - code coverage report
Current view: top level - vnet/ethernet - p2p_ethernet.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 83 122 68.0 %
Date: 2023-10-26 01:39:38 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /*
       2             :  * p2p_ethernet.c: p2p ethernet
       3             :  *
       4             :  * Copyright (c) 2012 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 <vppinfra/bihash_16_8.h>
      19             : #include <vnet/vnet.h>
      20             : #include <vnet/ethernet/p2p_ethernet.h>
      21             : #include <vnet/l2/l2_input.h>
      22             : 
      23             : p2p_ethernet_main_t p2p_main;
      24             : 
      25             : static void
      26        4204 : create_p2pe_key (p2p_key_t * p2pe_key, u32 parent_if_index, u8 * client_mac)
      27             : {
      28        4204 :   clib_memcpy (p2pe_key->mac, client_mac, 6);
      29        4204 :   p2pe_key->pad1 = 0;
      30        4204 :   p2pe_key->hw_if_index = parent_if_index;
      31        4204 :   p2pe_key->pad2 = 0;
      32        4204 : }
      33             : 
      34             : u32
      35        3160 : p2p_ethernet_lookup (u32 parent_if_index, u8 * client_mac)
      36             : {
      37        3160 :   p2p_ethernet_main_t *p2pm = &p2p_main;
      38             :   p2p_key_t p2pe_key;
      39             :   uword *p;
      40             : 
      41        3160 :   create_p2pe_key (&p2pe_key, parent_if_index, client_mac);
      42        3160 :   p = hash_get_mem (p2pm->p2p_ethernet_by_key, &p2pe_key);
      43        3160 :   if (p)
      44        1107 :     return p[0];
      45             : 
      46        2053 :   return ~0;
      47             : }
      48             : 
      49             : int
      50        1044 : p2p_ethernet_add_del (vlib_main_t * vm, u32 parent_if_index,
      51             :                       u8 * client_mac, u32 p2pe_subif_id, int is_add,
      52             :                       u32 * p2pe_if_index)
      53             : {
      54        1044 :   vnet_main_t *vnm = vnet_get_main ();
      55        1044 :   p2p_ethernet_main_t *p2pm = &p2p_main;
      56        1044 :   vnet_interface_main_t *im = &vnm->interface_main;
      57             : 
      58        1044 :   u32 p2pe_sw_if_index = ~0;
      59        1044 :   p2pe_sw_if_index = p2p_ethernet_lookup (parent_if_index, client_mac);
      60             : 
      61        1044 :   if (p2pe_if_index)
      62        1023 :     *p2pe_if_index = ~0;
      63             : 
      64        1044 :   if (is_add)
      65             :     {
      66        1023 :       if (p2pe_sw_if_index == ~0)
      67             :         {
      68             :           vnet_hw_interface_t *hi;
      69             : 
      70        1023 :           hi = vnet_get_hw_interface (vnm, parent_if_index);
      71        1023 :           if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
      72           0 :             return VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED;
      73             : 
      74        1023 :           u64 sup_and_sub_key =
      75        1023 :             ((u64) (hi->sw_if_index) << 32) | (u64) p2pe_subif_id;
      76             :           uword *p;
      77        1023 :           p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
      78        1023 :           if (p)
      79             :             {
      80             :               if (CLIB_DEBUG > 0)
      81           0 :                 clib_warning
      82             :                   ("p2p ethernet sub-interface on sw_if_index %d with sub id %d already exists\n",
      83             :                    hi->sw_if_index, p2pe_subif_id);
      84           0 :               return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
      85             :             }
      86        1023 :           vnet_sw_interface_t template = {
      87             :             .type = VNET_SW_INTERFACE_TYPE_P2P,
      88             :             .flood_class = VNET_FLOOD_CLASS_NORMAL,
      89        1023 :             .sup_sw_if_index = hi->sw_if_index,
      90             :             .sub.id = p2pe_subif_id
      91             :           };
      92             : 
      93        1023 :           clib_memcpy (template.p2p.client_mac, client_mac,
      94             :                        sizeof (template.p2p.client_mac));
      95             : 
      96        1023 :           if (vnet_create_sw_interface (vnm, &template, &p2pe_sw_if_index))
      97           0 :             return VNET_API_ERROR_SUBIF_CREATE_FAILED;
      98             : 
      99             :           /* Allocate counters for this interface. */
     100             :           {
     101             :             u32 i;
     102             : 
     103        1023 :             vnet_interface_counter_lock (im);
     104             : 
     105       10230 :             for (i = 0; i < vec_len (im->sw_if_counters); i++)
     106             :               {
     107        9207 :                 vlib_validate_simple_counter (&im->sw_if_counters[i],
     108             :                                               p2pe_sw_if_index);
     109        9207 :                 vlib_zero_simple_counter (&im->sw_if_counters[i],
     110             :                                           p2pe_sw_if_index);
     111             :               }
     112             : 
     113        9207 :             for (i = 0; i < vec_len (im->combined_sw_if_counters); i++)
     114             :               {
     115        8184 :                 vlib_validate_combined_counter (&im->combined_sw_if_counters
     116        8184 :                                                 [i], p2pe_sw_if_index);
     117        8184 :                 vlib_zero_combined_counter (&im->combined_sw_if_counters[i],
     118             :                                             p2pe_sw_if_index);
     119             :               }
     120             : 
     121        1023 :             vnet_interface_counter_unlock (im);
     122             :           }
     123             : 
     124        1023 :           vnet_interface_main_t *im = &vnm->interface_main;
     125        1023 :           sup_and_sub_key =
     126        1023 :             ((u64) (hi->sw_if_index) << 32) | (u64) p2pe_subif_id;
     127        1023 :           u64 *kp = clib_mem_alloc (sizeof (*kp));
     128             : 
     129        1023 :           *kp = sup_and_sub_key;
     130        1023 :           hash_set (hi->sub_interface_sw_if_index_by_id, p2pe_subif_id,
     131             :                     p2pe_sw_if_index);
     132        2046 :           hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, p2pe_sw_if_index);
     133             : 
     134             :           p2p_key_t *p_p2pe_key;
     135        1023 :           p_p2pe_key = clib_mem_alloc (sizeof (*p_p2pe_key));
     136        1023 :           create_p2pe_key (p_p2pe_key, parent_if_index, client_mac);
     137        2046 :           hash_set_mem (p2pm->p2p_ethernet_by_key, p_p2pe_key,
     138             :                         p2pe_sw_if_index);
     139             : 
     140        1023 :           if (p2pe_if_index)
     141        1023 :             *p2pe_if_index = p2pe_sw_if_index;
     142             : 
     143        1023 :           vec_validate (p2pm->p2p_ethernet_by_sw_if_index, parent_if_index);
     144        1023 :           if (p2pm->p2p_ethernet_by_sw_if_index[parent_if_index] == 0)
     145             :             {
     146          12 :               vnet_feature_enable_disable ("device-input",
     147             :                                            "p2p-ethernet-input",
     148             :                                            parent_if_index, 1, 0, 0);
     149             :               /* Set promiscuous mode on the l2 interface */
     150          12 :               ethernet_set_flags (vnm, parent_if_index,
     151             :                                   ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
     152             : 
     153             :             }
     154        1023 :           p2pm->p2p_ethernet_by_sw_if_index[parent_if_index]++;
     155             :           /* set the interface mode */
     156        1023 :           set_int_l2_mode (vm, vnm, MODE_L3, p2pe_sw_if_index, 0,
     157             :                            L2_BD_PORT_TYPE_NORMAL, 0, 0);
     158        1023 :           return 0;
     159             :         }
     160           0 :       return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
     161             :     }
     162             :   else
     163             :     {
     164          21 :       if (p2pe_sw_if_index == ~0)
     165           0 :         return VNET_API_ERROR_SUBIF_DOESNT_EXIST;
     166             :       else
     167             :         {
     168          21 :           int rv = 0;
     169          21 :           rv = vnet_delete_sub_interface (p2pe_sw_if_index);
     170          21 :           if (!rv)
     171             :             {
     172          21 :               vec_validate (p2pm->p2p_ethernet_by_sw_if_index,
     173             :                             parent_if_index);
     174          21 :               if (p2pm->p2p_ethernet_by_sw_if_index[parent_if_index] == 1)
     175             :                 {
     176          10 :                   vnet_feature_enable_disable ("device-input",
     177             :                                                "p2p-ethernet-input",
     178             :                                                parent_if_index, 0, 0, 0);
     179             :                   /* Disable promiscuous mode on the l2 interface */
     180          10 :                   ethernet_set_flags (vnm, parent_if_index, 0);
     181             :                 }
     182          21 :               p2pm->p2p_ethernet_by_sw_if_index[parent_if_index]--;
     183             : 
     184             :               /* Remove p2p_ethernet from hash map */
     185             :               p2p_key_t *p_p2pe_key;
     186          21 :               p_p2pe_key = clib_mem_alloc (sizeof (*p_p2pe_key));
     187          21 :               create_p2pe_key (p_p2pe_key, parent_if_index, client_mac);
     188          21 :               hash_unset_mem (p2pm->p2p_ethernet_by_key, p_p2pe_key);
     189             :             }
     190          21 :           return rv;
     191             :         }
     192             :     }
     193             : }
     194             : 
     195             : static clib_error_t *
     196           0 : vnet_p2p_ethernet_add_del (vlib_main_t * vm, unformat_input_t * input,
     197             :                            vlib_cli_command_t * cmd)
     198             : {
     199           0 :   vnet_main_t *vnm = vnet_get_main ();
     200             : 
     201           0 :   int is_add = 1;
     202           0 :   int remote_mac = 0;
     203           0 :   u32 hw_if_index = ~0;
     204           0 :   u32 sub_id = ~0;
     205             :   u8 client_mac[6];
     206             : 
     207           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     208             :     {
     209           0 :       if (unformat
     210             :           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
     211             :         ;
     212           0 :       else if (unformat (input, "%U", unformat_ethernet_address, &client_mac))
     213           0 :         remote_mac = 1;
     214           0 :       else if (unformat (input, "sub-id %d", &sub_id))
     215             :         ;
     216           0 :       else if (unformat (input, "del"))
     217           0 :         is_add = 0;
     218             :       else
     219           0 :         break;
     220             :     }
     221             : 
     222           0 :   if (hw_if_index == ~0)
     223           0 :     return clib_error_return (0, "Please specify parent interface ...");
     224           0 :   if (!remote_mac)
     225           0 :     return clib_error_return (0, "Please specify client MAC address ...");
     226           0 :   if (sub_id == ~0 && is_add)
     227           0 :     return clib_error_return (0, "Please specify sub-interface id ...");
     228             : 
     229             :   u32 rv;
     230           0 :   rv = p2p_ethernet_add_del (vm, hw_if_index, client_mac, sub_id, is_add, 0);
     231           0 :   switch (rv)
     232             :     {
     233           0 :     case VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED:
     234           0 :       return clib_error_return (0,
     235             :                                 "not allowed as parent interface belongs to a BondEthernet interface");
     236           0 :     case -1:
     237           0 :       return clib_error_return (0,
     238             :                                 "p2p ethernet for given parent interface and client mac already exists");
     239           0 :     case -2:
     240           0 :       return clib_error_return (0,
     241             :                                 "couldn't create p2p ethernet subinterface");
     242           0 :     case -3:
     243           0 :       return clib_error_return (0,
     244             :                                 "p2p ethernet for given parent interface and client mac doesn't exist");
     245           0 :     default:
     246           0 :       break;
     247             :     }
     248           0 :   return 0;
     249             : }
     250             : 
     251      285289 : VLIB_CLI_COMMAND (p2p_ethernet_add_del_command, static) = {
     252             :   .path = "p2p_ethernet",
     253             :   .function = vnet_p2p_ethernet_add_del,
     254             :   .short_help = "p2p_ethernet <intfc> <mac-address> [sub-id <id>|del]",
     255             : };
     256             : 
     257             : static clib_error_t *
     258         575 : p2p_ethernet_init (vlib_main_t * vm)
     259             : {
     260         575 :   p2p_ethernet_main_t *p2pm = &p2p_main;
     261             : 
     262         575 :   p2pm->vlib_main = vm;
     263         575 :   p2pm->vnet_main = vnet_get_main ();
     264         575 :   p2pm->p2p_ethernet_by_key =
     265         575 :     hash_create_mem (0, sizeof (p2p_key_t), sizeof (uword));
     266             : 
     267         575 :   return 0;
     268             : }
     269             : 
     270       13823 : VLIB_INIT_FUNCTION (p2p_ethernet_init);
     271             : 
     272             : /*
     273             :  * fd.io coding-style-patch-verification: ON
     274             :  *
     275             :  * Local Variables:
     276             :  * eval: (c-set-style "gnu")
     277             :  * End:
     278             :  */

Generated by: LCOV version 1.14