vlib: reset stop_timer_handle on expired processes
[vpp.git] / test / test_ip6.py
index ca153db..b46bef6 100644 (file)
@@ -193,6 +193,22 @@ class TestIPv6ND(VppTestCase):
         self.assertEqual(ip.src, sip)
         self.assertEqual(ip.dst, dip)
 
+    def get_ip6_nd_rx_requests(self, itf):
+        """Get IP6 ND RX request stats for and interface"""
+        return self.statistics["/net/ip6-nd/rx/requests"][:, itf.sw_if_index].sum()
+
+    def get_ip6_nd_tx_requests(self, itf):
+        """Get IP6 ND TX request stats for and interface"""
+        return self.statistics["/net/ip6-nd/tx/requests"][:, itf.sw_if_index].sum()
+
+    def get_ip6_nd_rx_replies(self, itf):
+        """Get IP6 ND RX replies stats for and interface"""
+        return self.statistics["/net/ip6-nd/rx/replies"][:, itf.sw_if_index].sum()
+
+    def get_ip6_nd_tx_replies(self, itf):
+        """Get IP6 ND TX replies stats for and interface"""
+        return self.statistics["/net/ip6-nd/tx/replies"][:, itf.sw_if_index].sum()
+
 
 @tag_run_solo
 class TestIPv6(TestIPv6ND):
@@ -258,7 +274,7 @@ class TestIPv6(TestIPv6ND):
 
     def tearDown(self):
         """Run standard test teardown and log ``show ip6 neighbors``."""
-        for i in self.interfaces:
+        for i in reversed(self.interfaces):
             i.unconfig_ip6()
             i.admin_down()
         for i in self.sub_interfaces:
@@ -430,6 +446,9 @@ class TestIPv6(TestIPv6ND):
            - Send NS for a target address the router does not onn.
         """
 
+        n_rx_req_pg0 = self.get_ip6_nd_rx_requests(self.pg0)
+        n_tx_rep_pg0 = self.get_ip6_nd_tx_replies(self.pg0)
+
         #
         # An NS from a non link source address
         #
@@ -447,6 +466,7 @@ class TestIPv6(TestIPv6ND):
         self.send_and_assert_no_replies(
             self.pg0, pkts, "No response to NS source by address not on sub-net"
         )
+        self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 1)
 
         #
         # An NS for sent to a solicited mcast group the router is
@@ -485,6 +505,7 @@ class TestIPv6(TestIPv6ND):
         self.send_and_assert_no_replies(
             self.pg0, pkts, "No response to NS for unknown target"
         )
+        self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 2)
 
         #
         # A neighbor entry that has no associated FIB-entry
@@ -525,6 +546,8 @@ class TestIPv6(TestIPv6ND):
             dst_ip=self.pg0._remote_hosts[2].ip6_ll,
             tgt_ip=self.pg0.local_ip6,
         )
+        self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 3)
+        self.assert_equal(self.get_ip6_nd_tx_replies(self.pg0), n_tx_rep_pg0 + 1)
 
         #
         # we should have learned an ND entry for the peer's link-local
@@ -574,6 +597,37 @@ class TestIPv6(TestIPv6ND):
         )
         self.assertFalse(find_route(self, self.pg0._remote_hosts[3].ip6_ll, 128))
 
+    def test_nd_incomplete(self):
+        """IP6-ND Incomplete"""
+        self.pg1.generate_remote_hosts(3)
+
+        p0 = (
+            Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
+            / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_hosts[1].ip6)
+            / UDP(sport=1234, dport=1234)
+            / Raw()
+        )
+
+        #
+        # a packet to an unresolved destination generates an ND request
+        #
+        n_tx_req_pg1 = self.get_ip6_nd_tx_requests(self.pg1)
+        self.send_and_expect_ns(self.pg0, self.pg1, p0, self.pg1.remote_hosts[1].ip6)
+        self.assert_equal(self.get_ip6_nd_tx_requests(self.pg1), n_tx_req_pg1 + 1)
+
+        #
+        # a reply to the request
+        #
+        self.assert_equal(self.get_ip6_nd_rx_replies(self.pg1), 0)
+        na = (
+            Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
+            / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_hosts[1].ip6)
+            / ICMPv6ND_NA(tgt=self.pg1.remote_hosts[1].ip6)
+            / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_hosts[1].mac)
+        )
+        self.send_and_assert_no_replies(self.pg1, [na])
+        self.assert_equal(self.get_ip6_nd_rx_replies(self.pg1), 1)
+
     def test_ns_duplicates(self):
         """ND Duplicates"""
 
@@ -725,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
 
@@ -1046,6 +1179,8 @@ class TestIPv6(TestIPv6ND):
         self.pg_start()
 
         subitf = VppDot1QSubint(self, self.pg1, 99)
+        self.interfaces.append(subitf)
+        self.sub_interfaces.append(subitf)
 
         subitf.admin_up()
         subitf.config_ip6()