Add adjacency counters to the stats segment
[vpp.git] / test / test_neighbor.py
index 565a8b4..a15106a 100644 (file)
@@ -12,6 +12,7 @@ from scapy.packet import Raw
 from scapy.layers.l2 import Ether, ARP, Dot1Q
 from scapy.layers.inet import IP, UDP
 from scapy.contrib.mpls import MPLS
 from scapy.layers.l2 import Ether, ARP, Dot1Q
 from scapy.layers.inet import IP, UDP
 from scapy.contrib.mpls import MPLS
+from scapy.layers.inet6 import IPv6
 
 # not exported by scapy, so redefined here
 arp_opts = {"who-has": 1, "is-at": 2}
 
 # not exported by scapy, so redefined here
 arp_opts = {"who-has": 1, "is-at": 2}
@@ -132,16 +133,6 @@ class ARPTestCase(VppTestCase):
         self.assertEqual(ip.src, sip)
         self.assertEqual(ip.dst, dip)
 
         self.assertEqual(ip.src, sip)
         self.assertEqual(ip.dst, dip)
 
-    def send_and_assert_no_replies(self, intf, pkts, remark):
-        intf.add_stream(pkts)
-        self.pg_enable_capture(self.pg_interfaces)
-        self.pg_start()
-        timeout = 1
-        for i in self.pg_interfaces:
-            i.get_capture(0, timeout=timeout)
-            i.assert_nothing_captured(remark=remark)
-            timeout = 0.1
-
     def test_arp(self):
         """ ARP """
 
     def test_arp(self):
         """ ARP """
 
@@ -306,6 +297,10 @@ class ARPTestCase(VppTestCase):
         #
         self.pg2.set_unnumbered(self.pg1.sw_if_index)
 
         #
         self.pg2.set_unnumbered(self.pg1.sw_if_index)
 
+        unnum = self.vapi.ip_unnumbered_dump()
+        self.assertEqual(unnum[0].ip_sw_if_index, self.pg1.sw_if_index)
+        self.assertEqual(unnum[0].sw_if_index, self.pg2.sw_if_index)
+
         #
         # We should respond to ARP requests for the unnumbered to address
         # once an attached route to the source is known
         #
         # We should respond to ARP requests for the unnumbered to address
         # once an attached route to the source is known
@@ -1154,6 +1149,313 @@ class ARPTestCase(VppTestCase):
         self.pg2.unconfig_ip4()
         self.pg2.set_table_ip4(0)
 
         self.pg2.unconfig_ip4()
         self.pg2.set_table_ip4(0)
 
