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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
18 #include <igmp/igmp_report.h>
19 #include <igmp/igmp_pkt.h>
21 static ip46_address_t *
22 igmp_group_mk_source_list (const igmp_membership_group_v3_t * r)
24 ip46_address_t *srcs = NULL;
25 const ip4_address_t *s;
29 * we validated this packet when we accepted it in the DP, so
30 * this number is safe to use
32 n = clib_net_to_host_u16 (r->n_src_addresses);
36 /* a (*,G) join has no source address specified */
37 vec_validate (srcs, 0);
38 srcs[0].ip4.as_u32 = 0;
42 vec_validate (srcs, n - 1);
45 for (ii = 0; ii < n; ii++)
56 igmp_handle_group_exclude (igmp_config_t * config,
57 const igmp_membership_group_v3_t * igmp_group)
59 ip46_address_t key = {
60 .ip4 = igmp_group->group_address,
65 * treat an exclude all sources as a *,G join
67 n = clib_net_to_host_u16 (igmp_group->n_src_addresses);
71 ip46_address_t *src, *srcs;
74 group = igmp_group_lookup (config, &key);
75 srcs = igmp_group_mk_source_list (igmp_group);
77 IGMP_DBG (" ..group-update: %U (*, %U)",
78 format_vnet_sw_if_index_name,
79 vnet_get_main (), config->sw_if_index, format_igmp_key, &key);
83 group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE);
85 vec_foreach (src, srcs)
87 igmp_group_src_update (group, src, IGMP_MODE_ROUTER);
94 IGMP_DBG (" ..group-update: %U (*, %U) source exclude ignored",
95 format_vnet_sw_if_index_name,
96 vnet_get_main (), config->sw_if_index, format_igmp_key, &key);
101 igmp_handle_group_block (igmp_config_t * config,
102 const igmp_membership_group_v3_t * igmp_group)
104 ip46_address_t *s, *srcs;
105 igmp_pkt_build_query_t bq;
107 ip46_address_t key = {
108 .ip4 = igmp_group->group_address,
111 srcs = igmp_group_mk_source_list (igmp_group);
112 group = igmp_group_lookup (config, &key);
114 IGMP_DBG (" ..group-block: %U (%U, %U)",
115 format_vnet_sw_if_index_name,
116 vnet_get_main (), config->sw_if_index,
117 format_igmp_key, &key, format_igmp_src_addr_list, srcs);
123 * send a group+source specific query
125 igmp_pkt_build_query_init (&bq, config->sw_if_index);
126 igmp_pkt_query_v3_add_group (&bq, group, srcs);
127 igmp_pkt_query_v3_send (&bq);
130 * for each source left/blocked drop the source expire timer to the leave
133 vec_foreach (s, srcs)
135 src = igmp_src_lookup (group, s);
137 igmp_src_blocked (src);
141 * a block/leave from a group for which we have no state
148 igmp_handle_group_update (igmp_config_t * config,
149 const igmp_membership_group_v3_t * igmp_group)
151 ip46_address_t *src, *srcs;
153 ip46_address_t key = {
154 .ip4 = igmp_group->group_address,
158 * treat a TO_INC({}) as a (*,G) leave
160 if (0 == clib_net_to_host_u16 (igmp_group->n_src_addresses))
162 return (igmp_handle_group_block (config, igmp_group));
165 srcs = igmp_group_mk_source_list (igmp_group);
166 group = igmp_group_lookup (config, &key);
168 IGMP_DBG (" ..group-update: %U (%U, %U)",
169 format_vnet_sw_if_index_name,
170 vnet_get_main (), config->sw_if_index,
171 format_igmp_key, &key, format_igmp_src_addr_list, srcs);
175 group = igmp_group_alloc (config, &key, IGMP_FILTER_MODE_INCLUDE);
178 /* create or update all sources */
179 vec_foreach (src, srcs)
181 igmp_group_src_update (group, src, IGMP_MODE_ROUTER);
188 igmp_handle_group (igmp_config_t * config,
189 const igmp_membership_group_v3_t * igmp_group)
191 IGMP_DBG ("rx-group-report: %U",
192 format_vnet_sw_if_index_name,
193 vnet_get_main (), config->sw_if_index);
195 switch (igmp_group->type)
197 case IGMP_MEMBERSHIP_GROUP_mode_is_include:
198 case IGMP_MEMBERSHIP_GROUP_change_to_include:
199 case IGMP_MEMBERSHIP_GROUP_allow_new_sources:
200 igmp_handle_group_update (config, igmp_group);
202 case IGMP_MEMBERSHIP_GROUP_block_old_sources:
203 igmp_handle_group_block (config, igmp_group);
205 case IGMP_MEMBERSHIP_GROUP_mode_is_exclude:
206 case IGMP_MEMBERSHIP_GROUP_change_to_exclude:
207 igmp_handle_group_exclude (config, igmp_group);
210 * all other types ignored
216 igmp_handle_report (const igmp_report_args_t * args)
218 const igmp_membership_group_v3_t *igmp_group;
219 igmp_config_t *config;
222 config = igmp_config_lookup (args->sw_if_index);
226 * no IGMP config on the interface. quit
230 if (IGMP_MODE_HOST == config->mode)
233 * Hosts need not listen to the reports of other hosts.
240 * we validated this packet when we accepted it in the DP, so
241 * this number is safe to use
243 n_groups = clib_net_to_host_u16 (args->report[0].n_groups);
244 igmp_group = args->report[0].groups;
246 for (ii = 0; ii < n_groups; ii++)
248 igmp_handle_group (config, igmp_group);
250 igmp_group = group_cptr (igmp_group,
251 igmp_membership_group_v3_length (igmp_group));
254 igmp_proxy_device_merge_config (config, 0);
258 * fd.io coding-style-patch-verification: ON
261 * eval: (c-set-style "gnu")