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:
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.h>
20 #include <vlibapi/api.h>
21 #include <vlibmemory/api.h>
22 #include <vnet/ip/ip_types_api.h>
23 #include <igmp/igmp_ssm_range.h>
25 /* define message IDs */
26 #include <igmp/igmp.api_enum.h>
27 #include <igmp/igmp.api_types.h>
28 #include <vnet/format_fns.h>
30 #include <vlibapi/api_helper_macros.h>
32 #define IGMP_MSG_ID(_id) (_id + igmp_main.msg_id_base)
35 vl_api_igmp_listen_t_handler (vl_api_igmp_listen_t * mp)
37 vlib_main_t *vm = vlib_get_main ();
38 vnet_main_t *vnm = vnet_get_main ();
39 vl_api_igmp_listen_reply_t *rmp;
41 ip46_address_t gaddr, *saddrs = NULL;
43 VALIDATE_SW_IF_INDEX (&mp->group);
45 if ((vnet_sw_interface_get_flags (vnm, ntohl (mp->group.sw_if_index)) &&
46 VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
48 // FIXME - don't we clear this state on interface down ...
49 rv = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
53 clib_memset (&gaddr, 0, sizeof (gaddr));
54 clib_memcpy (&gaddr.ip4, &mp->group.gaddr, sizeof (ip4_address_t));
56 vec_validate (saddrs, mp->group.n_srcs - 1);
58 vec_foreach_index (ii, saddrs)
60 clib_memcpy (&saddrs[ii].ip4,
61 &mp->group.saddrs[ii], sizeof (ip4_address_t));
66 IGMP_FILTER_MODE_INCLUDE :
67 IGMP_FILTER_MODE_EXCLUDE),
68 ntohl (mp->group.sw_if_index), saddrs, &gaddr);
72 BAD_SW_IF_INDEX_LABEL;
74 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_LISTEN_REPLY));
78 vl_api_igmp_enable_disable_t_handler (vl_api_igmp_enable_disable_t * mp)
80 vl_api_igmp_enable_disable_reply_t *rmp;
83 VALIDATE_SW_IF_INDEX (mp);
85 rv = igmp_enable_disable (ntohl (mp->sw_if_index),
87 (mp->mode ? IGMP_MODE_HOST : IGMP_MODE_ROUTER));
89 BAD_SW_IF_INDEX_LABEL;
91 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_ENABLE_DISABLE_REPLY));
95 vl_api_igmp_proxy_device_add_del_t_handler (vl_api_igmp_proxy_device_add_del_t
98 vl_api_igmp_proxy_device_add_del_reply_t *rmp;
101 VALIDATE_SW_IF_INDEX (mp);
104 igmp_proxy_device_add_del (ntohl (mp->vrf_id), ntohl (mp->sw_if_index),
107 BAD_SW_IF_INDEX_LABEL;
109 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_REPLY));
113 vl_api_igmp_proxy_device_add_del_interface_t_handler
114 (vl_api_igmp_proxy_device_add_del_interface_t * mp)
116 vl_api_igmp_proxy_device_add_del_interface_reply_t *rmp;
119 VALIDATE_SW_IF_INDEX (mp);
122 igmp_proxy_device_add_del_interface (ntohl (mp->vrf_id),
123 ntohl (mp->sw_if_index), mp->add);
125 BAD_SW_IF_INDEX_LABEL;
127 REPLY_MACRO (IGMP_MSG_ID
128 (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_INTERFACE_REPLY));
132 send_igmp_details (vl_api_registration_t * rp, igmp_main_t * im,
133 igmp_config_t * config, igmp_group_t * group,
134 igmp_src_t * src, u32 context)
136 vl_api_igmp_details_t *mp;
138 mp = vl_msg_api_alloc (sizeof (*mp));
139 clib_memset (mp, 0, sizeof (*mp));
141 mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
142 mp->context = context;
143 mp->sw_if_index = htonl (config->sw_if_index);
144 clib_memcpy (&mp->saddr, &src->key->ip4, sizeof (src->key->ip4));
145 clib_memcpy (&mp->gaddr, &group->key->ip4, sizeof (group->key->ip4));
147 vl_api_send_msg (rp, (u8 *) mp);
151 igmp_config_dump (igmp_main_t * im,
152 vl_api_registration_t * rp,
153 u32 context, igmp_config_t * config)
159 FOR_EACH_GROUP (group, config,
161 FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
163 send_igmp_details (rp, im, config, group, src, context);
170 vl_api_igmp_dump_t_handler (vl_api_igmp_dump_t * mp)
172 igmp_main_t *im = &igmp_main;
173 igmp_config_t *config;
175 vl_api_registration_t *rp;
177 rp = vl_api_client_index_to_registration (mp->client_index);
181 sw_if_index = ntohl (mp->sw_if_index);
182 if (~0 == sw_if_index)
185 pool_foreach (config, im->configs,
187 igmp_config_dump(im, rp, mp->context, config);
193 config = igmp_config_lookup (sw_if_index);
196 igmp_config_dump (im, rp, mp->context, config);
202 vl_api_igmp_clear_interface_t_handler (vl_api_igmp_clear_interface_t * mp)
204 vl_api_igmp_clear_interface_reply_t *rmp;
205 igmp_config_t *config;
208 config = igmp_config_lookup (ntohl (mp->sw_if_index));
210 igmp_clear_config (config);
212 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_CLEAR_INTERFACE_REPLY));
215 static vl_api_group_prefix_type_t
216 igmp_group_type_int_to_api (igmp_group_prefix_type_t t)
220 case IGMP_GROUP_PREFIX_TYPE_ASM:
221 return (htonl (ASM));
222 case IGMP_GROUP_PREFIX_TYPE_SSM:
223 return (htonl (SSM));
229 static igmp_group_prefix_type_t
230 igmp_group_type_api_to_int (vl_api_group_prefix_type_t t)
235 return (IGMP_GROUP_PREFIX_TYPE_ASM);
237 return (IGMP_GROUP_PREFIX_TYPE_SSM);
240 return (IGMP_GROUP_PREFIX_TYPE_SSM);
244 vl_api_igmp_group_prefix_set_t_handler (vl_api_igmp_group_prefix_set_t * mp)
246 vl_api_igmp_group_prefix_set_reply_t *rmp;
250 ip_prefix_decode (&mp->gp.prefix, &pfx);
251 igmp_group_prefix_set (&pfx, igmp_group_type_api_to_int (mp->gp.type));
253 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_GROUP_PREFIX_SET_REPLY));
256 typedef struct igmp_ssm_range_walk_ctx_t_
258 vl_api_registration_t *rp;
260 } igmp_ssm_range_walk_ctx_t;
263 igmp_ssm_range_walk_dump (const fib_prefix_t * pfx,
264 igmp_group_prefix_type_t type, void *args)
266 igmp_ssm_range_walk_ctx_t *ctx = args;
267 vl_api_igmp_group_prefix_details_t *mp;
269 mp = vl_msg_api_alloc (sizeof (*mp));
270 clib_memset (mp, 0, sizeof (*mp));
272 mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
273 mp->context = ctx->context;
274 mp->gp.type = igmp_group_type_int_to_api (type);
275 ip_prefix_encode (pfx, &mp->gp.prefix);
277 vl_api_send_msg (ctx->rp, (u8 *) mp);
279 return (WALK_CONTINUE);
283 vl_api_igmp_group_prefix_dump_t_handler (vl_api_igmp_dump_t * mp)
285 vl_api_registration_t *rp;
287 rp = vl_api_client_index_to_registration (mp->client_index);
291 igmp_ssm_range_walk_ctx_t ctx = {
293 .context = mp->context,
296 igmp_ssm_range_walk (igmp_ssm_range_walk_dump, &ctx);
299 static vpe_client_registration_t *
300 igmp_api_client_lookup (igmp_main_t * im, u32 client_index)
303 vpe_client_registration_t *api_client = NULL;
305 p = hash_get (im->igmp_api_client_by_client_index, client_index);
307 api_client = vec_elt_at_index (im->api_clients, p[0]);
313 vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp)
315 igmp_main_t *im = &igmp_main;
316 vpe_client_registration_t *api_client;
317 vl_api_want_igmp_events_reply_t *rmp;
320 api_client = igmp_api_client_lookup (im, mp->client_index);
325 rv = VNET_API_ERROR_INVALID_REGISTRATION;
328 hash_unset (im->igmp_api_client_by_client_index,
329 api_client->client_index);
330 pool_put (im->api_clients, api_client);
335 pool_get (im->api_clients, api_client);
336 clib_memset (api_client, 0, sizeof (vpe_client_registration_t));
337 api_client->client_index = mp->client_index;
338 api_client->client_pid = mp->pid;
339 hash_set (im->igmp_api_client_by_client_index,
340 mp->client_index, api_client - im->api_clients);
343 rv = VNET_API_ERROR_INVALID_REGISTRATION;
346 REPLY_MACRO (VL_API_WANT_IGMP_EVENTS_REPLY + im->msg_id_base);
349 static clib_error_t *
350 want_igmp_events_reaper (u32 client_index)
352 igmp_main_t *im = &igmp_main;
353 vpe_client_registration_t *api_client;
356 p = hash_get (im->igmp_api_client_by_client_index, client_index);
360 api_client = pool_elt_at_index (im->api_clients, p[0]);
361 pool_put (im->api_clients, api_client);
362 hash_unset (im->igmp_api_client_by_client_index, client_index);
367 VL_MSG_API_REAPER_FUNCTION (want_igmp_events_reaper);
370 send_igmp_event (vl_api_registration_t * rp,
371 igmp_filter_mode_t filter,
373 const ip46_address_t * saddr, const ip46_address_t * gaddr)
375 vl_api_igmp_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
376 clib_memset (mp, 0, sizeof (*mp));
378 mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + igmp_main.msg_id_base);
379 mp->sw_if_index = htonl (sw_if_index);
380 mp->filter = htonl (filter);
381 clib_memcpy (&mp->saddr, &saddr->ip4, sizeof (ip4_address_t));
382 clib_memcpy (&mp->gaddr, &gaddr->ip4, sizeof (ip4_address_t));
384 vl_api_send_msg (rp, (u8 *) mp);
388 igmp_event (igmp_filter_mode_t filter,
390 const ip46_address_t * saddr, const ip46_address_t * gaddr)
392 vpe_client_registration_t *api_client;
393 vl_api_registration_t *rp;
398 IGMP_DBG ("event: (%U, %U) %U %U",
399 format_ip46_address, saddr, IP46_TYPE_ANY,
400 format_ip46_address, saddr, IP46_TYPE_ANY,
401 format_vnet_sw_if_index_name,
402 vnet_get_main (), sw_if_index, format_igmp_filter_mode, filter);
406 pool_foreach (api_client, im->api_clients,
408 rp = vl_api_client_index_to_registration (api_client->client_index);
410 send_igmp_event (rp, filter, sw_if_index, saddr, gaddr);
415 /* Set up the API message handling tables */
416 #include <igmp/igmp.api.c>
417 static clib_error_t *
418 igmp_plugin_api_hookup (vlib_main_t * vm)
420 igmp_main_t *im = &igmp_main;
422 /* Ask for a correctly-sized block of API message decode slots */
423 im->msg_id_base = setup_message_id_table ();
428 VLIB_API_INIT_FUNCTION (igmp_plugin_api_hookup);
431 * fd.io coding-style-patch-verification: ON
434 * eval: (c-set-style "gnu")