LCOV - code coverage report
Current view: top level - vnet - interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 542 836 64.8 %
Date: 2023-07-05 22:20:52 Functions: 44 66 66.7 %

          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         559 : 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       54333 : 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       54333 :   clib_error_t *error = 0;
     253             : 
     254      162999 :   for (prio = VNET_ITF_FUNC_PRIORITY_LOW;
     255      108666 :        prio <= VNET_ITF_FUNC_PRIORITY_HIGH; prio++)
     256             :     {
     257      108666 :       elt = elts[prio];
     258             : 
     259      831358 :       while (elt)
     260             :         {
     261      722692 :           error = elt->fp (vnm, if_index, flags);
     262      722692 :           if (error)
     263           0 :             return error;
     264      722692 :           elt = elt->next_interface_function;
     265             :         }
     266             :     }
     267       54333 :   return error;
     268             : }
     269             : 
     270             : static clib_error_t *
     271       10415 : call_hw_interface_add_del_callbacks (vnet_main_t * vnm, u32 hw_if_index,
     272             :                                      u32 is_create)
     273             : {
     274       10415 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     275             :   vnet_hw_interface_class_t *hw_class =
     276       10415 :     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     277             :   vnet_device_class_t *dev_class =
     278       10415 :     vnet_get_device_class (vnm, hi->dev_class_index);
     279       10415 :   clib_error_t *error = 0;
     280             : 
     281       10415 :   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       10415 :   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       10415 :   error = call_elf_section_interface_callbacks
     293       10415 :     (vnm, hw_if_index, is_create, vnm->hw_interface_add_del_functions);
     294             : 
     295       10415 :   return error;
     296             : }
     297             : 
     298             : static clib_error_t *
     299       11597 : call_sw_interface_add_del_callbacks (vnet_main_t * vnm, u32 sw_if_index,
     300             :                                      u32 is_create)
     301             : {
     302       23194 :   return call_elf_section_interface_callbacks
     303       11597 :     (vnm, sw_if_index, is_create, vnm->sw_interface_add_del_functions);
     304             : }
     305             : 
     306             : static clib_error_t *
     307       35949 : 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       35949 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     313             :   vnet_hw_interface_class_t *hw_class =
     314       35949 :     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     315             :   u32 mask;
     316       35949 :   clib_error_t *error = 0;
     317       35949 :   u32 is_create =
     318       35949 :     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
     319             : 
     320       35949 :   mask =
     321             :     (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK);
     322       35949 :   flags &= mask;
     323             : 
     324             :   /* Call hardware interface add/del callbacks. */
     325       35949 :   if (is_create)
     326        6300 :     call_hw_interface_add_del_callbacks (vnm, hw_if_index, is_create);
     327             : 
     328             :   /* Already in the desired state? */
     329       35949 :   if (!is_create && (hi->flags & mask) == flags)
     330       16557 :     goto done;
     331             : 
     332       19392 :   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       13092 :       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       13092 :       error = call_elf_section_interface_callbacks
     342       13092 :         (vnm, hw_if_index, flags, vnm->hw_interface_link_up_down_functions);
     343             : 
     344       13092 :       if (error)
     345           0 :         goto done;
     346             :     }
     347             : 
     348       19392 :   hi->flags &= ~mask;
     349       19392 :   hi->flags |= flags;
     350             : 
     351       35949 : done:
     352       35949 :   if (error)
     353           0 :     log_err ("hw_set_flags_helper: %U", format_clib_error, error);
     354       35949 :   return error;
     355             : }
     356             : 
     357             : static clib_error_t *
     358       35842 : 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       35842 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     364             :   u32 mask;
     365       35842 :   clib_error_t *error = 0;
     366       35842 :   u32 is_create =
     367       35842 :     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
     368             :   u32 old_flags;
     369             : 
     370       35842 :   mask = VNET_SW_INTERFACE_FLAG_ADMIN_UP | VNET_SW_INTERFACE_FLAG_PUNT;
     371       35842 :   flags &= mask;
     372             : 
     373       35842 :   if (is_create)
     374             :     {
     375             :       error =
     376        7418 :         call_sw_interface_add_del_callbacks (vnm, sw_if_index, is_create);
     377        7418 :       if (error)
     378           0 :         goto done;
     379             : 
     380        7418 :       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       28424 :       vnet_sw_interface_t *si_sup = si;
     394             : 
     395             :       /* Check that super interface is in correct state. */
     396       28424 :       if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
     397             :         {
     398         142 :           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         142 :           if ((flags != (si_sup->flags & mask)) &&
     402          39 :               (!((flags == 0)
     403          39 :                  && ((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       28424 :       if ((si->flags & mask) == flags)
     417       15156 :         goto done;
     418             : 
     419             :       /* Sub-interfaces of hardware interfaces that do no redistribute,
     420             :          do not redistribute themselves. */
     421       13268 :       if (si_sup->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
     422             :         {
     423             :           vnet_hw_interface_t *hi =
     424       13224 :             vnet_get_hw_interface (vnm, si_sup->hw_if_index);
     425             :           vnet_device_class_t *dev_class =
     426       13224 :             vnet_get_device_class (vnm, hi->dev_class_index);
     427       13224 :           if (!dev_class->redistribute)
     428       13224 :             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       13268 :       old_flags = si->flags;
     435       13268 :       si->flags &= ~mask;
     436       13268 :       si->flags |= flags;
     437       13268 :       if ((flags | old_flags) & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     438       13268 :         error = call_elf_section_interface_callbacks
     439             :           (vnm, sw_if_index, flags,
     440       13268 :            vnm->sw_interface_admin_up_down_functions);
     441             : 
     442       13268 :       if (error)
     443             :         {
     444             :           /* restore flags on error */
     445           0 :           si->flags = old_flags;
     446           0 :           goto done;
     447             :         }
     448             : 
     449       13268 :       if (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
     450             :         {
     451             :           vnet_hw_interface_t *hi =
     452       13090 :             vnet_get_hw_interface (vnm, si->hw_if_index);
     453             :           vnet_hw_interface_class_t *hw_class =
     454       13090 :             vnet_get_hw_interface_class (vnm, hi->hw_class_index);
     455             :           vnet_device_class_t *dev_class =
     456       13090 :             vnet_get_device_class (vnm, hi->dev_class_index);
     457             : 
     458       13090 :           if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
     459        6776 :               (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       13090 :           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
     467        6314 :             si->flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
     468             : 
     469       13090 :           if (dev_class->admin_up_down_function
     470       13085 :               && (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       13090 :           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       13090 :           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     491        6314 :               && (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       13090 :           vnet_hw_if_update_runtime_data (vnm, si->hw_if_index);
     497             :         }
     498             :     }
     499             : 
     500       20686 :   si->flags &= ~mask;
     501       20686 :   si->flags |= flags;
     502             : 
     503       35842 : done:
     504       35842 :   if (error)
     505           0 :     log_err ("sw_set_flags_helper: %U", format_clib_error, error);
     506       35842 :   return error;
     507             : }
     508             : 
     509             : clib_error_t *
     510       29635 : vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
     511             :                              vnet_hw_interface_flags_t flags)
     512             : {
     513       29635 :   log_debug ("hw_set_flags: hw_if_index %u flags 0x%x", hw_if_index, flags);
     514       29635 :   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       28424 : vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
     521             :                              vnet_sw_interface_flags_t flags)
     522             : {
     523       28424 :   log_debug ("sw_set_flags: sw_if_index %u flags 0x%x", sw_if_index, flags);
     524       28424 :   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       10212 : vnet_if_update_lookup_tables (vnet_main_t *vnm, u32 sw_if_index)
     557             : {
     558       10212 :   vnet_interface_main_t *im = &vnm->interface_main;
     559       10212 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
     560             : 
     561       14109 :   vec_validate_init_empty (im->hw_if_index_by_sw_if_index, sw_if_index, ~0);
     562       14109 :   vec_validate_init_empty (im->if_out_arc_end_next_index_by_sw_if_index,
     563             :                            sw_if_index, ~0);
     564             : 
     565       10212 :   im->hw_if_index_by_sw_if_index[sw_if_index] = hi->hw_if_index;
     566       10212 :   im->if_out_arc_end_next_index_by_sw_if_index[sw_if_index] =
     567       10212 :     hi->if_out_arc_end_node_next_index;
     568       10212 : }
     569             : 
     570             : static u32
     571        7418 : vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
     572             :                                        vnet_sw_interface_t * template)
     573             : {
     574        7418 :   vnet_interface_main_t *im = &vnm->interface_main;
     575             :   vnet_sw_interface_t *sw;
     576             :   u32 sw_if_index;
     577             : 
     578        7418 :   pool_get (im->sw_interfaces, sw);
     579        7418 :   sw_if_index = sw - im->sw_interfaces;
     580             : 
     581        7418 :   sw[0] = template[0];
     582             : 
     583        7418 :   sw->flags = 0;
     584        7418 :   sw->sw_if_index = sw_if_index;
     585        7418 :   if (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
     586        6300 :     sw->sup_sw_if_index = sw->sw_if_index;
     587             : 
     588             :   /* Allocate counters for this interface. */
     589             :   {
     590             :     u32 i;
     591             : 
     592        7418 :     vnet_interface_counter_lock (im);
     593             : 
     594       74180 :     for (i = 0; i < vec_len (im->sw_if_counters); i++)
     595             :       {
     596       66762 :         vlib_validate_simple_counter (&im->sw_if_counters[i], sw_if_index);
     597       66762 :         vlib_zero_simple_counter (&im->sw_if_counters[i], sw_if_index);
     598             :       }
     599             : 
     600       66762 :     for (i = 0; i < vec_len (im->combined_sw_if_counters); i++)
     601             :       {
     602       59344 :         vlib_validate_combined_counter (&im->combined_sw_if_counters[i],
     603             :                                         sw_if_index);
     604       59344 :         vlib_zero_combined_counter (&im->combined_sw_if_counters[i],
     605             :                                     sw_if_index);
     606             :       }
     607             : 
     608        7418 :     vnet_interface_counter_unlock (im);
     609             :   }
     610             : 
     611        7418 :   vnet_if_update_lookup_tables (vnm, sw_if_index);
     612        7418 :   return sw_if_index;
     613             : }
     614             : 
     615             : clib_error_t *
     616        1118 : vnet_create_sw_interface (vnet_main_t * vnm, vnet_sw_interface_t * template,
     617             :                           u32 * sw_if_index)
     618             : {
     619        1118 :   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        1118 :   if (template->sub.eth.flags.two_tags == 1
     625          18 :       && template->sub.eth.flags.exact_match == 1
     626          18 :       && (template->sub.eth.flags.inner_vlan_id_any == 1
     627          18 :           || 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        1118 :   hi = vnet_get_sup_hw_interface (vnm, template->sup_sw_if_index);
     636        1118 :   dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
     637             : 
     638        1118 :   if (template->type == VNET_SW_INTERFACE_TYPE_SUB &&
     639          91 :       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        1118 :   *sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, template);
     649        1118 :   error = vnet_sw_interface_set_flags_helper
     650        1118 :     (vnm, *sw_if_index, template->flags,
     651             :      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
     652             : 
     653        1118 :   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        1118 :       vnet_sw_interface_t *sw =
     666        1118 :         pool_elt_at_index (im->sw_interfaces, *sw_if_index);
     667        1118 :       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        1118 :   return error;
     672             : }
     673             : 
     674             : void
     675        4179 : vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
     676             : {
     677        4179 :   vnet_interface_main_t *im = &vnm->interface_main;
     678        4179 :   vnet_sw_interface_t *sw =
     679        4179 :     pool_elt_at_index (im->sw_interfaces, sw_if_index);
     680             : 
     681        4179 :   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        4179 :   vnet_clear_sw_interface_tag (vnm, sw_if_index);
     686             : 
     687             :   /* Bring down interface in case it is up. */
     688        4179 :   if (sw->flags != 0)
     689         637 :     vnet_sw_interface_set_flags (vnm, sw_if_index, /* flags */ 0);
     690             : 
     691        4179 :   call_sw_interface_add_del_callbacks (vnm, sw_if_index, /* is_create */ 0);
     692             : 
     693        4179 :   pool_put (im->sw_interfaces, sw);
     694        4179 : }
     695             : 
     696             : static clib_error_t *
     697        5961 : call_sw_interface_mtu_change_callbacks (vnet_main_t * vnm, u32 sw_if_index)
     698             : {
     699       11922 :   return call_elf_section_interface_callbacks
     700        5961 :     (vnm, sw_if_index, 0, vnm->sw_interface_mtu_change_functions);
     701             : }
     702             : 
     703             : void
     704       11825 : vnet_sw_interface_set_mtu (vnet_main_t * vnm, u32 sw_if_index, u32 mtu)
     705             : {
     706       11825 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     707             : 
     708       11825 :   if (si->mtu[VNET_MTU_L3] != mtu)
     709             :     {
     710        5505 :       si->mtu[VNET_MTU_L3] = mtu;
     711        5505 :       log_debug ("set_mtu: interface %U, new mtu %u",
     712             :                  format_vnet_sw_if_index_name, vnm, sw_if_index, mtu);
     713             : 
     714        5505 :       call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
     715             :     }
     716       11825 : }
     717             : 
     718             : void
     719         543 : vnet_sw_interface_set_protocol_mtu (vnet_main_t * vnm, u32 sw_if_index,
     720             :                                     u32 mtu[])
     721             : {
     722         543 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
     723         543 :   bool changed = false;
     724             :   int i;
     725             : 
     726        2715 :   for (i = 0; i < VNET_N_MTU; i++)
     727             :     {
     728        2172 :       if (si->mtu[i] != mtu[i])
     729             :         {
     730         456 :           si->mtu[i] = mtu[i];
     731         456 :           changed = true;
     732             :         }
     733             :     }
     734             :   /* Notify interested parties */
     735         543 :   if (changed)
     736             :     {
     737         456 :       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         456 :       call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
     742             :     }
     743         543 : }
     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        2794 : setup_tx_node (vlib_main_t * vm,
     811             :                u32 node_index, vnet_device_class_t * dev_class)
     812             : {
     813        2794 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     814             : 
     815        2794 :   n->format_trace = dev_class->format_tx_trace;
     816             : 
     817        2794 :   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        2794 : }
     821             : 
     822             : static void
     823        2794 : setup_output_node (vlib_main_t * vm,
     824             :                    u32 node_index, vnet_hw_interface_class_t * hw_class)
     825             : {
     826        2794 :   vlib_node_t *n = vlib_get_node (vm, node_index);
     827        2794 :   n->format_buffer = hw_class->format_header;
     828        2794 :   n->unformat_buffer = hw_class->unformat_header;
     829        2794 : }
     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        6300 : 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        6300 :   vnet_interface_main_t *im = &vnm->interface_main;
     869             :   vnet_hw_interface_t *hw;
     870             :   vnet_device_class_t *dev_class =
     871        6300 :     vnet_get_device_class (vnm, dev_class_index);
     872             :   vnet_hw_interface_class_t *hw_class =
     873        6300 :     vnet_get_hw_interface_class (vnm, hw_class_index);
     874        6300 :   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        6300 :     vlib_get_node (vm, vnet_interface_output_node.index);
     880             : 
     881        6300 :   pool_get (im->hw_interfaces, hw);
     882        6300 :   clib_memset (hw, 0, sizeof (*hw));
     883        6300 :   hw->trace_classify_table_index = ~0;
     884             : 
     885        6300 :   hw_index = hw - im->hw_interfaces;
     886        6300 :   hw->hw_if_index = hw_index;
     887        6300 :   hw->default_rx_mode = VNET_HW_IF_RX_MODE_POLLING;
     888             : 
     889        6300 :   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        6300 :     hw->hf = vnet_hash_default_function (hw_class->tx_hash_fn_type);
     892             : 
     893        6300 :   if (dev_class->format_device_name)
     894        5730 :     hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
     895         570 :   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         570 :     hw->name = format (0, "%s%x", hw_class->name, dev_instance);
     900             : 
     901        6300 :   if (!im->hw_interface_by_name)
     902         559 :     im->hw_interface_by_name = hash_create_vec ( /* size */ 0,
     903             :                                                 sizeof (hw->name[0]),
     904             :                                                 sizeof (uword));
     905             : 
     906       12600 :   hash_set_mem (im->hw_interface_by_name, hw->name, hw_index);
     907             : 
     908             :   /* Make hardware interface point to software interface. */
     909             :   {
     910        6300 :     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        6300 :     hw->sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, &sw);
     916             :   }
     917             : 
     918        6300 :   hw->dev_class_index = dev_class_index;
     919        6300 :   hw->dev_instance = dev_instance;
     920        6300 :   hw->hw_class_index = hw_class_index;
     921        6300 :   hw->hw_instance = hw_instance;
     922             : 
     923        6300 :   hw->max_rate_bits_per_sec = 0;
     924        6300 :   vnet_sw_interface_set_mtu (vnm, hw->sw_if_index, 0);
     925             : 
     926        6300 :   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        2794 :   if (vec_len (im->deleted_hw_interface_nodes) > 0)
     931         623 :     {
     932             :       vnet_hw_interface_nodes_t *hn;
     933             :       vlib_node_t *node;
     934             :       vlib_node_runtime_t *nrt;
     935             : 
     936         623 :       hn = vec_end (im->deleted_hw_interface_nodes) - 1;
     937             : 
     938         623 :       hw->tx_node_index = hn->tx_node_index;
     939         623 :       hw->output_node_index = hn->output_node_index;
     940             : 
     941         623 :       vlib_node_rename (vm, hw->tx_node_index, "%v-tx", hw->name);
     942         623 :       vlib_node_rename (vm, hw->output_node_index, "%v-output", hw->name);
     943             : 
     944        1262 :       foreach_vlib_main ()
     945             :         {
     946             :           vnet_interface_output_runtime_t *rt;
     947             : 
     948             :           rt =
     949         639 :             vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
     950         639 :           ASSERT (rt->is_deleted == 1);
     951         639 :           rt->is_deleted = 0;
     952         639 :           rt->hw_if_index = hw_index;
     953         639 :           rt->sw_if_index = hw->sw_if_index;
     954         639 :           rt->dev_instance = hw->dev_instance;
     955             : 
     956         639 :           rt = vlib_node_get_runtime_data (this_vlib_main, hw->tx_node_index);
     957         639 :           rt->hw_if_index = hw_index;
     958         639 :           rt->sw_if_index = hw->sw_if_index;
     959         639 :           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         623 :       node = vlib_get_node (vm, hw->output_node_index);
     965         623 :       node->format_trace = format_vnet_interface_output_trace;
     966         623 :       node->node_fn_registrations = if_out_node->node_fn_registrations;
     967         623 :       node->function = if_out_node->function;
     968             : 
     969        1262 :       foreach_vlib_main ()
     970             :         {
     971         639 :           nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
     972         639 :           nrt->function = node->function;
     973         639 :           vlib_node_runtime_perf_counter (this_vlib_main, nrt, 0, 0, 0,
     974             :                                           VLIB_NODE_RUNTIME_PERF_RESET);
     975             :         }
     976             : 
     977         623 :       node = vlib_get_node (vm, hw->tx_node_index);
     978         623 :       if (dev_class->tx_fn_registrations)
     979             :         {
     980         569 :           node->node_fn_registrations = dev_class->tx_fn_registrations;
     981         569 :           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         623 :       node->format_trace = dev_class->format_tx_trace;
     987             : 
     988        1262 :       foreach_vlib_main ()
     989             :         {
     990         639 :           nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
     991         639 :           nrt->function = node->function;
     992         639 :           vlib_node_runtime_perf_counter (this_vlib_main, nrt, 0, 0, 0,
     993             :                                           VLIB_NODE_RUNTIME_PERF_RESET);
     994             :         }
     995             : 
     996         623 :       vec_dec_len (im->deleted_hw_interface_nodes, 1);
     997             :     }
     998             :   else
     999             :     {
    1000             :       vlib_node_registration_t r;
    1001        2171 :       vnet_interface_output_runtime_t rt = {
    1002             :         .hw_if_index = hw_index,
    1003        2171 :         .sw_if_index = hw->sw_if_index,
    1004        2171 :         .dev_instance = hw->dev_instance,
    1005             :         .is_deleted = 0,
    1006             :       };
    1007             : 
    1008        2171 :       clib_memset (&r, 0, sizeof (r));
    1009        2171 :       r.type = VLIB_NODE_TYPE_INTERNAL;
    1010        2171 :       r.runtime_data = &rt;
    1011        2171 :       r.runtime_data_bytes = sizeof (rt);
    1012        2171 :       r.scalar_size = sizeof (vnet_hw_if_tx_frame_t);
    1013        2171 :       r.vector_size = sizeof (u32);
    1014             : 
    1015        2171 :       r.flags = VLIB_NODE_FLAG_IS_OUTPUT;
    1016        2171 :       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        2149 :         r.function = dev_class->tx_function;
    1023             : 
    1024        2171 :       hw->tx_node_index = vlib_register_node (vm, &r, "%v-tx", hw->name);
    1025             : 
    1026        2171 :       vlib_node_add_named_next_with_slot (vm, hw->tx_node_index,
    1027             :                                           "error-drop",
    1028             :                                           VNET_INTERFACE_TX_NEXT_DROP);
    1029             : 
    1030        2171 :       r.flags = 0;
    1031        2171 :       r.format_trace = format_vnet_interface_output_trace;
    1032        2171 :       if (if_out_node->node_fn_registrations)
    1033             :         {
    1034        2171 :           r.function = 0;
    1035        2171 :           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        2171 :         r.n_errors = ARRAY_LEN (e);
    1048        2171 :         r.error_strings = e;
    1049             :       }
    1050        4342 :       hw->output_node_index =
    1051        2171 :         vlib_register_node (vm, &r, "%v-output", hw->name);
    1052             : 
    1053        2171 :       vlib_node_add_named_next_with_slot (vm, hw->output_node_index,
    1054             :                                           "error-drop",
    1055             :                                           VNET_INTERFACE_OUTPUT_NEXT_DROP);
    1056        2171 :       vlib_node_add_next_with_slot (vm, hw->output_node_index,
    1057        2171 :                                     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        2171 :       fcm = vnet_feature_get_config_main (im->output_feature_arc_index);
    1062        2171 :       cm = &fcm->config_main;
    1063        2171 :       i = vec_len (cm->start_node_indices);
    1064        2171 :       vec_validate (cm->start_node_indices, i);
    1065        2171 :       cm->start_node_indices[i] = hw->output_node_index;
    1066        2171 :       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        1612 :           first_hw = vnet_get_hw_interface (vnm, /* hw_if_index */ 0);
    1073        1612 :           first_node = vlib_get_node (vm, first_hw->output_node_index);
    1074             : 
    1075             :           /* 1st 2 nexts are already added above */
    1076        1612 :           for (i = 2; i < vec_len (first_node->next_nodes); i++)
    1077           0 :             vlib_node_add_next_with_slot (vm, hw->output_node_index,
    1078           0 :                                           first_node->next_nodes[i], i);
    1079             :         }
    1080             :     }
    1081             : 
    1082        5588 :   hw->if_out_arc_end_node_next_index = vlib_node_add_next (
    1083        2794 :     vm, vnet_interface_output_arc_end_node.index, hw->tx_node_index);
    1084        2794 :   vnet_if_update_lookup_tables (vnm, hw->sw_if_index);
    1085        2794 :   setup_output_node (vm, hw->output_node_index, hw_class);
    1086        2794 :   setup_tx_node (vm, hw->tx_node_index, dev_class);
    1087             : 
    1088        6300 : no_output_nodes:
    1089             :   /* Call all up/down callbacks with zero flags when interface is created. */
    1090        6300 :   vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0,
    1091             :                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
    1092        6300 :   vnet_hw_interface_set_flags_helper (vnm, hw_index, /* flags */ 0,
    1093             :                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
    1094        6300 :   return hw_index;
    1095             : }
    1096             : 
    1097             : void
    1098        4115 : vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
    1099             : {
    1100        4115 :   vnet_interface_main_t *im = &vnm->interface_main;
    1101        4115 :   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
    1102        4115 :   vlib_main_t *vm = vnm->vlib_main;
    1103        4115 :   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        4115 :   if (hw->flags != 0)
    1107         321 :     vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0);
    1108             : 
    1109             :   /* Call delete callbacks. */
    1110        4115 :   call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
    1111             : 
    1112             :   /* delete rx & tx queues */
    1113        4115 :   vnet_hw_if_unregister_all_rx_queues (vnm, hw_if_index);
    1114        4115 :   vnet_hw_if_unregister_all_tx_queues (vnm, hw_if_index);
    1115        4115 :   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        4308 :     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        4115 :     hash_free (hw->sub_interface_sw_if_index_by_id);
    1130             :     /* *INDENT-ON* */
    1131             :   }
    1132             : 
    1133             :   /* Delete software interface corresponding to hardware interface. */
    1134        4115 :   vnet_delete_sw_interface (vnm, hw->sw_if_index);
    1135             : 
    1136        4115 :   if (dev_class->tx_function)
    1137             :     {
    1138             :       /* Put output/tx nodes into recycle pool */
    1139             :       vnet_hw_interface_nodes_t *dn;
    1140             : 
    1141        1410 :       foreach_vlib_main ()
    1142             :         {
    1143             :           vnet_interface_output_runtime_t *rt =
    1144         721 :             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         721 :           rt->is_deleted = 1;
    1149             :         }
    1150             : 
    1151         689 :       vlib_node_rename (vm, hw->output_node_index,
    1152             :                         "interface-%d-output-deleted", hw_if_index);
    1153         689 :       vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
    1154             :                         hw_if_index);
    1155         689 :       vlib_unregister_errors (vm, hw->output_node_index);
    1156         689 :       vlib_unregister_errors (vm, hw->tx_node_index);
    1157         689 :       vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
    1158         689 :       dn->tx_node_index = hw->tx_node_index;
    1159         689 :       dn->output_node_index = hw->output_node_index;
    1160             :     }
    1161        8230 :   hash_unset_mem (im->hw_interface_by_name, hw->name);
    1162        4115 :   vec_free (hw->name);
    1163        4115 :   vec_free (hw->hw_address);
    1164        4115 :   vec_free (hw->output_node_thread_runtimes);
    1165        4115 :   pool_put (im->hw_interfaces, hw);
    1166        4115 : }
    1167             : 
    1168             : void
    1169       58687 : 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       58687 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
    1177             :   /* the super first, then the sub interfaces */
    1178       58687 :   if (WALK_STOP == fn (vnm, hi->sw_if_index, ctx))
    1179           0 :     return;
    1180             : 
    1181             :   /* *INDENT-OFF* */
    1182       81159 :   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      163982 : vnet_sw_interface_compare (vnet_main_t * vnm,
    1335             :                            uword sw_if_index0, uword sw_if_index1)
    1336             : {
    1337      163982 :   vnet_sw_interface_t *sup0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
    1338      163982 :   vnet_sw_interface_t *sup1 = vnet_get_sup_sw_interface (vnm, sw_if_index1);
    1339      163982 :   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, sup0->hw_if_index);
    1340      163982 :   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, sup1->hw_if_index);
    1341             : 
    1342      163982 :   if (h0 != h1)
    1343      108915 :     return vec_cmp (h0->name, h1->name);
    1344      128277 :   return (word) h0->hw_instance - (word) h1->hw_instance;
    1345             : }
    1346             : 
    1347             : word
    1348       16553 : vnet_hw_interface_compare (vnet_main_t * vnm,
    1349             :                            uword hw_if_index0, uword hw_if_index1)
    1350             : {
    1351       16553 :   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, hw_if_index0);
    1352       16553 :   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, hw_if_index1);
    1353             : 
    1354       16553 :   if (h0 != h1)
    1355       77575 :     return vec_cmp (h0->name, h1->name);
    1356           0 :   return (word) h0->hw_instance - (word) h1->hw_instance;
    1357             : }
    1358             : 
    1359             : int
    1360       58736 : vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
    1361             : {
    1362       58736 :   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
    1363       58736 :   if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
    1364       58636 :       (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
    1365         102 :     return 1;
    1366             : 
    1367       58634 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1368             :   vnet_hw_interface_class_t *hc =
    1369       58634 :     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
    1370             : 
    1371       58634 :   return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_P2P);
    1372             : }
    1373             : 
    1374             : int
    1375       34656 : vnet_sw_interface_is_nbma (vnet_main_t * vnm, u32 sw_if_index)
    1376             : {
    1377       34656 :   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1378             :   vnet_hw_interface_class_t *hc =
    1379       34656 :     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
    1380             : 
    1381       34656 :   return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_NBMA);
    1382             : }
    1383             : 
    1384             : clib_error_t *
    1385        8697 : vnet_sw_interface_supports_addressing (vnet_main_t *vnm, u32 sw_if_index)
    1386             : {
    1387        8697 :   if (sw_if_index == 0)
    1388             :     {
    1389           0 :       return clib_error_create (
    1390             :         "local0 interface doesn't support IP addressing");
    1391             :     }
    1392             : 
    1393        8697 :   if (vnet_sw_interface_is_sub (vnm, sw_if_index))
    1394             :     {
    1395             :       vnet_sw_interface_t *si;
    1396         169 :       si = vnet_get_sw_interface_or_null (vnm, sw_if_index);
    1397         169 :       if (si && si->type == VNET_SW_INTERFACE_TYPE_SUB &&
    1398         129 :           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        8697 :   return NULL;
    1405             : }
    1406             : 
    1407             : clib_error_t *
    1408         559 : vnet_interface_init (vlib_main_t * vm)
    1409             : {
    1410         559 :   vnet_main_t *vnm = vnet_get_main ();
    1411         559 :   vnet_interface_main_t *im = &vnm->interface_main;
    1412         559 :   vlib_buffer_t *b = 0;
    1413         559 :   vnet_buffer_opaque_t *o = 0;
    1414             :   clib_error_t *error;
    1415             : 
    1416             :   /*
    1417             :    * Keep people from shooting themselves in the foot.
    1418             :    */
    1419             :   if (sizeof (b->opaque) != sizeof (vnet_buffer_opaque_t))
    1420             :     {
    1421             : #define _(a) if (sizeof(o->a) > sizeof (o->unused))                     \
    1422             :       clib_warning                                                      \
    1423             :         ("FATAL: size of opaque union subtype %s is %d (max %d)",       \
    1424             :          #a, sizeof(o->a), sizeof (o->unused));
    1425             :       foreach_buffer_opaque_union_subtype;
    1426             : #undef _
    1427             : 
    1428             :       return clib_error_return
    1429             :         (0, "FATAL: size of vlib buffer opaque %d, size of vnet opaque %d",
    1430             :          sizeof (b->opaque), sizeof (vnet_buffer_opaque_t));
    1431             :     }
    1432             : 
    1433         559 :   clib_spinlock_init (&im->sw_if_counter_lock);
    1434         559 :   clib_spinlock_lock (&im->sw_if_counter_lock);  /* should be no need */
    1435             : 
    1436         559 :   vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
    1437             : #define _(E,n,p)                                                        \
    1438             :   im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n;          \
    1439             :   im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
    1440         559 :   foreach_simple_interface_counter_name
    1441             : #undef _
    1442         559 :     vec_validate (im->combined_sw_if_counters,
    1443             :                   VNET_N_COMBINED_INTERFACE_COUNTER - 1);
    1444             : #define _(E,n,p)                                                        \
    1445             :   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n; \
    1446             :   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
    1447         559 :   foreach_combined_interface_counter_name
    1448             : #undef _
    1449         559 :     clib_spinlock_unlock (&im->sw_if_counter_lock);
    1450             : 
    1451         559 :   im->device_class_by_name = hash_create_string ( /* size */ 0,
    1452             :                                                  sizeof (uword));
    1453             :   {
    1454             :     vnet_device_class_t *c;
    1455             : 
    1456         559 :     c = vnm->device_class_registrations;
    1457             : 
    1458       19006 :     while (c)
    1459             :       {
    1460       18447 :         c->index = vec_len (im->device_classes);
    1461       36894 :         hash_set_mem (im->device_class_by_name, c->name, c->index);
    1462             : 
    1463             :         /* to avoid confusion, please remove ".tx_function" statement
    1464             :           from VNET_DEVICE_CLASS() if using function candidates */
    1465       18447 :         ASSERT (c->tx_fn_registrations == 0 || c->tx_function == 0);
    1466             : 
    1467       18447 :         if (c->tx_fn_registrations)
    1468        5031 :           c->tx_function = vlib_node_get_preferred_node_fn_variant (
    1469             :             vm, c->tx_fn_registrations);
    1470             : 
    1471       18447 :         vec_add1 (im->device_classes, c[0]);
    1472       18447 :         c = c->next_class_registration;
    1473             :       }
    1474             :   }
    1475             : 
    1476         559 :   im->hw_interface_class_by_name = hash_create_string ( /* size */ 0,
    1477             :                                                        sizeof (uword));
    1478             : 
    1479         559 :   im->rxq_index_by_hw_if_index_and_queue_id =
    1480         559 :     hash_create_mem (0, sizeof (u64), sizeof (u32));
    1481         559 :   im->txq_index_by_hw_if_index_and_queue_id =
    1482         559 :     hash_create_mem (0, sizeof (u64), sizeof (u32));
    1483         559 :   im->sw_if_index_by_sup_and_sub = hash_create_mem (0, sizeof (u64),
    1484             :                                                     sizeof (uword));
    1485             :   {
    1486             :     vnet_hw_interface_class_t *c;
    1487             : 
    1488         559 :     c = vnm->hw_interface_class_registrations;
    1489             : 
    1490       17329 :     while (c)
    1491             :       {
    1492       16770 :         c->index = vec_len (im->hw_interface_classes);
    1493       33540 :         hash_set_mem (im->hw_interface_class_by_name, c->name, c->index);
    1494             : 
    1495       16770 :         if (NULL == c->build_rewrite)
    1496        4472 :           c->build_rewrite = default_build_rewrite;
    1497       16770 :         if (NULL == c->update_adjacency)
    1498        9503 :           c->update_adjacency = default_update_adjacency;
    1499             : 
    1500       16770 :         vec_add1 (im->hw_interface_classes, c[0]);
    1501       16770 :         c = c->next_class_registration;
    1502             :       }
    1503             :   }
    1504             : 
    1505             :   /* init per-thread data */
    1506         559 :   vec_validate_aligned (im->per_thread_data, vlib_num_workers (),
    1507             :                         CLIB_CACHE_LINE_BYTES);
    1508             : 
    1509         559 :   if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
    1510           0 :     return error;
    1511             : 
    1512         559 :   vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
    1513             : 
    1514         559 :   return 0;
    1515             : }
    1516             : 
    1517       10079 : VLIB_INIT_FUNCTION (vnet_interface_init);
    1518             : 
    1519             : /* Kludge to renumber interface names [only!] */
    1520             : int
    1521           0 : vnet_interface_name_renumber (u32 sw_if_index, u32 new_show_dev_instance)
    1522             : {
    1523             :   int rv;
    1524           0 :   vnet_main_t *vnm = vnet_get_main ();
    1525           0 :   vnet_interface_main_t *im = &vnm->interface_main;
    1526           0 :   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1527             : 
    1528           0 :   vnet_device_class_t *dev_class = vnet_get_device_class
    1529             :     (vnm, hi->dev_class_index);
    1530             : 
    1531           0 :   if (dev_class->name_renumber == 0 || dev_class->format_device_name == 0)
    1532           0 :     return VNET_API_ERROR_UNIMPLEMENTED;
    1533             : 
    1534           0 :   rv = dev_class->name_renumber (hi, new_show_dev_instance);
    1535             : 
    1536           0 :   if (rv)
    1537           0 :     return rv;
    1538             : 
    1539           0 :   hash_unset_mem (im->hw_interface_by_name, hi->name);
    1540           0 :   vec_free (hi->name);
    1541             :   /* Use the mapping we set up to call it Ishmael */
    1542           0 :   hi->name = format (0, "%U", dev_class->format_device_name,
    1543             :                      hi->dev_instance);
    1544             : 
    1545           0 :   hash_set_mem (im->hw_interface_by_name, hi->name, hi->hw_if_index);
    1546           0 :   return rv;
    1547             : }
    1548             : 
    1549             : clib_error_t *
    1550           0 : vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
    1551             : {
    1552           0 :   vnet_interface_main_t *im = &vnm->interface_main;
    1553           0 :   vlib_main_t *vm = vnm->vlib_main;
    1554             :   vnet_hw_interface_t *hw;
    1555             :   u8 *old_name;
    1556           0 :   clib_error_t *error = 0;
    1557             : 
    1558           0 :   hw = vnet_get_hw_interface (vnm, hw_if_index);
    1559           0 :   if (!hw)
    1560             :     {
    1561           0 :       return clib_error_return (0,
    1562             :                                 "unable to find hw interface for index %u",
    1563             :                                 hw_if_index);
    1564             :     }
    1565             : 
    1566           0 :   old_name = hw->name;
    1567             : 
    1568             :   /* set new hw->name */
    1569           0 :   hw->name = format (0, "%s", new_name);
    1570             : 
    1571             :   /* remove the old name to hw_if_index mapping and install the new one */
    1572           0 :   hash_unset_mem (im->hw_interface_by_name, old_name);
    1573           0 :   hash_set_mem (im->hw_interface_by_name, hw->name, hw_if_index);
    1574             : 
    1575             :   /* rename tx/output nodes */
    1576           0 :   vlib_node_rename (vm, hw->tx_node_index, "%v-tx", hw->name);
    1577           0 :   vlib_node_rename (vm, hw->output_node_index, "%v-output", hw->name);
    1578             : 
    1579             :   /* free the old name vector */
    1580           0 :   vec_free (old_name);
    1581             : 
    1582           0 :   return error;
    1583             : }
    1584             : 
    1585             : clib_error_t *
    1586       27669 : vnet_hw_interface_add_del_mac_address (vnet_main_t * vnm,
    1587             :                                        u32 hw_if_index,
    1588             :                                        const u8 * mac_address, u8 is_add)
    1589             : {
    1590       27669 :   clib_error_t *error = 0;
    1591       27669 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1592             : 
    1593             :   vnet_device_class_t *dev_class =
    1594       27669 :     vnet_get_device_class (vnm, hi->dev_class_index);
    1595             : 
    1596       27669 :   if (!hi->hw_address)
    1597             :     {
    1598             :       error =
    1599        2497 :         clib_error_return
    1600             :         (0, "Secondary MAC Addresses not supported for interface index %u",
    1601             :          hw_if_index);
    1602        2497 :       goto done;
    1603             :     }
    1604             : 
    1605       25172 :   if (dev_class->mac_addr_add_del_function)
    1606       23890 :     error = dev_class->mac_addr_add_del_function (hi, mac_address, is_add);
    1607             : 
    1608       25172 :   if (!error)
    1609             :     {
    1610             :       vnet_hw_interface_class_t *hw_class;
    1611             : 
    1612       25172 :       hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
    1613             : 
    1614       25172 :       if (NULL != hw_class->mac_addr_add_del_function)
    1615           0 :         error = hw_class->mac_addr_add_del_function (hi, mac_address, is_add);
    1616             :     }
    1617             : 
    1618             :   /* If no errors, add to the list of secondary MACs on the ethernet intf */
    1619       25172 :   if (!error)
    1620       25172 :     ethernet_interface_add_del_address (&ethernet_main, hw_if_index,
    1621             :                                         mac_address, is_add);
    1622             : 
    1623           0 : done:
    1624       27669 :   if (error)
    1625        2497 :     log_err ("hw_add_del_mac_address: %U", format_clib_error, error);
    1626       27669 :   return error;
    1627             : }
    1628             : 
    1629             : static clib_error_t *
    1630          29 : vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
    1631             :                                              u32 hw_if_index,
    1632             :                                              const u8 * mac_address)
    1633             : {
    1634          29 :   clib_error_t *error = 0;
    1635          29 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
    1636             : 
    1637          29 :   if (hi->hw_address)
    1638             :     {
    1639          29 :       u8 *old_address = vec_dup (hi->hw_address);
    1640             :       vnet_device_class_t *dev_class =
    1641          29 :         vnet_get_device_class (vnm, hi->dev_class_index);
    1642          29 :       if (dev_class->mac_addr_change_function)
    1643             :         {
    1644             :           error =
    1645           1 :             dev_class->mac_addr_change_function (hi, old_address,
    1646             :                                                  mac_address);
    1647             :         }
    1648          29 :       if (!error)
    1649             :         {
    1650             :           vnet_hw_interface_class_t *hw_class;
    1651             : 
    1652          29 :           hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
    1653             : 
    1654          29 :           if (NULL != hw_class->mac_addr_change_function)
    1655          29 :             hw_class->mac_addr_change_function (hi, old_address, mac_address);
    1656             :         }
    1657             :       else
    1658             :         {
    1659             :           error =
    1660           0 :             clib_error_return (0,
    1661             :                                "MAC Address Change is not supported on this interface");
    1662             :         }
    1663          29 :       vec_free (old_address);
    1664             :     }
    1665             :   else
    1666             :     {
    1667             :       error =
    1668           0 :         clib_error_return (0,
    1669             :                            "mac address change is not supported for interface index %u",
    1670             :                            hw_if_index);
    1671             :     }
    1672          29 :   return error;
    1673             : }
    1674             : 
    1675             : clib_error_t *
    1676          29 : vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index,
    1677             :                                       const u8 * mac_address)
    1678             : {
    1679          29 :   return vnet_hw_interface_change_mac_address_helper
    1680             :     (vnm, hw_if_index, mac_address);
    1681             : }
    1682             : 
    1683             : static int
    1684          30 : vnet_sw_interface_check_table_same (u32 unnumbered_sw_if_index,
    1685             :                                     u32 ip_sw_if_index)
    1686             : {
    1687          30 :   if (ip4_main.fib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1688          30 :       ip4_main.fib_index_by_sw_if_index[ip_sw_if_index])
    1689           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1690             : 
    1691          30 :   if (ip4_main.mfib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1692          30 :       ip4_main.mfib_index_by_sw_if_index[ip_sw_if_index])
    1693           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1694             : 
    1695          30 :   if (ip6_main.fib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1696          30 :       ip6_main.fib_index_by_sw_if_index[ip_sw_if_index])
    1697           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1698             : 
    1699          30 :   if (ip6_main.mfib_index_by_sw_if_index[unnumbered_sw_if_index] !=
    1700          30 :       ip6_main.mfib_index_by_sw_if_index[ip_sw_if_index])
    1701           0 :     return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
    1702             : 
    1703          30 :   return 0;
    1704             : }
    1705             : 
    1706             : /* update the unnumbered state of an interface*/
    1707             : int
    1708        8391 : vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index,
    1709             :                                      u32 ip_sw_if_index, u8 enable)
    1710             : {
    1711        8391 :   vnet_main_t *vnm = vnet_get_main ();
    1712             :   vnet_sw_interface_t *si;
    1713             :   u32 was_unnum;
    1714        8391 :   int rv = 0;
    1715             : 
    1716        8391 :   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
    1717        8391 :   was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
    1718             : 
    1719        8391 :   if (enable)
    1720             :     {
    1721          30 :       rv = vnet_sw_interface_check_table_same (unnumbered_sw_if_index,
    1722             :                                                ip_sw_if_index);
    1723          30 :       if (rv != 0)
    1724           0 :         return rv;
    1725          30 :       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
    1726          30 :       si->unnumbered_sw_if_index = ip_sw_if_index;
    1727             : 
    1728          30 :       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
    1729          30 :         [unnumbered_sw_if_index] =
    1730             :         ip4_main.
    1731          30 :         lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
    1732             :       ip6_main.
    1733          30 :         lookup_main.if_address_pool_index_by_sw_if_index
    1734          30 :         [unnumbered_sw_if_index] =
    1735             :         ip6_main.
    1736          30 :         lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
    1737             :     }
    1738             :   else
    1739             :     {
    1740             :       /*
    1741             :        * Unless the interface is actually unnumbered, don't
    1742             :        * smash e.g. if_address_pool_index_by_sw_if_index
    1743             :        */
    1744        8361 :       if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
    1745             :         {
    1746          21 :           si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
    1747          21 :           si->unnumbered_sw_if_index = (u32) ~0;
    1748             : 
    1749             :           ip4_main.lookup_main
    1750          21 :             .if_address_pool_index_by_sw_if_index[unnumbered_sw_if_index] = ~0;
    1751             :           ip6_main.lookup_main
    1752          21 :             .if_address_pool_index_by_sw_if_index[unnumbered_sw_if_index] = ~0;
    1753             :         }
    1754             :     }
    1755             : 
    1756        8391 :   if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
    1757             :     {
    1758          48 :       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
    1759          48 :       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
    1760             :     }
    1761             : 
    1762        8391 :   return 0;
    1763             : }
    1764             : 
    1765             : vnet_l3_packet_type_t
    1766           0 : vnet_link_to_l3_proto (vnet_link_t link)
    1767             : {
    1768           0 :   switch (link)
    1769             :     {
    1770           0 :     case VNET_LINK_IP4:
    1771           0 :       return (VNET_L3_PACKET_TYPE_IP4);
    1772           0 :     case VNET_LINK_IP6:
    1773           0 :       return (VNET_L3_PACKET_TYPE_IP6);
    1774           0 :     case VNET_LINK_MPLS:
    1775           0 :       return (VNET_L3_PACKET_TYPE_MPLS);
    1776           0 :     case VNET_LINK_ARP:
    1777           0 :       return (VNET_L3_PACKET_TYPE_ARP);
    1778           0 :     case VNET_LINK_ETHERNET:
    1779             :     case VNET_LINK_NSH:
    1780           0 :       ASSERT (0);
    1781           0 :       break;
    1782             :     }
    1783           0 :   ASSERT (0);
    1784           0 :   return (0);
    1785             : }
    1786             : 
    1787             : vnet_mtu_t
    1788       42615 : vnet_link_to_mtu (vnet_link_t link)
    1789             : {
    1790       42615 :   switch (link)
    1791             :     {
    1792       15722 :     case VNET_LINK_IP4:
    1793       15722 :       return (VNET_MTU_IP4);
    1794       22215 :     case VNET_LINK_IP6:
    1795       22215 :       return (VNET_MTU_IP6);
    1796         152 :     case VNET_LINK_MPLS:
    1797         152 :       return (VNET_MTU_MPLS);
    1798        4526 :     default:
    1799        4526 :       return (VNET_MTU_L3);
    1800             :     }
    1801             : }
    1802             : 
    1803             : u8 *
    1804          56 : default_build_rewrite (vnet_main_t * vnm,
    1805             :                        u32 sw_if_index,
    1806             :                        vnet_link_t link_type, const void *dst_address)
    1807             : {
    1808          56 :   return (NULL);
    1809             : }
    1810             : 
    1811             : void
    1812          90 : default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
    1813             : {
    1814             :   ip_adjacency_t *adj;
    1815             : 
    1816          90 :   adj = adj_get (ai);
    1817             : 
    1818          90 :   switch (adj->lookup_next_index)
    1819             :     {
    1820           0 :     case IP_LOOKUP_NEXT_GLEAN:
    1821           0 :       adj_glean_update_rewrite (ai);
    1822           0 :       break;
    1823          78 :     case IP_LOOKUP_NEXT_ARP:
    1824             :     case IP_LOOKUP_NEXT_BCAST:
    1825             :       /*
    1826             :        * default rewrite in neighbour adj
    1827             :        */
    1828          78 :       adj_nbr_update_rewrite
    1829             :         (ai,
    1830             :          ADJ_NBR_REWRITE_FLAG_COMPLETE,
    1831             :          vnet_build_rewrite_for_sw_interface (vnm,
    1832             :                                               sw_if_index,
    1833          78 :                                               adj_get_link_type (ai), NULL));
    1834          78 :       break;
    1835          12 :     case IP_LOOKUP_NEXT_MCAST:
    1836             :       /*
    1837             :        * mcast traffic also uses default rewrite string with no mcast
    1838             :        * switch time updates.
    1839             :        */
    1840          12 :       adj_mcast_update_rewrite
    1841             :         (ai,
    1842             :          vnet_build_rewrite_for_sw_interface (vnm,
    1843             :                                               sw_if_index,
    1844          12 :                                               adj_get_link_type (ai),
    1845             :                                               NULL), 0);
    1846          12 :       break;
    1847           0 :     case IP_LOOKUP_NEXT_DROP:
    1848             :     case IP_LOOKUP_NEXT_PUNT:
    1849             :     case IP_LOOKUP_NEXT_LOCAL:
    1850             :     case IP_LOOKUP_NEXT_REWRITE:
    1851             :     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
    1852             :     case IP_LOOKUP_NEXT_MIDCHAIN:
    1853             :     case IP_LOOKUP_NEXT_ICMP_ERROR:
    1854             :     case IP_LOOKUP_N_NEXT:
    1855           0 :       ASSERT (0);
    1856           0 :       break;
    1857             :     }
    1858          90 : }
    1859             : 
    1860             : clib_error_t *
    1861           0 : vnet_hw_interface_set_rss_queues (vnet_main_t * vnm,
    1862             :                                   vnet_hw_interface_t * hi,
    1863             :                                   clib_bitmap_t * bitmap)
    1864             : {
    1865           0 :   clib_error_t *error = 0;
    1866             :   vnet_device_class_t *dev_class =
    1867           0 :     vnet_get_device_class (vnm, hi->dev_class_index);
    1868             : 
    1869           0 :   if (dev_class->set_rss_queues_function)
    1870             :     {
    1871           0 :       if (clib_bitmap_count_set_bits (bitmap) == 0)
    1872             :         {
    1873           0 :           error = clib_error_return (0,
    1874             :                                      "must assign at least one valid rss queue");
    1875           0 :           goto done;
    1876             :         }
    1877             : 
    1878           0 :       error = dev_class->set_rss_queues_function (vnm, hi, bitmap);
    1879             :     }
    1880             :   else
    1881             :     {
    1882           0 :       error = clib_error_return (0,
    1883             :                                  "setting rss queues is not supported on this interface");
    1884             :     }
    1885             : 
    1886           0 :   if (!error)
    1887             :     {
    1888           0 :       clib_bitmap_free (hi->rss_queues);
    1889           0 :       hi->rss_queues = clib_bitmap_dup (bitmap);
    1890             :     }
    1891             : 
    1892           0 : done:
    1893           0 :   if (error)
    1894           0 :     log_err ("hw_set_rss_queues: %U", format_clib_error, error);
    1895           0 :   return error;
    1896             : }
    1897             : 
    1898             : int collect_detailed_interface_stats_flag = 0;
    1899             : 
    1900             : void
    1901           0 : collect_detailed_interface_stats_flag_set (void)
    1902             : {
    1903           0 :   collect_detailed_interface_stats_flag = 1;
    1904           0 : }
    1905             : 
    1906             : void
    1907           0 : collect_detailed_interface_stats_flag_clear (void)
    1908             : {
    1909           0 :   collect_detailed_interface_stats_flag = 0;
    1910           0 : }
    1911             : 
    1912             : static clib_error_t *
    1913           0 : collect_detailed_interface_stats_cli (vlib_main_t * vm,
    1914             :                                       unformat_input_t * input,
    1915             :                                       vlib_cli_command_t * cmd)
    1916             : {
    1917           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    1918           0 :   clib_error_t *error = NULL;
    1919             : 
    1920             :   /* Get a line of input. */
    1921           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    1922           0 :     return clib_error_return (0, "expected enable | disable");
    1923             : 
    1924           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1925             :     {
    1926           0 :       if (unformat (line_input, "enable") || unformat (line_input, "on"))
    1927           0 :         collect_detailed_interface_stats_flag_set ();
    1928           0 :       else if (unformat (line_input, "disable")
    1929           0 :                || unformat (line_input, "off"))
    1930           0 :         collect_detailed_interface_stats_flag_clear ();
    1931             :       else
    1932             :         {
    1933           0 :           error = clib_error_return (0, "unknown input `%U'",
    1934             :                                      format_unformat_error, line_input);
    1935           0 :           goto done;
    1936             :         }
    1937             :     }
    1938             : 
    1939           0 : done:
    1940           0 :   unformat_free (line_input);
    1941           0 :   return error;
    1942             : }
    1943             : 
    1944             : /* *INDENT-OFF* */
    1945      272887 : VLIB_CLI_COMMAND (collect_detailed_interface_stats_command, static) = {
    1946             :   .path = "interface collect detailed-stats",
    1947             :   .short_help = "interface collect detailed-stats <enable|disable>",
    1948             :   .function = collect_detailed_interface_stats_cli,
    1949             : };
    1950             : /* *INDENT-ON* */
    1951             : 
    1952             : /*
    1953             :  * fd.io coding-style-patch-verification: ON
    1954             :  *
    1955             :  * Local Variables:
    1956             :  * eval: (c-set-style "gnu")
    1957             :  * End:
    1958             :  */

Generated by: LCOV version 1.14