Skip to content

Commit d6e3feb

Browse files
mweglicxblp
authored andcommitted
Add support for extended netdev statistics based on RFC 2819.
Implementation of new statistics extension for DPDK ports: - Add new counters definition to netdev struct and open flow, based on RFC2819. - Initialize netdev statistics as "filtered out" before passing it to particular netdev implementation (because of that change, statistics which are not collected are reported as filtered out, and some unit tests were modified in this respect). - New statistics are retrieved using experimenter code and are printed as a result to ofctl dump-ports. - New counters are available for OpenFlow 1.4+. - Add new vendor id: INTEL_VENDOR_ID. - New statistics are printed to output via ofctl only if those are present in reply message. - Add new file header: include/openflow/intel-ext.h which contains new statistics definition. - Extended statistics are implemented only for dpdk-physical and dpdk-vhost port types. - Dpdk-physical implementation uses xstats to collect statistics. - Dpdk-vhost implements only part of statistics (RX packet sized based counters). Signed-off-by: Michal Weglicki <michalx.weglicki@intel.com> [blp@ovn.org made software devices more consistent] Signed-off-by: Ben Pfaff <blp@ovn.org>
1 parent 104aec4 commit d6e3feb

17 files changed

Lines changed: 563 additions & 116 deletions

include/openflow/automake.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
openflowincludedir = $(includedir)/openflow
22
openflowinclude_HEADERS = \
3+
include/openflow/intel-ext.h \
34
include/openflow/netronome-ext.h \
45
include/openflow/nicira-ext.h \
56
include/openflow/openflow-1.0.h \

include/openflow/intel-ext.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright(c) 2016 Intel Corporation. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef OPENFLOW_INTEL_EXT_H
18+
#define OPENFLOW_INTEL_EXT_H
19+
20+
/* This file presents Intel vendor extension. It is not anyhow
21+
* standardized, so all those definitions are not part of
22+
* official openflow headers (openflow.h). Nevertheless below
23+
* features introduces real value so it could be suitable for
24+
* standardization */
25+
26+
/* Intel extended statistics type */
27+
28+
enum intel_port_stats_subtype {
29+
INTEL_PORT_STATS_RFC2819 = 1,
30+
};
31+
32+
#define INTEL_PORT_STATS_RFC2819_SIZE 184
33+
34+
/* Struct implements custom property type based on
35+
* 'ofp_prop_experimenter'. */
36+
struct intel_port_stats_rfc2819 {
37+
ovs_be16 type; /* OFPPSPT14_EXPERIMENTER. */
38+
ovs_be16 length; /* Length in bytes of this property excluding
39+
* trailing padding. */
40+
ovs_be32 experimenter; /* INTEL_VENDOR_ID. */
41+
ovs_be32 exp_type; /* INTEL_PORT_STATS_*. */
42+
43+
uint8_t pad[4];
44+
45+
ovs_be64 rx_1_to_64_packets;
46+
ovs_be64 rx_65_to_127_packets;
47+
ovs_be64 rx_128_to_255_packets;
48+
ovs_be64 rx_256_to_511_packets;
49+
ovs_be64 rx_512_to_1023_packets;
50+
ovs_be64 rx_1024_to_1522_packets;
51+
ovs_be64 rx_1523_to_max_packets;
52+
53+
ovs_be64 tx_1_to_64_packets;
54+
ovs_be64 tx_65_to_127_packets;
55+
ovs_be64 tx_128_to_255_packets;
56+
ovs_be64 tx_256_to_511_packets;
57+
ovs_be64 tx_512_to_1023_packets;
58+
ovs_be64 tx_1024_to_1522_packets;
59+
ovs_be64 tx_1523_to_max_packets;
60+
61+
ovs_be64 tx_multicast_packets;
62+
ovs_be64 rx_broadcast_packets;
63+
ovs_be64 tx_broadcast_packets;
64+
ovs_be64 rx_undersized_errors;
65+
ovs_be64 rx_oversize_errors;
66+
ovs_be64 rx_fragmented_errors;
67+
ovs_be64 rx_jabber_errors;
68+
69+
};
70+
OFP_ASSERT(sizeof (struct intel_port_stats_rfc2819) ==
71+
INTEL_PORT_STATS_RFC2819_SIZE);
72+
73+
#endif /* openflow/intel-ext.h */

