Signed-off-by: Paolo Abeni <pab...@redhat.com>
---
v1 -> v2:
- squashed vhost support into this patch
- dropped tun offload consistency checks; they are implemented in
the kernel side
- virtio_has_tnl_hdr ->virtio_has_tunnel_hdr
---
hw/net/vhost_net.c | 2 ++
hw/net/virtio-net.c | 34 ++++++++++++++++++++++++++--------
include/net/net.h | 2 ++
net/net.c | 3 ++-
net/tap-linux.c | 6 ++++++
5 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index bae595607a..a15dc51d84 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -52,6 +52,8 @@ static const int kernel_feature_bits[] = {
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
};
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 8ed1cad363..ff2f34d98a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -103,6 +103,12 @@
#define VIRTIO_NET_F2O_SHIFT (VIRTIO_NET_OFFLOAD_MAP_MIN - \
VIRTIO_NET_FEATURES_MAP_MIN + 64)
+static bool virtio_has_tunnel_hdr(const uint64_t *features)
+{
+ return virtio_has_feature_ex(features, VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO) |
+ virtio_has_feature_ex(features, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO);
+}
+
static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_NET_F_MAC,
.end = endof(struct virtio_net_config, mac)},
@@ -659,7 +665,8 @@ static bool peer_has_tunnel(VirtIONet *n)
}
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
- int version_1, int hash_report)
+ int version_1, int hash_report,
+ int tunnel)
{
int i;
NetClientState *nc;
@@ -667,9 +674,11 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int
mergeable_rx_bufs,
n->mergeable_rx_bufs = mergeable_rx_bufs;
if (version_1) {
- n->guest_hdr_len = hash_report ?
- sizeof(struct virtio_net_hdr_v1_hash) :
- sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ n->guest_hdr_len = tunnel ?
+ sizeof(struct virtio_net_hdr_v1_hash_tunnel) :
+ (hash_report ?
+ sizeof(struct virtio_net_hdr_v1_hash) :
+ sizeof(struct virtio_net_hdr_mrg_rxbuf));
n->rss_data.populate_hash = !!hash_report;
} else {
n->guest_hdr_len = n->mergeable_rx_bufs ?
@@ -886,6 +895,10 @@ static void virtio_net_apply_guest_offloads(VirtIONet *n)
.ufo = !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_UFO)),
.uso4 = !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_USO4)),
.uso6 = !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_USO6)),
+ .tnl = !!(n->curr_guest_offloads &
+ (1ULL << VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_MAPPED)),
+ .tnl_csum = !!(n->curr_guest_offloads &
+ (1ULL << VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM_MAPPED)),
};
qemu_set_offload(qemu_get_queue(n->nic)->peer, &ol);
@@ -907,7 +920,9 @@ virtio_net_guest_offloads_by_features(const uint64_t
*features)
(1ULL << VIRTIO_NET_F_GUEST_ECN) |
(1ULL << VIRTIO_NET_F_GUEST_UFO) |
(1ULL << VIRTIO_NET_F_GUEST_USO4) |
- (1ULL << VIRTIO_NET_F_GUEST_USO6);
+ (1ULL << VIRTIO_NET_F_GUEST_USO6) |
+ (1ULL << VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_MAPPED) |
+ (1ULL << VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM_MAPPED);
return guest_offloads_mask & virtio_net_features_to_offload(features);
}
@@ -1020,7 +1035,8 @@ static void virtio_net_set_features(VirtIODevice *vdev,
virtio_has_feature_ex(features,
VIRTIO_F_VERSION_1),
virtio_has_feature_ex(features,
- VIRTIO_NET_F_HASH_REPORT));
+ VIRTIO_NET_F_HASH_REPORT),
+ virtio_has_tunnel_hdr(features));
n->rsc4_enabled = virtio_has_feature_ex(features, VIRTIO_NET_F_RSC_EXT) &&
virtio_has_feature_ex(features, VIRTIO_NET_F_GUEST_TSO4);
@@ -3132,13 +3148,15 @@ static int virtio_net_post_load_device(void *opaque,
int version_id)
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
int i, link_down;
+ bool has_tunnel_hdr = virtio_has_tunnel_hdr(vdev->guest_features_array);
trace_virtio_net_post_load_device();
virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs,
virtio_vdev_has_feature(vdev,
VIRTIO_F_VERSION_1),
virtio_vdev_has_feature(vdev,
-
VIRTIO_NET_F_HASH_REPORT));
+
VIRTIO_NET_F_HASH_REPORT),
+ has_tunnel_hdr);
/* MAC_TABLE_ENTRIES may be different from the saved image */
if (n->mac_table.in_use > MAC_TABLE_ENTRIES) {
@@ -3945,7 +3963,7 @@ static void virtio_net_device_realize(DeviceState *dev,
Error **errp)
n->vqs[0].tx_waiting = 0;
n->tx_burst = n->net_conf.txburst;
- virtio_net_set_mrg_rx_bufs(n, 0, 0, 0);
+ virtio_net_set_mrg_rx_bufs(n, 0, 0, 0, 0);
n->promisc = 1; /* for compatibility */
n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
diff --git a/include/net/net.h b/include/net/net.h
index c71d7c6074..5049d293f2 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -43,6 +43,8 @@ typedef struct NetOffloads {
bool ufo;
bool uso4;
bool uso6;
+ bool tnl;
+ bool tnl_csum;
} NetOffloads;
#define DEFINE_NIC_PROPERTIES(_state, _conf) \
diff --git a/net/net.c b/net/net.c
index 5a2f00c108..eb98c8a8b9 100644
--- a/net/net.c
+++ b/net/net.c
@@ -575,7 +575,8 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
len == sizeof(struct virtio_net_hdr) ||
- len == sizeof(struct virtio_net_hdr_v1_hash));
+ len == sizeof(struct virtio_net_hdr_v1_hash) ||
+ len == sizeof(struct virtio_net_hdr_v1_hash_tunnel));
nc->vnet_hdr_len = len;
nc->info->set_vnet_hdr_len(nc, len);
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 4ec638add6..5e6c2d3cbd 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -279,6 +279,12 @@ void tap_fd_set_offload(int fd, const NetOffloads *ol)
if (ol->uso6) {
offload |= TUN_F_USO6;
}
+ if (ol->tnl) {
+ offload |= TUN_F_UDP_TUNNEL_GSO;
+ }
+ if (ol->tnl_csum) {
+ offload |= TUN_F_UDP_TUNNEL_GSO_CSUM;
+ }
}
if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {