bonding lacp: replace slave string with member
[vpp.git] / src / plugins / lacp / lacp.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 #include <stdint.h>
17 #include <vlib/vlib.h>
18 #include <vlib/unix/unix.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vpp/app/version.h>
21 #include <vppinfra/hash.h>
22 #include <vnet/bonding/node.h>
23 #include <lacp/node.h>
24 #include <vpp/stats/stat_segment.h>
25
26 lacp_main_t lacp_main;
27
28 /*
29  * Generate lacp pdu
30  */
31 static void
32 lacp_fill_pdu (lacp_pdu_t * lacpdu, member_if_t * mif)
33 {
34   /* Actor TLV */
35   lacpdu->actor.port_info = mif->actor;
36
37   /* Partner TLV */
38   lacpdu->partner.port_info = mif->partner;
39 }
40
41 /*
42  * send a lacp pkt on an ethernet interface
43  */
44 static void
45 lacp_send_ethernet_lacp_pdu (vlib_main_t * vm, member_if_t * mif)
46 {
47   lacp_main_t *lm = &lacp_main;
48   u32 *to_next;
49   ethernet_lacp_pdu_t *h0;
50   vnet_hw_interface_t *hw;
51   u32 bi0;
52   vlib_buffer_t *b0;
53   vlib_frame_t *f;
54   vnet_main_t *vnm = lm->vnet_main;
55
56   /*
57    * see lacp_periodic_init() to understand what's already painted
58    * into the buffer by the packet template mechanism
59    */
60   h0 = vlib_packet_template_get_packet
61     (vm, &lm->packet_templates[mif->packet_template_index], &bi0);
62
63   if (!h0)
64     return;
65
66   /* Add the interface's ethernet source address */
67   hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index);
68
69   clib_memcpy (h0->ethernet.src_address, hw->hw_address,
70                vec_len (hw->hw_address));
71
72   lacp_fill_pdu (&h0->lacp, mif);
73
74   /* Set the outbound packet length */
75   b0 = vlib_get_buffer (vm, bi0);
76   b0->current_length = sizeof (ethernet_lacp_pdu_t);
77   b0->current_data = 0;
78   b0->total_length_not_including_first_buffer = 0;
79
80   /* And the outbound interface */
81   vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
82
83   /* And output the packet on the correct interface */
84   f = vlib_get_frame_to_node (vm, hw->output_node_index);
85
86   to_next = vlib_frame_vector_args (f);
87   to_next[0] = bi0;
88   f->n_vectors = 1;
89
90   vlib_put_frame_to_node (vm, hw->output_node_index, f);
91
92   mif->last_lacpdu_sent_time = vlib_time_now (vm);
93   mif->pdu_sent++;
94 }
95
96 /*
97  * Decide which lacp packet template to use
98  */
99 static int
100 lacp_pick_packet_template (member_if_t * mif)
101 {
102   mif->packet_template_index = LACP_PACKET_TEMPLATE_ETHERNET;
103
104   return 0;
105 }
106
107 void
108 lacp_send_lacp_pdu (vlib_main_t * vm, member_if_t * mif)
109 {
110   if ((mif->mode != BOND_MODE_LACP) || (mif->port_enabled == 0))
111     {
112       lacp_stop_timer (&mif->periodic_timer);
113       return;
114     }
115
116   if (mif->packet_template_index == (u8) ~ 0)
117     {
118       /* If we don't know how to talk to this peer, don't try again */
119       if (lacp_pick_packet_template (mif))
120         {
121           lacp_stop_timer (&mif->periodic_timer);
122           return;
123         }
124     }
125
126   switch (mif->packet_template_index)
127     {
128     case LACP_PACKET_TEMPLATE_ETHERNET:
129       lacp_send_ethernet_lacp_pdu (vm, mif);
130       break;
131
132     default:
133       ASSERT (0);
134     }
135 }
136
137 void
138 lacp_periodic (vlib_main_t * vm)
139 {
140   bond_main_t *bm = &bond_main;
141   member_if_t *mif;
142   bond_if_t *bif;
143   u8 actor_state, partner_state;
144
145   /* *INDENT-OFF* */
146   pool_foreach (mif, bm->neighbors,
147   ({
148     if (mif->port_enabled == 0)
149       continue;
150
151     actor_state = mif->actor.state;
152     partner_state = mif->partner.state;
153     if (lacp_timer_is_running (mif->current_while_timer) &&
154         lacp_timer_is_expired (vm, mif->current_while_timer))
155       {
156         lacp_machine_dispatch (&lacp_rx_machine, vm, mif,
157                                LACP_RX_EVENT_TIMER_EXPIRED, &mif->rx_state);
158       }
159
160     if (lacp_timer_is_running (mif->periodic_timer) &&
161         lacp_timer_is_expired (vm, mif->periodic_timer))
162       {
163         lacp_machine_dispatch (&lacp_ptx_machine, vm, mif,
164                                LACP_PTX_EVENT_TIMER_EXPIRED, &mif->ptx_state);
165       }
166     if (lacp_timer_is_running (mif->wait_while_timer) &&
167         lacp_timer_is_expired (vm, mif->wait_while_timer))
168       {
169         mif->ready_n = 1;
170         lacp_stop_timer (&mif->wait_while_timer);
171         lacp_selection_logic (vm, mif);
172       }
173     if (actor_state != mif->actor.state)
174       {
175         bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
176         stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
177                                         [mif->sw_if_index].actor_state,
178                                         mif->actor.state);
179       }
180     if (partner_state != mif->partner.state)
181       {
182         bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
183         stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
184                                         [mif->sw_if_index].partner_state,
185                                         mif->partner.state);
186       }
187   }));
188   /* *INDENT-ON* */
189 }
190
191 static void
192 lacp_interface_enable_disable (vlib_main_t * vm, bond_if_t * bif,
193                                member_if_t * mif, u8 enable)
194 {
195   lacp_main_t *lm = &lacp_main;
196   uword port_number;
197
198   if (enable)
199     {
200       lacp_create_periodic_process ();
201       port_number = clib_bitmap_first_clear (bif->port_number_bitmap);
202       bif->port_number_bitmap = clib_bitmap_set (bif->port_number_bitmap,
203                                                  port_number, 1);
204       // bitmap starts at 0. Our port number starts at 1.
205       lacp_init_neighbor (mif, bif->hw_address, port_number + 1, mif->group);
206       lacp_init_state_machines (vm, mif);
207       lm->lacp_int++;
208       if (lm->lacp_int == 1)
209         {
210           vlib_process_signal_event (vm, lm->lacp_process_node_index,
211                                      LACP_PROCESS_EVENT_START, 0);
212         }
213     }
214   else
215     {
216       ASSERT (lm->lacp_int >= 1);
217       if (lm->lacp_int == 0)
218         {
219           /* *INDENT-OFF* */
220           ELOG_TYPE_DECLARE (e) =
221             {
222               .format = "lacp-int-en-dis: BUG lacp_int == 0",
223             };
224           /* *INDENT-ON* */
225           ELOG_DATA (&vlib_global_main.elog_main, e);
226         }
227       else
228         {
229           lm->lacp_int--;
230           if (lm->lacp_int == 0)
231             vlib_process_signal_event (vm, lm->lacp_process_node_index,
232                                        LACP_PROCESS_EVENT_STOP, 0);
233         }
234     }
235 }
236
237 static clib_error_t *
238 lacp_periodic_init (vlib_main_t * vm)
239 {
240   lacp_main_t *lm = &lacp_main;
241   ethernet_lacp_pdu_t h;
242   ethernet_marker_pdu_t m;
243   u8 dst[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
244
245   /* initialize binary API */
246   lacp_plugin_api_hookup (vm);
247
248   /* Create the ethernet lacp packet template */
249
250   clib_memset (&h, 0, sizeof (h));
251
252   memcpy (h.ethernet.dst_address, dst, sizeof (h.ethernet.dst_address));
253
254   /* leave src address blank (fill in at send time) */
255
256   h.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
257
258   h.lacp.subtype = LACP_SUBTYPE;
259   h.lacp.version_number = LACP_ACTOR_LACP_VERSION;
260
261   /* Actor TLV */
262   h.lacp.actor.tlv_type = LACP_ACTOR_INFORMATION;
263   h.lacp.actor.tlv_length = sizeof (lacp_actor_partner_t);
264
265   /* Partner TLV */
266   h.lacp.partner.tlv_type = LACP_PARTNER_INFORMATION;
267   h.lacp.partner.tlv_length = sizeof (lacp_actor_partner_t);
268
269   /* Collector TLV */
270   h.lacp.collector.tlv_type = LACP_COLLECTOR_INFORMATION;
271   h.lacp.collector.tlv_length = sizeof (lacp_collector_t);
272   h.lacp.collector.max_delay = 0;
273
274   /* Terminator TLV */
275   h.lacp.terminator.tlv_type = LACP_TERMINATOR_INFORMATION;
276   h.lacp.terminator.tlv_length = 0;
277
278   vlib_packet_template_init
279     (vm, &lm->packet_templates[LACP_PACKET_TEMPLATE_ETHERNET],
280      /* data */ &h,
281      sizeof (h),
282      /* alloc chunk size */ 8,
283      "lacp-ethernet");
284
285   /* Create the ethernet marker protocol packet template */
286
287   clib_memset (&m, 0, sizeof (m));
288
289   memcpy (m.ethernet.dst_address, dst, sizeof (m.ethernet.dst_address));
290
291   /* leave src address blank (fill in at send time) */
292
293   m.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
294
295   m.marker.subtype = MARKER_SUBTYPE;
296   m.marker.version_number = MARKER_PROTOCOL_VERSION;
297
298   m.marker.marker_info.tlv_length = sizeof (marker_information_t);
299
300   /* Terminator TLV */
301   m.marker.terminator.tlv_type = MARKER_TERMINATOR_INFORMATION;
302   m.marker.terminator.tlv_length = 0;
303
304   vlib_packet_template_init
305     (vm, &lm->marker_packet_templates[MARKER_PACKET_TEMPLATE_ETHERNET],
306      /* data */ &m,
307      sizeof (m),
308      /* alloc chunk size */ 8,
309      "marker-ethernet");
310
311   bond_register_callback (lacp_interface_enable_disable);
312
313   return 0;
314 }
315
316 int
317 lacp_machine_dispatch (lacp_machine_t * machine, vlib_main_t * vm,
318                        member_if_t * mif, int event, int *state)
319 {
320   lacp_fsm_state_t *transition;
321   int rc = 0;
322
323   transition = &machine->tables[*state].state_table[event];
324   LACP_DBG2 (mif, event, *state, machine, transition);
325   *state = transition->next_state;
326   if (transition->action)
327     rc = (*transition->action) ((void *) vm, (void *) mif);
328
329   return rc;
330 }
331
332 void
333 lacp_init_neighbor (member_if_t * mif, u8 * hw_address, u16 port_number,
334                     u32 group)
335 {
336   lacp_stop_timer (&mif->wait_while_timer);
337   lacp_stop_timer (&mif->current_while_timer);
338   lacp_stop_timer (&mif->actor_churn_timer);
339   lacp_stop_timer (&mif->partner_churn_timer);
340   lacp_stop_timer (&mif->periodic_timer);
341   lacp_stop_timer (&mif->last_lacpdu_sent_time);
342   lacp_stop_timer (&mif->last_lacpdu_recd_time);
343   lacp_stop_timer (&mif->last_marker_pdu_sent_time);
344   lacp_stop_timer (&mif->last_marker_pdu_recd_time);
345   mif->lacp_enabled = 1;
346   mif->loopback_port = 0;
347   mif->ready = 0;
348   mif->ready_n = 0;
349   mif->port_moved = 0;
350   mif->ntt = 0;
351   mif->selected = LACP_PORT_UNSELECTED;
352   mif->actor.state = LACP_STATE_AGGREGATION;
353   if (mif->ttl_in_seconds == LACP_SHORT_TIMOUT_TIME)
354     mif->actor.state |= LACP_STATE_LACP_TIMEOUT;
355   if (mif->is_passive == 0)
356     mif->actor.state |= LACP_STATE_LACP_ACTIVITY;
357   clib_memcpy (mif->actor.system, hw_address, 6);
358   mif->actor.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
359   mif->actor.key = htons (group);
360   mif->actor.port_number = htons (port_number);
361   mif->actor.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
362
363   mif->partner.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
364   mif->partner.key = htons (group);
365   mif->partner.port_number = htons (port_number);
366   mif->partner.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
367   mif->partner.state = 0;
368
369   mif->actor_admin = mif->actor;
370   mif->partner_admin = mif->partner;
371 }
372
373 void
374 lacp_init_state_machines (vlib_main_t * vm, member_if_t * mif)
375 {
376   bond_main_t *bm = &bond_main;
377   bond_if_t *bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance);
378
379   lacp_init_tx_machine (vm, mif);
380   lacp_init_mux_machine (vm, mif);
381   lacp_init_ptx_machine (vm, mif);
382   lacp_init_rx_machine (vm, mif);
383   stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
384                                   [mif->sw_if_index].actor_state,
385                                   mif->actor.state);
386   stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
387                                   [mif->sw_if_index].partner_state,
388                                   mif->partner.state);
389 }
390
391 VLIB_INIT_FUNCTION (lacp_periodic_init);
392
393 static clib_error_t *
394 lacp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
395 {
396   lacp_main_t *lm = &lacp_main;
397   member_if_t *mif;
398   vlib_main_t *vm = lm->vlib_main;
399
400   mif = bond_get_member_by_sw_if_index (sw_if_index);
401   if (mif)
402     {
403       if (mif->lacp_enabled == 0)
404         return 0;
405
406       /* port_enabled is both admin up and hw link up */
407       mif->port_enabled = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
408                            vnet_sw_interface_is_link_up (vnm, sw_if_index));
409       if (mif->port_enabled == 0)
410         {
411           lacp_init_neighbor (mif, mif->actor_admin.system,
412                               ntohs (mif->actor_admin.port_number),
413                               ntohs (mif->actor_admin.key));
414           lacp_init_state_machines (vm, mif);
415         }
416     }
417
418   return 0;
419 }
420
421 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (lacp_sw_interface_up_down);
422
423 static clib_error_t *
424 lacp_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
425 {
426   lacp_main_t *lm = &lacp_main;
427   member_if_t *mif;
428   vnet_sw_interface_t *sw;
429   vlib_main_t *vm = lm->vlib_main;
430
431   sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
432   mif = bond_get_member_by_sw_if_index (sw->sw_if_index);
433   if (mif)
434     {
435       if (mif->lacp_enabled == 0)
436         return 0;
437
438       /* port_enabled is both admin up and hw link up */
439       mif->port_enabled = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
440                            vnet_sw_interface_is_admin_up (vnm,
441                                                           sw->sw_if_index));
442       if (mif->port_enabled == 0)
443         {
444           lacp_init_neighbor (mif, mif->actor_admin.system,
445                               ntohs (mif->actor_admin.port_number),
446                               ntohs (mif->actor_admin.key));
447           lacp_init_state_machines (vm, mif);
448         }
449     }
450
451   return 0;
452 }
453
454 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lacp_hw_interface_up_down);
455
456 /* *INDENT-OFF* */
457 VLIB_PLUGIN_REGISTER () = {
458     .version = VPP_BUILD_VER,
459     .description = "Link Aggregation Control Protocol (LACP)",
460 };
461 /* *INDENT-ON* */
462
463 /*
464  * fd.io coding-style-patch-verification: ON
465  *
466  * Local Variables:
467  * eval: (c-set-style "gnu")
468  * End:
469  */