-----BEGIN PGP SIGNATURE-----

iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmcglKYACgkQ7wSWWzmN
 YhEm/wf/cYA7i3asKMUoYqlff5mBiY3aFCWzTR5qHLBcWfnB33f9FYpAW6RgDwMa
 3aFAJm1VZAynmUWgz+f537+e+7900M+P54zbD7kHCthAy7l/E7t9SkKNpe6jZHEA
 P4hB09CSKm/TY1XtsFMvO5tkF9IgY51VEO+mZJesO1H2X2+3ulJYusx9fh/P6yST
 bG8sbXr55v23R3z4UOovqfkuskPETwRh3qoiOLPPBy8CWkBVze8J+siC7HC+eFIo
 KrQ+jhUYpIK8CAgHV09ZnlurLo6UZ0+vlo9IcJN+GQp/gsmg8OErjvzPdKKbynC/
 1zjvkgyW27aHsei+baTMXGCE0P8dIw==
 =6+yo
 -----END PGP SIGNATURE-----

Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmcglKYACgkQ7wSWWzmN
# YhEm/wf/cYA7i3asKMUoYqlff5mBiY3aFCWzTR5qHLBcWfnB33f9FYpAW6RgDwMa
# 3aFAJm1VZAynmUWgz+f537+e+7900M+P54zbD7kHCthAy7l/E7t9SkKNpe6jZHEA
# P4hB09CSKm/TY1XtsFMvO5tkF9IgY51VEO+mZJesO1H2X2+3ulJYusx9fh/P6yST
# bG8sbXr55v23R3z4UOovqfkuskPETwRh3qoiOLPPBy8CWkBVze8J+siC7HC+eFIo
# KrQ+jhUYpIK8CAgHV09ZnlurLo6UZ0+vlo9IcJN+GQp/gsmg8OErjvzPdKKbynC/
# 1zjvkgyW27aHsei+baTMXGCE0P8dIw==
# =6+yo
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 29 Oct 2024 07:54:14 GMT
# gpg:                using RSA key 215D46F48246689EC77F3562EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* tag 'net-pull-request' of https://github.com/jasowang/qemu:
  virtio-net: Avoid indirection_table_mask overflow
  Fix calculation of minimum in colo_compare_tcp
  net: Check if nc is NULL in qemu_get_vnet_hdr_len()
  net/tap-win32: Fix gcc 14 format truncation errors
  chardev: finalize 'reconnect' deprecation
  net/stream: deprecate 'reconnect' in favor of 'reconnect-ms'
  hw/net: improve tracing of eBPF RSS setup
  ebpf: improve trace event coverage to all key operations
  hw/net: report errors from failing to use eBPF RSS FDs
  ebpf: add formal error reporting to all APIs
  ebpf: improve error trace events
  ebpf: drop redundant parameter checks in static methods
  hw/net: fix typo s/epbf/ebpf/ in virtio-net
  net: fix build when libbpf is disabled, but libxdp is enabled

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-10-29 14:00:43 +00:00
commit 58d49b5895
21 changed files with 246 additions and 140 deletions

View File

@ -193,8 +193,8 @@ any IP's here, except for the $primary_ip variable.
-device piix3-usb-uhci -device usb-tablet -name secondary \
-netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \
-device rtl8139,id=e0,netdev=hn0 \
-chardev socket,id=red0,host=$primary_ip,port=9003,reconnect=1 \
-chardev socket,id=red1,host=$primary_ip,port=9004,reconnect=1 \
-chardev socket,id=red0,host=$primary_ip,port=9003,reconnect-ms=1000 \
-chardev socket,id=red1,host=$primary_ip,port=9004,reconnect-ms=1000 \
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 \
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 \
-object filter-rewriter,id=rew0,netdev=hn0,queue=all \

View File

