aboutsummaryrefslogtreecommitdiff
path: root/net/tap.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tap.c')
-rw-r--r--net/tap.c92
1 files changed, 65 insertions, 27 deletions
diff --git a/net/tap.c b/net/tap.c
index ae1c7e3..abe3b2d 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -42,11 +42,31 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/sockets.h"
+#include "hw/virtio/vhost.h"
#include "net/tap.h"
#include "net/vhost_net.h"
+static const int kernel_feature_bits[] = {
+ VIRTIO_F_NOTIFY_ON_EMPTY,
+ VIRTIO_RING_F_INDIRECT_DESC,
+ VIRTIO_RING_F_EVENT_IDX,
+ VIRTIO_NET_F_MRG_RXBUF,
+ VIRTIO_F_VERSION_1,
+ VIRTIO_NET_F_MTU,
+ VIRTIO_F_IOMMU_PLATFORM,
+ VIRTIO_F_RING_PACKED,
+ VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
+ VIRTIO_F_NOTIFICATION_DATA,
+ VIRTIO_NET_F_RSC_EXT,
+ VIRTIO_NET_F_HASH_REPORT,
+ VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO,
+ VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO,
+ VHOST_INVALID_FEATURE_BIT
+};
+
typedef struct TAPState {
NetClientState nc;
int fd;
@@ -58,6 +78,7 @@ typedef struct TAPState {
bool using_vnet_hdr;
bool has_ufo;
bool has_uso;
+ bool has_tunnel;
bool enabled;
VHostNetState *vhost_net;
unsigned host_vnet_hdr_len;
@@ -172,6 +193,11 @@ static void tap_send(void *opaque)
break;
}
+ if (s->host_vnet_hdr_len && size <= s->host_vnet_hdr_len) {
+ /* Invalid packet */
+ break;
+ }
+
if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {
buf += s->host_vnet_hdr_len;
size -= s->host_vnet_hdr_len;
@@ -223,6 +249,14 @@ static bool tap_has_uso(NetClientState *nc)
return s->has_uso;
}
+static bool tap_has_tunnel(NetClientState *nc)
+{
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
+
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
+ return s->has_tunnel;
+}
+
static bool tap_has_vnet_hdr(NetClientState *nc)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
@@ -262,15 +296,14 @@ static int tap_set_vnet_be(NetClientState *nc, bool is_be)
return tap_fd_set_vnet_be(s->fd, is_be);
}
-static void tap_set_offload(NetClientState *nc, int csum, int tso4,
- int tso6, int ecn, int ufo, int uso4, int uso6)
+static void tap_set_offload(NetClientState *nc, const NetOffloads *ol)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
if (s->fd < 0) {
return;
}
- tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo, uso4, uso6);
+ tap_fd_set_offload(s->fd, ol);
}
static void tap_exit_notify(Notifier *notifier, void *data)
@@ -329,6 +362,18 @@ int tap_get_fd(NetClientState *nc)
return s->fd;
}
+/*
+ * tap_get_vhost_net() can return NULL if a tap net-device backend is
+ * created with 'vhost=off' option, 'vhostforce=off' or no vhost or
+ * vhostforce or vhostfd options at all. Please see net_init_tap_one().
+ */
+static VHostNetState *tap_get_vhost_net(NetClientState *nc)
+{
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
+ return s->vhost_net;
+}
+
/* fd support */
static NetClientInfo net_tap_info = {
@@ -340,6 +385,7 @@ static NetClientInfo net_tap_info = {
.cleanup = tap_cleanup,
.has_ufo = tap_has_ufo,
.has_uso = tap_has_uso,
+ .has_tunnel = tap_has_tunnel,
.has_vnet_hdr = tap_has_vnet_hdr,
.has_vnet_hdr_len = tap_has_vnet_hdr_len,
.set_offload = tap_set_offload,
@@ -347,6 +393,7 @@ static NetClientInfo net_tap_info = {
.set_vnet_le = tap_set_vnet_le,
.set_vnet_be = tap_set_vnet_be,
.set_steering_ebpf = tap_set_steering_ebpf,
+ .get_vhost_net = tap_get_vhost_net,
};
static TAPState *net_tap_fd_init(NetClientState *peer,
@@ -355,6 +402,7 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
int fd,
int vnet_hdr)
{
+ NetOffloads ol = {};
NetClientState *nc;
TAPState *s;
@@ -367,8 +415,9 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
s->using_vnet_hdr = false;
s->has_ufo = tap_probe_has_ufo(s->fd);
s->has_uso = tap_probe_has_uso(s->fd);
+ s->has_tunnel = tap_probe_has_tunnel(s->fd);
s->enabled = true;
- tap_set_offload(&s->nc, 0, 0, 0, 0, 0, 0, 0);
+ tap_set_offload(&s->nc, &ol);
/*
* Make sure host header length is set correctly in tap:
* it might have been modified by another instance of qemu.
@@ -591,8 +640,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
return -1;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fd, false, errp)) {
return -1;
}
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
@@ -693,9 +741,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
error_propagate(errp, err);
goto failed;
}
- if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
- error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
- name, fd);
+ if (!qemu_set_blocking(vhostfd, false, errp)) {
goto failed;
}
} else {
@@ -705,13 +751,17 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
"tap: open vhost char device failed");
goto failed;
}
- if (!g_unix_set_fd_nonblocking(vhostfd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(vhostfd, false, errp)) {
goto failed;
}
}
options.opaque = (void *)(uintptr_t)vhostfd;
options.nvqs = 2;
+ options.feature_bits = kernel_feature_bits;
+ options.get_acked_features = NULL;
+ options.save_acked_features = NULL;
+ options.max_tx_queue_size = 0;
+ options.is_vhost_user = false;
s->vhost_net = vhost_net_init(&options);
if (!s->vhost_net) {
@@ -798,9 +848,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
return -1;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "%s: Can't use file descriptor %d",
- name, fd);
+ if (!qemu_set_blocking(fd, false, errp)) {
close(fd);
return -1;
}
@@ -854,10 +902,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
goto free_fail;
}
- 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);
+ if (!qemu_set_blocking(fd, false, errp)) {
+ ret = -1;
goto free_fail;
}
@@ -910,8 +956,7 @@ free_fail:
return -1;
}
- if (!g_unix_set_fd_nonblocking(fd, true, NULL)) {
- error_setg_errno(errp, errno, "Failed to set FD nonblocking");
+ if (!qemu_set_blocking(fd, false, errp)) {
return -1;
}
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
@@ -980,13 +1025,6 @@ free_fail:
return 0;
}
-VHostNetState *tap_get_vhost_net(NetClientState *nc)
-{
- TAPState *s = DO_UPCAST(TAPState, nc, nc);
- assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
- return s->vhost_net;
-}
-
int tap_enable(NetClientState *nc)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);