LCOV - code coverage report
Current view: top level - vnet/ethernet - interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 365 524 69.7 %
Date: 2023-10-26 01:39:38 Functions: 39 44 88.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /*
      16             :  * ethernet_interface.c: ethernet interfaces
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vnet/vnet.h>
      41             : #include <vnet/ip/ip.h>
      42             : #include <vnet/pg/pg.h>
      43             : #include <vnet/ethernet/ethernet.h>
      44             : //#include <vnet/ethernet/arp.h>
      45             : #include <vnet/l2/l2_input.h>
      46             : #include <vnet/l2/l2_bd.h>
      47             : #include <vnet/adj/adj.h>
      48             : #include <vnet/adj/adj_mcast.h>
      49             : #include <vnet/ip-neighbor/ip_neighbor.h>
      50             : 
      51             : /**
      52             :  * @file
      53             :  * @brief Loopback Interfaces.
      54             :  *
      55             :  * This file contains code to manage loopback interfaces.
      56             :  */
      57             : 
      58             : static const u8 *
      59          44 : ethernet_ip4_mcast_dst_addr (void)
      60             : {
      61             :   const static u8 ethernet_mcast_dst_mac[] = {
      62             :     0x1, 0x0, 0x5e, 0x0, 0x0, 0x0,
      63             :   };
      64             : 
      65          44 :   return (ethernet_mcast_dst_mac);
      66             : }
      67             : 
      68             : static const u8 *
      69        1954 : ethernet_ip6_mcast_dst_addr (void)
      70             : {
      71             :   const static u8 ethernet_mcast_dst_mac[] = {
      72             :     0x33, 0x33, 0x00, 0x0, 0x0, 0x0,
      73             :   };
      74             : 
      75        1954 :   return (ethernet_mcast_dst_mac);
      76             : }
      77             : 
      78             : /**
      79             :  * @brief build a rewrite string to use for sending packets of type 'link_type'
      80             :  * to 'dst_address'
      81             :  */
      82             : u8 *
      83       37858 : ethernet_build_rewrite (vnet_main_t * vnm,
      84             :                         u32 sw_if_index,
      85             :                         vnet_link_t link_type, const void *dst_address)
      86             : {
      87       37858 :   vnet_sw_interface_t *sub_sw = vnet_get_sw_interface (vnm, sw_if_index);
      88       37858 :   vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
      89       37858 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
      90       37858 :   ethernet_main_t *em = &ethernet_main;
      91             :   ethernet_interface_t *ei;
      92             :   ethernet_header_t *h;
      93             :   ethernet_type_t type;
      94       37858 :   uword n_bytes = sizeof (h[0]);
      95       37858 :   u8 *rewrite = NULL;
      96       37858 :   u8 is_p2p = 0;
      97             : 
      98       37858 :   if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
      99       37826 :       (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
     100          34 :     is_p2p = 1;
     101       37858 :   if (sub_sw != sup_sw)
     102             :     {
     103         440 :       if (sub_sw->sub.eth.flags.one_tag)
     104             :         {
     105         306 :           n_bytes += sizeof (ethernet_vlan_header_t);
     106             :         }
     107         134 :       else if (sub_sw->sub.eth.flags.two_tags)
     108             :         {
     109         100 :           n_bytes += 2 * (sizeof (ethernet_vlan_header_t));
     110             :         }
     111          34 :       else if (PREDICT_FALSE (is_p2p))
     112             :         {
     113          34 :           n_bytes = sizeof (ethernet_header_t);
     114             :         }
     115         440 :       if (PREDICT_FALSE (!is_p2p))
     116             :         {
     117             :           // Check for encaps that are not supported for L3 interfaces
     118         406 :           if (!(sub_sw->sub.eth.flags.exact_match) ||
     119         406 :               (sub_sw->sub.eth.flags.default_sub) ||
     120         406 :               (sub_sw->sub.eth.flags.outer_vlan_id_any) ||
     121             :               (sub_sw->sub.eth.flags.inner_vlan_id_any))
     122             :             {
     123           0 :               return 0;
     124             :             }
     125             :         }
     126             :       else
     127             :         {
     128          34 :           n_bytes = sizeof (ethernet_header_t);
     129             :         }
     130             :     }
     131             : 
     132       37858 :   switch (link_type)
     133             :     {
     134             : #define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
     135       10957 :       _(IP4, IP4);
     136       14479 :       _(IP6, IP6);
     137          57 :       _(MPLS, MPLS);
     138       12365 :       _(ARP, ARP);
     139             : #undef _
     140           0 :     default:
     141           0 :       return NULL;
     142             :     }
     143             : 
     144       37858 :   vec_validate (rewrite, n_bytes - 1);
     145       37858 :   h = (ethernet_header_t *) rewrite;
     146       37858 :   ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
     147       37858 :   clib_memcpy (h->src_address, &ei->address, sizeof (h->src_address));
     148       37858 :   if (is_p2p)
     149             :     {
     150          34 :       clib_memcpy (h->dst_address, sub_sw->p2p.client_mac,
     151             :                    sizeof (h->dst_address));
     152             :     }
     153             :   else
     154             :     {
     155       37824 :       if (dst_address)
     156       23575 :         clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
     157             :       else
     158       14249 :         clib_memset (h->dst_address, ~0, sizeof (h->dst_address));        /* broadcast */
     159             :     }
     160             : 
     161       37858 :   if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
     162         306 :     {
     163         306 :       ethernet_vlan_header_t *outer = (void *) (h + 1);
     164             : 
     165         306 :       h->type = sub_sw->sub.eth.flags.dot1ad ?
     166           0 :         clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
     167         306 :         clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     168         306 :       outer->priority_cfi_and_id =
     169         306 :         clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
     170         306 :       outer->type = clib_host_to_net_u16 (type);
     171             : 
     172             :     }
     173       37552 :   else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
     174         100 :     {
     175         100 :       ethernet_vlan_header_t *outer = (void *) (h + 1);
     176         100 :       ethernet_vlan_header_t *inner = (void *) (outer + 1);
     177             : 
     178         100 :       h->type = sub_sw->sub.eth.flags.dot1ad ?
     179         100 :         clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
     180           0 :         clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     181         100 :       outer->priority_cfi_and_id =
     182         100 :         clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
     183         100 :       outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     184         100 :       inner->priority_cfi_and_id =
     185         100 :         clib_host_to_net_u16 (sub_sw->sub.eth.inner_vlan_id);
     186         100 :       inner->type = clib_host_to_net_u16 (type);
     187             : 
     188             :     }
     189             :   else
     190             :     {
     191       37452 :       h->type = clib_host_to_net_u16 (type);
     192             :     }
     193             : 
     194       37858 :   return (rewrite);
     195             : }
     196             : 
     197             : void
     198       20471 : ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
     199             : {
     200       20471 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     201             : 
     202       20471 :   if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
     203       20439 :       (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
     204             :     {
     205          34 :       default_update_adjacency (vnm, sw_if_index, ai);
     206             :     }
     207             :   else
     208             :     {
     209             :       ip_adjacency_t *adj;
     210             : 
     211       20437 :       adj = adj_get (ai);
     212             : 
     213       20437 :       switch (adj->lookup_next_index)
     214             :         {
     215        8527 :         case IP_LOOKUP_NEXT_GLEAN:
     216        8527 :           adj_glean_update_rewrite (ai);
     217        8527 :           break;
     218        9905 :         case IP_LOOKUP_NEXT_ARP:
     219             :         case IP_LOOKUP_NEXT_REWRITE:
     220        9905 :           ip_neighbor_update (vnm, ai);
     221        9905 :           break;
     222           7 :         case IP_LOOKUP_NEXT_BCAST:
     223           7 :           adj_nbr_update_rewrite (ai,
     224             :                                   ADJ_NBR_REWRITE_FLAG_COMPLETE,
     225             :                                   ethernet_build_rewrite
     226             :                                   (vnm,
     227             :                                    adj->rewrite_header.sw_if_index,
     228           7 :                                    adj->ia_link,
     229             :                                    VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
     230           7 :           break;
     231        1998 :         case IP_LOOKUP_NEXT_MCAST:
     232             :           {
     233             :             /*
     234             :              * Construct a partial rewrite from the known ethernet mcast dest MAC
     235             :              */
     236             :             u8 *rewrite;
     237             :             u8 offset;
     238             : 
     239        3996 :             rewrite = ethernet_build_rewrite
     240             :               (vnm,
     241             :                sw_if_index,
     242        1998 :                adj->ia_link,
     243        1998 :                (adj->ia_nh_proto == FIB_PROTOCOL_IP6 ?
     244        1954 :                 ethernet_ip6_mcast_dst_addr () :
     245          44 :                 ethernet_ip4_mcast_dst_addr ()));
     246             : 
     247             :             /*
     248             :              * Complete the remaining fields of the adj's rewrite to direct the
     249             :              * complete of the rewrite at switch time by copying in the IP
     250             :              * dst address's bytes.
     251             :              * Ofset is 2 bytes into the destintation address.
     252             :              */
     253        1998 :             offset = vec_len (rewrite) - 2;
     254        1998 :             adj_mcast_update_rewrite (ai, rewrite, offset);
     255             : 
     256        1998 :             break;
     257             :           }
     258           0 :         case IP_LOOKUP_NEXT_DROP:
     259             :         case IP_LOOKUP_NEXT_PUNT:
     260             :         case IP_LOOKUP_NEXT_LOCAL:
     261             :         case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
     262             :         case IP_LOOKUP_NEXT_MIDCHAIN:
     263             :         case IP_LOOKUP_NEXT_ICMP_ERROR:
     264             :         case IP_LOOKUP_N_NEXT:
     265           0 :           ASSERT (0);
     266           0 :           break;
     267             :         }
     268       20471 :     }
     269       20471 : }
     270             : 
     271             : static void
     272       17688 : ethernet_interface_address_copy (ethernet_interface_address_t * dst,
     273             :                                  const u8 * mac)
     274             : {
     275       17688 :   clib_memcpy (&dst->mac, (u8 *) mac, sizeof (dst->mac));
     276             :   /*
     277             :    * ethernet dataplane loads mac as u64, makes sure the last 2 bytes are 0
     278             :    * for comparison purpose
     279             :    */
     280       17688 :   dst->zero = 0;
     281       17688 : }
     282             : 
     283             : static void
     284        5261 : ethernet_set_mac (vnet_hw_interface_t * hi, ethernet_interface_t * ei,
     285             :                   const u8 * mac_address)
     286             : {
     287        5261 :   vec_validate (hi->hw_address, sizeof (mac_address_t) - 1);
     288        5261 :   clib_memcpy (hi->hw_address, mac_address, sizeof (mac_address_t));
     289        5261 :   ethernet_interface_address_copy (&ei->address, mac_address);
     290        5261 : }
     291             : 
     292             : static clib_error_t *
     293          31 : ethernet_mac_change (vnet_hw_interface_t * hi,
     294             :                      const u8 * old_address, const u8 * mac_address)
     295             : {
     296             :   ethernet_interface_t *ei;
     297             :   ethernet_main_t *em;
     298             : 
     299          31 :   em = &ethernet_main;
     300          31 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
     301             : 
     302          31 :   ethernet_set_mac (hi, ei, mac_address);
     303             : 
     304             :   {
     305             :     ethernet_address_change_ctx_t *cb;
     306             :     u32 id, sw_if_index;
     307          93 :     vec_foreach (cb, em->address_change_callbacks)
     308             :       {
     309          62 :         cb->function (em, hi->sw_if_index, cb->function_opaque);
     310             :         /* clang-format off */
     311         448 :         hash_foreach (id, sw_if_index, hi->sub_interface_sw_if_index_by_id,
     312             :         ({
     313             :           cb->function (em, sw_if_index, cb->function_opaque);
     314             :         }));
     315             :         /* clang-format on */
     316             :       }
     317             :   }
     318             : 
     319          31 :   return (NULL);
     320             : }
     321             : 
     322             : static clib_error_t *
     323           0 : ethernet_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
     324             :                              u32 frame_size)
     325             : {
     326           0 :   ethernet_interface_t *ei =
     327           0 :     pool_elt_at_index (ethernet_main.interfaces, hi->hw_instance);
     328             : 
     329           0 :   if (ei->cb.set_max_frame_size)
     330           0 :     return ei->cb.set_max_frame_size (vnm, hi, frame_size);
     331             : 
     332           0 :   return vnet_error (
     333             :     VNET_ERR_UNSUPPORTED,
     334             :     "underlying driver doesn't support changing Max Frame Size");
     335             : }
     336             : 
     337             : /* *INDENT-OFF* */
     338        8063 : VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = {
     339             :   .name = "Ethernet",
     340             :   .tx_hash_fn_type = VNET_HASH_FN_TYPE_ETHERNET,
     341             :   .format_address = format_ethernet_address,
     342             :   .format_header = format_ethernet_header_with_length,
     343             :   .unformat_hw_address = unformat_ethernet_address,
     344             :   .unformat_header = unformat_ethernet_header,
     345             :   .build_rewrite = ethernet_build_rewrite,
     346             :   .update_adjacency = ethernet_update_adjacency,
     347             :   .mac_addr_change_function = ethernet_mac_change,
     348             :   .set_max_frame_size = ethernet_set_max_frame_size,
     349             : };
     350             : /* *INDENT-ON* */
     351             : 
     352             : uword
     353           0 : unformat_ethernet_interface (unformat_input_t * input, va_list * args)
     354             : {
     355           0 :   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
     356           0 :   u32 *result = va_arg (*args, u32 *);
     357             :   u32 hw_if_index;
     358           0 :   ethernet_main_t *em = &ethernet_main;
     359             :   ethernet_interface_t *eif;
     360             : 
     361           0 :   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
     362           0 :     return 0;
     363             : 
     364           0 :   eif = ethernet_get_interface (em, hw_if_index);
     365           0 :   if (eif)
     366             :     {
     367           0 :       *result = hw_if_index;
     368           0 :       return 1;
     369             :     }
     370           0 :   return 0;
     371             : }
     372             : 
     373             : u32
     374        5230 : vnet_eth_register_interface (vnet_main_t *vnm,
     375             :                              vnet_eth_interface_registration_t *r)
     376             : {
     377        5230 :   ethernet_main_t *em = &ethernet_main;
     378             :   ethernet_interface_t *ei;
     379             :   vnet_hw_interface_t *hi;
     380             :   u32 hw_if_index;
     381             : 
     382        5230 :   pool_get (em->interfaces, ei);
     383        5230 :   clib_memcpy (&ei->cb, &r->cb, sizeof (vnet_eth_if_callbacks_t));
     384             : 
     385        5230 :   hw_if_index = vnet_register_interface (
     386             :     vnm, r->dev_class_index, r->dev_instance,
     387        5230 :     ethernet_hw_interface_class.index, ei - em->interfaces);
     388             : 
     389        5230 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     390             : 
     391        5230 :   ethernet_setup_node (vnm->vlib_main, hi->output_node_index);
     392             : 
     393        5230 :   hi->min_frame_size = ETHERNET_MIN_PACKET_BYTES;
     394        5230 :   hi->frame_overhead =
     395        5230 :     r->frame_overhead ?
     396             :             r->frame_overhead :
     397             :             sizeof (ethernet_header_t) + 2 * sizeof (ethernet_vlan_header_t);
     398       10460 :   hi->max_frame_size = r->max_frame_size ?
     399        5230 :                          r->max_frame_size :
     400        5230 :                          ethernet_main.default_mtu + hi->frame_overhead;
     401             :   ;
     402             : 
     403             :   /* Default ethernet MTU, 9000 unless set by ethernet_config see below */
     404        5230 :   vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, em->default_mtu);
     405             : 
     406        5230 :   ethernet_set_mac (hi, ei, r->address);
     407        5230 :   return hw_if_index;
     408             : }
     409             : 
     410             : void
     411         728 : ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
     412             : {
     413         728 :   ethernet_main_t *em = &ethernet_main;
     414             :   ethernet_interface_t *ei;
     415             :   vnet_hw_interface_t *hi;
     416             :   main_intf_t *main_intf;
     417             :   vlan_table_t *vlan_table;
     418             :   u32 idx;
     419             : 
     420         728 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     421         728 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
     422             : 
     423             :   /* Delete vlan mapping table for dot1q and dot1ad. */
     424         728 :   main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
     425         728 :   if (main_intf->dot1q_vlans)
     426             :     {
     427           3 :       vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
     428       12291 :       for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
     429             :         {
     430       12288 :           if (vlan_table->vlans[idx].qinqs)
     431             :             {
     432           0 :               pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
     433           0 :               vlan_table->vlans[idx].qinqs = 0;
     434             :             }
     435             :         }
     436           3 :       pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
     437           3 :       main_intf->dot1q_vlans = 0;
     438             :     }
     439         728 :   if (main_intf->dot1ad_vlans)
     440             :     {
     441           0 :       vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
     442           0 :       for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
     443             :         {
     444           0 :           if (vlan_table->vlans[idx].qinqs)
     445             :             {
     446           0 :               pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
     447           0 :               vlan_table->vlans[idx].qinqs = 0;
     448             :             }
     449             :         }
     450           0 :       pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
     451           0 :       main_intf->dot1ad_vlans = 0;
     452             :     }
     453             : 
     454         728 :   vnet_delete_hw_interface (vnm, hw_if_index);
     455         728 :   pool_put (em->interfaces, ei);
     456         728 : }
     457             : 
     458             : u32
     459        2309 : ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     460             : {
     461        2309 :   ethernet_main_t *em = &ethernet_main;
     462             :   vnet_hw_interface_t *hi;
     463             :   ethernet_interface_t *ei;
     464        2309 :   u32 opn_flags = flags & ETHERNET_INTERFACE_FLAGS_SET_OPN_MASK;
     465             : 
     466        2309 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     467             : 
     468        2309 :   ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index);
     469             : 
     470        2309 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
     471             : 
     472             :   /* preserve status bits and update last set operation bits */
     473        2309 :   ei->flags = (ei->flags & ETHERNET_INTERFACE_FLAGS_STATUS_MASK) | opn_flags;
     474             : 
     475        2309 :   if (ei->cb.flag_change)
     476             :     {
     477        1947 :       switch (opn_flags)
     478             :         {
     479         946 :         case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
     480         946 :           if (hi->caps & VNET_HW_IF_CAP_MAC_FILTER)
     481             :             {
     482           0 :               if (ei->cb.flag_change (vnm, hi, opn_flags) != ~0)
     483             :                 {
     484           0 :                   ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
     485           0 :                   return 0;
     486             :                 }
     487           0 :               ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
     488           0 :               return ~0;
     489             :             }
     490             :           /* fall through */
     491             :         case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
     492        1947 :           ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
     493        1947 :           return ei->cb.flag_change (vnm, hi, opn_flags);
     494           0 :         default:
     495           0 :           return ~0;
     496             :         }
     497             :     }
     498         362 :   return ~0;
     499             : }
     500             : 
     501             : /**
     502             :  * Echo packets back to ethernet/l2-input.
     503             :  */
     504             : static uword
     505         132 : simulated_ethernet_interface_tx (vlib_main_t * vm,
     506             :                                  vlib_node_runtime_t *
     507             :                                  node, vlib_frame_t * frame)
     508             : {
     509             :   u32 n_left_from, *from;
     510         132 :   u32 next_index = 0;
     511             :   u32 n_bytes;
     512         132 :   u32 thread_index = vm->thread_index;
     513         132 :   vnet_main_t *vnm = vnet_get_main ();
     514         132 :   vnet_interface_main_t *im = &vnm->interface_main;
     515             :   l2_input_config_t *config;
     516             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     517             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     518         132 :   u32 new_rx_sw_if_index = ~0;
     519         132 :   u32 new_tx_sw_if_index = ~0;
     520             : 
     521         132 :   n_left_from = frame->n_vectors;
     522         132 :   from = vlib_frame_vector_args (frame);
     523             : 
     524         132 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     525         132 :   b = bufs;
     526         132 :   next = nexts;
     527             : 
     528             :   /* Ordinarily, this is the only config lookup. */
     529         132 :   config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
     530         132 :   next_index = (l2_input_is_bridge (config) ?
     531         132 :                 VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     532             :                 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     533         132 :   new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     534         132 :   new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     535             : 
     536         238 :   while (n_left_from >= 4)
     537             :     {
     538             :       u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
     539             :       u32x4 xor_ifx4;
     540             : 
     541             :       /* Prefetch next iteration. */
     542         106 :       if (PREDICT_TRUE (n_left_from >= 8))
     543             :         {
     544          66 :           vlib_prefetch_buffer_header (b[4], STORE);
     545          66 :           vlib_prefetch_buffer_header (b[5], STORE);
     546          66 :           vlib_prefetch_buffer_header (b[6], STORE);
     547          66 :           vlib_prefetch_buffer_header (b[7], STORE);
     548             :         }
     549             : 
     550             :       /* Make sure all pkts were transmitted on the same (loop) intfc */
     551         106 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     552         106 :       sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
     553         106 :       sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
     554         106 :       sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
     555             : 
     556         106 :       xor_ifx4 = u32x4_gather (&sw_if_index0, &sw_if_index1, &sw_if_index2,
     557             :                                &sw_if_index3);
     558             : 
     559             :       /* Speed path / expected case: all pkts on the same intfc */
     560         106 :       if (PREDICT_TRUE (u32x4_is_all_equal (xor_ifx4, new_rx_sw_if_index)))
     561             :         {
     562         106 :           next[0] = next_index;
     563         106 :           next[1] = next_index;
     564         106 :           next[2] = next_index;
     565         106 :           next[3] = next_index;
     566         106 :           vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     567         106 :           vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     568         106 :           vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     569         106 :           vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     570         106 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     571         106 :           vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     572         106 :           vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     573         106 :           vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     574         106 :           n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
     575         106 :           n_bytes += vlib_buffer_length_in_chain (vm, b[1]);
     576         106 :           n_bytes += vlib_buffer_length_in_chain (vm, b[2]);
     577         106 :           n_bytes += vlib_buffer_length_in_chain (vm, b[3]);
     578             : 
     579         106 :           if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     580             :             {
     581          44 :               vnet_update_l2_len (b[0]);
     582          44 :               vnet_update_l2_len (b[1]);
     583          44 :               vnet_update_l2_len (b[2]);
     584          44 :               vnet_update_l2_len (b[3]);
     585             :             }
     586             : 
     587             :           /* increment TX interface stat */
     588         106 :           vlib_increment_combined_counter (im->combined_sw_if_counters +
     589             :                                            VNET_INTERFACE_COUNTER_TX,
     590             :                                            thread_index, new_rx_sw_if_index,
     591             :                                            4 /* pkts */ , n_bytes);
     592         106 :           b += 4;
     593         106 :           next += 4;
     594         106 :           n_left_from -= 4;
     595         106 :           continue;
     596             :         }
     597             : 
     598             :       /*
     599             :        * Slow path: we know that at least one of the pkts
     600             :        * was transmitted on a different sw_if_index, so
     601             :        * check each sw_if_index against the cached data and proceed
     602             :        * accordingly.
     603             :        *
     604             :        * This shouldn't happen, but code can (and does) bypass the
     605             :        * per-interface output node, so deal with it.
     606             :        */
     607           0 :       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
     608             :                          != new_rx_sw_if_index))
     609             :         {
     610           0 :           config = l2input_intf_config
     611           0 :             (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
     612           0 :           next_index = (l2_input_is_bridge (config) ?
     613           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     614             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     615           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     616           0 :           new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     617             :         }
     618           0 :       next[0] = next_index;
     619           0 :       vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     620           0 :       vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     621           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
     622           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     623           0 :         vnet_update_l2_len (b[0]);
     624             : 
     625           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     626             :                                        VNET_INTERFACE_COUNTER_TX,
     627             :                                        thread_index, new_rx_sw_if_index,
     628             :                                        1 /* pkts */ , n_bytes);
     629             : 
     630           0 :       if (PREDICT_FALSE (vnet_buffer (b[1])->sw_if_index[VLIB_TX]
     631             :                          != new_rx_sw_if_index))
     632             :         {
     633           0 :           config = l2input_intf_config
     634           0 :             (vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
     635           0 :           next_index = (l2_input_is_bridge (config) ?
     636           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     637             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     638           0 :           new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
     639           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     640             :         }
     641           0 :       next[1] = next_index;
     642           0 :       vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     643           0 :       vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     644           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[1]);
     645           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     646           0 :         vnet_update_l2_len (b[1]);
     647             : 
     648           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     649             :                                        VNET_INTERFACE_COUNTER_TX,
     650             :                                        thread_index, new_rx_sw_if_index,
     651             :                                        1 /* pkts */ , n_bytes);
     652             : 
     653           0 :       if (PREDICT_FALSE (vnet_buffer (b[2])->sw_if_index[VLIB_TX]
     654             :                          != new_rx_sw_if_index))
     655             :         {
     656           0 :           config = l2input_intf_config
     657           0 :             (vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
     658           0 :           next_index = (l2_input_is_bridge (config) ?
     659           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     660             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     661           0 :           new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
     662           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     663             :         }
     664           0 :       next[2] = next_index;
     665           0 :       vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     666           0 :       vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     667           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[2]);
     668           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     669           0 :         vnet_update_l2_len (b[2]);
     670             : 
     671           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     672             :                                        VNET_INTERFACE_COUNTER_TX,
     673             :                                        thread_index, new_rx_sw_if_index,
     674             :                                        1 /* pkts */ , n_bytes);
     675             : 
     676           0 :       if (PREDICT_FALSE (vnet_buffer (b[3])->sw_if_index[VLIB_TX]
     677             :                          != new_rx_sw_if_index))
     678             :         {
     679           0 :           config = l2input_intf_config
     680           0 :             (vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
     681           0 :           next_index = (l2_input_is_bridge (config) ?
     682           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     683             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     684           0 :           new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
     685           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     686             :         }
     687           0 :       next[3] = next_index;
     688           0 :       vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     689           0 :       vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     690           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[3]);
     691           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     692           0 :         vnet_update_l2_len (b[3]);
     693             : 
     694           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     695             :                                        VNET_INTERFACE_COUNTER_TX,
     696             :                                        thread_index, new_rx_sw_if_index,
     697             :                                        1 /* pkts */ , n_bytes);
     698           0 :       b += 4;
     699           0 :       next += 4;
     700           0 :       n_left_from -= 4;
     701             :     }
     702         304 :   while (n_left_from > 0)
     703             :     {
     704         172 :       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
     705             :                          != new_rx_sw_if_index))
     706             :         {
     707           0 :           config = l2input_intf_config
     708           0 :             (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
     709           0 :           next_index = (l2_input_is_bridge (config) ?
     710           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     711             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     712           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     713           0 :           new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     714             :         }
     715         172 :       next[0] = next_index;
     716         172 :       vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     717         172 :       vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     718         172 :       n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
     719         172 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     720         102 :         vnet_update_l2_len (b[0]);
     721             : 
     722         172 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     723             :                                        VNET_INTERFACE_COUNTER_TX,
     724             :                                        thread_index, new_rx_sw_if_index,
     725             :                                        1 /* pkts */ , n_bytes);
     726         172 :       b += 1;
     727         172 :       next += 1;
     728         172 :       n_left_from -= 1;
     729             :     }
     730             : 
     731         132 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     732             : 
     733         132 :   return frame->n_vectors;
     734             : }
     735             : 
     736             : static u8 *
     737         449 : format_simulated_ethernet_name (u8 * s, va_list * args)
     738             : {
     739         449 :   u32 dev_instance = va_arg (*args, u32);
     740         449 :   return format (s, "loop%d", dev_instance);
     741             : }
     742             : 
     743             : static clib_error_t *
     744         200 : simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     745             :                                   u32 flags)
     746             : {
     747         200 :   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
     748             :     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
     749         200 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     750         200 :   return 0;
     751             : }
     752             : 
     753             : static clib_error_t *
     754           0 : simulated_ethernet_mac_change (vnet_hw_interface_t * hi,
     755             :                                const u8 * old_address, const u8 * mac_address)
     756             : {
     757           0 :   l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
     758             : 
     759           0 :   return (NULL);
     760             : }
     761             : 
     762             : 
     763             : /* *INDENT-OFF* */
     764       12095 : VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
     765             :   .name = "Loopback",
     766             :   .format_device_name = format_simulated_ethernet_name,
     767             :   .tx_function = simulated_ethernet_interface_tx,
     768             :   .admin_up_down_function = simulated_ethernet_admin_up_down,
     769             :   .mac_addr_change_function = simulated_ethernet_mac_change,
     770             : };
     771             : /* *INDENT-ON* */
     772             : 
     773             : /*
     774             :  * Maintain a bitmap of allocated loopback instance numbers.
     775             :  */
     776             : #define LOOPBACK_MAX_INSTANCE           (16 * 1024)
     777             : 
     778             : static u32
     779         178 : loopback_instance_alloc (u8 is_specified, u32 want)
     780             : {
     781         178 :   ethernet_main_t *em = &ethernet_main;
     782             : 
     783             :   /*
     784             :    * Check for dynamically allocaetd instance number.
     785             :    */
     786         178 :   if (!is_specified)
     787             :     {
     788             :       u32 bit;
     789             : 
     790         176 :       bit = clib_bitmap_first_clear (em->bm_loopback_instances);
     791         176 :       if (bit >= LOOPBACK_MAX_INSTANCE)
     792             :         {
     793           0 :           return ~0;
     794             :         }
     795         176 :       em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
     796             :                                                    bit, 1);
     797         176 :       return bit;
     798             :     }
     799             : 
     800             :   /*
     801             :    * In range?
     802             :    */
     803           2 :   if (want >= LOOPBACK_MAX_INSTANCE)
     804             :     {
     805           0 :       return ~0;
     806             :     }
     807             : 
     808             :   /*
     809             :    * Already in use?
     810             :    */
     811           2 :   if (clib_bitmap_get (em->bm_loopback_instances, want))
     812             :     {
     813           0 :       return ~0;
     814             :     }
     815             : 
     816             :   /*
     817             :    * Grant allocation request.
     818             :    */
     819           2 :   em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
     820             :                                                want, 1);
     821             : 
     822           2 :   return want;
     823             : }
     824             : 
     825             : static int
     826         106 : loopback_instance_free (u32 instance)
     827             : {
     828         106 :   ethernet_main_t *em = &ethernet_main;
     829             : 
     830         106 :   if (instance >= LOOPBACK_MAX_INSTANCE)
     831             :     {
     832           0 :       return -1;
     833             :     }
     834             : 
     835         106 :   if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
     836             :     {
     837           0 :       return -1;
     838             :     }
     839             : 
     840         106 :   em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
     841             :                                                instance, 0);
     842         106 :   return 0;
     843             : }
     844             : 
     845             : int
     846         178 : vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
     847             :                                 u8 is_specified, u32 user_instance)
     848             : {
     849         178 :   vnet_main_t *vnm = vnet_get_main ();
     850         178 :   vlib_main_t *vm = vlib_get_main ();
     851             :   u32 instance;
     852             :   u8 address[6];
     853             :   u32 hw_if_index;
     854             :   vnet_hw_interface_t *hw_if;
     855             :   u32 slot;
     856             : 
     857         178 :   ASSERT (sw_if_indexp);
     858             : 
     859         178 :   *sw_if_indexp = (u32) ~ 0;
     860             : 
     861         178 :   clib_memset (address, 0, sizeof (address));
     862             : 
     863             :   /*
     864             :    * Allocate a loopback instance.  Either select on dynamically
     865             :    * or try to use the desired user_instance number.
     866             :    */
     867         178 :   instance = loopback_instance_alloc (is_specified, user_instance);
     868         178 :   if (instance == ~0)
     869             :     {
     870           0 :       return VNET_API_ERROR_INVALID_REGISTRATION;
     871             :     }
     872             : 
     873             :   /*
     874             :    * Default MAC address (dead:0000:0000 + instance) is allocated
     875             :    * if zero mac_address is configured. Otherwise, user-configurable MAC
     876             :    * address is programmed on the loopback interface.
     877             :    */
     878         178 :   if (memcmp (address, mac_address, sizeof (address)))
     879          20 :     clib_memcpy (address, mac_address, sizeof (address));
     880             :   else
     881             :     {
     882         158 :       address[0] = 0xde;
     883         158 :       address[1] = 0xad;
     884         158 :       address[5] = instance;
     885             :     }
     886             : 
     887         178 :   vnet_eth_interface_registration_t eir = {};
     888         178 :   eir.dev_class_index = ethernet_simulated_device_class.index;
     889         178 :   eir.dev_instance = instance;
     890         178 :   eir.address = address;
     891         178 :   hw_if_index = vnet_eth_register_interface (vnm, &eir);
     892         178 :   hw_if = vnet_get_hw_interface (vnm, hw_if_index);
     893         356 :   slot = vlib_node_add_named_next_with_slot
     894         178 :     (vm, hw_if->tx_node_index,
     895             :      "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     896         178 :   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     897             : 
     898         356 :   slot = vlib_node_add_named_next_with_slot
     899         178 :     (vm, hw_if->tx_node_index,
     900             :      "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
     901         178 :   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
     902             : 
     903             :   {
     904         178 :     vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
     905         178 :     *sw_if_indexp = si->sw_if_index;
     906             : 
     907             :     /* By default don't flood to loopbacks, as packets just keep
     908             :      * coming back ... If this loopback becomes a BVI, we'll change it */
     909         178 :     si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
     910             :   }
     911             : 
     912         178 :   return 0;
     913             : }
     914             : 
     915             : static clib_error_t *
     916           9 : create_simulated_ethernet_interfaces (vlib_main_t * vm,
     917             :                                       unformat_input_t * input,
     918             :                                       vlib_cli_command_t * cmd)
     919             : {
     920             :   int rv;
     921             :   u32 sw_if_index;
     922             :   u8 mac_address[6];
     923           9 :   u8 is_specified = 0;
     924           9 :   u32 user_instance = 0;
     925             : 
     926           9 :   clib_memset (mac_address, 0, sizeof (mac_address));
     927             : 
     928           9 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     929             :     {
     930           0 :       if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
     931             :         ;
     932           0 :       if (unformat (input, "instance %d", &user_instance))
     933           0 :         is_specified = 1;
     934             :       else
     935           0 :         break;
     936             :     }
     937             : 
     938           9 :   rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
     939             :                                        is_specified, user_instance);
     940             : 
     941           9 :   if (rv)
     942           0 :     return clib_error_return (0, "vnet_create_loopback_interface failed");
     943             : 
     944           9 :   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
     945             :                    sw_if_index);
     946           9 :   return 0;
     947             : }
     948             : 
     949             : /*?
     950             :  * Create a loopback interface. Optionally, a MAC Address can be
     951             :  * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
     952             :  *
     953             :  * @cliexpar
     954             :  * The following two command syntaxes are equivalent:
     955             :  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
     956             :  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
     957             :  * Example of how to create a loopback interface:
     958             :  * @cliexcmd{loopback create-interface}
     959             : ?*/
     960             : /* *INDENT-OFF* */
     961      285289 : VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
     962             :   .path = "loopback create-interface",
     963             :   .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
     964             :   .function = create_simulated_ethernet_interfaces,
     965             : };
     966             : /* *INDENT-ON* */
     967             : 
     968             : /*?
     969             :  * Create a loopback interface. Optionally, a MAC Address can be
     970             :  * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
     971             :  *
     972             :  * @cliexpar
     973             :  * The following two command syntaxes are equivalent:
     974             :  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
     975             :  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
     976             :  * Example of how to create a loopback interface:
     977             :  * @cliexcmd{create loopback interface}
     978             : ?*/
     979             : /* *INDENT-OFF* */
     980      285289 : VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
     981             :   .path = "create loopback interface",
     982             :   .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
     983             :   .function = create_simulated_ethernet_interfaces,
     984             : };
     985             : /* *INDENT-ON* */
     986             : 
     987             : ethernet_interface_t *
     988     2255320 : ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
     989             : {
     990             :   vnet_hw_interface_t *i =
     991     2255320 :     vnet_get_hw_interface (vnet_get_main (), hw_if_index);
     992     2255320 :   return (i->hw_class_index ==
     993     2255320 :           ethernet_hw_interface_class.
     994     2255320 :           index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
     995             : }
     996             : 
     997             : mac_address_t *
     998       25990 : ethernet_interface_add_del_address (ethernet_main_t * em,
     999             :                                     u32 hw_if_index, const u8 * address,
    1000             :                                     u8 is_add)
    1001             : {
    1002       25990 :   ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index);
    1003       25990 :   ethernet_interface_address_t *if_addr = 0;
    1004       25990 :   int found = 0;
    1005             : 
    1006             :   /* return if there is not an ethernet interface for this hw interface */
    1007       25990 :   if (!ei)
    1008           0 :     return 0;
    1009             : 
    1010             :   /* determine whether the address is configured on the interface */
    1011      281190 :   vec_foreach (if_addr, ei->secondary_addrs)
    1012             :   {
    1013      268756 :     if (ethernet_mac_address_equal (if_addr->mac.bytes, address))
    1014             :       {
    1015       13556 :         found = 1;
    1016       13556 :         break;
    1017             :       }
    1018             :   }
    1019             : 
    1020       25990 :   if (is_add)
    1021             :     {
    1022       14818 :       if (!found)
    1023             :         {
    1024             :           /* address not found yet: add it */
    1025       12427 :           vec_add2 (ei->secondary_addrs, if_addr, 1);
    1026       12427 :           ethernet_interface_address_copy (if_addr, address);
    1027             :         }
    1028       14818 :       return &if_addr->mac;
    1029             :     }
    1030             : 
    1031             :   /* delete case */
    1032       11172 :   if (found)
    1033       11165 :     vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs);
    1034             : 
    1035       11172 :   return 0;
    1036             : }
    1037             : 
    1038             : int
    1039         106 : vnet_delete_loopback_interface (u32 sw_if_index)
    1040             : {
    1041         106 :   vnet_main_t *vnm = vnet_get_main ();
    1042             : 
    1043         106 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    1044           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1045             : 
    1046         106 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1047         106 :   if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
    1048           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1049             : 
    1050         106 :   if (loopback_instance_free (hw->dev_instance) < 0)
    1051           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1052             : 
    1053         106 :   ethernet_delete_interface (vnm, hw->hw_if_index);
    1054             : 
    1055         106 :   return 0;
    1056             : }
    1057             : 
    1058             : int
    1059          19 : vnet_create_sub_interface (u32 sw_if_index, u32 id,
    1060             :                            u32 flags, u16 inner_vlan_id, u16 outer_vlan_id,
    1061             :                            u32 * sub_sw_if_index)
    1062             : {
    1063          19 :   vnet_main_t *vnm = vnet_get_main ();
    1064          19 :   vnet_interface_main_t *im = &vnm->interface_main;
    1065             :   vnet_hw_interface_t *hi;
    1066          19 :   u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id;
    1067             :   vnet_sw_interface_t template;
    1068             :   uword *p;
    1069             :   u64 *kp;
    1070             : 
    1071          19 :   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1072             : 
    1073          19 :   p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
    1074          19 :   if (p)
    1075             :     {
    1076           0 :       return (VNET_API_ERROR_VLAN_ALREADY_EXISTS);
    1077             :     }
    1078             : 
    1079          19 :   clib_memset (&template, 0, sizeof (template));
    1080          19 :   template.type = VNET_SW_INTERFACE_TYPE_SUB;
    1081          19 :   template.flood_class = VNET_FLOOD_CLASS_NORMAL;
    1082          19 :   template.sup_sw_if_index = sw_if_index;
    1083          19 :   template.sub.id = id;
    1084          19 :   template.sub.eth.raw_flags = flags;
    1085          19 :   template.sub.eth.outer_vlan_id = outer_vlan_id;
    1086          19 :   template.sub.eth.inner_vlan_id = inner_vlan_id;
    1087             : 
    1088          19 :   if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index))
    1089           0 :     return (VNET_API_ERROR_UNSPECIFIED);
    1090             : 
    1091          19 :   kp = clib_mem_alloc (sizeof (*kp));
    1092          19 :   *kp = sup_and_sub_key;
    1093             : 
    1094          19 :   hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index);
    1095          38 :   hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index);
    1096             : 
    1097          19 :   return (0);
    1098             : }
    1099             : 
    1100             : int
    1101          64 : vnet_delete_sub_interface (u32 sw_if_index)
    1102             : {
    1103          64 :   vnet_main_t *vnm = vnet_get_main ();
    1104             :   vnet_sw_interface_t *si;
    1105          64 :   int rv = 0;
    1106             : 
    1107          64 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    1108           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1109             : 
    1110          64 :   si = vnet_get_sw_interface (vnm, sw_if_index);
    1111          64 :   if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
    1112          21 :       si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
    1113          21 :       si->type == VNET_SW_INTERFACE_TYPE_P2P)
    1114          64 :     {
    1115          64 :       vnet_interface_main_t *im = &vnm->interface_main;
    1116          64 :       vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1117          64 :       u64 sup_and_sub_key =
    1118          64 :         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
    1119          64 :       hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
    1120          64 :       hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
    1121          64 :       vnet_delete_sw_interface (vnm, sw_if_index);
    1122             :     }
    1123             :   else
    1124           0 :     rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
    1125             : 
    1126          64 :   return rv;
    1127             : }
    1128             : 
    1129             : static clib_error_t *
    1130           0 : delete_simulated_ethernet_interfaces (vlib_main_t * vm,
    1131             :                                       unformat_input_t * input,
    1132             :                                       vlib_cli_command_t * cmd)
    1133             : {
    1134             :   int rv;
    1135           0 :   u32 sw_if_index = ~0;
    1136           0 :   vnet_main_t *vnm = vnet_get_main ();
    1137             : 
    1138           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1139             :     {
    1140           0 :       if (unformat (input, "intfc %U",
    1141             :                     unformat_vnet_sw_interface, vnm, &sw_if_index))
    1142             :         ;
    1143             :       else
    1144           0 :         break;
    1145             :     }
    1146             : 
    1147           0 :   if (sw_if_index == ~0)
    1148           0 :     return clib_error_return (0, "interface not specified");
    1149             : 
    1150           0 :   rv = vnet_delete_loopback_interface (sw_if_index);
    1151             : 
    1152           0 :   if (rv)
    1153           0 :     return clib_error_return (0, "vnet_delete_loopback_interface failed");
    1154             : 
    1155           0 :   return 0;
    1156             : }
    1157             : 
    1158             : static clib_error_t *
    1159           0 : delete_sub_interface (vlib_main_t * vm,
    1160             :                       unformat_input_t * input, vlib_cli_command_t * cmd)
    1161             : {
    1162           0 :   int rv = 0;
    1163           0 :   u32 sw_if_index = ~0;
    1164           0 :   vnet_main_t *vnm = vnet_get_main ();
    1165             : 
    1166           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1167             :     {
    1168           0 :       if (unformat
    1169             :           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
    1170             :         ;
    1171             :       else
    1172           0 :         break;
    1173             :     }
    1174           0 :   if (sw_if_index == ~0)
    1175           0 :     return clib_error_return (0, "interface doesn't exist");
    1176             : 
    1177           0 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    1178           0 :     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1179             :   else
    1180           0 :     rv = vnet_delete_sub_interface (sw_if_index);
    1181           0 :   if (rv)
    1182           0 :     return clib_error_return (0, "delete_subinterface_interface failed");
    1183           0 :   return 0;
    1184             : }
    1185             : 
    1186             : /*?
    1187             :  * Delete a loopback interface.
    1188             :  *
    1189             :  * @cliexpar
    1190             :  * The following two command syntaxes are equivalent:
    1191             :  * @cliexcmd{loopback delete-interface intfc <interface>}
    1192             :  * @cliexcmd{delete loopback interface intfc <interface>}
    1193             :  * Example of how to delete a loopback interface:
    1194             :  * @cliexcmd{loopback delete-interface intfc loop0}
    1195             : ?*/
    1196             : /* *INDENT-OFF* */
    1197      285289 : VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
    1198             :   .path = "loopback delete-interface",
    1199             :   .short_help = "loopback delete-interface intfc <interface>",
    1200             :   .function = delete_simulated_ethernet_interfaces,
    1201             : };
    1202             : /* *INDENT-ON* */
    1203             : 
    1204             : /*?
    1205             :  * Delete a loopback interface.
    1206             :  *
    1207             :  * @cliexpar
    1208             :  * The following two command syntaxes are equivalent:
    1209             :  * @cliexcmd{loopback delete-interface intfc <interface>}
    1210             :  * @cliexcmd{delete loopback interface intfc <interface>}
    1211             :  * Example of how to delete a loopback interface:
    1212             :  * @cliexcmd{delete loopback interface intfc loop0}
    1213             : ?*/
    1214             : /* *INDENT-OFF* */
    1215      285289 : VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
    1216             :   .path = "delete loopback interface",
    1217             :   .short_help = "delete loopback interface intfc <interface>",
    1218             :   .function = delete_simulated_ethernet_interfaces,
    1219             : };
    1220             : /* *INDENT-ON* */
    1221             : 
    1222             : /*?
    1223             :  * Delete a sub-interface.
    1224             :  *
    1225             :  * @cliexpar
    1226             :  * Example of how to delete a sub-interface:
    1227             :  * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
    1228             : ?*/
    1229             : /* *INDENT-OFF* */
    1230      285289 : VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
    1231             :   .path = "delete sub-interface",
    1232             :   .short_help = "delete sub-interface <interface>",
    1233             :   .function = delete_sub_interface,
    1234             : };
    1235             : /* *INDENT-ON* */
    1236             : 
    1237             : /* ethernet { ... } configuration. */
    1238             : /*?
    1239             :  *
    1240             :  * @cfgcmd{default-mtu &lt;n&gt;}
    1241             :  * Specify the default mtu in the range of 64-9000. The default is 9000 bytes.
    1242             :  *
    1243             :  */
    1244             : static clib_error_t *
    1245         575 : ethernet_config (vlib_main_t * vm, unformat_input_t * input)
    1246             : {
    1247         575 :   ethernet_main_t *em = &ethernet_main;
    1248             : 
    1249         575 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1250             :     {
    1251           0 :       if (unformat (input, "default-mtu %u", &em->default_mtu))
    1252             :         {
    1253           0 :           if (em->default_mtu < 64 || em->default_mtu > 9000)
    1254           0 :             return clib_error_return (0, "default MTU must be >=64, <=9000");
    1255             :         }
    1256             :       else
    1257             :         {
    1258           0 :           return clib_error_return (0, "unknown input '%U'",
    1259             :                                     format_unformat_error, input);
    1260             :         }
    1261             :     }
    1262         575 :   return 0;
    1263             : }
    1264             : 
    1265        7514 : VLIB_CONFIG_FUNCTION (ethernet_config, "ethernet");
    1266             : 
    1267             : /*
    1268             :  * fd.io coding-style-patch-verification: ON
    1269             :  *
    1270             :  * Local Variables:
    1271             :  * eval: (c-set-style "gnu")
    1272             :  * End:
    1273             :  */

Generated by: LCOV version 1.14