FD.io VPP  v18.07-rc0-415-g6c78436
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 void
38 {
39  igmp_src_t *src;
40 
41  ASSERT (config);
42  ASSERT (group);
43 
44  IGMP_DBG ("group_type %u, sw_if_index %d", group->type,
45  config->sw_if_index);
46 
47  /* *INDENT-OFF* */
48  pool_foreach (src, group->srcs, (
49  {
50  clib_mem_free (src->key);
51  }));
52  /* *INDENT-ON* */
53  pool_free (group->srcs);
54  hash_free (group->igmp_src_by_key);
55 
56  hash_unset_mem (config->igmp_group_by_key, group->key);
57  clib_mem_free (group->key);
58  pool_put (config->groups, group);
59 }
60 
61 void
63 {
64  igmp_main_t *im = &igmp_main;
65  igmp_group_t *group;
66 
67  ASSERT (config);
68  /* *INDENT-OFF* */
69  pool_foreach (group, config->groups, (
70  {
71  igmp_clear_group (config, group);
72  }));
73  /* *INDENT-ON* */
74  pool_free (config->groups);
75  hash_free (config->igmp_group_by_key);
76 
78  pool_put (im->configs, config);
79 }
80 
81 /** \brief igmp timer compare
82  @param _a - igmp timer
83  @param _b - igmp timer
84 
85  Compare function for igmp_timer_t sorting.
86 */
87 int
88 igmp_timer_compare (const void *_a, const void *_b)
89 {
90  const igmp_timer_t *a = _a;
91  const igmp_timer_t *b = _b;
92  f64 dt = b->exp_time - a->exp_time;
93  return dt < 0 ? -1 : (dt > 0 ? +1 : 0);
94 }
95 
96 void
98 {
100 
101  qsort (timers, vec_len (timers), sizeof (igmp_timer_t), igmp_timer_compare);
102 
105 }
106 
107 void
108 igmp_create_int_timer (f64 time, u32 sw_if_index,
109  igmp_timer_function_t * func)
110 {
111  igmp_main_t *im = &igmp_main;
112  igmp_timer_t *timer;
113 
114  pool_get (im->timers, timer);
115  memset (timer, 0, sizeof (igmp_timer_t));
116  timer->func = func;
117  timer->exp_time = time;
118  timer->sw_if_index = sw_if_index;
119 
120  igmp_sort_timers (im->timers);
121 }
122 
123 void
124 igmp_create_group_timer (f64 time, u32 sw_if_index, igmp_key_t * gkey,
125  igmp_timer_function_t * func)
126 {
127  igmp_main_t *im = &igmp_main;
128  igmp_timer_t *timer;
129 
130  pool_get (im->timers, timer);
131  memset (timer, 0, sizeof (igmp_timer_t));
132  timer->func = func;
133  timer->exp_time = time;
134  timer->sw_if_index = sw_if_index;
135 
136 
137  ASSERT (gkey);
138  /* duplicate keys, to prevent segmentation fault if (S,G) is removed */
139  timer->data = clib_mem_alloc (sizeof (igmp_key_t));
140  clib_memcpy (&((igmp_key_t *) timer->data)[0], gkey, sizeof (igmp_key_t));
141 
142  igmp_sort_timers (im->timers);
143 }
144 
145 void
146 igmp_create_src_timer (f64 time, u32 sw_if_index, igmp_key_t * gkey,
147  igmp_key_t * skey, igmp_timer_function_t * func)
148 {
149  igmp_main_t *im = &igmp_main;
150  igmp_timer_t *timer;
151 
152  pool_get (im->timers, timer);
153  memset (timer, 0, sizeof (igmp_timer_t));
154  timer->func = func;
155  timer->exp_time = time;
156  timer->sw_if_index = sw_if_index;
157 
158  ASSERT (gkey);
159  ASSERT (skey);
160  /* duplicate keys, to prevent segmentation fault if (S,G) is removed */
161  timer->data = clib_mem_alloc (sizeof (igmp_key_t) * 2);
162  clib_memcpy (&((igmp_key_t *) timer->data)[0], gkey, sizeof (igmp_key_t));
163  clib_memcpy (&((igmp_key_t *) timer->data)[1], skey, sizeof (igmp_key_t));
164 
165  igmp_sort_timers (im->timers);
166 }
167 
168 /** \brief igmp get next timer
169  @param im - igmp main
170 
171  Get next timer.
172 */
175 {
176  if (pool_elts (im->timers) > 0)
177  return vec_elt_at_index (im->timers, pool_elts (im->timers) - 1);
178  return NULL;
179 }
180 
181 /*
182 static void
183 igmp_create_report_v2 (vlib_buffer_t * b, igmp_config_t * config)
184 {
185  ip_csum_t sum;
186  u16 csum;
187  igmp_main_t *im = &igmp_main;
188  igmp_sg_t *sg;
189 
190  sg = vec_elt_at_index (config->sg, im->next_index.sg_index);
191 
192  igmp_message_t *igmp = (igmp_message_t *) (vlib_buffer_get_current (b));
193  memset (igmp, 0, sizeof (igmp_message_t));
194 
195  clib_memcpy (&igmp->dst, &sg->gaddr.ip4, sizeof (ip4_address_t));
196  igmp->header.type =
197  (sg->group_type == IGMP_MEMBERSHIP_GROUP_block_old_sources) ?
198  IGMP_TYPE_leave_group_v2 : IGMP_TYPE_membership_report_v2;
199  sum = ip_incremental_checksum (0, igmp, sizeof (igmp_message_t));
200  csum = ~ip_csum_fold (sum);
201  igmp->header.checksum = csum;
202 
203  b->current_data += sizeof (igmp_message_t);
204  b->current_length += sizeof (igmp_message_t);
205 }
206 */
207 
208 /* TODO: divide (S,G)s to multiple reports...
209  * - create report limited by <packet size|number of (S,G)s>?
210  * - save loop state
211  * - on next timer continue loop
212  * - case of new query -> reset loop
213  */
214 
215 /** \brief igmp create report all (v3)
216  @param b - vlib buffer
217  @param config - igmp configuration
218  @param group - igmp group
219 
220  Create IGMPv3 report. If group is NULL, send all groups on interface.
221 */
222 static void
224  igmp_group_t * group)
225 {
226  ip_csum_t sum;
227  u16 csum;
228  u32 len = 0;
229  int i;
230 
231  igmp_src_t *src;
232 
233  igmp_membership_group_v3_t *igmp_group;
234 
235  len = sizeof (igmp_membership_report_v3_t);
236 
239  memset (igmp, 0, sizeof (igmp_membership_report_v3_t));
240 
241  igmp->header.type = IGMP_TYPE_membership_report_v3;
242  igmp->n_groups =
243  clib_net_to_host_u16 ((group) ? 1 : pool_elts (config->groups));
244 
245  /* get pointer to first group */
246  igmp_group = igmp->groups;
247 
248  /* if group is not NULL, send the specified group */
249  if (group)
250  {
251  memset (igmp_group, 0, sizeof (igmp_membership_group_v3_t));
252  igmp_group->type = group->type;
253  igmp_group->n_src_addresses =
254  clib_host_to_net_u16 (pool_elts (group->srcs));
255  igmp_group->dst_address = group->addr.ip4;
256  i = 0;
257  /* *INDENT-OFF* */
258  pool_foreach (src, group->srcs, (
259  {
260  igmp_group->src_addresses[i++] = src->addr.ip4;
261  }));
262  /* *INDENT-ON* */
263  len += sizeof (ip4_address_t) * i;
264  len += sizeof (igmp_membership_group_v3_t);
265  }
266  else
267  {
268  /* *INDENT-OFF* */
269  pool_foreach (group, config->groups, (
270  {
271  memset (igmp_group, 0, sizeof (igmp_membership_group_v3_t));
272  igmp_group->type = group->type;
273  igmp_group->n_src_addresses =
274  clib_host_to_net_u16 (pool_elts (group->srcs));
275  igmp_group->dst_address = group->addr.ip4;
276  i = 0;
277  pool_foreach (src, group->srcs, (
278  {
279  igmp_group->src_addresses[i++] = src->addr.ip4;
280  }));
281  len += sizeof (ip4_address_t) * i;
282  len += sizeof (igmp_membership_group_v3_t);
283  igmp_group = group_ptr (igmp, len);
284  }));
285  /* *INDENT-ON* */
286  }
287 
288  sum = ip_incremental_checksum (0, igmp, len);
289  csum = ~ip_csum_fold (sum);
290  igmp->header.checksum = csum;
291 
292  b->current_data += len;
293  b->current_length += len;
294 }
295 
296 /** \brief igmp create query (v3)
297  @param b - vlib buffer
298  @param config - configuration that sends the query
299  @param group - if not NULL, create Group-specific query
300 
301  Create igmp v3 qeury inside vlib buffer b.
302  If group == NULL create general query,
303  else, create group specific query.
304 */
305 static void
307  igmp_group_t * group)
308 {
310  ip_csum_t sum;
311  u16 csum;
312 
315  memset (igmp, 0, sizeof (igmp_membership_query_v3_t));
316 
317  igmp->header.type = IGMP_TYPE_membership_query;
318  igmp->header.code = 100;
319 
321  igmp_create_int_timer (vlib_time_now (vm) + (f64) (igmp->header.code / 10),
323 
324  if (PREDICT_FALSE (group != NULL))
325  clib_memcpy (&igmp->dst, &group->addr.ip4, sizeof (ip4_address_t));
326 
327  sum =
329  csum = ~ip_csum_fold (sum);
330  igmp->header.checksum = csum;
331 
334 }
335 
336 /** \brief igmp create ip4
337  @param b - vlib buffer
338  @param config - igmp configuration
339  @param group - igmp membership group
340  @param is_report - if zero create query, else create report
341 
342  Create ip4 header in vlib buffer b.
343 */
344 static void
346  igmp_group_t * group, u8 is_report)
347 {
349 
351  memset (ip4, 0, sizeof (ip4_header_t));
352  ip4->ip_version_and_header_length = 0x45;
353  ip4->ttl = 1;
354  ip4->protocol = 2;
355  ip4->tos = 0xc0;
356 
357  u32 if_add_index =
359  if (PREDICT_TRUE (if_add_index != ~0))
360  {
361  ip_interface_address_t *if_add =
362  pool_elt_at_index (lm->if_address_pool, if_add_index);
363  ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add);
364  clib_memcpy (&ip4->src_address, if_ip, sizeof (ip4_address_t));
365  }
366 
367  if (is_report)
368  ip4->dst_address.as_u32 =
369  clib_host_to_net_u32 (IGMP_MEMBERSHIP_REPORT_ADDRESS);
370  else
371  {
372  if ((group != NULL))
373  clib_memcpy (&ip4->dst_address, &group->addr.ip4,
374  sizeof (ip4_address_t));
375  else
376  ip4->dst_address.as_u32 =
377  clib_host_to_net_u32 (IGMP_GENERAL_QUERY_ADDRESS);
378  }
379 
380  b->current_data += ip4_header_bytes (ip4);
381  b->current_length += ip4_header_bytes (ip4);
382 
383  config->next_create_msg (b, config, group);
384  ip4->length = clib_host_to_net_u16 (b->current_length);
385 
386  ip4->checksum = ip4_header_checksum (ip4);
387 }
388 
389 
390 /** \brief igmp send message
391  @param vm - vlib main
392  @param node - vlib runtime node
393  @param im - igmp main
394  @param config - igmp configuration
395  @param group - igmp mebership group
396  @param is_report - 0 == qeury, else report
397 
398  Send an igmp message. Get free vlib buffer fill it with igmp packet and transmit.
399 */
400 static void
402  igmp_main_t * im, igmp_config_t * config, igmp_group_t * group,
403  u8 is_report)
404 {
405  u32 thread_index = vlib_get_thread_index ();
406  u32 *to_next;
408 
409  u32 n_free_bufs = vec_len (im->buffers[thread_index]);
410  if (PREDICT_FALSE (n_free_bufs < 1))
411  {
412  vec_validate (im->buffers[thread_index], 1 + n_free_bufs - 1);
413  n_free_bufs +=
414  vlib_buffer_alloc (vm, &im->buffers[thread_index][n_free_bufs], 1);
415  _vec_len (im->buffers[thread_index]) = n_free_bufs;
416  }
417 
418  u32 n_left_to_next;
419  u32 next0 = next_index;
420  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
421 
422  if (n_left_to_next > 0)
423  {
424  vlib_buffer_t *b = 0;
425  u32 bi = 0;
426 
427  if (n_free_bufs)
428  {
429  u32 last_buf = vec_len (im->buffers[thread_index]) - 1;
430  bi = im->buffers[thread_index][last_buf];
431  b = vlib_get_buffer (vm, bi);
432  _vec_len (im->buffers[thread_index]) = last_buf;
433  n_free_bufs--;
434  if (PREDICT_FALSE (n_free_bufs == 0))
435  {
436  n_free_bufs += vlib_buffer_alloc (vm,
437  &im->buffers[thread_index]
438  [n_free_bufs], 1);
439  _vec_len (im->buffers[thread_index]) = n_free_bufs;
440  }
441 
442  b->current_data = 0;
443  b->current_length = 0;
444 
445  igmp_create_ip4 (b, config, group, is_report);
446 
447  b->current_data = 0;
448 
450  b->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
451  vnet_buffer (b)->sw_if_index[VLIB_RX] = (u32) ~ 0;
452  vnet_buffer (b)->ip.adj_index[VLIB_TX] = config->adj_index;
453  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
454  }
455 
456  to_next[0] = bi;
457  to_next += 1;
458  n_left_to_next -= 1;
459 
460  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
461  n_left_to_next, bi, next0);
462  }
463  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
464 }
465 
466 void
468  igmp_timer_t * timer)
469 {
470  igmp_config_t *config;
471 /* TODO: group-specific query: pass group key in timer */
472  igmp_group_t *group = NULL;
473 
474  u32 sw_if_index = timer->sw_if_index;
475 
476  pool_put (im->timers, timer);
477 
478  config = igmp_config_lookup (im, sw_if_index);
479  if (!config)
480  return;
481 
482  /* TODO: implement IGMPv2 */
484  igmp_send_msg (vm, rt, im, config, group, /* is_report */ 0);
485 
486  /* in case of group query we don't want to set up another qery timer */
487  if (PREDICT_TRUE (!group))
490 }
491 
492 void
494  igmp_main_t * im, igmp_timer_t * timer)
495 {
496  igmp_config_t *config;
497 /* TODO: group-specific query: pass group key in timer */
498  igmp_group_t *group = NULL;
499 
500  u32 sw_if_index = timer->sw_if_index;
501 
502  pool_put (im->timers, timer);
503 
504  config = igmp_config_lookup (im, sw_if_index);
505  if (!config)
506  return;
507 
508  /* if group != NULL this is a group-specific qeury timer */
509  if (PREDICT_FALSE (group != NULL))
510  {
511  if ((group->flags & IGMP_GROUP_FLAG_QUERY_RESP_RECVED) == 0)
512  {
513  igmp_clear_group (config, group);
514  return;
515  }
516  }
517  /* if report not received in max resp time clear igmp on interface */
518  if ((config->flags & IGMP_CONFIG_FLAG_QUERY_RESP_RECVED) == 0)
519  {
520  igmp_clear_config (config);
521  }
522 }
523 
524 void
526  igmp_main_t * im, igmp_timer_t * timer)
527 {
528  igmp_config_t *config;
529 
530  u32 sw_if_index = timer->sw_if_index;
531 
532  pool_put (im->timers, timer);
533 
534  config = igmp_config_lookup (im, sw_if_index);
535  if (!config)
536  return;
537 
539  {
540  /* TODO: implement IGMPv2 and IGMPv1 */
542  /* pass NULL as group to send all groups at once */
543  igmp_send_msg (vm, rt, im, config, NULL, /* is_report */ 1);
544  /* WIP: unset flag after all reports sent */
546  }
547 }
548 
549 void
551  igmp_main_t * im, igmp_timer_t * timer)
552 {
553  igmp_config_t *config;
554  igmp_group_t *group;
555  igmp_src_t *src;
556  igmp_key_t gkey;
557 
558  u32 sw_if_index = timer->sw_if_index;
559  IGMP_DBG ("sw_if_index %d", sw_if_index);
560 
561  ASSERT (timer->data);
562  clib_memcpy (&gkey, timer->data, sizeof (igmp_key_t));
563 
564  pool_put (im->timers, timer);
565 
566  config = igmp_config_lookup (im, sw_if_index);
567  if (!config)
568  return;
569 
570  group = igmp_group_lookup (config, &gkey);
571  if (!group)
572  return;
573 
575  igmp_send_msg (vm, rt, im, config, group, /* is_report */ 1);
576 
577  IGMP_DBG ("group_type %u", group->type);
578 
579  if (group->type == IGMP_MEMBERSHIP_GROUP_change_to_filter_include)
580  {
581  igmp_key_t new_gkey;
582  igmp_group_t *new_group;
583  igmp_src_t *new_src;
584 
585  clib_memcpy (&new_gkey.data, &group->addr, sizeof (ip46_address_t));
586  new_gkey.group_type = IGMP_MEMBERSHIP_GROUP_mode_is_filter_include;
587 
588  new_group = igmp_group_lookup (config, &new_gkey);
589  if (!new_group)
590  {
591  IGMP_DBG ("creating new group...");
592  pool_get (config->groups, new_group);
593  /* get valid pointer to old group */
594  group = igmp_group_lookup (config, &gkey);
595 
596  memset (new_group, 0, sizeof (igmp_group_t));
597 
598  clib_memcpy (&new_group->addr, &group->addr,
599  sizeof (ip46_address_t));
600  new_group->n_srcs = 0;
601  new_group->type = new_gkey.group_type;
602 
603  new_group->key = clib_mem_alloc (sizeof (igmp_key_t));
604  clib_memcpy (new_group->key, &new_gkey, sizeof (igmp_key_t));
605  new_group->igmp_src_by_key =
606  hash_create_mem (0, sizeof (igmp_key_t), sizeof (uword));
607  hash_set_mem (config->igmp_group_by_key, new_group->key,
608  new_group - config->groups);
609  }
610  /* *INDENT-OFF* */
611  /* loop through old group sources */
612  pool_foreach (src, group->srcs, (
613  {
614  /* add sources to new group */
615  new_src = igmp_src_lookup (new_group, src->key);
616  if (!new_src)
617  {
618  pool_get (new_group->srcs, new_src);
619  memset (new_src, 0, sizeof (igmp_src_t));
620  new_group->n_srcs += 1;
621  new_src->key = clib_mem_alloc (sizeof (igmp_key_t));
622  clib_memcpy (new_src->key, src->key, sizeof (igmp_key_t));
623  clib_memcpy (&new_src->addr, &src->addr,
624  sizeof (ip46_address_t));
625 
626  hash_set_mem (new_group->igmp_src_by_key, new_src->key,
627  new_src - new_group->srcs);
628  }
629  }));
630  /* *INDENT-ON* */
631  }
632 
633  /* remove group */
634  IGMP_DBG ("remove group");
635  igmp_clear_group (config, group);
636  if (pool_elts (config->groups) == 0)
637  {
638  hash_unset (im->igmp_config_by_sw_if_index, config->sw_if_index);
639  pool_put (im->configs, config);
640  }
641 }
642 
643 void
645  igmp_main_t * im, igmp_timer_t * timer)
646 {
647  igmp_config_t *config;
648  igmp_group_t *group;
649  igmp_src_t *src;
650 
651  ASSERT (timer->data);
652 
653  igmp_key_t *gkey = (igmp_key_t *) & ((igmp_key_t *) timer->data)[0];
654  igmp_key_t *skey = (igmp_key_t *) & ((igmp_key_t *) timer->data)[1];
655 
656  config = igmp_config_lookup (im, timer->sw_if_index);
657  if (!config)
658  goto done;
659  group = igmp_group_lookup (config, gkey);
660  if (!group)
661  goto done;
662  src = igmp_src_lookup (group, skey);
663  if (!src)
664  goto done;
665  /* check if this timer is valid */
666  if (timer->exp_time != src->exp_time)
667  {
668  timer->exp_time = src->exp_time;
669  igmp_sort_timers (im->timers);
670  return;
671  }
672 
673  ip46_address_t saddr;
674  ip46_address_t gaddr;
675  clib_memcpy (&saddr, skey->data, sizeof (ip46_address_t));
676  clib_memcpy (&gaddr, gkey->data, sizeof (ip46_address_t));
677 
678  /* source timer expired, remove src */
679  igmp_listen (vm, 0, timer->sw_if_index, saddr, gaddr, 0);
680 done:
681  clib_mem_free (timer->data);
682  pool_put (im->timers, timer);
683 }
684 
685 /** \brief igmp timer process
686  @param vm - vlib main
687  @param rt - vlib runtime node
688  @param f - vlib frame
689 
690  Handle igmp timers.
691 */
692 static uword
694  vlib_frame_t * f)
695 {
696  igmp_main_t *im = &igmp_main;
697  uword *event_data = 0, event_type;
698  f64 time_start;
699  igmp_timer_t *timer = NULL;
700  while (1)
701  {
702  /* suspend util timer expires */
703  if (NULL != timer)
705  timer->exp_time - time_start);
706  else
708  time_start = vlib_time_now (vm);
709  event_type = vlib_process_get_events (vm, &event_data);
710  vec_reset_length (event_data);
711  if (event_type == IGMP_PROCESS_EVENT_UPDATE_TIMER)
712  goto next_timer;
713  IGMP_DBG ("time: %f", vlib_time_now (vm));
714  /* timer expired */
715  if (NULL != timer && timer->func != NULL)
716  timer->func (vm, rt, im, timer);
717  next_timer:
718  timer = igmp_get_next_timer (im);
719  }
720  return 0;
721 }
722 
723 /* *INDENT-OFF* */
725 {
726  .function = igmp_timer_process,
727  .type = VLIB_NODE_TYPE_PROCESS,
728  .name = "igmp-timer-process",
729  .n_next_nodes = IGMP_N_NEXT,
730  .next_nodes = {
731  [IGMP_NEXT_IP4_REWRITE_MCAST_NODE] = "ip4-rewrite-mcast",
732  [IGMP_NEXT_IP6_REWRITE_MCAST_NODE] = "ip6-rewrite-mcast",
733  }
734 };
735 /* *INDENT-ON* */
736 
737 int
738 igmp_listen (vlib_main_t * vm, u8 enable, u32 sw_if_index,
739  ip46_address_t saddr, ip46_address_t gaddr,
740  u8 cli_api_configured)
741 {
742  igmp_main_t *im = &igmp_main;
743  igmp_config_t *config;
744  igmp_group_t *group;
745  igmp_src_t *src;
746  igmp_key_t skey;
747  igmp_key_t gkey;
748 
750  (cli_api_configured) ?
751  IGMP_MEMBERSHIP_GROUP_change_to_filter_include :
752  IGMP_MEMBERSHIP_GROUP_mode_is_filter_include;
753  int rv = 0;
754 
755  /* set the lookup keys */
756  skey.group_type = 0;
757  gkey.group_type = group_type;
758  clib_memcpy (&skey.data, &saddr, sizeof (ip46_address_t));
759  clib_memcpy (&gkey.data, &gaddr, sizeof (ip46_address_t));
760 
761  if (enable)
762  {
763  /* find configuration, if it dosn't exist, create new */
764  config = igmp_config_lookup (im, sw_if_index);
765  if (!config)
766  {
767  pool_get (im->configs, config);
768  memset (config, 0, sizeof (igmp_config_t));
769  config->sw_if_index = sw_if_index;
770  config->igmp_group_by_key =
771  hash_create_mem (0, sizeof (igmp_key_t), sizeof (uword));
772  config->cli_api_configured = cli_api_configured;
773  /* use IGMPv3 by default */
774  config->igmp_ver = IGMP_V3;
777 
778  if (!cli_api_configured)
779  {
780  /* create qery timer */
782  sw_if_index, igmp_send_query);
783  }
784  config->adj_index =
786  config->sw_if_index);
788  config->sw_if_index, config - im->configs);
789  }
790  else if (config->cli_api_configured != cli_api_configured)
791  {
792  rv = -2;
793  goto error;
794  }
795  /* find igmp group, if it dosn't exist, create new */
796  group = igmp_group_lookup (config, &gkey);
797  if (!group)
798  {
799  pool_get (config->groups, group);
800  memset (group, 0, sizeof (igmp_group_t));
801  group->key = clib_mem_alloc (sizeof (igmp_key_t));
802  clib_memcpy (group->key, &gkey, sizeof (igmp_key_t));
803  clib_memcpy (&group->addr, &gaddr, sizeof (ip46_address_t));
804  group->igmp_src_by_key =
805  hash_create_mem (0, sizeof (igmp_key_t), sizeof (uword));
806  group->n_srcs = 0;
807  group->type = gkey.group_type;
808  if (cli_api_configured)
809  {
810  /* create state-changed report timer with zero timeout */
811  igmp_create_group_timer (0, sw_if_index, group->key,
813  }
814 
815  hash_set_mem (config->igmp_group_by_key, group->key,
816  group - config->groups);
817  }
818  /* find source, if it dosn't exist, create new */
819  src = igmp_src_lookup (group, &skey);
820  if (!src)
821  {
822  pool_get (group->srcs, src);
823  memset (src, 0, sizeof (igmp_src_t));
824  group->n_srcs += 1;
825  src->key = clib_mem_alloc (sizeof (igmp_key_t));
826  clib_memcpy (src->key, &skey, sizeof (igmp_key_t));
827  clib_memcpy (&src->addr, &saddr, sizeof (ip46_address_t));
828  if (!cli_api_configured)
829  {
830  /* arm source timer (after expiration remove (S,G)) */
831  igmp_event (im, config, group, src);
832  src->exp_time = vlib_time_now (vm) + IGMP_SRC_TIMER;
834  group->key, src->key, igmp_src_exp);
835  }
836 
837  hash_set_mem (group->igmp_src_by_key, src->key, src - group->srcs);
838  }
839  else
840  {
841  rv = -1;
842  goto error;
843  }
844  }
845  else
846  {
847  config = igmp_config_lookup (im, sw_if_index);
848  if (config)
849  {
850  gkey.group_type = IGMP_MEMBERSHIP_GROUP_mode_is_filter_include;
851  group = igmp_group_lookup (config, &gkey);
852  if (group)
853  {
854  src = igmp_src_lookup (group, &skey);
855  if (src)
856  {
857  /* add source to block_all_sources group */
858  igmp_key_t new_gkey;
859  igmp_group_t *new_group;
860 
861  clib_memcpy (&new_gkey, &gkey, sizeof (igmp_key_t));
862  new_gkey.group_type =
863  IGMP_MEMBERSHIP_GROUP_block_old_sources;
864  new_group = igmp_group_lookup (config, &new_gkey);
865  if (!new_group)
866  {
867  pool_get (config->groups, new_group);
868 
869  group = igmp_group_lookup (config, &gkey);
870 
871  memset (new_group, 0, sizeof (igmp_group_t));
872  new_group->key = clib_mem_alloc (sizeof (igmp_key_t));
873  clib_memcpy (new_group->key, &new_gkey,
874  sizeof (igmp_key_t));
875  clib_memcpy (&new_group->addr, &group->addr,
876  sizeof (ip46_address_t));
877  new_group->igmp_src_by_key =
878  hash_create_mem (0, sizeof (igmp_key_t),
879  sizeof (uword));
880  new_group->n_srcs = 0;
881  new_group->type = new_gkey.group_type;
882  hash_set_mem (config->igmp_group_by_key, new_group->key,
883  new_group - config->groups);
884  }
885  igmp_src_t *new_src;
886  new_src = igmp_src_lookup (new_group, &skey);
887  if (!new_src)
888  {
889  pool_get (new_group->srcs, new_src);
890  memset (new_src, 0, sizeof (igmp_src_t));
891  new_group->n_srcs += 1;
892  new_src->key = clib_mem_alloc (sizeof (igmp_key_t));
893  clib_memcpy (new_src->key, src->key,
894  sizeof (igmp_key_t));
895  clib_memcpy (&new_src->addr, &src->addr,
896  sizeof (ip46_address_t));
897  hash_set_mem (new_group->igmp_src_by_key, new_src->key,
898  new_src - new_group->srcs);
899  }
900 
901  /* notify all registered api clients */
902  if (!cli_api_configured)
903  igmp_event (im, config, new_group, new_src);
904  else
905  igmp_create_group_timer (0, sw_if_index, new_group->key,
907  /* remove source form mode_is_filter_include group */
908  hash_unset_mem (group->igmp_src_by_key, src->key);
909  clib_mem_free (src->key);
910  pool_put (group->srcs, src);
911  group->n_srcs -= 1;
912  if (group->n_srcs <= 0)
913  igmp_clear_group (config, group);
914  if (pool_elts (config->groups) <= 0)
915  igmp_clear_config (config);
916  }
917  else
918  {
919  rv = -1;
920  goto error;
921  }
922  }
923  else
924  {
925  rv = -1;
926  goto error;
927  }
928  }
929  else
930  {
931  rv = -1;
932  goto error;
933  }
934  }
935 
936 error:
937  return rv;
938 }
939 
940 /** \brief igmp hardware interface link up down
941  @param vnm - vnet main
942  @param hw_if_index - interface hw_if_index
943  @param flags - hw interface flags
944 
945  If an interface goes down, remove its (S,G)s.
946 */
947 static clib_error_t *
949 {
950  igmp_main_t *im = &igmp_main;
951  igmp_config_t *config;
952  clib_error_t *error = NULL;
953  /* remove igmp from a down interface to prevent crashes... */
954  config =
955  igmp_config_lookup (im,
957  hw_if_index)->sw_if_index);
958  if (config)
959  {
960  if ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
961  igmp_clear_config (config);
962  }
963  return error;
964 }
965 
967 
968 /** \brief igmp initialization
969  @param vm - vlib main
970 
971  initialize igmp plugin. Initialize igmp_main, set mfib to allow igmp traffic.
972 */
973 static clib_error_t *
975 {
976  clib_error_t *error;
977  igmp_main_t *im = &igmp_main;
979  int i;
980  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
981  return error;
982  im->igmp_config_by_sw_if_index = hash_create (0, sizeof (u32));
983  im->igmp_api_client_by_client_index = hash_create (0, sizeof (u32));
986  ip4_register_protocol (IP_PROTOCOL_IGMP, igmp_input_node.index);
987  igmp_type_info_t *ti;
989 #define igmp_type(n,s) \
990 do { \
991  vec_add2 (im->type_infos, ti, 1); \
992  ti->type = n; \
993  ti->name = (u8 *) #s; \
994 } while (0);
995 #define igmp_report_type(n,s) \
996 do { \
997  vec_add2 (im->report_type_infos, rti, 1); \
998  rti->type = n; \
999  rti->name = (u8 *) #s; \
1000 } while (0);
1001 #include "igmp.def"
1002 #undef igmp_type
1003 #undef igmp_report_type
1004  for (i = 0; i < vec_len (im->type_infos); i++)
1005  {
1006  ti = im->type_infos + i;
1007  hash_set (im->type_info_by_type, ti->type, i);
1008  }
1009 
1010  for (i = 0; i < vec_len (im->report_type_infos); i++)
1011  {
1012  rti = im->report_type_infos + i;
1014  }
1015 
1016  /* General Query address */
1017  ip46_address_t addr0 = {
1018  .as_u64[0] = 0,
1019  .as_u64[1] = 0
1020  };
1021  addr0.ip4.as_u32 = clib_host_to_net_u32 (IGMP_GENERAL_QUERY_ADDRESS);
1022 
1023  /* Report address */
1024  ip46_address_t addr1 = {
1025  .as_u64[0] = 0,
1026  .as_u64[1] = 0
1027  };
1028  addr1.ip4.as_u32 = clib_host_to_net_u32 (IGMP_MEMBERSHIP_REPORT_ADDRESS);
1029 
1030  fib_route_path_t path = {
1032  .frp_addr = zero_addr,
1033  .frp_sw_if_index = 0xffffffff,
1034  .frp_fib_index = 0,
1035  .frp_weight = 0,
1036  .frp_flags = FIB_ROUTE_PATH_LOCAL,
1037  };
1038 
1039  const mfib_prefix_t mpfx0 = {
1041  .fp_len = 32,
1042  .fp_grp_addr = addr0,
1043  };
1044 
1045  const mfib_prefix_t mpfx1 = {
1047  .fp_len = 32,
1048  .fp_grp_addr = addr1,
1049  };
1050 
1051  /* configure MFIB to accept IGMPv3 general query
1052  * and reports from all interfaces
1053  */
1054  mfib_table_entry_path_update (0, &mpfx0,
1057  mfib_table_entry_path_update (0, &mpfx1,
1064  return (error);
1065 }
1066 
1068 /* *INDENT-OFF* */
1069 VLIB_PLUGIN_REGISTER () = {
1070  .version = VPP_BUILD_VER,
1071  .description = "IGMP messaging",
1072 };
1073 /* *INDENT-ON* */
1074 
1075 /*
1076  * fd.io coding-style-patch-verification: ON
1077  *
1078  * Local Variables:
1079  * eval: (c-set-style "gnu")
1080  * End:
1081  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
igmp_membership_group_v3_type_t type
Definition: igmp.h:121
igmp_membership_group_v3_type_t type
Definition: igmp_packet.h:121
#define IGMP_CONFIG_FLAG_CAN_SEND_REPORT
Definition: igmp.h:160
#define IGMP_GROUP_FLAG_QUERY_RESP_RECVED
reponse to query was received
Definition: igmp.h:127
static igmp_timer_t * igmp_get_next_timer(igmp_main_t *im)
igmp get next timer
Definition: igmp.c:174
u32 sw_if_index
Definition: igmp.h:244
#define hash_set(h, key, value)
Definition: hash.h:255
vlib_node_registration_t igmp_timer_process_node
(constructor) VLIB_REGISTER_NODE (igmp_timer_process_node)
Definition: igmp.c:724
void * data
Definition: igmp.h:245
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:261
a
Definition: bitmap.h:537
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:169
void igmp_clear_group(igmp_config_t *config, igmp_group_t *group)
igmp clear group
Definition: igmp.c:37
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
static int ip4_header_bytes(ip4_header_t *i)
Definition: ip4_packet.h:232
#define NULL
Definition: clib.h:55
igmp source
Definition: igmp.h:94
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:225
u16 n_srcs
Definition: igmp.h:123
igmp_config_t * configs
Definition: igmp.h:208
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(igmp_hw_interface_link_up_down)
adj_index_t adj_index
Definition: igmp.h:148
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
static igmp_group_t * igmp_group_lookup(igmp_config_t *config, igmp_key_t *key)
igmp group lookup
Definition: igmp.h:420
igmp_membership_group_v3_type_t
Definition: igmp_packet.h:112
igmp_src_t * srcs
Definition: igmp.h:130
static clib_error_t * igmp_hw_interface_link_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
igmp hardware interface link up down
Definition: igmp.c:948
int i
#define hash_set_mem(h, key, value)
Definition: hash.h:275
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
ip46_address_t addr
Definition: igmp.h:115
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:458
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:448
#define IGMP_GENERAL_QUERY_ADDRESS
General Query address - 224.0.0.1.
Definition: igmp.h:41
static clib_error_t * igmp_init(vlib_main_t *vm)
igmp initialization
Definition: igmp.c:974
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1584
#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)
igmp sort timers
Definition: igmp.c:97
unsigned char u8
Definition: types.h:56
#define IGMP_DBG(...)
Definition: igmp.h:37
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
void igmp_clear_config(igmp_config_t *config)
igmp clear config
Definition: igmp.c:62
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:104
static void igmp_create_ip4(vlib_buffer_t *b, igmp_config_t *config, igmp_group_t *group, u8 is_report)
igmp create ip4
Definition: igmp.c:345
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:440
igmp_type_info_t * type_infos
Definition: igmp.h:214
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
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
igmp key
Definition: igmp.h:83
#define always_inline
Definition: clib.h:92
ip4_address_t dst_address
Definition: ip4_packet.h:169
static timer_callback_t * timers
Definition: timer.c:57
igmp_type_t type
Definition: igmp.h:174
#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)
igmp send report (igmp_timer_function_t)
Definition: igmp.c:525
u64 data[2]
Definition: igmp.h:85
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
void igmp_src_exp(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
igmp source expiration (igmp_timer_function_t)
Definition: igmp.c:644
unsigned int u32
Definition: types.h:88
u8 flags
Definition: igmp.h:125
f64 exp_time
Definition: igmp.h:98
#define vlib_call_init_function(vm, x)
Definition: init.h:227
void igmp_send_state_changed(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
igmp send state changed (igmp_timer_function_t)
Definition: igmp.c:550
void igmp_create_group_timer(f64 time, u32 sw_if_index, igmp_key_t *gkey, igmp_timer_function_t *func)
igmp create group timer
Definition: igmp.c:124
uword * igmp_group_by_key
Definition: igmp.h:162
void igmp_create_src_timer(f64 time, u32 sw_if_index, igmp_key_t *gkey, igmp_key_t *skey, igmp_timer_function_t *func)
igmp create group timer
Definition: igmp.c:146
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:661
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
static void igmp_create_query_v3(vlib_buffer_t *b, igmp_config_t *config, igmp_group_t *group)
igmp create query (v3)
Definition: igmp.c:306
#define hash_unset_mem(h, key)
Definition: hash.h:291
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
uword * igmp_src_by_key
Definition: igmp.h:129
int igmp_timer_compare(const void *_a, const void *_b)
igmp timer compare
Definition: igmp.c:88
uword * igmp_config_by_sw_if_index
Definition: igmp.h:206
unsigned short u16
Definition: types.h:57
#define IGMP_MEMBERSHIP_REPORT_ADDRESS
Membership Report address - 224.0.0.22.
Definition: igmp.h:43
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
#define hash_free(h)
Definition: hash.h:310
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:273
Definition: igmp.h:58
u64 group_type
Definition: igmp.h:86
#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: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
#define pool_free(p)
Free a pool.
Definition: pool.h:354
#define IGMP_SRC_TIMER
Definition: igmp.h:29
void( igmp_timer_function_t)(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
igmp timer function
Definition: igmp.h:229
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
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
vlib_node_registration_t igmp_input_node
(constructor) VLIB_REGISTER_NODE (igmp_input_node)
Definition: input.c:221
ip46_address_t addr
Definition: igmp.h:96
#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
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:696
void igmp_event(igmp_main_t *im, igmp_config_t *config, igmp_group_t *group, igmp_src_t *src)
igmp event
Definition: igmp_api.c:301
#define ASSERT(truth)
igmp_membership_group_v3_type_t type
Definition: igmp.h:180
static void clib_mem_free(void *p)
Definition: mem.h:179
u32 ** buffers
Definition: igmp.h:210
dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto)
Definition: fib_types.c:236
void igmp_query_resp_exp(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
igmp query response expiration (igmp_timer_function_t)
Definition: igmp.c:493
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:835
static void * clib_mem_alloc(uword size)
Definition: mem.h:112
u8 robustness_var
Definition: igmp.h:156
igmp_key_t * key
Definition: igmp.h:100
uword * report_type_info_by_report_type
Definition: igmp.h:218
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
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
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:152
fib_protocol_t fp_proto
protocol type
Definition: mfib_types.h:33
Definition: defs.h:47
igmp timer
Definition: igmp.h:239
static igmp_config_t * igmp_config_lookup(igmp_main_t *im, u32 sw_if_index)
igmp config lookup
Definition: igmp.h:403
void qsort(void *base, uword n, uword size, int(*compar)(const void *, const void *))
Definition: qsort.c:56
A for-us/local path.
Definition: fib_types.h:317
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
igmp_key_t * key
Definition: igmp.h:119
static uword igmp_timer_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
igmp timer process
Definition: igmp.c:693
igmp group
Definition: igmp.h:113
void igmp_send_query(vlib_main_t *vm, vlib_node_runtime_t *rt, igmp_main_t *im, igmp_timer_t *timer)
igmp send query (igmp_timer_function_t)
Definition: igmp.c:467
u8 cli_api_configured
Definition: igmp.h:150
static void igmp_create_report_v3(vlib_buffer_t *b, igmp_config_t *config, igmp_group_t *group)
igmp create report all (v3)
Definition: igmp.c:223
u64 uword
Definition: types.h:112
u32 sw_if_index
Definition: igmp.h:146
igmp_timer_t * timers
Definition: igmp.h:212
f64 exp_time
Definition: igmp.h:241
#define vnet_buffer(b)
Definition: buffer.h:360
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:832
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:242
uword * igmp_api_client_by_client_index
Definition: igmp.h:202
u8 ip_version_and_header_length
Definition: ip4_packet.h:137
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)
helper macro to get igmp mebership group from pointer plus offset
Definition: igmp.h:46
u32 flags
Definition: vhost-user.h:77
void igmp_create_int_timer(f64 time, u32 sw_if_index, igmp_timer_function_t *func)
igmp create int timer
Definition: igmp.c:108
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:62
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:490
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
igmp_group_t * groups
Definition: igmp.h:164
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:244
igmp_ver_t igmp_ver
Definition: igmp.h:154
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:217
Definition: defs.h:46
igmp_report_type_info_t * report_type_infos
Definition: igmp.h:215
static void igmp_send_msg(vlib_main_t *vm, vlib_node_runtime_t *node, igmp_main_t *im, igmp_config_t *config, igmp_group_t *group, u8 is_report)
igmp send message
Definition: igmp.c:401
create_msg_t * next_create_msg
Definition: igmp.h:152
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128