+    def test_arp_incomplete(self):
+        """ ARP Incomplete"""
+        self.pg1.generate_remote_hosts(3)
+
+        p0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+              IP(src=self.pg0.remote_ip4,
+                 dst=self.pg1.remote_hosts[1].ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+        p1 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
+              IP(src=self.pg0.remote_ip4,
+                 dst=self.pg1.remote_hosts[2].ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+
+        #
+        # a packet to an unresolved destination generates an ARP request
+        #
+        rx = self.send_and_expect(self.pg0, [p0], self.pg1)
+        self.verify_arp_req(rx[0],
+                            self.pg1.local_mac,
+                            self.pg1.local_ip4,
+                            self.pg1._remote_hosts[1].ip4)
+
+        #
+        # add a neighbour for remote host 1
+        #
+        static_arp = VppNeighbor(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1.remote_hosts[1].mac,
+                                 self.pg1.remote_hosts[1].ip4,
+                                 is_static=1)
+        static_arp.add_vpp_config()
+
+        #
+        # change the interface's MAC
+        #
+        mac = [chr(0x00), chr(0x00), chr(0x00),
+               chr(0x33), chr(0x33), chr(0x33)]
+        mac_string = ''.join(mac)
+
+        self.vapi.sw_interface_set_mac_address(self.pg1.sw_if_index,
+                                               mac_string)
+
+        #
+        # now ARP requests come from the new source mac
+        #
+        rx = self.send_and_expect(self.pg0, [p1], self.pg1)
+        self.verify_arp_req(rx[0],
+                            "00:00:00:33:33:33",
+                            self.pg1.local_ip4,
+                            self.pg1._remote_hosts[2].ip4)
+
+        #
+        # packets to the resolved host also have the new source mac
+        #
+        rx = self.send_and_expect(self.pg0, [p0], self.pg1)
+        self.verify_ip(rx[0],
+                       "00:00:00:33:33:33",
+                       self.pg1.remote_hosts[1].mac,
+                       self.pg0.remote_ip4,
+                       self.pg1.remote_hosts[1].ip4)
+
+        #
+        # set the mac address on the inteface that does not have a
+        # configured subnet and thus no glean
+        #
+        self.vapi.sw_interface_set_mac_address(self.pg2.sw_if_index,
+                                               mac_string)
+
+    def test_garp(self):
+        """ GARP """
+
+        #
+        # Generate some hosts on the LAN
+        #
+        self.pg1.generate_remote_hosts(4)
+
+        #
+        # And an ARP entry
+        #
+        arp = VppNeighbor(self,
+                          self.pg1.sw_if_index,
+                          self.pg1.remote_hosts[1].mac,
+                          self.pg1.remote_hosts[1].ip4)
+        arp.add_vpp_config()
+
+        self.assertTrue(find_nbr(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1.remote_hosts[1].ip4,
+                                 mac=self.pg1.remote_hosts[1].mac))
+
+        #
+        # Send a GARP (request) to swap the host 1's address to that of host 2
+        #
+        p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
+                    src=self.pg1.remote_hosts[2].mac) /
+              ARP(op="who-has",
+                  hwdst=self.pg1.local_mac,
+                  hwsrc=self.pg1.remote_hosts[2].mac,
+                  pdst=self.pg1.remote_hosts[1].ip4,
+                  psrc=self.pg1.remote_hosts[1].ip4))
+
+        self.pg1.add_stream(p1)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        self.assertTrue(find_nbr(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1.remote_hosts[1].ip4,
+                                 mac=self.pg1.remote_hosts[2].mac))
+
+        #
+        # Send a GARP (reply) to swap the host 1's address to that of host 3
+        #
+        p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
+                    src=self.pg1.remote_hosts[3].mac) /
+              ARP(op="is-at",
+                  hwdst=self.pg1.local_mac,
+                  hwsrc=self.pg1.remote_hosts[3].mac,
+                  pdst=self.pg1.remote_hosts[1].ip4,
+                  psrc=self.pg1.remote_hosts[1].ip4))
+
+        self.pg1.add_stream(p1)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        self.assertTrue(find_nbr(self,
+                                 self.pg1.sw_if_index,
+                                 self.pg1.remote_hosts[1].ip4,
+                                 mac=self.pg1.remote_hosts[3].mac))
+
+        #
+        # GARPs (requets nor replies) for host we don't know yet
+        # don't result in new neighbour entries
+        #
+        p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
+                    src=self.pg1.remote_hosts[3].mac) /
+              ARP(op="who-has",
+                  hwdst=self.pg1.local_mac,
+                  hwsrc=self.pg1.remote_hosts[3].mac,
+                  pdst=self.pg1.remote_hosts[2].ip4,
+                  psrc=self.pg1.remote_hosts[2].ip4))
+
+        self.pg1.add_stream(p1)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        self.assertFalse(find_nbr(self,
+                                  self.pg1.sw_if_index,
+                                  self.pg1.remote_hosts[2].ip4))
+
+        p1 = (Ether(dst="ff:ff:ff:ff:ff:ff",
+                    src=self.pg1.remote_hosts[3].mac) /
+              ARP(op="is-at",
+                  hwdst=self.pg1.local_mac,
+                  hwsrc=self.pg1.remote_hosts[3].mac,
+                  pdst=self.pg1.remote_hosts[2].ip4,
+                  psrc=self.pg1.remote_hosts[2].ip4))
+
+        self.pg1.add_stream(p1)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+
+        self.assertFalse(find_nbr(self,
+                                  self.pg1.sw_if_index,
+                                  self.pg1.remote_hosts[2].ip4))
+
+    def test_arp_incomplete(self):
+        """ Incomplete Entries """
+
+        #
+        # ensure that we throttle the ARP requests
+        #
+        self.pg0.generate_remote_hosts(2)
+
+        ip_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
+                                 [VppRoutePath(self.pg0.remote_hosts[1].ip4,
+                                               self.pg0.sw_if_index,
+                                               labels=[55])])
+        ip_10_0_0_1.add_vpp_config()
+
+        p1 = (Ether(dst=self.pg1.local_mac,
+                    src=self.pg1.remote_mac) /
+              IP(src=self.pg1.remote_ip4,
+                 dst="10.0.0.1") /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+
+        self.pg1.add_stream(p1 * 257)
+        self.pg_enable_capture(self.pg_interfaces)
+        self.pg_start()
+        rx = self.pg0._get_capture(1)
+
+        #
+        # how many we get is going to be dependent on the time for packet
+        # processing but it should be small
+        #
+        self.assertTrue(len(rx) < 64)
+
+
+class NeighborStatsTestCase(VppTestCase):
+    """ ARP Test Case """
+
+    def setUp(self):
+        super(NeighborStatsTestCase, self).setUp()
+
+        self.create_pg_interfaces(range(2))
+
+        # pg0 configured with ip4 and 6 addresses used for input
+        # pg1 configured with ip4 and 6 addresses used for output
+        # pg2 is unnumbered to pg0
+        for i in self.pg_interfaces:
+            i.admin_up()
+            i.config_ip4()
+            i.config_ip6()
+            i.resolve_arp()
+            i.resolve_ndp()
+
+    def tearDown(self):
+        super(NeighborStatsTestCase, self).tearDown()
+
+        for i in self.pg_interfaces:
+            i.unconfig_ip4()
+            i.unconfig_ip6()
+            i.admin_down()
+
+    def test_arp_stats(self):
+        """ ARP Counters """
+
+        self.vapi.cli("adj counters enable")
+        self.pg1.generate_remote_hosts(2)
+
+        arp1 = VppNeighbor(self,
+                           self.pg1.sw_if_index,
+                           self.pg1.remote_hosts[0].mac,
+                           self.pg1.remote_hosts[0].ip4)
+        arp1.add_vpp_config()
+        arp2 = VppNeighbor(self,
+                           self.pg1.sw_if_index,
+                           self.pg1.remote_hosts[1].mac,
+                           self.pg1.remote_hosts[1].ip4)
+        arp2.add_vpp_config()
+
+        p1 = (Ether(dst=self.pg0.local_mac,
+                    src=self.pg0.remote_mac) /
+              IP(src=self.pg0.remote_ip4,
+                 dst=self.pg1.remote_hosts[0].ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+        p2 = (Ether(dst=self.pg0.local_mac,
+                    src=self.pg0.remote_mac) /
+              IP(src=self.pg0.remote_ip4,
+                 dst=self.pg1.remote_hosts[1].ip4) /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+
+        rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
+        rx = self.send_and_expect(self.pg0, p2 * 65, self.pg1)
+
+        self.assertEqual(65, arp1.get_stats()['packets'])
+        self.assertEqual(65, arp2.get_stats()['packets'])
+
+        rx = self.send_and_expect(self.pg0, p1 * 65, self.pg1)
+        self.assertEqual(130, arp1.get_stats()['packets'])
+
+    def test_nd_stats(self):
+        """ ND Counters """
+
+        self.vapi.cli("adj counters enable")
+        self.pg0.generate_remote_hosts(3)
+
+        nd1 = VppNeighbor(self,
+                          self.pg0.sw_if_index,
+                          self.pg0.remote_hosts[1].mac,
+                          self.pg0.remote_hosts[1].ip6,
+                          af=AF_INET6)
+        nd1.add_vpp_config()
+        nd2 = VppNeighbor(self,
+                          self.pg0.sw_if_index,
+                          self.pg0.remote_hosts[2].mac,
+                          self.pg0.remote_hosts[2].ip6,
+                          af=AF_INET6)
+        nd2.add_vpp_config()
+
+        p1 = (Ether(dst=self.pg1.local_mac,
+                    src=self.pg1.remote_mac) /
+              IPv6(src=self.pg1.remote_ip6,
+                   dst=self.pg0.remote_hosts[1].ip6) /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+        p2 = (Ether(dst=self.pg1.local_mac,
+                    src=self.pg1.remote_mac) /
+              IPv6(src=self.pg1.remote_ip6,
+                   dst=self.pg0.remote_hosts[2].ip6) /
+              UDP(sport=1234, dport=1234) /
+              Raw())
+
+        rx = self.send_and_expect(self.pg1, p1 * 16, self.pg0)
+        rx = self.send_and_expect(self.pg1, p2 * 16, self.pg0)
+
+        self.assertEqual(16, nd1.get_stats()['packets'])
+        self.assertEqual(16, nd2.get_stats()['packets'])
+
+        rx = self.send_and_expect(self.pg1, p1 * 65, self.pg0)
+        self.assertEqual(81, nd1.get_stats()['packets'])
+
 
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
 
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)