diff options
author | Alexander Chernavin <achernavin@netgate.com> | 2023-02-02 14:22:56 +0000 |
---|---|---|
committer | Neale Ranns <neale@graphiant.com> | 2023-02-08 03:20:32 +0000 |
commit | 3b28fd730625a475a4093bec3e2ed9b1b6932131 (patch) | |
tree | 5afc537c75cde2bddc45981a0ab01be0a3095fdf | |
parent | 02dfd296342525a0802132d85d0ea51da841e5ce (diff) |
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 <achernavin@netgate.com>
Change-Id: I89fa93439d33cc36252377f27187b18b3d30a1d4
-rw-r--r-- | src/vnet/ip6-nd/ip6_nd.api | 130 | ||||
-rw-r--r-- | src/vnet/ip6-nd/ip6_nd_api.c | 169 | ||||
-rw-r--r-- | src/vnet/ip6-nd/ip6_nd_test.c | 57 | ||||
-rw-r--r-- | src/vnet/ip6-nd/ip6_ra.c | 103 | ||||
-rw-r--r-- | src/vnet/ip6-nd/ip6_ra.h | 109 | ||||
-rw-r--r-- | test/test_ip6.py | 79 |
6 files changed, 549 insertions, 98 deletions
diff --git a/src/vnet/ip6-nd/ip6_nd.api b/src/vnet/ip6-nd/ip6_nd.api index 0a519c16f7f..3ddf25103c1 100644 --- a/src/vnet/ip6-nd/ip6_nd.api +++ b/src/vnet/ip6-nd/ip6_nd.api @@ -20,7 +20,7 @@ called through a shared memory interface. */ -option version = "1.0.0"; +option version = "1.1.0"; import "vnet/ip/ip_types.api"; import "vnet/interface_types.api"; @@ -106,6 +106,134 @@ autoreply define sw_interface_ip6nd_ra_prefix u32 pref_lifetime; }; +/** \brief IPv6 Router Advertisements prefix entry + @param prefix - prefix to advertise + @param onlink_flag - if true, the prefix can be used for on-link + determination + @param autonomous_flag - if true, the prefix can be used for stateless + address configuration + @param val_lifetime - valid lifetime in seconds (0xffffffff represents + infinity) + @param pref_lifetime - preferred lifetime in seconds (0xffffffff represents + infinity) + @param valid_lifetime_expires - number of seconds in which valid lifetime + expires (zero means never, negative value + means expired this number of seconds ago) + @param pref_lifetime_expires - number of seconds in which preferred + lifetime expires (zero means never, negative + value means expired this number of seconds + ago) + @param decrement_lifetime_flag - if true, decrement valid lifetime and + preferred lifetime + @param no_advertise - if true, the prefix will not be advertised +*/ +typedef ip6nd_ra_prefix +{ + vl_api_prefix_t prefix; + bool onlink_flag; + bool autonomous_flag; + u32 val_lifetime; + u32 pref_lifetime; + f64 valid_lifetime_expires; + f64 pref_lifetime_expires; + bool decrement_lifetime_flag; + bool no_advertise; +}; + +/** \brief Dump IPv6 Router Advertisements details on a per-interface basis + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface index to use as a filter (0xffffffff + represents all interfaces) +*/ +define sw_interface_ip6nd_ra_dump +{ + option in_progress; + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; + option vat_help = "[(<if-name>|sw_if_index <if-idx>)]"; +}; + +/** \brief Details on IPv6 Router Advertisements for a single interface + @param context - returned sender context, to match reply w/ request + @param sw_if_index - interface index the details are belong to + @param cur_hop_limit - current hop limit + @param adv_managed_flag - if true, enable DHCP for address + @param adv_other_flag - if true, Enable DHCP for other information + @param adv_router_lifetime - lifetime associated with the default router in + seconds (zero indicates that the router is not + a default router) + @param adv_neighbor_reachable_time - number of milliseconds within which a + neighbor is assumed to be reachable + (zero means unspecified) + @param adv_retransmit_interval - number of milliseconds between + retransmitted Neighbor Solicitation + messages (zero means unspecified) + @param adv_link_mtu - MTU that all the nodes on a link use + @param send_radv - if true, send periodic Router Advertisements + @param cease_radv - if true, cease to send periodic Router Advertisements + @param send_unicast - if true, destination address of a Router + Advertisement message will use the source address of + the Router Solicitation message (when available). + Otherwise, multicast address will be used + @param adv_link_layer_address - if true, add link layer address option + @param max_radv_interval - maximum time in seconds allowed between sending + unsolicited multicast Router Advertisements + @param min_radv_interval - minimum time in seconds allowed between sending + unsolicited multicast Router Advertisements + @param last_radv_time - number of seconds since the last time a solicited + Router Advertisement message was sent (zero means + never) + @param last_multicast_time - number of seconds since the last time a + multicast Router Advertisements message was + sent (zero means never) + @param next_multicast_time - number of seconds within which next time a + multicast Router Advertisement message will be + sent (zero means never) + @param initial_adverts_count - number of initial Router Advertisement + messages to send + @param initial_adverts_interval - number of seconds between initial Router + Advertisement messages + @param initial_adverts_sent - if true, all initial Router Advertisement + messages were sent + @param n_advertisements_sent - number of Router Advertisements sent + @param n_solicitations_rcvd - number of Router Solicitations received + @param n_solicitations_dropped - number of Router Solicitations dropped + @param n_prefixes - number of prefix entries + @param prefixes - array of prefix entries +*/ +define sw_interface_ip6nd_ra_details +{ + option in_progress; + u32 context; + vl_api_interface_index_t sw_if_index; + u8 cur_hop_limit; + bool adv_managed_flag; + bool adv_other_flag; + u16 adv_router_lifetime; + u32 adv_neighbor_reachable_time; + u32 adv_retransmit_interval; + u32 adv_link_mtu; + bool send_radv; + bool cease_radv; + bool send_unicast; + bool adv_link_layer_address; + f64 max_radv_interval; + f64 min_radv_interval; + f64 last_radv_time; + f64 last_multicast_time; + f64 next_multicast_time; + u32 initial_adverts_count; + f64 initial_adverts_interval; + bool initial_adverts_sent; + u32 n_advertisements_sent; + u32 n_solicitations_rcvd; + u32 n_solicitations_dropped; + u32 n_prefixes; + vl_api_ip6nd_ra_prefix_t prefixes[n_prefixes]; +}; + /** \brief IPv6 ND (mirror) proxy @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request 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 @@ -222,6 +222,175 @@ static void } 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) { diff --git a/src/vnet/ip6-nd/ip6_nd_test.c b/src/vnet/ip6-nd/ip6_nd_test.c index 933029d7593..488ca591ba0 100644 --- a/src/vnet/ip6-nd/ip6_nd_test.c +++ b/src/vnet/ip6-nd/ip6_nd_test.c @@ -325,6 +325,63 @@ api_ip6nd_proxy_enable_disable (vat_main_t *vam) return -1; } +static int +api_sw_interface_ip6nd_ra_dump (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6nd_ra_dump_t *mp; + vl_api_control_ping_t *mp_ping; + u32 sw_if_index = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6ND_RA_DUMP, mp); + mp->sw_if_index = ntohl (sw_if_index); + + /* Send it */ + S (mp); + + /* Use control ping for synchronization */ + PING (&ip6_nd_test_main, mp_ping); + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + + return ret; +} + +static void +vl_api_sw_interface_ip6nd_ra_details_t_handler ( + vl_api_sw_interface_ip6nd_ra_details_t *mp) +{ + vat_main_t *vam = ip6_nd_test_main.vat_main; + u32 sw_if_index; + u8 send_radv; + + /* Read the message */ + sw_if_index = ntohl (mp->sw_if_index); + send_radv = mp->send_radv; + + /* Print it */ + print (vam->ofp, "sw_if_index: %u, send_radv: %s", sw_if_index, + (send_radv ? "on" : "off")); +} + #include <ip6-nd/ip6_nd.api_test.c> /* diff --git a/src/vnet/ip6-nd/ip6_ra.c b/src/vnet/ip6-nd/ip6_ra.c index 65b7cf09983..3781ea3b891 100644 --- a/src/vnet/ip6-nd/ip6_ra.c +++ b/src/vnet/ip6-nd/ip6_ra.c @@ -65,95 +65,6 @@ typedef CLIB_PACKED (struct #define MAX_DELAY_BETWEEN_RAS 1800 /* seconds */ #define MAX_RA_DELAY_TIME .5 /* seconds */ -/* advertised prefix option */ -typedef struct -{ - /* basic advertised information */ - ip6_address_t prefix; - u8 prefix_len; - int adv_on_link_flag; - int adv_autonomous_flag; - u32 adv_valid_lifetime_in_secs; - u32 adv_pref_lifetime_in_secs; - - /* advertised values are computed from these times if decrementing */ - f64 valid_lifetime_expires; - f64 pref_lifetime_expires; - - /* local information */ - int enabled; - int deprecated_prefix_flag; - int decrement_lifetime_flag; - -#define MIN_ADV_VALID_LIFETIME 7203 /* seconds */ -#define DEF_ADV_VALID_LIFETIME 2592000 -#define DEF_ADV_PREF_LIFETIME 604800 - - /* extensions are added here, mobile, DNS etc.. */ -} ip6_radv_prefix_t; - -typedef struct ip6_ra_t_ -{ - /* advertised config information, zero means unspecified */ - u8 curr_hop_limit; - int adv_managed_flag; - int adv_other_flag; - u16 adv_router_lifetime_in_sec; - u32 adv_neighbor_reachable_time_in_msec; - u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations; - - /* mtu option */ - u32 adv_link_mtu; - - /* local information */ - u32 sw_if_index; - int send_radv; /* radv on/off on this interface - set by config */ - int cease_radv; /* we are ceasing to send - set byf config */ - int send_unicast; - int adv_link_layer_address; - int prefix_option; - int failed_device_check; - int ref_count; - - /* prefix option */ - ip6_radv_prefix_t *adv_prefixes_pool; - - /* Hash table mapping address to index in interface advertised prefix pool. */ - mhash_t address_to_prefix_index; - - f64 max_radv_interval; - f64 min_radv_interval; - f64 min_delay_between_radv; - f64 max_delay_between_radv; - f64 max_rtr_default_lifetime; - - f64 last_radv_time; - f64 last_multicast_time; - f64 next_multicast_time; - - - u32 initial_adverts_count; - f64 initial_adverts_interval; - u32 initial_adverts_sent; - - /* stats */ - u32 n_advertisements_sent; - u32 n_solicitations_rcvd; - u32 n_solicitations_dropped; - - /* router solicitations sending state */ - u8 keep_sending_rs; /* when true then next fields are valid */ - icmp6_send_router_solicitation_params_t params; - f64 sleep_interval; - f64 due_time; - u32 n_left; - f64 start_time; - vlib_buffer_t *buffer; - - u32 seed; - -} ip6_ra_t; - static ip6_link_delegate_id_t ip6_ra_delegate_id; static ip6_ra_t *ip6_ra_pool; @@ -191,7 +102,7 @@ ip6_ra_report_unregister (ip6_ra_report_notify_t fn) } } -static inline ip6_ra_t * +ip6_ra_t * ip6_ra_get_itf (u32 sw_if_index) { index_t rai; @@ -214,6 +125,18 @@ ip6_ra_adv_enabled (u32 sw_if_index) return ((ra != NULL) && (ra->send_radv != 0)); } +void +ip6_ra_itf_walk (ip6_ra_itf_walk_fn_t fn, void *ctx) +{ + ip6_ra_t *radv_info; + + pool_foreach (radv_info, ip6_ra_pool) + { + if (WALK_STOP == fn (radv_info->sw_if_index, ctx)) + break; + } +} + /* for "syslogging" - use elog for now */ #define foreach_log_level \ _ (DEBUG, "DEBUG") \ diff --git a/src/vnet/ip6-nd/ip6_ra.h b/src/vnet/ip6-nd/ip6_ra.h index c5012477d80..958845b0a55 100644 --- a/src/vnet/ip6-nd/ip6_ra.h +++ b/src/vnet/ip6-nd/ip6_ra.h @@ -21,6 +21,105 @@ #include <vnet/fib/fib_types.h> +/* advertised prefix option */ +typedef struct +{ + /* basic advertised information */ + ip6_address_t prefix; + u8 prefix_len; + int adv_on_link_flag; + int adv_autonomous_flag; + u32 adv_valid_lifetime_in_secs; + u32 adv_pref_lifetime_in_secs; + + /* advertised values are computed from these times if decrementing */ + f64 valid_lifetime_expires; + f64 pref_lifetime_expires; + + /* local information */ + int enabled; + int deprecated_prefix_flag; + int decrement_lifetime_flag; + +#define MIN_ADV_VALID_LIFETIME 7203 /* seconds */ +#define DEF_ADV_VALID_LIFETIME 2592000 +#define DEF_ADV_PREF_LIFETIME 604800 + + /* extensions are added here, mobile, DNS etc.. */ +} ip6_radv_prefix_t; + +typedef struct +{ + u32 irt; + u32 mrt; + u32 mrc; + u32 mrd; +} icmp6_send_router_solicitation_params_t; + +typedef struct ip6_ra_t_ +{ + /* advertised config information, zero means unspecified */ + u8 curr_hop_limit; + int adv_managed_flag; + int adv_other_flag; + u16 adv_router_lifetime_in_sec; + u32 adv_neighbor_reachable_time_in_msec; + u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations; + + /* mtu option */ + u32 adv_link_mtu; + + /* local information */ + u32 sw_if_index; + int send_radv; /* radv on/off on this interface - set by config */ + int cease_radv; /* we are ceasing to send - set byf config */ + int send_unicast; + int adv_link_layer_address; + int prefix_option; + int failed_device_check; + int ref_count; + + /* prefix option */ + ip6_radv_prefix_t *adv_prefixes_pool; + + /* Hash table mapping address to index in interface advertised prefix pool. + */ + mhash_t address_to_prefix_index; + + f64 max_radv_interval; + f64 min_radv_interval; + f64 min_delay_between_radv; + f64 max_delay_between_radv; + f64 max_rtr_default_lifetime; + + f64 last_radv_time; + f64 last_multicast_time; + f64 next_multicast_time; + + u32 initial_adverts_count; + f64 initial_adverts_interval; + u32 initial_adverts_sent; + + /* stats */ + u32 n_advertisements_sent; + u32 n_solicitations_rcvd; + u32 n_solicitations_dropped; + + /* router solicitations sending state */ + u8 keep_sending_rs; /* when true then next fields are valid */ + icmp6_send_router_solicitation_params_t params; + f64 sleep_interval; + f64 due_time; + u32 n_left; + f64 start_time; + vlib_buffer_t *buffer; + + u32 seed; + +} ip6_ra_t; + +extern ip6_ra_t *ip6_ra_get_itf (u32 sw_if_index); + extern int ip6_ra_config (vlib_main_t * vm, u32 sw_if_index, u8 suppress, u8 managed, u8 other, u8 ll_option, u8 send_unicast, u8 cease, @@ -35,13 +134,9 @@ extern int ip6_ra_prefix (vlib_main_t * vm, u32 sw_if_index, u8 off_link, u8 no_autoconfig, u8 no_onlink, u8 is_no); -typedef struct -{ - u32 irt; - u32 mrt; - u32 mrc; - u32 mrd; -} icmp6_send_router_solicitation_params_t; +typedef walk_rc_t (*ip6_ra_itf_walk_fn_t) (u32 sw_if_index, void *ctx); + +extern void ip6_ra_itf_walk (ip6_ra_itf_walk_fn_t fn, void *ctx); extern void icmp6_send_router_solicitation (vlib_main_t * vm, u32 sw_if_index, diff --git a/test/test_ip6.py b/test/test_ip6.py index 38bce973e86..b46bef65f16 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -779,6 +779,85 @@ class TestIPv6(TestIPv6ND): rx = rx[0] self.validate_ra(intf, rx, dst_ip, src_ip=src_ip, pi_opt=opt) + def test_ip6_ra_dump(self): + """IPv6 RA dump""" + + # Dump IPv6 RA for all interfaces + ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(sw_if_index=0xFFFFFFFF) + self.assertEqual(len(ip6_ra_dump), len(self.interfaces)) + + for ip6_ra in ip6_ra_dump: + self.assertFalse(ip6_ra.send_radv) + self.assertEqual(ip6_ra.n_prefixes, 0) + self.assertEqual(len(ip6_ra.prefixes), 0) + self.assertEqual(ip6_ra.last_radv_time, 0.0) + self.assertEqual(ip6_ra.last_multicast_time, 0.0) + self.assertEqual(ip6_ra.next_multicast_time, 0.0) + self.assertEqual(ip6_ra.n_advertisements_sent, 0) + self.assertEqual(ip6_ra.n_solicitations_rcvd, 0) + self.assertEqual(ip6_ra.n_solicitations_dropped, 0) + + # Enable sending IPv6 RA for an interface + self.pg0.ip6_ra_config(no=1, suppress=1) + + # Add IPv6 RA prefixes for the interface + pfx0 = IPv6Network( + "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), strict=False + ) + pfx1 = IPv6Network("fafa::/96") + self.pg0.ip6_ra_prefix(pfx0, off_link=0, no_autoconfig=0) + self.pg0.ip6_ra_prefix(pfx1, off_link=1, no_autoconfig=1) + + # Wait for multicast IPv6 RA + self.sleep(1) + + # Dump IPv6 RA for the interface + ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump( + sw_if_index=self.pg0.sw_if_index + ) + self.assertEqual(len(ip6_ra_dump), 1) + ip6_ra = ip6_ra_dump[0] + + self.assertEqual(ip6_ra.sw_if_index, self.pg0.sw_if_index) + self.assertTrue(ip6_ra.send_radv) + self.assertEqual(ip6_ra.n_prefixes, 2) + self.assertEqual(len(ip6_ra.prefixes), 2) + self.assertEqual(ip6_ra.last_radv_time, 0.0) + self.assertGreater(ip6_ra.last_multicast_time, 0.0) + self.assertGreater(ip6_ra.next_multicast_time, 0.0) + self.assertGreater(ip6_ra.n_advertisements_sent, 0) + self.assertEqual(ip6_ra.n_solicitations_rcvd, 0) + self.assertEqual(ip6_ra.n_solicitations_dropped, 0) + + self.assertEqual(ip6_ra.prefixes[0].prefix, pfx0) + self.assertTrue(ip6_ra.prefixes[0].onlink_flag) + self.assertTrue(ip6_ra.prefixes[0].autonomous_flag) + self.assertFalse(ip6_ra.prefixes[0].no_advertise) + + self.assertEqual(ip6_ra.prefixes[1].prefix, pfx1) + self.assertFalse(ip6_ra.prefixes[1].onlink_flag) + self.assertFalse(ip6_ra.prefixes[1].autonomous_flag) + self.assertFalse(ip6_ra.prefixes[1].no_advertise) + + # Reset sending IPv6 RA for the interface + self.pg0.ip6_ra_config(suppress=1) + + # Remove IPv6 RA prefixes for the interface + self.pg0.ip6_ra_prefix(pfx0, is_no=1) + self.pg0.ip6_ra_prefix(pfx1, is_no=1) + + # Dump IPv6 RA for the interface + ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump( + sw_if_index=self.pg0.sw_if_index + ) + self.assertEqual(len(ip6_ra_dump), 1) + ip6_ra = ip6_ra_dump[0] + + self.assertEqual(ip6_ra.sw_if_index, self.pg0.sw_if_index) + self.assertFalse(ip6_ra.send_radv) + self.assertEqual(ip6_ra.n_prefixes, 0) + self.assertEqual(len(ip6_ra.prefixes), 0) + def test_rs(self): """IPv6 Router Solicitation Exceptions |