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. */
 #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
 
 /*
  * 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));
     /* 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);
 
     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
 /** \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;
     @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];
     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
 */
     @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;
 {
   u32 client_index;
   u32 context;
@@ -160,6 +163,13 @@ autoreply define ip_neighbor_add_del
   u8 dst_address[16];
 };
 
   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
 /** \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;
   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);
   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,
 
   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;
   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
 }
 
 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,
 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;
 
   /*
   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));
                                           (flags & IP_NEIGHBOR_FLAG_STATIC),
                                           (flags &
                                            IP_NEIGHBOR_FLAG_NO_ADJ_FIB));
-
+      fproto = FIB_PROTOCOL_IP6;
+      linkt = VNET_LINK_IP6;
     }
   else
     {
     }
   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));
                                           (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);
 }
 
   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,
 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);
 
 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.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}
@@ -1317,6 +1318,7 @@ class ARPTestCase(VppTestCase):
                                   self.pg1.remote_hosts[2].ip4))
 
     def test_arp_incomplete(self):
                                   self.pg1.remote_hosts[2].ip4))
 
     def test_arp_incomplete(self):
+        """ Incomplete Entries """
 
         #
         # ensure that we throttle the ARP requests
 
         #
         # ensure that we throttle the ARP requests
@@ -1348,5 +1350,112 @@ class ARPTestCase(VppTestCase):
         self.assertTrue(len(rx) < 64)
 
 
         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)
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.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,
             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)
             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):
         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 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]