Add adjacency counters to the stats segment 35/15035/4
authorNeale Ranns <neale.ranns@cisco.com>
Fri, 28 Sep 2018 12:00:57 +0000 (05:00 -0700)
committerDamjan Marion <dmarion@me.com>
Mon, 1 Oct 2018 17:02:18 +0000 (17:02 +0000)
Change-Id: I6b59df939c9daf40e261d73d19f500bd90abe6ff
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
src/vnet/adj/adj.c
src/vnet/ip/ip.api
src/vnet/ip/ip_api.c
src/vnet/ip/ip_neighbor.c
src/vnet/ip/ip_neighbor.h
test/test_neighbor.py
test/vpp_neighbor.py

index 90e7e60..a06a122 100644 (file)
 #include <vnet/fib/fib_node_list.h>
 
 /* Adjacency packet/byte counters indexed by adjacency index. */
-vlib_combined_counter_main_t adjacency_counters;
+vlib_combined_counter_main_t adjacency_counters = {
+    .name = "adjacency",
+    .stat_segment_name = "/net/adjacency",
+};
 
 /*
  * the single adj pool
@@ -64,7 +67,8 @@ adj_alloc (fib_protocol_t proto)
     /* Validate adjacency counters. */
     vlib_validate_combined_counter(&adjacency_counters,
                                    adj_get_index(adj));
-
+    vlib_zero_combined_counter(&adjacency_counters,
+                               adj_get_index(adj));
     fib_node_init(&adj->ia_node,
                   FIB_NODE_TYPE_ADJ);
 
