Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging
# -----BEGIN PGP SIGNATURE----- # # iQEzBAABCAAdFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmlzZqsACgkQ7wSWWzmN # YhGITAf+I46cGYha4dE7Gepbqnk+/eHxURNhToX2yZwWsRBkn4LEWHxavWzYGhTk # acaVL7zPiHG7S33xSUT7Ie3yrLvbpATAlBsa5xbEKS26KAVIzVtsmMJA6jHyKXUX # RKBoX2zUkveMZCDtU0XSPjf/wzf7LyeFEDk/o9Agl5zzqfU3mfe58Zk+9MkpFJ9Y # HEGgocbW4Kuu65RJzesejbrBw0f3PMq8cfktUJ8rj0o5v5MX58hrijBAbE5JLrxG # Z2u1GvMFR4ZA3e+Mmgu5zg2/AZ4/ZrN9c8moxB9DWLVX8Psz4fJwyYm2Hx0ldhf4 # 4ETQ326nrAZ5REiUTea1FPACBSK7dw== # =TV7k # -----END PGP SIGNATURE----- # gpg: Signature made Fri 23 Jan 2026 11:16:43 PM AEDT # gpg: using RSA key 215D46F48246689EC77F3562EF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication 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: tests/qtest: Add test for filter-redirector rx event opened qtest: add a test to test redirector status change net/filter-redirector: add support for dynamic status on/off switching tests/qtest: add test for filter-buffer interval change net/filter-buffer: make interval change take effect immediately net/tap: rework tap_set_sndbuf() net/tap: tap_set_sndbuf(): add return value net/tap: setup exit notifier only when needed net/tap: rework scripts handling net/tap: pass NULL to net_init_tap_one() in cases when scripts are NULL net/tap: net_init_tap_one(): move parameter checking earlier net/tap: net_init_tap_one(): drop extra error propagation net/tap-linux.c: avoid abort when setting invalid fd Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -159,6 +159,7 @@ static void filter_buffer_set_interval(Object *obj, Visitor *v,
|
||||
Error **errp)
|
||||
{
|
||||
FilterBufferState *s = FILTER_BUFFER(obj);
|
||||
NetFilterState *nf = NETFILTER(obj);
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
@@ -170,6 +171,11 @@ static void filter_buffer_set_interval(Object *obj, Visitor *v,
|
||||
return;
|
||||
}
|
||||
s->interval = value;
|
||||
|
||||
if (nf->netdev && nf->on) {
|
||||
timer_mod(&s->release_timer,
|
||||
qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_buffer_class_init(ObjectClass *oc, const void *data)
|
||||
|
||||
@@ -179,9 +179,16 @@ static void redirector_chr_event(void *opaque, QEMUChrEvent event)
|
||||
MirrorState *s = FILTER_REDIRECTOR(nf);
|
||||
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
if (nf->on) {
|
||||
qemu_chr_fe_set_handlers_full(&s->chr_in, redirector_chr_can_read,
|
||||
redirector_chr_read, redirector_chr_event,
|
||||
NULL, nf, NULL, false, false);
|
||||
}
|
||||
break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, true);
|
||||
qemu_chr_fe_set_handlers_full(&s->chr_in, NULL, NULL, redirector_chr_event,
|
||||
NULL, nf, NULL, false, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -306,9 +313,11 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
|
||||
redirector_chr_read, redirector_chr_event,
|
||||
NULL, nf, NULL, true);
|
||||
if (nf->on) {
|
||||
qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
|
||||
redirector_chr_read, redirector_chr_event,
|
||||
NULL, nf, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->outdev) {
|
||||
@@ -324,6 +333,24 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_redirector_status_changed(NetFilterState *nf, Error **errp)
|
||||
{
|
||||
MirrorState *s = FILTER_REDIRECTOR(nf);
|
||||
|
||||
if (!s->indev) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nf->on) {
|
||||
qemu_chr_fe_set_handlers(&s->chr_in, redirector_chr_can_read,
|
||||
redirector_chr_read, redirector_chr_event,
|
||||
NULL, nf, NULL, true);
|
||||
} else {
|
||||
qemu_chr_fe_set_handlers(&s->chr_in, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
static char *filter_redirector_get_indev(Object *obj, Error **errp)
|
||||
{
|
||||
MirrorState *s = FILTER_REDIRECTOR(obj);
|
||||
@@ -440,6 +467,7 @@ static void filter_redirector_class_init(ObjectClass *oc, const void *data)
|
||||
nfc->setup = filter_redirector_setup;
|
||||
nfc->cleanup = filter_redirector_cleanup;
|
||||
nfc->receive_iov = filter_redirector_receive_iov;
|
||||
nfc->status_changed = filter_redirector_status_changed;
|
||||
}
|
||||
|
||||
static void filter_mirror_init(Object *obj)
|
||||
|
||||
@@ -206,8 +206,9 @@ error:
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
|
||||
bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int tap_probe_vnet_hdr(int fd, Error **errp)
|
||||
|
||||
@@ -143,23 +143,14 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
* Ethernet NICs generally have txqueuelen=1000, so 1Mb is
|
||||
* a good value, given a 1500 byte MTU.
|
||||
*/
|
||||
#define TAP_DEFAULT_SNDBUF 0
|
||||
|
||||
void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
|
||||
bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
|
||||
{
|
||||
int sndbuf;
|
||||
|
||||
sndbuf = !tap->has_sndbuf ? TAP_DEFAULT_SNDBUF :
|
||||
tap->sndbuf > INT_MAX ? INT_MAX :
|
||||
tap->sndbuf;
|
||||
|
||||
if (!sndbuf) {
|
||||
sndbuf = INT_MAX;
|
||||
}
|
||||
|
||||
if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && tap->has_sndbuf) {
|
||||
if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1) {
|
||||
error_setg_errno(errp, errno, "TUNSETSNDBUF ioctl failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int tap_probe_vnet_hdr(int fd, Error **errp)
|
||||
@@ -214,10 +205,11 @@ bool tap_probe_has_tunnel(int fd)
|
||||
|
||||
void tap_fd_set_vnet_hdr_len(int fd, int len)
|
||||
{
|
||||
if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) {
|
||||
fprintf(stderr, "TUNSETVNETHDRSZ ioctl() failed: %s. Exiting.\n",
|
||||
strerror(errno));
|
||||
abort();
|
||||
int ret;
|
||||
|
||||
ret = ioctl(fd, TUNSETVNETHDRSZ, &len);
|
||||
if (ret != 0) {
|
||||
error_report("TUNSETVNETHDRSZ ioctl() failed: %s.", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -208,8 +208,9 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
|
||||
bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int tap_probe_vnet_hdr(int fd, Error **errp)
|
||||
|
||||
@@ -33,8 +33,9 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
|
||||
bool tap_set_sndbuf(int fd, int sndbuf, Error **errp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int tap_probe_vnet_hdr(int fd, Error **errp)
|
||||
|
||||
94
net/tap.c
94
net/tap.c
@@ -91,6 +91,21 @@ static void launch_script(const char *setup_script, const char *ifname,
|
||||
static void tap_send(void *opaque);
|
||||
static void tap_writable(void *opaque);
|
||||
|
||||
static char *tap_parse_script(const char *script_arg, const char *default_path)
|
||||
{
|
||||
g_autofree char *res = g_strdup(script_arg);
|
||||
|
||||
if (!res) {
|
||||
res = get_relocated_path(default_path);
|
||||
}
|
||||
|
||||
if (res[0] == '\0' || strcmp(res, "no") == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&res);
|
||||
}
|
||||
|
||||
static void tap_update_fd_handler(TAPState *s)
|
||||
{
|
||||
qemu_set_fd_handler(s->fd,
|
||||
@@ -311,11 +326,9 @@ static void tap_exit_notify(Notifier *notifier, void *data)
|
||||
TAPState *s = container_of(notifier, TAPState, exit);
|
||||
Error *err = NULL;
|
||||
|
||||
if (s->down_script[0]) {
|
||||
launch_script(s->down_script, s->down_script_arg, s->fd, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
launch_script(s->down_script, s->down_script_arg, s->fd, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,8 +344,11 @@ static void tap_cleanup(NetClientState *nc)
|
||||
|
||||
qemu_purge_queued_packets(nc);
|
||||
|
||||
tap_exit_notify(&s->exit, NULL);
|
||||
qemu_remove_exit_notifier(&s->exit);
|
||||
if (s->exit.notify) {
|
||||
tap_exit_notify(&s->exit, NULL);
|
||||
qemu_remove_exit_notifier(&s->exit);
|
||||
s->exit.notify = NULL;
|
||||
}
|
||||
|
||||
tap_read_poll(s, false);
|
||||
tap_write_poll(s, false);
|
||||
@@ -428,9 +444,6 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
|
||||
tap_read_poll(s, true);
|
||||
s->vhost_net = NULL;
|
||||
|
||||
s->exit.notify = tap_exit_notify;
|
||||
qemu_add_exit_notifier(&s->exit);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -676,9 +689,7 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setup_script &&
|
||||
setup_script[0] != '\0' &&
|
||||
strcmp(setup_script, "no") != 0) {
|
||||
if (setup_script) {
|
||||
launch_script(setup_script, ifname, fd, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
@@ -698,13 +709,14 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
const char *downscript, const char *vhostfdname,
|
||||
int vnet_hdr, int fd, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr);
|
||||
int vhostfd;
|
||||
bool sndbuf_required = tap->has_sndbuf;
|
||||
int sndbuf =
|
||||
(tap->has_sndbuf && tap->sndbuf) ? MIN(tap->sndbuf, INT_MAX) : INT_MAX;
|
||||
|
||||
tap_set_sndbuf(s->fd, tap, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
if (!tap_set_sndbuf(fd, sndbuf, sndbuf_required ? errp : NULL) &&
|
||||
sndbuf_required) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@@ -714,12 +726,14 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
qemu_set_info_str(&s->nc, "helper=%s", tap->helper);
|
||||
} else {
|
||||
qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname,
|
||||
script, downscript);
|
||||
script ?: "no", downscript ?: "no");
|
||||
|
||||
if (strcmp(downscript, "no") != 0) {
|
||||
if (downscript) {
|
||||
snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
|
||||
snprintf(s->down_script_arg, sizeof(s->down_script_arg),
|
||||
"%s", ifname);
|
||||
s->exit.notify = tap_exit_notify;
|
||||
qemu_add_exit_notifier(&s->exit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,9 +750,8 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
}
|
||||
|
||||
if (vhostfdname) {
|
||||
vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, &err);
|
||||
vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, errp);
|
||||
if (vhostfd == -1) {
|
||||
error_propagate(errp, err);
|
||||
goto failed;
|
||||
}
|
||||
if (!qemu_set_blocking(vhostfd, false, errp)) {
|
||||
@@ -768,9 +781,6 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
|
||||
"vhost-net requested but could not be initialized");
|
||||
goto failed;
|
||||
}
|
||||
} else if (vhostfdname) {
|
||||
error_setg(errp, "vhostfd(s)= is not valid without vhost");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -811,8 +821,6 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
const NetdevTapOptions *tap;
|
||||
int fd, vnet_hdr = 0, i = 0, queues;
|
||||
/* for the no-fd, no-helper case */
|
||||
const char *script;
|
||||
const char *downscript;
|
||||
Error *err = NULL;
|
||||
const char *vhostfdname;
|
||||
char ifname[128];
|
||||
@@ -822,8 +830,6 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
tap = &netdev->u.tap;
|
||||
queues = tap->has_queues ? tap->queues : 1;
|
||||
vhostfdname = tap->vhostfd;
|
||||
script = tap->script;
|
||||
downscript = tap->downscript;
|
||||
|
||||
/* QEMU hubs do not support multiqueue tap, in this case peer is set.
|
||||
* For -netdev, peer is always NULL. */
|
||||
@@ -832,6 +838,11 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tap->has_vhost && !tap->vhost && (tap->vhostfds || tap->vhostfd)) {
|
||||
error_setg(errp, "vhostfd(s)= is not valid without vhost");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tap->fd) {
|
||||
if (tap->ifname || tap->script || tap->downscript ||
|
||||
tap->has_vnet_hdr || tap->helper || tap->has_queues ||
|
||||
@@ -859,7 +870,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
}
|
||||
|
||||
net_init_tap_one(tap, peer, "tap", name, NULL,
|
||||
script, downscript,
|
||||
NULL, NULL,
|
||||
vhostfdname, vnet_hdr, fd, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
@@ -920,7 +931,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
||||
}
|
||||
|
||||
net_init_tap_one(tap, peer, "tap", name, ifname,
|
||||
script, downscript,
|
||||
NULL, NULL,
|
||||
tap->vhostfds ? vhost_fds[i] : NULL,
|
||||
vnet_hdr, fd, &err);
|
||||
if (err) {
|
||||
@@ -965,7 +976,7 @@ free_fail:
|
||||
}
|
||||
|
||||
net_init_tap_one(tap, peer, "bridge", name, ifname,
|
||||
script, downscript, vhostfdname,
|
||||
NULL, NULL, vhostfdname,
|
||||
vnet_hdr, fd, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
@@ -973,21 +984,16 @@ free_fail:
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
g_autofree char *default_script = NULL;
|
||||
g_autofree char *default_downscript = NULL;
|
||||
g_autofree char *script =
|
||||
tap_parse_script(tap->script, DEFAULT_NETWORK_SCRIPT);
|
||||
g_autofree char *downscript =
|
||||
tap_parse_script(tap->downscript, DEFAULT_NETWORK_DOWN_SCRIPT);
|
||||
|
||||
if (tap->vhostfds) {
|
||||
error_setg(errp, "vhostfds= is invalid if fds= wasn't specified");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!script) {
|
||||
script = default_script = get_relocated_path(DEFAULT_NETWORK_SCRIPT);
|
||||
}
|
||||
if (!downscript) {
|
||||
downscript = default_downscript =
|
||||
get_relocated_path(DEFAULT_NETWORK_DOWN_SCRIPT);
|
||||
}
|
||||
|
||||
if (tap->ifname) {
|
||||
pstrcpy(ifname, sizeof ifname, tap->ifname);
|
||||
} else {
|
||||
@@ -995,7 +1001,7 @@ free_fail:
|
||||
}
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? "no" : script,
|
||||
fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? NULL : script,
|
||||
ifname, sizeof ifname, queues > 1, errp);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
@@ -1010,8 +1016,8 @@ free_fail:
|
||||
}
|
||||
|
||||
net_init_tap_one(tap, peer, "tap", name, ifname,
|
||||
i >= 1 ? "no" : script,
|
||||
i >= 1 ? "no" : downscript,
|
||||
i >= 1 ? NULL : script,
|
||||
i >= 1 ? NULL : downscript,
|
||||
vhostfdname, vnet_hdr, fd, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#ifndef NET_TAP_INT_H
|
||||
#define NET_TAP_INT_H
|
||||
|
||||
#include "qapi/qapi-types-net.h"
|
||||
#include "net/net.h"
|
||||
|
||||
int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
@@ -34,7 +33,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
|
||||
ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen);
|
||||
|
||||
void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp);
|
||||
bool tap_set_sndbuf(int fd, int sndbuf, Error **errp);
|
||||
int tap_probe_vnet_hdr(int fd, Error **errp);
|
||||
int tap_probe_has_ufo(int fd);
|
||||
int tap_probe_has_uso(int fd);
|
||||
|
||||
Reference in New Issue
Block a user