[PATCH net 0/3] vxlan: vnifilter: bound the VNI range per request
From: Ali Firas <hidden>
Date: 2026-09-09 09:27:28
Also in:
lkml
A single RTM_NEWTUNNEL or RTM_DELTUNNEL message can currently ask the
vnifilter code for the whole 24-bit VNI space, and vxlan_vni_add_del()
loops over that span under rtnl_lock creating one VNI node and one
per-CPU stats block per iteration. That is reachable by an unprivileged
user in a user+network namespace and it costs roughly 2.1 GiB + 1 GiB
per possible CPU (128 B slab plus 64 B per possible CPU per VNI): on
2, 4 and 8 CPU guests every full-range request
ended in a global OOM, with no errno returned because the caller is
itself OOM-killed, and with unrelated root-owned processes killed on the
way down. Because rtnl_lock is global rather than per-netns, it also
stalled network configuration everywhere: a plain "ip link add dummy0
type dummy" in a different network namespace takes 0.011 s normally,
4.472 s while a 1,000,000 VNI request runs, and never completed at all
during a full-range one. Patch 1 caps the span of a single request at
4096 VNIs, which closes both. The cap is on one request, not on the
device: a device can still hold the whole VNI space, it just takes more
than one message.
Patch 2 charges the VNI node and its per-CPU stats to the caller's memcg.
With the cap in place this is no longer the primary defence, but nothing
limits how many capped requests a task may issue, so an unprivileged user
can still accumulate VNIs 4096 at a time with none of it charged to them.
It is also the same class fix as commit 1beb81947eb4 ("net/sched: account
classifier filter allocations to memcg"). One limitation is worth stating
up front: try_charge() reclaims and then invokes the memcg OOM killer
rather than returning -ENOMEM, so accounting confines the blast radius
without producing a graceful failure.
Patch 3 adds the selftest coverage Ido asked for, in the existing API
test: a range of exactly the maximum is accepted and one VNI more is
rejected, for both add and delete.
The limit is a driver-local constant rather than VLAN_N_VID: the values
coincide today, but a bound on a VXLAN netlink request is not a count of
VLAN IDs, and coupling them would make a change to one silently change
the other.
Patch 1 does tighten uAPI: a request spanning more than 4096 VNIs used
to succeed and now returns -EINVAL. Ido's assessment was that the limit
is unlikely to break anyone, since vnifilter is mainly used on bridged
VXLAN devices where the VNI is derived from the VLAN, capped at 4094.
I am sending the series to net because the stall is reachable by an
unprivileged user and crosses namespaces.
What I am less sure about is that Fixes: in net means this reaches
stable, where a script issuing one large range would start failing
across a point release. If that is the wrong trade, I am happy to respin
patch 1 against net-next without the Fixes tag.
Two things the series does not address. A single-VNI request with
START == END >= VXLAN_N_VID still passes the span check, and
vxlan_vni_field() shifts without masking, so such an entry is silently
truncated on the wire while holding its own rhashtable slot. That wants
a netlink policy range check, which I will send separately to net-next
as a pure uAPI tightening.
Measured worst case at the cap, on a 2 CPU / 2G guest: a request of
exactly 4096 VNIs takes 0.031 s to add and 0.022 s to delete, and the
cross-namespace "ip link add" blocks for 0.024 s during it. The old
full-range request is now rejected outright with
Error: VNI range spans more than 4096 VNIs.
for both add and delete.
The whole selftest file passes before and after: 27 tests passed and 0
failed on the base, 31 passed and 0 failed with the series applied.
The 4096 limit follows Ido Schimmel's suggestion:
https://lore.kernel.org/netdev/20260907141001.GA708129@shredder/ (local)
Ali Firas (3):
vxlan: vnifilter: limit the VNI range of a single request
vxlan: vnifilter: account VNI node and per-CPU stats to memcg
selftests: net: test the vxlan vnifilter VNI range limit
drivers/net/vxlan/vxlan_vnifilter.c | 24 +++++++++++++++++--
.../selftests/net/test_vxlan_vnifiltering.sh | 13 ++++++++++
2 files changed, 35 insertions(+), 2 deletions(-)
--
2.53.0