2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-02 07:15:17 +00:00

netdev: Custom statistics.

- New get_custom_stats interface function is added to netdev. It
  allows particular netdev implementation to expose custom
  counters in dictionary format (counter name/counter value).
- 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+.
- New statistics are printed to output via ofctl only if those
  are present in reply message.
- New statistics definition is added to include/openflow/intel-ext.h.
- Custom statistics are implemented only for dpdk-physical
  port type.
- DPDK-physical implementation uses xstats to collect statistics.
  Only dropped and error counters are exposed.

Co-authored-by: Ben Pfaff <blp@ovn.org>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Signed-off-by: Michal Weglicki <michalx.weglicki@intel.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Michal Weglicki
2018-01-09 07:55:37 +00:00
committed by Ben Pfaff
parent cd32509e4a
commit 971f4b394c
19 changed files with 498 additions and 18 deletions

View File

@@ -434,6 +434,14 @@ struct netdev_dpdk {
* from the enum set 'dpdk_hw_ol_features' */
uint32_t hw_ol_features;
);
PADDED_MEMBERS(CACHE_LINE_SIZE,
/* Names of all XSTATS counters */
struct rte_eth_xstat_name *rte_xstats_names;
int rte_xstats_names_size;
int rte_xstats_ids_size;
uint64_t *rte_xstats_ids;
);
};
struct netdev_rxq_dpdk {
@@ -916,6 +924,12 @@ common_construct(struct netdev *netdev, dpdk_port_t port_no,
netdev_request_reconfigure(netdev);
dev->rte_xstats_names = NULL;
dev->rte_xstats_names_size = 0;
dev->rte_xstats_ids = NULL;
dev->rte_xstats_ids_size = 0;
return 0;
}
@@ -1154,6 +1168,126 @@ netdev_dpdk_dealloc(struct netdev *netdev)
rte_free(dev);
}
static void
netdev_dpdk_clear_xstats(struct netdev_dpdk *dev) OVS_REQUIRES(dev->mutex)
{
/* If statistics are already allocated, we have to
* reconfigure, as port_id could have been changed. */
if (dev->rte_xstats_names) {
free(dev->rte_xstats_names);
dev->rte_xstats_names = NULL;
dev->rte_xstats_names_size = 0;
}
if (dev->rte_xstats_ids) {
free(dev->rte_xstats_ids);
dev->rte_xstats_ids = NULL;
dev->rte_xstats_ids_size = 0;
}
}
static const char*
netdev_dpdk_get_xstat_name(struct netdev_dpdk *dev, uint64_t id)
{
if (id >= dev->rte_xstats_names_size) {
return "UNKNOWN";
}
return dev->rte_xstats_names[id].name;
}
static bool
netdev_dpdk_configure_xstats(struct netdev_dpdk *dev)
OVS_REQUIRES(dev->mutex)
{
int rte_xstats_len;
bool ret;
struct rte_eth_xstat *rte_xstats;
uint64_t id;
int xstats_no;
const char *name;
/* Retrieving all XSTATS names. If something will go wrong
* or amount of counters will be equal 0, rte_xstats_names
* buffer will be marked as NULL, and any further xstats
* query won't be performed (e.g. during netdev_dpdk_get_stats
* execution). */
ret = false;
rte_xstats = NULL;
if (dev->rte_xstats_names == NULL || dev->rte_xstats_ids == NULL) {
dev->rte_xstats_names_size =
rte_eth_xstats_get_names(dev->port_id, NULL, 0);
if (dev->rte_xstats_names_size < 0) {
VLOG_WARN("Cannot get XSTATS for port: %"PRIu8, dev->port_id);
dev->rte_xstats_names_size = 0;
} else {
/* Reserve memory for xstats names and values */
dev->rte_xstats_names = xcalloc(dev->rte_xstats_names_size,
sizeof *dev->rte_xstats_names);
if (dev->rte_xstats_names) {
/* Retreive xstats names */
rte_xstats_len =
rte_eth_xstats_get_names(dev->port_id,
dev->rte_xstats_names,
dev->rte_xstats_names_size);
if (rte_xstats_len < 0) {
VLOG_WARN("Cannot get XSTATS names for port: %"PRIu8,
dev->port_id);
goto out;
} else if (rte_xstats_len != dev->rte_xstats_names_size) {
VLOG_WARN("XSTATS size doesn't match for port: %"PRIu8,
dev->port_id);
goto out;
}
dev->rte_xstats_ids = xcalloc(dev->rte_xstats_names_size,
sizeof(uint64_t));
/* We have to calculate number of counters */
rte_xstats = xmalloc(rte_xstats_len * sizeof *rte_xstats);
memset(rte_xstats, 0xff, sizeof *rte_xstats * rte_xstats_len);
/* Retreive xstats values */
if (rte_eth_xstats_get(dev->port_id, rte_xstats,
rte_xstats_len) > 0) {
dev->rte_xstats_ids_size = 0;
xstats_no = 0;
for (uint32_t i = 0; i < rte_xstats_len; i++) {
id = rte_xstats[i].id;
name = netdev_dpdk_get_xstat_name(dev, id);
/* We need to filter out everything except
* dropped, error and management counters */
if (string_ends_with(name, "_errors") ||
strstr(name, "_management_") ||
string_ends_with(name, "_dropped")) {
dev->rte_xstats_ids[xstats_no] = id;
xstats_no++;
}
}
dev->rte_xstats_ids_size = xstats_no;
ret = true;
} else {
VLOG_WARN("Can't get XSTATS IDs for port: %"PRIu8,
dev->port_id);
}
}
}
} else {
/* Already configured */
ret = true;
}
out:
if (!ret) {
netdev_dpdk_clear_xstats(dev);
}
return ret;
}
static int
netdev_dpdk_get_config(const struct netdev *netdev, struct smap *args)
{
@@ -1325,6 +1459,7 @@ netdev_dpdk_set_config(struct netdev *netdev, const struct smap *args,
dev->devargs = xstrdup(new_devargs);
dev->port_id = new_port_id;
netdev_request_reconfigure(&dev->up);
netdev_dpdk_clear_xstats(dev);
err = 0;
}
}
@@ -2181,6 +2316,56 @@ out:
return 0;
}
static int
netdev_dpdk_get_custom_stats(const struct netdev *netdev,
struct netdev_custom_stats *custom_stats)
{
uint32_t i;
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
int rte_xstats_ret;
ovs_mutex_lock(&dev->mutex);
if (netdev_dpdk_configure_xstats(dev)) {
uint64_t *values = xcalloc(dev->rte_xstats_ids_size,
sizeof(uint64_t));
rte_xstats_ret =
rte_eth_xstats_get_by_id(dev->port_id, dev->rte_xstats_ids,
values, dev->rte_xstats_ids_size);
if (rte_xstats_ret > 0 &&
rte_xstats_ret <= dev->rte_xstats_ids_size) {
custom_stats->size = rte_xstats_ret;
custom_stats->counters =
(struct netdev_custom_counter *) xcalloc(rte_xstats_ret,
sizeof(struct netdev_custom_counter));
for (i = 0; i < rte_xstats_ret; i++) {
ovs_strlcpy(custom_stats->counters[i].name,
netdev_dpdk_get_xstat_name(dev,
dev->rte_xstats_ids[i]),
NETDEV_CUSTOM_STATS_NAME_SIZE);
custom_stats->counters[i].value = values[i];
}
} else {
VLOG_WARN("Cannot get XSTATS values for port: %"PRIu8,
dev->port_id);
custom_stats->counters = NULL;
custom_stats->size = 0;
/* Let's clear statistics cache, so it will be
* reconfigured */
netdev_dpdk_clear_xstats(dev);
}
}
ovs_mutex_unlock(&dev->mutex);
return 0;
}
static int
netdev_dpdk_get_features(const struct netdev *netdev,
enum netdev_features *current,
@@ -3391,7 +3576,8 @@ unlock:
#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, \
SET_CONFIG, SET_TX_MULTIQ, SEND, \
GET_CARRIER, GET_STATS, \
GET_CARRIER, GET_STATS, \
GET_CUSTOM_STATS, \
GET_FEATURES, GET_STATUS, \
RECONFIGURE, RXQ_RECV) \
{ \
@@ -3426,6 +3612,7 @@ unlock:
netdev_dpdk_get_carrier_resets, \
netdev_dpdk_set_miimon, \
GET_STATS, \
GET_CUSTOM_STATS, \
GET_FEATURES, \
NULL, /* set_advertisements */ \
NULL, /* get_pt_mode */ \
@@ -3475,6 +3662,7 @@ static const struct netdev_class dpdk_class =
netdev_dpdk_eth_send,
netdev_dpdk_get_carrier,
netdev_dpdk_get_stats,
netdev_dpdk_get_custom_stats,
netdev_dpdk_get_features,
netdev_dpdk_get_status,
netdev_dpdk_reconfigure,
@@ -3491,6 +3679,7 @@ static const struct netdev_class dpdk_ring_class =
netdev_dpdk_ring_send,
netdev_dpdk_get_carrier,
netdev_dpdk_get_stats,
netdev_dpdk_get_custom_stats,
netdev_dpdk_get_features,
netdev_dpdk_get_status,
netdev_dpdk_reconfigure,
@@ -3509,6 +3698,7 @@ static const struct netdev_class dpdk_vhost_class =
netdev_dpdk_vhost_get_stats,
NULL,
NULL,
NULL,
netdev_dpdk_vhost_reconfigure,
netdev_dpdk_vhost_rxq_recv);
static const struct netdev_class dpdk_vhost_client_class =
@@ -3524,6 +3714,7 @@ static const struct netdev_class dpdk_vhost_client_class =
netdev_dpdk_vhost_get_stats,
NULL,
NULL,
NULL,
netdev_dpdk_vhost_client_reconfigure,
netdev_dpdk_vhost_rxq_recv);