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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
26 lacp_main_t lacp_main;
32 lacp_fill_pdu (lacp_pdu_t * lacpdu, slave_if_t * sif)
35 lacpdu->actor.port_info = sif->actor;
38 lacpdu->partner.port_info = sif->partner;
42 * send a lacp pkt on an ethernet interface
45 lacp_send_ethernet_lacp_pdu (slave_if_t * sif)
47 lacp_main_t *lm = &lacp_main;
49 ethernet_lacp_pdu_t *h0;
50 vnet_hw_interface_t *hw;
54 vlib_main_t *vm = lm->vlib_main;
55 vnet_main_t *vnm = lm->vnet_main;
58 * see lacp_periodic_init() to understand what's already painted
59 * into the buffer by the packet template mechanism
61 h0 = vlib_packet_template_get_packet
62 (vm, &lm->packet_templates[sif->packet_template_index], &bi0);
67 /* Add the interface's ethernet source address */
68 hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
70 clib_memcpy (h0->ethernet.src_address, hw->hw_address,
71 vec_len (hw->hw_address));
73 lacp_fill_pdu (&h0->lacp, sif);
75 /* Set the outbound packet length */
76 b0 = vlib_get_buffer (vm, bi0);
77 b0->current_length = sizeof (ethernet_lacp_pdu_t);
79 b0->total_length_not_including_first_buffer = 0;
81 /* And the outbound interface */
82 vnet_buffer (b0)->sw_if_index[VLIB_TX] = hw->sw_if_index;
84 /* And output the packet on the correct interface */
85 f = vlib_get_frame_to_node (vm, hw->output_node_index);
87 to_next = vlib_frame_vector_args (f);
91 vlib_put_frame_to_node (vm, hw->output_node_index, f);
93 sif->last_lacpdu_sent_time = vlib_time_now (lm->vlib_main);
98 * Decide which lacp packet template to use
101 lacp_pick_packet_template (slave_if_t * sif)
103 sif->packet_template_index = LACP_PACKET_TEMPLATE_ETHERNET;
109 lacp_send_lacp_pdu (vlib_main_t * vm, slave_if_t * sif)
111 if ((sif->mode != BOND_MODE_LACP) || (sif->port_enabled == 0))
113 lacp_stop_timer (&sif->periodic_timer);
117 if (sif->packet_template_index == (u8) ~ 0)
119 /* If we don't know how to talk to this peer, don't try again */
120 if (lacp_pick_packet_template (sif))
122 lacp_stop_timer (&sif->periodic_timer);
127 switch (sif->packet_template_index)
129 case LACP_PACKET_TEMPLATE_ETHERNET:
130 lacp_send_ethernet_lacp_pdu (sif);
139 lacp_periodic (vlib_main_t * vm)
141 bond_main_t *bm = &bond_main;
142 lacp_main_t *lm = &lacp_main;
145 u8 actor_state, partner_state;
148 pool_foreach (sif, bm->neighbors,
150 if (sif->port_enabled == 0)
153 actor_state = sif->actor.state;
154 partner_state = sif->partner.state;
155 if (lacp_timer_is_running (sif->current_while_timer) &&
156 lacp_timer_is_expired (lm->vlib_main, sif->current_while_timer))
158 lacp_machine_dispatch (&lacp_rx_machine, vm, sif,
159 LACP_RX_EVENT_TIMER_EXPIRED, &sif->rx_state);
162 if (lacp_timer_is_running (sif->periodic_timer) &&
163 lacp_timer_is_expired (lm->vlib_main, sif->periodic_timer))
165 lacp_machine_dispatch (&lacp_ptx_machine, vm, sif,
166 LACP_PTX_EVENT_TIMER_EXPIRED, &sif->ptx_state);
168 if (lacp_timer_is_running (sif->wait_while_timer) &&
169 lacp_timer_is_expired (lm->vlib_main, sif->wait_while_timer))
172 lacp_stop_timer (&sif->wait_while_timer);
173 lacp_selection_logic (vm, sif);
175 if (actor_state != sif->actor.state)
177 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
178 stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
179 [sif->sw_if_index].actor_state,
182 if (partner_state != sif->partner.state)
184 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
185 stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
186 [sif->sw_if_index].partner_state,
194 lacp_interface_enable_disable (vlib_main_t * vm, bond_if_t * bif,
195 slave_if_t * sif, u8 enable)
197 lacp_main_t *lm = &lacp_main;
202 lacp_create_periodic_process ();
203 port_number = clib_bitmap_first_clear (bif->port_number_bitmap);
204 bif->port_number_bitmap = clib_bitmap_set (bif->port_number_bitmap,
206 // bitmap starts at 0. Our port number starts at 1.
207 lacp_init_neighbor (sif, bif->hw_address, port_number + 1, sif->group);
208 lacp_init_state_machines (vm, sif);
210 if (lm->lacp_int == 1)
212 vlib_process_signal_event (vm, lm->lacp_process_node_index,
213 LACP_PROCESS_EVENT_START, 0);
218 ASSERT (lm->lacp_int >= 1);
219 if (lm->lacp_int == 0)
222 ELOG_TYPE_DECLARE (e) =
224 .format = "lacp-int-en-dis: BUG lacp_int == 0",
227 ELOG_DATA (&vlib_global_main.elog_main, e);
232 if (lm->lacp_int == 0)
233 vlib_process_signal_event (vm, lm->lacp_process_node_index,
234 LACP_PROCESS_EVENT_STOP, 0);
239 static clib_error_t *
240 lacp_periodic_init (vlib_main_t * vm)
242 lacp_main_t *lm = &lacp_main;
243 ethernet_lacp_pdu_t h;
244 ethernet_marker_pdu_t m;
245 u8 dst[] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 };
247 /* initialize binary API */
248 lacp_plugin_api_hookup (vm);
250 /* Create the ethernet lacp packet template */
252 clib_memset (&h, 0, sizeof (h));
254 memcpy (h.ethernet.dst_address, dst, sizeof (h.ethernet.dst_address));
256 /* leave src address blank (fill in at send time) */
258 h.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
260 h.lacp.subtype = LACP_SUBTYPE;
261 h.lacp.version_number = LACP_ACTOR_LACP_VERSION;
264 h.lacp.actor.tlv_type = LACP_ACTOR_INFORMATION;
265 h.lacp.actor.tlv_length = sizeof (lacp_actor_partner_t);
268 h.lacp.partner.tlv_type = LACP_PARTNER_INFORMATION;
269 h.lacp.partner.tlv_length = sizeof (lacp_actor_partner_t);
272 h.lacp.collector.tlv_type = LACP_COLLECTOR_INFORMATION;
273 h.lacp.collector.tlv_length = sizeof (lacp_collector_t);
274 h.lacp.collector.max_delay = 0;
277 h.lacp.terminator.tlv_type = LACP_TERMINATOR_INFORMATION;
278 h.lacp.terminator.tlv_length = 0;
280 vlib_packet_template_init
281 (vm, &lm->packet_templates[LACP_PACKET_TEMPLATE_ETHERNET],
284 /* alloc chunk size */ 8,
287 /* Create the ethernet marker protocol packet template */
289 clib_memset (&m, 0, sizeof (m));
291 memcpy (m.ethernet.dst_address, dst, sizeof (m.ethernet.dst_address));
293 /* leave src address blank (fill in at send time) */
295 m.ethernet.type = htons (ETHERNET_TYPE_SLOW_PROTOCOLS);
297 m.marker.subtype = MARKER_SUBTYPE;
298 m.marker.version_number = MARKER_PROTOCOL_VERSION;
300 m.marker.marker_info.tlv_length = sizeof (marker_information_t);
303 m.marker.terminator.tlv_type = MARKER_TERMINATOR_INFORMATION;
304 m.marker.terminator.tlv_length = 0;
306 vlib_packet_template_init
307 (vm, &lm->marker_packet_templates[MARKER_PACKET_TEMPLATE_ETHERNET],
310 /* alloc chunk size */ 8,
313 bond_register_callback (lacp_interface_enable_disable);
319 lacp_machine_dispatch (lacp_machine_t * machine, vlib_main_t * vm,
320 slave_if_t * sif, int event, int *state)
322 lacp_fsm_state_t *transition;
325 transition = &machine->tables[*state].state_table[event];
326 LACP_DBG2 (sif, event, *state, machine, transition);
327 *state = transition->next_state;
328 if (transition->action)
329 rc = (*transition->action) ((void *) vm, (void *) sif);
335 lacp_init_neighbor (slave_if_t * sif, u8 * hw_address, u16 port_number,
338 lacp_stop_timer (&sif->wait_while_timer);
339 lacp_stop_timer (&sif->current_while_timer);
340 lacp_stop_timer (&sif->actor_churn_timer);
341 lacp_stop_timer (&sif->partner_churn_timer);
342 lacp_stop_timer (&sif->periodic_timer);
343 lacp_stop_timer (&sif->last_lacpdu_sent_time);
344 lacp_stop_timer (&sif->last_lacpdu_recd_time);
345 lacp_stop_timer (&sif->last_marker_pdu_sent_time);
346 lacp_stop_timer (&sif->last_marker_pdu_recd_time);
347 sif->lacp_enabled = 1;
348 sif->loopback_port = 0;
353 sif->selected = LACP_PORT_UNSELECTED;
354 sif->actor.state = LACP_STATE_AGGREGATION;
355 if (sif->ttl_in_seconds == LACP_SHORT_TIMOUT_TIME)
356 sif->actor.state |= LACP_STATE_LACP_TIMEOUT;
357 if (sif->is_passive == 0)
358 sif->actor.state |= LACP_STATE_LACP_ACTIVITY;
359 clib_memcpy (sif->actor.system, hw_address, 6);
360 sif->actor.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
361 sif->actor.key = htons (group);
362 sif->actor.port_number = htons (port_number);
363 sif->actor.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
365 sif->partner.system_priority = htons (LACP_DEFAULT_SYSTEM_PRIORITY);
366 sif->partner.key = htons (group);
367 sif->partner.port_number = htons (port_number);
368 sif->partner.port_priority = htons (LACP_DEFAULT_PORT_PRIORITY);
369 sif->partner.state = 0;
371 sif->actor_admin = sif->actor;
372 sif->partner_admin = sif->partner;
376 lacp_init_state_machines (vlib_main_t * vm, slave_if_t * sif)
378 bond_main_t *bm = &bond_main;
379 bond_if_t *bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
381 lacp_init_tx_machine (vm, sif);
382 lacp_init_mux_machine (vm, sif);
383 lacp_init_ptx_machine (vm, sif);
384 lacp_init_rx_machine (vm, sif);
385 stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
386 [sif->sw_if_index].actor_state,
388 stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
389 [sif->sw_if_index].partner_state,
393 VLIB_INIT_FUNCTION (lacp_periodic_init);
395 static clib_error_t *
396 lacp_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
398 lacp_main_t *lm = &lacp_main;
400 vlib_main_t *vm = lm->vlib_main;
402 sif = bond_get_slave_by_sw_if_index (sw_if_index);
405 if (sif->lacp_enabled == 0)
408 /* port_enabled is both admin up and hw link up */
409 sif->port_enabled = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
410 vnet_sw_interface_is_link_up (vnm, sw_if_index));
411 if (sif->port_enabled == 0)
413 lacp_init_neighbor (sif, sif->actor_admin.system,
414 ntohs (sif->actor_admin.port_number),
415 ntohs (sif->actor_admin.key));
416 lacp_init_state_machines (vm, sif);
423 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (lacp_sw_interface_up_down);
425 static clib_error_t *
426 lacp_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
428 lacp_main_t *lm = &lacp_main;
430 vnet_sw_interface_t *sw;
431 vlib_main_t *vm = lm->vlib_main;
433 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
434 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
437 if (sif->lacp_enabled == 0)
440 /* port_enabled is both admin up and hw link up */
441 sif->port_enabled = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
442 vnet_sw_interface_is_admin_up (vnm,
444 if (sif->port_enabled == 0)
446 lacp_init_neighbor (sif, sif->actor_admin.system,
447 ntohs (sif->actor_admin.port_number),
448 ntohs (sif->actor_admin.key));
449 lacp_init_state_machines (vm, sif);
456 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lacp_hw_interface_up_down);
459 VLIB_PLUGIN_REGISTER () = {
460 .version = VPP_BUILD_VER,
461 .description = "Link Aggregation Control Protocol (LACP)",
466 * fd.io coding-style-patch-verification: ON
469 * eval: (c-set-style "gnu")