FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
igmp_query.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 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_query.h>
19 #include <igmp/igmp_pkt.h>
20 
21 static f64
23 {
24  u32 seed;
25 
26  seed = vlib_time_now (vlib_get_main ());
27 
28  return ((random_f64 (&seed) * igmp_header_get_max_resp_time (header)));
29 
30 }
31 
32 static ip46_address_t *
34 {
35  ip46_address_t *srcs = NULL;
36  const ip4_address_t *s;
37  u16 ii, n;
38 
39  /*
40  * we validated this packet when we accepted it in the DP, so
41  * this number is safe to use
42  */
43  n = clib_net_to_host_u16 (q->n_src_addresses);
44 
45  if (0 == n)
46  return (NULL);
47 
48  vec_validate (srcs, n - 1);
49  s = q->src_addresses;
50 
51  for (ii = 0; ii < n; ii++)
52  {
53  srcs[ii].ip4 = *s;
54  s++;
55  }
56 
57  return (srcs);
58 }
59 
60 static void
62 {
64  igmp_config_t *config;
65  ip46_address_t *srcs;
66  igmp_group_t *group;
67  igmp_main_t *im;
68 
69  im = &igmp_main;
70  srcs = data;
71  group = pool_elt_at_index (im->groups, obj);
72  config = pool_elt_at_index (im->configs, group->config);
73 
75  ASSERT (group->timers[IGMP_GROUP_TIMER_QUERY_REPLY] !=
77 
78  IGMP_DBG ("send-group-report: %U",
80  vnet_get_main (), config->sw_if_index);
81 
82  if (NULL == srcs)
83  {
84  /*
85  * there were no sources specified, so this is a group-specific query.
86  * We should respond with all our sources
87  */
88  igmp_pkt_report_v3_add_group (&br, group,
89  IGMP_MEMBERSHIP_GROUP_mode_is_include);
90  }
91  else
92  {
93  /*
94  * the sources stored in the timer object are the combined set of sources
95  * to be required. We need to respond only to those queried, not our full set.
96  */
97  ip46_address_t *intersect;
98 
99  intersect = igmp_group_new_intersect_present (group,
100  IGMP_FILTER_MODE_INCLUDE,
101  srcs);
102 
103  if (vec_len (intersect))
104  {
106  group->key,
107  intersect,
108  IGMP_MEMBERSHIP_GROUP_mode_is_include);
109  vec_free (intersect);
110  }
111  }
112 
114 
115  igmp_timer_retire (&group->timers[IGMP_GROUP_TIMER_QUERY_REPLY]);
116  vec_free (srcs);
117 }
118 
121 {
122  switch (mode)
123  {
124  case IGMP_FILTER_MODE_INCLUDE:
125  return (IGMP_MEMBERSHIP_GROUP_mode_is_include);
126  case IGMP_FILTER_MODE_EXCLUDE:
127  return (IGMP_MEMBERSHIP_GROUP_mode_is_exclude);
128  }
129 
130  return (IGMP_MEMBERSHIP_GROUP_mode_is_include);
131 }
132 
133 /**
134  * Send igmp membership general report.
135  */
136 static void
138 {
140  igmp_config_t *config;
141  igmp_group_t *group;
142  igmp_main_t *im;
143 
144  im = &igmp_main;
145  config = pool_elt_at_index (im->configs, obj);
146 
147  ASSERT (config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT] !=
149 
150  igmp_timer_retire (&config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT]);
151 
152  IGMP_DBG ("send-general-report: %U",
154  vnet_get_main (), config->sw_if_index);
155 
157 
158  /* *INDENT-OFF* */
159  FOR_EACH_GROUP (group, config,
160  ({
162  (&br, group,
164  }));
165  /* *INDENT-ON* */
166 
168 }
169 
170 /**
171  * Called from the main thread on reception of a Query message
172  */
173 void
175 {
176  igmp_config_t *config;
177 
178  config = igmp_config_lookup (args->sw_if_index);
179 
180  if (!config)
181  /*
182  * no IGMP config on the interface. quit
183  */
184  return;
185 
186  if (IGMP_MODE_ROUTER == config->mode)
187  {
188  ASSERT (0);
189  // code here for querier election */
190  }
191 
192  IGMP_DBG ("query-rx: %U", format_vnet_sw_if_index_name,
193  vnet_get_main (), args->sw_if_index);
194 
195 
196  /*
197  Section 5.2
198  "When a system receives a Query, it does not respond immediately.
199  Instead, it delays its response by a random amount of time, bounded
200  by the Max Resp Time value derived from the Max Resp Code in the
201  received Query message. A system may receive a variety of Queries on
202  different interfaces and of different kinds (e.g., General Queries,
203  Group-Specific Queries, and Group-and-Source-Specific Queries), each
204  of which may require its own delayed response.
205  */
207  {
208  IGMP_DBG ("...general-query-rx: %U", format_vnet_sw_if_index_name,
209  vnet_get_main (), args->sw_if_index);
210 
211  /*
212  * A general query has no info that needs saving from the response
213  */
214  if (IGMP_TIMER_ID_INVALID ==
215  config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT])
216  {
217  f64 delay = igmp_get_random_resp_delay (&args->query[0].header);
218 
219  IGMP_DBG ("...general-query-rx: %U schedule for %f",
221  args->sw_if_index, delay);
222 
223  /*
224  * no currently running timer, schedule a new one
225  */
226  config->timers[IGMP_CONFIG_TIMER_GENERAL_REPORT] =
227  igmp_timer_schedule (delay,
228  igmp_config_index (config),
230  }
231  /*
232  * else
233  * don't reschedule timers, we'll reply soon enough..
234  */
235  }
236  else
237  {
238  /*
239  * G or SG query. we'll need to save the sources quered
240  */
241  igmp_key_t key = {
242  .ip4 = args->query[0].group_address,
243  };
244  ip46_address_t *srcs;
245  igmp_timer_id_t tid;
246  igmp_group_t *group;
247 
248  group = igmp_group_lookup (config, &key);
249 
250  /*
251  * If there is no group config, no worries, we can ignore this
252  * query. If the group state does come soon, we'll send a
253  * state-change report at that time.
254  */
255  if (!group)
256  return;
257 
258  srcs = igmp_query_mk_source_list (args->query);
259  tid = group->timers[IGMP_GROUP_TIMER_QUERY_REPLY];
260 
261  IGMP_DBG ("...group-query-rx: %U for (%U, %U)",
263  vnet_get_main (), args->sw_if_index,
265 
266 
267  if (IGMP_TIMER_ID_INVALID != tid)
268  {
269  /*
270  * There is a timer already running, merge the sources list
271  */
272  ip46_address_t *current, *s;
273 
274  current = igmp_timer_get_data (tid);
275 
276  vec_foreach (s, srcs)
277  {
278  if (~0 == vec_search_with_function (current, s,
280  {
281  vec_add1 (current, *s);
282  }
283  }
284 
285  igmp_timer_set_data (tid, current);
286  }
287  else
288  {
289  /*
290  * schedule a new G-specific query
291  */
292  f64 delay = igmp_get_random_resp_delay (&args->query[0].header);
293 
294  IGMP_DBG ("...group-query-rx: schedule:%f", delay);
295 
296  group->timers[IGMP_GROUP_TIMER_QUERY_REPLY] =
297  igmp_timer_schedule (delay,
298  igmp_group_index (group),
300  }
301  }
302 }
303 
304 
305 /*
306  * fd.io coding-style-patch-verification: ON
307  *
308  * Local Variables:
309  * eval: (c-set-style "gnu")
310  * End:
311  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
igmp_timer_id_t timers[IGMP_CONFIG_N_TIMERS]
A vector of scheduled query-response timers.
Definition: igmp_config.h:77
u8 * format_igmp_src_addr_list(u8 *s, va_list *args)
Definition: igmp_format.c:186
u8 * format_igmp_key(u8 *s, va_list *args)
Definition: igmp_format.c:203
A copy of the query message sent from the worker to the main thread.
Definition: igmp_query.h:23
void igmp_timer_retire(igmp_timer_id_t *tid)
Definition: igmp_timer.c:221
igmp_group_t * igmp_group_lookup(igmp_config_t *config, const igmp_key_t *key)
igmp group lookup
Definition: igmp_config.c:76
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
ip4_address_t src_addresses[0]
Definition: igmp_packet.h:115
igmp_main_t igmp_main
Definition: igmp.c:36
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:333
igmp_config_t * configs
pool of configs
Definition: igmp.h:95
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:349
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
igmp_membership_group_v3_type_t
Definition: igmp_packet.h:140
static igmp_membership_group_v3_type_t igmp_filter_mode_to_report_type(igmp_filter_mode_t mode)
Definition: igmp_query.c:120
format_function_t format_vnet_sw_if_index_name
void igmp_pkt_build_report_init(igmp_pkt_build_report_t *br, u32 sw_if_index)
Definition: igmp_pkt.c:400
#define IGMP_DBG(...)
Definition: igmp.h:38
u8 data[128]
Definition: ipsec_types.api:89
igmp_timer_id_t igmp_timer_schedule(f64 when, u32 obj, igmp_timer_function_t fn, void *data)
Schedule a timer to expire in &#39;when&#39; seconds.
Definition: igmp_timer.c:195
double f64
Definition: types.h:142
static void igmp_send_general_report_v3(u32 obj, void *data)
Send igmp membership general report.
Definition: igmp_query.c:137
u32 igmp_config_index(const igmp_config_t *c)
Get the pool index for a config.
Definition: igmp_config.c:64
void * igmp_timer_get_data(igmp_timer_id_t tid)
Definition: igmp_timer.c:111
static f64 igmp_get_random_resp_delay(const igmp_header_t *header)
Definition: igmp_query.c:22
#define FOR_EACH_GROUP(_group, _config, _body)
Definition: igmp_config.h:85
unsigned int u32
Definition: types.h:88
void igmp_pkt_report_v3_send(igmp_pkt_build_report_t *br)
Definition: igmp_pkt.c:208
igmp_config_t * igmp_config_lookup(u32 sw_if_index)
igmp config lookup
Definition: igmp_config.c:45
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
u32 config
The pool index of the config object this group is in.
Definition: igmp_group.h:77
unsigned short u16
Definition: types.h:57
u32 igmp_timer_id_t
The id of a running timer.
Definition: igmp_timer.h:26
collection of data related to IGMP
Definition: igmp.h:63
vl_api_tunnel_mode_t mode
Definition: gre.api:48
static u8 ip46_address_is_equal(const ip46_address_t *ip46_1, const ip46_address_t *ip46_2)
Definition: ip46_address.h:93
static ip46_address_t * igmp_query_mk_source_list(const igmp_membership_query_v3_t *q)
Definition: igmp_query.c:33
static f64 igmp_header_get_max_resp_time(const igmp_header_t *header)
Calculate the maximum response time allowed from the header.
Definition: igmp_packet.h:82
void igmp_timer_set_data(igmp_timer_id_t tid, void *data)
Definition: igmp_timer.c:121
u32 timers[IGMP_GROUP_N_TIMERS]
A vector of running timers for the group.
Definition: igmp_group.h:67
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
#define vec_search_with_function(v, E, fn)
Search a vector for the index of the entry that matches.
Definition: vec.h:1033
enum igmp_filter_mode_t_ igmp_filter_mode_t
#define IGMP_TIMER_ID_INVALID
Definition: igmp_timer.h:28
#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:309
static void igmp_send_group_report_v3(u32 obj, void *data)
Definition: igmp_query.c:61
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
ip46_address_t igmp_key_t
IGMP Key Used to index groups within an interface config and sources within a list.
Definition: igmp_types.h:49
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
ip46_address_t * igmp_group_new_intersect_present(igmp_group_t *group, igmp_filter_mode_t mode, const ip46_address_t *saddrs)
Definition: igmp_group.c:223
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
typedef key
Definition: ipsec_types.api:85
void igmp_handle_query(const igmp_query_args_t *args)
Called from the main thread on reception of a Query message.
Definition: igmp_query.c:174
static int igmp_membership_query_v3_is_general(const igmp_membership_query_v3_t *q)
Definition: igmp_packet.h:127
igmp_group_t * groups
pool of groups
Definition: igmp.h:100
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
igmp_key_t * key
The group&#39;s key within the per-interface config.
Definition: igmp_group.h:59
IGMP group A multicast group address for which reception has been requested.
Definition: igmp_group.h:56
igmp_membership_query_v3_t query[0]
Definition: igmp_query.h:26
#define vec_foreach(var, vec)
Vector iterator.
igmp_mode_t mode
Definition: igmp_config.h:62
u32 igmp_group_index(const igmp_group_t *g)
Definition: igmp_group.c:273
ip4_address_t group_address
Definition: igmp_packet.h:105