IGMP plugin
[vpp.git] / src / plugins / igmp / igmp_api.c
1 /*
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:
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 <igmp/igmp.h>
19
20 #include <vlibapi/api.h>
21 #include <vlibmemory/api.h>
22
23 /* define message IDs */
24 #include <igmp/igmp_msg_enum.h>
25
26 /* define message structures */
27 #define vl_typedefs
28 #include <igmp/igmp_all_api_h.h>
29 #undef vl_typedefs
30
31 /* define generated endian-swappers */
32 #define vl_endianfun
33 #include <igmp/igmp_all_api_h.h>
34 #undef vl_endianfun
35
36 /* instantiate all the print functions we know about */
37 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
38 #define vl_printfun
39 #include <igmp/igmp_all_api_h.h>
40 #undef vl_printfun
41
42 /* Get the API version number */
43 #define vl_api_version(n,v) static u32 api_version=(v);
44 #include <igmp/igmp_all_api_h.h>
45 #undef vl_api_version
46
47 #include <vlibapi/api_helper_macros.h>
48
49 #define foreach_igmp_plugin_api_msg                      \
50 _(IGMP_LISTEN, igmp_listen)                              \
51 _(IGMP_ENABLE_DISABLE, igmp_enable_disable)              \
52 _(IGMP_DUMP, igmp_dump)                                  \
53 _(IGMP_CLEAR_INTERFACE, igmp_clear_interface)            \
54 _(WANT_IGMP_EVENTS, want_igmp_events)                    \
55
56 static void
57 vl_api_igmp_listen_t_handler (vl_api_igmp_listen_t * mp)
58 {
59   vlib_main_t *vm = vlib_get_main ();
60   vnet_main_t *vnm = vnet_get_main ();
61   igmp_main_t *im = &igmp_main;
62   vl_api_igmp_listen_reply_t *rmp;
63   int rv = 0;
64   ip46_address_t saddr, gaddr;
65
66   if (!vnet_sw_interface_is_api_valid (vnm, ntohl (mp->sw_if_index)))
67     {
68       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
69       goto done;
70     }
71
72   if ((vnet_sw_interface_get_flags (vnm, ntohl (mp->sw_if_index)) &&
73        VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
74     {
75       rv = VNET_API_ERROR_UNEXPECTED_INTF_STATE;
76       goto done;
77     }
78
79   clib_memcpy (&saddr.ip4.as_u8, mp->saddr, sizeof (u8) * 4);
80   clib_memcpy (&gaddr.ip4.as_u8, mp->gaddr, sizeof (u8) * 4);
81
82   rv = igmp_listen (vm, mp->enable, ntohl (mp->sw_if_index), saddr, gaddr, 1);
83
84 done:;
85   unix_shared_memory_queue_t *q =
86     vl_api_client_index_to_input_queue (mp->client_index);
87   if (!q)
88     return;
89
90   rmp = vl_msg_api_alloc (sizeof (*rmp));
91   rmp->_vl_msg_id = htons ((VL_API_IGMP_LISTEN_REPLY) + im->msg_id_base);
92   rmp->context = mp->context;
93   rmp->retval = htonl (rv);
94
95   vl_msg_api_send_shmem (q, (u8 *) & rmp);
96 }
97
98 static void
99 vl_api_igmp_enable_disable_t_handler (vl_api_igmp_enable_disable_t * mp)
100 {
101   vl_api_igmp_enable_disable_reply_t *rmp;
102   igmp_main_t *im = &igmp_main;
103   int rv = 0;
104
105   REPLY_MACRO (VL_API_IGMP_ENABLE_DISABLE_REPLY + im->msg_id_base);
106 }
107
108 static void
109 send_igmp_details (unix_shared_memory_queue_t * q, igmp_main_t * im,
110                    igmp_config_t * config, igmp_sg_t * sg, u32 context)
111 {
112   vl_api_igmp_details_t *mp;
113
114   mp = vl_msg_api_alloc (sizeof (*mp));
115   memset (mp, 0, sizeof (*mp));
116
117   mp->_vl_msg_id = htons (VL_API_IGMP_DETAILS + im->msg_id_base);
118   mp->context = context;
119   mp->sw_if_index = htonl (config->sw_if_index);
120   clib_memcpy (mp->saddr, &sg->saddr.ip4, sizeof (u8) * 4);
121   clib_memcpy (mp->gaddr, &sg->gaddr.ip4, sizeof (u8) * 4);
122
123   vl_msg_api_send_shmem (q, (u8 *) & mp);
124 }
125
126 static void
127 vl_api_igmp_dump_t_handler (vl_api_igmp_dump_t * mp)
128 {
129   igmp_main_t *im = &igmp_main;
130   igmp_config_t *config;
131   igmp_sg_t *sg;
132
133   unix_shared_memory_queue_t *q =
134     vl_api_client_index_to_input_queue (mp->client_index);
135   if (!q)
136     return;
137
138   if (mp->dump_all)
139     {
140       /* *INDENT-OFF* */
141       pool_foreach (config, im->configs, (
142         {
143             pool_foreach (sg, config->sg, (
144               {
145                 send_igmp_details (q, im, config, sg, mp->context);
146               }));
147         }));
148       /* *INDENT-ON* */
149       return;
150     }
151   config = igmp_config_lookup (im, ntohl (mp->sw_if_index));
152   if (config)
153     {
154       /* *INDENT-OFF* */
155       pool_foreach (sg, config->sg, (
156         {
157           send_igmp_details (q, im, config, sg, mp->context);
158         }));
159       /* *INDENT-ON* */
160     }
161 }
162
163 static void
164 vl_api_igmp_clear_interface_t_handler (vl_api_igmp_clear_interface_t * mp)
165 {
166   igmp_main_t *im = &igmp_main;
167   igmp_config_t *config;
168   vl_api_igmp_clear_interface_reply_t *rmp;
169   int rv = 0;
170
171   config = igmp_config_lookup (im, ntohl (mp->sw_if_index));
172   if (config)
173     igmp_clear_config (config);
174
175   unix_shared_memory_queue_t *q =
176     vl_api_client_index_to_input_queue (mp->client_index);
177   if (!q)
178     return;
179
180   rmp = vl_msg_api_alloc (sizeof (*rmp));
181   rmp->_vl_msg_id =
182     htons ((VL_API_IGMP_CLEAR_INTERFACE_REPLY) + im->msg_id_base);
183   rmp->context = mp->context;
184   rmp->retval = htonl (rv);
185
186   vl_msg_api_send_shmem (q, (u8 *) & rmp);
187 }
188
189 static void
190 vl_api_want_igmp_events_t_handler (vl_api_want_igmp_events_t * mp)
191 {
192   igmp_main_t *im = &igmp_main;
193   igmp_api_client_t *api_client;
194   vl_api_want_igmp_events_reply_t *rmp;
195   int rv = 0;
196
197   api_client = igmp_api_client_lookup (im, mp->client_index);
198   if (api_client)
199     {
200       if (mp->enable)
201         {
202           rv = VNET_API_ERROR_INVALID_REGISTRATION;
203           goto done;
204         }
205       hash_unset_mem (im->igmp_api_client_by_client_index,
206                       &api_client->client_index);
207       pool_put (im->api_clients, api_client);
208       goto done;
209     }
210   if (mp->enable)
211     {
212       pool_get (im->api_clients, api_client);
213       memset (api_client, 0, sizeof (igmp_api_client_t));
214       api_client->client_index = mp->client_index;
215       api_client->pid = mp->pid;
216       hash_set_mem (im->igmp_api_client_by_client_index,
217                     &mp->client_index, api_client - im->api_clients);
218       goto done;
219     }
220   rv = VNET_API_ERROR_INVALID_REGISTRATION;
221
222 done:;
223   unix_shared_memory_queue_t *q =
224     vl_api_client_index_to_input_queue (mp->client_index);
225   if (!q)
226     return;
227
228   rmp = vl_msg_api_alloc (sizeof (*rmp));
229   rmp->_vl_msg_id = htons ((VL_API_WANT_IGMP_EVENTS_REPLY) + im->msg_id_base);
230   rmp->context = mp->context;
231   rmp->retval = htonl (rv);
232
233   vl_msg_api_send_shmem (q, (u8 *) & rmp);
234 }
235
236 void
237 send_igmp_event (unix_shared_memory_queue_t * q, u32 context,
238                  igmp_main_t * im, igmp_config_t * config, igmp_sg_t * sg)
239 {
240   vl_api_igmp_event_t *mp = vl_msg_api_alloc (sizeof (*mp));
241   memset (mp, 0, sizeof (*mp));
242
243   mp->_vl_msg_id = ntohs ((VL_API_IGMP_EVENT) + im->msg_id_base);
244   mp->context = context;
245   mp->sw_if_index = htonl (config->sw_if_index);
246   clib_memcpy (&mp->saddr, &sg->saddr.ip4, sizeof (ip4_address_t));
247   clib_memcpy (&mp->gaddr, &sg->gaddr.ip4, sizeof (ip4_address_t));
248   mp->is_join =
249     (sg->group_type == IGMP_MEMBERSHIP_GROUP_mode_is_filter_include) ? 1 : 0;
250
251   vl_msg_api_send_shmem (q, (u8 *) & mp);
252 }
253
254 void
255 igmp_event (igmp_main_t * im, igmp_config_t * config, igmp_sg_t * sg)
256 {
257   igmp_api_client_t *api_client;
258   unix_shared_memory_queue_t *q;
259   /* *INDENT-OFF* */
260   pool_foreach (api_client, im->api_clients,
261     ({
262       q = vl_api_client_index_to_input_queue (api_client->client_index);
263       if (q)
264         send_igmp_event (q, 0, im, config, sg);
265     }));
266   /* *INDENT-ON* */
267   if (sg->group_type == IGMP_MEMBERSHIP_GROUP_block_old_sources)
268     {
269       hash_unset_mem (config->igmp_sg_by_key, sg->key);
270       clib_mem_free (sg->key);
271       pool_put (config->sg, sg);
272       if (pool_elts (config->sg) == 0)
273         {
274           hash_unset_mem (im->igmp_config_by_sw_if_index,
275                           &config->sw_if_index);
276           pool_put (im->configs, config);
277         }
278     }
279 }
280
281 #define vl_msg_name_crc_list
282 #include <igmp/igmp_all_api_h.h>
283 #undef vl_msg_name_crc_list
284
285 static void
286 setup_message_id_table (igmp_main_t * im, api_main_t * am)
287 {
288 #define _(id,n,crc) \
289   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + im->msg_id_base);
290   foreach_vl_msg_name_crc_igmp;
291 #undef _
292 }
293
294 /* Set up the API message handling tables */
295 static clib_error_t *
296 igmp_plugin_api_hookup (vlib_main_t * vm)
297 {
298   igmp_main_t *im = &igmp_main;
299   api_main_t *am = &api_main;
300   u8 *name;
301
302   /* Construct the API name */
303   name = format (0, "igmp_%08x%c", api_version, 0);
304
305   /* Ask for a correctly-sized block of API message decode slots */
306   im->msg_id_base = vl_msg_api_get_msg_ids
307     ((char *) name, VL_MSG_FIRST_AVAILABLE);
308
309 #define _(N,n)                                                  \
310     vl_msg_api_set_handlers((VL_API_##N + im->msg_id_base),     \
311                            #n,                                  \
312                            vl_api_##n##_t_handler,              \
313                            vl_noop_handler,                     \
314                            vl_api_##n##_t_endian,               \
315                            vl_api_##n##_t_print,                \
316                            sizeof(vl_api_##n##_t), 1);
317   foreach_igmp_plugin_api_msg;
318 #undef _
319
320   /*
321    * Set up the (msg_name, crc, message-id) table
322    */
323   setup_message_id_table (im, am);
324
325   vec_free (name);
326   return 0;
327 }
328
329 VLIB_API_INIT_FUNCTION (igmp_plugin_api_hookup);
330
331 /*
332  * fd.io coding-style-patch-verification: ON
333  *
334  * Local Variables:
335  * eval: (c-set-style "gnu")
336  * End:
337  */