blob: 15640071aa8f6ca14454ac5a87ec70087d05517d [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>
24
25#define LACP_FAST_PERIODIC_TIMER 1.0
26#define LACP_SHORT_TIMOUT_TIME (LACP_FAST_PERIODIC_TIMER * 3)
27#define LACP_SLOW_PERIODIC_TIMER 30.0
28#define LACP_LONG_TIMOUT_TIME (LACP_SLOW_PERIODIC_TIMER * 3)
29
30#ifndef MIN
31#define MIN(x,y) (((x)<(y))?(x):(y))
32#endif
33
Steven0d883012018-05-11 11:06:23 -070034#define BOND_MODULO_SHORTCUT(a) \
Damjan Marion69fdfee2018-10-06 14:33:18 +020035 (is_pow2 (a))
Steven0d883012018-05-11 11:06:23 -070036
Steven9cd2d7a2017-12-20 12:43:01 -080037#define foreach_bond_mode \
38 _ (1, ROUND_ROBIN, "round-robin") \
39 _ (2, ACTIVE_BACKUP, "active-backup") \
40 _ (3, XOR, "xor") \
41 _ (4, BROADCAST, "broadcast") \
42 _ (5, LACP, "lacp")
43
44typedef enum
45{
46#define _(v, f, s) BOND_MODE_##f = v,
47 foreach_bond_mode
48#undef _
49} bond_mode_t;
50
51/* configurable load-balances */
52#define foreach_bond_lb \
53 _ (2, L23, "l23", l23) \
Damjan Marion16de39e2018-09-26 10:15:41 +020054 _ (1, L34 , "l34", l34) \
Steven9cd2d7a2017-12-20 12:43:01 -080055 _ (0, L2, "l2", l2)
56
57/* load-balance functions implemented in bond-output */
58#define foreach_bond_lb_algo \
59 _ (0, L2, "l2", l2) \
Damjan Marion16de39e2018-09-26 10:15:41 +020060 _ (1, L34 , "l34", l34) \
Steven9cd2d7a2017-12-20 12:43:01 -080061 _ (2, L23, "l23", l23) \
62 _ (3, RR, "round-robin", round_robin) \
63 _ (4, BC, "broadcast", broadcast) \
64 _ (5, AB, "active-backup", active_backup)
65
66typedef enum
67{
68#define _(v, f, s, p) BOND_LB_##f = v,
69 foreach_bond_lb_algo
70#undef _
71} bond_load_balance_t;
72
Steven9f781d82018-06-05 11:09:32 -070073enum
74{
75 BOND_SEND_GARP_NA = 1,
76} bond_send_garp_na_process_event_t;
77
Steven9cd2d7a2017-12-20 12:43:01 -080078typedef struct
79{
Alexander Chernavinad9d5282018-12-13 09:08:09 -050080 u32 id;
Steven9cd2d7a2017-12-20 12:43:01 -080081 u8 hw_addr_set;
82 u8 hw_addr[6];
83 u8 mode;
84 u8 lb;
85 /* return */
86 u32 sw_if_index;
87 int rv;
88 clib_error_t *error;
89} bond_create_if_args_t;
90
91typedef struct
92{
93 /* slave's sw_if_index */
94 u32 slave;
95 /* bond's sw_if_index */
96 u32 group;
97 u8 is_passive;
98 u8 is_long_timeout;
99 /* return */
100 int rv;
101 clib_error_t *error;
102} bond_enslave_args_t;
103
104typedef struct
105{
106 u32 slave;
107 /* return */
108 int rv;
109 clib_error_t *error;
110} bond_detach_slave_args_t;
111
112/** BOND interface details struct */
113typedef struct
114{
115 u32 sw_if_index;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500116 u32 id;
Steven9cd2d7a2017-12-20 12:43:01 -0800117 u8 interface_name[64];
118 u8 mode;
119 u8 lb;
120 u32 active_slaves;
121 u32 slaves;
122} bond_interface_details_t;
123
124/** slave interface details struct */
125typedef struct
126{
127 u32 sw_if_index;
128 u8 interface_name[64];
129 u8 is_passive;
130 u8 is_long_timeout;
131 u32 active_slaves;
132} slave_interface_details_t;
133
134typedef CLIB_PACKED (struct
135 {
136 u16 system_priority;
137 u8 system[6];
138 u16 key; u16 port_priority; u16 port_number;
139 u8 state;
140 }) lacp_port_info_t;
141
142typedef struct
143{
Stevenc4e99c52018-09-27 20:06:26 -0700144 CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
145 u32 buffers[VLIB_FRAME_SIZE];
146 u32 n_buffers;
147} bond_per_port_queue_t;
Stevena005e7f2018-03-22 17:46:58 -0700148
Stevenc4e99c52018-09-27 20:06:26 -0700149typedef struct
150{
151 bond_per_port_queue_t *per_port_queue;
152} bond_per_thread_data_t;
Stevena005e7f2018-03-22 17:46:58 -0700153
154typedef struct
155{
Steven9cd2d7a2017-12-20 12:43:01 -0800156 u8 admin_up;
157 u8 mode;
158 u8 lb;
159
160 /* the last slave index for the rr lb */
161 u32 lb_rr_last_index;
162
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500163 /* Real device instance in interface vector */
Steven9cd2d7a2017-12-20 12:43:01 -0800164 u32 dev_instance;
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500165
166 /* Interface ID being shown to user */
167 u32 id;
168
Steven9cd2d7a2017-12-20 12:43:01 -0800169 u32 hw_if_index;
170 u32 sw_if_index;
171
172 /* Configured slaves */
173 u32 *slaves;
174
175 /* Slaves that are in DISTRIBUTING state */
176 u32 *active_slaves;
177
178 /* rapidly find an active slave */
179 uword *active_slave_by_sw_if_index;
180
181 lacp_port_info_t partner;
182 lacp_port_info_t actor;
183 u8 individual_aggregator;
184
185 u32 group;
186 uword *port_number_bitmap;
187 u8 use_custom_mac;
188 u8 hw_address[6];
Stevena005e7f2018-03-22 17:46:58 -0700189
190 clib_spinlock_t lockp;
Steven9cd2d7a2017-12-20 12:43:01 -0800191} bond_if_t;
192
193typedef struct
194{
195 u8 persistent_hw_address[6];
196
197 /* neighbor's vlib software interface index */
198 u32 sw_if_index;
199
200 /* Neighbor time-to-live (usually 3s) */
201 f32 ttl_in_seconds;
202
203 /* 1 = interface is configured with long timeout (60s) */
204 u8 is_long_timeout;
205
206 /* 1 = debug is on; 0 = debug is off */
207 u8 debug;
208
209 /* tx packet template id for this neighbor */
210 u8 packet_template_index;
211
212 /* Info we actually keep about each neighbor */
213
214 /* Jenkins hash optimization: avoid tlv scan, send short keepalive msg */
215 u8 last_packet_signature_valid;
216 uword last_packet_signature;
217
218 /* last received lacp packet, for the J-hash optimization */
219 u8 *last_rx_pkt;
220
221 /* last marker packet */
222 u8 *last_marker_pkt;
223
224 /* neighbor vlib hw_if_index */
225 u32 hw_if_index;
226
227 /* actor does not initiate the protocol exchange */
228 u8 is_passive;
229
230 /* Partner port information */
231 lacp_port_info_t partner;
232 lacp_port_info_t partner_admin;;
233
234 /* Partner port information */
235 lacp_port_info_t actor;
236 lacp_port_info_t actor_admin;
237
238 /* Need To Transmit flag */
239 u8 ntt;
240
241 /* Link has been established and Aggregate Port is operable */
242 u8 port_enabled;
243
244 /* Initialization or reinitialization of the lacp protocol entity */
245 u8 begin;
246
247 /* Aggregation Port is operating the lacp */
248 u8 lacp_enabled;
249
250 /* MUX to indicate to the Selection Logic wait_while_timer expired */
251 u8 ready_n;
252
253 /* Selection Logic indicates al Aggregation Ports attached */
254 u8 ready;
255
256 /* Selection Logic selected an Aggregator */
257 int selected;
258
259 /* RX machine indicates an Aggregation Port in PORT_DISABLED state */
260 u8 port_moved;
261
262 /* timer used to detect whether received protocol information has expired */
263 f64 current_while_timer;
264
265 /* timer used to detect actor churn states */
266 f64 actor_churn_timer;
267
268 /* time last lacpdu was sent */
269 f64 last_lacpdu_time;
270
271 /* timer used to generate periodic transmission */
272 f64 periodic_timer;
273
274 /* timer used to detect partner churn states */
275 f64 partner_churn_timer;
276
277 /* provides hysteresis before performing an aggregation change */
278 f64 wait_while_timer;
279
280 /* Implemention variables, not in the spec */
281 int rx_state;
282 int tx_state;
283 int mux_state;
284 int ptx_state;
285
286 /* actor admin key */
287 u32 group;
288
289 u32 marker_tx_id;
290
291 u32 bif_dev_instance;
292
293 u8 loopback_port;
294
295 /* bond mode */
296 u8 mode;
Steven9cd2d7a2017-12-20 12:43:01 -0800297} slave_if_t;
298
299typedef void (*lacp_enable_disable_func) (vlib_main_t * vm, bond_if_t * bif,
300 slave_if_t * sif, u8 enable);
301
302typedef struct
303{
304 /* pool of bonding interfaces */
305 bond_if_t *interfaces;
306
Alexander Chernavinad9d5282018-12-13 09:08:09 -0500307 /* record used interface IDs */
308 uword *id_used;
309
Stevenc4e99c52018-09-27 20:06:26 -0700310 /* pool of slave interfaces */
Steven9cd2d7a2017-12-20 12:43:01 -0800311 slave_if_t *neighbors;
312
Steven9cd2d7a2017-12-20 12:43:01 -0800313 /* rapidly find a bond by vlib software interface index */
314 uword *bond_by_sw_if_index;
315
316 /* convenience variables */
317 vlib_main_t *vlib_main;
318 vnet_main_t *vnet_main;
319
320 /* lacp plugin is loaded */
321 u8 lacp_plugin_loaded;
322
323 lacp_enable_disable_func lacp_enable_disable;
Steven0d883012018-05-11 11:06:23 -0700324
325 uword *slave_by_sw_if_index;
Stevenc4e99c52018-09-27 20:06:26 -0700326
327 bond_per_thread_data_t *per_thread_data;
Steven9cd2d7a2017-12-20 12:43:01 -0800328} bond_main_t;
329
330/* bond packet trace capture */
331typedef struct
332{
333 ethernet_header_t ethernet;
334 u32 sw_if_index;
335 u32 bond_sw_if_index;
336} bond_packet_trace_t;
337
338typedef u32 (*load_balance_func) (vlib_main_t * vm,
339 vlib_node_runtime_t * node, bond_if_t * bif,
Steven18c0f222018-03-26 21:52:11 -0700340 vlib_buffer_t * b0, uword slave_count);
Steven9cd2d7a2017-12-20 12:43:01 -0800341
342typedef struct
343{
344 load_balance_func load_balance;
345} bond_load_balance_func_t;
346
347extern vlib_node_registration_t bond_input_node;
Steven9f781d82018-06-05 11:09:32 -0700348extern vlib_node_registration_t bond_process_node;
Steven9cd2d7a2017-12-20 12:43:01 -0800349extern vnet_device_class_t bond_dev_class;
350extern bond_main_t bond_main;
351
352void bond_disable_collecting_distributing (vlib_main_t * vm,
353 slave_if_t * sif);
354void bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif);
355u8 *format_bond_interface_name (u8 * s, va_list * args);
356
357void bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args);
358int bond_delete_if (vlib_main_t * vm, u32 sw_if_index);
359void bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args);
360void bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args);
361int bond_dump_ifs (bond_interface_details_t ** out_bondids);
362int bond_dump_slave_ifs (slave_interface_details_t ** out_slaveids,
363 u32 bond_sw_if_index);
364
365static inline uword
366unformat_bond_mode (unformat_input_t * input, va_list * args)
367{
368 u8 *r = va_arg (*args, u8 *);
369
370 if (0);
371#define _(v, f, s) else if (unformat (input, s)) *r = BOND_MODE_##f;
372 foreach_bond_mode
373#undef _
374 else
375 return 0;
376
377 return 1;
378}
379
380static inline u8 *
381format_bond_mode (u8 * s, va_list * args)
382{
383 u32 i = va_arg (*args, u32);
384 u8 *t = 0;
385
386 switch (i)
387 {
388#define _(v, f, s) case BOND_MODE_##f: t = (u8 *) s; break;
389 foreach_bond_mode
390#undef _
391 default:
392 return format (s, "unknown");
393 }
394 return format (s, "%s", t);
395}
396
397static inline uword
398unformat_bond_load_balance (unformat_input_t * input, va_list * args)
399{
400 u8 *r = va_arg (*args, u8 *);
401
402 if (0);
403#define _(v, f, s, p) else if (unformat (input, s)) *r = BOND_LB_##f;
404 foreach_bond_lb
405#undef _
406 else
407 return 0;
408
409 return 1;
410}
411
412static inline u8 *
413format_bond_load_balance (u8 * s, va_list * args)
414{
415 u32 i = va_arg (*args, u32);
416 u8 *t = 0;
417
418 switch (i)
419 {
420#define _(v, f, s, p) case BOND_LB_##f: t = (u8 *) s; break;
421 foreach_bond_lb_algo
422#undef _
423 default:
424 return format (s, "unknown");
425 }
426 return format (s, "%s", t);
427}
428
429static inline void
430bond_register_callback (lacp_enable_disable_func func)
431{
432 bond_main_t *bm = &bond_main;
433
434 bm->lacp_plugin_loaded = 1;
435 bm->lacp_enable_disable = func;
436}
437
438static inline bond_if_t *
439bond_get_master_by_sw_if_index (u32 sw_if_index)
440{
441 bond_main_t *bm = &bond_main;
442 uword *p;
443
444 p = hash_get (bm->bond_by_sw_if_index, sw_if_index);
445 if (!p)
446 {
447 return 0;
448 }
449 return pool_elt_at_index (bm->interfaces, p[0]);
450}
451
452static inline bond_if_t *
453bond_get_master_by_dev_instance (u32 dev_instance)
454{
455 bond_main_t *bm = &bond_main;
456
457 return pool_elt_at_index (bm->interfaces, dev_instance);
458}
459
460static inline slave_if_t *
461bond_get_slave_by_sw_if_index (u32 sw_if_index)
462{
463 bond_main_t *bm = &bond_main;
464 slave_if_t *sif = 0;
Steven0d883012018-05-11 11:06:23 -0700465 uword p;
Steven9cd2d7a2017-12-20 12:43:01 -0800466
Steven0d883012018-05-11 11:06:23 -0700467 if (sw_if_index < vec_len (bm->slave_by_sw_if_index))
Steven9cd2d7a2017-12-20 12:43:01 -0800468 {
Steven0d883012018-05-11 11:06:23 -0700469 p = bm->slave_by_sw_if_index[sw_if_index];
470 if (p)
471 sif = pool_elt_at_index (bm->neighbors, p >> 1);
Steven9cd2d7a2017-12-20 12:43:01 -0800472 }
Steven0d883012018-05-11 11:06:23 -0700473
Steven9cd2d7a2017-12-20 12:43:01 -0800474 return sif;
475}
476
477#endif /* __included_vnet_bonding_node_h__ */
478
479/*
480 * fd.io coding-style-patch-verification: ON
481 *
482 * Local Variables:
483 * eval: (c-set-style "gnu")
484 * End:
485 */