FD.io VPP  v21.06-1-gbb7418cf9
Vector Packet Processing
igmp_pkt.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 <igmp/igmp_pkt.h>
19 #include <vnet/fib/fib_sas.h>
20 
21 static void
23 {
24  b->current_data += l;
25  b->current_length += l;
26 }
27 
28 static vlib_buffer_t *
30 {
31  vlib_main_t *vm;
33  u32 bi;
34 
35  vm = vlib_get_main ();
36 
37  if (vlib_buffer_alloc (vm, &bi, 1) != 1)
38  return (NULL);
39 
40  b = vlib_get_buffer (vm, bi);
41 
42  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
43  b->flags |= VLIB_BUFFER_IS_TRACED;
44 
45  /* clear out stale data */
46  vnet_buffer (b)->sw_if_index[VLIB_RX] = ~0;
47 
48  /*
49  * save progress in the builder
50  */
51  vec_add1 (bk->buffers, bi);
54 
55  return (b);
56 }
57 
58 static vlib_buffer_t *
60  igmp_msg_type_t msg_type,
61  const igmp_group_t * group)
62 {
65  u8 *option;
66 
67  b = igmp_pkt_get_buffer (bk);
68 
69  if (NULL == b)
70  return (NULL);
71 
72  ip4 = vlib_buffer_get_current (b);
73  clib_memset (ip4, 0, sizeof (ip4_header_t));
74  ip4->ip_version_and_header_length = 0x46;
75  ip4->ttl = 1;
76  ip4->protocol = IP_PROTOCOL_IGMP;
77  ip4->tos = 0xc0;
78 
79  fib_sas4_get (bk->sw_if_index, NULL, &ip4->src_address);
80 
81  vlib_buffer_append (b, sizeof (*ip4));
82  bk->n_avail -= sizeof (*ip4);
83 
84  switch (msg_type)
85  {
86  case IGMP_MSG_REPORT:
88  break;
89  case IGMP_MSG_QUERY:
90  if (group != NULL)
91  clib_memcpy_fast (&ip4->dst_address, &group->key->ip4,
92  sizeof (ip4_address_t));
93  else
95  break;
96  }
97 
98  /* add the router alert options */
99  option = vlib_buffer_get_current (b);
100  option[0] = 0x80 | 20; // IP4_ROUTER_ALERT_OPTION;
101  option[1] = 4; // length
102  option[2] = option[3] = 0;
103 
104  vlib_buffer_append (b, 4);
105  bk->n_avail -= 4;
106 
107  return (b);
108 }
109 
110 static vlib_buffer_t *
112  const igmp_group_t * group)
113 {
115  vlib_buffer_t *b;
116 
117  b = igmp_pkt_build_ip_header (&br->base, IGMP_MSG_REPORT, group);
118 
119  if (NULL == b)
120  return (NULL);
121 
122  report = vlib_buffer_get_current (b);
123  report->header.type = IGMP_TYPE_membership_report_v3;
124  report->header.code = 0;
125  report->header.checksum = 0;
126  report->unused = 0;
127 
129  br->base.n_avail -= sizeof (igmp_membership_report_v3_t);
130  br->base.n_bytes += sizeof (igmp_membership_report_v3_t);
131 
132  return (b);
133 }
134 
135 static void
137 {
138  const igmp_config_t *config;
139  vlib_buffer_t *b;
140  vlib_main_t *vm;
141  vlib_frame_t *f;
142  u32 *to_next;
143  u32 ii;
144 
145  vm = vlib_get_main ();
146  config = igmp_config_lookup (bk->sw_if_index);
147 
148  if (NULL == config)
149  return;
150 
152  to_next = vlib_frame_vector_args (f);
153 
154  vec_foreach_index (ii, bk->buffers)
155  {
156  b = vlib_get_buffer (vm, bk->buffers[ii]);
157  vnet_buffer (b)->ip.adj_index[VLIB_TX] = config->adj_index;
158  to_next[ii] = bk->buffers[ii];
159  f->n_vectors++;
160  }
161 
163 
165  vnet_get_main (), bk->sw_if_index);
166 
167  vec_free (bk->buffers);
168  bk->buffers = 0;
169 }
170 
171 static vlib_buffer_t *
173 {
174  if (NULL == br->base.buffers)
175  return (NULL);
176 
177  return (vlib_get_buffer (vlib_get_main (),
178  br->base.buffers[vec_len (br->base.buffers) - 1]));
179 }
180 
181 static void
183 {
185  ip4_header_t *ip4;
186  vlib_buffer_t *b;
187 
189 
190  b->current_data = 0;
191 
192  ip4 = vlib_buffer_get_current (b);
193  igmp = (igmp_membership_report_v3_t *) (((u32 *) ip4) + 6);
194 
195  igmp->n_groups = clib_host_to_net_u16 (br->n_groups);
196 
197  igmp->header.checksum =
199 
200  ip4->length = clib_host_to_net_u16 (b->current_length);
201  ip4->checksum = ip4_header_checksum (ip4);
202 
203  br->base.n_bytes = br->base.n_avail = br->n_groups = 0;
204 }
205 
206 void
208 {
209  if (NULL == br->base.buffers)
210  return;
211 
213  igmp_pkt_tx (&br->base);
214 }
215 
216 static u32
218 {
219  ASSERT (IGMP_FILTER_MODE_INCLUDE == group->router_filter_mode);
220 
221  return ((hash_elts (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE]) *
222  sizeof (ip4_address_t)) + sizeof (igmp_membership_group_v3_t));
223 }
224 
227  const ip46_address_t * grp,
229 {
231  vlib_buffer_t *b;
232 
234 
235  if (br->base.n_avail < sizeof (igmp_membership_group_v3_t))
236  {
238  b = igmp_pkt_build_report_v3 (br, NULL);
239  if (NULL == b)
240  return (NULL);
241  }
242  br->base.n_avail -= sizeof (igmp_membership_group_v3_t);
243  br->base.n_bytes += sizeof (igmp_membership_group_v3_t);
244  br->n_groups++;
245  br->n_srcs = 0;
246 
247  igmp_group = vlib_buffer_get_current (b);
249 
250  igmp_group->type = type;
251  igmp_group->n_aux_u32s = 0;
252  igmp_group->n_src_addresses = 0;
253  igmp_group->group_address.as_u32 = grp->ip4.as_u32;
254 
255  return (igmp_group);
256 }
257 
258 /**
259  * 4.2.16
260  " If the set of Group Records required in a Report does not fit within
261  * the size limit of a single Report message (as determined by the MTU
262  * of the network on which it will be sent), the Group Records are sent
263  * in as many Report messages as needed to report the entire set.
264 
265  * If a single Group Record contains so many source addresses that it
266  * does not fit within the size limit of a single Report message, if its
267  * Type is not MODE_IS_EXCLUDE or CHANGE_TO_EXCLUDE_MODE, it is split
268  * into multiple Group Records, each containing a different subset of
269  * the source addresses and each sent in a separate Report message. If
270  * its Type is MODE_IS_EXCLUDE or CHANGE_TO_EXCLUDE_MODE, a single Group
271  * Record is sent, containing as many source addresses as can fit, and
272  * the remaining source addresses are not reported; though the choice of
273  * which sources to report is arbitrary, it is preferable to report the
274  * same set of sources in each subsequent report, rather than reporting
275  * different sources each time."
276  */
280  const ip46_address_t * grp,
282  const ip46_address_t * src)
283 {
284  vlib_buffer_t *b;
285 
287 
288  if (br->base.n_avail < sizeof (ip4_address_t))
289  {
290  igmp_group->n_src_addresses = clib_host_to_net_u16 (br->n_srcs);
292  b = igmp_pkt_build_report_v3 (br, NULL);
293  if (NULL == b)
294  return (NULL);
295  igmp_group = igmp_pkt_report_v3_append_group (br, grp, type);
296  }
297 
298  igmp_group->src_addresses[br->n_srcs].as_u32 = src->ip4.as_u32;
299  br->n_srcs++;
300  br->base.n_avail -= sizeof (ip4_address_t);
301  br->base.n_bytes += sizeof (ip4_address_t);
302  vlib_buffer_append (b, sizeof (ip4_address_t));
303 
304  return (igmp_group);
305 }
306 
307 void
309  const ip46_address_t * grp,
310  const ip46_address_t * srcs,
312 {
314  const ip46_address_t *s;
315  vlib_buffer_t *b;
316 
318 
319  if (NULL == b)
320  {
321  b = igmp_pkt_build_report_v3 (br, NULL);
322  if (NULL == b)
323  /* failed to allocate buffer */
324  return;
325  }
326 
327  igmp_group = igmp_pkt_report_v3_append_group (br, grp, type);
328 
329  if (NULL == igmp_group)
330  return;
331 
332  /* *INDENT-OFF* */
333  vec_foreach(s, srcs)
334  {
335  igmp_group = igmp_pkt_report_v3_append_src(br, igmp_group,
336  grp, type, s);
337  if (NULL == igmp_group)
338  return;
339  };
340  /* *INDENT-ON* */
341 
342  igmp_group->n_src_addresses = clib_host_to_net_u16 (br->n_srcs);
343 
344  IGMP_DBG (" ..add-group: %U", format_ip46_address, grp, IP46_TYPE_IP4);
345 }
346 
347 void
349  const igmp_group_t * group,
351 {
353  vlib_buffer_t *b;
354  igmp_src_t *src;
355 
357 
358  if (NULL == b)
359  {
360  b = igmp_pkt_build_report_v3 (br, NULL);
361  if (NULL == b)
362  /* failed to allocate buffer */
363  return;
364  }
365 
366  /*
367  * if the group won't fit in a partially full buffer, start again
368  */
369  if ((0 != br->n_groups) &&
370  (igmp_pkt_report_v3_get_size (group) > br->base.n_avail))
371  {
373  b = igmp_pkt_build_report_v3 (br, NULL);
374  if (NULL == b)
375  /* failed to allocate buffer */
376  return;
377  }
378 
379  igmp_group = igmp_pkt_report_v3_append_group (br, group->key, type);
380 
381  /* *INDENT-OFF* */
382  FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
383  ({
384  igmp_group = igmp_pkt_report_v3_append_src(br, igmp_group,
385  group->key, type,
386  src->key);
387  if (NULL == igmp_group)
388  return;
389  }));
390  /* *INDENT-ON* */
391  igmp_group->n_src_addresses = clib_host_to_net_u16 (br->n_srcs);
392 
393  IGMP_DBG (" ..add-group: %U srcs:%d",
394  format_igmp_key, group->key,
395  hash_elts (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE]));
396 }
397 
398 void
400 {
401  clib_memset (br, 0, sizeof (*br));
403 }
404 
405 static vlib_buffer_t *
407 {
408  if (NULL == bq->base.buffers)
409  return (NULL);
410 
411  return (vlib_get_buffer (vlib_get_main (),
412  bq->base.buffers[vec_len (bq->base.buffers) - 1]));
413 }
414 
415 static vlib_buffer_t *
417  const igmp_group_t * group)
418 {
420  vlib_buffer_t *b;
421 
422  b = igmp_pkt_build_ip_header (&bq->base, IGMP_MSG_QUERY, group);
423 
424  if (NULL == b)
425  return (NULL);
426 
427  query = vlib_buffer_get_current (b);
428  query->header.type = IGMP_TYPE_membership_query;
429  query->header.code = 0;
430  query->header.checksum = 0;
431  query->qqi_code = 0;
432  query->resv_s_qrv = 0;
433 
434  if (NULL != group)
435  query->group_address.as_u32 = group->key->ip4.as_u32;
436  else
437  query->group_address.as_u32 = 0;
438 
440  bq->base.n_avail -= sizeof (igmp_membership_query_v3_t);
441  bq->base.n_bytes += sizeof (igmp_membership_query_v3_t);
442 
443  return (b);
444 }
445 
446 void
448  const igmp_group_t * group,
449  const ip46_address_t * srcs)
450 {
451  vlib_buffer_t *b;
452 
454 
455  if (NULL == b)
456  {
457  b = igmp_pkt_build_query_v3 (bq, group);
458  if (NULL == b)
459  /* failed to allocate buffer */
460  return;
461  }
462 
463  if (NULL != srcs)
464  {
466  const ip46_address_t *src;
467 
468  query = vlib_buffer_get_current (b);
469 
470  vec_foreach (src, srcs)
471  {
472  query->src_addresses[bq->n_srcs++].as_u32 = src->ip4.as_u32;
473 
474  vlib_buffer_append (b, sizeof (ip4_address_t));
475  bq->base.n_bytes += sizeof (ip4_address_t);
476  bq->base.n_avail += sizeof (ip4_address_t);
477  }
478  }
479  /*
480  * else
481  * general query and we're done
482  */
483 }
484 
485 static void
487 {
489  ip4_header_t *ip4;
490  vlib_buffer_t *b;
491 
493 
494  b->current_data = 0;
495 
496  ip4 = vlib_buffer_get_current (b);
497  // account for options
498  igmp = (igmp_membership_query_v3_t *) (((u32 *) ip4) + 6);
499 
500  igmp->n_src_addresses = clib_host_to_net_u16 (bq->n_srcs);
501 
502  igmp->header.checksum =
504 
505  ip4->length = clib_host_to_net_u16 (b->current_length);
506  ip4->checksum = ip4_header_checksum (ip4);
507 
508  bq->base.n_bytes = bq->base.n_avail = bq->n_srcs = 0;
509 }
510 
511 void
513 {
514  if (NULL == bq->base.buffers)
515  return;
516 
518  igmp_pkt_tx (&bq->base);
519 }
520 
521 void
523 {
524  clib_memset (bq, 0, sizeof (*bq));
526 }
527 
528 /*
529  * fd.io coding-style-patch-verification: ON
530  *
531  * Local Variables:
532  * eval: (c-set-style "gnu")
533  * End:
534  */
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:133
igmp_membership_group_v3_type_t type
Definition: igmp_packet.h:149
igmp_pkt_build_t base
Definition: igmp_pkt.h:33
#define vec_foreach_index(var, v)
Iterate over vector indices.
u8 * format_igmp_key(u8 *s, va_list *args)
Definition: igmp_format.c:203
void igmp_pkt_query_v3_send(igmp_pkt_build_query_t *bq)
Definition: igmp_pkt.c:512
ip4_address_t src_address
Definition: ip4_packet.h:125
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:115
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:119
static void vlib_buffer_append(vlib_buffer_t *b, uword l)
Definition: igmp_pkt.c:22
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
adj_index_t adj_index
Definition: igmp_config.h:57
void igmp_pkt_report_v3_add_group(igmp_pkt_build_report_t *br, const igmp_group_t *group, igmp_membership_group_v3_type_t type)
Definition: igmp_pkt.c:348
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:122
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
typedef igmp_group
Used by a &#39;host&#39; to enable the reception/listening of packets for a specific multicast group...
Definition: igmp.api:66
igmp_membership_group_v3_type_t
Definition: igmp_packet.h:140
vl_api_address_t src
Definition: gre.api:54
static u32 vnet_sw_interface_get_mtu(vnet_main_t *vnm, u32 sw_if_index, vnet_mtu_t af)
#define IGMP_GENERAL_QUERY_ADDRESS
General Query address - 224.0.0.1 Membership Report address - 224.0.0.22 SSM default range 232/8...
Definition: igmp.h:51
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
vlib_buffer_t ** b
void igmp_pkt_build_report_init(igmp_pkt_build_report_t *br, u32 sw_if_index)
Definition: igmp_pkt.c:399
#define IGMP_DBG(...)
Definition: igmp.h:38
unsigned int u32
Definition: types.h:88
vlib_node_registration_t ip4_rewrite_mcast_node
(constructor) VLIB_REGISTER_NODE (ip4_rewrite_mcast_node)
Definition: ip4_forward.c:2641
vlib_frame_t * f
enum igmp_msg_type_t_ igmp_msg_type_t
ip4_address_t dst_address
Definition: ip4_packet.h:125
static vlib_buffer_t * igmp_pkt_build_ip_header(igmp_pkt_build_t *bk, igmp_msg_type_t msg_type, const igmp_group_t *group)
Definition: igmp_pkt.c:59
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:184
vnet_main_t * vnet_get_main(void)
static vlib_buffer_t * igmp_pkt_build_report_get_active(igmp_pkt_build_report_t *br)
Definition: igmp_pkt.c:172
igmp_pkt_build_t base
Definition: igmp_pkt.h:57
void igmp_pkt_report_v3_send(igmp_pkt_build_report_t *br)
Definition: igmp_pkt.c:207
vl_api_fib_path_type_t type
Definition: fib_types.api:123
igmp_config_t * igmp_config_lookup(u32 sw_if_index)
igmp config lookup
Definition: igmp_config.c:45
static void igmp_pkt_build_query_bake(igmp_pkt_build_query_t *bq)
Definition: igmp_pkt.c:486
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
static vlib_buffer_t * igmp_pkt_build_query_get_active(igmp_pkt_build_query_t *bq)
Definition: igmp_pkt.c:406
static __clib_warn_unused_result u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:708
#define IGMP_MEMBERSHIP_REPORT_ADDRESS
Definition: igmp.h:52
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:218
static vlib_buffer_t * igmp_pkt_get_buffer(igmp_pkt_build_t *bk)
Definition: igmp_pkt.c:29
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:257
vl_api_ip4_address_t ip4
Definition: one.api:376
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
igmp_type_t type
Definition: igmp_packet.h:70
static void igmp_pkt_tx(igmp_pkt_build_t *bk)
Definition: igmp_pkt.c:136
format_function_t format_ip46_address
Definition: ip46_address.h:50
static igmp_membership_group_v3_t * igmp_pkt_report_v3_append_src(igmp_pkt_build_report_t *br, igmp_membership_group_v3_t *igmp_group, const ip46_address_t *grp, igmp_membership_group_v3_type_t type, const ip46_address_t *src)
4.2.16 " If the set of Group Records required in a Report does not fit within the size limit of a sin...
Definition: igmp_pkt.c:278
u16 n_vectors
Definition: node.h:388
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
static u32 igmp_pkt_report_v3_get_size(const igmp_group_t *group)
Definition: igmp_pkt.c:217
void igmp_pkt_query_v3_add_group(igmp_pkt_build_query_t *bq, const igmp_group_t *group, const ip46_address_t *srcs)
Definition: igmp_pkt.c:447
static vlib_buffer_t * igmp_pkt_build_query_v3(igmp_pkt_build_query_t *bq, const igmp_group_t *group)
Definition: igmp_pkt.c:416
static uword hash_elts(void *v)
Definition: hash.h:118
#define ASSERT(truth)
void igmp_pkt_report_v3_add_report(igmp_pkt_build_report_t *br, const ip46_address_t *grp, const ip46_address_t *srcs, igmp_membership_group_v3_type_t type)
Definition: igmp_pkt.c:308
ip_dscp_t tos
Definition: ip4_packet.h:96
static vlib_buffer_t * igmp_pkt_build_report_v3(igmp_pkt_build_report_t *br, const igmp_group_t *group)
Definition: igmp_pkt.c:111
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
ip4_address_t group_address
Definition: igmp_packet.h:158
static igmp_membership_group_v3_t * igmp_pkt_report_v3_append_group(igmp_pkt_build_report_t *br, const ip46_address_t *grp, igmp_membership_group_v3_type_t type)
Definition: igmp_pkt.c:226
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
igmp_filter_mode_t router_filter_mode
The current filter mode of the group (see 6.2.1)
Definition: igmp_group.h:72
IGMP interface configuration.
Definition: igmp_config.h:47
static void igmp_pkt_build_report_bake(igmp_pkt_build_report_t *br)
Definition: igmp_pkt.c:182
Definition: defs.h:47
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define FOR_EACH_SRC(_src, _group, _filter, _body)
Definition: igmp_group.h:90
igmp_key_t * key
The group&#39;s key within the per-interface config.
Definition: igmp_group.h:59
bool fib_sas4_get(u32 sw_if_index, const ip4_address_t *dst, ip4_address_t *src)
Get an IPv4 Source address to use in a packet being sent out an interface.
Definition: fib_sas.c:50
IGMP group A multicast group address for which reception has been requested.
Definition: igmp_group.h:56
VLIB buffer representation.
Definition: buffer.h:111
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
igmp_key_t * key
The source&#39;s key.
Definition: igmp_src.h:46
void igmp_pkt_build_query_init(igmp_pkt_build_query_t *bq, u32 sw_if_index)
Definition: igmp_pkt.c:522
#define vnet_buffer(b)
Definition: buffer.h:437
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:160
#define vec_foreach(var, vec)
Vector iterator.
u8 ip_version_and_header_length
Definition: ip4_packet.h:93
uword * igmp_src_by_key[IGMP_N_FILTER_MODES]
Source list per-filter mode.
Definition: igmp_group.h:87
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:319
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:111
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:314
IGMP source The representation of a specified source address with in multicast group.
Definition: igmp_src.h:41
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:301
Definition: defs.h:46
ip4_address_t group_address
Definition: igmp_packet.h:105