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_msg_enum.h>
28 /* define message structures */
30 #include <igmp/igmp_all_api_h.h>
33 /* define generated endian-swappers */
35 #include <igmp/igmp_all_api_h.h>
38 /* instantiate all the print functions we know about */
39 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
41 #include <igmp/igmp_all_api_h.h>
44 /* Get the API version number */
45 #define vl_api_version(n,v) static u32 api_version=(v);
46 #include <igmp/igmp_all_api_h.h>
49 #include <vlibapi/api_helper_macros.h>
51 #define IGMP_MSG_ID(_id) (_id + igmp_main.msg_id_base)
53 #define foreach_igmp_plugin_api_msg \
54 _(IGMP_LISTEN, igmp_listen) \
55 _(IGMP_ENABLE_DISABLE, igmp_enable_disable) \
56 _(IGMP_DUMP, igmp_dump) \
57 _(IGMP_CLEAR_INTERFACE, igmp_clear_interface) \
58 _(IGMP_CLEAR_INTERFACE, igmp_clear_interface) \
59 _(IGMP_GROUP_PREFIX_SET, igmp_group_prefix_set) \
60 _(IGMP_GROUP_PREFIX_DUMP, igmp_group_prefix_dump) \
61 _(WANT_IGMP_EVENTS, want_igmp_events) \
64 vl_api_igmp_listen_t_handler (vl_api_igmp_listen_t * mp)
66 vlib_main_t *vm = vlib_get_main ();
67 vnet_main_t *vnm = vnet_get_main ();
68 vl_api_igmp_listen_reply_t *rmp;
70 ip46_address_t gaddr, *saddrs = NULL;
72 VALIDATE_SW_IF_INDEX (&mp->group);
74 if ((vnet_sw_interface_get_flags (vnm, ntohl (mp->group.sw_if_index)) &&
75 VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
77 // FIXME - don't we clear this state on interface down ...
78 rv = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
82 memset (&gaddr, 0, sizeof (gaddr));
83 clib_memcpy (&gaddr.ip4, &mp->group.gaddr, sizeof (ip4_address_t));
85 vec_validate (saddrs, mp->group.n_srcs - 1);
87 vec_foreach_index (ii, saddrs)
89 clib_memcpy (&saddrs[ii].ip4,
90 &mp->group.saddrs[ii], sizeof (ip4_address_t));
95 IGMP_FILTER_MODE_INCLUDE :
96 IGMP_FILTER_MODE_EXCLUDE),
97 ntohl (mp->group.sw_if_index), saddrs, &gaddr);
101 BAD_SW_IF_INDEX_LABEL;
103 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_LISTEN_REPLY));
107 vl_api_igmp_enable_disable_t_handler (vl_api_igmp_enable_disable_t * mp)
109 vl_api_igmp_enable_disable_reply_t *rmp;
112 VALIDATE_SW_IF_INDEX (mp);
114 rv = igmp_enable_disable (ntohl (mp->sw_if_index),
116 (mp->mode ? IGMP_MODE_HOST : IGMP_MODE_ROUTER));
118 BAD_SW_IF_INDEX_LABEL;
120 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_ENABLE_DISABLE_REPLY));
124 send_igmp_details (unix_shared_memory_queue_t * q, igmp_main_t * im,
125 igmp_config_t * config, igmp_group_t * group,
126 igmp_src_t * src, u32 context)
128 vl_api_igmp_details_t *mp;
130 mp = vl_msg_api_alloc (sizeof (*mp));
131 memset (mp, 0, sizeof (*mp));
133 mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
134 mp->context = context;
135 mp->sw_if_index = htonl (config->sw_if_index);
136 clib_memcpy (mp->saddr.address, &src->key->ip4, sizeof (src->key->ip4));
137 clib_memcpy (mp->gaddr.address, &group->key->ip4, sizeof (group->key->ip6));
139 vl_msg_api_send_shmem (q, (u8 *) & mp);
143 igmp_config_dump (igmp_main_t * im,
144 unix_shared_memory_queue_t * q,
145 u32 context, igmp_config_t * config)
151 FOR_EACH_GROUP (group, config,
153 FOR_EACH_SRC (src, group, IGMP_FILTER_MODE_INCLUDE,
155 send_igmp_details (q, im, config, group, src, context);
162 vl_api_igmp_dump_t_handler (vl_api_igmp_dump_t * mp)
164 unix_shared_memory_queue_t *q;
165 igmp_main_t *im = &igmp_main;
166 igmp_config_t *config;
169 q = vl_api_client_index_to_input_queue (mp->client_index);
173 sw_if_index = ntohl (mp->sw_if_index);
174 if (~0 == sw_if_index)
177 pool_foreach (config, im->configs,
179 igmp_config_dump(im, q, mp->context, config);
185 config = igmp_config_lookup (sw_if_index);
188 igmp_config_dump (im, q, mp->context, config);
194 vl_api_igmp_clear_interface_t_handler (vl_api_igmp_clear_interface_t * mp)
196 vl_api_igmp_clear_interface_reply_t *rmp;
197 igmp_config_t *config;
200 config = igmp_config_lookup (ntohl (mp->sw_if_index));
202 igmp_clear_config (config);
204 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_CLEAR_INTERFACE_REPLY));
207 static vl_api_group_prefix_type_t
208 igmp_group_type_int_to_api (igmp_group_prefix_type_t t)
212 case IGMP_GROUP_PREFIX_TYPE_ASM:
213 return (htonl (ASM));
214 case IGMP_GROUP_PREFIX_TYPE_SSM:
215 return (htonl (SSM));
221 static igmp_group_prefix_type_t
222 igmp_group_type_api_to_int (vl_api_group_prefix_type_t t)
227 return (IGMP_GROUP_PREFIX_TYPE_ASM);
229 return (IGMP_GROUP_PREFIX_TYPE_SSM);
232 return (IGMP_GROUP_PREFIX_TYPE_SSM);
236 vl_api_igmp_group_prefix_set_t_handler (vl_api_igmp_group_prefix_set_t * mp)
238 vl_api_igmp_group_prefix_set_reply_t *rmp;
242 ip_prefix_decode (&mp->gp.prefix, &pfx);
243 igmp_group_prefix_set (&pfx, igmp_group_type_api_to_int (mp->gp.type));
245 REPLY_MACRO (IGMP_MSG_ID (VL_API_IGMP_GROUP_PREFIX_SET_REPLY));
248 typedef struct igmp_ssm_range_walk_ctx_t_
250 unix_shared_memory_queue_t *q;
252 } igmp_ssm_range_walk_ctx_t;
255 igmp_ssm_range_walk_dump (const fib_prefix_t * pfx,
256 igmp_group_prefix_type_t type, void *args)
258 igmp_ssm_range_walk_ctx_t *ctx = args;
259 vl_api_igmp_group_prefix_details_t *mp;
261 mp = vl_msg_api_alloc (sizeof (*mp));
262 memset (mp, 0, sizeof (*mp));
264 mp->_vl_msg_id = htons (IGMP_MSG_ID (VL_API_IGMP_DETAILS));
265 mp->context = ctx->context;
266 mp->gp.type = igmp_group_type_int_to_api (type);
267 ip_prefix_encode (pfx, &mp->gp.prefix);
269 vl_msg_api_send_shmem (ctx->q, (u8 *) & mp);
271 return (WALK_CONTINUE);
275 vl_api_igmp_group_prefix_dump_t_handler (vl_api_igmp_dump_t * mp)
277 unix_shared_memory_queue_t *q;
279 q = vl_api_client_index_to_input_queue (mp->client_index);
283 igmp_ssm_range_walk_ctx_t ctx = {
285 .context = mp->context,
288 igmp_ssm_range_walk (igmp_ssm_range_walk_dump, &ctx);
291 static vpe_client_registration_t *
292 igmp_api_client_lookup (igmp_main_t * im, u32 client_index)
295 vpe_client_registration_t *api_client = NULL;
297 p = hash_get (im->igmp_api_client_by_client_index, client_index);
299 api_client = vec_elt_at_index (im->api_clients, p[0]);
305 vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp)
307 igmp_main_t *im = &igmp_main;
308 vpe_client_registration_t *api_client;
309 vl_api_want_igmp_events_reply_t *rmp;
312 api_client = igmp_api_client_lookup (im, mp->client_index);
317 rv = VNET_API_ERROR_INVALID_REGISTRATION;
320 hash_unset (im->igmp_api_client_by_client_index,
321 api_client->client_index);
322 pool_put (im->api_clients, api_client);
327 pool_get (im->api_clients, api_client);
328 memset (api_client, 0, sizeof (vpe_client_registration_t));
329 api_client->client_index = mp->client_index;
330 api_client->client_pid = mp->pid;
331 hash_set (im->igmp_api_client_by_client_index,
332 mp->client_index, api_client - im->api_clients);
335 rv = VNET_API_ERROR_INVALID_REGISTRATION;
338 REPLY_MACRO (VL_API_WANT_IGMP_EVENTS_REPLY + im->msg_id_base);
341 static clib_error_t *
342 want_igmp_events_reaper (u32 client_index)
344 igmp_main_t *im = &igmp_main;
345 vpe_client_registration_t *api_client;
348 p = hash_get (im->igmp_api_client_by_client_index, client_index);
352 api_client = pool_elt_at_index (im->api_clients, p[0]);
353 pool_put (im->api_clients, api_client);
354 hash_unset (im->igmp_api_client_by_client_index, client_index);
359 VL_MSG_API_REAPER_FUNCTION (want_igmp_events_reaper);
362 send_igmp_event (unix_shared_memory_queue_t * q,
364 igmp_filter_mode_t filter,
366 const ip46_address_t * saddr, const ip46_address_t * gaddr)
368 vl_api_igmp_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
369 memset (mp, 0, sizeof (*mp));
371 mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + igmp_main.msg_id_base);
372 mp->context = context;
373 mp->sw_if_index = htonl (sw_if_index);
374 mp->filter = htonl (filter);
375 clib_memcpy (&mp->saddr, &saddr->ip4, sizeof (ip4_address_t));
376 clib_memcpy (&mp->gaddr, &gaddr->ip4, sizeof (ip4_address_t));
378 vl_msg_api_send_shmem (q, (u8 *) & mp);
382 igmp_event (igmp_filter_mode_t filter,
384 const ip46_address_t * saddr, const ip46_address_t * gaddr)
386 vpe_client_registration_t *api_client;
387 unix_shared_memory_queue_t *q;
392 IGMP_DBG ("event: (%U, %U) %U %U",
393 format_ip46_address, saddr, IP46_TYPE_ANY,
394 format_ip46_address, saddr, IP46_TYPE_ANY,
395 format_vnet_sw_if_index_name,
396 vnet_get_main (), sw_if_index, format_igmp_filter_mode, filter);
400 pool_foreach (api_client, im->api_clients,
402 q = vl_api_client_index_to_input_queue (api_client->client_index);
404 send_igmp_event (q, 0, filter, sw_if_index, saddr, gaddr);
409 #define vl_msg_name_crc_list
410 #include <igmp/igmp_all_api_h.h>
411 #undef vl_msg_name_crc_list
414 setup_message_id_table (igmp_main_t * im, api_main_t * am)
416 #define _(id,n,crc) \
417 vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + im->msg_id_base);
418 foreach_vl_msg_name_crc_igmp;
422 /* Set up the API message handling tables */
423 static clib_error_t *
424 igmp_plugin_api_hookup (vlib_main_t * vm)
426 igmp_main_t *im = &igmp_main;
427 api_main_t *am = &api_main;
430 /* Construct the API name */
431 name = format (0, "igmp_%08x%c", api_version, 0);
433 /* Ask for a correctly-sized block of API message decode slots */
434 im->msg_id_base = vl_msg_api_get_msg_ids
435 ((char *) name, VL_MSG_FIRST_AVAILABLE);
438 vl_msg_api_set_handlers((VL_API_##N + im->msg_id_base), \
440 vl_api_##n##_t_handler, \
442 vl_api_##n##_t_endian, \
443 vl_api_##n##_t_print, \
444 sizeof(vl_api_##n##_t), 1);
445 foreach_igmp_plugin_api_msg;
449 * Set up the (msg_name, crc, message-id) table
451 setup_message_id_table (im, am);
457 VLIB_API_INIT_FUNCTION (igmp_plugin_api_hookup);
460 * fd.io coding-style-patch-verification: ON
463 * eval: (c-set-style "gnu")