summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/adj/adj.c8
-rw-r--r--src/vnet/ip/ip.api12
-rw-r--r--src/vnet/ip/ip_api.c11
-rw-r--r--src/vnet/ip/ip_neighbor.c14
-rw-r--r--src/vnet/ip/ip_neighbor.h3
-rw-r--r--test/test_neighbor.py109
-rw-r--r--test/vpp_neighbor.py7
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 <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);
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]