mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
virtio-net: support queue stat
To enhance functionality, we now support reporting statistics through the netdev-generic netlink (netdev-genl) queue stats interface. However, this does not extend to all statistics, so a new field, qstat_offset, has been introduced. This field determines which statistics should be reported via netdev-genl queue stats. Given that queue stats are retrieved individually per queue, it's necessary for the virtnet_get_hw_stats() function to be capable of fetching statistics for a specific queue. As the document https://docs.kernel.org/next/networking/statistics.html#notes-for-driver-authors We should not duplicate the stats which get reported via the netlink API in ethtool. If the stats are for queue stat, that will not be reported by ethtool -S. python3 ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump qstats-get --json '{"scope": "queue"}' [{'ifindex': 2, 'queue-id': 0, 'queue-type': 'rx', 'rx-bytes': 157844011, 'rx-csum-bad': 0, 'rx-csum-none': 0, 'rx-csum-unnecessary': 2195386, 'rx-hw-drop-overruns': 0, 'rx-hw-drop-ratelimits': 0, 'rx-hw-drops': 12964, 'rx-packets': 598929}, {'ifindex': 2, 'queue-id': 0, 'queue-type': 'tx', 'tx-bytes': 1938511, 'tx-csum-none': 0, 'tx-hw-drop-errors': 0, 'tx-hw-drop-ratelimits': 0, 'tx-hw-drops': 0, 'tx-needs-csum': 61263, 'tx-packets': 15515}] Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> Reviewed-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
0cfe71f45f
commit
d888f04c09
@ -24,6 +24,7 @@
|
||||
#include <net/xdp.h>
|
||||
#include <net/net_failover.h>
|
||||
#include <net/netdev_rx_queue.h>
|
||||
#include <net/netdev_queues.h>
|
||||
|
||||
static int napi_weight = NAPI_POLL_WEIGHT;
|
||||
module_param(napi_weight, int, 0444);
|
||||
@ -78,6 +79,7 @@ static const unsigned long guest_offloads[] = {
|
||||
struct virtnet_stat_desc {
|
||||
char desc[ETH_GSTRING_LEN];
|
||||
size_t offset;
|
||||
size_t qstat_offset;
|
||||
};
|
||||
|
||||
struct virtnet_sq_free_stats {
|
||||
@ -107,12 +109,24 @@ struct virtnet_rq_stats {
|
||||
u64_stats_t kicks;
|
||||
};
|
||||
|
||||
#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m)}
|
||||
#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m)}
|
||||
#define VIRTNET_SQ_STAT(name, m) {name, offsetof(struct virtnet_sq_stats, m), -1}
|
||||
#define VIRTNET_RQ_STAT(name, m) {name, offsetof(struct virtnet_rq_stats, m), -1}
|
||||
|
||||
#define VIRTNET_SQ_STAT_QSTAT(name, m) \
|
||||
{ \
|
||||
name, \
|
||||
offsetof(struct virtnet_sq_stats, m), \
|
||||
offsetof(struct netdev_queue_stats_tx, m), \
|
||||
}
|
||||
|
||||
#define VIRTNET_RQ_STAT_QSTAT(name, m) \
|
||||
{ \
|
||||
name, \
|
||||
offsetof(struct virtnet_rq_stats, m), \
|
||||
offsetof(struct netdev_queue_stats_rx, m), \
|
||||
}
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
|
||||
VIRTNET_SQ_STAT("packets", packets),
|
||||
VIRTNET_SQ_STAT("bytes", bytes),
|
||||
VIRTNET_SQ_STAT("xdp_tx", xdp_tx),
|
||||
VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops),
|
||||
VIRTNET_SQ_STAT("kicks", kicks),
|
||||
@ -120,8 +134,6 @@ static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
|
||||
VIRTNET_RQ_STAT("packets", packets),
|
||||
VIRTNET_RQ_STAT("bytes", bytes),
|
||||
VIRTNET_RQ_STAT("drops", drops),
|
||||
VIRTNET_RQ_STAT("xdp_packets", xdp_packets),
|
||||
VIRTNET_RQ_STAT("xdp_tx", xdp_tx),
|
||||
@ -130,14 +142,25 @@ static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
|
||||
VIRTNET_RQ_STAT("kicks", kicks),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_sq_stats_desc_qstat[] = {
|
||||
VIRTNET_SQ_STAT_QSTAT("packets", packets),
|
||||
VIRTNET_SQ_STAT_QSTAT("bytes", bytes),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_rq_stats_desc_qstat[] = {
|
||||
VIRTNET_RQ_STAT_QSTAT("packets", packets),
|
||||
VIRTNET_RQ_STAT_QSTAT("bytes", bytes),
|
||||
};
|
||||
|
||||
#define VIRTNET_STATS_DESC_CQ(name) \
|
||||
{#name, offsetof(struct virtio_net_stats_cvq, name)}
|
||||
{#name, offsetof(struct virtio_net_stats_cvq, name), -1}
|
||||
|
||||
#define VIRTNET_STATS_DESC_RX(class, name) \
|
||||
{#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name)}
|
||||
{#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name), -1}
|
||||
|
||||
#define VIRTNET_STATS_DESC_TX(class, name) \
|
||||
{#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name)}
|
||||
{#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name), -1}
|
||||
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_cvq_desc[] = {
|
||||
VIRTNET_STATS_DESC_CQ(command_num),
|
||||
@ -177,6 +200,63 @@ static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc[] = {
|
||||
VIRTNET_STATS_DESC_TX(speed, ratelimit_bytes),
|
||||
};
|
||||
|
||||
#define VIRTNET_STATS_DESC_RX_QSTAT(class, name, qstat_field) \
|
||||
{ \
|
||||
#name, \
|
||||
offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name), \
|
||||
offsetof(struct netdev_queue_stats_rx, qstat_field), \
|
||||
}
|
||||
|
||||
#define VIRTNET_STATS_DESC_TX_QSTAT(class, name, qstat_field) \
|
||||
{ \
|
||||
#name, \
|
||||
offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name), \
|
||||
offsetof(struct netdev_queue_stats_tx, qstat_field), \
|
||||
}
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_rx_basic_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(basic, drops, hw_drops),
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(basic, drop_overruns, hw_drop_overruns),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_tx_basic_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(basic, drops, hw_drops),
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(basic, drop_malformed, hw_drop_errors),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_rx_csum_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_valid, csum_unnecessary),
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_none, csum_none),
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(csum, csum_bad, csum_bad),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_tx_csum_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(csum, csum_none, csum_none),
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(csum, needs_csum, needs_csum),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_rx_gso_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_packets, hw_gro_packets),
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_bytes, hw_gro_bytes),
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_packets_coalesced, hw_gro_wire_packets),
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(gso, gso_bytes_coalesced, hw_gro_wire_bytes),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_tx_gso_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_packets, hw_gso_packets),
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_bytes, hw_gso_bytes),
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_segments, hw_gso_wire_packets),
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(gso, gso_segments_bytes, hw_gso_wire_bytes),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_rx_speed_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_RX_QSTAT(speed, ratelimit_packets, hw_drop_ratelimits),
|
||||
};
|
||||
|
||||
static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc_qstat[] = {
|
||||
VIRTNET_STATS_DESC_TX_QSTAT(speed, ratelimit_packets, hw_drop_ratelimits),
|
||||
};
|
||||
|
||||
#define VIRTNET_Q_TYPE_RX 0
|
||||
#define VIRTNET_Q_TYPE_TX 1
|
||||
#define VIRTNET_Q_TYPE_CQ 2
|
||||
@ -2215,6 +2295,10 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
|
||||
src = (u64_stats_t *)((u8 *)&stats + offset);
|
||||
u64_stats_add(item, u64_stats_read(src));
|
||||
}
|
||||
|
||||
u64_stats_add(&rq->stats.packets, u64_stats_read(&stats.packets));
|
||||
u64_stats_add(&rq->stats.bytes, u64_stats_read(&stats.bytes));
|
||||
|
||||
u64_stats_update_end(&rq->stats.syncp);
|
||||
|
||||
return packets;
|
||||
@ -3474,6 +3558,9 @@ static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid,
|
||||
}
|
||||
|
||||
struct virtnet_stats_ctx {
|
||||
/* The stats are write to qstats or ethtool -S */
|
||||
bool to_qstat;
|
||||
|
||||
/* Used to calculate the offset inside the output buffer. */
|
||||
u32 desc_num[3];
|
||||
|
||||
@ -3489,11 +3576,71 @@ struct virtnet_stats_ctx {
|
||||
|
||||
static void virtnet_stats_ctx_init(struct virtnet_info *vi,
|
||||
struct virtnet_stats_ctx *ctx,
|
||||
u64 *data)
|
||||
u64 *data, bool to_qstat)
|
||||
{
|
||||
u32 queue_type;
|
||||
|
||||
ctx->data = data;
|
||||
ctx->to_qstat = to_qstat;
|
||||
|
||||
if (to_qstat) {
|
||||
ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc_qstat);
|
||||
ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc_qstat);
|
||||
|
||||
queue_type = VIRTNET_Q_TYPE_RX;
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_BASIC;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_basic_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_basic);
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_CSUM;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_csum_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_csum);
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_GSO) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_GSO;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_gso_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_gso);
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_SPEED) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_RX_SPEED;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_rx_speed_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_speed);
|
||||
}
|
||||
|
||||
queue_type = VIRTNET_Q_TYPE_TX;
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_BASIC;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_basic_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_basic);
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_CSUM) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_CSUM;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_csum_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_csum);
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_GSO;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_gso_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_gso);
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_SPEED) {
|
||||
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_TX_SPEED;
|
||||
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_tx_speed_desc_qstat);
|
||||
ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_speed);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->desc_num[VIRTNET_Q_TYPE_RX] = ARRAY_SIZE(virtnet_rq_stats_desc);
|
||||
ctx->desc_num[VIRTNET_Q_TYPE_TX] = ARRAY_SIZE(virtnet_sq_stats_desc);
|
||||
@ -3590,7 +3737,104 @@ static void virtnet_fill_total_fields(struct virtnet_info *vi,
|
||||
stats_sum_queue(data, num_tx, first_tx_q, vi->curr_queue_pairs);
|
||||
}
|
||||
|
||||
/* virtnet_fill_stats - copy the stats to ethtool -S
|
||||
static void virtnet_fill_stats_qstat(struct virtnet_info *vi, u32 qid,
|
||||
struct virtnet_stats_ctx *ctx,
|
||||
const u8 *base, bool drv_stats, u8 reply_type)
|
||||
{
|
||||
const struct virtnet_stat_desc *desc;
|
||||
const u64_stats_t *v_stat;
|
||||
u64 offset, bitmap;
|
||||
const __le64 *v;
|
||||
u32 queue_type;
|
||||
int i, num;
|
||||
|
||||
queue_type = vq_type(vi, qid);
|
||||
bitmap = ctx->bitmap[queue_type];
|
||||
|
||||
if (drv_stats) {
|
||||
if (queue_type == VIRTNET_Q_TYPE_RX) {
|
||||
desc = &virtnet_rq_stats_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_rq_stats_desc_qstat);
|
||||
} else {
|
||||
desc = &virtnet_sq_stats_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_sq_stats_desc_qstat);
|
||||
}
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
offset = desc[i].qstat_offset / sizeof(*ctx->data);
|
||||
v_stat = (const u64_stats_t *)(base + desc[i].offset);
|
||||
ctx->data[offset] = u64_stats_read(v_stat);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
|
||||
desc = &virtnet_stats_rx_basic_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_rx_basic_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_BASIC)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
|
||||
desc = &virtnet_stats_rx_csum_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_rx_csum_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_CSUM)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_GSO) {
|
||||
desc = &virtnet_stats_rx_gso_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_rx_gso_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_GSO)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_SPEED) {
|
||||
desc = &virtnet_stats_rx_speed_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_rx_speed_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_SPEED)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
|
||||
desc = &virtnet_stats_tx_basic_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_tx_basic_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_BASIC)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_CSUM) {
|
||||
desc = &virtnet_stats_tx_csum_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_tx_csum_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_CSUM)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
|
||||
desc = &virtnet_stats_tx_gso_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_tx_gso_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_GSO)
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_SPEED) {
|
||||
desc = &virtnet_stats_tx_speed_desc_qstat[0];
|
||||
num = ARRAY_SIZE(virtnet_stats_tx_speed_desc_qstat);
|
||||
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_SPEED)
|
||||
goto found;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
found:
|
||||
for (i = 0; i < num; ++i) {
|
||||
offset = desc[i].qstat_offset / sizeof(*ctx->data);
|
||||
v = (const __le64 *)(base + desc[i].offset);
|
||||
ctx->data[offset] = le64_to_cpu(*v);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtnet_fill_stats - copy the stats to qstats or ethtool -S
|
||||
* The stats source is the device or the driver.
|
||||
*
|
||||
* @vi: virtio net info
|
||||
@ -3611,6 +3855,9 @@ static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid,
|
||||
const __le64 *v;
|
||||
int i, num;
|
||||
|
||||
if (ctx->to_qstat)
|
||||
return virtnet_fill_stats_qstat(vi, qid, ctx, base, drv_stats, reply_type);
|
||||
|
||||
num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ];
|
||||
num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX];
|
||||
num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX];
|
||||
@ -3770,22 +4017,34 @@ static void virtnet_make_stat_req(struct virtnet_info *vi,
|
||||
*idx += 1;
|
||||
}
|
||||
|
||||
/* qid: -1: get stats of all vq.
|
||||
* > 0: get the stats for the special vq. This must not be cvq.
|
||||
*/
|
||||
static int virtnet_get_hw_stats(struct virtnet_info *vi,
|
||||
struct virtnet_stats_ctx *ctx)
|
||||
struct virtnet_stats_ctx *ctx, int qid)
|
||||
{
|
||||
int qnum, i, j, res_size, qtype, last_vq, first_vq;
|
||||
struct virtio_net_ctrl_queue_stats *req;
|
||||
int qnum, i, j, res_size, qtype, last_vq;
|
||||
bool enable_cvq;
|
||||
void *reply;
|
||||
int ok;
|
||||
|
||||
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS))
|
||||
return 0;
|
||||
|
||||
last_vq = vi->curr_queue_pairs * 2 - 1;
|
||||
if (qid == -1) {
|
||||
last_vq = vi->curr_queue_pairs * 2 - 1;
|
||||
first_vq = 0;
|
||||
enable_cvq = true;
|
||||
} else {
|
||||
last_vq = qid;
|
||||
first_vq = qid;
|
||||
enable_cvq = false;
|
||||
}
|
||||
|
||||
qnum = 0;
|
||||
res_size = 0;
|
||||
for (i = 0; i <= last_vq ; ++i) {
|
||||
for (i = first_vq; i <= last_vq ; ++i) {
|
||||
qtype = vq_type(vi, i);
|
||||
if (ctx->bitmap[qtype]) {
|
||||
++qnum;
|
||||
@ -3793,7 +4052,7 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi,
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->bitmap[VIRTNET_Q_TYPE_CQ]) {
|
||||
if (enable_cvq && ctx->bitmap[VIRTNET_Q_TYPE_CQ]) {
|
||||
res_size += ctx->size[VIRTNET_Q_TYPE_CQ];
|
||||
qnum += 1;
|
||||
}
|
||||
@ -3809,10 +4068,11 @@ static int virtnet_get_hw_stats(struct virtnet_info *vi,
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i <= last_vq ; ++i)
|
||||
for (i = first_vq; i <= last_vq ; ++i)
|
||||
virtnet_make_stat_req(vi, ctx, req, i, &j);
|
||||
|
||||
virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j);
|
||||
if (enable_cvq)
|
||||
virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j);
|
||||
|
||||
ok = __virtnet_get_hw_stats(vi, ctx, req, sizeof(*req) * j, reply, res_size);
|
||||
|
||||
@ -3853,7 +4113,7 @@ static int virtnet_get_sset_count(struct net_device *dev, int sset)
|
||||
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
virtnet_stats_ctx_init(vi, &ctx, NULL);
|
||||
virtnet_stats_ctx_init(vi, &ctx, NULL, false);
|
||||
|
||||
pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX];
|
||||
|
||||
@ -3872,8 +4132,8 @@ static void virtnet_get_ethtool_stats(struct net_device *dev,
|
||||
unsigned int start, i;
|
||||
const u8 *stats_base;
|
||||
|
||||
virtnet_stats_ctx_init(vi, &ctx, data);
|
||||
if (virtnet_get_hw_stats(vi, &ctx))
|
||||
virtnet_stats_ctx_init(vi, &ctx, data, false);
|
||||
if (virtnet_get_hw_stats(vi, &ctx, -1))
|
||||
dev_warn(&vi->dev->dev, "Failed to get hw stats.\n");
|
||||
|
||||
for (i = 0; i < vi->curr_queue_pairs; i++) {
|
||||
@ -4428,6 +4688,95 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
|
||||
.set_rxnfc = virtnet_set_rxnfc,
|
||||
};
|
||||
|
||||
static void virtnet_get_queue_stats_rx(struct net_device *dev, int i,
|
||||
struct netdev_queue_stats_rx *stats)
|
||||
{
|
||||
struct virtnet_info *vi = netdev_priv(dev);
|
||||
struct receive_queue *rq = &vi->rq[i];
|
||||
struct virtnet_stats_ctx ctx = {0};
|
||||
|
||||
virtnet_stats_ctx_init(vi, &ctx, (void *)stats, true);
|
||||
|
||||
virtnet_get_hw_stats(vi, &ctx, i * 2);
|
||||
virtnet_fill_stats(vi, i * 2, &ctx, (void *)&rq->stats, true, 0);
|
||||
}
|
||||
|
||||
static void virtnet_get_queue_stats_tx(struct net_device *dev, int i,
|
||||
struct netdev_queue_stats_tx *stats)
|
||||
{
|
||||
struct virtnet_info *vi = netdev_priv(dev);
|
||||
struct send_queue *sq = &vi->sq[i];
|
||||
struct virtnet_stats_ctx ctx = {0};
|
||||
|
||||
virtnet_stats_ctx_init(vi, &ctx, (void *)stats, true);
|
||||
|
||||
virtnet_get_hw_stats(vi, &ctx, i * 2 + 1);
|
||||
virtnet_fill_stats(vi, i * 2 + 1, &ctx, (void *)&sq->stats, true, 0);
|
||||
}
|
||||
|
||||
static void virtnet_get_base_stats(struct net_device *dev,
|
||||
struct netdev_queue_stats_rx *rx,
|
||||
struct netdev_queue_stats_tx *tx)
|
||||
{
|
||||
struct virtnet_info *vi = netdev_priv(dev);
|
||||
|
||||
/* The queue stats of the virtio-net will not be reset. So here we
|
||||
* return 0.
|
||||
*/
|
||||
rx->bytes = 0;
|
||||
rx->packets = 0;
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
|
||||
rx->hw_drops = 0;
|
||||
rx->hw_drop_overruns = 0;
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
|
||||
rx->csum_unnecessary = 0;
|
||||
rx->csum_none = 0;
|
||||
rx->csum_bad = 0;
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_GSO) {
|
||||
rx->hw_gro_packets = 0;
|
||||
rx->hw_gro_bytes = 0;
|
||||
rx->hw_gro_wire_packets = 0;
|
||||
rx->hw_gro_wire_bytes = 0;
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_SPEED)
|
||||
rx->hw_drop_ratelimits = 0;
|
||||
|
||||
tx->bytes = 0;
|
||||
tx->packets = 0;
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
|
||||
tx->hw_drops = 0;
|
||||
tx->hw_drop_errors = 0;
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_CSUM) {
|
||||
tx->csum_none = 0;
|
||||
tx->needs_csum = 0;
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
|
||||
tx->hw_gso_packets = 0;
|
||||
tx->hw_gso_bytes = 0;
|
||||
tx->hw_gso_wire_packets = 0;
|
||||
tx->hw_gso_wire_bytes = 0;
|
||||
}
|
||||
|
||||
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_SPEED)
|
||||
tx->hw_drop_ratelimits = 0;
|
||||
}
|
||||
|
||||
static const struct netdev_stat_ops virtnet_stat_ops = {
|
||||
.get_queue_stats_rx = virtnet_get_queue_stats_rx,
|
||||
.get_queue_stats_tx = virtnet_get_queue_stats_tx,
|
||||
.get_base_stats = virtnet_get_base_stats,
|
||||
};
|
||||
|
||||
static void virtnet_freeze_down(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtnet_info *vi = vdev->priv;
|
||||
@ -5231,6 +5580,7 @@ static int virtnet_probe(struct virtio_device *vdev)
|
||||
dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE |
|
||||
IFF_TX_SKB_NO_LINEAR;
|
||||
dev->netdev_ops = &virtnet_netdev;
|
||||
dev->stat_ops = &virtnet_stat_ops;
|
||||
dev->features = NETIF_F_HIGHDMA;
|
||||
|
||||
dev->ethtool_ops = &virtnet_ethtool_ops;
|
||||
|
Loading…
Reference in New Issue
Block a user