aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/ip/ip.api36
-rw-r--r--src/vnet/ip/ip6_neighbor.c244
-rw-r--r--src/vppinfra/pool.h26
-rw-r--r--test/test_ip6.py219
-rw-r--r--test/vpp_interface.py11
-rw-r--r--test/vpp_neighbor.py2
-rw-r--r--test/vpp_papi_provider.py25
7 files changed, 400 insertions, 163 deletions
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api
index 326c825b39f..ff16e781c05 100644
--- a/src/vnet/ip/ip.api
+++ b/src/vnet/ip/ip.api
@@ -241,17 +241,31 @@ define sw_interface_ip6nd_ra_config_reply
/** \brief IPv6 router advertisement prefix config request
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
- @param sw_if_index -
- @param address[] -
- @param address_length -
- @param use_default -
- @param no_advertise -
- @param off_link -
- @param no_autoconfig -
- @param no_onlink -
- @param is_no -
- @param val_lifetime -
- @param pref_lifetime -
+ @param sw_if_index - The interface the RA prefix information is for
+ @param address[] - The prefix to advertise
+ @param address_length - the prefix length
+ @param use_default - Revert to default settings
+ @param no_advertise - Do not advertise this prefix
+ @param off_link - The prefix is off link (it is not configured on the interface)
+ Configures the L-flag, When set, indicates that this
+ prefix can be used for on-link determination.
+ @param no_autoconfig - Setting for the A-flag. When
+ set indicates that this prefix can be used for
+ stateless address configuration.
+ @param no_onlink - The prefix is not on link. Make sure this is consistent
+ with the off_link parameter else YMMV
+ @param is_no - add/delete
+ @param val_lifetime - The length of time in
+ seconds (relative to the time the packet is sent)
+ that the prefix is valid for the purpose of on-link
+ determination. A value of all one bits
+ (0xffffffff) represents infinity
+ @param pref_lifetime - The length of time in
+ seconds (relative to the time the packet is sent)
+ that addresses generated from the prefix via
+ stateless address autoconfiguration remain
+ preferred [ADDRCONF]. A value of all one bits
+ (0xffffffff) represents infinity.
*/
define sw_interface_ip6nd_ra_prefix
{
diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c
index 91ff224c68e..43d68cd18bb 100644
--- a/src/vnet/ip/ip6_neighbor.c
+++ b/src/vnet/ip/ip6_neighbor.c
@@ -107,7 +107,6 @@ typedef struct
/* local information */
u32 sw_if_index;
- u32 fib_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;
@@ -1924,7 +1923,79 @@ icmp6_router_advertisement (vlib_main_t * vm,
return frame->n_vectors;
}
-/* create and initialize router advertisement parameters with default values for this intfc */
+/**
+ * @brief Add a multicast Address to the advertised MLD set
+ */
+static void
+ip6_neighbor_add_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr)
+{
+ ip6_mldp_group_t *mcast_group_info;
+ uword *p;
+
+ /* lookup mldp info for this interface */
+ p = mhash_get (&radv_info->address_to_mldp_index, &addr);
+ mcast_group_info =
+ p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
+
+ /* add address */
+ if (!mcast_group_info)
+ {
+ /* add */
+ u32 mi;
+ pool_get (radv_info->mldp_group_pool, mcast_group_info);
+
+ mi = mcast_group_info - radv_info->mldp_group_pool;
+ mhash_set (&radv_info->address_to_mldp_index, &addr, mi, /* old_value */
+ 0);
+
+ mcast_group_info->type = 4;
+ mcast_group_info->mcast_source_address_pool = 0;
+ mcast_group_info->num_sources = 0;
+ clib_memcpy (&mcast_group_info->mcast_address, &addr,
+ sizeof (ip6_address_t));
+ }
+}
+
+/**
+ * @brief Delete a multicast Address from the advertised MLD set
+ */
+static void
+ip6_neighbor_del_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr)
+{
+ ip6_mldp_group_t *mcast_group_info;
+ uword *p;
+
+ p = mhash_get (&radv_info->address_to_mldp_index, &addr);
+ mcast_group_info =
+ p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
+
+ if (mcast_group_info)
+ {
+ mhash_unset (&radv_info->address_to_mldp_index, &addr,
+ /* old_value */ 0);
+ pool_put (radv_info->mldp_group_pool, mcast_group_info);
+ }
+}
+
+/**
+ * @brief Add a multicast Address to the advertised MLD set
+ */
+static void
+ip6_neighbor_add_mld_grp (ip6_radv_t * a,
+ ip6_multicast_address_scope_t scope,
+ ip6_multicast_link_local_group_id_t group)
+{
+ ip6_address_t addr;
+
+ ip6_set_reserved_multicast_address (&addr, scope, group);
+
+ ip6_neighbor_add_mld_prefix (a, &addr);
+}
+
+/**
+ * @brief create and initialize router advertisement parameters with default
+ * values for this intfc
+ */
static u32
ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
u32 sw_if_index, u32 is_add)
@@ -1953,47 +2024,29 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
if (!is_add)
{
- u32 i, *to_delete = 0;
ip6_radv_prefix_t *p;
ip6_mldp_group_t *m;
/* release the lock on the interface's mcast adj */
adj_unlock (a->mcast_adj_index);
- /* clean up prefix_pool */
+ /* clean up prefix and MDP pools */
/* *INDENT-OFF* */
- pool_foreach (p, a->adv_prefixes_pool,
+ pool_flush(p, a->adv_prefixes_pool,
({
- vec_add1 (to_delete, p - a->adv_prefixes_pool);
- }));
- /* *INDENT-ON* */
-
- for (i = 0; i < vec_len (to_delete); i++)
- {
- p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
- pool_put (a->adv_prefixes_pool, p);
- }
-
- vec_free (to_delete);
- to_delete = 0;
-
- /* clean up mldp group pool */
- /* *INDENT-OFF* */
- pool_foreach (m, a->mldp_group_pool,
+ }));
+ pool_flush (m, a->mldp_group_pool,
({
- vec_add1 (to_delete, m - a->mldp_group_pool);
+ mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
}));
/* *INDENT-ON* */
- for (i = 0; i < vec_len (to_delete); i++)
- {
- m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
- mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
- pool_put (a->mldp_group_pool, m);
- }
+ pool_free (a->mldp_group_pool);
+ pool_free (a->adv_prefixes_pool);
- vec_free (to_delete);
+ mhash_free (&a->address_to_prefix_index);
+ mhash_free (&a->address_to_mldp_index);
pool_put (nm->if_radv_pool, a);
nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
@@ -2017,13 +2070,13 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
memset (a, 0, sizeof (a[0]));
a->sw_if_index = sw_if_index;
- a->fib_index = ~0;
a->max_radv_interval = DEF_MAX_RADV_INTERVAL;
a->min_radv_interval = DEF_MIN_RADV_INTERVAL;
a->curr_hop_limit = DEF_CURR_HOP_LIMIT;
a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;
- a->adv_link_layer_address = 1; /* send ll address source address option */
+ /* send ll address source address option */
+ a->adv_link_layer_address = 1;
a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
@@ -2059,86 +2112,15 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
sw_if_index);
/* add multicast groups we will always be reporting */
- ip6_address_t addr;
- ip6_mldp_group_t *mcast_group_info;
-
- ip6_set_reserved_multicast_address (&addr,
- IP6_MULTICAST_SCOPE_link_local,
- IP6_MULTICAST_GROUP_ID_all_hosts);
-
- /* lookup mldp info for this interface */
-
- uword *p = mhash_get (&a->address_to_mldp_index, &addr);
- mcast_group_info =
- p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
-
- /* add address */
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (a->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - a->mldp_group_pool;
- mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */
- 0);
-
- mcast_group_info->type = 4;
- mcast_group_info->mcast_source_address_pool = 0;
- mcast_group_info->num_sources = 0;
- clib_memcpy (&mcast_group_info->mcast_address, &addr,
- sizeof (ip6_address_t));
- }
-
- ip6_set_reserved_multicast_address (&addr,
- IP6_MULTICAST_SCOPE_link_local,
- IP6_MULTICAST_GROUP_ID_all_routers);
-
- p = mhash_get (&a->address_to_mldp_index, &addr);
- mcast_group_info =
- p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
-
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (a->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - a->mldp_group_pool;
- mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */
- 0);
-
- mcast_group_info->type = 4;
- mcast_group_info->mcast_source_address_pool = 0;
- mcast_group_info->num_sources = 0;
- clib_memcpy (&mcast_group_info->mcast_address, &addr,
- sizeof (ip6_address_t));
- }
-
- ip6_set_reserved_multicast_address (&addr,
- IP6_MULTICAST_SCOPE_link_local,
- IP6_MULTICAST_GROUP_ID_mldv2_routers);
-
- p = mhash_get (&a->address_to_mldp_index, &addr);
- mcast_group_info =
- p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
-
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (a->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - a->mldp_group_pool;
- mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */
- 0);
-
- mcast_group_info->type = 4;
- mcast_group_info->mcast_source_address_pool = 0;
- mcast_group_info->num_sources = 0;
- clib_memcpy (&mcast_group_info->mcast_address, &addr,
- sizeof (ip6_address_t));
- }
+ ip6_neighbor_add_mld_grp (a,
+ IP6_MULTICAST_SCOPE_link_local,
+ IP6_MULTICAST_GROUP_ID_all_hosts);
+ ip6_neighbor_add_mld_grp (a,
+ IP6_MULTICAST_SCOPE_link_local,
+ IP6_MULTICAST_GROUP_ID_all_routers);
+ ip6_neighbor_add_mld_grp (a,
+ IP6_MULTICAST_SCOPE_link_local,
+ IP6_MULTICAST_GROUP_ID_mldv2_routers);
}
}
return ri;
@@ -3695,7 +3677,9 @@ VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) =
};
/* *INDENT-ON* */
-/* callback when an interface address is added or deleted */
+/**
+ * @brief callback when an interface address is added or deleted
+ */
static void
ip6_neighbor_add_del_interface_address (ip6_main_t * im,
uword opaque,
@@ -3710,7 +3694,6 @@ ip6_neighbor_add_del_interface_address (ip6_main_t * im,
vlib_main_t *vm = vnm->vlib_main;
ip6_radv_t *radv_info;
ip6_address_t a;
- ip6_mldp_group_t *mcast_group_info;
/* create solicited node multicast address for this interface adddress */
ip6_set_solicited_node_multicast_address (&a, 0);
@@ -3737,28 +3720,7 @@ ip6_neighbor_add_del_interface_address (ip6_main_t * im,
if (!ip6_address_is_link_local_unicast (address))
radv_info->ref_count++;
- /* lookup prefix info for this address on this interface */
- uword *p = mhash_get (&radv_info->address_to_mldp_index, &a);
- mcast_group_info =
- p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
-
- /* add -solicted node multicast address */
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (radv_info->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - radv_info->mldp_group_pool;
- mhash_set (&radv_info->address_to_mldp_index, &a, mi,
- /* old_value */ 0);
-
- mcast_group_info->type = 4;
- mcast_group_info->mcast_source_address_pool = 0;
- mcast_group_info->num_sources = 0;
- clib_memcpy (&mcast_group_info->mcast_address, &a,
- sizeof (ip6_address_t));
- }
+ ip6_neighbor_add_mld_prefix (radv_info, &a);
}
}
else
@@ -3775,17 +3737,7 @@ ip6_neighbor_add_del_interface_address (ip6_main_t * im,
/* get radv_info */
radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
- /* lookup prefix info for this address on this interface */
- uword *p = mhash_get (&radv_info->address_to_mldp_index, &a);
- mcast_group_info =
- p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
-
- if (mcast_group_info)
- {
- mhash_unset (&radv_info->address_to_mldp_index, &a,
- /* old_value */ 0);
- pool_put (radv_info->mldp_group_pool, mcast_group_info);
- }
+ ip6_neighbor_del_mld_prefix (radv_info, &a);
/* if interface up send MLDP "report" */
radv_info->all_routers_mcast = 0;
diff --git a/src/vppinfra/pool.h b/src/vppinfra/pool.h
index 586d13e73a9..57838e1c609 100644
--- a/src/vppinfra/pool.h
+++ b/src/vppinfra/pool.h
@@ -350,6 +350,7 @@ do { \
It is a bad idea to allocate or free pool element from within
@c pool_foreach. Build a vector of indices and dispose of them later.
+ Or call pool_flush.
@par Example
@@ -421,6 +422,31 @@ do { \
do { body; } while (0); \
}
+/**
+ * @brief Remove all elemenets from a pool in a safe way
+ *
+ * @param VAR each element in the pool
+ * @param POOL The pool to flush
+ * @param BODY The actions to perform on each element before it is returned to
+ * the pool. i.e. before it is 'freed'
+ */
+#define pool_flush(VAR, POOL, BODY) \
+{ \
+ uword *_pool_var(ii), *_pool_var(dv) = NULL; \
+ \
+ pool_foreach((VAR), (POOL), \
+ ({ \
+ vec_add1(_pool_var(dv), (VAR) - (POOL)); \
+ })); \
+ vec_foreach(_pool_var(ii), _pool_var(dv)) \
+ { \
+ (VAR) = pool_elt_at_index((POOL), *_pool_var(ii)); \
+ do { BODY; } while (0); \
+ pool_put((POOL), (VAR)); \
+ } \
+ vec_free(_pool_var(dv)); \
+}
+
#endif /* included_pool_h */
/*
diff --git a/test/test_ip6.py b/test/test_ip6.py
index fb5383cfc0c..b8278329ba9 100644
--- a/test/test_ip6.py
+++ b/test/test_ip6.py
@@ -10,7 +10,8 @@ from vpp_pg_interface import is_ipv6_misc
from scapy.packet import Raw
from scapy.layers.l2 import Ether, Dot1Q
from scapy.layers.inet6 import IPv6, UDP, ICMPv6ND_NS, ICMPv6ND_RS, \
- ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation
+ ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation, \
+ ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo
from util import ppp
from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \
in6_mactoifaceid, in6_ismaddr
@@ -288,7 +289,7 @@ class TestIPv6(VppTestCase):
self.send_and_assert_no_replies(self.pg0, pkts,
"No response to NS for unknown target")
- def validate_ra(self, intf, rx, dst_ip=None):
+ def validate_ra(self, intf, rx, dst_ip=None, mtu=9000, pi_opt=None):
if not dst_ip:
dst_ip = intf.remote_ip6
@@ -308,17 +309,47 @@ class TestIPv6(VppTestCase):
self.assertEqual(in6_ptop(rx[IPv6].src),
in6_ptop(mk_ll_addr(intf.local_mac)))
+ # it should contain the links MTU
+ ra = rx[ICMPv6ND_RA]
+ self.assertEqual(ra[ICMPv6NDOptMTU].mtu, mtu)
+
+ # it should contain the source's link layer address option
+ sll = ra[ICMPv6NDOptSrcLLAddr]
+ self.assertEqual(sll.lladdr, intf.local_mac)
+
+ if not pi_opt:
+ # the RA should not contain prefix information
+ self.assertFalse(ra.haslayer(ICMPv6NDOptPrefixInfo))
+ else:
+ raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1)
+
+ # the options are nested in the scapy packet in way that i cannot
+ # decipher how to decode. this 1st layer of option always returns
+ # nested classes, so a direct obj1=obj2 comparison always fails.
+ # however, the getlayer(.., 2) does give one instnace.
+ # so we cheat here and construct a new opt instnace for comparison
+ rd = ICMPv6NDOptPrefixInfo(prefixlen=raos.prefixlen,
+ prefix=raos.prefix,
+ L=raos.L,
+ A=raos.A)
+ if type(pi_opt) is list:
+ for ii in range(len(pi_opt)):
+ self.assertEqual(pi_opt[ii], rd)
+ rd = rx.getlayer(ICMPv6NDOptPrefixInfo, ii+2)
+ else:
+ self.assertEqual(pi_opt, raos)
+
def send_and_expect_ra(self, intf, pkts, remark, dst_ip=None,
- filter_out_fn=is_ipv6_misc):
+ filter_out_fn=is_ipv6_misc,
+ opt=None):
intf.add_stream(pkts)
- self.pg0.add_stream(pkts)
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
self.assertEqual(len(rx), 1)
rx = rx[0]
- self.validate_ra(intf, rx, dst_ip)
+ self.validate_ra(intf, rx, dst_ip, pi_opt=opt)
def test_rs(self):
""" IPv6 Router Solicitation Exceptions
@@ -416,6 +447,184 @@ class TestIPv6(VppTestCase):
filter_out_fn=None)
#
+ # Configure The RA to announce the links prefix
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len)
+
+ #
+ # RAs should now contain the prefix information option
+ #
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=1,
+ A=1)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ ll = mk_ll_addr(self.pg0.remote_mac)
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(dst=self.pg0.local_ip6, src=ll) /
+ ICMPv6ND_RS())
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with prefix-info",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Change the prefix info to not off-link
+ # L-flag is clear
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len,
+ off_link=1)
+
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=0,
+ A=1)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix info with L-flag=0",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Change the prefix info to not off-link, no-autoconfig
+ # L and A flag are clear in the advert
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len,
+ off_link=1,
+ no_autoconfig=1)
+
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=0,
+ A=0)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix info with A & L-flag=0",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Change the flag settings back to the defaults
+ # L and A flag are set in the advert
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len)
+
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=1,
+ A=1)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix info",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Change the prefix info to not off-link, no-autoconfig
+ # L and A flag are clear in the advert
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len,
+ off_link=1,
+ no_autoconfig=1)
+
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=0,
+ A=0)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix info with A & L-flag=0",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Use the reset to defults option to revert to defaults
+ # L and A flag are clear in the advert
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len,
+ use_default=1)
+
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=1,
+ A=1)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix reverted to defaults",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Advertise Another prefix. With no L-flag/A-flag
+ #
+ self.pg0.ip6_ra_prefix(self.pg1.local_ip6n,
+ self.pg1.local_ip6_prefix_len,
+ off_link=1,
+ no_autoconfig=1)
+
+ opt = [ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len,
+ prefix=self.pg0.local_ip6,
+ L=1,
+ A=1),
+ ICMPv6NDOptPrefixInfo(prefixlen=self.pg1.local_ip6_prefix_len,
+ prefix=self.pg1.local_ip6,
+ L=0,
+ A=0)]
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ ll = mk_ll_addr(self.pg0.remote_mac)
+ p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+ IPv6(dst=self.pg0.local_ip6, src=ll) /
+ ICMPv6ND_RS())
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with multiple Prefix infos",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Remove the first refix-info - expect the second is still in the
+ # advert
+ #
+ self.pg0.ip6_ra_prefix(self.pg0.local_ip6n,
+ self.pg0.local_ip6_prefix_len,
+ is_no=1)
+
+ opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg1.local_ip6_prefix_len,
+ prefix=self.pg1.local_ip6,
+ L=0,
+ A=0)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix reverted to defaults",
+ dst_ip=ll,
+ opt=opt)
+
+ #
+ # Remove the second prefix-info - expect no prefix-info i nthe adverts
+ #
+ self.pg0.ip6_ra_prefix(self.pg1.local_ip6n,
+ self.pg1.local_ip6_prefix_len,
+ is_no=1)
+
+ self.pg0.ip6_ra_config(send_unicast=1)
+ self.send_and_expect_ra(self.pg0, p,
+ "RA with Prefix reverted to defaults",
+ dst_ip=ll)
+
+ #
# Reset the periodic advertisements back to default values
#
self.pg0.ip6_ra_config(no=1, suppress=1, send_unicast=0)
diff --git a/test/vpp_interface.py b/test/vpp_interface.py
index 4588943dd8a..53a0ae8de98 100644
--- a/test/vpp_interface.py
+++ b/test/vpp_interface.py
@@ -272,6 +272,17 @@ class VppInterface(object):
suppress,
send_unicast)
+ def ip6_ra_prefix(self, address, address_length, is_no=0,
+ off_link=0, no_autoconfig=0, use_default=0):
+ """Configure IPv6 RA suppress on the VPP interface."""
+ self.test.vapi.ip6_sw_interface_ra_prefix(self.sw_if_index,
+ address,
+ address_length,
+ is_no=is_no,
+ off_link=off_link,
+ no_autoconfig=no_autoconfig,
+ use_default=use_default)
+
def admin_up(self):
"""Put interface ADMIN-UP."""
self.test.vapi.sw_interface_set_flags(self.sw_if_index,
diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py
index fbd41eb5352..5c2e34794ec 100644
--- a/test/vpp_neighbor.py
+++ b/test/vpp_neighbor.py
@@ -31,7 +31,7 @@ class VppNeighbor(VppObject):
"""
def __init__(self, test, sw_if_index, mac_addr, nbr_addr,
- af=AF_INET, is_static=0):
+ af=AF_INET, is_static=False):
self._test = test
self.sw_if_index = sw_if_index
self.mac_addr = mactobinary(mac_addr)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index 5d4d6b7ef0c..fe152de3969 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -286,6 +286,31 @@ class VppPapiProvider(object):
'suppress': suppress,
'send_unicast': send_unicast})
+ def ip6_sw_interface_ra_prefix(self,
+ sw_if_index,
+ address,
+ address_length,
+ use_default=0,
+ no_advertise=0,
+ off_link=0,
+ no_autoconfig=0,
+ no_onlink=0,
+ is_no=0,
+ val_lifetime=0xffffffff,
+ pref_lifetime=0xffffffff):
+ return self.api(self.papi.sw_interface_ip6nd_ra_prefix,
+ {'sw_if_index': sw_if_index,
+ 'address': address,
+ 'address_length': address_length,
+ 'use_default': use_default,
+ 'no_advertise': no_advertise,
+ 'off_link': off_link,
+ 'no_autoconfig': no_autoconfig,
+ 'no_onlink': no_onlink,
+ 'is_no': is_no,
+ 'val_lifetime': val_lifetime,
+ 'pref_lifetime': pref_lifetime})
+
def ip6_sw_interface_enable_disable(self, sw_if_index, enable):
"""
Enable/Disable An interface for IPv6