public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [PATCH] sdn: qinq: apply zone MTU to the notag vnet veth pair
@ 2026-09-04  8:59 Thomas Glanzmann
  2026-09-10  4:41 ` Thomas Glanzmann
  0 siblings, 1 reply; 2+ messages in thread
From: Thomas Glanzmann @ 2026-09-04  8:59 UTC (permalink / raw)
  To: pve-devel

The QinQ zone applies its configured MTU to the zone bridge and to the
vnet bridge, but not to the ln_<zone>/pr_<zone> veth pair it creates as
the uplink for an untagged vnet. Both ends therefore stay at the kernel
default of 1500.

For a vnet without a tag, pr_<zone> is a port of the vnet bridge itself,
so that veth sits directly in the guest data path and silently caps the
whole zone at 1500 while every other interface in the chain reports the
configured MTU. Frames above the limit are dropped by the bridge with no
error and no counter. Guests hit the ceiling at ping -M do -s 1476,
since br_forward() still permits mtu + hard_header_len + VLAN_HLEN bytes
of frame.

Tagged vnets are unaffected, as they attach through z_<zone>.<ctag> and
never traverse the veth. That also makes the bug easy to miss when
trying to reproduce it.

Set the MTU on both ends of the pair. Guarding on $mtu keeps the
generated config byte-identical for zones without an explicit MTU.

Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
---
 src/PVE/Network/SDN/Zones/QinQPlugin.pm | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/PVE/Network/SDN/Zones/QinQPlugin.pm b/src/PVE/Network/SDN/Zones/QinQPlugin.pm
index a75940c..00f8814 100644
--- a/src/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -150,11 +150,13 @@ sub generate_sdn_config {
     @iface_config = ();
     push @iface_config, "link-type veth";
     push @iface_config, "veth-peer-name $zone_notag_uplinkpeer";
+    push @iface_config, "mtu $mtu" if $mtu;
     push(@{ $config->{$zone_notag_uplink} }, @iface_config) if !$config->{$zone_notag_uplink};
 
     @iface_config = ();
     push @iface_config, "link-type veth";
     push @iface_config, "veth-peer-name $zone_notag_uplink";
+    push @iface_config, "mtu $mtu" if $mtu;
     push(@{ $config->{$zone_notag_uplinkpeer} }, @iface_config)
         if !$config->{$zone_notag_uplinkpeer};
 
-- 
2.53.0



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

* Re: [PATCH] sdn: qinq: apply zone MTU to the notag vnet veth pair
  2026-09-04  8:59 [PATCH] sdn: qinq: apply zone MTU to the notag vnet veth pair Thomas Glanzmann
@ 2026-09-10  4:41 ` Thomas Glanzmann
  0 siblings, 0 replies; 2+ messages in thread
From: Thomas Glanzmann @ 2026-09-10  4:41 UTC (permalink / raw)
  To: pve-devel

Hi,

this is a reproducer for the bug fixed by the patch I sent on 2026-09-04
("sdn: qinq: apply zone MTU to the notag vnet veth pair"), which has not
been picked up yet. The fix is a two-line change and the bug it fixes is
obvious and user-visible, so I would like to ping again and provide a
complete, tested reproduction.

Summary
-------
A QinQ zone with an explicit MTU applies that MTU to the zone bridge
(z_<zone>) and to the vnet bridge, but *not* to the ln_<zone>/pr_<zone>
veth pair it creates as the uplink for a vnet without a tag. Both veth
ends stay at the kernel default of 1500.

For a tagless vnet, pr_<zone> is a port of the vnet bridge itself, so
that veth sits directly in the guest data path. Every other interface in
the chain reports the configured MTU, but the veth silently caps the zone
at 1500 and drops larger frames with no error and no counter.

Tagged vnets are unaffected because they attach through z_<zone>.<ctag>
and never traverse the veth. That is why the bug is easy to miss.

Environment
-----------
    pve-manager/9.2.11/f6997e698c7933ea
    kernel 7.0.14-15-pve

  * uplink bridge: vmbr0, VLAN-aware, MTU 9214
  * QinQ zone:     qz, bridge vmbr0, tag 10, mtu 9000
  * vnet:          qv1, zone qz, no tag  (this is what triggers the bug)
  * guest:         VM 101 attached to qv1

Reproduction
------------
1) Create the QinQ zone and a *tagless* vnet, then apply the SDN config:

    pvesh create /cluster/sdn/zones --type qinq --zone qz \
        --bridge vmbr0 --tag 10 --mtu 9000 --nodes host-08
    pvesh create /cluster/sdn/vnets --vnet qv1 --zone qz
    pvesh set /cluster/sdn

2) Inspect the MTU of the interfaces created for the zone:

    # for i in z_qz ln_qz pr_qz qv1; do \
          printf "%-6s %s\n" "$i" "$(cat /sys/class/net/$i/mtu)"; done
    z_qz   9000
    ln_qz  1500      <-- kernel default, should be 9000
    pr_qz  1500      <-- kernel default, should be 9000
    qv1    9000

   Both ends of the ln_qz/pr_qz veth pair are stuck at 1500 while the
   zone and vnet bridges correctly report 9000.

3) Confirm pr_qz is directly in the guest data path:

    # bridge link | grep -E 'pr_qz|ln_qz|qv1'
    25: ln_qz@pr_qz ... mtu 1500 master z_qz  state forwarding ...
    26: pr_qz@ln_qz ... mtu 1500 master qv1   state forwarding ...

   The vnet bridge qv1 has pr_qz as its port because qv1 has no tag.

4) Attach a guest to qv1 and ping a peer across the veth (any peer that
   is reachable through z_qz / vmbr0.10). With DF set, frames larger than
   the veth MTU are silently dropped:

    # guest: ping -M do -s <size> <peer>
    payload 1472  -> reply
    payload 1476  -> reply
    payload 1477  -> no reply, 100% loss, no ICMP error, no counter
    payload 2000  -> no reply, 100% loss

   The ceiling is exactly at ping -M do -s 1476, consistent with
   br_forward() allowing mtu + hard_header_len + VLAN_HLEN bytes of
   frame, and matches the behaviour described in the patch.

After the patch
---------------
Applying the two-line fix from the original patch to
src/PVE/Network/SDN/Zones/QinQPlugin.pm and re-applying the SDN config
gives:

    z_qz   9000
    ln_qz  9000
    pr_qz  9000
    qv1    9000

and the same ping across the veth now succeeds at every size:

    payload 1472  -> reply
    payload 1476  -> reply
    payload 1477  -> reply
    payload 2000  -> reply
    payload 8000  -> reply
    payload 8972  -> reply

So the fix is correct and complete: it makes the veth pair honour the
configured zone MTU and removes the silent 1500 cap from the tagless
vnet data path.

Zones without an explicit MTU are byte-for-byte unaffected, since the
added lines are guarded with `if $mtu`.

Please consider picking up the patch. I am happy to re-send it in a
thread or as a new submission if that is easier.

If our shared customer who I developed this patch for should open a case
with you in order to address this, please let me know. This issue showed
up during integration testing from VMware vSphere to Proxmox.

Cheers,
        Thomas



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

end of thread, other threads:[~2026-09-10  4:41 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-04  8:59 [PATCH] sdn: qinq: apply zone MTU to the notag vnet veth pair Thomas Glanzmann
2026-09-10  4:41 ` Thomas Glanzmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal