lacp: convert clib_warning to event logger
[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   lacp_main_t *lm = &lacp_main;
178
179   if ((states & lacpdu->partner.port_info.state) !=
180       (states & sif->actor.state)
181       || memcmp (&sif->actor, &lacpdu->partner.port_info,
182                  sizeof (sif->actor) - sizeof (sif->actor.state)))
183     {
184       sif->ntt = 1;
185       lacp_start_periodic_timer (lm->vlib_main, sif, 0);
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 (vlib_main_t * vm, slave_if_t * sif)
210 {
211   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
212   u8 match;
213
214   /* Transition PTX out of NO_PERIODIC if needed */
215   if (!(sif->partner.state & LACP_STATE_LACP_ACTIVITY) &&
216       (lacpdu->actor.port_info.state & LACP_STATE_LACP_ACTIVITY))
217     lacp_ptx_post_short_timeout_event (vm, sif);
218   match = lacp_compare_partner (sif);
219   sif->partner = lacpdu->actor.port_info;
220   sif->actor.state &= ~LACP_STATE_DEFAULTED;
221   if (match && (lacpdu->actor.port_info.state & LACP_STATE_SYNCHRONIZATION))
222     sif->partner.state |= LACP_STATE_SYNCHRONIZATION;
223   else
224     sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
225 }
226
227 static void
228 lacp_set_port_moved (vlib_main_t * vm, slave_if_t * sif, u8 val)
229 {
230   sif->port_moved = val;
231
232   if (sif->port_moved)
233     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
234                            LACP_RX_EVENT_PORT_MOVED, &sif->rx_state);
235   else if (!sif->port_enabled)
236     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
237                            LACP_RX_EVENT_PORT_DISABLED, &sif->rx_state);
238 }
239
240 int
241 lacp_rx_action_initialize (void *p1, void *p2)
242 {
243   vlib_main_t *vm = p1;
244   slave_if_t *sif = p2;
245
246   lacp_set_port_unselected (vm, sif);
247   lacp_record_default (sif);
248   sif->actor.state &= ~LACP_STATE_EXPIRED;
249   lacp_set_port_moved (vm, sif, 0);
250   /* UCT */
251   lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
252                          LACP_RX_EVENT_BEGIN, &sif->rx_state);
253
254   return 0;
255 }
256
257 int
258 lacp_rx_action_port_disabled (void *p1, void *p2)
259 {
260   vlib_main_t *vm = p1;
261   slave_if_t *sif = p2;
262
263   sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
264   if (sif->port_moved)
265     {
266       lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
267                              LACP_RX_EVENT_PORT_MOVED, &sif->rx_state);
268     }
269   if (sif->port_enabled)
270     {
271       if (sif->lacp_enabled)
272         lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
273                                LACP_RX_EVENT_LACP_ENABLED, &sif->rx_state);
274       else
275         lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
276                                LACP_RX_EVENT_LACP_DISABLED, &sif->rx_state);
277     }
278
279   return 0;
280 }
281
282 int
283 lacp_rx_action_expired (void *p1, void *p2)
284 {
285   vlib_main_t *vm = p1;
286   slave_if_t *sif = p2;
287   u8 timer_expired;
288   lacp_main_t *lm = &lacp_main;
289
290   sif->partner.state &= ~LACP_STATE_SYNCHRONIZATION;
291   sif->partner.state |= LACP_STATE_LACP_TIMEOUT;
292   lacp_ptx_post_short_timeout_event (vm, sif);
293   if (lacp_timer_is_running (sif->current_while_timer) &&
294       lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
295     timer_expired = 1;
296   else
297     timer_expired = 0;
298   lacp_start_current_while_timer (lm->vlib_main, sif, sif->ttl_in_seconds);
299   sif->actor.state |= LACP_STATE_EXPIRED;
300   if (timer_expired)
301     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
302                            LACP_RX_EVENT_TIMER_EXPIRED, &sif->rx_state);
303   if (sif->last_rx_pkt && vec_len (sif->last_rx_pkt))
304     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
305                            LACP_RX_EVENT_PDU_RECEIVED, &sif->rx_state);
306
307   return 0;
308 }
309
310 int
311 lacp_rx_action_lacp_disabled (void *p1, void *p2)
312 {
313   vlib_main_t *vm = p1;
314   slave_if_t *sif = p2;
315
316   lacp_set_port_unselected (vm, sif);
317   lacp_record_default (sif);
318   sif->partner.state &= ~LACP_STATE_AGGREGATION;
319   sif->actor.state &= ~LACP_STATE_EXPIRED;
320
321   return 0;
322 }
323
324 int
325 lacp_rx_action_defaulted (void *p1, void *p2)
326 {
327   vlib_main_t *vm = p1;
328   slave_if_t *sif = p2;
329
330   lacp_stop_timer (&sif->current_while_timer);
331   lacp_update_default_selected (vm, sif);
332   lacp_record_default (sif);
333   sif->actor.state &= ~LACP_STATE_EXPIRED;
334   if (sif->last_rx_pkt && vec_len (sif->last_rx_pkt))
335     lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
336                            LACP_RX_EVENT_PDU_RECEIVED, &sif->rx_state);
337
338   return 0;
339 }
340
341 static int
342 lacp_port_is_moved (vlib_main_t * vm, slave_if_t * sif)
343 {
344   bond_main_t *bm = &bond_main;
345   slave_if_t *sif2;
346   lacp_pdu_t *lacpdu = (lacp_pdu_t *) sif->last_rx_pkt;
347
348   /* *INDENT-OFF* */
349   pool_foreach (sif2, bm->neighbors, {
350       {
351         if ((sif != sif2) && (sif2->rx_state == LACP_RX_STATE_PORT_DISABLED) &&
352             !memcmp (sif2->partner.system,
353                      lacpdu->partner.port_info.system, 6) &&
354             (sif2->partner.port_number == lacpdu->partner.port_info.port_number))
355           return 1;
356       }
357   });
358   /* *INDENT-ON* */
359
360   return 0;
361 }
362
363 int
364 lacp_rx_action_current (void *p1, void *p2)
365 {
366   vlib_main_t *vm = p1;
367   slave_if_t *sif = p2;
368   lacp_main_t *lm = &lacp_main;
369
370   lacp_update_selected (vm, sif);
371   lacp_update_ntt (vm, sif);
372   lacp_record_pdu (vm, sif);
373   lacp_start_current_while_timer (lm->vlib_main, sif, sif->ttl_in_seconds);
374   sif->actor.state &= ~LACP_STATE_EXPIRED;
375   if (lacp_port_is_moved (vm, sif))
376     lacp_set_port_moved (vm, sif, 1);
377   lacp_selection_logic (vm, sif);
378
379   return 0;
380 }
381
382 static u8 *
383 format_rx_event (u8 * s, va_list * args)
384 {
385   static lacp_event_struct lacp_rx_event_array[] = {
386 #define _(b, s, n) {.bit = b, .str = #s, },
387     foreach_lacp_rx_event
388 #undef _
389     {.str = NULL}
390   };
391   int e = va_arg (*args, int);
392   lacp_event_struct *event_entry = lacp_rx_event_array;
393
394   if (e >= (sizeof (lacp_rx_event_array) / sizeof (*event_entry)))
395     s = format (s, "Bad event %d", e);
396   else
397     s = format (s, "%s", event_entry[e].str);
398
399   return s;
400 }
401
402 void
403 lacp_rx_debug_func (slave_if_t * sif, int event, int state,
404                     lacp_fsm_state_t * transition)
405 {
406   vlib_worker_thread_t *w = vlib_worker_threads + os_get_thread_index ();
407   /* *INDENT-OFF* */
408   ELOG_TYPE_DECLARE (e) =
409     {
410       .format = "%s",
411       .format_args = "T4",
412     };
413   /* *INDENT-ON* */
414   struct
415   {
416     u32 event;
417   } *ed = 0;
418
419   ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e, w->elog_track);
420   ed->event = elog_string (&vlib_global_main.elog_main, "%U-RX: %U, %U->%U%c",
421                            format_vnet_sw_if_index_name, vnet_get_main (),
422                            sif->sw_if_index, format_rx_event, event,
423                            format_rx_sm_state, state, format_rx_sm_state,
424                            transition->next_state, 0);
425 }
426
427 void
428 lacp_init_rx_machine (vlib_main_t * vm, slave_if_t * sif)
429 {
430   lacp_machine_dispatch (&lacp_rx_machine, vm, sif, LACP_RX_EVENT_BEGIN,
431                          &sif->rx_state);
432   lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
433                          LACP_RX_EVENT_LACP_ENABLED, &sif->rx_state);
434 }
435
436 /*
437  * fd.io coding-style-patch-verification: ON
438  *
439  * Local Variables:
440  * eval: (c-set-style "gnu")
441  * End:
442  */