From 3b28fd730625a475a4093bec3e2ed9b1b6932131 Mon Sep 17 00:00:00 2001 From: Alexander Chernavin Date: Thu, 2 Feb 2023 14:22:56 +0000 Subject: ip6-nd: support dump/details for IPv6 RA Type: improvement With this change, add support for dumping IPv6 Router Advertisements details on a per-interface basis (or all). Also, cover that with a test. Signed-off-by: Alexander Chernavin Change-Id: I89fa93439d33cc36252377f27187b18b3d30a1d4 --- src/vnet/ip6-nd/ip6_nd_api.c | 169 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) (limited to 'src/vnet/ip6-nd/ip6_nd_api.c') diff --git a/src/vnet/ip6-nd/ip6_nd_api.c b/src/vnet/ip6-nd/ip6_nd_api.c index 6520a61f691..c11c3cb6597 100644 --- a/src/vnet/ip6-nd/ip6_nd_api.c +++ b/src/vnet/ip6-nd/ip6_nd_api.c @@ -221,6 +221,175 @@ static void REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY); } +static void +ip6_radv_prefix_encode (f64 now, const ip6_radv_prefix_t *in, + vl_api_ip6nd_ra_prefix_t *out) +{ + fib_prefix_t in_ip6_pfx = { + .fp_addr = { + .ip6 = in->prefix, + }, + .fp_len = in->prefix_len, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + ip_prefix_encode (&in_ip6_pfx, &out->prefix); + + out->onlink_flag = in->adv_on_link_flag; + out->autonomous_flag = in->adv_autonomous_flag; + out->val_lifetime = htonl (in->adv_valid_lifetime_in_secs); + out->pref_lifetime = htonl (in->adv_pref_lifetime_in_secs); + + if (in->adv_valid_lifetime_in_secs != ~0) + { + out->valid_lifetime_expires = + clib_host_to_net_f64 (in->valid_lifetime_expires - now); + } + + if (in->adv_pref_lifetime_in_secs != ~0) + { + out->pref_lifetime_expires = + clib_host_to_net_f64 (in->pref_lifetime_expires - now); + } + + out->decrement_lifetime_flag = in->decrement_lifetime_flag; + out->no_advertise = (in->enabled == 0); +} + +static void +send_sw_interface_ip6nd_ra_details (vl_api_registration_t *reg, u32 context, + ip6_ra_t *radv_info) +{ + vl_api_sw_interface_ip6nd_ra_details_t *rmp = 0; + vl_api_ip6nd_ra_prefix_t *api_radv_pfx; + u32 n_prefixes = pool_elts (radv_info->adv_prefixes_pool); + ip6_radv_prefix_t *radv_pfx; + u32 msg_size = sizeof (*rmp) + n_prefixes * sizeof (*api_radv_pfx); + vlib_main_t *vm = vlib_get_main (); + f64 now = vlib_time_now (vm); + + rmp = vl_msg_api_alloc (msg_size); + if (!rmp) + return; + clib_memset (rmp, 0, msg_size); + rmp->_vl_msg_id = + ntohs (VL_API_SW_INTERFACE_IP6ND_RA_DETAILS + REPLY_MSG_ID_BASE); + rmp->context = context; + + rmp->sw_if_index = htonl (radv_info->sw_if_index); + rmp->cur_hop_limit = radv_info->curr_hop_limit; + rmp->adv_managed_flag = radv_info->adv_managed_flag; + rmp->adv_other_flag = radv_info->adv_other_flag; + rmp->adv_router_lifetime = htons (radv_info->adv_router_lifetime_in_sec); + rmp->adv_neighbor_reachable_time = + htonl (radv_info->adv_neighbor_reachable_time_in_msec); + rmp->adv_retransmit_interval = htonl ( + radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations); + rmp->adv_link_mtu = htonl (radv_info->adv_link_mtu); + rmp->send_radv = radv_info->send_radv; + rmp->cease_radv = radv_info->cease_radv; + rmp->send_unicast = radv_info->send_unicast; + rmp->adv_link_layer_address = radv_info->adv_link_layer_address; + rmp->max_radv_interval = clib_host_to_net_f64 (radv_info->max_radv_interval); + rmp->min_radv_interval = clib_host_to_net_f64 (radv_info->min_radv_interval); + + if (radv_info->last_radv_time > 0.0) + { + rmp->last_radv_time = + clib_host_to_net_f64 (now - radv_info->last_radv_time); + } + + if ((radv_info->next_multicast_time - radv_info->last_multicast_time) > 0.0) + { + rmp->last_multicast_time = + clib_host_to_net_f64 (now - radv_info->last_multicast_time); + rmp->next_multicast_time = + clib_host_to_net_f64 (radv_info->next_multicast_time - now); + } + + rmp->initial_adverts_count = htonl (radv_info->initial_adverts_count); + rmp->initial_adverts_interval = + clib_host_to_net_f64 (radv_info->initial_adverts_interval); + rmp->initial_adverts_sent = (radv_info->initial_adverts_sent == 0); + rmp->n_advertisements_sent = htonl (radv_info->n_advertisements_sent); + rmp->n_solicitations_rcvd = htonl (radv_info->n_solicitations_rcvd); + rmp->n_solicitations_dropped = htonl (radv_info->n_solicitations_dropped); + rmp->n_prefixes = htonl (n_prefixes); + + api_radv_pfx = rmp->prefixes; + pool_foreach (radv_pfx, radv_info->adv_prefixes_pool) + { + ip6_radv_prefix_encode (now, radv_pfx, api_radv_pfx); + + api_radv_pfx++; + } + + vl_api_send_msg (reg, (u8 *) rmp); +} + +typedef struct +{ + u32 *sw_if_indices; +} api_dump_ip6_ra_itf_walk_ctx_t; + +static walk_rc_t +api_dump_ip6_ra_itf_walk_fn (u32 sw_if_index, void *arg) +{ + api_dump_ip6_ra_itf_walk_ctx_t *ctx = arg; + + vec_add1 (ctx->sw_if_indices, sw_if_index); + + return (WALK_CONTINUE); +} + +static void +vl_api_sw_interface_ip6nd_ra_dump_t_handler ( + vl_api_sw_interface_ip6nd_ra_dump_t *mp) +{ + vl_api_registration_t *reg; + u32 sw_if_index; + ip6_ra_t *radv_info; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + sw_if_index = ntohl (mp->sw_if_index); + + if (sw_if_index == INDEX_INVALID) + { + /* dump all interfaces */ + + api_dump_ip6_ra_itf_walk_ctx_t ctx = { + .sw_if_indices = NULL, + }; + u32 *sw_if_i; + + ip6_ra_itf_walk (api_dump_ip6_ra_itf_walk_fn, &ctx); + + vec_foreach (sw_if_i, ctx.sw_if_indices) + { + radv_info = ip6_ra_get_itf (*sw_if_i); + if (radv_info != NULL) + { + send_sw_interface_ip6nd_ra_details (reg, mp->context, radv_info); + } + } + + vec_free (ctx.sw_if_indices); + } + else + { + /* dump a single interface */ + + radv_info = ip6_ra_get_itf (sw_if_index); + if (radv_info != NULL) + { + send_sw_interface_ip6nd_ra_details (reg, mp->context, radv_info); + } + } +} + static void vl_api_ip6nd_send_router_solicitation_t_handler (vl_api_ip6nd_send_router_solicitation_t * mp) -- cgit 1.2.3-korg