include/openflow/openflow-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ enum ofp_version {
108108
#define NTR_COMPAT_VENDOR_ID 0x00001540 /* Incorrect value used in v2.4. */
109109
#define NX_VENDOR_ID 0x00002320 /* Nicira. */
110110
#define ONF_VENDOR_ID 0x4f4e4600 /* Open Networking Foundation. */
111+
#define INTEL_VENDOR_ID 0x0000AA01 /* Intel */
111112

112113
#define OFP_MAX_TABLE_NAME_LEN 32
113114
#define OFP_MAX_PORT_NAME_LEN 16

include/openvswitch/netdev.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,33 @@ struct netdev_stats {
5252
uint64_t tx_fifo_errors;
5353
uint64_t tx_heartbeat_errors;
5454
uint64_t tx_window_errors;
55+
56+
/* Extended statistics based on RFC2819. */
57+
uint64_t rx_1_to_64_packets;
58+
uint64_t rx_65_to_127_packets;
59+
uint64_t rx_128_to_255_packets;
60+
uint64_t rx_256_to_511_packets;
61+
uint64_t rx_512_to_1023_packets;
62+
uint64_t rx_1024_to_1522_packets;
63+
uint64_t rx_1523_to_max_packets;
64+
65+
uint64_t tx_1_to_64_packets;
66+
uint64_t tx_65_to_127_packets;
67+
uint64_t tx_128_to_255_packets;
68+
uint64_t tx_256_to_511_packets;
69+
uint64_t tx_512_to_1023_packets;
70+
uint64_t tx_1024_to_1522_packets;
71+
uint64_t tx_1523_to_max_packets;
72+
73+
uint64_t tx_multicast_packets;
74+
75+
uint64_t rx_broadcast_packets;
76+
uint64_t tx_broadcast_packets;
77+
78+
uint64_t rx_undersized_errors;
79+
uint64_t rx_oversize_errors;
80+
uint64_t rx_fragmented_errors;
81+
uint64_t rx_jabber_errors;
5582
};
5683

5784
/* Features. */

lib/netdev-dpdk.c

Lines changed: 150 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,33 @@ BUILD_ASSERT_DECL(MAX_NB_MBUF % ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF) == 0);
9999
BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
100100
% MP_CACHE_SZ == 0);
101101

102+
/*
103+
* DPDK XSTATS Counter names definition
104+
*/
105+
#define XSTAT_RX_64_PACKETS "rx_size_64_packets"
106+
#define XSTAT_RX_65_TO_127_PACKETS "rx_size_65_to_127_packets"
107+
#define XSTAT_RX_128_TO_255_PACKETS "rx_size_128_to_255_packets"
108+
#define XSTAT_RX_256_TO_511_PACKETS "rx_size_256_to_511_packets"
109+
#define XSTAT_RX_512_TO_1023_PACKETS "rx_size_512_to_1023_packets"
110+
#define XSTAT_RX_1024_TO_1522_PACKETS "rx_size_1024_to_1522_packets"
111+
#define XSTAT_RX_1523_TO_MAX_PACKETS "rx_size_1523_to_max_packets"
112+
113+
#define XSTAT_TX_64_PACKETS "tx_size_64_packets"
114+
#define XSTAT_TX_65_TO_127_PACKETS "tx_size_65_to_127_packets"
115+
#define XSTAT_TX_128_TO_255_PACKETS "tx_size_128_to_255_packets"
116+
#define XSTAT_TX_256_TO_511_PACKETS "tx_size_256_to_511_packets"
117+
#define XSTAT_TX_512_TO_1023_PACKETS "tx_size_512_to_1023_packets"
118+
#define XSTAT_TX_1024_TO_1522_PACKETS "tx_size_1024_to_1522_packets"
119+
#define XSTAT_TX_1523_TO_MAX_PACKETS "tx_size_1523_to_max_packets"
120+
121+
#define XSTAT_TX_MULTICAST_PACKETS "tx_multicast_packets"
122+
#define XSTAT_RX_BROADCAST_PACKETS "rx_broadcast_packets"
123+
#define XSTAT_TX_BROADCAST_PACKETS "tx_broadcast_packets"
124+
#define XSTAT_RX_UNDERSIZED_ERRORS "rx_undersized_errors"
125+
#define XSTAT_RX_OVERSIZE_ERRORS "rx_oversize_errors"
126+
#define XSTAT_RX_FRAGMENTED_ERRORS "rx_fragmented_errors"
127+
#define XSTAT_RX_JABBER_ERRORS "rx_jabber_errors"
128+
102129
#define SOCKET0 0
103130