@ -400,6 +400,16 @@ Backend ``memory`` (since 9.0)
The ``reconnect`` option only allows specifiying second granularity timeouts,
which is not enough for all types of use cases, use ``reconnect-ms`` instead.
Net device options
''''''''''''''''''
Stream ``reconnect`` (since 9.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``reconnect`` option only allows specifiying second granularity timeouts,
which is not enough for all types of use cases, use ``reconnect-ms`` instead.
CPU device properties
'''''''''''''''''''''

View File

@ -181,7 +181,7 @@ connected to a remote QEMU machine acting as BMC, using these options
.. code-block:: bash
-chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 \
-chardev socket,id=ipmi0,host=localhost,port=9002,reconnect-ms=10000 \
-device ipmi-bmc-extern,id=bmc0,chardev=ipmi0 \
-device isa-ipmi-bt,bmc=bmc0,irq=10 \
-nodefaults

View File

@ -23,19 +23,21 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
return false;
}
bool ebpf_rss_load(struct EBPFRSSContext *ctx)
bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp)
{
return false;
}
bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
int config_fd, int toeplitz_fd, int table_fd)
int config_fd, int toeplitz_fd, int table_fd,
Error **errp)
{
return false;
}
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
uint16_t *indirections_table, uint8_t *toeplitz_key)
uint16_t *indirections_table, uint8_t *toeplitz_key,
Error **errp)
{
return false;
}

View File

@ -47,34 +47,37 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
return ctx != NULL && (ctx->obj != NULL || ctx->program_fd != -1);
}
static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx, Error **errp)
{
if (!ebpf_rss_is_loaded(ctx)) {
return false;
}
ctx->mmap_configuration = mmap(NULL, qemu_real_host_page_size(),
PROT_READ | PROT_WRITE, MAP_SHARED,
ctx->map_configuration, 0);
if (ctx->mmap_configuration == MAP_FAILED) {
trace_ebpf_error("eBPF RSS", "can not mmap eBPF configuration array");
trace_ebpf_rss_mmap_error(ctx, "configuration");
error_setg(errp, "Unable to map eBPF configuration array");
return false;
}
ctx->mmap_toeplitz_key = mmap(NULL, qemu_real_host_page_size(),
PROT_READ | PROT_WRITE, MAP_SHARED,
ctx->map_toeplitz_key, 0);
if (ctx->mmap_toeplitz_key == MAP_FAILED) {
trace_ebpf_error("eBPF RSS", "can not mmap eBPF toeplitz key");
trace_ebpf_rss_mmap_error(ctx, "toeplitz key");
error_setg(errp, "Unable to map eBPF toeplitz array");
goto toeplitz_fail;
}
ctx->mmap_indirections_table = mmap(NULL, qemu_real_host_page_size(),
PROT_READ | PROT_WRITE, MAP_SHARED,
ctx->map_indirections_table, 0);
if (ctx->mmap_indirections_table == MAP_FAILED) {
trace_ebpf_error("eBPF RSS", "can not mmap eBPF indirection table");
trace_ebpf_rss_mmap_error(ctx, "indirections table");
error_setg(errp, "Unable to map eBPF indirection array");
goto indirection_fail;
}
trace_ebpf_rss_mmap(ctx,
ctx->mmap_configuration,
ctx->mmap_toeplitz_key,
ctx->mmap_indirections_table);
return true;
indirection_fail:
@ -90,10 +93,6 @@ toeplitz_fail:
static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
{
if (!ebpf_rss_is_loaded(ctx)) {
return;
}
munmap(ctx->mmap_indirections_table, qemu_real_host_page_size());
munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size());
munmap(ctx->mmap_configuration, qemu_real_host_page_size());
@ -103,7 +102,7 @@ static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
ctx->mmap_indirections_table = NULL;
}
bool ebpf_rss_load(struct EBPFRSSContext *ctx)
bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp)
{
struct rss_bpf *rss_bpf_ctx;
@ -113,14 +112,16 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
rss_bpf_ctx = rss_bpf__open();
if (rss_bpf_ctx == NULL) {
trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
trace_ebpf_rss_open_error(ctx);
error_setg(errp, "Unable to open eBPF RSS object");
goto error;
}
bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER);
if (rss_bpf__load(rss_bpf_ctx)) {
trace_ebpf_error("eBPF RSS", "can not load RSS program");
trace_ebpf_rss_load_error(ctx);
error_setg(errp, "Unable to load eBPF program");
goto error;
}
@ -134,7 +135,12 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
ctx->map_toeplitz_key = bpf_map__fd(
rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
if (!ebpf_rss_mmap(ctx)) {
trace_ebpf_rss_load(ctx,
ctx->program_fd,
ctx->map_configuration,
ctx->map_indirections_table,
ctx->map_toeplitz_key);
if (!ebpf_rss_mmap(ctx, errp)) {
goto error;
}
@ -151,13 +157,28 @@ error:
}
bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
int config_fd, int toeplitz_fd, int table_fd)
int config_fd, int toeplitz_fd, int table_fd,
Error **errp)
{
if (ebpf_rss_is_loaded(ctx)) {
error_setg(errp, "eBPF program is already loaded");
return false;
}
if (program_fd < 0 || config_fd < 0 || toeplitz_fd < 0 || table_fd < 0) {
if (program_fd < 0) {
error_setg(errp, "eBPF program FD is not open");
return false;
}
if (config_fd < 0) {
error_setg(errp, "eBPF config FD is not open");
return false;
}
if (toeplitz_fd < 0) {
error_setg(errp, "eBPF toeplitz FD is not open");
return false;
}
if (table_fd < 0) {
error_setg(errp, "eBPF indirection FD is not open");
return false;
}
@ -166,7 +187,13 @@ bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
ctx->map_toeplitz_key = toeplitz_fd;
ctx->map_indirections_table = table_fd;
if (!ebpf_rss_mmap(ctx)) {
trace_ebpf_rss_load(ctx,
ctx->program_fd,
ctx->map_configuration,
ctx->map_indirections_table,
ctx->map_toeplitz_key);
if (!ebpf_rss_mmap(ctx, errp)) {
ctx->program_fd = -1;
ctx->map_configuration = -1;
ctx->map_toeplitz_key = -1;
@ -177,25 +204,22 @@ bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
return true;
}
static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
static void ebpf_rss_set_config(struct EBPFRSSContext *ctx,
struct EBPFRSSConfig *config)
{
if (!ebpf_rss_is_loaded(ctx)) {
return false;
}
memcpy(ctx->mmap_configuration, config, sizeof(*config));
return true;
}
static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
uint16_t *indirections_table,
size_t len)
size_t len,
Error **errp)
{
char *cursor = ctx->mmap_indirections_table;
if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
if (len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
error_setg(errp, "Indirections table length %zu exceeds limit %d",
len, VIRTIO_NET_RSS_MAX_TABLE_LEN);
return false;
}
@ -207,42 +231,50 @@ static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
return true;
}
static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
static void ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
uint8_t *toeplitz_key)
{
/* prepare toeplitz key */
uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
return false;
}
memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
*(uint32_t *)toe = ntohl(*(uint32_t *)toe);
memcpy(ctx->mmap_toeplitz_key, toe, VIRTIO_NET_RSS_MAX_KEY_SIZE);
return true;
}
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
uint16_t *indirections_table, uint8_t *toeplitz_key)
uint16_t *indirections_table, uint8_t *toeplitz_key,
Error **errp)
{
if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
indirections_table == NULL || toeplitz_key == NULL) {
if (!ebpf_rss_is_loaded(ctx)) {
error_setg(errp, "eBPF program is not loaded");
return false;
}
if (config == NULL) {
error_setg(errp, "eBPF config table is NULL");
return false;
}
if (indirections_table == NULL) {
error_setg(errp, "eBPF indirections table is NULL");
return false;
}
if (toeplitz_key == NULL) {
error_setg(errp, "eBPF toeplitz key is NULL");
return false;
}
if (!ebpf_rss_set_config(ctx, config)) {
return false;
}
ebpf_rss_set_config(ctx, config);
if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
config->indirections_len)) {
config->indirections_len,
errp)) {
return false;
}
if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
return false;
}
ebpf_rss_set_toepliz_key(ctx, toeplitz_key);
trace_ebpf_rss_set_data(ctx, config, indirections_table, toeplitz_key);
return true;
}
@ -253,6 +285,8 @@ void ebpf_rss_unload(struct EBPFRSSContext *ctx)
return;
}
trace_ebpf_rss_unload(ctx);
ebpf_rss_munmap(ctx);
if (ctx->obj) {

View File

@ -14,6 +14,8 @@
#ifndef QEMU_EBPF_RSS_H
#define QEMU_EBPF_RSS_H
#include "qapi/error.h"
#define EBPF_RSS_MAX_FDS 4
struct EBPFRSSContext {
@ -41,13 +43,15 @@ void ebpf_rss_init(struct EBPFRSSContext *ctx);
bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
bool ebpf_rss_load(struct EBPFRSSContext *ctx);
bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp);
bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
int config_fd, int toeplitz_fd, int table_fd);
int config_fd, int toeplitz_fd, int table_fd,
Error **errp);
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
uint16_t *indirections_table, uint8_t *toeplitz_key);
uint16_t *indirections_table, uint8_t *toeplitz_key,
Error **errp);
void ebpf_rss_unload(struct EBPFRSSContext *ctx);

View File

@ -1,4 +1,10 @@
# See docs/devel/tracing.rst for syntax documentation.
# ebpf-rss.c
ebpf_error(const char *s1, const char *s2) "error in %s: %s"
ebpf_rss_load(void *ctx, int progfd, int cfgfd, int toepfd, int indirfd) "ctx=%p program-fd=%d config-fd=%d toeplitz-fd=%d indirection-fd=%d"
ebpf_rss_load_error(void *ctx) "ctx=%p"
ebpf_rss_mmap(void *ctx, void *cfgptr, void *toepptr, void *indirptr) "ctx=%p config-ptr=%p toeplitz-ptr=%p indirection-ptr=%p"
ebpf_rss_mmap_error(void *ctx, const char *object) "ctx=%p object=%s"
ebpf_rss_open_error(void *ctx) "ctx=%p"
ebpf_rss_set_data(void *ctx, void *cfgptr, void *toepptr, void *indirptr) "ctx=%p config-ptr=%p toeplitz-ptr=%p indirection-ptr=%p"
ebpf_rss_unload(void *ctx) "rss unload ctx=%p"

View File

@ -394,9 +394,11 @@ virtio_net_announce_notify(void) ""
virtio_net_announce_timer(int round) "%d"
virtio_net_handle_announce(int round) "%d"
virtio_net_post_load_device(void)
virtio_net_rss_disable(void)
virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x"
virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d"
virtio_net_rss_load(void *nic, size_t nfds, void *fds) "nic=%p nfds=%zu fds=%p"
virtio_net_rss_attach_ebpf(void *nic, int prog_fd) "nic=%p prog-fd=%d"
virtio_net_rss_disable(void *nic) "nic=%p"
virtio_net_rss_error(void *nic, const char *msg, uint32_t value) "nic=%p msg=%s, value 0x%08x"
virtio_net_rss_enable(void *nic, uint32_t p1, uint16_t p2, uint8_t p3) "nic=%p hashes 0x%x, table of %d, key of %d"
# tulip.c
tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64

View File

@ -1241,6 +1241,7 @@ static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
return false;
}
trace_virtio_net_rss_attach_ebpf(nic, prog_fd);
return nc->info->set_steering_ebpf(nc, prog_fd);
}
@ -1254,7 +1255,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data,
config->default_queue = data->default_queue;
}
static bool virtio_net_attach_epbf_rss(VirtIONet *n)
static bool virtio_net_attach_ebpf_rss(VirtIONet *n)
{
struct EBPFRSSConfig config = {};
@ -1265,7 +1266,8 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n)
rss_data_to_rss_config(&n->rss_data, &config);
if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
n->rss_data.indirections_table, n->rss_data.key)) {
n->rss_data.indirections_table, n->rss_data.key,
NULL)) {
return false;
}
@ -1276,7 +1278,7 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n)
return true;
}
static void virtio_net_detach_epbf_rss(VirtIONet *n)
static void virtio_net_detach_ebpf_rss(VirtIONet *n)
{
virtio_net_attach_ebpf_to_backend(n->nic, -1);
}
@ -1286,8 +1288,8 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
if (n->rss_data.enabled) {
n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
if (n->rss_data.populate_hash) {
virtio_net_detach_epbf_rss(n);
} else if (!virtio_net_attach_epbf_rss(n)) {
virtio_net_detach_ebpf_rss(n);
} else if (!virtio_net_attach_ebpf_rss(n)) {
if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
warn_report("Can't load eBPF RSS for vhost");
} else {
@ -1296,12 +1298,13 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
}
}
trace_virtio_net_rss_enable(n->rss_data.hash_types,
trace_virtio_net_rss_enable(n,
n->rss_data.hash_types,
n->rss_data.indirections_len,
sizeof(n->rss_data.key));
} else {
virtio_net_detach_epbf_rss(n);
trace_virtio_net_rss_disable();
virtio_net_detach_ebpf_rss(n);
trace_virtio_net_rss_disable(n);
}
}
@ -1315,28 +1318,27 @@ static void virtio_net_disable_rss(VirtIONet *n)
virtio_net_commit_rss_config(n);
}
static bool virtio_net_load_ebpf_fds(VirtIONet *n)
static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
{
int fds[EBPF_RSS_MAX_FDS] = { [0 ... EBPF_RSS_MAX_FDS - 1] = -1};
int ret = true;
int i = 0;
if (n->nr_ebpf_rss_fds != EBPF_RSS_MAX_FDS) {
warn_report("Expected %d file descriptors but got %d",
EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds);
return false;
}
error_setg(errp, "Expected %d file descriptors but got %d",
EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds);
return false;
}
for (i = 0; i < n->nr_ebpf_rss_fds; i++) {
fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i],
&error_warn);
fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], errp);
if (fds[i] < 0) {
ret = false;
goto exit;
}
}
ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], errp);
exit:
if (!ret) {
@ -1348,13 +1350,16 @@ exit:
return ret;
}
static bool virtio_net_load_ebpf(VirtIONet *n)
static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
{
bool ret = false;
if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
if (!(n->ebpf_rss_fds && virtio_net_load_ebpf_fds(n))) {
ret = ebpf_rss_load(&n->ebpf_rss);
trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds);
if (n->ebpf_rss_fds) {
ret = virtio_net_load_ebpf_fds(n, errp);
} else {
ret = ebpf_rss_load(&n->ebpf_rss, errp);
}
}
@ -1401,17 +1406,17 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
n->rss_data.indirections_len =
virtio_lduw_p(vdev, &cfg.indirection_table_mask);
n->rss_data.indirections_len++;
if (!do_rss) {
n->rss_data.indirections_len = 1;
n->rss_data.indirections_len = 0;
}
if (!is_power_of_2(n->rss_data.indirections_len)) {
err_msg = "Invalid size of indirection table";
if (n->rss_data.indirections_len >= VIRTIO_NET_RSS_MAX_TABLE_LEN) {
err_msg = "Too large indirection table";
err_value = n->rss_data.indirections_len;
goto error;
}
if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
err_msg = "Too large indirection table";
n->rss_data.indirections_len++;
if (!is_power_of_2(n->rss_data.indirections_len)) {
err_msg = "Invalid size of indirection table";
err_value = n->rss_data.indirections_len;
goto error;
}
@ -1482,7 +1487,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
virtio_net_commit_rss_config(n);
return queue_pairs;
error:
trace_virtio_net_rss_error(err_msg, err_value);
trace_virtio_net_rss_error(n, err_msg, err_value);
virtio_net_disable_rss(n);
return 0;
}
@ -3760,7 +3765,23 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
net_rx_pkt_init(&n->rx_pkt);
if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
virtio_net_load_ebpf(n);
Error *err = NULL;
if (!virtio_net_load_ebpf(n, &err)) {
/*
* If user explicitly gave QEMU RSS FDs to use, then
* failing to use them must be considered a fatal
* error. If no RSS FDs were provided, QEMU is trying
* eBPF on a "best effort" basis only, so report a
* warning and allow fallback to software RSS.
*/
if (n->ebpf_rss_fds) {
error_propagate(errp, err);
} else {
warn_report("unable to load eBPF RSS: %s",
error_get_pretty(err));
error_free(err);
}
}
}
}

View File

@ -2172,8 +2172,14 @@ endif
# libxdp
libxdp = not_found
if not get_option('af_xdp').auto() or have_system
libxdp = dependency('libxdp', required: get_option('af_xdp'),
version: '>=1.4.0', method: 'pkg-config')
if libbpf.found()
libxdp = dependency('libxdp', required: get_option('af_xdp'),
version: '>=1.4.0', method: 'pkg-config')
else
if get_option('af_xdp').enabled()
error('libxdp requested, but libbpf is not available')
endif
endif
endif
# libdw

View File

@ -412,8 +412,7 @@ static void colo_compare_tcp(CompareState *s, Connection *conn)
* can ensure that the packet's payload is acknowledged by
* primary and secondary.
*/
uint32_t min_ack = conn->pack - conn->sack > 0 ?
conn->sack : conn->pack;
uint32_t min_ack = MIN(conn->pack, conn->sack);
pri:
if (g_queue_is_empty(&conn->primary_list)) {

View File

@ -39,7 +39,7 @@ if have_netmap
system_ss.add(files('netmap.c'))
endif
system_ss.add(when: libxdp, if_true: files('af-xdp.c'))
system_ss.add(when: [libxdp, libbpf], if_true: files('af-xdp.c'))
if have_vhost_net_user
system_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c'))

View File

@ -542,6 +542,10 @@ void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
int qemu_get_vnet_hdr_len(NetClientState *nc)
{
if (!nc) {
return 0;
}
return nc->vnet_hdr_len;
}

View File

@ -51,7 +51,7 @@ typedef struct NetStreamState {
guint ioc_write_tag;
SocketReadState rs;
unsigned int send_index; /* number of bytes sent*/
uint32_t reconnect;
uint32_t reconnect_ms;
guint timer_tag;
SocketAddress *addr;
} NetStreamState;
@ -387,10 +387,9 @@ static gboolean net_stream_reconnect(gpointer data)
static void net_stream_arm_reconnect(NetStreamState *s)
{
if (s->reconnect && s->timer_tag == 0) {
if (s->reconnect_ms && s->timer_tag == 0) {
qemu_set_info_str(&s->nc, "connecting");
s->timer_tag = g_timeout_add_seconds(s->reconnect,
net_stream_reconnect, s);
s->timer_tag = g_timeout_add(s->reconnect_ms, net_stream_reconnect, s);
}
}
@ -398,7 +397,7 @@ static int net_stream_client_init(NetClientState *peer,
const char *model,
const char *name,
SocketAddress *addr,
uint32_t reconnect,
uint32_t reconnect_ms,
Error **errp)
{
NetStreamState *s;
@ -412,8 +411,8 @@ static int net_stream_client_init(NetClientState *peer,
s->ioc = QIO_CHANNEL(sioc);
s->nc.link_down = true;
s->reconnect = reconnect;
if (reconnect) {
s->reconnect_ms = reconnect_ms;
if (reconnect_ms) {
s->addr = QAPI_CLONE(SocketAddress, addr);
}
qio_channel_socket_connect_async(sioc, addr,
@ -432,13 +431,24 @@ int net_init_stream(const Netdev *netdev, const char *name,
sock = &netdev->u.stream;
if (!sock->has_server || !sock->server) {
uint32_t reconnect_ms = 0;
if (sock->has_reconnect && sock->has_reconnect_ms) {
error_setg(errp, "'reconnect' and 'reconnect-ms' are mutually "
"exclusive");
return -1;
} else if (sock->has_reconnect_ms) {
reconnect_ms = sock->reconnect_ms;
} else if (sock->has_reconnect) {
reconnect_ms = sock->reconnect * 1000u;
}
return net_stream_client_init(peer, "stream", name, sock->addr,
sock->has_reconnect ? sock->reconnect : 0,
errp);
reconnect_ms, errp);
}
if (sock->has_reconnect) {
error_setg(errp, "'reconnect' option is incompatible with "
"socket in server mode");
if (sock->has_reconnect || sock->has_reconnect_ms) {
error_setg(errp, "'reconnect' and 'reconnect-ms' options are "
"incompatible with socket in server mode");
return -1;
}
return net_stream_server_init(peer, "stream", name, sock->addr, errp);

View File

@ -214,7 +214,7 @@ static int is_tap_win32_dev(const char *guid)
for (;;) {
char enum_name[256];
char unit_string[256];
g_autofree char *unit_string = NULL;
HKEY unit_key;
char component_id_string[] = "ComponentId";
char component_id[256];
@ -239,8 +239,7 @@ static int is_tap_win32_dev(const char *guid)
return FALSE;
}
snprintf (unit_string, sizeof(unit_string), "%s\\%s",
ADAPTER_KEY, enum_name);
unit_string = g_strdup_printf("%s\\%s", ADAPTER_KEY, enum_name);
status = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
@ -315,7 +314,7 @@ static int get_device_guid(
while (!stop)
{
char enum_name[256];
char connection_string[256];
g_autofree char *connection_string = NULL;
HKEY connection_key;
char name_data[256];
DWORD name_type;
@ -338,9 +337,7 @@ static int get_device_guid(
return -1;
}
snprintf(connection_string,
sizeof(connection_string),
"%s\\%s\\Connection",
connection_string = g_strdup_printf("%s\\%s\\Connection",
NETWORK_CONNECTIONS_KEY, enum_name);
status = RegOpenKeyEx(
@ -595,7 +592,7 @@ static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
static int tap_win32_open(tap_win32_overlapped_t **phandle,
const char *preferred_name)
{
char device_path[256];
g_autofree char *device_path = NULL;
char device_guid[0x100];
int rc;
HANDLE handle;
@ -617,7 +614,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
if (rc)
return -1;
snprintf (device_path, sizeof(device_path), "%s%s%s",
device_path = g_strdup_printf("%s%s%s",
USERMODEDEVICEDIR,
device_guid,
TAPSUFFIX);

View File

@ -650,15 +650,26 @@
# attempt a reconnect after the given number of seconds. Setting
# this to zero disables this function. (default: 0) (since 8.0)
#
# @reconnect-ms: For a client socket, if a socket is disconnected, then
# attempt a reconnect after the given number of milliseconds. Setting
# this to zero disables this function. This member is mutually
# exclusive with @reconnect. (default: 0) (Since: 9.2)
#
# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
#
# Features:
#
# @deprecated: Member @reconnect is deprecated. Use @reconnect-ms
# instead.
#
# Since: 7.2
##
{ 'struct': 'NetdevStreamOptions',
'data': {
'addr': 'SocketAddress',
'*server': 'bool',
'*reconnect': 'uint32' } }
'*reconnect': { 'type': 'int', 'features': [ 'deprecated' ] },
'*reconnect-ms': 'int' } }
##
# @NetdevDgramOptions:

View File

@ -1102,7 +1102,7 @@ SRST
external entity that provides the IPMI services.
A connection is made to an external BMC simulator. If you do this,
it is strongly recommended that you use the "reconnect=" chardev
it is strongly recommended that you use the "reconnect-ms=" chardev
option to reconnect to the simulator if the connection is lost. Note
that if this is not used carefully, it can be a security issue, as
the interface has the ability to send resets, NMIs, and power off
@ -2833,9 +2833,9 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
" configure a network backend to connect to another network\n"
" using an UDP tunnel\n"
"-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect=seconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect=seconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect=seconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
" configure a network backend to connect to another network\n"
" using a socket connection in stream mode.\n"
"-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n"
@ -3291,7 +3291,7 @@ SRST
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
-netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect=seconds]``
``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
``server=on|off``
@ -3318,8 +3318,8 @@ SRST
``ipv6=on|off``
whether to accept IPv6 addresses, default to try both IPv4 and IPv6
``reconnect=seconds``
for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of seconds.
``reconnect-ms=milliseconds``
for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of milliseconds.
Setting this to zero disables this function. (default: 0)
Example (two guests connected using a TCP/IP socket):
@ -3333,9 +3333,9 @@ SRST
# second VM
|qemu_system| linux.img \\
-device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
-netdev stream,id=net0,server=off,addr.type=inet,addr.host=localhost,addr.port=1234,reconnect=5
-netdev stream,id=net0,server=off,addr.type=inet,addr.host=localhost,addr.port=1234,reconnect-ms=5000
``-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect=seconds]``
``-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a stream oriented unix domain socket.
``server=on|off``
@ -3350,8 +3350,8 @@ SRST
``tight=on|off``
if false, pad an abstract socket address with enough null bytes to make it fill struct sockaddr_un member sun_path.
``reconnect=seconds``
for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of seconds.
``reconnect-ms=milliseconds``
for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of milliseconds.
Setting this to zero disables this function. (default: 0)
Example (using passt as a replacement of -netdev user):
@ -3377,9 +3377,9 @@ SRST
# second VM
|qemu_system| linux.img \\
-device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
-netdev stream,id=net0,server=off,addr.type=unix,addr.path=/tmp/qemu0,reconnect=5
-netdev stream,id=net0,server=off,addr.type=unix,addr.path=/tmp/qemu0,reconnect-ms=5000
``-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect=seconds]``
``-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a stream oriented socket file descriptor.
``server=on|off``
@ -3388,8 +3388,8 @@ SRST
``addr.str=file-descriptor``
file descriptor number to use as a socket
``reconnect=seconds``
for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of seconds.
``reconnect-ms=milliseconds``
for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of milliseconds.
Setting this to zero disables this function. (default: 0)
``-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]``
@ -3679,9 +3679,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev help\n"
"-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4=on|off][,ipv6=on|off][,nodelay=on|off]\n"
" [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,mux=on|off]\n"
" [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect-ms=milliseconds][,mux=on|off]\n"
" [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n"
"-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds]\n"
"-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect-ms=milliseconds]\n"
" [,mux=on|off][,logfile=PATH][,logappend=on|off][,abstract=on|off][,tight=on|off] (unix)\n"
"-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n"
" [,localport=localport][,ipv4=on|off][,ipv6=on|off][,mux=on|off]\n"
@ -3792,7 +3792,7 @@ The available backends are:
A void device. This device will not emit any data, and will drop any
data it receives. The null backend does not take any options.
``-chardev socket,id=id[,TCP options or unix options][,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,tls-creds=id][,tls-authz=id]``
``-chardev socket,id=id[,TCP options or unix options][,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect-ms=milliseconds][,tls-creds=id][,tls-authz=id]``
Create a two-way stream socket, which can be either a TCP or a unix
socket. A unix socket will be created if ``path`` is specified.
Behaviour is undefined if TCP options are specified for a unix
@ -3809,9 +3809,9 @@ The available backends are:
``websocket=on|off`` specifies that the socket uses WebSocket protocol for
communication.
``reconnect`` sets the timeout for reconnecting on non-server
``reconnect-ms`` sets the timeout for reconnecting on non-server
sockets when the remote end goes away. qemu will delay this many
seconds and then attempt to reconnect. Zero disables reconnecting,
milliseconds and then attempt to reconnect. Zero disables reconnecting,
and is the default.
``tls-creds`` requests enablement of the TLS protocol for
@ -4390,14 +4390,14 @@ SRST
``telnet options:``
localhost 5555
``tcp:[host]:port[,server=on|off][,wait=on|off][,nodelay=on|off][,reconnect=seconds]``
``tcp:[host]:port[,server=on|off][,wait=on|off][,nodelay=on|off][,reconnect-ms=milliseconds]``
The TCP Net Console has two modes of operation. It can send the
serial I/O to a location or wait for a connection from a
location. By default the TCP Net Console is sent to host at the
port. If you use the ``server=on`` option QEMU will wait for a client
socket application to connect to the port before continuing,
unless the ``wait=on|off`` option was specified. The ``nodelay=on|off``
option disables the Nagle buffering algorithm. The ``reconnect=on``
option disables the Nagle buffering algorithm. The ``reconnect-ms``
option only applies if ``server=no`` is set, if the connection goes
down it will attempt to reconnect at the given interval. If host
is omitted, 0.0.0.0 is assumed. Only one TCP connection at a
@ -4427,7 +4427,7 @@ SRST
The WebSocket protocol is used instead of raw tcp socket. The
port acts as a WebSocket server. Client mode is not supported.
``unix:path[,server=on|off][,wait=on|off][,reconnect=seconds]``
``unix:path[,server=on|off][,wait=on|off][,reconnect-ms=milliseconds]``
A unix domain socket is used instead of a tcp socket. The option
works the same as if you had specified ``-serial tcp`` except
the unix domain socket path is used for connections.

View File

@ -411,7 +411,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
global_qtest = qtest_initf(
" -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect=10"
" -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect-ms=10000"
" -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
" -device isa-ipmi-bt,bmc=bmc0", emu_port);
qtest_irq_intercept_in(global_qtest, "ioapic");

View File

@ -204,7 +204,7 @@ static void test_stream_unix_reconnect(void)
qts1 = qtest_initf("-nodefaults -M none "
"-netdev stream,server=false,id=st0,addr.type=unix,"
"addr.path=%s,reconnect=1", path);
"addr.path=%s,reconnect-ms=1000", path);
wait_stream_connected(qts0, "st0", &addr);
g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX);

View File

@ -920,7 +920,7 @@ static void wait_for_rings_started(TestServer *s, size_t count)
static inline void test_server_connect(TestServer *server)
{
test_server_create_chr(server, ",reconnect=1");
test_server_create_chr(server, ",reconnect-ms=1000");
}
static gboolean

View File

@ -1545,18 +1545,18 @@ int main(int argc, char **argv)
static CharSocketClientTestConfig client2 ## name = \
{ addr, NULL, true, false, char_socket_event }; \
static CharSocketClientTestConfig client3 ## name = \
{ addr, ",reconnect=1", false, false, char_socket_event }; \
{ addr, ",reconnect-ms=1000", false, false, char_socket_event }; \
static CharSocketClientTestConfig client4 ## name = \
{ addr, ",reconnect=1", true, false, char_socket_event }; \
{ addr, ",reconnect-ms=1000", true, false, char_socket_event }; \
static CharSocketClientTestConfig client5 ## name = \
{ addr, NULL, false, true, char_socket_event }; \
static CharSocketClientTestConfig client6 ## name = \
{ addr, NULL, true, true, char_socket_event }; \
static CharSocketClientTestConfig client7 ## name = \
{ addr, ",reconnect=1", true, false, \
{ addr, ",reconnect-ms=1000", true, false, \
char_socket_event_with_error }; \
static CharSocketClientTestConfig client8 ## name = \
{ addr, ",reconnect=1", false, false, char_socket_event }; \
{ addr, ",reconnect-ms=1000", false, false, char_socket_event };\
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \