FD.io VPP  v19.01.3-6-g70449b9b9
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 
20 static void
22 {
23  b->current_data += l;
24  b->current_length += l;
25 }
26 
27 static vlib_buffer_t *
29 {
31  vlib_main_t *vm;
32  vlib_buffer_t *b;
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);
44 
45  b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
46  b->flags |= VLIB_BUFFER_IS_TRACED;
47 
48  /* clear out stale data */
49  vnet_buffer (b)->sw_if_index[VLIB_RX] = ~0;
50 
51  /*
52  * save progress in the builder
53  */
54  vec_add1 (bk->buffers, bi);
57 
58  return (b);
59 }
60 
61 static vlib_buffer_t *
63  igmp_msg_type_t msg_type,
64  const igmp_group_t * group)
65 {
66  ip4_header_t *ip4;
67  vlib_buffer_t *b;
68  u8 *option;
69 
70  b = igmp_pkt_get_buffer (bk);
71 
72  if (NULL == b)
73  return (NULL);
74 
75  ip4 = vlib_buffer_get_current (b);
76  clib_memset (ip4, 0, sizeof (ip4_header_t));
77  ip4->ip_version_and_header_length = 0x46;
78  ip4->ttl = 1;
79  ip4->protocol = IP_PROTOCOL_IGMP;
80  ip4->tos = 0xc0;
81 
83  bk->sw_if_index, &ip4->src_address);
84 
85  vlib_buffer_append (b, sizeof (*ip4));
86  bk->n_avail -= sizeof (*ip4);
87 
88  switch (msg_type)
89  {
90  case IGMP_MSG_REPORT:
92  break;
93  case IGMP_MSG_QUERY:
94  if (group != NULL)
95  clib_memcpy_fast (&ip4->dst_address, &group->key->ip4,
96  sizeof (ip4_address_t));
97  else
99  break;
100  }
101 
102  /* add the router alert options */
103  option = vlib_buffer_get_current (b);
104  option[0] = 0x80 | 20; // IP4_ROUTER_ALERT_OPTION;
105  option[1] = 4; // length
106  option[2] = option[3] = 0;
107 
108  vlib_buffer_append (b, 4);
109  bk->n_avail -= 4;
110 
111  return (b);
112 }
113 
114 static vlib_buffer_t *
116  const igmp_group_t * group)
117 {
119  vlib_buffer_t *b;
120 
121  b = igmp_pkt_build_ip_header (&br->base, IGMP_MSG_REPORT, group);
122 
123  if (NULL == b)
124  return (NULL);
125 
126  report = vlib_buffer_get_current (b);
127  report->header.type = IGMP_TYPE_membership_report_v3;
128  report->header.code = 0;
129  report->header.checksum = 0;
130  report->unused = 0;
131 
133  br->base.n_avail -= sizeof (igmp_membership_report_v3_t);
134  br->base.n_bytes += sizeof (igmp_membership_report_v3_t);
135 
136  return (b);
137 }
138 
139 static void
141 {
142  const igmp_config_t *config;
143  vlib_buffer_t *b;
144  vlib_main_t *vm;
145  vlib_frame_t *f;
146  u32 *to_next;
147  u32 ii;
148 
149  vm = vlib_get_main ();
150  config = igmp_config_lookup (bk->sw_if_index);
151 
152  if (NULL == config)
153  return;
154 
156  to_next = vlib_frame_vector_args (f);
157 
158  vec_foreach_index (ii, bk->buffers)
159  {
160  b = vlib_get_buffer (vm, bk->buffers[ii]);
161  vnet_buffer (b)->ip.adj_index[VLIB_TX] = config->adj_index;
162  to_next[ii] = bk->buffers[ii];
163  f->n_vectors++;
164  }
165 
167 
169  vnet_get_main (), bk->sw_if_index);
170 
171  vec_free (bk->buffers);
172  bk->buffers = 0;
173 }
174 
175 static vlib_buffer_t *
177 {
178  if (NULL == br->base.buffers)
179  return (NULL);
180 
181  return (vlib_get_buffer (vlib_get_main (),
182  br->base.buffers[vec_len (br->base.buffers) - 1]));
183 }
184 
185 static void
187 {
189  ip4_header_t *ip4;
190  vlib_buffer_t *b;
191 
193 
194  b->current_data = 0;
195 
196  ip4 = vlib_buffer_get_current (b);
197  igmp = (igmp_membership_report_v3_t *) (((u32 *) ip4) + 6);
198 
199  igmp->n_groups = clib_host_to_net_u16 (br->n_groups);
200 
201  igmp->header.checksum =
203 
204  ip4->length = clib_host_to_net_u16 (b->current_length);
205  ip4->checksum = ip4_header_checksum (ip4);
206 
207  br->base.n_bytes = br->base.n_avail = br->n_groups = 0;
208 }
209 
210 void
212 {
213  if (NULL == br->base.buffers)
214  return;
215 
217  igmp_pkt_tx (&br->base);
218 }
219 
220 static u32
222 {
223  ASSERT (IGMP_FILTER_MODE_INCLUDE == group->router_filter_mode);
224 
225  return ((hash_elts (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE]) *
226  sizeof (ip4_address_t)) + sizeof (igmp_membership_group_v3_t));
227 }
228 
231  const ip46_address_t * grp,
233 {
234  igmp_membership_group_v3_t *igmp_group;
235  vlib_buffer_t *b;
236 
238 
239  if (br->base.n_avail < sizeof (igmp_membership_group_v3_t))
240  {
242  b = igmp_pkt_build_report_v3 (br, NULL);
243  if (NULL == b)
244  return (NULL);
245  }
246  br->base.n_avail -= sizeof (igmp_membership_group_v3_t);
247  br->base.n_bytes += sizeof (igmp_membership_group_v3_t);
248  br->n_groups++;
249  br->n_srcs = 0;
250 
251  igmp_group = vlib_buffer_get_current (b);
253 
254  igmp_group->type = type;
255  igmp_group->n_aux_u32s = 0;
256  igmp_group->n_src_addresses = 0;
257  igmp_group->group_address.as_u32 = grp->ip4.as_u32;
258 
259  return (igmp_group);
260 }
261 
262 /**
263  * 4.2.16
264  " If the set of Group Records required in a Report does not fit within
265  * the size limit of a single Report message (as determined by the MTU
266  * of the network on which it will be sent), the Group Records are sent
267  * in as many Report messages as needed to report the entire set.
268 
269  * If a single Group Record contains so many source addresses that it
270  * does not fit within the size limit of a single Report message, if its
271  * Type is not MODE_IS_EXCLUDE or CHANGE_TO_EXCLUDE_MODE, it is split
272  * into multiple Group Records, each containing a different subset of
273  * the source addresses and each sent in a separate Report message. If
274  * its Type is MODE_IS_EXCLUDE or CHANGE_TO_EXCLUDE_MODE, a single Group
275  * Record is sent, containing as many source addresses as can fit, and
276  * the remaining source addresses are not reported; though the choice of
277  * which sources to report is arbitrary, it is preferable to report the
278  * same set of sources in each subsequent report, rather than reporting
279  * different sources each time."
280  */
283  igmp_membership_group_v3_t * igmp_group,
284  const ip46_address_t * grp,
286  const ip46_address_t * src)
287 {
288  vlib_buffer_t *b;
289 
291 
292  if (br->base.n_avail < sizeof (ip4_address_t))
293  {
294  igmp_group->n_src_addresses = clib_host_to_net_u16 (br->n_srcs);
296  b = igmp_pkt_build_report_v3 (br, NULL);
297  if (NULL == b)
298  return (NULL);
299  igmp_group = igmp_pkt_report_v3_append_group (br, grp, type);
300  }
301 
302  igmp_group->src_addresses[br->n_srcs].as_u32 = src->ip4.as_u32;
303  br->n_srcs++;
304  br->base.n_avail -= sizeof (ip4_address_t);
305  br->base.n_bytes += sizeof (ip4_address_t);
306  vlib_buffer_append (b, sizeof (ip4_address_t));
307 
308  return (igmp_group);
309 }
310 
311 void
313  const ip46_address_t * grp,
314  const ip46_address_t * srcs,
316 {
317  igmp_membership_group_v3_t *igmp_group;
318  const ip46_address_t *s;
319  vlib_buffer_t *b;
320 
322 
323  if (NULL == b)
324  {
325  b = igmp_pkt_build_report_v3 (br, NULL);
326  if (NULL == b)
327  /* failed to allocate buffer */
328  return;
329  }
330 
331  igmp_group = igmp_pkt_report_v3_append_group (br, grp, type);
332 
333  if (NULL == igmp_group)
334  return;
335 
336  /* *INDENT-OFF* */
337  vec_foreach(s, srcs)
338  {
339  igmp_group = igmp_pkt_report_v3_append_src(br, igmp_group,
340  grp, type, s);
341  if (NULL == igmp_group)
342  return;
343  };
344  /* *INDENT-ON* */
345 
346  igmp_group->n_src_addresses = clib_host_to_net_u16 (br->n_srcs);
347 
348  IGMP_DBG (" ..add-group: %U", format_ip46_address, grp, IP46_TYPE_IP4);
349 }
350 
351 void
353  const igmp_group_t * group,
355 {
356  igmp_membership_group_v3_t *igmp_group;
357  vlib_buffer_t *b;
358  igmp_src_t *src;
359 
361 
362  if (NULL == b)
363  {
364  b = igmp_pkt_build_report_v3 (br, NULL);
365  if (NULL == b)
366  /* failed to allocate buffer */
367  return;
368  }
369 
370  /*
371  * if the group won't fit in a partially full buffer, start again
372  */
373  if ((0 != br->n_groups) &&
374  (igmp_pkt_report_v3_get_size (group) > br->base.n_avail))
375  {
377  b = igmp_pkt_build_report_v3 (br, NULL);
378  if (NULL == b)
379  /* failed to allocate buffer */
380  return;
381  }
382 
383  igmp_group = igmp_pkt_report_v3_append_group (br, group->key, type);
384 
385  /* *INDENT-OFF* */
386  FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
387  ({
388  igmp_group = igmp_pkt_report_v3_append_src(br, igmp_group,
389  group->key, type,
390  src->key);
391  if (NULL == igmp_group)
392  return;
393  }));
394  /* *INDENT-ON* */
395  igmp_group->n_src_addresses = clib_host_to_net_u16 (br->n_srcs);
396 
397  IGMP_DBG (" ..add-group: %U srcs:%d",
398  format_igmp_key, group->key,
399  hash_elts (group->igmp_src_by_key[IGMP_FILTER_MODE_INCLUDE]));
400 }
401 
402 void
404 {
405  clib_memset (br, 0, sizeof (*br));
407 }
408 
409 static vlib_buffer_t *
411 {
412  if (NULL == bq->base.buffers)
413  return (NULL);
414 
415  return (vlib_get_buffer (vlib_get_main (),
416  bq->base.buffers[vec_len (bq->base.buffers) - 1]));
417 }
418 
419 static vlib_buffer_t *
421  const igmp_group_t * group)
422 {
424  vlib_buffer_t *b;
425 
426  b = igmp_pkt_build_ip_header (&bq->base, IGMP_MSG_QUERY, group);
427 
428  if (NULL == b)
429  return (NULL);
430 
431  query = vlib_buffer_get_current (b);
432  query->header.type = IGMP_TYPE_membership_query;
433  query->header.code = 0;
434  query->header.checksum = 0;
435  query->qqi_code = 0;
436  query->resv_s_qrv = 0;
437 
438  if (NULL != group)
439  query->group_address.as_u32 = group->key->ip4.as_u32;
440  else
441  query->group_address.as_u32 = 0;
442 
444  bq->base.n_avail -= sizeof (igmp_membership_query_v3_t);
445  bq->base.n_bytes += sizeof (igmp_membership_query_v3_t);
446 
447  return (b);
448 }
449 
450 void
452  const igmp_group_t * group,
453  const ip46_address_t * srcs)
454 {
455  vlib_buffer_t *b;
456 
458 
459  if (NULL == b)
460  {
461  b = igmp_pkt_build_query_v3 (bq, group);
462  if (NULL == b)
463  /* failed to allocate buffer */
464  return;
465  }
466 
467  if (NULL != srcs)
468  {
470  const ip46_address_t *src;
471 
472  query = vlib_buffer_get_current (b);
473 
474  vec_foreach (src, srcs)
475  {
476  query->src_addresses[bq->n_srcs++].as_u32 = src->ip4.as_u32;
477 
478  vlib_buffer_append (b, sizeof (ip4_address_t));
479  bq->base.n_bytes += sizeof (ip4_address_t);
480  bq->base.n_avail += sizeof (ip4_address_t);
481  }
482  }
483  /*
484  * else
485  * general query and we're done
486  */
487 }
488 
489 static void
491 {
493  ip4_header_t *ip4;
494  vlib_buffer_t *b;
495 
497 
498  b->current_data = 0;
499 
500  ip4 = vlib_buffer_get_current (b);
501  // account for options
502  igmp = (igmp_membership_query_v3_t *) (((u32 *) ip4) + 6);
503 
504  igmp->n_src_addresses = clib_host_to_net_u16 (bq->n_srcs);
505 
506  igmp->header.checksum =
508 
509  ip4->length = clib_host_to_net_u16 (b->current_length);
510  ip4->checksum = ip4_header_checksum (ip4);
511 
512  bq->base.n_bytes = bq->base.n_avail = bq->n_srcs = 0;
513 }
514 
515 void
517 {
518  if (NULL == bq->base.buffers)
519  return;
520 
522  igmp_pkt_tx (&bq->base);
523 }
524 
525 void
527 {
528  clib_memset (bq, 0, sizeof (*bq));
530 }
531 
532 /*
533  * fd.io coding-style-patch-verification: ON
534  *
535  * Local Variables:
536  * eval: (c-set-style "gnu")
537  * End:
538  */
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.
vl_api_address_t src
Definition: vxlan_gbp.api:32
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:516
ip4_address_t src_address
Definition: ip4_packet.h:170
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:115
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
static void vlib_buffer_append(vlib_buffer_t *b, uword l)
Definition: igmp_pkt.c:21
#define NULL
Definition: clib.h:58
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:352
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:525
igmp_membership_group_v3_type_t
Definition: igmp_packet.h:140
format_function_t format_ip46_address
Definition: format.h:61
ip_lookup_main_t lookup_main
Definition: ip4.h:98
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
void igmp_pkt_build_report_init(igmp_pkt_build_report_t *br, u32 sw_if_index)
Definition: igmp_pkt.c:403
#define IGMP_DBG(...)
Definition: igmp.h:38
vlib_node_registration_t ip4_rewrite_mcast_node
(constructor) VLIB_REGISTER_NODE (ip4_rewrite_mcast_node)
Definition: ip4_forward.c:2577
enum igmp_msg_type_t_ igmp_msg_type_t
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:110
u32 sw_if_index
Definition: vxlan_gbp.api:37
ip4_address_t dst_address
Definition: ip4_packet.h:170
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:62
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:181
unsigned int u32
Definition: types.h:88
static vlib_buffer_t * igmp_pkt_build_report_get_active(igmp_pkt_build_report_t *br)
Definition: igmp_pkt.c:176
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:211
#define fl(x, y)
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:490
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:114
static vlib_buffer_t * igmp_pkt_build_query_get_active(igmp_pkt_build_query_t *bq)
Definition: igmp_pkt.c:410
#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:190
static vlib_buffer_t * igmp_pkt_get_buffer(igmp_pkt_build_t *bk)
Definition: igmp_pkt.c:28
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:214
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:442
igmp_type_t type
Definition: igmp_packet.h:70
static void igmp_pkt_tx(igmp_pkt_build_t *bk)
Definition: igmp_pkt.c:140
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:282
u16 n_vectors
Definition: node.h:420
vlib_main_t * vm
Definition: buffer.c:301
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
static u32 igmp_pkt_report_v3_get_size(const igmp_group_t *group)
Definition: igmp_pkt.c:221
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:451
static ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_packet.h:254
static vlib_buffer_t * igmp_pkt_build_query_v3(igmp_pkt_build_query_t *bq, const igmp_group_t *group)
Definition: igmp_pkt.c:420
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:312
static vlib_buffer_t * igmp_pkt_build_report_v3(igmp_pkt_build_report_t *br, const igmp_group_t *group)
Definition: igmp_pkt.c:115
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:230
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
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:186
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
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:495
IGMP group A multicast group address for which reception has been requested.
Definition: igmp_group.h:56
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:244
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:526
static void vlib_buffer_init_for_free_list(vlib_buffer_t *dst, vlib_buffer_free_list_t *fl)
#define vnet_buffer(b)
Definition: buffer.h:368
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:160
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:903
#define vec_foreach(var, vec)
Vector iterator.
u8 ip_version_and_header_length
Definition: ip4_packet.h:138
static vlib_buffer_free_list_t * vlib_buffer_get_free_list(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index)
Definition: buffer_funcs.h:657
uword * igmp_src_by_key[IGMP_N_FILTER_MODES]
Source list per-filter mode.
Definition: igmp_group.h:87
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:117
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:485
static int ip4_src_address_for_packet(ip_lookup_main_t *lm, u32 sw_if_index, ip4_address_t *src)
Definition: ip4.h:198
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:247
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:237
Definition: defs.h:46
ip4_address_t group_address
Definition: igmp_packet.h:105