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