From 14260393c096b270ef318d74b481911c7def0496 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Fri, 28 Sep 2018 05:00:57 -0700 Subject: [PATCH] Add adjacency counters to the stats segment Change-Id: I6b59df939c9daf40e261d73d19f500bd90abe6ff Signed-off-by: Neale Ranns --- src/vnet/adj/adj.c | 8 +++- src/vnet/ip/ip.api | 12 ++++- src/vnet/ip/ip_api.c | 11 ++++- src/vnet/ip/ip_neighbor.c | 14 +++++- src/vnet/ip/ip_neighbor.h | 3 +- test/test_neighbor.py | 109 ++++++++++++++++++++++++++++++++++++++++++++++ test/vpp_neighbor.py | 7 ++- 7 files changed, 155 insertions(+), 9 deletions(-) diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c index 90e7e60a329..a06a12210bc 100644 --- a/src/vnet/adj/adj.c +++ b/src/vnet/adj/adj.c @@ -22,7 +22,10 @@ #include /* 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); diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index 71ad1c189c1..5cd0dfaac54 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -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 diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 5dbc02d5c59..b0a7e82949b 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -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 diff --git a/src/vnet/ip/ip_neighbor.c b/src/vnet/ip/ip_neighbor.c index 2edd737aa07..f5a816d5a18 100644 --- a/src/vnet/ip/ip_neighbor.c +++ b/src/vnet/ip/ip_neighbor.c @@ -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); } diff --git a/src/vnet/ip/ip_neighbor.h b/src/vnet/ip/ip_neighbor.h index b865862c06e..9eeebdb1555 100644 --- a/src/vnet/ip/ip_neighbor.h +++ b/src/vnet/ip/ip_neighbor.h @@ -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); diff --git a/test/test_neighbor.py b/test/test_neighbor.py index f01f5367703..a15106af1f9 100644 --- a/test/test_neighbor.py +++ b/test/test_neighbor.py @@ -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) diff --git a/test/vpp_neighbor.py b/test/vpp_neighbor.py index c08132d1d40..b4803c24cbd 100644 --- a/test/vpp_neighbor.py +++ b/test/vpp_neighbor.py @@ -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] -- 2.16.6