19cd2d7a5SSteven/*
29cd2d7a5SSteven * Copyright (c) 2017 Cisco and/or its affiliates.
39cd2d7a5SSteven * Licensed under the Apache License, Version 2.0 (the "License");
49cd2d7a5SSteven * you may not use this file except in compliance with the License.
59cd2d7a5SSteven * You may obtain a copy of the License at:
69cd2d7a5SSteven *
79cd2d7a5SSteven *     http://www.apache.org/licenses/LICENSE-2.0
89cd2d7a5SSteven *
99cd2d7a5SSteven * Unless required by applicable law or agreed to in writing, software
109cd2d7a5SSteven * distributed under the License is distributed on an "AS IS" BASIS,
119cd2d7a5SSteven * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
129cd2d7a5SSteven * See the License for the specific language governing permissions and
139cd2d7a5SSteven * limitations under the License.
149cd2d7a5SSteven */
159cd2d7a5SSteven
169cd2d7a5SSteven#define _GNU_SOURCE
179cd2d7a5SSteven
189cd2d7a5SSteven#include <vlib/vlib.h>
199cd2d7a5SSteven#include <vnet/bonding/node.h>
209cd2d7a5SSteven#include <lacp/node.h>
219cd2d7a5SSteven
229cd2d7a5SSteven/*
239cd2d7a5SSteven *  LACP State = DETACHED
249cd2d7a5SSteven */
259cd2d7a5SStevenstatic lacp_fsm_state_t lacp_mux_state_detached[] = {
269cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 0 BEGIN
279cd2d7a5SSteven  {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},	// event 1 SELECTED
289cd2d7a5SSteven  {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},	// event 2 STANDBY
299cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 3 UNSELECTED
309cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 4 READY
319cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 5 SYNC
329cd2d7a5SSteven};
339cd2d7a5SSteven
349cd2d7a5SSteven/*
359cd2d7a5SSteven *  LACP State = WAITING
369cd2d7a5SSteven */
379cd2d7a5SStevenstatic lacp_fsm_state_t lacp_mux_state_waiting[] = {
389cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 0 BEGIN
399cd2d7a5SSteven  {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},	// event 1 SELECTED
409cd2d7a5SSteven  {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},	// event 2 STANDBY
419cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 3 UNSELECTED
429cd2d7a5SSteven  {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},	// event 4 READY
439cd2d7a5SSteven  {LACP_ACTION_WAITING, LACP_MUX_STATE_WAITING},	// event 5 SYNC
449cd2d7a5SSteven};
459cd2d7a5SSteven
469cd2d7a5SSteven/*
479cd2d7a5SSteven *  LACP State = ATTACHED
489cd2d7a5SSteven */
499cd2d7a5SStevenstatic lacp_fsm_state_t lacp_mux_state_attached[] = {
509cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 0 BEGIN
519cd2d7a5SSteven  {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},	// event 1 SELECTED
529cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 2 STANDBY
539cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 3 UNSELECTED
549cd2d7a5SSteven  {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},	// event 4 READY
559cd2d7a5SSteven  {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},	// event 5_SYNC
569cd2d7a5SSteven};
579cd2d7a5SSteven
589cd2d7a5SSteven/*
599cd2d7a5SSteven *  LACP State = COLLECTING_DISTRIBUTING
609cd2d7a5SSteven */
619cd2d7a5SStevenstatic lacp_fsm_state_t lacp_mux_state_collecting_distributing[] = {
629cd2d7a5SSteven  {LACP_ACTION_DETACHED, LACP_MUX_STATE_DETACHED},	// event 0 BEGIN
639cd2d7a5SSteven  {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},	// event 1 SELECTED
649cd2d7a5SSteven  {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},	// event 2 STANDBY
659cd2d7a5SSteven  {LACP_ACTION_ATTACHED, LACP_MUX_STATE_ATTACHED},	// event 3 UNSELECTED
669cd2d7a5SSteven  {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},	// event 4 READY
679cd2d7a5SSteven  {LACP_ACTION_COLLECTING_DISTRIBUTING, LACP_MUX_STATE_COLLECTING_DISTRIBUTING},	// event 5 SYNC
689cd2d7a5SSteven};
699cd2d7a5SSteven
709cd2d7a5SStevenstatic lacp_fsm_machine_t lacp_mux_fsm_table[] = {
719cd2d7a5SSteven  {lacp_mux_state_detached},
729cd2d7a5SSteven  {lacp_mux_state_waiting},
739cd2d7a5SSteven  {lacp_mux_state_attached},
749cd2d7a5SSteven  {lacp_mux_state_collecting_distributing},
759cd2d7a5SSteven};
769cd2d7a5SSteven
779cd2d7a5SStevenlacp_machine_t lacp_mux_machine = {
789cd2d7a5SSteven  lacp_mux_fsm_table,
799cd2d7a5SSteven  lacp_mux_debug_func,
809cd2d7a5SSteven};
819cd2d7a5SSteven
829cd2d7a5SStevenstatic void
839cd2d7a5SStevenlacp_detach_mux_from_aggregator (vlib_main_t * vm, slave_if_t * sif)
849cd2d7a5SSteven{
859cd2d7a5SSteven  sif->actor.state &= ~LACP_STATE_SYNCHRONIZATION;
869cd2d7a5SSteven  sif->ready = 0;
879cd2d7a5SSteven  sif->ready_n = 0;
889cd2d7a5SSteven}
899cd2d7a5SSteven
909cd2d7a5SStevenstatic void
919cd2d7a5SStevenlacp_attach_mux_to_aggregator (vlib_main_t * vm, slave_if_t * sif)
929cd2d7a5SSteven{
939cd2d7a5SSteven  sif->actor.state |= LACP_STATE_SYNCHRONIZATION;
949cd2d7a5SSteven}
959cd2d7a5SSteven
969cd2d7a5SStevenint
979cd2d7a5SStevenlacp_mux_action_detached (void *p1, void *p2)
989cd2d7a5SSteven{
9991c51291SZhiyong Yang  vlib_main_t *vm = p1;
10091c51291SZhiyong Yang  slave_if_t *sif = p2;
1019cd2d7a5SSteven
1029cd2d7a5SSteven  lacp_detach_mux_from_aggregator (vm, sif);
1039cd2d7a5SSteven  sif->actor.state &= ~LACP_STATE_COLLECTING;
1049cd2d7a5SSteven  bond_disable_collecting_distributing (vm, sif);
1059cd2d7a5SSteven  sif->actor.state &= ~LACP_STATE_DISTRIBUTING;
1069cd2d7a5SSteven  sif->ntt = 1;
10792e1b83aSElias Rudberg  lacp_start_periodic_timer (vm, sif, 0);
1089cd2d7a5SSteven
1099cd2d7a5SSteven  if (sif->selected == LACP_PORT_SELECTED)
1109cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
1119cd2d7a5SSteven			   LACP_MUX_EVENT_SELECTED, &sif->mux_state);
1129cd2d7a5SSteven
1139cd2d7a5SSteven  if (sif->selected == LACP_PORT_STANDBY)
1149cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif, LACP_MUX_EVENT_STANDBY,
1159cd2d7a5SSteven			   &sif->mux_state);
1169cd2d7a5SSteven
1179cd2d7a5SSteven  return 0;
1189cd2d7a5SSteven}
1199cd2d7a5SSteven
1209cd2d7a5SStevenint
1219cd2d7a5SStevenlacp_mux_action_attached (void *p1, void *p2)
1229cd2d7a5SSteven{
12391c51291SZhiyong Yang  vlib_main_t *vm = p1;
12491c51291SZhiyong Yang  slave_if_t *sif = p2;
1259cd2d7a5SSteven
1269cd2d7a5SSteven  lacp_attach_mux_to_aggregator (vm, sif);
1279cd2d7a5SSteven  sif->actor.state &= ~LACP_STATE_COLLECTING;
1289cd2d7a5SSteven  bond_disable_collecting_distributing (vm, sif);
1299cd2d7a5SSteven  sif->actor.state &= ~LACP_STATE_DISTRIBUTING;
1309cd2d7a5SSteven  sif->ntt = 1;
13192e1b83aSElias Rudberg  lacp_start_periodic_timer (vm, sif, 0);
1329cd2d7a5SSteven
1339cd2d7a5SSteven  if ((sif->selected == LACP_PORT_UNSELECTED) ||
1349cd2d7a5SSteven      (sif->selected == LACP_PORT_STANDBY))
1359cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
1369cd2d7a5SSteven			   LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
1379cd2d7a5SSteven
1389cd2d7a5SSteven  if ((sif->selected == LACP_PORT_SELECTED) &&
1399cd2d7a5SSteven      (sif->partner.state & LACP_STATE_SYNCHRONIZATION))
1409cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif, LACP_MUX_EVENT_SYNC,
1419cd2d7a5SSteven			   &sif->mux_state);
1429cd2d7a5SSteven  return 0;
1439cd2d7a5SSteven}
1449cd2d7a5SSteven
1459cd2d7a5SStevenint
1469cd2d7a5SStevenlacp_mux_action_waiting (void *p1, void *p2)
1479cd2d7a5SSteven{
14891c51291SZhiyong Yang  vlib_main_t *vm = p1;
14991c51291SZhiyong Yang  slave_if_t *sif = p2;
1509cd2d7a5SSteven
1519cd2d7a5SSteven  if (!lacp_timer_is_running (sif->wait_while_timer))
15292e1b83aSElias Rudberg    lacp_start_wait_while_timer (vm, sif, LACP_AGGREGATE_WAIT_TIME);
1539cd2d7a5SSteven
1549cd2d7a5SSteven  if ((sif->selected == LACP_PORT_SELECTED) && sif->ready)
1559cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
1569cd2d7a5SSteven			   LACP_MUX_EVENT_READY, &sif->mux_state);
1579cd2d7a5SSteven
1589cd2d7a5SSteven  if (sif->selected == LACP_PORT_UNSELECTED)
1599cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
1609cd2d7a5SSteven			   LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
1619cd2d7a5SSteven
1629cd2d7a5SSteven  return 0;
1639cd2d7a5SSteven}
1649cd2d7a5SSteven
1659cd2d7a5SStevenint
1669cd2d7a5SStevenlacp_mux_action_collecting_distributing (void *p1, void *p2)
1679cd2d7a5SSteven{
16891c51291SZhiyong Yang  vlib_main_t *vm = p1;
16991c51291SZhiyong Yang  slave_if_t *sif = p2;
1709cd2d7a5SSteven
1719cd2d7a5SSteven  sif->actor.state |= LACP_STATE_SYNCHRONIZATION | LACP_STATE_COLLECTING |
1729cd2d7a5SSteven    LACP_STATE_DISTRIBUTING;
1739cd2d7a5SSteven  bond_enable_collecting_distributing (vm, sif);
1749cd2d7a5SSteven  sif->ntt = 1;
17592e1b83aSElias Rudberg  lacp_start_periodic_timer (vm, sif, 0);
1769cd2d7a5SSteven  if ((sif->selected == LACP_PORT_UNSELECTED) ||
1779cd2d7a5SSteven      (sif->selected == LACP_PORT_STANDBY) ||
1789cd2d7a5SSteven      !(sif->partner.state & LACP_STATE_SYNCHRONIZATION))
1799cd2d7a5SSteven    lacp_machine_dispatch (&lacp_mux_machine, vm, sif,
1809cd2d7a5SSteven			   LACP_MUX_EVENT_UNSELECTED, &sif->mux_state);
1819cd2d7a5SSteven
1829cd2d7a5SSteven
1839cd2d7a5SSteven  return 0;
1849cd2d7a5SSteven}
1859cd2d7a5SSteven
1869cd2d7a5SStevenstatic u8 *
1879cd2d7a5SStevenformat_mux_event (u8 * s, va_list * args)
1889cd2d7a5SSteven{
1899cd2d7a5SSteven  static lacp_event_struct lacp_mux_event_array[] = {
1909cd2d7a5SSteven#define _(b, s, n) {.bit = b, .str = #s, },
1919cd2d7a5SSteven    foreach_lacp_mux_event
1929cd2d7a5SSteven#undef _
1939cd2d7a5SSteven    {.str = NULL}
1949cd2d7a5SSteven  };
1959cd2d7a5SSteven  int e = va_arg (*args, int);
19691c51291SZhiyong Yang  lacp_event_struct *event_entry = lacp_mux_event_array;
1979cd2d7a5SSteven
1989cd2d7a5SSteven  if (e >= (sizeof (lacp_mux_event_array) / sizeof (*event_entry)))
1999cd2d7a5SSteven    s = format (s, "Bad event %d", e);
2009cd2d7a5SSteven  else
2019cd2d7a5SSteven    s = format (s, "%s", event_entry[e].str);
2029cd2d7a5SSteven
2039cd2d7a5SSteven  return s;
2049cd2d7a5SSteven}
2059cd2d7a5SSteven
2069cd2d7a5SStevenvoid
2079cd2d7a5SStevenlacp_mux_debug_func (slave_if_t * sif, int event, int state,
2089cd2d7a5SSteven		     lacp_fsm_state_t * transition)
2099cd2d7a5SSteven{
210b98dbb1fSSteven Luong  vlib_worker_thread_t *w = vlib_worker_threads + os_get_thread_index ();
211b98dbb1fSSteven Luong  /* *INDENT-OFF* */
212b98dbb1fSSteven Luong  ELOG_TYPE_DECLARE (e) =
213b98dbb1fSSteven Luong    {
214b98dbb1fSSteven Luong      .format = "%s",
215b98dbb1fSSteven Luong      .format_args = "T4",
216b98dbb1fSSteven Luong    };
217b98dbb1fSSteven Luong  /* *INDENT-ON* */
218b98dbb1fSSteven Luong  struct
219b98dbb1fSSteven Luong  {
220b98dbb1fSSteven Luong    u32 event;
221b98dbb1fSSteven Luong  } *ed = 0;
222b98dbb1fSSteven Luong
223b98dbb1fSSteven Luong  ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e, w->elog_track);
224b98dbb1fSSteven Luong  ed->event =
225b98dbb1fSSteven Luong    elog_string (&vlib_global_main.elog_main, "%U-MUX: %U, %U->%U%c",
226b98dbb1fSSteven Luong		 format_vnet_sw_if_index_name, vnet_get_main (),
227b98dbb1fSSteven Luong		 sif->sw_if_index, format_mux_event, event,
228b98dbb1fSSteven Luong		 format_mux_sm_state, state, format_mux_sm_state,
229b98dbb1fSSteven Luong		 transition->next_state, 0);
2309cd2d7a5SSteven}
2319cd2d7a5SSteven
2329cd2d7a5SStevenvoid
2339cd2d7a5SStevenlacp_init_mux_machine (vlib_main_t * vm, slave_if_t * sif)
2349cd2d7a5SSteven{
2359cd2d7a5SSteven  lacp_machine_dispatch (&lacp_mux_machine, vm, sif, LACP_MUX_EVENT_BEGIN,
2369cd2d7a5SSteven			 &sif->mux_state);
2379cd2d7a5SSteven}
2389cd2d7a5SSteven
2399cd2d7a5SSteven/*
2409cd2d7a5SSteven * fd.io coding-style-patch-verification: ON
2419cd2d7a5SSteven *
2429cd2d7a5SSteven * Local Variables:
2439cd2d7a5SSteven * eval: (c-set-style "gnu")
2449cd2d7a5SSteven * End:
2459cd2d7a5SSteven */
246