#include <sys/socket.h>
#include <net/if.h>
+#include "net/eth.h"
#include "net/net.h"
#include "clients.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
{
ssize_t len;
- do {
- len = writev(s->fd, iov, iovcnt);
- } while (len == -1 && errno == EINTR);
+ len = RETRY_ON_EINTR(writev(s->fd, iov, iovcnt));
if (len == -1 && errno == EAGAIN) {
tap_write_poll(s, true);
while (true) {
uint8_t *buf = s->buf;
+ uint8_t min_pkt[ETH_ZLEN];
+ size_t min_pktsz = sizeof(min_pkt);
size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
if (size <= 0) {
size -= s->host_vnet_hdr_len;
}
+ if (net_peer_needs_padding(&s->nc)) {
+ if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) {
+ buf = min_pkt;
+ size = min_pktsz;
+ }
+ }
+
size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
if (size == 0) {
tap_read_poll(s, false);
tap_write_poll(s, enable);
}
+static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
+{
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
+
+ return tap_fd_set_steering_ebpf(s->fd, prog_fd) == 0;
+}
+
int tap_get_fd(NetClientState *nc)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
.set_vnet_hdr_len = tap_set_vnet_hdr_len,
.set_vnet_le = tap_set_vnet_le,
.set_vnet_be = tap_set_vnet_be,
+ .set_steering_ebpf = tap_set_steering_ebpf,
};
static TAPState *net_tap_fd_init(NetClientState *peer,
close(sv[1]);
- do {
- fd = recv_fd(sv[0]);
- } while (fd == -1 && errno == EINTR);
+ fd = RETRY_ON_EINTR(recv_fd(sv[0]));
saved_errno = errno;
close(sv[0]);
const char *helper, *br;
TAPState *s;
int fd, vnet_hdr;
- NetdevBridgeOptions *stored;
assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE);
bridge = &netdev->u.bridge;
- helper = bridge->has_helper ? bridge->helper : NULL;
- br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE;
+ helper = bridge->helper;
+ br = bridge->br ?: DEFAULT_BRIDGE_INTERFACE;
fd = net_bridge_run_helper(helper, br, errp);
if (fd == -1) {
return -1;
}
- qemu_set_nonblock(fd);
+ if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
+ error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ return -1;
+ }
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
if (vnet_hdr < 0) {
close(fd);
}
s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
- /* Store startup parameters */
- s->nc.stored_config = g_new0(NetdevInfo, 1);
- s->nc.stored_config->type = NET_BACKEND_BRIDGE;
- stored = &s->nc.stored_config->u.bridge;
-
- if (br) {
- stored->has_br = true;
- stored->br = g_strdup(br);
- }
-
- if (helper) {
- stored->has_helper = true;
- stored->helper = g_strdup(helper);
- }
+ qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br);
return 0;
}
vnet_hdr_required = 0;
}
- TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required,
+ fd = RETRY_ON_EINTR(tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required,
mq_required, errp));
if (fd < 0) {
return -1;
const char *model, const char *name,
const char *ifname, const char *script,
const char *downscript, const char *vhostfdname,
- int vnet_hdr, int fd, NetdevInfo **common_stored,
- Error **errp)
+ int vnet_hdr, int fd, Error **errp)
{
Error *err = NULL;
TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr);
int vhostfd;
- NetdevTapOptions *stored;
tap_set_sndbuf(s->fd, tap, &err);
if (err) {
error_propagate(errp, err);
- return;
- }
-
- /* Store startup parameters */
- if (!*common_stored) {
- *common_stored = g_new0(NetdevInfo, 1);
- (*common_stored)->type = NET_BACKEND_TAP;
- s->nc.stored_config = *common_stored;
+ goto failed;
}
- stored = &(*common_stored)->u.tap;
-
- if (tap->has_sndbuf && !stored->has_sndbuf) {
- stored->has_sndbuf = true;
- stored->sndbuf = tap->sndbuf;
- }
-
- if (vnet_hdr && !stored->has_vnet_hdr) {
- stored->has_vnet_hdr = true;
- stored->vnet_hdr = true;
- }
-
- if (tap->has_fd || tap->has_fds) {
- if (!stored->has_fds) {
- stored->has_fds = true;
- stored->fds = g_strdup_printf("%d", fd);
- } else {
- char *tmp_s = stored->fds;
- stored->fds = g_strdup_printf("%s:%d", stored->fds, fd);
- g_free(tmp_s);
- }
- } else if (tap->has_helper) {
- if (!stored->has_helper) {
- stored->has_helper = true;
- stored->helper = g_strdup(tap->helper);
- }
- if (!stored->has_br) {
- stored->has_br = true;
- stored->br = tap->has_br ? g_strdup(tap->br) :
- g_strdup(DEFAULT_BRIDGE_INTERFACE);
- }
+ if (tap->fd || tap->fds) {
+ qemu_set_info_str(&s->nc, "fd=%d", fd);
+ } else if (tap->helper) {
+ qemu_set_info_str(&s->nc, "helper=%s", tap->helper);
} else {
- if (ifname && !stored->has_ifname) {
- stored->has_ifname = true;
- stored->ifname = g_strdup(ifname);
- }
-
- if (script && !stored->has_script) {
- stored->has_script = true;
- stored->script = g_strdup(script);
- }
-
- if (downscript && !stored->has_downscript) {
- stored->has_downscript = true;
- stored->downscript = g_strdup(downscript);
- }
+ qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname,
+ script, downscript);
if (strcmp(downscript, "no") != 0) {
snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
VhostNetOptions options;
- stored->has_vhost = true;
- stored->vhost = true;
-
- if (tap->has_vhostforce && tap->vhostforce) {
- stored->has_vhostforce = true;
- stored->vhostforce = true;
- }
-
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
options.net_backend = &s->nc;
if (tap->has_poll_us) {
- stored->has_poll_us = true;
- stored->poll_us = tap->poll_us;
-
options.busyloop_timeout = tap->poll_us;
} else {
options.busyloop_timeout = 0;
}
if (vhostfdname) {
- int ret;
-
vhostfd = monitor_fd_param(monitor_cur(), vhostfdname, &err);
if (vhostfd == -1) {
if (tap->has_vhostforce && tap->vhostforce) {
} else {
warn_report_err(err);
}
- return;
+ goto failed;
}
- ret = qemu_try_set_nonblock(vhostfd);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
+ if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
+ error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
name, fd);
- return;
+ goto failed;
}
} else {
vhostfd = open("/dev/vhost-net", O_RDWR);
warn_report("tap: open vhost char device failed: %s",
strerror(errno));
}
- return;
+ goto failed;
+ }
+ if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
+ error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ goto failed;
}
- qemu_set_nonblock(vhostfd);
}
options.opaque = (void *)(uintptr_t)vhostfd;
-
- if (!stored->has_vhostfds) {
- stored->has_vhostfds = true;
- stored->vhostfds = g_strdup_printf("%d", vhostfd);
- } else {
- char *tmp_s = stored->vhostfds;
- stored->vhostfds = g_strdup_printf("%s:%d", stored->fds, vhostfd);
- g_free(tmp_s);
- }
+ options.nvqs = 2;
s->vhost_net = vhost_net_init(&options);
if (!s->vhost_net) {
} else {
warn_report(VHOST_NET_INIT_FAILED);
}
- return;
+ goto failed;
}
} else if (vhostfdname) {
error_setg(errp, "vhostfd(s)= is not valid without vhost");
+ goto failed;
}
+
+ return;
+
+failed:
+ qemu_del_net_client(&s->nc);
}
static int get_fds(char *str, char *fds[], int max)
const char *vhostfdname;
char ifname[128];
int ret = 0;
- NetdevInfo *common_stored = NULL; /* will store configuration */
assert(netdev->type == NET_CLIENT_DRIVER_TAP);
tap = &netdev->u.tap;
queues = tap->has_queues ? tap->queues : 1;
- vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
- script = tap->has_script ? tap->script : NULL;
- downscript = tap->has_downscript ? tap->downscript : NULL;
+ 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. */
- if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
+ if (peer && (tap->has_queues || tap->fds || tap->vhostfds)) {
error_setg(errp, "Multiqueue tap cannot be used with hubs");
return -1;
}
- if (tap->has_fd) {
- if (tap->has_ifname || tap->has_script || tap->has_downscript ||
- tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
- tap->has_fds || tap->has_vhostfds) {
+ if (tap->fd) {
+ if (tap->ifname || tap->script || tap->downscript ||
+ tap->has_vnet_hdr || tap->helper || tap->has_queues ||
+ tap->fds || tap->vhostfds) {
error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
"helper=, queues=, fds=, and vhostfds= "
"are invalid with fd=");
return -1;
}
- ret = qemu_try_set_nonblock(fd);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
+ if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
+ error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
name, fd);
close(fd);
return -1;
net_init_tap_one(tap, peer, "tap", name, NULL,
script, downscript,
- vhostfdname, vnet_hdr, fd, &common_stored, &err);
+ vhostfdname, vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
close(fd);
return -1;
}
- } else if (tap->has_fds) {
+ } else if (tap->fds) {
char **fds;
char **vhost_fds;
int nfds = 0, nvhosts = 0;
- if (tap->has_ifname || tap->has_script || tap->has_downscript ||
- tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||
- tap->has_vhostfd) {
+ if (tap->ifname || tap->script || tap->downscript ||
+ tap->has_vnet_hdr || tap->helper || tap->has_queues ||
+ tap->vhostfd) {
error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
"helper=, queues=, and vhostfd= "
"are invalid with fds=");
vhost_fds = g_new0(char *, MAX_TAP_QUEUES);
nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
- if (tap->has_vhostfds) {
+ if (tap->vhostfds) {
nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
if (nfds != nvhosts) {
error_setg(errp, "The number of fds passed does not match "
goto free_fail;
}
- ret = qemu_try_set_nonblock(fd);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
+ ret = g_unix_set_fd_nonblocking(fd, true, NULL);
+ if (!ret) {
+ error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
name, fd);
goto free_fail;
}
if (i == 0) {
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
if (vnet_hdr < 0) {
+ ret = -1;
goto free_fail;
}
} else if (vnet_hdr != tap_probe_vnet_hdr(fd, NULL)) {
net_init_tap_one(tap, peer, "tap", name, ifname,
script, downscript,
- tap->has_vhostfds ? vhost_fds[i] : NULL,
- vnet_hdr, fd, &common_stored, &err);
+ tap->vhostfds ? vhost_fds[i] : NULL,
+ vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
ret = -1;
g_free(fds);
g_free(vhost_fds);
return ret;
- } else if (tap->has_helper) {
- if (tap->has_ifname || tap->has_script || tap->has_downscript ||
- tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) {
+ } else if (tap->helper) {
+ if (tap->ifname || tap->script || tap->downscript ||
+ tap->has_vnet_hdr || tap->has_queues || tap->vhostfds) {
error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, "
"queues=, and vhostfds= are invalid with helper=");
return -1;
}
fd = net_bridge_run_helper(tap->helper,
- tap->has_br ?
- tap->br : DEFAULT_BRIDGE_INTERFACE,
+ tap->br ?: DEFAULT_BRIDGE_INTERFACE,
errp);
if (fd == -1) {
return -1;
}
- qemu_set_nonblock(fd);
+ if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
+ error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ return -1;
+ }
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
if (vnet_hdr < 0) {
close(fd);
net_init_tap_one(tap, peer, "bridge", name, ifname,
script, downscript, vhostfdname,
- vnet_hdr, fd, &common_stored, &err);
+ vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
close(fd);
} else {
g_autofree char *default_script = NULL;
g_autofree char *default_downscript = NULL;
- if (tap->has_vhostfds) {
+ if (tap->vhostfds) {
error_setg(errp, "vhostfds= is invalid if fds= wasn't specified");
return -1;
}
get_relocated_path(DEFAULT_NETWORK_DOWN_SCRIPT);
}
- if (tap->has_ifname) {
+ if (tap->ifname) {
pstrcpy(ifname, sizeof ifname, tap->ifname);
} else {
ifname[0] = '\0';
return -1;
}
- if (queues > 1 && i == 0 && !tap->has_ifname) {
+ if (queues > 1 && i == 0 && !tap->ifname) {
if (tap_fd_get_ifname(fd, ifname)) {
error_setg(errp, "Fail to get ifname");
close(fd);
net_init_tap_one(tap, peer, "tap", name, ifname,
i >= 1 ? "no" : script,
i >= 1 ? "no" : downscript,
- vhostfdname, vnet_hdr, fd,
- &common_stored, &err);
+ vhostfdname, vnet_hdr, fd, &err);
if (err) {
error_propagate(errp, err);
close(fd);