LCOV - code coverage report
Current view: top level - vnet/bonding - device.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 117 311 37.6 %
Date: 2023-07-05 22:20:52 Functions: 21 31 67.7 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #define _GNU_SOURCE
      19             : #include <stdint.h>
      20             : #include <vnet/ip-neighbor/ip4_neighbor.h>
      21             : #include <vnet/ip-neighbor/ip6_neighbor.h>
      22             : #include <vnet/bonding/node.h>
      23             : 
      24             : #define foreach_bond_tx_error                                                 \
      25             :   _ (NONE, "no error")                                                        \
      26             :   _ (IF_DOWN, "interface down")                                               \
      27             :   _ (BAD_LB_MODE, "bad load balance mode")                                    \
      28             :   _ (NO_MEMBER, "no member")
      29             : 
      30             : typedef enum
      31             : {
      32             : #define _(f,s) BOND_TX_ERROR_##f,
      33             :   foreach_bond_tx_error
      34             : #undef _
      35             :     BOND_TX_N_ERROR,
      36             : } bond_tx_error_t;
      37             : 
      38             : static char *bond_tx_error_strings[] = {
      39             : #define _(n,s) s,
      40             :   foreach_bond_tx_error
      41             : #undef _
      42             : };
      43             : 
      44             : static u8 *
      45           0 : format_bond_tx_trace (u8 * s, va_list * args)
      46             : {
      47           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      48           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      49           0 :   bond_packet_trace_t *t = va_arg (*args, bond_packet_trace_t *);
      50             :   vnet_hw_interface_t *hw, *hw1;
      51           0 :   vnet_main_t *vnm = vnet_get_main ();
      52             : 
      53           0 :   hw = vnet_get_sup_hw_interface (vnm, t->sw_if_index);
      54           0 :   hw1 = vnet_get_sup_hw_interface (vnm, t->bond_sw_if_index);
      55           0 :   s = format (s, "src %U, dst %U, %s -> %s",
      56           0 :               format_ethernet_address, t->ethernet.src_address,
      57           0 :               format_ethernet_address, t->ethernet.dst_address,
      58             :               hw->name, hw1->name);
      59             : 
      60           0 :   return s;
      61             : }
      62             : 
      63             : #ifndef CLIB_MARCH_VARIANT
      64             : u8 *
      65           9 : format_bond_interface_name (u8 * s, va_list * args)
      66             : {
      67           9 :   u32 dev_instance = va_arg (*args, u32);
      68           9 :   bond_main_t *bm = &bond_main;
      69           9 :   bond_if_t *bif = pool_elt_at_index (bm->interfaces, dev_instance);
      70             : 
      71           9 :   s = format (s, "BondEthernet%lu", bif->id);
      72             : 
      73           9 :   return s;
      74             : }
      75             : #endif
      76             : 
      77             : static __clib_unused clib_error_t *
      78           0 : bond_set_l2_mode_function (vnet_main_t * vnm,
      79             :                            struct vnet_hw_interface_t *bif_hw,
      80             :                            i32 l2_if_adjust)
      81             : {
      82             :   bond_if_t *bif;
      83             :   u32 *sw_if_index;
      84             :   struct vnet_hw_interface_t *mif_hw;
      85             : 
      86           0 :   bif = bond_get_bond_if_by_sw_if_index (bif_hw->sw_if_index);
      87           0 :   if (!bif)
      88           0 :     return 0;
      89             : 
      90           0 :   if ((bif_hw->l2_if_count == 1) && (l2_if_adjust == 1))
      91             :     {
      92             :       /* Just added first L2 interface on this port */
      93           0 :       vec_foreach (sw_if_index, bif->members)
      94             :       {
      95           0 :         mif_hw = vnet_get_sup_hw_interface (vnm, *sw_if_index);
      96           0 :         ethernet_set_flags (vnm, mif_hw->hw_if_index,
      97             :                             ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
      98             :       }
      99             :     }
     100           0 :   else if ((bif_hw->l2_if_count == 0) && (l2_if_adjust == -1))
     101             :     {
     102             :       /* Just removed last L2 subinterface on this port */
     103           0 :       vec_foreach (sw_if_index, bif->members)
     104             :       {
     105           0 :         mif_hw = vnet_get_sup_hw_interface (vnm, *sw_if_index);
     106           0 :         ethernet_set_flags (vnm, mif_hw->hw_if_index,
     107             :                             /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);
     108             :       }
     109             :     }
     110             : 
     111           0 :   return 0;
     112             : }
     113             : 
     114             : static __clib_unused clib_error_t *
     115           0 : bond_subif_add_del_function (vnet_main_t * vnm, u32 hw_if_index,
     116             :                              struct vnet_sw_interface_t *st, int is_add)
     117             : {
     118             :   /* Nothing for now */
     119           0 :   return 0;
     120             : }
     121             : 
     122             : static clib_error_t *
     123          20 : bond_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
     124             : {
     125          20 :   vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
     126          20 :   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
     127          20 :   bond_main_t *bm = &bond_main;
     128          20 :   bond_if_t *bif = pool_elt_at_index (bm->interfaces, hif->dev_instance);
     129             : 
     130          20 :   bif->admin_up = is_up;
     131          20 :   if (is_up)
     132          10 :     vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
     133             :                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
     134          20 :   return 0;
     135             : }
     136             : 
     137             : static clib_error_t *
     138           4 : bond_add_del_mac_address (vnet_hw_interface_t * hi, const u8 * address,
     139             :                           u8 is_add)
     140             : {
     141           4 :   vnet_main_t *vnm = vnet_get_main ();
     142             :   bond_if_t *bif;
     143           4 :   clib_error_t *error = 0;
     144             :   vnet_hw_interface_t *s_hi;
     145             :   int i;
     146             : 
     147             : 
     148           4 :   bif = bond_get_bond_if_by_sw_if_index (hi->sw_if_index);
     149           4 :   if (!bif)
     150             :     {
     151           0 :       return clib_error_return (0,
     152             :                                 "No bond interface found for sw_if_index %u",
     153             :                                 hi->sw_if_index);
     154             :     }
     155             : 
     156             :   /* Add/del address on each member hw intf, they control the hardware */
     157           4 :   vec_foreach_index (i, bif->members)
     158             :   {
     159           0 :     s_hi = vnet_get_sup_hw_interface (vnm, vec_elt (bif->members, i));
     160           0 :     error = vnet_hw_interface_add_del_mac_address (vnm, s_hi->hw_if_index,
     161             :                                                    address, is_add);
     162             : 
     163           0 :     if (error)
     164             :       {
     165             :         int j;
     166             : 
     167             :         /* undo any that were completed before the failure */
     168           0 :         for (j = i - 1; j > -1; j--)
     169             :           {
     170           0 :             s_hi = vnet_get_sup_hw_interface (vnm, vec_elt (bif->members, j));
     171           0 :             vnet_hw_interface_add_del_mac_address (vnm, s_hi->hw_if_index,
     172             :                                                    address, !(is_add));
     173             :           }
     174             : 
     175           0 :         return error;
     176             :       }
     177             :   }
     178             : 
     179           4 :   return 0;
     180             : }
     181             : 
     182             : static_always_inline void
     183           2 : bond_tx_add_to_queue (bond_per_thread_data_t * ptd, u32 port, u32 bi)
     184             : {
     185           2 :   u32 idx = ptd->per_port_queue[port].n_buffers++;
     186           2 :   ptd->per_port_queue[port].buffers[idx] = bi;
     187           2 : }
     188             : 
     189             : static_always_inline u32
     190           0 : bond_lb_broadcast (vlib_main_t *vm, bond_if_t *bif, vlib_buffer_t *b0,
     191             :                    uword n_members)
     192             : {
     193           0 :   bond_main_t *bm = &bond_main;
     194             :   vlib_buffer_t *c0;
     195             :   int port;
     196             :   u32 sw_if_index;
     197           0 :   u16 thread_index = vm->thread_index;
     198           0 :   bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
     199             :                                                   thread_index);
     200             : 
     201           0 :   for (port = 1; port < n_members; port++)
     202             :     {
     203           0 :       sw_if_index = *vec_elt_at_index (bif->active_members, port);
     204           0 :       c0 = vlib_buffer_copy (vm, b0);
     205           0 :       if (PREDICT_TRUE (c0 != 0))
     206             :         {
     207           0 :           vnet_buffer (c0)->sw_if_index[VLIB_TX] = sw_if_index;
     208           0 :           bond_tx_add_to_queue (ptd, port, vlib_get_buffer_index (vm, c0));
     209             :         }
     210             :     }
     211             : 
     212           0 :   return 0;
     213             : }
     214             : 
     215             : static_always_inline u32
     216           0 : bond_lb_round_robin (bond_if_t *bif, vlib_buffer_t *b0, uword n_members)
     217             : {
     218           0 :   bif->lb_rr_last_index++;
     219           0 :   if (bif->lb_rr_last_index >= n_members)
     220           0 :     bif->lb_rr_last_index = 0;
     221             : 
     222           0 :   return bif->lb_rr_last_index;
     223             : }
     224             : 
     225             : static_always_inline void
     226           1 : bond_tx_hash (vlib_main_t *vm, bond_per_thread_data_t *ptd, bond_if_t *bif,
     227             :               vlib_buffer_t **b, u32 *h, u32 n_left)
     228             : {
     229           1 :   u32 n_left_from = n_left;
     230             :   void **data;
     231             : 
     232           1 :   ASSERT (bif->hash_func != 0);
     233             : 
     234           1 :   vec_validate_aligned (ptd->data, n_left - 1, CLIB_CACHE_LINE_BYTES);
     235           1 :   data = ptd->data;
     236           1 :   while (n_left >= 8)
     237             :     {
     238             :       // Prefetch next iteration
     239           0 :       vlib_prefetch_buffer_header (b[4], LOAD);
     240           0 :       vlib_prefetch_buffer_header (b[5], LOAD);
     241           0 :       vlib_prefetch_buffer_header (b[6], LOAD);
     242           0 :       vlib_prefetch_buffer_header (b[7], LOAD);
     243             : 
     244           0 :       data[0] = vlib_buffer_get_current (b[0]);
     245           0 :       data[1] = vlib_buffer_get_current (b[1]);
     246           0 :       data[2] = vlib_buffer_get_current (b[2]);
     247           0 :       data[3] = vlib_buffer_get_current (b[3]);
     248             : 
     249           0 :       n_left -= 4;
     250           0 :       b += 4;
     251           0 :       data += 4;
     252             :     }
     253             : 
     254           3 :   while (n_left > 0)
     255             :     {
     256           2 :       data[0] = vlib_buffer_get_current (b[0]);
     257             : 
     258           2 :       n_left -= 1;
     259           2 :       b += 1;
     260           2 :       data += 1;
     261             :     }
     262             : 
     263           1 :   bif->hash_func (ptd->data, h, n_left_from);
     264           1 :   vec_reset_length (ptd->data);
     265           1 : }
     266             : 
     267             : static_always_inline void
     268           0 : bond_tx_no_hash (vlib_main_t *vm, bond_if_t *bif, vlib_buffer_t **b, u32 *h,
     269             :                  u32 n_left, uword n_members, u32 lb_alg)
     270             : {
     271           0 :   while (n_left >= 8)
     272             :     {
     273             :       // Prefetch next iteration
     274           0 :       vlib_prefetch_buffer_header (b[4], LOAD);
     275           0 :       vlib_prefetch_buffer_header (b[5], LOAD);
     276           0 :       vlib_prefetch_buffer_header (b[6], LOAD);
     277           0 :       vlib_prefetch_buffer_header (b[7], LOAD);
     278             : 
     279           0 :       clib_prefetch_load (b[4]->data);
     280           0 :       clib_prefetch_load (b[5]->data);
     281           0 :       clib_prefetch_load (b[6]->data);
     282           0 :       clib_prefetch_load (b[7]->data);
     283             : 
     284           0 :       if (lb_alg == BOND_LB_RR)
     285             :         {
     286           0 :           h[0] = bond_lb_round_robin (bif, b[0], n_members);
     287           0 :           h[1] = bond_lb_round_robin (bif, b[1], n_members);
     288           0 :           h[2] = bond_lb_round_robin (bif, b[2], n_members);
     289           0 :           h[3] = bond_lb_round_robin (bif, b[3], n_members);
     290             :         }
     291           0 :       else if (lb_alg == BOND_LB_BC)
     292             :         {
     293           0 :           h[0] = bond_lb_broadcast (vm, bif, b[0], n_members);
     294           0 :           h[1] = bond_lb_broadcast (vm, bif, b[1], n_members);
     295           0 :           h[2] = bond_lb_broadcast (vm, bif, b[2], n_members);
     296           0 :           h[3] = bond_lb_broadcast (vm, bif, b[3], n_members);
     297             :         }
     298             :       else
     299             :         {
     300           0 :           ASSERT (0);
     301             :         }
     302             : 
     303           0 :       n_left -= 4;
     304           0 :       b += 4;
     305           0 :       h += 4;
     306             :     }
     307             : 
     308           0 :   while (n_left > 0)
     309             :     {
     310           0 :       if (bif->lb == BOND_LB_RR)
     311           0 :         h[0] = bond_lb_round_robin (bif, b[0], n_members);
     312           0 :       else if (bif->lb == BOND_LB_BC)
     313           0 :         h[0] = bond_lb_broadcast (vm, bif, b[0], n_members);
     314             :       else
     315             :         {
     316           0 :           ASSERT (0);
     317             :         }
     318             : 
     319           0 :       n_left -= 1;
     320           0 :       b += 1;
     321           0 :       h += 1;
     322             :     }
     323           0 : }
     324             : 
     325             : static_always_inline void
     326           1 : bond_hash_to_port (u32 * h, u32 n_left, u32 n_members,
     327             :                    int use_modulo_shortcut)
     328             : {
     329           1 :   u32 mask = n_members - 1;
     330             : 
     331           1 :   while (n_left > 4)
     332             :     {
     333           0 :       if (use_modulo_shortcut)
     334             :         {
     335           0 :           h[0] &= mask;
     336           0 :           h[1] &= mask;
     337           0 :           h[2] &= mask;
     338           0 :           h[3] &= mask;
     339             :         }
     340             :       else
     341             :         {
     342           0 :           h[0] %= n_members;
     343           0 :           h[1] %= n_members;
     344           0 :           h[2] %= n_members;
     345           0 :           h[3] %= n_members;
     346             :         }
     347           0 :       n_left -= 4;
     348           0 :       h += 4;
     349             :     }
     350           3 :   while (n_left)
     351             :     {
     352           2 :       if (use_modulo_shortcut)
     353           2 :         h[0] &= mask;
     354             :       else
     355           0 :         h[0] %= n_members;
     356           2 :       n_left -= 1;
     357           2 :       h += 1;
     358             :     }
     359           1 : }
     360             : 
     361             : static_always_inline void
     362           1 : bond_update_sw_if_index (bond_per_thread_data_t * ptd, bond_if_t * bif,
     363             :                          u32 * bi, vlib_buffer_t ** b, u32 * data, u32 n_left,
     364             :                          int single_sw_if_index)
     365             : {
     366           1 :   u32 sw_if_index = data[0];
     367           1 :   u32 *h = data;
     368             : 
     369           1 :   while (n_left >= 8)
     370             :     {
     371             :       // Prefetch next iteration
     372           0 :       vlib_prefetch_buffer_header (b[4], LOAD);
     373           0 :       vlib_prefetch_buffer_header (b[5], LOAD);
     374           0 :       vlib_prefetch_buffer_header (b[6], LOAD);
     375           0 :       vlib_prefetch_buffer_header (b[7], LOAD);
     376             : 
     377           0 :       if (PREDICT_FALSE (single_sw_if_index))
     378             :         {
     379           0 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = sw_if_index;
     380           0 :           vnet_buffer (b[1])->sw_if_index[VLIB_TX] = sw_if_index;
     381           0 :           vnet_buffer (b[2])->sw_if_index[VLIB_TX] = sw_if_index;
     382           0 :           vnet_buffer (b[3])->sw_if_index[VLIB_TX] = sw_if_index;
     383             : 
     384           0 :           bond_tx_add_to_queue (ptd, 0, bi[0]);
     385           0 :           bond_tx_add_to_queue (ptd, 0, bi[1]);
     386           0 :           bond_tx_add_to_queue (ptd, 0, bi[2]);
     387           0 :           bond_tx_add_to_queue (ptd, 0, bi[3]);
     388             :         }
     389             :       else
     390             :         {
     391           0 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
     392           0 :             *vec_elt_at_index (bif->active_members, h[0]);
     393           0 :           vnet_buffer (b[1])->sw_if_index[VLIB_TX] =
     394           0 :             *vec_elt_at_index (bif->active_members, h[1]);
     395           0 :           vnet_buffer (b[2])->sw_if_index[VLIB_TX] =
     396           0 :             *vec_elt_at_index (bif->active_members, h[2]);
     397           0 :           vnet_buffer (b[3])->sw_if_index[VLIB_TX] =
     398           0 :             *vec_elt_at_index (bif->active_members, h[3]);
     399             : 
     400           0 :           bond_tx_add_to_queue (ptd, h[0], bi[0]);
     401           0 :           bond_tx_add_to_queue (ptd, h[1], bi[1]);
     402           0 :           bond_tx_add_to_queue (ptd, h[2], bi[2]);
     403           0 :           bond_tx_add_to_queue (ptd, h[3], bi[3]);
     404             :         }
     405             : 
     406           0 :       bi += 4;
     407           0 :       h += 4;
     408           0 :       b += 4;
     409           0 :       n_left -= 4;
     410             :     }
     411           3 :   while (n_left)
     412             :     {
     413           2 :       if (PREDICT_FALSE (single_sw_if_index))
     414             :         {
     415           0 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] = sw_if_index;
     416           0 :           bond_tx_add_to_queue (ptd, 0, bi[0]);
     417             :         }
     418             :       else
     419             :         {
     420           2 :           vnet_buffer (b[0])->sw_if_index[VLIB_TX] =
     421           2 :             *vec_elt_at_index (bif->active_members, h[0]);
     422           2 :           bond_tx_add_to_queue (ptd, h[0], bi[0]);
     423             :         }
     424             : 
     425           2 :       bi += 1;
     426           2 :       h += 1;
     427           2 :       b += 1;
     428           2 :       n_left -= 1;
     429             :     }
     430           1 : }
     431             : 
     432             : static_always_inline void
     433           1 : bond_tx_trace (vlib_main_t * vm, vlib_node_runtime_t * node, bond_if_t * bif,
     434             :                vlib_buffer_t ** b, u32 n_left, u32 * h)
     435             : {
     436           1 :   uword n_trace = vlib_get_trace_count (vm, node);
     437             : 
     438           1 :   while (n_trace > 0 && n_left > 0)
     439             :     {
     440           0 :       if (PREDICT_TRUE
     441             :           (vlib_trace_buffer (vm, node, 0, b[0], 0 /* follow_chain */ )))
     442             :         {
     443             :           bond_packet_trace_t *t0;
     444             :           ethernet_header_t *eth;
     445             : 
     446           0 :           vlib_set_trace_count (vm, node, --n_trace);
     447           0 :           t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
     448           0 :           eth = vlib_buffer_get_current (b[0]);
     449           0 :           t0->ethernet = *eth;
     450           0 :           t0->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
     451           0 :           if (!h)
     452             :             {
     453           0 :               t0->bond_sw_if_index =
     454           0 :                 *vec_elt_at_index (bif->active_members, 0);
     455             :             }
     456             :           else
     457             :             {
     458           0 :               t0->bond_sw_if_index =
     459           0 :                 *vec_elt_at_index (bif->active_members, h[0]);
     460           0 :               h++;
     461             :             }
     462             :         }
     463           0 :       b++;
     464           0 :       n_left--;
     465             :     }
     466           1 : }
     467             : 
     468        2237 : VNET_DEVICE_CLASS_TX_FN (bond_dev_class) (vlib_main_t * vm,
     469             :                                           vlib_node_runtime_t * node,
     470             :                                           vlib_frame_t * frame)
     471             : {
     472           1 :   vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
     473           1 :   bond_main_t *bm = &bond_main;
     474           1 :   u16 thread_index = vm->thread_index;
     475           1 :   bond_if_t *bif = pool_elt_at_index (bm->interfaces, rund->dev_instance);
     476             :   uword n_members;
     477             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
     478           1 :   u32 *from = vlib_frame_vector_args (frame);
     479           1 :   u32 n_left = frame->n_vectors;
     480             :   u32 hashes[VLIB_FRAME_SIZE], *h;
     481           1 :   vnet_main_t *vnm = vnet_get_main ();
     482           1 :   bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
     483             :                                                   thread_index);
     484             :   u32 p, sw_if_index;
     485             : 
     486           1 :   if (PREDICT_FALSE (bif->admin_up == 0))
     487             :     {
     488           0 :       vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
     489           0 :       vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
     490             :                                      VNET_INTERFACE_COUNTER_DROP,
     491             :                                      thread_index, bif->sw_if_index,
     492           0 :                                      frame->n_vectors);
     493           0 :       vlib_error_count (vm, node->node_index, BOND_TX_ERROR_IF_DOWN,
     494           0 :                         frame->n_vectors);
     495           0 :       return frame->n_vectors;
     496             :     }
     497             : 
     498           1 :   n_members = vec_len (bif->active_members);
     499           1 :   if (PREDICT_FALSE (n_members == 0))
     500             :     {
     501           0 :       vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
     502           0 :       vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
     503             :                                      VNET_INTERFACE_COUNTER_DROP,
     504             :                                      thread_index, bif->sw_if_index,
     505           0 :                                      frame->n_vectors);
     506           0 :       vlib_error_count (vm, node->node_index, BOND_TX_ERROR_NO_MEMBER,
     507           0 :                         frame->n_vectors);
     508           0 :       return frame->n_vectors;
     509             :     }
     510             : 
     511           1 :   vlib_get_buffers (vm, from, bufs, n_left);
     512             : 
     513             :   /* active-backup mode, ship everything to first sw if index */
     514           1 :   if ((bif->lb == BOND_LB_AB) || PREDICT_FALSE (n_members == 1))
     515             :     {
     516           0 :       sw_if_index = *vec_elt_at_index (bif->active_members, 0);
     517             : 
     518           0 :       bond_tx_trace (vm, node, bif, bufs, frame->n_vectors, 0);
     519           0 :       bond_update_sw_if_index (ptd, bif, from, bufs, &sw_if_index, n_left,
     520             :                                /* single_sw_if_index */ 1);
     521           0 :       goto done;
     522             :     }
     523             : 
     524           1 :   if (bif->lb == BOND_LB_BC)
     525             :     {
     526           0 :       sw_if_index = *vec_elt_at_index (bif->active_members, 0);
     527             : 
     528           0 :       bond_tx_no_hash (vm, bif, bufs, hashes, n_left, n_members, BOND_LB_BC);
     529           0 :       bond_tx_trace (vm, node, bif, bufs, frame->n_vectors, 0);
     530           0 :       bond_update_sw_if_index (ptd, bif, from, bufs, &sw_if_index, n_left,
     531             :                                /* single_sw_if_index */ 1);
     532           0 :       goto done;
     533             :     }
     534             : 
     535             :   /* if have at least one member on local numa node, only members on local numa
     536             :      node will transmit pkts when bif->local_numa_only is enabled */
     537           1 :   if (bif->n_numa_members >= 1)
     538           0 :     n_members = bif->n_numa_members;
     539             : 
     540           1 :   if (bif->lb == BOND_LB_RR)
     541           0 :     bond_tx_no_hash (vm, bif, bufs, hashes, n_left, n_members, BOND_LB_RR);
     542             :   else
     543           1 :     bond_tx_hash (vm, ptd, bif, bufs, hashes, n_left);
     544             : 
     545             :   /* calculate port out of hash */
     546           1 :   h = hashes;
     547           1 :   if (BOND_MODULO_SHORTCUT (n_members))
     548           1 :     bond_hash_to_port (h, frame->n_vectors, n_members, 1);
     549             :   else
     550           0 :     bond_hash_to_port (h, frame->n_vectors, n_members, 0);
     551             : 
     552           1 :   bond_tx_trace (vm, node, bif, bufs, frame->n_vectors, h);
     553             : 
     554           1 :   bond_update_sw_if_index (ptd, bif, from, bufs, hashes, frame->n_vectors,
     555             :                            /* single_sw_if_index */ 0);
     556             : 
     557           1 : done:
     558           3 :   for (p = 0; p < n_members; p++)
     559             :     {
     560             :       vlib_frame_t *f;
     561             :       u32 *to_next;
     562             : 
     563           2 :       sw_if_index = *vec_elt_at_index (bif->active_members, p);
     564           2 :       if (PREDICT_TRUE (ptd->per_port_queue[p].n_buffers))
     565             :         {
     566           2 :           f = vnet_get_frame_to_sw_interface (vnm, sw_if_index);
     567           2 :           f->n_vectors = ptd->per_port_queue[p].n_buffers;
     568           2 :           to_next = vlib_frame_vector_args (f);
     569           2 :           clib_memcpy_fast (to_next, ptd->per_port_queue[p].buffers,
     570           2 :                             f->n_vectors * sizeof (u32));
     571           2 :           vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
     572           2 :           ptd->per_port_queue[p].n_buffers = 0;
     573             :         }
     574             :     }
     575           1 :   return frame->n_vectors;
     576             : }
     577             : 
     578             : static walk_rc_t
     579           0 : bond_active_interface_switch_cb (vnet_main_t * vnm, u32 sw_if_index,
     580             :                                  void *arg)
     581             : {
     582           0 :   bond_main_t *bm = &bond_main;
     583             : 
     584           0 :   ip4_neighbor_advertise (bm->vlib_main, bm->vnet_main, sw_if_index,
     585           0 :                           vlib_get_thread_index (), NULL);
     586           0 :   ip6_neighbor_advertise (bm->vlib_main, bm->vnet_main, sw_if_index,
     587           0 :                           vlib_get_thread_index (), NULL);
     588             : 
     589           0 :   return (WALK_CONTINUE);
     590             : }
     591             : 
     592             : static uword
     593         559 : bond_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
     594             : {
     595         559 :   vnet_main_t *vnm = vnet_get_main ();
     596         559 :   uword event_type, *event_data = 0;
     597             : 
     598             :   while (1)
     599           0 :     {
     600             :       u32 i;
     601             :       u32 hw_if_index;
     602             : 
     603         559 :       vlib_process_wait_for_event (vm);
     604           0 :       event_type = vlib_process_get_events (vm, &event_data);
     605           0 :       ASSERT (event_type == BOND_SEND_GARP_NA);
     606           0 :       for (i = 0; i < vec_len (event_data); i++)
     607             :         {
     608           0 :           hw_if_index = event_data[i];
     609           0 :           if (vnet_get_hw_interface_or_null (vnm, hw_if_index))
     610             :             /* walk hw interface to process all subinterfaces */
     611           0 :             vnet_hw_interface_walk_sw (vnm, hw_if_index,
     612             :                                        bond_active_interface_switch_cb, 0);
     613             :         }
     614           0 :       vec_reset_length (event_data);
     615             :     }
     616             :   return 0;
     617             : }
     618             : 
     619             : /* *INDENT-OFF* */
     620      178120 : VLIB_REGISTER_NODE (bond_process_node) = {
     621             :   .function = bond_process,
     622             :   .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
     623             :   .type = VLIB_NODE_TYPE_PROCESS,
     624             :   .name = "bond-process",
     625             : };
     626             : /* *INDENT-ON* */
     627             : 
     628             : /* *INDENT-OFF* */
     629       11199 : VNET_DEVICE_CLASS (bond_dev_class) = {
     630             :   .name = "bond",
     631             :   .tx_function_n_errors = BOND_TX_N_ERROR,
     632             :   .tx_function_error_strings = bond_tx_error_strings,
     633             :   .format_device_name = format_bond_interface_name,
     634             :   .set_l2_mode_function = bond_set_l2_mode_function,
     635             :   .admin_up_down_function = bond_interface_admin_up_down,
     636             :   .subif_add_del_function = bond_subif_add_del_function,
     637             :   .format_tx_trace = format_bond_tx_trace,
     638             :   .mac_addr_add_del_function = bond_add_del_mac_address,
     639             : };
     640             : 
     641             : /* *INDENT-ON* */
     642             : 
     643             : static clib_error_t *
     644       11597 : bond_member_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
     645             : {
     646       11597 :   bond_main_t *bm = &bond_main;
     647             :   member_if_t *mif;
     648       11597 :   bond_detach_member_args_t args = { 0 };
     649             : 
     650       11597 :   if (is_add)
     651        7418 :     return 0;
     652        4179 :   mif = bond_get_member_by_sw_if_index (sw_if_index);
     653        4179 :   if (!mif)
     654        4179 :     return 0;
     655           0 :   args.member = sw_if_index;
     656           0 :   bond_detach_member (bm->vlib_main, &args);
     657           0 :   return args.error;
     658             : }
     659             : 
     660        3363 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (bond_member_interface_add_del);
     661             : 
     662             : /*
     663             :  * fd.io coding-style-patch-verification: ON
     664             :  *
     665             :  * Local Variables:
     666             :  * eval: (c-set-style "gnu")
     667             :  * End:
     668             :  */

Generated by: LCOV version 1.14