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:
committed by
Ben Pfaff
parent
cd32509e4a
commit
971f4b394c
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user