2019-05-19 13:51:43 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2009-09-24 15:59:20 +00:00
|
|
|
/* A network driver using virtio.
|
2007-10-22 01:03:37 +00:00
|
|
|
*
|
|
|
|
* Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
|
|
|
|
*/
|
|
|
|
//#define DEBUG
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/etherdevice.h>
|
2008-04-18 03:21:42 +00:00
|
|
|
#include <linux/ethtool.h>
|
2007-10-22 01:03:37 +00:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/virtio.h>
|
|
|
|
#include <linux/virtio_net.h>
|
2016-12-15 20:13:24 +00:00
|
|
|
#include <linux/bpf.h>
|
bpf: add initial bpf tracepoints
This work adds a number of tracepoints to paths that are either
considered slow-path or exception-like states, where monitoring or
inspecting them would be desirable.
For bpf(2) syscall, tracepoints have been placed for main commands
when they succeed. In XDP case, tracepoint is for exceptions, that
is, f.e. on abnormal BPF program exit such as unknown or XDP_ABORTED
return code, or when error occurs during XDP_TX action and the packet
could not be forwarded.
Both have been split into separate event headers, and can be further
extended. Worst case, if they unexpectedly should get into our way in
future, they can also removed [1]. Of course, these tracepoints (like
any other) can be analyzed by eBPF itself, etc. Example output:
# ./perf record -a -e bpf:* sleep 10
# ./perf script
sock_example 6197 [005] 283.980322: bpf:bpf_map_create: map type=ARRAY ufd=4 key=4 val=8 max=256 flags=0
sock_example 6197 [005] 283.980721: bpf:bpf_prog_load: prog=a5ea8fa30ea6849c type=SOCKET_FILTER ufd=5
sock_example 6197 [005] 283.988423: bpf:bpf_prog_get_type: prog=a5ea8fa30ea6849c type=SOCKET_FILTER
sock_example 6197 [005] 283.988443: bpf:bpf_map_lookup_elem: map type=ARRAY ufd=4 key=[06 00 00 00] val=[00 00 00 00 00 00 00 00]
[...]
sock_example 6197 [005] 288.990868: bpf:bpf_map_lookup_elem: map type=ARRAY ufd=4 key=[01 00 00 00] val=[14 00 00 00 00 00 00 00]
swapper 0 [005] 289.338243: bpf:bpf_prog_put_rcu: prog=a5ea8fa30ea6849c type=SOCKET_FILTER
[1] https://lwn.net/Articles/705270/
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-01-25 01:28:18 +00:00
|
|
|
#include <linux/bpf_trace.h>
|
2007-10-22 01:03:37 +00:00
|
|
|
#include <linux/scatterlist.h>
|
2009-01-26 02:06:26 +00:00
|
|
|
#include <linux/if_vlan.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2013-01-24 23:51:31 +00:00
|
|
|
#include <linux/cpu.h>
|
2014-01-17 06:23:27 +00:00
|
|
|
#include <linux/average.h>
|
2017-09-19 09:42:43 +00:00
|
|
|
#include <linux/filter.h>
|
2018-08-10 00:28:40 +00:00
|
|
|
#include <linux/kernel.h>
|
2023-12-11 10:36:07 +00:00
|
|
|
#include <linux/dim.h>
|
2017-03-09 00:21:21 +00:00
|
|
|
#include <net/route.h>
|
2018-01-03 10:26:04 +00:00
|
|
|
#include <net/xdp.h>
|
2018-05-24 16:55:17 +00:00
|
|
|
#include <net/net_failover.h>
|
2023-08-03 01:02:29 +00:00
|
|
|
#include <net/netdev_rx_queue.h>
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
#include <net/netdev_queues.h>
|
2024-07-08 11:25:33 +00:00
|
|
|
#include <net/xdp_sock_drv.h>
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2013-05-09 19:50:51 +00:00
|
|
|
static int napi_weight = NAPI_POLL_WEIGHT;
|
2007-12-16 13:19:43 +00:00
|
|
|
module_param(napi_weight, int, 0444);
|
|
|
|
|
2019-06-13 16:24:57 +00:00
|
|
|
static bool csum = true, gso = true, napi_tx = true;
|
2008-02-05 04:50:02 +00:00
|
|
|
module_param(csum, bool, 0444);
|
|
|
|
module_param(gso, bool, 0444);
|
2017-04-24 17:49:27 +00:00
|
|
|
module_param(napi_tx, bool, 0644);
|
2008-02-05 04:50:02 +00:00
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
/* FIXME: MTU in config. */
|
2013-11-14 18:41:04 +00:00
|
|
|
#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
|
2008-11-17 06:41:34 +00:00
|
|
|
#define GOOD_COPY_LEN 128
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2017-02-21 08:46:28 +00:00
|
|
|
#define VIRTNET_RX_PAD (NET_IP_ALIGN + NET_SKB_PAD)
|
|
|
|
|
2018-06-26 15:39:58 +00:00
|
|
|
/* Separating two types of XDP xmit */
|
|
|
|
#define VIRTIO_XDP_TX BIT(0)
|
|
|
|
#define VIRTIO_XDP_REDIR BIT(1)
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
#define VIRTIO_XDP_FLAG BIT(0)
|
|
|
|
#define VIRTIO_ORPHAN_FLAG BIT(1)
|
2019-01-29 00:45:59 +00:00
|
|
|
|
2015-08-19 07:48:40 +00:00
|
|
|
/* RX packet size EWMA. The average packet size is used to determine the packet
|
|
|
|
* buffer size when refilling RX rings. As the entire RX ring may be refilled
|
|
|
|
* at once, the weight is chosen so that the EWMA will be insensitive to short-
|
|
|
|
* term, transient changes in packet size.
|
2014-01-17 06:23:27 +00:00
|
|
|
*/
|
2017-02-15 08:49:26 +00:00
|
|
|
DECLARE_EWMA(pkt_len, 0, 64)
|
2014-01-17 06:23:27 +00:00
|
|
|
|
2011-11-14 14:17:08 +00:00
|
|
|
#define VIRTNET_DRIVER_VERSION "1.0.0"
|
2009-02-04 09:02:34 +00:00
|
|
|
|
2017-08-12 21:45:53 +00:00
|
|
|
static const unsigned long guest_offloads[] = {
|
|
|
|
VIRTIO_NET_F_GUEST_TSO4,
|
|
|
|
VIRTIO_NET_F_GUEST_TSO6,
|
|
|
|
VIRTIO_NET_F_GUEST_ECN,
|
2018-11-22 06:36:30 +00:00
|
|
|
VIRTIO_NET_F_GUEST_UFO,
|
2022-12-07 11:35:58 +00:00
|
|
|
VIRTIO_NET_F_GUEST_CSUM,
|
|
|
|
VIRTIO_NET_F_GUEST_USO4,
|
2023-03-09 09:45:59 +00:00
|
|
|
VIRTIO_NET_F_GUEST_USO6,
|
|
|
|
VIRTIO_NET_F_GUEST_HDRLEN
|
2017-08-12 21:45:53 +00:00
|
|
|
};
|
2017-07-19 08:54:49 +00:00
|
|
|
|
2021-08-17 08:06:59 +00:00
|
|
|
#define GUEST_OFFLOAD_GRO_HW_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
|
2020-09-29 01:58:06 +00:00
|
|
|
(1ULL << VIRTIO_NET_F_GUEST_TSO6) | \
|
|
|
|
(1ULL << VIRTIO_NET_F_GUEST_ECN) | \
|
2022-12-07 11:35:58 +00:00
|
|
|
(1ULL << VIRTIO_NET_F_GUEST_UFO) | \
|
|
|
|
(1ULL << VIRTIO_NET_F_GUEST_USO4) | \
|
|
|
|
(1ULL << VIRTIO_NET_F_GUEST_USO6))
|
2020-09-29 01:58:06 +00:00
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
struct virtnet_stat_desc {
|
|
|
|
char desc[ETH_GSTRING_LEN];
|
|
|
|
size_t offset;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
size_t qstat_offset;
|
2011-06-15 06:36:29 +00:00
|
|
|
};
|
|
|
|
|
2024-02-29 07:20:42 +00:00
|
|
|
struct virtnet_sq_free_stats {
|
|
|
|
u64 packets;
|
|
|
|
u64 bytes;
|
2024-06-18 14:44:56 +00:00
|
|
|
u64 napi_packets;
|
|
|
|
u64 napi_bytes;
|
2024-02-29 07:20:42 +00:00
|
|
|
};
|
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
struct virtnet_sq_stats {
|
|
|
|
struct u64_stats_sync syncp;
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_t packets;
|
|
|
|
u64_stats_t bytes;
|
|
|
|
u64_stats_t xdp_tx;
|
|
|
|
u64_stats_t xdp_tx_drops;
|
|
|
|
u64_stats_t kicks;
|
|
|
|
u64_stats_t tx_timeouts;
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
u64_stats_t stop;
|
|
|
|
u64_stats_t wake;
|
2018-01-17 06:38:25 +00:00
|
|
|
};
|
|
|
|
|
2018-07-31 09:43:39 +00:00
|
|
|
struct virtnet_rq_stats {
|
|
|
|
struct u64_stats_sync syncp;
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_t packets;
|
|
|
|
u64_stats_t bytes;
|
|
|
|
u64_stats_t drops;
|
|
|
|
u64_stats_t xdp_packets;
|
|
|
|
u64_stats_t xdp_tx;
|
|
|
|
u64_stats_t xdp_redirects;
|
|
|
|
u64_stats_t xdp_drops;
|
|
|
|
u64_stats_t kicks;
|
2018-01-17 06:38:25 +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>
2024-04-26 03:39:28 +00:00
|
|
|
#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), \
|
|
|
|
}
|
2018-01-17 06:38:25 +00:00
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_sq_stats_desc[] = {
|
2024-04-26 03:39:25 +00:00
|
|
|
VIRTNET_SQ_STAT("xdp_tx", xdp_tx),
|
|
|
|
VIRTNET_SQ_STAT("xdp_tx_drops", xdp_tx_drops),
|
|
|
|
VIRTNET_SQ_STAT("kicks", kicks),
|
|
|
|
VIRTNET_SQ_STAT("tx_timeouts", tx_timeouts),
|
2018-01-17 06:38:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_rq_stats_desc[] = {
|
2024-04-26 03:39:25 +00:00
|
|
|
VIRTNET_RQ_STAT("drops", drops),
|
|
|
|
VIRTNET_RQ_STAT("xdp_packets", xdp_packets),
|
|
|
|
VIRTNET_RQ_STAT("xdp_tx", xdp_tx),
|
|
|
|
VIRTNET_RQ_STAT("xdp_redirects", xdp_redirects),
|
|
|
|
VIRTNET_RQ_STAT("xdp_drops", xdp_drops),
|
|
|
|
VIRTNET_RQ_STAT("kicks", kicks),
|
2018-01-17 06:38:25 +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>
2024-04-26 03:39:28 +00:00
|
|
|
static const struct virtnet_stat_desc virtnet_sq_stats_desc_qstat[] = {
|
|
|
|
VIRTNET_SQ_STAT_QSTAT("packets", packets),
|
|
|
|
VIRTNET_SQ_STAT_QSTAT("bytes", bytes),
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
VIRTNET_SQ_STAT_QSTAT("stop", stop),
|
|
|
|
VIRTNET_SQ_STAT_QSTAT("wake", wake),
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_rq_stats_desc_qstat[] = {
|
|
|
|
VIRTNET_RQ_STAT_QSTAT("packets", packets),
|
|
|
|
VIRTNET_RQ_STAT_QSTAT("bytes", bytes),
|
|
|
|
};
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
#define VIRTNET_STATS_DESC_CQ(name) \
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
{#name, offsetof(struct virtio_net_stats_cvq, name), -1}
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
#define VIRTNET_STATS_DESC_RX(class, name) \
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
{#name, offsetof(struct virtio_net_stats_rx_ ## class, rx_ ## name), -1}
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
#define VIRTNET_STATS_DESC_TX(class, name) \
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
{#name, offsetof(struct virtio_net_stats_tx_ ## class, tx_ ## name), -1}
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_cvq_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_CQ(command_num),
|
|
|
|
VIRTNET_STATS_DESC_CQ(ok_num),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_rx_basic_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_RX(basic, packets),
|
|
|
|
VIRTNET_STATS_DESC_RX(basic, bytes),
|
|
|
|
|
|
|
|
VIRTNET_STATS_DESC_RX(basic, notifications),
|
|
|
|
VIRTNET_STATS_DESC_RX(basic, interrupts),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_tx_basic_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_TX(basic, packets),
|
|
|
|
VIRTNET_STATS_DESC_TX(basic, bytes),
|
|
|
|
|
|
|
|
VIRTNET_STATS_DESC_TX(basic, notifications),
|
|
|
|
VIRTNET_STATS_DESC_TX(basic, interrupts),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_rx_csum_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_RX(csum, needs_csum),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_tx_gso_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_TX(gso, gso_packets_noseg),
|
|
|
|
VIRTNET_STATS_DESC_TX(gso, gso_bytes_noseg),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_rx_speed_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_RX(speed, ratelimit_bytes),
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct virtnet_stat_desc virtnet_stats_tx_speed_desc[] = {
|
|
|
|
VIRTNET_STATS_DESC_TX(speed, ratelimit_bytes),
|
|
|
|
};
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
#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),
|
|
|
|
};
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
#define VIRTNET_Q_TYPE_RX 0
|
|
|
|
#define VIRTNET_Q_TYPE_TX 1
|
|
|
|
#define VIRTNET_Q_TYPE_CQ 2
|
|
|
|
|
2023-07-31 07:06:54 +00:00
|
|
|
struct virtnet_interrupt_coalesce {
|
|
|
|
u32 max_packets;
|
|
|
|
u32 max_usecs;
|
|
|
|
};
|
|
|
|
|
2023-08-10 12:30:57 +00:00
|
|
|
/* The dma information of pages allocated at a time. */
|
|
|
|
struct virtnet_rq_dma {
|
|
|
|
dma_addr_t addr;
|
|
|
|
u32 ref;
|
|
|
|
u16 len;
|
|
|
|
u16 need_sync;
|
|
|
|
};
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
/* Internal representation of a send virtqueue */
|
|
|
|
struct send_queue {
|
|
|
|
/* Virtqueue associated with this send _queue */
|
|
|
|
struct virtqueue *vq;
|
|
|
|
|
|
|
|
/* TX: fragments + linear part + virtio header */
|
|
|
|
struct scatterlist sg[MAX_SKB_FRAGS + 2];
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
/* Name of the send queue: output.$index */
|
2023-01-23 03:55:11 +00:00
|
|
|
char name[16];
|
2017-04-24 17:49:27 +00:00
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
struct virtnet_sq_stats stats;
|
|
|
|
|
2023-07-31 07:06:55 +00:00
|
|
|
struct virtnet_interrupt_coalesce intr_coal;
|
|
|
|
|
2017-04-24 17:49:27 +00:00
|
|
|
struct napi_struct napi;
|
2022-08-01 06:39:01 +00:00
|
|
|
|
|
|
|
/* Record whether sq is in reset state. */
|
|
|
|
bool reset;
|
2012-12-07 07:04:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Internal representation of a receive virtqueue */
|
|
|
|
struct receive_queue {
|
|
|
|
/* Virtqueue associated with this receive_queue */
|
|
|
|
struct virtqueue *vq;
|
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
struct napi_struct napi;
|
|
|
|
|
2016-12-15 20:13:24 +00:00
|
|
|
struct bpf_prog __rcu *xdp_prog;
|
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
struct virtnet_rq_stats stats;
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
/* The number of rx notifications */
|
|
|
|
u16 calls;
|
|
|
|
|
|
|
|
/* Is dynamic interrupt moderation enabled? */
|
|
|
|
bool dim_enabled;
|
|
|
|
|
2024-05-03 20:24:44 +00:00
|
|
|
/* Used to protect dim_enabled and inter_coal */
|
|
|
|
struct mutex dim_lock;
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
/* Dynamic Interrupt Moderation */
|
|
|
|
struct dim dim;
|
|
|
|
|
|
|
|
u32 packets_in_napi;
|
|
|
|
|
2023-07-31 07:06:55 +00:00
|
|
|
struct virtnet_interrupt_coalesce intr_coal;
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
/* Chain pages by the private ptr. */
|
|
|
|
struct page *pages;
|
|
|
|
|
2014-01-17 06:23:27 +00:00
|
|
|
/* Average packet length for mergeable receive buffers. */
|
2015-08-19 07:48:40 +00:00
|
|
|
struct ewma_pkt_len mrg_avg_pkt_len;
|
2014-01-17 06:23:27 +00:00
|
|
|
|
2014-01-17 06:23:26 +00:00
|
|
|
/* Page frag for packet buffer allocation. */
|
|
|
|
struct page_frag alloc_frag;
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
/* RX: fragments + linear part + virtio header */
|
|
|
|
struct scatterlist sg[MAX_SKB_FRAGS + 2];
|
2012-12-07 07:04:56 +00:00
|
|
|
|
2017-03-09 00:21:21 +00:00
|
|
|
/* Min single buffer size for mergeable buffers case. */
|
|
|
|
unsigned int min_buf_len;
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* Name of this receive queue: input.$index */
|
2023-01-23 03:55:11 +00:00
|
|
|
char name[16];
|
2018-01-03 10:26:04 +00:00
|
|
|
|
|
|
|
struct xdp_rxq_info xdp_rxq;
|
2023-08-10 12:30:57 +00:00
|
|
|
|
|
|
|
/* Record the last dma info to free after new pages is allocated. */
|
|
|
|
struct virtnet_rq_dma *last_dma;
|
2024-07-08 11:25:33 +00:00
|
|
|
|
|
|
|
struct xsk_buff_pool *xsk_pool;
|
|
|
|
|
|
|
|
/* xdp rxq used by xsk */
|
|
|
|
struct xdp_rxq_info xsk_rxq_info;
|
2024-07-08 11:25:35 +00:00
|
|
|
|
|
|
|
struct xdp_buff **xsk_buffs;
|
2024-09-06 12:31:35 +00:00
|
|
|
|
|
|
|
/* Do dma by self */
|
|
|
|
bool do_dma;
|
2012-12-07 07:04:55 +00:00
|
|
|
};
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
/* This structure can contain rss message with maximum settings for indirection table and keysize
|
|
|
|
* Note, that default structure that describes RSS configuration virtio_net_rss_config
|
|
|
|
* contains same info but can't handle table values.
|
|
|
|
* In any case, structure would be passed to virtio hw through sg_buf split by parts
|
|
|
|
* because table sizes may be differ according to the device configuration.
|
|
|
|
*/
|
|
|
|
#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
|
|
|
|
#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
|
|
|
|
struct virtio_net_ctrl_rss {
|
|
|
|
u32 hash_types;
|
|
|
|
u16 indirection_table_mask;
|
|
|
|
u16 unclassified_queue;
|
|
|
|
u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
|
|
|
|
u16 max_tx_vq;
|
|
|
|
u8 hash_key_length;
|
|
|
|
u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
|
|
|
|
};
|
|
|
|
|
2018-04-19 05:30:48 +00:00
|
|
|
/* Control VQ buffers: protected by the rtnl lock */
|
|
|
|
struct control_buf {
|
|
|
|
struct virtio_net_ctrl_hdr hdr;
|
|
|
|
virtio_net_ctrl_ack status;
|
|
|
|
};
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
struct virtnet_info {
|
|
|
|
struct virtio_device *vdev;
|
|
|
|
struct virtqueue *cvq;
|
|
|
|
struct net_device *dev;
|
2012-12-07 07:04:56 +00:00
|
|
|
struct send_queue *sq;
|
|
|
|
struct receive_queue *rq;
|
2012-12-07 07:04:55 +00:00
|
|
|
unsigned int status;
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* Max # of queue pairs supported by the device */
|
|
|
|
u16 max_queue_pairs;
|
|
|
|
|
|
|
|
/* # of queue pairs currently used by the driver */
|
|
|
|
u16 curr_queue_pairs;
|
|
|
|
|
2016-12-15 20:13:49 +00:00
|
|
|
/* # of XDP queue pairs currently used by the driver */
|
|
|
|
u16 xdp_queue_pairs;
|
|
|
|
|
2021-03-10 02:24:45 +00:00
|
|
|
/* xdp_queue_pairs may be 0, when xdp is already loaded. So add this. */
|
|
|
|
bool xdp_enabled;
|
|
|
|
|
2008-04-18 03:24:27 +00:00
|
|
|
/* I like... big packets and I cannot lie! */
|
|
|
|
bool big_packets;
|
|
|
|
|
2022-09-14 14:49:11 +00:00
|
|
|
/* number of sg entries allocated for big packets */
|
|
|
|
unsigned int big_packets_num_skbfrags;
|
|
|
|
|
2008-11-17 06:41:34 +00:00
|
|
|
/* Host will merge rx buffers for big packets (shake it! shake it!) */
|
|
|
|
bool mergeable_rx_bufs;
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
/* Host supports rss and/or hash report */
|
|
|
|
bool has_rss;
|
2022-03-28 17:53:35 +00:00
|
|
|
bool has_rss_hash_report;
|
2022-03-28 17:53:34 +00:00
|
|
|
u8 rss_key_size;
|
|
|
|
u16 rss_indir_table_size;
|
|
|
|
u32 rss_hash_types_supported;
|
2022-03-28 17:53:36 +00:00
|
|
|
u32 rss_hash_types_saved;
|
2024-05-03 20:24:40 +00:00
|
|
|
struct virtio_net_ctrl_rss rss;
|
2022-03-28 17:53:34 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* Has control virtqueue */
|
|
|
|
bool has_cvq;
|
|
|
|
|
2024-05-03 20:24:42 +00:00
|
|
|
/* Lock to protect the control VQ */
|
|
|
|
struct mutex cvq_lock;
|
|
|
|
|
2013-07-25 00:50:23 +00:00
|
|
|
/* Host can handle any s/g split between our header and packet data */
|
|
|
|
bool any_header_sg;
|
|
|
|
|
2014-10-24 13:55:57 +00:00
|
|
|
/* Packet virtio header size */
|
|
|
|
u8 hdr_len;
|
|
|
|
|
2022-07-25 07:21:59 +00:00
|
|
|
/* Work struct for delayed refilling if we run low on memory. */
|
2009-08-26 19:22:32 +00:00
|
|
|
struct delayed_work refill;
|
|
|
|
|
2022-07-25 07:21:59 +00:00
|
|
|
/* Is delayed refill enabled? */
|
|
|
|
bool refill_enabled;
|
|
|
|
|
|
|
|
/* The lock to synchronize the access to refill_enabled */
|
|
|
|
spinlock_t refill_lock;
|
|
|
|
|
2012-04-11 20:43:52 +00:00
|
|
|
/* Work struct for config space updates */
|
|
|
|
struct work_struct config_work;
|
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
/* Work struct for setting rx mode */
|
|
|
|
struct work_struct rx_mode_work;
|
|
|
|
|
|
|
|
/* OK to queue work setting RX mode? */
|
|
|
|
bool rx_mode_work_enabled;
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* Does the affinity hint is set for virtqueues? */
|
|
|
|
bool affinity_hint_set;
|
2013-01-24 23:51:29 +00:00
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
/* CPU hotplug instances for online & dead */
|
|
|
|
struct hlist_node node;
|
|
|
|
struct hlist_node node_dead;
|
2015-11-15 13:11:00 +00:00
|
|
|
|
2018-04-19 05:30:48 +00:00
|
|
|
struct control_buf *ctrl;
|
2016-02-03 03:04:37 +00:00
|
|
|
|
|
|
|
/* Ethtool settings */
|
|
|
|
u8 duplex;
|
|
|
|
u32 speed;
|
2017-07-19 08:54:49 +00:00
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
/* Is rx dynamic interrupt moderation enabled? */
|
|
|
|
bool rx_dim_enabled;
|
|
|
|
|
2022-07-18 09:11:02 +00:00
|
|
|
/* Interrupt coalescing settings */
|
2023-07-31 07:06:54 +00:00
|
|
|
struct virtnet_interrupt_coalesce intr_coal_tx;
|
|
|
|
struct virtnet_interrupt_coalesce intr_coal_rx;
|
2022-07-18 09:11:02 +00:00
|
|
|
|
2017-07-19 08:54:49 +00:00
|
|
|
unsigned long guest_offloads;
|
2018-12-20 22:14:54 +00:00
|
|
|
unsigned long guest_offloads_capable;
|
2018-05-24 16:55:17 +00:00
|
|
|
|
|
|
|
/* failover when STANDBY feature enabled */
|
|
|
|
struct failover *failover;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
u64 device_stats_cap;
|
2007-10-22 01:03:37 +00:00
|
|
|
};
|
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
struct padded_vnet_hdr {
|
2022-03-28 17:53:33 +00:00
|
|
|
struct virtio_net_hdr_v1_hash hdr;
|
2010-01-29 03:20:04 +00:00
|
|
|
/*
|
2014-10-24 13:55:57 +00:00
|
|
|
* hdr is in a separate sg buffer, and data sg buffer shares same page
|
|
|
|
* with this header sg. This padding makes next sg 16 byte aligned
|
|
|
|
* after the header.
|
2010-01-29 03:20:04 +00:00
|
|
|
*/
|
2022-03-28 17:53:33 +00:00
|
|
|
char padding[12];
|
2010-01-29 03:20:04 +00:00
|
|
|
};
|
|
|
|
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
struct virtio_net_common_hdr {
|
|
|
|
union {
|
|
|
|
struct virtio_net_hdr hdr;
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf mrg_hdr;
|
|
|
|
struct virtio_net_hdr_v1_hash hash_v1_hdr;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2022-08-01 06:39:01 +00:00
|
|
|
static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf);
|
2024-07-08 11:25:36 +00:00
|
|
|
static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp,
|
|
|
|
struct net_device *dev,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats);
|
|
|
|
static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
struct sk_buff *skb, u8 flags);
|
2024-07-08 11:25:37 +00:00
|
|
|
static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
|
|
|
|
struct sk_buff *curr_skb,
|
|
|
|
struct page *page, void *buf,
|
|
|
|
int len, int truesize);
|
2022-08-01 06:39:00 +00:00
|
|
|
|
2019-01-29 00:45:59 +00:00
|
|
|
static bool is_xdp_frame(void *ptr)
|
|
|
|
{
|
|
|
|
return (unsigned long)ptr & VIRTIO_XDP_FLAG;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *xdp_to_ptr(struct xdp_frame *ptr)
|
|
|
|
{
|
|
|
|
return (void *)((unsigned long)ptr | VIRTIO_XDP_FLAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct xdp_frame *ptr_to_xdp(void *ptr)
|
|
|
|
{
|
|
|
|
return (struct xdp_frame *)((unsigned long)ptr & ~VIRTIO_XDP_FLAG);
|
|
|
|
}
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
static bool is_orphan_skb(void *ptr)
|
|
|
|
{
|
|
|
|
return (unsigned long)ptr & VIRTIO_ORPHAN_FLAG;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *skb_to_ptr(struct sk_buff *skb, bool orphan)
|
|
|
|
{
|
|
|
|
return (void *)((unsigned long)skb | (orphan ? VIRTIO_ORPHAN_FLAG : 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *ptr_to_skb(void *ptr)
|
|
|
|
{
|
|
|
|
return (struct sk_buff *)((unsigned long)ptr & ~VIRTIO_ORPHAN_FLAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __free_old_xmit(struct send_queue *sq, struct netdev_queue *txq,
|
|
|
|
bool in_napi, struct virtnet_sq_free_stats *stats)
|
2024-02-29 07:20:42 +00:00
|
|
|
{
|
|
|
|
unsigned int len;
|
|
|
|
void *ptr;
|
|
|
|
|
|
|
|
while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) {
|
|
|
|
if (!is_xdp_frame(ptr)) {
|
2024-06-18 14:44:56 +00:00
|
|
|
struct sk_buff *skb = ptr_to_skb(ptr);
|
2024-02-29 07:20:42 +00:00
|
|
|
|
|
|
|
pr_debug("Sent skb %p\n", skb);
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
if (is_orphan_skb(ptr)) {
|
|
|
|
stats->packets++;
|
|
|
|
stats->bytes += skb->len;
|
|
|
|
} else {
|
|
|
|
stats->napi_packets++;
|
|
|
|
stats->napi_bytes += skb->len;
|
|
|
|
}
|
2024-02-29 07:20:42 +00:00
|
|
|
napi_consume_skb(skb, in_napi);
|
|
|
|
} else {
|
|
|
|
struct xdp_frame *frame = ptr_to_xdp(ptr);
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
stats->packets++;
|
2024-02-29 07:20:42 +00:00
|
|
|
stats->bytes += xdp_get_frame_len(frame);
|
|
|
|
xdp_return_frame(frame);
|
|
|
|
}
|
|
|
|
}
|
2024-06-18 14:44:56 +00:00
|
|
|
netdev_tx_completed_queue(txq, stats->napi_packets, stats->napi_bytes);
|
2024-02-29 07:20:42 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* Converting between virtqueue no. and kernel tx/rx queue no.
|
|
|
|
* 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq
|
|
|
|
*/
|
|
|
|
static int vq2txq(struct virtqueue *vq)
|
|
|
|
{
|
2013-03-21 14:17:34 +00:00
|
|
|
return (vq->index - 1) / 2;
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int txq2vq(int txq)
|
|
|
|
{
|
|
|
|
return txq * 2 + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vq2rxq(struct virtqueue *vq)
|
|
|
|
{
|
2013-03-21 14:17:34 +00:00
|
|
|
return vq->index / 2;
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int rxq2vq(int rxq)
|
|
|
|
{
|
|
|
|
return rxq * 2;
|
|
|
|
}
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
static int vq_type(struct virtnet_info *vi, int qid)
|
|
|
|
{
|
|
|
|
if (qid == vi->max_queue_pairs * 2)
|
|
|
|
return VIRTNET_Q_TYPE_CQ;
|
|
|
|
|
|
|
|
if (qid % 2)
|
|
|
|
return VIRTNET_Q_TYPE_TX;
|
|
|
|
|
|
|
|
return VIRTNET_Q_TYPE_RX;
|
|
|
|
}
|
|
|
|
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
static inline struct virtio_net_common_hdr *
|
|
|
|
skb_vnet_common_hdr(struct sk_buff *skb)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
return (struct virtio_net_common_hdr *)skb->cb;
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
/*
|
|
|
|
* private is used to chain pages for big packets, put the whole
|
|
|
|
* most recent used list in the beginning for reuse
|
|
|
|
*/
|
2012-12-07 07:04:55 +00:00
|
|
|
static void give_pages(struct receive_queue *rq, struct page *page)
|
2008-11-17 06:39:18 +00:00
|
|
|
{
|
2010-01-29 03:20:04 +00:00
|
|
|
struct page *end;
|
2008-11-17 06:39:18 +00:00
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
/* Find end of list, sew whole thing into vi->rq.pages. */
|
2010-01-29 03:20:04 +00:00
|
|
|
for (end = page; end->private; end = (struct page *)end->private);
|
2012-12-07 07:04:55 +00:00
|
|
|
end->private = (unsigned long)rq->pages;
|
|
|
|
rq->pages = page;
|
2008-11-17 06:39:18 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask)
|
2008-07-25 17:06:01 +00:00
|
|
|
{
|
2012-12-07 07:04:55 +00:00
|
|
|
struct page *p = rq->pages;
|
2008-07-25 17:06:01 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
if (p) {
|
2012-12-07 07:04:55 +00:00
|
|
|
rq->pages = (struct page *)p->private;
|
2010-01-29 03:20:04 +00:00
|
|
|
/* clear private here, it is used to chain pages */
|
|
|
|
p->private = 0;
|
|
|
|
} else
|
2008-07-25 17:06:01 +00:00
|
|
|
p = alloc_page(gfp_mask);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2023-12-26 09:43:33 +00:00
|
|
|
static void virtnet_rq_free_buf(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq, void *buf)
|
|
|
|
{
|
|
|
|
if (vi->mergeable_rx_bufs)
|
|
|
|
put_page(virt_to_head_page(buf));
|
|
|
|
else if (vi->big_packets)
|
|
|
|
give_pages(rq, buf);
|
|
|
|
else
|
|
|
|
put_page(virt_to_head_page(buf));
|
|
|
|
}
|
|
|
|
|
2022-07-25 07:21:59 +00:00
|
|
|
static void enable_delayed_refill(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
spin_lock_bh(&vi->refill_lock);
|
|
|
|
vi->refill_enabled = true;
|
|
|
|
spin_unlock_bh(&vi->refill_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disable_delayed_refill(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
spin_lock_bh(&vi->refill_lock);
|
|
|
|
vi->refill_enabled = false;
|
|
|
|
spin_unlock_bh(&vi->refill_lock);
|
|
|
|
}
|
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
static void enable_rx_mode_work(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
rtnl_lock();
|
|
|
|
vi->rx_mode_work_enabled = true;
|
|
|
|
rtnl_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disable_rx_mode_work(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
rtnl_lock();
|
|
|
|
vi->rx_mode_work_enabled = false;
|
|
|
|
rtnl_unlock();
|
|
|
|
}
|
|
|
|
|
2017-04-24 17:49:26 +00:00
|
|
|
static void virtqueue_napi_schedule(struct napi_struct *napi,
|
|
|
|
struct virtqueue *vq)
|
|
|
|
{
|
|
|
|
if (napi_schedule_prep(napi)) {
|
|
|
|
virtqueue_disable_cb(vq);
|
|
|
|
__napi_schedule(napi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:04 +00:00
|
|
|
static bool virtqueue_napi_complete(struct napi_struct *napi,
|
2017-04-24 17:49:26 +00:00
|
|
|
struct virtqueue *vq, int processed)
|
|
|
|
{
|
|
|
|
int opaque;
|
|
|
|
|
|
|
|
opaque = virtqueue_enable_cb_prepare(vq);
|
2017-12-07 04:15:15 +00:00
|
|
|
if (napi_complete_done(napi, processed)) {
|
|
|
|
if (unlikely(virtqueue_poll(vq, opaque)))
|
|
|
|
virtqueue_napi_schedule(napi, vq);
|
2023-12-11 10:36:04 +00:00
|
|
|
else
|
|
|
|
return true;
|
2017-12-07 04:15:15 +00:00
|
|
|
} else {
|
|
|
|
virtqueue_disable_cb(vq);
|
|
|
|
}
|
2023-12-11 10:36:04 +00:00
|
|
|
|
|
|
|
return false;
|
2017-04-24 17:49:26 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
static void skb_xmit_done(struct virtqueue *vq)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
2012-12-07 07:04:55 +00:00
|
|
|
struct virtnet_info *vi = vq->vdev->priv;
|
2017-04-24 17:49:27 +00:00
|
|
|
struct napi_struct *napi = &vi->sq[vq2txq(vq)].napi;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2008-02-05 04:50:07 +00:00
|
|
|
/* Suppress further interrupts. */
|
2012-12-07 07:04:55 +00:00
|
|
|
virtqueue_disable_cb(vq);
|
2008-05-26 07:48:13 +00:00
|
|
|
|
2017-04-24 17:49:27 +00:00
|
|
|
if (napi->weight)
|
|
|
|
virtqueue_napi_schedule(napi, vq);
|
|
|
|
else
|
|
|
|
/* We were probably waiting for more output buffers. */
|
|
|
|
netif_wake_subqueue(vi->dev, vq2txq(vq));
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-07-19 08:54:46 +00:00
|
|
|
#define MRG_CTX_HEADER_SHIFT 22
|
|
|
|
static void *mergeable_len_to_ctx(unsigned int truesize,
|
|
|
|
unsigned int headroom)
|
|
|
|
{
|
|
|
|
return (void *)(unsigned long)((headroom << MRG_CTX_HEADER_SHIFT) | truesize);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int mergeable_ctx_to_headroom(void *mrg_ctx)
|
|
|
|
{
|
|
|
|
return (unsigned long)mrg_ctx >> MRG_CTX_HEADER_SHIFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int mergeable_ctx_to_truesize(void *mrg_ctx)
|
|
|
|
{
|
|
|
|
return (unsigned long)mrg_ctx & ((1 << MRG_CTX_HEADER_SHIFT) - 1);
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:17 +00:00
|
|
|
static struct sk_buff *virtnet_build_skb(void *buf, unsigned int buflen,
|
|
|
|
unsigned int headroom,
|
|
|
|
unsigned int len)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
skb = build_skb(buf, buflen);
|
|
|
|
if (unlikely(!skb))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
skb_reserve(skb, headroom);
|
|
|
|
skb_put(skb, len);
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2012-01-04 12:52:32 +00:00
|
|
|
/* Called from bottom half context */
|
2014-10-23 21:12:10 +00:00
|
|
|
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
2013-10-28 22:44:18 +00:00
|
|
|
struct page *page, unsigned int offset,
|
2023-03-15 01:52:22 +00:00
|
|
|
unsigned int len, unsigned int truesize,
|
|
|
|
unsigned int headroom)
|
2010-01-29 03:20:04 +00:00
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
struct virtio_net_common_hdr *hdr;
|
2013-10-28 22:44:18 +00:00
|
|
|
unsigned int copy, hdr_len, hdr_padded_len;
|
2021-04-20 09:43:41 +00:00
|
|
|
struct page *page_to_free = NULL;
|
2021-04-16 09:16:15 +00:00
|
|
|
int tailroom, shinfo_size;
|
2021-04-22 15:16:20 +00:00
|
|
|
char *p, *hdr_p, *buf;
|
2008-07-25 17:06:01 +00:00
|
|
|
|
2013-10-28 22:44:18 +00:00
|
|
|
p = page_address(page) + offset;
|
2021-04-16 09:16:15 +00:00
|
|
|
hdr_p = p;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2014-10-24 13:55:57 +00:00
|
|
|
hdr_len = vi->hdr_len;
|
|
|
|
if (vi->mergeable_rx_bufs)
|
2022-03-28 17:53:33 +00:00
|
|
|
hdr_padded_len = hdr_len;
|
2014-10-24 13:55:57 +00:00
|
|
|
else
|
2013-10-28 22:44:18 +00:00
|
|
|
hdr_padded_len = sizeof(struct padded_vnet_hdr);
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2023-03-15 01:52:22 +00:00
|
|
|
buf = p - headroom;
|
2010-01-29 03:20:04 +00:00
|
|
|
len -= hdr_len;
|
2013-10-28 22:44:18 +00:00
|
|
|
offset += hdr_padded_len;
|
|
|
|
p += hdr_padded_len;
|
2023-03-15 01:52:22 +00:00
|
|
|
tailroom = truesize - headroom - hdr_padded_len - len;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2021-04-16 09:16:15 +00:00
|
|
|
shinfo_size = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
|
|
|
|
2021-04-20 20:01:44 +00:00
|
|
|
if (!NET_IP_ALIGN && len > GOOD_COPY_LEN && tailroom >= shinfo_size) {
|
2023-05-08 06:14:17 +00:00
|
|
|
skb = virtnet_build_skb(buf, truesize, p - buf, len);
|
2021-04-16 09:16:15 +00:00
|
|
|
if (unlikely(!skb))
|
|
|
|
return NULL;
|
|
|
|
|
2021-09-17 08:34:06 +00:00
|
|
|
page = (struct page *)page->private;
|
|
|
|
if (page)
|
|
|
|
give_pages(rq, page);
|
2021-04-16 09:16:15 +00:00
|
|
|
goto ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy small packet so we can reuse these pages for small data */
|
|
|
|
skb = napi_alloc_skb(&rq->napi, GOOD_COPY_LEN);
|
|
|
|
if (unlikely(!skb))
|
|
|
|
return NULL;
|
|
|
|
|
2021-04-02 13:26:02 +00:00
|
|
|
/* Copy all frame if it fits skb->head, otherwise
|
|
|
|
* we let virtio_net_hdr_to_skb() and GRO pull headers as needed.
|
|
|
|
*/
|
|
|
|
if (len <= skb_tailroom(skb))
|
|
|
|
copy = len;
|
|
|
|
else
|
2023-01-14 08:22:28 +00:00
|
|
|
copy = ETH_HLEN;
|
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 12:29:20 +00:00
|
|
|
skb_put_data(skb, p, copy);
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
len -= copy;
|
|
|
|
offset += copy;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2013-10-28 22:44:18 +00:00
|
|
|
if (vi->mergeable_rx_bufs) {
|
|
|
|
if (len)
|
|
|
|
skb_add_rx_frag(skb, 0, page, offset, len, truesize);
|
|
|
|
else
|
2021-04-20 09:43:41 +00:00
|
|
|
page_to_free = page;
|
2021-04-16 09:16:15 +00:00
|
|
|
goto ok;
|
2013-10-28 22:44:18 +00:00
|
|
|
}
|
|
|
|
|
2011-09-28 04:40:54 +00:00
|
|
|
/*
|
|
|
|
* Verify that we can indeed put this data into a skb.
|
|
|
|
* This is here to handle cases when the device erroneously
|
|
|
|
* tries to receive more than is possible. This is usually
|
|
|
|
* the case of a broken device.
|
|
|
|
*/
|
|
|
|
if (unlikely(len > MAX_SKB_FRAGS * PAGE_SIZE)) {
|
2012-11-08 17:47:28 +00:00
|
|
|
net_dbg_ratelimited("%s: too much data\n", skb->dev->name);
|
2011-09-28 04:40:54 +00:00
|
|
|
dev_kfree_skb(skb);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-10-28 22:44:18 +00:00
|
|
|
BUG_ON(offset >= PAGE_SIZE);
|
2010-01-29 03:20:04 +00:00
|
|
|
while (len) {
|
2013-10-28 22:44:18 +00:00
|
|
|
unsigned int frag_size = min((unsigned)PAGE_SIZE - offset, len);
|
|
|
|
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset,
|
|
|
|
frag_size, truesize);
|
|
|
|
len -= frag_size;
|
2010-01-29 03:20:04 +00:00
|
|
|
page = (struct page *)page->private;
|
|
|
|
offset = 0;
|
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
if (page)
|
2012-12-07 07:04:55 +00:00
|
|
|
give_pages(rq, page);
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2021-04-16 09:16:15 +00:00
|
|
|
ok:
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
hdr = skb_vnet_common_hdr(skb);
|
2023-01-14 08:22:28 +00:00
|
|
|
memcpy(hdr, hdr_p, hdr_len);
|
2021-04-20 09:43:41 +00:00
|
|
|
if (page_to_free)
|
|
|
|
put_page(page_to_free);
|
2021-04-16 09:16:15 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
return skb;
|
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2023-08-10 12:30:57 +00:00
|
|
|
static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len)
|
|
|
|
{
|
|
|
|
struct page *page = virt_to_head_page(buf);
|
|
|
|
struct virtnet_rq_dma *dma;
|
|
|
|
void *head;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
head = page_address(page);
|
|
|
|
|
|
|
|
dma = head;
|
|
|
|
|
|
|
|
--dma->ref;
|
|
|
|
|
2023-09-27 05:52:46 +00:00
|
|
|
if (dma->need_sync && len) {
|
|
|
|
offset = buf - (head + sizeof(*dma));
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2023-09-27 05:52:46 +00:00
|
|
|
virtqueue_dma_sync_single_range_for_cpu(rq->vq, dma->addr,
|
|
|
|
offset, len,
|
|
|
|
DMA_FROM_DEVICE);
|
|
|
|
}
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2023-09-27 05:52:46 +00:00
|
|
|
if (dma->ref)
|
2023-08-10 12:30:57 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
virtqueue_dma_unmap_single_attrs(rq->vq, dma->addr, dma->len,
|
|
|
|
DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
|
|
|
|
put_page(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx)
|
|
|
|
{
|
|
|
|
void *buf;
|
|
|
|
|
|
|
|
buf = virtqueue_get_buf_ctx(rq->vq, len, ctx);
|
2024-09-06 12:31:35 +00:00
|
|
|
if (buf && rq->do_dma)
|
2023-08-10 12:30:57 +00:00
|
|
|
virtnet_rq_unmap(rq, buf, *len);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len)
|
|
|
|
{
|
|
|
|
struct virtnet_rq_dma *dma;
|
|
|
|
dma_addr_t addr;
|
|
|
|
u32 offset;
|
|
|
|
void *head;
|
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
if (!rq->do_dma) {
|
|
|
|
sg_init_one(rq->sg, buf, len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-10 12:30:57 +00:00
|
|
|
head = page_address(rq->alloc_frag.page);
|
|
|
|
|
|
|
|
offset = buf - head;
|
|
|
|
|
|
|
|
dma = head;
|
|
|
|
|
|
|
|
addr = dma->addr - sizeof(*dma) + offset;
|
|
|
|
|
|
|
|
sg_init_table(rq->sg, 1);
|
|
|
|
rq->sg[0].dma_address = addr;
|
|
|
|
rq->sg[0].length = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct page_frag *alloc_frag = &rq->alloc_frag;
|
|
|
|
struct virtnet_rq_dma *dma;
|
|
|
|
void *buf, *head;
|
|
|
|
dma_addr_t addr;
|
|
|
|
|
|
|
|
if (unlikely(!skb_page_frag_refill(size, alloc_frag, gfp)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
head = page_address(alloc_frag->page);
|
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
if (rq->do_dma) {
|
|
|
|
dma = head;
|
|
|
|
|
|
|
|
/* new pages */
|
|
|
|
if (!alloc_frag->offset) {
|
|
|
|
if (rq->last_dma) {
|
|
|
|
/* Now, the new page is allocated, the last dma
|
|
|
|
* will not be used. So the dma can be unmapped
|
|
|
|
* if the ref is 0.
|
|
|
|
*/
|
|
|
|
virtnet_rq_unmap(rq, rq->last_dma, 0);
|
|
|
|
rq->last_dma = NULL;
|
|
|
|
}
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
dma->len = alloc_frag->size - sizeof(*dma);
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1,
|
|
|
|
dma->len, DMA_FROM_DEVICE, 0);
|
|
|
|
if (virtqueue_dma_mapping_error(rq->vq, addr))
|
|
|
|
return NULL;
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
dma->addr = addr;
|
|
|
|
dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr);
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
/* Add a reference to dma to prevent the entire dma from
|
|
|
|
* being released during error handling. This reference
|
|
|
|
* will be freed after the pages are no longer used.
|
|
|
|
*/
|
|
|
|
get_page(alloc_frag->page);
|
|
|
|
dma->ref = 1;
|
|
|
|
alloc_frag->offset = sizeof(*dma);
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
rq->last_dma = dma;
|
|
|
|
}
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2024-09-06 12:31:35 +00:00
|
|
|
++dma->ref;
|
2023-08-10 12:30:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
buf = head + alloc_frag->offset;
|
|
|
|
|
|
|
|
get_page(alloc_frag->page);
|
|
|
|
alloc_frag->offset += size;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2023-12-26 09:43:33 +00:00
|
|
|
static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vq->vdev->priv;
|
|
|
|
struct receive_queue *rq;
|
|
|
|
int i = vq2rxq(vq);
|
|
|
|
|
|
|
|
rq = &vi->rq[i];
|
|
|
|
|
2024-07-08 11:25:37 +00:00
|
|
|
if (rq->xsk_pool) {
|
|
|
|
xsk_buff_free((struct xdp_buff *)buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-09-06 12:31:36 +00:00
|
|
|
if (rq->do_dma)
|
2023-12-26 09:43:33 +00:00
|
|
|
virtnet_rq_unmap(rq, buf, 0);
|
|
|
|
|
|
|
|
virtnet_rq_free_buf(vi, rq, buf);
|
|
|
|
}
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
static void free_old_xmit(struct send_queue *sq, struct netdev_queue *txq,
|
|
|
|
bool in_napi)
|
2023-03-08 02:49:33 +00:00
|
|
|
{
|
2024-02-29 07:20:42 +00:00
|
|
|
struct virtnet_sq_free_stats stats = {0};
|
2023-03-08 02:49:33 +00:00
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
__free_old_xmit(sq, txq, in_napi, &stats);
|
2023-03-08 02:49:33 +00:00
|
|
|
|
|
|
|
/* Avoid overhead when no packets have been processed
|
|
|
|
* happens when called speculatively from start_xmit.
|
|
|
|
*/
|
2024-06-18 14:44:56 +00:00
|
|
|
if (!stats.packets && !stats.napi_packets)
|
2023-03-08 02:49:33 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
2024-06-18 14:44:56 +00:00
|
|
|
u64_stats_add(&sq->stats.bytes, stats.bytes + stats.napi_bytes);
|
|
|
|
u64_stats_add(&sq->stats.packets, stats.packets + stats.napi_packets);
|
2023-03-08 02:49:33 +00:00
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_xdp_raw_buffer_queue(struct virtnet_info *vi, int q)
|
|
|
|
{
|
|
|
|
if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs))
|
|
|
|
return false;
|
|
|
|
else if (q < vi->curr_queue_pairs)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-03-08 02:49:34 +00:00
|
|
|
static void check_sq_full_and_disable(struct virtnet_info *vi,
|
|
|
|
struct net_device *dev,
|
|
|
|
struct send_queue *sq)
|
|
|
|
{
|
|
|
|
bool use_napi = sq->napi.weight;
|
|
|
|
int qnum;
|
|
|
|
|
|
|
|
qnum = sq - vi->sq;
|
|
|
|
|
|
|
|
/* If running out of space, stop queue to avoid getting packets that we
|
|
|
|
* are then unable to transmit.
|
|
|
|
* An alternative would be to force queuing layer to requeue the skb by
|
|
|
|
* returning NETDEV_TX_BUSY. However, NETDEV_TX_BUSY should not be
|
|
|
|
* returned in a normal path of operation: it means that driver is not
|
|
|
|
* maintaining the TX queue stop/start state properly, and causes
|
|
|
|
* the stack to do a non-trivial amount of useless work.
|
|
|
|
* Since most packets only take 1 or 2 ring slots, stopping the queue
|
|
|
|
* early means 16 slots are typically wasted.
|
|
|
|
*/
|
|
|
|
if (sq->vq->num_free < 2+MAX_SKB_FRAGS) {
|
2024-06-18 14:44:56 +00:00
|
|
|
struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
|
|
|
|
|
|
|
|
netif_tx_stop_queue(txq);
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
|
|
|
u64_stats_inc(&sq->stats.stop);
|
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
2023-03-08 02:49:34 +00:00
|
|
|
if (use_napi) {
|
|
|
|
if (unlikely(!virtqueue_enable_cb_delayed(sq->vq)))
|
|
|
|
virtqueue_napi_schedule(&sq->napi, sq->vq);
|
|
|
|
} else if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) {
|
|
|
|
/* More just got used, free them then recheck. */
|
2024-06-18 14:44:56 +00:00
|
|
|
free_old_xmit(sq, txq, false);
|
2023-03-08 02:49:34 +00:00
|
|
|
if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) {
|
|
|
|
netif_start_subqueue(dev, qnum);
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
|
|
|
u64_stats_inc(&sq->stats.wake);
|
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
2023-03-08 02:49:34 +00:00
|
|
|
virtqueue_disable_cb(sq->vq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:35 +00:00
|
|
|
static void sg_fill_dma(struct scatterlist *sg, dma_addr_t addr, u32 len)
|
|
|
|
{
|
|
|
|
sg->dma_address = addr;
|
|
|
|
sg->length = len;
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:36 +00:00
|
|
|
static struct xdp_buff *buf_to_xdp(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq, void *buf, u32 len)
|
|
|
|
{
|
|
|
|
struct xdp_buff *xdp;
|
|
|
|
u32 bufsize;
|
|
|
|
|
|
|
|
xdp = (struct xdp_buff *)buf;
|
|
|
|
|
|
|
|
bufsize = xsk_pool_get_rx_frame_size(rq->xsk_pool) + vi->hdr_len;
|
|
|
|
|
|
|
|
if (unlikely(len > bufsize)) {
|
|
|
|
pr_debug("%s: rx error: len %u exceeds truesize %u\n",
|
|
|
|
vi->dev->name, len, bufsize);
|
|
|
|
DEV_STATS_INC(vi->dev, rx_length_errors);
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
xsk_buff_set_size(xdp, len);
|
|
|
|
xsk_buff_dma_sync_for_cpu(xdp);
|
|
|
|
|
|
|
|
return xdp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *xsk_construct_skb(struct receive_queue *rq,
|
|
|
|
struct xdp_buff *xdp)
|
|
|
|
{
|
|
|
|
unsigned int metasize = xdp->data - xdp->data_meta;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
unsigned int size;
|
|
|
|
|
|
|
|
size = xdp->data_end - xdp->data_hard_start;
|
|
|
|
skb = napi_alloc_skb(&rq->napi, size);
|
|
|
|
if (unlikely(!skb)) {
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb_reserve(skb, xdp->data_meta - xdp->data_hard_start);
|
|
|
|
|
|
|
|
size = xdp->data_end - xdp->data_meta;
|
|
|
|
memcpy(__skb_put(skb, size), xdp->data_meta, size);
|
|
|
|
|
|
|
|
if (metasize) {
|
|
|
|
__skb_pull(skb, metasize);
|
|
|
|
skb_metadata_set(skb, metasize);
|
|
|
|
}
|
|
|
|
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *virtnet_receive_xsk_small(struct net_device *dev, struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq, struct xdp_buff *xdp,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct bpf_prog *prog;
|
|
|
|
u32 ret;
|
|
|
|
|
|
|
|
ret = XDP_PASS;
|
|
|
|
rcu_read_lock();
|
|
|
|
prog = rcu_dereference(rq->xdp_prog);
|
|
|
|
if (prog)
|
|
|
|
ret = virtnet_xdp_handler(prog, xdp, dev, xdp_xmit, stats);
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case XDP_PASS:
|
|
|
|
return xsk_construct_skb(rq, xdp);
|
|
|
|
|
|
|
|
case XDP_TX:
|
|
|
|
case XDP_REDIRECT:
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* drop packet */
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
u64_stats_inc(&stats->drops);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:37 +00:00
|
|
|
static void xsk_drop_follow_bufs(struct net_device *dev,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
u32 num_buf,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct xdp_buff *xdp;
|
|
|
|
u32 len;
|
|
|
|
|
|
|
|
while (num_buf-- > 1) {
|
|
|
|
xdp = virtqueue_get_buf(rq->vq, &len);
|
|
|
|
if (unlikely(!xdp)) {
|
|
|
|
pr_debug("%s: rx error: %d buffers missing\n",
|
|
|
|
dev->name, num_buf);
|
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
u64_stats_add(&stats->bytes, len);
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xsk_append_merge_buffer(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
struct sk_buff *head_skb,
|
|
|
|
u32 num_buf,
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct sk_buff *curr_skb;
|
|
|
|
struct xdp_buff *xdp;
|
|
|
|
u32 len, truesize;
|
|
|
|
struct page *page;
|
|
|
|
void *buf;
|
|
|
|
|
|
|
|
curr_skb = head_skb;
|
|
|
|
|
|
|
|
while (--num_buf) {
|
|
|
|
buf = virtqueue_get_buf(rq->vq, &len);
|
|
|
|
if (unlikely(!buf)) {
|
|
|
|
pr_debug("%s: rx error: %d buffers out of %d missing\n",
|
|
|
|
vi->dev->name, num_buf,
|
|
|
|
virtio16_to_cpu(vi->vdev,
|
|
|
|
hdr->num_buffers));
|
|
|
|
DEV_STATS_INC(vi->dev, rx_length_errors);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64_stats_add(&stats->bytes, len);
|
|
|
|
|
|
|
|
xdp = buf_to_xdp(vi, rq, buf, len);
|
|
|
|
if (!xdp)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
buf = napi_alloc_frag(len);
|
|
|
|
if (!buf) {
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf, xdp->data - vi->hdr_len, len);
|
|
|
|
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
|
|
|
|
page = virt_to_page(buf);
|
|
|
|
|
|
|
|
truesize = len;
|
|
|
|
|
|
|
|
curr_skb = virtnet_skb_append_frag(head_skb, curr_skb, page,
|
|
|
|
buf, len, truesize);
|
|
|
|
if (!curr_skb) {
|
|
|
|
put_page(page);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
xsk_drop_follow_bufs(vi->dev, rq, num_buf, stats);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *virtnet_receive_xsk_merge(struct net_device *dev, struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq, struct xdp_buff *xdp,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr;
|
|
|
|
struct bpf_prog *prog;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
u32 ret, num_buf;
|
|
|
|
|
|
|
|
hdr = xdp->data - vi->hdr_len;
|
|
|
|
num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
|
|
|
|
|
|
|
|
ret = XDP_PASS;
|
|
|
|
rcu_read_lock();
|
|
|
|
prog = rcu_dereference(rq->xdp_prog);
|
|
|
|
/* TODO: support multi buffer. */
|
|
|
|
if (prog && num_buf == 1)
|
|
|
|
ret = virtnet_xdp_handler(prog, xdp, dev, xdp_xmit, stats);
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
switch (ret) {
|
|
|
|
case XDP_PASS:
|
|
|
|
skb = xsk_construct_skb(rq, xdp);
|
|
|
|
if (!skb)
|
|
|
|
goto drop_bufs;
|
|
|
|
|
|
|
|
if (xsk_append_merge_buffer(vi, rq, skb, num_buf, hdr, stats)) {
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
|
|
|
|
case XDP_TX:
|
|
|
|
case XDP_REDIRECT:
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* drop packet */
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
}
|
|
|
|
|
|
|
|
drop_bufs:
|
|
|
|
xsk_drop_follow_bufs(dev, rq, num_buf, stats);
|
|
|
|
|
|
|
|
drop:
|
|
|
|
u64_stats_inc(&stats->drops);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:36 +00:00
|
|
|
static void virtnet_receive_xsk_buf(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
void *buf, u32 len,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct net_device *dev = vi->dev;
|
|
|
|
struct sk_buff *skb = NULL;
|
|
|
|
struct xdp_buff *xdp;
|
|
|
|
u8 flags;
|
|
|
|
|
|
|
|
len -= vi->hdr_len;
|
|
|
|
|
|
|
|
u64_stats_add(&stats->bytes, len);
|
|
|
|
|
|
|
|
xdp = buf_to_xdp(vi, rq, buf, len);
|
|
|
|
if (!xdp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (unlikely(len < ETH_HLEN)) {
|
|
|
|
pr_debug("%s: short packet %i\n", dev->name, len);
|
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
|
|
|
xsk_buff_free(xdp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = ((struct virtio_net_common_hdr *)(xdp->data - vi->hdr_len))->hdr.flags;
|
|
|
|
|
|
|
|
if (!vi->mergeable_rx_bufs)
|
|
|
|
skb = virtnet_receive_xsk_small(dev, vi, rq, xdp, xdp_xmit, stats);
|
2024-07-08 11:25:37 +00:00
|
|
|
else
|
|
|
|
skb = virtnet_receive_xsk_merge(dev, vi, rq, xdp, xdp_xmit, stats);
|
2024-07-08 11:25:36 +00:00
|
|
|
|
|
|
|
if (skb)
|
|
|
|
virtnet_receive_done(vi, rq, skb, flags);
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:35 +00:00
|
|
|
static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
struct xsk_buff_pool *pool, gfp_t gfp)
|
|
|
|
{
|
|
|
|
struct xdp_buff **xsk_buffs;
|
|
|
|
dma_addr_t addr;
|
|
|
|
int err = 0;
|
|
|
|
u32 len, i;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
xsk_buffs = rq->xsk_buffs;
|
|
|
|
|
|
|
|
num = xsk_buff_alloc_batch(pool, xsk_buffs, rq->vq->num_free);
|
|
|
|
if (!num)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
len = xsk_pool_get_rx_frame_size(pool) + vi->hdr_len;
|
|
|
|
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
/* Use the part of XDP_PACKET_HEADROOM as the virtnet hdr space.
|
|
|
|
* We assume XDP_PACKET_HEADROOM is larger than hdr->len.
|
|
|
|
* (see function virtnet_xsk_pool_enable)
|
|
|
|
*/
|
|
|
|
addr = xsk_buff_xdp_get_dma(xsk_buffs[i]) - vi->hdr_len;
|
|
|
|
|
|
|
|
sg_init_table(rq->sg, 1);
|
|
|
|
sg_fill_dma(rq->sg, addr, len);
|
|
|
|
|
|
|
|
err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, xsk_buffs[i], gfp);
|
|
|
|
if (err)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return num;
|
|
|
|
|
|
|
|
err:
|
|
|
|
for (; i < num; ++i)
|
|
|
|
xsk_buff_free(xsk_buffs[i]);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:34 +00:00
|
|
|
static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
struct send_queue *sq;
|
|
|
|
|
|
|
|
if (!netif_running(dev))
|
|
|
|
return -ENETDOWN;
|
|
|
|
|
|
|
|
if (qid >= vi->curr_queue_pairs)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
sq = &vi->sq[qid];
|
|
|
|
|
|
|
|
if (napi_if_scheduled_mark_missed(&sq->napi))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
local_bh_disable();
|
|
|
|
virtqueue_napi_schedule(&sq->napi, sq->vq);
|
|
|
|
local_bh_enable();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
|
|
|
|
struct send_queue *sq,
|
|
|
|
struct xdp_frame *xdpf)
|
2016-12-15 20:14:13 +00:00
|
|
|
{
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr;
|
2023-01-14 08:22:26 +00:00
|
|
|
struct skb_shared_info *shinfo;
|
|
|
|
u8 nr_frags = 0;
|
|
|
|
int err, i;
|
2016-12-15 20:14:13 +00:00
|
|
|
|
2018-04-17 14:45:52 +00:00
|
|
|
if (unlikely(xdpf->headroom < vi->hdr_len))
|
|
|
|
return -EOVERFLOW;
|
|
|
|
|
2023-01-14 08:22:26 +00:00
|
|
|
if (unlikely(xdp_frame_has_frags(xdpf))) {
|
|
|
|
shinfo = xdp_get_shared_info_from_frame(xdpf);
|
|
|
|
nr_frags = shinfo->nr_frags;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In wrapping function virtnet_xdp_xmit(), we need to free
|
|
|
|
* up the pending old buffers, where we need to calculate the
|
|
|
|
* position of skb_shared_info in xdp_get_frame_len() and
|
|
|
|
* xdp_return_frame(), which will involve to xdpf->data and
|
|
|
|
* xdpf->headroom. Therefore, we need to update the value of
|
|
|
|
* headroom synchronously here.
|
|
|
|
*/
|
|
|
|
xdpf->headroom -= vi->hdr_len;
|
2018-04-17 14:45:52 +00:00
|
|
|
xdpf->data -= vi->hdr_len;
|
2017-02-21 08:46:28 +00:00
|
|
|
/* Zero header and leave csum up to XDP layers */
|
2018-04-17 14:45:52 +00:00
|
|
|
hdr = xdpf->data;
|
2017-02-21 08:46:28 +00:00
|
|
|
memset(hdr, 0, vi->hdr_len);
|
2018-04-17 14:45:52 +00:00
|
|
|
xdpf->len += vi->hdr_len;
|
2016-12-23 14:37:32 +00:00
|
|
|
|
2023-01-14 08:22:26 +00:00
|
|
|
sg_init_table(sq->sg, nr_frags + 1);
|
|
|
|
sg_set_buf(sq->sg, xdpf->data, xdpf->len);
|
|
|
|
for (i = 0; i < nr_frags; i++) {
|
|
|
|
skb_frag_t *frag = &shinfo->frags[i];
|
|
|
|
|
|
|
|
sg_set_page(&sq->sg[i + 1], skb_frag_page(frag),
|
|
|
|
skb_frag_size(frag), skb_frag_off(frag));
|
|
|
|
}
|
2016-12-23 14:37:32 +00:00
|
|
|
|
2023-01-14 08:22:26 +00:00
|
|
|
err = virtqueue_add_outbuf(sq->vq, sq->sg, nr_frags + 1,
|
|
|
|
xdp_to_ptr(xdpf), GFP_ATOMIC);
|
2018-02-20 13:32:15 +00:00
|
|
|
if (unlikely(err))
|
2018-04-17 14:45:52 +00:00
|
|
|
return -ENOSPC; /* Caller handle free/refcnt */
|
2016-12-15 20:14:13 +00:00
|
|
|
|
2018-04-17 14:45:52 +00:00
|
|
|
return 0;
|
2016-12-15 20:14:13 +00:00
|
|
|
}
|
|
|
|
|
2021-03-10 02:24:45 +00:00
|
|
|
/* when vi->curr_queue_pairs > nr_cpu_ids, the txq/sq is only used for xdp tx on
|
|
|
|
* the current cpu, so it does not need to be locked.
|
|
|
|
*
|
|
|
|
* Here we use marco instead of inline functions because we have to deal with
|
|
|
|
* three issues at the same time: 1. the choice of sq. 2. judge and execute the
|
|
|
|
* lock/unlock of txq 3. make sparse happy. It is difficult for two inline
|
|
|
|
* functions to perfectly solve these three problems at the same time.
|
|
|
|
*/
|
|
|
|
#define virtnet_xdp_get_sq(vi) ({ \
|
2021-08-26 08:21:35 +00:00
|
|
|
int cpu = smp_processor_id(); \
|
2021-03-10 02:24:45 +00:00
|
|
|
struct netdev_queue *txq; \
|
|
|
|
typeof(vi) v = (vi); \
|
|
|
|
unsigned int qp; \
|
|
|
|
\
|
|
|
|
if (v->curr_queue_pairs > nr_cpu_ids) { \
|
|
|
|
qp = v->curr_queue_pairs - v->xdp_queue_pairs; \
|
2021-08-26 08:21:35 +00:00
|
|
|
qp += cpu; \
|
2021-03-10 02:24:45 +00:00
|
|
|
txq = netdev_get_tx_queue(v->dev, qp); \
|
|
|
|
__netif_tx_acquire(txq); \
|
|
|
|
} else { \
|
2021-08-26 08:21:35 +00:00
|
|
|
qp = cpu % v->curr_queue_pairs; \
|
2021-03-10 02:24:45 +00:00
|
|
|
txq = netdev_get_tx_queue(v->dev, qp); \
|
2021-08-26 08:21:35 +00:00
|
|
|
__netif_tx_lock(txq, cpu); \
|
2021-03-10 02:24:45 +00:00
|
|
|
} \
|
|
|
|
v->sq + qp; \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define virtnet_xdp_put_sq(vi, q) { \
|
|
|
|
struct netdev_queue *txq; \
|
|
|
|
typeof(vi) v = (vi); \
|
|
|
|
\
|
|
|
|
txq = netdev_get_tx_queue(v->dev, (q) - v->sq); \
|
|
|
|
if (v->curr_queue_pairs > nr_cpu_ids) \
|
|
|
|
__netif_tx_release(txq); \
|
|
|
|
else \
|
|
|
|
__netif_tx_unlock(txq); \
|
2018-07-23 14:36:07 +00:00
|
|
|
}
|
|
|
|
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
static int virtnet_xdp_xmit(struct net_device *dev,
|
2018-05-31 08:59:47 +00:00
|
|
|
int n, struct xdp_frame **frames, u32 flags)
|
2017-09-19 09:42:43 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2024-02-29 07:20:42 +00:00
|
|
|
struct virtnet_sq_free_stats stats = {0};
|
2018-02-20 13:32:20 +00:00
|
|
|
struct receive_queue *rq = vi->rq;
|
|
|
|
struct bpf_prog *xdp_prog;
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
struct send_queue *sq;
|
2021-03-08 11:06:58 +00:00
|
|
|
int nxmit = 0;
|
2018-07-23 14:36:09 +00:00
|
|
|
int kicks = 0;
|
2021-03-08 11:06:58 +00:00
|
|
|
int ret;
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
int i;
|
|
|
|
|
2018-02-20 13:32:20 +00:00
|
|
|
/* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this
|
|
|
|
* indicate XDP resources have been successfully allocated.
|
|
|
|
*/
|
2020-01-27 00:14:01 +00:00
|
|
|
xdp_prog = rcu_access_pointer(rq->xdp_prog);
|
2019-01-29 00:45:56 +00:00
|
|
|
if (!xdp_prog)
|
|
|
|
return -ENXIO;
|
|
|
|
|
2021-03-10 02:24:45 +00:00
|
|
|
sq = virtnet_xdp_get_sq(vi);
|
2019-01-29 00:45:56 +00:00
|
|
|
|
|
|
|
if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) {
|
|
|
|
ret = -EINVAL;
|
2018-07-23 14:36:08 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2018-02-20 13:32:20 +00:00
|
|
|
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
/* Free up any pending old buffers before queueing new ones. */
|
2024-06-18 14:44:56 +00:00
|
|
|
__free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq),
|
|
|
|
false, &stats);
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
struct xdp_frame *xdpf = frames[i];
|
|
|
|
|
2021-03-08 11:06:58 +00:00
|
|
|
if (__virtnet_xdp_xmit_one(vi, sq, xdpf))
|
|
|
|
break;
|
|
|
|
nxmit++;
|
xdp: change ndo_xdp_xmit API to support bulking
This patch change the API for ndo_xdp_xmit to support bulking
xdp_frames.
When kernel is compiled with CONFIG_RETPOLINE, XDP sees a huge slowdown.
Most of the slowdown is caused by DMA API indirect function calls, but
also the net_device->ndo_xdp_xmit() call.
Benchmarked patch with CONFIG_RETPOLINE, using xdp_redirect_map with
single flow/core test (CPU E5-1650 v4 @ 3.60GHz), showed
performance improved:
for driver ixgbe: 6,042,682 pps -> 6,853,768 pps = +811,086 pps
for driver i40e : 6,187,169 pps -> 6,724,519 pps = +537,350 pps
With frames avail as a bulk inside the driver ndo_xdp_xmit call,
further optimizations are possible, like bulk DMA-mapping for TX.
Testing without CONFIG_RETPOLINE show the same performance for
physical NIC drivers.
The virtual NIC driver tun sees a huge performance boost, as it can
avoid doing per frame producer locking, but instead amortize the
locking cost over the bulk.
V2: Fix compile errors reported by kbuild test robot <lkp@intel.com>
V4: Isolated ndo, driver changes and callers.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2018-05-24 14:46:12 +00:00
|
|
|
}
|
2021-03-08 11:06:58 +00:00
|
|
|
ret = nxmit;
|
2018-05-31 09:00:08 +00:00
|
|
|
|
2023-03-08 02:49:35 +00:00
|
|
|
if (!is_xdp_raw_buffer_queue(vi, sq - vi->sq))
|
|
|
|
check_sq_full_and_disable(vi, dev, sq);
|
|
|
|
|
2018-07-23 14:36:09 +00:00
|
|
|
if (flags & XDP_XMIT_FLUSH) {
|
|
|
|
if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq))
|
|
|
|
kicks = 1;
|
|
|
|
}
|
2018-07-23 14:36:08 +00:00
|
|
|
out:
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
2024-02-29 07:20:42 +00:00
|
|
|
u64_stats_add(&sq->stats.bytes, stats.bytes);
|
|
|
|
u64_stats_add(&sq->stats.packets, stats.packets);
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&sq->stats.xdp_tx, n);
|
|
|
|
u64_stats_add(&sq->stats.xdp_tx_drops, n - nxmit);
|
|
|
|
u64_stats_add(&sq->stats.kicks, kicks);
|
2018-07-23 14:36:08 +00:00
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
2018-05-31 09:00:08 +00:00
|
|
|
|
2021-03-10 02:24:45 +00:00
|
|
|
virtnet_xdp_put_sq(vi, sq);
|
2018-07-23 14:36:08 +00:00
|
|
|
return ret;
|
2017-09-19 09:42:43 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:07 +00:00
|
|
|
static void put_xdp_frags(struct xdp_buff *xdp)
|
|
|
|
{
|
|
|
|
struct skb_shared_info *shinfo;
|
|
|
|
struct page *xdp_page;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (xdp_buff_has_frags(xdp)) {
|
|
|
|
shinfo = xdp_get_shared_info_from_buff(xdp);
|
|
|
|
for (i = 0; i < shinfo->nr_frags; i++) {
|
|
|
|
xdp_page = skb_frag_page(&shinfo->frags[i]);
|
|
|
|
put_page(xdp_page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:06 +00:00
|
|
|
static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp,
|
|
|
|
struct net_device *dev,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct xdp_frame *xdpf;
|
|
|
|
int err;
|
|
|
|
u32 act;
|
|
|
|
|
|
|
|
act = bpf_prog_run_xdp(xdp_prog, xdp);
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->xdp_packets);
|
2023-05-08 06:14:06 +00:00
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case XDP_PASS:
|
|
|
|
return act;
|
|
|
|
|
|
|
|
case XDP_TX:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->xdp_tx);
|
2023-05-08 06:14:06 +00:00
|
|
|
xdpf = xdp_convert_buff_to_frame(xdp);
|
|
|
|
if (unlikely(!xdpf)) {
|
|
|
|
netdev_dbg(dev, "convert buff to frame failed for xdp\n");
|
|
|
|
return XDP_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = virtnet_xdp_xmit(dev, 1, &xdpf, 0);
|
|
|
|
if (unlikely(!err)) {
|
|
|
|
xdp_return_frame_rx_napi(xdpf);
|
|
|
|
} else if (unlikely(err < 0)) {
|
|
|
|
trace_xdp_exception(dev, xdp_prog, act);
|
|
|
|
return XDP_DROP;
|
|
|
|
}
|
|
|
|
*xdp_xmit |= VIRTIO_XDP_TX;
|
|
|
|
return act;
|
|
|
|
|
|
|
|
case XDP_REDIRECT:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->xdp_redirects);
|
2023-05-08 06:14:06 +00:00
|
|
|
err = xdp_do_redirect(dev, xdp, xdp_prog);
|
|
|
|
if (err)
|
|
|
|
return XDP_DROP;
|
|
|
|
|
|
|
|
*xdp_xmit |= VIRTIO_XDP_REDIR;
|
|
|
|
return act;
|
|
|
|
|
|
|
|
default:
|
|
|
|
bpf_warn_invalid_xdp_action(dev, xdp_prog, act);
|
|
|
|
fallthrough;
|
|
|
|
case XDP_ABORTED:
|
|
|
|
trace_xdp_exception(dev, xdp_prog, act);
|
|
|
|
fallthrough;
|
|
|
|
case XDP_DROP:
|
|
|
|
return XDP_DROP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-21 08:46:28 +00:00
|
|
|
static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
|
|
|
|
{
|
2024-07-08 11:25:28 +00:00
|
|
|
return vi->xdp_enabled ? XDP_PACKET_HEADROOM : 0;
|
2017-02-21 08:46:28 +00:00
|
|
|
}
|
|
|
|
|
2017-07-19 08:54:48 +00:00
|
|
|
/* We copy the packet for XDP in the following cases:
|
|
|
|
*
|
|
|
|
* 1) Packet is scattered across multiple rx buffers.
|
|
|
|
* 2) Headroom space is insufficient.
|
|
|
|
*
|
|
|
|
* This is inefficient but it's a temporary condition that
|
|
|
|
* we hit right after XDP is enabled and until queue is refilled
|
|
|
|
* with large buffers with sufficient headroom - so it should affect
|
|
|
|
* at most queue size packets.
|
|
|
|
* Afterwards, the conditions to enable
|
|
|
|
* XDP should preclude the underlying device from sending packets
|
|
|
|
* across multiple buffers (num_buf > 1), and we make sure buffers
|
|
|
|
* have enough headroom.
|
|
|
|
*/
|
|
|
|
static struct page *xdp_linearize_page(struct receive_queue *rq,
|
2023-01-31 08:50:04 +00:00
|
|
|
int *num_buf,
|
2017-07-19 08:54:48 +00:00
|
|
|
struct page *p,
|
|
|
|
int offset,
|
|
|
|
int page_off,
|
|
|
|
unsigned int *len)
|
|
|
|
{
|
2023-04-14 06:08:35 +00:00
|
|
|
int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
|
|
|
struct page *page;
|
2017-07-19 08:54:48 +00:00
|
|
|
|
2023-04-14 06:08:35 +00:00
|
|
|
if (page_off + *len + tailroom > PAGE_SIZE)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
page = alloc_page(GFP_ATOMIC);
|
2017-07-19 08:54:48 +00:00
|
|
|
if (!page)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
|
|
|
|
page_off += *len;
|
|
|
|
|
|
|
|
while (--*num_buf) {
|
|
|
|
unsigned int buflen;
|
|
|
|
void *buf;
|
|
|
|
int off;
|
|
|
|
|
2023-08-10 12:30:57 +00:00
|
|
|
buf = virtnet_rq_get_buf(rq, &buflen, NULL);
|
2017-07-19 08:54:48 +00:00
|
|
|
if (unlikely(!buf))
|
|
|
|
goto err_buf;
|
|
|
|
|
|
|
|
p = virt_to_head_page(buf);
|
|
|
|
off = buf - page_address(p);
|
|
|
|
|
|
|
|
/* guard against a misconfigured or uncooperative backend that
|
|
|
|
* is sending packet larger than the MTU.
|
|
|
|
*/
|
2018-03-02 09:29:14 +00:00
|
|
|
if ((page_off + buflen + tailroom) > PAGE_SIZE) {
|
2017-07-19 08:54:48 +00:00
|
|
|
put_page(p);
|
|
|
|
goto err_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(page_address(page) + page_off,
|
|
|
|
page_address(p) + off, buflen);
|
|
|
|
page_off += buflen;
|
|
|
|
put_page(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Headroom does not contribute to packet length */
|
2024-07-08 11:25:28 +00:00
|
|
|
*len = page_off - XDP_PACKET_HEADROOM;
|
2017-07-19 08:54:48 +00:00
|
|
|
return page;
|
|
|
|
err_buf:
|
|
|
|
__free_pages(page, 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:16 +00:00
|
|
|
static struct sk_buff *receive_small_build_skb(struct virtnet_info *vi,
|
|
|
|
unsigned int xdp_headroom,
|
|
|
|
void *buf,
|
|
|
|
unsigned int len)
|
|
|
|
{
|
|
|
|
unsigned int header_offset;
|
|
|
|
unsigned int headroom;
|
|
|
|
unsigned int buflen;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
header_offset = VIRTNET_RX_PAD + xdp_headroom;
|
|
|
|
headroom = vi->hdr_len + header_offset;
|
|
|
|
buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
|
|
|
|
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
|
|
|
|
2023-05-08 06:14:17 +00:00
|
|
|
skb = virtnet_build_skb(buf, buflen, headroom, len);
|
|
|
|
if (unlikely(!skb))
|
2023-05-08 06:14:16 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
buf += header_offset;
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
memcpy(skb_vnet_common_hdr(skb), buf, vi->hdr_len);
|
2023-05-08 06:14:16 +00:00
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:12 +00:00
|
|
|
static struct sk_buff *receive_small_xdp(struct net_device *dev,
|
|
|
|
struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
struct bpf_prog *xdp_prog,
|
|
|
|
void *buf,
|
|
|
|
unsigned int xdp_headroom,
|
|
|
|
unsigned int len,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
unsigned int header_offset = VIRTNET_RX_PAD + xdp_headroom;
|
|
|
|
unsigned int headroom = vi->hdr_len + header_offset;
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr = buf + header_offset;
|
|
|
|
struct page *page = virt_to_head_page(buf);
|
|
|
|
struct page *xdp_page;
|
|
|
|
unsigned int buflen;
|
|
|
|
struct xdp_buff xdp;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
unsigned int metasize = 0;
|
|
|
|
u32 act;
|
|
|
|
|
|
|
|
if (unlikely(hdr->hdr.gso_type))
|
|
|
|
goto err_xdp;
|
|
|
|
|
2024-06-17 13:15:24 +00:00
|
|
|
/* Partially checksummed packets must be dropped. */
|
|
|
|
if (unlikely(hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM))
|
|
|
|
goto err_xdp;
|
|
|
|
|
2023-05-08 06:14:12 +00:00
|
|
|
buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
|
|
|
|
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
|
|
|
|
|
|
|
if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) {
|
|
|
|
int offset = buf - page_address(page) + header_offset;
|
|
|
|
unsigned int tlen = len + vi->hdr_len;
|
|
|
|
int num_buf = 1;
|
|
|
|
|
|
|
|
xdp_headroom = virtnet_get_headroom(vi);
|
|
|
|
header_offset = VIRTNET_RX_PAD + xdp_headroom;
|
|
|
|
headroom = vi->hdr_len + header_offset;
|
|
|
|
buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
|
|
|
|
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
|
|
|
xdp_page = xdp_linearize_page(rq, &num_buf, page,
|
|
|
|
offset, header_offset,
|
|
|
|
&tlen);
|
|
|
|
if (!xdp_page)
|
|
|
|
goto err_xdp;
|
|
|
|
|
|
|
|
buf = page_address(xdp_page);
|
|
|
|
put_page(page);
|
|
|
|
page = xdp_page;
|
|
|
|
}
|
|
|
|
|
|
|
|
xdp_init_buff(&xdp, buflen, &rq->xdp_rxq);
|
|
|
|
xdp_prepare_buff(&xdp, buf + VIRTNET_RX_PAD + vi->hdr_len,
|
|
|
|
xdp_headroom, len, true);
|
|
|
|
|
|
|
|
act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats);
|
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case XDP_PASS:
|
|
|
|
/* Recalculate length in case bpf program changed it */
|
|
|
|
len = xdp.data_end - xdp.data;
|
|
|
|
metasize = xdp.data - xdp.data_meta;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XDP_TX:
|
|
|
|
case XDP_REDIRECT:
|
|
|
|
goto xdp_xmit;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto err_xdp;
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:17 +00:00
|
|
|
skb = virtnet_build_skb(buf, buflen, xdp.data - buf, len);
|
|
|
|
if (unlikely(!skb))
|
2023-05-08 06:14:12 +00:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (metasize)
|
|
|
|
skb_metadata_set(skb, metasize);
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
|
|
|
|
err_xdp:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->xdp_drops);
|
2023-05-08 06:14:12 +00:00
|
|
|
err:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->drops);
|
2023-05-08 06:14:12 +00:00
|
|
|
put_page(page);
|
|
|
|
xdp_xmit:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-12-23 14:37:32 +00:00
|
|
|
static struct sk_buff *receive_small(struct net_device *dev,
|
|
|
|
struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
2017-07-19 08:54:47 +00:00
|
|
|
void *buf, void *ctx,
|
2017-09-19 09:42:43 +00:00
|
|
|
unsigned int len,
|
2018-07-23 14:36:04 +00:00
|
|
|
unsigned int *xdp_xmit,
|
2018-07-31 09:43:39 +00:00
|
|
|
struct virtnet_rq_stats *stats)
|
2013-11-28 11:30:59 +00:00
|
|
|
{
|
2017-07-19 08:54:48 +00:00
|
|
|
unsigned int xdp_headroom = (unsigned long)ctx;
|
|
|
|
struct page *page = virt_to_head_page(buf);
|
2023-05-08 06:14:15 +00:00
|
|
|
struct sk_buff *skb;
|
2018-02-20 13:32:15 +00:00
|
|
|
|
2024-09-19 08:13:51 +00:00
|
|
|
/* We passed the address of virtnet header to virtio-core,
|
|
|
|
* so truncate the padding.
|
|
|
|
*/
|
|
|
|
buf -= VIRTNET_RX_PAD + xdp_headroom;
|
|
|
|
|
2014-10-24 13:55:57 +00:00
|
|
|
len -= vi->hdr_len;
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&stats->bytes, len);
|
2013-11-28 11:30:59 +00:00
|
|
|
|
2021-05-31 13:58:52 +00:00
|
|
|
if (unlikely(len > GOOD_PACKET_LEN)) {
|
|
|
|
pr_debug("%s: rx error: len %u exceeds max size %d\n",
|
|
|
|
dev->name, len, GOOD_PACKET_LEN);
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2021-12-16 03:11:35 +00:00
|
|
|
goto err;
|
2021-05-31 13:58:52 +00:00
|
|
|
}
|
2021-10-09 09:32:43 +00:00
|
|
|
|
2023-05-08 06:14:15 +00:00
|
|
|
if (unlikely(vi->xdp_enabled)) {
|
|
|
|
struct bpf_prog *xdp_prog;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
xdp_prog = rcu_dereference(rq->xdp_prog);
|
|
|
|
if (xdp_prog) {
|
|
|
|
skb = receive_small_xdp(dev, vi, rq, xdp_prog, buf,
|
|
|
|
xdp_headroom, len, xdp_xmit,
|
|
|
|
stats);
|
|
|
|
rcu_read_unlock();
|
|
|
|
return skb;
|
|
|
|
}
|
2023-05-08 06:14:12 +00:00
|
|
|
rcu_read_unlock();
|
2016-12-23 14:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:16 +00:00
|
|
|
skb = receive_small_build_skb(vi, xdp_headroom, buf, len);
|
|
|
|
if (likely(skb))
|
|
|
|
return skb;
|
2016-12-23 14:37:32 +00:00
|
|
|
|
2021-12-16 03:11:35 +00:00
|
|
|
err:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->drops);
|
2017-07-19 08:54:48 +00:00
|
|
|
put_page(page);
|
2016-12-23 14:37:32 +00:00
|
|
|
return NULL;
|
2013-11-28 11:30:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *receive_big(struct net_device *dev,
|
2014-10-23 21:12:10 +00:00
|
|
|
struct virtnet_info *vi,
|
2013-11-28 11:30:59 +00:00
|
|
|
struct receive_queue *rq,
|
|
|
|
void *buf,
|
2018-07-23 14:36:04 +00:00
|
|
|
unsigned int len,
|
2018-07-31 09:43:39 +00:00
|
|
|
struct virtnet_rq_stats *stats)
|
2013-11-28 11:30:59 +00:00
|
|
|
{
|
|
|
|
struct page *page = buf;
|
2020-02-25 03:32:12 +00:00
|
|
|
struct sk_buff *skb =
|
2023-03-15 01:52:22 +00:00
|
|
|
page_to_skb(vi, rq, page, 0, len, PAGE_SIZE, 0);
|
2016-12-15 20:13:24 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&stats->bytes, len - vi->hdr_len);
|
2013-11-28 11:30:59 +00:00
|
|
|
if (unlikely(!skb))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
|
|
|
|
err:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->drops);
|
2013-11-28 11:30:59 +00:00
|
|
|
give_pages(rq, page);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:08 +00:00
|
|
|
static void mergeable_buf_free(struct receive_queue *rq, int num_buf,
|
|
|
|
struct net_device *dev,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct page *page;
|
|
|
|
void *buf;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
while (num_buf-- > 1) {
|
2023-08-10 12:30:57 +00:00
|
|
|
buf = virtnet_rq_get_buf(rq, &len, NULL);
|
2023-05-08 06:14:08 +00:00
|
|
|
if (unlikely(!buf)) {
|
|
|
|
pr_debug("%s: rx error: %d buffers missing\n",
|
|
|
|
dev->name, num_buf);
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2023-05-08 06:14:08 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&stats->bytes, len);
|
2023-05-08 06:14:08 +00:00
|
|
|
page = virt_to_head_page(buf);
|
|
|
|
put_page(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:22:27 +00:00
|
|
|
/* Why not use xdp_build_skb_from_frame() ?
|
|
|
|
* XDP core assumes that xdp frags are PAGE_SIZE in length, while in
|
|
|
|
* virtio-net there are 2 points that do not match its requirements:
|
|
|
|
* 1. The size of the prefilled buffer is not fixed before xdp is set.
|
|
|
|
* 2. xdp_build_skb_from_frame() does more checks that we don't need,
|
|
|
|
* like eth_type_trans() (which virtio-net does in receive_buf()).
|
|
|
|
*/
|
|
|
|
static struct sk_buff *build_skb_from_xdp_buff(struct net_device *dev,
|
|
|
|
struct virtnet_info *vi,
|
|
|
|
struct xdp_buff *xdp,
|
|
|
|
unsigned int xdp_frags_truesz)
|
|
|
|
{
|
|
|
|
struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
|
|
|
|
unsigned int headroom, data_len;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int metasize;
|
|
|
|
u8 nr_frags;
|
|
|
|
|
|
|
|
if (unlikely(xdp->data_end > xdp_data_hard_end(xdp))) {
|
|
|
|
pr_debug("Error building skb as missing reserved tailroom for xdp");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlikely(xdp_buff_has_frags(xdp)))
|
|
|
|
nr_frags = sinfo->nr_frags;
|
|
|
|
|
|
|
|
skb = build_skb(xdp->data_hard_start, xdp->frame_sz);
|
|
|
|
if (unlikely(!skb))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
headroom = xdp->data - xdp->data_hard_start;
|
|
|
|
data_len = xdp->data_end - xdp->data;
|
|
|
|
skb_reserve(skb, headroom);
|
|
|
|
__skb_put(skb, data_len);
|
|
|
|
|
|
|
|
metasize = xdp->data - xdp->data_meta;
|
|
|
|
metasize = metasize > 0 ? metasize : 0;
|
|
|
|
if (metasize)
|
|
|
|
skb_metadata_set(skb, metasize);
|
|
|
|
|
|
|
|
if (unlikely(xdp_buff_has_frags(xdp)))
|
|
|
|
xdp_update_skb_shared_info(skb, nr_frags,
|
|
|
|
sinfo->xdp_frags_size,
|
|
|
|
xdp_frags_truesz,
|
|
|
|
xdp_buff_is_frag_pfmemalloc(xdp));
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:22:24 +00:00
|
|
|
/* TODO: build xdp in big mode */
|
|
|
|
static int virtnet_build_xdp_buff_mrg(struct net_device *dev,
|
|
|
|
struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
struct xdp_buff *xdp,
|
|
|
|
void *buf,
|
|
|
|
unsigned int len,
|
|
|
|
unsigned int frame_sz,
|
2023-01-31 08:50:04 +00:00
|
|
|
int *num_buf,
|
2023-01-14 08:22:24 +00:00
|
|
|
unsigned int *xdp_frags_truesize,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
|
|
|
|
unsigned int headroom, tailroom, room;
|
|
|
|
unsigned int truesize, cur_frag_size;
|
|
|
|
struct skb_shared_info *shinfo;
|
|
|
|
unsigned int xdp_frags_truesz = 0;
|
|
|
|
struct page *page;
|
|
|
|
skb_frag_t *frag;
|
|
|
|
int offset;
|
|
|
|
void *ctx;
|
|
|
|
|
|
|
|
xdp_init_buff(xdp, frame_sz, &rq->xdp_rxq);
|
2024-07-08 11:25:28 +00:00
|
|
|
xdp_prepare_buff(xdp, buf - XDP_PACKET_HEADROOM,
|
|
|
|
XDP_PACKET_HEADROOM + vi->hdr_len, len - vi->hdr_len, true);
|
2023-01-14 08:22:24 +00:00
|
|
|
|
2023-01-31 08:50:04 +00:00
|
|
|
if (!*num_buf)
|
|
|
|
return 0;
|
|
|
|
|
2023-01-14 08:22:24 +00:00
|
|
|
if (*num_buf > 1) {
|
|
|
|
/* If we want to build multi-buffer xdp, we need
|
|
|
|
* to specify that the flags of xdp_buff have the
|
|
|
|
* XDP_FLAGS_HAS_FRAG bit.
|
|
|
|
*/
|
|
|
|
if (!xdp_buff_has_frags(xdp))
|
|
|
|
xdp_buff_set_frags_flag(xdp);
|
|
|
|
|
|
|
|
shinfo = xdp_get_shared_info_from_buff(xdp);
|
|
|
|
shinfo->nr_frags = 0;
|
|
|
|
shinfo->xdp_frags_size = 0;
|
|
|
|
}
|
|
|
|
|
2023-01-31 08:50:04 +00:00
|
|
|
if (*num_buf > MAX_SKB_FRAGS + 1)
|
2023-01-14 08:22:24 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2023-01-31 08:50:04 +00:00
|
|
|
while (--*num_buf > 0) {
|
2023-08-10 12:30:57 +00:00
|
|
|
buf = virtnet_rq_get_buf(rq, &len, &ctx);
|
2023-01-14 08:22:24 +00:00
|
|
|
if (unlikely(!buf)) {
|
|
|
|
pr_debug("%s: rx error: %d buffers out of %d missing\n",
|
|
|
|
dev->name, *num_buf,
|
|
|
|
virtio16_to_cpu(vi->vdev, hdr->num_buffers));
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2023-05-08 06:14:09 +00:00
|
|
|
goto err;
|
2023-01-14 08:22:24 +00:00
|
|
|
}
|
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&stats->bytes, len);
|
2023-01-14 08:22:24 +00:00
|
|
|
page = virt_to_head_page(buf);
|
|
|
|
offset = buf - page_address(page);
|
|
|
|
|
|
|
|
truesize = mergeable_ctx_to_truesize(ctx);
|
|
|
|
headroom = mergeable_ctx_to_headroom(ctx);
|
|
|
|
tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
|
|
|
|
room = SKB_DATA_ALIGN(headroom + tailroom);
|
|
|
|
|
|
|
|
cur_frag_size = truesize;
|
|
|
|
xdp_frags_truesz += cur_frag_size;
|
|
|
|
if (unlikely(len > truesize - room || cur_frag_size > PAGE_SIZE)) {
|
|
|
|
put_page(page);
|
|
|
|
pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
|
|
|
|
dev->name, len, (unsigned long)(truesize - room));
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2023-05-08 06:14:09 +00:00
|
|
|
goto err;
|
2023-01-14 08:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
frag = &shinfo->frags[shinfo->nr_frags++];
|
2023-05-11 01:12:12 +00:00
|
|
|
skb_frag_fill_page_desc(frag, page, offset, len);
|
2023-01-14 08:22:24 +00:00
|
|
|
if (page_is_pfmemalloc(page))
|
|
|
|
xdp_buff_set_frag_pfmemalloc(xdp);
|
|
|
|
|
|
|
|
shinfo->xdp_frags_size += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
*xdp_frags_truesize = xdp_frags_truesz;
|
|
|
|
return 0;
|
2023-05-08 06:14:09 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
put_xdp_frags(xdp);
|
|
|
|
return -EINVAL;
|
2023-01-14 08:22:24 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:04 +00:00
|
|
|
static void *mergeable_xdp_get_buf(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
struct bpf_prog *xdp_prog,
|
|
|
|
void *ctx,
|
|
|
|
unsigned int *frame_sz,
|
|
|
|
int *num_buf,
|
|
|
|
struct page **page,
|
|
|
|
int offset,
|
|
|
|
unsigned int *len,
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr)
|
|
|
|
{
|
|
|
|
unsigned int truesize = mergeable_ctx_to_truesize(ctx);
|
|
|
|
unsigned int headroom = mergeable_ctx_to_headroom(ctx);
|
|
|
|
struct page *xdp_page;
|
|
|
|
unsigned int xdp_room;
|
|
|
|
|
|
|
|
/* Transient failure which in theory could occur if
|
|
|
|
* in-flight packets from before XDP was enabled reach
|
|
|
|
* the receive path after XDP is loaded.
|
|
|
|
*/
|
|
|
|
if (unlikely(hdr->hdr.gso_type))
|
|
|
|
return NULL;
|
|
|
|
|
2024-06-17 13:15:24 +00:00
|
|
|
/* Partially checksummed packets must be dropped. */
|
|
|
|
if (unlikely(hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM))
|
|
|
|
return NULL;
|
|
|
|
|
2023-05-08 06:14:04 +00:00
|
|
|
/* Now XDP core assumes frag size is PAGE_SIZE, but buffers
|
|
|
|
* with headroom may add hole in truesize, which
|
|
|
|
* make their length exceed PAGE_SIZE. So we disabled the
|
|
|
|
* hole mechanism for xdp. See add_recvbuf_mergeable().
|
|
|
|
*/
|
|
|
|
*frame_sz = truesize;
|
|
|
|
|
2023-05-08 06:14:05 +00:00
|
|
|
if (likely(headroom >= virtnet_get_headroom(vi) &&
|
|
|
|
(*num_buf == 1 || xdp_prog->aux->xdp_has_frags))) {
|
|
|
|
return page_address(*page) + offset;
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:04 +00:00
|
|
|
/* This happens when headroom is not enough because
|
|
|
|
* of the buffer was prefilled before XDP is set.
|
|
|
|
* This should only happen for the first several packets.
|
|
|
|
* In fact, vq reset can be used here to help us clean up
|
|
|
|
* the prefilled buffers, but many existing devices do not
|
|
|
|
* support it, and we don't want to bother users who are
|
|
|
|
* using xdp normally.
|
|
|
|
*/
|
2023-05-08 06:14:05 +00:00
|
|
|
if (!xdp_prog->aux->xdp_has_frags) {
|
2023-05-08 06:14:04 +00:00
|
|
|
/* linearize data for XDP */
|
|
|
|
xdp_page = xdp_linearize_page(rq, num_buf,
|
|
|
|
*page, offset,
|
2024-07-08 11:25:28 +00:00
|
|
|
XDP_PACKET_HEADROOM,
|
2023-05-08 06:14:04 +00:00
|
|
|
len);
|
|
|
|
if (!xdp_page)
|
|
|
|
return NULL;
|
2023-05-08 06:14:05 +00:00
|
|
|
} else {
|
2024-07-08 11:25:28 +00:00
|
|
|
xdp_room = SKB_DATA_ALIGN(XDP_PACKET_HEADROOM +
|
2023-05-08 06:14:04 +00:00
|
|
|
sizeof(struct skb_shared_info));
|
|
|
|
if (*len + xdp_room > PAGE_SIZE)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
xdp_page = alloc_page(GFP_ATOMIC);
|
|
|
|
if (!xdp_page)
|
|
|
|
return NULL;
|
|
|
|
|
2024-07-08 11:25:28 +00:00
|
|
|
memcpy(page_address(xdp_page) + XDP_PACKET_HEADROOM,
|
2023-05-08 06:14:04 +00:00
|
|
|
page_address(*page) + offset, *len);
|
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:05 +00:00
|
|
|
*frame_sz = PAGE_SIZE;
|
|
|
|
|
|
|
|
put_page(*page);
|
|
|
|
|
|
|
|
*page = xdp_page;
|
|
|
|
|
2024-07-08 11:25:28 +00:00
|
|
|
return page_address(*page) + XDP_PACKET_HEADROOM;
|
2023-05-08 06:14:04 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 06:14:10 +00:00
|
|
|
static struct sk_buff *receive_mergeable_xdp(struct net_device *dev,
|
|
|
|
struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
struct bpf_prog *xdp_prog,
|
|
|
|
void *buf,
|
|
|
|
void *ctx,
|
|
|
|
unsigned int len,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
|
|
|
|
int num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
|
|
|
|
struct page *page = virt_to_head_page(buf);
|
|
|
|
int offset = buf - page_address(page);
|
|
|
|
unsigned int xdp_frags_truesz = 0;
|
|
|
|
struct sk_buff *head_skb;
|
|
|
|
unsigned int frame_sz;
|
|
|
|
struct xdp_buff xdp;
|
|
|
|
void *data;
|
|
|
|
u32 act;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
data = mergeable_xdp_get_buf(vi, rq, xdp_prog, ctx, &frame_sz, &num_buf, &page,
|
|
|
|
offset, &len, hdr);
|
|
|
|
if (unlikely(!data))
|
|
|
|
goto err_xdp;
|
|
|
|
|
|
|
|
err = virtnet_build_xdp_buff_mrg(dev, vi, rq, &xdp, data, len, frame_sz,
|
|
|
|
&num_buf, &xdp_frags_truesz, stats);
|
|
|
|
if (unlikely(err))
|
|
|
|
goto err_xdp;
|
|
|
|
|
|
|
|
act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats);
|
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case XDP_PASS:
|
|
|
|
head_skb = build_skb_from_xdp_buff(dev, vi, &xdp, xdp_frags_truesz);
|
|
|
|
if (unlikely(!head_skb))
|
|
|
|
break;
|
|
|
|
return head_skb;
|
|
|
|
|
|
|
|
case XDP_TX:
|
|
|
|
case XDP_REDIRECT:
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
put_xdp_frags(&xdp);
|
|
|
|
|
|
|
|
err_xdp:
|
|
|
|
put_page(page);
|
|
|
|
mergeable_buf_free(rq, num_buf, dev, stats);
|
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->xdp_drops);
|
|
|
|
u64_stats_inc(&stats->drops);
|
2023-05-08 06:14:10 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:32 +00:00
|
|
|
static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
|
|
|
|
struct sk_buff *curr_skb,
|
|
|
|
struct page *page, void *buf,
|
|
|
|
int len, int truesize)
|
|
|
|
{
|
|
|
|
int num_skb_frags;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
num_skb_frags = skb_shinfo(curr_skb)->nr_frags;
|
|
|
|
if (unlikely(num_skb_frags == MAX_SKB_FRAGS)) {
|
|
|
|
struct sk_buff *nskb = alloc_skb(0, GFP_ATOMIC);
|
|
|
|
|
|
|
|
if (unlikely(!nskb))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (curr_skb == head_skb)
|
|
|
|
skb_shinfo(curr_skb)->frag_list = nskb;
|
|
|
|
else
|
|
|
|
curr_skb->next = nskb;
|
|
|
|
curr_skb = nskb;
|
|
|
|
head_skb->truesize += nskb->truesize;
|
|
|
|
num_skb_frags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (curr_skb != head_skb) {
|
|
|
|
head_skb->data_len += len;
|
|
|
|
head_skb->len += len;
|
|
|
|
head_skb->truesize += truesize;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset = buf - page_address(page);
|
|
|
|
if (skb_can_coalesce(curr_skb, num_skb_frags, page, offset)) {
|
|
|
|
put_page(page);
|
|
|
|
skb_coalesce_rx_frag(curr_skb, num_skb_frags - 1,
|
|
|
|
len, truesize);
|
|
|
|
} else {
|
|
|
|
skb_add_rx_frag(curr_skb, num_skb_frags, page,
|
|
|
|
offset, len, truesize);
|
|
|
|
}
|
|
|
|
|
|
|
|
return curr_skb;
|
|
|
|
}
|
|
|
|
|
2013-11-28 11:30:55 +00:00
|
|
|
static struct sk_buff *receive_mergeable(struct net_device *dev,
|
2014-10-07 14:39:48 +00:00
|
|
|
struct virtnet_info *vi,
|
2013-11-28 11:30:55 +00:00
|
|
|
struct receive_queue *rq,
|
2017-03-06 19:29:47 +00:00
|
|
|
void *buf,
|
|
|
|
void *ctx,
|
2017-09-19 09:42:43 +00:00
|
|
|
unsigned int len,
|
2018-07-23 14:36:04 +00:00
|
|
|
unsigned int *xdp_xmit,
|
2018-07-31 09:43:39 +00:00
|
|
|
struct virtnet_rq_stats *stats)
|
2010-01-29 03:20:04 +00:00
|
|
|
{
|
2014-10-24 13:55:57 +00:00
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
|
2023-01-31 08:50:04 +00:00
|
|
|
int num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
|
2013-11-28 11:30:55 +00:00
|
|
|
struct page *page = virt_to_head_page(buf);
|
|
|
|
int offset = buf - page_address(page);
|
2016-12-15 20:13:24 +00:00
|
|
|
struct sk_buff *head_skb, *curr_skb;
|
virtio_net: Add XDP frame size in two code paths
The virtio_net driver is running inside the guest-OS. There are two
XDP receive code-paths in virtio_net, namely receive_small() and
receive_mergeable(). The receive_big() function does not support XDP.
In receive_small() the frame size is available in buflen. The buffer
backing these frames are allocated in add_recvbuf_small() with same
size, except for the headroom, but tailroom have reserved room for
skb_shared_info. The headroom is encoded in ctx pointer as a value.
In receive_mergeable() the frame size is more dynamic. There are two
basic cases: (1) buffer size is based on a exponentially weighted
moving average (see DECLARE_EWMA) of packet length. Or (2) in case
virtnet_get_headroom() have any headroom then buffer size is
PAGE_SIZE. The ctx pointer is this time used for encoding two values;
the buffer len "truesize" and headroom. In case (1) if the rx buffer
size is underestimated, the packet will have been split over more
buffers (num_buf info in virtio_net_hdr_mrg_rxbuf placed in top of
buffer area). If that happens the XDP path does a xdp_linearize_page
operation.
V3: Adjust frame_sz in receive_mergeable() case, spotted by Jason Wang.
The code is really hard to follow, so some hints to reviewers.
The receive_mergeable() case gets frames that were allocated in
add_recvbuf_mergeable() which uses headroom=virtnet_get_headroom(),
and 'buf' ptr is advanced this headroom. The headroom can only
be 0 or VIRTIO_XDP_HEADROOM, as virtnet_get_headroom is really
simple:
static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
{
return vi->xdp_queue_pairs ? VIRTIO_XDP_HEADROOM : 0;
}
As frame_sz is an offset size from xdp.data_hard_start, reviewers
should notice how this is calculated in receive_mergeable():
int offset = buf - page_address(page);
[...]
data = page_address(xdp_page) + offset;
xdp.data_hard_start = data - VIRTIO_XDP_HEADROOM + vi->hdr_len;
The calculated offset will always be VIRTIO_XDP_HEADROOM when
reaching this code. Thus, xdp.data_hard_start will be page-start
address plus vi->hdr_len. Given this xdp.frame_sz need to be
reduced with vi->hdr_len size.
IMHO a followup patch should cleanup this code to make it easier
to maintain and understand, but it is outside the scope of this
patchset.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Link: https://lore.kernel.org/bpf/158945344436.97035.9445115070189151680.stgit@firesoul
2020-05-14 10:50:44 +00:00
|
|
|
unsigned int truesize = mergeable_ctx_to_truesize(ctx);
|
2017-07-19 08:54:48 +00:00
|
|
|
unsigned int headroom = mergeable_ctx_to_headroom(ctx);
|
2023-01-14 08:22:24 +00:00
|
|
|
unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
|
|
|
|
unsigned int room = SKB_DATA_ALIGN(headroom + tailroom);
|
2016-12-15 20:13:24 +00:00
|
|
|
|
2016-12-15 20:14:13 +00:00
|
|
|
head_skb = NULL;
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&stats->bytes, len - vi->hdr_len);
|
2016-12-15 20:14:13 +00:00
|
|
|
|
2023-01-14 08:22:24 +00:00
|
|
|
if (unlikely(len > truesize - room)) {
|
2021-05-31 13:58:52 +00:00
|
|
|
pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
|
2023-01-14 08:22:24 +00:00
|
|
|
dev->name, len, (unsigned long)(truesize - room));
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2021-05-31 13:58:52 +00:00
|
|
|
goto err_skb;
|
|
|
|
}
|
2021-10-09 09:32:43 +00:00
|
|
|
|
2023-05-08 06:14:11 +00:00
|
|
|
if (unlikely(vi->xdp_enabled)) {
|
|
|
|
struct bpf_prog *xdp_prog;
|
2021-10-09 09:32:43 +00:00
|
|
|
|
2023-05-08 06:14:11 +00:00
|
|
|
rcu_read_lock();
|
|
|
|
xdp_prog = rcu_dereference(rq->xdp_prog);
|
|
|
|
if (xdp_prog) {
|
|
|
|
head_skb = receive_mergeable_xdp(dev, vi, rq, xdp_prog, buf, ctx,
|
|
|
|
len, xdp_xmit, stats);
|
|
|
|
rcu_read_unlock();
|
|
|
|
return head_skb;
|
|
|
|
}
|
2023-05-08 06:14:10 +00:00
|
|
|
rcu_read_unlock();
|
2016-12-15 20:13:24 +00:00
|
|
|
}
|
2014-01-17 06:23:27 +00:00
|
|
|
|
2023-03-15 01:52:22 +00:00
|
|
|
head_skb = page_to_skb(vi, rq, page, offset, len, truesize, headroom);
|
2016-12-15 20:13:24 +00:00
|
|
|
curr_skb = head_skb;
|
2010-01-29 03:20:04 +00:00
|
|
|
|
2013-11-28 11:30:55 +00:00
|
|
|
if (unlikely(!curr_skb))
|
|
|
|
goto err_skb;
|
2010-01-29 03:20:04 +00:00
|
|
|
while (--num_buf) {
|
2023-08-10 12:30:57 +00:00
|
|
|
buf = virtnet_rq_get_buf(rq, &len, &ctx);
|
2017-12-04 06:02:19 +00:00
|
|
|
if (unlikely(!buf)) {
|
2013-11-28 11:30:55 +00:00
|
|
|
pr_debug("%s: rx error: %d buffers out of %d missing\n",
|
2014-10-07 14:39:48 +00:00
|
|
|
dev->name, num_buf,
|
2014-10-24 13:55:57 +00:00
|
|
|
virtio16_to_cpu(vi->vdev,
|
|
|
|
hdr->num_buffers));
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2013-11-28 11:30:55 +00:00
|
|
|
goto err_buf;
|
2008-11-17 06:41:34 +00:00
|
|
|
}
|
2013-11-28 11:30:55 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_add(&stats->bytes, len);
|
2013-11-28 11:30:55 +00:00
|
|
|
page = virt_to_head_page(buf);
|
2017-07-19 08:54:46 +00:00
|
|
|
|
|
|
|
truesize = mergeable_ctx_to_truesize(ctx);
|
2023-01-14 08:22:24 +00:00
|
|
|
headroom = mergeable_ctx_to_headroom(ctx);
|
|
|
|
tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
|
|
|
|
room = SKB_DATA_ALIGN(headroom + tailroom);
|
|
|
|
if (unlikely(len > truesize - room)) {
|
2017-04-06 09:04:47 +00:00
|
|
|
pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
|
2023-01-14 08:22:24 +00:00
|
|
|
dev->name, len, (unsigned long)(truesize - room));
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2017-03-06 19:29:47 +00:00
|
|
|
goto err_skb;
|
|
|
|
}
|
2013-11-28 11:30:55 +00:00
|
|
|
|
2024-07-08 11:25:32 +00:00
|
|
|
curr_skb = virtnet_skb_append_frag(head_skb, curr_skb, page,
|
|
|
|
buf, len, truesize);
|
|
|
|
if (!curr_skb)
|
|
|
|
goto err_skb;
|
2013-11-28 11:30:55 +00:00
|
|
|
}
|
|
|
|
|
2015-08-19 07:48:40 +00:00
|
|
|
ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len);
|
2013-11-28 11:30:55 +00:00
|
|
|
return head_skb;
|
|
|
|
|
|
|
|
err_skb:
|
|
|
|
put_page(page);
|
2023-05-08 06:14:08 +00:00
|
|
|
mergeable_buf_free(rq, num_buf, dev, stats);
|
|
|
|
|
2013-11-28 11:30:55 +00:00
|
|
|
err_buf:
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&stats->drops);
|
2013-11-28 11:30:55 +00:00
|
|
|
dev_kfree_skb(head_skb);
|
|
|
|
return NULL;
|
2010-01-29 03:20:04 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 17:53:35 +00:00
|
|
|
static void virtio_skb_set_hash(const struct virtio_net_hdr_v1_hash *hdr_hash,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
enum pkt_hash_types rss_hash_type;
|
|
|
|
|
|
|
|
if (!hdr_hash || !skb)
|
|
|
|
return;
|
|
|
|
|
2022-08-11 12:51:58 +00:00
|
|
|
switch (__le16_to_cpu(hdr_hash->hash_report)) {
|
2022-03-28 17:53:35 +00:00
|
|
|
case VIRTIO_NET_HASH_REPORT_TCPv4:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_UDPv4:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_TCPv6:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_UDPv6:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_TCPv6_EX:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_UDPv6_EX:
|
|
|
|
rss_hash_type = PKT_HASH_TYPE_L4;
|
|
|
|
break;
|
|
|
|
case VIRTIO_NET_HASH_REPORT_IPv4:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_IPv6:
|
|
|
|
case VIRTIO_NET_HASH_REPORT_IPv6_EX:
|
|
|
|
rss_hash_type = PKT_HASH_TYPE_L3;
|
|
|
|
break;
|
|
|
|
case VIRTIO_NET_HASH_REPORT_NONE:
|
|
|
|
default:
|
|
|
|
rss_hash_type = PKT_HASH_TYPE_NONE;
|
|
|
|
}
|
2022-08-11 12:51:58 +00:00
|
|
|
skb_set_hash(skb, __le32_to_cpu(hdr_hash->hash_value), rss_hash_type);
|
2022-03-28 17:53:35 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:31 +00:00
|
|
|
static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
struct sk_buff *skb, u8 flags)
|
|
|
|
{
|
|
|
|
struct virtio_net_common_hdr *hdr;
|
|
|
|
struct net_device *dev = vi->dev;
|
|
|
|
|
|
|
|
hdr = skb_vnet_common_hdr(skb);
|
|
|
|
if (dev->features & NETIF_F_RXHASH && vi->has_rss_hash_report)
|
|
|
|
virtio_skb_set_hash(&hdr->hash_v1_hdr, skb);
|
|
|
|
|
|
|
|
if (flags & VIRTIO_NET_HDR_F_DATA_VALID)
|
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
|
|
|
|
if (virtio_net_hdr_to_skb(skb, &hdr->hdr,
|
|
|
|
virtio_is_little_endian(vi->vdev))) {
|
|
|
|
net_warn_ratelimited("%s: bad gso: type: %u, size: %u\n",
|
|
|
|
dev->name, hdr->hdr.gso_type,
|
|
|
|
hdr->hdr.gso_size);
|
|
|
|
goto frame_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb_record_rx_queue(skb, vq2rxq(rq->vq));
|
|
|
|
skb->protocol = eth_type_trans(skb, dev);
|
|
|
|
pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
|
|
|
|
ntohs(skb->protocol), skb->len, skb->pkt_type);
|
|
|
|
|
|
|
|
napi_gro_receive(&rq->napi, skb);
|
|
|
|
return;
|
|
|
|
|
|
|
|
frame_err:
|
|
|
|
DEV_STATS_INC(dev, rx_frame_errors);
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
}
|
|
|
|
|
2018-07-23 14:36:04 +00:00
|
|
|
static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
void *buf, unsigned int len, void **ctx,
|
2018-07-23 14:36:05 +00:00
|
|
|
unsigned int *xdp_xmit,
|
2018-07-31 09:43:39 +00:00
|
|
|
struct virtnet_rq_stats *stats)
|
2010-01-29 03:20:04 +00:00
|
|
|
{
|
2012-12-07 07:04:55 +00:00
|
|
|
struct net_device *dev = vi->dev;
|
2010-01-29 03:20:04 +00:00
|
|
|
struct sk_buff *skb;
|
2024-06-17 13:15:24 +00:00
|
|
|
u8 flags;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2014-10-23 21:22:11 +00:00
|
|
|
if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
|
2010-01-29 03:20:04 +00:00
|
|
|
pr_debug("%s: short packet %i\n", dev->name, len);
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, rx_length_errors);
|
2023-12-26 09:43:33 +00:00
|
|
|
virtnet_rq_free_buf(vi, rq, buf);
|
2018-07-23 14:36:04 +00:00
|
|
|
return;
|
2010-01-29 03:20:04 +00:00
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2024-06-17 13:15:24 +00:00
|
|
|
/* 1. Save the flags early, as the XDP program might overwrite them.
|
|
|
|
* These flags ensure packets marked as VIRTIO_NET_HDR_F_DATA_VALID
|
|
|
|
* stay valid after XDP processing.
|
|
|
|
* 2. XDP doesn't work with partially checksummed packets (refer to
|
|
|
|
* virtnet_xdp_set()), so packets marked as
|
|
|
|
* VIRTIO_NET_HDR_F_NEEDS_CSUM get dropped during XDP processing.
|
|
|
|
*/
|
|
|
|
flags = ((struct virtio_net_common_hdr *)buf)->hdr.flags;
|
|
|
|
|
2013-11-28 11:30:59 +00:00
|
|
|
if (vi->mergeable_rx_bufs)
|
2018-07-23 14:36:04 +00:00
|
|
|
skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit,
|
2018-07-23 14:36:05 +00:00
|
|
|
stats);
|
2013-11-28 11:30:59 +00:00
|
|
|
else if (vi->big_packets)
|
2018-07-23 14:36:05 +00:00
|
|
|
skb = receive_big(dev, vi, rq, buf, len, stats);
|
2013-11-28 11:30:59 +00:00
|
|
|
else
|
2018-07-23 14:36:05 +00:00
|
|
|
skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit, stats);
|
2013-11-28 11:30:59 +00:00
|
|
|
|
|
|
|
if (unlikely(!skb))
|
2018-07-23 14:36:04 +00:00
|
|
|
return;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2024-07-08 11:25:31 +00:00
|
|
|
virtnet_receive_done(vi, rq, skb, flags);
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-07-19 08:54:47 +00:00
|
|
|
/* Unlike mergeable buffers, all buffers are allocated to the
|
|
|
|
* same size, except for the headroom. For this reason we do
|
|
|
|
* not need to use mergeable_len_to_ctx here - it is enough
|
|
|
|
* to store the headroom as the context ignoring the truesize.
|
|
|
|
*/
|
2014-10-23 21:12:10 +00:00
|
|
|
static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
gfp_t gfp)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
2017-02-21 08:46:28 +00:00
|
|
|
char *buf;
|
2017-02-03 03:16:29 +00:00
|
|
|
unsigned int xdp_headroom = virtnet_get_headroom(vi);
|
2017-07-19 08:54:47 +00:00
|
|
|
void *ctx = (void *)(unsigned long)xdp_headroom;
|
2017-02-21 08:46:28 +00:00
|
|
|
int len = vi->hdr_len + VIRTNET_RX_PAD + GOOD_PACKET_LEN + xdp_headroom;
|
2010-01-29 03:20:04 +00:00
|
|
|
int err;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2017-02-21 08:46:28 +00:00
|
|
|
len = SKB_DATA_ALIGN(len) +
|
|
|
|
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
2023-08-10 12:30:57 +00:00
|
|
|
|
|
|
|
buf = virtnet_rq_alloc(rq, len, gfp);
|
|
|
|
if (unlikely(!buf))
|
2010-01-29 03:20:04 +00:00
|
|
|
return -ENOMEM;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2024-09-19 08:13:51 +00:00
|
|
|
buf += VIRTNET_RX_PAD + xdp_headroom;
|
|
|
|
|
|
|
|
virtnet_rq_init_one_sg(rq, buf, vi->hdr_len + GOOD_PACKET_LEN);
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2017-07-19 08:54:47 +00:00
|
|
|
err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp);
|
2023-08-10 12:30:57 +00:00
|
|
|
if (err < 0) {
|
2024-09-06 12:31:35 +00:00
|
|
|
if (rq->do_dma)
|
|
|
|
virtnet_rq_unmap(rq, buf, 0);
|
2017-02-21 08:46:28 +00:00
|
|
|
put_page(virt_to_head_page(buf));
|
2023-08-10 12:30:57 +00:00
|
|
|
}
|
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
return err;
|
|
|
|
}
|
2008-04-18 03:24:27 +00:00
|
|
|
|
2014-10-24 13:55:57 +00:00
|
|
|
static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
gfp_t gfp)
|
2010-01-29 03:20:04 +00:00
|
|
|
{
|
|
|
|
struct page *first, *list = NULL;
|
|
|
|
char *p;
|
|
|
|
int i, err, offset;
|
|
|
|
|
2022-09-14 14:49:11 +00:00
|
|
|
sg_init_table(rq->sg, vi->big_packets_num_skbfrags + 2);
|
2014-09-11 00:47:36 +00:00
|
|
|
|
2022-09-14 14:49:11 +00:00
|
|
|
/* page in rq->sg[vi->big_packets_num_skbfrags + 1] is list tail */
|
|
|
|
for (i = vi->big_packets_num_skbfrags + 1; i > 1; --i) {
|
2012-12-07 07:04:55 +00:00
|
|
|
first = get_a_page(rq, gfp);
|
2010-01-29 03:20:04 +00:00
|
|
|
if (!first) {
|
|
|
|
if (list)
|
2012-12-07 07:04:55 +00:00
|
|
|
give_pages(rq, list);
|
2010-01-29 03:20:04 +00:00
|
|
|
return -ENOMEM;
|
2008-04-18 03:24:27 +00:00
|
|
|
}
|
2012-12-07 07:04:55 +00:00
|
|
|
sg_set_buf(&rq->sg[i], page_address(first), PAGE_SIZE);
|
2008-04-18 03:24:27 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
/* chain new page in list head to match sg */
|
|
|
|
first->private = (unsigned long)list;
|
|
|
|
list = first;
|
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
first = get_a_page(rq, gfp);
|
2010-01-29 03:20:04 +00:00
|
|
|
if (!first) {
|
2012-12-07 07:04:55 +00:00
|
|
|
give_pages(rq, list);
|
2010-01-29 03:20:04 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
p = page_address(first);
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
/* rq->sg[0], rq->sg[1] share the same page */
|
2014-10-24 13:55:57 +00:00
|
|
|
/* a separated rq->sg[0] for header - required in case !any_header_sg */
|
|
|
|
sg_set_buf(&rq->sg[0], p, vi->hdr_len);
|
2010-01-29 03:20:04 +00:00
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
/* rq->sg[1] for data packet, from offset */
|
2010-01-29 03:20:04 +00:00
|
|
|
offset = sizeof(struct padded_vnet_hdr);
|
2012-12-07 07:04:55 +00:00
|
|
|
sg_set_buf(&rq->sg[1], p + offset, PAGE_SIZE - offset);
|
2010-01-29 03:20:04 +00:00
|
|
|
|
|
|
|
/* chain first in list head */
|
|
|
|
first->private = (unsigned long)list;
|
2022-09-14 14:49:11 +00:00
|
|
|
err = virtqueue_add_inbuf(rq->vq, rq->sg, vi->big_packets_num_skbfrags + 2,
|
2013-03-20 05:14:28 +00:00
|
|
|
first, gfp);
|
2010-01-29 03:20:04 +00:00
|
|
|
if (err < 0)
|
2012-12-07 07:04:55 +00:00
|
|
|
give_pages(rq, first);
|
2010-01-29 03:20:04 +00:00
|
|
|
|
|
|
|
return err;
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 00:21:21 +00:00
|
|
|
static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
|
2018-03-02 09:29:14 +00:00
|
|
|
struct ewma_pkt_len *avg_pkt_len,
|
|
|
|
unsigned int room)
|
2008-11-17 06:41:34 +00:00
|
|
|
{
|
2022-03-28 17:53:33 +00:00
|
|
|
struct virtnet_info *vi = rq->vq->vdev->priv;
|
|
|
|
const size_t hdr_len = vi->hdr_len;
|
2014-01-17 06:23:30 +00:00
|
|
|
unsigned int len;
|
|
|
|
|
2018-03-02 09:29:14 +00:00
|
|
|
if (room)
|
|
|
|
return PAGE_SIZE - room;
|
|
|
|
|
|
|
|
len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len),
|
2017-06-02 14:54:33 +00:00
|
|
|
rq->min_buf_len, PAGE_SIZE - hdr_len);
|
2018-03-02 09:29:14 +00:00
|
|
|
|
2017-03-06 20:21:35 +00:00
|
|
|
return ALIGN(len, L1_CACHE_BYTES);
|
2014-01-17 06:23:30 +00:00
|
|
|
}
|
|
|
|
|
2017-02-03 03:16:29 +00:00
|
|
|
static int add_recvbuf_mergeable(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq, gfp_t gfp)
|
2014-01-17 06:23:30 +00:00
|
|
|
{
|
2014-01-17 06:23:26 +00:00
|
|
|
struct page_frag *alloc_frag = &rq->alloc_frag;
|
2017-02-03 03:16:29 +00:00
|
|
|
unsigned int headroom = virtnet_get_headroom(vi);
|
2018-03-02 09:29:14 +00:00
|
|
|
unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
|
|
|
|
unsigned int room = SKB_DATA_ALIGN(headroom + tailroom);
|
2023-08-10 12:30:57 +00:00
|
|
|
unsigned int len, hole;
|
2017-03-06 19:29:47 +00:00
|
|
|
void *ctx;
|
2023-08-10 12:30:57 +00:00
|
|
|
char *buf;
|
2008-11-17 06:41:34 +00:00
|
|
|
int err;
|
|
|
|
|
2018-03-02 09:29:14 +00:00
|
|
|
/* Extra tailroom is needed to satisfy XDP's assumption. This
|
|
|
|
* means rx frags coalescing won't work, but consider we've
|
|
|
|
* disabled GSO for XDP, it won't be a big issue.
|
|
|
|
*/
|
|
|
|
len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room);
|
2023-08-10 12:30:57 +00:00
|
|
|
|
|
|
|
buf = virtnet_rq_alloc(rq, len + room, gfp);
|
|
|
|
if (unlikely(!buf))
|
2010-01-29 03:20:04 +00:00
|
|
|
return -ENOMEM;
|
2014-01-17 06:23:27 +00:00
|
|
|
|
2017-02-03 03:16:29 +00:00
|
|
|
buf += headroom; /* advance address leaving hole at front of pkt */
|
2014-01-17 06:23:26 +00:00
|
|
|
hole = alloc_frag->size - alloc_frag->offset;
|
2018-03-02 09:29:14 +00:00
|
|
|
if (hole < len + room) {
|
2014-01-17 06:23:27 +00:00
|
|
|
/* To avoid internal fragmentation, if there is very likely not
|
|
|
|
* enough space for another buffer, add the remaining space to
|
2017-07-31 18:49:49 +00:00
|
|
|
* the current buffer.
|
2023-01-14 08:22:20 +00:00
|
|
|
* XDP core assumes that frame_size of xdp_buff and the length
|
|
|
|
* of the frag are PAGE_SIZE, so we disable the hole mechanism.
|
2014-01-17 06:23:27 +00:00
|
|
|
*/
|
2023-01-14 08:22:20 +00:00
|
|
|
if (!headroom)
|
|
|
|
len += hole;
|
2014-01-17 06:23:26 +00:00
|
|
|
alloc_frag->offset += hole;
|
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2023-08-10 12:30:57 +00:00
|
|
|
virtnet_rq_init_one_sg(rq, buf, len);
|
|
|
|
|
2023-01-14 08:22:24 +00:00
|
|
|
ctx = mergeable_len_to_ctx(len + room, headroom);
|
2017-03-06 19:29:47 +00:00
|
|
|
err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp);
|
2023-08-10 12:30:57 +00:00
|
|
|
if (err < 0) {
|
2024-09-06 12:31:35 +00:00
|
|
|
if (rq->do_dma)
|
|
|
|
virtnet_rq_unmap(rq, buf, 0);
|
2013-10-28 22:44:18 +00:00
|
|
|
put_page(virt_to_head_page(buf));
|
2023-08-10 12:30:57 +00:00
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
return err;
|
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2011-12-29 00:42:38 +00:00
|
|
|
/*
|
|
|
|
* Returns false if we couldn't fill entirely (OOM).
|
|
|
|
*
|
|
|
|
* Normally run in the receive path, but can also be run from ndo_open
|
|
|
|
* before we're receiving packets, or from refill_work which is
|
|
|
|
* careful to disable receiving (using napi_disable).
|
|
|
|
*/
|
2014-10-23 21:12:10 +00:00
|
|
|
static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
gfp_t gfp)
|
2010-01-29 03:20:04 +00:00
|
|
|
{
|
|
|
|
int err;
|
2024-07-08 11:25:35 +00:00
|
|
|
|
|
|
|
if (rq->xsk_pool) {
|
|
|
|
err = virtnet_add_recvbuf_xsk(vi, rq, rq->xsk_pool, gfp);
|
|
|
|
goto kick;
|
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2010-01-29 03:20:04 +00:00
|
|
|
do {
|
|
|
|
if (vi->mergeable_rx_bufs)
|
2017-02-03 03:16:29 +00:00
|
|
|
err = add_recvbuf_mergeable(vi, rq, gfp);
|
2010-01-29 03:20:04 +00:00
|
|
|
else if (vi->big_packets)
|
2014-10-24 13:55:57 +00:00
|
|
|
err = add_recvbuf_big(vi, rq, gfp);
|
2010-01-29 03:20:04 +00:00
|
|
|
else
|
2014-10-23 21:12:10 +00:00
|
|
|
err = add_recvbuf_small(vi, rq, gfp);
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2012-10-16 13:26:14 +00:00
|
|
|
if (err)
|
2008-11-17 06:41:34 +00:00
|
|
|
break;
|
2012-12-20 16:37:04 +00:00
|
|
|
} while (rq->vq->num_free);
|
2024-07-08 11:25:35 +00:00
|
|
|
|
|
|
|
kick:
|
2018-07-23 14:36:09 +00:00
|
|
|
if (virtqueue_kick_prepare(rq->vq) && virtqueue_notify(rq->vq)) {
|
2020-05-07 07:25:56 +00:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
flags = u64_stats_update_begin_irqsave(&rq->stats.syncp);
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&rq->stats.kicks);
|
2020-05-07 07:25:56 +00:00
|
|
|
u64_stats_update_end_irqrestore(&rq->stats.syncp, flags);
|
2018-07-23 14:36:09 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:35 +00:00
|
|
|
return err != -ENOMEM;
|
2008-11-17 06:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-02-05 04:49:57 +00:00
|
|
|
static void skb_recv_done(struct virtqueue *rvq)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = rvq->vdev->priv;
|
2012-12-07 07:04:56 +00:00
|
|
|
struct receive_queue *rq = &vi->rq[vq2rxq(rvq)];
|
2012-12-07 07:04:55 +00:00
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
rq->calls++;
|
2017-04-24 17:49:26 +00:00
|
|
|
virtqueue_napi_schedule(&rq->napi, rvq);
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-04-24 17:49:26 +00:00
|
|
|
static void virtnet_napi_enable(struct virtqueue *vq, struct napi_struct *napi)
|
2011-02-10 19:03:31 +00:00
|
|
|
{
|
2017-04-24 17:49:26 +00:00
|
|
|
napi_enable(napi);
|
2011-02-10 19:03:31 +00:00
|
|
|
|
|
|
|
/* If all buffers were filled by other side before we napi_enabled, we
|
2017-04-24 17:49:26 +00:00
|
|
|
* won't get another interrupt, so process any outstanding packets now.
|
|
|
|
* Call local_bh_enable after to trigger softIRQ processing.
|
|
|
|
*/
|
|
|
|
local_bh_disable();
|
|
|
|
virtqueue_napi_schedule(napi, vq);
|
|
|
|
local_bh_enable();
|
2011-02-10 19:03:31 +00:00
|
|
|
}
|
|
|
|
|
2017-04-24 17:49:27 +00:00
|
|
|
static void virtnet_napi_tx_enable(struct virtnet_info *vi,
|
|
|
|
struct virtqueue *vq,
|
|
|
|
struct napi_struct *napi)
|
|
|
|
{
|
|
|
|
if (!napi->weight)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Tx napi touches cachelines on the cpu handling tx interrupts. Only
|
|
|
|
* enable the feature if this is likely affine with the transmit path.
|
|
|
|
*/
|
|
|
|
if (!vi->affinity_hint_set) {
|
|
|
|
napi->weight = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virtnet_napi_enable(vq, napi);
|
|
|
|
}
|
|
|
|
|
2017-04-25 19:59:17 +00:00
|
|
|
static void virtnet_napi_tx_disable(struct napi_struct *napi)
|
|
|
|
{
|
|
|
|
if (napi->weight)
|
|
|
|
napi_disable(napi);
|
|
|
|
}
|
|
|
|
|
2009-08-26 19:22:32 +00:00
|
|
|
static void refill_work(struct work_struct *work)
|
|
|
|
{
|
2012-12-07 07:04:55 +00:00
|
|
|
struct virtnet_info *vi =
|
|
|
|
container_of(work, struct virtnet_info, refill.work);
|
2009-08-26 19:22:32 +00:00
|
|
|
bool still_empty;
|
2012-12-07 07:04:56 +00:00
|
|
|
int i;
|
|
|
|
|
2013-04-29 02:30:08 +00:00
|
|
|
for (i = 0; i < vi->curr_queue_pairs; i++) {
|
2012-12-07 07:04:56 +00:00
|
|
|
struct receive_queue *rq = &vi->rq[i];
|
2009-08-26 19:22:32 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
napi_disable(&rq->napi);
|
2014-10-23 21:12:10 +00:00
|
|
|
still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
|
2017-04-24 17:49:26 +00:00
|
|
|
virtnet_napi_enable(rq->vq, &rq->napi);
|
2009-08-26 19:22:32 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* In theory, this can happen: if we don't get any buffers in
|
|
|
|
* we will *never* try to fill again.
|
|
|
|
*/
|
|
|
|
if (still_empty)
|
|
|
|
schedule_delayed_work(&vi->refill, HZ/2);
|
|
|
|
}
|
2009-08-26 19:22:32 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:36 +00:00
|
|
|
static int virtnet_receive_xsk_bufs(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
int budget,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
|
|
|
{
|
|
|
|
unsigned int len;
|
|
|
|
int packets = 0;
|
|
|
|
void *buf;
|
|
|
|
|
|
|
|
while (packets < budget) {
|
|
|
|
buf = virtqueue_get_buf(rq->vq, &len);
|
|
|
|
if (!buf)
|
|
|
|
break;
|
|
|
|
|
|
|
|
virtnet_receive_xsk_buf(vi, rq, buf, len, xdp_xmit, stats);
|
|
|
|
packets++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return packets;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_receive_packets(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq,
|
|
|
|
int budget,
|
|
|
|
unsigned int *xdp_xmit,
|
|
|
|
struct virtnet_rq_stats *stats)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
2018-07-23 14:36:05 +00:00
|
|
|
unsigned int len;
|
2023-10-26 17:18:40 +00:00
|
|
|
int packets = 0;
|
2010-01-29 03:20:04 +00:00
|
|
|
void *buf;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2017-07-19 08:54:47 +00:00
|
|
|
if (!vi->big_packets || vi->mergeable_rx_bufs) {
|
2017-03-06 19:29:47 +00:00
|
|
|
void *ctx;
|
2023-10-26 17:18:40 +00:00
|
|
|
while (packets < budget &&
|
2023-08-10 12:30:57 +00:00
|
|
|
(buf = virtnet_rq_get_buf(rq, &len, &ctx))) {
|
2024-07-08 11:25:36 +00:00
|
|
|
receive_buf(vi, rq, buf, len, ctx, xdp_xmit, stats);
|
2023-10-26 17:18:40 +00:00
|
|
|
packets++;
|
2017-03-06 19:29:47 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-10-26 17:18:40 +00:00
|
|
|
while (packets < budget &&
|
2024-09-06 12:31:36 +00:00
|
|
|
(buf = virtnet_rq_get_buf(rq, &len, NULL)) != NULL) {
|
2024-07-08 11:25:36 +00:00
|
|
|
receive_buf(vi, rq, buf, len, NULL, xdp_xmit, stats);
|
2023-10-26 17:18:40 +00:00
|
|
|
packets++;
|
2017-03-06 19:29:47 +00:00
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:36 +00:00
|
|
|
return packets;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_receive(struct receive_queue *rq, int budget,
|
|
|
|
unsigned int *xdp_xmit)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = rq->vq->vdev->priv;
|
|
|
|
struct virtnet_rq_stats stats = {};
|
|
|
|
int i, packets;
|
|
|
|
|
|
|
|
if (rq->xsk_pool)
|
|
|
|
packets = virtnet_receive_xsk_bufs(vi, rq, budget, xdp_xmit, &stats);
|
|
|
|
else
|
|
|
|
packets = virtnet_receive_packets(vi, rq, budget, xdp_xmit, &stats);
|
|
|
|
|
2019-08-20 02:51:23 +00:00
|
|
|
if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) {
|
2022-07-25 07:21:59 +00:00
|
|
|
if (!try_fill_recv(vi, rq, GFP_ATOMIC)) {
|
|
|
|
spin_lock(&vi->refill_lock);
|
|
|
|
if (vi->refill_enabled)
|
|
|
|
schedule_delayed_work(&vi->refill, 0);
|
|
|
|
spin_unlock(&vi->refill_lock);
|
|
|
|
}
|
2009-08-26 19:22:32 +00:00
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_set(&stats.packets, packets);
|
2018-01-17 06:38:25 +00:00
|
|
|
u64_stats_update_begin(&rq->stats.syncp);
|
2024-04-26 03:39:25 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(virtnet_rq_stats_desc); i++) {
|
2018-07-23 14:36:05 +00:00
|
|
|
size_t offset = virtnet_rq_stats_desc[i].offset;
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_t *item, *src;
|
2018-07-23 14:36:05 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
item = (u64_stats_t *)((u8 *)&rq->stats + offset);
|
|
|
|
src = (u64_stats_t *)((u8 *)&stats + offset);
|
|
|
|
u64_stats_add(item, u64_stats_read(src));
|
2018-07-23 14:36:05 +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>
2024-04-26 03:39:28 +00:00
|
|
|
|
|
|
|
u64_stats_add(&rq->stats.packets, u64_stats_read(&stats.packets));
|
|
|
|
u64_stats_add(&rq->stats.bytes, u64_stats_read(&stats.bytes));
|
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
u64_stats_update_end(&rq->stats.syncp);
|
2017-02-17 03:33:09 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
return packets;
|
2014-07-23 08:33:54 +00:00
|
|
|
}
|
|
|
|
|
2024-07-12 11:53:25 +00:00
|
|
|
static void virtnet_poll_cleantx(struct receive_queue *rq, int budget)
|
2017-04-24 17:49:29 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = rq->vq->vdev->priv;
|
|
|
|
unsigned int index = vq2rxq(rq->vq);
|
|
|
|
struct send_queue *sq = &vi->sq[index];
|
|
|
|
struct netdev_queue *txq = netdev_get_tx_queue(vi->dev, index);
|
|
|
|
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
if (!sq->napi.weight || is_xdp_raw_buffer_queue(vi, index))
|
2017-04-24 17:49:29 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (__netif_tx_trylock(txq)) {
|
2022-08-01 06:39:01 +00:00
|
|
|
if (sq->reset) {
|
|
|
|
__netif_tx_unlock(txq);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-13 05:30:45 +00:00
|
|
|
do {
|
|
|
|
virtqueue_disable_cb(sq->vq);
|
2024-07-12 11:53:25 +00:00
|
|
|
free_old_xmit(sq, txq, !!budget);
|
2021-04-13 05:30:45 +00:00
|
|
|
} while (unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
|
2021-04-13 05:38:08 +00:00
|
|
|
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) {
|
|
|
|
if (netif_tx_queue_stopped(txq)) {
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
|
|
|
u64_stats_inc(&sq->stats.wake);
|
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
|
|
|
}
|
2021-04-13 05:38:08 +00:00
|
|
|
netif_tx_wake_queue(txq);
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
}
|
2021-04-13 05:38:08 +00:00
|
|
|
|
2017-04-24 17:49:29 +00:00
|
|
|
__netif_tx_unlock(txq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
static void virtnet_rx_dim_update(struct virtnet_info *vi, struct receive_queue *rq)
|
|
|
|
{
|
|
|
|
struct dim_sample cur_sample = {};
|
|
|
|
|
|
|
|
if (!rq->packets_in_napi)
|
|
|
|
return;
|
|
|
|
|
2024-06-21 09:45:52 +00:00
|
|
|
/* Don't need protection when fetching stats, since fetcher and
|
|
|
|
* updater of the stats are in same context
|
|
|
|
*/
|
2023-12-11 10:36:07 +00:00
|
|
|
dim_update_sample(rq->calls,
|
|
|
|
u64_stats_read(&rq->stats.packets),
|
|
|
|
u64_stats_read(&rq->stats.bytes),
|
|
|
|
&cur_sample);
|
|
|
|
|
|
|
|
net_dim(&rq->dim, cur_sample);
|
|
|
|
rq->packets_in_napi = 0;
|
|
|
|
}
|
|
|
|
|
2014-07-23 08:33:54 +00:00
|
|
|
static int virtnet_poll(struct napi_struct *napi, int budget)
|
|
|
|
{
|
|
|
|
struct receive_queue *rq =
|
|
|
|
container_of(napi, struct receive_queue, napi);
|
2018-04-13 06:58:25 +00:00
|
|
|
struct virtnet_info *vi = rq->vq->vdev->priv;
|
|
|
|
struct send_queue *sq;
|
2018-07-23 14:36:07 +00:00
|
|
|
unsigned int received;
|
2018-06-26 15:39:58 +00:00
|
|
|
unsigned int xdp_xmit = 0;
|
2023-12-11 10:36:07 +00:00
|
|
|
bool napi_complete;
|
2014-07-23 08:33:54 +00:00
|
|
|
|
2024-07-12 11:53:25 +00:00
|
|
|
virtnet_poll_cleantx(rq, budget);
|
2017-04-24 17:49:29 +00:00
|
|
|
|
2017-09-19 09:42:43 +00:00
|
|
|
received = virtnet_receive(rq, budget, &xdp_xmit);
|
2023-12-11 10:36:07 +00:00
|
|
|
rq->packets_in_napi += received;
|
2014-07-23 08:33:54 +00:00
|
|
|
|
2023-01-25 07:48:59 +00:00
|
|
|
if (xdp_xmit & VIRTIO_XDP_REDIR)
|
|
|
|
xdp_do_flush();
|
|
|
|
|
2007-11-19 16:20:43 +00:00
|
|
|
/* Out of packets? */
|
2023-12-11 10:36:07 +00:00
|
|
|
if (received < budget) {
|
|
|
|
napi_complete = virtqueue_napi_complete(napi, rq->vq, received);
|
2024-05-03 20:24:44 +00:00
|
|
|
/* Intentionally not taking dim_lock here. This may result in a
|
|
|
|
* spurious net_dim call. But if that happens virtnet_rx_dim_work
|
|
|
|
* will not act on the scheduled work.
|
|
|
|
*/
|
2023-12-11 10:36:07 +00:00
|
|
|
if (napi_complete && rq->dim_enabled)
|
|
|
|
virtnet_rx_dim_update(vi, rq);
|
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2018-06-26 15:39:58 +00:00
|
|
|
if (xdp_xmit & VIRTIO_XDP_TX) {
|
2021-03-10 02:24:45 +00:00
|
|
|
sq = virtnet_xdp_get_sq(vi);
|
2018-07-23 14:36:09 +00:00
|
|
|
if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&sq->stats.kicks);
|
2018-07-23 14:36:09 +00:00
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
|
|
|
}
|
2021-03-10 02:24:45 +00:00
|
|
|
virtnet_xdp_put_sq(vi, sq);
|
2018-04-13 06:58:25 +00:00
|
|
|
}
|
2017-09-19 09:42:43 +00:00
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
return received;
|
|
|
|
}
|
|
|
|
|
2023-05-12 15:18:12 +00:00
|
|
|
static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
|
|
|
|
{
|
|
|
|
virtnet_napi_tx_disable(&vi->sq[qp_index].napi);
|
|
|
|
napi_disable(&vi->rq[qp_index].napi);
|
|
|
|
xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
|
|
|
|
{
|
|
|
|
struct net_device *dev = vi->dev;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = xdp_rxq_info_reg(&vi->rq[qp_index].xdp_rxq, dev, qp_index,
|
|
|
|
vi->rq[qp_index].napi.napi_id);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = xdp_rxq_info_reg_mem_model(&vi->rq[qp_index].xdp_rxq,
|
|
|
|
MEM_TYPE_PAGE_SHARED, NULL);
|
|
|
|
if (err < 0)
|
|
|
|
goto err_xdp_reg_mem_model;
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, qp_index));
|
2024-08-14 12:25:00 +00:00
|
|
|
virtnet_napi_enable(vi->rq[qp_index].vq, &vi->rq[qp_index].napi);
|
2023-05-12 15:18:12 +00:00
|
|
|
virtnet_napi_tx_enable(vi, vi->sq[qp_index].vq, &vi->sq[qp_index].napi);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_xdp_reg_mem_model:
|
|
|
|
xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-06-21 10:13:53 +00:00
|
|
|
static void virtnet_cancel_dim(struct virtnet_info *vi, struct dim *dim)
|
|
|
|
{
|
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
|
|
|
|
return;
|
|
|
|
net_dim_work_cancel(dim);
|
|
|
|
}
|
|
|
|
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
static void virtnet_update_settings(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
u32 speed;
|
|
|
|
u8 duplex;
|
|
|
|
|
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_SPEED_DUPLEX))
|
|
|
|
return;
|
|
|
|
|
|
|
|
virtio_cread_le(vi->vdev, struct virtio_net_config, speed, &speed);
|
|
|
|
|
|
|
|
if (ethtool_validate_speed(speed))
|
|
|
|
vi->speed = speed;
|
|
|
|
|
|
|
|
virtio_cread_le(vi->vdev, struct virtio_net_config, duplex, &duplex);
|
|
|
|
|
|
|
|
if (ethtool_validate_duplex(duplex))
|
|
|
|
vi->duplex = duplex;
|
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
static int virtnet_open(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2018-01-03 10:26:04 +00:00
|
|
|
int i, err;
|
2012-12-07 07:04:56 +00:00
|
|
|
|
2022-07-25 07:21:59 +00:00
|
|
|
enable_delayed_refill(vi);
|
|
|
|
|
2013-05-21 20:03:58 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
if (i < vi->curr_queue_pairs)
|
|
|
|
/* Make sure we have some buffers: if oom use wq. */
|
2014-10-23 21:12:10 +00:00
|
|
|
if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
|
2013-05-21 20:03:58 +00:00
|
|
|
schedule_delayed_work(&vi->refill, 0);
|
2018-01-03 10:26:04 +00:00
|
|
|
|
2023-05-12 15:18:12 +00:00
|
|
|
err = virtnet_enable_queue_pair(vi, i);
|
2018-01-03 10:26:04 +00:00
|
|
|
if (err < 0)
|
2023-05-12 15:18:12 +00:00
|
|
|
goto err_enable_qp;
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
|
|
|
|
if (vi->status & VIRTIO_NET_S_LINK_UP)
|
|
|
|
netif_carrier_on(vi->dev);
|
|
|
|
virtio_config_driver_enable(vi->vdev);
|
|
|
|
} else {
|
|
|
|
vi->status = VIRTIO_NET_S_LINK_UP;
|
|
|
|
netif_carrier_on(dev);
|
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
return 0;
|
2023-05-12 15:18:12 +00:00
|
|
|
|
|
|
|
err_enable_qp:
|
|
|
|
disable_delayed_refill(vi);
|
|
|
|
cancel_delayed_work_sync(&vi->refill);
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
for (i--; i >= 0; i--) {
|
2023-05-12 15:18:12 +00:00
|
|
|
virtnet_disable_queue_pair(vi, i);
|
2024-06-21 10:13:53 +00:00
|
|
|
virtnet_cancel_dim(vi, &vi->rq[i].dim);
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
|
|
|
|
2023-05-12 15:18:12 +00:00
|
|
|
return err;
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2017-04-24 17:49:27 +00:00
|
|
|
static int virtnet_poll_tx(struct napi_struct *napi, int budget)
|
|
|
|
{
|
|
|
|
struct send_queue *sq = container_of(napi, struct send_queue, napi);
|
|
|
|
struct virtnet_info *vi = sq->vq->vdev->priv;
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
unsigned int index = vq2txq(sq->vq);
|
|
|
|
struct netdev_queue *txq;
|
2021-04-13 05:35:26 +00:00
|
|
|
int opaque;
|
|
|
|
bool done;
|
2017-04-24 17:49:27 +00:00
|
|
|
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
if (unlikely(is_xdp_raw_buffer_queue(vi, index))) {
|
|
|
|
/* We don't need to enable cb for XDP */
|
|
|
|
napi_complete_done(napi, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
txq = netdev_get_tx_queue(vi->dev, index);
|
2017-04-24 17:49:27 +00:00
|
|
|
__netif_tx_lock(txq, raw_smp_processor_id());
|
2021-04-13 05:35:26 +00:00
|
|
|
virtqueue_disable_cb(sq->vq);
|
2024-07-12 11:53:25 +00:00
|
|
|
free_old_xmit(sq, txq, !!budget);
|
2021-04-13 05:35:26 +00:00
|
|
|
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) {
|
|
|
|
if (netif_tx_queue_stopped(txq)) {
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
|
|
|
u64_stats_inc(&sq->stats.wake);
|
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
|
|
|
}
|
2021-04-13 05:38:08 +00:00
|
|
|
netif_tx_wake_queue(txq);
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
}
|
2021-04-13 05:38:08 +00:00
|
|
|
|
2021-04-13 05:35:26 +00:00
|
|
|
opaque = virtqueue_enable_cb_prepare(sq->vq);
|
|
|
|
|
|
|
|
done = napi_complete_done(napi, 0);
|
|
|
|
|
|
|
|
if (!done)
|
|
|
|
virtqueue_disable_cb(sq->vq);
|
|
|
|
|
2017-04-24 17:49:27 +00:00
|
|
|
__netif_tx_unlock(txq);
|
|
|
|
|
2021-04-13 05:35:26 +00:00
|
|
|
if (done) {
|
|
|
|
if (unlikely(virtqueue_poll(sq->vq, opaque))) {
|
|
|
|
if (napi_schedule_prep(napi)) {
|
|
|
|
__netif_tx_lock(txq, raw_smp_processor_id());
|
|
|
|
virtqueue_disable_cb(sq->vq);
|
|
|
|
__netif_tx_unlock(txq);
|
|
|
|
__napi_schedule(napi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-04-24 17:49:27 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
2014-10-24 13:55:57 +00:00
|
|
|
struct virtio_net_hdr_mrg_rxbuf *hdr;
|
2007-10-22 01:03:37 +00:00
|
|
|
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
|
2012-12-07 07:04:55 +00:00
|
|
|
struct virtnet_info *vi = sq->vq->vdev->priv;
|
2017-06-04 02:16:26 +00:00
|
|
|
int num_sg;
|
2014-10-24 13:55:57 +00:00
|
|
|
unsigned hdr_len = vi->hdr_len;
|
2013-07-25 00:50:23 +00:00
|
|
|
bool can_push;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2008-10-27 22:59:26 +00:00
|
|
|
pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
|
2013-07-25 00:50:23 +00:00
|
|
|
|
|
|
|
can_push = vi->any_header_sg &&
|
|
|
|
!((unsigned long)skb->data & (__alignof__(*hdr) - 1)) &&
|
|
|
|
!skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len;
|
|
|
|
/* Even if we can, don't push here yet as this would skew
|
|
|
|
* csum_start offset below. */
|
|
|
|
if (can_push)
|
2014-10-24 13:55:57 +00:00
|
|
|
hdr = (struct virtio_net_hdr_mrg_rxbuf *)(skb->data - hdr_len);
|
2013-07-25 00:50:23 +00:00
|
|
|
else
|
virtio_net: Introduce skb_vnet_common_hdr to avoid typecasting
The virtio_net driver currently deals with different versions and types
of virtio net headers, such as virtio_net_hdr_mrg_rxbuf,
virtio_net_hdr_v1_hash, etc. Due to these variations, the code relies
on multiple type casts to convert memory between different structures,
potentially leading to bugs when there are changes in these structures.
Introduces the "struct skb_vnet_common_hdr" as a unifying header
structure using a union. With this approach, various virtio net header
structures can be converted by accessing different members of this
structure, thus eliminating the need for type casting and reducing the
risk of potential bugs.
For example following code:
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize,
unsigned int headroom)
{
[...]
struct virtio_net_hdr_mrg_rxbuf *hdr;
[...]
hdr_len = vi->hdr_len;
[...]
ok:
hdr = skb_vnet_hdr(skb);
memcpy(hdr, hdr_p, hdr_len);
[...]
}
When VIRTIO_NET_F_HASH_REPORT feature is enabled, hdr_len = 20
But the sizeof(*hdr) is 12,
memcpy(hdr, hdr_p, hdr_len); will copy 20 bytes to the hdr,
which make a potential risk of bug. And this risk can be avoided by
introducing struct skb_vnet_common_hdr.
Change log
v1->v2
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
feedback from Simon Horman <horms@kernel.org>
1. change to use net-next tree.
2. move skb_vnet_common_hdr inside kernel file instead of the UAPI header.
v2->v3
feedback from Willem de Bruijn <willemdebruijn.kernel@gmail.com>
1. fix typo in commit message.
2. add original struct virtio_net_hdr into union
3. remove virtio_net_hdr_mrg_rxbuf variable in receive_buf;
Signed-off-by: Feng Liu <feliu@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2023-08-21 14:27:13 +00:00
|
|
|
hdr = &skb_vnet_common_hdr(skb)->mrg_hdr;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2016-06-08 13:09:21 +00:00
|
|
|
if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
|
2018-06-06 15:23:01 +00:00
|
|
|
virtio_is_little_endian(vi->vdev), false,
|
|
|
|
0))
|
2021-06-05 15:31:00 +00:00
|
|
|
return -EPROTO;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2008-11-17 06:41:34 +00:00
|
|
|
if (vi->mergeable_rx_bufs)
|
2014-10-24 13:55:57 +00:00
|
|
|
hdr->num_buffers = 0;
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2015-08-27 06:53:06 +00:00
|
|
|
sg_init_table(sq->sg, skb_shinfo(skb)->nr_frags + (can_push ? 1 : 2));
|
2013-07-25 00:50:23 +00:00
|
|
|
if (can_push) {
|
|
|
|
__skb_push(skb, hdr_len);
|
|
|
|
num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
|
2017-06-04 02:16:26 +00:00
|
|
|
if (unlikely(num_sg < 0))
|
|
|
|
return num_sg;
|
2013-07-25 00:50:23 +00:00
|
|
|
/* Pull header back to avoid skew in tx bytes calculations. */
|
|
|
|
__skb_pull(skb, hdr_len);
|
|
|
|
} else {
|
|
|
|
sg_set_buf(sq->sg, hdr, hdr_len);
|
2017-06-04 02:16:26 +00:00
|
|
|
num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len);
|
|
|
|
if (unlikely(num_sg < 0))
|
|
|
|
return num_sg;
|
|
|
|
num_sg++;
|
2013-07-25 00:50:23 +00:00
|
|
|
}
|
2024-06-18 14:44:56 +00:00
|
|
|
return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg,
|
|
|
|
skb_to_ptr(skb, orphan), GFP_ATOMIC);
|
2008-05-26 07:48:13 +00:00
|
|
|
}
|
|
|
|
|
2009-08-31 19:50:51 +00:00
|
|
|
static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
|
2008-05-03 02:50:46 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2012-12-07 07:04:56 +00:00
|
|
|
int qnum = skb_get_queue_mapping(skb);
|
|
|
|
struct send_queue *sq = &vi->sq[qnum];
|
2012-10-16 13:26:14 +00:00
|
|
|
int err;
|
2014-10-15 13:23:28 +00:00
|
|
|
struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
|
2024-06-18 14:44:56 +00:00
|
|
|
bool xmit_more = netdev_xmit_more();
|
2017-04-24 17:49:27 +00:00
|
|
|
bool use_napi = sq->napi.weight;
|
2024-06-18 14:44:56 +00:00
|
|
|
bool kick;
|
2008-02-05 04:50:07 +00:00
|
|
|
|
|
|
|
/* Free up any pending old buffers before queueing new ones. */
|
2021-04-13 05:30:45 +00:00
|
|
|
do {
|
|
|
|
if (use_napi)
|
|
|
|
virtqueue_disable_cb(sq->vq);
|
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
free_old_xmit(sq, txq, false);
|
2008-05-03 02:50:46 +00:00
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
} while (use_napi && !xmit_more &&
|
2021-04-13 05:30:45 +00:00
|
|
|
unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
|
2017-04-24 17:49:30 +00:00
|
|
|
|
2014-06-25 02:37:13 +00:00
|
|
|
/* timestamp packet in software */
|
|
|
|
skb_tx_timestamp(skb);
|
|
|
|
|
2009-10-28 11:03:38 +00:00
|
|
|
/* Try to transmit */
|
2024-06-18 14:44:56 +00:00
|
|
|
err = xmit_skb(sq, skb, !use_napi);
|
2009-09-24 15:59:20 +00:00
|
|
|
|
2012-10-16 13:26:14 +00:00
|
|
|
/* This should not happen! */
|
2014-03-26 05:03:00 +00:00
|
|
|
if (unlikely(err)) {
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, tx_fifo_errors);
|
2012-10-16 13:26:14 +00:00
|
|
|
if (net_ratelimit())
|
|
|
|
dev_warn(&dev->dev,
|
2019-04-03 09:10:13 +00:00
|
|
|
"Unexpected TXQ (%d) queue failure: %d\n",
|
|
|
|
qnum, err);
|
2023-09-21 08:52:17 +00:00
|
|
|
DEV_STATS_INC(dev, tx_dropped);
|
2014-03-16 01:43:33 +00:00
|
|
|
dev_kfree_skb_any(skb);
|
2010-07-02 16:34:01 +00:00
|
|
|
return NETDEV_TX_OK;
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
2009-10-28 11:03:38 +00:00
|
|
|
|
2009-09-24 15:59:20 +00:00
|
|
|
/* Don't wait up for transmitted skbs to be freed. */
|
2017-04-24 17:49:27 +00:00
|
|
|
if (!use_napi) {
|
|
|
|
skb_orphan(skb);
|
2019-09-29 18:54:03 +00:00
|
|
|
nf_reset_ct(skb);
|
2017-04-24 17:49:27 +00:00
|
|
|
}
|
2009-09-24 15:59:20 +00:00
|
|
|
|
2023-03-08 02:49:34 +00:00
|
|
|
check_sq_full_and_disable(vi, dev, sq);
|
2009-09-24 15:59:20 +00:00
|
|
|
|
2024-06-18 14:44:56 +00:00
|
|
|
kick = use_napi ? __netdev_tx_sent_queue(txq, skb->len, xmit_more) :
|
|
|
|
!xmit_more || netif_xmit_stopped(txq);
|
|
|
|
if (kick) {
|
2018-07-23 14:36:09 +00:00
|
|
|
if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&sq->stats.kicks);
|
2018-07-23 14:36:09 +00:00
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
|
|
|
}
|
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2014-08-25 22:51:53 +00:00
|
|
|
return NETDEV_TX_OK;
|
2014-08-23 20:18:10 +00:00
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:29 +00:00
|
|
|
static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
|
2022-08-01 06:39:00 +00:00
|
|
|
{
|
|
|
|
bool running = netif_running(vi->dev);
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
if (running) {
|
2022-08-01 06:39:00 +00:00
|
|
|
napi_disable(&rq->napi);
|
2024-06-21 10:13:53 +00:00
|
|
|
virtnet_cancel_dim(vi, &rq->dim);
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
2024-07-08 11:25:29 +00:00
|
|
|
}
|
2022-08-01 06:39:00 +00:00
|
|
|
|
2024-07-08 11:25:29 +00:00
|
|
|
static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
|
|
|
|
{
|
|
|
|
bool running = netif_running(vi->dev);
|
2022-08-01 06:39:00 +00:00
|
|
|
|
|
|
|
if (!try_fill_recv(vi, rq, GFP_KERNEL))
|
|
|
|
schedule_delayed_work(&vi->refill, 0);
|
|
|
|
|
|
|
|
if (running)
|
|
|
|
virtnet_napi_enable(rq->vq, &rq->napi);
|
2024-07-08 11:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_rx_resize(struct virtnet_info *vi,
|
|
|
|
struct receive_queue *rq, u32 ring_num)
|
|
|
|
{
|
|
|
|
int err, qindex;
|
|
|
|
|
|
|
|
qindex = rq - vi->rq;
|
|
|
|
|
|
|
|
virtnet_rx_pause(vi, rq);
|
|
|
|
|
|
|
|
err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf);
|
|
|
|
if (err)
|
|
|
|
netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err);
|
|
|
|
|
|
|
|
virtnet_rx_resume(vi, rq);
|
2022-08-01 06:39:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:30 +00:00
|
|
|
static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
|
2022-08-01 06:39:01 +00:00
|
|
|
{
|
|
|
|
bool running = netif_running(vi->dev);
|
|
|
|
struct netdev_queue *txq;
|
2024-07-08 11:25:30 +00:00
|
|
|
int qindex;
|
2022-08-01 06:39:01 +00:00
|
|
|
|
|
|
|
qindex = sq - vi->sq;
|
|
|
|
|
|
|
|
if (running)
|
|
|
|
virtnet_napi_tx_disable(&sq->napi);
|
|
|
|
|
|
|
|
txq = netdev_get_tx_queue(vi->dev, qindex);
|
|
|
|
|
|
|
|
/* 1. wait all ximt complete
|
|
|
|
* 2. fix the race of netif_stop_subqueue() vs netif_start_subqueue()
|
|
|
|
*/
|
|
|
|
__netif_tx_lock_bh(txq);
|
|
|
|
|
|
|
|
/* Prevent rx poll from accessing sq. */
|
|
|
|
sq->reset = true;
|
|
|
|
|
|
|
|
/* Prevent the upper layer from trying to send packets. */
|
|
|
|
netif_stop_subqueue(vi->dev, qindex);
|
|
|
|
|
|
|
|
__netif_tx_unlock_bh(txq);
|
2024-07-08 11:25:30 +00:00
|
|
|
}
|
2022-08-01 06:39:01 +00:00
|
|
|
|
2024-07-08 11:25:30 +00:00
|
|
|
static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
|
|
|
|
{
|
|
|
|
bool running = netif_running(vi->dev);
|
|
|
|
struct netdev_queue *txq;
|
|
|
|
int qindex;
|
|
|
|
|
|
|
|
qindex = sq - vi->sq;
|
|
|
|
|
|
|
|
txq = netdev_get_tx_queue(vi->dev, qindex);
|
2022-08-01 06:39:01 +00:00
|
|
|
|
|
|
|
__netif_tx_lock_bh(txq);
|
|
|
|
sq->reset = false;
|
|
|
|
netif_tx_wake_queue(txq);
|
|
|
|
__netif_tx_unlock_bh(txq);
|
|
|
|
|
|
|
|
if (running)
|
|
|
|
virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
|
2024-07-08 11:25:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq,
|
|
|
|
u32 ring_num)
|
|
|
|
{
|
|
|
|
int qindex, err;
|
|
|
|
|
|
|
|
qindex = sq - vi->sq;
|
|
|
|
|
|
|
|
virtnet_tx_pause(vi, sq);
|
|
|
|
|
|
|
|
err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf);
|
|
|
|
if (err)
|
|
|
|
netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err);
|
|
|
|
|
|
|
|
virtnet_tx_resume(vi, sq);
|
|
|
|
|
2022-08-01 06:39:01 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-01-21 01:17:21 +00:00
|
|
|
/*
|
|
|
|
* Send command via the control virtqueue and check status. Commands
|
|
|
|
* supported by the hypervisor, as indicated by feature bits, should
|
2013-12-10 00:18:45 +00:00
|
|
|
* never fail unless improperly formatted.
|
2013-01-21 01:17:21 +00:00
|
|
|
*/
|
2024-04-26 03:39:21 +00:00
|
|
|
static bool virtnet_send_command_reply(struct virtnet_info *vi, u8 class, u8 cmd,
|
|
|
|
struct scatterlist *out,
|
|
|
|
struct scatterlist *in)
|
2013-01-21 01:17:21 +00:00
|
|
|
{
|
2024-04-26 03:39:21 +00:00
|
|
|
struct scatterlist *sgs[5], hdr, stat;
|
|
|
|
u32 out_num = 0, tmp, in_num = 0;
|
2024-05-30 03:41:43 +00:00
|
|
|
bool ok;
|
2021-07-10 03:32:49 +00:00
|
|
|
int ret;
|
2013-01-21 01:17:21 +00:00
|
|
|
|
|
|
|
/* Caller should know better */
|
2013-03-20 05:14:28 +00:00
|
|
|
BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ));
|
2013-01-21 01:17:21 +00:00
|
|
|
|
2024-05-03 20:24:42 +00:00
|
|
|
mutex_lock(&vi->cvq_lock);
|
2018-04-19 05:30:48 +00:00
|
|
|
vi->ctrl->status = ~0;
|
|
|
|
vi->ctrl->hdr.class = class;
|
|
|
|
vi->ctrl->hdr.cmd = cmd;
|
2013-03-20 05:14:28 +00:00
|
|
|
/* Add header */
|
2018-04-19 05:30:48 +00:00
|
|
|
sg_init_one(&hdr, &vi->ctrl->hdr, sizeof(vi->ctrl->hdr));
|
2013-03-20 05:14:28 +00:00
|
|
|
sgs[out_num++] = &hdr;
|
2013-01-21 01:17:21 +00:00
|
|
|
|
2013-03-20 05:14:28 +00:00
|
|
|
if (out)
|
|
|
|
sgs[out_num++] = out;
|
2013-01-21 01:17:21 +00:00
|
|
|
|
2013-03-20 05:14:28 +00:00
|
|
|
/* Add return status. */
|
2018-04-19 05:30:48 +00:00
|
|
|
sg_init_one(&stat, &vi->ctrl->status, sizeof(vi->ctrl->status));
|
2024-04-26 03:39:21 +00:00
|
|
|
sgs[out_num + in_num++] = &stat;
|
2013-01-21 01:17:21 +00:00
|
|
|
|
2024-04-26 03:39:21 +00:00
|
|
|
if (in)
|
|
|
|
sgs[out_num + in_num++] = in;
|
|
|
|
|
|
|
|
BUG_ON(out_num + in_num > ARRAY_SIZE(sgs));
|
|
|
|
ret = virtqueue_add_sgs(vi->cvq, sgs, out_num, in_num, vi, GFP_ATOMIC);
|
2021-07-10 03:32:49 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
dev_warn(&vi->vdev->dev,
|
|
|
|
"Failed to add sgs for command vq: %d\n.", ret);
|
2024-05-03 20:24:42 +00:00
|
|
|
mutex_unlock(&vi->cvq_lock);
|
2021-07-10 03:32:49 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-21 01:17:21 +00:00
|
|
|
|
2013-10-28 23:10:02 +00:00
|
|
|
if (unlikely(!virtqueue_kick(vi->cvq)))
|
2024-05-03 20:24:42 +00:00
|
|
|
goto unlock;
|
2013-01-21 01:17:21 +00:00
|
|
|
|
|
|
|
/* Spin for a response, the kick causes an ioport write, trapping
|
|
|
|
* into the hypervisor, so the request should be handled immediately.
|
|
|
|
*/
|
2013-10-28 23:10:47 +00:00
|
|
|
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
|
2023-07-20 08:38:39 +00:00
|
|
|
!virtqueue_is_broken(vi->cvq)) {
|
|
|
|
cond_resched();
|
2013-01-21 01:17:21 +00:00
|
|
|
cpu_relax();
|
2023-07-20 08:38:39 +00:00
|
|
|
}
|
2013-01-21 01:17:21 +00:00
|
|
|
|
2024-05-03 20:24:42 +00:00
|
|
|
unlock:
|
2024-05-30 03:41:43 +00:00
|
|
|
ok = vi->ctrl->status == VIRTIO_NET_OK;
|
2024-05-03 20:24:42 +00:00
|
|
|
mutex_unlock(&vi->cvq_lock);
|
2024-05-30 03:41:43 +00:00
|
|
|
return ok;
|
2013-01-21 01:17:21 +00:00
|
|
|
}
|
|
|
|
|
2024-04-26 03:39:21 +00:00
|
|
|
static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
|
|
|
|
struct scatterlist *out)
|
|
|
|
{
|
|
|
|
return virtnet_send_command_reply(vi, class, cmd, out, NULL);
|
|
|
|
}
|
|
|
|
|
2009-02-05 00:36:34 +00:00
|
|
|
static int virtnet_set_mac_address(struct net_device *dev, void *p)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
struct virtio_device *vdev = vi->vdev;
|
2012-06-29 05:10:06 +00:00
|
|
|
int ret;
|
2016-12-06 02:10:58 +00:00
|
|
|
struct sockaddr *addr;
|
2013-01-21 01:17:23 +00:00
|
|
|
struct scatterlist sg;
|
2009-02-05 00:36:34 +00:00
|
|
|
|
2018-05-24 16:55:17 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STANDBY))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2016-12-23 19:14:58 +00:00
|
|
|
addr = kmemdup(p, sizeof(*addr), GFP_KERNEL);
|
2016-12-06 02:10:58 +00:00
|
|
|
if (!addr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
ret = eth_prepare_mac_addr_change(dev, addr);
|
2012-06-29 05:10:06 +00:00
|
|
|
if (ret)
|
2016-12-06 02:10:58 +00:00
|
|
|
goto out;
|
2009-02-05 00:36:34 +00:00
|
|
|
|
2013-01-21 01:17:23 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
|
|
|
|
sg_init_one(&sg, addr->sa_data, dev->addr_len);
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) {
|
2013-01-21 01:17:23 +00:00
|
|
|
dev_warn(&vdev->dev,
|
|
|
|
"Failed to set mac address by vq command.\n");
|
2016-12-06 02:10:58 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
2013-01-21 01:17:23 +00:00
|
|
|
}
|
2014-11-26 13:58:28 +00:00
|
|
|
} else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
|
|
|
|
!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
2013-10-14 07:41:51 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
/* Naturally, this has an atomicity problem. */
|
|
|
|
for (i = 0; i < dev->addr_len; i++)
|
|
|
|
virtio_cwrite8(vdev,
|
|
|
|
offsetof(struct virtio_net_config, mac) +
|
|
|
|
i, addr->sa_data[i]);
|
2013-01-21 01:17:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
eth_commit_mac_addr_change(dev, p);
|
2016-12-06 02:10:58 +00:00
|
|
|
ret = 0;
|
2009-02-05 00:36:34 +00:00
|
|
|
|
2016-12-06 02:10:58 +00:00
|
|
|
out:
|
|
|
|
kfree(addr);
|
|
|
|
return ret;
|
2009-02-05 00:36:34 +00:00
|
|
|
}
|
|
|
|
|
2017-01-07 03:12:52 +00:00
|
|
|
static void virtnet_stats(struct net_device *dev,
|
|
|
|
struct rtnl_link_stats64 *tot)
|
2011-06-15 06:36:29 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
unsigned int start;
|
2018-01-17 06:38:25 +00:00
|
|
|
int i;
|
2011-06-15 06:36:29 +00:00
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2021-09-17 08:40:06 +00:00
|
|
|
u64 tpackets, tbytes, terrors, rpackets, rbytes, rdrops;
|
2018-01-17 06:38:25 +00:00
|
|
|
struct receive_queue *rq = &vi->rq[i];
|
|
|
|
struct send_queue *sq = &vi->sq[i];
|
2011-06-15 06:36:29 +00:00
|
|
|
|
|
|
|
do {
|
2022-10-26 13:22:14 +00:00
|
|
|
start = u64_stats_fetch_begin(&sq->stats.syncp);
|
2023-10-26 17:18:40 +00:00
|
|
|
tpackets = u64_stats_read(&sq->stats.packets);
|
|
|
|
tbytes = u64_stats_read(&sq->stats.bytes);
|
|
|
|
terrors = u64_stats_read(&sq->stats.tx_timeouts);
|
2022-10-26 13:22:14 +00:00
|
|
|
} while (u64_stats_fetch_retry(&sq->stats.syncp, start));
|
2012-06-05 22:35:24 +00:00
|
|
|
|
|
|
|
do {
|
2022-10-26 13:22:14 +00:00
|
|
|
start = u64_stats_fetch_begin(&rq->stats.syncp);
|
2023-10-26 17:18:40 +00:00
|
|
|
rpackets = u64_stats_read(&rq->stats.packets);
|
|
|
|
rbytes = u64_stats_read(&rq->stats.bytes);
|
|
|
|
rdrops = u64_stats_read(&rq->stats.drops);
|
2022-10-26 13:22:14 +00:00
|
|
|
} while (u64_stats_fetch_retry(&rq->stats.syncp, start));
|
2011-06-15 06:36:29 +00:00
|
|
|
|
|
|
|
tot->rx_packets += rpackets;
|
|
|
|
tot->tx_packets += tpackets;
|
|
|
|
tot->rx_bytes += rbytes;
|
|
|
|
tot->tx_bytes += tbytes;
|
2018-07-23 14:36:06 +00:00
|
|
|
tot->rx_dropped += rdrops;
|
2021-09-17 08:40:06 +00:00
|
|
|
tot->tx_errors += terrors;
|
2011-06-15 06:36:29 +00:00
|
|
|
}
|
|
|
|
|
2023-09-21 08:52:17 +00:00
|
|
|
tot->tx_dropped = DEV_STATS_READ(dev, tx_dropped);
|
|
|
|
tot->tx_fifo_errors = DEV_STATS_READ(dev, tx_fifo_errors);
|
|
|
|
tot->rx_length_errors = DEV_STATS_READ(dev, rx_length_errors);
|
|
|
|
tot->rx_frame_errors = DEV_STATS_READ(dev, rx_frame_errors);
|
2011-06-15 06:36:29 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 20:43:52 +00:00
|
|
|
static void virtnet_ack_link_announce(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_ANNOUNCE,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL))
|
2012-04-11 20:43:52 +00:00
|
|
|
dev_warn(&vi->dev->dev, "Failed to ack link announce.\n");
|
|
|
|
}
|
|
|
|
|
2024-05-03 20:24:45 +00:00
|
|
|
static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
|
2012-12-07 07:04:56 +00:00
|
|
|
{
|
2024-05-03 20:24:41 +00:00
|
|
|
struct virtio_net_ctrl_mq *mq __free(kfree) = NULL;
|
2012-12-07 07:04:56 +00:00
|
|
|
struct scatterlist sg;
|
|
|
|
struct net_device *dev = vi->dev;
|
|
|
|
|
|
|
|
if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ))
|
|
|
|
return 0;
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
mq = kzalloc(sizeof(*mq), GFP_KERNEL);
|
|
|
|
if (!mq)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
mq->virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs);
|
|
|
|
sg_init_one(&sg, mq, sizeof(*mq));
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &sg)) {
|
2012-12-07 07:04:56 +00:00
|
|
|
dev_warn(&dev->dev, "Fail to set num of queue pairs to %d\n",
|
|
|
|
queue_pairs);
|
|
|
|
return -EINVAL;
|
2013-04-29 02:30:08 +00:00
|
|
|
} else {
|
2012-12-07 07:04:56 +00:00
|
|
|
vi->curr_queue_pairs = queue_pairs;
|
2013-10-15 03:18:59 +00:00
|
|
|
/* virtnet_open() will refill when device is going to up. */
|
|
|
|
if (dev->flags & IFF_UP)
|
|
|
|
schedule_delayed_work(&vi->refill, 0);
|
2013-04-29 02:30:08 +00:00
|
|
|
}
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
static int virtnet_close(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2012-12-07 07:04:56 +00:00
|
|
|
int i;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2022-07-25 07:21:59 +00:00
|
|
|
/* Make sure NAPI doesn't schedule refill work */
|
|
|
|
disable_delayed_refill(vi);
|
2011-12-29 00:42:38 +00:00
|
|
|
/* Make sure refill_work doesn't re-enable napi! */
|
|
|
|
cancel_delayed_work_sync(&vi->refill);
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
/* Prevent the config change callback from changing carrier
|
|
|
|
* after close
|
|
|
|
*/
|
|
|
|
virtio_config_driver_disable(vi->vdev);
|
|
|
|
/* Stop getting status/speed updates: we don't care until next
|
|
|
|
* open
|
|
|
|
*/
|
|
|
|
cancel_work_sync(&vi->config_work);
|
2012-12-07 07:04:56 +00:00
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2023-05-12 15:18:12 +00:00
|
|
|
virtnet_disable_queue_pair(vi, i);
|
2024-06-21 10:13:53 +00:00
|
|
|
virtnet_cancel_dim(vi, &vi->rq[i].dim);
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
netif_carrier_off(dev);
|
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
static void virtnet_rx_mode_work(struct work_struct *work)
|
2009-02-04 09:02:40 +00:00
|
|
|
{
|
2023-07-20 08:38:38 +00:00
|
|
|
struct virtnet_info *vi =
|
|
|
|
container_of(work, struct virtnet_info, rx_mode_work);
|
2024-05-09 18:36:34 +00:00
|
|
|
u8 *promisc_allmulti __free(kfree) = NULL;
|
2023-07-20 08:38:38 +00:00
|
|
|
struct net_device *dev = vi->dev;
|
2009-02-04 09:02:45 +00:00
|
|
|
struct scatterlist sg[2];
|
|
|
|
struct virtio_net_ctrl_mac *mac_data;
|
2009-05-22 23:22:17 +00:00
|
|
|
struct netdev_hw_addr *ha;
|
2010-01-25 21:36:10 +00:00
|
|
|
int uc_count;
|
2010-02-08 04:30:35 +00:00
|
|
|
int mc_count;
|
2009-02-04 09:02:45 +00:00
|
|
|
void *buf;
|
|
|
|
int i;
|
2009-02-04 09:02:40 +00:00
|
|
|
|
2013-12-10 00:18:45 +00:00
|
|
|
/* We can't dynamically set ndo_set_rx_mode, so return gracefully */
|
2009-02-04 09:02:40 +00:00
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
|
|
|
|
return;
|
|
|
|
|
2024-05-15 16:31:25 +00:00
|
|
|
promisc_allmulti = kzalloc(sizeof(*promisc_allmulti), GFP_KERNEL);
|
2024-05-03 20:24:41 +00:00
|
|
|
if (!promisc_allmulti) {
|
|
|
|
dev_warn(&dev->dev, "Failed to set RX mode, no memory.\n");
|
|
|
|
return;
|
|
|
|
}
|
2009-02-04 09:02:40 +00:00
|
|
|
|
2024-05-15 16:31:25 +00:00
|
|
|
rtnl_lock();
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
*promisc_allmulti = !!(dev->flags & IFF_PROMISC);
|
|
|
|
sg_init_one(sg, promisc_allmulti, sizeof(*promisc_allmulti));
|
2009-02-04 09:02:40 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_RX_PROMISC, sg))
|
2009-02-04 09:02:40 +00:00
|
|
|
dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
|
2024-05-03 20:24:41 +00:00
|
|
|
*promisc_allmulti ? "en" : "dis");
|
2009-02-04 09:02:40 +00:00
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
*promisc_allmulti = !!(dev->flags & IFF_ALLMULTI);
|
|
|
|
sg_init_one(sg, promisc_allmulti, sizeof(*promisc_allmulti));
|
2009-02-04 09:02:40 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_RX_ALLMULTI, sg))
|
2009-02-04 09:02:40 +00:00
|
|
|
dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
|
2024-05-03 20:24:41 +00:00
|
|
|
*promisc_allmulti ? "en" : "dis");
|
2009-02-04 09:02:45 +00:00
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
netif_addr_lock_bh(dev);
|
|
|
|
|
2010-01-25 21:36:10 +00:00
|
|
|
uc_count = netdev_uc_count(dev);
|
2010-02-08 04:30:35 +00:00
|
|
|
mc_count = netdev_mc_count(dev);
|
2009-02-04 09:02:45 +00:00
|
|
|
/* MAC filter - use one buffer for both lists */
|
2010-02-08 04:30:35 +00:00
|
|
|
buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) +
|
|
|
|
(2 * sizeof(mac_data->entries)), GFP_ATOMIC);
|
|
|
|
mac_data = buf;
|
2023-07-20 08:38:38 +00:00
|
|
|
if (!buf) {
|
|
|
|
netif_addr_unlock_bh(dev);
|
|
|
|
rtnl_unlock();
|
2009-02-04 09:02:45 +00:00
|
|
|
return;
|
2023-07-20 08:38:38 +00:00
|
|
|
}
|
2009-02-04 09:02:45 +00:00
|
|
|
|
2009-05-01 17:27:56 +00:00
|
|
|
sg_init_table(sg, 2);
|
|
|
|
|
2009-02-04 09:02:45 +00:00
|
|
|
/* Store the unicast list and count in the front of the buffer */
|
2014-10-07 14:39:48 +00:00
|
|
|
mac_data->entries = cpu_to_virtio32(vi->vdev, uc_count);
|
2009-05-22 23:22:17 +00:00
|
|
|
i = 0;
|
2010-01-25 21:36:10 +00:00
|
|
|
netdev_for_each_uc_addr(ha, dev)
|
2009-05-22 23:22:17 +00:00
|
|
|
memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
|
2009-02-04 09:02:45 +00:00
|
|
|
|
|
|
|
sg_set_buf(&sg[0], mac_data,
|
2010-01-25 21:36:10 +00:00
|
|
|
sizeof(mac_data->entries) + (uc_count * ETH_ALEN));
|
2009-02-04 09:02:45 +00:00
|
|
|
|
|
|
|
/* multicast list and count fill the end */
|
2010-01-25 21:36:10 +00:00
|
|
|
mac_data = (void *)&mac_data->macs[uc_count][0];
|
2009-02-04 09:02:45 +00:00
|
|
|
|
2014-10-07 14:39:48 +00:00
|
|
|
mac_data->entries = cpu_to_virtio32(vi->vdev, mc_count);
|
2010-02-23 23:17:07 +00:00
|
|
|
i = 0;
|
2010-04-01 21:22:57 +00:00
|
|
|
netdev_for_each_mc_addr(ha, dev)
|
|
|
|
memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
|
2009-02-04 09:02:45 +00:00
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
netif_addr_unlock_bh(dev);
|
|
|
|
|
2009-02-04 09:02:45 +00:00
|
|
|
sg_set_buf(&sg[1], mac_data,
|
2010-02-08 04:30:35 +00:00
|
|
|
sizeof(mac_data->entries) + (mc_count * ETH_ALEN));
|
2009-02-04 09:02:45 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_MAC_TABLE_SET, sg))
|
2013-11-29 09:02:19 +00:00
|
|
|
dev_warn(&dev->dev, "Failed to set MAC filter table.\n");
|
2009-02-04 09:02:45 +00:00
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
rtnl_unlock();
|
|
|
|
|
2009-02-04 09:02:45 +00:00
|
|
|
kfree(buf);
|
2009-02-04 09:02:40 +00:00
|
|
|
}
|
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
static void virtnet_set_rx_mode(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
|
|
|
if (vi->rx_mode_work_enabled)
|
|
|
|
schedule_work(&vi->rx_mode_work);
|
|
|
|
}
|
|
|
|
|
2013-04-19 02:04:28 +00:00
|
|
|
static int virtnet_vlan_rx_add_vid(struct net_device *dev,
|
|
|
|
__be16 proto, u16 vid)
|
2009-02-04 09:02:50 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2024-05-03 20:24:41 +00:00
|
|
|
__virtio16 *_vid __free(kfree) = NULL;
|
2009-02-04 09:02:50 +00:00
|
|
|
struct scatterlist sg;
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
_vid = kzalloc(sizeof(*_vid), GFP_KERNEL);
|
|
|
|
if (!_vid)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*_vid = cpu_to_virtio16(vi->vdev, vid);
|
|
|
|
sg_init_one(&sg, _vid, sizeof(*_vid));
|
2009-02-04 09:02:50 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_VLAN_ADD, &sg))
|
2009-02-04 09:02:50 +00:00
|
|
|
dev_warn(&dev->dev, "Failed to add VLAN ID %d.\n", vid);
|
2011-12-09 00:52:37 +00:00
|
|
|
return 0;
|
2009-02-04 09:02:50 +00:00
|
|
|
}
|
|
|
|
|
2013-04-19 02:04:28 +00:00
|
|
|
static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
|
|
|
|
__be16 proto, u16 vid)
|
2009-02-04 09:02:50 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2024-05-03 20:24:41 +00:00
|
|
|
__virtio16 *_vid __free(kfree) = NULL;
|
2009-02-04 09:02:50 +00:00
|
|
|
struct scatterlist sg;
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
_vid = kzalloc(sizeof(*_vid), GFP_KERNEL);
|
|
|
|
if (!_vid)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*_vid = cpu_to_virtio16(vi->vdev, vid);
|
|
|
|
sg_init_one(&sg, _vid, sizeof(*_vid));
|
2009-02-04 09:02:50 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN,
|
2013-12-10 00:17:40 +00:00
|
|
|
VIRTIO_NET_CTRL_VLAN_DEL, &sg))
|
2009-02-04 09:02:50 +00:00
|
|
|
dev_warn(&dev->dev, "Failed to kill VLAN ID %d.\n", vid);
|
2011-12-09 00:52:37 +00:00
|
|
|
return 0;
|
2009-02-04 09:02:50 +00:00
|
|
|
}
|
|
|
|
|
2019-03-18 06:56:06 +00:00
|
|
|
static void virtnet_clean_affinity(struct virtnet_info *vi)
|
2012-12-07 07:04:56 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2013-01-24 23:51:30 +00:00
|
|
|
if (vi->affinity_hint_set) {
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2018-08-10 01:18:28 +00:00
|
|
|
virtqueue_set_affinity(vi->rq[i].vq, NULL);
|
|
|
|
virtqueue_set_affinity(vi->sq[i].vq, NULL);
|
2013-01-24 23:51:29 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 23:51:30 +00:00
|
|
|
vi->affinity_hint_set = false;
|
|
|
|
}
|
|
|
|
}
|
2013-01-24 23:51:29 +00:00
|
|
|
|
2013-01-24 23:51:30 +00:00
|
|
|
static void virtnet_set_affinity(struct virtnet_info *vi)
|
|
|
|
{
|
2018-08-10 00:28:40 +00:00
|
|
|
cpumask_var_t mask;
|
|
|
|
int stragglers;
|
|
|
|
int group_size;
|
|
|
|
int i, j, cpu;
|
|
|
|
int num_cpu;
|
|
|
|
int stride;
|
|
|
|
|
|
|
|
if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
|
2019-03-18 06:56:06 +00:00
|
|
|
virtnet_clean_affinity(vi);
|
2013-01-24 23:51:30 +00:00
|
|
|
return;
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2018-08-10 00:28:40 +00:00
|
|
|
num_cpu = num_online_cpus();
|
|
|
|
stride = max_t(int, num_cpu / vi->curr_queue_pairs, 1);
|
|
|
|
stragglers = num_cpu >= vi->curr_queue_pairs ?
|
|
|
|
num_cpu % vi->curr_queue_pairs :
|
|
|
|
0;
|
2021-08-14 21:17:05 +00:00
|
|
|
cpu = cpumask_first(cpu_online_mask);
|
2018-08-09 03:07:35 +00:00
|
|
|
|
2018-08-10 00:28:40 +00:00
|
|
|
for (i = 0; i < vi->curr_queue_pairs; i++) {
|
|
|
|
group_size = stride + (i < stragglers ? 1 : 0);
|
|
|
|
|
|
|
|
for (j = 0; j < group_size; j++) {
|
|
|
|
cpumask_set_cpu(cpu, mask);
|
|
|
|
cpu = cpumask_next_wrap(cpu, cpu_online_mask,
|
|
|
|
nr_cpu_ids, false);
|
|
|
|
}
|
|
|
|
virtqueue_set_affinity(vi->rq[i].vq, mask);
|
|
|
|
virtqueue_set_affinity(vi->sq[i].vq, mask);
|
2021-03-18 18:37:46 +00:00
|
|
|
__netif_set_xps_queue(vi->dev, cpumask_bits(mask), i, XPS_CPUS);
|
2018-08-10 00:28:40 +00:00
|
|
|
cpumask_clear(mask);
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 23:51:30 +00:00
|
|
|
vi->affinity_hint_set = true;
|
2018-08-10 00:28:40 +00:00
|
|
|
free_cpumask_var(mask);
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
static int virtnet_cpu_online(unsigned int cpu, struct hlist_node *node)
|
2013-01-24 23:51:31 +00:00
|
|
|
{
|
2016-08-12 17:49:43 +00:00
|
|
|
struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
|
|
|
|
node);
|
|
|
|
virtnet_set_affinity(vi);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-24 23:51:31 +00:00
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
static int virtnet_cpu_dead(unsigned int cpu, struct hlist_node *node)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
|
|
|
|
node_dead);
|
|
|
|
virtnet_set_affinity(vi);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-10-15 03:18:58 +00:00
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
static int virtnet_cpu_down_prep(unsigned int cpu, struct hlist_node *node)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info,
|
|
|
|
node);
|
|
|
|
|
2019-03-18 06:56:06 +00:00
|
|
|
virtnet_clean_affinity(vi);
|
2016-08-12 17:49:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum cpuhp_state virtionet_online;
|
|
|
|
|
|
|
|
static int virtnet_cpu_notif_add(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = cpuhp_state_add_instance_nocalls(virtionet_online, &vi->node);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
ret = cpuhp_state_add_instance_nocalls(CPUHP_VIRT_NET_DEAD,
|
|
|
|
&vi->node_dead);
|
|
|
|
if (!ret)
|
|
|
|
return ret;
|
|
|
|
cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_cpu_notif_remove(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node);
|
|
|
|
cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_NET_DEAD,
|
|
|
|
&vi->node_dead);
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:06 +00:00
|
|
|
static int virtnet_send_ctrl_coal_vq_cmd(struct virtnet_info *vi,
|
|
|
|
u16 vqn, u32 max_usecs, u32 max_packets)
|
|
|
|
{
|
2024-05-03 20:24:41 +00:00
|
|
|
struct virtio_net_ctrl_coal_vq *coal_vq __free(kfree) = NULL;
|
2023-12-11 10:36:06 +00:00
|
|
|
struct scatterlist sgs;
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
coal_vq = kzalloc(sizeof(*coal_vq), GFP_KERNEL);
|
|
|
|
if (!coal_vq)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
coal_vq->vqn = cpu_to_le16(vqn);
|
|
|
|
coal_vq->coal.max_usecs = cpu_to_le32(max_usecs);
|
|
|
|
coal_vq->coal.max_packets = cpu_to_le32(max_packets);
|
|
|
|
sg_init_one(&sgs, coal_vq, sizeof(*coal_vq));
|
2023-12-11 10:36:06 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
|
|
|
|
VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET,
|
|
|
|
&sgs))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_send_rx_ctrl_coal_vq_cmd(struct virtnet_info *vi,
|
|
|
|
u16 queue, u32 max_usecs,
|
|
|
|
u32 max_packets)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2024-08-01 13:23:37 +00:00
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-12-11 10:36:06 +00:00
|
|
|
err = virtnet_send_ctrl_coal_vq_cmd(vi, rxq2vq(queue),
|
|
|
|
max_usecs, max_packets);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
vi->rq[queue].intr_coal.max_usecs = max_usecs;
|
|
|
|
vi->rq[queue].intr_coal.max_packets = max_packets;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_send_tx_ctrl_coal_vq_cmd(struct virtnet_info *vi,
|
|
|
|
u16 queue, u32 max_usecs,
|
|
|
|
u32 max_packets)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2024-08-01 13:23:37 +00:00
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-12-11 10:36:06 +00:00
|
|
|
err = virtnet_send_ctrl_coal_vq_cmd(vi, txq2vq(queue),
|
|
|
|
max_usecs, max_packets);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
vi->sq[queue].intr_coal.max_usecs = max_usecs;
|
|
|
|
vi->sq[queue].intr_coal.max_packets = max_packets;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-19 08:10:59 +00:00
|
|
|
static void virtnet_get_ringparam(struct net_device *dev,
|
2021-11-18 12:12:43 +00:00
|
|
|
struct ethtool_ringparam *ring,
|
|
|
|
struct kernel_ethtool_ringparam *kernel_ring,
|
|
|
|
struct netlink_ext_ack *extack)
|
2011-10-19 08:10:59 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
2022-08-01 06:38:58 +00:00
|
|
|
ring->rx_max_pending = vi->rq[0].vq->num_max;
|
|
|
|
ring->tx_max_pending = vi->sq[0].vq->num_max;
|
|
|
|
ring->rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
|
|
|
|
ring->tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
|
2011-10-19 08:10:59 +00:00
|
|
|
}
|
|
|
|
|
2022-08-01 06:39:02 +00:00
|
|
|
static int virtnet_set_ringparam(struct net_device *dev,
|
|
|
|
struct ethtool_ringparam *ring,
|
|
|
|
struct kernel_ethtool_ringparam *kernel_ring,
|
|
|
|
struct netlink_ext_ack *extack)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
u32 rx_pending, tx_pending;
|
|
|
|
struct receive_queue *rq;
|
|
|
|
struct send_queue *sq;
|
|
|
|
int i, err;
|
|
|
|
|
|
|
|
if (ring->rx_mini_pending || ring->rx_jumbo_pending)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rx_pending = virtqueue_get_vring_size(vi->rq[0].vq);
|
|
|
|
tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
|
|
|
|
|
|
|
|
if (ring->rx_pending == rx_pending &&
|
|
|
|
ring->tx_pending == tx_pending)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ring->rx_pending > vi->rq[0].vq->num_max)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (ring->tx_pending > vi->sq[0].vq->num_max)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
rq = vi->rq + i;
|
|
|
|
sq = vi->sq + i;
|
|
|
|
|
|
|
|
if (ring->tx_pending != tx_pending) {
|
|
|
|
err = virtnet_tx_resize(vi, sq, ring->tx_pending);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2023-10-08 06:27:43 +00:00
|
|
|
|
|
|
|
/* Upon disabling and re-enabling a transmit virtqueue, the device must
|
|
|
|
* set the coalescing parameters of the virtqueue to those configured
|
|
|
|
* through the VIRTIO_NET_CTRL_NOTF_COAL_TX_SET command, or, if the driver
|
|
|
|
* did not set any TX coalescing parameters, to 0.
|
|
|
|
*/
|
2023-12-11 10:36:06 +00:00
|
|
|
err = virtnet_send_tx_ctrl_coal_vq_cmd(vi, i,
|
|
|
|
vi->intr_coal_tx.max_usecs,
|
|
|
|
vi->intr_coal_tx.max_packets);
|
2024-08-01 13:23:38 +00:00
|
|
|
|
|
|
|
/* Don't break the tx resize action if the vq coalescing is not
|
|
|
|
* supported. The same is true for rx resize below.
|
|
|
|
*/
|
|
|
|
if (err && err != -EOPNOTSUPP)
|
2023-10-08 06:27:43 +00:00
|
|
|
return err;
|
2022-08-01 06:39:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ring->rx_pending != rx_pending) {
|
|
|
|
err = virtnet_rx_resize(vi, rq, ring->rx_pending);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2023-10-08 06:27:43 +00:00
|
|
|
|
|
|
|
/* The reason is same as the transmit virtqueue reset */
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_lock(&vi->rq[i].dim_lock);
|
2023-12-11 10:36:06 +00:00
|
|
|
err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, i,
|
|
|
|
vi->intr_coal_rx.max_usecs,
|
|
|
|
vi->intr_coal_rx.max_packets);
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_unlock(&vi->rq[i].dim_lock);
|
2024-08-01 13:23:38 +00:00
|
|
|
if (err && err != -EOPNOTSUPP)
|
2023-10-08 06:27:43 +00:00
|
|
|
return err;
|
2022-08-01 06:39:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2011-10-19 08:10:59 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
static bool virtnet_commit_rss_command(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
struct net_device *dev = vi->dev;
|
|
|
|
struct scatterlist sgs[4];
|
|
|
|
unsigned int sg_buf_size;
|
|
|
|
|
|
|
|
/* prepare sgs */
|
|
|
|
sg_init_table(sgs, 4);
|
|
|
|
|
|
|
|
sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
|
2024-05-03 20:24:40 +00:00
|
|
|
sg_set_buf(&sgs[0], &vi->rss, sg_buf_size);
|
2022-03-28 17:53:34 +00:00
|
|
|
|
2024-05-03 20:24:40 +00:00
|
|
|
sg_buf_size = sizeof(uint16_t) * (vi->rss.indirection_table_mask + 1);
|
|
|
|
sg_set_buf(&sgs[1], vi->rss.indirection_table, sg_buf_size);
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
|
|
|
|
- offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
|
2024-05-03 20:24:40 +00:00
|
|
|
sg_set_buf(&sgs[2], &vi->rss.max_tx_vq, sg_buf_size);
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
sg_buf_size = vi->rss_key_size;
|
2024-05-03 20:24:40 +00:00
|
|
|
sg_set_buf(&sgs[3], vi->rss.key, sg_buf_size);
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
|
2022-03-28 17:53:35 +00:00
|
|
|
vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
|
2024-05-03 20:24:41 +00:00
|
|
|
: VIRTIO_NET_CTRL_MQ_HASH_CONFIG, sgs))
|
|
|
|
goto err;
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
return true;
|
2024-05-03 20:24:41 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
|
|
|
|
return false;
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_init_default_rss(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
u32 indir_val = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.hash_types = vi->rss_hash_types_supported;
|
2022-03-28 17:53:36 +00:00
|
|
|
vi->rss_hash_types_saved = vi->rss_hash_types_supported;
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.indirection_table_mask = vi->rss_indir_table_size
|
2022-03-28 17:53:34 +00:00
|
|
|
? vi->rss_indir_table_size - 1 : 0;
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.unclassified_queue = 0;
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
for (; i < vi->rss_indir_table_size; ++i) {
|
|
|
|
indir_val = ethtool_rxfh_indir_default(i, vi->curr_queue_pairs);
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.indirection_table[i] = indir_val;
|
2022-03-28 17:53:34 +00:00
|
|
|
}
|
|
|
|
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.max_tx_vq = vi->has_rss ? vi->curr_queue_pairs : 0;
|
|
|
|
vi->rss.hash_key_length = vi->rss_key_size;
|
2022-03-28 17:53:34 +00:00
|
|
|
|
2024-05-03 20:24:40 +00:00
|
|
|
netdev_rss_key_fill(vi->rss.key, vi->rss_key_size);
|
2022-03-28 17:53:34 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 17:53:36 +00:00
|
|
|
static void virtnet_get_hashflow(const struct virtnet_info *vi, struct ethtool_rxnfc *info)
|
|
|
|
{
|
|
|
|
info->data = 0;
|
|
|
|
switch (info->flow_type) {
|
|
|
|
case TCP_V4_FLOW:
|
|
|
|
if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST |
|
|
|
|
RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
|
} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TCP_V6_FLOW:
|
|
|
|
if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST |
|
|
|
|
RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
|
} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UDP_V4_FLOW:
|
|
|
|
if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST |
|
|
|
|
RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
|
} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UDP_V6_FLOW:
|
|
|
|
if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST |
|
|
|
|
RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
|
|
|
} else if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPV4_FLOW:
|
|
|
|
if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4)
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case IPV6_FLOW:
|
|
|
|
if (vi->rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6)
|
|
|
|
info->data = RXH_IP_SRC | RXH_IP_DST;
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
info->data = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *info)
|
|
|
|
{
|
|
|
|
u32 new_hashtypes = vi->rss_hash_types_saved;
|
|
|
|
bool is_disable = info->data & RXH_DISCARD;
|
|
|
|
bool is_l4 = info->data == (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3);
|
|
|
|
|
|
|
|
/* supports only 'sd', 'sdfn' and 'r' */
|
|
|
|
if (!((info->data == (RXH_IP_SRC | RXH_IP_DST)) | is_l4 | is_disable))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (info->flow_type) {
|
|
|
|
case TCP_V4_FLOW:
|
|
|
|
new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv4 | VIRTIO_NET_RSS_HASH_TYPE_TCPv4);
|
|
|
|
if (!is_disable)
|
|
|
|
new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4
|
|
|
|
| (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_TCPv4 : 0);
|
|
|
|
break;
|
|
|
|
case UDP_V4_FLOW:
|
|
|
|
new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv4 | VIRTIO_NET_RSS_HASH_TYPE_UDPv4);
|
|
|
|
if (!is_disable)
|
|
|
|
new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4
|
|
|
|
| (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_UDPv4 : 0);
|
|
|
|
break;
|
|
|
|
case IPV4_FLOW:
|
|
|
|
new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv4;
|
|
|
|
if (!is_disable)
|
|
|
|
new_hashtypes = VIRTIO_NET_RSS_HASH_TYPE_IPv4;
|
|
|
|
break;
|
|
|
|
case TCP_V6_FLOW:
|
|
|
|
new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv6 | VIRTIO_NET_RSS_HASH_TYPE_TCPv6);
|
|
|
|
if (!is_disable)
|
|
|
|
new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6
|
|
|
|
| (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_TCPv6 : 0);
|
|
|
|
break;
|
|
|
|
case UDP_V6_FLOW:
|
|
|
|
new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv6 | VIRTIO_NET_RSS_HASH_TYPE_UDPv6);
|
|
|
|
if (!is_disable)
|
|
|
|
new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6
|
|
|
|
| (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_UDPv6 : 0);
|
|
|
|
break;
|
|
|
|
case IPV6_FLOW:
|
|
|
|
new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv6;
|
|
|
|
if (!is_disable)
|
|
|
|
new_hashtypes = VIRTIO_NET_RSS_HASH_TYPE_IPv6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* unsupported flow */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if unsupported hashtype was set */
|
|
|
|
if (new_hashtypes != (new_hashtypes & vi->rss_hash_types_supported))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (new_hashtypes != vi->rss_hash_types_saved) {
|
|
|
|
vi->rss_hash_types_saved = new_hashtypes;
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.hash_types = vi->rss_hash_types_saved;
|
2022-03-28 17:53:36 +00:00
|
|
|
if (vi->dev->features & NETIF_F_RXHASH)
|
|
|
|
return virtnet_commit_rss_command(vi);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-11-14 14:17:08 +00:00
|
|
|
|
|
|
|
static void virtnet_get_drvinfo(struct net_device *dev,
|
|
|
|
struct ethtool_drvinfo *info)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
struct virtio_device *vdev = vi->vdev;
|
|
|
|
|
2022-08-30 20:14:52 +00:00
|
|
|
strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
|
|
|
|
strscpy(info->version, VIRTNET_DRIVER_VERSION, sizeof(info->version));
|
|
|
|
strscpy(info->bus_info, virtio_bus_name(vdev), sizeof(info->bus_info));
|
2011-11-14 14:17:08 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:57 +00:00
|
|
|
/* TODO: Eliminate OOO packets during switching */
|
|
|
|
static int virtnet_set_channels(struct net_device *dev,
|
|
|
|
struct ethtool_channels *channels)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
u16 queue_pairs = channels->combined_count;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* We don't support separate rx/tx channels.
|
|
|
|
* We don't allow setting 'other' channels.
|
|
|
|
*/
|
|
|
|
if (channels->rx_count || channels->tx_count || channels->other_count)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-04-18 05:45:41 +00:00
|
|
|
if (queue_pairs > vi->max_queue_pairs || queue_pairs == 0)
|
2012-12-07 07:04:57 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-12-15 20:13:24 +00:00
|
|
|
/* For now we don't support modifying channels while XDP is loaded
|
|
|
|
* also when XDP is loaded all RX queues have XDP programs so we only
|
|
|
|
* need to check a single RX queue.
|
|
|
|
*/
|
|
|
|
if (vi->rq[0].xdp_prog)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2021-08-03 14:16:04 +00:00
|
|
|
cpus_read_lock();
|
2024-05-03 20:24:45 +00:00
|
|
|
err = virtnet_set_queues(vi, queue_pairs);
|
2020-12-23 02:54:21 +00:00
|
|
|
if (err) {
|
2021-08-03 14:16:04 +00:00
|
|
|
cpus_read_unlock();
|
2020-12-23 02:54:21 +00:00
|
|
|
goto err;
|
2012-12-07 07:04:57 +00:00
|
|
|
}
|
2020-12-23 02:54:21 +00:00
|
|
|
virtnet_set_affinity(vi);
|
2021-08-03 14:16:04 +00:00
|
|
|
cpus_read_unlock();
|
2012-12-07 07:04:57 +00:00
|
|
|
|
2020-12-23 02:54:21 +00:00
|
|
|
netif_set_real_num_tx_queues(dev, queue_pairs);
|
|
|
|
netif_set_real_num_rx_queues(dev, queue_pairs);
|
|
|
|
err:
|
2012-12-07 07:04:57 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
static void virtnet_stats_sprintf(u8 **p, const char *fmt, const char *noq_fmt,
|
|
|
|
int num, int qid, const struct virtnet_stat_desc *desc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (qid < 0) {
|
|
|
|
for (i = 0; i < num; ++i)
|
|
|
|
ethtool_sprintf(p, noq_fmt, desc[i].desc);
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < num; ++i)
|
|
|
|
ethtool_sprintf(p, fmt, qid, desc[i].desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
/* qid == -1: for rx/tx queue total field */
|
2024-04-26 03:39:25 +00:00
|
|
|
static void virtnet_get_stats_string(struct virtnet_info *vi, int type, int qid, u8 **data)
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
{
|
|
|
|
const struct virtnet_stat_desc *desc;
|
|
|
|
const char *fmt, *noq_fmt;
|
|
|
|
u8 *p = *data;
|
2024-04-26 03:39:26 +00:00
|
|
|
u32 num;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
if (type == VIRTNET_Q_TYPE_CQ && qid >= 0) {
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
noq_fmt = "cq_hw_%s";
|
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_CVQ) {
|
|
|
|
desc = &virtnet_stats_cvq_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_cvq_desc);
|
|
|
|
|
|
|
|
virtnet_stats_sprintf(&p, NULL, noq_fmt, num, -1, desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == VIRTNET_Q_TYPE_RX) {
|
2024-04-26 03:39:25 +00:00
|
|
|
fmt = "rx%u_%s";
|
2024-04-26 03:39:26 +00:00
|
|
|
noq_fmt = "rx_%s";
|
2024-04-26 03:39:25 +00:00
|
|
|
|
|
|
|
desc = &virtnet_rq_stats_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_rq_stats_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
2024-04-26 03:39:25 +00:00
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
fmt = "rx%u_hw_%s";
|
2024-04-26 03:39:26 +00:00
|
|
|
noq_fmt = "rx_hw_%s";
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
|
|
|
|
desc = &virtnet_stats_rx_basic_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_rx_basic_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
|
|
|
|
desc = &virtnet_stats_rx_csum_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_rx_csum_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_RX_SPEED) {
|
|
|
|
desc = &virtnet_stats_rx_speed_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_rx_speed_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == VIRTNET_Q_TYPE_TX) {
|
2024-04-26 03:39:25 +00:00
|
|
|
fmt = "tx%u_%s";
|
2024-04-26 03:39:26 +00:00
|
|
|
noq_fmt = "tx_%s";
|
2024-04-26 03:39:25 +00:00
|
|
|
|
|
|
|
desc = &virtnet_sq_stats_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_sq_stats_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
2024-04-26 03:39:25 +00:00
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
fmt = "tx%u_hw_%s";
|
2024-04-26 03:39:26 +00:00
|
|
|
noq_fmt = "tx_hw_%s";
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
|
|
|
|
desc = &virtnet_stats_tx_basic_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_tx_basic_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
|
|
|
|
desc = &virtnet_stats_tx_gso_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_tx_gso_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_TX_SPEED) {
|
|
|
|
desc = &virtnet_stats_tx_speed_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_tx_speed_desc);
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
virtnet_stats_sprintf(&p, fmt, noq_fmt, num, qid, desc);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*data = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virtnet_stats_ctx {
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
/* The stats are write to qstats or ethtool -S */
|
|
|
|
bool to_qstat;
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
/* Used to calculate the offset inside the output buffer. */
|
|
|
|
u32 desc_num[3];
|
|
|
|
|
|
|
|
/* The actual supported stat types. */
|
|
|
|
u32 bitmap[3];
|
|
|
|
|
|
|
|
/* Used to calculate the reply buffer size. */
|
|
|
|
u32 size[3];
|
|
|
|
|
|
|
|
/* Record the output buffer. */
|
|
|
|
u64 *data;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virtnet_stats_ctx_init(struct virtnet_info *vi,
|
|
|
|
struct virtnet_stats_ctx *ctx,
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
u64 *data, bool to_qstat)
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
{
|
|
|
|
u32 queue_type;
|
|
|
|
|
|
|
|
ctx->data = data;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
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;
|
|
|
|
}
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
2024-04-26 03:39:25 +00:00
|
|
|
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);
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
if (vi->device_stats_cap & VIRTIO_NET_STATS_TYPE_CVQ) {
|
|
|
|
queue_type = VIRTNET_Q_TYPE_CQ;
|
|
|
|
|
|
|
|
ctx->bitmap[queue_type] |= VIRTIO_NET_STATS_TYPE_CVQ;
|
|
|
|
ctx->desc_num[queue_type] += ARRAY_SIZE(virtnet_stats_cvq_desc);
|
|
|
|
ctx->size[queue_type] += sizeof(struct virtio_net_stats_cvq);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
ctx->size[queue_type] += sizeof(struct virtio_net_stats_rx_csum);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_basic);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
ctx->size[queue_type] += sizeof(struct virtio_net_stats_tx_speed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
/* stats_sum_queue - Calculate the sum of the same fields in sq or rq.
|
|
|
|
* @sum: the position to store the sum values
|
|
|
|
* @num: field num
|
|
|
|
* @q_value: the first queue fields
|
|
|
|
* @q_num: number of the queues
|
|
|
|
*/
|
|
|
|
static void stats_sum_queue(u64 *sum, u32 num, u64 *q_value, u32 q_num)
|
|
|
|
{
|
|
|
|
u32 step = num;
|
|
|
|
int i, j;
|
|
|
|
u64 *p;
|
|
|
|
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
p = sum + i;
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < q_num; ++j)
|
|
|
|
*p += *(q_value + i + j * step);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_fill_total_fields(struct virtnet_info *vi,
|
|
|
|
struct virtnet_stats_ctx *ctx)
|
|
|
|
{
|
|
|
|
u64 *data, *first_rx_q, *first_tx_q;
|
|
|
|
u32 num_cq, num_rx, num_tx;
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
first_rx_q = ctx->data + num_rx + num_tx + num_cq;
|
|
|
|
first_tx_q = first_rx_q + vi->curr_queue_pairs * num_rx;
|
|
|
|
|
|
|
|
data = ctx->data;
|
|
|
|
|
|
|
|
stats_sum_queue(data, num_rx, first_rx_q, vi->curr_queue_pairs);
|
|
|
|
|
|
|
|
data = ctx->data + num_rx;
|
|
|
|
|
|
|
|
stats_sum_queue(data, num_tx, first_tx_q, vi->curr_queue_pairs);
|
|
|
|
}
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
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
|
2024-04-26 03:39:25 +00:00
|
|
|
* The stats source is the device or the driver.
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
*
|
|
|
|
* @vi: virtio net info
|
|
|
|
* @qid: the vq id
|
|
|
|
* @ctx: stats ctx (initiated by virtnet_stats_ctx_init())
|
2024-04-26 03:39:25 +00:00
|
|
|
* @base: pointer to the device reply or the driver stats structure.
|
|
|
|
* @drv_stats: designate the base type (device reply, driver stats)
|
|
|
|
* @type: the type of the device reply (if drv_stats is true, this must be zero)
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
*/
|
|
|
|
static void virtnet_fill_stats(struct virtnet_info *vi, u32 qid,
|
|
|
|
struct virtnet_stats_ctx *ctx,
|
2024-04-26 03:39:25 +00:00
|
|
|
const u8 *base, bool drv_stats, u8 reply_type)
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
{
|
|
|
|
u32 queue_type, num_rx, num_tx, num_cq;
|
|
|
|
const struct virtnet_stat_desc *desc;
|
2024-04-26 03:39:25 +00:00
|
|
|
const u64_stats_t *v_stat;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
u64 offset, bitmap;
|
|
|
|
const __le64 *v;
|
|
|
|
int i, num;
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
if (ctx->to_qstat)
|
|
|
|
return virtnet_fill_stats_qstat(vi, qid, ctx, base, drv_stats, reply_type);
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
num_cq = ctx->desc_num[VIRTNET_Q_TYPE_CQ];
|
2024-04-26 03:39:25 +00:00
|
|
|
num_rx = ctx->desc_num[VIRTNET_Q_TYPE_RX];
|
|
|
|
num_tx = ctx->desc_num[VIRTNET_Q_TYPE_TX];
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
queue_type = vq_type(vi, qid);
|
|
|
|
bitmap = ctx->bitmap[queue_type];
|
2024-04-26 03:39:26 +00:00
|
|
|
|
|
|
|
/* skip the total fields of pairs */
|
|
|
|
offset = num_rx + num_tx;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
if (queue_type == VIRTNET_Q_TYPE_TX) {
|
2024-04-26 03:39:25 +00:00
|
|
|
offset += num_cq + num_rx * vi->curr_queue_pairs + num_tx * (qid / 2);
|
|
|
|
|
|
|
|
num = ARRAY_SIZE(virtnet_sq_stats_desc);
|
|
|
|
if (drv_stats) {
|
|
|
|
desc = &virtnet_sq_stats_desc[0];
|
|
|
|
goto drv_stats;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
} else if (queue_type == VIRTNET_Q_TYPE_RX) {
|
2024-04-26 03:39:25 +00:00
|
|
|
offset += num_cq + num_rx * (qid / 2);
|
|
|
|
|
|
|
|
num = ARRAY_SIZE(virtnet_rq_stats_desc);
|
|
|
|
if (drv_stats) {
|
|
|
|
desc = &virtnet_rq_stats_desc[0];
|
|
|
|
goto drv_stats;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += num;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_CVQ) {
|
|
|
|
desc = &virtnet_stats_cvq_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_cvq_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_CVQ)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_BASIC) {
|
|
|
|
desc = &virtnet_stats_rx_basic_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_rx_basic_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_BASIC)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_CSUM) {
|
|
|
|
desc = &virtnet_stats_rx_csum_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_rx_csum_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_CSUM)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_RX_SPEED) {
|
|
|
|
desc = &virtnet_stats_rx_speed_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_rx_speed_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_RX_SPEED)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_BASIC) {
|
|
|
|
desc = &virtnet_stats_tx_basic_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_tx_basic_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_BASIC)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_GSO) {
|
|
|
|
desc = &virtnet_stats_tx_gso_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_tx_gso_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_GSO)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmap & VIRTIO_NET_STATS_TYPE_TX_SPEED) {
|
|
|
|
desc = &virtnet_stats_tx_speed_desc[0];
|
|
|
|
num = ARRAY_SIZE(virtnet_stats_tx_speed_desc);
|
|
|
|
if (reply_type == VIRTIO_NET_STATS_TYPE_REPLY_TX_SPEED)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
offset += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
found:
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
v = (const __le64 *)(base + desc[i].offset);
|
|
|
|
ctx->data[offset + i] = le64_to_cpu(*v);
|
|
|
|
}
|
2024-04-26 03:39:25 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
drv_stats:
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
v_stat = (const u64_stats_t *)(base + desc[i].offset);
|
|
|
|
ctx->data[offset + i] = u64_stats_read(v_stat);
|
|
|
|
}
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int __virtnet_get_hw_stats(struct virtnet_info *vi,
|
|
|
|
struct virtnet_stats_ctx *ctx,
|
|
|
|
struct virtio_net_ctrl_queue_stats *req,
|
|
|
|
int req_size, void *reply, int res_size)
|
|
|
|
{
|
|
|
|
struct virtio_net_stats_reply_hdr *hdr;
|
|
|
|
struct scatterlist sgs_in, sgs_out;
|
|
|
|
void *p;
|
|
|
|
u32 qid;
|
|
|
|
int ok;
|
|
|
|
|
|
|
|
sg_init_one(&sgs_out, req, req_size);
|
|
|
|
sg_init_one(&sgs_in, reply, res_size);
|
|
|
|
|
|
|
|
ok = virtnet_send_command_reply(vi, VIRTIO_NET_CTRL_STATS,
|
|
|
|
VIRTIO_NET_CTRL_STATS_GET,
|
|
|
|
&sgs_out, &sgs_in);
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
return ok;
|
|
|
|
|
|
|
|
for (p = reply; p - reply < res_size; p += le16_to_cpu(hdr->size)) {
|
|
|
|
hdr = p;
|
|
|
|
qid = le16_to_cpu(hdr->vq_index);
|
2024-04-26 03:39:25 +00:00
|
|
|
virtnet_fill_stats(vi, qid, ctx, p, false, hdr->type);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_make_stat_req(struct virtnet_info *vi,
|
|
|
|
struct virtnet_stats_ctx *ctx,
|
|
|
|
struct virtio_net_ctrl_queue_stats *req,
|
|
|
|
int qid, int *idx)
|
|
|
|
{
|
|
|
|
int qtype = vq_type(vi, qid);
|
|
|
|
u64 bitmap = ctx->bitmap[qtype];
|
|
|
|
|
|
|
|
if (!bitmap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
req->stats[*idx].vq_index = cpu_to_le16(qid);
|
|
|
|
req->stats[*idx].types_bitmap[0] = cpu_to_le64(bitmap);
|
|
|
|
*idx += 1;
|
|
|
|
}
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
/* qid: -1: get stats of all vq.
|
|
|
|
* > 0: get the stats for the special vq. This must not be cvq.
|
|
|
|
*/
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
static int virtnet_get_hw_stats(struct virtnet_info *vi,
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
struct virtnet_stats_ctx *ctx, int qid)
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +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>
2024-04-26 03:39:28 +00:00
|
|
|
int qnum, i, j, res_size, qtype, last_vq, first_vq;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
struct virtio_net_ctrl_queue_stats *req;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
bool enable_cvq;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
void *reply;
|
|
|
|
int ok;
|
|
|
|
|
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS))
|
|
|
|
return 0;
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
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;
|
|
|
|
}
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
qnum = 0;
|
|
|
|
res_size = 0;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
for (i = first_vq; i <= last_vq ; ++i) {
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
qtype = vq_type(vi, i);
|
|
|
|
if (ctx->bitmap[qtype]) {
|
|
|
|
++qnum;
|
|
|
|
res_size += ctx->size[qtype];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
if (enable_cvq && ctx->bitmap[VIRTNET_Q_TYPE_CQ]) {
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
res_size += ctx->size[VIRTNET_Q_TYPE_CQ];
|
|
|
|
qnum += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
req = kcalloc(qnum, sizeof(*req), GFP_KERNEL);
|
|
|
|
if (!req)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
reply = kmalloc(res_size, GFP_KERNEL);
|
|
|
|
if (!reply) {
|
|
|
|
kfree(req);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
j = 0;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
for (i = first_vq; i <= last_vq ; ++i)
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
virtnet_make_stat_req(vi, ctx, req, i, &j);
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
if (enable_cvq)
|
|
|
|
virtnet_make_stat_req(vi, ctx, req, vi->max_queue_pairs * 2, &j);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
ok = __virtnet_get_hw_stats(vi, ctx, req, sizeof(*req) * j, reply, res_size);
|
|
|
|
|
|
|
|
kfree(req);
|
|
|
|
kfree(reply);
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2024-04-26 03:39:25 +00:00
|
|
|
unsigned int i;
|
2021-03-17 00:31:29 +00:00
|
|
|
u8 *p = data;
|
2018-01-17 06:38:25 +00:00
|
|
|
|
|
|
|
switch (stringset) {
|
|
|
|
case ETH_SS_STATS:
|
2024-04-26 03:39:26 +00:00
|
|
|
/* Generate the total field names. */
|
|
|
|
virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_RX, -1, &p);
|
|
|
|
virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_TX, -1, &p);
|
|
|
|
|
2024-04-26 03:39:25 +00:00
|
|
|
virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_CQ, 0, &p);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
2024-04-26 03:39:25 +00:00
|
|
|
for (i = 0; i < vi->curr_queue_pairs; ++i)
|
|
|
|
virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_RX, i, &p);
|
2018-01-17 06:38:25 +00:00
|
|
|
|
2024-04-26 03:39:25 +00:00
|
|
|
for (i = 0; i < vi->curr_queue_pairs; ++i)
|
|
|
|
virtnet_get_stats_string(vi, VIRTNET_Q_TYPE_TX, i, &p);
|
2018-01-17 06:38:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_get_sset_count(struct net_device *dev, int sset)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
struct virtnet_stats_ctx ctx = {0};
|
|
|
|
u32 pair_count;
|
2018-01-17 06:38:25 +00:00
|
|
|
|
|
|
|
switch (sset) {
|
|
|
|
case ETH_SS_STATS:
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
virtnet_stats_ctx_init(vi, &ctx, NULL, false);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
2024-04-26 03:39:25 +00:00
|
|
|
pair_count = ctx.desc_num[VIRTNET_Q_TYPE_RX] + ctx.desc_num[VIRTNET_Q_TYPE_TX];
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
2024-04-26 03:39:26 +00:00
|
|
|
return pair_count + ctx.desc_num[VIRTNET_Q_TYPE_CQ] +
|
|
|
|
vi->curr_queue_pairs * pair_count;
|
2018-01-17 06:38:25 +00:00
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_get_ethtool_stats(struct net_device *dev,
|
|
|
|
struct ethtool_stats *stats, u64 *data)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
struct virtnet_stats_ctx ctx = {0};
|
2024-04-26 03:39:25 +00:00
|
|
|
unsigned int start, i;
|
2018-01-17 06:38:25 +00:00
|
|
|
const u8 *stats_base;
|
|
|
|
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
virtnet_stats_ctx_init(vi, &ctx, data, false);
|
|
|
|
if (virtnet_get_hw_stats(vi, &ctx, -1))
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
dev_warn(&vi->dev->dev, "Failed to get hw stats.\n");
|
|
|
|
|
2018-01-17 06:38:25 +00:00
|
|
|
for (i = 0; i < vi->curr_queue_pairs; i++) {
|
|
|
|
struct receive_queue *rq = &vi->rq[i];
|
2024-04-26 03:39:25 +00:00
|
|
|
struct send_queue *sq = &vi->sq[i];
|
2018-01-17 06:38:25 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
stats_base = (const u8 *)&rq->stats;
|
2018-01-17 06:38:25 +00:00
|
|
|
do {
|
2022-10-26 13:22:14 +00:00
|
|
|
start = u64_stats_fetch_begin(&rq->stats.syncp);
|
2024-04-26 03:39:25 +00:00
|
|
|
virtnet_fill_stats(vi, i * 2, &ctx, stats_base, true, 0);
|
2022-10-26 13:22:14 +00:00
|
|
|
} while (u64_stats_fetch_retry(&rq->stats.syncp, start));
|
2018-01-17 06:38:25 +00:00
|
|
|
|
2023-10-26 17:18:40 +00:00
|
|
|
stats_base = (const u8 *)&sq->stats;
|
2018-01-17 06:38:25 +00:00
|
|
|
do {
|
2022-10-26 13:22:14 +00:00
|
|
|
start = u64_stats_fetch_begin(&sq->stats.syncp);
|
2024-04-26 03:39:25 +00:00
|
|
|
virtnet_fill_stats(vi, i * 2 + 1, &ctx, stats_base, true, 0);
|
2022-10-26 13:22:14 +00:00
|
|
|
} while (u64_stats_fetch_retry(&sq->stats.syncp, start));
|
2018-01-17 06:38:25 +00:00
|
|
|
}
|
2024-04-26 03:39:26 +00:00
|
|
|
|
|
|
|
virtnet_fill_total_fields(vi, &ctx);
|
2018-01-17 06:38:25 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:57 +00:00
|
|
|
static void virtnet_get_channels(struct net_device *dev,
|
|
|
|
struct ethtool_channels *channels)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
|
|
|
channels->combined_count = vi->curr_queue_pairs;
|
|
|
|
channels->max_combined = vi->max_queue_pairs;
|
|
|
|
channels->max_other = 0;
|
|
|
|
channels->rx_count = 0;
|
|
|
|
channels->tx_count = 0;
|
|
|
|
channels->other_count = 0;
|
|
|
|
}
|
|
|
|
|
2017-03-21 22:24:24 +00:00
|
|
|
static int virtnet_set_link_ksettings(struct net_device *dev,
|
|
|
|
const struct ethtool_link_ksettings *cmd)
|
2016-02-03 03:04:37 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
2020-02-28 20:12:05 +00:00
|
|
|
return ethtool_virtdev_set_link_ksettings(dev, cmd,
|
|
|
|
&vi->speed, &vi->duplex);
|
2016-02-03 03:04:37 +00:00
|
|
|
}
|
|
|
|
|
2017-03-21 22:24:24 +00:00
|
|
|
static int virtnet_get_link_ksettings(struct net_device *dev,
|
|
|
|
struct ethtool_link_ksettings *cmd)
|
2016-02-03 03:04:37 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
2017-03-21 22:24:24 +00:00
|
|
|
cmd->base.speed = vi->speed;
|
|
|
|
cmd->base.duplex = vi->duplex;
|
|
|
|
cmd->base.port = PORT_OTHER;
|
2016-02-03 03:04:37 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:05 +00:00
|
|
|
static int virtnet_send_tx_notf_coal_cmds(struct virtnet_info *vi,
|
|
|
|
struct ethtool_coalesce *ec)
|
2022-07-18 09:11:02 +00:00
|
|
|
{
|
2024-05-03 20:24:41 +00:00
|
|
|
struct virtio_net_ctrl_coal_tx *coal_tx __free(kfree) = NULL;
|
2023-12-11 10:36:05 +00:00
|
|
|
struct scatterlist sgs_tx;
|
2023-10-08 06:27:41 +00:00
|
|
|
int i;
|
2022-07-18 09:11:02 +00:00
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
coal_tx = kzalloc(sizeof(*coal_tx), GFP_KERNEL);
|
|
|
|
if (!coal_tx)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
coal_tx->tx_usecs = cpu_to_le32(ec->tx_coalesce_usecs);
|
|
|
|
coal_tx->tx_max_packets = cpu_to_le32(ec->tx_max_coalesced_frames);
|
|
|
|
sg_init_one(&sgs_tx, coal_tx, sizeof(*coal_tx));
|
2022-07-18 09:11:02 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
|
|
|
|
VIRTIO_NET_CTRL_NOTF_COAL_TX_SET,
|
|
|
|
&sgs_tx))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-07-31 07:06:54 +00:00
|
|
|
vi->intr_coal_tx.max_usecs = ec->tx_coalesce_usecs;
|
|
|
|
vi->intr_coal_tx.max_packets = ec->tx_max_coalesced_frames;
|
2023-10-08 06:27:41 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
vi->sq[i].intr_coal.max_usecs = ec->tx_coalesce_usecs;
|
|
|
|
vi->sq[i].intr_coal.max_packets = ec->tx_max_coalesced_frames;
|
|
|
|
}
|
2022-07-18 09:11:02 +00:00
|
|
|
|
2023-12-11 10:36:05 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
|
|
|
|
struct ethtool_coalesce *ec)
|
|
|
|
{
|
2024-05-03 20:24:41 +00:00
|
|
|
struct virtio_net_ctrl_coal_rx *coal_rx __free(kfree) = NULL;
|
2023-12-11 10:36:07 +00:00
|
|
|
bool rx_ctrl_dim_on = !!ec->use_adaptive_rx_coalesce;
|
2023-12-11 10:36:05 +00:00
|
|
|
struct scatterlist sgs_rx;
|
|
|
|
int i;
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
if (rx_ctrl_dim_on && !virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (rx_ctrl_dim_on && (ec->rx_coalesce_usecs != vi->intr_coal_rx.max_usecs ||
|
|
|
|
ec->rx_max_coalesced_frames != vi->intr_coal_rx.max_packets))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (rx_ctrl_dim_on && !vi->rx_dim_enabled) {
|
|
|
|
vi->rx_dim_enabled = true;
|
2024-05-28 13:41:16 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
mutex_lock(&vi->rq[i].dim_lock);
|
2023-12-11 10:36:07 +00:00
|
|
|
vi->rq[i].dim_enabled = true;
|
2024-05-28 13:41:16 +00:00
|
|
|
mutex_unlock(&vi->rq[i].dim_lock);
|
|
|
|
}
|
|
|
|
return 0;
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
coal_rx = kzalloc(sizeof(*coal_rx), GFP_KERNEL);
|
2024-05-28 13:41:16 +00:00
|
|
|
if (!coal_rx)
|
|
|
|
return -ENOMEM;
|
2024-05-03 20:24:41 +00:00
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
if (!rx_ctrl_dim_on && vi->rx_dim_enabled) {
|
|
|
|
vi->rx_dim_enabled = false;
|
2024-05-28 13:41:16 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
mutex_lock(&vi->rq[i].dim_lock);
|
2023-12-11 10:36:07 +00:00
|
|
|
vi->rq[i].dim_enabled = false;
|
2024-05-28 13:41:16 +00:00
|
|
|
mutex_unlock(&vi->rq[i].dim_lock);
|
|
|
|
}
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Since the per-queue coalescing params can be set,
|
|
|
|
* we need apply the global new params even if they
|
|
|
|
* are not updated.
|
|
|
|
*/
|
2024-05-03 20:24:41 +00:00
|
|
|
coal_rx->rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
|
|
|
|
coal_rx->rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
|
|
|
|
sg_init_one(&sgs_rx, coal_rx, sizeof(*coal_rx));
|
2022-07-18 09:11:02 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
|
|
|
|
VIRTIO_NET_CTRL_NOTF_COAL_RX_SET,
|
2024-05-28 13:41:16 +00:00
|
|
|
&sgs_rx))
|
|
|
|
return -EINVAL;
|
2022-07-18 09:11:02 +00:00
|
|
|
|
2023-07-31 07:06:54 +00:00
|
|
|
vi->intr_coal_rx.max_usecs = ec->rx_coalesce_usecs;
|
|
|
|
vi->intr_coal_rx.max_packets = ec->rx_max_coalesced_frames;
|
2023-10-08 06:27:41 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2024-05-28 13:41:16 +00:00
|
|
|
mutex_lock(&vi->rq[i].dim_lock);
|
2023-10-08 06:27:41 +00:00
|
|
|
vi->rq[i].intr_coal.max_usecs = ec->rx_coalesce_usecs;
|
|
|
|
vi->rq[i].intr_coal.max_packets = ec->rx_max_coalesced_frames;
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_unlock(&vi->rq[i].dim_lock);
|
2024-05-28 13:41:16 +00:00
|
|
|
}
|
2022-07-18 09:11:02 +00:00
|
|
|
|
2024-05-28 13:41:16 +00:00
|
|
|
return 0;
|
2022-07-18 09:11:02 +00:00
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:05 +00:00
|
|
|
static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
|
|
|
|
struct ethtool_coalesce *ec)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = virtnet_send_tx_notf_coal_cmds(vi, ec);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = virtnet_send_rx_notf_coal_cmds(vi, ec);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
|
|
|
|
struct ethtool_coalesce *ec,
|
|
|
|
u16 queue)
|
2023-07-31 07:06:55 +00:00
|
|
|
{
|
2023-12-11 10:36:07 +00:00
|
|
|
bool rx_ctrl_dim_on = !!ec->use_adaptive_rx_coalesce;
|
|
|
|
u32 max_usecs, max_packets;
|
2024-05-03 20:24:44 +00:00
|
|
|
bool cur_rx_dim;
|
2023-07-31 07:06:55 +00:00
|
|
|
int err;
|
|
|
|
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_lock(&vi->rq[queue].dim_lock);
|
|
|
|
cur_rx_dim = vi->rq[queue].dim_enabled;
|
2023-12-11 10:36:07 +00:00
|
|
|
max_usecs = vi->rq[queue].intr_coal.max_usecs;
|
|
|
|
max_packets = vi->rq[queue].intr_coal.max_packets;
|
|
|
|
|
|
|
|
if (rx_ctrl_dim_on && (ec->rx_coalesce_usecs != max_usecs ||
|
2024-05-03 20:24:44 +00:00
|
|
|
ec->rx_max_coalesced_frames != max_packets)) {
|
|
|
|
mutex_unlock(&vi->rq[queue].dim_lock);
|
2023-12-11 10:36:07 +00:00
|
|
|
return -EINVAL;
|
2024-05-03 20:24:44 +00:00
|
|
|
}
|
2023-12-11 10:36:07 +00:00
|
|
|
|
|
|
|
if (rx_ctrl_dim_on && !cur_rx_dim) {
|
|
|
|
vi->rq[queue].dim_enabled = true;
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_unlock(&vi->rq[queue].dim_lock);
|
2023-12-11 10:36:07 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rx_ctrl_dim_on && cur_rx_dim)
|
|
|
|
vi->rq[queue].dim_enabled = false;
|
|
|
|
|
|
|
|
/* If no params are updated, userspace ethtool will
|
|
|
|
* reject the modification.
|
|
|
|
*/
|
2023-12-11 10:36:06 +00:00
|
|
|
err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, queue,
|
|
|
|
ec->rx_coalesce_usecs,
|
|
|
|
ec->rx_max_coalesced_frames);
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_unlock(&vi->rq[queue].dim_lock);
|
|
|
|
return err;
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_send_notf_coal_vq_cmds(struct virtnet_info *vi,
|
|
|
|
struct ethtool_coalesce *ec,
|
|
|
|
u16 queue)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = virtnet_send_rx_notf_coal_vq_cmds(vi, ec, queue);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2023-12-11 10:36:06 +00:00
|
|
|
err = virtnet_send_tx_ctrl_coal_vq_cmd(vi, queue,
|
|
|
|
ec->tx_coalesce_usecs,
|
|
|
|
ec->tx_max_coalesced_frames);
|
2023-10-08 06:27:42 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2023-07-31 07:06:55 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-12-11 10:36:07 +00:00
|
|
|
static void virtnet_rx_dim_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct dim *dim = container_of(work, struct dim, work);
|
|
|
|
struct receive_queue *rq = container_of(dim,
|
|
|
|
struct receive_queue, dim);
|
|
|
|
struct virtnet_info *vi = rq->vq->vdev->priv;
|
|
|
|
struct net_device *dev = vi->dev;
|
|
|
|
struct dim_cq_moder update_moder;
|
2024-05-03 20:24:43 +00:00
|
|
|
int qnum, err;
|
2023-12-11 10:36:07 +00:00
|
|
|
|
2024-05-03 20:24:43 +00:00
|
|
|
qnum = rq - vi->rq;
|
2023-12-11 10:36:07 +00:00
|
|
|
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_lock(&rq->dim_lock);
|
2024-05-03 20:24:43 +00:00
|
|
|
if (!rq->dim_enabled)
|
|
|
|
goto out;
|
2023-12-11 10:36:07 +00:00
|
|
|
|
2024-06-21 10:13:53 +00:00
|
|
|
update_moder = net_dim_get_rx_irq_moder(dev, dim);
|
2024-05-03 20:24:43 +00:00
|
|
|
if (update_moder.usec != rq->intr_coal.max_usecs ||
|
|
|
|
update_moder.pkts != rq->intr_coal.max_packets) {
|
|
|
|
err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, qnum,
|
|
|
|
update_moder.usec,
|
|
|
|
update_moder.pkts);
|
|
|
|
if (err)
|
|
|
|
pr_debug("%s: Failed to send dim parameters on rxq%d\n",
|
|
|
|
dev->name, qnum);
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
2024-05-03 20:24:43 +00:00
|
|
|
out:
|
2024-05-28 13:41:15 +00:00
|
|
|
dim->state = DIM_START_MEASURE;
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_unlock(&rq->dim_lock);
|
2023-12-11 10:36:07 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 09:11:02 +00:00
|
|
|
static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
|
|
|
|
{
|
|
|
|
/* usecs coalescing is supported only if VIRTIO_NET_F_NOTF_COAL
|
2023-10-08 06:27:44 +00:00
|
|
|
* or VIRTIO_NET_F_VQ_NOTF_COAL feature is negotiated.
|
2022-07-18 09:11:02 +00:00
|
|
|
*/
|
|
|
|
if (ec->rx_coalesce_usecs || ec->tx_coalesce_usecs)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (ec->tx_max_coalesced_frames > 1 ||
|
|
|
|
ec->rx_max_coalesced_frames != 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-31 07:06:55 +00:00
|
|
|
static int virtnet_should_update_vq_weight(int dev_flags, int weight,
|
|
|
|
int vq_weight, bool *should_update)
|
|
|
|
{
|
|
|
|
if (weight ^ vq_weight) {
|
|
|
|
if (dev_flags & IFF_UP)
|
|
|
|
return -EBUSY;
|
|
|
|
*should_update = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-09 02:06:26 +00:00
|
|
|
static int virtnet_set_coalesce(struct net_device *dev,
|
2021-08-20 07:35:18 +00:00
|
|
|
struct ethtool_coalesce *ec,
|
|
|
|
struct kernel_ethtool_coalesce *kernel_coal,
|
|
|
|
struct netlink_ext_ack *extack)
|
2018-10-09 02:06:26 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2023-07-31 07:06:55 +00:00
|
|
|
int ret, queue_number, napi_weight;
|
2022-07-18 09:11:02 +00:00
|
|
|
bool update_napi = false;
|
2018-10-09 02:06:26 +00:00
|
|
|
|
2022-07-18 09:11:02 +00:00
|
|
|
/* Can't change NAPI weight if the link is up */
|
2018-10-09 02:06:26 +00:00
|
|
|
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
|
2023-07-31 07:06:55 +00:00
|
|
|
for (queue_number = 0; queue_number < vi->max_queue_pairs; queue_number++) {
|
|
|
|
ret = virtnet_should_update_vq_weight(dev->flags, napi_weight,
|
|
|
|
vi->sq[queue_number].napi.weight,
|
|
|
|
&update_napi);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (update_napi) {
|
|
|
|
/* All queues that belong to [queue_number, vi->max_queue_pairs] will be
|
|
|
|
* updated for the sake of simplicity, which might not be necessary
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
2022-07-18 09:11:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL))
|
|
|
|
ret = virtnet_send_notf_coal_cmds(vi, ec);
|
|
|
|
else
|
|
|
|
ret = virtnet_coal_params_supported(ec);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (update_napi) {
|
2023-07-31 07:06:55 +00:00
|
|
|
for (; queue_number < vi->max_queue_pairs; queue_number++)
|
|
|
|
vi->sq[queue_number].napi.weight = napi_weight;
|
2018-10-09 02:06:26 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 09:11:02 +00:00
|
|
|
return ret;
|
2018-10-09 02:06:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_get_coalesce(struct net_device *dev,
|
2021-08-20 07:35:18 +00:00
|
|
|
struct ethtool_coalesce *ec,
|
|
|
|
struct kernel_ethtool_coalesce *kernel_coal,
|
|
|
|
struct netlink_ext_ack *extack)
|
2018-10-09 02:06:26 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
2022-07-18 09:11:02 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
|
2023-07-31 07:06:54 +00:00
|
|
|
ec->rx_coalesce_usecs = vi->intr_coal_rx.max_usecs;
|
|
|
|
ec->tx_coalesce_usecs = vi->intr_coal_tx.max_usecs;
|
|
|
|
ec->tx_max_coalesced_frames = vi->intr_coal_tx.max_packets;
|
|
|
|
ec->rx_max_coalesced_frames = vi->intr_coal_rx.max_packets;
|
2023-12-11 10:36:07 +00:00
|
|
|
ec->use_adaptive_rx_coalesce = vi->rx_dim_enabled;
|
2022-07-18 09:11:02 +00:00
|
|
|
} else {
|
|
|
|
ec->rx_max_coalesced_frames = 1;
|
2018-10-09 02:06:26 +00:00
|
|
|
|
2022-07-18 09:11:02 +00:00
|
|
|
if (vi->sq[0].napi.weight)
|
|
|
|
ec->tx_max_coalesced_frames = 1;
|
|
|
|
}
|
2018-10-09 02:06:26 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-31 07:06:55 +00:00
|
|
|
static int virtnet_set_per_queue_coalesce(struct net_device *dev,
|
|
|
|
u32 queue,
|
|
|
|
struct ethtool_coalesce *ec)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
int ret, napi_weight;
|
|
|
|
bool update_napi = false;
|
|
|
|
|
|
|
|
if (queue >= vi->max_queue_pairs)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Can't change NAPI weight if the link is up */
|
|
|
|
napi_weight = ec->tx_max_coalesced_frames ? NAPI_POLL_WEIGHT : 0;
|
|
|
|
ret = virtnet_should_update_vq_weight(dev->flags, napi_weight,
|
|
|
|
vi->sq[queue].napi.weight,
|
|
|
|
&update_napi);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
|
|
|
|
ret = virtnet_send_notf_coal_vq_cmds(vi, ec, queue);
|
|
|
|
else
|
|
|
|
ret = virtnet_coal_params_supported(ec);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (update_napi)
|
|
|
|
vi->sq[queue].napi.weight = napi_weight;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_get_per_queue_coalesce(struct net_device *dev,
|
|
|
|
u32 queue,
|
|
|
|
struct ethtool_coalesce *ec)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
|
|
|
if (queue >= vi->max_queue_pairs)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL)) {
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_lock(&vi->rq[queue].dim_lock);
|
2023-07-31 07:06:55 +00:00
|
|
|
ec->rx_coalesce_usecs = vi->rq[queue].intr_coal.max_usecs;
|
|
|
|
ec->tx_coalesce_usecs = vi->sq[queue].intr_coal.max_usecs;
|
|
|
|
ec->tx_max_coalesced_frames = vi->sq[queue].intr_coal.max_packets;
|
|
|
|
ec->rx_max_coalesced_frames = vi->rq[queue].intr_coal.max_packets;
|
2023-12-11 10:36:07 +00:00
|
|
|
ec->use_adaptive_rx_coalesce = vi->rq[queue].dim_enabled;
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_unlock(&vi->rq[queue].dim_lock);
|
2023-07-31 07:06:55 +00:00
|
|
|
} else {
|
|
|
|
ec->rx_max_coalesced_frames = 1;
|
|
|
|
|
2023-10-08 06:27:40 +00:00
|
|
|
if (vi->sq[queue].napi.weight)
|
2023-07-31 07:06:55 +00:00
|
|
|
ec->tx_max_coalesced_frames = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-03 03:04:37 +00:00
|
|
|
static void virtnet_init_settings(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
|
|
|
|
vi->speed = SPEED_UNKNOWN;
|
|
|
|
vi->duplex = DUPLEX_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
|
|
|
|
{
|
|
|
|
return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
|
|
|
|
{
|
|
|
|
return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
|
|
|
|
}
|
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
static int virtnet_get_rxfh(struct net_device *dev,
|
|
|
|
struct ethtool_rxfh_param *rxfh)
|
2022-03-28 17:53:34 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
int i;
|
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
if (rxfh->indir) {
|
2022-03-28 17:53:34 +00:00
|
|
|
for (i = 0; i < vi->rss_indir_table_size; ++i)
|
2024-05-03 20:24:40 +00:00
|
|
|
rxfh->indir[i] = vi->rss.indirection_table[i];
|
2022-03-28 17:53:34 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
if (rxfh->key)
|
2024-05-03 20:24:40 +00:00
|
|
|
memcpy(rxfh->key, vi->rss.key, vi->rss_key_size);
|
2022-03-28 17:53:34 +00:00
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
rxfh->hfunc = ETH_RSS_HASH_TOP;
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
static int virtnet_set_rxfh(struct net_device *dev,
|
|
|
|
struct ethtool_rxfh_param *rxfh,
|
|
|
|
struct netlink_ext_ack *extack)
|
2022-03-28 17:53:34 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
bool update = false;
|
2022-03-28 17:53:34 +00:00
|
|
|
int i;
|
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
|
|
|
|
rxfh->hfunc != ETH_RSS_HASH_TOP)
|
2022-03-28 17:53:34 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-12-13 00:33:14 +00:00
|
|
|
if (rxfh->indir) {
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
if (!vi->has_rss)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
for (i = 0; i < vi->rss_indir_table_size; ++i)
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.indirection_table[i] = rxfh->indir[i];
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
update = true;
|
2022-03-28 17:53:34 +00:00
|
|
|
}
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
|
|
|
|
if (rxfh->key) {
|
|
|
|
/* If either _F_HASH_REPORT or _F_RSS are negotiated, the
|
|
|
|
* device provides hash calculation capabilities, that is,
|
|
|
|
* hash_key is configured.
|
|
|
|
*/
|
|
|
|
if (!vi->has_rss && !vi->has_rss_hash_report)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2024-05-03 20:24:40 +00:00
|
|
|
memcpy(vi->rss.key, rxfh->key, vi->rss_key_size);
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
update = true;
|
|
|
|
}
|
2022-03-28 17:53:34 +00:00
|
|
|
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
if (update)
|
|
|
|
virtnet_commit_rss_command(vi);
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (info->cmd) {
|
|
|
|
case ETHTOOL_GRXRINGS:
|
|
|
|
info->data = vi->curr_queue_pairs;
|
2022-03-28 17:53:36 +00:00
|
|
|
break;
|
|
|
|
case ETHTOOL_GRXFH:
|
|
|
|
virtnet_get_hashflow(vi, info);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
switch (info->cmd) {
|
|
|
|
case ETHTOOL_SRXFH:
|
|
|
|
if (!virtnet_set_hashflow(vi, info))
|
|
|
|
rc = -EINVAL;
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-09-02 08:03:33 +00:00
|
|
|
static const struct ethtool_ops virtnet_ethtool_ops = {
|
2022-07-18 09:11:02 +00:00
|
|
|
.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |
|
2023-12-11 10:36:07 +00:00
|
|
|
ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
|
2011-11-14 14:17:08 +00:00
|
|
|
.get_drvinfo = virtnet_get_drvinfo,
|
2009-01-20 01:09:49 +00:00
|
|
|
.get_link = ethtool_op_get_link,
|
2011-10-19 08:10:59 +00:00
|
|
|
.get_ringparam = virtnet_get_ringparam,
|
2022-08-01 06:39:02 +00:00
|
|
|
.set_ringparam = virtnet_set_ringparam,
|
2018-01-17 06:38:25 +00:00
|
|
|
.get_strings = virtnet_get_strings,
|
|
|
|
.get_sset_count = virtnet_get_sset_count,
|
|
|
|
.get_ethtool_stats = virtnet_get_ethtool_stats,
|
2012-12-07 07:04:57 +00:00
|
|
|
.set_channels = virtnet_set_channels,
|
|
|
|
.get_channels = virtnet_get_channels,
|
2014-06-25 02:37:13 +00:00
|
|
|
.get_ts_info = ethtool_op_get_ts_info,
|
2017-03-21 22:24:24 +00:00
|
|
|
.get_link_ksettings = virtnet_get_link_ksettings,
|
|
|
|
.set_link_ksettings = virtnet_set_link_ksettings,
|
2018-10-09 02:06:26 +00:00
|
|
|
.set_coalesce = virtnet_set_coalesce,
|
|
|
|
.get_coalesce = virtnet_get_coalesce,
|
2023-07-31 07:06:55 +00:00
|
|
|
.set_per_queue_coalesce = virtnet_set_per_queue_coalesce,
|
|
|
|
.get_per_queue_coalesce = virtnet_get_per_queue_coalesce,
|
2022-03-28 17:53:34 +00:00
|
|
|
.get_rxfh_key_size = virtnet_get_rxfh_key_size,
|
|
|
|
.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
|
|
|
|
.get_rxfh = virtnet_get_rxfh,
|
|
|
|
.set_rxfh = virtnet_set_rxfh,
|
|
|
|
.get_rxnfc = virtnet_get_rxnfc,
|
2022-03-28 17:53:36 +00:00
|
|
|
.set_rxnfc = virtnet_set_rxnfc,
|
2008-04-18 03:21:42 +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>
2024-04-26 03:39:28 +00:00
|
|
|
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;
|
virtio_net: Add TX stopped and wake counters
Add a tx queue stop and wake counters, they are useful for debugging.
$ ./tools/net/ynl/cli.py --spec netlink/specs/netdev.yaml \
--dump qstats-get --json '{"scope": "queue"}'
...
{'ifindex': 13,
'queue-id': 0,
'queue-type': 'tx',
'tx-bytes': 14756682850,
'tx-packets': 226465,
'tx-stop': 113208,
'tx-wake': 113208},
{'ifindex': 13,
'queue-id': 1,
'queue-type': 'tx',
'tx-bytes': 18167675008,
'tx-packets': 278660,
'tx-stop': 8632,
'tx-wake': 8632}]
Signed-off-by: Daniel Jurgens <danielj@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
Link: https://lore.kernel.org/r/20240510201927.1821109-3-danielj@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 20:19:27 +00:00
|
|
|
tx->stop = 0;
|
|
|
|
tx->wake = 0;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2017-02-03 03:16:01 +00:00
|
|
|
static void virtnet_freeze_down(struct virtio_device *vdev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vdev->priv;
|
|
|
|
|
|
|
|
/* Make sure no work handler is accessing the device */
|
|
|
|
flush_work(&vi->config_work);
|
2023-07-20 08:38:38 +00:00
|
|
|
disable_rx_mode_work(vi);
|
|
|
|
flush_work(&vi->rx_mode_work);
|
2017-02-03 03:16:01 +00:00
|
|
|
|
2018-10-17 10:44:12 +00:00
|
|
|
netif_tx_lock_bh(vi->dev);
|
2017-02-03 03:16:01 +00:00
|
|
|
netif_device_detach(vi->dev);
|
2018-10-17 10:44:12 +00:00
|
|
|
netif_tx_unlock_bh(vi->dev);
|
2022-06-21 11:48:44 +00:00
|
|
|
if (netif_running(vi->dev))
|
|
|
|
virtnet_close(vi->dev);
|
2017-02-03 03:16:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int init_vqs(struct virtnet_info *vi);
|
|
|
|
|
|
|
|
static int virtnet_restore_up(struct virtio_device *vdev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vdev->priv;
|
2022-06-21 11:48:44 +00:00
|
|
|
int err;
|
2017-02-03 03:16:01 +00:00
|
|
|
|
|
|
|
err = init_vqs(vi);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
virtio_device_ready(vdev);
|
|
|
|
|
2022-07-25 07:21:59 +00:00
|
|
|
enable_delayed_refill(vi);
|
2023-07-20 08:38:38 +00:00
|
|
|
enable_rx_mode_work(vi);
|
2022-07-25 07:21:59 +00:00
|
|
|
|
2017-02-03 03:16:01 +00:00
|
|
|
if (netif_running(vi->dev)) {
|
2022-06-21 11:48:44 +00:00
|
|
|
err = virtnet_open(vi->dev);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2017-02-03 03:16:01 +00:00
|
|
|
}
|
|
|
|
|
2018-10-17 10:44:12 +00:00
|
|
|
netif_tx_lock_bh(vi->dev);
|
2017-02-03 03:16:01 +00:00
|
|
|
netif_device_attach(vi->dev);
|
2018-10-17 10:44:12 +00:00
|
|
|
netif_tx_unlock_bh(vi->dev);
|
2017-02-03 03:16:01 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-07-19 08:54:49 +00:00
|
|
|
static int virtnet_set_guest_offloads(struct virtnet_info *vi, u64 offloads)
|
|
|
|
{
|
2024-05-03 20:24:41 +00:00
|
|
|
__virtio64 *_offloads __free(kfree) = NULL;
|
2017-07-19 08:54:49 +00:00
|
|
|
struct scatterlist sg;
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
_offloads = kzalloc(sizeof(*_offloads), GFP_KERNEL);
|
|
|
|
if (!_offloads)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*_offloads = cpu_to_virtio64(vi->vdev, offloads);
|
|
|
|
|
|
|
|
sg_init_one(&sg, _offloads, sizeof(*_offloads));
|
2017-07-19 08:54:49 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_GUEST_OFFLOADS,
|
|
|
|
VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &sg)) {
|
2019-04-03 09:10:13 +00:00
|
|
|
dev_warn(&vi->dev->dev, "Fail to set guest offload.\n");
|
2017-07-19 08:54:49 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_clear_guest_offloads(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
u64 offloads = 0;
|
|
|
|
|
|
|
|
if (!vi->guest_offloads)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return virtnet_set_guest_offloads(vi, offloads);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_restore_guest_offloads(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
u64 offloads = vi->guest_offloads;
|
|
|
|
|
|
|
|
if (!vi->guest_offloads)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return virtnet_set_guest_offloads(vi, offloads);
|
|
|
|
}
|
|
|
|
|
2024-07-08 11:25:33 +00:00
|
|
|
static int virtnet_rq_bind_xsk_pool(struct virtnet_info *vi, struct receive_queue *rq,
|
|
|
|
struct xsk_buff_pool *pool)
|
|
|
|
{
|
|
|
|
int err, qindex;
|
|
|
|
|
|
|
|
qindex = rq - vi->rq;
|
|
|
|
|
|
|
|
if (pool) {
|
|
|
|
err = xdp_rxq_info_reg(&rq->xsk_rxq_info, vi->dev, qindex, rq->napi.napi_id);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = xdp_rxq_info_reg_mem_model(&rq->xsk_rxq_info,
|
|
|
|
MEM_TYPE_XSK_BUFF_POOL, NULL);
|
|
|
|
if (err < 0)
|
|
|
|
goto unreg;
|
|
|
|
|
|
|
|
xsk_pool_set_rxq_info(pool, &rq->xsk_rxq_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtnet_rx_pause(vi, rq);
|
|
|
|
|
|
|
|
err = virtqueue_reset(rq->vq, virtnet_rq_unmap_free_buf);
|
|
|
|
if (err) {
|
|
|
|
netdev_err(vi->dev, "reset rx fail: rx queue index: %d err: %d\n", qindex, err);
|
|
|
|
|
|
|
|
pool = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rq->xsk_pool = pool;
|
|
|
|
|
|
|
|
virtnet_rx_resume(vi, rq);
|
|
|
|
|
|
|
|
if (pool)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unreg:
|
|
|
|
xdp_rxq_info_unreg(&rq->xsk_rxq_info);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_xsk_pool_enable(struct net_device *dev,
|
|
|
|
struct xsk_buff_pool *pool,
|
|
|
|
u16 qid)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
struct receive_queue *rq;
|
|
|
|
struct device *dma_dev;
|
|
|
|
struct send_queue *sq;
|
2024-07-08 11:25:35 +00:00
|
|
|
int err, size;
|
2024-07-08 11:25:33 +00:00
|
|
|
|
|
|
|
if (vi->hdr_len > xsk_pool_get_headroom(pool))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* In big_packets mode, xdp cannot work, so there is no need to
|
|
|
|
* initialize xsk of rq.
|
|
|
|
*/
|
|
|
|
if (vi->big_packets && !vi->mergeable_rx_bufs)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
if (qid >= vi->curr_queue_pairs)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
sq = &vi->sq[qid];
|
|
|
|
rq = &vi->rq[qid];
|
|
|
|
|
|
|
|
/* xsk assumes that tx and rx must have the same dma device. The af-xdp
|
|
|
|
* may use one buffer to receive from the rx and reuse this buffer to
|
|
|
|
* send by the tx. So the dma dev of sq and rq must be the same one.
|
|
|
|
*
|
|
|
|
* But vq->dma_dev allows every vq has the respective dma dev. So I
|
|
|
|
* check the dma dev of vq and sq is the same dev.
|
|
|
|
*/
|
|
|
|
if (virtqueue_dma_dev(rq->vq) != virtqueue_dma_dev(sq->vq))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dma_dev = virtqueue_dma_dev(rq->vq);
|
|
|
|
if (!dma_dev)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2024-07-08 11:25:35 +00:00
|
|
|
size = virtqueue_get_vring_size(rq->vq);
|
|
|
|
|
|
|
|
rq->xsk_buffs = kvcalloc(size, sizeof(*rq->xsk_buffs), GFP_KERNEL);
|
|
|
|
if (!rq->xsk_buffs)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2024-07-08 11:25:33 +00:00
|
|
|
err = xsk_pool_dma_map(pool, dma_dev, 0);
|
|
|
|
if (err)
|
|
|
|
goto err_xsk_map;
|
|
|
|
|
|
|
|
err = virtnet_rq_bind_xsk_pool(vi, rq, pool);
|
|
|
|
if (err)
|
|
|
|
goto err_rq;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_rq:
|
|
|
|
xsk_pool_dma_unmap(pool, 0);
|
|
|
|
err_xsk_map:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
struct xsk_buff_pool *pool;
|
|
|
|
struct receive_queue *rq;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (qid >= vi->curr_queue_pairs)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rq = &vi->rq[qid];
|
|
|
|
|
|
|
|
pool = rq->xsk_pool;
|
|
|
|
|
|
|
|
err = virtnet_rq_bind_xsk_pool(vi, rq, NULL);
|
|
|
|
|
|
|
|
xsk_pool_dma_unmap(pool, 0);
|
|
|
|
|
2024-07-08 11:25:35 +00:00
|
|
|
kvfree(rq->xsk_buffs);
|
|
|
|
|
2024-07-08 11:25:33 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_xsk_pool_setup(struct net_device *dev, struct netdev_bpf *xdp)
|
|
|
|
{
|
|
|
|
if (xdp->xsk.pool)
|
|
|
|
return virtnet_xsk_pool_enable(dev, xdp->xsk.pool,
|
|
|
|
xdp->xsk.queue_id);
|
|
|
|
else
|
|
|
|
return virtnet_xsk_pool_disable(dev, xdp->xsk.queue_id);
|
|
|
|
}
|
|
|
|
|
2017-05-01 04:46:48 +00:00
|
|
|
static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
|
|
|
|
struct netlink_ext_ack *extack)
|
2016-12-15 20:13:24 +00:00
|
|
|
{
|
2024-07-08 11:25:28 +00:00
|
|
|
unsigned int room = SKB_DATA_ALIGN(XDP_PACKET_HEADROOM +
|
2023-01-14 08:22:21 +00:00
|
|
|
sizeof(struct skb_shared_info));
|
|
|
|
unsigned int max_sz = PAGE_SIZE - room - ETH_HLEN;
|
2016-12-15 20:13:24 +00:00
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
struct bpf_prog *old_prog;
|
2017-02-20 03:50:20 +00:00
|
|
|
u16 xdp_qp = 0, curr_qp;
|
2016-12-15 20:13:49 +00:00
|
|
|
int i, err;
|
2016-12-15 20:13:24 +00:00
|
|
|
|
2017-07-19 08:54:49 +00:00
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)
|
|
|
|
&& (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
|
2018-11-22 06:36:31 +00:00
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO) ||
|
2022-12-07 11:35:58 +00:00
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM) ||
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_USO4) ||
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_USO6))) {
|
2021-08-17 08:06:59 +00:00
|
|
|
NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing GRO_HW/CSUM, disable GRO_HW/CSUM first");
|
2016-12-15 20:13:24 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi->mergeable_rx_bufs && !vi->any_header_sg) {
|
2017-05-02 22:39:17 +00:00
|
|
|
NL_SET_ERR_MSG_MOD(extack, "XDP expects header/data in single page, any_header_sg required");
|
2016-12-15 20:13:24 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:22:22 +00:00
|
|
|
if (prog && !prog->aux->xdp_has_frags && dev->mtu > max_sz) {
|
|
|
|
NL_SET_ERR_MSG_MOD(extack, "MTU too large to enable XDP without frags");
|
|
|
|
netdev_warn(dev, "single-buffer XDP requires MTU less than %u\n", max_sz);
|
2016-12-15 20:13:24 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-12-15 20:13:49 +00:00
|
|
|
curr_qp = vi->curr_queue_pairs - vi->xdp_queue_pairs;
|
|
|
|
if (prog)
|
|
|
|
xdp_qp = nr_cpu_ids;
|
|
|
|
|
|
|
|
/* XDP requires extra queues for XDP_TX */
|
|
|
|
if (curr_qp + xdp_qp > vi->max_queue_pairs) {
|
2021-09-18 06:06:15 +00:00
|
|
|
netdev_warn_once(dev, "XDP request %i queues but max is %i. XDP_TX and XDP_REDIRECT will operate in a slower locked tx mode.\n",
|
|
|
|
curr_qp + xdp_qp, vi->max_queue_pairs);
|
2021-03-10 02:24:45 +00:00
|
|
|
xdp_qp = 0;
|
2016-12-15 20:13:49 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 00:45:57 +00:00
|
|
|
old_prog = rtnl_dereference(vi->rq[0].xdp_prog);
|
|
|
|
if (!prog && !old_prog)
|
|
|
|
return 0;
|
|
|
|
|
2019-11-17 17:28:03 +00:00
|
|
|
if (prog)
|
|
|
|
bpf_prog_add(prog, vi->max_queue_pairs - 1);
|
2017-02-03 03:16:29 +00:00
|
|
|
|
2017-07-19 08:54:48 +00:00
|
|
|
/* Make sure NAPI is not using any XDP TX queues for RX. */
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
if (netif_running(dev)) {
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2018-02-28 10:20:04 +00:00
|
|
|
napi_disable(&vi->rq[i].napi);
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
virtnet_napi_tx_disable(&vi->sq[i].napi);
|
|
|
|
}
|
|
|
|
}
|
2016-12-15 20:13:24 +00:00
|
|
|
|
2019-01-29 00:45:57 +00:00
|
|
|
if (!prog) {
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
|
|
|
|
if (i == 0)
|
|
|
|
virtnet_restore_guest_offloads(vi);
|
|
|
|
}
|
|
|
|
synchronize_net();
|
|
|
|
}
|
2016-12-15 20:13:24 +00:00
|
|
|
|
2024-05-03 20:24:45 +00:00
|
|
|
err = virtnet_set_queues(vi, curr_qp + xdp_qp);
|
2017-07-19 08:54:48 +00:00
|
|
|
if (err)
|
|
|
|
goto err;
|
2019-01-29 00:45:55 +00:00
|
|
|
netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp);
|
2017-07-19 08:54:48 +00:00
|
|
|
vi->xdp_queue_pairs = xdp_qp;
|
2016-12-15 20:13:49 +00:00
|
|
|
|
2019-01-29 00:45:57 +00:00
|
|
|
if (prog) {
|
2021-03-10 02:24:45 +00:00
|
|
|
vi->xdp_enabled = true;
|
2019-01-29 00:45:57 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
rcu_assign_pointer(vi->rq[i].xdp_prog, prog);
|
|
|
|
if (i == 0 && !old_prog)
|
2017-07-19 08:54:49 +00:00
|
|
|
virtnet_clear_guest_offloads(vi);
|
|
|
|
}
|
drivers: net: turn on XDP features
A summary of the flags being set for various drivers is given below.
Note that XDP_F_REDIRECT_TARGET and XDP_F_FRAG_TARGET are features
that can be turned off and on at runtime. This means that these flags
may be set and unset under RTNL lock protection by the driver. Hence,
READ_ONCE must be used by code loading the flag value.
Also, these flags are not used for synchronization against the availability
of XDP resources on a device. It is merely a hint, and hence the read
may race with the actual teardown of XDP resources on the device. This
may change in the future, e.g. operations taking a reference on the XDP
resources of the driver, and in turn inhibiting turning off this flag.
However, for now, it can only be used as a hint to check whether device
supports becoming a redirection target.
Turn 'hw-offload' feature flag on for:
- netronome (nfp)
- netdevsim.
Turn 'native' and 'zerocopy' features flags on for:
- intel (i40e, ice, ixgbe, igc)
- mellanox (mlx5).
- stmmac
- netronome (nfp)
Turn 'native' features flags on for:
- amazon (ena)
- broadcom (bnxt)
- freescale (dpaa, dpaa2, enetc)
- funeth
- intel (igb)
- marvell (mvneta, mvpp2, octeontx2)
- mellanox (mlx4)
- mtk_eth_soc
- qlogic (qede)
- sfc
- socionext (netsec)
- ti (cpsw)
- tap
- tsnep
- veth
- xen
- virtio_net.
Turn 'basic' (tx, pass, aborted and drop) features flags on for:
- netronome (nfp)
- cavium (thunder)
- hyperv.
Turn 'redirect_target' feature flag on for:
- amanzon (ena)
- broadcom (bnxt)
- freescale (dpaa, dpaa2)
- intel (i40e, ice, igb, ixgbe)
- ti (cpsw)
- marvell (mvneta, mvpp2)
- sfc
- socionext (netsec)
- qlogic (qede)
- mellanox (mlx5)
- tap
- veth
- virtio_net
- xen
Reviewed-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Acked-by: Stanislav Fomichev <sdf@google.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Co-developed-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Marek Majtyka <alardam@gmail.com>
Link: https://lore.kernel.org/r/3eca9fafb308462f7edb1f58e451d59209aa07eb.1675245258.git.lorenzo@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-02-01 10:24:18 +00:00
|
|
|
if (!old_prog)
|
2023-02-07 09:53:40 +00:00
|
|
|
xdp_features_set_redirect_target(dev, true);
|
2021-03-10 02:24:45 +00:00
|
|
|
} else {
|
drivers: net: turn on XDP features
A summary of the flags being set for various drivers is given below.
Note that XDP_F_REDIRECT_TARGET and XDP_F_FRAG_TARGET are features
that can be turned off and on at runtime. This means that these flags
may be set and unset under RTNL lock protection by the driver. Hence,
READ_ONCE must be used by code loading the flag value.
Also, these flags are not used for synchronization against the availability
of XDP resources on a device. It is merely a hint, and hence the read
may race with the actual teardown of XDP resources on the device. This
may change in the future, e.g. operations taking a reference on the XDP
resources of the driver, and in turn inhibiting turning off this flag.
However, for now, it can only be used as a hint to check whether device
supports becoming a redirection target.
Turn 'hw-offload' feature flag on for:
- netronome (nfp)
- netdevsim.
Turn 'native' and 'zerocopy' features flags on for:
- intel (i40e, ice, ixgbe, igc)
- mellanox (mlx5).
- stmmac
- netronome (nfp)
Turn 'native' features flags on for:
- amazon (ena)
- broadcom (bnxt)
- freescale (dpaa, dpaa2, enetc)
- funeth
- intel (igb)
- marvell (mvneta, mvpp2, octeontx2)
- mellanox (mlx4)
- mtk_eth_soc
- qlogic (qede)
- sfc
- socionext (netsec)
- ti (cpsw)
- tap
- tsnep
- veth
- xen
- virtio_net.
Turn 'basic' (tx, pass, aborted and drop) features flags on for:
- netronome (nfp)
- cavium (thunder)
- hyperv.
Turn 'redirect_target' feature flag on for:
- amanzon (ena)
- broadcom (bnxt)
- freescale (dpaa, dpaa2)
- intel (i40e, ice, igb, ixgbe)
- ti (cpsw)
- marvell (mvneta, mvpp2)
- sfc
- socionext (netsec)
- qlogic (qede)
- mellanox (mlx5)
- tap
- veth
- virtio_net
- xen
Reviewed-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Acked-by: Stanislav Fomichev <sdf@google.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Co-developed-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Marek Majtyka <alardam@gmail.com>
Link: https://lore.kernel.org/r/3eca9fafb308462f7edb1f58e451d59209aa07eb.1675245258.git.lorenzo@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-02-01 10:24:18 +00:00
|
|
|
xdp_features_clear_redirect_target(dev);
|
2021-03-10 02:24:45 +00:00
|
|
|
vi->xdp_enabled = false;
|
2019-01-29 00:45:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2016-12-15 20:13:24 +00:00
|
|
|
if (old_prog)
|
|
|
|
bpf_prog_put(old_prog);
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
if (netif_running(dev)) {
|
2018-02-28 10:20:04 +00:00
|
|
|
virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
virtnet_napi_tx_enable(vi, vi->sq[i].vq,
|
|
|
|
&vi->sq[i].napi);
|
|
|
|
}
|
2016-12-15 20:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2017-02-03 03:16:29 +00:00
|
|
|
|
2017-07-19 08:54:48 +00:00
|
|
|
err:
|
2019-01-29 00:45:57 +00:00
|
|
|
if (!prog) {
|
|
|
|
virtnet_clear_guest_offloads(vi);
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++)
|
|
|
|
rcu_assign_pointer(vi->rq[i].xdp_prog, old_prog);
|
|
|
|
}
|
|
|
|
|
2019-01-29 00:45:53 +00:00
|
|
|
if (netif_running(dev)) {
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2019-01-29 00:45:53 +00:00
|
|
|
virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
|
virtio_net: Don't call free_old_xmit_skbs for xdp_frames
When napi_tx is enabled, virtnet_poll_cleantx() called
free_old_xmit_skbs() even for xdp send queue.
This is bogus since the queue has xdp_frames, not sk_buffs, thus mangled
device tx bytes counters because skb->len is meaningless value, and even
triggered oops due to general protection fault on freeing them.
Since xdp send queues do not aquire locks, old xdp_frames should be
freed only in virtnet_xdp_xmit(), so just skip free_old_xmit_skbs() for
xdp send queues.
Similarly virtnet_poll_tx() called free_old_xmit_skbs(). This NAPI
handler is called even without calling start_xmit() because cb for tx is
by default enabled. Once the handler is called, it enabled the cb again,
and then the handler would be called again. We don't need this handler
for XDP, so don't enable cb as well as not calling free_old_xmit_skbs().
Also, we need to disable tx NAPI when disabling XDP, so
virtnet_poll_tx() can safely access curr_queue_pairs and
xdp_queue_pairs, which are not atomically updated while disabling XDP.
Fixes: b92f1e6751a6 ("virtio-net: transmit napi")
Fixes: 7b0411ef4aa6 ("virtio-net: clean tx descriptors from rx napi")
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-01-29 00:45:54 +00:00
|
|
|
virtnet_napi_tx_enable(vi, vi->sq[i].vq,
|
|
|
|
&vi->sq[i].napi);
|
|
|
|
}
|
2019-01-29 00:45:53 +00:00
|
|
|
}
|
2017-02-03 03:16:29 +00:00
|
|
|
if (prog)
|
|
|
|
bpf_prog_sub(prog, vi->max_queue_pairs - 1);
|
|
|
|
return err;
|
2016-12-15 20:13:24 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 20:56:16 +00:00
|
|
|
static int virtnet_xdp(struct net_device *dev, struct netdev_bpf *xdp)
|
2016-12-15 20:13:24 +00:00
|
|
|
{
|
|
|
|
switch (xdp->command) {
|
|
|
|
case XDP_SETUP_PROG:
|
2017-05-01 04:46:48 +00:00
|
|
|
return virtnet_xdp_set(dev, xdp->prog, xdp->extack);
|
2024-07-08 11:25:33 +00:00
|
|
|
case XDP_SETUP_XSK_POOL:
|
|
|
|
return virtnet_xsk_pool_setup(dev, xdp);
|
2016-12-15 20:13:24 +00:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-24 16:55:17 +00:00
|
|
|
static int virtnet_get_phys_port_name(struct net_device *dev, char *buf,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_STANDBY))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
ret = snprintf(buf, len, "sby");
|
|
|
|
if (ret >= len)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-20 22:14:54 +00:00
|
|
|
static int virtnet_set_features(struct net_device *dev,
|
|
|
|
netdev_features_t features)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(dev);
|
2020-10-21 14:30:43 +00:00
|
|
|
u64 offloads;
|
2018-12-20 22:14:54 +00:00
|
|
|
int err;
|
|
|
|
|
2021-08-17 08:06:59 +00:00
|
|
|
if ((dev->features ^ features) & NETIF_F_GRO_HW) {
|
2021-03-10 02:24:45 +00:00
|
|
|
if (vi->xdp_enabled)
|
2020-10-21 14:30:43 +00:00
|
|
|
return -EBUSY;
|
|
|
|
|
2021-08-17 08:06:59 +00:00
|
|
|
if (features & NETIF_F_GRO_HW)
|
2020-10-21 14:30:43 +00:00
|
|
|
offloads = vi->guest_offloads_capable;
|
2018-12-20 22:14:54 +00:00
|
|
|
else
|
2020-10-21 14:30:43 +00:00
|
|
|
offloads = vi->guest_offloads_capable &
|
2021-08-17 08:06:59 +00:00
|
|
|
~GUEST_OFFLOAD_GRO_HW_MASK;
|
2018-12-20 22:14:54 +00:00
|
|
|
|
2020-10-21 14:30:43 +00:00
|
|
|
err = virtnet_set_guest_offloads(vi, offloads);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
vi->guest_offloads = offloads;
|
2018-12-20 22:14:54 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
if ((dev->features ^ features) & NETIF_F_RXHASH) {
|
|
|
|
if (features & NETIF_F_RXHASH)
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.hash_types = vi->rss_hash_types_saved;
|
2022-03-28 17:53:34 +00:00
|
|
|
else
|
2024-05-03 20:24:40 +00:00
|
|
|
vi->rss.hash_types = VIRTIO_NET_HASH_REPORT_NONE;
|
2022-03-28 17:53:34 +00:00
|
|
|
|
|
|
|
if (!virtnet_commit_rss_command(vi))
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-12-20 22:14:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-09-17 08:40:06 +00:00
|
|
|
static void virtnet_tx_timeout(struct net_device *dev, unsigned int txqueue)
|
|
|
|
{
|
|
|
|
struct virtnet_info *priv = netdev_priv(dev);
|
|
|
|
struct send_queue *sq = &priv->sq[txqueue];
|
|
|
|
struct netdev_queue *txq = netdev_get_tx_queue(dev, txqueue);
|
|
|
|
|
|
|
|
u64_stats_update_begin(&sq->stats.syncp);
|
2023-10-26 17:18:40 +00:00
|
|
|
u64_stats_inc(&sq->stats.tx_timeouts);
|
2021-09-17 08:40:06 +00:00
|
|
|
u64_stats_update_end(&sq->stats.syncp);
|
|
|
|
|
|
|
|
netdev_err(dev, "TX timeout on queue: %u, sq: %s, vq: 0x%x, name: %s, %u usecs ago\n",
|
|
|
|
txqueue, sq->name, sq->vq->index, sq->vq->name,
|
2021-11-17 03:29:22 +00:00
|
|
|
jiffies_to_usecs(jiffies - READ_ONCE(txq->trans_start)));
|
2021-09-17 08:40:06 +00:00
|
|
|
}
|
|
|
|
|
2024-06-21 10:13:53 +00:00
|
|
|
static int virtnet_init_irq_moder(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
u8 profile_flags = 0, coal_flags = 0;
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
profile_flags |= DIM_PROFILE_RX;
|
|
|
|
coal_flags |= DIM_COALESCE_USEC | DIM_COALESCE_PKTS;
|
|
|
|
ret = net_dim_init_irq_moder(vi->dev, profile_flags, coal_flags,
|
|
|
|
DIM_CQ_PERIOD_MODE_START_FROM_EQE,
|
|
|
|
0, virtnet_rx_dim_work, NULL);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++)
|
|
|
|
net_dim_setting(vi->dev, &vi->rq[i].dim, false);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_free_irq_moder(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
net_dim_free_irq_moder(vi->dev);
|
|
|
|
rtnl_unlock();
|
|
|
|
}
|
|
|
|
|
2009-01-06 18:44:22 +00:00
|
|
|
static const struct net_device_ops virtnet_netdev = {
|
|
|
|
.ndo_open = virtnet_open,
|
|
|
|
.ndo_stop = virtnet_close,
|
|
|
|
.ndo_start_xmit = start_xmit,
|
|
|
|
.ndo_validate_addr = eth_validate_addr,
|
2009-02-05 00:36:34 +00:00
|
|
|
.ndo_set_mac_address = virtnet_set_mac_address,
|
2009-02-04 09:02:40 +00:00
|
|
|
.ndo_set_rx_mode = virtnet_set_rx_mode,
|
2011-06-15 06:36:29 +00:00
|
|
|
.ndo_get_stats64 = virtnet_stats,
|
2009-05-01 17:31:10 +00:00
|
|
|
.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
|
|
|
|
.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
|
2017-11-03 20:56:16 +00:00
|
|
|
.ndo_bpf = virtnet_xdp,
|
2017-09-19 09:42:43 +00:00
|
|
|
.ndo_xdp_xmit = virtnet_xdp_xmit,
|
2024-07-08 11:25:34 +00:00
|
|
|
.ndo_xsk_wakeup = virtnet_xsk_wakeup,
|
2017-05-23 17:38:43 +00:00
|
|
|
.ndo_features_check = passthru_features_check,
|
2018-05-24 16:55:17 +00:00
|
|
|
.ndo_get_phys_port_name = virtnet_get_phys_port_name,
|
2018-12-20 22:14:54 +00:00
|
|
|
.ndo_set_features = virtnet_set_features,
|
2021-09-17 08:40:06 +00:00
|
|
|
.ndo_tx_timeout = virtnet_tx_timeout,
|
2009-01-06 18:44:22 +00:00
|
|
|
};
|
|
|
|
|
2012-04-11 20:43:52 +00:00
|
|
|
static void virtnet_config_changed_work(struct work_struct *work)
|
2009-01-20 01:09:49 +00:00
|
|
|
{
|
2012-04-11 20:43:52 +00:00
|
|
|
struct virtnet_info *vi =
|
|
|
|
container_of(work, struct virtnet_info, config_work);
|
2009-01-20 01:09:49 +00:00
|
|
|
u16 v;
|
|
|
|
|
2013-10-14 07:41:51 +00:00
|
|
|
if (virtio_cread_feature(vi->vdev, VIRTIO_NET_F_STATUS,
|
|
|
|
struct virtio_net_config, status, &v) < 0)
|
2014-10-14 23:52:30 +00:00
|
|
|
return;
|
2012-04-11 20:43:52 +00:00
|
|
|
|
|
|
|
if (v & VIRTIO_NET_S_ANNOUNCE) {
|
2012-08-09 22:14:56 +00:00
|
|
|
netdev_notify_peers(vi->dev);
|
2012-04-11 20:43:52 +00:00
|
|
|
virtnet_ack_link_announce(vi);
|
|
|
|
}
|
2009-01-20 01:09:49 +00:00
|
|
|
|
|
|
|
/* Ignore unknown (future) status bits */
|
|
|
|
v &= VIRTIO_NET_S_LINK_UP;
|
|
|
|
|
|
|
|
if (vi->status == v)
|
2014-10-14 23:52:30 +00:00
|
|
|
return;
|
2009-01-20 01:09:49 +00:00
|
|
|
|
|
|
|
vi->status = v;
|
|
|
|
|
|
|
|
if (vi->status & VIRTIO_NET_S_LINK_UP) {
|
2018-01-05 22:44:54 +00:00
|
|
|
virtnet_update_settings(vi);
|
2009-01-20 01:09:49 +00:00
|
|
|
netif_carrier_on(vi->dev);
|
2012-12-07 07:04:56 +00:00
|
|
|
netif_tx_wake_all_queues(vi->dev);
|
2009-01-20 01:09:49 +00:00
|
|
|
} else {
|
|
|
|
netif_carrier_off(vi->dev);
|
2012-12-07 07:04:56 +00:00
|
|
|
netif_tx_stop_all_queues(vi->dev);
|
2009-01-20 01:09:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtnet_config_changed(struct virtio_device *vdev)
|
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vdev->priv;
|
|
|
|
|
2012-08-20 21:51:24 +00:00
|
|
|
schedule_work(&vi->config_work);
|
2009-01-20 01:09:49 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
static void virtnet_free_queues(struct virtnet_info *vi)
|
|
|
|
{
|
2013-12-05 14:36:21 +00:00
|
|
|
int i;
|
|
|
|
|
2015-03-12 05:57:44 +00:00
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2020-09-09 17:37:51 +00:00
|
|
|
__netif_napi_del(&vi->rq[i].napi);
|
|
|
|
__netif_napi_del(&vi->sq[i].napi);
|
2015-03-12 05:57:44 +00:00
|
|
|
}
|
2013-12-05 14:36:21 +00:00
|
|
|
|
2020-09-09 17:37:51 +00:00
|
|
|
/* We called __netif_napi_del(),
|
2016-11-16 06:24:12 +00:00
|
|
|
* we need to respect an RCU grace period before freeing vi->rq
|
|
|
|
*/
|
|
|
|
synchronize_net();
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
kfree(vi->rq);
|
|
|
|
kfree(vi->sq);
|
2018-04-19 05:30:48 +00:00
|
|
|
kfree(vi->ctrl);
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2017-02-03 03:14:32 +00:00
|
|
|
static void _free_receive_bufs(struct virtnet_info *vi)
|
2012-12-07 07:04:56 +00:00
|
|
|
{
|
2016-12-15 20:13:24 +00:00
|
|
|
struct bpf_prog *old_prog;
|
2012-12-07 07:04:56 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
while (vi->rq[i].pages)
|
|
|
|
__free_pages(get_a_page(&vi->rq[i], GFP_KERNEL), 0);
|
2016-12-15 20:13:24 +00:00
|
|
|
|
|
|
|
old_prog = rtnl_dereference(vi->rq[i].xdp_prog);
|
|
|
|
RCU_INIT_POINTER(vi->rq[i].xdp_prog, NULL);
|
|
|
|
if (old_prog)
|
|
|
|
bpf_prog_put(old_prog);
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
2017-02-03 03:14:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void free_receive_bufs(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
rtnl_lock();
|
|
|
|
_free_receive_bufs(vi);
|
2016-12-15 20:13:24 +00:00
|
|
|
rtnl_unlock();
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
2014-01-17 06:23:26 +00:00
|
|
|
static void free_receive_page_frags(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++)
|
2023-08-10 12:30:57 +00:00
|
|
|
if (vi->rq[i].alloc_frag.page) {
|
2024-09-06 12:31:35 +00:00
|
|
|
if (vi->rq[i].do_dma && vi->rq[i].last_dma)
|
2023-08-10 12:30:57 +00:00
|
|
|
virtnet_rq_unmap(&vi->rq[i], vi->rq[i].last_dma, 0);
|
2014-01-17 06:23:26 +00:00
|
|
|
put_page(vi->rq[i].alloc_frag.page);
|
2023-08-10 12:30:57 +00:00
|
|
|
}
|
2014-01-17 06:23:26 +00:00
|
|
|
}
|
|
|
|
|
2022-08-01 06:38:59 +00:00
|
|
|
static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf)
|
|
|
|
{
|
|
|
|
if (!is_xdp_frame(buf))
|
|
|
|
dev_kfree_skb(buf);
|
|
|
|
else
|
|
|
|
xdp_return_frame(ptr_to_xdp(buf));
|
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
static void free_unused_bufs(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
void *buf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
struct virtqueue *vq = vi->sq[i].vq;
|
2022-08-01 06:38:59 +00:00
|
|
|
while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
|
|
|
|
virtnet_sq_free_unused_buf(vq, buf);
|
2023-05-04 02:27:06 +00:00
|
|
|
cond_resched();
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2023-12-26 09:43:33 +00:00
|
|
|
struct virtqueue *vq = vi->rq[i].vq;
|
2023-08-10 12:30:57 +00:00
|
|
|
|
2023-12-26 09:43:33 +00:00
|
|
|
while ((buf = virtqueue_detach_unused_buf(vq)) != NULL)
|
|
|
|
virtnet_rq_unmap_free_buf(vq, buf);
|
2023-05-04 02:27:06 +00:00
|
|
|
cond_resched();
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
static void virtnet_del_vqs(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
struct virtio_device *vdev = vi->vdev;
|
|
|
|
|
2019-03-18 06:56:06 +00:00
|
|
|
virtnet_clean_affinity(vi);
|
2012-12-07 07:04:56 +00:00
|
|
|
|
2012-12-07 07:04:55 +00:00
|
|
|
vdev->config->del_vqs(vdev);
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
virtnet_free_queues(vi);
|
2012-12-07 07:04:55 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 00:21:21 +00:00
|
|
|
/* How large should a single buffer be so a queue full of these can fit at
|
|
|
|
* least one full packet?
|
|
|
|
* Logic below assumes the mergeable buffer header is used.
|
|
|
|
*/
|
|
|
|
static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqueue *vq)
|
|
|
|
{
|
2022-03-28 17:53:33 +00:00
|
|
|
const unsigned int hdr_len = vi->hdr_len;
|
2017-03-09 00:21:21 +00:00
|
|
|
unsigned int rq_size = virtqueue_get_vring_size(vq);
|
|
|
|
unsigned int packet_len = vi->big_packets ? IP_MAX_MTU : vi->dev->max_mtu;
|
|
|
|
unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;
|
|
|
|
unsigned int min_buf_len = DIV_ROUND_UP(buf_len, rq_size);
|
|
|
|
|
2017-06-02 14:54:33 +00:00
|
|
|
return max(max(min_buf_len, hdr_len) - hdr_len,
|
|
|
|
(unsigned int)GOOD_PACKET_LEN);
|
2017-03-09 00:21:21 +00:00
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
static int virtnet_find_vqs(struct virtnet_info *vi)
|
2011-12-22 11:28:31 +00:00
|
|
|
{
|
2024-07-08 07:48:08 +00:00
|
|
|
struct virtqueue_info *vqs_info;
|
2012-12-07 07:04:56 +00:00
|
|
|
struct virtqueue **vqs;
|
virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region of size 10" warnings
Fix the warnings when building virtio_net driver.
"
drivers/net/virtio_net.c: In function ‘init_vqs’:
drivers/net/virtio_net.c:4551:48: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 10 [-Wformat-overflow=]
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~
In function ‘virtnet_find_vqs’,
inlined from ‘init_vqs’ at drivers/net/virtio_net.c:4645:8:
drivers/net/virtio_net.c:4551:41: note: directive argument in the range [-2147483643, 65534]
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~~~~~~~~~
drivers/net/virtio_net.c:4551:17: note: ‘sprintf’ output between 8 and 18 bytes into a destination of size 16
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/virtio_net.c: In function ‘init_vqs’:
drivers/net/virtio_net.c:4552:49: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 9 [-Wformat-overflow=]
4552 | sprintf(vi->sq[i].name, "output.%d", i);
| ^~
In function ‘virtnet_find_vqs’,
inlined from ‘init_vqs’ at drivers/net/virtio_net.c:4645:8:
drivers/net/virtio_net.c:4552:41: note: directive argument in the range [-2147483643, 65534]
4552 | sprintf(vi->sq[i].name, "output.%d", i);
| ^~~~~~~~~~~
drivers/net/virtio_net.c:4552:17: note: ‘sprintf’ output between 9 and 19 bytes into a destination of size 16
4552 | sprintf(vi->sq[i].name, "output.%d", i);
"
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Link: https://lore.kernel.org/r/20240104020902.2753599-1-yanjun.zhu@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-01-04 02:09:02 +00:00
|
|
|
int ret = -ENOMEM;
|
|
|
|
int total_vqs;
|
2017-03-06 18:31:21 +00:00
|
|
|
bool *ctx;
|
virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region of size 10" warnings
Fix the warnings when building virtio_net driver.
"
drivers/net/virtio_net.c: In function ‘init_vqs’:
drivers/net/virtio_net.c:4551:48: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 10 [-Wformat-overflow=]
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~
In function ‘virtnet_find_vqs’,
inlined from ‘init_vqs’ at drivers/net/virtio_net.c:4645:8:
drivers/net/virtio_net.c:4551:41: note: directive argument in the range [-2147483643, 65534]
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~~~~~~~~~
drivers/net/virtio_net.c:4551:17: note: ‘sprintf’ output between 8 and 18 bytes into a destination of size 16
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/virtio_net.c: In function ‘init_vqs’:
drivers/net/virtio_net.c:4552:49: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 9 [-Wformat-overflow=]
4552 | sprintf(vi->sq[i].name, "output.%d", i);
| ^~
In function ‘virtnet_find_vqs’,
inlined from ‘init_vqs’ at drivers/net/virtio_net.c:4645:8:
drivers/net/virtio_net.c:4552:41: note: directive argument in the range [-2147483643, 65534]
4552 | sprintf(vi->sq[i].name, "output.%d", i);
| ^~~~~~~~~~~
drivers/net/virtio_net.c:4552:17: note: ‘sprintf’ output between 9 and 19 bytes into a destination of size 16
4552 | sprintf(vi->sq[i].name, "output.%d", i);
"
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Link: https://lore.kernel.org/r/20240104020902.2753599-1-yanjun.zhu@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-01-04 02:09:02 +00:00
|
|
|
u16 i;
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
/* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by
|
|
|
|
* possible N-1 RX/TX queue pairs used in multiqueue mode, followed by
|
|
|
|
* possible control vq.
|
|
|
|
*/
|
|
|
|
total_vqs = vi->max_queue_pairs * 2 +
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ);
|
|
|
|
|
|
|
|
/* Allocate space for find_vqs parameters */
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:03:40 +00:00
|
|
|
vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL);
|
2012-12-07 07:04:56 +00:00
|
|
|
if (!vqs)
|
|
|
|
goto err_vq;
|
2024-07-08 07:48:08 +00:00
|
|
|
vqs_info = kcalloc(total_vqs, sizeof(*vqs_info), GFP_KERNEL);
|
|
|
|
if (!vqs_info)
|
|
|
|
goto err_vqs_info;
|
2017-07-19 08:54:47 +00:00
|
|
|
if (!vi->big_packets || vi->mergeable_rx_bufs) {
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:03:40 +00:00
|
|
|
ctx = kcalloc(total_vqs, sizeof(*ctx), GFP_KERNEL);
|
2017-03-06 18:31:21 +00:00
|
|
|
if (!ctx)
|
|
|
|
goto err_ctx;
|
|
|
|
} else {
|
|
|
|
ctx = NULL;
|
|
|
|
}
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
/* Parameters for control virtqueue, if any */
|
|
|
|
if (vi->has_cvq) {
|
2024-07-08 07:48:08 +00:00
|
|
|
vqs_info[total_vqs - 1].name = "control";
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
2011-12-22 11:28:31 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
/* Allocate/initialize parameters for send/receive virtqueues */
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
2024-07-08 07:48:08 +00:00
|
|
|
vqs_info[rxq2vq(i)].callback = skb_recv_done;
|
|
|
|
vqs_info[txq2vq(i)].callback = skb_xmit_done;
|
virtio_net: Fix "‘%d’ directive writing between 1 and 11 bytes into a region of size 10" warnings
Fix the warnings when building virtio_net driver.
"
drivers/net/virtio_net.c: In function ‘init_vqs’:
drivers/net/virtio_net.c:4551:48: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 10 [-Wformat-overflow=]
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~
In function ‘virtnet_find_vqs’,
inlined from ‘init_vqs’ at drivers/net/virtio_net.c:4645:8:
drivers/net/virtio_net.c:4551:41: note: directive argument in the range [-2147483643, 65534]
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~~~~~~~~~
drivers/net/virtio_net.c:4551:17: note: ‘sprintf’ output between 8 and 18 bytes into a destination of size 16
4551 | sprintf(vi->rq[i].name, "input.%d", i);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/net/virtio_net.c: In function ‘init_vqs’:
drivers/net/virtio_net.c:4552:49: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 9 [-Wformat-overflow=]
4552 | sprintf(vi->sq[i].name, "output.%d", i);
| ^~
In function ‘virtnet_find_vqs’,
inlined from ‘init_vqs’ at drivers/net/virtio_net.c:4645:8:
drivers/net/virtio_net.c:4552:41: note: directive argument in the range [-2147483643, 65534]
4552 | sprintf(vi->sq[i].name, "output.%d", i);
| ^~~~~~~~~~~
drivers/net/virtio_net.c:4552:17: note: ‘sprintf’ output between 9 and 19 bytes into a destination of size 16
4552 | sprintf(vi->sq[i].name, "output.%d", i);
"
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Link: https://lore.kernel.org/r/20240104020902.2753599-1-yanjun.zhu@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-01-04 02:09:02 +00:00
|
|
|
sprintf(vi->rq[i].name, "input.%u", i);
|
|
|
|
sprintf(vi->sq[i].name, "output.%u", i);
|
2024-07-08 07:48:08 +00:00
|
|
|
vqs_info[rxq2vq(i)].name = vi->rq[i].name;
|
|
|
|
vqs_info[txq2vq(i)].name = vi->sq[i].name;
|
2017-03-06 18:31:21 +00:00
|
|
|
if (ctx)
|
2024-07-08 07:48:08 +00:00
|
|
|
vqs_info[rxq2vq(i)].ctx = true;
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
2011-12-22 11:28:31 +00:00
|
|
|
|
2024-07-08 07:48:14 +00:00
|
|
|
ret = virtio_find_vqs(vi->vdev, total_vqs, vqs, vqs_info, NULL);
|
2012-12-07 07:04:56 +00:00
|
|
|
if (ret)
|
|
|
|
goto err_find;
|
2011-12-22 11:28:31 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
if (vi->has_cvq) {
|
|
|
|
vi->cvq = vqs[total_vqs - 1];
|
2011-12-22 11:28:31 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
|
2013-04-19 02:04:27 +00:00
|
|
|
vi->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
2011-12-22 11:28:31 +00:00
|
|
|
}
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
vi->rq[i].vq = vqs[rxq2vq(i)];
|
2017-03-09 00:21:21 +00:00
|
|
|
vi->rq[i].min_buf_len = mergeable_min_buf_len(vi, vi->rq[i].vq);
|
2012-12-07 07:04:56 +00:00
|
|
|
vi->sq[i].vq = vqs[txq2vq(i)];
|
|
|
|
}
|
|
|
|
|
2018-05-31 14:16:32 +00:00
|
|
|
/* run here: ret == 0. */
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
err_find:
|
2017-03-06 18:31:21 +00:00
|
|
|
kfree(ctx);
|
|
|
|
err_ctx:
|
2024-07-08 07:48:08 +00:00
|
|
|
kfree(vqs_info);
|
|
|
|
err_vqs_info:
|
2012-12-07 07:04:56 +00:00
|
|
|
kfree(vqs);
|
|
|
|
err_vq:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtnet_alloc_queues(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2021-05-02 09:33:19 +00:00
|
|
|
if (vi->has_cvq) {
|
|
|
|
vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
|
|
|
|
if (!vi->ctrl)
|
|
|
|
goto err_ctrl;
|
|
|
|
} else {
|
|
|
|
vi->ctrl = NULL;
|
|
|
|
}
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:03:40 +00:00
|
|
|
vi->sq = kcalloc(vi->max_queue_pairs, sizeof(*vi->sq), GFP_KERNEL);
|
2012-12-07 07:04:56 +00:00
|
|
|
if (!vi->sq)
|
|
|
|
goto err_sq;
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 21:03:40 +00:00
|
|
|
vi->rq = kcalloc(vi->max_queue_pairs, sizeof(*vi->rq), GFP_KERNEL);
|
2012-12-10 02:24:08 +00:00
|
|
|
if (!vi->rq)
|
2012-12-07 07:04:56 +00:00
|
|
|
goto err_rq;
|
|
|
|
|
|
|
|
INIT_DELAYED_WORK(&vi->refill, refill_work);
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++) {
|
|
|
|
vi->rq[i].pages = NULL;
|
2022-05-06 17:07:50 +00:00
|
|
|
netif_napi_add_weight(vi->dev, &vi->rq[i].napi, virtnet_poll,
|
|
|
|
napi_weight);
|
2022-05-04 16:37:25 +00:00
|
|
|
netif_napi_add_tx_weight(vi->dev, &vi->sq[i].napi,
|
|
|
|
virtnet_poll_tx,
|
|
|
|
napi_tx ? napi_weight : 0);
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg));
|
2015-08-19 07:48:40 +00:00
|
|
|
ewma_pkt_len_init(&vi->rq[i].mrg_avg_pkt_len);
|
2012-12-07 07:04:56 +00:00
|
|
|
sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg));
|
2018-01-17 06:38:25 +00:00
|
|
|
|
|
|
|
u64_stats_init(&vi->rq[i].stats.syncp);
|
|
|
|
u64_stats_init(&vi->sq[i].stats.syncp);
|
2024-05-03 20:24:44 +00:00
|
|
|
mutex_init(&vi->rq[i].dim_lock);
|
2012-12-07 07:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_rq:
|
|
|
|
kfree(vi->sq);
|
|
|
|
err_sq:
|
2018-04-19 05:30:48 +00:00
|
|
|
kfree(vi->ctrl);
|
|
|
|
err_ctrl:
|
2012-12-07 07:04:56 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int init_vqs(struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Allocate send & receive queues */
|
|
|
|
ret = virtnet_alloc_queues(vi);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ret = virtnet_find_vqs(vi);
|
|
|
|
if (ret)
|
|
|
|
goto err_free;
|
|
|
|
|
2021-08-03 14:16:04 +00:00
|
|
|
cpus_read_lock();
|
2013-01-24 23:51:30 +00:00
|
|
|
virtnet_set_affinity(vi);
|
2021-08-03 14:16:04 +00:00
|
|
|
cpus_read_unlock();
|
2013-01-24 23:51:29 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_free:
|
|
|
|
virtnet_free_queues(vi);
|
|
|
|
err:
|
|
|
|
return ret;
|
2011-12-22 11:28:31 +00:00
|
|
|
}
|
|
|
|
|
2014-01-17 06:23:30 +00:00
|
|
|
#ifdef CONFIG_SYSFS
|
|
|
|
static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue,
|
2017-08-18 20:46:24 +00:00
|
|
|
char *buf)
|
2014-01-17 06:23:30 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = netdev_priv(queue->dev);
|
|
|
|
unsigned int queue_index = get_netdev_rx_queue_index(queue);
|
2018-03-02 09:29:14 +00:00
|
|
|
unsigned int headroom = virtnet_get_headroom(vi);
|
|
|
|
unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
|
2015-08-19 07:48:40 +00:00
|
|
|
struct ewma_pkt_len *avg;
|
2014-01-17 06:23:30 +00:00
|
|
|
|
|
|
|
BUG_ON(queue_index >= vi->max_queue_pairs);
|
|
|
|
avg = &vi->rq[queue_index].mrg_avg_pkt_len;
|
2017-03-09 00:21:21 +00:00
|
|
|
return sprintf(buf, "%u\n",
|
2018-03-02 09:29:14 +00:00
|
|
|
get_mergeable_buf_len(&vi->rq[queue_index], avg,
|
|
|
|
SKB_DATA_ALIGN(headroom + tailroom)));
|
2014-01-17 06:23:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct rx_queue_attribute mergeable_rx_buffer_size_attribute =
|
|
|
|
__ATTR_RO(mergeable_rx_buffer_size);
|
|
|
|
|
|
|
|
static struct attribute *virtio_net_mrg_rx_attrs[] = {
|
|
|
|
&mergeable_rx_buffer_size_attribute.attr,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group virtio_net_mrg_rx_group = {
|
|
|
|
.name = "virtio_net",
|
|
|
|
.attrs = virtio_net_mrg_rx_attrs
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2014-11-20 09:03:05 +00:00
|
|
|
static bool virtnet_fail_on_feature(struct virtio_device *vdev,
|
|
|
|
unsigned int fbit,
|
|
|
|
const char *fname, const char *dname)
|
|
|
|
{
|
|
|
|
if (!virtio_has_feature(vdev, fbit))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev_err(&vdev->dev, "device advertises feature %s but not %s",
|
|
|
|
fname, dname);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define VIRTNET_FAIL_ON(vdev, fbit, dbit) \
|
|
|
|
virtnet_fail_on_feature(vdev, fbit, #fbit, dbit)
|
|
|
|
|
|
|
|
static bool virtnet_validate_features(struct virtio_device *vdev)
|
|
|
|
{
|
|
|
|
if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) &&
|
|
|
|
(VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_RX,
|
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_VLAN,
|
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE,
|
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
|
2022-03-28 17:53:34 +00:00
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS,
|
2022-03-28 17:53:35 +00:00
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_HASH_REPORT,
|
2022-07-18 09:11:02 +00:00
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_NOTF_COAL,
|
2023-07-31 07:06:56 +00:00
|
|
|
"VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
|
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_VQ_NOTF_COAL,
|
2014-11-20 09:03:05 +00:00
|
|
|
"VIRTIO_NET_F_CTRL_VQ"))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-20 17:55:21 +00:00
|
|
|
#define MIN_MTU ETH_MIN_MTU
|
|
|
|
#define MAX_MTU ETH_MAX_MTU
|
|
|
|
|
2017-03-29 16:09:14 +00:00
|
|
|
static int virtnet_validate(struct virtio_device *vdev)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
2015-01-12 14:23:37 +00:00
|
|
|
if (!vdev->config->get) {
|
|
|
|
dev_err(&vdev->dev, "%s failure: config access disabled\n",
|
|
|
|
__func__);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-11-20 09:03:05 +00:00
|
|
|
if (!virtnet_validate_features(vdev))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-03-29 16:09:14 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
|
|
|
|
int mtu = virtio_cread16(vdev,
|
|
|
|
offsetof(struct virtio_net_config,
|
|
|
|
mtu));
|
|
|
|
if (mtu < MIN_MTU)
|
|
|
|
__virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
|
|
|
|
}
|
|
|
|
|
2023-01-27 20:44:59 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY) &&
|
|
|
|
!virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
|
|
|
|
dev_warn(&vdev->dev, "device advertises feature VIRTIO_NET_F_STANDBY but not VIRTIO_NET_F_MAC, disabling standby");
|
|
|
|
__virtio_clear_bit(vdev, VIRTIO_NET_F_STANDBY);
|
|
|
|
}
|
|
|
|
|
2017-03-29 16:09:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-14 14:49:10 +00:00
|
|
|
static bool virtnet_check_guest_gso(const struct virtnet_info *vi)
|
|
|
|
{
|
|
|
|
return virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
|
2022-12-07 11:35:58 +00:00
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO) ||
|
|
|
|
(virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_USO4) &&
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_USO6));
|
2022-09-14 14:49:10 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 14:49:11 +00:00
|
|
|
static void virtnet_set_big_packets(struct virtnet_info *vi, const int mtu)
|
|
|
|
{
|
|
|
|
bool guest_gso = virtnet_check_guest_gso(vi);
|
|
|
|
|
|
|
|
/* If device can receive ANY guest GSO packets, regardless of mtu,
|
|
|
|
* allocate packets of maximum size, otherwise limit it to only
|
|
|
|
* mtu size worth only.
|
|
|
|
*/
|
|
|
|
if (mtu > ETH_DATA_LEN || guest_gso) {
|
|
|
|
vi->big_packets = true;
|
|
|
|
vi->big_packets_num_skbfrags = guest_gso ? MAX_SKB_FRAGS : DIV_ROUND_UP(mtu, PAGE_SIZE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-17 07:18:22 +00:00
|
|
|
#define VIRTIO_NET_HASH_REPORT_MAX_TABLE 10
|
|
|
|
static enum xdp_rss_hash_type
|
|
|
|
virtnet_xdp_rss_type[VIRTIO_NET_HASH_REPORT_MAX_TABLE] = {
|
|
|
|
[VIRTIO_NET_HASH_REPORT_NONE] = XDP_RSS_TYPE_NONE,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_IPv4] = XDP_RSS_TYPE_L3_IPV4,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_TCPv4] = XDP_RSS_TYPE_L4_IPV4_TCP,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_UDPv4] = XDP_RSS_TYPE_L4_IPV4_UDP,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_IPv6] = XDP_RSS_TYPE_L3_IPV6,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_TCPv6] = XDP_RSS_TYPE_L4_IPV6_TCP,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_UDPv6] = XDP_RSS_TYPE_L4_IPV6_UDP,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_IPv6_EX] = XDP_RSS_TYPE_L3_IPV6_EX,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_TCPv6_EX] = XDP_RSS_TYPE_L4_IPV6_TCP_EX,
|
|
|
|
[VIRTIO_NET_HASH_REPORT_UDPv6_EX] = XDP_RSS_TYPE_L4_IPV6_UDP_EX
|
|
|
|
};
|
|
|
|
|
|
|
|
static int virtnet_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
|
|
|
|
enum xdp_rss_hash_type *rss_type)
|
|
|
|
{
|
|
|
|
const struct xdp_buff *xdp = (void *)_ctx;
|
|
|
|
struct virtio_net_hdr_v1_hash *hdr_hash;
|
|
|
|
struct virtnet_info *vi;
|
|
|
|
u16 hash_report;
|
|
|
|
|
|
|
|
if (!(xdp->rxq->dev->features & NETIF_F_RXHASH))
|
|
|
|
return -ENODATA;
|
|
|
|
|
|
|
|
vi = netdev_priv(xdp->rxq->dev);
|
|
|
|
hdr_hash = (struct virtio_net_hdr_v1_hash *)(xdp->data - vi->hdr_len);
|
|
|
|
hash_report = __le16_to_cpu(hdr_hash->hash_report);
|
|
|
|
|
|
|
|
if (hash_report >= VIRTIO_NET_HASH_REPORT_MAX_TABLE)
|
|
|
|
hash_report = VIRTIO_NET_HASH_REPORT_NONE;
|
|
|
|
|
|
|
|
*rss_type = virtnet_xdp_rss_type[hash_report];
|
|
|
|
*hash = __le32_to_cpu(hdr_hash->hash_value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct xdp_metadata_ops virtnet_xdp_metadata_ops = {
|
|
|
|
.xmo_rx_hash = virtnet_xdp_rx_hash,
|
|
|
|
};
|
|
|
|
|
2017-03-29 16:09:14 +00:00
|
|
|
static int virtnet_probe(struct virtio_device *vdev)
|
|
|
|
{
|
2018-01-17 06:38:25 +00:00
|
|
|
int i, err = -ENOMEM;
|
2017-03-29 16:09:14 +00:00
|
|
|
struct net_device *dev;
|
|
|
|
struct virtnet_info *vi;
|
|
|
|
u16 max_queue_pairs;
|
2022-09-14 14:49:11 +00:00
|
|
|
int mtu = 0;
|
2017-03-29 16:09:14 +00:00
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
/* Find if host supports multiqueue/rss virtio_net device */
|
|
|
|
max_queue_pairs = 1;
|
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
|
|
|
|
max_queue_pairs =
|
|
|
|
virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
|
2012-12-07 07:04:56 +00:00
|
|
|
|
|
|
|
/* We need at least 2 queue's */
|
2022-03-28 17:53:34 +00:00
|
|
|
if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
|
2012-12-07 07:04:56 +00:00
|
|
|
max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
|
|
|
|
!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
|
|
|
|
max_queue_pairs = 1;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
|
|
|
/* Allocate ourselves a network device with room for our info */
|
2012-12-07 07:04:56 +00:00
|
|
|
dev = alloc_etherdev_mq(sizeof(struct virtnet_info), max_queue_pairs);
|
2007-10-22 01:03:37 +00:00
|
|
|
if (!dev)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* Set up network device as normal. */
|
2021-02-18 20:50:17 +00:00
|
|
|
dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE |
|
|
|
|
IFF_TX_SKB_NO_LINEAR;
|
2009-01-06 18:44:22 +00:00
|
|
|
dev->netdev_ops = &virtnet_netdev;
|
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>
2024-04-26 03:39:28 +00:00
|
|
|
dev->stat_ops = &virtnet_stat_ops;
|
2007-10-22 01:03:37 +00:00
|
|
|
dev->features = NETIF_F_HIGHDMA;
|
2011-06-15 06:36:29 +00:00
|
|
|
|
2014-05-11 00:12:32 +00:00
|
|
|
dev->ethtool_ops = &virtnet_ethtool_ops;
|
2007-10-22 01:03:37 +00:00
|
|
|
SET_NETDEV_DEV(dev, &vdev->dev);
|
|
|
|
|
|
|
|
/* Do we support "hardware" checksums? */
|
2011-03-31 01:01:35 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
|
2007-10-22 01:03:37 +00:00
|
|
|
/* This opens up the world of extra features. */
|
2015-08-05 02:34:04 +00:00
|
|
|
dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG;
|
2011-03-31 01:01:35 +00:00
|
|
|
if (csum)
|
2015-08-05 02:34:04 +00:00
|
|
|
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
|
2011-03-31 01:01:35 +00:00
|
|
|
|
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
|
2017-07-03 13:37:32 +00:00
|
|
|
dev->hw_features |= NETIF_F_TSO
|
2008-02-05 04:50:02 +00:00
|
|
|
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
|
|
|
|
}
|
2008-05-03 02:50:46 +00:00
|
|
|
/* Individual feature bits: what can host handle? */
|
2011-03-31 01:01:35 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
|
|
|
|
dev->hw_features |= NETIF_F_TSO;
|
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
|
|
|
|
dev->hw_features |= NETIF_F_TSO6;
|
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
|
|
|
|
dev->hw_features |= NETIF_F_TSO_ECN;
|
2022-12-07 11:35:58 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_USO))
|
|
|
|
dev->hw_features |= NETIF_F_GSO_UDP_L4;
|
2011-03-31 01:01:35 +00:00
|
|
|
|
2014-12-24 03:03:52 +00:00
|
|
|
dev->features |= NETIF_F_GSO_ROBUST;
|
|
|
|
|
2011-03-31 01:01:35 +00:00
|
|
|
if (gso)
|
2017-07-03 13:37:32 +00:00
|
|
|
dev->features |= dev->hw_features & NETIF_F_ALL_TSO;
|
2011-03-31 01:01:35 +00:00
|
|
|
/* (!csum && gso) case will be fixed by register_netdev() */
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
2024-06-17 13:15:23 +00:00
|
|
|
|
|
|
|
/* 1. With VIRTIO_NET_F_GUEST_CSUM negotiation, the driver doesn't
|
|
|
|
* need to calculate checksums for partially checksummed packets,
|
|
|
|
* as they're considered valid by the upper layer.
|
|
|
|
* 2. Without VIRTIO_NET_F_GUEST_CSUM negotiation, the driver only
|
|
|
|
* receives fully checksummed packets. The device may assist in
|
|
|
|
* validating these packets' checksums, so the driver won't have to.
|
|
|
|
*/
|
|
|
|
dev->features |= NETIF_F_RXCSUM;
|
|
|
|
|
2018-12-20 22:14:54 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
|
|
|
|
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6))
|
2021-08-17 08:06:59 +00:00
|
|
|
dev->features |= NETIF_F_GRO_HW;
|
2020-10-21 14:30:43 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS))
|
2021-08-17 08:06:59 +00:00
|
|
|
dev->hw_features |= NETIF_F_GRO_HW;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2013-04-10 23:32:21 +00:00
|
|
|
dev->vlan_features = dev->features;
|
drivers: net: turn on XDP features
A summary of the flags being set for various drivers is given below.
Note that XDP_F_REDIRECT_TARGET and XDP_F_FRAG_TARGET are features
that can be turned off and on at runtime. This means that these flags
may be set and unset under RTNL lock protection by the driver. Hence,
READ_ONCE must be used by code loading the flag value.
Also, these flags are not used for synchronization against the availability
of XDP resources on a device. It is merely a hint, and hence the read
may race with the actual teardown of XDP resources on the device. This
may change in the future, e.g. operations taking a reference on the XDP
resources of the driver, and in turn inhibiting turning off this flag.
However, for now, it can only be used as a hint to check whether device
supports becoming a redirection target.
Turn 'hw-offload' feature flag on for:
- netronome (nfp)
- netdevsim.
Turn 'native' and 'zerocopy' features flags on for:
- intel (i40e, ice, ixgbe, igc)
- mellanox (mlx5).
- stmmac
- netronome (nfp)
Turn 'native' features flags on for:
- amazon (ena)
- broadcom (bnxt)
- freescale (dpaa, dpaa2, enetc)
- funeth
- intel (igb)
- marvell (mvneta, mvpp2, octeontx2)
- mellanox (mlx4)
- mtk_eth_soc
- qlogic (qede)
- sfc
- socionext (netsec)
- ti (cpsw)
- tap
- tsnep
- veth
- xen
- virtio_net.
Turn 'basic' (tx, pass, aborted and drop) features flags on for:
- netronome (nfp)
- cavium (thunder)
- hyperv.
Turn 'redirect_target' feature flag on for:
- amanzon (ena)
- broadcom (bnxt)
- freescale (dpaa, dpaa2)
- intel (i40e, ice, igb, ixgbe)
- ti (cpsw)
- marvell (mvneta, mvpp2)
- sfc
- socionext (netsec)
- qlogic (qede)
- mellanox (mlx5)
- tap
- veth
- virtio_net
- xen
Reviewed-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Acked-by: Stanislav Fomichev <sdf@google.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Co-developed-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Marek Majtyka <alardam@gmail.com>
Link: https://lore.kernel.org/r/3eca9fafb308462f7edb1f58e451d59209aa07eb.1675245258.git.lorenzo@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-02-01 10:24:18 +00:00
|
|
|
dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT;
|
2013-04-10 23:32:21 +00:00
|
|
|
|
2016-10-20 17:55:21 +00:00
|
|
|
/* MTU range: 68 - 65535 */
|
|
|
|
dev->min_mtu = MIN_MTU;
|
|
|
|
dev->max_mtu = MAX_MTU;
|
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
/* Configuration may specify what MAC to use. Otherwise random. */
|
2021-10-27 15:20:12 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
|
|
|
|
u8 addr[ETH_ALEN];
|
|
|
|
|
2013-10-14 07:41:51 +00:00
|
|
|
virtio_cread_bytes(vdev,
|
|
|
|
offsetof(struct virtio_net_config, mac),
|
2021-10-27 15:20:12 +00:00
|
|
|
addr, ETH_ALEN);
|
|
|
|
eth_hw_addr_set(dev, addr);
|
|
|
|
} else {
|
2012-02-15 06:45:39 +00:00
|
|
|
eth_hw_addr_random(dev);
|
2023-01-27 20:45:00 +00:00
|
|
|
dev_info(&vdev->dev, "Assigned random MAC address %pM\n",
|
|
|
|
dev->dev_addr);
|
2021-10-27 15:20:12 +00:00
|
|
|
}
|
2007-10-22 01:03:37 +00:00
|
|
|
|
|
|
|
/* Set up our device-specific information */
|
|
|
|
vi = netdev_priv(dev);
|
|
|
|
vi->dev = dev;
|
|
|
|
vi->vdev = vdev;
|
2008-02-18 09:02:51 +00:00
|
|
|
vdev->priv = vi;
|
2013-10-07 22:51:58 +00:00
|
|
|
|
2012-04-11 20:43:52 +00:00
|
|
|
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
|
2023-07-20 08:38:38 +00:00
|
|
|
INIT_WORK(&vi->rx_mode_work, virtnet_rx_mode_work);
|
2022-07-25 07:21:59 +00:00
|
|
|
spin_lock_init(&vi->refill_lock);
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2023-02-07 09:53:40 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) {
|
2008-11-17 06:41:34 +00:00
|
|
|
vi->mergeable_rx_bufs = true;
|
2023-02-07 09:53:40 +00:00
|
|
|
dev->xdp_features |= NETDEV_XDP_ACT_RX_SG;
|
|
|
|
}
|
2008-11-17 06:41:34 +00:00
|
|
|
|
2022-03-28 17:53:35 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT))
|
|
|
|
vi->has_rss_hash_report = true;
|
|
|
|
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
|
2022-03-28 17:53:34 +00:00
|
|
|
vi->has_rss = true;
|
2022-03-28 17:53:35 +00:00
|
|
|
|
2022-03-28 17:53:34 +00:00
|
|
|
vi->rss_indir_table_size =
|
|
|
|
virtio_cread16(vdev, offsetof(struct virtio_net_config,
|
|
|
|
rss_max_indirection_table_length));
|
virtio_net: Do not send RSS key if it is not supported
There is a bug when setting the RSS options in virtio_net that can break
the whole machine, getting the kernel into an infinite loop.
Running the following command in any QEMU virtual machine with virtionet
will reproduce this problem:
# ethtool -X eth0 hfunc toeplitz
This is how the problem happens:
1) ethtool_set_rxfh() calls virtnet_set_rxfh()
2) virtnet_set_rxfh() calls virtnet_commit_rss_command()
3) virtnet_commit_rss_command() populates 4 entries for the rss
scatter-gather
4) Since the command above does not have a key, then the last
scatter-gatter entry will be zeroed, since rss_key_size == 0.
sg_buf_size = vi->rss_key_size;
5) This buffer is passed to qemu, but qemu is not happy with a buffer
with zero length, and do the following in virtqueue_map_desc() (QEMU
function):
if (!sz) {
virtio_error(vdev, "virtio: zero sized buffers are not allowed");
6) virtio_error() (also QEMU function) set the device as broken
vdev->broken = true;
7) Qemu bails out, and do not repond this crazy kernel.
8) The kernel is waiting for the response to come back (function
virtnet_send_command())
9) The kernel is waiting doing the following :
while (!virtqueue_get_buf(vi->cvq, &tmp) &&
!virtqueue_is_broken(vi->cvq))
cpu_relax();
10) None of the following functions above is true, thus, the kernel
loops here forever. Keeping in mind that virtqueue_is_broken() does
not look at the qemu `vdev->broken`, so, it never realizes that the
vitio is broken at QEMU side.
Fix it by not sending RSS commands if the feature is not available in
the device.
Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Cc: stable@vger.kernel.org
Cc: qemu-devel@nongnu.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2024-04-03 15:43:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vi->has_rss || vi->has_rss_hash_report) {
|
2022-03-28 17:53:34 +00:00
|
|
|
vi->rss_key_size =
|
|
|
|
virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
|
|
|
|
|
|
|
|
vi->rss_hash_types_supported =
|
|
|
|
virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
|
|
|
|
vi->rss_hash_types_supported &=
|
|
|
|
~(VIRTIO_NET_RSS_HASH_TYPE_IP_EX |
|
|
|
|
VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
|
|
|
|
VIRTIO_NET_RSS_HASH_TYPE_UDP_EX);
|
|
|
|
|
|
|
|
dev->hw_features |= NETIF_F_RXHASH;
|
2024-04-17 07:18:22 +00:00
|
|
|
dev->xdp_metadata_ops = &virtnet_xdp_metadata_ops;
|
2022-03-28 17:53:34 +00:00
|
|
|
}
|
2022-03-28 17:53:35 +00:00
|
|
|
|
|
|
|
if (vi->has_rss_hash_report)
|
|
|
|
vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash);
|
|
|
|
else if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
|
|
|
|
virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
|
2014-10-24 13:55:57 +00:00
|
|
|
vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
|
|
|
|
else
|
|
|
|
vi->hdr_len = sizeof(struct virtio_net_hdr);
|
|
|
|
|
2015-07-15 12:26:19 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT) ||
|
|
|
|
virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
|
2013-07-25 00:50:23 +00:00
|
|
|
vi->any_header_sg = true;
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
|
|
|
|
vi->has_cvq = true;
|
|
|
|
|
2024-05-03 20:24:42 +00:00
|
|
|
mutex_init(&vi->cvq_lock);
|
|
|
|
|
2016-06-03 20:57:12 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
|
|
|
|
mtu = virtio_cread16(vdev,
|
|
|
|
offsetof(struct virtio_net_config,
|
|
|
|
mtu));
|
2016-10-25 20:12:12 +00:00
|
|
|
if (mtu < dev->min_mtu) {
|
2017-03-29 16:09:14 +00:00
|
|
|
/* Should never trigger: MTU was previously validated
|
|
|
|
* in virtnet_validate.
|
|
|
|
*/
|
2019-04-03 09:10:13 +00:00
|
|
|
dev_err(&vdev->dev,
|
|
|
|
"device MTU appears to have changed it is now %d < %d",
|
|
|
|
mtu, dev->min_mtu);
|
2020-12-04 14:23:16 +00:00
|
|
|
err = -EINVAL;
|
2018-01-17 06:38:25 +00:00
|
|
|
goto free;
|
2016-10-25 20:12:12 +00:00
|
|
|
}
|
2017-03-08 00:14:25 +00:00
|
|
|
|
2017-03-29 16:09:14 +00:00
|
|
|
dev->mtu = mtu;
|
|
|
|
dev->max_mtu = mtu;
|
2016-06-03 20:57:12 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 14:49:11 +00:00
|
|
|
virtnet_set_big_packets(vi, mtu);
|
|
|
|
|
2014-10-24 13:55:57 +00:00
|
|
|
if (vi->any_header_sg)
|
|
|
|
dev->needed_headroom = vi->hdr_len;
|
virtio-net: Set needed_headroom for virtio-net when VIRTIO_F_ANY_LAYOUT is true
This is a small supplement for commit e7428e95a06fb516fac1308bd0e176e27c0b9287
("virtio-net: put virtio-net header inline with data"). TCP packages have
enough room to put virtio-net header in, but UDP packages do not. By
setting dev->needed_headroom for virtio-net device, UDP packages could have
enough room.
For UDP packages, sk_buff is alloced in fun __ip_append_data. The size is
"alloclen + hh_len + 15", and "hh_len = LL_RESERVED_SPACE(rt-dst.dev);".
The Macro is defined as follows:
#define LL_RESERVED_SPACE(dev) \
((((dev)->hard_header_len+(dev)->needed_headroom)\
&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
By default, for UDP packages, after skb is allocated, only 16 bytes
reserved. And 2 bytes remained after mac header is set. That is not enough
to put virtio-net header in. If we set dev->needed_headroom to 12 or 10
(according to mergeable_rx_bufs is on or off ), more room can be reserved.
Then there is enough room for UDP packages to put the header in.
test result list as below:
guest and host: suse11sp3, netperf, intel 2.4GHz
+-------+---------+---------+---------+---------+
| | old | new |
+-------+---------+---------+---------+---------+
| UDP | Gbit/s | pps | Gbit/s | pps |
| 64 | 0.57 | 692232 | 0.61 | 742420 |
| 256 | 1.60 | 686860 | 1.71 | 733331 |
| 512 | 2.92 | 674576 | 3.07 | 710446 |
| 1024 | 4.99 | 598977 | 5.17 | 620821 |
| 1460 | 5.68 | 483757 | 7.16 | 610519 |
| 4096 | 6.98 | 637468 | 7.21 | 658471 |
+-------+---------+---------+---------+---------+
Signed-off-by: Zhang Jie <zhangjie14@huawei.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-04-29 10:43:22 +00:00
|
|
|
|
2016-11-25 04:37:26 +00:00
|
|
|
/* Enable multiqueue by default */
|
|
|
|
if (num_online_cpus() >= max_queue_pairs)
|
|
|
|
vi->curr_queue_pairs = max_queue_pairs;
|
|
|
|
else
|
|
|
|
vi->curr_queue_pairs = num_online_cpus();
|
2012-12-07 07:04:56 +00:00
|
|
|
vi->max_queue_pairs = max_queue_pairs;
|
|
|
|
|
|
|
|
/* Allocate/initialize the rx/tx queues, and invoke find_vqs */
|
2011-12-22 11:28:31 +00:00
|
|
|
err = init_vqs(vi);
|
2009-06-13 04:16:36 +00:00
|
|
|
if (err)
|
2018-01-17 06:38:25 +00:00
|
|
|
goto free;
|
2007-10-22 01:03:37 +00:00
|
|
|
|
2023-10-08 06:27:39 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_NOTF_COAL)) {
|
|
|
|
vi->intr_coal_rx.max_usecs = 0;
|
|
|
|
vi->intr_coal_tx.max_usecs = 0;
|
|
|
|
vi->intr_coal_rx.max_packets = 0;
|
|
|
|
|
|
|
|
/* Keep the default values of the coalescing parameters
|
|
|
|
* aligned with the default napi_tx state.
|
|
|
|
*/
|
|
|
|
if (vi->sq[0].napi.weight)
|
|
|
|
vi->intr_coal_tx.max_packets = 1;
|
|
|
|
else
|
|
|
|
vi->intr_coal_tx.max_packets = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL)) {
|
|
|
|
/* The reason is the same as VIRTIO_NET_F_NOTF_COAL. */
|
|
|
|
for (i = 0; i < vi->max_queue_pairs; i++)
|
|
|
|
if (vi->sq[i].napi.weight)
|
|
|
|
vi->sq[i].intr_coal.max_packets = 1;
|
2024-06-21 10:13:53 +00:00
|
|
|
|
|
|
|
err = virtnet_init_irq_moder(vi);
|
|
|
|
if (err)
|
|
|
|
goto free;
|
2023-10-08 06:27:39 +00:00
|
|
|
}
|
|
|
|
|
2014-01-17 06:23:30 +00:00
|
|
|
#ifdef CONFIG_SYSFS
|
|
|
|
if (vi->mergeable_rx_bufs)
|
|
|
|
dev->sysfs_rx_queue_group = &virtio_net_mrg_rx_group;
|
|
|
|
#endif
|
2013-11-18 13:19:27 +00:00
|
|
|
netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs);
|
|
|
|
netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs);
|
2012-12-07 07:04:56 +00:00
|
|
|
|
2022-08-16 05:36:27 +00:00
|
|
|
virtnet_init_settings(dev);
|
|
|
|
|
2018-05-24 16:55:17 +00:00
|
|
|
if (virtio_has_feature(vdev, VIRTIO_NET_F_STANDBY)) {
|
|
|
|
vi->failover = net_failover_create(vi->dev);
|
2018-05-31 02:05:07 +00:00
|
|
|
if (IS_ERR(vi->failover)) {
|
|
|
|
err = PTR_ERR(vi->failover);
|
2018-05-24 16:55:17 +00:00
|
|
|
goto free_vqs;
|
2018-05-31 02:05:07 +00:00
|
|
|
}
|
2018-05-24 16:55:17 +00:00
|
|
|
}
|
|
|
|
|
2022-03-28 17:53:35 +00:00
|
|
|
if (vi->has_rss || vi->has_rss_hash_report)
|
2022-03-28 17:53:34 +00:00
|
|
|
virtnet_init_default_rss(vi);
|
|
|
|
|
2023-07-20 08:38:38 +00:00
|
|
|
enable_rx_mode_work(vi);
|
|
|
|
|
2022-06-17 07:29:49 +00:00
|
|
|
/* serialize netdev register + virtio_device_ready() with ndo_open() */
|
|
|
|
rtnl_lock();
|
|
|
|
|
|
|
|
err = register_netdevice(dev);
|
2007-10-22 01:03:37 +00:00
|
|
|
if (err) {
|
|
|
|
pr_debug("virtio_net: registering device failed\n");
|
2022-06-17 07:29:49 +00:00
|
|
|
rtnl_unlock();
|
2018-05-24 16:55:17 +00:00
|
|
|
goto free_failover;
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
2008-02-05 04:50:02 +00:00
|
|
|
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
/* Disable config change notification until ndo_open. */
|
|
|
|
virtio_config_driver_disable(vi->vdev);
|
|
|
|
|
2014-10-14 23:52:30 +00:00
|
|
|
virtio_device_ready(vdev);
|
|
|
|
|
2024-05-03 20:24:45 +00:00
|
|
|
virtnet_set_queues(vi, vi->curr_queue_pairs);
|
2023-08-10 03:12:56 +00:00
|
|
|
|
2023-01-27 20:45:00 +00:00
|
|
|
/* a random MAC address has been assigned, notify the device.
|
|
|
|
* We don't fail probe if VIRTIO_NET_F_CTRL_MAC_ADDR is not there
|
|
|
|
* because many devices work fine without getting MAC explicitly
|
|
|
|
*/
|
|
|
|
if (!virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
|
|
|
|
virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
|
|
|
|
struct scatterlist sg;
|
|
|
|
|
|
|
|
sg_init_one(&sg, dev->dev_addr, dev->addr_len);
|
|
|
|
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
|
|
|
|
VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) {
|
|
|
|
pr_debug("virtio_net: setting MAC address failed\n");
|
|
|
|
rtnl_unlock();
|
|
|
|
err = -EINVAL;
|
|
|
|
goto free_unregister_netdev;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_DEVICE_STATS)) {
|
2024-05-03 20:24:41 +00:00
|
|
|
struct virtio_net_stats_capabilities *stats_cap __free(kfree) = NULL;
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
struct scatterlist sg;
|
|
|
|
__le64 v;
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
stats_cap = kzalloc(sizeof(*stats_cap), GFP_KERNEL);
|
|
|
|
if (!stats_cap) {
|
|
|
|
rtnl_unlock();
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto free_unregister_netdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
sg_init_one(&sg, stats_cap, sizeof(*stats_cap));
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
|
|
|
|
if (!virtnet_send_command_reply(vi, VIRTIO_NET_CTRL_STATS,
|
|
|
|
VIRTIO_NET_CTRL_STATS_QUERY,
|
|
|
|
NULL, &sg)) {
|
|
|
|
pr_debug("virtio_net: fail to get stats capability\n");
|
|
|
|
rtnl_unlock();
|
|
|
|
err = -EINVAL;
|
|
|
|
goto free_unregister_netdev;
|
|
|
|
}
|
|
|
|
|
2024-05-03 20:24:41 +00:00
|
|
|
v = stats_cap->supported_stats_types[0];
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
vi->device_stats_cap = le64_to_cpu(v);
|
|
|
|
}
|
|
|
|
|
2010-11-10 14:45:41 +00:00
|
|
|
/* Assume link up if device can't report link status,
|
|
|
|
otherwise get link status from config. */
|
2018-03-22 14:42:41 +00:00
|
|
|
netif_carrier_off(dev);
|
2010-11-10 14:45:41 +00:00
|
|
|
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
virtnet_config_changed_work(&vi->config_work);
|
2010-11-10 14:45:41 +00:00
|
|
|
} else {
|
|
|
|
vi->status = VIRTIO_NET_S_LINK_UP;
|
2018-01-05 22:44:54 +00:00
|
|
|
virtnet_update_settings(vi);
|
2010-11-10 14:45:41 +00:00
|
|
|
netif_carrier_on(dev);
|
|
|
|
}
|
2009-01-20 01:09:49 +00:00
|
|
|
|
2024-08-14 05:22:28 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(guest_offloads); i++)
|
|
|
|
if (virtio_has_feature(vi->vdev, guest_offloads[i]))
|
|
|
|
set_bit(guest_offloads[i], &vi->guest_offloads);
|
|
|
|
vi->guest_offloads_capable = vi->guest_offloads;
|
|
|
|
|
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863.
This is done by trying to toggle the carrier upon open/close and
synchronize with the config change work. This allows to propagate
status correctly to stacked devices like:
ip link add link enp0s3 macvlan0 type macvlan
ip link set link enp0s3 down
ip link show
Before this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
......
5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
After this patch:
3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff
...
5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff
Cc: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-08-14 05:22:27 +00:00
|
|
|
rtnl_unlock();
|
|
|
|
|
|
|
|
err = virtnet_cpu_notif_add(vi);
|
|
|
|
if (err) {
|
|
|
|
pr_debug("virtio_net: registering cpu notifier failed\n");
|
|
|
|
goto free_unregister_netdev;
|
|
|
|
}
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
pr_debug("virtnet: registered device %s with %d RX and TX vq's\n",
|
|
|
|
dev->name, max_queue_pairs);
|
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
return 0;
|
|
|
|
|
2016-05-31 03:52:43 +00:00
|
|
|
free_unregister_netdev:
|
2008-02-05 04:50:02 +00:00
|
|
|
unregister_netdev(dev);
|
2018-05-24 16:55:17 +00:00
|
|
|
free_failover:
|
|
|
|
net_failover_destroy(vi->failover);
|
2009-06-13 04:16:36 +00:00
|
|
|
free_vqs:
|
virtio_net: Fix probe failed when modprobe virtio_net
When doing the following test steps, an error was found:
step 1: modprobe virtio_net succeeded
# modprobe virtio_net <-- OK
step 2: fault injection in register_netdevice()
# modprobe -r virtio_net <-- OK
# ...
FAULT_INJECTION: forcing a failure.
name failslab, interval 1, probability 0, space 0, times 0
CPU: 0 PID: 3521 Comm: modprobe
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
Call Trace:
<TASK>
...
should_failslab+0xa/0x20
...
dev_set_name+0xc0/0x100
netdev_register_kobject+0xc2/0x340
register_netdevice+0xbb9/0x1320
virtnet_probe+0x1d72/0x2658 [virtio_net]
...
</TASK>
virtio_net: probe of virtio0 failed with error -22
step 3: modprobe virtio_net failed
# modprobe virtio_net <-- failed
virtio_net: probe of virtio0 failed with error -2
The root cause of the problem is that the queues are not
disable on the error handling path when register_netdevice()
fails in virtnet_probe(), resulting in an error "-ENOENT"
returned in the next modprobe call in setup_vq().
virtio_pci_modern_device uses virtqueues to send or
receive message, and "queue_enable" records whether the
queues are available. In vp_modern_find_vqs(), all queues
will be selected and activated, but once queues are enabled
there is no way to go back except reset.
Fix it by reset virtio device on error handling path. This
makes error handling follow the same order as normal device
cleanup in virtnet_remove() which does: unregister, destroy
failover, then reset. And that flow is better tested than
error handling so we can be reasonably sure it works well.
Fixes: 024655555021 ("virtio_net: fix use after free on allocation failure")
Signed-off-by: Li Zetao <lizetao1@huawei.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Link: https://lore.kernel.org/r/20221122150046.3910638-1-lizetao1@huawei.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2022-11-22 15:00:46 +00:00
|
|
|
virtio_reset_device(vdev);
|
2012-12-07 07:04:56 +00:00
|
|
|
cancel_delayed_work_sync(&vi->refill);
|
2014-01-17 06:23:26 +00:00
|
|
|
free_receive_page_frags(vi);
|
2012-12-07 07:04:55 +00:00
|
|
|
virtnet_del_vqs(vi);
|
2007-10-22 01:03:37 +00:00
|
|
|
free:
|
|
|
|
free_netdev(dev);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2011-12-22 11:28:32 +00:00
|
|
|
static void remove_vq_common(struct virtnet_info *vi)
|
2007-10-22 01:03:37 +00:00
|
|
|
{
|
2021-10-13 10:55:44 +00:00
|
|
|
virtio_reset_device(vi->vdev);
|
2010-02-08 14:14:42 +00:00
|
|
|
|
|
|
|
/* Free unused buffers in both send and recv, if any. */
|
2010-01-29 03:20:04 +00:00
|
|
|
free_unused_bufs(vi);
|
2008-07-25 17:06:01 +00:00
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
free_receive_bufs(vi);
|
2009-06-13 04:16:36 +00:00
|
|
|
|
2014-01-17 06:23:26 +00:00
|
|
|
free_receive_page_frags(vi);
|
|
|
|
|
2012-12-07 07:04:56 +00:00
|
|
|
virtnet_del_vqs(vi);
|
2011-12-22 11:28:32 +00:00
|
|
|
}
|
|
|
|
|
2012-12-03 14:24:15 +00:00
|
|
|
static void virtnet_remove(struct virtio_device *vdev)
|
2011-12-22 11:28:32 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vdev->priv;
|
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
virtnet_cpu_notif_remove(vi);
|
2013-01-24 23:51:31 +00:00
|
|
|
|
2014-10-14 23:52:29 +00:00
|
|
|
/* Make sure no work handler is accessing the device. */
|
|
|
|
flush_work(&vi->config_work);
|
2023-07-20 08:38:38 +00:00
|
|
|
disable_rx_mode_work(vi);
|
|
|
|
flush_work(&vi->rx_mode_work);
|
2012-04-11 20:43:52 +00:00
|
|
|
|
2024-06-21 10:13:53 +00:00
|
|
|
virtnet_free_irq_moder(vi);
|
|
|
|
|
2011-12-22 11:28:32 +00:00
|
|
|
unregister_netdev(vi->dev);
|
|
|
|
|
2018-05-24 16:55:17 +00:00
|
|
|
net_failover_destroy(vi->failover);
|
|
|
|
|
2011-12-22 11:28:32 +00:00
|
|
|
remove_vq_common(vi);
|
2008-07-25 17:06:01 +00:00
|
|
|
|
2007-11-19 16:20:42 +00:00
|
|
|
free_netdev(vi->dev);
|
2007-10-22 01:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-07-25 15:35:50 +00:00
|
|
|
static __maybe_unused int virtnet_freeze(struct virtio_device *vdev)
|
2011-12-22 11:28:33 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vdev->priv;
|
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
virtnet_cpu_notif_remove(vi);
|
2017-02-03 03:16:01 +00:00
|
|
|
virtnet_freeze_down(vdev);
|
2011-12-22 11:28:33 +00:00
|
|
|
remove_vq_common(vi);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-25 15:35:50 +00:00
|
|
|
static __maybe_unused int virtnet_restore(struct virtio_device *vdev)
|
2011-12-22 11:28:33 +00:00
|
|
|
{
|
|
|
|
struct virtnet_info *vi = vdev->priv;
|
2017-02-03 03:16:01 +00:00
|
|
|
int err;
|
2011-12-22 11:28:33 +00:00
|
|
|
|
2017-02-03 03:16:01 +00:00
|
|
|
err = virtnet_restore_up(vdev);
|
2011-12-22 11:28:33 +00:00
|
|
|
if (err)
|
|
|
|
return err;
|
2012-12-07 07:04:56 +00:00
|
|
|
virtnet_set_queues(vi, vi->curr_queue_pairs);
|
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
err = virtnet_cpu_notif_add(vi);
|
2021-05-17 08:45:16 +00:00
|
|
|
if (err) {
|
|
|
|
virtnet_freeze_down(vdev);
|
|
|
|
remove_vq_common(vi);
|
2013-10-29 07:11:07 +00:00
|
|
|
return err;
|
2021-05-17 08:45:16 +00:00
|
|
|
}
|
2013-10-29 07:11:07 +00:00
|
|
|
|
2011-12-22 11:28:33 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-10-22 01:03:37 +00:00
|
|
|
static struct virtio_device_id id_table[] = {
|
|
|
|
{ VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
|
|
|
|
{ 0 },
|
|
|
|
};
|
|
|
|
|
2016-11-04 10:55:36 +00:00
|
|
|
#define VIRTNET_FEATURES \
|
|
|
|
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, \
|
|
|
|
VIRTIO_NET_F_MAC, \
|
|
|
|
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, \
|
|
|
|
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, \
|
|
|
|
VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, \
|
2022-12-07 11:35:58 +00:00
|
|
|
VIRTIO_NET_F_HOST_USO, VIRTIO_NET_F_GUEST_USO4, VIRTIO_NET_F_GUEST_USO6, \
|
2016-11-04 10:55:36 +00:00
|
|
|
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \
|
|
|
|
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \
|
|
|
|
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
|
|
|
|
VIRTIO_NET_F_CTRL_MAC_ADDR, \
|
2018-01-05 22:44:54 +00:00
|
|
|
VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
|
2022-03-28 17:53:34 +00:00
|
|
|
VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
|
2023-03-09 09:45:59 +00:00
|
|
|
VIRTIO_NET_F_RSS, VIRTIO_NET_F_HASH_REPORT, VIRTIO_NET_F_NOTF_COAL, \
|
2023-07-31 07:06:56 +00:00
|
|
|
VIRTIO_NET_F_VQ_NOTF_COAL, \
|
virtio_net: support device stats
As the spec https://github.com/oasis-tcs/virtio-spec/commit/42f389989823039724f95bbbd243291ab0064f82
make virtio-net support getting the stats from the device by ethtool -S
<eth0>.
NIC statistics:
rx0_packets: 582951
rx0_bytes: 155307077
rx0_drops: 0
rx0_xdp_packets: 0
rx0_xdp_tx: 0
rx0_xdp_redirects: 0
rx0_xdp_drops: 0
rx0_kicks: 17007
rx0_hw_packets: 2179409
rx0_hw_bytes: 510015040
rx0_hw_notifications: 0
rx0_hw_interrupts: 0
rx0_hw_needs_csum: 2179409
rx0_hw_ratelimit_bytes: 0
tx0_packets: 15361
tx0_bytes: 1918970
tx0_xdp_tx: 0
tx0_xdp_tx_drops: 0
tx0_kicks: 15361
tx0_timeouts: 0
tx0_hw_packets: 32272
tx0_hw_bytes: 4311698
tx0_hw_notifications: 0
tx0_hw_interrupts: 0
tx0_hw_ratelimit_bytes: 0
The follow stats are hidden, there are exported by the queue stat API
in the subsequent comment.
VIRTNET_STATS_DESC_RX(basic, drops)
VIRTNET_STATS_DESC_RX(basic, drop_overruns),
VIRTNET_STATS_DESC_TX(basic, drops),
VIRTNET_STATS_DESC_TX(basic, drop_malformed),
VIRTNET_STATS_DESC_RX(csum, csum_valid),
VIRTNET_STATS_DESC_RX(csum, csum_none),
VIRTNET_STATS_DESC_RX(csum, csum_bad),
VIRTNET_STATS_DESC_TX(csum, needs_csum),
VIRTNET_STATS_DESC_TX(csum, csum_none),
VIRTNET_STATS_DESC_RX(gso, gso_packets),
VIRTNET_STATS_DESC_RX(gso, gso_bytes),
VIRTNET_STATS_DESC_RX(gso, gso_packets_coalesced),
VIRTNET_STATS_DESC_RX(gso, gso_bytes_coalesced),
VIRTNET_STATS_DESC_TX(gso, gso_packets),
VIRTNET_STATS_DESC_TX(gso, gso_bytes),
VIRTNET_STATS_DESC_TX(gso, gso_segments),
VIRTNET_STATS_DESC_TX(gso, gso_segments_bytes),
VIRTNET_STATS_DESC_RX(speed, ratelimit_packets),
VIRTNET_STATS_DESC_TX(speed, ratelimit_packets),
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2024-04-26 03:39:24 +00:00
|
|
|
VIRTIO_NET_F_GUEST_HDRLEN, VIRTIO_NET_F_DEVICE_STATS
|
2016-11-04 10:55:36 +00:00
|
|
|
|
2008-05-03 02:50:50 +00:00
|
|
|
static unsigned int features[] = {
|
2016-11-04 10:55:36 +00:00
|
|
|
VIRTNET_FEATURES,
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int features_legacy[] = {
|
|
|
|
VIRTNET_FEATURES,
|
|
|
|
VIRTIO_NET_F_GSO,
|
2013-07-25 00:50:23 +00:00
|
|
|
VIRTIO_F_ANY_LAYOUT,
|
2008-05-03 02:50:50 +00:00
|
|
|
};
|
|
|
|
|
2009-11-05 09:32:44 +00:00
|
|
|
static struct virtio_driver virtio_net_driver = {
|
2008-05-03 02:50:50 +00:00
|
|
|
.feature_table = features,
|
|
|
|
.feature_table_size = ARRAY_SIZE(features),
|
2016-11-04 10:55:36 +00:00
|
|
|
.feature_table_legacy = features_legacy,
|
|
|
|
.feature_table_size_legacy = ARRAY_SIZE(features_legacy),
|
2007-10-22 01:03:37 +00:00
|
|
|
.driver.name = KBUILD_MODNAME,
|
|
|
|
.id_table = id_table,
|
2017-03-29 16:09:14 +00:00
|
|
|
.validate = virtnet_validate,
|
2007-10-22 01:03:37 +00:00
|
|
|
.probe = virtnet_probe,
|
2012-12-03 14:24:15 +00:00
|
|
|
.remove = virtnet_remove,
|
2009-01-20 01:09:49 +00:00
|
|
|
.config_changed = virtnet_config_changed,
|
2013-09-16 23:55:23 +00:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2011-12-22 11:28:33 +00:00
|
|
|
.freeze = virtnet_freeze,
|
|
|
|
.restore = virtnet_restore,
|
|
|
|
#endif
|
2007-10-22 01:03:37 +00:00
|
|
|
};
|
|
|
|
|
2016-08-12 17:49:43 +00:00
|
|
|
static __init int virtio_net_driver_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2016-12-21 19:19:54 +00:00
|
|
|
ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "virtio/net:online",
|
2016-08-12 17:49:43 +00:00
|
|
|
virtnet_cpu_online,
|
|
|
|
virtnet_cpu_down_prep);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
virtionet_online = ret;
|
2016-12-21 19:19:54 +00:00
|
|
|
ret = cpuhp_setup_state_multi(CPUHP_VIRT_NET_DEAD, "virtio/net:dead",
|
2016-08-12 17:49:43 +00:00
|
|
|
NULL, virtnet_cpu_dead);
|
|
|
|
if (ret)
|
|
|
|
goto err_dead;
|
2022-02-13 08:01:41 +00:00
|
|
|
ret = register_virtio_driver(&virtio_net_driver);
|
2016-08-12 17:49:43 +00:00
|
|
|
if (ret)
|
|
|
|
goto err_virtio;
|
|
|
|
return 0;
|
|
|
|
err_virtio:
|
|
|
|
cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
|
|
|
|
err_dead:
|
|
|
|
cpuhp_remove_multi_state(virtionet_online);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
module_init(virtio_net_driver_init);
|
|
|
|
|
|
|
|
static __exit void virtio_net_driver_exit(void)
|
|
|
|
{
|
2017-07-24 13:38:32 +00:00
|
|
|
unregister_virtio_driver(&virtio_net_driver);
|
2016-08-12 17:49:43 +00:00
|
|
|
cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD);
|
|
|
|
cpuhp_remove_multi_state(virtionet_online);
|
|
|
|
}
|
|
|
|
module_exit(virtio_net_driver_exit);
|
2007-10-22 01:03:37 +00:00
|
|
|
|
|
|
|
MODULE_DEVICE_TABLE(virtio, id_table);
|
|
|
|
MODULE_DESCRIPTION("Virtio network driver");
|
|
|
|
MODULE_LICENSE("GPL");
|