FD.io VPP  v21.01.1
Vector Packet Processing
igmp_proxy.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 <vlib/vlib.h>
19 #include <vnet/mfib/mfib_entry.h>
20 #include <vnet/mfib/mfib_table.h>
21 
22 #include <igmp/igmp_proxy.h>
23 #include <igmp/igmp.h>
24 #include <igmp/igmp_pkt.h>
25 
26 void
28 {
29  igmp_config_t *config;
30  u32 mfib_index;
31 
32  config = igmp_config_get (group->config);
33  mfib_index =
35  config->sw_if_index);
36 
37  /* *INDENT-OFF* */
38  mfib_prefix_t mpfx_group_addr = {
40  .fp_len = 32,
41  .fp_grp_addr = {
42  .ip4 = (*group->key).ip4,
43  },
44  };
45  fib_route_path_t via_itf_path =
46  {
48  .frp_addr = zero_addr,
49  .frp_sw_if_index = config->sw_if_index,
50  .frp_fib_index = 0,
51  .frp_weight = 1,
52  .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
53  };
54  /* *INDENT-ON* */
55 
56  if (add)
57  mfib_table_entry_path_update (mfib_index, &mpfx_group_addr,
58  MFIB_SOURCE_IGMP, &via_itf_path);
59  else
60  mfib_table_entry_path_remove (mfib_index, &mpfx_group_addr,
61  MFIB_SOURCE_IGMP, &via_itf_path);
62 }
63 
66 {
67  igmp_main_t *im = &igmp_main;
68 
69  if (vec_len (im->igmp_proxy_device_by_vrf_id) > vrf_id)
70  {
71  u32 index;
73  if (index != ~0)
74  return (vec_elt_at_index (im->proxy_devices, index));
75  }
76  return NULL;
77 }
78 
79 int
81 {
82  igmp_main_t *im = &igmp_main;
83  igmp_proxy_device_t *proxy_device;
84  igmp_config_t *config;
85  u32 mfib_index;
86 
87  /* check VRF id */
88  mfib_index =
90  if (mfib_index == ~0)
91  return VNET_API_ERROR_INVALID_INTERFACE;
92  if (vrf_id != mfib_table_get (mfib_index, FIB_PROTOCOL_IP4)->mft_table_id)
93  return VNET_API_ERROR_INVALID_INTERFACE;
94 
95  /* check IGMP configuration */
96  config = igmp_config_lookup (sw_if_index);
97  if (!config)
98  return VNET_API_ERROR_INVALID_INTERFACE;
99  if (config->mode != IGMP_MODE_HOST)
100  return VNET_API_ERROR_INVALID_INTERFACE;
101 
102  proxy_device = igmp_proxy_device_lookup (vrf_id);
103  if (!proxy_device && add)
104  {
106  pool_get (im->proxy_devices, proxy_device);
108  proxy_device - im->proxy_devices;
109  clib_memset (proxy_device, 0, sizeof (igmp_proxy_device_t));
110  proxy_device->vrf_id = vrf_id;
111  proxy_device->upstream_if = sw_if_index;
112  config->proxy_device_id = vrf_id;
113  /* lock mfib table */
115  }
116  else if (proxy_device && !add)
117  {
118  while (vec_len (proxy_device->downstream_ifs) > 0)
119  {
121  proxy_device->downstream_ifs
122  [0], 0);
123  }
124  vec_free (proxy_device->downstream_ifs);
125  proxy_device->downstream_ifs = NULL;
127  pool_put (im->proxy_devices, proxy_device);
128  config->proxy_device_id = ~0;
129  /* clear proxy database */
130  igmp_clear_config (config);
131  /* unlock mfib table */
133  }
134  else
135  return -1;
136 
137  return 0;
138 }
139 
140 int
142 {
143  igmp_proxy_device_t *proxy_device;
144  u32 index;
145  u32 mfib_index;
146 
147  proxy_device = igmp_proxy_device_lookup (vrf_id);
148  if (!proxy_device)
149  return -1;
150 
151  /* check VRF id */
152  mfib_index =
154  if (mfib_index == ~0)
155  return VNET_API_ERROR_INVALID_INTERFACE;
156  if (vrf_id != mfib_table_get (mfib_index, FIB_PROTOCOL_IP4)->mft_table_id)
157  return VNET_API_ERROR_INVALID_INTERFACE;
158 
159  /* check IGMP configuration */
160  igmp_config_t *config;
161  config = igmp_config_lookup (sw_if_index);
162  if (!config)
163  return VNET_API_ERROR_INVALID_INTERFACE;
164  if (config->mode != IGMP_MODE_ROUTER)
165  return VNET_API_ERROR_INVALID_INTERFACE;
166 
167  if (add)
168  {
169  if (proxy_device->downstream_ifs)
170  {
171  index = vec_search (proxy_device->downstream_ifs, sw_if_index);
172  if (index != ~0)
173  return -1;
174  }
175  vec_add1 (proxy_device->downstream_ifs, sw_if_index);
176  config->proxy_device_id = vrf_id;
177  }
178  else
179  {
180  if (!proxy_device->downstream_ifs)
181  return -2;
182  index = vec_search (proxy_device->downstream_ifs, sw_if_index);
183  if (index == ~0)
184  return -3;
185  /* remove (S,G)s belonging to this interface from proxy database */
186  igmp_proxy_device_merge_config (config, /* block */ 1);
187  vec_del1 (proxy_device->downstream_ifs, index);
188  config->proxy_device_id = ~0;
189  }
190 
191  return 0;
192 }
193 
194 void
196  igmp_src_t * src)
197 {
198  igmp_proxy_device_t *proxy_device;
199  igmp_config_t *proxy_config;
200  igmp_group_t *proxy_group;
201  igmp_src_t *proxy_src;
202  u8 *ref;
203 
204  proxy_device = igmp_proxy_device_lookup (config->proxy_device_id);
205  if (!proxy_device)
206  return;
207 
208  proxy_config = igmp_config_lookup (proxy_device->upstream_if);
209  ASSERT (proxy_config);
210 
211  proxy_group = igmp_group_lookup (proxy_config, group->key);
212  if (proxy_group == NULL)
213  return;
214 
215  proxy_src = igmp_src_lookup (proxy_group, src->key);
216  if (proxy_src == NULL)
217  return;
218 
219  if (vec_len (proxy_src->referance_by_config_index) <= group->config)
220  {
221  IGMP_DBG ("proxy block src: invalid config %u", group->config);
222  return;
223  }
224  proxy_src->referance_by_config_index[group->config] = 0;
225  vec_foreach (ref, proxy_src->referance_by_config_index)
226  {
227  if ((*ref) > 0)
228  return;
229  }
230 
231  /* build "Block Old Sources" report */
233  ip46_address_t *srcaddrs = NULL;
234 
235  igmp_pkt_build_report_init (&br, proxy_config->sw_if_index);
236  vec_add1 (srcaddrs, *proxy_src->key);
237  igmp_pkt_report_v3_add_report (&br, proxy_group->key, srcaddrs,
238  IGMP_MEMBERSHIP_GROUP_block_old_sources);
240 
241 
242  igmp_group_src_remove (proxy_group, proxy_src);
243  igmp_src_free (proxy_src);
244 
245  if (igmp_group_n_srcs (proxy_group, IGMP_FILTER_MODE_INCLUDE) == 0)
246  {
247  igmp_proxy_device_mfib_path_add_del (proxy_group, 0);
249  igmp_group_clear (&proxy_group);
250  }
251 }
252 
253 always_inline void
255  ip46_address_t ** srcaddrs, u8 block)
256 {
257  igmp_src_t *proxy_src;
258  u32 d_config;
259 
260  proxy_src = igmp_src_lookup (*proxy_group, src->key);
261 
262  if (proxy_src == NULL)
263  {
264  if (block)
265  return;
266  /* store downstream config index */
267  d_config = igmp_group_get (src->group)->config;
268 
269  proxy_src =
270  igmp_src_alloc (igmp_group_index (*proxy_group), src->key,
271  IGMP_MODE_HOST);
272 
273  hash_set_mem ((*proxy_group)->igmp_src_by_key
274  [(*proxy_group)->router_filter_mode], proxy_src->key,
275  igmp_src_index (proxy_src));
276 
278  0);
279  proxy_src->referance_by_config_index[d_config] = 1;
280  vec_add1 (*srcaddrs, *proxy_src->key);
281  }
282  else
283  {
284  if (block)
285  {
286  d_config = igmp_group_get (src->group)->config;
287  if (vec_len (proxy_src->referance_by_config_index) <= d_config)
288  {
289  IGMP_DBG ("proxy block src: invalid config %u", d_config);
290  return;
291  }
292  proxy_src->referance_by_config_index[d_config] = 0;
293  u8 *ref;
294  vec_foreach (ref, proxy_src->referance_by_config_index)
295  {
296  if ((*ref) > 0)
297  return;
298  }
299 
300  vec_add1 (*srcaddrs, *proxy_src->key);
301 
302  igmp_group_src_remove (*proxy_group, proxy_src);
303  igmp_src_free (proxy_src);
304 
305  if (igmp_group_n_srcs (*proxy_group, IGMP_FILTER_MODE_INCLUDE) == 0)
306  {
307  igmp_proxy_device_mfib_path_add_del (*proxy_group, 0);
308  igmp_group_clear (proxy_group);
309  }
310  return;
311  }
312  d_config = igmp_group_get (src->group)->config;
313  vec_validate (proxy_src->referance_by_config_index, d_config);
314  proxy_src->referance_by_config_index[d_config] = 1;
315  return;
316  }
317 }
318 
321  igmp_group_t * group,
322  ip46_address_t ** srcaddrs, u8 block)
323 {
324  igmp_config_t *proxy_config;
325  igmp_group_t *proxy_group;
326  igmp_src_t *src;
327 
328  proxy_config = igmp_config_lookup (proxy_device->upstream_if);
329  ALWAYS_ASSERT (proxy_config);
330 
331  proxy_group = igmp_group_lookup (proxy_config, group->key);
332  if (!proxy_group)
333  {
334  if (block)
335  return NULL;
336  u32 tmp = igmp_group_index (group);
337  proxy_group =
338  igmp_group_alloc (proxy_config, group->key,
339  group->router_filter_mode);
340  igmp_proxy_device_mfib_path_add_del (proxy_group, 1);
341  group = igmp_group_get (tmp);
342  }
343  if (block)
344  {
346  }
347 
348  /* *INDENT-OFF* */
349  FOR_EACH_SRC (src, group, group->router_filter_mode,
350  ({
351  igmp_proxy_device_merge_src (&proxy_group, src, srcaddrs, block);
352  }));
353  /* *INDENT-ON* */
354  return proxy_group;
355 }
356 
357 void
359 {
360  igmp_proxy_device_t *proxy_device;
361  igmp_group_t *group;
362  igmp_group_t *proxy_group;
363  ip46_address_t *srcaddrs = NULL;
365 
366  proxy_device = igmp_proxy_device_lookup (config->proxy_device_id);
367  if (!proxy_device)
368  return;
369 
370  igmp_pkt_build_report_init (&br, proxy_device->upstream_if);
371 
372  /* *INDENT-OFF* */
373  FOR_EACH_GROUP(group, config,
374  ({
375  proxy_group = igmp_proxy_device_merge_group (proxy_device, group, &srcaddrs, block);
376 
377  if ((vec_len(srcaddrs) > 0) && proxy_group)
378  {
379  igmp_pkt_report_v3_add_report (&br, proxy_group->key, srcaddrs,
380  block ? IGMP_MEMBERSHIP_GROUP_block_old_sources :
381  IGMP_MEMBERSHIP_GROUP_allow_new_sources);
382  }
383  vec_free (srcaddrs);
384  }));
385  /* *INDENT-ON* */
386 
388 
389 }
390 
391 /*
392  * fd.io coding-style-patch-verification: ON
393  *
394  * Local Variables:
395  * eval: (c-set-style "gnu")
396  * End:
397  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
void igmp_proxy_device_mfib_path_add_del(igmp_group_t *group, u8 add)
Definition: igmp_proxy.c:27
igmp_group_t * igmp_group_lookup(igmp_config_t *config, const igmp_key_t *key)
igmp group lookup
Definition: igmp_config.c:76
A representation of a path as described by a route producer.
Definition: fib_types.h:500
int igmp_proxy_device_add_del_interface(u32 vrf_id, u32 sw_if_index, u8 add)
IGMP proxy device add/del interface.
Definition: igmp_proxy.c:141
u32 group
The group this source is on.
Definition: igmp_src.h:57
igmp_main_t igmp_main
Definition: igmp.c:36
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)
Add n paths to an entry (aka route) in the FIB.
Definition: mfib_table.c:325
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
void igmp_proxy_device_merge_config(igmp_config_t *config, u8 block)
Definition: igmp_proxy.c:358
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
vl_api_address_t src
Definition: gre.api:54
u32 vrf_id
Definition: nat44.api:1029
#define hash_set_mem(h, key, value)
Definition: hash.h:275
dpo_proto_t frp_proto
The protocol of the address below.
Definition: fib_types.h:505
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:251
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:400
void igmp_src_free(igmp_src_t *src)
Definition: igmp_src.c:23
#define IGMP_DBG(...)
Definition: igmp.h:38
void igmp_clear_config(igmp_config_t *config)
igmp clear config
Definition: igmp_config.c:22
u8 * referance_by_config_index
Tells us which configurations have this source.
Definition: igmp_src.h:73
u32 mfib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: mfib_table.c:527
igmp_src_t * igmp_src_alloc(u32 group_index, const igmp_key_t *skey, igmp_mode_t mode)
Definition: igmp_src.c:73
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u32 * igmp_proxy_device_by_vrf_id
per-vrf DB of proxy devices
Definition: igmp.h:109
igmp_config_t * igmp_config_get(u32 index)
Get the config from the pool index.
Definition: igmp_config.c:70
#define ALWAYS_ASSERT(truth)
#define FOR_EACH_GROUP(_group, _config, _body)
Definition: igmp_config.h:85
unsigned int u32
Definition: types.h:88
#define vec_search(v, E)
Search a vector for the index of the entry that matches.
Definition: vec.h:1012
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
void mfib_table_unlock(u32 fib_index, fib_protocol_t proto, mfib_source_t source)
Take a reference counting lock on the table.
Definition: mfib_table.c:777
u32 config
The pool index of the config object this group is in.
Definition: igmp_group.h:77
void igmp_group_src_remove(igmp_group_t *group, igmp_src_t *src)
Definition: igmp_group.c:38
igmp_src_t * igmp_src_lookup(igmp_group_t *group, const igmp_key_t *key)
igmp group lookup
Definition: igmp_group.c:258
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
#define always_inline
Definition: ipsec.h:28
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:875
vl_api_ip4_address_t ip4
Definition: one.api:376
void igmp_group_clear(igmp_group_t **group)
Definition: igmp_group.c:68
void mfib_table_lock(u32 fib_index, fib_protocol_t proto, mfib_source_t source)
Release a reference counting lock on the table.
Definition: mfib_table.c:806
collection of data related to IGMP
Definition: igmp.h:63
igmp_group_t * igmp_group_alloc(igmp_config_t *config, const igmp_key_t *gkey, igmp_filter_mode_t mode)
Definition: igmp_group.c:104
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
Aggregate type for a prefix.
Definition: mfib_types.h:24
igmp_proxy_device_t * igmp_proxy_device_lookup(u32 vrf_id)
Definition: igmp_proxy.c:65
#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
igmp_group_t * igmp_group_get(u32 index)
Definition: igmp_group.c:279
u32 igmp_src_index(igmp_src_t *src)
Definition: igmp_src.c:141
static void igmp_proxy_device_merge_src(igmp_group_t **proxy_group, igmp_src_t *src, ip46_address_t **srcaddrs, u8 block)
Definition: igmp_proxy.c:254
dpo_proto_t fib_proto_to_dpo(fib_protocol_t fib_proto)
Definition: fib_types.c:343
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
u32 proxy_device_id
ID of a proxy device this configuration is on.
Definition: igmp_config.h:82
fib_protocol_t fp_proto
protocol type
Definition: mfib_types.h:33
mfib_table_t * mfib_table_get(fib_node_index_t index, fib_protocol_t proto)
Get a pointer to a FIB table.
Definition: mfib_table.c:30
#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
IGMP group A multicast group address for which reception has been requested.
Definition: igmp_group.h:56
u32 index
Definition: flow_types.api:221
igmp_key_t * key
The source&#39;s key.
Definition: igmp_src.h:46
void igmp_proxy_device_block_src(igmp_config_t *config, igmp_group_t *group, igmp_src_t *src)
Definition: igmp_proxy.c:195
static igmp_group_t * igmp_proxy_device_merge_group(igmp_proxy_device_t *proxy_device, igmp_group_t *group, ip46_address_t **srcaddrs, u8 block)
Definition: igmp_proxy.c:320
igmp_proxy_device_t * proxy_devices
pool of proxy devices
Definition: igmp.h:114
#define vec_foreach(var, vec)
Vector iterator.
igmp_mode_t mode
Definition: igmp_config.h:62
u32 igmp_group_n_srcs(const igmp_group_t *group, igmp_filter_mode_t mode)
Definition: igmp_group.c:251
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:556
void mfib_table_entry_path_remove(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, const fib_route_path_t *rpath)
Remove n paths to an entry (aka route) in the FIB.
Definition: mfib_table.c:407
int igmp_proxy_device_add_del(u32 vrf_id, u32 sw_if_index, u8 add)
IGMP proxy device add/del.
Definition: igmp_proxy.c:80
u32 igmp_group_index(const igmp_group_t *g)
Definition: igmp_group.c:273
IGMP source The representation of a specified source address with in multicast group.
Definition: igmp_src.h:41
const ip46_address_t zero_addr
#include <vnet/feature/feature.h>
Definition: lookup.c:180
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34