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 (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 (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 (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 (VL_API_IGMP_PROXY_DEVICE_ADD_DEL_INTERFACE_REPLY);
131 send_igmp_details (vl_api_registration_t * rp, igmp_main_t * im,
132 igmp_config_t * config, igmp_group_t * group,
133 igmp_src_t * src, u32 context)
135 vl_api_igmp_details_t *mp;
137 mp = vl_msg_api_alloc (sizeof (*mp));
138 clib_memset (mp, 0, sizeof (*mp));
140 mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
141 mp->context = context;
142 mp->sw_if_index = htonl (config->sw_if_index);
143 clib_memcpy (&mp->saddr, &src->key->ip4, sizeof (src->key->ip4));
144 clib_memcpy (&mp->gaddr, &group->key->ip4, sizeof (group->key->ip4));
146 vl_api_send_msg (rp, (u8 *) mp);
150 igmp_config_dump (igmp_main_t * im,
151 vl_api_registration_t * rp,
152 u32 context, igmp_config_t * config)
157 FOR_EACH_GROUP (group, config,
159 FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
161 send_igmp_details (rp, im, config, group, src, context);
167 vl_api_igmp_dump_t_handler (vl_api_igmp_dump_t * mp)
169 igmp_main_t *im = &igmp_main;
170 igmp_config_t *config;
172 vl_api_registration_t *rp;
174 rp = vl_api_client_index_to_registration (mp->client_index);
178 sw_if_index = ntohl (mp->sw_if_index);
179 if (~0 == sw_if_index)
181 pool_foreach (config, im->configs)
183 igmp_config_dump(im, rp, mp->context, config);
188 config = igmp_config_lookup (sw_if_index);
191 igmp_config_dump (im, rp, mp->context, config);
197 vl_api_igmp_clear_interface_t_handler (vl_api_igmp_clear_interface_t * mp)
199 vl_api_igmp_clear_interface_reply_t *rmp;
200 igmp_config_t *config;
203 config = igmp_config_lookup (ntohl (mp->sw_if_index));
205 igmp_clear_config (config);
207 REPLY_MACRO (VL_API_IGMP_CLEAR_INTERFACE_REPLY);
210 static vl_api_group_prefix_type_t
211 igmp_group_type_int_to_api (igmp_group_prefix_type_t t)
215 case IGMP_GROUP_PREFIX_TYPE_ASM:
216 return (htonl (ASM));
217 case IGMP_GROUP_PREFIX_TYPE_SSM:
218 return (htonl (SSM));
224 static igmp_group_prefix_type_t
225 igmp_group_type_api_to_int (vl_api_group_prefix_type_t t)
230 return (IGMP_GROUP_PREFIX_TYPE_ASM);
232 return (IGMP_GROUP_PREFIX_TYPE_SSM);
235 return (IGMP_GROUP_PREFIX_TYPE_SSM);
239 vl_api_igmp_group_prefix_set_t_handler (vl_api_igmp_group_prefix_set_t * mp)
241 vl_api_igmp_group_prefix_set_reply_t *rmp;
245 ip_prefix_decode (&mp->gp.prefix, &pfx);
246 igmp_group_prefix_set (&pfx, igmp_group_type_api_to_int (mp->gp.type));
248 REPLY_MACRO (VL_API_IGMP_GROUP_PREFIX_SET_REPLY);
251 typedef struct igmp_ssm_range_walk_ctx_t_
253 vl_api_registration_t *rp;
255 } igmp_ssm_range_walk_ctx_t;
258 igmp_ssm_range_walk_dump (const fib_prefix_t * pfx,
259 igmp_group_prefix_type_t type, void *args)
261 igmp_ssm_range_walk_ctx_t *ctx = args;
262 vl_api_igmp_group_prefix_details_t *mp;
264 mp = vl_msg_api_alloc (sizeof (*mp));
265 clib_memset (mp, 0, sizeof (*mp));
267 mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
268 mp->context = ctx->context;
269 mp->gp.type = igmp_group_type_int_to_api (type);
270 ip_prefix_encode (pfx, &mp->gp.prefix);
272 vl_api_send_msg (ctx->rp, (u8 *) mp);
274 return (WALK_CONTINUE);
278 vl_api_igmp_group_prefix_dump_t_handler (vl_api_igmp_dump_t * mp)
280 vl_api_registration_t *rp;
282 rp = vl_api_client_index_to_registration (mp->client_index);
286 igmp_ssm_range_walk_ctx_t ctx = {
288 .context = mp->context,
291 igmp_ssm_range_walk (igmp_ssm_range_walk_dump, &ctx);
294 static vpe_client_registration_t *
295 igmp_api_client_lookup (igmp_main_t * im, u32 client_index)
298 vpe_client_registration_t *api_client = NULL;
300 p = hash_get (im->igmp_api_client_by_client_index, client_index);
302 api_client = vec_elt_at_index (im->api_clients, p[0]);
308 vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp)
310 igmp_main_t *im = &igmp_main;
311 vpe_client_registration_t *api_client;
312 vl_api_want_igmp_events_reply_t *rmp;
315 api_client = igmp_api_client_lookup (im, mp->client_index);
320 rv = VNET_API_ERROR_INVALID_REGISTRATION;
323 hash_unset (im->igmp_api_client_by_client_index,
324 api_client->client_index);
325 pool_put (im->api_clients, api_client);
330 pool_get (im->api_clients, api_client);
331 clib_memset (api_client, 0, sizeof (vpe_client_registration_t));
332 api_client->client_index = mp->client_index;
333 api_client->client_pid = mp->pid;
334 hash_set (im->igmp_api_client_by_client_index,
335 mp->client_index, api_client - im->api_clients);
338 rv = VNET_API_ERROR_INVALID_REGISTRATION;
341 REPLY_MACRO (VL_API_WANT_IGMP_EVENTS_REPLY);
344 static clib_error_t *
345 want_igmp_events_reaper (u32 client_index)
347 igmp_main_t *im = &igmp_main;
348 vpe_client_registration_t *api_client;
351 p = hash_get (im->igmp_api_client_by_client_index, client_index);
355 api_client = pool_elt_at_index (im->api_clients, p[0]);
356 pool_put (im->api_clients, api_client);
357 hash_unset (im->igmp_api_client_by_client_index, client_index);
362 VL_MSG_API_REAPER_FUNCTION (want_igmp_events_reaper);
365 send_igmp_event (vl_api_registration_t * rp,
366 igmp_filter_mode_t filter,
368 const ip46_address_t * saddr, const ip46_address_t * gaddr)
370 vl_api_igmp_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
371 clib_memset (mp, 0, sizeof (*mp));
373 mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + igmp_main.msg_id_base);
374 mp->sw_if_index = htonl (sw_if_index);
375 mp->filter = htonl (filter);
376 clib_memcpy (&mp->saddr, &saddr->ip4, sizeof (ip4_address_t));
377 clib_memcpy (&mp->gaddr, &gaddr->ip4, sizeof (ip4_address_t));
379 vl_api_send_msg (rp, (u8 *) mp);
383 igmp_event (igmp_filter_mode_t filter,
385 const ip46_address_t * saddr, const ip46_address_t * gaddr)
387 vpe_client_registration_t *api_client;
388 vl_api_registration_t *rp;
393 IGMP_DBG ("event: (%U, %U) %U %U",
394 format_ip46_address, saddr, IP46_TYPE_ANY,
395 format_ip46_address, saddr, IP46_TYPE_ANY,
396 format_vnet_sw_if_index_name,
397 vnet_get_main (), sw_if_index, format_igmp_filter_mode, filter);
400 pool_foreach (api_client, im->api_clients)
402 rp = vl_api_client_index_to_registration (api_client->client_index);
404 send_igmp_event (rp, filter, sw_if_index, saddr, gaddr);
408 /* Set up the API message handling tables */
409 #include <igmp/igmp.api.c>
410 static clib_error_t *
411 igmp_plugin_api_hookup (vlib_main_t * vm)
413 igmp_main_t *im = &igmp_main;
415 /* Ask for a correctly-sized block of API message decode slots */
416 im->msg_id_base = setup_message_id_table ();
421 VLIB_API_INIT_FUNCTION (igmp_plugin_api_hookup);
424 * fd.io coding-style-patch-verification: ON
427 * eval: (c-set-style "gnu")