net: implement tunnel probing

Tap devices support GSO over UDP tunnel offload. Probe for such
feature in a similar manner to other offloads.

GSO over UDP tunnel needs to be enabled in addition to a "plain"
offload (TSO or USO).

No need to check separately for the outer header checksum offload:
the kernel is going to support both of them or none.

The new features are disabled by default to avoid compat issues,
and could be enabled, after that hw_compat_10_1 will be added,
together with the related compat entries.

Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Tested-by: Lei Yang <leiyang@redhat.com>
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <a987a8a7613cbf33bb2209c7c7f5889b512638a7.1758549625.git.pabeni@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Paolo Abeni 2025-09-22 16:18:27 +02:00 committed by Michael S. Tsirkin
parent 3a7741c3bd
commit fffac04628
10 changed files with 100 additions and 0 deletions

View file

@ -522,6 +522,15 @@ bool qemu_has_uso(NetClientState *nc)
return nc->info->has_uso(nc);
}
bool qemu_has_tunnel(NetClientState *nc)
{
if (!nc || !nc->info->has_tunnel) {
return false;
}
return nc->info->has_tunnel(nc);
}
bool qemu_has_vnet_hdr(NetClientState *nc)
{
if (!nc || !nc->info->has_vnet_hdr) {

View file

@ -225,6 +225,11 @@ int tap_probe_has_uso(int fd)
return 0;
}
bool tap_probe_has_tunnel(int fd)
{
return false;
}
void tap_fd_set_vnet_hdr_len(int fd, int len)
{
}

View file

@ -201,6 +201,17 @@ int tap_probe_has_uso(int fd)
return 1;
}
bool tap_probe_has_tunnel(int fd)
{
unsigned offload;
offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_UDP_TUNNEL_GSO;
if (ioctl(fd, TUNSETOFFLOAD, offload) < 0) {
return false;
}
return true;
}
void tap_fd_set_vnet_hdr_len(int fd, int len)
{
if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) {

View file

@ -53,4 +53,13 @@
#define TUN_F_USO4 0x20 /* I can handle USO for IPv4 packets */
#define TUN_F_USO6 0x40 /* I can handle USO for IPv6 packets */
/* I can handle TSO/USO for UDP tunneled packets */
#define TUN_F_UDP_TUNNEL_GSO 0x080
/*
* I can handle TSO/USO for UDP tunneled packets requiring csum offload for
* the outer header
*/
#define TUN_F_UDP_TUNNEL_GSO_CSUM 0x100
#endif /* QEMU_TAP_LINUX_H */

View file

@ -227,6 +227,11 @@ int tap_probe_has_uso(int fd)
return 0;
}
bool tap_probe_has_tunnel(int fd)
{
return false;
}
void tap_fd_set_vnet_hdr_len(int fd, int len)
{
}

View file

@ -52,6 +52,11 @@ int tap_probe_has_uso(int fd)
return 0;
}
bool tap_probe_has_tunnel(int fd)
{
return false;
}
void tap_fd_set_vnet_hdr_len(int fd, int len)
{
}

View file

@ -76,6 +76,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;
@ -246,6 +247,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);
@ -374,6 +383,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,
@ -403,6 +413,7 @@ 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, &ol);
/*

View file

@ -38,6 +38,7 @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, 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);
bool tap_probe_has_tunnel(int fd);
void tap_fd_set_offload(int fd, const NetOffloads *ol);
void tap_fd_set_vnet_hdr_len(int fd, int len);
int tap_fd_set_vnet_le(int fd, int vnet_is_le);