node.c revision 977c1dec
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#include <vnet/bonding/node.h>
18#include <vnet/ethernet/packet.h>
19#include <lacp/node.h>
20
21lacp_state_struct lacp_state_array[] = {
22#define _(b, s, n) {.bit = b, .str = #s, },
23  foreach_lacp_state_flag
24#undef _
25  {.str = NULL}
26};
27
28/** \file
29
30    2 x LACP graph nodes: an "interior" node to process
31    incoming announcements, and a "process" node to periodically
32    send announcements.
33
34    The interior node is neither pipelined nor dual-looped, because
35    it would be very unusual to see more than one LACP packet in
36    a given input frame. So, it's a very simple / straighforward
37    example.
38*/
39
40/*
41 * packet counter strings
42 * Dump these counters via the "show error" CLI command
43 */
44static char *lacp_error_strings[] = {
45#define _(sym,string) string,
46  foreach_lacp_error
47#undef _
48};
49
50/*
51 * We actually send all lacp pkts to the "error" node after scanning
52 * them, so the graph node has only one next-index. The "error-drop"
53 * node automatically bumps our per-node packet counters for us.
54 */
55typedef enum
56{
57  LACP_INPUT_NEXT_NORMAL,
58  LACP_INPUT_N_NEXT,
59} lacp_next_t;
60
61/*
62 * Process a frame of lacp packets
63 * Expect 1 packet / frame
64 */
65static uword
66lacp_node_fn (vlib_main_t * vm,
67	      vlib_node_runtime_t * node, vlib_frame_t * frame)
68{
69  u32 n_left_from, *from;
70  lacp_input_trace_t *t0;
71
72  from = vlib_frame_vector_args (frame);	/* array of buffer indices */
73  n_left_from = frame->n_vectors;	/* number of buffer indices */
74
75  while (n_left_from > 0)
76    {
77      u32 bi0;
78      vlib_buffer_t *b0;
79      u32 next0, error0;
80
81      bi0 = from[0];
82      b0 = vlib_get_buffer (vm, bi0);
83
84      next0 = LACP_INPUT_NEXT_NORMAL;
85
86      /* scan this lacp pkt. error0 is the counter index to bump */
87      error0 = lacp_input (vm, b0, bi0);
88      b0->error = node->errors[error0];
89
90      /* If this pkt is traced, snapshoot the data */
91      if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
92	{
93	  int len;
94
95	  t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
96	  len = (b0->current_length < sizeof (t0->pkt))
97	    ? b0->current_length : sizeof (t0->pkt);
98	  t0->len = len;
99	  t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
100	  clib_memcpy_fast (&t0->pkt, vlib_buffer_get_current (b0), len);
101	}
102      /* push this pkt to the next graph node, always error-drop */
103      vlib_set_next_frame_buffer (vm, node, next0, bi0);
104
105      from += 1;
106      n_left_from -= 1;
107    }
108
109  return frame->n_vectors;
110}
111
112/*
113 * lacp input graph node declaration
114 */
115/* *INDENT-OFF* */
116VLIB_REGISTER_NODE (lacp_input_node, static) = {
117  .function = lacp_node_fn,
118  .name = "lacp-input",
119  .vector_size = sizeof (u32),
120  .type = VLIB_NODE_TYPE_INTERNAL,
121
122  .n_errors = LACP_N_ERROR,
123  .error_strings = lacp_error_strings,
124
125  .format_trace = lacp_input_format_trace,
126
127  .n_next_nodes = LACP_INPUT_N_NEXT,
128  .next_nodes = {
129    [LACP_INPUT_NEXT_NORMAL] = "error-drop",
130  },
131};
132/* *INDENT-ON* */
133
134static void
135lacp_elog_start_event (void)
136{
137  lacp_main_t *lm = &lacp_main;
138  /* *INDENT-OFF* */
139  ELOG_TYPE_DECLARE (e) =
140    {
141      .format = "Starting LACP process, interface count = %d",
142      .format_args = "i4",
143    };
144  /* *INDENT-ON* */
145  struct
146  {
147    u32 count;
148  } *ed;
149
150  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
151  ed->count = lm->lacp_int;
152}
153
154static void
155lacp_elog_stop_event (void)
156{
157  lacp_main_t *lm = &lacp_main;
158  /* *INDENT-OFF* */
159  ELOG_TYPE_DECLARE (e) =
160    {
161      .format = "Stopping LACP process, interface count = %d",
162      .format_args = "i4",
163    };
164  /* *INDENT-ON* */
165  struct
166  {
167    u32 count;
168  } *ed;
169
170  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
171  ed->count = lm->lacp_int;
172}
173
174/*
175 * lacp periodic function
176 */
177static uword
178lacp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
179{
180  lacp_main_t *lm = &lacp_main;
181  f64 poll_time_remaining;
182  uword event_type, *event_data = 0;
183
184  ethernet_register_input_type (vm, ETHERNET_TYPE_SLOW_PROTOCOLS /* LACP */ ,
185				lacp_input_node.index);
186
187  poll_time_remaining = 0.2;
188  while (1)
189    {
190      if (lm->lacp_int > 0)
191	poll_time_remaining =
192	  vlib_process_wait_for_event_or_clock (vm, poll_time_remaining);
193      else
194	vlib_process_wait_for_event (vm);
195
196      event_type = vlib_process_get_events (vm, &event_data);
197      switch (event_type)
198	{
199	case ~0:		/* no events => timeout */
200	  break;
201	case LACP_PROCESS_EVENT_START:
202	  poll_time_remaining = 0.2;
203	  lacp_elog_start_event ();
204	  break;
205	case LACP_PROCESS_EVENT_STOP:
206	  if (lm->lacp_int == 0)
207	    {
208	      poll_time_remaining = SECS_IN_A_DAY;
209	      lacp_elog_stop_event ();
210	    }
211	  break;
212	default:
213	  clib_warning ("BUG: event type 0x%wx", event_type);
214	  break;
215	}
216      vec_reset_length (event_data);
217
218      if (vlib_process_suspend_time_is_zero (poll_time_remaining))
219	{
220	  lacp_periodic (vm);
221	  poll_time_remaining = 0.2;
222	}
223    }
224
225  return 0;
226}
227
228void
229lacp_create_periodic_process (void)
230{
231  lacp_main_t *lm = &lacp_main;
232
233  /* Already created the process node? */
234  if (lm->lacp_process_node_index > 0)
235    return;
236
237  /* No, create it now and make a note of the node index */
238  lm->lacp_process_node_index =
239    vlib_process_create (lm->vlib_main, "lacp-process", lacp_process,
240			 16 /* log2_n_stack_bytes */ );
241}
242
243/*
244 * fd.io coding-style-patch-verification: ON
245 *
246 * Local Variables:
247 * eval: (c-set-style "gnu")
248 * End:
249 */
250