/* * Copyright (c) 2017 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include /* * LACP State = INITIALIZE */ static lacp_fsm_state_t lacp_rx_state_initialize[] = { {LACP_ACTION_INITIALIZE, LACP_RX_STATE_PORT_DISABLED}, // event 0 BEGIN {LACP_ACTION_INITIALIZE, LACP_RX_STATE_PORT_DISABLED}, // event 1 PORT_DISABLED {LACP_ACTION_INITIALIZE, LACP_RX_STATE_PORT_DISABLED}, // event 2 PORT_MOVED {LACP_NOACTION, LACP_RX_STATE_INITIALIZE}, // event 3 LACP_ENABLED {LACP_NOACTION, LACP_RX_STATE_INITIALIZE}, // event 4 LACP_DISABLED {LACP_NOACTION, LACP_RX_STATE_INITIALIZE}, // event 5 PDU_RECEIVED {LACP_NOACTION, LACP_RX_STATE_INITIALIZE}, // event 6 TIMER_EXPIRED }; /* * LACP State = PORT_DISABLED */ static lacp_fsm_state_t lacp_rx_state_port_disabled[] = { {LACP_ACTION_PORT_DISABLED, LACP_RX_STATE_PORT_DISABLED}, // event 0 BEGIN {LACP_ACTION_PORT_DISABLED, LACP_RX_STATE_PORT_DISABLED}, // event 1 PORT_DISABLED {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE}, // event 2 PORT_MOVED {LACP_ACTION_EXPIRED, LACP_RX_STATE_EXPIRED}, // event 3 LACP_ENABLED {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED}, // event 4 LACP_DISABLED {LACP_NOACTION, LACP_RX_STATE_PORT_DISABLED}, // event 5 PDU_RECEIVED {LACP_NOACTION, LACP_RX_STATE_PORT_DISABLED}, // event 6 TIMER_EXPIRED }; /* * LACP State = EXPIRED */ static lacp_fsm_state_t lacp_rx_state_expired[] = { {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE}, // event 0 BEGIN {LACP_NOACTION, LACP_RX_STATE_EXPIRED}, // event 1 PORT_DISABLED {LACP_NOACTION, LACP_RX_STATE_EXPIRED}, // event 2 PORT_MOVED {LACP_NOACTION, LACP_RX_STATE_EXPIRED}, // event 3 LACP_ENABLED {LACP_NOACTION, LACP_RX_STATE_EXPIRED}, // event 4 LACP_DISABLED {LACP_ACTION_CURRENT, LACP_RX_STATE_CURRENT}, // event 5 PDU_RECEIVED {LACP_ACTION_DEFAULTED, LACP_RX_STATE_DEFAULTED}, // event 6 TIMER_EXPIRED }; /* * LACP State = LACP_DISABLED */ static lacp_fsm_state_t lacp_rx_state_lacp_disabled[] = { {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE}, // event 0 BEGIN {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 1 PORT_DISABLED {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 2 PORT_MOVED {LACP_ACTION_EXPIRED, LACP_RX_STATE_EXPIRED}, // event 3 LACP_ENABLED XXX {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED}, // event 4 LACP_DISABLED {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 5 PDU_RECEIVED {LACP_NOACTION, LACP_RX_STATE_LACP_DISABLED}, // event 6 TIMER_EXPIRED }; /* * LACP State = DEFAULTED */ static lacp_fsm_state_t lacp_rx_state_defaulted[] = { {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE}, // event 0 BEGIN {LACP_NOACTION, LACP_RX_STATE_DEFAULTED}, // event 1 PORT_DISABLED {LACP_NOACTION, LACP_RX_STATE_DEFAULTED}, // event 2 PORT_MOVED {LACP_NOACTION, LACP_RX_STATE_DEFAULTED}, // event 3 LACP_ENABLED {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED}, // event 4 LACP_DISABLED {LACP_ACTION_CURRENT, LACP_RX_STATE_CURRENT}, // event 5 PDU_RECEIVED {LACP_ACTION_DEFAULTED, LACP_RX_STATE_DEFAULTED}, // event 6 TIMER_EXPIRED }; /* * LACP State = CURRENT */ static lacp_fsm_state_t lacp_rx_state_current[] = { {LACP_ACTION_INITIALIZE, LACP_RX_STATE_INITIALIZE}, // event 0 BEGIN {LACP_NOACTION, LACP_RX_STATE_CURRENT}, // event 1 PORT_DISABLED {LACP_NOACTION, LACP_RX_STATE_CURRENT}, // event 1 PORT_MOVED {LACP_NOACTION, LACP_RX_STATE_CURRENT}, // event 2 LACP_ENABLED {LACP_ACTION_LACP_DISABLED, LACP_RX_STATE_LACP_DISABLED}, // event 3 LACP_DISABLED {LACP_ACTION_CURRENT, LACP_RX_STATE_CURRENT}, // event 4 PDU_RECEIVED {LACP_ACTION_EXPIRED, LACP_RX_STATE_EXPIRED}, // event 5 TIMER_EXPIRED }; static lacp_fsm_machine_t lacp_rx_fsm_table[] = { {lacp_rx_state_initialize}, {lacp_rx_state_port_disabled}, {lacp_rx_state_expired}, {lacp_rx_state_lacp_disabled}, {lacp_rx_state_defaulted}, {lacp_rx_state_current}, }; lacp_machine_t lacp_rx_machine = { lacp_rx_fsm_table, lacp_rx_debug_func, }; static void lacp_set_port_unselected (vlib_main_t * vm, member_if_t * mif) { mif->selected = LACP_PORT_UNSELECTED; switch (mif->mux_state) { case LACP_MUX_STATE_DETACHED: break; case LACP_MUX_STATE_WAITING: break; case LACP_MUX_STATE_ATTACHED: return; break; case LACP_MUX_STATE_COLLECTING_DISTRIBUTING: if (mif->partner.state & LACP_STATE_SYNCHRONIZATION) return; break; default: break; } lacp_machine_dispatch (&lacp_mux_machine, vm, mif, LACP_MUX_EVENT_UNSELECTED, &mif->mux_state); } static void lacp_update_default_selected (vlib_main_t * vm, member_if_t * mif) { if ((mif->partner_admin.state & LACP_STATE_AGGREGATION) != (mif->partner.state & LACP_STATE_AGGREGATION) || memcmp (&mif->partner, &mif->partner_admin, sizeof (mif->partner) - sizeof (mif->partner.state))) { lacp_set_port_unselected (vm, mif); } } static void lacp_record_default (member_if_t * mif) { mif->partner = mif->partner_admin; mif->actor.state |= LACP_STATE_DEFAULTED; } static void lacp_update_selected (vlib_main_t * vm, member_if_t * mif) { lacp_pdu_t *lacpdu = (lacp_pdu_t *) mif->last_rx_pkt; if ((lacpdu->actor.port_info.state & LACP_STATE_AGGREGATION) != (mif->partner.state & LACP_STATE_AGGREGATION) || memcmp (&mif->partner, &lacpdu->actor.port_info, sizeof (mif->partner) - sizeof (mif->partner.state))) { lacp_set_port_unselected (vm, mif); } } static void lacp_update_ntt (vlib_main_t * vm, member_if_t * mif) { lacp_pdu_t *lacpdu = (lacp_pdu_t *) mif->last_rx_pkt; u8 states = LACP_STATE_LACP_ACTIVITY | LACP_STATE_LACP_TIMEOUT | LACP_STATE_S