IPv6 RA improvements 36/5536/4
authorNeale Ranns <nranns@cisco.com>
Sat, 18 Feb 2017 16:16:41 +0000 (08:16 -0800)
committerDamjan Marion <dmarion.lists@gmail.com>
Fri, 3 Mar 2017 17:23:50 +0000 (17:23 +0000)
 1) tests for RA options
 2) memleaks deleteing a ip6_radv_info_t
 3) MLD prefix code refactoring

Change-Id: I34db103994bd8fbdbbec50b202d72770dd145681
Signed-off-by: Neale Ranns <nranns@cisco.com>
src/vnet/ip/ip.api
src/vnet/ip/ip6_neighbor.c
src/vppinfra/pool.h
test/test_ip6.py
test/vpp_interface.py
test/vpp_neighbor.py
test/vpp_papi_provider.py

index 326c825..ff16e78 100644 (file)
@@ -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
 {
index 91ff224..43d68cd 100644 (file)
@@ -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;
index 586d13e..57838e1 100644 (file)
@@ -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 */
 
 /*
index fb5383c..b827832 100644 (file)
@@ -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
@@ -415,6 +446,184 @@ class TestIPv6(VppTestCase):
                                 dst_ip="ff02::1",
                                 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
         #
index 4588943..53a0ae8 100644 (file)
@@ -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,
index fbd41eb..5c2e347 100644 (file)
@@ -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)
index 5d4d6b7..fe152de 100644 (file)
@@ -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