LCOV - code coverage report
Current view: top level - vnet/ethernet - interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 364 523 69.6 %
Date: 2023-07-05 22:20:52 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        1887 : 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        1887 :   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       38927 : ethernet_build_rewrite (vnet_main_t * vnm,
      84             :                         u32 sw_if_index,
      85             :                         vnet_link_t link_type, const void *dst_address)
      86             : {
      87       38927 :   vnet_sw_interface_t *sub_sw = vnet_get_sw_interface (vnm, sw_if_index);
      88       38927 :   vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
      89       38927 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
      90       38927 :   ethernet_main_t *em = &ethernet_main;
      91             :   ethernet_interface_t *ei;
      92             :   ethernet_header_t *h;
      93             :   ethernet_type_t type;
      94       38927 :   uword n_bytes = sizeof (h[0]);
      95       38927 :   u8 *rewrite = NULL;
      96       38927 :   u8 is_p2p = 0;
      97             : 
      98       38927 :   if ((sub_sw->type == VNET_SW_INTERFACE_TYPE_P2P) ||
      99       38895 :       (sub_sw->type == VNET_SW_INTERFACE_TYPE_PIPE))
     100          34 :     is_p2p = 1;
     101       38927 :   if (sub_sw != sup_sw)
     102             :     {
     103         490 :       if (sub_sw->sub.eth.flags.one_tag)
     104             :         {
     105         346 :           n_bytes += sizeof (ethernet_vlan_header_t);
     106             :         }
     107         144 :       else if (sub_sw->sub.eth.flags.two_tags)
     108             :         {
     109         110 :           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         490 :       if (PREDICT_FALSE (!is_p2p))
     116             :         {
     117             :           // Check for encaps that are not supported for L3 interfaces
     118         456 :           if (!(sub_sw->sub.eth.flags.exact_match) ||
     119         456 :               (sub_sw->sub.eth.flags.default_sub) ||
     120         456 :               (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       38927 :   switch (link_type)
     133             :     {
     134             : #define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
     135       10817 :       _(IP4, IP4);
     136       16027 :       _(IP6, IP6);
     137          57 :       _(MPLS, MPLS);
     138       12026 :       _(ARP, ARP);
     139             : #undef _
     140           0 :     default:
     141           0 :       return NULL;
     142             :     }
     143             : 
     144       38927 :   vec_validate (rewrite, n_bytes - 1);
     145       38927 :   h = (ethernet_header_t *) rewrite;
     146       38927 :   ei = pool_elt_at_index (em->interfaces, hw->hw_instance);
     147       38927 :   clib_memcpy (h->src_address, &ei->address, sizeof (h->src_address));
     148       38927 :   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       38893 :       if (dst_address)
     156       23181 :         clib_memcpy (h->dst_address, dst_address, sizeof (h->dst_address));
     157             :       else
     158       15712 :         clib_memset (h->dst_address, ~0, sizeof (h->dst_address));        /* broadcast */
     159             :     }
     160             : 
     161       38927 :   if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.one_tag)
     162         346 :     {
     163         346 :       ethernet_vlan_header_t *outer = (void *) (h + 1);
     164             : 
     165         346 :       h->type = sub_sw->sub.eth.flags.dot1ad ?
     166           0 :         clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
     167         346 :         clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     168         346 :       outer->priority_cfi_and_id =
     169         346 :         clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
     170         346 :       outer->type = clib_host_to_net_u16 (type);
     171             : 
     172             :     }
     173       38581 :   else if (PREDICT_FALSE (!is_p2p) && sub_sw->sub.eth.flags.two_tags)
     174         110 :     {
     175         110 :       ethernet_vlan_header_t *outer = (void *) (h + 1);
     176         110 :       ethernet_vlan_header_t *inner = (void *) (outer + 1);
     177             : 
     178         110 :       h->type = sub_sw->sub.eth.flags.dot1ad ?
     179         110 :         clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD) :
     180           0 :         clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     181         110 :       outer->priority_cfi_and_id =
     182         110 :         clib_host_to_net_u16 (sub_sw->sub.eth.outer_vlan_id);
     183         110 :       outer->type = clib_host_to_net_u16 (ETHERNET_TYPE_VLAN);
     184         110 :       inner->priority_cfi_and_id =
     185         110 :         clib_host_to_net_u16 (sub_sw->sub.eth.inner_vlan_id);
     186         110 :       inner->type = clib_host_to_net_u16 (type);
     187             : 
     188             :     }
     189             :   else
     190             :     {
     191       38471 :       h->type = clib_host_to_net_u16 (type);
     192             :     }
     193             : 
     194       38927 :   return (rewrite);
     195             : }
     196             : 
     197             : void
     198       21886 : ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
     199             : {
     200       21886 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     201             : 
     202       21886 :   if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
     203       21854 :       (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       21852 :       adj = adj_get (ai);
     212             : 
     213       21852 :       switch (adj->lookup_next_index)
     214             :         {
     215       10142 :         case IP_LOOKUP_NEXT_GLEAN:
     216       10142 :           adj_glean_update_rewrite (ai);
     217       10142 :           break;
     218        9772 :         case IP_LOOKUP_NEXT_ARP:
     219             :         case IP_LOOKUP_NEXT_REWRITE:
     220        9772 :           ip_neighbor_update (vnm, ai);
     221        9772 :           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        1931 :         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        3862 :             rewrite = ethernet_build_rewrite
     240             :               (vnm,
     241             :                sw_if_index,
     242        1931 :                adj->ia_link,
     243        1931 :                (adj->ia_nh_proto == FIB_PROTOCOL_IP6 ?
     244        1887 :                 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        1931 :             offset = vec_len (rewrite) - 2;
     254        1931 :             adj_mcast_update_rewrite (ai, rewrite, offset);
     255             : 
     256        1931 :             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       21886 :     }
     269       21886 : }
     270             : 
     271             : static void
     272       17178 : ethernet_interface_address_copy (ethernet_interface_address_t * dst,
     273             :                                  const u8 * mac)
     274             : {
     275       17178 :   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       17178 :   dst->zero = 0;
     281       17178 : }
     282             : 
     283             : static void
     284        5147 : ethernet_set_mac (vnet_hw_interface_t * hi, ethernet_interface_t * ei,
     285             :                   const u8 * mac_address)
     286             : {
     287        5147 :   vec_validate (hi->hw_address, sizeof (mac_address_t) - 1);
     288        5147 :   clib_memcpy (hi->hw_address, mac_address, sizeof (mac_address_t));
     289        5147 :   ethernet_interface_address_copy (&ei->address, mac_address);
     290        5147 : }
     291             : 
     292             : static clib_error_t *
     293          29 : 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          29 :   em = &ethernet_main;
     300          29 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
     301             : 
     302          29 :   ethernet_set_mac (hi, ei, mac_address);
     303             : 
     304             :   {
     305             :     ethernet_address_change_ctx_t *cb;
     306          87 :     vec_foreach (cb, em->address_change_callbacks)
     307          58 :       cb->function (em, hi->sw_if_index, cb->function_opaque);
     308             :   }
     309             : 
     310          29 :   return (NULL);
     311             : }
     312             : 
     313             : static clib_error_t *
     314           0 : ethernet_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
     315             :                              u32 frame_size)
     316             : {
     317           0 :   ethernet_interface_t *ei =
     318           0 :     pool_elt_at_index (ethernet_main.interfaces, hi->hw_instance);
     319             : 
     320           0 :   if (ei->cb.set_max_frame_size)
     321           0 :     return ei->cb.set_max_frame_size (vnm, hi, frame_size);
     322             : 
     323           0 :   return vnet_error (
     324             :     VNET_ERR_UNSUPPORTED,
     325             :     "underlying driver doesn't support changing Max Frame Size");
     326             : }
     327             : 
     328             : /* *INDENT-OFF* */
     329        7279 : VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = {
     330             :   .name = "Ethernet",
     331             :   .tx_hash_fn_type = VNET_HASH_FN_TYPE_ETHERNET,
     332             :   .format_address = format_ethernet_address,
     333             :   .format_header = format_ethernet_header_with_length,
     334             :   .unformat_hw_address = unformat_ethernet_address,
     335             :   .unformat_header = unformat_ethernet_header,
     336             :   .build_rewrite = ethernet_build_rewrite,
     337             :   .update_adjacency = ethernet_update_adjacency,
     338             :   .mac_addr_change_function = ethernet_mac_change,
     339             :   .set_max_frame_size = ethernet_set_max_frame_size,
     340             : };
     341             : /* *INDENT-ON* */
     342             : 
     343             : uword
     344           0 : unformat_ethernet_interface (unformat_input_t * input, va_list * args)
     345             : {
     346           0 :   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
     347           0 :   u32 *result = va_arg (*args, u32 *);
     348             :   u32 hw_if_index;
     349           0 :   ethernet_main_t *em = &ethernet_main;
     350             :   ethernet_interface_t *eif;
     351             : 
     352           0 :   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
     353           0 :     return 0;
     354             : 
     355           0 :   eif = ethernet_get_interface (em, hw_if_index);
     356           0 :   if (eif)
     357             :     {
     358           0 :       *result = hw_if_index;
     359           0 :       return 1;
     360             :     }
     361           0 :   return 0;
     362             : }
     363             : 
     364             : u32
     365        5118 : vnet_eth_register_interface (vnet_main_t *vnm,
     366             :                              vnet_eth_interface_registration_t *r)
     367             : {
     368        5118 :   ethernet_main_t *em = &ethernet_main;
     369             :   ethernet_interface_t *ei;
     370             :   vnet_hw_interface_t *hi;
     371             :   u32 hw_if_index;
     372             : 
     373        5118 :   pool_get (em->interfaces, ei);
     374        5118 :   clib_memcpy (&ei->cb, &r->cb, sizeof (vnet_eth_if_callbacks_t));
     375             : 
     376        5118 :   hw_if_index = vnet_register_interface (
     377             :     vnm, r->dev_class_index, r->dev_instance,
     378        5118 :     ethernet_hw_interface_class.index, ei - em->interfaces);
     379             : 
     380        5118 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     381             : 
     382        5118 :   ethernet_setup_node (vnm->vlib_main, hi->output_node_index);
     383             : 
     384        5118 :   hi->min_frame_size = ETHERNET_MIN_PACKET_BYTES;
     385        5118 :   hi->frame_overhead =
     386        5118 :     r->frame_overhead ?
     387             :             r->frame_overhead :
     388             :             sizeof (ethernet_header_t) + 2 * sizeof (ethernet_vlan_header_t);
     389       10236 :   hi->max_frame_size = r->max_frame_size ?
     390        5118 :                          r->max_frame_size :
     391        5118 :                          ethernet_main.default_mtu + hi->frame_overhead;
     392             :   ;
     393             : 
     394             :   /* Default ethernet MTU, 9000 unless set by ethernet_config see below */
     395        5118 :   vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, em->default_mtu);
     396             : 
     397        5118 :   ethernet_set_mac (hi, ei, r->address);
     398        5118 :   return hw_if_index;
     399             : }
     400             : 
     401             : void
     402         657 : ethernet_delete_interface (vnet_main_t * vnm, u32 hw_if_index)
     403             : {
     404         657 :   ethernet_main_t *em = &ethernet_main;
     405             :   ethernet_interface_t *ei;
     406             :   vnet_hw_interface_t *hi;
     407             :   main_intf_t *main_intf;
     408             :   vlan_table_t *vlan_table;
     409             :   u32 idx;
     410             : 
     411         657 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     412         657 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
     413             : 
     414             :   /* Delete vlan mapping table for dot1q and dot1ad. */
     415         657 :   main_intf = vec_elt_at_index (em->main_intfs, hi->hw_if_index);
     416         657 :   if (main_intf->dot1q_vlans)
     417             :     {
     418           3 :       vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1q_vlans);
     419       12291 :       for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
     420             :         {
     421       12288 :           if (vlan_table->vlans[idx].qinqs)
     422             :             {
     423           0 :               pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
     424           0 :               vlan_table->vlans[idx].qinqs = 0;
     425             :             }
     426             :         }
     427           3 :       pool_put_index (em->vlan_pool, main_intf->dot1q_vlans);
     428           3 :       main_intf->dot1q_vlans = 0;
     429             :     }
     430         657 :   if (main_intf->dot1ad_vlans)
     431             :     {
     432           0 :       vlan_table = vec_elt_at_index (em->vlan_pool, main_intf->dot1ad_vlans);
     433           0 :       for (idx = 0; idx < ETHERNET_N_VLAN; idx++)
     434             :         {
     435           0 :           if (vlan_table->vlans[idx].qinqs)
     436             :             {
     437           0 :               pool_put_index (em->qinq_pool, vlan_table->vlans[idx].qinqs);
     438           0 :               vlan_table->vlans[idx].qinqs = 0;
     439             :             }
     440             :         }
     441           0 :       pool_put_index (em->vlan_pool, main_intf->dot1ad_vlans);
     442           0 :       main_intf->dot1ad_vlans = 0;
     443             :     }
     444             : 
     445         657 :   vnet_delete_hw_interface (vnm, hw_if_index);
     446         657 :   pool_put (em->interfaces, ei);
     447         657 : }
     448             : 
     449             : u32
     450        2263 : ethernet_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     451             : {
     452        2263 :   ethernet_main_t *em = &ethernet_main;
     453             :   vnet_hw_interface_t *hi;
     454             :   ethernet_interface_t *ei;
     455        2263 :   u32 opn_flags = flags & ETHERNET_INTERFACE_FLAGS_SET_OPN_MASK;
     456             : 
     457        2263 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     458             : 
     459        2263 :   ASSERT (hi->hw_class_index == ethernet_hw_interface_class.index);
     460             : 
     461        2263 :   ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
     462             : 
     463             :   /* preserve status bits and update last set operation bits */
     464        2263 :   ei->flags = (ei->flags & ETHERNET_INTERFACE_FLAGS_STATUS_MASK) | opn_flags;
     465             : 
     466        2263 :   if (ei->cb.flag_change)
     467             :     {
     468        1901 :       switch (opn_flags)
     469             :         {
     470         922 :         case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
     471         922 :           if (hi->caps & VNET_HW_IF_CAP_MAC_FILTER)
     472             :             {
     473           0 :               if (ei->cb.flag_change (vnm, hi, opn_flags) != ~0)
     474             :                 {
     475           0 :                   ei->flags |= ETHERNET_INTERFACE_FLAG_STATUS_L3;
     476           0 :                   return 0;
     477             :                 }
     478           0 :               ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
     479           0 :               return ~0;
     480             :             }
     481             :           /* fall through */
     482             :         case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
     483        1901 :           ei->flags &= ~ETHERNET_INTERFACE_FLAG_STATUS_L3;
     484        1901 :           return ei->cb.flag_change (vnm, hi, opn_flags);
     485           0 :         default:
     486           0 :           return ~0;
     487             :         }
     488             :     }
     489         362 :   return ~0;
     490             : }
     491             : 
     492             : /**
     493             :  * Echo packets back to ethernet/l2-input.
     494             :  */
     495             : static uword
     496         134 : simulated_ethernet_interface_tx (vlib_main_t * vm,
     497             :                                  vlib_node_runtime_t *
     498             :                                  node, vlib_frame_t * frame)
     499             : {
     500             :   u32 n_left_from, *from;
     501         134 :   u32 next_index = 0;
     502             :   u32 n_bytes;
     503         134 :   u32 thread_index = vm->thread_index;
     504         134 :   vnet_main_t *vnm = vnet_get_main ();
     505         134 :   vnet_interface_main_t *im = &vnm->interface_main;
     506             :   l2_input_config_t *config;
     507             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     508             :   u16 nexts[VLIB_FRAME_SIZE], *next;
     509         134 :   u32 new_rx_sw_if_index = ~0;
     510         134 :   u32 new_tx_sw_if_index = ~0;
     511             : 
     512         134 :   n_left_from = frame->n_vectors;
     513         134 :   from = vlib_frame_vector_args (frame);
     514             : 
     515         134 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     516         134 :   b = bufs;
     517         134 :   next = nexts;
     518             : 
     519             :   /* Ordinarily, this is the only config lookup. */
     520         134 :   config = l2input_intf_config (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
     521         134 :   next_index = (l2_input_is_bridge (config) ?
     522         134 :                 VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     523             :                 VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     524         134 :   new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     525         134 :   new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     526             : 
     527         240 :   while (n_left_from >= 4)
     528             :     {
     529             :       u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3;
     530             :       u32x4 xor_ifx4;
     531             : 
     532             :       /* Prefetch next iteration. */
     533         106 :       if (PREDICT_TRUE (n_left_from >= 8))
     534             :         {
     535          66 :           vlib_prefetch_buffer_header (b[4], STORE);
     536          66 :           vlib_prefetch_buffer_header (b[5], STORE);
     537          66 :           vlib_prefetch_buffer_header (b[6], STORE);
     538          66 :           vlib_prefetch_buffer_header (b[7], STORE);
     539             :         }
     540             : 
     541             :       /* Make sure all pkts were transmitted on the same (loop) intfc */
     542         106 :       sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     543         106 :       sw_if_index1 = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
     544         106 :       sw_if_index2 = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
     545         106 :       sw_if_index3 = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
     546             : 
     547         106 :       xor_ifx4 = u32x4_gather (&sw_if_index0, &sw_if_index1, &sw_if_index2,
     548             :                                &sw_if_index3);
     549             : 
     550             :       /* Speed path / expected case: all pkts on the same intfc */
     551         106 :       if (PREDICT_TRUE (u32x4_is_all_equal (xor_ifx4, new_rx_sw_if_index)))
     552             :         {
     553         106 :           next[0] = next_index;
     554         106 :           next[1] = next_index;
     555         106 :           next[2] = next_index;
     556         106 :           next[3] = next_index;
     557         106 :           vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     558         106 :           vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     559         106 :           vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     560         106 :           vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     561         106 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     562         106 :           vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     563         106 :           vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     564         106 :           vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     565         106 :           n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
     566         106 :           n_bytes += vlib_buffer_length_in_chain (vm, b[1]);
     567         106 :           n_bytes += vlib_buffer_length_in_chain (vm, b[2]);
     568         106 :           n_bytes += vlib_buffer_length_in_chain (vm, b[3]);
     569             : 
     570         106 :           if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     571             :             {
     572          44 :               vnet_update_l2_len (b[0]);
     573          44 :               vnet_update_l2_len (b[1]);
     574          44 :               vnet_update_l2_len (b[2]);
     575          44 :               vnet_update_l2_len (b[3]);
     576             :             }
     577             : 
     578             :           /* increment TX interface stat */
     579         106 :           vlib_increment_combined_counter (im->combined_sw_if_counters +
     580             :                                            VNET_INTERFACE_COUNTER_TX,
     581             :                                            thread_index, new_rx_sw_if_index,
     582             :                                            4 /* pkts */ , n_bytes);
     583         106 :           b += 4;
     584         106 :           next += 4;
     585         106 :           n_left_from -= 4;
     586         106 :           continue;
     587             :         }
     588             : 
     589             :       /*
     590             :        * Slow path: we know that at least one of the pkts
     591             :        * was transmitted on a different sw_if_index, so
     592             :        * check each sw_if_index against the cached data and proceed
     593             :        * accordingly.
     594             :        *
     595             :        * This shouldn't happen, but code can (and does) bypass the
     596             :        * per-interface output node, so deal with it.
     597             :        */
     598           0 :       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
     599             :                          != new_rx_sw_if_index))
     600             :         {
     601           0 :           config = l2input_intf_config
     602           0 :             (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
     603           0 :           next_index = (l2_input_is_bridge (config) ?
     604           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     605             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     606           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     607           0 :           new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     608             :         }
     609           0 :       next[0] = next_index;
     610           0 :       vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     611           0 :       vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     612           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
     613           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     614           0 :         vnet_update_l2_len (b[0]);
     615             : 
     616           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     617             :                                        VNET_INTERFACE_COUNTER_TX,
     618             :                                        thread_index, new_rx_sw_if_index,
     619             :                                        1 /* pkts */ , n_bytes);
     620             : 
     621           0 :       if (PREDICT_FALSE (vnet_buffer (b[1])->sw_if_index[VLIB_TX]
     622             :                          != new_rx_sw_if_index))
     623             :         {
     624           0 :           config = l2input_intf_config
     625           0 :             (vnet_buffer (b[1])->sw_if_index[VLIB_TX]);
     626           0 :           next_index = (l2_input_is_bridge (config) ?
     627           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     628             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     629           0 :           new_rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
     630           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     631             :         }
     632           0 :       next[1] = next_index;
     633           0 :       vnet_buffer (b[1])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     634           0 :       vnet_buffer (b[1])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     635           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[1]);
     636           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     637           0 :         vnet_update_l2_len (b[1]);
     638             : 
     639           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     640             :                                        VNET_INTERFACE_COUNTER_TX,
     641             :                                        thread_index, new_rx_sw_if_index,
     642             :                                        1 /* pkts */ , n_bytes);
     643             : 
     644           0 :       if (PREDICT_FALSE (vnet_buffer (b[2])->sw_if_index[VLIB_TX]
     645             :                          != new_rx_sw_if_index))
     646             :         {
     647           0 :           config = l2input_intf_config
     648           0 :             (vnet_buffer (b[2])->sw_if_index[VLIB_TX]);
     649           0 :           next_index = (l2_input_is_bridge (config) ?
     650           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     651             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     652           0 :           new_rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
     653           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     654             :         }
     655           0 :       next[2] = next_index;
     656           0 :       vnet_buffer (b[2])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     657           0 :       vnet_buffer (b[2])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     658           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[2]);
     659           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     660           0 :         vnet_update_l2_len (b[2]);
     661             : 
     662           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     663             :                                        VNET_INTERFACE_COUNTER_TX,
     664             :                                        thread_index, new_rx_sw_if_index,
     665             :                                        1 /* pkts */ , n_bytes);
     666             : 
     667           0 :       if (PREDICT_FALSE (vnet_buffer (b[3])->sw_if_index[VLIB_TX]
     668             :                          != new_rx_sw_if_index))
     669             :         {
     670           0 :           config = l2input_intf_config
     671           0 :             (vnet_buffer (b[3])->sw_if_index[VLIB_TX]);
     672           0 :           next_index = (l2_input_is_bridge (config) ?
     673           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     674             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     675           0 :           new_rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
     676           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     677             :         }
     678           0 :       next[3] = next_index;
     679           0 :       vnet_buffer (b[3])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     680           0 :       vnet_buffer (b[3])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     681           0 :       n_bytes = vlib_buffer_length_in_chain (vm, b[3]);
     682           0 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     683           0 :         vnet_update_l2_len (b[3]);
     684             : 
     685           0 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     686             :                                        VNET_INTERFACE_COUNTER_TX,
     687             :                                        thread_index, new_rx_sw_if_index,
     688             :                                        1 /* pkts */ , n_bytes);
     689           0 :       b += 4;
     690           0 :       next += 4;
     691           0 :       n_left_from -= 4;
     692             :     }
     693         308 :   while (n_left_from > 0)
     694             :     {
     695         174 :       if (PREDICT_FALSE (vnet_buffer (b[0])->sw_if_index[VLIB_TX]
     696             :                          != new_rx_sw_if_index))
     697             :         {
     698           0 :           config = l2input_intf_config
     699           0 :             (vnet_buffer (b[0])->sw_if_index[VLIB_TX]);
     700           0 :           next_index = (l2_input_is_bridge (config) ?
     701           0 :                         VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT :
     702             :                         VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     703           0 :           new_tx_sw_if_index = l2_input_is_bvi (config) ? L2INPUT_BVI : ~0;
     704           0 :           new_rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     705             :         }
     706         174 :       next[0] = next_index;
     707         174 :       vnet_buffer (b[0])->sw_if_index[VLIB_RX] = new_rx_sw_if_index;
     708         174 :       vnet_buffer (b[0])->sw_if_index[VLIB_TX] = new_tx_sw_if_index;
     709         174 :       n_bytes = vlib_buffer_length_in_chain (vm, b[0]);
     710         174 :       if (next_index == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT)
     711         102 :         vnet_update_l2_len (b[0]);
     712             : 
     713         174 :       vlib_increment_combined_counter (im->combined_sw_if_counters +
     714             :                                        VNET_INTERFACE_COUNTER_TX,
     715             :                                        thread_index, new_rx_sw_if_index,
     716             :                                        1 /* pkts */ , n_bytes);
     717         174 :       b += 1;
     718         174 :       next += 1;
     719         174 :       n_left_from -= 1;
     720             :     }
     721             : 
     722         134 :   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
     723             : 
     724         134 :   return frame->n_vectors;
     725             : }
     726             : 
     727             : static u8 *
     728         463 : format_simulated_ethernet_name (u8 * s, va_list * args)
     729             : {
     730         463 :   u32 dev_instance = va_arg (*args, u32);
     731         463 :   return format (s, "loop%d", dev_instance);
     732             : }
     733             : 
     734             : static clib_error_t *
     735         202 : simulated_ethernet_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     736             :                                   u32 flags)
     737             : {
     738         202 :   u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
     739             :     VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
     740         202 :   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
     741         202 :   return 0;
     742             : }
     743             : 
     744             : static clib_error_t *
     745           0 : simulated_ethernet_mac_change (vnet_hw_interface_t * hi,
     746             :                                const u8 * old_address, const u8 * mac_address)
     747             : {
     748           0 :   l2input_interface_mac_change (hi->sw_if_index, old_address, mac_address);
     749             : 
     750           0 :   return (NULL);
     751             : }
     752             : 
     753             : 
     754             : /* *INDENT-OFF* */
     755       11199 : VNET_DEVICE_CLASS (ethernet_simulated_device_class) = {
     756             :   .name = "Loopback",
     757             :   .format_device_name = format_simulated_ethernet_name,
     758             :   .tx_function = simulated_ethernet_interface_tx,
     759             :   .admin_up_down_function = simulated_ethernet_admin_up_down,
     760             :   .mac_addr_change_function = simulated_ethernet_mac_change,
     761             : };
     762             : /* *INDENT-ON* */
     763             : 
     764             : /*
     765             :  * Maintain a bitmap of allocated loopback instance numbers.
     766             :  */
     767             : #define LOOPBACK_MAX_INSTANCE           (16 * 1024)
     768             : 
     769             : static u32
     770         176 : loopback_instance_alloc (u8 is_specified, u32 want)
     771             : {
     772         176 :   ethernet_main_t *em = &ethernet_main;
     773             : 
     774             :   /*
     775             :    * Check for dynamically allocaetd instance number.
     776             :    */
     777         176 :   if (!is_specified)
     778             :     {
     779             :       u32 bit;
     780             : 
     781         174 :       bit = clib_bitmap_first_clear (em->bm_loopback_instances);
     782         174 :       if (bit >= LOOPBACK_MAX_INSTANCE)
     783             :         {
     784           0 :           return ~0;
     785             :         }
     786         174 :       em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
     787             :                                                    bit, 1);
     788         174 :       return bit;
     789             :     }
     790             : 
     791             :   /*
     792             :    * In range?
     793             :    */
     794           2 :   if (want >= LOOPBACK_MAX_INSTANCE)
     795             :     {
     796           0 :       return ~0;
     797             :     }
     798             : 
     799             :   /*
     800             :    * Already in use?
     801             :    */
     802           2 :   if (clib_bitmap_get (em->bm_loopback_instances, want))
     803             :     {
     804           0 :       return ~0;
     805             :     }
     806             : 
     807             :   /*
     808             :    * Grant allocation request.
     809             :    */
     810           2 :   em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
     811             :                                                want, 1);
     812             : 
     813           2 :   return want;
     814             : }
     815             : 
     816             : static int
     817         107 : loopback_instance_free (u32 instance)
     818             : {
     819         107 :   ethernet_main_t *em = &ethernet_main;
     820             : 
     821         107 :   if (instance >= LOOPBACK_MAX_INSTANCE)
     822             :     {
     823           0 :       return -1;
     824             :     }
     825             : 
     826         107 :   if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0)
     827             :     {
     828           0 :       return -1;
     829             :     }
     830             : 
     831         107 :   em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances,
     832             :                                                instance, 0);
     833         107 :   return 0;
     834             : }
     835             : 
     836             : int
     837         176 : vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address,
     838             :                                 u8 is_specified, u32 user_instance)
     839             : {
     840         176 :   vnet_main_t *vnm = vnet_get_main ();
     841         176 :   vlib_main_t *vm = vlib_get_main ();
     842             :   u32 instance;
     843             :   u8 address[6];
     844             :   u32 hw_if_index;
     845             :   vnet_hw_interface_t *hw_if;
     846             :   u32 slot;
     847             : 
     848         176 :   ASSERT (sw_if_indexp);
     849             : 
     850         176 :   *sw_if_indexp = (u32) ~ 0;
     851             : 
     852         176 :   clib_memset (address, 0, sizeof (address));
     853             : 
     854             :   /*
     855             :    * Allocate a loopback instance.  Either select on dynamically
     856             :    * or try to use the desired user_instance number.
     857             :    */
     858         176 :   instance = loopback_instance_alloc (is_specified, user_instance);
     859         176 :   if (instance == ~0)
     860             :     {
     861           0 :       return VNET_API_ERROR_INVALID_REGISTRATION;
     862             :     }
     863             : 
     864             :   /*
     865             :    * Default MAC address (dead:0000:0000 + instance) is allocated
     866             :    * if zero mac_address is configured. Otherwise, user-configurable MAC
     867             :    * address is programmed on the loopback interface.
     868             :    */
     869         176 :   if (memcmp (address, mac_address, sizeof (address)))
     870          20 :     clib_memcpy (address, mac_address, sizeof (address));
     871             :   else
     872             :     {
     873         156 :       address[0] = 0xde;
     874         156 :       address[1] = 0xad;
     875         156 :       address[5] = instance;
     876             :     }
     877             : 
     878         176 :   vnet_eth_interface_registration_t eir = {};
     879         176 :   eir.dev_class_index = ethernet_simulated_device_class.index;
     880         176 :   eir.dev_instance = instance;
     881         176 :   eir.address = address;
     882         176 :   hw_if_index = vnet_eth_register_interface (vnm, &eir);
     883         176 :   hw_if = vnet_get_hw_interface (vnm, hw_if_index);
     884         352 :   slot = vlib_node_add_named_next_with_slot
     885         176 :     (vm, hw_if->tx_node_index,
     886             :      "ethernet-input", VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     887         176 :   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
     888             : 
     889         352 :   slot = vlib_node_add_named_next_with_slot
     890         176 :     (vm, hw_if->tx_node_index,
     891             :      "l2-input", VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
     892         176 :   ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_L2_INPUT);
     893             : 
     894             :   {
     895         176 :     vnet_sw_interface_t *si = vnet_get_hw_sw_interface (vnm, hw_if_index);
     896         176 :     *sw_if_indexp = si->sw_if_index;
     897             : 
     898             :     /* By default don't flood to loopbacks, as packets just keep
     899             :      * coming back ... If this loopback becomes a BVI, we'll change it */
     900         176 :     si->flood_class = VNET_FLOOD_CLASS_NO_FLOOD;
     901             :   }
     902             : 
     903         176 :   return 0;
     904             : }
     905             : 
     906             : static clib_error_t *
     907           5 : create_simulated_ethernet_interfaces (vlib_main_t * vm,
     908             :                                       unformat_input_t * input,
     909             :                                       vlib_cli_command_t * cmd)
     910             : {
     911             :   int rv;
     912             :   u32 sw_if_index;
     913             :   u8 mac_address[6];
     914           5 :   u8 is_specified = 0;
     915           5 :   u32 user_instance = 0;
     916             : 
     917           5 :   clib_memset (mac_address, 0, sizeof (mac_address));
     918             : 
     919           5 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     920             :     {
     921           0 :       if (unformat (input, "mac %U", unformat_ethernet_address, mac_address))
     922             :         ;
     923           0 :       if (unformat (input, "instance %d", &user_instance))
     924           0 :         is_specified = 1;
     925             :       else
     926           0 :         break;
     927             :     }
     928             : 
     929           5 :   rv = vnet_create_loopback_interface (&sw_if_index, mac_address,
     930             :                                        is_specified, user_instance);
     931             : 
     932           5 :   if (rv)
     933           0 :     return clib_error_return (0, "vnet_create_loopback_interface failed");
     934             : 
     935           5 :   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
     936             :                    sw_if_index);
     937           5 :   return 0;
     938             : }
     939             : 
     940             : /*?
     941             :  * Create a loopback interface. Optionally, a MAC Address can be
     942             :  * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
     943             :  *
     944             :  * @cliexpar
     945             :  * The following two command syntaxes are equivalent:
     946             :  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
     947             :  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
     948             :  * Example of how to create a loopback interface:
     949             :  * @cliexcmd{loopback create-interface}
     950             : ?*/
     951             : /* *INDENT-OFF* */
     952      272887 : VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = {
     953             :   .path = "loopback create-interface",
     954             :   .short_help = "loopback create-interface [mac <mac-addr>] [instance <instance>]",
     955             :   .function = create_simulated_ethernet_interfaces,
     956             : };
     957             : /* *INDENT-ON* */
     958             : 
     959             : /*?
     960             :  * Create a loopback interface. Optionally, a MAC Address can be
     961             :  * provided. If not provided, de:ad:00:00:00:<loopId> will be used.
     962             :  *
     963             :  * @cliexpar
     964             :  * The following two command syntaxes are equivalent:
     965             :  * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
     966             :  * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <instance>]}
     967             :  * Example of how to create a loopback interface:
     968             :  * @cliexcmd{create loopback interface}
     969             : ?*/
     970             : /* *INDENT-OFF* */
     971      272887 : VLIB_CLI_COMMAND (create_loopback_interface_command, static) = {
     972             :   .path = "create loopback interface",
     973             :   .short_help = "create loopback interface [mac <mac-addr>] [instance <instance>]",
     974             :   .function = create_simulated_ethernet_interfaces,
     975             : };
     976             : /* *INDENT-ON* */
     977             : 
     978             : ethernet_interface_t *
     979     1992820 : ethernet_get_interface (ethernet_main_t * em, u32 hw_if_index)
     980             : {
     981             :   vnet_hw_interface_t *i =
     982     1992820 :     vnet_get_hw_interface (vnet_get_main (), hw_if_index);
     983     1992820 :   return (i->hw_class_index ==
     984     1992820 :           ethernet_hw_interface_class.
     985     1992820 :           index ? pool_elt_at_index (em->interfaces, i->hw_instance) : 0);
     986             : }
     987             : 
     988             : mac_address_t *
     989       25172 : ethernet_interface_add_del_address (ethernet_main_t * em,
     990             :                                     u32 hw_if_index, const u8 * address,
     991             :                                     u8 is_add)
     992             : {
     993       25172 :   ethernet_interface_t *ei = ethernet_get_interface (em, hw_if_index);
     994       25172 :   ethernet_interface_address_t *if_addr = 0;
     995       25172 :   int found = 0;
     996             : 
     997             :   /* return if there is not an ethernet interface for this hw interface */
     998       25172 :   if (!ei)
     999           0 :     return 0;
    1000             : 
    1001             :   /* determine whether the address is configured on the interface */
    1002      279578 :   vec_foreach (if_addr, ei->secondary_addrs)
    1003             :   {
    1004      267540 :     if (ethernet_mac_address_equal (if_addr->mac.bytes, address))
    1005             :       {
    1006       13134 :         found = 1;
    1007       13134 :         break;
    1008             :       }
    1009             :   }
    1010             : 
    1011       25172 :   if (is_add)
    1012             :     {
    1013       14422 :       if (!found)
    1014             :         {
    1015             :           /* address not found yet: add it */
    1016       12031 :           vec_add2 (ei->secondary_addrs, if_addr, 1);
    1017       12031 :           ethernet_interface_address_copy (if_addr, address);
    1018             :         }
    1019       14422 :       return &if_addr->mac;
    1020             :     }
    1021             : 
    1022             :   /* delete case */
    1023       10750 :   if (found)
    1024       10743 :     vec_delete (ei->secondary_addrs, 1, if_addr - ei->secondary_addrs);
    1025             : 
    1026       10750 :   return 0;
    1027             : }
    1028             : 
    1029             : int
    1030         107 : vnet_delete_loopback_interface (u32 sw_if_index)
    1031             : {
    1032         107 :   vnet_main_t *vnm = vnet_get_main ();
    1033             : 
    1034         107 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    1035           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1036             : 
    1037         107 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1038         107 :   if (hw == 0 || hw->dev_class_index != ethernet_simulated_device_class.index)
    1039           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1040             : 
    1041         107 :   if (loopback_instance_free (hw->dev_instance) < 0)
    1042           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1043             : 
    1044         107 :   ethernet_delete_interface (vnm, hw->hw_if_index);
    1045             : 
    1046         107 :   return 0;
    1047             : }
    1048             : 
    1049             : int
    1050          18 : vnet_create_sub_interface (u32 sw_if_index, u32 id,
    1051             :                            u32 flags, u16 inner_vlan_id, u16 outer_vlan_id,
    1052             :                            u32 * sub_sw_if_index)
    1053             : {
    1054          18 :   vnet_main_t *vnm = vnet_get_main ();
    1055          18 :   vnet_interface_main_t *im = &vnm->interface_main;
    1056             :   vnet_hw_interface_t *hi;
    1057          18 :   u64 sup_and_sub_key = ((u64) (sw_if_index) << 32) | (u64) id;
    1058             :   vnet_sw_interface_t template;
    1059             :   uword *p;
    1060             :   u64 *kp;
    1061             : 
    1062          18 :   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1063             : 
    1064          18 :   p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
    1065          18 :   if (p)
    1066             :     {
    1067           0 :       return (VNET_API_ERROR_VLAN_ALREADY_EXISTS);
    1068             :     }
    1069             : 
    1070          18 :   clib_memset (&template, 0, sizeof (template));
    1071          18 :   template.type = VNET_SW_INTERFACE_TYPE_SUB;
    1072          18 :   template.flood_class = VNET_FLOOD_CLASS_NORMAL;
    1073          18 :   template.sup_sw_if_index = sw_if_index;
    1074          18 :   template.sub.id = id;
    1075          18 :   template.sub.eth.raw_flags = flags;
    1076          18 :   template.sub.eth.outer_vlan_id = outer_vlan_id;
    1077          18 :   template.sub.eth.inner_vlan_id = inner_vlan_id;
    1078             : 
    1079          18 :   if (vnet_create_sw_interface (vnm, &template, sub_sw_if_index))
    1080           0 :     return (VNET_API_ERROR_UNSPECIFIED);
    1081             : 
    1082          18 :   kp = clib_mem_alloc (sizeof (*kp));
    1083          18 :   *kp = sup_and_sub_key;
    1084             : 
    1085          18 :   hash_set (hi->sub_interface_sw_if_index_by_id, id, *sub_sw_if_index);
    1086          36 :   hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, *sub_sw_if_index);
    1087             : 
    1088          18 :   return (0);
    1089             : }
    1090             : 
    1091             : int
    1092          63 : vnet_delete_sub_interface (u32 sw_if_index)
    1093             : {
    1094          63 :   vnet_main_t *vnm = vnet_get_main ();
    1095             :   vnet_sw_interface_t *si;
    1096          63 :   int rv = 0;
    1097             : 
    1098          63 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    1099           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1100             : 
    1101          63 :   si = vnet_get_sw_interface (vnm, sw_if_index);
    1102          63 :   if (si->type == VNET_SW_INTERFACE_TYPE_SUB ||
    1103          21 :       si->type == VNET_SW_INTERFACE_TYPE_PIPE ||
    1104          21 :       si->type == VNET_SW_INTERFACE_TYPE_P2P)
    1105          63 :     {
    1106          63 :       vnet_interface_main_t *im = &vnm->interface_main;
    1107          63 :       vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1108          63 :       u64 sup_and_sub_key =
    1109          63 :         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
    1110          63 :       hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
    1111          63 :       hash_unset (hi->sub_interface_sw_if_index_by_id, si->sub.id);
    1112          63 :       vnet_delete_sw_interface (vnm, sw_if_index);
    1113             :     }
    1114             :   else
    1115           0 :     rv = VNET_API_ERROR_INVALID_SUB_SW_IF_INDEX;
    1116             : 
    1117          63 :   return rv;
    1118             : }
    1119             : 
    1120             : static clib_error_t *
    1121           0 : delete_simulated_ethernet_interfaces (vlib_main_t * vm,
    1122             :                                       unformat_input_t * input,
    1123             :                                       vlib_cli_command_t * cmd)
    1124             : {
    1125             :   int rv;
    1126           0 :   u32 sw_if_index = ~0;
    1127           0 :   vnet_main_t *vnm = vnet_get_main ();
    1128             : 
    1129           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1130             :     {
    1131           0 :       if (unformat (input, "intfc %U",
    1132             :                     unformat_vnet_sw_interface, vnm, &sw_if_index))
    1133             :         ;
    1134             :       else
    1135           0 :         break;
    1136             :     }
    1137             : 
    1138           0 :   if (sw_if_index == ~0)
    1139           0 :     return clib_error_return (0, "interface not specified");
    1140             : 
    1141           0 :   rv = vnet_delete_loopback_interface (sw_if_index);
    1142             : 
    1143           0 :   if (rv)
    1144           0 :     return clib_error_return (0, "vnet_delete_loopback_interface failed");
    1145             : 
    1146           0 :   return 0;
    1147             : }
    1148             : 
    1149             : static clib_error_t *
    1150           0 : delete_sub_interface (vlib_main_t * vm,
    1151             :                       unformat_input_t * input, vlib_cli_command_t * cmd)
    1152             : {
    1153           0 :   int rv = 0;
    1154           0 :   u32 sw_if_index = ~0;
    1155           0 :   vnet_main_t *vnm = vnet_get_main ();
    1156             : 
    1157           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1158             :     {
    1159           0 :       if (unformat
    1160             :           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
    1161             :         ;
    1162             :       else
    1163           0 :         break;
    1164             :     }
    1165           0 :   if (sw_if_index == ~0)
    1166           0 :     return clib_error_return (0, "interface doesn't exist");
    1167             : 
    1168           0 :   if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
    1169           0 :     rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
    1170             :   else
    1171           0 :     rv = vnet_delete_sub_interface (sw_if_index);
    1172           0 :   if (rv)
    1173           0 :     return clib_error_return (0, "delete_subinterface_interface failed");
    1174           0 :   return 0;
    1175             : }
    1176             : 
    1177             : /*?
    1178             :  * Delete a loopback interface.
    1179             :  *
    1180             :  * @cliexpar
    1181             :  * The following two command syntaxes are equivalent:
    1182             :  * @cliexcmd{loopback delete-interface intfc <interface>}
    1183             :  * @cliexcmd{delete loopback interface intfc <interface>}
    1184             :  * Example of how to delete a loopback interface:
    1185             :  * @cliexcmd{loopback delete-interface intfc loop0}
    1186             : ?*/
    1187             : /* *INDENT-OFF* */
    1188      272887 : VLIB_CLI_COMMAND (delete_simulated_ethernet_interface_command, static) = {
    1189             :   .path = "loopback delete-interface",
    1190             :   .short_help = "loopback delete-interface intfc <interface>",
    1191             :   .function = delete_simulated_ethernet_interfaces,
    1192             : };
    1193             : /* *INDENT-ON* */
    1194             : 
    1195             : /*?
    1196             :  * Delete a loopback interface.
    1197             :  *
    1198             :  * @cliexpar
    1199             :  * The following two command syntaxes are equivalent:
    1200             :  * @cliexcmd{loopback delete-interface intfc <interface>}
    1201             :  * @cliexcmd{delete loopback interface intfc <interface>}
    1202             :  * Example of how to delete a loopback interface:
    1203             :  * @cliexcmd{delete loopback interface intfc loop0}
    1204             : ?*/
    1205             : /* *INDENT-OFF* */
    1206      272887 : VLIB_CLI_COMMAND (delete_loopback_interface_command, static) = {
    1207             :   .path = "delete loopback interface",
    1208             :   .short_help = "delete loopback interface intfc <interface>",
    1209             :   .function = delete_simulated_ethernet_interfaces,
    1210             : };
    1211             : /* *INDENT-ON* */
    1212             : 
    1213             : /*?
    1214             :  * Delete a sub-interface.
    1215             :  *
    1216             :  * @cliexpar
    1217             :  * Example of how to delete a sub-interface:
    1218             :  * @cliexcmd{delete sub-interface GigabitEthernet0/8/0.200}
    1219             : ?*/
    1220             : /* *INDENT-OFF* */
    1221      272887 : VLIB_CLI_COMMAND (delete_sub_interface_command, static) = {
    1222             :   .path = "delete sub-interface",
    1223             :   .short_help = "delete sub-interface <interface>",
    1224             :   .function = delete_sub_interface,
    1225             : };
    1226             : /* *INDENT-ON* */
    1227             : 
    1228             : /* ethernet { ... } configuration. */
    1229             : /*?
    1230             :  *
    1231             :  * @cfgcmd{default-mtu &lt;n&gt;}
    1232             :  * Specify the default mtu in the range of 64-9000. The default is 9000 bytes.
    1233             :  *
    1234             :  */
    1235             : static clib_error_t *
    1236         559 : ethernet_config (vlib_main_t * vm, unformat_input_t * input)
    1237             : {
    1238         559 :   ethernet_main_t *em = &ethernet_main;
    1239             : 
    1240         559 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
    1241             :     {
    1242           0 :       if (unformat (input, "default-mtu %u", &em->default_mtu))
    1243             :         {
    1244           0 :           if (em->default_mtu < 64 || em->default_mtu > 9000)
    1245           0 :             return clib_error_return (0, "default MTU must be >=64, <=9000");
    1246             :         }
    1247             :       else
    1248             :         {
    1249           0 :           return clib_error_return (0, "unknown input '%U'",
    1250             :                                     format_unformat_error, input);
    1251             :         }
    1252             :     }
    1253         559 :   return 0;
    1254             : }
    1255             : 
    1256        7306 : VLIB_CONFIG_FUNCTION (ethernet_config, "ethernet");
    1257             : 
    1258             : /*
    1259             :  * fd.io coding-style-patch-verification: ON
    1260             :  *
    1261             :  * Local Variables:
    1262             :  * eval: (c-set-style "gnu")
    1263             :  * End:
    1264             :  */

Generated by: LCOV version 1.14