index 71ad1c1..5cd0dfa 100644 (file)
@@ -120,12 +120,15 @@ define ip_neighbor_dump
 /** \brief IP neighboors dump response
     @param context - sender context which was passed in the request
     @param sw_if_index - The interface used to reach the neighbor
+    @param stats_index - An index in the stats segment that can be used to read
+                         the counters for this neighbour.
     @param is_static - [1|0] to indicate if neighbor is statically configured
     @param is_ipv6 - [1|0] to indicate if address family is ipv[6|4]
 */
 define ip_neighbor_details {
     u32 context;
     u32 sw_if_index;
+    u32 stats_index;
     u8  is_static;
     u8  is_ipv6;
     u8  mac_address[6];
@@ -146,7 +149,7 @@ define ip_neighbor_details {
     @param mac_address - l2 address of the neighbor
     @param dst_address - ip4 or ip6 address of the neighbor
 */
-autoreply define ip_neighbor_add_del
+define ip_neighbor_add_del
 {
   u32 client_index;
   u32 context;
@@ -160,6 +163,13 @@ autoreply define ip_neighbor_add_del
   u8 dst_address[16];
 };
 
+define ip_neighbor_add_del_reply
+{
+  u32 context;
+  i32 retval;
+  u32 stats_index;
+};
+
 /** \brief Set the ip flow hash config for a fib request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
index 5dbc02d..b0a7e82 100644 (file)
@@ -659,6 +659,7 @@ vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
   ip46_address_t ip = ip46_address_initializer;
   vl_api_ip_neighbor_add_del_reply_t *rmp;
   ip_neighbor_flags_t flags;
+  u32 stats_index = ~0;
   int rv = 0;
 
   VALIDATE_SW_IF_INDEX (mp);
@@ -678,14 +679,20 @@ vl_api_ip_neighbor_add_del_t_handler (vl_api_ip_neighbor_add_del_t * mp,
 
   if (mp->is_add)
     rv = ip_neighbor_add (&ip, mp->is_ipv6, mp->mac_address,
-                         ntohl (mp->sw_if_index), flags);
+                         ntohl (mp->sw_if_index), flags, &stats_index);
   else
     rv = ip_neighbor_del (&ip, mp->is_ipv6, ntohl (mp->sw_if_index));
 
   stats_dsunlock ();
 
   BAD_SW_IF_INDEX_LABEL;
-  REPLY_MACRO (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_IP_NEIGHBOR_ADD_DEL_REPLY,
+  ({
+    rmp->stats_index = htonl (stats_index);
+  }));
+  /* *INDENT-ON* */
 }
 
 void
index 2edd737..f5a816d 100644 (file)
@@ -50,8 +50,12 @@ static ip_neighbor_scan_config_t ip_neighbor_scan_conf;
 int
 ip_neighbor_add (const ip46_address_t * ip,
                 u8 is_ip6,
-                const u8 * mac, u32 sw_if_index, ip_neighbor_flags_t flags)
+                const u8 * mac,
+                u32 sw_if_index,
+                ip_neighbor_flags_t flags, u32 * stats_index)
 {
+  fib_protocol_t fproto;
+  vnet_link_t linkt;
   int rv;
 
   /*
@@ -66,7 +70,8 @@ ip_neighbor_add (const ip46_address_t * ip,
                                           (flags & IP_NEIGHBOR_FLAG_STATIC),
                                           (flags &
                                            IP_NEIGHBOR_FLAG_NO_ADJ_FIB));
-
+      fproto = FIB_PROTOCOL_IP6;
+      linkt = VNET_LINK_IP6;
     }
   else
     {
@@ -82,8 +87,13 @@ ip_neighbor_add (const ip46_address_t * ip,
                                           (flags & IP_NEIGHBOR_FLAG_STATIC),
                                           (flags &
                                            IP_NEIGHBOR_FLAG_NO_ADJ_FIB));
+      fproto = FIB_PROTOCOL_IP4;
+      linkt = VNET_LINK_IP4;
     }
 
+  if (0 == rv && stats_index)
+    *stats_index = adj_nbr_find (fproto, linkt, ip, sw_if_index);
+
   return (rv);
 }
 
index b865862..9eeebdb 100644 (file)
@@ -45,7 +45,8 @@ typedef enum ip_neighbor_flags_t_
 extern int ip_neighbor_add (const ip46_address_t * ip,
                            u8 is_ip6,
                            const u8 * mac,
-                           u32 sw_if_index, ip_neighbor_flags_t flags);
+                           u32 sw_if_index,
+                           ip_neighbor_flags_t flags, u32 * stats_index);
 
 extern int ip_neighbor_del (const ip46_address_t * ip,
                            u8 is_ip6, u32 sw_if_index);
index f01f536..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.inet6 import IPv6
 
 # not exported by scapy, so redefined here
 arp_opts = {"who-has": 1, "is-at": 2}
@@ -1317,6 +1318,7 @@ class ARPTestCase(VppTestCase):
                                   self.pg1.remote_hosts[2].ip4))
 
     def test_arp_incomplete(self):
+        """ Incomplete Entries """
 
         #
         # ensure that we throttle the ARP requests
@@ -1348,5 +1350,112 @@ class ARPTestCase(VppTestCase):
         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)
index c08132d..b4803c2 100644 (file)
@@ -46,7 +46,7 @@ class VppNeighbor(VppObject):
         self.nbr_addr_n = inet_pton(af, nbr_addr)
 
     def add_vpp_config(self):
-        self._test.vapi.ip_neighbor_add_del(
+        r = self._test.vapi.ip_neighbor_add_del(
             self.sw_if_index,
             self.mac_addr,
             self.nbr_addr_n,
@@ -54,6 +54,7 @@ class VppNeighbor(VppObject):
             is_ipv6=1 if AF_INET6 == self.af else 0,
             is_static=self.is_static,
             is_no_adj_fib=self.is_no_fib_entry)
+        self.stats_index = r.stats_index
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):
@@ -77,3 +78,7 @@ class VppNeighbor(VppObject):
 
     def object_id(self):
         return ("%d:%s" % (self.sw_if_index, self.nbr_addr))
+
+    def get_stats(self):
+        c = self._test.statistics.get_counter("/net/adjacency")
+        return c[0][self.stats_index]