bond: Add bonding driver and LACP protocol
[vpp.git] / src / plugins / lacp / mux_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 <vlib/vlib.h>
19 #include <vnet/bonding/node.h>
20 #include <lacp/node.h>
21
22 /*
23  *  LACP State = DETACHED
24  */
25 static lacp_fsm_state_t lacp_mux_state_detached[] = {
26   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 0 BEGIN
27   {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},        // event 1 SELECTED
28   {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},        // event 2 STANDBY
29   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 3 UNSELECTED
30   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 4 READY
31   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 5 SYNC
32 };
33
34 /*
35  *  LACP State = WAITING
36  */
37 static lacp_fsm_state_t lacp_mux_state_waiting[] = {
38   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 0 BEGIN
39   {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},        // event 1 SELECTED
40   {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},        // event 2 STANDBY
41   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 3 UNSELECTED
42   {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},      // event 4 READY
43   {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},        // event 5 SYNC
44 };
45
46 /*
47  *  LACP State = ATTACHED
48  */
49 static lacp_fsm_state_t lacp_mux_state_attached[] = {
50   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 0 BEGIN
51   {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},      // event 1 SELECTED
52   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 2 STANDBY
53   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 3 UNSELECTED
54   {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},      // event 4 READY
55   {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},        // event 5_SYNC
56 };
57
58 /*
59  *  LACP State = COLLECTING_DISTRIBUTING
60  */
61 static lacp_fsm_state_t lacp_mux_state_collecting_distributing[] = {
62   {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},      // event 0 BEGIN
63   {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},        // event 1 SELECTED
64   {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},        // event 2 STANDBY
65   {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},      // event 3 UNSELECTED
66   {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},        // event 4 READY
67   {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},        // event 5 SYNC
68 };
69
70 static lacp_fsm_machine_t lacp_mux_fsm_table[] = {
71   {lacp_mux_state_detached},
72   {lacp_mux_state_waiting},
73   {lacp_mux_state_attached},
74   {lacp_mux_state_collecting_distributing},
75 };
76
77 lacp_machine_t lacp_mux_machine = {
78   lacp_mux_fsm_table,
79   lacp_mux_debug_func,
80 };
81
82 static void
83 lacp_detach_mux_from_aggregator (vlib_main_t * vm, slave_if_t * sif)
84 {
85   sif->actor.state &= ~LACP_STATE_SYNCHRONIZATION;
86   sif->ready = 0;
87   sif->ready_n = 0;
88 }
89
90 static void
91 lacp_attach_mux_to_aggregator (vlib_main_t * vm, slave_if_t * sif)
92 {
93   sif->actor.state |= LACP_STATE_SYNCHRONIZATION;
94 }
95
96 int
97 lacp_mux_action_detached (void *p1, void *p2)
98 {
99   vlib_main_t *vm = (vlib_main_t *) p1;
100   slave_if_t *sif = (slave_if_t *) p2;
101
102   lacp_detach_mux_from_aggregator (vm, sif);
103   sif->actor.state &= ~LACP_STATE_COLLECTING;
104   bond_disable_collecting_distributing (vm, sif);
105   sif->actor.state &= ~LACP_STATE_DISTRIBUTING;
106   sif->ntt = 1;
107   lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
108                          &sif->tx_state);
109
110   if (sif->selected == LACP_PORT_SELECTED)
111     lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
112                            LACP_MUX_EVENT_SELECTED, &sif->mux_state);
113
114   if (sif->selected == LACP_PORT_STANDBY)
115     lacp_machine_dispatch (&lacp_mux_machine, vm, sif, LACP_MUX_EVENT_STANDBY,
116                            &sif->mux_state);
117
118   return 0;
119 }
120
121 int
122 lacp_mux_action_attached (void *p1, void *p2)
123 {
124   vlib_main_t *vm = (vlib_main_t *) p1;
125   slave_if_t *sif = (slave_if_t *) p2;
126
127   lacp_attach_mux_to_aggregator (vm, sif);
128   sif->actor.state &= ~LACP_STATE_COLLECTING;
129   bond_disable_collecting_distributing (vm, sif);
130   sif->actor.state &= ~LACP_STATE_DISTRIBUTING;
131   sif->ntt = 1;
132   lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
133                          &sif->tx_state);
134
135   if ((sif->selected == LACP_PORT_UNSELECTED) ||
136       (sif->selected == LACP_PORT_STANDBY))
137     lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
138                            LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
139
140   if ((sif->selected == LACP_PORT_SELECTED) &&
141       (sif->partner.state & LACP_STATE_SYNCHRONIZATION))
142     lacp_machine_dispatch (&lacp_mux_machine, vm, sif, LACP_MUX_EVENT_SYNC,
143                            &sif->mux_state);
144   return 0;
145 }
146
147 int
148 lacp_mux_action_waiting (void *p1, void *p2)
149 {
150   vlib_main_t *vm = (vlib_main_t *) p1;
151   slave_if_t *sif = (slave_if_t *) p2;
152   lacp_main_t *lm = &lacp_main;
153
154   if (!lacp_timer_is_running (sif->wait_while_timer))
155     lacp_start_wait_while_timer (lm->vlib_main, sif,
156                                  LACP_AGGREGATE_WAIT_TIME);
157
158   if ((sif->selected == LACP_PORT_SELECTED) && sif->ready)
159     lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
160                            LACP_MUX_EVENT_READY, &sif->mux_state);
161
162   if (sif->selected == LACP_PORT_UNSELECTED)
163     lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
164                            LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
165
166   return 0;
167 }
168
169 int
170 lacp_mux_action_collecting_distributing (void *p1, void *p2)
171 {
172   vlib_main_t *vm = (vlib_main_t *) p1;
173   slave_if_t *sif = (slave_if_t *) p2;
174
175   sif->actor.state |= LACP_STATE_SYNCHRONIZATION | LACP_STATE_COLLECTING |
176     LACP_STATE_DISTRIBUTING;
177   bond_enable_collecting_distributing (vm, sif);
178   sif->ntt = 1;
179   lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_NTT,
180                          &sif->tx_state);
181   if ((sif->selected == LACP_PORT_UNSELECTED) ||
182       (sif->selected == LACP_PORT_STANDBY) ||
183       !(sif->partner.state & LACP_STATE_SYNCHRONIZATION))
184     lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
185                            LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
186
187
188   return 0;
189 }
190
191 static u8 *
192 format_mux_event (u8 * s, va_list * args)
193 {
194   static lacp_event_struct lacp_mux_event_array[] = {
195 #define _(b, s, n) {.bit = b, .str = #s, },
196     foreach_lacp_mux_event
197 #undef _
198     {.str = NULL}
199   };
200   int e = va_arg (*args, int);
201   lacp_event_struct *event_entry =
202     (lacp_event_struct *) & lacp_mux_event_array;
203
204   if (e >= (sizeof (lacp_mux_event_array) / sizeof (*event_entry)))
205     s = format (s, "Bad event %d", e);
206   else
207     s = format (s, "%s", event_entry[e].str);
208
209   return s;
210 }
211
212 void
213 lacp_mux_debug_func (slave_if_t * sif, int event, int state,
214                      lacp_fsm_state_t * transition)
215 {
216   clib_warning ("%U-MUX: event %U, old state %U, new state %U",
217                 format_vnet_sw_if_index_name, vnet_get_main (),
218                 sif->sw_if_index, format_mux_event,
219                 event, format_mux_sm_state, state, format_mux_sm_state,
220                 transition->next_state);
221 }
222
223 void
224 lacp_init_mux_machine (vlib_main_t * vm, slave_if_t * sif)
225 {
226   lacp_machine_dispatch (&lacp_mux_machine, vm, sif, LACP_MUX_EVENT_BEGIN,
227                          &sif->mux_state);
228 }
229
230 /*
231  * fd.io coding-style-patch-verification: ON
232  *
233  * Local Variables:
234  * eval: (c-set-style "gnu")
235  * End:
236  */