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#define _GNU_SOURCE
17
18#include <vnet/bonding/node.h>
19#include <lacp/node.h>
20
21/*
22 *  LACP State = TRANSMIT
23 */
24static lacp_fsm_state_t lacp_tx_state_transmit[] = {
25  {LACP_ACTION_TRANSMIT, LACP_TX_STATE_TRANSMIT},	// event 0 BEGIN
26  {LACP_ACTION_TRANSMIT, LACP_TX_STATE_TRANSMIT},	// event 1 NTT
27};
28
29static lacp_fsm_machine_t lacp_tx_fsm_table[] = {
30  {lacp_tx_state_transmit},
31};
32
33lacp_machine_t lacp_tx_machine = {
34  lacp_tx_fsm_table,
35  lacp_tx_debug_func,
36};
37
38int
39lacp_tx_action_transmit (void *p1, void *p2)
40{
41  vlib_main_t *vm = p1;
42  slave_if_t *sif = p2;
43  f64 now = vlib_time_now (vm);
44
45  if (!lacp_timer_is_running (sif->periodic_timer))
46    return 0;
47
48  // No more than 3 LACPDUs per fast interval
49  if (now <= (sif->last_lacpdu_sent_time + 0.333))
50    return 0;
51
52  if (sif->ntt)
53    {
54      lacp_send_lacp_pdu (vm, sif);
55      lacp_schedule_periodic_timer (vm, sif);
56    }
57  sif->ntt = 0;
58
59  return 0;
60}
61
62static u8 *
63format_tx_event (u8 * s, va_list * args)
64{
65  static lacp_event_struct lacp_tx_event_array[] = {
66#define _(b, s, n) {.bit = b, .str = #s, },
67    foreach_lacp_tx_event
68#undef _
69    {.str = NULL}
70  };
71  int e = va_arg (*args, int);
72  lacp_event_struct *event_entry = lacp_tx_event_array;
73
74  if (e >= (sizeof (lacp_tx_event_array) / sizeof (*event_entry)))
75    s = format (s, "Bad event %d", e);
76  else
77    s = format (s, "%s", event_entry[e].str);
78
79  return s;
80}
81
82void
83lacp_tx_debug_func (slave_if_t * sif, int event, int state,
84		    lacp_fsm_state_t * transition)
85{
86  vlib_worker_thread_t *w = vlib_worker_threads + os_get_thread_index ();
87  /* *INDENT-OFF* */
88  ELOG_TYPE_DECLARE (e) =
89    {
90      .format = "%s",
91      .format_args = "T4",
92    };
93  /* *INDENT-ON* */
94  struct
95  {
96    u32 event;
97  } *ed = 0;
98
99  ed = ELOG_TRACK_DATA (&vlib_global_main.elog_main, e, w->elog_track);
100  ed->event = elog_string (&vlib_global_main.elog_main, "%U-TX: %U, %U->%U%c",
101			   format_vnet_sw_if_index_name, vnet_get_main (),
102			   sif->sw_if_index, format_tx_event, event,
103			   format_tx_sm_state, state, format_tx_sm_state,
104			   transition->next_state, 0);
105}
106
107void
108lacp_init_tx_machine (vlib_main_t * vm, slave_if_t * sif)
109{
110  lacp_machine_dispatch (&lacp_tx_machine, vm, sif, LACP_TX_EVENT_BEGIN,
111			 &sif->tx_state);
112}
113
114/*
115 * fd.io coding-style-patch-verification: ON
116 *
117 * Local Variables:
118 * eval: (c-set-style "gnu")
119 * End:
120 */
121