blob: 2acc670a33da75cad5bb2cb53f01133e7381f8ef [file] [log] [blame]
Steven9cd2d7a2017-12-20 12:43:01 -08001/*
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#include <stdint.h>
19#include <vlib/vlib.h>
20#include <vlib/unix/unix.h>
21#include <vnet/ethernet/ethernet.h>
22#include <vnet/bonding/node.h>
Steven Luong0f09a822019-08-07 12:20:22 -070023#include <vpp/stats/stat_segment.h>
Steven9cd2d7a2017-12-20 12:43:01 -080024
25void
26bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
27{
Steven9f781d82018-06-05 11:09:32 -070028 bond_main_t *bm = &bond_main;
Steven9cd2d7a2017-12-20 12:43:01 -080029 bond_if_t *bif;
30 int i;
31 uword p;
Steven9f781d82018-06-05 11:09:32 -070032 u8 switching_active = 0;
Steven9cd2d7a2017-12-20 12:43:01 -080033
34 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
Stevena005e7f2018-03-22 17:46:58 -070035 clib_spinlock_lock_if_init (&bif->lockp);
Steven9cd2d7a2017-12-20 12:43:01 -080036 vec_foreach_index (i, bif->active_slaves)
37 {
38 p = *vec_elt_at_index (bif->active_slaves, i);
39 if (p == sif->sw_if_index)
40 {
Steven Luonga1876b82019-08-20 16:58:00 -070041 if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && (i == 0) &&
42 (vec_len (bif->active_slaves) > 1))
43 /* deleting the active slave for active-backup */
44 switching_active = 1;
Steven9cd2d7a2017-12-20 12:43:01 -080045 vec_del1 (bif->active_slaves, i);
46 hash_unset (bif->active_slave_by_sw_if_index, sif->sw_if_index);
Zhiyong Yang751e3f32019-06-26 05:49:14 -040047 if (sif->lacp_enabled && bif->numa_only)
48 {
49 /* For lacp mode, if we check it is a slave on local numa node,
50 bif->n_numa_slaves should be decreased by 1 becasue the first
51 bif->n_numa_slaves are all slaves on local numa node */
52 if (i < bif->n_numa_slaves)
53 {
54 bif->n_numa_slaves--;
55 ASSERT (bif->n_numa_slaves >= 0);
56 }
57 }
Steven9cd2d7a2017-12-20 12:43:01 -080058 break;
59 }
60 }
Zhiyong Yang6865d3c2019-05-15 04:25:20 -040061
62 /* We get a new slave just becoming active */
Steven Luonga1876b82019-08-20 16:58:00 -070063 if (switching_active)
64 vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
65 BOND_SEND_GARP_NA, bif->hw_if_index);
Stevena005e7f2018-03-22 17:46:58 -070066 clib_spinlock_unlock_if_init (&bif->lockp);
Zhiyong Yang6865d3c2019-05-15 04:25:20 -040067
Steven Luong0f09a822019-08-07 12:20:22 -070068 if (bif->mode == BOND_MODE_LACP)
69 stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
70 [sif->sw_if_index], sif->actor.state);
Steven9cd2d7a2017-12-20 12:43:01 -080071}
72
Steven Luonga1876b82019-08-20 16:58:00 -070073/*
74 * return 1 if s2 is preferred.
75 * return -1 if s1 is preferred.
76 */
77static int
78bond_slave_sort (void *a1, void *a2)
79{
80 u32 *s1 = a1;
81 u32 *s2 = a2;
82 slave_if_t *sif1 = bond_get_slave_by_sw_if_index (*s1);
83 slave_if_t *sif2 = bond_get_slave_by_sw_if_index (*s2);
84 bond_if_t *bif;
85
86 ASSERT (sif1);
87 ASSERT (sif2);
88 /*
89 * sort entries according to preference rules:
90 * 1. biggest weight
91 * 2. numa-node
92 * 3. current active slave (to prevent churning)
93 * 4. lowest sw_if_index (for deterministic behavior)
94 *
95 */
96 if (sif2->weight > sif1->weight)
97 return 1;
98 if (sif2->weight < sif1->weight)
99 return -1;
100 else
101 {
102 if (sif2->is_local_numa > sif1->is_local_numa)
103 return 1;
104 if (sif2->is_local_numa < sif1->is_local_numa)
105 return -1;
106 else
107 {
108 bif = bond_get_master_by_dev_instance (sif1->bif_dev_instance);
109 /* Favor the current active slave to avoid churning */
110 if (bif->active_slaves[0] == sif2->sw_if_index)
111 return 1;
112 if (bif->active_slaves[0] == sif1->sw_if_index)
113 return -1;
114 /* go for the tiebreaker as the last resort */
115 if (sif1->sw_if_index > sif2->sw_if_index)
116 return 1;
117 if (sif1->sw_if_index < sif2->sw_if_index)
118 return -1;
119 else
120 ASSERT (0);
121 }
122 }
123 return 0;
124}
125
126static void
127bond_sort_slaves (bond_if_t * bif)
128{
129 bond_main_t *bm = &bond_main;
130 u32 old_active = bif->active_slaves[0];
131
132 vec_sort_with_function (bif->active_slaves, bond_slave_sort);
133 if (old_active != bif->active_slaves[0])
134 vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
135 BOND_SEND_GARP_NA, bif->hw_if_index);
136}
137
Steven9cd2d7a2017-12-20 12:43:01 -0800138void
139bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
140{
141 bond_if_t *bif;
Steven9f781d82018-06-05 11:09:32 -0700142 bond_main_t *bm = &bond_main;
Zhiyong Yang6865d3c2019-05-15 04:25:20 -0400143 vnet_main_t *vnm = vnet_get_main ();
144 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800145
146 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
Stevena005e7f2018-03-22 17:46:58 -0700147 clib_spinlock_lock_if_init (&bif->lockp);
Steven9cd2d7a2017-12-20 12:43:01 -0800148 if (!hash_get (bif->active_slave_by_sw_if_index, sif->sw_if_index))
149 {
150 hash_set (bif->active_slave_by_sw_if_index, sif->sw_if_index,
151 sif->sw_if_index);
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400152
153 if ((sif->lacp_enabled && bif->numa_only)
154 && (vm->numa_node == hw->numa_node))
155 {
156 vec_insert_elts (bif->active_slaves, &sif->sw_if_index, 1,
157 bif->n_numa_slaves);
158 bif->n_numa_slaves++;
159 }
160 else
Steven Luonga1876b82019-08-20 16:58:00 -0700161 vec_add1 (bif->active_slaves, sif->sw_if_index);
Steven9f781d82018-06-05 11:09:32 -0700162
Steven Luonga1876b82019-08-20 16:58:00 -0700163 sif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0;
164 if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
Zhiyong Yang6865d3c2019-05-15 04:25:20 -0400165 {
Steven Luonga1876b82019-08-20 16:58:00 -0700166 if (vec_len (bif->active_slaves) == 1)
167 /* First slave becomes active? */
168 vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
169 BOND_SEND_GARP_NA, bif->hw_if_index);
170 else
171 bond_sort_slaves (bif);
Zhiyong Yang6865d3c2019-05-15 04:25:20 -0400172 }
Steven9cd2d7a2017-12-20 12:43:01 -0800173 }
Stevena005e7f2018-03-22 17:46:58 -0700174 clib_spinlock_unlock_if_init (&bif->lockp);
Zhiyong Yang6865d3c2019-05-15 04:25:20 -0400175
Steven Luong0f09a822019-08-07 12:20:22 -0700176 if (bif->mode == BOND_MODE_LACP)
177 stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
178 [sif->sw_if_index], sif->actor.state);
Steven9cd2d7a2017-12-20 12:43:01 -0800179}
180
181int
182bond_dump_ifs (bond_interface_details_t ** out_bondifs)
183{
184 vnet_main_t *vnm = vnet_get_main ();
185 bond_main_t *bm = &bond_main;
186 bond_if_t *bif;
187 vnet_hw_interface_t *hi;
188 bond_interface_details_t *r_bondifs = NULL;
189 bond_interface_details_t *bondif = NULL;
190
191 /* *INDENT-OFF* */
192 pool_foreach (bif, bm->interfaces,
193 vec_add2(r_bondifs, bondif, 1);
Dave Barachb7b92992018-10-17 10:38:51 -0400194 clib_memset (bondif, 0, sizeof (*bondif));
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500195 bondif->id = bif->id;
Steven9cd2d7a2017-12-20 12:43:01 -0800196 bondif->sw_if_index = bif->sw_if_index;
197 hi = vnet_get_hw_interface (vnm, bif->hw_if_index);
198 clib_memcpy(bondif->interface_name, hi->name,
199 MIN (ARRAY_LEN (bondif->interface_name) - 1,
200 strlen ((const char *) hi->name)));
201 bondif->mode = bif->mode;
202 bondif->lb = bif->lb;
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400203 bondif->numa_only = bif->numa_only;
Steven9cd2d7a2017-12-20 12:43:01 -0800204 bondif->active_slaves = vec_len (bif->active_slaves);
205 bondif->slaves = vec_len (bif->slaves);
206 );
207 /* *INDENT-ON* */
208
209 *out_bondifs = r_bondifs;
210
211 return 0;
212}
213
214int
215bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs,
216 u32 bond_sw_if_index)
217{
218 vnet_main_t *vnm = vnet_get_main ();
219 bond_if_t *bif;
220 vnet_hw_interface_t *hi;
221 vnet_sw_interface_t *sw;
222 slave_interface_details_t *r_slaveifs = NULL;
223 slave_interface_details_t *slaveif = NULL;
224 u32 *sw_if_index = NULL;
225 slave_if_t *sif;
226
227 bif = bond_get_master_by_sw_if_index (bond_sw_if_index);
228 if (!bif)
229 return 1;
230
231 vec_foreach (sw_if_index, bif->slaves)
232 {
233 vec_add2 (r_slaveifs, slaveif, 1);
Dave Barachb7b92992018-10-17 10:38:51 -0400234 clib_memset (slaveif, 0, sizeof (*slaveif));
Steven9cd2d7a2017-12-20 12:43:01 -0800235 sif = bond_get_slave_by_sw_if_index (*sw_if_index);
236 if (sif)
237 {
238 sw = vnet_get_sw_interface (vnm, sif->sw_if_index);
239 hi = vnet_get_hw_interface (vnm, sw->hw_if_index);
240 clib_memcpy (slaveif->interface_name, hi->name,
241 MIN (ARRAY_LEN (slaveif->interface_name) - 1,
242 strlen ((const char *) hi->name)));
243 slaveif->sw_if_index = sif->sw_if_index;
244 slaveif->is_passive = sif->is_passive;
245 slaveif->is_long_timeout = sif->is_long_timeout;
Steven Luonga1876b82019-08-20 16:58:00 -0700246 slaveif->is_local_numa = sif->is_local_numa;
247 slaveif->weight = sif->weight;
Steven9cd2d7a2017-12-20 12:43:01 -0800248 }
249 }
250 *out_slaveifs = r_slaveifs;
251
252 return 0;
253}
254
255static void
256bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, slave_if_t * sif)
257{
258 bond_main_t *bm = &bond_main;
259 vnet_main_t *vnm = vnet_get_main ();
260 int i;
Stevence2db6a2018-04-23 17:06:24 -0700261 vnet_hw_interface_t *sif_hw;
Steven4f8863b2018-04-12 19:36:19 -0700262
263 sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800264
265 bif->port_number_bitmap =
266 clib_bitmap_set (bif->port_number_bitmap,
267 ntohs (sif->actor_admin.port_number) - 1, 0);
Steven0d883012018-05-11 11:06:23 -0700268 bm->slave_by_sw_if_index[sif->sw_if_index] = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800269 vec_free (sif->last_marker_pkt);
270 vec_free (sif->last_rx_pkt);
271 vec_foreach_index (i, bif->slaves)
272 {
273 uword p = *vec_elt_at_index (bif->slaves, i);
274 if (p == sif->sw_if_index)
275 {
276 vec_del1 (bif->slaves, i);
277 break;
278 }
279 }
280
281 bond_disable_collecting_distributing (vm, sif);
282
Steven5967baf2018-09-24 21:09:36 -0700283 vnet_feature_enable_disable ("device-input", "bond-input",
284 sif_hw->hw_if_index, 0, 0, 0);
285
Steven9cd2d7a2017-12-20 12:43:01 -0800286 /* Put back the old mac */
Steven4f8863b2018-04-12 19:36:19 -0700287 vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
Steven9cd2d7a2017-12-20 12:43:01 -0800288 sif->persistent_hw_address);
289
Steven9cd2d7a2017-12-20 12:43:01 -0800290 if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
291 (*bm->lacp_enable_disable) (vm, bif, sif, 0);
Steven5967baf2018-09-24 21:09:36 -0700292
Steven Luong0f09a822019-08-07 12:20:22 -0700293 if (bif->mode == BOND_MODE_LACP)
294 stat_segment_deregister_state_counter
295 (bm->stats[bif->sw_if_index][sif->sw_if_index]);
296
Steven5967baf2018-09-24 21:09:36 -0700297 pool_put (bm->neighbors, sif);
Steven9cd2d7a2017-12-20 12:43:01 -0800298}
299
300int
301bond_delete_if (vlib_main_t * vm, u32 sw_if_index)
302{
303 bond_main_t *bm = &bond_main;
304 vnet_main_t *vnm = vnet_get_main ();
305 bond_if_t *bif;
306 slave_if_t *sif;
307 vnet_hw_interface_t *hw;
308 u32 *sif_sw_if_index;
Steven70488ab2018-03-28 17:59:00 -0700309 u32 **s_list = 0;
310 u32 i;
Steven9cd2d7a2017-12-20 12:43:01 -0800311
312 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
313 if (hw == NULL || bond_dev_class.index != hw->dev_class_index)
314 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
315
316 bif = bond_get_master_by_dev_instance (hw->dev_instance);
317
318 vec_foreach (sif_sw_if_index, bif->slaves)
319 {
Steven70488ab2018-03-28 17:59:00 -0700320 vec_add1 (s_list, sif_sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800321 }
322
Steven70488ab2018-03-28 17:59:00 -0700323 for (i = 0; i < vec_len (s_list); i++)
324 {
325 sif_sw_if_index = s_list[i];
326 sif = bond_get_slave_by_sw_if_index (*sif_sw_if_index);
327 if (sif)
328 bond_delete_neighbor (vm, bif, sif);
329 }
330
331 if (s_list)
332 vec_free (s_list);
333
Steven9cd2d7a2017-12-20 12:43:01 -0800334 /* bring down the interface */
335 vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0);
336 vnet_sw_interface_set_flags (vnm, bif->sw_if_index, 0);
337
338 ethernet_delete_interface (vnm, bif->hw_if_index);
339
340 clib_bitmap_free (bif->port_number_bitmap);
341 hash_unset (bm->bond_by_sw_if_index, bif->sw_if_index);
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500342 hash_unset (bm->id_used, bif->id);
Dave Barachb7b92992018-10-17 10:38:51 -0400343 clib_memset (bif, 0, sizeof (*bif));
Steven9cd2d7a2017-12-20 12:43:01 -0800344 pool_put (bm->interfaces, bif);
345
346 return 0;
347}
348
349void
350bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args)
351{
352 bond_main_t *bm = &bond_main;
353 vnet_main_t *vnm = vnet_get_main ();
354 vnet_sw_interface_t *sw;
355 bond_if_t *bif;
356
357 if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0)
358 {
359 args->rv = VNET_API_ERROR_FEATURE_DISABLED;
360 args->error = clib_error_return (0, "LACP plugin is not loaded");
361 return;
362 }
363 if (args->mode > BOND_MODE_LACP || args->mode < BOND_MODE_ROUND_ROBIN)
364 {
365 args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
366 args->error = clib_error_return (0, "Invalid mode");
367 return;
368 }
369 if (args->lb > BOND_LB_L23)
370 {
371 args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
372 args->error = clib_error_return (0, "Invalid load-balance");
373 return;
374 }
375 pool_get (bm->interfaces, bif);
Dave Barachb7b92992018-10-17 10:38:51 -0400376 clib_memset (bif, 0, sizeof (*bif));
Steven9cd2d7a2017-12-20 12:43:01 -0800377 bif->dev_instance = bif - bm->interfaces;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500378 bif->id = args->id;
Steven9cd2d7a2017-12-20 12:43:01 -0800379 bif->lb = args->lb;
380 bif->mode = args->mode;
381
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500382 // Adjust requested interface id
383 if (bif->id == ~0)
384 bif->id = bif->dev_instance;
385 if (hash_get (bm->id_used, bif->id))
386 {
387 args->rv = VNET_API_ERROR_INSTANCE_IN_USE;
388 pool_put (bm->interfaces, bif);
389 return;
390 }
391 hash_set (bm->id_used, bif->id, 1);
392
Steven9cd2d7a2017-12-20 12:43:01 -0800393 // Special load-balance mode used for rr and bc
394 if (bif->mode == BOND_MODE_ROUND_ROBIN)
395 bif->lb = BOND_LB_RR;
396 else if (bif->mode == BOND_MODE_BROADCAST)
397 bif->lb = BOND_LB_BC;
Steven318de5d2018-10-06 22:30:50 -0700398 else if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
399 bif->lb = BOND_LB_AB;
Steven9cd2d7a2017-12-20 12:43:01 -0800400
401 bif->use_custom_mac = args->hw_addr_set;
402 if (!args->hw_addr_set)
403 {
404 f64 now = vlib_time_now (vm);
405 u32 rnd;
406 rnd = (u32) (now * 1e6);
407 rnd = random_u32 (&rnd);
408
409 memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
410 args->hw_addr[0] = 2;
411 args->hw_addr[1] = 0xfe;
412 }
413 memcpy (bif->hw_address, args->hw_addr, 6);
414 args->error = ethernet_register_interface
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500415 (vnm, bond_dev_class.index, bif->dev_instance /* device instance */ ,
Steven9cd2d7a2017-12-20 12:43:01 -0800416 bif->hw_address /* ethernet address */ ,
417 &bif->hw_if_index, 0 /* flag change */ );
418
419 if (args->error)
420 {
421 args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500422 hash_unset (bm->id_used, bif->id);
Steven9cd2d7a2017-12-20 12:43:01 -0800423 pool_put (bm->interfaces, bif);
424 return;
425 }
426
427 sw = vnet_get_hw_sw_interface (vnm, bif->hw_if_index);
428 bif->sw_if_index = sw->sw_if_index;
429 bif->group = bif->sw_if_index;
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400430 bif->numa_only = args->numa_only;
Stevena005e7f2018-03-22 17:46:58 -0700431 if (vlib_get_thread_main ()->n_vlib_mains > 1)
432 clib_spinlock_init (&bif->lockp);
Steven9cd2d7a2017-12-20 12:43:01 -0800433
434 vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
435 VNET_HW_INTERFACE_FLAG_LINK_UP);
436
437 hash_set (bm->bond_by_sw_if_index, bif->sw_if_index, bif->dev_instance);
438
439 // for return
440 args->sw_if_index = bif->sw_if_index;
Mohsin Kazmi8c1280f2019-07-01 11:08:20 +0200441 args->rv = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800442}
443
444static clib_error_t *
445bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
446 vlib_cli_command_t * cmd)
447{
448 unformat_input_t _line_input, *line_input = &_line_input;
449 bond_create_if_args_t args = { 0 };
450 u8 mode_is_set = 0;
451
452 /* Get a line of input. */
453 if (!unformat_user (input, unformat_line_input, line_input))
454 return clib_error_return (0, "Missing required arguments.");
455
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500456 args.id = ~0;
Steven9cd2d7a2017-12-20 12:43:01 -0800457 args.mode = -1;
458 args.lb = BOND_LB_L2;
Mohsin Kazmi8c1280f2019-07-01 11:08:20 +0200459 args.rv = -1;
Steven9cd2d7a2017-12-20 12:43:01 -0800460 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
461 {
462 if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode))
463 mode_is_set = 1;
464 else if (((args.mode == BOND_MODE_LACP) || (args.mode == BOND_MODE_XOR))
465 && unformat (line_input, "load-balance %U",
466 unformat_bond_load_balance, &args.lb))
467 ;
468 else if (unformat (line_input, "hw-addr %U",
469 unformat_ethernet_address, args.hw_addr))
470 args.hw_addr_set = 1;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500471 else if (unformat (line_input, "id %u", &args.id))
472 ;
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400473 else if (unformat (line_input, "numa-only"))
474 {
475 if (args.mode == BOND_MODE_LACP)
476 args.numa_only = 1;
477 else
478 return clib_error_return (0,
479 "Only lacp mode supports numa-only so far!");
480 }
Steven9cd2d7a2017-12-20 12:43:01 -0800481 else
482 return clib_error_return (0, "unknown input `%U'",
483 format_unformat_error, input);
484 }
485 unformat_free (line_input);
486
487 if (mode_is_set == 0)
488 return clib_error_return (0, "Missing bond mode");
489
490 bond_create_if (vm, &args);
491
Mohsin Kazmi8c1280f2019-07-01 11:08:20 +0200492 if (!args.rv)
493 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
494 vnet_get_main (), args.sw_if_index);
495
Steven9cd2d7a2017-12-20 12:43:01 -0800496 return args.error;
497}
498
499/* *INDENT-OFF* */
500VLIB_CLI_COMMAND (bond_create_command, static) = {
501 .path = "create bond",
502 .short_help = "create bond mode {round-robin | active-backup | broadcast | "
Zhiyong Yanga58fec12019-07-21 21:51:21 -0400503 "{lacp | xor} [load-balance { l2 | l23 | l34 } [numa-only]]} [hw-addr <mac-address>] "
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500504 "[id <if-id>]",
Steven9cd2d7a2017-12-20 12:43:01 -0800505 .function = bond_create_command_fn,
506};
507/* *INDENT-ON* */
508
509static clib_error_t *
510bond_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
511 vlib_cli_command_t * cmd)
512{
513 unformat_input_t _line_input, *line_input = &_line_input;
514 u32 sw_if_index = ~0;
515 vnet_main_t *vnm = vnet_get_main ();
516 int rv;
517
518 /* Get a line of input. */
519 if (!unformat_user (input, unformat_line_input, line_input))
520 return clib_error_return (0, "Missing <interface>");
521
522 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
523 {
524 if (unformat (line_input, "sw_if_index %d", &sw_if_index))
525 ;
526 else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
527 vnm, &sw_if_index))
528 ;
529 else
530 return clib_error_return (0, "unknown input `%U'",
531 format_unformat_error, input);
532 }
533 unformat_free (line_input);
534
535 if (sw_if_index == ~0)
536 return clib_error_return (0,
537 "please specify interface name or sw_if_index");
538
539 rv = bond_delete_if (vm, sw_if_index);
540 if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX)
541 return clib_error_return (0, "not a bond interface");
542 else if (rv != 0)
543 return clib_error_return (0, "error on deleting bond interface");
544
545 return 0;
546}
547
548/* *INDENT-OFF* */
549VLIB_CLI_COMMAND (bond_delete__command, static) =
550{
551 .path = "delete bond",
552 .short_help = "delete bond {<interface> | sw_if_index <sw_idx>}",
553 .function = bond_delete_command_fn,
554};
555/* *INDENT-ON* */
556
557void
558bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args)
559{
560 bond_main_t *bm = &bond_main;
561 vnet_main_t *vnm = vnet_get_main ();
562 bond_if_t *bif;
563 slave_if_t *sif;
564 vnet_interface_main_t *im = &vnm->interface_main;
Steven4f8863b2018-04-12 19:36:19 -0700565 vnet_hw_interface_t *bif_hw, *sif_hw;
Steven9cd2d7a2017-12-20 12:43:01 -0800566 vnet_sw_interface_t *sw;
Stevenc4e99c52018-09-27 20:06:26 -0700567 u32 thread_index;
568 u32 sif_if_index;
Steven9cd2d7a2017-12-20 12:43:01 -0800569
570 bif = bond_get_master_by_sw_if_index (args->group);
571 if (!bif)
572 {
573 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
574 args->error = clib_error_return (0, "bond interface not found");
575 return;
576 }
577 // make sure the interface is not already enslaved
578 if (bond_get_slave_by_sw_if_index (args->slave))
579 {
580 args->rv = VNET_API_ERROR_VALUE_EXIST;
581 args->error = clib_error_return (0, "interface was already enslaved");
582 return;
583 }
Steven4f8863b2018-04-12 19:36:19 -0700584 sif_hw = vnet_get_sup_hw_interface (vnm, args->slave);
585 if (sif_hw->dev_class_index == bond_dev_class.index)
Steven9cd2d7a2017-12-20 12:43:01 -0800586 {
587 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
588 args->error =
589 clib_error_return (0, "bond interface cannot be enslaved");
590 return;
591 }
Steven Luong0f09a822019-08-07 12:20:22 -0700592 if (bif->mode == BOND_MODE_LACP)
593 {
594 u8 *name = format (0, "/if/lacp/%u/%u/state", bif->sw_if_index,
595 args->slave);
596
597 vec_validate (bm->stats, bif->sw_if_index);
598 vec_validate (bm->stats[bif->sw_if_index], args->slave);
599
600 args->error = stat_segment_register_state_counter
601 (name, &bm->stats[bif->sw_if_index][args->slave]);
602 vec_free (name);
603 if (args->error != 0)
604 {
605 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
606 return;
607 }
608 }
609
Steven9cd2d7a2017-12-20 12:43:01 -0800610 pool_get (bm->neighbors, sif);
Dave Barachb7b92992018-10-17 10:38:51 -0400611 clib_memset (sif, 0, sizeof (*sif));
Steven9cd2d7a2017-12-20 12:43:01 -0800612 sw = pool_elt_at_index (im->sw_interfaces, args->slave);
Steven Luongbac326c2019-08-05 09:47:58 -0700613 /* port_enabled is both admin up and hw link up */
614 sif->port_enabled = vnet_sw_interface_is_up (vnm, sw->sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800615 sif->sw_if_index = sw->sw_if_index;
616 sif->hw_if_index = sw->hw_if_index;
617 sif->packet_template_index = (u8) ~ 0;
618 sif->is_passive = args->is_passive;
619 sif->group = args->group;
620 sif->bif_dev_instance = bif->dev_instance;
621 sif->mode = bif->mode;
622
623 sif->is_long_timeout = args->is_long_timeout;
624 if (args->is_long_timeout)
625 sif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME;
626 else
627 sif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME;
628
Steven0d883012018-05-11 11:06:23 -0700629 vec_validate_aligned (bm->slave_by_sw_if_index, sif->sw_if_index,
630 CLIB_CACHE_LINE_BYTES);
631 /*
632 * sif - bm->neighbors may be 0
633 * Left shift it by 1 bit to distinguish the valid entry that we actually
634 * store from the null entries
635 */
636 bm->slave_by_sw_if_index[sif->sw_if_index] =
637 (uword) (((sif - bm->neighbors) << 1) | 1);
Steven9cd2d7a2017-12-20 12:43:01 -0800638 vec_add1 (bif->slaves, sif->sw_if_index);
639
Steven4f8863b2018-04-12 19:36:19 -0700640 sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
641
Steven9cd2d7a2017-12-20 12:43:01 -0800642 /* Save the old mac */
Steven4f8863b2018-04-12 19:36:19 -0700643 memcpy (sif->persistent_hw_address, sif_hw->hw_address, 6);
644 bif_hw = vnet_get_sup_hw_interface (vnm, bif->sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800645 if (bif->use_custom_mac)
646 {
Steven4f8863b2018-04-12 19:36:19 -0700647 vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
Steven9cd2d7a2017-12-20 12:43:01 -0800648 bif->hw_address);
649 }
650 else
651 {
652 // bond interface gets the mac address from the first slave
653 if (vec_len (bif->slaves) == 1)
654 {
Steven4f8863b2018-04-12 19:36:19 -0700655 memcpy (bif->hw_address, sif_hw->hw_address, 6);
656 vnet_hw_interface_change_mac_address (vnm, bif_hw->hw_if_index,
657 sif_hw->hw_address);
Steven9cd2d7a2017-12-20 12:43:01 -0800658 }
659 else
660 {
661 // subsequent slaves gets the mac address of the bond interface
Steven4f8863b2018-04-12 19:36:19 -0700662 vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
Steven9cd2d7a2017-12-20 12:43:01 -0800663 bif->hw_address);
664 }
665 }
666
Steven4f8863b2018-04-12 19:36:19 -0700667 if (bif_hw->l2_if_count)
668 {
669 ethernet_set_flags (vnm, sif_hw->hw_if_index,
670 ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
671 /* ensure all packets go to ethernet-input */
672 ethernet_set_rx_redirect (vnm, sif_hw, 1);
673 }
674
Stevene43278f2019-01-17 15:11:29 -0800675 if (bif->mode == BOND_MODE_LACP)
Steven9cd2d7a2017-12-20 12:43:01 -0800676 {
Stevene43278f2019-01-17 15:11:29 -0800677 if (bm->lacp_enable_disable)
678 (*bm->lacp_enable_disable) (vm, bif, sif, 1);
Steven9cd2d7a2017-12-20 12:43:01 -0800679 }
Steven Luongbac326c2019-08-05 09:47:58 -0700680 else if (sif->port_enabled)
Steven9cd2d7a2017-12-20 12:43:01 -0800681 {
682 bond_enable_collecting_distributing (vm, sif);
683 }
684
Stevenc4e99c52018-09-27 20:06:26 -0700685 vec_foreach_index (thread_index, bm->per_thread_data)
686 {
687 bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
688 thread_index);
689
Damjan Marion69fdfee2018-10-06 14:33:18 +0200690 vec_validate_aligned (ptd->per_port_queue, vec_len (bif->slaves) - 1,
Stevenc4e99c52018-09-27 20:06:26 -0700691 CLIB_CACHE_LINE_BYTES);
692
693 vec_foreach_index (sif_if_index, ptd->per_port_queue)
694 {
695 ptd->per_port_queue[sif_if_index].n_buffers = 0;
696 }
697 }
698
Steven9cd2d7a2017-12-20 12:43:01 -0800699 args->rv = vnet_feature_enable_disable ("device-input", "bond-input",
Steven4f8863b2018-04-12 19:36:19 -0700700 sif_hw->hw_if_index, 1, 0, 0);
Steven9cd2d7a2017-12-20 12:43:01 -0800701
702 if (args->rv)
703 {
704 args->error =
705 clib_error_return (0,
706 "Error encountered on input feature arc enable");
707 }
708}
709
710static clib_error_t *
711enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
712 vlib_cli_command_t * cmd)
713{
714 bond_enslave_args_t args = { 0 };
715 unformat_input_t _line_input, *line_input = &_line_input;
716 vnet_main_t *vnm = vnet_get_main ();
717
718 /* Get a line of input. */
719 if (!unformat_user (input, unformat_line_input, line_input))
720 return clib_error_return (0, "Missing required arguments.");
721
722 args.slave = ~0;
723 args.group = ~0;
724 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
725 {
Stevenb3caf552018-03-27 15:04:47 -0700726 if (unformat (line_input, "%U %U",
727 unformat_vnet_sw_interface, vnm, &args.group,
Steven9cd2d7a2017-12-20 12:43:01 -0800728 unformat_vnet_sw_interface, vnm, &args.slave))
729 ;
Steven9cd2d7a2017-12-20 12:43:01 -0800730 else if (unformat (line_input, "passive"))
731 args.is_passive = 1;
732 else if (unformat (line_input, "long-timeout"))
733 args.is_long_timeout = 1;
734 else
735 {
736 args.error = clib_error_return (0, "unknown input `%U'",
737 format_unformat_error, input);
738 break;
739 }
740 }
741 unformat_free (line_input);
742
743 if (args.error)
744 return args.error;
745 if (args.group == ~0)
746 return clib_error_return (0, "Missing bond interface");
747 if (args.slave == ~0)
Stevenb3caf552018-03-27 15:04:47 -0700748 return clib_error_return (0, "please specify valid slave interface name");
Steven9cd2d7a2017-12-20 12:43:01 -0800749
750 bond_enslave (vm, &args);
751
752 return args.error;
753}
754
755/* *INDENT-OFF* */
756VLIB_CLI_COMMAND (enslave_interface_command, static) = {
Stevenb3caf552018-03-27 15:04:47 -0700757 .path = "bond add",
758 .short_help = "bond add <BondEthernetx> <slave-interface> "
759 "[passive] [long-timeout]",
Steven9cd2d7a2017-12-20 12:43:01 -0800760 .function = enslave_interface_command_fn,
761};
762/* *INDENT-ON* */
763
764void
765bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args)
766{
767 bond_if_t *bif;
768 slave_if_t *sif;
769
770 sif = bond_get_slave_by_sw_if_index (args->slave);
771 if (!sif)
772 {
773 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
774 args->error = clib_error_return (0, "interface was not enslaved");
775 return;
776 }
777 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
778 bond_delete_neighbor (vm, bif, sif);
779}
780
781static clib_error_t *
782detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
783 vlib_cli_command_t * cmd)
784{
785 bond_detach_slave_args_t args = { 0 };
786 unformat_input_t _line_input, *line_input = &_line_input;
787 vnet_main_t *vnm = vnet_get_main ();
788
789 /* Get a line of input. */
790 if (!unformat_user (input, unformat_line_input, line_input))
791 return clib_error_return (0, "Missing required arguments.");
792
793 args.slave = ~0;
794 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
795 {
Stevenb3caf552018-03-27 15:04:47 -0700796 if (unformat (line_input, "%U",
Steven9cd2d7a2017-12-20 12:43:01 -0800797 unformat_vnet_sw_interface, vnm, &args.slave))
798 ;
799 else
800 {
801 args.error = clib_error_return (0, "unknown input `%U'",
802 format_unformat_error, input);
803 break;
804 }
805 }
806 unformat_free (line_input);
807
808 if (args.error)
809 return args.error;
810 if (args.slave == ~0)
Stevenb3caf552018-03-27 15:04:47 -0700811 return clib_error_return (0, "please specify valid slave interface name");
Steven9cd2d7a2017-12-20 12:43:01 -0800812
813 bond_detach_slave (vm, &args);
814
815 return args.error;
816}
817
818/* *INDENT-OFF* */
819VLIB_CLI_COMMAND (detach_interface_command, static) = {
Stevenb3caf552018-03-27 15:04:47 -0700820 .path = "bond del",
821 .short_help = "bond del <slave-interface>",
Steven9cd2d7a2017-12-20 12:43:01 -0800822 .function = detach_interface_command_fn,
823};
824/* *INDENT-ON* */
825
826static void
827show_bond (vlib_main_t * vm)
828{
829 bond_main_t *bm = &bond_main;
830 bond_if_t *bif;
831
Steven318de5d2018-10-06 22:30:50 -0700832 vlib_cli_output (vm, "%-16s %-12s %-13s %-13s %-14s %s",
Steven9cd2d7a2017-12-20 12:43:01 -0800833 "interface name", "sw_if_index", "mode",
834 "load balance", "active slaves", "slaves");
835
836 /* *INDENT-OFF* */
837 pool_foreach (bif, bm->interfaces,
838 ({
Steven318de5d2018-10-06 22:30:50 -0700839 vlib_cli_output (vm, "%-16U %-12d %-13U %-13U %-14u %u",
Steven9cd2d7a2017-12-20 12:43:01 -0800840 format_bond_interface_name, bif->dev_instance,
841 bif->sw_if_index, format_bond_mode, bif->mode,
842 format_bond_load_balance, bif->lb,
843 vec_len (bif->active_slaves), vec_len (bif->slaves));
844 }));
845 /* *INDENT-ON* */
846}
847
848static void
849show_bond_details (vlib_main_t * vm)
850{
851 bond_main_t *bm = &bond_main;
852 bond_if_t *bif;
853 u32 *sw_if_index;
854
855 /* *INDENT-OFF* */
856 pool_foreach (bif, bm->interfaces,
857 ({
858 vlib_cli_output (vm, "%U", format_bond_interface_name, bif->dev_instance);
859 vlib_cli_output (vm, " mode: %U",
860 format_bond_mode, bif->mode);
861 vlib_cli_output (vm, " load balance: %U",
862 format_bond_load_balance, bif->lb);
863 if (bif->mode == BOND_MODE_ROUND_ROBIN)
864 vlib_cli_output (vm, " last xmit slave index: %u",
865 bif->lb_rr_last_index);
866 vlib_cli_output (vm, " number of active slaves: %d",
867 vec_len (bif->active_slaves));
868 vec_foreach (sw_if_index, bif->active_slaves)
869 {
870 vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name,
871 vnet_get_main (), *sw_if_index);
Steven Luonga1876b82019-08-20 16:58:00 -0700872 if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
873 {
874 slave_if_t *sif = bond_get_slave_by_sw_if_index (*sw_if_index);
875 if (sif)
876 vlib_cli_output (vm, " weight: %u, is_local_numa: %u, "
877 "sw_if_index: %u", sif->weight,
878 sif->is_local_numa, sif->sw_if_index);
879 }
Steven9cd2d7a2017-12-20 12:43:01 -0800880 }
881 vlib_cli_output (vm, " number of slaves: %d", vec_len (bif->slaves));
882 vec_foreach (sw_if_index, bif->slaves)
883 {
884 vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name,
885 vnet_get_main (), *sw_if_index);
886 }
887 vlib_cli_output (vm, " device instance: %d", bif->dev_instance);
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500888 vlib_cli_output (vm, " interface id: %d", bif->id);
Steven9cd2d7a2017-12-20 12:43:01 -0800889 vlib_cli_output (vm, " sw_if_index: %d", bif->sw_if_index);
890 vlib_cli_output (vm, " hw_if_index: %d", bif->hw_if_index);
891 }));
892 /* *INDENT-ON* */
893}
894
895static clib_error_t *
896show_bond_fn (vlib_main_t * vm, unformat_input_t * input,
897 vlib_cli_command_t * cmd)
898{
899 u8 details = 0;
900
901 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
902 {
903 if (unformat (input, "details"))
904 details = 1;
905 else
906 {
907 return clib_error_return (0, "unknown input `%U'",
908 format_unformat_error, input);
909 }
910 }
911
912 if (details)
913 show_bond_details (vm);
914 else
915 show_bond (vm);
916
917 return 0;
918}
919
920/* *INDENT-OFF* */
921VLIB_CLI_COMMAND (show_bond_command, static) = {
922 .path = "show bond",
923 .short_help = "show bond [details]",
924 .function = show_bond_fn,
925};
926/* *INDENT-ON* */
927
Steven Luonga1876b82019-08-20 16:58:00 -0700928void
929bond_set_intf_weight (vlib_main_t * vm, bond_set_intf_weight_args_t * args)
930{
931 slave_if_t *sif;
932 bond_if_t *bif;
933 vnet_main_t *vnm;
934 u32 old_weight;
935
936 sif = bond_get_slave_by_sw_if_index (args->sw_if_index);
937 if (!sif)
938 {
939 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
940 args->error = clib_error_return (0, "Interface not enslaved");
941 return;
942 }
943 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
944 if (!bif)
945 {
946 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
947 args->error = clib_error_return (0, "bond interface not found");
948 return;
949 }
950 if (bif->mode != BOND_MODE_ACTIVE_BACKUP)
951 {
952 args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
953 args->error =
954 clib_error_return (0, "Weight valid for active-backup only");
955 return;
956 }
957
958 old_weight = sif->weight;
959 sif->weight = args->weight;
960 vnm = vnet_get_main ();
961 /*
962 * No need to sort the list if the affected slave is not up (not in active
963 * slave set), active slave count is 1, or the current slave is already the
964 * primary slave and new weight > old weight.
965 */
966 if (!vnet_sw_interface_is_up (vnm, sif->sw_if_index) ||
967 (vec_len (bif->active_slaves) == 1) ||
968 ((bif->active_slaves[0] == sif->sw_if_index) &&
969 (sif->weight >= old_weight)))
970 return;
971
972 bond_sort_slaves (bif);
973}
974
975static clib_error_t *
976bond_set_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
977 vlib_cli_command_t * cmd)
978{
979 bond_set_intf_weight_args_t args = { 0 };
980 u32 sw_if_index = (u32) ~ 0;
981 unformat_input_t _line_input, *line_input = &_line_input;
982 vnet_main_t *vnm = vnet_get_main ();
983 u8 weight_enter = 0;
984 u32 weight = 0;
985
986 /* Get a line of input. */
987 if (!unformat_user (input, unformat_line_input, line_input))
988 return clib_error_return (0, "Missing required arguments.");
989
990 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
991 {
992 if (unformat (line_input, "sw_if_index %d", &sw_if_index))
993 ;
994 else if (unformat (line_input, "%U", unformat_vnet_sw_interface, vnm,
995 &sw_if_index))
996 ;
997 else if (unformat (line_input, "weight %u", &weight))
998 weight_enter = 1;
999 else
1000 {
1001 clib_error_return (0, "unknown input `%U'", format_unformat_error,
1002 input);
1003 break;
1004 }
1005 }
1006
1007 unformat_free (line_input);
1008 if (sw_if_index == (u32) ~ 0)
1009 {
1010 args.rv = VNET_API_ERROR_INVALID_INTERFACE;
1011 clib_error_return (0, "Interface name is invalid!");
1012 }
1013 if (weight_enter == 0)
1014 {
1015 args.rv = VNET_API_ERROR_INVALID_ARGUMENT;
1016 clib_error_return (0, "weight missing");
1017 }
1018
1019 args.sw_if_index = sw_if_index;
1020 args.weight = weight;
1021 bond_set_intf_weight (vm, &args);
1022
1023 return args.error;
1024}
1025
1026/* *INDENT-OFF* */
1027VLIB_CLI_COMMAND(set_interface_bond_cmd, static) = {
1028 .path = "set interface bond",
1029 .short_help = "set interface bond <interface> | sw_if_index <idx>"
1030 " weight <value>",
1031 .function = bond_set_intf_cmd,
1032};
1033/* *INDENT-ON* */
1034
Steven9cd2d7a2017-12-20 12:43:01 -08001035clib_error_t *
1036bond_cli_init (vlib_main_t * vm)
1037{
1038 bond_main_t *bm = &bond_main;
1039
1040 bm->vlib_main = vm;
1041 bm->vnet_main = vnet_get_main ();
Steven0d883012018-05-11 11:06:23 -07001042 vec_validate_aligned (bm->slave_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES);
Stevenc4e99c52018-09-27 20:06:26 -07001043 vec_validate_aligned (bm->per_thread_data,
1044 vlib_get_thread_main ()->n_vlib_mains - 1,
1045 CLIB_CACHE_LINE_BYTES);
Steven9cd2d7a2017-12-20 12:43:01 -08001046
1047 return 0;
1048}
1049
1050VLIB_INIT_FUNCTION (bond_cli_init);
1051
1052/*
1053 * fd.io coding-style-patch-verification: ON
1054 *
1055 * Local Variables:
1056 * eval: (c-set-style "gnu")
1057 * End:
1058 */