blob: 5555d8fea64c1374659269e5e3ae50e2b2723e14 [file] [log] [blame]
Neale Rannscbe25aa2019-09-30 10:53:31 +00001/*
2 *------------------------------------------------------------------
3 * ip_api.c - vnet ip api
4 *
5 * Copyright (c) 2016 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
18 */
19
20#include <stddef.h>
21
22#include <vnet/ip6-nd/ip6_nd.h>
23#include <vnet/ip6-nd/ip6_ra.h>
24
25#include <vnet/fib/fib_table.h>
26#include <vnet/ip/ip_types_api.h>
27
28#include <vpp/app/version.h>
29
30#include <vlibapi/api.h>
31#include <vlibmemory/api.h>
32
33/* define message IDs */
34#include <vnet/format_fns.h>
35#include <vnet/ip6-nd/ip6_nd.api_enum.h>
36#include <vnet/ip6-nd/ip6_nd.api_types.h>
37
38/**
39 * Base message ID fot the plugin
40 */
41static u32 ip6_nd_base_msg_id;
42#define REPLY_MSG_ID_BASE ip6_nd_base_msg_id
43
44#include <vlibapi/api_helper_macros.h>
45
46static void
47send_ip6nd_proxy_details (vl_api_registration_t * reg,
48 u32 context,
49 const ip46_address_t * addr, u32 sw_if_index)
50{
51 vl_api_ip6nd_proxy_details_t *mp;
52
53 mp = vl_msg_api_alloc (sizeof (*mp));
54 clib_memset (mp, 0, sizeof (*mp));
55 mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
56 mp->context = context;
57 mp->sw_if_index = htonl (sw_if_index);
58
59 ip6_address_encode (&addr->ip6, mp->ip);
60
61 vl_api_send_msg (reg, (u8 *) mp);
62}
63
64typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
65{
66 u32 *indices;
67} api_ip6nd_proxy_fib_table_walk_ctx_t;
68
69static fib_table_walk_rc_t
70api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
71{
72 api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
73
74 if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
75 {
76 vec_add1 (ctx->indices, fei);
77 }
78
79 return (FIB_TABLE_WALK_CONTINUE);
80}
81
82static void
83vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
84{
85 ip6_main_t *im6 = &ip6_main;
Neale Rannsd6953332021-08-10 07:39:18 +000086 u32 fib_index;
Neale Rannscbe25aa2019-09-30 10:53:31 +000087 api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
88 .indices = NULL,
89 };
90 fib_node_index_t *feip;
91 const fib_prefix_t *pfx;
92 vl_api_registration_t *reg;
93
94 reg = vl_api_client_index_to_registration (mp->client_index);
95 if (!reg)
96 return;
97
Neale Rannsd6953332021-08-10 07:39:18 +000098 pool_foreach_index (fib_index, im6->fibs)
99 {
100 fib_table_walk (fib_index, FIB_PROTOCOL_IP6,
101 api_ip6nd_proxy_fib_table_walk, &ctx);
102 }
Neale Rannscbe25aa2019-09-30 10:53:31 +0000103
104 vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
105
106 vec_foreach (feip, ctx.indices)
107 {
108 pfx = fib_entry_get_prefix (*feip);
109
110 send_ip6nd_proxy_details (reg,
111 mp->context,
112 &pfx->fp_addr,
113 fib_entry_get_resolving_interface (*feip));
114 }
115
116 vec_free (ctx.indices);
117}
118
119static void
Mohsin Kazmicebb4772021-04-07 19:50:35 +0200120vl_api_ip6nd_proxy_enable_disable_t_handler (
121 vl_api_ip6nd_proxy_enable_disable_t *mp)
122{
123 vl_api_ip6nd_proxy_enable_disable_reply_t *rmp;
124 int rv = 0;
125
126 VALIDATE_SW_IF_INDEX (mp);
127
128 if (mp->is_enable)
129 rv = ip6_nd_proxy_enable_disable (ntohl (mp->sw_if_index), 1);
130 else
131 rv = ip6_nd_proxy_enable_disable (ntohl (mp->sw_if_index), 0);
132
133 BAD_SW_IF_INDEX_LABEL;
134 REPLY_MACRO (VL_API_IP6ND_PROXY_ENABLE_DISABLE_REPLY);
135}
136
137static void
Neale Rannscbe25aa2019-09-30 10:53:31 +0000138vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
139{
140 vl_api_ip6nd_proxy_add_del_reply_t *rmp;
141 ip6_address_t ip6;
142 int rv = 0;
143
144 VALIDATE_SW_IF_INDEX (mp);
145
146 ip6_address_decode (mp->ip, &ip6);
147 if (mp->is_add)
148 rv = ip6_nd_proxy_add (ntohl (mp->sw_if_index), &ip6);
149 else
150 rv = ip6_nd_proxy_del (ntohl (mp->sw_if_index), &ip6);
151
152 BAD_SW_IF_INDEX_LABEL;
153 REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
154}
155
156static void
157 vl_api_sw_interface_ip6nd_ra_config_t_handler
158 (vl_api_sw_interface_ip6nd_ra_config_t * mp)
159{
160 vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
161 vlib_main_t *vm = vlib_get_main ();
162 int rv = 0;
163 u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
164 default_router;
165
166 is_no = mp->is_no == 1;
167 suppress = mp->suppress == 1;
168 managed = mp->managed == 1;
169 other = mp->other == 1;
170 ll_option = mp->ll_option == 1;
171 send_unicast = mp->send_unicast == 1;
172 cease = mp->cease == 1;
173 default_router = mp->default_router == 1;
174
175 VALIDATE_SW_IF_INDEX (mp);
176
177 rv = ip6_ra_config (vm, ntohl (mp->sw_if_index),
178 suppress, managed, other,
179 ll_option, send_unicast, cease,
180 default_router, ntohl (mp->lifetime),
181 ntohl (mp->initial_count),
182 ntohl (mp->initial_interval),
183 ntohl (mp->max_interval),
184 ntohl (mp->min_interval), is_no);
185
186 BAD_SW_IF_INDEX_LABEL;
187
188 REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
189}
190
191static void
192 vl_api_sw_interface_ip6nd_ra_prefix_t_handler
193 (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
194{
195 vlib_main_t *vm = vlib_get_main ();
196 vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
197 fib_prefix_t pfx;
198 int rv = 0;
199 u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
200
201 VALIDATE_SW_IF_INDEX (mp);
202
203 ip_prefix_decode (&mp->prefix, &pfx);
204 is_no = mp->is_no == 1;
205 use_default = mp->use_default == 1;
206 no_advertise = mp->no_advertise == 1;
207 off_link = mp->off_link == 1;
208 no_autoconfig = mp->no_autoconfig == 1;
209 no_onlink = mp->no_onlink == 1;
210
211 rv = ip6_ra_prefix (vm, ntohl (mp->sw_if_index),
212 &pfx.fp_addr.ip6,
213 pfx.fp_len, use_default,
214 ntohl (mp->val_lifetime),
215 ntohl (mp->pref_lifetime), no_advertise,
216 off_link, no_autoconfig, no_onlink, is_no);
217
218 BAD_SW_IF_INDEX_LABEL;
219 REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
220}
221
222static void
Alexander Chernavin3b28fd72023-02-02 14:22:56 +0000223ip6_radv_prefix_encode (f64 now, const ip6_radv_prefix_t *in,
224 vl_api_ip6nd_ra_prefix_t *out)
225{
226 fib_prefix_t in_ip6_pfx = {
227 .fp_addr = {
228 .ip6 = in->prefix,
229 },
230 .fp_len = in->prefix_len,
231 .fp_proto = FIB_PROTOCOL_IP6,
232 };
233
234 ip_prefix_encode (&in_ip6_pfx, &out->prefix);
235
236 out->onlink_flag = in->adv_on_link_flag;
237 out->autonomous_flag = in->adv_autonomous_flag;
238 out->val_lifetime = htonl (in->adv_valid_lifetime_in_secs);
239 out->pref_lifetime = htonl (in->adv_pref_lifetime_in_secs);
240
241 if (in->adv_valid_lifetime_in_secs != ~0)
242 {
243 out->valid_lifetime_expires =
244 clib_host_to_net_f64 (in->valid_lifetime_expires - now);
245 }
246
247 if (in->adv_pref_lifetime_in_secs != ~0)
248 {
249 out->pref_lifetime_expires =
250 clib_host_to_net_f64 (in->pref_lifetime_expires - now);
251 }
252
253 out->decrement_lifetime_flag = in->decrement_lifetime_flag;
254 out->no_advertise = (in->enabled == 0);
255}
256
257static void
258send_sw_interface_ip6nd_ra_details (vl_api_registration_t *reg, u32 context,
259 ip6_ra_t *radv_info)
260{
261 vl_api_sw_interface_ip6nd_ra_details_t *rmp = 0;
262 vl_api_ip6nd_ra_prefix_t *api_radv_pfx;
263 u32 n_prefixes = pool_elts (radv_info->adv_prefixes_pool);
264 ip6_radv_prefix_t *radv_pfx;
265 u32 msg_size = sizeof (*rmp) + n_prefixes * sizeof (*api_radv_pfx);
266 vlib_main_t *vm = vlib_get_main ();
267 f64 now = vlib_time_now (vm);
268
269 rmp = vl_msg_api_alloc (msg_size);
270 if (!rmp)
271 return;
272 clib_memset (rmp, 0, msg_size);
273 rmp->_vl_msg_id =
274 ntohs (VL_API_SW_INTERFACE_IP6ND_RA_DETAILS + REPLY_MSG_ID_BASE);
275 rmp->context = context;
276
277 rmp->sw_if_index = htonl (radv_info->sw_if_index);
278 rmp->cur_hop_limit = radv_info->curr_hop_limit;
279 rmp->adv_managed_flag = radv_info->adv_managed_flag;
280 rmp->adv_other_flag = radv_info->adv_other_flag;
281 rmp->adv_router_lifetime = htons (radv_info->adv_router_lifetime_in_sec);
282 rmp->adv_neighbor_reachable_time =
283 htonl (radv_info->adv_neighbor_reachable_time_in_msec);
284 rmp->adv_retransmit_interval = htonl (
285 radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
286 rmp->adv_link_mtu = htonl (radv_info->adv_link_mtu);
287 rmp->send_radv = radv_info->send_radv;
288 rmp->cease_radv = radv_info->cease_radv;
289 rmp->send_unicast = radv_info->send_unicast;
290 rmp->adv_link_layer_address = radv_info->adv_link_layer_address;
291 rmp->max_radv_interval = clib_host_to_net_f64 (radv_info->max_radv_interval);
292 rmp->min_radv_interval = clib_host_to_net_f64 (radv_info->min_radv_interval);
293
294 if (radv_info->last_radv_time > 0.0)
295 {
296 rmp->last_radv_time =
297 clib_host_to_net_f64 (now - radv_info->last_radv_time);
298 }
299
300 if ((radv_info->next_multicast_time - radv_info->last_multicast_time) > 0.0)
301 {
302 rmp->last_multicast_time =
303 clib_host_to_net_f64 (now - radv_info->last_multicast_time);
304 rmp->next_multicast_time =
305 clib_host_to_net_f64 (radv_info->next_multicast_time - now);
306 }
307
308 rmp->initial_adverts_count = htonl (radv_info->initial_adverts_count);
309 rmp->initial_adverts_interval =
310 clib_host_to_net_f64 (radv_info->initial_adverts_interval);
311 rmp->initial_adverts_sent = (radv_info->initial_adverts_sent == 0);
312 rmp->n_advertisements_sent = htonl (radv_info->n_advertisements_sent);
313 rmp->n_solicitations_rcvd = htonl (radv_info->n_solicitations_rcvd);
314 rmp->n_solicitations_dropped = htonl (radv_info->n_solicitations_dropped);
315 rmp->n_prefixes = htonl (n_prefixes);
316
317 api_radv_pfx = rmp->prefixes;
318 pool_foreach (radv_pfx, radv_info->adv_prefixes_pool)
319 {
320 ip6_radv_prefix_encode (now, radv_pfx, api_radv_pfx);
321
322 api_radv_pfx++;
323 }
324
325 vl_api_send_msg (reg, (u8 *) rmp);
326}
327
328typedef struct
329{
330 u32 *sw_if_indices;
331} api_dump_ip6_ra_itf_walk_ctx_t;
332
333static walk_rc_t
334api_dump_ip6_ra_itf_walk_fn (u32 sw_if_index, void *arg)
335{
336 api_dump_ip6_ra_itf_walk_ctx_t *ctx = arg;
337
338 vec_add1 (ctx->sw_if_indices, sw_if_index);
339
340 return (WALK_CONTINUE);
341}
342
343static void
344vl_api_sw_interface_ip6nd_ra_dump_t_handler (
345 vl_api_sw_interface_ip6nd_ra_dump_t *mp)
346{
347 vl_api_registration_t *reg;
348 u32 sw_if_index;
349 ip6_ra_t *radv_info;
350
351 reg = vl_api_client_index_to_registration (mp->client_index);
352 if (!reg)
353 return;
354
355 sw_if_index = ntohl (mp->sw_if_index);
356
357 if (sw_if_index == INDEX_INVALID)
358 {
359 /* dump all interfaces */
360
361 api_dump_ip6_ra_itf_walk_ctx_t ctx = {
362 .sw_if_indices = NULL,
363 };
364 u32 *sw_if_i;
365
366 ip6_ra_itf_walk (api_dump_ip6_ra_itf_walk_fn, &ctx);
367
368 vec_foreach (sw_if_i, ctx.sw_if_indices)
369 {
370 radv_info = ip6_ra_get_itf (*sw_if_i);
371 if (radv_info != NULL)
372 {
373 send_sw_interface_ip6nd_ra_details (reg, mp->context, radv_info);
374 }
375 }
376
377 vec_free (ctx.sw_if_indices);
378 }
379 else
380 {
381 /* dump a single interface */
382
383 radv_info = ip6_ra_get_itf (sw_if_index);
384 if (radv_info != NULL)
385 {
386 send_sw_interface_ip6nd_ra_details (reg, mp->context, radv_info);
387 }
388 }
389}
390
391static void
Neale Rannscbe25aa2019-09-30 10:53:31 +0000392 vl_api_ip6nd_send_router_solicitation_t_handler
393 (vl_api_ip6nd_send_router_solicitation_t * mp)
394{
395 vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
396 icmp6_send_router_solicitation_params_t params;
397 vlib_main_t *vm = vlib_get_main ();
398 int rv = 0;
399
400 VALIDATE_SW_IF_INDEX (mp);
401
402 BAD_SW_IF_INDEX_LABEL;
403 REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
404
405 if (rv != 0)
406 return;
407
408 params.irt = ntohl (mp->irt);
409 params.mrt = ntohl (mp->mrt);
410 params.mrc = ntohl (mp->mrc);
411 params.mrd = ntohl (mp->mrd);
412
413 icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
414 &params);
415}
416
417static void
418ip6_ra_handle_report (const ip6_ra_report_t * rap)
419{
Neale Rannscbe25aa2019-09-30 10:53:31 +0000420 vpe_client_registration_t *rp;
421
Damjan Marionb2c31b62020-12-13 21:47:40 +0100422 pool_foreach (rp, vpe_api_main.ip6_ra_events_registrations)
423 {
Neale Rannscbe25aa2019-09-30 10:53:31 +0000424 vl_api_registration_t *vl_reg;
425
426 vl_reg = vl_api_client_index_to_registration (rp->client_index);
427
428 if (vl_reg && vl_api_can_send_msg (vl_reg))
429 {
430 vl_api_ip6_ra_prefix_info_t *prefix;
431 vl_api_ip6_ra_event_t *event;
432
433 u32 event_size = (sizeof (vl_api_ip6_ra_event_t) +
434 vec_len (rap->prefixes) *
435 sizeof (vl_api_ip6_ra_prefix_info_t));
436 event = vl_msg_api_alloc_zero (event_size);
437
438 event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT + REPLY_MSG_ID_BASE);
439 event->client_index = rp->client_index;
440 event->pid = rp->client_pid;
441 event->sw_if_index = clib_host_to_net_u32 (rap->sw_if_index);
442
443 ip6_address_encode (&rap->router_address,
444 event->router_addr);
445
446 event->current_hop_limit = rap->current_hop_limit;
447 event->flags = rap->flags;
448 event->router_lifetime_in_sec =
449 clib_host_to_net_u16 (rap->router_lifetime_in_sec);
450 event->neighbor_reachable_time_in_msec =
451 clib_host_to_net_u32 (rap->neighbor_reachable_time_in_msec);
452 event->time_in_msec_between_retransmitted_neighbor_solicitations =
453 clib_host_to_net_u32 (rap->time_in_msec_between_retransmitted_neighbor_solicitations);
454 event->n_prefixes = clib_host_to_net_u32 (vec_len (rap->prefixes));
455
456 prefix = event->prefixes;
457 // (typeof (prefix)) event->prefixes;
458 u32 j;
459 for (j = 0; j < vec_len (rap->prefixes); j++)
460 {
461 ra_report_prefix_info_t *info = &rap->prefixes[j];
462 ip_prefix_encode(&info->prefix, &prefix->prefix);
463 prefix->flags = info->flags;
464 prefix->valid_time = clib_host_to_net_u32 (info->valid_time);
465 prefix->preferred_time =
466 clib_host_to_net_u32 (info->preferred_time);
467 prefix++;
468 }
469
470 vl_api_send_msg (vl_reg, (u8 *) event);
471 }
Damjan Marionb2c31b62020-12-13 21:47:40 +0100472 }
Neale Rannscbe25aa2019-09-30 10:53:31 +0000473}
474
475static void
476vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
477{
478 vpe_api_main_t *am = &vpe_api_main;
479 vl_api_want_ip6_ra_events_reply_t *rmp;
480 int rv = 0, had_reg, have_reg;
481
482 had_reg = hash_elts (am->ip6_ra_events_registration_hash);
483 uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
484 vpe_client_registration_t *rp;
485 if (p)
486 {
487 if (mp->enable)
488 {
489 clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
490 rv = VNET_API_ERROR_INVALID_REGISTRATION;
491 goto reply;
492 }
493 else
494 {
495 rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
496 pool_put (am->ip6_ra_events_registrations, rp);
497 hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
498 goto reply;
499 }
500 }
501 if (mp->enable == 0)
502 {
503 clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
504 rv = VNET_API_ERROR_INVALID_REGISTRATION;
505 goto reply;
506 }
507 pool_get (am->ip6_ra_events_registrations, rp);
508 rp->client_index = mp->client_index;
509 rp->client_pid = ntohl (mp->pid);
510 hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
511 rp - am->ip6_ra_events_registrations);
512
513reply:
514 have_reg = hash_elts (am->ip6_ra_events_registration_hash);
515
516 if (!had_reg && have_reg)
517 ip6_ra_report_register (ip6_ra_handle_report);
518 else if (had_reg && !have_reg)
519 ip6_ra_report_unregister (ip6_ra_handle_report);
520
521 REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
522}
523
524static clib_error_t *
525want_ip6_ra_events_reaper (u32 client_index)
526{
527 vpe_api_main_t *am = &vpe_api_main;
528 vpe_client_registration_t *rp;
529 uword *p;
530
531 p = hash_get (am->ip6_ra_events_registration_hash, client_index);
532
533 if (p)
534 {
535 rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
536 pool_put (am->ip6_ra_events_registrations, rp);
537 hash_unset (am->ip6_ra_events_registration_hash, client_index);
538 }
539 return (NULL);
540}
541
542VL_MSG_API_REAPER_FUNCTION (want_ip6_ra_events_reaper);
543
544#include <vnet/ip6-nd/ip6_nd.api.c>
545
546static clib_error_t *
547ip6_nd_api_init (vlib_main_t * vm)
548{
549 /* Ask for a correctly-sized block of API message decode slots */
550 ip6_nd_base_msg_id = setup_message_id_table ();
551
552 return 0;
553}
554
555VLIB_INIT_FUNCTION (ip6_nd_api_init);
556
557/*
558 * fd.io coding-style-patch-verification: ON
559 *
560 * Local Variables:
561 * eval: (c-set-style "gnu")
562 * End:
563 */