blob: c6602ef01b969fc16cd4803b770546c9c87e5046 [file] [log] [blame]
Steven9cd2d7a2017-12-20 12:43:01 -08001/*
2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#ifndef __included_vnet_bonding_node_h__
16#define __included_vnet_bonding_node_h__
17
18#include <vlib/vlib.h>
19#include <vlib/unix/unix.h>
20#include <vppinfra/format.h>
21#include <vppinfra/hash.h>
22#include <vnet/ethernet/ethernet.h>
23#include <vnet/interface.h>
Steven Luong05a68d62021-12-03 12:05:45 -080024#include <vnet/hash/hash.h>
Steven9cd2d7a2017-12-20 12:43:01 -080025
26#define LACP_FAST_PERIODIC_TIMER 1.0
27#define LACP_SHORT_TIMOUT_TIME (LACP_FAST_PERIODIC_TIMER * 3)
28#define LACP_SLOW_PERIODIC_TIMER 30.0
29#define LACP_LONG_TIMOUT_TIME (LACP_SLOW_PERIODIC_TIMER * 3)
30
31#ifndef MIN
32#define MIN(x,y) (((x)<(y))?(x):(y))
33#endif
34
Steven0d883012018-05-11 11:06:23 -070035#define BOND_MODULO_SHORTCUT(a) \
Damjan Marion69fdfee2018-10-06 14:33:18 +020036 (is_pow2 (a))
Steven0d883012018-05-11 11:06:23 -070037
Steven9cd2d7a2017-12-20 12:43:01 -080038#define foreach_bond_mode \
39 _ (1, ROUND_ROBIN, "round-robin") \
40 _ (2, ACTIVE_BACKUP, "active-backup") \
41 _ (3, XOR, "xor") \
42 _ (4, BROADCAST, "broadcast") \
43 _ (5, LACP, "lacp")
44
45typedef enum
46{
47#define _(v, f, s) BOND_MODE_##f = v,
48 foreach_bond_mode
49#undef _
50} bond_mode_t;
51
52/* configurable load-balances */
53#define foreach_bond_lb \
54 _ (2, L23, "l23", l23) \
Damjan Marion16de39e2018-09-26 10:15:41 +020055 _ (1, L34 , "l34", l34) \
Steven9cd2d7a2017-12-20 12:43:01 -080056 _ (0, L2, "l2", l2)
57
58/* load-balance functions implemented in bond-output */
59#define foreach_bond_lb_algo \
60 _ (0, L2, "l2", l2) \
Damjan Marion16de39e2018-09-26 10:15:41 +020061 _ (1, L34 , "l34", l34) \
Steven9cd2d7a2017-12-20 12:43:01 -080062 _ (2, L23, "l23", l23) \
63 _ (3, RR, "round-robin", round_robin) \
64 _ (4, BC, "broadcast", broadcast) \
65 _ (5, AB, "active-backup", active_backup)
66
67typedef enum
68{
69#define _(v, f, s, p) BOND_LB_##f = v,
70 foreach_bond_lb_algo
71#undef _
72} bond_load_balance_t;
73
BenoƮt Ganne47727c02019-02-12 13:35:08 +010074typedef enum
Steven9f781d82018-06-05 11:09:32 -070075{
76 BOND_SEND_GARP_NA = 1,
77} bond_send_garp_na_process_event_t;
78
Steven9cd2d7a2017-12-20 12:43:01 -080079typedef struct
80{
Alexander Chernavinad9d5282018-12-13 09:08:09 -050081 u32 id;
Steven9cd2d7a2017-12-20 12:43:01 -080082 u8 hw_addr_set;
83 u8 hw_addr[6];
84 u8 mode;
85 u8 lb;
Zhiyong Yang751e3f32019-06-26 05:49:14 -040086 u8 numa_only;
Steven Luong2e1fa542020-01-06 15:14:46 -080087 u8 gso;
Steven9cd2d7a2017-12-20 12:43:01 -080088 /* return */
89 u32 sw_if_index;
90 int rv;
91 clib_error_t *error;
92} bond_create_if_args_t;
93
94typedef struct
95{
Steven Luong4c4223e2020-07-15 08:44:54 -070096 /* member's sw_if_index */
97 u32 member;
Steven9cd2d7a2017-12-20 12:43:01 -080098 /* bond's sw_if_index */
99 u32 group;
100 u8 is_passive;
101 u8 is_long_timeout;
102 /* return */
103 int rv;
104 clib_error_t *error;
Steven Luong4c4223e2020-07-15 08:44:54 -0700105} bond_add_member_args_t;
Steven9cd2d7a2017-12-20 12:43:01 -0800106
107typedef struct
108{
Steven Luong4c4223e2020-07-15 08:44:54 -0700109 u32 member;
Steven9cd2d7a2017-12-20 12:43:01 -0800110 /* return */
111 int rv;
112 clib_error_t *error;
Steven Luong4c4223e2020-07-15 08:44:54 -0700113} bond_detach_member_args_t;
Steven9cd2d7a2017-12-20 12:43:01 -0800114
Steven Luonga1876b82019-08-20 16:58:00 -0700115typedef struct
116{
117 u32 sw_if_index;
118 u32 weight;
119 /* return */
120 int rv;
121 clib_error_t *error;
122} bond_set_intf_weight_args_t;
123
Steven9cd2d7a2017-12-20 12:43:01 -0800124/** BOND interface details struct */
125typedef struct
126{
127 u32 sw_if_index;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500128 u32 id;
Steven9cd2d7a2017-12-20 12:43:01 -0800129 u8 interface_name[64];
Steven Luong4c4223e2020-07-15 08:44:54 -0700130 u32 mode;
131 u32 lb;
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400132 u8 numa_only;
Steven Luong4c4223e2020-07-15 08:44:54 -0700133 u32 active_members;
134 u32 members;
Steven9cd2d7a2017-12-20 12:43:01 -0800135} bond_interface_details_t;
136
Steven Luong4c4223e2020-07-15 08:44:54 -0700137/** member interface details struct */
Steven9cd2d7a2017-12-20 12:43:01 -0800138typedef struct
139{
140 u32 sw_if_index;
141 u8 interface_name[64];
142 u8 is_passive;
143 u8 is_long_timeout;
Steven Luonga1876b82019-08-20 16:58:00 -0700144 u8 is_local_numa;
145 u32 weight;
Steven Luong4c4223e2020-07-15 08:44:54 -0700146 u32 active_members;
147} member_interface_details_t;
Steven9cd2d7a2017-12-20 12:43:01 -0800148
149typedef CLIB_PACKED (struct
150 {
151 u16 system_priority;
152 u8 system[6];
153 u16 key; u16 port_priority; u16 port_number;
154 u8 state;
155 }) lacp_port_info_t;
156
157typedef struct
158{
Stevenc4e99c52018-09-27 20:06:26 -0700159 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
160 u32 buffers[VLIB_FRAME_SIZE];
161 u32 n_buffers;
162} bond_per_port_queue_t;
Stevena005e7f2018-03-22 17:46:58 -0700163
Stevenc4e99c52018-09-27 20:06:26 -0700164typedef struct
165{
166 bond_per_port_queue_t *per_port_queue;
Steven Luong05a68d62021-12-03 12:05:45 -0800167 void **data;
Stevenc4e99c52018-09-27 20:06:26 -0700168} bond_per_thread_data_t;
Stevena005e7f2018-03-22 17:46:58 -0700169
170typedef struct
171{
Steven9cd2d7a2017-12-20 12:43:01 -0800172 u8 admin_up;
173 u8 mode;
174 u8 lb;
175
Steven Luong4c4223e2020-07-15 08:44:54 -0700176 /* the last member index for the rr lb */
Steven9cd2d7a2017-12-20 12:43:01 -0800177 u32 lb_rr_last_index;
178
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500179 /* Real device instance in interface vector */
Steven9cd2d7a2017-12-20 12:43:01 -0800180 u32 dev_instance;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500181
182 /* Interface ID being shown to user */
183 u32 id;
184
Steven9cd2d7a2017-12-20 12:43:01 -0800185 u32 hw_if_index;
186 u32 sw_if_index;
187
Steven Luong4c4223e2020-07-15 08:44:54 -0700188 /* Configured members */
189 u32 *members;
Steven9cd2d7a2017-12-20 12:43:01 -0800190
Steven Luong4c4223e2020-07-15 08:44:54 -0700191 /* Members that are in DISTRIBUTING state */
192 u32 *active_members;
Steven9cd2d7a2017-12-20 12:43:01 -0800193
Steven9cd2d7a2017-12-20 12:43:01 -0800194 lacp_port_info_t partner;
195 lacp_port_info_t actor;
196 u8 individual_aggregator;
197
Steven Luong4c4223e2020-07-15 08:44:54 -0700198 /* If the flag numa_only is set, it means that only members
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400199 on local numa node works for lacp mode if have at least one,
200 otherwise it works as usual. */
201 u8 numa_only;
Steven Luong2e1fa542020-01-06 15:14:46 -0800202 u8 gso;
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400203
Steven Luong4c4223e2020-07-15 08:44:54 -0700204 /* How many members on local numa node are there in lacp mode? */
205 word n_numa_members;
Zhiyong Yang751e3f32019-06-26 05:49:14 -0400206
Steven9cd2d7a2017-12-20 12:43:01 -0800207 u32 group;
208 uword *port_number_bitmap;
209 u8 use_custom_mac;
210 u8 hw_address[6];
Stevena005e7f2018-03-22 17:46:58 -0700211
212 clib_spinlock_t lockp;
Steven Luong05a68d62021-12-03 12:05:45 -0800213 vnet_hash_fn_t hash_func;
Steven9cd2d7a2017-12-20 12:43:01 -0800214} bond_if_t;
215
216typedef struct
217{
218 u8 persistent_hw_address[6];
219
220 /* neighbor's vlib software interface index */
221 u32 sw_if_index;
222
223 /* Neighbor time-to-live (usually 3s) */
224 f32 ttl_in_seconds;
225
226 /* 1 = interface is configured with long timeout (60s) */
227 u8 is_long_timeout;
228
229 /* 1 = debug is on; 0 = debug is off */
230 u8 debug;
231
232 /* tx packet template id for this neighbor */
233 u8 packet_template_index;
234
235 /* Info we actually keep about each neighbor */
236
237 /* Jenkins hash optimization: avoid tlv scan, send short keepalive msg */
238 u8 last_packet_signature_valid;
239 uword last_packet_signature;
240
241 /* last received lacp packet, for the J-hash optimization */
242 u8 *last_rx_pkt;
243
244 /* last marker packet */
245 u8 *last_marker_pkt;
246
247 /* neighbor vlib hw_if_index */
248 u32 hw_if_index;
249
Steven Luonga1876b82019-08-20 16:58:00 -0700250 /* weight -- valid only for active backup */
251 u32 weight;
252
Steven9cd2d7a2017-12-20 12:43:01 -0800253 /* actor does not initiate the protocol exchange */
254 u8 is_passive;
255
256 /* Partner port information */
257 lacp_port_info_t partner;
258 lacp_port_info_t partner_admin;;
259
Zhiyong Yang52c5f262019-06-13 21:14:33 -0400260 /* Actor port information */
Steven9cd2d7a2017-12-20 12:43:01 -0800261 lacp_port_info_t actor;
262 lacp_port_info_t actor_admin;
263
264 /* Need To Transmit flag */
265 u8 ntt;
266
267 /* Link has been established and Aggregate Port is operable */
268 u8 port_enabled;
269
270 /* Initialization or reinitialization of the lacp protocol entity */
271 u8 begin;
272
273 /* Aggregation Port is operating the lacp */
274 u8 lacp_enabled;
275
276 /* MUX to indicate to the Selection Logic wait_while_timer expired */
277 u8 ready_n;
278
279 /* Selection Logic indicates al Aggregation Ports attached */
280 u8 ready;
281
282 /* Selection Logic selected an Aggregator */
283 int selected;
284
285 /* RX machine indicates an Aggregation Port in PORT_DISABLED state */
286 u8 port_moved;
287
288 /* timer used to detect whether received protocol information has expired */
289 f64 current_while_timer;
290
291 /* timer used to detect actor churn states */
292 f64 actor_churn_timer;
293
294 /* time last lacpdu was sent */
Steven Luong82c5dda2019-03-05 09:38:33 -0800295 f64 last_lacpdu_sent_time;
296
297 /* time last lacpdu was received */
298 f64 last_lacpdu_recd_time;
299
300 /* time last marker pdu was sent */
301 f64 last_marker_pdu_sent_time;
302
303 /* time last marker pdu was received */
304 f64 last_marker_pdu_recd_time;
Steven9cd2d7a2017-12-20 12:43:01 -0800305
306 /* timer used to generate periodic transmission */
307 f64 periodic_timer;
308
309 /* timer used to detect partner churn states */
310 f64 partner_churn_timer;
311
312 /* provides hysteresis before performing an aggregation change */
313 f64 wait_while_timer;
314
315 /* Implemention variables, not in the spec */
316 int rx_state;
317 int tx_state;
318 int mux_state;
319 int ptx_state;
320
321 /* actor admin key */
322 u32 group;
323
324 u32 marker_tx_id;
325
326 u32 bif_dev_instance;
327
328 u8 loopback_port;
329
330 /* bond mode */
331 u8 mode;
Steven Luong82c5dda2019-03-05 09:38:33 -0800332
333 /* good lacp pdu received */
334 u64 pdu_received;
335
336 /* bad lacp pdu received */
337 u64 bad_pdu_received;
338
339 /* pdu sent */
340 u64 pdu_sent;
341
342 /* good marker pdu received */
343 u64 marker_pdu_received;
344
345 /* bad marker pdu received */
346 u64 marker_bad_pdu_received;
347
348 /* pdu sent */
349 u64 marker_pdu_sent;
Steven Luonga1876b82019-08-20 16:58:00 -0700350
Steven Luong4c4223e2020-07-15 08:44:54 -0700351 /* member is numa node */
Steven Luonga1876b82019-08-20 16:58:00 -0700352 u8 is_local_numa;
Steven Luong4c4223e2020-07-15 08:44:54 -0700353} member_if_t;
Steven9cd2d7a2017-12-20 12:43:01 -0800354
355typedef void (*lacp_enable_disable_func) (vlib_main_t * vm, bond_if_t * bif,
Steven Luong4c4223e2020-07-15 08:44:54 -0700356 member_if_t * mif, u8 enable);
Steven9cd2d7a2017-12-20 12:43:01 -0800357
358typedef struct
359{
Steven Luongaa725782019-11-12 19:45:49 -0800360 u32 partner_state;
361 u32 actor_state;
362} lacp_stats_t;
363
364typedef struct
365{
Steven9cd2d7a2017-12-20 12:43:01 -0800366 /* pool of bonding interfaces */
367 bond_if_t *interfaces;
368
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500369 /* record used interface IDs */
370 uword *id_used;
371
Steven Luong4c4223e2020-07-15 08:44:54 -0700372 /* pool of member interfaces */
373 member_if_t *neighbors;
Steven9cd2d7a2017-12-20 12:43:01 -0800374
Steven9cd2d7a2017-12-20 12:43:01 -0800375 /* rapidly find a bond by vlib software interface index */
376 uword *bond_by_sw_if_index;
377
378 /* convenience variables */
379 vlib_main_t *vlib_main;
380 vnet_main_t *vnet_main;
381
382 /* lacp plugin is loaded */
383 u8 lacp_plugin_loaded;
384
385 lacp_enable_disable_func lacp_enable_disable;
Steven0d883012018-05-11 11:06:23 -0700386
Steven Luong4c4223e2020-07-15 08:44:54 -0700387 uword *member_by_sw_if_index;
Stevenc4e99c52018-09-27 20:06:26 -0700388
389 bond_per_thread_data_t *per_thread_data;
Steven Luong0f09a822019-08-07 12:20:22 -0700390
Steven Luongaa725782019-11-12 19:45:49 -0800391 lacp_stats_t **stats;
Steven9cd2d7a2017-12-20 12:43:01 -0800392} bond_main_t;
393
394/* bond packet trace capture */
395typedef struct
396{
397 ethernet_header_t ethernet;
398 u32 sw_if_index;
399 u32 bond_sw_if_index;
400} bond_packet_trace_t;
401
402typedef u32 (*load_balance_func) (vlib_main_t * vm,
403 vlib_node_runtime_t * node, bond_if_t * bif,
Steven Luong4c4223e2020-07-15 08:44:54 -0700404 vlib_buffer_t * b0, uword member_count);
Steven9cd2d7a2017-12-20 12:43:01 -0800405
406typedef struct
407{
408 load_balance_func load_balance;
409} bond_load_balance_func_t;
410
411extern vlib_node_registration_t bond_input_node;
Steven9f781d82018-06-05 11:09:32 -0700412extern vlib_node_registration_t bond_process_node;
Steven9cd2d7a2017-12-20 12:43:01 -0800413extern vnet_device_class_t bond_dev_class;
414extern bond_main_t bond_main;
415
416void bond_disable_collecting_distributing (vlib_main_t * vm,
Steven Luong4c4223e2020-07-15 08:44:54 -0700417 member_if_t * mif);
418void bond_enable_collecting_distributing (vlib_main_t * vm,
419 member_if_t * mif);
Steven9cd2d7a2017-12-20 12:43:01 -0800420u8 *format_bond_interface_name (u8 * s, va_list * args);
421
Steven Luonga1876b82019-08-20 16:58:00 -0700422void bond_set_intf_weight (vlib_main_t * vm,
423 bond_set_intf_weight_args_t * args);
Steven9cd2d7a2017-12-20 12:43:01 -0800424void bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args);
425int bond_delete_if (vlib_main_t * vm, u32 sw_if_index);
Steven Luong4c4223e2020-07-15 08:44:54 -0700426void bond_add_member (vlib_main_t * vm, bond_add_member_args_t * args);
427void bond_detach_member (vlib_main_t * vm, bond_detach_member_args_t * args);
Steven9cd2d7a2017-12-20 12:43:01 -0800428int bond_dump_ifs (bond_interface_details_t ** out_bondids);
Steven Luong4c4223e2020-07-15 08:44:54 -0700429int bond_dump_member_ifs (member_interface_details_t ** out_memberids,
430 u32 bond_sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800431
432static inline uword
433unformat_bond_mode (unformat_input_t * input, va_list * args)
434{
435 u8 *r = va_arg (*args, u8 *);
436
437 if (0);
438#define _(v, f, s) else if (unformat (input, s)) *r = BOND_MODE_##f;
439 foreach_bond_mode
440#undef _
441 else
442 return 0;
443
444 return 1;
445}
446
447static inline u8 *
448format_bond_mode (u8 * s, va_list * args)
449{
450 u32 i = va_arg (*args, u32);
451 u8 *t = 0;
452
453 switch (i)
454 {
455#define _(v, f, s) case BOND_MODE_##f: t = (u8 *) s; break;
456 foreach_bond_mode
457#undef _
458 default:
459 return format (s, "unknown");
460 }
461 return format (s, "%s", t);
462}
463
464static inline uword
465unformat_bond_load_balance (unformat_input_t * input, va_list * args)
466{
467 u8 *r = va_arg (*args, u8 *);
468
469 if (0);
470#define _(v, f, s, p) else if (unformat (input, s)) *r = BOND_LB_##f;
471 foreach_bond_lb
472#undef _
473 else
474 return 0;
475
476 return 1;
477}
478
479static inline u8 *
480format_bond_load_balance (u8 * s, va_list * args)
481{
482 u32 i = va_arg (*args, u32);
483 u8 *t = 0;
484
485 switch (i)
486 {
487#define _(v, f, s, p) case BOND_LB_##f: t = (u8 *) s; break;
488 foreach_bond_lb_algo
489#undef _
490 default:
491 return format (s, "unknown");
492 }
493 return format (s, "%s", t);
494}
495
496static inline void
497bond_register_callback (lacp_enable_disable_func func)
498{
499 bond_main_t *bm = &bond_main;
500
501 bm->lacp_plugin_loaded = 1;
502 bm->lacp_enable_disable = func;
503}
504
505static inline bond_if_t *
Steven Luong4c4223e2020-07-15 08:44:54 -0700506bond_get_bond_if_by_sw_if_index (u32 sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800507{
508 bond_main_t *bm = &bond_main;
509 uword *p;
510
511 p = hash_get (bm->bond_by_sw_if_index, sw_if_index);
512 if (!p)
513 {
514 return 0;
515 }
516 return pool_elt_at_index (bm->interfaces, p[0]);
517}
518
519static inline bond_if_t *
Steven Luong4c4223e2020-07-15 08:44:54 -0700520bond_get_bond_if_by_dev_instance (u32 dev_instance)
Steven9cd2d7a2017-12-20 12:43:01 -0800521{
522 bond_main_t *bm = &bond_main;
523
524 return pool_elt_at_index (bm->interfaces, dev_instance);
525}
526
Steven Luong4c4223e2020-07-15 08:44:54 -0700527static inline member_if_t *
528bond_get_member_by_sw_if_index (u32 sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -0800529{
530 bond_main_t *bm = &bond_main;
Steven Luong4c4223e2020-07-15 08:44:54 -0700531 member_if_t *mif = 0;
Steven0d883012018-05-11 11:06:23 -0700532 uword p;
Steven9cd2d7a2017-12-20 12:43:01 -0800533
Steven Luong4c4223e2020-07-15 08:44:54 -0700534 if (sw_if_index < vec_len (bm->member_by_sw_if_index))
Steven9cd2d7a2017-12-20 12:43:01 -0800535 {
Steven Luong4c4223e2020-07-15 08:44:54 -0700536 p = bm->member_by_sw_if_index[sw_if_index];
Steven0d883012018-05-11 11:06:23 -0700537 if (p)
Steven Luong4c4223e2020-07-15 08:44:54 -0700538 mif = pool_elt_at_index (bm->neighbors, p >> 1);
Steven9cd2d7a2017-12-20 12:43:01 -0800539 }
Steven0d883012018-05-11 11:06:23 -0700540
Steven Luong4c4223e2020-07-15 08:44:54 -0700541 return mif;
Steven9cd2d7a2017-12-20 12:43:01 -0800542}
543
544#endif /* __included_vnet_bonding_node_h__ */
545
546/*
547 * fd.io coding-style-patch-verification: ON
548 *
549 * Local Variables:
550 * eval: (c-set-style "gnu")
551 * End:
552 */