All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device
@ 2026-08-16  4:34 Nariman Sayed
  2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-08-16  4:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: Nariman Sayed

This series adds automatic detection of the host tap device's MTU
and exposes it to the guest via VIRTIO_NET_F_MTU, addressing
gitlab.com/qemu-project/qemu/-/issues/3155.

Currently, host_mtu= must be set manually on the virtio-net-pci
device, duplicating the MTU already configured on the host's tap
interface. This series adds a new mtu-from-tap boolean property
(default off) that, when enabled, automatically reads the tap
device's MTU via SIOCGIFMTU and uses it for the guest, avoiding
the need to specify the value twice.

The series is split into three patches:
 - patch 1 adds a helper to query a tap fd's host MTU (Linux only,
   with build-safe stubs for BSD/Solaris/stub backends)
 - patch 2 exposes this via NetClientState for use by device models
 - patch 3 adds the new virtio-net property and wires it up,
   including a note on a config-space sizing timing issue
   discovered during testing

Tested manually with a tap device configured for MTU 9000 and an
Alpine Linux guest, confirming the guest correctly negotiates
VIRTIO_NET_F_MTU and reports the expected MTU.

This patch series is part of my effort to get more familiar with
QEMU's networking stack ahead of GSoC 2027.

Nariman Sayed (3):
  net/tap: add tap_fd_get_mtu() to query host tap MTU
  net/tap: expose tap_get_mtu() via NetClientState
  virtio-net: add mtu-from-tap property for automatic MTU detection

 hw/net/virtio-net.c            | 12 ++++++++++++
 include/hw/virtio/virtio-net.h |  1 +
 include/net/tap.h              |  1 +
 net/tap-bsd.c                  |  5 +++++
 net/tap-linux.c                | 30 ++++++++++++++++++++++++++++++
 net/tap-solaris.c              |  5 +++++
 net/tap-stub.c                 |  5 +++++
 net/tap.c                      |  7 +++++++
 net/tap_int.h                  |  1 +
 9 files changed, 67 insertions(+)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU
  2026-08-16  4:34 [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Nariman Sayed
@ 2026-08-16  4:34 ` Nariman Sayed
  2026-08-26 17:17   ` Aniket Sahu
                     ` (2 more replies)
  2026-08-16  4:34 ` [PATCH 2/3] net/tap: expose tap_get_mtu() via NetClientState Nariman Sayed
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-08-16  4:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: Nariman Sayed

Add a helper function to read the host tap device's configured
MTU via SIOCGIFMTU. Since this ioctl requires a socket rather than
the tap character device fd itself, a separate control socket is
opened to perform the query, following the same pattern used by
net/can/can_socketcan.c.

This is implemented for Linux only, with stub implementations
returning -1 for BSD, Solaris, and the tap-stub backend, matching
the existing pattern used by tap_fd_get_ifname() and
tap_fd_set_steering_ebpf() in those files.

This is a preparatory patch; the function is not yet called from
anywhere.

Signed-off-by: Nariman Sayed <narimansayed28@gmail.com>
---
 net/tap-bsd.c     |  5 +++++
 net/tap-linux.c   | 30 ++++++++++++++++++++++++++++++
 net/tap-solaris.c |  5 +++++
 net/tap-stub.c    |  5 +++++
 net/tap_int.h     |  1 +
 5 files changed, 46 insertions(+)

diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index c39daf9385..17cedccf9e 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -264,6 +264,11 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return -1;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    return -1;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     return -1;
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 3cd7d26710..23a10151c1 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -34,6 +34,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
+#include "qemu/sockets.h"
 
 #define PATH_NET_TUN "/dev/net/tun"
 
@@ -346,6 +347,35 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return 0;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    struct ifreq ifr;
+    int s, ret, mtu;
+
+    memset(&ifr, 0, sizeof(ifr));
+    if (tap_fd_get_ifname(fd, ifr.ifr_name) != 0) {
+        return -1;
+    }
+
+    s = qemu_socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        error_report("could not create control socket: %s",
+                      strerror(errno));
+        return -1;
+    }
+
+    ret = ioctl(s, SIOCGIFMTU, &ifr);
+    if (ret != 0) {
+        error_report("SIOCGIFMTU ioctl() failed: %s", strerror(errno));
+        close(s);
+        return -1;
+    }
+
+    mtu = ifr.ifr_mtu;
+    close(s);
+    return mtu;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     if (ioctl(fd, TUNSETSTEERINGEBPF, (void *) &prog_fd) != 0) {
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index 8704b1084b..d3bd6e6b48 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -266,6 +266,11 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return -1;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    return -1;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     return -1;
diff --git a/net/tap-stub.c b/net/tap-stub.c
index 6aa60d96ad..756ce882a7 100644
--- a/net/tap-stub.c
+++ b/net/tap-stub.c
@@ -91,6 +91,11 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return -1;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    return -1;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     return -1;
diff --git a/net/tap_int.h b/net/tap_int.h
index dc4f484006..360d61c889 100644
--- a/net/tap_int.h
+++ b/net/tap_int.h
@@ -45,6 +45,7 @@ int tap_fd_set_vnet_be(int fd, int vnet_is_be);
 int tap_fd_enable(int fd);
 int tap_fd_disable(int fd);
 int tap_fd_get_ifname(int fd, char *ifname);
+int tap_fd_get_mtu(int fd);
 int tap_fd_set_steering_ebpf(int fd, int prog_fd);
 
 #endif /* NET_TAP_INT_H */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] net/tap: expose tap_get_mtu() via NetClientState
  2026-08-16  4:34 [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Nariman Sayed
  2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
@ 2026-08-16  4:34 ` Nariman Sayed
  2026-08-16  4:34 ` [PATCH 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection Nariman Sayed
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-08-16  4:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: Nariman Sayed

Add a public tap_get_mtu() function, following the same pattern
as the existing tap_get_fd(), to allow other subsystems (such as
virtio-net) to query a tap netdev's host MTU via its
NetClientState without depending on tap-internal headers.

This is a preparatory patch; the function is not yet called from
anywhere.

Signed-off-by: Nariman Sayed <narimansayed28@gmail.com>
---
 include/net/tap.h | 1 +
 net/tap.c         | 7 +++++++
 2 files changed, 8 insertions(+)

diff --git a/include/net/tap.h b/include/net/tap.h
index 6f34f13eae..6b478acbfb 100644
--- a/include/net/tap.h
+++ b/include/net/tap.h
@@ -32,5 +32,6 @@ int tap_enable(NetClientState *nc);
 int tap_disable(NetClientState *nc);
 
 int tap_get_fd(NetClientState *nc);
+int tap_get_mtu(NetClientState *nc);
 
 #endif /* QEMU_NET_TAP_H */
diff --git a/net/tap.c b/net/tap.c
index 57ffb09885..122319d5f3 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -379,6 +379,13 @@ int tap_get_fd(NetClientState *nc)
     return s->fd;
 }
 
+int tap_get_mtu(NetClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
+    return tap_fd_get_mtu(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
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection
  2026-08-16  4:34 [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Nariman Sayed
  2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
  2026-08-16  4:34 ` [PATCH 2/3] net/tap: expose tap_get_mtu() via NetClientState Nariman Sayed
@ 2026-08-16  4:34 ` Nariman Sayed
  2026-08-24 13:40 ` [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Stefan Hajnoczi
  2026-10-07  5:07 ` [PATCH v2 " Nariman Sayed
  4 siblings, 0 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-08-16  4:34 UTC (permalink / raw)
  To: qemu-devel; +Cc: Nariman Sayed

Currently, exposing the host tap device's MTU to the guest via
VIRTIO_NET_F_MTU requires manually specifying host_mtu= on the
virtio-net-pci device, duplicating the MTU already configured on
the host's tap interface.

Add a new mtu-from-tap boolean property (default off, preserving
existing behavior). When enabled and the device's netdev peer is
a tap client, the host tap's MTU is queried via tap_get_mtu() and
used to set net_conf.mtu and enable VIRTIO_NET_F_MTU.

This detection must happen in virtio_net_device_realize(), before
virtio_net_set_config_size() computes the virtio config space
size from host_features. Performing the detection later (e.g. in
the get_features_ex() callback, which runs after the NIC and its
config space are already sized) results in the mtu config field
falling outside the sized config space, and the guest reading
back an unmapped garbage value (0xffff) instead of the intended
MTU.

Since qemu_new_nic() has not yet been called at this point in
realize(), the tap peer is accessed via n->nic_conf.peers.ncs[0]
(populated during property parsing, before realize() runs, via
the netdev= property) rather than through n->nic.

Signed-off-by: Nariman Sayed <narimansayed28@gmail.com>
---
 hw/net/virtio-net.c            | 12 ++++++++++++
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 13 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 814b99a43d..6faeca87d4 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3901,6 +3901,17 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
         n->host_features |= (1ULL << VIRTIO_NET_F_MTU);
     }
 
+    if (n->net_conf.mtu_from_tap) {
+        NetClientState *tap_peer = n->nic_conf.peers.ncs[0];
+        if (tap_peer && tap_peer->info->type == NET_CLIENT_DRIVER_TAP) {
+            int mtu = tap_get_mtu(tap_peer);
+            if (mtu > 0) {
+                n->net_conf.mtu = mtu;
+                n->host_features |= (1ULL << VIRTIO_NET_F_MTU);
+            }
+        }
+    }
+
     if (n->net_conf.duplex_str) {
         if (strncmp(n->net_conf.duplex_str, "half", 5) == 0) {
             n->net_conf.duplex = DUPLEX_HALF;
@@ -4275,6 +4286,7 @@ static const Property virtio_net_properties[] = {
     DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size,
                        VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE),
     DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0),
+    DEFINE_PROP_BOOL("mtu-from-tap", VirtIONet, net_conf.mtu_from_tap, false),
     DEFINE_PROP_INT32("speed", VirtIONet, net_conf.speed, SPEED_UNKNOWN),
     DEFINE_PROP_STRING("duplex", VirtIONet, net_conf.duplex_str),
     DEFINE_PROP_BOOL("failover", VirtIONet, failover, false),
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 371e376428..11044b6d27 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -52,6 +52,7 @@ typedef struct virtio_net_conf
     uint16_t rx_queue_size;
     uint16_t tx_queue_size;
     uint16_t mtu;
+    bool mtu_from_tap;
     int32_t speed;
     char *duplex_str;
     uint8_t duplex;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device
  2026-08-16  4:34 [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Nariman Sayed
                   ` (2 preceding siblings ...)
  2026-08-16  4:34 ` [PATCH 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection Nariman Sayed
@ 2026-08-24 13:40 ` Stefan Hajnoczi
  2026-10-07  5:07 ` [PATCH v2 " Nariman Sayed
  4 siblings, 0 replies; 12+ messages in thread
From: Stefan Hajnoczi @ 2026-08-24 13:40 UTC (permalink / raw)
  To: Nariman Sayed; +Cc: qemu-devel, jasowangio

On Sun, Aug 16, 2026 at 7:50 AM Nariman Sayed <narimansayed28@gmail.com> wrote:
>
> This series adds automatic detection of the host tap device's MTU
> and exposes it to the guest via VIRTIO_NET_F_MTU, addressing
> gitlab.com/qemu-project/qemu/-/issues/3155.
>
> Currently, host_mtu= must be set manually on the virtio-net-pci
> device, duplicating the MTU already configured on the host's tap
> interface. This series adds a new mtu-from-tap boolean property
> (default off) that, when enabled, automatically reads the tap
> device's MTU via SIOCGIFMTU and uses it for the guest, avoiding
> the need to specify the value twice.
>
> The series is split into three patches:
>  - patch 1 adds a helper to query a tap fd's host MTU (Linux only,
>    with build-safe stubs for BSD/Solaris/stub backends)
>  - patch 2 exposes this via NetClientState for use by device models
>  - patch 3 adds the new virtio-net property and wires it up,
>    including a note on a config-space sizing timing issue
>    discovered during testing
>
> Tested manually with a tap device configured for MTU 9000 and an
> Alpine Linux guest, confirming the guest correctly negotiates
> VIRTIO_NET_F_MTU and reports the expected MTU.
>
> This patch series is part of my effort to get more familiar with
> QEMU's networking stack ahead of GSoC 2027.
>
> Nariman Sayed (3):
>   net/tap: add tap_fd_get_mtu() to query host tap MTU
>   net/tap: expose tap_get_mtu() via NetClientState
>   virtio-net: add mtu-from-tap property for automatic MTU detection
>
>  hw/net/virtio-net.c            | 12 ++++++++++++
>  include/hw/virtio/virtio-net.h |  1 +
>  include/net/tap.h              |  1 +
>  net/tap-bsd.c                  |  5 +++++
>  net/tap-linux.c                | 30 ++++++++++++++++++++++++++++++
>  net/tap-solaris.c              |  5 +++++
>  net/tap-stub.c                 |  5 +++++
>  net/tap.c                      |  7 +++++++
>  net/tap_int.h                  |  1 +
>  9 files changed, 67 insertions(+)

CCing Jason Wang, network subsystem maintainer, so he can review this
patch series.

Stefan


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU
  2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
@ 2026-08-26 17:17   ` Aniket Sahu
  2026-09-17 10:28   ` Eugenio Pérez
  2026-09-17 10:28   ` Eugenio Pérez
  2 siblings, 0 replies; 12+ messages in thread
From: Aniket Sahu @ 2026-08-26 17:17 UTC (permalink / raw)
  To: Nariman Sayed, qemu-devel; +Cc: asahu1x

On Fri, Aug 16, 2026 at 04:34:48AM +0000, Nariman Sayed wrote:
 > This series adds automatic detection of the host tap device's MTU and
 > exposes it to the guest via the VIRTIO_NET_F_MTU feature flag.

Thanks for this patch Nariman. Please feel free to add:

Tested-by: Aniket Sahu <asahu1x@linux.ibm.com>

I've tested this patch series on ppc64le (POWER10 LPAR) and can confirm
the mtu-from-tap feature works as you have described it.

Test environment:
- Host: Ubuntu 26.04 ppc64le on POWER10 LPAR
- Guest: SLES 16.1 RC2 (kernel 7.2.0-rc7)
- QEMU: Built from master with this patch series applied
- Tap device: tap-test with MTU 9000
    root@ltcden6-lp4:~# ip link show tap-test
    4: tap-test: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc 
fq_codel state UP mode DEFAULT group default qlen 1000
       link/ether 9a:81:53:15:e9:cb brd ff:ff:ff:ff:ff:ff

Test results:

1. Control (without mtu-from-tap):
    Command: qemu-system-ppc64 -machine pseries -cpu POWER10 -m 10G -smp 8 \
             -accel kvm -netdev bridge,id=net0,br=virbr0 \
             -device virtio-net-pci,netdev=net0

    Guest MTU: 1500 (default)

    Guest console output:
    Welcome to SUSE Linux Enterprise Server 16.1 012-RC2 (ppc64le) - 
Kernel 7.2.0-rc7-160099.47-default+ (hvc0).

    enp0s2: 192.168.122.203



    localhost login: root
    Password:
    Last login: Wed Aug 26 18:52:47 CEST 2026 on hvc0
    Have a lot of fun...
    localhost:~ #
    localhost:~ #
    localhost:~ #
    localhost:~ # ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
group default qlen 1000
       link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
       inet 127.0.0.1/8 scope host lo
          valid_lft forever preferred_lft forever
       inet6 ::1/128 scope host noprefixroute
          valid_lft forever preferred_lft forever
    2: enp0s2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc 
pfifo_fast state UP group default qlen 1000
       link/ether 52:54:00:b2:6a:47 brd ff:ff:ff:ff:ff:ff
       altname enx525400b26a47
       inet 192.168.122.203/24 brd 192.168.122.255 scope global dynamic 
noprefixroute enp0s2
          valid_lft 3585sec preferred_lft 3585sec
       inet6 fe80::5054:ff:feb2:6a47/64 scope link noprefixroute
          valid_lft forever preferred_lft forever

2. With mtu-from-tap=on:
    Command: qemu-system-ppc64 -machine pseries -cpu POWER10 -m 10G -smp 8 \
             -accel kvm -netdev 
tap,id=net0,ifname=tap-test,script=no,downscript=no \
             -device virtio-net-pci,netdev=net0,mtu-from-tap=on

    Guest MTU: 9000 (correctly auto-detected from host tap device)

    Guest console output:
    Welcome to SUSE Linux Enterprise Server 16.1 012-RC2 (ppc64le) - 
Kernel 7.2.0-rc7-160099.47-default+ (hvc0).

    enp0s2: fe80::5054:ff:feb2:6a47%enp0s2



    localhost login: root
    Password:
    Last login: Wed Aug 26 18:58:22 CEST 2026 on hvc0
    Have a lot of fun...
    localhost:~ # ip link show eth0
    Device "eth0" does not exist.
    localhost:~ # ip link show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
mode DEFAULT group default qlen 1000
       link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: enp0s2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc 
pfifo_fast state UP mode DEFAULT group default qlen 1000
       link/ether 52:54:00:b2:6a:47 brd ff:ff:ff:ff:ff:ff
       altname enx525400b26a47
    localhost:~ #

The guest successfully negotiated VIRTIO_NET_F_MTU and inherited the MTU
from the host tap device without requiring manual host_mtu= configuration.

Thanks,
Aniket



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU
  2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
  2026-08-26 17:17   ` Aniket Sahu
@ 2026-09-17 10:28   ` Eugenio Pérez
  2026-09-17 10:28   ` Eugenio Pérez
  2 siblings, 0 replies; 12+ messages in thread
From: Eugenio Pérez @ 2026-09-17 10:28 UTC (permalink / raw)
  To: Nariman Sayed; +Cc: qemu-devel, Stefan Hajnoczi

Good feature! I'm sorry, the series fell through the cracks.

On Sun, 16 Aug 2026 at 07:34:49 +0300, Nariman Sayed wrote:
> +    if (n->net_conf.mtu_from_tap) {
> +        NetClientState *tap_peer = n->nic_conf.peers.ncs[0];
> +        if (tap_peer && tap_peer->info->type == NET_CLIENT_DRIVER_TAP) {
> +            int mtu = tap_get_mtu(tap_peer);
> +            if (mtu > 0) {
> +                n->net_conf.mtu = mtu;
> +                n->host_features |= (1ULL << VIRTIO_NET_F_MTU);
> +            }
> +        }
> +    }

The series looks good, but this part should not check for the backend type.
Instead, rename the callback as get_mtu and call peer->get_mtu, so if we add
the feature to other backends like vhost-user or vhost-vdpa this part of the
code does not need to be modified.

Thanks!



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU
  2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
  2026-08-26 17:17   ` Aniket Sahu
  2026-09-17 10:28   ` Eugenio Pérez
@ 2026-09-17 10:28   ` Eugenio Pérez
  2 siblings, 0 replies; 12+ messages in thread
From: Eugenio Pérez @ 2026-09-17 10:28 UTC (permalink / raw)
  To: Nariman Sayed; +Cc: qemu-devel, Stefan Hajnoczi

From: Eugenio Perez Martin <eperezma@redhat.com>


Good feature! I'm sorry, all of the series fell through the cracks.

On Sun, 16 Aug 2026 at 07:34:49 +0300, Nariman Sayed wrote:
> +    if (n->net_conf.mtu_from_tap) {
> +        NetClientState *tap_peer = n->nic_conf.peers.ncs[0];
> +        if (tap_peer && tap_peer->info->type == NET_CLIENT_DRIVER_TAP) {
> +            int mtu = tap_get_mtu(tap_peer);
> +            if (mtu > 0) {
> +                n->net_conf.mtu = mtu;
> +                n->host_features |= (1ULL << VIRTIO_NET_F_MTU);
> +            }
> +        }
> +    }

The series looks good, but this part should not check for the backend type.
Instead, rename the callback as get_mtu and call peer->get_mtu, so if we add
the feature to other backends like vhost-user or vhost-vdpa this part of the
code does not need to be modified.

Good addition by the way :).

Thanks!



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 0/3] net/tap, virtio-net: auto-detect MTU from host tap device
  2026-08-16  4:34 [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Nariman Sayed
                   ` (3 preceding siblings ...)
  2026-08-24 13:40 ` [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Stefan Hajnoczi
@ 2026-10-07  5:07 ` Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
                     ` (2 more replies)
  4 siblings, 3 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-10-07  5:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jason Wang, Michael S . Tsirkin, Nariman Sayed

This series adds automatic detection of the host tap device's MTU
and exposes it to the guest via VIRTIO_NET_F_MTU, addressing
gitlab.com/qemu-project/qemu/-/issues/3155.

Currently, host_mtu= must be set manually on the virtio-net-pci
device, duplicating the MTU already configured on the host's tap
interface. This series adds a new mtu-from-tap boolean property
(default off) that, when enabled, automatically reads the backend's
MTU and uses it for the guest, avoiding the need to specify the
value twice.

v2:
 - Addressed feedback from Eugenio Perez Martin: rather than
   checking for NET_CLIENT_DRIVER_TAP and calling tap_get_mtu()
   directly, added a generic get_mtu callback to NetClientInfo and
   a qemu_get_mtu() wrapper, following the existing qemu_has_ufo()
   pattern. virtio-net.c now calls qemu_get_mtu() without any
   backend-type check, so other backends (e.g. vhost-user,
   vhost-vdpa) can implement get_mtu in the future without
   requiring any change to virtio-net.c. (patch 2 is new as a
   result; patch 3 updated accordingly)

The series is split into three patches:
 - patch 1 adds a helper to query a tap fd's host MTU (Linux only,
   with build-safe stubs for BSD/Solaris/stub backends)
 - patch 2 adds a generic get_mtu NetClientInfo callback and wires
   it up for the tap backend
 - patch 3 adds the new virtio-net property and wires it up,
   including a note on a config-space sizing timing issue
   discovered during testing

Tested manually with a tap device configured for MTU 9000 and an
Alpine Linux guest, confirming the guest correctly negotiates
VIRTIO_NET_F_MTU and reports the expected MTU. Also tested by
Aniket Sahu on ppc64le/POWER10 with a SLES guest.

Nariman Sayed (3):
  net/tap: add tap_fd_get_mtu() to query host tap MTU
  net: add generic get_mtu NetClientInfo callback
  virtio-net: add mtu-from-tap property for automatic MTU detection

 hw/net/virtio-net.c            | 10 ++++++++++
 include/hw/virtio/virtio-net.h |  1 +
 include/net/net.h              |  3 +++
 net/net.c                      |  9 +++++++++
 net/tap-bsd.c                  |  5 +++++
 net/tap-linux.c                | 30 ++++++++++++++++++++++++++++++
 net/tap-solaris.c              |  5 +++++
 net/tap-stub.c                 |  5 +++++
 net/tap.c                      |  8 ++++++++
 net/tap_int.h                  |  1 +
 10 files changed, 77 insertions(+)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU
  2026-10-07  5:07 ` [PATCH v2 " Nariman Sayed
@ 2026-10-07  5:07   ` Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 2/3] net: add generic get_mtu NetClientInfo callback Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection Nariman Sayed
  2 siblings, 0 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-10-07  5:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jason Wang, Michael S . Tsirkin, Nariman Sayed

Add a helper function to read the host tap device's configured
MTU via SIOCGIFMTU. Since this ioctl requires a socket rather than
the tap character device fd itself, a separate control socket is
opened to perform the query, following the same pattern used by
net/can/can_socketcan.c.

This is implemented for Linux only, with stub implementations
returning -1 for BSD, Solaris, and the tap-stub backend, matching
the existing pattern used by tap_fd_get_ifname() and
tap_fd_set_steering_ebpf() in those files.

This is a preparatory patch; the function is not yet called from
anywhere.

Signed-off-by: Nariman Sayed <narimansayed28@gmail.com>
---
 net/tap-bsd.c     |  5 +++++
 net/tap-linux.c   | 30 ++++++++++++++++++++++++++++++
 net/tap-solaris.c |  5 +++++
 net/tap-stub.c    |  5 +++++
 net/tap_int.h     |  1 +
 5 files changed, 46 insertions(+)

diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index c39daf9385..17cedccf9e 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -264,6 +264,11 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return -1;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    return -1;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     return -1;
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 3cd7d26710..23a10151c1 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -34,6 +34,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
+#include "qemu/sockets.h"
 
 #define PATH_NET_TUN "/dev/net/tun"
 
@@ -346,6 +347,35 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return 0;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    struct ifreq ifr;
+    int s, ret, mtu;
+
+    memset(&ifr, 0, sizeof(ifr));
+    if (tap_fd_get_ifname(fd, ifr.ifr_name) != 0) {
+        return -1;
+    }
+
+    s = qemu_socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        error_report("could not create control socket: %s",
+                      strerror(errno));
+        return -1;
+    }
+
+    ret = ioctl(s, SIOCGIFMTU, &ifr);
+    if (ret != 0) {
+        error_report("SIOCGIFMTU ioctl() failed: %s", strerror(errno));
+        close(s);
+        return -1;
+    }
+
+    mtu = ifr.ifr_mtu;
+    close(s);
+    return mtu;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     if (ioctl(fd, TUNSETSTEERINGEBPF, (void *) &prog_fd) != 0) {
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
index 8704b1084b..d3bd6e6b48 100644
--- a/net/tap-solaris.c
+++ b/net/tap-solaris.c
@@ -266,6 +266,11 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return -1;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    return -1;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     return -1;
diff --git a/net/tap-stub.c b/net/tap-stub.c
index 6aa60d96ad..756ce882a7 100644
--- a/net/tap-stub.c
+++ b/net/tap-stub.c
@@ -91,6 +91,11 @@ int tap_fd_get_ifname(int fd, char *ifname)
     return -1;
 }
 
+int tap_fd_get_mtu(int fd)
+{
+    return -1;
+}
+
 int tap_fd_set_steering_ebpf(int fd, int prog_fd)
 {
     return -1;
diff --git a/net/tap_int.h b/net/tap_int.h
index dc4f484006..360d61c889 100644
--- a/net/tap_int.h
+++ b/net/tap_int.h
@@ -45,6 +45,7 @@ int tap_fd_set_vnet_be(int fd, int vnet_is_be);
 int tap_fd_enable(int fd);
 int tap_fd_disable(int fd);
 int tap_fd_get_ifname(int fd, char *ifname);
+int tap_fd_get_mtu(int fd);
 int tap_fd_set_steering_ebpf(int fd, int prog_fd);
 
 #endif /* NET_TAP_INT_H */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 2/3] net: add generic get_mtu NetClientInfo callback
  2026-10-07  5:07 ` [PATCH v2 " Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
@ 2026-10-07  5:07   ` Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection Nariman Sayed
  2 siblings, 0 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-10-07  5:07 UTC (permalink / raw)
  To: qemu-devel
  Cc: Jason Wang, Michael S . Tsirkin, Nariman Sayed,
	Eugenio Perez Martin

Add a get_mtu callback to NetClientInfo, along with a qemu_get_mtu()
wrapper following the existing qemu_has_ufo()-style pattern, so that
device models can query a netdev backend's host MTU generically
without needing to know or check its backend type.

Wire this up for the tap backend via tap_get_mtu(), which is now
static and only referenced through net_tap_info.get_mtu, matching
the existing pattern used by tap_has_ufo() and similar callbacks.

This allows other backends (e.g. vhost-user, vhost-vdpa) to
implement get_mtu in the future without requiring changes to any
code that calls qemu_get_mtu().

Suggested-by: Eugenio Perez Martin <eperezma@redhat.com>
Signed-off-by: Nariman Sayed <narimansayed28@gmail.com>
---
 include/net/net.h | 3 +++
 net/net.c         | 9 +++++++++
 net/tap.c         | 8 ++++++++
 3 files changed, 20 insertions(+)

diff --git a/include/net/net.h b/include/net/net.h
index 9edfacf827..ed06814644 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -72,6 +72,7 @@ typedef bool (HasVnetHdr)(NetClientState *);
 typedef bool (HasVnetHdrLen)(NetClientState *, int);
 typedef void (SetOffload)(NetClientState *, const NetOffloads *);
 typedef int (GetVnetHdrLen)(NetClientState *);
+typedef int (GetMtu)(NetClientState *);
 typedef void (SetVnetHdrLen)(NetClientState *, int);
 typedef bool (GetVnetHashSupportedTypes)(NetClientState *, uint32_t *);
 typedef int (SetVnetLE)(NetClientState *, bool);
@@ -110,6 +111,7 @@ typedef struct NetClientInfo {
     SetSteeringEBPF *set_steering_ebpf;
     NetCheckPeerType *check_peer_type;
     GetVHostNet *get_vhost_net;
+    GetMtu *get_mtu;
 } NetClientInfo;
 
 struct NetClientState {
@@ -204,6 +206,7 @@ bool qemu_has_uso(NetClientState *nc);
 bool qemu_has_tunnel(NetClientState *nc);
 bool qemu_has_vnet_hdr(NetClientState *nc);
 bool qemu_has_vnet_hdr_len(NetClientState *nc, int len);
+int qemu_get_mtu(NetClientState *nc);
 void qemu_set_offload(NetClientState *nc, const NetOffloads *ol);
 int qemu_get_vnet_hdr_len(NetClientState *nc);
 void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
diff --git a/net/net.c b/net/net.c
index 0a30579ca4..9fb70e412a 100644
--- a/net/net.c
+++ b/net/net.c
@@ -514,6 +514,15 @@ bool qemu_has_ufo(NetClientState *nc)
     return nc->info->has_ufo(nc);
 }
 
+int qemu_get_mtu(NetClientState *nc)
+{
+    if (!nc || !nc->info->get_mtu) {
+        return -1;
+    }
+
+    return nc->info->get_mtu(nc);
+}
+
 bool qemu_has_uso(NetClientState *nc)
 {
     if (!nc || !nc->info->has_uso) {
diff --git a/net/tap.c b/net/tap.c
index 57ffb09885..89cec2accd 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -379,6 +379,13 @@ int tap_get_fd(NetClientState *nc)
     return s->fd;
 }
 
+static int tap_get_mtu(NetClientState *nc)
+{
+    TAPState *s = DO_UPCAST(TAPState, nc, nc);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
+    return tap_fd_get_mtu(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
@@ -411,6 +418,7 @@ static NetClientInfo net_tap_info = {
     .set_vnet_be = tap_set_vnet_be,
     .set_steering_ebpf = tap_set_steering_ebpf,
     .get_vhost_net = tap_get_vhost_net,
+    .get_mtu = tap_get_mtu,
 };
 
 static TAPState *net_tap_fd_init(NetClientState *peer,
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection
  2026-10-07  5:07 ` [PATCH v2 " Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
  2026-10-07  5:07   ` [PATCH v2 2/3] net: add generic get_mtu NetClientInfo callback Nariman Sayed
@ 2026-10-07  5:07   ` Nariman Sayed
  2 siblings, 0 replies; 12+ messages in thread
From: Nariman Sayed @ 2026-10-07  5:07 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jason Wang, Michael S . Tsirkin, Nariman Sayed, Aniket Sahu

Currently, exposing the host tap device's MTU to the guest via
VIRTIO_NET_F_MTU requires manually specifying host_mtu= on the
virtio-net-pci device, duplicating the MTU already configured on
the host's tap interface.

Add a new mtu-from-tap boolean property (default off, preserving
existing behavior). When enabled, the netdev peer's MTU is queried
via the generic qemu_get_mtu() and used to set net_conf.mtu and
enable VIRTIO_NET_F_MTU, regardless of the backend's type.

This detection must happen in virtio_net_device_realize(), before
virtio_net_set_config_size() computes the virtio config space
size from host_features. Performing the detection later (e.g. in
the get_features_ex() callback, which runs after the NIC and its
config space are already sized) results in the mtu config field
falling outside the sized config space, and the guest reading
back an unmapped garbage value (0xffff) instead of the intended
MTU.

Since qemu_new_nic() has not yet been called at this point in
realize(), the peer is accessed via n->nic_conf.peers.ncs[0]
(populated during property parsing, before realize() runs, via
the netdev= property) rather than through n->nic.

Signed-off-by: Nariman Sayed <narimansayed28@gmail.com>
Tested-by: Aniket Sahu <asahu1x@linux.ibm.com>
---
 hw/net/virtio-net.c            | 10 ++++++++++
 include/hw/virtio/virtio-net.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 814b99a43d..89fb3bad10 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3901,6 +3901,15 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
         n->host_features |= (1ULL << VIRTIO_NET_F_MTU);
     }
 
+    if (n->net_conf.mtu_from_tap) {
+        NetClientState *peer = n->nic_conf.peers.ncs[0];
+        int mtu = qemu_get_mtu(peer);
+        if (mtu > 0) {
+            n->net_conf.mtu = mtu;
+            n->host_features |= (1ULL << VIRTIO_NET_F_MTU);
+        }
+    }
+
     if (n->net_conf.duplex_str) {
         if (strncmp(n->net_conf.duplex_str, "half", 5) == 0) {
             n->net_conf.duplex = DUPLEX_HALF;
@@ -4275,6 +4284,7 @@ static const Property virtio_net_properties[] = {
     DEFINE_PROP_UINT16("tx_queue_size", VirtIONet, net_conf.tx_queue_size,
                        VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE),
     DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0),
+    DEFINE_PROP_BOOL("mtu-from-tap", VirtIONet, net_conf.mtu_from_tap, false),
     DEFINE_PROP_INT32("speed", VirtIONet, net_conf.speed, SPEED_UNKNOWN),
     DEFINE_PROP_STRING("duplex", VirtIONet, net_conf.duplex_str),
     DEFINE_PROP_BOOL("failover", VirtIONet, failover, false),
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 371e376428..11044b6d27 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -52,6 +52,7 @@ typedef struct virtio_net_conf
     uint16_t rx_queue_size;
     uint16_t tx_queue_size;
     uint16_t mtu;
+    bool mtu_from_tap;
     int32_t speed;
     char *duplex_str;
     uint8_t duplex;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-10-07  9:14 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-16  4:34 [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Nariman Sayed
2026-08-16  4:34 ` [PATCH 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
2026-08-26 17:17   ` Aniket Sahu
2026-09-17 10:28   ` Eugenio Pérez
2026-09-17 10:28   ` Eugenio Pérez
2026-08-16  4:34 ` [PATCH 2/3] net/tap: expose tap_get_mtu() via NetClientState Nariman Sayed
2026-08-16  4:34 ` [PATCH 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection Nariman Sayed
2026-08-24 13:40 ` [PATCH 0/3] net/tap, virtio-net: auto-detect MTU from host tap device Stefan Hajnoczi
2026-10-07  5:07 ` [PATCH v2 " Nariman Sayed
2026-10-07  5:07   ` [PATCH v2 1/3] net/tap: add tap_fd_get_mtu() to query host tap MTU Nariman Sayed
2026-10-07  5:07   ` [PATCH v2 2/3] net: add generic get_mtu NetClientInfo callback Nariman Sayed
2026-10-07  5:07   ` [PATCH v2 3/3] virtio-net: add mtu-from-tap property for automatic MTU detection Nariman Sayed

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.