104131
#define NIC_PORT_RX_Q_SIZE 2048 /* Size of Physical NIC RX Queue, Max (n+32<=4096)*/
@@ -1142,18 +1169,46 @@ is_vhost_running(struct virtio_net *virtio_dev)
11421169
return (virtio_dev != NULL && (virtio_dev->flags & VIRTIO_DEV_RUNNING));
11431170
}
11441171

1172+
static inline void
1173+
netdev_dpdk_vhost_update_rx_size_counters(struct netdev_stats *stats,
1174+
unsigned int packet_size)
1175+
{
1176+
/* Hard-coded search for the size bucket. */
1177+
if (packet_size < 256) {
1178+
if (packet_size >= 128) {
1179+
stats->rx_128_to_255_packets++;
1180+
} else if (packet_size <= 64) {
1181+
stats->rx_1_to_64_packets++;
1182+
} else {
1183+
stats->rx_65_to_127_packets++;
1184+
}
1185+
} else {
1186+
if (packet_size >= 1523) {
1187+
stats->rx_1523_to_max_packets++;
1188+
} else if (packet_size >= 1024) {
1189+
stats->rx_1024_to_1522_packets++;
1190+
} else if (packet_size < 512) {
1191+
stats->rx_256_to_511_packets++;
1192+
} else {
1193+
stats->rx_512_to_1023_packets++;
1194+
}
1195+
}
1196+
}
1197+
11451198
static inline void
11461199
netdev_dpdk_vhost_update_rx_counters(struct netdev_stats *stats,
11471200
struct dp_packet **packets, int count)
11481201
{
11491202
int i;
1203+
unsigned int packet_size;
11501204
struct dp_packet *packet;
11511205

11521206
stats->rx_packets += count;
11531207
for (i = 0; i < count; i++) {
11541208
packet = packets[i];
1209+
packet_size = dp_packet_size(packet);
11551210

1156-
if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) {
1211+
if (OVS_UNLIKELY(packet_size < ETH_HEADER_LEN)) {
11571212
/* This only protects the following multicast counting from
11581213
* too short packets, but it does not stop the packet from
11591214
* further processing. */
@@ -1162,12 +1217,14 @@ netdev_dpdk_vhost_update_rx_counters(struct netdev_stats *stats,
11621217
continue;
11631218
}
11641219

1220+
netdev_dpdk_vhost_update_rx_size_counters(stats, packet_size);
1221+
11651222
struct eth_header *eh = (struct eth_header *) dp_packet_data(packet);
11661223
if (OVS_UNLIKELY(eth_addr_is_multicast(eh->eth_dst))) {
11671224
stats->multicast++;
11681225
}
11691226

1170-
stats->rx_bytes += dp_packet_size(packet);
1227+
stats->rx_bytes += packet_size;
11711228
}
11721229
}
11731230

@@ -1659,21 +1716,6 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
16591716
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
16601717

16611718
ovs_mutex_lock(&dev->mutex);
1662-
memset(stats, 0, sizeof(*stats));
1663-
/* Unsupported Stats */
1664-
stats->collisions = UINT64_MAX;
1665-
stats->rx_crc_errors = UINT64_MAX;
1666-
stats->rx_fifo_errors = UINT64_MAX;
1667-
stats->rx_frame_errors = UINT64_MAX;
1668-
stats->rx_missed_errors = UINT64_MAX;
1669-
stats->rx_over_errors = UINT64_MAX;
1670-
stats->tx_aborted_errors = UINT64_MAX;
1671-
stats->tx_carrier_errors = UINT64_MAX;
1672-
stats->tx_errors = UINT64_MAX;
1673-
stats->tx_fifo_errors = UINT64_MAX;
1674-
stats->tx_heartbeat_errors = UINT64_MAX;
1675-
stats->tx_window_errors = UINT64_MAX;
1676-
stats->rx_dropped += UINT64_MAX;
16771719

16781720
rte_spinlock_lock(&dev->stats_lock);
16791721
/* Supported Stats */
@@ -1685,13 +1727,83 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
16851727
stats->tx_bytes = dev->stats.tx_bytes;
16861728
stats->rx_errors = dev->stats.rx_errors;
16871729
stats->rx_length_errors = dev->stats.rx_length_errors;
1730+
1731+
stats->rx_1_to_64_packets = dev->stats.rx_1_to_64_packets;
1732+
stats->rx_65_to_127_packets = dev->stats.rx_65_to_127_packets;
1733+
stats->rx_128_to_255_packets = dev->stats.rx_128_to_255_packets;
1734+
stats->rx_256_to_511_packets = dev->stats.rx_256_to_511_packets;
1735+
stats->rx_512_to_1023_packets = dev->stats.rx_512_to_1023_packets;
1736+
stats->rx_1024_to_1522_packets = dev->stats.rx_1024_to_1522_packets;
1737+
stats->rx_1523_to_max_packets = dev->stats.rx_1523_to_max_packets;
1738+
16881739
rte_spinlock_unlock(&dev->stats_lock);
16891740

16901741
ovs_mutex_unlock(&dev->mutex);
16911742

16921743
return 0;
16931744
}
16941745

