blob: 104b7b157005257bb48230b4901a7ed03afcad6c [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) \
35 (((a) == 2) || ((a) == 4) || ((a) == 8) || ((a) == 16))
36
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) \
54 _ (1, l34 , "l34", l34) \
55 _ (0, L2, "l2", l2)
56
57/* load-balance functions implemented in bond-output */
58#define foreach_bond_lb_algo \
59 _ (0, L2, "l2", l2) \
60 _ (1, l34 , "l34", l34) \
61 _ (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{
80 u8 hw_addr_set;
81 u8 hw_addr[6];
82 u8 mode;
83 u8 lb;
84 /* return */
85 u32 sw_if_index;
86 int rv;
87 clib_error_t *error;
88} bond_create_if_args_t;
89
90typedef struct
91{
92 /* slave's sw_if_index */
93 u32 slave;
94 /* bond's sw_if_index */
95 u32 group;
96 u8 is_passive;
97 u8 is_long_timeout;
98 /* return */
99 int rv;
100 clib_error_t *error;
101} bond_enslave_args_t;
102
103typedef struct
104{
105 u32 slave;
106 /* return */
107 int rv;
108 clib_error_t *error;
109} bond_detach_slave_args_t;
110
111/** BOND interface details struct */
112typedef struct
113{
114 u32 sw_if_index;
115 u8 interface_name[64];
116 u8 mode;
117 u8 lb;
118 u32 active_slaves;
119 u32 slaves;
120} bond_interface_details_t;
121
122/** slave interface details struct */
123typedef struct
124{
125 u32 sw_if_index;
126 u8 interface_name[64];
127 u8 is_passive;
128 u8 is_long_timeout;
129 u32 active_slaves;
130} slave_interface_details_t;
131
132typedef CLIB_PACKED (struct
133 {
134 u16 system_priority;
135 u8 system[6];
136 u16 key; u16 port_priority; u16 port_number;
137 u8 state;
138 }) lacp_port_info_t;
139
140typedef struct
141{
Stevena005e7f2018-03-22 17:46:58 -0700142 vlib_frame_t **frame;
143
144} bond_if_per_thread_t;
145
146typedef struct
147{
Steven9cd2d7a2017-12-20 12:43:01 -0800148 u8 admin_up;
149 u8 mode;
150 u8 lb;
151
152 /* the last slave index for the rr lb */
153 u32 lb_rr_last_index;
154
155 u32 dev_instance;
156 u32 hw_if_index;
157 u32 sw_if_index;
158
159 /* Configured slaves */
160 u32 *slaves;
161
162 /* Slaves that are in DISTRIBUTING state */
163 u32 *active_slaves;
164
165 /* rapidly find an active slave */
166 uword *active_slave_by_sw_if_index;
167
168 lacp_port_info_t partner;
169 lacp_port_info_t actor;
170 u8 individual_aggregator;
171
172 u32 group;
173 uword *port_number_bitmap;
174 u8 use_custom_mac;
175 u8 hw_address[6];
Stevena005e7f2018-03-22 17:46:58 -0700176
177 clib_spinlock_t lockp;
178 bond_if_per_thread_t *per_thread_info;
Steven9cd2d7a2017-12-20 12:43:01 -0800179} bond_if_t;
180
181typedef struct
182{
183 u8 persistent_hw_address[6];
184
185 /* neighbor's vlib software interface index */
186 u32 sw_if_index;
187
188 /* Neighbor time-to-live (usually 3s) */
189 f32 ttl_in_seconds;
190
191 /* 1 = interface is configured with long timeout (60s) */
192 u8 is_long_timeout;
193
194 /* 1 = debug is on; 0 = debug is off */
195 u8 debug;
196
197 /* tx packet template id for this neighbor */
198 u8 packet_template_index;
199
200 /* Info we actually keep about each neighbor */
201
202 /* Jenkins hash optimization: avoid tlv scan, send short keepalive msg */
203 u8 last_packet_signature_valid;
204 uword last_packet_signature;
205
206 /* last received lacp packet, for the J-hash optimization */
207 u8 *last_rx_pkt;
208
209 /* last marker packet */
210 u8 *last_marker_pkt;
211
212 /* neighbor vlib hw_if_index */
213 u32 hw_if_index;
214
215 /* actor does not initiate the protocol exchange */
216 u8 is_passive;
217
218 /* Partner port information */
219 lacp_port_info_t partner;
220 lacp_port_info_t partner_admin;;
221
222 /* Partner port information */
223 lacp_port_info_t actor;
224 lacp_port_info_t actor_admin;
225
226 /* Need To Transmit flag */
227 u8 ntt;
228
229 /* Link has been established and Aggregate Port is operable */
230 u8 port_enabled;
231
232 /* Initialization or reinitialization of the lacp protocol entity */
233 u8 begin;
234
235 /* Aggregation Port is operating the lacp */
236 u8 lacp_enabled;
237
238 /* MUX to indicate to the Selection Logic wait_while_timer expired */
239 u8 ready_n;
240
241 /* Selection Logic indicates al Aggregation Ports attached */
242 u8 ready;
243
244 /* Selection Logic selected an Aggregator */
245 int selected;
246
247 /* RX machine indicates an Aggregation Port in PORT_DISABLED state */
248 u8 port_moved;
249
250 /* timer used to detect whether received protocol information has expired */
251 f64 current_while_timer;
252
253 /* timer used to detect actor churn states */
254 f64 actor_churn_timer;
255
256 /* time last lacpdu was sent */
257 f64 last_lacpdu_time;
258
259 /* timer used to generate periodic transmission */
260 f64 periodic_timer;
261
262 /* timer used to detect partner churn states */
263 f64 partner_churn_timer;
264
265 /* provides hysteresis before performing an aggregation change */
266 f64 wait_while_timer;
267
268 /* Implemention variables, not in the spec */
269 int rx_state;
270 int tx_state;
271 int mux_state;
272 int ptx_state;
273
274 /* actor admin key */
275 u32 group;
276
277 u32 marker_tx_id;
278
279 u32 bif_dev_instance;
280
281 u8 loopback_port;
282
283 /* bond mode */
284 u8 mode;
Steven9cd2d7a2017-12-20 12:43:01 -0800285} slave_if_t;
286
287typedef void (*lacp_enable_disable_func) (vlib_main_t * vm, bond_if_t * bif,
288 slave_if_t * sif, u8 enable);
289
290typedef struct
291{
292 /* pool of bonding interfaces */
293 bond_if_t *interfaces;
294
295 /* pool of lacp neighbors */
296 slave_if_t *neighbors;
297
Steven9cd2d7a2017-12-20 12:43:01 -0800298 /* rapidly find a bond by vlib software interface index */
299 uword *bond_by_sw_if_index;
300
301 /* convenience variables */
302 vlib_main_t *vlib_main;
303 vnet_main_t *vnet_main;
304
305 /* lacp plugin is loaded */
306 u8 lacp_plugin_loaded;
307
308 lacp_enable_disable_func lacp_enable_disable;
Steven0d883012018-05-11 11:06:23 -0700309
310 uword *slave_by_sw_if_index;
Steven9cd2d7a2017-12-20 12:43:01 -0800311} bond_main_t;
312
313/* bond packet trace capture */
314typedef struct
315{
316 ethernet_header_t ethernet;
317 u32 sw_if_index;
318 u32 bond_sw_if_index;
319} bond_packet_trace_t;
320
321typedef u32 (*load_balance_func) (vlib_main_t * vm,
322 vlib_node_runtime_t * node, bond_if_t * bif,
Steven18c0f222018-03-26 21:52:11 -0700323 vlib_buffer_t * b0, uword slave_count);
Steven9cd2d7a2017-12-20 12:43:01 -0800324
325typedef struct
326{
327 load_balance_func load_balance;
328} bond_load_balance_func_t;
329
330extern vlib_node_registration_t bond_input_node;
Steven9f781d82018-06-05 11:09:32 -0700331extern vlib_node_registration_t bond_process_node;
Steven9cd2d7a2017-12-20 12:43:01 -0800332extern vnet_device_class_t bond_dev_class;
333extern bond_main_t bond_main;
334
335void bond_disable_collecting_distributing (vlib_main_t * vm,
336 slave_if_t * sif);
337void bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif);
338u8 *format_bond_interface_name (u8 * s, va_list * args);
339
340void bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args);
341int bond_delete_if (vlib_main_t * vm, u32 sw_if_index);
342void bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args);
343void bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args);
344int bond_dump_ifs (bond_interface_details_t ** out_bondids);
345int bond_dump_slave_ifs (slave_interface_details_t ** out_slaveids,
346 u32 bond_sw_if_index);
347
348static inline uword
349unformat_bond_mode (unformat_input_t * input, va_list * args)
350{
351 u8 *r = va_arg (*args, u8 *);
352
353 if (0);
354#define _(v, f, s) else if (unformat (input, s)) *r = BOND_MODE_##f;
355 foreach_bond_mode
356#undef _
357 else
358 return 0;
359
360 return 1;
361}
362
363static inline u8 *
364format_bond_mode (u8 * s, va_list * args)
365{
366 u32 i = va_arg (*args, u32);
367 u8 *t = 0;
368
369 switch (i)
370 {
371#define _(v, f, s) case BOND_MODE_##f: t = (u8 *) s; break;
372 foreach_bond_mode
373#undef _
374 default:
375 return format (s, "unknown");
376 }
377 return format (s, "%s", t);
378}
379
380static inline uword
381unformat_bond_load_balance (unformat_input_t * input, va_list * args)
382{
383 u8 *r = va_arg (*args, u8 *);
384
385 if (0);
386#define _(v, f, s, p) else if (unformat (input, s)) *r = BOND_LB_##f;
387 foreach_bond_lb
388#undef _
389 else
390 return 0;
391
392 return 1;
393}
394
395static inline u8 *
396format_bond_load_balance (u8 * s, va_list * args)
397{
398 u32 i = va_arg (*args, u32);
399 u8 *t = 0;
400
401 switch (i)
402 {
403#define _(v, f, s, p) case BOND_LB_##f: t = (u8 *) s; break;
404 foreach_bond_lb_algo
405#undef _
406 default:
407 return format (s, "unknown");
408 }
409 return format (s, "%s", t);
410}
411
412static inline void
413bond_register_callback (lacp_enable_disable_func func)
414{
415 bond_main_t *bm = &bond_main;
416
417 bm->lacp_plugin_loaded = 1;
418 bm->lacp_enable_disable = func;
419}
420
421static inline bond_if_t *
422bond_get_master_by_sw_if_index (u32 sw_if_index)
423{
424 bond_main_t *bm = &bond_main;
425 uword *p;
426
427 p = hash_get (bm->bond_by_sw_if_index, sw_if_index);
428 if (!p)
429 {
430 return 0;
431 }
432 return pool_elt_at_index (bm->interfaces, p[0]);
433}
434
435static inline bond_if_t *
436bond_get_master_by_dev_instance (u32 dev_instance)
437{
438 bond_main_t *bm = &bond_main;
439
440 return pool_elt_at_index (bm->interfaces, dev_instance);
441}
442
443static inline slave_if_t *
444bond_get_slave_by_sw_if_index (u32 sw_if_index)
445{
446 bond_main_t *bm = &bond_main;
447 slave_if_t *sif = 0;
Steven0d883012018-05-11 11:06:23 -0700448 uword p;
Steven9cd2d7a2017-12-20 12:43:01 -0800449
Steven0d883012018-05-11 11:06:23 -0700450 if (sw_if_index < vec_len (bm->slave_by_sw_if_index))
Steven9cd2d7a2017-12-20 12:43:01 -0800451 {
Steven0d883012018-05-11 11:06:23 -0700452 p = bm->slave_by_sw_if_index[sw_if_index];
453 if (p)
454 sif = pool_elt_at_index (bm->neighbors, p >> 1);
Steven9cd2d7a2017-12-20 12:43:01 -0800455 }
Steven0d883012018-05-11 11:06:23 -0700456
Steven9cd2d7a2017-12-20 12:43:01 -0800457 return sif;
458}
459
460#endif /* __included_vnet_bonding_node_h__ */
461
462/*
463 * fd.io coding-style-patch-verification: ON
464 *
465 * Local Variables:
466 * eval: (c-set-style "gnu")
467 * End:
468 */