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 : */
|