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