FD.io VPP  v18.04-17-g3a0d853
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  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  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  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  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_sg_t *sg;
359  ip4_address_t *src;
360  igmp_sg_key_t key;
361  memset (&key, 0, sizeof (igmp_sg_key_t));
362  ip46_address_t saddr;
363  memset (&saddr, 0, sizeof (ip46_address_t));
364  ip46_address_t gaddr;
365  memset (&gaddr, 0, sizeof (ip46_address_t));
366  u32 len;
367  vlib_node_runtime_t *error_node =
369  u8 error;
370 
371  from = vlib_frame_vector_args (frame);
372  n_left_from = frame->n_vectors;
373  next_index = node->cached_next_index;
374 
375  while (n_left_from > 0)
376  {
377  u32 n_left_to_next;
378 
379  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
380 
381  while (n_left_from > 0 && n_left_to_next > 0)
382  {
383  vlib_buffer_t *b;
384  u32 sw_if_index, bi, next;
386 
387  bi = from[0];
388  to_next[0] = bi;
389  from++;
390  to_next++;
391  n_left_from--;
392  n_left_to_next--;
393 
394  b = vlib_get_buffer (vm, bi);
395 
396  error = IGMP_ERROR_NONE;
397  b->error = error_node->errors[error];
398 
399  sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
400 
402  ASSERT (igmp->header.type == IGMP_TYPE_membership_report_v3);
403  len = sizeof (igmp_membership_report_v3_t);
404 
405  /* if interface (S,G)s were configured by CLI/API goto next frame */
406  config = igmp_config_lookup (im, sw_if_index);
407  if (config)
408  {
410  if (config->cli_api_configured)
411  {
412  DBG ("Interface %u has (S,G)s configured by CLI/API",
413  sw_if_index);
414  error = IGMP_ERROR_CLI_API_CONFIG;
415  b->error = error_node->errors[error];
416  goto next_frame;
417  }
418  }
419  DBG ("interface %u", sw_if_index);
420  int i, j = 0;
421  for (i = 0; i < clib_net_to_host_u16 (igmp->n_groups); i++)
422  {
423  group = group_ptr (igmp, len);
424  src = group->src_addresses;
425  if (group->type == IGMP_MEMBERSHIP_GROUP_mode_is_filter_include)
426  {
427  for (j = 0;
428  j < clib_net_to_host_u16 (group->n_src_addresses); j++)
429  {
430  /* update (S,G) expiration timer */
431  key.saddr.ip4 = *src;
432  key.gaddr.ip4 = group->dst_address;
433  sg = igmp_sg_lookup (config, &key);
434  if (sg)
435  sg->exp_time = vlib_time_now (vm) + IGMP_SG_TIMER;
436  src++;
437  }
438  }
439  else if (group->type ==
440  IGMP_MEMBERSHIP_GROUP_mode_is_filter_exclude)
441  {
442  for (j = 0;
443  j < clib_net_to_host_u16 (group->n_src_addresses); j++)
444  {
445  /* nothing for now... */
446  src++;
447  }
448  }
449  else if (group->type ==
450  IGMP_MEMBERSHIP_GROUP_change_to_filter_include)
451  {
452  for (j = 0;
453  j < clib_net_to_host_u16 (group->n_src_addresses); j++)
454  {
455  /* add new (S,G) to interface */
456  saddr.ip4 = *src;
457  gaddr.ip4 = group->dst_address;
458  igmp_listen (vm, 1, sw_if_index, saddr, gaddr, 0);
459  src++;
460  }
461  }
462  else if (group->type ==
463  IGMP_MEMBERSHIP_GROUP_change_to_filter_exclude)
464  {
465  for (j = 0;
466  j < clib_net_to_host_u16 (group->n_src_addresses); j++)
467  {
468  /* remove (S,G) from interface */
469  saddr.ip4 = *src;
470  gaddr.ip4 = group->dst_address;
471  igmp_listen (vm, 0, sw_if_index, saddr, gaddr, 0);
472  src++;
473  }
474  }
475  else if (group->type == IGMP_MEMBERSHIP_GROUP_allow_new_sources)
476  {
477  for (j = 0;
478  j < clib_net_to_host_u16 (group->n_src_addresses); j++)
479  {
480  /* nothing for now... */
481  src++;
482  }
483  }
484  else if (group->type == IGMP_MEMBERSHIP_GROUP_block_old_sources)
485  {
486  for (j = 0;
487  j < clib_net_to_host_u16 (group->n_src_addresses); j++)
488  {
489  /* remove (S,G) from interface */
490  saddr.ip4 = *src;
491  gaddr.ip4 = group->dst_address;
492  igmp_listen (vm, 0, sw_if_index, saddr, gaddr, 0);
493  src++;
494  }
495  }
496  /*
497  * Unrecognized Record Type values MUST be silently ignored.
498  */
499 
500  /* move ptr to next Group Record */
501  len +=
502  sizeof (igmp_membership_group_v3_t) +
503  (sizeof (ip4_address_t) * j);
504  }
505  next_frame:
506  if (node->flags & VLIB_NODE_FLAG_TRACE)
507  {
508  igmp_input_trace_t *tr;
509  tr = vlib_add_trace (vm, node, b, sizeof (*tr));
510  tr->next_index = next;
511  tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
513  sizeof (tr->packet_data));
514  }
515  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
516  n_left_to_next, bi, next);
517  }
518  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
519  }
520 
521  return frame->n_vectors;
522 }
523 
524 /* *INDENT-OFF* */
526 {
527  .function = igmp_parse_report,
528  .name = "igmp-parse-report",
529  .vector_size = sizeof (u32),
530 
531  .format_buffer = format_igmp_report_v3,
532  .format_trace = format_igmp_parse_report_trace,
533 
534  .n_errors = IGMP_N_ERROR,
535  .error_strings = igmp_error_strings,
536 
537  .n_next_nodes = IGMP_PARSE_REPORT_N_NEXT,
538  .next_nodes = {
539  [IGMP_PARSE_REPORT_NEXT_DROP] = "error-drop",
540  }
541 };
542 /* *INDENT-ON* */
543 
544 /*
545  * fd.io coding-style-patch-verification: ON
546  *
547  * Local Variables:
548  * eval: (c-set-style "gnu")
549  * End:
550  */
igmp_membership_group_v3_type_t type
Definition: igmp_packet.h:121
#define IGMP_CONFIG_FLAG_CAN_SEND_REPORT
Definition: igmp.h:102
vlib_node_registration_t igmp_timer_process_node
(constructor) VLIB_REGISTER_NODE (igmp_timer_process_node)
Definition: igmp.c:581
#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:227
static igmp_sg_t * igmp_sg_lookup(igmp_config_t *config, igmp_sg_key_t *key)
Definition: igmp.h:246
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
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:415
#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:525
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
f64 exp_time
Definition: igmp.h:81
void igmp_send_report(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
Definition: igmp.c:455
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:952
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:209
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:101
#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
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:130
uword igmp_parse_query(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: input.c:243
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u16 n_vectors
Definition: node.h:344
vlib_main_t * vm
Definition: buffer.c:294
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
#define DBG(...)
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:456
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
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
ip46_address_t gaddr
Definition: igmp.h:69
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:222
ip46_address_t saddr
Definition: igmp.h:70
igmp_input_next_t
Definition: input.c:38
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
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)
Definition: igmp.c:595
unsigned short u16
Definition: types.h:57
#define IGMP_SG_TIMER
Definition: igmp.h:29
static igmp_config_t * igmp_config_lookup(igmp_main_t *im, u32 sw_if_index)
Definition: igmp.h:233
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static u8 * format_igmp_parse_query_trace(u8 *s, va_list *va)
Definition: input.c:103
u8 * format_igmp_query_v3(u8 *s, va_list *args)
Definition: igmp_format.c:115
u8 cli_api_configured
Definition: igmp.h:92
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:372
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:132
u16 flags
Copy of main node flags.
Definition: node.h:450
#define group_ptr(p, l)
Definition: igmp.h:40
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
void igmp_create_int_timer(f64 time, u32 sw_if_index, igmp_timer_function_t *func)
Definition: igmp.c:86
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