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 <vnet/bonding/node.h>
199cd2d7a5SSteven#include <lacp/node.h>
209cd2d7a5SSteven
219cd2d7a5SSteven/*
229cd2d7a5SSteven *  LACP State = TRANSMIT
239cd2d7a5SSteven */
249cd2d7a5SStevenstatic lacp_fsm_state_t lacp_tx_state_transmit[] = {
259cd2d7a5SSteven  {LACP_ACTION_TRANSMIT, LACP_TX_STATE_TRANSMIT},	// event 0 BEGIN
269cd2d7a5SSteven  {LACP_ACTION_TRANSMIT, LACP_TX_STATE_TRANSMIT},	// event 1 NTT
279cd2d7a5SSteven};
289cd2d7a5SSteven
299cd2d7a5SStevenstatic lacp_fsm_machine_t lacp_tx_fsm_table[] = {
309cd2d7a5SSteven  {lacp_tx_state_transmit},
319cd2d7a5SSteven};
329cd2d7a5SSteven
339cd2d7a5SStevenlacp_machine_t lacp_tx_machine = {
349cd2d7a5SSteven  lacp_tx_fsm_table,
359cd2d7a5SSteven  lacp_tx_debug_func,
369cd2d7a5SSteven};
379cd2d7a5SSteven
389cd2d7a5SStevenint
399cd2d7a5SStevenlacp_tx_action_transmit (void *p1, void *p2)
409cd2d7a5SSteven{
4191c51291SZhiyong Yang  vlib_main_t *vm = p1;
4291c51291SZhiyong Yang  slave_if_t *sif = p2;
4392e1b83aSElias Rudberg  f64 now = vlib_time_now (vm);
449cd2d7a5SSteven
459cd2d7a5SSteven  if (!lacp_timer_is_running (sif->periodic_timer))
469cd2d7a5SSteven    return 0;
479cd2d7a5SSteven
489cd2d7a5SSteven  // No more than 3 LACPDUs per fast interval
4982c5dda4SSteven Luong  if (now <= (sif->last_lacpdu_sent_time + 0.333))
509cd2d7a5SSteven    return 0;
519cd2d7a5SSteven
529cd2d7a5SSteven  if (sif->ntt)
539cd2d7a5SSteven    {
549cd2d7a5SSteven      lacp_send_lacp_pdu (vm, sif);
5592e1b83aSElias Rudberg      lacp_schedule_periodic_timer (vm, sif);
569cd2d7a5SSteven    }
579cd2d7a5SSteven  sif->ntt = 0;
589cd2d7a5SSteven
599cd2d7a5SSteven  return 0;
609cd2d7a5SSteven}
619cd2d7a5SSteven
629cd2d7a5SStevenstatic u8 *
639cd2d7a5SStevenformat_tx_event (u8 * s, va_list * args)
649cd2d7a5SSteven{
659cd2d7a5SSteven  static lacp_event_struct lacp_tx_event_array[] = {
669cd2d7a5SSteven#define _(b, s, n) {.bit = b, .str = #s, },
679cd2d7a5SSteven    foreach_lacp_tx_event
689cd2d7a5SSteven#undef _
699cd2d7a5SSteven    {.str = NULL}
709cd2d7a5SSteven  };
719cd2d7a5SSteven  int e = va_arg (*args, int);
7291c51291SZhiyong Yang  lacp_event_struct *event_entry = lacp_tx_event_array;
739cd2d7a5SSteven
749cd2d7a5SSteven  if (e >= (sizeof (lacp_tx_event_array) / sizeof (*event_entry)))
759cd2d7a5SSteven    s = format (s, "Bad event %d", e);
769cd2d7a5SSteven  else
779cd2d7a5SSteven    s = format (s, "%s", event_entry[e].str);
789cd2d7a5SSteven
799cd2d7a5SSteven  return s;
809cd2d7a5SSteven}
819cd2d7a5SSteven
829cd2d7a5SStevenvoid
839cd2d7a5SStevenlacp_tx_debug_func (slave_if_t * sif, int event, int state,
849cd2d7a5SSteven		    lacp_fsm_state_t * transition)
859cd2d7a5SSteven{
86b98dbb1fSSteven Luong  vlib_worker_thread_t *w = vlib_worker_threads + os_get_thread_index ();
87b98dbb1fSSteven Luong  /* *INDENT-OFF* */
88b98dbb1fSSteven Luong  ELOG_TYPE_DECLARE (e) =
89b98dbb1fSSteven Luong    {
90b98dbb1fSSteven Luong      .format = "%s",
91b98dbb1fSSteven Luong      .format_args = "T4",
92b98dbb1fSSteven Luong    };
93b98dbb1fSSteven Luong  /* *INDENT-ON* */
94b98dbb1fSSteven Luong  struct
95b98dbb1fSSteven Luong  {
96b98dbb1fSSteven Luong    u32 event;
97b98dbb1fSSteven Luong  } *ed = 0;
98b98dbb1fSSteven Luong
99b98dbb1fSSteven Luong  ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e, w->elog_track);
100b98dbb1fSSteven Luong  ed->event = elog_string (&vlib_global_main.elog_main, "%U-TX: %U, %U->%U%c",
101b98dbb1fSSteven Luong			   format_vnet_sw_if_index_name, vnet_get_main (),
102b98dbb1fSSteven Luong			   sif->sw_if_index, format_tx_event, event,
103b98dbb1fSSteven Luong			   format_tx_sm_state, state, format_tx_sm_state,
104b98dbb1fSSteven Luong			   transition->next_state, 0);
1059cd2d7a5SSteven}
1069cd2d7a5SSteven
1079cd2d7a5SStevenvoid
1089cd2d7a5SStevenlacp_init_tx_machine (vlib_main_t * vm, slave_if_t * sif)
1099cd2d7a5SSteven{
1109cd2d7a5SSteven  lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_BEGIN,
1119cd2d7a5SSteven			 &sif->tx_state);
1129cd2d7a5SSteven}
1139cd2d7a5SSteven
1149cd2d7a5SSteven/*
1159cd2d7a5SSteven * fd.io coding-style-patch-verification: ON
1169cd2d7a5SSteven *
1179cd2d7a5SSteven * Local Variables:
1189cd2d7a5SSteven * eval: (c-set-style "gnu")
1199cd2d7a5SSteven * End:
1209cd2d7a5SSteven */
121