bond: Add bonding driver and LACP protocol
[vpp.git] / src / plugins / lacp / rx_machine.c
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
16 #define _GNU_SOURCE
17
18 #include <vnet/bonding/node.h>
19 #include <lacp/node.h>
20
21 /*
22  *  LACP State = INITIALIZE
23  */
24 static lacp_fsm_state_t lacp_rx_state_initialize[] = {
25   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_PORT_DISABLED},        // event 0 BEGIN
26   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_PORT_DISABLED},        // event 1 PORT_DISABLED
27   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_PORT_DISABLED},        // event 2 PORT_MOVED
28   {LACP_NOACTION, LACP_RX_STATE_INITIALIZE},    // event 3 LACP_ENABLED
29   {LACP_NOACTION, LACP_RX_STATE_INITIALIZE},    // event 4 LACP_DISABLED
30   {LACP_NOACTION, LACP_RX_STATE_INITIALIZE},    // event 5 PDU_RECEIVED
31   {LACP_NOACTION, LACP_RX_STATE_INITIALIZE},    // event 6 TIMER_EXPIRED
32 };
33
34 /*
35  *  LACP State = PORT_DISABLED
36  */
37 static lacp_fsm_state_t lacp_rx_state_port_disabled[] = {
38   {LACP_ACTION_PORT_DISABLED, LACP_RX_STATE_PORT_DISABLED},     // event 0 BEGIN
39   {LACP_ACTION_PORT_DISABLED, LACP_RX_STATE_PORT_DISABLED},     // event 1 PORT_DISABLED
40   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE},   // event 2 PORT_MOVED
41   {LACP_ACTION_EXPIRED, LACP_RX_STATE_EXPIRED}, // event 3 LACP_ENABLED
42   {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED},     // event 4 LACP_DISABLED
43   {LACP_NOACTION, LACP_RX_STATE_PORT_DISABLED}, // event 5 PDU_RECEIVED
44   {LACP_NOACTION, LACP_RX_STATE_PORT_DISABLED}, // event 6 TIMER_EXPIRED
45 };
46
47 /*
48  *  LACP State = EXPIRED
49  */
50 static lacp_fsm_state_t lacp_rx_state_expired[] = {
51   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE},   // event 0 BEGIN
52   {LACP_NOACTION, LACP_RX_STATE_EXPIRED},       // event 1 PORT_DISABLED
53   {LACP_NOACTION, LACP_RX_STATE_EXPIRED},       // event 2 PORT_MOVED
54   {LACP_NOACTION, LACP_RX_STATE_EXPIRED},       // event 3 LACP_ENABLED
55   {LACP_NOACTION, LACP_RX_STATE_EXPIRED},       // event 4 LACP_DISABLED
56   {LACP_ACTION_CURRENT, LACP_RX_STATE_CURRENT}, // event 5 PDU_RECEIVED
57   {LACP_ACTION_DEFAULTED, LACP_RX_STATE_DEFAULTED},     // event 6 TIMER_EXPIRED
58 };
59
60 /*
61  *  LACP State = LACP_DISABLED
62  */
63 static lacp_fsm_state_t lacp_rx_state_lacp_disabled[] = {
64   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE},   // event 0 BEGIN
65   {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 1 PORT_DISABLED
66   {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 2 PORT_MOVED
67   {LACP_ACTION_EXPIRED, LACP_RX_STATE_EXPIRED}, // event 3 LACP_ENABLED XXX
68   {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED},     // event 4 LACP_DISABLED
69   {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 5 PDU_RECEIVED
70   {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 6 TIMER_EXPIRED
71 };
72
73 /*
74  *  LACP State = DEFAULTED
75  */
76 static lacp_fsm_state_t lacp_rx_state_defaulted[] = {
77   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE},   // event 0 BEGIN
78   {LACP_NOACTION, LACP_RX_STATE_DEFAULTED},     // event 1 PORT_DISABLED
79   {LACP_NOACTION, LACP_RX_STATE_DEFAULTED},     // event 2 PORT_MOVED
80   {LACP_NOACTION, LACP_RX_STATE_DEFAULTED},     // event 3 LACP_ENABLED
81   {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED},     // event 4 LACP_DISABLED
82   {LACP_ACTION_CURRENT, LACP_RX_STATE_CURRENT}, // event 5 PDU_RECEIVED
83   {LACP_ACTION_DEFAULTED, LACP_RX_STATE_DEFAULTED},     // event 6 TIMER_EXPIRED
84 };
85
86 /*
87  *  LACP State = CURRENT
88  */
89 static lacp_fsm_state_t lacp_rx_state_current[] = {
90   {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE},   // event 0 BEGIN
91   {LACP_NOACTION, LACP_RX_STATE_CURRENT},       // event 1 PORT_DISABLED
92   {LACP_NOACTION, LACP_RX_STATE_CURRENT},       // event 1 PORT_MOVED
93   {LACP_NOACTION, LACP_RX_STATE_CURRENT},       // event 2 LACP_ENABLED
94   {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED},     // event 3 LACP_DISABLED
95   {LACP_ACTION_CURRENT, LACP_RX_STATE_CURRENT}, // event 4 PDU_RECEIVED
96   {LACP_ACTION_EXPIRED, LACP_RX_STATE_EXPIRED}, // event 5 TIMER_EXPIRED
97 };
98
99 static lacp_fsm_machine_t lacp_rx_fsm_table[] = {
100   {lacp_rx_state_initialize},
101   {lacp_rx_state_port_disabled},
102   {lacp_rx_state_expired},
103   {lacp_rx_state_lacp_disabled},
104   {lacp_rx_state_defaulted},
105   {lacp_rx_state_current},
106 };
107
108 lacp_machine_t lacp_rx_machine = {
109   lacp_rx_fsm_table,
110   lacp_rx_debug_func,
111 };
112
113 static void
114 lacp_set_port_unselected (vlib_main_t * vm, slave_if_t * sif)
115 {
116   sif->selected = LACP_PORT_UNSELECTED;
117
118   switch (sif->mux_state)
119     {
120     case LACP_MUX_STATE_DETACHED:
121       break;
122     case LACP_MUX_STATE_WAITING:
123       break;
124     case LACP_MUX_STATE_ATTACHED:
125       return;
126       break;
127     case LACP_MUX_STATE_COLLECTING_DISTRIBUTING:
128       if (sif->partner.state & LACP_STATE_SYNCHRONIZATION)
129         return;
130       break;
131     default:
132       break;
133     }
134   lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
135                          LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
136 }
137
138 static void
139 lacp_update_default_selected (vlib_main_t * vm, slave_if_t * sif)
140 {
141   if ((sif->partner_admin.state & LACP_STATE_AGGREGATION) !=
142       (sif->partner.state & LACP_STATE_AGGREGATION) ||
143       memcmp (&sif->partner, &sif->partner_admin,
144               sizeof (sif->partner) - sizeof (sif->partner.state)))
145     {
146       lacp_set_port_unselected (vm, sif);
147     }
148 }
149
150 static void
151 lacp_record_default (slave_if_t * sif)
152 {
153   sif->partner = sif->partner_admin;
154   sif->actor.state |= LACP_STATE_DEFAULTED;
155 }
156
157 static void
158 lacp_update_selected (vlib_main_t * vm, slave_if_t * sif)
159 {
160   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
161
162   if ((lacpdu->actor.port_info.state & LACP_STATE_AGGREGATION) !=
163       (sif->partner.state & LACP_STATE_AGGREGATION) ||
164       memcmp (&sif->partner, &lacpdu->actor.port_info,
165               sizeof (sif->partner) - sizeof (sif->partner.state)))
166     {
167       lacp_set_port_unselected (vm, sif);
168     }
169 }
170
171 static void
172 lacp_update_ntt (vlib_main_t * vm, slave_if_t * sif)
173 {
174   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
175   u8 states = LACP_STATE_LACP_ACTIVITY | LACP_STATE_LACP_TIMEOUT |
176     LACP_STATE_SYNCHRONIZATION | LACP_STATE_AGGREGATION;
177
178   if ((states & lacpdu->partner.port_info.state) !=
179       (states & sif->actor.state)
180       || memcmp (&sif->actor, &lacpdu->partner.port_info,
181                  sizeof (sif->actor) - sizeof (sif->actor.state)))
182     {
183       sif->ntt = 1;
184       lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
185                              &sif->tx_state);
186     }
187 }
188
189 /*
190  * compare lacpdu partner info against sif->partner. Return 1 if they match, 0
191  * otherwise.
192  */
193 static u8
194 lacp_compare_partner (slave_if_t * sif)
195 {
196   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
197
198   if ((!memcmp (&sif->partner, &lacpdu->actor.port_info,
199                 sizeof (sif->partner) - sizeof (sif->partner.state)) &&
200        ((sif->actor.state & LACP_STATE_AGGREGATION) ==
201         (lacpdu->partner.port_info.state & LACP_STATE_AGGREGATION))) ||
202       ((lacpdu->actor.port_info.state & LACP_STATE_AGGREGATION) == 0))
203     return 1;
204
205   return 0;
206 }
207
208 static void
209 lacp_record_pdu (slave_if_t * sif)
210 {
211   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
212   u8 match;
213
214   match = lacp_compare_partner (sif);
215   sif->partner = lacpdu->actor.port_info;
216   sif->actor.state &= ~LACP_STATE_DEFAULTED;
217   if (match && (lacpdu->actor.port_info.state & LACP_STATE_SYNCHRONIZATION))
218     sif->partner.state |= LACP_STATE_SYNCHRONIZATION;
219   else
220     sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
221 }
222
223 static void
224 lacp_set_port_moved (vlib_main_t * vm, slave_if_t * sif, u8 val)
225 {
226   sif->port_moved = val;
227
228   if (sif->port_moved)
229     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
230                            LACP_RX_EVENT_PORT_MOVED, &sif->rx_state);
231   else if (!sif->port_enabled)
232     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
233                            LACP_RX_EVENT_PORT_DISABLED, &sif->rx_state);
234 }
235
236 int
237 lacp_rx_action_initialize (void *p1, void *p2)
238 {
239   vlib_main_t *vm = (vlib_main_t *) p1;
240   slave_if_t *sif = (slave_if_t *) p2;
241
242   lacp_set_port_unselected (vm, sif);
243   lacp_record_default (sif);
244   sif->actor.state &= ~LACP_STATE_EXPIRED;
245   lacp_set_port_moved (vm, sif, 0);
246   /* UCT */
247   lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
248                          LACP_RX_EVENT_BEGIN, &sif->rx_state);
249
250   return 0;
251 }
252
253 int
254 lacp_rx_action_port_disabled (void *p1, void *p2)
255 {
256   vlib_main_t *vm = (vlib_main_t *) p1;
257   slave_if_t *sif = (slave_if_t *) p2;
258
259   sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
260   if (sif->port_moved)
261     {
262       lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
263                              LACP_RX_EVENT_PORT_MOVED, &sif->rx_state);
264     }
265   if (sif->port_enabled)
266     {
267       if (sif->lacp_enabled)
268         lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
269                                LACP_RX_EVENT_LACP_ENABLED, &sif->rx_state);
270       else
271         lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
272                                LACP_RX_EVENT_LACP_DISABLED, &sif->rx_state);
273     }
274
275   return 0;
276 }
277
278 int
279 lacp_rx_action_expired (void *p1, void *p2)
280 {
281   vlib_main_t *vm = (vlib_main_t *) p1;
282   slave_if_t *sif = (slave_if_t *) p2;
283   u8 timer_expired;
284   lacp_main_t *lm = &lacp_main;
285
286   sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
287   sif->partner.state |= LACP_STATE_LACP_TIMEOUT;
288   lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
289                          LACP_PTX_EVENT_SHORT_TIMEOUT, &sif->ptx_state);
290   if (lacp_timer_is_running (sif->current_while_timer) &&
291       lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
292     timer_expired = 1;
293   else
294     timer_expired = 0;
295   lacp_start_current_while_timer (lm->vlib_main, sif, LACP_SHORT_TIMOUT_TIME);
296   sif->actor.state |= LACP_STATE_EXPIRED;
297   if (timer_expired)
298     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
299                            LACP_RX_EVENT_TIMER_EXPIRED, &sif->rx_state);
300   if (sif->last_rx_pkt && vec_len (sif->last_rx_pkt))
301     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
302                            LACP_RX_EVENT_PDU_RECEIVED, &sif->rx_state);
303
304   return 0;
305 }
306
307 int
308 lacp_rx_action_lacp_disabled (void *p1, void *p2)
309 {
310   vlib_main_t *vm = (vlib_main_t *) p1;
311   slave_if_t *sif = (slave_if_t *) p2;
312
313   lacp_set_port_unselected (vm, sif);
314   lacp_record_default (sif);
315   sif->partner.state &= ~LACP_STATE_AGGREGATION;
316   sif->actor.state &= ~LACP_STATE_EXPIRED;
317
318   return 0;
319 }
320
321 int
322 lacp_rx_action_defaulted (void *p1, void *p2)
323 {
324   vlib_main_t *vm = (vlib_main_t *) p1;
325   slave_if_t *sif = (slave_if_t *) p2;
326
327   lacp_update_default_selected (vm, sif);
328   lacp_record_default (sif);
329   sif->actor.state &= ~LACP_STATE_EXPIRED;
330   if (sif->last_rx_pkt && vec_len (sif->last_rx_pkt))
331     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
332                            LACP_RX_EVENT_PDU_RECEIVED, &sif->rx_state);
333
334   return 0;
335 }
336
337 static int
338 lacp_port_is_moved (vlib_main_t * vm, slave_if_t * sif)
339 {
340   bond_main_t *bm = &bond_main;
341   slave_if_t *sif2;
342   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
343
344   /* *INDENT-OFF* */
345   pool_foreach (sif2, bm->neighbors, {
346       {
347         if ((sif != sif2) && (sif2->rx_state == LACP_RX_STATE_PORT_DISABLED) &&
348             !memcmp (sif2->partner.system,
349                      lacpdu->partner.port_info.system, 6) &&
350             (sif2->partner.port_number == lacpdu->partner.port_info.port_number))
351           return 1;
352       }
353   });
354   /* *INDENT-ON* */
355
356   return 0;
357 }
358
359 int
360 lacp_rx_action_current (void *p1, void *p2)
361 {
362   vlib_main_t *vm = (vlib_main_t *) p1;
363   slave_if_t *sif = (slave_if_t *) p2;
364   lacp_main_t *lm = &lacp_main;
365
366   lacp_update_selected (vm, sif);
367   lacp_update_ntt (vm, sif);
368   lacp_record_pdu (sif);
369   lacp_start_current_while_timer (lm->vlib_main, sif, sif->ttl_in_seconds);
370   sif->actor.state &= ~LACP_STATE_EXPIRED;
371   if (lacp_port_is_moved (vm, sif))
372     lacp_set_port_moved (vm, sif, 1);
373   lacp_selection_logic (vm, sif);
374
375   return 0;
376 }
377
378 static u8 *
379 format_rx_event (u8 * s, va_list * args)
380 {
381   static lacp_event_struct lacp_rx_event_array[] = {
382 #define _(b, s, n) {.bit = b, .str = #s, },
383     foreach_lacp_rx_event
384 #undef _
385     {.str = NULL}
386   };
387   int e = va_arg (*args, int);
388   lacp_event_struct *event_entry =
389     (lacp_event_struct *) & lacp_rx_event_array;
390
391   if (e >= (sizeof (lacp_rx_event_array) / sizeof (*event_entry)))
392     s = format (s, "Bad event %d", e);
393   else
394     s = format (s, "%s", event_entry[e].str);
395
396   return s;
397 }
398
399 void
400 lacp_rx_debug_func (slave_if_t * sif, int event, int state,
401                     lacp_fsm_state_t * transition)
402 {
403   clib_warning ("%U-RX: event %U, old state %U, new state %U",
404                 format_vnet_sw_if_index_name, vnet_get_main (),
405                 sif->sw_if_index, format_rx_event,
406                 event, format_rx_sm_state, state, format_rx_sm_state,
407                 transition->next_state);
408 }
409
410 void
411 lacp_init_rx_machine (vlib_main_t * vm, slave_if_t * sif)
412 {
413   lacp_machine_dispatch (&lacp_rx_machine, vm, sif, LACP_RX_EVENT_BEGIN,
414                          &sif->rx_state);
415   lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
416                          LACP_RX_EVENT_LACP_ENABLED, &sif->rx_state);
417 }
418
419 /*
420  * fd.io coding-style-patch-verification: ON
421  *
422  * Local Variables:
423  * eval: (c-set-style "gnu")
424  * End:
425  */