1746+
static void
1747+
netdev_dpdk_convert_xstats(struct netdev_stats *stats,
1748+
const struct rte_eth_xstats *xstats,
1749+
const unsigned int size)
1750+
{
1751+
/* XXX Current implementation is simple search through an array
1752+
* to find hardcoded counter names. In future DPDK release (TBD)
1753+
* XSTATS API will change so each counter will be represented by
1754+
* unique ID instead of String. */
1755+
1756+
for (unsigned int i = 0; i < size; i++) {
1757+
if (strcmp(XSTAT_RX_64_PACKETS, xstats[i].name) == 0) {
1758+
stats->rx_1_to_64_packets = xstats[i].value;
1759+
} else if (strcmp(XSTAT_RX_65_TO_127_PACKETS, xstats[i].name) == 0) {
1760+
stats->rx_65_to_127_packets = xstats[i].value;
1761+
} else if (strcmp(XSTAT_RX_128_TO_255_PACKETS, xstats[i].name) == 0) {
1762+
stats->rx_128_to_255_packets = xstats[i].value;
1763+
} else if (strcmp(XSTAT_RX_256_TO_511_PACKETS, xstats[i].name) == 0) {
1764+
stats->rx_256_to_511_packets = xstats[i].value;
1765+
} else if (strcmp(XSTAT_RX_512_TO_1023_PACKETS,
1766+
xstats[i].name) == 0) {
1767+
stats->rx_512_to_1023_packets = xstats[i].value;
1768+
} else if (strcmp(XSTAT_RX_1024_TO_1522_PACKETS,
1769+
xstats[i].name) == 0) {
1770+
stats->rx_1024_to_1522_packets = xstats[i].value;
1771+
} else if (strcmp(XSTAT_RX_1523_TO_MAX_PACKETS,
1772+
xstats[i].name) == 0) {
1773+
stats->rx_1523_to_max_packets = xstats[i].value;
1774+
} else if (strcmp(XSTAT_TX_64_PACKETS, xstats[i].name) == 0) {
1775+
stats->tx_1_to_64_packets = xstats[i].value;
1776+
} else if (strcmp(XSTAT_TX_65_TO_127_PACKETS, xstats[i].name) == 0) {
1777+
stats->tx_65_to_127_packets = xstats[i].value;
1778+
} else if (strcmp(XSTAT_TX_128_TO_255_PACKETS, xstats[i].name) == 0) {
1779+
stats->tx_128_to_255_packets = xstats[i].value;
1780+
} else if (strcmp(XSTAT_TX_256_TO_511_PACKETS, xstats[i].name) == 0) {
1781+
stats->tx_256_to_511_packets = xstats[i].value;
1782+
} else if (strcmp(XSTAT_TX_512_TO_1023_PACKETS,
1783+
xstats[i].name) == 0) {
1784+
stats->tx_512_to_1023_packets = xstats[i].value;
1785+
} else if (strcmp(XSTAT_TX_1024_TO_1522_PACKETS,
1786+
xstats[i].name) == 0) {
1787+
stats->tx_1024_to_1522_packets = xstats[i].value;
1788+
} else if (strcmp(XSTAT_TX_1523_TO_MAX_PACKETS,
1789+
xstats[i].name) == 0) {
1790+
stats->tx_1523_to_max_packets = xstats[i].value;
1791+
} else if (strcmp(XSTAT_TX_MULTICAST_PACKETS, xstats[i].name) == 0) {
1792+
stats->tx_multicast_packets = xstats[i].value;
1793+
} else if (strcmp(XSTAT_RX_BROADCAST_PACKETS, xstats[i].name) == 0) {
1794+
stats->rx_broadcast_packets = xstats[i].value;
1795+
} else if (strcmp(XSTAT_TX_BROADCAST_PACKETS, xstats[i].name) == 0) {
1796+
stats->tx_broadcast_packets = xstats[i].value;
1797+
} else if (strcmp(XSTAT_RX_UNDERSIZED_ERRORS, xstats[i].name) == 0) {
1798+
stats->rx_undersized_errors = xstats[i].value;
1799+
} else if (strcmp(XSTAT_RX_FRAGMENTED_ERRORS, xstats[i].name) == 0) {
1800+
stats->rx_fragmented_errors = xstats[i].value;
1801+
} else if (strcmp(XSTAT_RX_JABBER_ERRORS, xstats[i].name) == 0) {
1802+
stats->rx_jabber_errors = xstats[i].value;
1803+
}
1804+
}
1805+
}
1806+
16951807
static int
16961808
netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
16971809
{
@@ -1701,9 +1813,28 @@ netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
17011813

17021814
netdev_dpdk_get_carrier(netdev, &gg);
17031815
ovs_mutex_lock(&dev->mutex);
1704-
rte_eth_stats_get(dev->port_id, &rte_stats);
17051816

1706-
memset(stats, 0, sizeof(*stats));
1817+
struct rte_eth_xstats *rte_xstats;
1818+
int rte_xstats_len, rte_xstats_ret;
1819+
1820+
if (rte_eth_stats_get(dev->port_id, &rte_stats)) {
1821+
VLOG_ERR("Can't get ETH statistics for port: %i.", dev->port_id);
1822+
return EPROTO;
1823+
}
1824+
1825+
rte_xstats_len = rte_eth_xstats_get(dev->port_id, NULL, 0);
1826+
if (rte_xstats_len > 0) {
1827+
rte_xstats = dpdk_rte_mzalloc(sizeof(*rte_xstats) * rte_xstats_len);
1828+
memset(rte_xstats, 0xff, sizeof(*rte_xstats) * rte_xstats_len);
1829+
rte_xstats_ret = rte_eth_xstats_get(dev->port_id, rte_xstats,
1830+
rte_xstats_len);
1831+
if (rte_xstats_ret > 0 && rte_xstats_ret <= rte_xstats_len) {
1832+
netdev_dpdk_convert_xstats(stats, rte_xstats, rte_xstats_ret);
1833+
}
1834+
rte_free(rte_xstats);
1835+
} else {
1836+
VLOG_WARN("Can't get XSTATS counters for port: %i.", dev->port_id);
1837+
}
17071838

17081839
stats->rx_packets = rte_stats.ipackets;
17091840
stats->tx_packets = rte_stats.opackets;
@@ -1721,21 +1852,8 @@ netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
17211852
/* These are the available DPDK counters for packets not received due to
17221853
* local resource constraints in DPDK and NIC respectively. */
17231854
stats->rx_dropped = rte_stats.rx_nombuf + rte_stats.imissed;
1724-
stats->collisions = UINT64_MAX;
1725-
1726-
stats->rx_length_errors = UINT64_MAX;
1727-
stats->rx_over_errors = UINT64_MAX;
1728-
stats->rx_crc_errors = UINT64_MAX;
1729-
stats->rx_frame_errors = UINT64_MAX;
1730-
stats->rx_fifo_errors = UINT64_MAX;
17311855
stats->rx_missed_errors = rte_stats.imissed;
17321856

1733-
stats->tx_aborted_errors = UINT64_MAX;
1734-
stats->tx_carrier_errors = UINT64_MAX;
1735-
stats->tx_fifo_errors = UINT64_MAX;
1736-
stats->tx_heartbeat_errors = UINT64_MAX;
1737-
stats->tx_window_errors = UINT64_MAX;
1738-
17391857
ovs_mutex_unlock(&dev->mutex);
17401858

17411859
return 0;

lib/netdev-dummy.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,11 @@ netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
10751075
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
10761076

10771077
ovs_mutex_lock(&dev->mutex);
1078-
*stats = dev->stats;
1078+
/* Passing only collected counters */
1079+
stats->tx_packets = dev->stats.tx_packets;
1080+
stats->tx_bytes = dev->stats.tx_bytes;
1081+
stats->rx_packets = dev->stats.rx_packets;
1082+
stats->rx_bytes = dev->stats.rx_bytes;
10791083
ovs_mutex_unlock(&dev->mutex);
10801084

10811085
return 0;

0 commit comments

Comments
 (0)