FD.io VPP  v18.01.2-1-g9b554f3
Vector Packet Processing
lldp_node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2016 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  * @file
17  * @brief LLDP nodes implementation
18  */
19 #include <vnet/lldp/lldp_node.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vnet/ethernet/packet.h>
22 
23 /* set this to 1 to turn on debug prints via clib_warning() */
24 #define LLDP_DEBUG (0)
25 
27 
28 #define F(sym, string) static char LLDP_ERR_##sym##_STR[] = string;
30 #undef F
31 
32 /*
33  * packet counter strings
34  * Dump these counters via the "show error" CLI command
35  */
36 static char *lldp_error_strings[] = {
37 #define F(sym, string) LLDP_ERR_##sym##_STR,
39 #undef F
40 };
41 
42 /*
43  * We actually send all lldp pkts to the "error" node after scanning
44  * them, so the graph node has only one next-index. The "error-drop"
45  * node automatically bumps our per-node packet counters for us.
46  */
47 typedef enum
48 {
51 } lldp_next_t;
52 
53 /*
54  * Process a frame of lldp packets
55  * Expect 1 packet / frame
56  */
57 static uword
59  vlib_frame_t * frame)
60 {
61  u32 n_left_from, *from;
63 
64  from = vlib_frame_vector_args (frame); /* array of buffer indices */
65  n_left_from = frame->n_vectors; /* number of buffer indices */
66 
67  while (n_left_from > 0)
68  {
69  u32 bi0;
70  vlib_buffer_t *b0;
71  u32 next0, error0;
72 
73  bi0 = from[0];
74  b0 = vlib_get_buffer (vm, bi0);
75 
76  next0 = LLDP_INPUT_NEXT_NORMAL;
77 
78  /* scan this lldp pkt. error0 is the counter index to bump */
79  error0 = lldp_input (vm, b0, bi0);
80  b0->error = node->errors[error0];
81 
82  /* If this pkt is traced, snapshot the data */
83  if (b0->flags & VLIB_BUFFER_IS_TRACED)
84  {
85  int len;
86  t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
87  len = (b0->current_length < sizeof (t0->data)) ? b0->current_length
88  : sizeof (t0->data);
89  t0->len = len;
90  clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
91  }
92  /* push this pkt to the next graph node, always error-drop */
93  vlib_set_next_frame_buffer (vm, node, next0, bi0);
94 
95  from += 1;
96  n_left_from -= 1;
97  }
98 
99  return frame->n_vectors;
100 }
101 
102 /*
103  * lldp input graph node declaration
104  */
105 /* *INDENT-OFF* */
107  .function = lldp_node_fn,
108  .name = "lldp-input",
109  .vector_size = sizeof(u32),
110  .type = VLIB_NODE_TYPE_INTERNAL,
111 
112  .n_errors = LLDP_N_ERROR,
113  .error_strings = lldp_error_strings,
114 
115  .format_trace = lldp_input_format_trace,
116 
117  .n_next_nodes = LLDP_INPUT_N_NEXT,
118  .next_nodes =
119  {
120  [LLDP_INPUT_NEXT_NORMAL] = "error-drop",
121  },
122 };
123 /* *INDENT-ON* */
124 
125 /*
126  * lldp process node function
127  */
128 static uword
130 {
131  lldp_main_t *lm = &lldp_main;
132  f64 timeout = 0;
133  uword event_type, *event_data = 0;
134 
135  /* So we can send events to the lldp process */
137 
138  /* with ethernet input */
139  ethernet_register_input_type (vm, ETHERNET_TYPE_802_1_LLDP /* LLDP */ ,
140  lldp_input_node.index);
141 
142  while (1)
143  {
144  if (vec_len (lm->intfs_timeouts))
145  {
146 #if LLDP_DEBUG
147  clib_warning ("DEBUG: wait for event with timeout %f", timeout);
148 #endif
149  (void) vlib_process_wait_for_event_or_clock (vm, timeout);
150  }
151  else
152  {
153 #if LLDP_DEBUG
154  clib_warning ("DEBUG: wait for event without timeout");
155 #endif
156  (void) vlib_process_wait_for_event (vm);
157  }
158  event_type = vlib_process_get_events (vm, &event_data);
159  switch (event_type)
160  {
161  case ~0: /* no events => timeout */
162  /* nothing to do here */
163  break;
165  /* nothing to do here - reschedule is done automatically after
166  * each event or timeout */
167  break;
168  default:
169  clib_warning ("BUG: event type 0x%wx", event_type);
170  break;
171  }
172  if (!vec_len (lm->intfs_timeouts))
173  {
174  continue;
175  }
176  /* send packet(s) and schedule another timeut */
177  const f64 now = vlib_time_now (lm->vlib_main);
178  while (1)
179  {
181  lm->intfs_timeouts
182  [lm->intfs_timeouts_idx]);
183  if (n->last_sent < 0.01 || now > n->last_sent + lm->msg_tx_interval)
184  {
185 #if LLDP_DEBUG
186  clib_warning ("send packet to lldp %p, if idx %d", n,
187  n->hw_if_index);
188 #endif
189  lldp_send_ethernet (lm, n, 0);
190  ++lm->intfs_timeouts_idx;
191  if (lm->intfs_timeouts_idx >= vec_len (lm->intfs_timeouts))
192  {
193  lm->intfs_timeouts_idx = 0;
194  }
195  continue;
196  }
197  else
198  {
199  timeout = n->last_sent + lm->msg_tx_interval - now;
200  break;
201  }
202  }
203 #if LLDP_DEBUG
204  clib_warning ("DEBUG: timeout set to %f", timeout);
205  u8 *s = NULL;
206  u32 i;
208  {
209  if (i == lm->intfs_timeouts_idx)
210  {
211  s = format (s, " [%d]", lm->intfs_timeouts[i]);
212  }
213  else
214  {
215  s = format (s, " %d", lm->intfs_timeouts[i]);
216  }
217  }
218  clib_warning ("DEBUG: timeout schedule: %s", s);
219  vec_free (s);
220 #endif
221  if (event_data)
222  {
223  _vec_len (event_data) = 0;
224  }
225  }
226 
227  return 0;
228 }
229 
230 /*
231  * lldp process node declaration
232  */
233 /* *INDENT-OFF* */
235  .function = lldp_process,
236  .type = VLIB_NODE_TYPE_PROCESS,
237  .name = "lldp-process",
238 };
239 /* *INDENT-ON* */
240 
241 void
243 {
244  const int idx = n - lm->intfs;
245  u32 v;
247  {
248  if (lm->intfs_timeouts[v] == idx)
249  {
250  /* already scheduled */
251  return;
252  }
253  }
254  n->last_sent = 0; /* ensure that a packet is sent out immediately */
255  /* put the interface at the current position in the timeouts - it
256  * will timeout immediately */
258  lm->intfs_timeouts[lm->intfs_timeouts_idx] = n - lm->intfs;
261 #if LLDP_DEBUG
262  clib_warning ("DEBUG: schedule interface %p, if idx %d", n, n->hw_if_index);
263 #endif
264 }
265 
266 void
268 {
269  if (!n)
270  {
271  return;
272  }
273 #if LLDP_DEBUG
274  clib_warning ("DEBUG: unschedule interface %p, if idx %d", n,
275  n->hw_if_index);
276 #endif
277  const int idx = n - lm->intfs;
278  u32 v;
279  /* remove intf index from timeouts vector */
281  {
282  if (lm->intfs_timeouts[v] == idx)
283  {
284  vec_delete (lm->intfs_timeouts, 1, v);
285  break;
286  }
287  }
288  /* wrap current timeout index to first element if needed */
289  if (lm->intfs_timeouts_idx >= vec_len (lm->intfs_timeouts))
290  {
291  lm->intfs_timeouts_idx = 0;
292  }
295 }
296 
297 static clib_error_t *
299 {
300  lldp_main_t *lm = &lldp_main;
301  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
302  lldp_intf_t *n = lldp_get_intf (lm, hi->hw_if_index);
303  if (n)
304  {
305  if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
306  {
307  /* FIXME - the packet sent here isn't send properly - need to find a
308  * way to send the packet before interface goes down */
309  lldp_send_ethernet (lm, n, 1);
310  lldp_unschedule_intf (lm, n);
311  }
312  }
313  return 0;
314 }
315 
317 
318 static clib_error_t *
320 {
321  lldp_main_t *lm = &lldp_main;
322  lldp_intf_t *n = lldp_get_intf (lm, hw_if_index);
323  if (n)
324  {
325  if (flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
326  {
327  lldp_schedule_intf (lm, n);
328  }
329  }
330  return 0;
331 }
332 
334 
335 /*
336  * fd.io coding-style-patch-verification: ON
337  *
338  * Local Variables:
339  * eval: (c-set-style "gnu")
340  * End:
341  */
lldp_main_t lldp_main
Definition: lldp_input.c:117
vmrglw vmrglh hi
u32 hw_if_index
Definition: lldp_node.h:33
#define vec_foreach_index(var, v)
Iterate over vector indices.
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define F(sym, string)
Definition: lldp_node.c:28
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:699
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:619
u32 intfs_timeouts_idx
Definition: lldp_node.h:74
static void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:397
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define NULL
Definition: clib.h:55
lldp_intf_t * intfs
Definition: lldp_node.h:62
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:224
static clib_error_t * lldp_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: lldp_node.c:298
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(lldp_sw_interface_up_down)
void lldp_schedule_intf(lldp_main_t *lm, lldp_intf_t *n)
Definition: lldp_node.c:242
static clib_error_t * lldp_hw_interface_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: lldp_node.c:319
struct _vlib_node_registration vlib_node_registration_t
f64 last_sent
Definition: lldp_node.h:37
lldp_intf_t * lldp_get_intf(lldp_main_t *lm, u32 hw_if_index)
Definition: lldp_input.c:212
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u32 * intfs_timeouts
Definition: lldp_node.h:71
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:394
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(lldp_hw_interface_up_down)
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:415
void lldp_send_ethernet(lldp_main_t *lm, lldp_intf_t *n, int shutdown)
Definition: lldp_output.c:199
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:542
u8 * lldp_input_format_trace(u8 *s, va_list *args)
Definition: lldp_cli.c:696
static vlib_node_registration_t lldp_input_node
(constructor) VLIB_REGISTER_NODE (lldp_input_node)
Definition: lldp_node.c:106
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:459
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:682
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:72
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:950
u16 msg_tx_interval
Definition: lldp_node.h:102
#define v
Definition: acl.c:341
static vlib_node_registration_t lldp_process_node
(constructor) VLIB_REGISTER_NODE (lldp_process_node)
Definition: lldp_node.c:26
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:195
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:283
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
foreach_lldp_error(F)
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
#define clib_memcpy(a, b, c)
Definition: string.h:75
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:576
lldp_error_t lldp_input(vlib_main_t *vm, vlib_buffer_t *b0, u32 bi0)
Definition: lldp_input.c:249
unsigned int u32
Definition: types.h:88
static uword lldp_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: lldp_node.c:58
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:781
u32 lldp_process_node_index
Definition: lldp_node.h:68
static uword lldp_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: lldp_node.c:129
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1355
u64 uword
Definition: types.h:112
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
vlib_main_t * vlib_main
Definition: lldp_node.h:80
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
static char * lldp_error_strings[]
Definition: lldp_node.c:36
void lldp_unschedule_intf(lldp_main_t *lm, lldp_intf_t *n)
Definition: lldp_node.c:267
LLDP global declarations.
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
lldp_next_t
Definition: lldp_node.c:47
u32 flags
Definition: vhost-user.h:77
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:75
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57