LCOV - code coverage report
Current view: top level - vnet - interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 549 841 65.3 %
Date: 2023-10-26 01:39:38 Functions: 45 67 67.2 %

          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             :  * interface.c: VNET interfaces/sub-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/plugin/plugin.h>
      42             : #include <vnet/adj/adj.h>
      43             : #include <vnet/adj/adj_mcast.h>
      44             : #include <vnet/ip/ip.h>
      45             : #include <vnet/interface/rx_queue_funcs.h>
      46             : #include <vnet/interface/tx_queue_funcs.h>
      47             : 
      48             : /* *INDENT-OFF* */
      49         575 : VLIB_REGISTER_LOG_CLASS (if_default_log, static) = {
      50             :   .class_name = "interface",
      51             : };
      52             : /* *INDENT-ON* */
      53             : 
      54             : #define log_debug(fmt,...) vlib_log_debug(if_default_log.class, fmt, __VA_ARGS__)
      55             : #define log_err(fmt,...) vlib_log_err(if_default_log.class, fmt, __VA_ARGS__)
      56             : 
      57             : typedef enum vnet_interface_helper_flags_t_
      58             : {
      59             :   VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE = (1 << 0),
      60             :   VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE = (1 << 1),
      61             : } vnet_interface_helper_flags_t;
      62             : 
      63             : static clib_error_t *vnet_hw_interface_set_flags_helper (vnet_main_t * vnm,
      64             :                                                          u32 hw_if_index,
      65             :                                                          vnet_hw_interface_flags_t
      66             :                                                          flags,
      67             :                                                          vnet_interface_helper_flags_t
      68             :                                                          helper_flags);
      69             : 
      70             : static clib_error_t *vnet_sw_interface_set_flags_helper (vnet_main_t * vnm,
      71             :                                                          u32 sw_if_index,
      72             :                                                          vnet_sw_interface_flags_t
      73             :                                                          flags,
      74             :                                                          vnet_interface_helper_flags_t
      75             :                                                          helper_flags);
      76             : 
      77             : static clib_error_t *vnet_hw_interface_set_class_helper (vnet_main_t * vnm,
      78             :                                                          u32 hw_if_index,
      79             :                                                          u32 hw_class_index,
      80             :                                                          u32 redistribute);
      81             : 
      82             : typedef struct
      83             : {
      84             :   /* Either sw or hw interface index. */
      85             :   u32 sw_hw_if_index;
      86             : 
      87             :   /* Flags. */
      88             :   u32 flags;
      89             : } vnet_sw_hw_interface_state_t;
      90             : 
      91             : static void
      92           0 : serialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m, va_list * va)
      93             : {
      94           0 :   vnet_sw_hw_interface_state_t *s =
      95             :     va_arg (*va, vnet_sw_hw_interface_state_t *);
      96           0 :   u32 n = va_arg (*va, u32);
      97             :   u32 i;
      98           0 :   for (i = 0; i < n; i++)
      99             :     {
     100           0 :       serialize_integer (m, s[i].sw_hw_if_index,
     101             :                          sizeof (s[i].sw_hw_if_index));
     102           0 :       serialize_integer (m, s[i].flags, sizeof (s[i].flags));
     103             :     }
     104           0 : }
     105             : 
     106             : static void
     107           0 : unserialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m,
     108             :                                             va_list * va)
     109             : {
     110           0 :   vnet_sw_hw_interface_state_t *s =
     111             :     va_arg (*va, vnet_sw_hw_interface_state_t *);
     112           0 :   u32 n = va_arg (*va, u32);
     113             :   u32 i;
     114           0 :   for (i = 0; i < n; i++)
     115             :     {
     116           0 :       unserialize_integer (m, &s[i].sw_hw_if_index,
     117             :                            sizeof (s[i].sw_hw_if_index));
     118           0 :       unserialize_integer (m, &s[i].flags, sizeof (s[i].flags));
     119             :     }
     120           0 : }
     121             : 
     122             : static vnet_sw_interface_flags_t
     123           0 : vnet_hw_interface_flags_to_sw (vnet_hw_interface_flags_t hwf)
     124             : {
     125           0 :   vnet_sw_interface_flags_t swf = VNET_SW_INTERFACE_FLAG_NONE;
     126             : 
     127           0 :   if (hwf & VNET_HW_INTERFACE_FLAG_LINK_UP)
     128           0 :     swf |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
     129             : 
     130           0 :   return (swf);
     131             : }
     132             : 
     133             : void
     134           0 : serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
     135             : {
     136           0 :   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
     137           0 :   vnet_sw_hw_interface_state_t *sts = 0, *st;
     138             :   vnet_sw_interface_t *sif;
     139             :   vnet_hw_interface_t *hif;
     140           0 :   vnet_interface_main_t *im = &vnm->interface_main;
     141             : 
     142             :   /* Serialize hardware interface classes since they may have changed.
     143             :      Must do this before sending up/down flags. */
     144             :   /* *INDENT-OFF* */
     145           0 :   pool_foreach (hif, im->hw_interfaces)  {
     146           0 :     vnet_hw_interface_class_t * hw_class = vnet_get_hw_interface_class (vnm, hif->hw_class_index);
     147           0 :     serialize_cstring (m, hw_class->name);
     148             :   }
     149             :   /* *INDENT-ON* */
     150             : 
     151             :   /* Send sw/hw interface state when non-zero. */
     152             :   /* *INDENT-OFF* */
     153           0 :   pool_foreach (sif, im->sw_interfaces)  {
     154           0 :     if (sif->flags != 0)
     155             :       {
     156           0 :         vec_add2 (sts, st, 1);
     157           0 :         st->sw_hw_if_index = sif->sw_if_index;
     158           0 :         st->flags = sif->flags;
     159             :       }
     160             :   }
     161             :   /* *INDENT-ON* */
     162             : 
     163           0 :   vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
     164             : 
     165           0 :   if (sts)
     166           0 :     vec_set_len (sts, 0);
     167             : 
     168             :   /* *INDENT-OFF* */
     169           0 :   pool_foreach (hif, im->hw_interfaces)  {
     170           0 :     if (hif->flags != 0)
     171             :       {
     172           0 :         vec_add2 (sts, st, 1);
     173           0 :         st->sw_hw_if_index = hif->hw_if_index;
     174           0 :         st->flags = vnet_hw_interface_flags_to_sw(hif->flags);
     175             :       }
     176             :   }
     177             :   /* *INDENT-ON* */
     178             : 
     179           0 :   vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
     180             : 
     181           0 :   vec_free (sts);
     182           0 : }
     183             : 
     184             : static vnet_hw_interface_flags_t
     185           0 : vnet_sw_interface_flags_to_hw (vnet_sw_interface_flags_t swf)
     186             : {
     187           0 :   vnet_hw_interface_flags_t hwf = VNET_HW_INTERFACE_FLAG_NONE;
     188             : 
     189           0 :   if (swf & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     190           0 :     hwf |= VNET_HW_INTERFACE_FLAG_LINK_UP;
     191             : 
     192           0 :   return (hwf);
     193             : }
     194             : 
     195             : void
     196           0 : unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
     197             : {
     198           0 :   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
     199           0 :   vnet_sw_hw_interface_state_t *sts = 0, *st;
     200             : 
     201             :   /* First set interface hardware class. */
     202             :   {
     203           0 :     vnet_interface_main_t *im = &vnm->interface_main;
     204             :     vnet_hw_interface_t *hif;
     205             :     char *class_name;
     206             :     uword *p;
     207             :     clib_error_t *error;
     208             : 
     209             :     /* *INDENT-OFF* */
     210           0 :     pool_foreach (hif, im->hw_interfaces)  {
     211           0 :       unserialize_cstring (m, &class_name);
     212           0 :       p = hash_get_mem (im->hw_interface_class_by_name, class_name);
     213           0 :       if (p)
     214             :         {
     215           0 :           error = vnet_hw_interface_set_class_helper
     216           0 :             (vnm, hif->hw_if_index, p[0], /* redistribute */ 0);
     217             :         }
     218             :       else
     219           0 :         error = clib_error_return (0, "hw class %s AWOL?", class_name);
     220             : 
     221           0 :       if (error)
     222           0 :         clib_error_report (error);
     223           0 :       vec_free (class_name);
     224             :     }
     225             :     /* *INDENT-ON* */
     226             :   }
     227             : 
     228           0 :   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
     229           0 :   vec_foreach (st, sts)
     230           0 :     vnet_sw_interface_set_flags_helper (vnm, st->sw_hw_if_index, st->flags,
     231             :                                         /* no distribute */ 0);
     232           0 :   vec_free (sts);
     233             : 
     234           0 :   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
     235           0 :   vec_foreach (st, sts)
     236             :   {
     237           0 :     vnet_hw_interface_set_flags_helper
     238           0 :       (vnm, st->sw_hw_if_index, vnet_sw_interface_flags_to_hw (st->flags),
     239             :        /* no distribute */ 0);
     240             :   }
     241           0 :   vec_free (sts);
     242           0 : }
     243             : 
     244             : static clib_error_t *
     245       55389 : call_elf_section_interface_callbacks (vnet_main_t * vnm, u32 if_index,
     246             :                                       u32 flags,
     247             :                                       _vnet_interface_function_list_elt_t **
     248             :                                       elts)
     249             : {
     250             :   _vnet_interface_function_list_elt_t *elt;
     251             :   vnet_interface_function_priority_t prio;
     252       55389 :   clib_error_t *error = 0;
     253             : 
     254      166167 :   for (prio = VNET_ITF_FUNC_PRIORITY_LOW;
     255      110778 :        prio <= VNET_ITF_FUNC_PRIORITY_HIGH; prio++)
     256             :     {
     257      110778 :       elt = elts[prio];
     258             : 
     259      846571 :       while (elt)
     260             :         {
     261      735793 :           error = elt->fp (vnm, if_index, flags);
     262      735793 :           if (error)
     263           0 :             return error;
     264      735793 :           elt = elt->next_interface_function;
     265             :         }
     266             :     }
     267       55389 :   return error;
     268             : }
     269             : 
     270             : static clib_error_t *
     271       10614 : call_hw_interface_add_del_callbacks (vnet_main_t * vnm, u32 hw_if_index,
     272             :                                      u32 is_create)
     273             : {
     274       10614 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     275             :   vnet_hw_interface_class_t *hw_class =
     276       10614 :     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     277             :   vnet_device_class_t *dev_class =
     278       10614 :     vnet_get_device_class (vnm, hi->dev_class_index);
     279       10614 :   clib_error_t *error = 0;
     280             : 
     281       10614 :   if (hw_class->interface_add_del_function
     282           0 :       && (error =
     283           0 :           hw_class->interface_add_del_function (vnm, hw_if_index, is_create)))
     284           0 :     return error;
     285             : 
     286       10614 :   if (dev_class->interface_add_del_function
     287           0 :       && (error =
     288           0 :           dev_class->interface_add_del_function (vnm, hw_if_index,
     289             :                                                  is_create)))
     290           0 :     return error;
     291             : 
     292       10614 :   error = call_elf_section_interface_callbacks
     293       10614 :     (vnm, hw_if_index, is_create, vnm->hw_interface_add_del_functions);
     294             : 
     295       10614 :   return error;
     296             : }
     297             : 
     298             : static clib_error_t *
     299       11798 : call_sw_interface_add_del_callbacks (vnet_main_t * vnm, u32 sw_if_index,
     300             :                                      u32 is_create)
     301             : {
     302       23596 :   return call_elf_section_interface_callbacks
     303       11798 :     (vnm, sw_if_index, is_create, vnm->sw_interface_add_del_functions);
     304             : }
     305             : 
     306             : static clib_error_t *
     307       37082 : vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
     308             :                                     vnet_hw_interface_flags_t flags,
     309             :                                     vnet_interface_helper_flags_t
     310             :                                     helper_flags)
     311             : {
     312       37082 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     313             :   vnet_hw_interface_class_t *hw_class =
     314       37082 :     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     315             :   u32 mask;
     316       37082 :   clib_error_t *error = 0;
     317       37082 :   u32 is_create =
     318       37082 :     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
     319             : 
     320       37082 :   mask =
     321             :     (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK);
     322       37082 :   flags &= mask;
     323             : 
     324             :   /* Call hardware interface add/del callbacks. */
     325       37082 :   if (is_create)
     326        6428 :     call_hw_interface_add_del_callbacks (vnm, hw_if_index, is_create);
     327             : 
     328             :   /* Already in the desired state? */
     329       37082 :   if (!is_create && (hi->flags & mask) == flags)
     330       17318 :     goto done;
     331             : 
     332       19764 :   if ((hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) !=
     333             :       (flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
     334             :     {
     335             :       /* Do hardware class (e.g. ethernet). */
     336       13336 :       if (hw_class->link_up_down_function
     337           0 :           && (error = hw_class->link_up_down_function (vnm, hw_if_index,
     338             :                                                        flags)))
     339           0 :         goto done;
     340             : 
     341       13336 :       error = call_elf_section_interface_callbacks
     342       13336 :         (vnm, hw_if_index, flags, vnm->hw_interface_link_up_down_functions);
     343             : 
     344       13336 :       if (error)
     345           0 :         goto done;
     346             :     }
     347             : 
     348       19764 :   hi->flags &= ~mask;
     349       19764 :   hi->flags |= flags;
     350             : 
     351       37082 : done:
     352       37082 :   if (error)
     353           0 :     log_err ("hw_set_flags_helper: %U", format_clib_error, error);
     354       37082 :   return error;
     355             : }
     356             : 
     357             : static clib_error_t *
     358       36833 : vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
     359             :                                     vnet_sw_interface_flags_t flags,
     360             :                                     vnet_interface_helper_flags_t
     361             :                                     helper_flags)
     362             : {
     363       36833 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     364             :   u32 mask;
     365       36833 :   clib_error_t *error = 0;
     366       36833 :   u32 is_create =
     367       36833 :     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
     368             :   u32 old_flags;
     369             : 
     370       36833 :   mask = VNET_SW_INTERFACE_FLAG_ADMIN_UP | VNET_SW_INTERFACE_FLAG_PUNT;
     371       36833 :   flags &= mask;
     372             : 
     373       36833 :   if (is_create)
     374             :     {
     375             :       error =
     376        7547 :         call_sw_interface_add_del_callbacks (vnm, sw_if_index, is_create);
     377        7547 :       if (error)
     378           0 :         goto done;
     379             : 
     380        7547 :       if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     381             :         {
     382             :           /* Notify everyone when the interface is created as admin up */
     383           0 :           error = call_elf_section_interface_callbacks (vnm, sw_if_index,
     384             :                                                         flags,
     385           0 :                                                         vnm->
     386             :                                                         sw_interface_admin_up_down_functions);
     387           0 :           if (error)
     388           0 :             goto done;
     389             :         }
     390             :     }
     391             :   else
     392             :     {
     393       29286 :       vnet_sw_interface_t *si_sup = si;
     394             : 
     395             :       /* Check that super interface is in correct state. */
     396       29286 :       if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
     397             :         {
     398         144 :           si_sup = vnet_get_sw_interface (vnm, si->sup_sw_if_index);
     399             : 
     400             :           /* Check to see if we're bringing down the soft interface and if it's parent is up */
     401         144 :           if ((flags != (si_sup->flags & mask)) &&
     402          40 :               (!((flags == 0)
     403          40 :                  && ((si_sup->flags & mask) ==
     404             :                      VNET_SW_INTERFACE_FLAG_ADMIN_UP))))
     405             :             {
     406           0 :               error = clib_error_return (0, "super-interface %U must be %U",
     407             :                                          format_vnet_sw_interface_name, vnm,
     408             :                                          si_sup,
     409             :                                          format_vnet_sw_interface_flags,
     410             :                                          flags);
     411           0 :               goto done;
     412             :             }
     413             :         }
     414             : 
     415             :       /* Already in the desired state? */
     416       29286 :       if ((si->flags & mask) == flags)
     417       15772 :         goto done;
     418             : 
     419             :       /* Sub-interfaces of hardware interfaces that do no redistribute,
     420             :          do not redistribute themselves. */
     421       13514 :       if (si_sup->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
     422             :         {
     423             :           vnet_hw_interface_t *hi =
     424       13470 :             vnet_get_hw_interface (vnm, si_sup->hw_if_index);
     425             :           vnet_device_class_t *dev_class =
     426       13470 :             vnet_get_device_class (vnm, hi->dev_class_index);
     427       13470 :           if (!dev_class->redistribute)
     428       13470 :             helper_flags &=
     429             :               ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
     430             :         }
     431             : 
     432             :       /* set the flags now before invoking the registered clients
     433             :        * so that the state they query is consistent with the state here notified */
     434       13514 :       old_flags = si->flags;
     435       13514 :       si->flags &= ~mask;
     436       13514 :       si->flags |= flags;
     437       13514 :       if ((flags | old_flags) & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     438       13514 :         error = call_elf_section_interface_callbacks
     439             :           (vnm, sw_if_index, flags,
     440       13514 :            vnm->sw_interface_admin_up_down_functions);
     441             : 
     442       13514 :       if (error)
     443             :         {
     444             :           /* restore flags on error */
     445           0 :           si->flags = old_flags;
     446           0 :           goto done;
     447             :         }
     448             : 
     449       13514 :       if (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
     450             :         {
     451             :           vnet_hw_interface_t *hi =
     452       13334 :             vnet_get_hw_interface (vnm, si->hw_if_index);
     453             :           vnet_hw_interface_class_t *hw_class =
     454       13334 :             vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     455             :           vnet_device_class_t *dev_class =
     456       13334 :             vnet_get_device_class (vnm, hi->dev_class_index);
     457             : 
     458       13334 :           if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
     459        6894 :               (si->flags & VNET_SW_INTERFACE_FLAG_ERROR))
     460             :             {
     461           0 :               error = clib_error_return (0, "Interface in the error state");
     462           0 :               goto done;
     463             :             }
     464             : 
     465             :           /* update si admin up flag in advance if we are going admin down */
     466       13334 :           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
     467        6440 :             si->flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
     468             : 
     469       13334 :           if (dev_class->admin_up_down_function
     470       13329 :               && (error = dev_class->admin_up_down_function (vnm,
     471             :                                                              si->hw_if_index,
     472             :                                                              flags)))
     473             :             {
     474             :               /* restore si admin up flag to it's original state on errors */
     475           0 :               si->flags = old_flags;
     476           0 :               goto done;
     477             :             }
     478             : 
     479       13334 :           if (hw_class->admin_up_down_function
     480           0 :               && (error = hw_class->admin_up_down_function (vnm,
     481             :                                                             si->hw_if_index,
     482             :                                                             flags)))
     483             :             {
     484             :               /* restore si admin up flag to it's original state on errors */
     485           0 :               si->flags = old_flags;
     486           0 :               goto done;
     487             :             }
     488             : 
     489             :           /* Admin down implies link down. */
     490       13334 :           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     491        6440 :               && (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
     492          14 :             vnet_hw_interface_set_flags_helper (vnm, si->hw_if_index,
     493          14 :                                                 hi->flags &
     494             :                                                 ~VNET_HW_INTERFACE_FLAG_LINK_UP,
     495             :                                                 helper_flags);
     496       13334 :           vnet_hw_if_update_runtime_data (vnm, si->hw_if_index);
     497             :         }
     498             :     }
     499             : 
     500       21061 :   si->flags &= ~mask;
     501       21061 :   si->flags |= flags;
     502             : 
     503       36833 : done:
     504       36833 :   if (error)
     505           0 :     log_err ("sw_set_flags_helper: %U", format_clib_error, error);
     506       36833 :   return error;
     507             : }
     508             : 
     509             : clib_error_t *
     510       30640 : vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
     511             :                              vnet_hw_interface_flags_t flags)
     512             : {
     513       30640 :   log_debug ("hw_set_flags: hw_if_index %u flags 0x%x", hw_if_index, flags);
     514       30640 :   return vnet_hw_interface_set_flags_helper
     515             :     (vnm, hw_if_index, flags,
     516             :      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
     517             : }
     518             : 
     519             : clib_error_t *
     520       29286 : vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
     521             :                              vnet_sw_interface_flags_t flags)
     522             : {
     523       29286 :   log_debug ("sw_set_flags: sw_if_index %u flags 0x%x", sw_if_index, flags);
     524       29286 :   return vnet_sw_interface_set_flags_helper
     525             :     (vnm, sw_if_index, flags,
     526             :      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
     527             : }
     528             : 
     529             : void
     530           0 : vnet_sw_interface_admin_up (vnet_main_t * vnm, u32 sw_if_index)
     531             : {
     532           0 :   u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
     533           0 :   log_debug ("sw_admin_up: sw_if_index %u", sw_if_index);
     534             : 
     535           0 :   if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
     536             :     {
     537           0 :       flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
     538           0 :       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
     539             :     }
     540           0 : }
     541             : 
     542             : void
     543           0 : vnet_sw_interface_admin_down (vnet_main_t * vnm, u32 sw_if_index)
     544             : {
     545           0 :   u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
     546           0 :   log_debug ("sw_admin_down: sw_if_index %u", sw_if_index);
     547             : 
     548           0 :   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     549             :     {
     550           0 :       flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     551           0 :       vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
     552             :     }
     553           0 : }
     554             : 
     555             : static void
     556       10469 : vnet_if_update_lookup_tables (vnet_main_t *vnm, u32 sw_if_index)
     557             : {
     558       10469 :   vnet_interface_main_t *im = &vnm->interface_main;
     559       10469 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     560             : 
     561       14423 :   vec_validate_init_empty (im->hw_if_index_by_sw_if_index, sw_if_index, ~0);
     562       14423 :   vec_validate_init_empty (im->if_out_arc_end_next_index_by_sw_if_index,
     563             :                            sw_if_index, ~0);
     564             : 
     565       10469 :   im->hw_if_index_by_sw_if_index[sw_if_index] = hi->hw_if_index;
     566       10469 :   im->if_out_arc_end_next_index_by_sw_if_index[sw_if_index] =
     567       10469 :     hi->if_out_arc_end_node_next_index;
     568       10469 : }
     569             : 
     570             : static u32
     571        7547 : vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
     572             :                                        vnet_sw_interface_t * template)
     573             : {
     574        7547 :   vnet_interface_main_t *im = &vnm->interface_main;
     575             :   vnet_sw_interface_t *sw;
     576             :   u32 sw_if_index;
     577             : 
     578        7547 :   pool_get (im->sw_interfaces, sw);
     579        7547 :   sw_if_index = sw - im->sw_interfaces;
     580             : 
     581        7547 :   sw[0] = template[0];
     582             : 
     583        7547 :   sw->flags = 0;
     584        7547 :   sw->sw_if_index = sw_if_index;
     585        7547 :   if (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
     586        6428 :     sw->sup_sw_if_index = sw->sw_if_index;
     587             : 
     588             :   /* Allocate counters for this interface. */
     589             :   {
     590             :     u32 i;
     591             : 
     592        7547 :     vnet_interface_counter_lock (im);
     593             : 
     594       75470 :     for (i = 0; i < vec_len (im->sw_if_counters); i++)
     595             :       {
     596       67923 :         vlib_validate_simple_counter (&im->sw_if_counters[i], sw_if_index);
     597       67923 :         vlib_zero_simple_counter (&im->sw_if_counters[i], sw_if_index);
     598             :       }
     599             : 
     600       67923 :     for (i = 0; i < vec_len (im->combined_sw_if_counters); i++)
     601             :       {
     602       60376 :         vlib_validate_combined_counter (&im->combined_sw_if_counters[i],
     603             :                                         sw_if_index);
     604       60376 :         vlib_zero_combined_counter (&im->combined_sw_if_counters[i],
     605             :                                     sw_if_index);
     606             :       }
     607             : 
     608        7547 :     vnet_interface_counter_unlock (im);
     609             :   }
     610             : 
     611        7547 :   vnet_if_update_lookup_tables (vnm, sw_if_index);
     612        7547 :   return sw_if_index;
     613             : }
     614             : 
     615             : clib_error_t *
     616        1119 : vnet_create_sw_interface (vnet_main_t * vnm, vnet_sw_interface_t * template,
     617             :                           u32 * sw_if_index)
     618             : {
     619        1119 :   vnet_interface_main_t *im = &vnm->interface_main;
     620             :   clib_error_t *error;
     621             :   vnet_hw_interface_t *hi;
     622             :   vnet_device_class_t *dev_class;
     623             : 
     624        1119 :   if (template->sub.eth.flags.two_tags == 1
     625          19 :       && template->sub.eth.flags.exact_match == 1
     626          19 :       && (template->sub.eth.flags.inner_vlan_id_any == 1
     627          19 :           || template->sub.eth.flags.outer_vlan_id_any == 1))
     628             :     {
     629           0 :       char *str = "inner-dot1q any exact-match is unsupported";
     630           0 :       error = clib_error_return (0, str);
     631           0 :       log_err ("create_sw_interface: %s", str);
     632           0 :       return error;
     633             :     }
     634             : 
     635        1119 :   hi = vnet_get_sup_hw_interface (vnm, template->sup_sw_if_index);
     636        1119 :   dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
     637             : 
     638        1119 :   if (template->type == VNET_SW_INTERFACE_TYPE_SUB &&
     639          92 :       dev_class->subif_add_del_function)
     640             :     {
     641           0 :       error = dev_class->subif_add_del_function (vnm, hi->hw_if_index,
     642             :                                                  (struct vnet_sw_interface_t
     643             :                                                   *) template, 1);
     644           0 :       if (error)
     645           0 :         return error;
     646             :     }
     647             : 
     648        1119 :   *sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, template);
     649        1119 :   error = vnet_sw_interface_set_flags_helper
     650        1119 :     (vnm, *sw_if_index, template->flags,
     651             :      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
     652             : 
     653        1119 :   if (error)
     654             :     {
     655             :       /* undo the work done by vnet_create_sw_interface_no_callbacks() */
     656           0 :       log_err ("create_sw_interface: set flags failed\n  %U",
     657             :                format_clib_error, error);
     658           0 :       call_sw_interface_add_del_callbacks (vnm, *sw_if_index, 0);
     659           0 :       vnet_sw_interface_t *sw =
     660           0 :         pool_elt_at_index (im->sw_interfaces, *sw_if_index);
     661           0 :       pool_put (im->sw_interfaces, sw);
     662             :     }
     663             :   else
     664             :     {
     665        1119 :       vnet_sw_interface_t *sw =
     666        1119 :         pool_elt_at_index (im->sw_interfaces, *sw_if_index);
     667        1119 :       log_debug ("create_sw_interface: interface %U (sw_if_index %u) created",
     668             :                  format_vnet_sw_interface_name, vnm, sw, *sw_if_index);
     669             :     }
     670             : 
     671        1119 :   return error;
     672             : }
     673             : 
     674             : void
     675        4251 : vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
     676             : {
     677        4251 :   vnet_interface_main_t *im = &vnm->interface_main;
     678        4251 :   vnet_sw_interface_t *sw =
     679        4251 :     pool_elt_at_index (im->sw_interfaces, sw_if_index);
     680             : 
     681        4251 :   log_debug ("delete_sw_interface: sw_if_index %u, name '%U'",
     682             :              sw_if_index, format_vnet_sw_if_index_name, vnm, sw_if_index);
     683             : 
     684             :   /* Check if the interface has config and is removed from L2 BD or XConnect */
     685        4251 :   vnet_clear_sw_interface_tag (vnm, sw_if_index);
     686             : 
     687             :   /* Bring down interface in case it is up. */
     688        4251 :   if (sw->flags != 0)
     689         637 :     vnet_sw_interface_set_flags (vnm, sw_if_index, /* flags */ 0);
     690             : 
     691        4251 :   call_sw_interface_add_del_callbacks (vnm, sw_if_index, /* is_create */ 0);
     692             : 
     693        4251 :   pool_put (im->sw_interfaces, sw);
     694        4251 : }
     695             : 
     696             : static clib_error_t *
     697        6127 : call_sw_interface_mtu_change_callbacks (vnet_main_t * vnm, u32 sw_if_index)
     698             : {
     699       12254 :   return call_elf_section_interface_callbacks
     700        6127 :     (vnm, sw_if_index, 0, vnm->sw_interface_mtu_change_functions);
     701             : }
     702             : 
     703             : void
     704       12065 : vnet_sw_interface_set_mtu (vnet_main_t * vnm, u32 sw_if_index, u32 mtu)
     705             : {
     706       12065 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     707             : 
     708       12065 :   if (si->mtu[VNET_MTU_L3] != mtu)
     709             :     {
     710        5617 :       si->mtu[VNET_MTU_L3] = mtu;
     711        5617 :       log_debug ("set_mtu: interface %U, new mtu %u",
     712             :                  format_vnet_sw_if_index_name, vnm, sw_if_index, mtu);
     713             : 
     714        5617 :       call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
     715             :     }
     716       12065 : }
     717             : 
     718             : void
     719         609 : vnet_sw_interface_set_protocol_mtu (vnet_main_t * vnm, u32 sw_if_index,
     720             :                                     u32 mtu[])
     721             : {
     722         609 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     723         609 :   bool changed = false;
     724             :   int i;
     725             : 
     726        3045 :   for (i = 0; i < VNET_N_MTU; i++)
     727             :     {
     728        2436 :       if (si->mtu[i] != mtu[i])
     729             :         {
     730         510 :           si->mtu[i] = mtu[i];
     731         510 :           changed = true;
     732             :         }
     733             :     }
     734             :   /* Notify interested parties */
     735         609 :   if (changed)
     736             :     {
     737         510 :       log_debug ("set_protocol_mtu: interface %U l3 %u ip4 %u ip6 %u mpls %u",
     738             :                  format_vnet_sw_if_index_name, vnm, sw_if_index,
     739             :                  mtu[VNET_MTU_L3], mtu[VNET_MTU_IP4], mtu[VNET_MTU_IP6],
     740             :                  mtu[VNET_MTU_MPLS]);
     741         510 :       call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
     742             :     }
     743         609 : }
     744             : 
     745             : void
     746           3 : vnet_sw_interface_ip_directed_broadcast (vnet_main_t * vnm,
     747             :                                          u32 sw_if_index, u8 enable)
     748             : {
     749             :   vnet_sw_interface_t *si;
     750             : 
     751           3 :   si = vnet_get_sw_interface (vnm, sw_if_index);
     752             : 
     753           3 :   if (enable)
     754           2 :     si->flags |= VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
     755             :   else
     756           1 :     si->flags &= ~VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
     757             : 
     758           3 :   ip4_directed_broadcast (sw_if_index, enable);
     759           3 : }
     760             : 
     761             : /*
     762             :  * Reflect a change in hardware MTU on protocol MTUs
     763             :  */
     764             : static walk_rc_t
     765           0 : sw_interface_walk_callback (vnet_main_t * vnm, u32 sw_if_index, void *ctx)
     766             : {
     767           0 :   u32 *link_mtu = ctx;
     768           0 :   vnet_sw_interface_set_mtu (vnm, sw_if_index, *link_mtu);
     769           0 :   return WALK_CONTINUE;
     770             : }
     771             : 
     772             : clib_error_t *
     773          48 : vnet_hw_interface_set_max_frame_size (vnet_main_t *vnm, u32 hw_if_index,
     774             :                                       u32 fs)
     775             : {
     776          48 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     777             :   vnet_hw_interface_class_t *hw_if_class =
     778          48 :     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     779          48 :   clib_error_t *err = 0;
     780             : 
     781          48 :   log_debug ("set_max_frame_size: interface %s, max_frame_size %u -> %u",
     782             :              hi->name, hi->max_frame_size, fs);
     783             : 
     784          48 :   if (hw_if_class->set_max_frame_size == 0)
     785          48 :     return vnet_error (VNET_ERR_UNSUPPORTED,
     786             :                        "hw class doesn't support changing Max Frame Size");
     787             : 
     788           0 :   if (hi->max_frame_size != fs)
     789             :     {
     790             :       u32 mtu;
     791           0 :       if (hw_if_class->set_max_frame_size)
     792           0 :         if ((err = hw_if_class->set_max_frame_size (vnm, hi, fs)))
     793           0 :           return err;
     794           0 :       hi->max_frame_size = fs;
     795           0 :       mtu = fs - hi->frame_overhead;
     796           0 :       vnet_hw_interface_walk_sw (vnm, hw_if_index, sw_interface_walk_callback,
     797             :                                  &mtu);
     798             :     }
     799           0 :   return 0;
     800             : }
     801             : clib_error_t *
     802          48 : vnet_hw_interface_set_mtu (vnet_main_t *vnm, u32 hw_if_index, u32 mtu)
     803             : {
     804          48 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     805          96 :   return vnet_hw_interface_set_max_frame_size (vnm, hw_if_index,
     806          48 :                                                mtu + hi->frame_overhead);
     807             : }
     808             : 
     809             : static void
     810        2922 : setup_tx_node (vlib_main_t * vm,
     811             :                u32 node_index, vnet_device_class_t * dev_class)
     812             : {
     813        2922 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     814             : 
     815        2922 :   n->format_trace = dev_class->format_tx_trace;
     816             : 
     817        2922 :   vlib_register_errors (vm, node_index, dev_class->tx_function_n_errors,
     818             :                         dev_class->tx_function_error_strings,
     819             :                         dev_class->tx_function_error_counters);
     820        2922 : }
     821             : 
     822             : static void
     823        2922 : setup_output_node (vlib_main_t * vm,
     824             :                    u32 node_index, vnet_hw_interface_class_t * hw_class)
     825             : {
     826        2922 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     827        2922 :   n->format_buffer = hw_class->format_header;
     828        2922 :   n->unformat_buffer = hw_class->unformat_header;
     829        2922 : }
     830             : 
     831             : void
     832         494 : vnet_reset_interface_l3_output_node (vlib_main_t *vm, u32 sw_if_index)
     833             : {
     834         494 :   vnet_set_interface_l3_output_node (vm, sw_if_index,
     835             :                                      (u8 *) "interface-output");
     836         494 : }
     837             : 
     838             : void
     839         873 : vnet_set_interface_l3_output_node (vlib_main_t *vm, u32 sw_if_index,
     840             :                                    u8 *output_node)
     841             : {
     842             :   vlib_node_t *l3_node;
     843             : 
     844         873 :   l3_node = vlib_get_node_by_name (vm, output_node);
     845             : 
     846             :   static char *arcs[] = {
     847             :     "ip4-output",
     848             :     "ip6-output",
     849             :     "mpls-output",
     850             :     "ethernet-output",
     851             :   };
     852             :   u8 a;
     853             : 
     854        4365 :   for (a = 0; a < ARRAY_LEN (arcs); a++)
     855             :     {
     856        3492 :       u8 arc = vnet_get_feature_arc_index (arcs[a]);
     857        3492 :       vnet_feature_modify_end_node (arc, sw_if_index, l3_node->index);
     858             :     }
     859         873 : }
     860             : 
     861             : /* Register an interface instance. */
     862             : u32
     863        6428 : vnet_register_interface (vnet_main_t * vnm,
     864             :                          u32 dev_class_index,
     865             :                          u32 dev_instance,
     866             :                          u32 hw_class_index, u32 hw_instance)
     867             : {
     868        6428 :   vnet_interface_main_t *im = &vnm->interface_main;
     869             :   vnet_hw_interface_t *hw;
     870             :   vnet_device_class_t *dev_class =
     871        6428 :     vnet_get_device_class (vnm, dev_class_index);
     872             :   vnet_hw_interface_class_t *hw_class =
     873        6428 :     vnet_get_hw_interface_class (vnm, hw_class_index);
     874        6428 :   vlib_main_t *vm = vnm->vlib_main;
     875             :   vnet_feature_config_main_t *fcm;
     876             :   vnet_config_main_t *cm;
     877             :   u32 hw_index, i;
     878             :   vlib_node_t *if_out_node =
     879        6428 :     vlib_get_node (vm, vnet_interface_output_node.index);
     880             : 
     881        6428 :   pool_get (im->hw_interfaces, hw);
     882        6428 :   clib_memset (hw, 0, sizeof (*hw));
     883        6428 :   hw->trace_classify_table_index = ~0;
     884             : 
     885        6428 :   hw_index = hw - im->hw_interfaces;
     886        6428 :   hw->hw_if_index = hw_index;
     887        6428 :   hw->default_rx_mode = VNET_HW_IF_RX_MODE_POLLING;
     888             : 
     889        6428 :   if (hw_class->tx_hash_fn_type == VNET_HASH_FN_TYPE_ETHERNET ||
     890          54 :       hw_class->tx_hash_fn_type == VNET_HASH_FN_TYPE_IP)
     891        6428 :     hw->hf = vnet_hash_default_function (hw_class->tx_hash_fn_type);
     892             : 
     893        6428 :   if (dev_class->format_device_name)
     894        5842 :     hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
     895         586 :   else if (hw_class->format_interface_name)
     896           0 :     hw->name = format (0, "%U", hw_class->format_interface_name,
     897             :                        dev_instance);
     898             :   else
     899         586 :     hw->name = format (0, "%s%x", hw_class->name, dev_instance);
     900             : 
     901        6428 :   if (!im->hw_interface_by_name)
     902         575 :     im->hw_interface_by_name = hash_create_vec ( /* size */ 0,
     903             :                                                 sizeof (hw->name[0]),
     904             :                                                 sizeof (uword));
     905             : 
     906       12856 :   hash_set_mem (im->hw_interface_by_name, hw->name, hw_index);
     907             : 
     908             :   /* Make hardware interface point to software interface. */
     909             :   {
     910        6428 :     vnet_sw_interface_t sw = {
     911             :       .type = VNET_SW_INTERFACE_TYPE_HARDWARE,
     912             :       .flood_class = VNET_FLOOD_CLASS_NORMAL,
     913             :       .hw_if_index = hw_index
     914             :     };
     915        6428 :     hw->sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, &sw);
     916             :   }
     917             : 
     918        6428 :   hw->dev_class_index = dev_class_index;
     919        6428 :   hw->dev_instance = dev_instance;
     920        6428 :   hw->hw_class_index = hw_class_index;
     921        6428 :   hw->hw_instance = hw_instance;
     922             : 
     923        6428 :   hw->max_rate_bits_per_sec = 0;
     924        6428 :   vnet_sw_interface_set_mtu (vnm, hw->sw_if_index, 0);
     925             : 
     926        6428 :   if (dev_class->tx_function == 0 && dev_class->tx_fn_registrations == 0)
     927        3506 :     goto no_output_nodes;       /* No output/tx nodes to create */
     928             : 
     929             :   /* If we have previously deleted interface nodes, re-use them. */
     930        2922 :   if (vec_len (im->deleted_hw_interface_nodes) > 0)
     931         695 :     {
     932             :       vnet_hw_interface_nodes_t *hn;
     933             :       vlib_node_t *node;
     934             :       vlib_node_runtime_t *nrt;
     935             : 
     936         695 :       hn = vec_end (im->deleted_hw_interface_nodes) - 1;
     937             : 
     938         695 :       hw->tx_node_index = hn->tx_node_index;
     939         695 :       hw->output_node_index = hn->output_node_index;
     940             : 
     941         695 :       vlib_node_rename (vm, hw->tx_node_index, "%v-tx", hw->name);
     942         695 :       vlib_node_rename (vm, hw->output_node_index, "%v-output", hw->name);
     943             : 
     944        1406 :       foreach_vlib_main ()
     945             :         {
     946             :           vnet_interface_output_runtime_t *rt;
     947             : 
     948             :           rt =
     949         711 :             vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
     950         711 :           ASSERT (rt->is_deleted == 1);
     951         711 :           rt->is_deleted = 0;
     952         711 :           rt->hw_if_index = hw_index;
     953         711 :           rt->sw_if_index = hw->sw_if_index;
     954         711 :           rt->dev_instance = hw->dev_instance;
     955             : 
     956         711 :           rt = vlib_node_get_runtime_data (this_vlib_main, hw->tx_node_index);
     957         711 :           rt->hw_if_index = hw_index;
     958         711 :           rt->sw_if_index = hw->sw_if_index;
     959         711 :           rt->dev_instance = hw->dev_instance;
     960             :         }
     961             : 
     962             :       /* The new class may differ from the old one.
     963             :        * Functions have to be updated. */
     964         695 :       node = vlib_get_node (vm, hw->output_node_index);
     965         695 :       node->format_trace = format_vnet_interface_output_trace;
     966         695 :       node->node_fn_registrations = if_out_node->node_fn_registrations;
     967         695 :       node->function = if_out_node->function;
     968             : 
     969        1406 :       foreach_vlib_main ()
     970             :         {
     971         711 :           nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
     972         711 :           nrt->function = node->function;
     973         711 :           vlib_node_runtime_perf_counter (this_vlib_main, nrt, 0, 0, 0,
     974             :                                           VLIB_NODE_RUNTIME_PERF_RESET);
     975             :         }
     976             : 
     977         695 :       node = vlib_get_node (vm, hw->tx_node_index);
     978         695 :       if (dev_class->tx_fn_registrations)
     979             :         {
     980         641 :           node->node_fn_registrations = dev_class->tx_fn_registrations;
     981         641 :           node->function = vlib_node_get_preferred_node_fn_variant (
     982             :             vm, dev_class->tx_fn_registrations);
     983             :         }
     984             :       else
     985          54 :         node->function = dev_class->tx_function;
     986         695 :       node->format_trace = dev_class->format_tx_trace;
     987             : 
     988        1406 :       foreach_vlib_main ()
     989             :         {
     990         711 :           nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
     991         711 :           nrt->function = node->function;
     992         711 :           vlib_node_runtime_perf_counter (this_vlib_main, nrt, 0, 0, 0,
     993             :                                           VLIB_NODE_RUNTIME_PERF_RESET);
     994             :         }
     995             : 
     996         695 :       vec_dec_len (im->deleted_hw_interface_nodes, 1);
     997             :     }
     998             :   else
     999             :     {
    1000             :       vlib_node_registration_t r;
    1001        2227 :       vnet_interface_output_runtime_t rt = {
    1002             :         .hw_if_index = hw_index,
    1003        2227 :         .sw_if_index = hw->sw_if_index,
    1004        2227 :         .dev_instance = hw->dev_instance,
    1005             :         .is_deleted = 0,
    1006             :       };
    1007             : 
    1008        2227 :       clib_memset (&r, 0, sizeof (r));
    1009        2227 :       r.type = VLIB_NODE_TYPE_INTERNAL;
    1010        2227 :       r.runtime_data = &rt;
    1011        2227 :       r.runtime_data_bytes = sizeof (rt);
    1012        2227 :       r.scalar_size = sizeof (vnet_hw_if_tx_frame_t);
    1013        2227 :       r.vector_size = sizeof (u32);
    1014             : 
    1015        2227 :       r.flags = VLIB_NODE_FLAG_IS_OUTPUT;
    1016        2227 :       if (dev_class->tx_fn_registrations)
    1017             :         {
    1018          22 :           r.function = 0;
    1019          22 :           r.node_fn_registrations = dev_class->tx_fn_registrations;
    1020             :         }
    1021             :       else
    1022        2205 :         r.function = dev_class->tx_function;
    1023             : 
    1024        2227 :       hw->tx_node_index = vlib_register_node (vm, &r, "%v-tx", hw->name);
    1025             : 
    1026        2227 :       vlib_node_add_named_next_with_slot (vm, hw->tx_node_index,
    1027             :                                           "error-drop",
    1028             :                                           VNET_INTERFACE_TX_NEXT_DROP);
    1029             : 
    1030        2227 :       r.flags = 0;
    1031        2227 :       r.format_trace = format_vnet_interface_output_trace;
    1032        2227 :       if (if_out_node->node_fn_registrations)
    1033             :         {
    1034        2227 :           r.function = 0;
    1035        2227 :           r.node_fn_registrations = if_out_node->node_fn_registrations;
    1036             :         }
    1037             :       else
    1038           0 :         r.function = if_out_node->function;
    1039             : 
    1040             :       {
    1041             :         static char *e[] = {
    1042             :           "interface is down",
    1043             :           "interface is deleted",
    1044             :           "no tx queue available",
    1045             :         };
    1046             : 
    1047        2227 :         r.n_errors = ARRAY_LEN (e);
    1048        2227 :         r.error_strings = e;
    1049             :       }
    1050        4454 :       hw->output_node_index =
    1051        2227 :         vlib_register_node (vm, &r, "%v-output", hw->name);
    1052             : 
    1053        2227 :       vlib_node_add_named_next_with_slot (vm, hw->output_node_index,
    1054             :                                           "error-drop",
    1055             :                                           VNET_INTERFACE_OUTPUT_NEXT_DROP);
    1056        2227 :       vlib_node_add_next_with_slot (vm, hw->output_node_index,
    1057        2227 :                                     hw->tx_node_index,
    1058             :                                     VNET_INTERFACE_OUTPUT_NEXT_TX);
    1059             :       /* add interface to the list of "output-interface" feature arc start nodes
    1060             :          and clone nexts from 1st interface if it exists */
    1061        2227 :       fcm = vnet_feature_get_config_main (im->output_feature_arc_index);
    1062        2227 :       cm = &fcm->config_main;
    1063        2227 :       i = vec_len (cm->start_node_indices);
    1064        2227 :       vec_validate (cm->start_node_indices, i);
    1065        2227 :       cm->start_node_indices[i] = hw->output_node_index;
    1066        2227 :       if (hw_index)
    1067             :         {
    1068             :           /* copy nexts from 1st interface */
    1069             :           vnet_hw_interface_t *first_hw;
    1070             :           vlib_node_t *first_node;
    1071             : 
    1072        1652 :           first_hw = vnet_get_hw_interface (vnm, /* hw_if_index */ 0);
    1073        1652 :           first_node = vlib_get_node (vm, first_hw->output_node_index);
    1074             : 
    1075             :           /* 1st 2 nexts are already added above */
    1076        1654 :           for (i = 2; i < vec_len (first_node->next_nodes); i++)
    1077           2 :             vlib_node_add_next_with_slot (vm, hw->output_node_index,
    1078           2 :                                           first_node->next_nodes[i], i);
    1079             :         }
    1080             :     }
    1081             : 
    1082        5844 :   hw->if_out_arc_end_node_next_index = vlib_node_add_next (
    1083        2922 :     vm, vnet_interface_output_arc_end_node.index, hw->tx_node_index);
    1084        2922 :   vnet_if_update_lookup_tables (vnm, hw->sw_if_index);
    1085        2922 :   setup_output_node (vm, hw->output_node_index, hw_class);
    1086        2922 :   setup_tx_node (vm, hw->tx_node_index, dev_class);
    1087             : 
    1088        6428 : no_output_nodes:
    1089             :   /* Call all up/down callbacks with zero flags when interface is created. */
    1090        6428 :   vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0,
    1091             :                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
    1092        6428 :   vnet_hw_interface_set_flags_helper (vnm, hw_index, /* flags */ 0,
    1093             :                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
    1094        6428 :   return hw_index;
    1095             : }
    1096             : 
    1097             : void
    1098        4186 : vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
    1099             : {
    1100        4186 :   vnet_interface_main_t *im = &vnm->interface_main;
    1101        4186 :   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
    1102        4186 :   vlib_main_t *vm = vnm->vlib_main;
    1103        4186 :   vnet_device_class_t *dev_class = vnet_get_device_class (vnm,
    1104             :                                                           hw->dev_class_index);
    1105             :   /* If it is up, mark it down. */
    1106        4186 :   if (hw->flags != 0)
    1107         320 :     vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0);
    1108             : 
    1109             :   /* Call delete callbacks. */
    1110        4186 :   call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
    1111             : 
    1112             :   /* delete rx & tx queues */
    1113        4186 :   vnet_hw_if_unregister_all_rx_queues (vnm, hw_if_index);
    1114        4186 :   vnet_hw_if_unregister_all_tx_queues (vnm, hw_if_index);
    1115        4186 :   vnet_hw_if_update_runtime_data (vnm, hw_if_index);
    1116             : 
    1117             :   /* Delete any sub-interfaces. */
    1118             :   {
    1119             :     u32 id, sw_if_index;
    1120             :     /* *INDENT-OFF* */
    1121        4379 :     hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id,
    1122             :     ({
    1123             :       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
    1124             :       u64 sup_and_sub_key =
    1125             :         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
    1126             :       hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
    1127             :       vnet_delete_sw_interface (vnm, sw_if_index);
    1128             :     }));
    1129        4186 :     hash_free (hw->sub_interface_sw_if_index_by_id);
    1130             :     /* *INDENT-ON* */
    1131             :   }
    1132             : 
    1133             :   /* Delete software interface corresponding to hardware interface. */
    1134        4186 :   vnet_delete_sw_interface (vnm, hw->sw_if_index);
    1135             : 
    1136        4186 :   if (dev_class->tx_function)
    1137             :     {
    1138             :       /* Put output/tx nodes into recycle pool */
    1139             :       vnet_hw_interface_nodes_t *dn;
    1140             : 
    1141        1552 :       foreach_vlib_main ()
    1142             :         {
    1143             :           vnet_interface_output_runtime_t *rt =
    1144         792 :             vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
    1145             : 
    1146             :           /* Mark node runtime as deleted so output node (if called)
    1147             :            * will drop packets. */
    1148         792 :           rt->is_deleted = 1;
    1149             :         }
    1150             : 
    1151         760 :       vlib_node_rename (vm, hw->output_node_index,
    1152             :                         "interface-%d-output-deleted", hw_if_index);
    1153         760 :       vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
    1154             :                         hw_if_index);
    1155         760 :       vlib_unregister_errors (vm, hw->output_node_index);
    1156         760 :       vlib_unregister_errors (vm, hw->tx_node_index);
    1157         760 :       vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
    1158         760 :       dn->tx_node_index = hw->tx_node_index;
    1159         760 :       dn->output_node_index = hw->output_node_index;
    1160             :     }
    1161        8372 :   hash_unset_mem (im->hw_interface_by_name, hw->name);
    1162        4186 :   vec_free (hw->name);
    1163        4186 :   vec_free (hw->hw_address);
    1164        4186 :   vec_free (hw->output_node_thread_runtimes);
    1165        4186 :   pool_put (im->hw_interfaces, hw);
    1166        4186 : }
    1167             : 
    1168             : void
    1169       59789 : vnet_hw_interface_walk_sw (vnet_main_t * vnm,
    1170             :                            u32 hw_if_index,
    1171             :                            vnet_hw_sw_interface_walk_t fn, void *ctx)
    1172             : {
    1173             :   vnet_hw_interface_t *hi;
    1174             :   u32 id, sw_if_index;
    1175             : 
    1176       59789 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
    1177             :   /* the super first, then the sub interfaces */
    1178       59789 :   if (WALK_STOP == fn (vnm, hi->sw_if_index, ctx))
    1179           0 :     return;
    1180             : 
    1181             :   /* *INDENT-OFF* */
    1182       91221 :   hash_foreach (id, sw_if_index,
    1183             :                 hi->sub_interface_sw_if_index_by_id,
    1184             :   ({
    1185             :     if (WALK_STOP == fn (vnm, sw_if_index, ctx))
    1186             :       break;
    1187             :   }));
    1188             :   /* *INDENT-ON* */
    1189             : }
    1190             : 
    1191             : void
    1192           0 : vnet_hw_interface_walk (vnet_main_t * vnm,
    1193             :                         vnet_hw_interface_walk_t fn, void *ctx)
    1194             : {
    1195             :   vnet_interface_main_t *im;
    1196             :   vnet_hw_interface_t *hi;
    1197             : 
    1198           0 :   im = &vnm->interface_main;
    1199             : 
    1200             :   /* *INDENT-OFF* */
    1201           0 :   pool_foreach (hi, im->hw_interfaces)
    1202             :    {
    1203           0 :     if (WALK_STOP == fn(vnm, hi->hw_if_index, ctx))
    1204           0 :       break;
    1205             :   }
    1206             :   /* *INDENT-ON* */
    1207           0 : }
    1208             : 
    1209             : void
    1210          23 : vnet_sw_interface_walk (vnet_main_t * vnm,
    1211             :                         vnet_sw_interface_walk_t fn, void *ctx)
    1212             : {
    1213             :   vnet_interface_main_t *im;
    1214             :   vnet_sw_interface_t *si;
    1215             : 
    1216          23 :   im = &vnm->interface_main;
    1217             : 
    1218             :   /* *INDENT-OFF* */
    1219         134 :   pool_foreach (si, im->sw_interfaces)
    1220             :   {
    1221         111 :     if (WALK_STOP == fn (vnm, si, ctx))
    1222           0 :       break;
    1223             :   }
    1224             :   /* *INDENT-ON* */
    1225          23 : }
    1226             : 
    1227             : void
    1228           0 : vnet_hw_interface_init_for_class (vnet_main_t * vnm, u32 hw_if_index,
    1229             :                                   u32 hw_class_index, u32 hw_instance)
    1230             : {
    1231           0 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1232             :   vnet_hw_interface_class_t *hc =
    1233           0 :     vnet_get_hw_interface_class (vnm, hw_class_index);
    1234             : 
    1235           0 :   hi->hw_class_index = hw_class_index;
    1236           0 :   hi->hw_instance = hw_instance;
    1237           0 :   setup_output_node (vnm->vlib_main, hi->output_node_index, hc);
    1238           0 : }
    1239             : 
    1240             : static clib_error_t *
    1241           0 : vnet_hw_interface_set_class_helper (vnet_main_t * vnm, u32 hw_if_index,
    1242             :                                     u32 hw_class_index, u32 redistribute)
    1243             : {
    1244           0 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1245           0 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, hi->sw_if_index);
    1246             :   vnet_hw_interface_class_t *old_class =
    1247           0 :     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
    1248             :   vnet_hw_interface_class_t *new_class =
    1249           0 :     vnet_get_hw_interface_class (vnm, hw_class_index);
    1250             :   vnet_device_class_t *dev_class =
    1251           0 :     vnet_get_device_class (vnm, hi->dev_class_index);
    1252           0 :   clib_error_t *error = 0;
    1253             : 
    1254             :   /* New class equals old class?  Nothing to do. */
    1255           0 :   if (hi->hw_class_index == hw_class_index)
    1256           0 :     return 0;
    1257             : 
    1258             :   /* No need (and incorrect since admin up flag may be set) to do error checking when
    1259             :      receiving unserialize message. */
    1260           0 :   if (redistribute)
    1261             :     {
    1262           0 :       if (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
    1263           0 :         return clib_error_return (0,
    1264             :                                   "%v must be admin down to change class from %s to %s",
    1265             :                                   hi->name, old_class->name, new_class->name);
    1266             : 
    1267             :       /* Make sure interface supports given class. */
    1268           0 :       if ((new_class->is_valid_class_for_interface
    1269           0 :            && !new_class->is_valid_class_for_interface (vnm, hw_if_index,
    1270             :                                                         hw_class_index))
    1271           0 :           || (dev_class->is_valid_class_for_interface
    1272           0 :               && !dev_class->is_valid_class_for_interface (vnm, hw_if_index,
    1273             :                                                            hw_class_index)))
    1274           0 :         return clib_error_return (0,
    1275             :                                   "%v class cannot be changed from %s to %s",
    1276             :                                   hi->name, old_class->name, new_class->name);
    1277             : 
    1278             :     }
    1279             : 
    1280           0 :   if (old_class->hw_class_change)
    1281           0 :     old_class->hw_class_change (vnm, hw_if_index, old_class->index,
    1282             :                                 new_class->index);
    1283             : 
    1284           0 :   vnet_hw_interface_init_for_class (vnm, hw_if_index, new_class->index,
    1285             :                                     /* instance */ ~0);
    1286             : 
    1287           0 :   if (new_class->hw_class_change)
    1288           0 :     new_class->hw_class_change (vnm, hw_if_index, old_class->index,
    1289             :                                 new_class->index);
    1290             : 
    1291           0 :   if (dev_class->hw_class_change)
    1292           0 :     dev_class->hw_class_change (vnm, hw_if_index, new_class->index);
    1293             : 
    1294           0 :   return error;
    1295             : }
    1296             : 
    1297             : clib_error_t *
    1298           0 : vnet_hw_interface_set_class (vnet_main_t * vnm, u32 hw_if_index,
    1299             :                              u32 hw_class_index)
    1300             : {
    1301           0 :   return vnet_hw_interface_set_class_helper (vnm, hw_if_index, hw_class_index,
    1302             :                                              /* redistribute */ 1);
    1303             : }
    1304             : 
    1305             : static int
    1306           0 : vnet_hw_interface_rx_redirect_to_node_helper (vnet_main_t * vnm,
    1307             :                                               u32 hw_if_index,
    1308             :                                               u32 node_index,
    1309             :                                               u32 redistribute)
    1310             : {
    1311           0 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1312           0 :   vnet_device_class_t *dev_class = vnet_get_device_class
    1313             :     (vnm, hi->dev_class_index);
    1314             : 
    1315           0 :   if (dev_class->rx_redirect_to_node)
    1316             :     {
    1317           0 :       dev_class->rx_redirect_to_node (vnm, hw_if_index, node_index);
    1318           0 :       return 0;
    1319             :     }
    1320             : 
    1321           0 :   return VNET_API_ERROR_UNIMPLEMENTED;
    1322             : }
    1323             : 
    1324             : int
    1325           0 : vnet_hw_interface_rx_redirect_to_node (vnet_main_t * vnm, u32 hw_if_index,
    1326             :                                        u32 node_index)
    1327             : {
    1328           0 :   return vnet_hw_interface_rx_redirect_to_node_helper (vnm, hw_if_index,
    1329             :                                                        node_index,
    1330             :                                                        1 /* redistribute */ );
    1331             : }
    1332             : 
    1333             : word
    1334      164196 : vnet_sw_interface_compare (vnet_main_t * vnm,
    1335             :                            uword sw_if_index0, uword sw_if_index1)
    1336             : {
    1337      164196 :   vnet_sw_interface_t *sup0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
    1338      164196 :   vnet_sw_interface_t *sup1 = vnet_get_sup_sw_interface (vnm, sw_if_index1);
    1339      164196 :   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, sup0->hw_if_index);
    1340      164196 :   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, sup1->hw_if_index);
    1341             : 
    1342      164196 :   if (h0 != h1)
    1343      109331 :     return vec_cmp (h0->name, h1->name);
    1344      128277 :   return (word) h0->hw_instance - (word) h1->hw_instance;
    1345             : }
    1346             : 
    1347             : word
    1348       16601 : vnet_hw_interface_compare (vnet_main_t * vnm,
    1349             :                            uword hw_if_index0, uword hw_if_index1)
    1350             : {
    1351       16601 :   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, hw_if_index0);
    1352       16601 :   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, hw_if_index1);
    1353             : 
    1354       16601 :   if (h0 != h1)
    1355       77659 :     return vec_cmp (h0->name, h1->name);
    1356           0 :   return (word) h0->hw_instance - (word) h1->hw_instance;
    1357             : }
    1358             : 
    1359             : int
    1360       59462 : vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
    1361             : {
    1362       59462 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
    1363       59462 :   if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
    1364       59362 :       (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
    1365         102 :     return 1;
    1366             : 
    1367       59360 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1368             :   vnet_hw_interface_class_t *hc =
    1369       59360 :     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
    1370             : 
    1371       59360 :   return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_P2P);
    1372             : }
    1373             : 
    1374             : int
    1375       35251 : vnet_sw_interface_is_nbma (vnet_main_t * vnm, u32 sw_if_index)
    1376             : {
    1377       35251 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1378             :   vnet_hw_interface_class_t *hc =
    1379       35251 :     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
    1380             : 
    1381       35251 :   return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_NBMA);
    1382             : }
    1383             : 
    1384             : clib_error_t *
    1385        8972 : vnet_sw_interface_supports_addressing (vnet_main_t *vnm, u32 sw_if_index)
    1386             : {
    1387        8972 :   if (sw_if_index == 0)
    1388             :     {
    1389           0 :       return clib_error_create (
    1390             :         "local0 interface doesn't support IP addressing");
    1391             :     }
    1392             : 
    1393        8972 :   if (vnet_sw_interface_is_sub (vnm, sw_if_index))
    1394             :     {
    1395             :       vnet_sw_interface_t *si;
    1396         171 :       si = vnet_get_sw_interface_or_null (vnm, sw_if_index);
    1397         171 :       if (si && si->type == VNET_SW_INTERFACE_TYPE_SUB &&
    1398         131 :           si->sub.eth.flags.exact_match == 0)
    1399             :         {
    1400           0 :           return clib_error_create (
    1401             :             "sub-interface without exact-match doesn't support IP addressing");
    1402             :         }
    1403             :     }
    1404        8972 :   return NULL;
    1405             : }
    1406             : 
    1407             : u32
    1408       19550 : vnet_register_device_class (vlib_main_t *vm, vnet_device_class_t *c)
    1409             : {
    1410       19550 :   vnet_main_t *vnm = vnet_get_main ();
    1411       19550 :   vnet_interface_main_t *im = &vnm->interface_main;
    1412       19550 :   c->index = vec_len (im->device_classes);
    1413       39100 :   hash_set_mem (im->device_class_by_name, c->name, c->index);
    1414             : 
    1415             :   /* to avoid confusion, please remove ".tx_function" statement
    1416             :     from VNET_DEVICE_CLASS() if using function candidates */
    1417       19550 :   ASSERT (c->tx_fn_registrations == 0 || c->tx_function == 0);
    1418             : 
    1419       19550 :   if (c->tx_fn_registrations)
    1420        5175 :     c->tx_function =
    1421        5175 :       vlib_node_get_preferred_node_fn_variant (vm, c->tx_fn_registrations);
    1422             : 
    1423       19550 :   vec_add1 (im->device_classes, c[0]);
    1424       19550 :   return c->index;
    1425             : }
    1426             : 
    1427             : clib_error_t *
    1428         575 : vnet_interface_init (vlib_main_t * vm)
    1429             : {
    1430         575 :   vnet_main_t *vnm = vnet_get_main ();
    1431         575 :   vnet_interface_main_t *im = &vnm->interface_main;
    1432         575 :   vlib_buffer_t *b = 0;
    1433         575 :   vnet_buffer_opaque_t *o = 0;
    1434             :   clib_error_t *error;
    1435             : 
    1436             :   /*
    1437             :    * Keep people from shooting themselves in the foot.
    1438             :    */
    1439             :   if (sizeof (b->opaque) != sizeof (vnet_buffer_opaque_t))
    1440             :     {
    1441             : #define _(a) if (sizeof(o->a) > sizeof (o->unused))                     \
    1442             :       clib_warning                                                      \
    1443             :         ("FATAL: size of opaque union subtype %s is %d (max %d)",       \
    1444             :          #a, sizeof(o->a), sizeof (o->unused));
    1445             :       foreach_buffer_opaque_union_subtype;
    1446             : #undef _
    1447             : 
    1448             :       return clib_error_return
    1449             :         (0, "FATAL: size of vlib buffer opaque %d, size of vnet opaque %d",
    1450             :          sizeof (b->opaque), sizeof (vnet_buffer_opaque_t));
    1451             :     }
    1452             : 
    1453         575 :   clib_spinlock_init (&im->sw_if_counter_lock);
    1454         575 :   clib_spinlock_lock (&im->sw_if_counter_lock);  /* should be no need */
    1455             : 
    1456         575 :   vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
    1457             : #define _(E,n,p)                                                        \
    1458             :   im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n;          \
    1459             :   im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
    1460         575 :   foreach_simple_interface_counter_name
    1461             : #undef _
    1462         575 :     vec_validate (im->combined_sw_if_counters,
    1463             :                   VNET_N_COMBINED_INTERFACE_COUNTER - 1);
    1464             : #define _(E,n,p)                                                        \
    1465             :   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n; \
    1466             :   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
    1467         575 :   foreach_combined_interface_counter_name
    1468             : #undef _
    1469         575 :     clib_spinlock_unlock (&im->sw_if_counter_lock);
    1470             : 
    1471         575 :   im->device_class_by_name = hash_create_string ( /* size */ 0,
    1472             :                                                  sizeof (uword));
    1473             : 
    1474       20125 :   for (vnet_device_class_t *c = vnm->device_class_registrations; c;
    1475       19550 :        c = c->next_class_registration)
    1476       19550 :     vnet_register_device_class (vm, c);
    1477             : 
    1478         575 :   im->hw_interface_class_by_name = hash_create_string ( /* size */ 0,
    1479             :                                                        sizeof (uword));
    1480             : 
    1481         575 :   im->rxq_index_by_hw_if_index_and_queue_id =
    1482         575 :     hash_create_mem (0, sizeof (u64), sizeof (u32));
    1483         575 :   im->txq_index_by_hw_if_index_and_queue_id =
    1484         575 :     hash_create_mem (0, sizeof (u64), sizeof (u32));
    1485         575 :   im->sw_if_index_by_sup_and_sub = hash_create_mem (0, sizeof (u64),
    1486             :                                                     sizeof (uword));
    1487             :   {
    1488             :     vnet_hw_interface_class_t *c;
    1489             : 
    1490         575 :     c = vnm->hw_interface_class_registrations;
    1491             : 
    1492       18400 :     while (c)
    1493             :       {
    1494       17825 :         c->index = vec_len (im->hw_interface_classes);
    1495       35650 :         hash_set_mem (im->hw_interface_class_by_name, c->name, c->index);
    1496             : 
    1497       17825 :         if (NULL == c->build_rewrite)
    1498        4600 :           c->build_rewrite = default_build_rewrite;
    1499       17825 :         if (NULL == c->update_adjacency)
    1500       10350 :           c->update_adjacency = default_update_adjacency;
    1501             : 
    1502       17825 :         vec_add1 (im->hw_interface_classes, c[0]);
    1503       17825 :         c = c->next_class_registration;
    1504             :       }
    1505             :   }
    1506             : 
    1507             :   /* init per-thread data */
    1508         575 :   vec_validate_aligned (im->per_thread_data, vlib_num_workers (),
    1509             :                         CLIB_CACHE_LINE_BYTES);
    1510             : 
    1511         575 :   if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
    1512           0 :     return error;
    1513             : 
    1514         575 :   vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
    1515             : 
    1516         575 :   return 0;
    1517             : }
    1518             : 
    1519        9791 : VLIB_INIT_FUNCTION (vnet_interface_init);
    1520             : 
    1521             : /* Kludge to renumber interface names [only!] */
    1522             : int
    1523           0 : vnet_interface_name_renumber (u32 sw_if_index, u32 new_show_dev_instance)
    1524             : {
    1525             :   int rv;
    1526           0 :   vnet_main_t *vnm = vnet_get_main ();
    1527           0 :   vnet_interface_main_t *im = &vnm->interface_main;
    1528           0 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1529             : 
    1530           0 :   vnet_device_class_t *dev_class = vnet_get_device_class
    1531             :     (vnm, hi->dev_class_index);
    1532             : 
    1533           0 :   if (dev_class->name_renumber == 0 || dev_class->format_device_name == 0)
    1534           0 :     return VNET_API_ERROR_UNIMPLEMENTED;
    1535             : 
    1536           0 :   rv = dev_class->name_renumber (hi, new_show_dev_instance);
    1537             : 
    1538           0 :   if (rv)
    1539           0 :     return rv;
    1540             : 
    1541           0 :   hash_unset_mem (im->hw_interface_by_name, hi->name);
    1542           0 :   vec_free (hi->name);
    1543             :   /* Use the mapping we set up to call it Ishmael */
    1544           0 :   hi->name = format (0, "%U", dev_class->format_device_name,
    1545             :                      hi->dev_instance);
    1546             : 
    1547           0 :   hash_set_mem (im->hw_interface_by_name, hi->name, hi->hw_if_index);
    1548           0 :   return rv;
    1549             : }
    1550             : 
    1551             : clib_error_t *
    1552           0 : vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
    1553             : {
    1554           0 :   vnet_interface_main_t *im = &vnm->interface_main;
    1555           0 :   vlib_main_t *vm = vnm->vlib_main;
    1556             :   vnet_hw_interface_t *hw;
    1557             :   u8 *old_name;
    1558           0 :   clib_error_t *error = 0;
    1559             : 
    1560           0 :   hw = vnet_get_hw_interface (vnm, hw_if_index);
    1561           0 :   if (!hw)
    1562             :     {
    1563           0 :       return clib_error_return (0,
    1564             :                                 "unable to find hw interface for index %u",
    1565             :                                 hw_if_index);
    1566             :     }
    1567             : 
    1568           0 :   old_name = hw->name;
    1569             : 
    1570             :   /* set new hw->name */
    1571           0 :   hw->name = format (0, "%s", new_name);
    1572             : 
    1573             :   /* remove the old name to hw_if_index mapping and install the new one */
    1574           0 :   hash_unset_mem (im->hw_interface_by_name, old_name);
    1575           0 :   hash_set_mem (im->hw_interface_by_name, hw->name, hw_if_index);
    1576             : 
    1577             :   /* rename tx/output nodes */
    1578           0 :   vlib_node_rename (vm, hw->tx_node_index, "%v-tx", hw->name);
    1579           0 :   vlib_node_rename (vm, hw->output_node_index, "%v-output", hw->name);
    1580             : 
    1581             :   /* free the old name vector */
    1582           0 :   vec_free (old_name);
    1583             : 
    1584           0 :   return error;
    1585             : }
    1586             : 
    1587             : clib_error_t *
    1588       28491 : vnet_hw_interface_add_del_mac_address (vnet_main_t * vnm,
    1589             :                                        u32 hw_if_index,
    1590             :                                        const u8 * mac_address, u8 is_add)
    1591             : {
    1592       28491 :   clib_error_t *error = 0;
    1593       28491 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1594             : 
    1595             :   vnet_device_class_t *dev_class =
    1596       28491 :     vnet_get_device_class (vnm, hi->dev_class_index);
    1597             : 
    1598       28491 :   if (!hi->hw_address)
    1599             :     {
    1600             :       error =
    1601        2501 :         clib_error_return
    1602             :         (0, "Secondary MAC Addresses not supported for interface index %u",
    1603             :          hw_if_index);
    1604        2501 :       goto done;
    1605             :     }
    1606             : 
    1607       25990 :   if (dev_class->mac_addr_add_del_function)
    1608       24426 :     error = dev_class->mac_addr_add_del_function (hi, mac_address, is_add);
    1609             : 
    1610       25990 :   if (!error)
    1611             :     {
    1612             :       vnet_hw_interface_class_t *hw_class;
    1613             : 
    1614       25990 :       hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
    1615             : 
    1616       25990 :       if (NULL != hw_class->mac_addr_add_del_function)
    1617           0 :         error = hw_class->mac_addr_add_del_function (hi, mac_address, is_add);
    1618             :     }
    1619             : 
    1620             :   /* If no errors, add to the list of secondary MACs on the ethernet intf */
    1621       25990 :   if (!error)
    1622       25990 :     ethernet_interface_add_del_address (&ethernet_main, hw_if_index,
    1623             :                                         mac_address, is_add);
    1624             : 
    1625           0 : done:
    1626       28491 :   if (error)
    1627        2501 :     log_err ("hw_add_del_mac_address: %U", format_clib_error, error);
    1628       28491 :   return error;
    1629             : }
    1630             : 
    1631             : static clib_error_t *
    1632          31 : vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
    1633             :                                              u32 hw_if_index,
    1634             :                                              const u8 * mac_address)
    1635             : {
    1636          31 :   clib_error_t *error = 0;
    1637          31 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1638             : 
    1639          31 :   if (hi->hw_address)
    1640             :     {
    1641          31 :       u8 *old_address = vec_dup (hi->hw_address);
    1642             :       vnet_device_class_t *dev_class =
    1643          31 :         vnet_get_device_class (vnm, hi->dev_class_index);
    1644          31 :       if (dev_class->mac_addr_change_function)
    1645             :         {
    1646             :           error =
    1647           1 :             dev_class->mac_addr_change_function (hi, old_address,
    1648             :                                                  mac_address);
    1649             :         }
    1650          31 :       if (!error)
    1651             :         {
    1652             :           vnet_hw_interface_class_t *hw_class;
    1653             : 
    1654          31 :           hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
    1655             : 
    1656          31 :           if (NULL != hw_class->mac_addr_change_function)
    1657          31 :             hw_class->mac_addr_change_function (hi, old_address, mac_address);
    1658             :         }
    1659             :       else
    1660             :         {
    1661             :           error =
    1662           0 :             clib_error_return (0,
    1663             :                                "MAC Address Change is not supported on this interface");
    1664             :         }
    1665          31 :       vec_free (old_address);
    1666             :     }
    1667             :   else
    1668             :     {
    1669             :       error =
    1670           0 :         clib_error_return (0,
    1671             :                            "mac address change is not supported for interface index %u",
    1672             :                            hw_if_index);
    1673             :     }
    1674          31 :   return error;
    1675             : }
    1676             : 
    1677             : clib_error_t *
    1678          31 : vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index,
    1679             :                                       const u8 * mac_address)
    1680             : {
    1681          31 :   return vnet_hw_interface_change_mac_address_helper
    1682             :     (vnm, hw_if_index, mac_address);
    1683             : }
    1684             : 
    1685             : static int
    1686          30 : vnet_sw_interface_check_table_same (u32 unnumbered_sw_if_index,
    1687             :                                     u32 ip_sw_if_index)
    1688             : {
    1689          30 :   if (ip4_main.fib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1690          30 :       ip4_main.fib_index_by_sw_if_index[ip_sw_if_index])
    1691           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1692             : 
    1693          30 :   if (ip4_main.mfib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1694          30 :       ip4_main.mfib_index_by_sw_if_index[ip_sw_if_index])
    1695           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1696             : 
    1697          30 :   if (ip6_main.fib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1698          30 :       ip6_main.fib_index_by_sw_if_index[ip_sw_if_index])
    1699           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1700             : 
    1701          30 :   if (ip6_main.mfib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1702          30 :       ip6_main.mfib_index_by_sw_if_index[ip_sw_if_index])
    1703           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1704             : 
    1705          30 :   return 0;
    1706             : }
    1707             : 
    1708             : /* update the unnumbered state of an interface*/
    1709             : int
    1710        8535 : vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index,
    1711             :                                      u32 ip_sw_if_index, u8 enable)
    1712             : {
    1713        8535 :   vnet_main_t *vnm = vnet_get_main ();
    1714             :   vnet_sw_interface_t *si;
    1715             :   u32 was_unnum;
    1716        8535 :   int rv = 0;
    1717             : 
    1718        8535 :   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
    1719        8535 :   was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
    1720             : 
    1721        8535 :   if (enable)
    1722             :     {
    1723          30 :       rv = vnet_sw_interface_check_table_same (unnumbered_sw_if_index,
    1724             :                                                ip_sw_if_index);
    1725          30 :       if (rv != 0)
    1726           0 :         return rv;
    1727          30 :       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
    1728          30 :       si->unnumbered_sw_if_index = ip_sw_if_index;
    1729             : 
    1730          30 :       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
    1731          30 :         [unnumbered_sw_if_index] =
    1732             :         ip4_main.
    1733          30 :         lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
    1734             :       ip6_main.
    1735          30 :         lookup_main.if_address_pool_index_by_sw_if_index
    1736          30 :         [unnumbered_sw_if_index] =
    1737             :         ip6_main.
    1738          30 :         lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
    1739             :     }
    1740             :   else
    1741             :     {
    1742             :       /*
    1743             :        * Unless the interface is actually unnumbered, don't
    1744             :        * smash e.g. if_address_pool_index_by_sw_if_index
    1745             :        */
    1746        8505 :       if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
    1747             :         {
    1748          21 :           si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
    1749          21 :           si->unnumbered_sw_if_index = (u32) ~0;
    1750             : 
    1751             :           ip4_main.lookup_main
    1752          21 :             .if_address_pool_index_by_sw_if_index[unnumbered_sw_if_index] = ~0;
    1753             :           ip6_main.lookup_main
    1754          21 :             .if_address_pool_index_by_sw_if_index[unnumbered_sw_if_index] = ~0;
    1755             :         }
    1756             :     }
    1757             : 
    1758        8535 :   if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
    1759             :     {
    1760          48 :       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
    1761          48 :       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
    1762             :     }
    1763             : 
    1764        8535 :   return 0;
    1765             : }
    1766             : 
    1767             : vnet_l3_packet_type_t
    1768           0 : vnet_link_to_l3_proto (vnet_link_t link)
    1769             : {
    1770           0 :   switch (link)
    1771             :     {
    1772           0 :     case VNET_LINK_IP4:
    1773           0 :       return (VNET_L3_PACKET_TYPE_IP4);
    1774           0 :     case VNET_LINK_IP6:
    1775           0 :       return (VNET_L3_PACKET_TYPE_IP6);
    1776           0 :     case VNET_LINK_MPLS:
    1777           0 :       return (VNET_L3_PACKET_TYPE_MPLS);
    1778           0 :     case VNET_LINK_ARP:
    1779           0 :       return (VNET_L3_PACKET_TYPE_ARP);
    1780           0 :     case VNET_LINK_ETHERNET:
    1781             :     case VNET_LINK_NSH:
    1782           0 :       ASSERT (0);
    1783           0 :       break;
    1784             :     }
    1785           0 :   ASSERT (0);
    1786           0 :   return (0);
    1787             : }
    1788             : 
    1789             : vnet_mtu_t
    1790       39743 : vnet_link_to_mtu (vnet_link_t link)
    1791             : {
    1792       39743 :   switch (link)
    1793             :     {
    1794       15991 :     case VNET_LINK_IP4:
    1795       15991 :       return (VNET_MTU_IP4);
    1796       18935 :     case VNET_LINK_IP6:
    1797       18935 :       return (VNET_MTU_IP6);
    1798         152 :     case VNET_LINK_MPLS:
    1799         152 :       return (VNET_MTU_MPLS);
    1800        4665 :     default:
    1801        4665 :       return (VNET_MTU_L3);
    1802             :     }
    1803             : }
    1804             : 
    1805             : u8 *
    1806          56 : default_build_rewrite (vnet_main_t * vnm,
    1807             :                        u32 sw_if_index,
    1808             :                        vnet_link_t link_type, const void *dst_address)
    1809             : {
    1810          56 :   return (NULL);
    1811             : }
    1812             : 
    1813             : void
    1814          90 : default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
    1815             : {
    1816             :   ip_adjacency_t *adj;
    1817             : 
    1818          90 :   adj = adj_get (ai);
    1819             : 
    1820          90 :   switch (adj->lookup_next_index)
    1821             :     {
    1822           0 :     case IP_LOOKUP_NEXT_GLEAN:
    1823           0 :       adj_glean_update_rewrite (ai);
    1824           0 :       break;
    1825          78 :     case IP_LOOKUP_NEXT_ARP:
    1826             :     case IP_LOOKUP_NEXT_BCAST:
    1827             :       /*
    1828             :        * default rewrite in neighbour adj
    1829             :        */
    1830          78 :       adj_nbr_update_rewrite
    1831             :         (ai,
    1832             :          ADJ_NBR_REWRITE_FLAG_COMPLETE,
    1833             :          vnet_build_rewrite_for_sw_interface (vnm,
    1834             :                                               sw_if_index,
    1835          78 :                                               adj_get_link_type (ai), NULL));
    1836          78 :       break;
    1837          12 :     case IP_LOOKUP_NEXT_MCAST:
    1838             :       /*
    1839             :        * mcast traffic also uses default rewrite string with no mcast
    1840             :        * switch time updates.
    1841             :        */
    1842          12 :       adj_mcast_update_rewrite
    1843             :         (ai,
    1844             :          vnet_build_rewrite_for_sw_interface (vnm,
    1845             :                                               sw_if_index,
    1846          12 :                                               adj_get_link_type (ai),
    1847             :                                               NULL), 0);
    1848          12 :       break;
    1849           0 :     case IP_LOOKUP_NEXT_DROP:
    1850             :     case IP_LOOKUP_NEXT_PUNT:
    1851             :     case IP_LOOKUP_NEXT_LOCAL:
    1852             :     case IP_LOOKUP_NEXT_REWRITE:
    1853             :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
    1854             :     case IP_LOOKUP_NEXT_MIDCHAIN:
    1855             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
    1856             :     case IP_LOOKUP_N_NEXT:
    1857           0 :       ASSERT (0);
    1858           0 :       break;
    1859             :     }
    1860          90 : }
    1861             : 
    1862             : clib_error_t *
    1863           0 : vnet_hw_interface_set_rss_queues (vnet_main_t * vnm,
    1864             :                                   vnet_hw_interface_t * hi,
    1865             :                                   clib_bitmap_t * bitmap)
    1866             : {
    1867           0 :   clib_error_t *error = 0;
    1868             :   vnet_device_class_t *dev_class =
    1869           0 :     vnet_get_device_class (vnm, hi->dev_class_index);
    1870             : 
    1871           0 :   if (dev_class->set_rss_queues_function)
    1872             :     {
    1873           0 :       if (clib_bitmap_count_set_bits (bitmap) == 0)
    1874             :         {
    1875           0 :           error = clib_error_return (0,
    1876             :                                      "must assign at least one valid rss queue");
    1877           0 :           goto done;
    1878             :         }
    1879             : 
    1880           0 :       error = dev_class->set_rss_queues_function (vnm, hi, bitmap);
    1881             :     }
    1882             :   else
    1883             :     {
    1884           0 :       error = clib_error_return (0,
    1885             :                                  "setting rss queues is not supported on this interface");
    1886             :     }
    1887             : 
    1888           0 :   if (!error)
    1889             :     {
    1890           0 :       clib_bitmap_free (hi->rss_queues);
    1891           0 :       hi->rss_queues = clib_bitmap_dup (bitmap);
    1892             :     }
    1893             : 
    1894           0 : done:
    1895           0 :   if (error)
    1896           0 :     log_err ("hw_set_rss_queues: %U", format_clib_error, error);
    1897           0 :   return error;
    1898             : }
    1899             : 
    1900             : int collect_detailed_interface_stats_flag = 0;
    1901             : 
    1902             : void
    1903           0 : collect_detailed_interface_stats_flag_set (void)
    1904             : {
    1905           0 :   collect_detailed_interface_stats_flag = 1;
    1906           0 : }
    1907             : 
    1908             : void
    1909           0 : collect_detailed_interface_stats_flag_clear (void)
    1910             : {
    1911           0 :   collect_detailed_interface_stats_flag = 0;
    1912           0 : }
    1913             : 
    1914             : static clib_error_t *
    1915           0 : collect_detailed_interface_stats_cli (vlib_main_t * vm,
    1916             :                                       unformat_input_t * input,
    1917             :                                       vlib_cli_command_t * cmd)
    1918             : {
    1919           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    1920           0 :   clib_error_t *error = NULL;
    1921             : 
    1922             :   /* Get a line of input. */
    1923           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    1924           0 :     return clib_error_return (0, "expected enable | disable");
    1925             : 
    1926           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1927             :     {
    1928           0 :       if (unformat (line_input, "enable") || unformat (line_input, "on"))
    1929           0 :         collect_detailed_interface_stats_flag_set ();
    1930           0 :       else if (unformat (line_input, "disable")
    1931           0 :                || unformat (line_input, "off"))
    1932           0 :         collect_detailed_interface_stats_flag_clear ();
    1933             :       else
    1934             :         {
    1935           0 :           error = clib_error_return (0, "unknown input `%U'",
    1936             :                                      format_unformat_error, line_input);
    1937           0 :           goto done;
    1938             :         }
    1939             :     }
    1940             : 
    1941           0 : done:
    1942           0 :   unformat_free (line_input);
    1943           0 :   return error;
    1944             : }
    1945             : 
    1946             : /* *INDENT-OFF* */
    1947      285289 : VLIB_CLI_COMMAND (collect_detailed_interface_stats_command, static) = {
    1948             :   .path = "interface collect detailed-stats",
    1949             :   .short_help = "interface collect detailed-stats <enable|disable>",
    1950             :   .function = collect_detailed_interface_stats_cli,
    1951             : };
    1952             : /* *INDENT-ON* */
    1953             : 
    1954             : /*
    1955             :  * fd.io coding-style-patch-verification: ON
    1956             :  *
    1957             :  * Local Variables:
    1958             :  * eval: (c-set-style "gnu")
    1959             :  * End:
    1960             :  */

Generated by: LCOV version 1.14