FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
input.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 
18 #include <vlib/vlib.h>
19 #include <vnet/plugin/plugin.h>
20 #include <vpp/app/version.h>
21 #include <vnet/ip/ip.h>
22 #include <vlib/unix/unix.h>
23 #include <vnet/adj/adj_mcast.h>
24 
25 #include <igmp/igmp.h>
26 #include <igmp/error.h>
27 
28 #include <limits.h>
29 
30 /* TODO: mld...
31 typedef enum
32 {
33  MLD_INPUT_NEXT_DROP,
34  ...
35 } mld_input_next_t;
36 */
37 
38 typedef enum
39 {
45 
46 typedef enum
47 {
51 
52 typedef enum
53 {
57 
58 char *igmp_error_strings[] = {
59 #define _(sym,string) string,
61 #undef _
62 };
63 
64 typedef struct
65 {
68 
69  u8 packet_data[64];
71 
72 static u8 *
73 format_igmp_input_trace (u8 * s, va_list * va)
74 {
75  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
76  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
77  igmp_input_trace_t *t = va_arg (*va, igmp_input_trace_t *);
78 
79  s =
80  format (s, "sw_if_index %u next-index %u", t->sw_if_index, t->next_index);
81  s =
82  format (s, "\n%U", format_igmp_header, t->packet_data,
83  sizeof (t->packet_data));
84  return s;
85 }
86 
87 static u8 *
89 {
90  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
91  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
92  igmp_input_trace_t *t = va_arg (*va, igmp_input_trace_t *);
93 
94  s =
95  format (s, "sw_if_index %u next-index %u", t->sw_if_index, t->next_index);
96  s =
98  sizeof (t->packet_data));
99  return s;
100 }
101 
102 static u8 *
104 {
105  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
106  CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
107  igmp_input_trace_t *t = va_arg (*va, igmp_input_trace_t *);
108 
109  s =
110  format (s, "sw_if_index %u next-input %u", t->sw_if_index, t->next_index);
111  s =
112  format (s, "\n%U", format_igmp_query_v3, t->packet_data,
113  sizeof (t->packet_data));
114  return s;
115 }
116 
117 uword
119  vlib_frame_t * frame)
120 {
121  IGMP_DBG ("IGMP_INPUT");
122  u32 n_left_from, *from, *to_next;
123  igmp_parse_query_next_t next_index;
124  vlib_node_runtime_t *error_node =
126  u8 error;
127  ip_csum_t sum;
128  u16 csum;
129 
130  error = IGMP_ERROR_NONE;
131 
132  from = vlib_frame_vector_args (frame);
133  n_left_from = frame->n_vectors;
134  next_index = node->cached_next_index;
135 
136  while (n_left_from > 0)
137  {
138  u32 n_left_to_next;
139 
140  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
141 
142  while (n_left_from > 0 && n_left_to_next > 0)
143  {
144  vlib_buffer_t *b;
145  ip4_header_t *ip;
146  u32 bi, next;
147  next = IGMP_INPUT_NEXT_DROP;
148 
149  bi = from[0];
150  to_next[0] = bi;
151  from++;
152  to_next++;
153  n_left_from--;
154  n_left_to_next--;
155 
156  b = vlib_get_buffer (vm, bi);
157  ip = vlib_buffer_get_current (b);
158 
159  if (ip->protocol != 2)
160  {
161  error = IGMP_ERROR_INVALID_PROTOCOL;
162  next = IGMP_INPUT_NEXT_DROP;
163  goto next_buffer;
164  }
165 
167 
169 
170  u16 checksum = igmp->checksum;
171  igmp->checksum = 0;
172  sum = ip_incremental_checksum (0, igmp,
173  clib_net_to_host_u16 (ip->length) -
174  ip4_header_bytes (ip));
175  igmp->checksum = checksum;
176  csum = ~ip_csum_fold (sum);
177  if (checksum != csum)
178  {
179  error = IGMP_ERROR_BAD_CHECKSUM;
180  next = IGMP_INPUT_NEXT_DROP;
181  goto next_buffer;
182  }
183 
184  /* TODO: IGMPv2 and IGMPv1 */
185  switch (igmp->type)
186  {
187  case IGMP_TYPE_membership_query:
189  break;
190  case IGMP_TYPE_membership_report_v3:
192  break;
193  default:
194  error = IGMP_ERROR_UNKNOWN_TYPE;
195  next = IGMP_INPUT_NEXT_DROP;
196  break;
197  }
198  next_buffer:
199  b->error = error_node->errors[error];
200 
201  if (node->flags & VLIB_NODE_FLAG_TRACE)
202  {
203  igmp_input_trace_t *tr;
204  tr = vlib_add_trace (vm, node, b, sizeof (*tr));
205  tr->next_index = next;
206  tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
208  sizeof (tr->packet_data));
209  }
210 
211  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
212  n_left_to_next, bi, next);
213  }
214  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
215  }
216 
217  return frame->n_vectors;
218 }
219 
220 /* *INDENT-OFF* */
222 {
223  .function = igmp_input,
224  .name = "igmp-input",
225  .vector_size = sizeof (u32),
226 
227  .format_buffer = format_igmp_header,
228  .format_trace = format_igmp_input_trace,
229 
230  .n_errors = IGMP_N_ERROR,
231  .error_strings = igmp_error_strings,
232 
233  .n_next_nodes = IGMP_INPUT_N_NEXT,
234  .next_nodes = {
235  [IGMP_INPUT_NEXT_DROP] = "error-drop",
236  [IGMP_INPUT_NEXT_PARSE_QUERY] = "igmp-parse-query",
237  [IGMP_INPUT_NEXT_PARSE_REPORT] = "igmp-parse-report",
238  }
239 };
240 /* *INDENT-ON* */
241 
242 uword
244  vlib_frame_t * frame)
245 {
246  IGMP_DBG ("IGMP_PARSE_QUERY");
247 
248  u32 n_left_from, *from, *to_next;
249  igmp_parse_query_next_t next_index;
250  igmp_main_t *im = &igmp_main;
251  igmp_config_t *config;
252 
253  from = vlib_frame_vector_args (frame);
254  n_left_from = frame->n_vectors;
255  next_index = node->cached_next_index;
256 
257  while (n_left_from > 0)
258  {
259  u32 n_left_to_next;
260 
261  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
262 
263  while (n_left_from > 0 && n_left_to_next > 0)
264  {
265  vlib_buffer_t *b;
266  u32 sw_if_index, bi, next;
268 
269  bi = from[0];
270  to_next[0] = bi;
271  from++;
272  to_next++;
273  n_left_from--;
274  n_left_to_next--;
275 
276  b = vlib_get_buffer (vm, bi);
277  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
278 
280  ASSERT (igmp->header.type == IGMP_TYPE_membership_query);
281 
282  /* if group address is zero, this is a general query */
283  if (igmp->dst.as_u32 == 0)
284  {
285  config = igmp_config_lookup (im, sw_if_index);
286  if (!config)
287  {
288  IGMP_DBG ("No config on interface %u", sw_if_index);
289  }
290  else
291  {
292  /* WIP
293  *
294  * TODO: divide to multipe reports in random time range [now, max resp time]
295  */
296  u32 seed = vlib_time_now (vm);
297  f64 next_resp_time = random_f64 (&seed) *
298  (f64) (igmp->header.code / 10) + vlib_time_now (vm);
300  igmp_create_int_timer (next_resp_time, sw_if_index,
305  0);
306  }
307  }
308 
309  if (node->flags & VLIB_NODE_FLAG_TRACE)
310  {
311  igmp_input_trace_t *tr;
312  tr = vlib_add_trace (vm, node, b, sizeof (*tr));
313  tr->next_index = next;
314  tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
316  sizeof (tr->packet_data));
317  }
318  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
319  n_left_to_next, bi, next);
320  }
321  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
322  }
323 
324  return frame->n_vectors;
325 }
326 
327 /* *INDENT-OFF* */
329 {
330  .function = igmp_parse_query,
331  .name = "igmp-parse-query",
332  .vector_size = sizeof (u32),
333 
334  .format_buffer = format_igmp_query_v3,
335  .format_trace = format_igmp_parse_query_trace,
336 
337  .n_errors = IGMP_N_ERROR,
338  .error_strings = igmp_error_strings,
339 
340  .n_next_nodes = IGMP_PARSE_QUERY_N_NEXT,
341  .next_nodes = {
342  [IGMP_PARSE_QUERY_NEXT_DROP] = "error-drop",
343  }
344 };
345 /* *INDENT-ON* */
346 
347 uword
349  vlib_frame_t * frame)
350 {
351  IGMP_DBG ("IGMP_PARSE_REPORT");
352 
353  igmp_main_t *im = &igmp_main;
354  u32 n_left_from, *from, *to_next;
355  igmp_input_next_t next_index;
356  igmp_config_t *config;
357  igmp_group_t *group;
358  igmp_src_t *src;
359  igmp_membership_group_v3_t *igmp_group;
360  ip4_address_t *src_addr;
361  igmp_key_t gkey;
362  igmp_key_t skey;
363  memset (&gkey, 0, sizeof (igmp_key_t));
364  memset (&skey, 0, sizeof (igmp_key_t));
365  ip46_address_t saddr;
366  memset (&saddr, 0, sizeof (ip46_address_t));
367  ip46_address_t gaddr;
368  memset (&gaddr, 0, sizeof (ip46_address_t));
369  u32 len;
370  vlib_node_runtime_t *error_node =
372  u8 error;
373 
374  from = vlib_frame_vector_args (frame);
375  n_left_from = frame->n_vectors;
376  next_index = node->cached_next_index;
377 
378  while (n_left_from > 0)
379  {
380  u32 n_left_to_next;
381 
382  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
383 
384  while (n_left_from > 0 && n_left_to_next > 0)
385  {
386  vlib_buffer_t *b;
387  u32 sw_if_index, bi, next;
389 
390  bi = from[0];
391  to_next[0] = bi;
392  from++;
393  to_next++;
394  n_left_from--;
395  n_left_to_next--;
396 
397  b = vlib_get_buffer (vm, bi);
398 
399  error = IGMP_ERROR_NONE;
400  b->error = error_node->errors[error];
401 
402  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
403 
405  ASSERT (igmp->header.type == IGMP_TYPE_membership_report_v3);
406  len = sizeof (igmp_membership_report_v3_t);
407 
408  /* if interface (S,G)s were configured by CLI/API goto next frame */
409  config = igmp_config_lookup (im, sw_if_index);
410  if (config)
411  {
413  if (config->cli_api_configured)
414  {
415  IGMP_DBG ("Interface %u has (S,G)s configured by CLI/API",
416  sw_if_index);
417  error = IGMP_ERROR_CLI_API_CONFIG;
418  b->error = error_node->errors[error];
419  goto next_frame;
420  }
421  }
422  IGMP_DBG ("interface %u", sw_if_index);
423  int i, j = 0;
424  for (i = 0; i < clib_net_to_host_u16 (igmp->n_groups); i++)
425  {
426  igmp_group = group_ptr (igmp, len);
427  src_addr = igmp_group->src_addresses;
428  if (igmp_group->type ==
429  IGMP_MEMBERSHIP_GROUP_mode_is_filter_include)
430  {
431  ip46_address_set_ip4 ((ip46_address_t *) & gkey.data,
432  &igmp_group->dst_address);
433 
434  gkey.group_type =
435  IGMP_MEMBERSHIP_GROUP_mode_is_filter_include;
436 
437  group = igmp_group_lookup (config, &gkey);
438  if (group)
439  {
440  for (j = 0;
441  j <
442  clib_net_to_host_u16 (igmp_group->n_src_addresses);
443  j++)
444  {
445  /* update (S,G) expiration timer */
446  ip46_address_set_ip4 ((ip46_address_t *) &
447  skey.data, src_addr);
448  src = igmp_src_lookup (group, &skey);
449  if (src)
450  src->exp_time =
452  src_addr++;
453  }
454  }
455  }
456  else if (igmp_group->type ==
457  IGMP_MEMBERSHIP_GROUP_mode_is_filter_exclude)
458  {
459  for (j = 0;
460  j < clib_net_to_host_u16 (igmp_group->n_src_addresses);
461  j++)
462  {
463  /* nothing for now... */
464  src_addr++;
465  }
466  }
467  else if (igmp_group->type ==
468  IGMP_MEMBERSHIP_GROUP_change_to_filter_include)
469  {
470  for (j = 0;
471  j < clib_net_to_host_u16 (igmp_group->n_src_addresses);
472  j++)
473  {
474  /* add new (S,G) to interface */
475  saddr.ip4 = *src_addr;
476  gaddr.ip4 = igmp_group->dst_address;
477  igmp_listen (vm, 1, sw_if_index, saddr, gaddr, 0);
478  src_addr++;
479  }
480  }
481  else if (igmp_group->type ==
482  IGMP_MEMBERSHIP_GROUP_change_to_filter_exclude)
483  {
484  for (j = 0;
485  j < clib_net_to_host_u16 (igmp_group->n_src_addresses);
486  j++)
487  {
488  /* remove (S,G) from interface */
489  saddr.ip4 = *src_addr;
490  gaddr.ip4 = igmp_group->dst_address;
491  igmp_listen (vm, 0, sw_if_index, saddr, gaddr, 0);
492  src_addr++;
493  }
494  }
495  else if (igmp_group->type ==
496  IGMP_MEMBERSHIP_GROUP_allow_new_sources)
497  {
498  for (j = 0;
499  j < clib_net_to_host_u16 (igmp_group->n_src_addresses);
500  j++)
501  {
502  /* nothing for now... */
503  src_addr++;
504  }
505  }
506  else if (igmp_group->type ==
507  IGMP_MEMBERSHIP_GROUP_block_old_sources)
508  {
509  for (j = 0;
510  j < clib_net_to_host_u16 (igmp_group->n_src_addresses);
511  j++)
512  {
513  /* remove (S,G) from interface */
514  saddr.ip4 = *src_addr;
515  gaddr.ip4 = igmp_group->dst_address;
516  igmp_listen (vm, 0, sw_if_index, saddr, gaddr, 0);
517  src_addr++;
518  }
519  }
520  /*
521  * Unrecognized Record Type values MUST be silently ignored.
522  */
523 
524  /* move ptr to next Group Record */
525  len +=
526  sizeof (igmp_membership_group_v3_t) +
527  (sizeof (ip4_address_t) * j);
528  }
529  next_frame:
530  if (node->flags & VLIB_NODE_FLAG_TRACE)
531  {
532  igmp_input_trace_t *tr;
533  tr = vlib_add_trace (vm, node, b, sizeof (*tr));
534  tr->next_index = next;
535  tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
537  sizeof (tr->packet_data));
538  }
539  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
540  n_left_to_next, bi, next);
541  }
542  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
543  }
544 
545  return frame->n_vectors;
546 }
547 
548 /* *INDENT-OFF* */
550 {
551  .function = igmp_parse_report,
552  .name = "igmp-parse-report",
553  .vector_size = sizeof (u32),
554 
555  .format_buffer = format_igmp_report_v3,
556  .format_trace = format_igmp_parse_report_trace,
557 
558  .n_errors = IGMP_N_ERROR,
559  .error_strings = igmp_error_strings,
560 
561  .n_next_nodes = IGMP_PARSE_REPORT_N_NEXT,
562  .next_nodes = {
563  [IGMP_PARSE_REPORT_NEXT_DROP] = "error-drop",
564  }
565 };
566 /* *INDENT-ON* */
567 
568 /*
569  * fd.io coding-style-patch-verification: ON
570  *
571  * Local Variables:
572  * eval: (c-set-style "gnu")
573  * End:
574  */
igmp_membership_group_v3_type_t type
Definition: igmp_packet.h:121
#define IGMP_CONFIG_FLAG_CAN_SEND_REPORT
Definition: igmp.h:160
vlib_node_registration_t igmp_timer_process_node
(constructor) VLIB_REGISTER_NODE (igmp_timer_process_node)
Definition: igmp.c:724
#define CLIB_UNUSED(x)
Definition: clib.h:79
vlib_node_registration_t igmp_input_node
(constructor) VLIB_REGISTER_NODE (igmp_input_node)
Definition: input.c:221
igmp_main_t igmp_main
Definition: igmp.c:34
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:232
igmp source
Definition: igmp.h:94
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:225
static igmp_group_t * igmp_group_lookup(igmp_config_t *config, igmp_key_t *key)
igmp group lookup
Definition: igmp.h:420
int i
uword ip_csum_t
Definition: ip_packet.h:90
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u8 * format_igmp_report_v3(u8 *s, va_list *args)
Definition: igmp_format.c:69
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:451
unsigned char u8
Definition: types.h:56
#define IGMP_DBG(...)
Definition: igmp.h:37
double f64
Definition: types.h:142
#define foreach_igmp_error
Definition: error.h:21
igmp_parse_query_next_t
Definition: input.c:46
vlib_node_registration_t igmp_parse_report_node
(constructor) VLIB_REGISTER_NODE (igmp_parse_report_node)
Definition: input.c:549
igmp key
Definition: igmp.h:83
void igmp_send_report(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
igmp send report (igmp_timer_function_t)
Definition: igmp.c:525
u64 data[2]
Definition: igmp.h:85
unsigned int u32
Definition: types.h:88
f64 exp_time
Definition: igmp.h:98
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:952
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
u64 group_type
Definition: igmp.h:86
u8 * format_igmp_header(u8 *s, va_list *args)
Definition: igmp_format.c:49
uword igmp_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: input.c:118
igmp_type_t type
Definition: igmp_packet.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define IGMP_CONFIG_FLAG_QUERY_RESP_RECVED
Definition: igmp.h:159
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:364
igmp main
Definition: igmp.h:198
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:135
uword igmp_parse_query(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: input.c:243
#define IGMP_SRC_TIMER
Definition: igmp.h:29
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
u16 n_vectors
Definition: node.h:380
vlib_main_t * vm
Definition: buffer.c:294
static igmp_src_t * igmp_src_lookup(igmp_group_t *group, igmp_key_t *key)
igmp group lookup
Definition: igmp.h:439
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:162
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:89
#define clib_memcpy(a, b, c)
Definition: string.h:75
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:454
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:492
#define ASSERT(truth)
static u8 * format_igmp_parse_report_trace(u8 *s, va_list *va)
Definition: input.c:88
igmp_parse_report_next_t
Definition: input.c:52
#define ip46_address_set_ip4(ip46, ip)
Definition: ip6_packet.h:83
uword igmp_parse_report(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: input.c:348
u8 packet_data[64]
Definition: input.c:69
vlib_node_registration_t igmp_parse_query_node
(constructor) VLIB_REGISTER_NODE (igmp_parse_query_node)
Definition: input.c:328
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:215
igmp_input_next_t
Definition: input.c:38
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
igmp configuration
Definition: igmp.h:144
int igmp_listen(vlib_main_t *vm, u8 enable, u32 sw_if_index, ip46_address_t saddr, ip46_address_t gaddr, u8 cli_api_configured)
igmp listen
Definition: igmp.c:738
static igmp_config_t * igmp_config_lookup(igmp_main_t *im, u32 sw_if_index)
igmp config lookup
Definition: igmp.h:403
static u8 * format_igmp_parse_query_trace(u8 *s, va_list *va)
Definition: input.c:103
igmp group
Definition: igmp.h:113
u8 * format_igmp_query_v3(u8 *s, va_list *args)
Definition: igmp_format.c:115
u8 cli_api_configured
Definition: igmp.h:150
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
#define vnet_buffer(b)
Definition: buffer.h:360
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:132
u16 flags
Copy of main node flags.
Definition: node.h:486
#define group_ptr(p, l)
helper macro to get igmp mebership group from pointer plus offset
Definition: igmp.h:46
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:295
void igmp_create_int_timer(f64 time, u32 sw_if_index, igmp_timer_function_t *func)
igmp create int timer
Definition: igmp.c:108
static u8 * format_igmp_input_trace(u8 *s, va_list *va)
Definition: input.c:73
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
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
Definition: defs.h:46
char * igmp_error_strings[]
Definition: input.c:58