FD.io VPP  v18.04-17-g3a0d853
Vector Packet Processing
igmp.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 <vnet/mfib/mfib_entry.h>
23 #include <vlib/unix/unix.h>
24 #include <vnet/adj/adj_mcast.h>
25 #include <vnet/fib/fib_entry.h>
26 #include <vnet/fib/fib_table.h>
27 #include <vnet/mfib/mfib_table.h>
28 
29 #include <igmp/igmp.h>
30 
31 #include <limits.h>
32 #include <float.h>
33 
35 
36 /* clear all (S,G)s on specified config and remove this config from pool */
37 void
39 {
40  igmp_main_t *im = &igmp_main;
41  igmp_sg_t *sg;
42 
43  ASSERT (config);
44  /* *INDENT-OFF* */
45  pool_foreach (sg, config->sg, (
46  {
47  clib_mem_free (sg->key);
48  }));
49  /* *INDENT-ON* */
50  pool_free (config->sg);
51  hash_free (config->igmp_sg_by_key);
52 
54  pool_put (im->configs, config);
55 }
56 
57 /* sort igmp timers, so that the first to expire is at end */
58 int
59 igmp_timer_compare (const void *_a, const void *_b)
60 {
61  const igmp_timer_t *a = _a;
62  const igmp_timer_t *b = _b;
63  f64 dt = b->exp_time - a->exp_time;
64  return dt < 0 ? -1 : (dt > 0 ? +1 : 0);
65 }
66 
67 void
69 {
71 
72  qsort (timers, vec_len (timers), sizeof (igmp_timer_t), igmp_timer_compare);
73 
76 }
77 
78 /* create new per interface timer
79  *
80  * - delayed reports
81  * - query msg
82  * - query resp
83  */
84 
85 void
86 igmp_create_int_timer (f64 time, u32 sw_if_index,
87  igmp_timer_function_t * func)
88 {
89  igmp_main_t *im = &igmp_main;
90  igmp_timer_t *timer;
91 
92  pool_get (im->timers, timer);
93  memset (timer, 0, sizeof (igmp_timer_t));
94  timer->func = func;
95  timer->exp_time = time;
96  timer->sw_if_index = sw_if_index;
97 
99 }
100 
101 void
102 igmp_create_sg_timer (f64 time, u32 sw_if_index, igmp_sg_key_t * key,
103  igmp_timer_function_t * func)
104 {
105  igmp_main_t *im = &igmp_main;
106  igmp_timer_t *timer;
107 
108  pool_get (im->timers, timer);
109  memset (timer, 0, sizeof (igmp_timer_t));
110  timer->func = func;
111  timer->exp_time = time;
112  timer->sw_if_index = sw_if_index;
113  /* duplicate key, to prevent segmentation fault if (S,G) is removed */
114  timer->data = clib_mem_alloc (sizeof (igmp_sg_key_t));
115  clib_memcpy (timer->data, key, sizeof (igmp_sg_key_t));
116 
117  igmp_sort_timers (im->timers);
118 }
119 
120 /* get next timer to expire */
123 {
124  if (pool_elts (im->timers) > 0)
125  return vec_elt_at_index (im->timers, pool_elts (im->timers) - 1);
126  return NULL;
127 }
128 
129 /*
130 static void
131 igmp_create_report_v2 (vlib_buffer_t * b, igmp_config_t * config)
132 {
133  ip_csum_t sum;
134  u16 csum;
135  igmp_main_t *im = &igmp_main;
136  igmp_sg_t *sg;
137 
138  sg = vec_elt_at_index (config->sg, im->next_index.sg_index);
139 
140  igmp_message_t *igmp = (igmp_message_t *) (vlib_buffer_get_current (b));
141  memset (igmp, 0, sizeof (igmp_message_t));
142 
143  clib_memcpy (&igmp->dst, &sg->gaddr.ip4, sizeof (ip4_address_t));
144  igmp->header.type =
145  (sg->group_type == IGMP_MEMBERSHIP_GROUP_block_old_sources) ?
146  IGMP_TYPE_leave_group_v2 : IGMP_TYPE_membership_report_v2;
147  sum = ip_incremental_checksum (0, igmp, sizeof (igmp_message_t));
148  csum = ~ip_csum_fold (sum);
149  igmp->header.checksum = csum;
150 
151  b->current_data += sizeof (igmp_message_t);
152  b->current_length += sizeof (igmp_message_t);
153 }
154 */
155 
156 /* create IGMPv3 report with single (S,G)
157  * used to send state chenge reports
158  */
159 static void
161 {
162  ip_csum_t sum;
163  u16 csum;
164  igmp_main_t *im = &igmp_main;
165  igmp_sg_t *sg;
166  u32 len = 0;
167 
168  sg = vec_elt_at_index (config->sg, im->next_index.sg_index);
169 
170  len = sizeof (igmp_membership_report_v3_t);
173  memset (igmp, 0, sizeof (igmp_membership_report_v3_t));
174 
175  igmp->header.type = IGMP_TYPE_membership_report_v3;
176  igmp->n_groups = clib_host_to_net_u16 (1);
177 
178  len += sizeof (igmp_membership_group_v3_t);
179  memset (igmp->groups, 0, sizeof (igmp_membership_group_v3_t));
180  igmp->groups[0].type = sg->group_type;
181  igmp->groups[0].n_aux_u32s = 0;
182  clib_memcpy (&igmp->groups[0].dst_address, &sg->gaddr.ip4,
183  sizeof (ip4_address_t));
184 
185  igmp->groups[0].n_src_addresses = clib_host_to_net_u16 (1);
186 
187  len += sizeof (ip4_address_t);
188  clib_memcpy (&igmp->groups[0].src_addresses[0], &sg->saddr.ip4,
189  sizeof (ip4_address_t));
190 
191  sum = ip_incremental_checksum (0, igmp, len);
192  csum = ~ip_csum_fold (sum);
193  igmp->header.checksum = csum;
194 
195  b->current_data += len;
196  b->current_length += len;
197 }
198 
199 u8
202 {
203  u16 i;
204  u8 rv = 0;
205  u32 l = sizeof (igmp_membership_report_v3_t);
206 
207  for (i = 0; i < n; i++)
208  {
209  if ((!ip4_address_compare (a, &(group_ptr (igmp, l)->dst_address))) &&
210  (type == group_ptr (igmp, l)->type))
211  {
212  rv = 1;
213  break;
214  }
215  l += sizeof (igmp_membership_group_v3_t) +
216  clib_net_to_host_u16 (group_ptr (igmp, l)->n_src_addresses) *
217  sizeof (ip4_address_t);
218  }
219 
220  return rv;
221 }
222 
223 /* create IGMPv3 report with all (S,G)s on config
224  * used to respond to general queries
225  */
226 static void
228 {
229  ip_csum_t sum;
230  u16 csum;
231  igmp_sg_t *sg0, *sg1;
232  u32 len = 0;
233  u16 n_groups = 0, n_srcs = 0;
234  u32 grp_s = sizeof (igmp_membership_group_v3_t);
235 
236  len = sizeof (igmp_membership_report_v3_t);
239  memset (igmp, 0, sizeof (igmp_membership_report_v3_t));
240 
241  igmp->header.type = IGMP_TYPE_membership_report_v3;
242 
243 /* TODO: divide (S,G)s to multiple reports...
244  * - create report limited by <packet size|number of (S,G)s>?
245  * - save loop state
246  * - on next timer continue loop
247  * - case of new query -> reset loop
248  */
249  /* *INDENT-OFF* */
250  pool_foreach (sg0, config->sg, (
251  {
252  if (ip4_lookup (&sg0->gaddr.ip4, igmp, n_groups, sg0->group_type))
253  continue;
254  memset (igmp + len, 0, grp_s);
255  clib_memcpy (&group_ptr (igmp, len)->dst_address, &sg0->gaddr.ip4, sizeof (ip4_address_t));
256  group_ptr (igmp, len)->type = sg0->group_type;
257  len += grp_s;
258  n_srcs = 0;
259  pool_foreach (sg1, config->sg, (
260  {
261  if ((!ip4_address_compare (&group_ptr (igmp, len - grp_s)->dst_address,
262  &sg1->gaddr.ip4)) && (group_ptr (igmp, len - grp_s)->type == (sg1->group_type)))
263  {
264  clib_memcpy (group_ptr (igmp, len + sizeof (ip4_address_t) * n_srcs),
265  &sg1->saddr.ip4, sizeof (ip4_address_t));
266  n_srcs++;
267  }
268  }));
269  group_ptr (igmp, len - grp_s)->n_src_addresses = clib_host_to_net_u16 (n_srcs);
270  len += sizeof (ip4_address_t) * n_srcs;
271  n_groups++;
272  }));
273  /* *INDENT-ON* */
274 
275  igmp->n_groups = clib_host_to_net_u16 (n_groups);
276 
277  sum = ip_incremental_checksum (0, igmp, len);
278  csum = ~ip_csum_fold (sum);
279  igmp->header.checksum = csum;
280 
281  b->current_data += len;
282  b->current_length += len;
283 }
284 
285 static void
287 {
289  ip_csum_t sum;
290  u16 csum;
291 
293  memset (igmp, 0, sizeof (igmp_membership_query_v3_t));
294 
295  igmp->header.type = IGMP_TYPE_membership_query;
296  igmp->header.code = 100;
297 
299  igmp_create_int_timer (vlib_time_now (vm) + (f64) (igmp->header.code / 10),
301 
302  sum =
304  csum = ~ip_csum_fold (sum);
305  igmp->header.checksum = csum;
306 
309 }
310 
311 
312 static void
313 igmp_create_ip4 (vlib_buffer_t * b, igmp_config_t * config, u8 is_report)
314 {
316 
318  memset (ip4, 0, sizeof (ip4_header_t));
319  ip4->ip_version_and_header_length = 0x45;
320  ip4->ttl = 1;
321  ip4->protocol = 2;
322  ip4->tos = 0xc0;
323 
324  u32 if_add_index =
326  if (PREDICT_TRUE (if_add_index != ~0))
327  {
328  ip_interface_address_t *if_add =
329  pool_elt_at_index (lm->if_address_pool, if_add_index);
330  ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add);
331  clib_memcpy (&ip4->src_address, if_ip, sizeof (ip4_address_t));
332  }
333  ip4->dst_address.as_u8[0] = 224;
334  ip4->dst_address.as_u8[1] = 0;
335  ip4->dst_address.as_u8[2] = 0;
336  ip4->dst_address.as_u8[3] = is_report ? 22 : 1;
337 
338  b->current_data += ip4_header_bytes (ip4);
339  b->current_length += ip4_header_bytes (ip4);
340 
341  config->next_create_msg (b, config);
342  ip4->length = clib_host_to_net_u16 (b->current_length);
343 
344  ip4->checksum = ip4_header_checksum (ip4);
345 }
346 
347 static void
349  igmp_main_t * im, igmp_config_t * config, u8 is_report)
350 {
351  u32 thread_index = vlib_get_thread_index ();
352  u32 *to_next;
354 
355  u32 n_free_bufs = vec_len (im->buffers[thread_index]);
356  if (PREDICT_FALSE (n_free_bufs < 1))
357  {
358  vec_validate (im->buffers[thread_index], 1 + n_free_bufs - 1);
359  n_free_bufs +=
360  vlib_buffer_alloc (vm, &im->buffers[thread_index][n_free_bufs], 1);
361  _vec_len (im->buffers[thread_index]) = n_free_bufs;
362  }
363 
364  u32 n_left_to_next;
365  u32 next0 = next_index;
366  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
367 
368  if (n_left_to_next > 0)
369  {
370  vlib_buffer_t *b = 0;
371  u32 bi = 0;
372 
373  if (n_free_bufs)
374  {
375  u32 last_buf = vec_len (im->buffers[thread_index]) - 1;
376  bi = im->buffers[thread_index][last_buf];
377  b = vlib_get_buffer (vm, bi);
378  _vec_len (im->buffers[thread_index]) = last_buf;
379  n_free_bufs--;
380  if (PREDICT_FALSE (n_free_bufs == 0))
381  {
382  n_free_bufs += vlib_buffer_alloc (vm,
383  &im->buffers[thread_index]
384  [n_free_bufs], 1);
385  _vec_len (im->buffers[thread_index]) = n_free_bufs;
386  }
387 
388  b->current_data = 0;
389  b->current_length = 0;
390 
391  igmp_create_ip4 (b, config, is_report);
392 
393  b->current_data = 0;
394 
396  b->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
397  vnet_buffer (b)->sw_if_index[VLIB_RX] = (u32) ~ 0;
398  vnet_buffer (b)->ip.adj_index[VLIB_TX] = config->adj_index;
399  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
400  }
401 
402  to_next[0] = bi;
403  to_next += 1;
404  n_left_to_next -= 1;
405 
406  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
407  n_left_to_next, bi, next0);
408  }
409  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
410 }
411 
412 void
414  igmp_timer_t * timer)
415 {
416  igmp_config_t *config;
417 
418  u32 sw_if_index = timer->sw_if_index;
419 
420  pool_put (im->timers, timer);
421 
422  config = igmp_config_lookup (im, sw_if_index);
423  if (!config)
424  return;
425 
426  /* TODO: implement IGMPv2 */
428  igmp_send_msg (vm, rt, im, config, /* is_report */ 0);
429 
432 }
433 
434 void
436  igmp_main_t * im, igmp_timer_t * timer)
437 {
438  igmp_config_t *config;
439 
440  u32 sw_if_index = timer->sw_if_index;
441 
442  pool_put (im->timers, timer);
443 
444  config = igmp_config_lookup (im, sw_if_index);
445  if (!config)
446  return;
447  /* if report not reveived in max resp time clear igmp on interface */
448  if ((config->flags & IGMP_CONFIG_FLAG_QUERY_RESP_RECVED) == 0)
449  {
450  igmp_clear_config (config);
451  }
452 }
453 
454 void
456  igmp_main_t * im, igmp_timer_t * timer)
457 {
458  igmp_config_t *config;
459 
460  u32 sw_if_index = timer->sw_if_index;
461 
462  pool_put (im->timers, timer);
463 
464  config = igmp_config_lookup (im, sw_if_index);
465  if (!config)
466  return;
467 
469  {
470  /* TODO: implement IGMPv2 and IGMPv1 */
472  igmp_send_msg (vm, rt, im, config, /* is_report */ 1);
473  /* WIP: unset flag after all reports sent */
475  }
476 }
477 
478 void
480  igmp_main_t * im, igmp_timer_t * timer)
481 {
482  igmp_config_t *config;
483  igmp_sg_t *sg;
484 
485  pool_put (im->timers, timer);
486 
487  config = vec_elt_at_index (im->configs, im->next_index.config_index);
488  sg = vec_elt_at_index (config->sg, im->next_index.sg_index);
489 
491  igmp_send_msg (vm, rt, im, config, /* is_report */ 1);
492 
493 
494  if (sg->group_type == IGMP_MEMBERSHIP_GROUP_change_to_filter_include)
495  {
496  sg->group_type = IGMP_MEMBERSHIP_GROUP_mode_is_filter_include;
497  }
498  else if (sg->group_type == IGMP_MEMBERSHIP_GROUP_block_old_sources)
499  {
500  /* remove API/CLI configured (S,G) */
501  hash_unset_mem (config->igmp_sg_by_key, sg->key);
502  clib_mem_free (sg->key);
503  pool_put (config->sg, sg);
504  if (pool_elts (config->sg) == 0)
505  {
507  pool_put (im->configs, config);
508  }
509  }
510 }
511 
512 void
514  igmp_timer_t * timer)
515 {
516  igmp_config_t *config;
517  igmp_sg_t *sg;
518 
519  igmp_sg_key_t *key = (igmp_sg_key_t *) timer->data;
520 
521  config = igmp_config_lookup (im, timer->sw_if_index);
522  if (!config)
523  goto done;
524  sg = igmp_sg_lookup (config, key);
525  if (!sg)
526  goto done;
527 
528  /* check if this timer is valid */
529  if (timer->exp_time != sg->exp_time)
530  {
531  timer->exp_time = sg->exp_time;
532  igmp_sort_timers (im->timers);
533  return;
534  }
535 
536  /* source timer expired, remove (S,G) */
537  igmp_listen (vm, 0, timer->sw_if_index, key->saddr, key->gaddr, 0);
538 
539 done:
540  pool_put (im->timers, timer);
541 }
542 
543 static uword
545  vlib_frame_t * f)
546 {
547  igmp_main_t *im = &igmp_main;
548  uword *event_data = 0, event_type;
549  f64 time_start;
550  igmp_timer_t *timer = NULL;
551 
552  while (1)
553  {
554  if (NULL != timer)
556  timer->exp_time - time_start);
557  else
559 
560  time_start = vlib_time_now (vm);
561 
562  event_type = vlib_process_get_events (vm, &event_data);
563  vec_reset_length (event_data);
564 
565  if (event_type == IGMP_PROCESS_EVENT_UPDATE_TIMER)
566  goto next_timer;
567 
568  DBG ("time: %f", vlib_time_now (vm));
569 
570  /* timer expired */
571  if (NULL != timer)
572  timer->func (vm, rt, im, timer);
573 
574  next_timer:
575  timer = igmp_get_next_timer (im);
576  }
577  return 0;
578 }
579 
580 /* *INDENT-OFF* */
582 {
583  .function = igmp_timer_process,
584  .type = VLIB_NODE_TYPE_PROCESS,
585  .name = "igmp-timer-process",
586  .n_next_nodes = IGMP_N_NEXT,
587  .next_nodes = {
588  [IGMP_NEXT_IP4_REWRITE_MCAST_NODE] = "ip4-rewrite-mcast",
589  [IGMP_NEXT_IP6_REWRITE_MCAST_NODE] = "ip6-rewrite-mcast",
590  }
591 };
592 /* *INDENT-ON* */
593 
594 int
595 igmp_listen (vlib_main_t * vm, u8 enable, u32 sw_if_index,
596  ip46_address_t saddr, ip46_address_t gaddr,
597  u8 cli_api_configured)
598 {
599  igmp_main_t *im = &igmp_main;
600  igmp_config_t *config;
601  igmp_sg_t *sg;
602  igmp_sg_key_t key;
603  int rv = 0;
604 
605  /* set the lookup key */
606  clib_memcpy (&key.saddr, &saddr, sizeof (ip46_address_t));
607  clib_memcpy (&key.gaddr, &gaddr, sizeof (ip46_address_t));
608 
609  if (enable)
610  {
611  config = igmp_config_lookup (im, sw_if_index);
612  if (!config)
613  {
614  pool_get (im->configs, config);
615  memset (config, 0, sizeof (igmp_config_t));
616  config->sw_if_index = sw_if_index;
617  config->igmp_sg_by_key =
618  hash_create_mem (0, sizeof (igmp_sg_key_t), sizeof (uword));
619  config->cli_api_configured = cli_api_configured;
620  /* use IGMPv3 by default */
621  config->igmp_ver = IGMP_V3;
624  if (!cli_api_configured)
625  {
627  sw_if_index, igmp_send_query);
628  }
629  config->adj_index =
631  config->sw_if_index);
633  config->sw_if_index, config - im->configs);
634  }
635  else if (config->cli_api_configured != cli_api_configured)
636  {
637  rv = -2;
638  goto error;
639  }
640  sg = igmp_sg_lookup (config, &key);
641  if (!sg)
642  {
643  pool_get (config->sg, sg);
644  memset (sg, 0, sizeof (igmp_sg_t));
645  sg->key = clib_mem_alloc (sizeof (igmp_sg_key_t));
646  clib_memcpy (sg->key, &key, sizeof (igmp_sg_key_t));
647  clib_memcpy (&sg->saddr, &saddr, sizeof (ip46_address_t));
648  clib_memcpy (&sg->gaddr, &gaddr, sizeof (ip46_address_t));
649  sg->group_type = IGMP_MEMBERSHIP_GROUP_change_to_filter_include;
650  if (cli_api_configured)
651  {
652  /* create state-changed report timer with zero timeout */
654  }
655  else
656  {
657  sg->group_type = IGMP_MEMBERSHIP_GROUP_mode_is_filter_include;
658  sg->exp_time = vlib_time_now (vm) + IGMP_SG_TIMER;
660  sg->key, igmp_sg_exp);
661  /* notify all registered api clients */
662  igmp_event (im, config, sg);
663  }
664  hash_set_mem (config->igmp_sg_by_key, sg->key, sg - config->sg);
665  }
666  else
667  {
668  rv = -1;
669  goto error;
670  }
671 
672  im->next_index.config_index = config - im->configs;
673  im->next_index.sg_index = sg - config->sg;
674  }
675  else
676  {
677  config = igmp_config_lookup (im, sw_if_index);
678  if (config)
679  {
680  sg = igmp_sg_lookup (config, &key);
681  if (sg)
682  {
683  sg->group_type = IGMP_MEMBERSHIP_GROUP_block_old_sources;
684  im->next_index.config_index = config - im->configs;
685  im->next_index.sg_index = sg - config->sg;
686  /* notify all registered api clients */
687  if (!cli_api_configured)
688  igmp_event (im, config, sg);
689  else
690  igmp_create_int_timer (0, sw_if_index,
692  }
693  else
694  {
695  rv = -1;
696  goto error;
697  }
698  }
699  else
700  {
701  rv = -1;
702  goto error;
703  }
704  }
705 
706 error:
707  return rv;
708 }
709 
710 static clib_error_t *
712 {
713  igmp_main_t *im = &igmp_main;
714  igmp_config_t *config;
715  clib_error_t *error = NULL;
716 
717  /* remove igmp from a down interface to prevent crashes... */
718  config =
719  igmp_config_lookup (im,
721  hw_if_index)->sw_if_index);
722  if (config)
723  {
724  if ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
725  igmp_clear_config (config);
726  }
727  return error;
728 }
729 
731 
732 static clib_error_t *
734 {
735  clib_error_t *error;
736  igmp_main_t *im = &igmp_main;
738  int i;
739 
740  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
741  return error;
742 
743  im->igmp_config_by_sw_if_index = hash_create (0, sizeof (u32));
744  im->igmp_api_client_by_client_index = hash_create (0, sizeof (u32));
747 
748  ip4_register_protocol (IP_PROTOCOL_IGMP, igmp_input_node.index);
749 
750  igmp_type_info_t *ti;
752 #define igmp_type(n,s) \
753 do { \
754  vec_add2 (im->type_infos, ti, 1); \
755  ti->type = n; \
756  ti->name = (u8 *) #s; \
757 } while (0);
758 
759 #define igmp_report_type(n,s) \
760 do { \
761  vec_add2 (im->report_type_infos, rti, 1); \
762  rti->type = n; \
763  rti->name = (u8 *) #s; \
764 } while (0);
765 
766 #include "igmp.def"
767 
768 #undef igmp_type
769 #undef igmp_report_type
770 
771  for (i = 0; i < vec_len (im->type_infos); i++)
772  {
773  ti = im->type_infos + i;
774  hash_set (im->type_info_by_type, ti->type, i);
775  }
776 
777  for (i = 0; i < vec_len (im->report_type_infos); i++)
778  {
779  rti = im->report_type_infos + i;
781  }
782 
783  /* General Query address */
784  ip46_address_t addr0;
785  addr0.ip4.as_u8[0] = 224;
786  addr0.ip4.as_u8[1] = 0;
787  addr0.ip4.as_u8[2] = 0;
788  addr0.ip4.as_u8[3] = 1;
789  /* Report address */
790  ip46_address_t addr1;
791  addr1.ip4.as_u8[0] = 224;
792  addr1.ip4.as_u8[1] = 0;
793  addr1.ip4.as_u8[2] = 0;
794  addr1.ip4.as_u8[3] = 22;
795 
796  fib_route_path_t path = {
798  .frp_addr = zero_addr,
799  .frp_sw_if_index = 0xffffffff,
800  .frp_fib_index = 0,
801  .frp_weight = 0,
802  .frp_flags = FIB_ROUTE_PATH_LOCAL,
803  };
804  const mfib_prefix_t mpfx0 = {
806  .fp_len = 32,
807  .fp_grp_addr = addr0,
808  };
809  const mfib_prefix_t mpfx1 = {
811  .fp_len = 32,
812  .fp_grp_addr = addr1,
813  };
814  /* configure MFIB to accept IGMPv3 general query and reports from all interfaces */
819 
824 
825  return (error);
826 }
827 
829 
830 /* *INDENT-OFF* */
832  .version = VPP_BUILD_VER,
833  .description = "IGMP messaging",
834 };
835 /* *INDENT-ON* */
836 
837 /*
838  * fd.io coding-style-patch-verification: ON
839  *
840  * Local Variables:
841  * eval: (c-set-style "gnu")
842  * End:
843  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:434
igmp_membership_group_v3_type_t type
Definition: igmp_packet.h:121
#define IGMP_CONFIG_FLAG_CAN_SEND_REPORT
Definition: igmp.h:102
u32 sg_index
Definition: igmp.h:64
static igmp_timer_t * igmp_get_next_timer(igmp_main_t *im)
Definition: igmp.c:122
u32 sw_if_index
Definition: igmp.h:171
#define hash_set(h, key, value)
Definition: hash.h:254
vlib_node_registration_t igmp_timer_process_node
(constructor) VLIB_REGISTER_NODE (igmp_timer_process_node)
Definition: igmp.c:581
void * data
Definition: igmp.h:172
igmp_membership_group_v3_t groups[0]
Definition: igmp_packet.h:153
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
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
Definition: node_funcs.h:619
A representation of a path as described by a route producer.
Definition: fib_types.h:455
ip4_address_t src_address
Definition: ip4_packet.h:164
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:122
igmp_main_t igmp_main
Definition: igmp.c:34
#define PREDICT_TRUE(x)
Definition: clib.h:106
#define IGMP_QUERY_TIMER
Definition: igmp.h:28
igmp_index_t next_index
Definition: igmp.h:147
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
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
igmp_config_t * configs
pool of igmp configurations
Definition: igmp.h:141
static void igmp_send_msg(vlib_main_t *vm, vlib_node_runtime_t *node, igmp_main_t *im, igmp_config_t *config, u8 is_report)
Definition: igmp.c:348
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(igmp_hw_interface_link_up_down)
adj_index_t adj_index
Definition: igmp.h:90
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
igmp_membership_group_v3_type_t
Definition: igmp_packet.h:112
static clib_error_t * igmp_hw_interface_link_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: igmp.c:711
int i
#define hash_set_mem(h, key, value)
Definition: hash.h:274
ip_lookup_main_t lookup_main
Definition: ip4.h:97
uword ip_csum_t
Definition: ip_packet.h:90
fib_node_index_t mfib_table_entry_update(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, fib_rpf_id_t rpf_id, mfib_entry_flags_t entry_flags)
Add a new (with no replication) or lock an existing entry.
Definition: mfib_table.c:165
dpo_proto_t frp_proto
The protocol of the address below.
Definition: fib_types.h:460
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:390
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:445
static clib_error_t * igmp_init(vlib_main_t *vm)
Definition: igmp.c:733
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1508
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:227
void igmp_sort_timers(igmp_timer_t *timers)
Definition: igmp.c:68
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
ip46_address_t saddr
Definition: igmp.h:76
void igmp_clear_config(igmp_config_t *config)
Definition: igmp.c:38
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:104
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:440
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
igmp_type_info_t * type_infos
Definition: igmp.h:152
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
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
#define always_inline
Definition: clib.h:92
f64 exp_time
Definition: igmp.h:81
ip4_address_t dst_address
Definition: ip4_packet.h:164
static void igmp_create_report_v32(vlib_buffer_t *b, igmp_config_t *config)
Definition: igmp.c:227
static timer_callback_t * timers
Definition: timer.c:57
igmp_type_t type
Definition: igmp.h:117
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
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
fib_node_index_t mfib_table_entry_path_update(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, const fib_route_path_t *rpath, mfib_itf_flags_t itf_flags)
Add n paths to an entry (aka route) in the FIB.
Definition: mfib_table.c:219
#define vlib_call_init_function(vm, x)
Definition: init.h:162
void igmp_send_state_changed(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
Definition: igmp.c:479
igmp_membership_group_v3_type_t group_type
Definition: igmp.h:78
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:660
u8 ip4_lookup(ip4_address_t *a, igmp_membership_report_v3_t *igmp, u16 n, igmp_membership_group_v3_type_t type)
Definition: igmp.c:200
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
#define hash_unset_mem(h, key)
Definition: hash.h:290
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:108
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:952
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE
Definition: igmp.h:30
int igmp_timer_compare(const void *_a, const void *_b)
Definition: igmp.c:59
uword * igmp_config_by_sw_if_index
Definition: igmp.h:138
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:209
#define hash_free(h)
Definition: hash.h:309
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:273
Definition: igmp.h:51
#define PREDICT_FALSE(x)
Definition: clib.h:105
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
#define pool_free(p)
Free a pool.
Definition: pool.h:354
void( igmp_timer_function_t)(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
Definition: igmp.h:162
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
vlib_main_t * vm
Definition: buffer.c:294
int ip4_address_compare(ip4_address_t *a1, ip4_address_t *a2)
Definition: ip46_cli.c:53
void igmp_event(igmp_main_t *im, igmp_config_t *config, igmp_sg_t *sg)
Definition: igmp_api.c:292
igmp_header_t header
Definition: igmp_packet.h:80
vlib_node_registration_t igmp_input_node
(constructor) VLIB_REGISTER_NODE (igmp_input_node)
Definition: input.c:221
#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
Aggregrate type for a prefix.
Definition: mfib_types.h:24
VLIB_PLUGIN_REGISTER()
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:129
#define hash_create(elts, value_bytes)
Definition: hash.h:681
#define ASSERT(truth)
igmp_sg_key_t * key
Definition: igmp.h:83
unsigned int u32
Definition: types.h:88
ip46_address_t gaddr
Definition: igmp.h:69
igmp_sg_t * sg
Definition: igmp.h:107
igmp_membership_group_v3_type_t type
Definition: igmp.h:123
static void clib_mem_free(void *p)
Definition: mem.h:179
u32 ** buffers
buffer cache
Definition: igmp.h:144
dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto)
Definition: fib_types.c:236
ip46_address_t saddr
Definition: igmp.h:70
void igmp_query_resp_exp(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
Definition: igmp.c:435
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:821
static void * clib_mem_alloc(uword size)
Definition: mem.h:112
u8 robustness_var
Definition: igmp.h:98
void igmp_sg_exp(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
Definition: igmp.c:513
uword * report_type_info_by_report_type
Definition: igmp.h:156
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u64 uword
Definition: types.h:112
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
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:159
fib_protocol_t fp_proto
protocol type
Definition: mfib_types.h:33
Definition: defs.h:47
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
void qsort(void *base, uword n, uword size, int(*compar)(const void *, const void *))
Definition: qsort.c:56
void igmp_create_sg_timer(f64 time, u32 sw_if_index, igmp_sg_key_t *key, igmp_timer_function_t *func)
Definition: igmp.c:102
A for-us/local path.
Definition: fib_types.h:317
#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 uword igmp_timer_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: igmp.c:544
void igmp_send_query(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
Definition: igmp.c:413
u8 cli_api_configured
Definition: igmp.h:92
u32 sw_if_index
Definition: igmp.h:88
igmp_timer_t * timers
pool of igmp timers
Definition: igmp.h:150
f64 exp_time
Definition: igmp.h:168
#define vnet_buffer(b)
Definition: buffer.h:372
static void igmp_create_report_v31(vlib_buffer_t *b, igmp_config_t *config)
Definition: igmp.c:160
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:132
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:818
ip46_address_t gaddr
Definition: igmp.h:75
uword * igmp_sg_by_key
Definition: igmp.h:104
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
adj_index_t adj_mcast_add_or_lock(fib_protocol_t proto, vnet_link_t link_type, u32 sw_if_index)
Mcast Adjacency.
Definition: adj_mcast.c:51
igmp_timer_function_t * func
Definition: igmp.h:169
uword * igmp_api_client_by_client_index
Definition: igmp.h:132
static void igmp_create_ip4(vlib_buffer_t *b, igmp_config_t *config, u8 is_report)
Definition: igmp.c:313
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:172
#define group_ptr(p, l)
Definition: igmp.h:40
u32 flags
Definition: vhost-user.h:77
void igmp_create_int_timer(f64 time, u32 sw_if_index, igmp_timer_function_t *func)
Definition: igmp.c:86
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 config_index
Definition: igmp.h:63
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:111
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:347
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 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:239
igmp_ver_t igmp_ver
Definition: igmp.h:96
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
const ip46_address_t zero_addr
Definition: lookup.c:318
uword * type_info_by_type
Definition: igmp.h:155
Definition: defs.h:46
igmp_report_type_info_t * report_type_infos
Definition: igmp.h:153
static void igmp_create_general_query_v3(vlib_buffer_t *b, igmp_config_t *config)
Definition: igmp.c:286
create_msg_t * next_create_msg
Definition: igmp.h:94
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128