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 : #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>
23 : #include <vlib/stats/stats.h>
24 :
25 : void
26 48 : bond_disable_collecting_distributing (vlib_main_t * vm, member_if_t * mif)
27 : {
28 48 : bond_main_t *bm = &bond_main;
29 : bond_if_t *bif;
30 : int i;
31 : uword p;
32 48 : u8 switching_active = 0;
33 :
34 48 : bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
35 48 : clib_spinlock_lock_if_init (&bif->lockp);
36 53 : vec_foreach_index (i, bif->active_members)
37 : {
38 11 : p = *vec_elt_at_index (bif->active_members, i);
39 11 : if (p == mif->sw_if_index)
40 : {
41 6 : if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && (i == 0) &&
42 0 : (vec_len (bif->active_members) > 1))
43 : /* deleting the active member for active-backup */
44 0 : switching_active = 1;
45 6 : vec_del1 (bif->active_members, i);
46 6 : if (mif->lacp_enabled && bif->numa_only)
47 : {
48 : /* For lacp mode, if we check it is a member on local numa node,
49 : bif->n_numa_members should be decreased by 1 becasue the first
50 : bif->n_numa_members are all members on local numa node */
51 0 : if (i < bif->n_numa_members)
52 : {
53 0 : bif->n_numa_members--;
54 0 : ASSERT (bif->n_numa_members >= 0);
55 : }
56 : }
57 6 : break;
58 : }
59 : }
60 :
61 : /* We get a new member just becoming active */
62 48 : if (switching_active)
63 0 : vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
64 0 : BOND_SEND_GARP_NA, bif->hw_if_index);
65 48 : clib_spinlock_unlock_if_init (&bif->lockp);
66 48 : }
67 :
68 : /*
69 : * return 1 if s2 is preferred.
70 : * return -1 if s1 is preferred.
71 : */
72 : static int
73 0 : bond_member_sort (void *a1, void *a2)
74 : {
75 0 : u32 *s1 = a1;
76 0 : u32 *s2 = a2;
77 0 : member_if_t *mif1 = bond_get_member_by_sw_if_index (*s1);
78 0 : member_if_t *mif2 = bond_get_member_by_sw_if_index (*s2);
79 : bond_if_t *bif;
80 :
81 0 : ALWAYS_ASSERT (mif1);
82 0 : ALWAYS_ASSERT (mif2);
83 : /*
84 : * sort entries according to preference rules:
85 : * 1. biggest weight
86 : * 2. numa-node
87 : * 3. current active member (to prevent churning)
88 : * 4. lowest sw_if_index (for deterministic behavior)
89 : *
90 : */
91 0 : if (mif2->weight > mif1->weight)
92 0 : return 1;
93 0 : if (mif2->weight < mif1->weight)
94 0 : return -1;
95 : else
96 : {
97 0 : if (mif2->is_local_numa > mif1->is_local_numa)
98 0 : return 1;
99 0 : if (mif2->is_local_numa < mif1->is_local_numa)
100 0 : return -1;
101 : else
102 : {
103 0 : bif = bond_get_bond_if_by_dev_instance (mif1->bif_dev_instance);
104 : /* Favor the current active member to avoid churning */
105 0 : if (bif->active_members[0] == mif2->sw_if_index)
106 0 : return 1;
107 0 : if (bif->active_members[0] == mif1->sw_if_index)
108 0 : return -1;
109 : /* go for the tiebreaker as the last resort */
110 0 : if (mif1->sw_if_index > mif2->sw_if_index)
111 0 : return 1;
112 0 : if (mif1->sw_if_index < mif2->sw_if_index)
113 0 : return -1;
114 : else
115 0 : ASSERT (0);
116 : }
117 : }
118 0 : return 0;
119 : }
120 :
121 : static void
122 0 : bond_sort_members (bond_if_t * bif)
123 : {
124 0 : bond_main_t *bm = &bond_main;
125 0 : u32 old_active = bif->active_members[0];
126 :
127 0 : vec_sort_with_function (bif->active_members, bond_member_sort);
128 0 : if (old_active != bif->active_members[0])
129 0 : vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
130 0 : BOND_SEND_GARP_NA, bif->hw_if_index);
131 0 : }
132 :
133 : void
134 14 : bond_enable_collecting_distributing (vlib_main_t * vm, member_if_t * mif)
135 : {
136 : bond_if_t *bif;
137 14 : bond_main_t *bm = &bond_main;
138 14 : vnet_main_t *vnm = vnet_get_main ();
139 14 : vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index);
140 : int i;
141 : uword p;
142 :
143 14 : bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
144 14 : clib_spinlock_lock_if_init (&bif->lockp);
145 19 : vec_foreach_index (i, bif->active_members)
146 : {
147 13 : p = *vec_elt_at_index (bif->active_members, i);
148 13 : if (p == mif->sw_if_index)
149 8 : goto done;
150 : }
151 :
152 6 : if (mif->lacp_enabled && bif->numa_only && (vm->numa_node == hw->numa_node))
153 : {
154 0 : vec_insert_elts (bif->active_members, &mif->sw_if_index, 1,
155 : bif->n_numa_members);
156 0 : bif->n_numa_members++;
157 : }
158 : else
159 6 : vec_add1 (bif->active_members, mif->sw_if_index);
160 :
161 6 : mif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0;
162 6 : if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
163 : {
164 0 : if (vec_len (bif->active_members) == 1)
165 : /* First member becomes active? */
166 0 : vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
167 0 : BOND_SEND_GARP_NA, bif->hw_if_index);
168 : else
169 0 : bond_sort_members (bif);
170 : }
171 :
172 6 : done:
173 14 : clib_spinlock_unlock_if_init (&bif->lockp);
174 14 : }
175 :
176 : int
177 7 : bond_dump_ifs (bond_interface_details_t ** out_bondifs)
178 : {
179 7 : vnet_main_t *vnm = vnet_get_main ();
180 7 : bond_main_t *bm = &bond_main;
181 : bond_if_t *bif;
182 : vnet_hw_interface_t *hi;
183 7 : bond_interface_details_t *r_bondifs = NULL;
184 7 : bond_interface_details_t *bondif = NULL;
185 :
186 : /* *INDENT-OFF* */
187 20 : pool_foreach (bif, bm->interfaces) {
188 13 : vec_add2(r_bondifs, bondif, 1);
189 13 : clib_memset (bondif, 0, sizeof (*bondif));
190 13 : bondif->id = bif->id;
191 13 : bondif->sw_if_index = bif->sw_if_index;
192 13 : hi = vnet_get_hw_interface (vnm, bif->hw_if_index);
193 13 : clib_memcpy(bondif->interface_name, hi->name,
194 : MIN (ARRAY_LEN (bondif->interface_name) - 1,
195 : vec_len ((const char *) hi->name)));
196 : /* enforce by memset() above */
197 13 : ASSERT(0 == bondif->interface_name[ARRAY_LEN (bondif->interface_name) - 1]);
198 13 : bondif->mode = bif->mode;
199 13 : bondif->lb = bif->lb;
200 13 : bondif->numa_only = bif->numa_only;
201 13 : bondif->active_members = vec_len (bif->active_members);
202 13 : bondif->members = vec_len (bif->members);
203 : }
204 : /* *INDENT-ON* */
205 :
206 7 : *out_bondifs = r_bondifs;
207 :
208 7 : return 0;
209 : }
210 :
211 : int
212 13 : bond_dump_member_ifs (member_interface_details_t ** out_memberifs,
213 : u32 bond_sw_if_index)
214 : {
215 13 : vnet_main_t *vnm = vnet_get_main ();
216 : bond_if_t *bif;
217 : vnet_hw_interface_t *hi;
218 : vnet_sw_interface_t *sw;
219 13 : member_interface_details_t *r_memberifs = NULL;
220 13 : member_interface_details_t *memberif = NULL;
221 13 : u32 *sw_if_index = NULL;
222 : member_if_t *mif;
223 :
224 13 : bif = bond_get_bond_if_by_sw_if_index (bond_sw_if_index);
225 13 : if (!bif)
226 0 : return 1;
227 :
228 27 : vec_foreach (sw_if_index, bif->members)
229 : {
230 14 : vec_add2 (r_memberifs, memberif, 1);
231 14 : clib_memset (memberif, 0, sizeof (*memberif));
232 14 : mif = bond_get_member_by_sw_if_index (*sw_if_index);
233 14 : if (mif)
234 : {
235 14 : sw = vnet_get_sw_interface (vnm, mif->sw_if_index);
236 14 : hi = vnet_get_hw_interface (vnm, sw->hw_if_index);
237 14 : clib_memcpy (memberif->interface_name, hi->name,
238 : MIN (ARRAY_LEN (memberif->interface_name) - 1,
239 : vec_len ((const char *) hi->name)));
240 : /* enforce by memset() above */
241 14 : ASSERT (0 ==
242 : memberif->interface_name[ARRAY_LEN (memberif->interface_name)
243 : - 1]);
244 14 : memberif->sw_if_index = mif->sw_if_index;
245 14 : memberif->is_passive = mif->is_passive;
246 14 : memberif->is_long_timeout = mif->is_long_timeout;
247 14 : memberif->is_local_numa = mif->is_local_numa;
248 14 : memberif->weight = mif->weight;
249 : }
250 : }
251 13 : *out_memberifs = r_memberifs;
252 :
253 13 : return 0;
254 : }
255 :
256 : /*
257 : * Manage secondary mac addresses when attaching/detaching a member.
258 : * If adding, copy any secondary addresses from bond interface to member.
259 : * If deleting, delete the bond interface's secondary addresses from the
260 : * member.
261 : */
262 : static void
263 26 : bond_member_add_del_mac_addrs (bond_if_t * bif, u32 mif_sw_if_index,
264 : u8 is_add)
265 : {
266 26 : vnet_main_t *vnm = vnet_get_main ();
267 : ethernet_interface_t *b_ei;
268 : ethernet_interface_address_t *sec_mac;
269 : vnet_hw_interface_t *s_hwif;
270 :
271 26 : b_ei = ethernet_get_interface (ðernet_main, bif->hw_if_index);
272 26 : if (!b_ei || !b_ei->secondary_addrs)
273 22 : return;
274 :
275 4 : s_hwif = vnet_get_sup_hw_interface (vnm, mif_sw_if_index);
276 :
277 12 : vec_foreach (sec_mac, b_ei->secondary_addrs)
278 8 : vnet_hw_interface_add_del_mac_address (vnm, s_hwif->hw_if_index,
279 8 : sec_mac->mac.bytes, is_add);
280 : }
281 :
282 : static void
283 13 : bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, member_if_t * mif)
284 : {
285 13 : bond_main_t *bm = &bond_main;
286 13 : vnet_main_t *vnm = vnet_get_main ();
287 : int i;
288 : vnet_hw_interface_t *mif_hw;
289 :
290 13 : mif_hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index);
291 :
292 13 : bif->port_number_bitmap =
293 13 : clib_bitmap_set (bif->port_number_bitmap,
294 13 : ntohs (mif->actor_admin.port_number) - 1, 0);
295 13 : bm->member_by_sw_if_index[mif->sw_if_index] = 0;
296 13 : vec_free (mif->last_marker_pkt);
297 13 : vec_free (mif->last_rx_pkt);
298 13 : vec_foreach_index (i, bif->members)
299 : {
300 13 : uword p = *vec_elt_at_index (bif->members, i);
301 13 : if (p == mif->sw_if_index)
302 : {
303 13 : vec_del1 (bif->members, i);
304 13 : break;
305 : }
306 : }
307 :
308 13 : bond_disable_collecting_distributing (vm, mif);
309 :
310 13 : vnet_feature_enable_disable ("device-input", "bond-input",
311 : mif->sw_if_index, 0, 0, 0);
312 :
313 : /* Put back the old mac */
314 13 : vnet_hw_interface_change_mac_address (vnm, mif_hw->hw_if_index,
315 13 : mif->persistent_hw_address);
316 :
317 : /* delete the bond's secondary/virtual mac addrs from the member */
318 13 : bond_member_add_del_mac_addrs (bif, mif->sw_if_index, 0 /* is_add */ );
319 :
320 :
321 13 : if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
322 11 : (*bm->lacp_enable_disable) (vm, bif, mif, 0);
323 :
324 13 : if (bif->mode == BOND_MODE_LACP)
325 : {
326 11 : vlib_stats_remove_entry (
327 11 : bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state);
328 11 : vlib_stats_remove_entry (
329 11 : bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state);
330 : }
331 :
332 13 : pool_put (bm->neighbors, mif);
333 13 : }
334 :
335 : int
336 9 : bond_delete_if (vlib_main_t * vm, u32 sw_if_index)
337 : {
338 9 : bond_main_t *bm = &bond_main;
339 9 : vnet_main_t *vnm = vnet_get_main ();
340 : bond_if_t *bif;
341 : member_if_t *mif;
342 : vnet_hw_interface_t *hw;
343 : u32 *mif_sw_if_index;
344 9 : u32 *s_list = 0;
345 :
346 9 : hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
347 9 : if (hw == NULL || bond_dev_class.index != hw->dev_class_index)
348 0 : return VNET_API_ERROR_INVALID_SW_IF_INDEX;
349 :
350 9 : bif = bond_get_bond_if_by_dev_instance (hw->dev_instance);
351 :
352 9 : vec_append (s_list, bif->members);
353 16 : vec_foreach (mif_sw_if_index, s_list)
354 : {
355 7 : mif = bond_get_member_by_sw_if_index (*mif_sw_if_index);
356 7 : if (mif)
357 7 : bond_delete_neighbor (vm, bif, mif);
358 : }
359 9 : vec_free (s_list);
360 :
361 : /* bring down the interface */
362 9 : vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0);
363 9 : vnet_sw_interface_set_flags (vnm, bif->sw_if_index, 0);
364 :
365 9 : ethernet_delete_interface (vnm, bif->hw_if_index);
366 :
367 9 : clib_bitmap_free (bif->port_number_bitmap);
368 9 : hash_unset (bm->bond_by_sw_if_index, bif->sw_if_index);
369 9 : hash_unset (bm->id_used, bif->id);
370 9 : clib_memset (bif, 0, sizeof (*bif));
371 9 : pool_put (bm->interfaces, bif);
372 :
373 9 : return 0;
374 : }
375 :
376 : void
377 9 : bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args)
378 : {
379 9 : vnet_eth_interface_registration_t eir = {};
380 9 : bond_main_t *bm = &bond_main;
381 9 : vnet_main_t *vnm = vnet_get_main ();
382 : vnet_sw_interface_t *sw;
383 : bond_if_t *bif;
384 :
385 9 : if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0)
386 : {
387 0 : args->rv = VNET_API_ERROR_FEATURE_DISABLED;
388 0 : args->error = clib_error_return (0, "LACP plugin is not loaded");
389 0 : return;
390 : }
391 9 : if (args->mode > BOND_MODE_LACP || args->mode < BOND_MODE_ROUND_ROBIN)
392 : {
393 0 : args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
394 0 : args->error = clib_error_return (0, "Invalid mode");
395 0 : return;
396 : }
397 9 : if (args->lb > BOND_LB_L23)
398 : {
399 0 : args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
400 0 : args->error = clib_error_return (0, "Invalid load-balance");
401 0 : return;
402 : }
403 9 : pool_get (bm->interfaces, bif);
404 9 : clib_memset (bif, 0, sizeof (*bif));
405 9 : bif->dev_instance = bif - bm->interfaces;
406 9 : bif->id = args->id;
407 9 : bif->lb = args->lb;
408 9 : bif->mode = args->mode;
409 9 : bif->gso = args->gso;
410 :
411 9 : if (bif->lb == BOND_LB_L2)
412 8 : bif->hash_func =
413 8 : vnet_hash_function_from_name ("hash-eth-l2", VNET_HASH_FN_TYPE_ETHERNET);
414 1 : else if (bif->lb == BOND_LB_L34)
415 1 : bif->hash_func = vnet_hash_function_from_name ("hash-eth-l34",
416 : VNET_HASH_FN_TYPE_ETHERNET);
417 0 : else if (bif->lb == BOND_LB_L23)
418 0 : bif->hash_func = vnet_hash_function_from_name ("hash-eth-l23",
419 : VNET_HASH_FN_TYPE_ETHERNET);
420 :
421 : // Adjust requested interface id
422 9 : if (bif->id == ~0)
423 9 : bif->id = bif->dev_instance;
424 9 : if (hash_get (bm->id_used, bif->id))
425 : {
426 0 : args->rv = VNET_API_ERROR_INSTANCE_IN_USE;
427 0 : pool_put (bm->interfaces, bif);
428 0 : return;
429 : }
430 9 : hash_set (bm->id_used, bif->id, 1);
431 :
432 : // Special load-balance mode used for rr and bc
433 9 : if (bif->mode == BOND_MODE_ROUND_ROBIN)
434 1 : bif->lb = BOND_LB_RR;
435 8 : else if (bif->mode == BOND_MODE_BROADCAST)
436 0 : bif->lb = BOND_LB_BC;
437 8 : else if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
438 0 : bif->lb = BOND_LB_AB;
439 :
440 9 : bif->use_custom_mac = args->hw_addr_set;
441 9 : if (!args->hw_addr_set)
442 : {
443 6 : f64 now = vlib_time_now (vm);
444 : u32 rnd;
445 6 : rnd = (u32) (now * 1e6);
446 6 : rnd = random_u32 (&rnd);
447 :
448 6 : memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
449 6 : args->hw_addr[0] = 2;
450 6 : args->hw_addr[1] = 0xfe;
451 : }
452 9 : memcpy (bif->hw_address, args->hw_addr, 6);
453 :
454 9 : eir.dev_class_index = bond_dev_class.index;
455 9 : eir.dev_instance = bif->dev_instance;
456 9 : eir.address = bif->hw_address;
457 9 : bif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
458 :
459 9 : sw = vnet_get_hw_sw_interface (vnm, bif->hw_if_index);
460 9 : bif->sw_if_index = sw->sw_if_index;
461 9 : bif->group = bif->sw_if_index;
462 9 : bif->numa_only = args->numa_only;
463 :
464 : /*
465 : * Add GSO and Checksum offload flags if GSO is enabled on Bond
466 : */
467 9 : if (args->gso)
468 : {
469 0 : vnet_hw_if_set_caps (vnm, bif->hw_if_index,
470 : VNET_HW_IF_CAP_TCP_GSO |
471 : VNET_HW_IF_CAP_TX_TCP_CKSUM |
472 : VNET_HW_IF_CAP_TX_UDP_CKSUM);
473 : }
474 9 : if (vlib_get_thread_main ()->n_vlib_mains > 1)
475 0 : clib_spinlock_init (&bif->lockp);
476 :
477 9 : vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
478 : VNET_HW_INTERFACE_FLAG_LINK_UP);
479 :
480 9 : hash_set (bm->bond_by_sw_if_index, bif->sw_if_index, bif->dev_instance);
481 :
482 : // for return
483 9 : args->sw_if_index = bif->sw_if_index;
484 9 : args->rv = 0;
485 : }
486 :
487 : static clib_error_t *
488 0 : bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
489 : vlib_cli_command_t * cmd)
490 : {
491 0 : unformat_input_t _line_input, *line_input = &_line_input;
492 0 : bond_create_if_args_t args = { 0 };
493 0 : u8 mode_is_set = 0;
494 :
495 : /* Get a line of input. */
496 0 : if (!unformat_user (input, unformat_line_input, line_input))
497 0 : return clib_error_return (0, "Missing required arguments.");
498 :
499 0 : args.id = ~0;
500 0 : args.mode = -1;
501 0 : args.lb = BOND_LB_L2;
502 0 : args.rv = -1;
503 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
504 : {
505 0 : if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode))
506 0 : mode_is_set = 1;
507 0 : else if (((args.mode == BOND_MODE_LACP) || (args.mode == BOND_MODE_XOR))
508 0 : && unformat (line_input, "load-balance %U",
509 : unformat_bond_load_balance, &args.lb))
510 : ;
511 0 : else if (unformat (line_input, "hw-addr %U",
512 : unformat_ethernet_address, args.hw_addr))
513 0 : args.hw_addr_set = 1;
514 0 : else if (unformat (line_input, "id %u", &args.id))
515 : ;
516 0 : else if (unformat (line_input, "gso"))
517 0 : args.gso = 1;
518 0 : else if (unformat (line_input, "numa-only"))
519 : {
520 0 : if (args.mode == BOND_MODE_LACP)
521 0 : args.numa_only = 1;
522 : else
523 : {
524 0 : unformat_free (line_input);
525 0 : return clib_error_return (
526 : 0, "Only lacp mode supports numa-only so far!");
527 : }
528 : }
529 : else
530 : {
531 0 : unformat_free (line_input);
532 0 : return clib_error_return (0, "unknown input `%U'",
533 : format_unformat_error, input);
534 : }
535 : }
536 0 : unformat_free (line_input);
537 :
538 0 : if (mode_is_set == 0)
539 0 : return clib_error_return (0, "Missing bond mode");
540 :
541 0 : bond_create_if (vm, &args);
542 :
543 0 : if (!args.rv)
544 0 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
545 : vnet_get_main (), args.sw_if_index);
546 :
547 0 : return args.error;
548 : }
549 :
550 : /* *INDENT-OFF* */
551 272887 : VLIB_CLI_COMMAND (bond_create_command, static) = {
552 : .path = "create bond",
553 : .short_help = "create bond mode {round-robin | active-backup | broadcast | "
554 : "{lacp | xor} [load-balance { l2 | l23 | l34 } [numa-only]]} "
555 : "[hw-addr <mac-address>] [id <if-id>] [gso]",
556 : .function = bond_create_command_fn,
557 : };
558 : /* *INDENT-ON* */
559 :
560 : static clib_error_t *
561 0 : bond_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
562 : vlib_cli_command_t * cmd)
563 : {
564 0 : unformat_input_t _line_input, *line_input = &_line_input;
565 0 : u32 sw_if_index = ~0;
566 0 : vnet_main_t *vnm = vnet_get_main ();
567 : int rv;
568 :
569 : /* Get a line of input. */
570 0 : if (!unformat_user (input, unformat_line_input, line_input))
571 0 : return clib_error_return (0, "Missing <interface>");
572 :
573 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
574 : {
575 0 : if (unformat (line_input, "sw_if_index %d", &sw_if_index))
576 : ;
577 0 : else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
578 : vnm, &sw_if_index))
579 : ;
580 : else
581 0 : return clib_error_return (0, "unknown input `%U'",
582 : format_unformat_error, input);
583 : }
584 0 : unformat_free (line_input);
585 :
586 0 : if (sw_if_index == ~0)
587 0 : return clib_error_return (0,
588 : "please specify interface name or sw_if_index");
589 :
590 0 : rv = bond_delete_if (vm, sw_if_index);
591 0 : if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX)
592 0 : return clib_error_return (0, "not a bond interface");
593 0 : else if (rv != 0)
594 0 : return clib_error_return (0, "error on deleting bond interface");
595 :
596 0 : return 0;
597 : }
598 :
599 : /* *INDENT-OFF* */
600 272887 : VLIB_CLI_COMMAND (bond_delete__command, static) =
601 : {
602 : .path = "delete bond",
603 : .short_help = "delete bond {<interface> | sw_if_index <sw_idx>}",
604 : .function = bond_delete_command_fn,
605 : };
606 : /* *INDENT-ON* */
607 :
608 : void
609 13 : bond_add_member (vlib_main_t * vm, bond_add_member_args_t * args)
610 : {
611 13 : bond_main_t *bm = &bond_main;
612 13 : vnet_main_t *vnm = vnet_get_main ();
613 : bond_if_t *bif;
614 : member_if_t *mif;
615 13 : vnet_interface_main_t *im = &vnm->interface_main;
616 : vnet_hw_interface_t *bif_hw, *mif_hw;
617 : vnet_sw_interface_t *sw;
618 : u32 thread_index;
619 : u32 mif_if_index;
620 :
621 13 : bif = bond_get_bond_if_by_sw_if_index (args->group);
622 13 : if (!bif)
623 : {
624 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
625 0 : args->error = clib_error_return (0, "bond interface not found");
626 0 : return;
627 : }
628 : // make sure the interface is not already added as member
629 13 : if (bond_get_member_by_sw_if_index (args->member))
630 : {
631 0 : args->rv = VNET_API_ERROR_VALUE_EXIST;
632 0 : args->error = clib_error_return
633 : (0, "interface was already added as member");
634 0 : return;
635 : }
636 13 : mif_hw = vnet_get_sup_hw_interface (vnm, args->member);
637 13 : if (mif_hw->dev_class_index == bond_dev_class.index)
638 : {
639 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
640 0 : args->error =
641 0 : clib_error_return (0, "bond interface cannot be added as member");
642 0 : return;
643 : }
644 13 : if (bif->gso && !(mif_hw->caps & VNET_HW_IF_CAP_TCP_GSO))
645 : {
646 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
647 0 : args->error =
648 0 : clib_error_return (0, "member interface is not gso capable");
649 0 : return;
650 : }
651 13 : if (bif->mode == BOND_MODE_LACP)
652 : {
653 : u32 actor_idx, partner_idx;
654 :
655 11 : actor_idx = vlib_stats_add_gauge ("/if/lacp/%u/%u/state",
656 : bif->sw_if_index, args->member);
657 11 : if (actor_idx == ~0)
658 : {
659 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
660 0 : return;
661 : }
662 :
663 11 : partner_idx = vlib_stats_add_gauge ("/if/lacp/%u/%u/partner-state",
664 : bif->sw_if_index, args->member);
665 11 : if (partner_idx == ~0)
666 : {
667 0 : vlib_stats_remove_entry (actor_idx);
668 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
669 0 : return;
670 : }
671 :
672 11 : vec_validate (bm->stats, bif->sw_if_index);
673 11 : vec_validate (bm->stats[bif->sw_if_index], args->member);
674 11 : bm->stats[bif->sw_if_index][args->member].actor_state = actor_idx;
675 11 : bm->stats[bif->sw_if_index][args->member].partner_state = partner_idx;
676 : }
677 :
678 13 : pool_get (bm->neighbors, mif);
679 13 : clib_memset (mif, 0, sizeof (*mif));
680 13 : sw = pool_elt_at_index (im->sw_interfaces, args->member);
681 : /* port_enabled is both admin up and hw link up */
682 13 : mif->port_enabled = vnet_sw_interface_is_up (vnm, sw->sw_if_index);
683 13 : mif->sw_if_index = sw->sw_if_index;
684 13 : mif->hw_if_index = sw->hw_if_index;
685 13 : mif->packet_template_index = (u8) ~ 0;
686 13 : mif->is_passive = args->is_passive;
687 13 : mif->group = args->group;
688 13 : mif->bif_dev_instance = bif->dev_instance;
689 13 : mif->mode = bif->mode;
690 :
691 13 : mif->is_long_timeout = args->is_long_timeout;
692 13 : if (args->is_long_timeout)
693 0 : mif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME;
694 : else
695 13 : mif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME;
696 :
697 13 : vec_validate_aligned (bm->member_by_sw_if_index, mif->sw_if_index,
698 : CLIB_CACHE_LINE_BYTES);
699 : /*
700 : * mif - bm->neighbors may be 0
701 : * Left shift it by 1 bit to distinguish the valid entry that we actually
702 : * store from the null entries
703 : */
704 13 : bm->member_by_sw_if_index[mif->sw_if_index] =
705 13 : (uword) (((mif - bm->neighbors) << 1) | 1);
706 13 : vec_add1 (bif->members, mif->sw_if_index);
707 :
708 13 : mif_hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index);
709 :
710 : /* Save the old mac */
711 13 : memcpy (mif->persistent_hw_address, mif_hw->hw_address, 6);
712 13 : bif_hw = vnet_get_sup_hw_interface (vnm, bif->sw_if_index);
713 13 : if (bif->use_custom_mac)
714 : {
715 5 : vnet_hw_interface_change_mac_address (vnm, mif_hw->hw_if_index,
716 5 : bif->hw_address);
717 : }
718 : else
719 : {
720 : // bond interface gets the mac address from the first member
721 8 : if (vec_len (bif->members) == 1)
722 : {
723 4 : memcpy (bif->hw_address, mif_hw->hw_address, 6);
724 4 : vnet_hw_interface_change_mac_address (vnm, bif_hw->hw_if_index,
725 4 : mif_hw->hw_address);
726 : }
727 : else
728 : {
729 : // subsequent members gets the mac address of the bond interface
730 4 : vnet_hw_interface_change_mac_address (vnm, mif_hw->hw_if_index,
731 4 : bif->hw_address);
732 : }
733 : }
734 :
735 : /* if there are secondary/virtual mac addrs, propagate to the member */
736 13 : bond_member_add_del_mac_addrs (bif, mif->sw_if_index, 1 /* is_add */ );
737 :
738 13 : if (bif_hw->l2_if_count)
739 0 : ethernet_set_flags (vnm, mif_hw->hw_if_index,
740 : ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
741 : else
742 13 : ethernet_set_flags (vnm, mif_hw->hw_if_index,
743 : /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);
744 :
745 13 : if (bif->mode == BOND_MODE_LACP)
746 : {
747 11 : if (bm->lacp_enable_disable)
748 11 : (*bm->lacp_enable_disable) (vm, bif, mif, 1);
749 : }
750 2 : else if (mif->port_enabled)
751 : {
752 2 : bond_enable_collecting_distributing (vm, mif);
753 : }
754 :
755 26 : vec_foreach_index (thread_index, bm->per_thread_data)
756 : {
757 13 : bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
758 : thread_index);
759 :
760 13 : vec_validate_aligned (ptd->per_port_queue, vec_len (bif->members) - 1,
761 : CLIB_CACHE_LINE_BYTES);
762 :
763 35 : vec_foreach_index (mif_if_index, ptd->per_port_queue)
764 : {
765 22 : ptd->per_port_queue[mif_if_index].n_buffers = 0;
766 : }
767 : }
768 :
769 26 : args->rv = vnet_feature_enable_disable ("device-input", "bond-input",
770 13 : mif->sw_if_index, 1, 0, 0);
771 :
772 13 : if (args->rv)
773 : {
774 0 : args->error =
775 0 : clib_error_return (0,
776 : "Error encountered on input feature arc enable");
777 : }
778 : }
779 :
780 : static clib_error_t *
781 0 : add_member_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
782 : vlib_cli_command_t * cmd)
783 : {
784 0 : bond_add_member_args_t args = { 0 };
785 0 : unformat_input_t _line_input, *line_input = &_line_input;
786 0 : vnet_main_t *vnm = vnet_get_main ();
787 :
788 : /* Get a line of input. */
789 0 : if (!unformat_user (input, unformat_line_input, line_input))
790 0 : return clib_error_return (0, "Missing required arguments.");
791 :
792 0 : args.member = ~0;
793 0 : args.group = ~0;
794 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
795 : {
796 0 : if (unformat (line_input, "%U %U",
797 : unformat_vnet_sw_interface, vnm, &args.group,
798 : unformat_vnet_sw_interface, vnm, &args.member))
799 : ;
800 0 : else if (unformat (line_input, "passive"))
801 0 : args.is_passive = 1;
802 0 : else if (unformat (line_input, "long-timeout"))
803 0 : args.is_long_timeout = 1;
804 : else
805 : {
806 0 : args.error = clib_error_return (0, "unknown input `%U'",
807 : format_unformat_error, input);
808 0 : break;
809 : }
810 : }
811 0 : unformat_free (line_input);
812 :
813 0 : if (args.error)
814 0 : return args.error;
815 0 : if (args.group == ~0)
816 0 : return clib_error_return (0, "Missing bond interface");
817 0 : if (args.member == ~0)
818 0 : return clib_error_return (0,
819 : "please specify valid member interface name");
820 :
821 0 : bond_add_member (vm, &args);
822 :
823 0 : return args.error;
824 : }
825 :
826 : /* *INDENT-OFF* */
827 272887 : VLIB_CLI_COMMAND (add_member_interface_command, static) = {
828 : .path = "bond add",
829 : .short_help = "bond add <BondEthernetx> <member-interface> "
830 : "[passive] [long-timeout]",
831 : .function = add_member_interface_command_fn,
832 : };
833 : /* *INDENT-ON* */
834 :
835 : void
836 6 : bond_detach_member (vlib_main_t * vm, bond_detach_member_args_t * args)
837 : {
838 : bond_if_t *bif;
839 : member_if_t *mif;
840 :
841 6 : mif = bond_get_member_by_sw_if_index (args->member);
842 6 : if (!mif)
843 : {
844 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
845 0 : args->error = clib_error_return (0, "interface was not a member");
846 0 : return;
847 : }
848 6 : bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
849 6 : bond_delete_neighbor (vm, bif, mif);
850 : }
851 :
852 : static clib_error_t *
853 0 : detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
854 : vlib_cli_command_t * cmd)
855 : {
856 0 : bond_detach_member_args_t args = { 0 };
857 0 : unformat_input_t _line_input, *line_input = &_line_input;
858 0 : vnet_main_t *vnm = vnet_get_main ();
859 :
860 : /* Get a line of input. */
861 0 : if (!unformat_user (input, unformat_line_input, line_input))
862 0 : return clib_error_return (0, "Missing required arguments.");
863 :
864 0 : args.member = ~0;
865 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
866 : {
867 0 : if (unformat (line_input, "%U",
868 : unformat_vnet_sw_interface, vnm, &args.member))
869 : ;
870 : else
871 : {
872 0 : args.error = clib_error_return (0, "unknown input `%U'",
873 : format_unformat_error, input);
874 0 : break;
875 : }
876 : }
877 0 : unformat_free (line_input);
878 :
879 0 : if (args.error)
880 0 : return args.error;
881 0 : if (args.member == ~0)
882 0 : return clib_error_return (0,
883 : "please specify valid member interface name");
884 :
885 0 : bond_detach_member (vm, &args);
886 :
887 0 : return args.error;
888 : }
889 :
890 : /* *INDENT-OFF* */
891 272887 : VLIB_CLI_COMMAND (detach_interface_command, static) = {
892 : .path = "bond del",
893 : .short_help = "bond del <member-interface>",
894 : .function = detach_interface_command_fn,
895 : };
896 : /* *INDENT-ON* */
897 :
898 : static void
899 0 : show_bond (vlib_main_t * vm)
900 : {
901 0 : bond_main_t *bm = &bond_main;
902 : bond_if_t *bif;
903 :
904 0 : vlib_cli_output (vm, "%-16s %-12s %-13s %-13s %-14s %s",
905 : "interface name", "sw_if_index", "mode",
906 : "load balance", "active members", "members");
907 :
908 : /* *INDENT-OFF* */
909 0 : pool_foreach (bif, bm->interfaces)
910 : {
911 0 : vlib_cli_output (vm, "%-16U %-12d %-13U %-13U %-14u %u",
912 : format_bond_interface_name, bif->dev_instance,
913 0 : bif->sw_if_index, format_bond_mode, bif->mode,
914 0 : format_bond_load_balance, bif->lb,
915 0 : vec_len (bif->active_members), vec_len (bif->members));
916 : }
917 : /* *INDENT-ON* */
918 0 : }
919 :
920 : static void
921 0 : show_bond_details (vlib_main_t * vm)
922 : {
923 0 : bond_main_t *bm = &bond_main;
924 : bond_if_t *bif;
925 : u32 *sw_if_index;
926 :
927 : /* *INDENT-OFF* */
928 0 : pool_foreach (bif, bm->interfaces)
929 : {
930 0 : vlib_cli_output (vm, "%U", format_bond_interface_name, bif->dev_instance);
931 0 : vlib_cli_output (vm, " mode: %U",
932 0 : format_bond_mode, bif->mode);
933 0 : vlib_cli_output (vm, " load balance: %U",
934 0 : format_bond_load_balance, bif->lb);
935 0 : if (bif->gso)
936 0 : vlib_cli_output (vm, " gso enable");
937 0 : if (bif->mode == BOND_MODE_ROUND_ROBIN)
938 0 : vlib_cli_output (vm, " last xmit member index: %u",
939 : bif->lb_rr_last_index);
940 0 : vlib_cli_output (vm, " number of active members: %d",
941 0 : vec_len (bif->active_members));
942 0 : vec_foreach (sw_if_index, bif->active_members)
943 : {
944 0 : vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name,
945 : vnet_get_main (), *sw_if_index);
946 0 : if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
947 : {
948 0 : member_if_t *mif = bond_get_member_by_sw_if_index (*sw_if_index);
949 0 : if (mif)
950 0 : vlib_cli_output (vm, " weight: %u, is_local_numa: %u, "
951 : "sw_if_index: %u", mif->weight,
952 0 : mif->is_local_numa, mif->sw_if_index);
953 : }
954 : }
955 0 : vlib_cli_output (vm, " number of members: %d", vec_len (bif->members));
956 0 : vec_foreach (sw_if_index, bif->members)
957 : {
958 0 : vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name,
959 : vnet_get_main (), *sw_if_index);
960 : }
961 0 : vlib_cli_output (vm, " device instance: %d", bif->dev_instance);
962 0 : vlib_cli_output (vm, " interface id: %d", bif->id);
963 0 : vlib_cli_output (vm, " sw_if_index: %d", bif->sw_if_index);
964 0 : vlib_cli_output (vm, " hw_if_index: %d", bif->hw_if_index);
965 : }
966 : /* *INDENT-ON* */
967 0 : }
968 :
969 : static clib_error_t *
970 0 : show_bond_fn (vlib_main_t * vm, unformat_input_t * input,
971 : vlib_cli_command_t * cmd)
972 : {
973 0 : u8 details = 0;
974 :
975 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
976 : {
977 0 : if (unformat (input, "details"))
978 0 : details = 1;
979 : else
980 : {
981 0 : return clib_error_return (0, "unknown input `%U'",
982 : format_unformat_error, input);
983 : }
984 : }
985 :
986 0 : if (details)
987 0 : show_bond_details (vm);
988 : else
989 0 : show_bond (vm);
990 :
991 0 : return 0;
992 : }
993 :
994 : /* *INDENT-OFF* */
995 272887 : VLIB_CLI_COMMAND (show_bond_command, static) = {
996 : .path = "show bond",
997 : .short_help = "show bond [details]",
998 : .function = show_bond_fn,
999 : };
1000 : /* *INDENT-ON* */
1001 :
1002 : void
1003 0 : bond_set_intf_weight (vlib_main_t * vm, bond_set_intf_weight_args_t * args)
1004 : {
1005 : member_if_t *mif;
1006 : bond_if_t *bif;
1007 : vnet_main_t *vnm;
1008 : u32 old_weight;
1009 :
1010 0 : mif = bond_get_member_by_sw_if_index (args->sw_if_index);
1011 0 : if (!mif)
1012 : {
1013 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
1014 0 : args->error = clib_error_return (0, "Interface not a member");
1015 0 : return;
1016 : }
1017 0 : bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
1018 0 : if (!bif)
1019 : {
1020 0 : args->rv = VNET_API_ERROR_INVALID_INTERFACE;
1021 0 : args->error = clib_error_return (0, "bond interface not found");
1022 0 : return;
1023 : }
1024 0 : if (bif->mode != BOND_MODE_ACTIVE_BACKUP)
1025 : {
1026 0 : args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
1027 0 : args->error =
1028 0 : clib_error_return (0, "Weight valid for active-backup only");
1029 0 : return;
1030 : }
1031 :
1032 0 : old_weight = mif->weight;
1033 0 : mif->weight = args->weight;
1034 0 : vnm = vnet_get_main ();
1035 : /*
1036 : * No need to sort the list if the affected member is not up (not in active
1037 : * member set), active member count is 1, or the current member is already the
1038 : * primary member and new weight > old weight.
1039 : */
1040 0 : if (!vnet_sw_interface_is_up (vnm, mif->sw_if_index) ||
1041 0 : (vec_len (bif->active_members) == 1) ||
1042 0 : ((bif->active_members[0] == mif->sw_if_index) &&
1043 0 : (mif->weight >= old_weight)))
1044 0 : return;
1045 :
1046 0 : bond_sort_members (bif);
1047 : }
1048 :
1049 : static clib_error_t *
1050 0 : bond_set_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
1051 : vlib_cli_command_t * cmd)
1052 : {
1053 0 : bond_set_intf_weight_args_t args = { 0 };
1054 0 : u32 sw_if_index = (u32) ~ 0;
1055 0 : unformat_input_t _line_input, *line_input = &_line_input;
1056 0 : vnet_main_t *vnm = vnet_get_main ();
1057 0 : u8 weight_enter = 0;
1058 0 : u32 weight = 0;
1059 :
1060 : /* Get a line of input. */
1061 0 : if (!unformat_user (input, unformat_line_input, line_input))
1062 0 : return clib_error_return (0, "Missing required arguments.");
1063 :
1064 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1065 : {
1066 0 : if (unformat (line_input, "sw_if_index %d", &sw_if_index))
1067 : ;
1068 0 : else if (unformat (line_input, "%U", unformat_vnet_sw_interface, vnm,
1069 : &sw_if_index))
1070 : ;
1071 0 : else if (unformat (line_input, "weight %u", &weight))
1072 0 : weight_enter = 1;
1073 : else
1074 : {
1075 0 : clib_error_return (0, "unknown input `%U'", format_unformat_error,
1076 : input);
1077 0 : break;
1078 : }
1079 : }
1080 :
1081 0 : unformat_free (line_input);
1082 0 : if (sw_if_index == (u32) ~ 0)
1083 : {
1084 0 : args.rv = VNET_API_ERROR_INVALID_INTERFACE;
1085 0 : clib_error_return (0, "Interface name is invalid!");
1086 : }
1087 0 : if (weight_enter == 0)
1088 : {
1089 0 : args.rv = VNET_API_ERROR_INVALID_ARGUMENT;
1090 0 : clib_error_return (0, "weight missing");
1091 : }
1092 :
1093 0 : args.sw_if_index = sw_if_index;
1094 0 : args.weight = weight;
1095 0 : bond_set_intf_weight (vm, &args);
1096 :
1097 0 : return args.error;
1098 : }
1099 :
1100 : /* *INDENT-OFF* */
1101 272887 : VLIB_CLI_COMMAND(set_interface_bond_cmd, static) = {
1102 : .path = "set interface bond",
1103 : .short_help = "set interface bond <interface> | sw_if_index <idx>"
1104 : " weight <value>",
1105 : .function = bond_set_intf_cmd,
1106 : };
1107 : /* *INDENT-ON* */
1108 :
1109 : clib_error_t *
1110 559 : bond_cli_init (vlib_main_t * vm)
1111 : {
1112 559 : bond_main_t *bm = &bond_main;
1113 :
1114 559 : bm->vlib_main = vm;
1115 559 : bm->vnet_main = vnet_get_main ();
1116 559 : vec_validate_aligned (bm->member_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES);
1117 559 : vec_validate_aligned (bm->per_thread_data,
1118 : vlib_get_thread_main ()->n_vlib_mains - 1,
1119 : CLIB_CACHE_LINE_BYTES);
1120 :
1121 559 : return 0;
1122 : }
1123 :
1124 30799 : VLIB_INIT_FUNCTION (bond_cli_init);
1125 :
1126 : /*
1127 : * fd.io coding-style-patch-verification: ON
1128 : *
1129 : * Local Variables:
1130 : * eval: (c-set-style "gnu")
1131 : * End:
1132 : */
|