FD.io VPP  v16.06
Vector Packet Processing
udp_local.c
Go to the documentation of this file.
1 /*
2  * node.c: udp packet processing
3  *
4  * Copyright (c) 2013 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/ip/udp.h>
21 #include <vnet/ip/udp_packet.h>
22 #include <vppinfra/sparse_vec.h>
23 
25 
26 #define foreach_udp_input_next \
27  _ (PUNT, "error-punt") \
28  _ (DROP, "error-drop")
29 
30 typedef enum {
31 #define _(s,n) UDP_INPUT_NEXT_##s,
33 #undef _
36 
37 typedef struct {
41 
42 u8 * format_udp_rx_trace (u8 * s, va_list * args)
43 {
44  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
45  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
46  udp_rx_trace_t * t = va_arg (*args, udp_rx_trace_t *);
47 
48  s = format (s, "UDP: src-port %d dst-port %d",
49  clib_net_to_host_u16(t->src_port),
50  clib_net_to_host_u16(t->dst_port));
51  return s;
52 }
53 
54 typedef struct {
55  /* Sparse vector mapping udp dst_port in network byte order
56  to next index. */
58 
61 
64 
67  vlib_node_runtime_t * node,
68  vlib_frame_t * from_frame,
69  int is_ip4)
70 {
71  udp_input_runtime_t * rt = is_ip4 ?
72  (void *) vlib_node_get_runtime_data (vm, udp4_input_node.index)
73  : (void *) vlib_node_get_runtime_data (vm, udp6_input_node.index);
74  __attribute__((unused)) u32 n_left_from, next_index, i_next, * from, * to_next;
75 
76  from = vlib_frame_vector_args (from_frame);
77  n_left_from = from_frame->n_vectors;
78 
79  next_index = node->cached_next_index;
80  i_next = vec_elt (rt->sparse_index_by_next_index, next_index);
81 
82  while (n_left_from > 0)
83  {
84  u32 n_left_to_next;
85 
86  vlib_get_next_frame (vm, node, next_index,
87  to_next, n_left_to_next);
88 
89  while (n_left_from >= 4 && n_left_to_next >= 2)
90  {
91  u32 bi0, bi1;
92  vlib_buffer_t * b0, * b1;
93  udp_header_t * h0 = 0, * h1 = 0;
94  u32 i0, i1, dst_port0, dst_port1;
95  u32 advance0, advance1;
96  u32 error0, next0, error1, next1;
97 
98  /* Prefetch next iteration. */
99  {
100  vlib_buffer_t * p2, * p3;
101 
102  p2 = vlib_get_buffer (vm, from[2]);
103  p3 = vlib_get_buffer (vm, from[3]);
104 
105  vlib_prefetch_buffer_header (p2, LOAD);
106  vlib_prefetch_buffer_header (p3, LOAD);
107 
108  CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
109  CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
110  }
111 
112  bi0 = from[0];
113  bi1 = from[1];
114  to_next[0] = bi0;
115  to_next[1] = bi1;
116  from += 2;
117  to_next += 2;
118  n_left_to_next -= 2;
119  n_left_from -= 2;
120 
121  b0 = vlib_get_buffer (vm, bi0);
122  b1 = vlib_get_buffer (vm, bi1);
123 
124  /* ip4/6_local hands us the ip header, not the udp header */
125  if (is_ip4)
126  {
127  advance0 = sizeof(ip4_header_t);
128  advance1 = sizeof(ip4_header_t);
129  }
130  else
131  {
132  advance0 = sizeof(ip6_header_t);
133  advance1 = sizeof(ip6_header_t);
134  }
135 
136  if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (*h0)))
137  {
138  error0 = UDP_ERROR_LENGTH_ERROR;
139  next0 = UDP_INPUT_NEXT_DROP;
140  }
141  else
142  {
143  vlib_buffer_advance (b0, advance0);
144  h0 = vlib_buffer_get_current (b0);
145  error0 = next0 = 0;
146  if (PREDICT_FALSE(clib_net_to_host_u16(h0->length) >
148  {
149  error0 = UDP_ERROR_LENGTH_ERROR;
150  next0 = UDP_INPUT_NEXT_DROP;
151  }
152  }
153 
154  if (PREDICT_FALSE(b1->current_length < advance1 + sizeof (*h1)))
155  {
156  error1 = UDP_ERROR_LENGTH_ERROR;
157  next1 = UDP_INPUT_NEXT_DROP;
158  }
159  else
160  {
161  vlib_buffer_advance (b1, advance1);
162  h1 = vlib_buffer_get_current (b1);
163  error1 = next1 = 0;
164  if (PREDICT_FALSE(clib_net_to_host_u16(h1->length) >
166  {
167  error1 = UDP_ERROR_LENGTH_ERROR;
168  next1 = UDP_INPUT_NEXT_DROP;
169  }
170  }
171 
172  /* Index sparse array with network byte order. */
173  dst_port0 = (error0 == 0) ? h0->dst_port : 0;
174  dst_port1 = (error1 == 0) ? h1->dst_port : 0;
175  sparse_vec_index2 (rt->next_by_dst_port, dst_port0, dst_port1,
176  &i0, &i1);
177  next0 = (error0 == 0) ? vec_elt(rt->next_by_dst_port, i0) : next0;
178  next1 = (error1 == 0) ? vec_elt(rt->next_by_dst_port, i1) : next1;
179 
180  b0->error = node->errors[next0 == SPARSE_VEC_INVALID_INDEX ?
181  UDP_ERROR_NO_LISTENER : error0];
182  b1->error = node->errors[next1 == SPARSE_VEC_INVALID_INDEX ?
183  UDP_ERROR_NO_LISTENER : error1];
184 
186  {
187  udp_rx_trace_t *tr = vlib_add_trace (vm, node,
188  b0, sizeof (*tr));
189  if (b0->error != node->errors[UDP_ERROR_LENGTH_ERROR])
190  {
191  tr->src_port = h0->src_port;
192  tr->dst_port = h0->dst_port;
193  }
194  }
196  {
197  udp_rx_trace_t *tr = vlib_add_trace (vm, node,
198  b1, sizeof (*tr));
199  if (b1->error != node->errors[UDP_ERROR_LENGTH_ERROR])
200  {
201  tr->src_port = h1->src_port;
202  tr->dst_port = h1->dst_port;
203  }
204  }
205 
206  vlib_buffer_advance (b0, sizeof (*h0));
207  vlib_buffer_advance (b1, sizeof (*h1));
208 
209  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
210  to_next, n_left_to_next,
211  bi0, bi1, next0, next1);
212  }
213 
214  while (n_left_from > 0 && n_left_to_next > 0)
215  {
216  u32 bi0;
217  vlib_buffer_t * b0;
218  udp_header_t * h0 = 0;
219  u32 i0, next0;
220  u32 advance0;
221 
222  bi0 = from[0];
223  to_next[0] = bi0;
224  from += 1;
225  to_next += 1;
226  n_left_from -= 1;
227  n_left_to_next -= 1;
228 
229  b0 = vlib_get_buffer (vm, bi0);
230 
231  /* ip4/6_local hands us the ip header, not the udp header */
232  if (is_ip4)
233  advance0 = sizeof(ip4_header_t);
234  else
235  advance0 = sizeof(ip6_header_t);
236 
237  if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (*h0)))
238  {
239  b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
240  next0 = UDP_INPUT_NEXT_DROP;
241  goto trace_x1;
242  }
243 
244  vlib_buffer_advance (b0, advance0);
245 
246  h0 = vlib_buffer_get_current (b0);
247 
248  if (PREDICT_TRUE(clib_net_to_host_u16(h0->length) <=
250  {
252  next0 = vec_elt(rt->next_by_dst_port, i0);
253 
254  b0->error = node->errors [next0 == SPARSE_VEC_INVALID_INDEX ? UDP_ERROR_NO_LISTENER : UDP_ERROR_NONE];
255  }
256  else
257  {
258  b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
259  next0 = UDP_INPUT_NEXT_DROP;
260  }
261 
262  trace_x1:
264  {
265  udp_rx_trace_t *tr = vlib_add_trace (vm, node,
266  b0, sizeof (*tr));
267  if (b0->error != node->errors[UDP_ERROR_LENGTH_ERROR])
268  {
269  tr->src_port = h0->src_port;
270  tr->dst_port = h0->dst_port;
271  }
272  }
273  vlib_buffer_advance (b0, sizeof (*h0));
274  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
275  to_next, n_left_to_next,
276  bi0, next0);
277  }
278 
279  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
280  }
281  return from_frame->n_vectors;
282 }
283 
284 static char * udp_error_strings[] = {
285 #define udp_error(n,s) s,
286 #include "udp_error.def"
287 #undef udp_error
288 };
289 
290 static uword
292  vlib_node_runtime_t * node,
293  vlib_frame_t * from_frame)
294 {
295  return udp46_input_inline (vm, node, from_frame, 1 /* is_ip4 */);
296 }
297 
298 static uword
300  vlib_node_runtime_t * node,
301  vlib_frame_t * from_frame)
302 {
303  return udp46_input_inline (vm, node, from_frame, 0 /* is_ip4 */);
304 }
305 
306 
308  .function = udp4_input,
309  .name = "ip4-udp-lookup",
310  /* Takes a vector of packets. */
311  .vector_size = sizeof (u32),
312 
313  .runtime_data_bytes = sizeof (udp_input_runtime_t),
314 
315  .n_errors = UDP_N_ERROR,
316  .error_strings = udp_error_strings,
317 
318  .n_next_nodes = UDP_INPUT_N_NEXT,
319  .next_nodes = {
320 #define _(s,n) [UDP_INPUT_NEXT_##s] = n,
322 #undef _
323  },
324 
325  .format_buffer = format_udp_header,
326  .format_trace = format_udp_rx_trace,
327  .unformat_buffer = unformat_udp_header,
328 };
329 
331  .function = udp6_input,
332  .name = "ip6-udp-lookup",
333  /* Takes a vector of packets. */
334  .vector_size = sizeof (u32),
335 
336  .runtime_data_bytes = sizeof (udp_input_runtime_t),
337 
338  .n_errors = UDP_N_ERROR,
339  .error_strings = udp_error_strings,
340 
341  .n_next_nodes = UDP_INPUT_N_NEXT,
342  .next_nodes = {
343 #define _(s,n) [UDP_INPUT_NEXT_##s] = n,
345 #undef _
346  },
347 
348  .format_buffer = format_udp_header,
349  .format_trace = format_udp_rx_trace,
350  .unformat_buffer = unformat_udp_header,
351 };
352 
353 static void add_dst_port (udp_main_t * um,
354  udp_dst_port_t dst_port,
355  char * dst_port_name, u8 is_ip4)
356 {
357  udp_dst_port_info_t * pi;
358  u32 i;
359 
360  vec_add2 (um->dst_port_infos[is_ip4], pi, 1);
361  i = pi - um->dst_port_infos[is_ip4];
362 
363  pi->name = dst_port_name;
364  pi->dst_port = dst_port;
365  pi->next_index = pi->node_index = ~0;
366 
367  hash_set (um->dst_port_info_by_dst_port[is_ip4], dst_port, i);
368 
369  if (pi->name)
370  hash_set_mem (um->dst_port_info_by_name[is_ip4], pi->name, i);
371 }
372 
373 void
375  udp_dst_port_t dst_port,
376  u32 node_index, u8 is_ip4)
377 {
378  udp_main_t * um = &udp_main;
379  udp_dst_port_info_t * pi;
380  udp_input_runtime_t * rt;
381  u16 * n;
382  u32 i;
383 
384  {
386  if (error)
387  clib_error_report (error);
388  }
389 
390  pi = udp_get_dst_port_info (um, dst_port, is_ip4);
391  if (! pi)
392  {
393  add_dst_port (um, dst_port, 0, is_ip4);
394  pi = udp_get_dst_port_info (um, dst_port, is_ip4);
395  ASSERT (pi);
396  }
397 
398  pi->node_index = node_index;
399  pi->next_index = vlib_node_add_next (vm,
400  is_ip4 ? udp4_input_node.index
401  : udp6_input_node.index,
402  node_index);
403 
404  /* Setup udp protocol -> next index sparse vector mapping. */
406  (vm, is_ip4 ? udp4_input_node.index: udp6_input_node.index);
408  clib_host_to_net_u16 (dst_port));
409  n[0] = pi->next_index;
410 
411  /* Rebuild next index -> sparse index inverse mapping when sparse vector
412  is updated. */
414  for (i = 1; i < vec_len (rt->next_by_dst_port); i++)
416 }
417 
418 /* Parse a UDP header. */
419 uword unformat_udp_header (unformat_input_t * input, va_list * args)
420 {
421  u8 ** result = va_arg (*args, u8 **);
422  udp_header_t * udp;
423  __attribute__((unused)) int old_length;
424  u16 src_port, dst_port;
425 
426  /* Allocate space for IP header. */
427  {
428  void * p;
429 
430  old_length = vec_len (*result);
431  vec_add2 (*result, p, sizeof (ip4_header_t));
432  udp = p;
433  }
434 
435  memset (udp, 0, sizeof (udp[0]));
436  if (unformat (input, "src-port %d dst-port %d",
437  &src_port, &dst_port))
438  {
439  udp->src_port = clib_host_to_net_u16 (src_port);
440  udp->dst_port = clib_host_to_net_u16 (dst_port);
441  return 1;
442  }
443  return 0;
444 }
445 
446 static void
447 udp_setup_node (vlib_main_t * vm, u32 node_index)
448 {
449  vlib_node_t * n = vlib_get_node (vm, node_index);
450  pg_node_t * pn = pg_get_node (node_index);
451 
455 }
456 
458 {
459  udp_input_runtime_t * rt;
460  udp_main_t * um = &udp_main;
461  int i;
462 
463  {
464  clib_error_t * error;
465  error = vlib_call_init_function (vm, udp_init);
466  if (error)
467  clib_error_report (error);
468  }
469 
470 
471  for (i = 0; i < 2; i++)
472  {
473  um->dst_port_info_by_name[i] = hash_create_string (0, sizeof(uword));
474  um->dst_port_info_by_dst_port[i] = hash_create (0, sizeof(uword));
475  }
476 
477  udp_setup_node (vm, udp4_input_node.index);
478  udp_setup_node (vm, udp6_input_node.index);
479 
481 
483  (/* elt bytes */ sizeof (rt->next_by_dst_port[0]),
484  /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
485 
486  vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_DROP);
487  vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_PUNT);
488  rt->sparse_index_by_next_index[UDP_INPUT_NEXT_DROP]
490  rt->sparse_index_by_next_index[UDP_INPUT_NEXT_PUNT]
492 
493 #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 1 /* is_ip4 */);
495 #undef _
496 
498 
499  rt->next_by_dst_port = sparse_vec_new
500  (/* elt bytes */ sizeof (rt->next_by_dst_port[0]),
501  /* bits in index */ BITS (((udp_header_t *) 0)->dst_port));
502 
503  vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_DROP);
504  vec_validate (rt->sparse_index_by_next_index, UDP_INPUT_NEXT_PUNT);
505  rt->sparse_index_by_next_index[UDP_INPUT_NEXT_DROP]
507  rt->sparse_index_by_next_index[UDP_INPUT_NEXT_PUNT]
509 
510 #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 0 /* is_ip4 */);
512 #undef _
513 
514  ip4_register_protocol (IP_PROTOCOL_UDP, udp4_input_node.index);
515  /* Note: ip6 differs from ip4, UDP is hotwired to ip6-udp-lookup */
516  return 0;
517 }
518 
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Definition: main.c:459
#define hash_set(h, key, value)
Definition: hash.h:237
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
clib_error_t * udp_local_init(vlib_main_t *vm)
Definition: udp_local.c:457
always_inline pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:335
static char * udp_error_strings[]
Definition: udp_local.c:284
always_inline vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Definition: node_funcs.h:46
udp_main_t udp_main
Definition: udp_local.c:24
#define PREDICT_TRUE(x)
Definition: clib.h:98
uword * dst_port_info_by_dst_port[N_UDP_AF]
Definition: udp.h:94
clib_error_t * udp_init(vlib_main_t *vm)
Definition: udp_init.c:43
Definition: udp.h:89
u32 node_index
Definition: udp.h:77
struct _vlib_node_registration vlib_node_registration_t
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:374
#define hash_set_mem(h, key, value)
Definition: hash.h:257
#define clib_error_report(e)
Definition: error.h:126
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:2125
vlib_error_t * errors
Definition: node.h:378
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
static void add_dst_port(udp_main_t *um, udp_dst_port_t dst_port, char *dst_port_name, u8 is_ip4)
Definition: udp_local.c:353
always_inline uword udp46_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, int is_ip4)
Definition: udp_local.c:66
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
#define always_inline
Definition: clib.h:84
#define sparse_vec_validate(v, i)
Definition: sparse_vec.h:213
always_inline uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:112
#define vlib_call_init_function(vm, x)
Definition: init.h:159
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
#define hash_create_string(elts, value_bytes)
Definition: hash.h:609
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
udp_dst_port_info_t * dst_port_infos[N_UDP_AF]
Definition: udp.h:90
always_inline void * sparse_vec_new(uword elt_bytes, uword sparse_index_bits)
Definition: sparse_vec.h:68
uword * dst_port_info_by_name[N_UDP_AF]
Definition: udp.h:93
u32 * sparse_index_by_next_index
Definition: udp_local.c:59
#define PREDICT_FALSE(x)
Definition: clib.h:97
format_function_t * format_buffer
Definition: node.h:277
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Definition: buffer_node.h:43
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Definition: buffer_node.h:83
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Definition: node_funcs.h:265
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:129
static void udp_setup_node(vlib_main_t *vm, u32 node_index)
Definition: udp_local.c:447
u16 n_vectors
Definition: node.h:307
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_node_registration_t udp4_input_node
(constructor) VLIB_REGISTER_NODE (udp4_input_node)
Definition: udp_local.c:62
unformat_function_t * unformat_buffer
Definition: node.h:278
unformat_function_t * unformat_edit
Definition: pg.h:290
u16 * next_by_dst_port
Definition: udp_local.c:57
vlib_node_registration_t udp6_input_node
(constructor) VLIB_REGISTER_NODE (udp6_input_node)
Definition: udp_local.c:63
udp_dst_port_t
Definition: udp.h:56
always_inline udp_dst_port_info_t * udp_get_dst_port_info(udp_main_t *um, udp_dst_port_t dst_port, u8 is_ip4)
Definition: udp.h:101
#define hash_create(elts, value_bytes)
Definition: hash.h:615
u16 cached_next_index
Definition: node.h:422
#define foreach_udp4_dst_port
Definition: udp.h:36
#define ASSERT(truth)
always_inline void sparse_vec_index2(void *v, u32 si0, u32 si1, u32 *i0_return, u32 *i1_return)
Definition: sparse_vec.h:158
unsigned int u32
Definition: types.h:88
udp_input_next_t
Definition: udp_local.c:30
#define foreach_udp_input_next
Definition: udp_local.c:26
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
udp_dst_port_t dst_port
Definition: udp.h:74
char * name
Definition: udp.h:71
static uword udp6_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: udp_local.c:299
always_inline uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:919
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:91
u64 uword
Definition: types.h:112
#define vec_elt(v, i)
Get vector value at index i.
static uword udp4_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: udp_local.c:291
unsigned short u16
Definition: types.h:57
always_inline void * vlib_node_get_runtime_data(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:76
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
always_inline void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:197
unsigned char u8
Definition: types.h:56
uword unformat_udp_header(unformat_input_t *input, va_list *args)
Definition: udp_local.c:419
u8 * format_udp_rx_trace(u8 *s, va_list *args)
Definition: udp_local.c:42
always_inline 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
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:162
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
u32 next_index
Definition: udp.h:80
u8 data[0]
Packet data.
Definition: buffer.h:150
format_function_t format_udp_header
Definition: format.h:94
struct _unformat_input_t unformat_input_t
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
#define BITS(x)
Definition: clib.h:58
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
unformat_function_t unformat_pg_udp_header
Definition: format.h:96
Definition: pg.h:288
#define SPARSE_VEC_INVALID_INDEX
Definition: sparse_vec.h:65
always_inline uword sparse_vec_index(void *v, uword sparse_index)
Definition: sparse_vec.h:150