* [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory
@ 2026-10-14 12:38 Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 1/7] vxlan: vnifilter: validate the VXLAN_VNIFILTER_ENTRY nest Ali Firas
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
The VNI filter interface accepts a START/END range with no bound on
either endpoint and no bound on how many VNIs one message may ask for,
and the memory it allocates per VNI is not charged to the caller's
cgroup.
Patch 1 links the VXLAN_VNIFILTER_ENTRY nest to its policy with
NLA_POLICY_NESTED(), as Jakub asked in v2:
https://lore.kernel.org/netdev/20260921150904.65a704eb@kernel.org/
Without it the entry attributes were validated only as each entry was
dispatched, so a multi-entry message whose later entry was invalid had
the earlier entries applied and notified before the message was
rejected. With the nest linked, an entry the policy rejects refuses the
message as a unit; faults the policy does not cover are still handled
one entry at a time, as before.
Patch 2 range-validates both endpoints to the 24-bit VNI space.
Patch 3 makes the dump re-enterable, and does so before patch 4 caps the
input, so no commit in the series reports a range its own input path
would reject. vxlan_vnifilter_dump_dev() coalesces a contiguous run of
VNIs, and packs as many entries into a netlink message as the skb holds,
with no bound on either. It introduces VXLAN_VNI_FILTER_MSG_MAX and
bounds both: it ends a coalesced run at the limit, and carries a
per-message VNI budget that ends the message once its entries would sum
past the limit, the same way the loop already ends it when the skb is
full. The same resume path (cb->args[1], counting nodes dumped) drives
both; the dump does not drop or repeat a VNI.
Patch 4 caps the number of VNIs one request may add or delete, summed
over its entries, at VXLAN_VNI_FILTER_MSG_MAX. Both add and delete walk
the span one VNI at a time under rtnl_lock, so both are bounded; that
walk is the cost, not the memory.
Patch 5 charges the per-VNI node and its per-CPU stats block to the
cgroup of the task that created the VNI, the way the device's own struct
and its Tx/Rx queues already are (commit c948f51c1654 ("memcg: enable
accounting for net_device and Tx/Rx queues")).
Patch 6 charges the default FDB entry a VNI with a group or remote
installs -- the vxlan_fdb, its vxlan_rdst and the per-CPU dst cache. It
threads a gfp argument through vxlan_fdb_update() down to
vxlan_fdb_alloc()/vxlan_fdb_append(), on both the create and the
remote-change paths, and a second gfp through
vxlan_update_default_fdb_entry() so each caller picks it. A per-request
add or change (RTM_NEWTUNNEL) passes GFP_NOWAIT | __GFP_ACCOUNT, which
is non-blocking like GFP_ATOMIC but hard-bounded by the memcg: at its
limit the request fails with -ENOMEM instead of charging past
memory.max, and because the new entry is allocated before the old is
freed, a failed add leaves the existing entry intact. The device-wide
default-remote change (RTM_NEWLINK, via vxlan_vnilist_update_group())
keeps GFP_ATOMIC | __GFP_ACCOUNT; that pre-existing walk is not bounded
here ("Not addressed" below). Every non-vnifilter caller --
vxlan_fdb_add(), vxlan_snoop(), vxlan_dev_create(), vxlan_changelink()
and the switchdev vxlan_fdb_external_learn_add() -- keeps plain
GFP_ATOMIC, so the data path and unrelated callers are untouched.
Patch 7 adds the selftests.
This is the reasoning of commit e2c8d550a973 ("netfilter: ebtables:
account ebt_table_info to kmemcg") and of the net_device accounting
above: memory whose lifetime is tied to the net namespace rather than to
the allocating task cannot be relieved by the OOM killer, so a
container's netadmin must not be able to grow it outside the memcg that
bounds the container.
What this series does and does not account, measured on production
builds (no lockdep/KASAN) in a memcg at 2 and 8 vCPU:
- every persistent per-VNI allocation the vnifilter path creates is
attributed to the cgroup of the task whose request allocates it, and
bounded by it on the per-request path. Patch 5's node (128 B) and
per-CPU stats (64 B/CPU), and patch 6's FDB entry -- vxlan_fdb
(128 B), vxlan_rdst (96 B) and a per-CPU dst cache -- on the
per-request path (RTM_NEWTUNNEL) are hard-bounded: the node and stats
use GFP_KERNEL_ACCOUNT and the FDB entry uses
GFP_NOWAIT | __GFP_ACCOUNT, so a cgroup at its limit fails the
create, the first remote, or a remote change with -ENOMEM, and
memory.current does not exceed memory.max (measured at 2 and 8 vCPU
in an 8 MiB cgroup). Failure is clean: the new entry is allocated
before the old is freed, so a failed add leaves the existing entry
intact and returns the error -- no established state is destroyed and
no false success is returned. The at-rest footprint is one node, its
stats and one FDB entry per VNI; this memory has device and net
namespace lifetime, not task lifetime (killing the cgroup's tasks did
not release it, only deleting the device did), so it must be charged
rather than left to the OOM killer;
- the rhashtable bucket tables backing the VNI and FDB hashes are not
charged. That is ~32 bytes per VNI across both tables, generic
infrastructure shared by every rhashtable user, O(entries) with
automatic shrinking (an add/delete cycle returns it, measured), and
the series does not address it.
The cap is symmetric, applied to add and delete alike, which is what Ido
asked for when he agreed to a 4k limit. Patch 3 is what makes that safe:
no dumped message carries more VNIs than one request may ask for, so a
device holding more than the limit can still be torn down by replaying
what "bridge vni show" reports. Device teardown itself
(vxlan_vnigroup_uninit()) is not a netlink message and is not subject to
the cap.
uAPI changes, all of them:
- a VNI at or above 2^24, previously accepted and stored (and
truncated on the wire), is now rejected with -ERANGE;
- a single request asking to add or delete more than 4096 VNIs, summed
over its entries, is now rejected with -EINVAL -- "bridge vni add
dev X vni 1-10000" used to be accepted;
- a request rejected by the entry policy, aimed at a missing or
non-vnifilter device, now returns that policy error rather than
-ENODEV or -EOPNOTSUPP, because the nest is validated before the
device is resolved (patch 1);
- "bridge vni show" now splits a contiguous run longer than the limit
into several entries, and across several messages, instead of one;
the set of VNIs it reports is unchanged;
- in a cgroup at its memory limit, adding a VNI, or adding or changing
a VNI's remote (RTM_NEWTUNNEL), now returns -ENOMEM instead of
charging past the limit; the existing entry, if any, is left intact.
This is a policy and hardening change, not a fix for a crash or
corruption; it targets net-next and should not be backported.
One pre-existing semantic is worth review: an entry that carries only
END and no START is treated as the range [0, END], so a lone END near
the top of the space is a whole-space request that the cap now rejects;
whether END-without-START should mean that is left as an open question.
Not addressed here:
- the device-wide default-remote change (RTM_NEWLINK) reaches the same
per-VNI FDB entries outside the request cap and force-charges them
rather than hard-bounding, so this series narrows the exposure to
the per-request route rather than closing it. Patch 6 does charge
those entries to the requesting task's cgroup, where before the
series they grew unaccounted host memory; bounding the walk is left
to a follow-up.
- vxlan_vni_add_del() still leaves the earlier VNIs of a range
installed if an allocation fails partway through it; with the cap
that is now bounded to fewer than 4096 VNIs. A fix needs a
transaction and is left to a follow-up.
- the rhashtable bucket memory described above.
Changes since v3:
- rebased onto current net-next.
- the dump patch (now patch 3) is ordered before the input cap (patch
4) and introduces VXLAN_VNI_FILTER_MSG_MAX, so every commit is
self-consistent; it also carries a per-message VNI budget, not only a
per-entry clamp, so a dump of a run longer than the limit splits into
messages the input path accepts (demonstrated with raw netlink).
- new patch 6 accounts the default FDB entry, scoped to the vnifilter
call site via a gfp argument so the data path stays on GFP_ATOMIC;
the gfp is threaded on both the create and the remote-change paths.
The per-request path (RTM_NEWTUNNEL) uses GFP_NOWAIT | __GFP_ACCOUNT
so the charge is hard-bounded (fails with -ENOMEM at the cgroup
limit); the pre-existing device-default walk (RTM_NEWLINK) keeps
GFP_ATOMIC | __GFP_ACCOUNT.
- patch 5 reworded to cover the node and stats only, with its
net_device-accounting reference narrowed to net_device and its Tx/Rx
queues.
- patch 1 reworded to scope the "rejected as a unit" claim to entries
the policy rejects.
Changes since v2:
- add patch 1 linking the nest to its policy (Jakub);
- the request cap applies to both add and delete (Ido).
Ali Firas (7):
vxlan: vnifilter: validate the VXLAN_VNIFILTER_ENTRY nest
vxlan: vnifilter: reject VNIs outside the 24-bit space
vxlan: vnifilter: clamp the dumped VNI range to the request limit
vxlan: vnifilter: bound the number of VNIs one request may touch
vxlan: vnifilter: account per-VNI memory to memcg
vxlan: vnifilter: account the default FDB entry to memcg
selftests: net: test the vxlan vnifilter request limit and dump replay
drivers/net/vxlan/vxlan_core.c | 47 +++---
drivers/net/vxlan/vxlan_private.h | 5 +-
drivers/net/vxlan/vxlan_vnifilter.c | 132 +++++++++++++++---
.../selftests/net/test_vxlan_vnifiltering.sh | 119 +++++++++++++++-
4 files changed, 270 insertions(+), 46 deletions(-)
base-commit: 05b5019b01fb9443b09ae4ed34af1135a80a84c8
--
2.53.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH net-next v4 1/7] vxlan: vnifilter: validate the VXLAN_VNIFILTER_ENTRY nest
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 2/7] vxlan: vnifilter: reject VNIs outside the 24-bit space Ali Firas
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
vxlan_vnifilter_process() parses the message with vni_filter_policy,
whose VXLAN_VNIFILTER_ENTRY is a bare NLA_NESTED with no nested policy
attached. The entry attributes are therefore validated only later, one
entry at a time, by the nla_parse_nested() inside
vxlan_process_vni_filter(). Entries are parsed as they are dispatched:
in a message whose first entry is valid and whose second is not, the
first entry is applied and its RTM_NEWTUNNEL notification sent before
the second is rejected.
Link the nest to vni_filter_entry_policy with NLA_POLICY_NESTED() so
every entry is checked against the entry policy up front, before any
entry is acted on. A message whose entry the policy rejects -- a
malformed attribute, or, with the next patch, an out-of-range endpoint
-- is now refused as a unit and installs nothing. Faults the policy does
not cover, such as a device or handler error raised on a later entry,
are unchanged: entries are still dispatched and applied one at a time.
This reorders two faults. The nest is validated before the device is
looked up and before the vnifilter flag is checked, so a request
rejected by the entry policy, aimed at a missing or non-vnifilter
device, now returns that policy error where it previously returned
-ENODEV or -EOPNOTSUPP. The request was invalid either way; only the
errno an operator sees changes.
The nla_parse_nested() in vxlan_process_vni_filter() stays: it is what
fills the per-entry attribute table the handler reads. It can no longer
fail on a message that has reached it.
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/netdev/20260921150904.65a704eb@kernel.org/
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: scope the "rejected as a unit" claim to
policy-rejected entries; rebased onto net-next.
drivers/net/vxlan/vxlan_vnifilter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index 41095096b698..124ba47758e9 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -499,7 +499,7 @@ static const struct nla_policy vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX
};
static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX + 1] = {
- [VXLAN_VNIFILTER_ENTRY] = { .type = NLA_NESTED },
+ [VXLAN_VNIFILTER_ENTRY] = NLA_POLICY_NESTED(vni_filter_entry_policy),
};
bool vxlan_vnifilter_has_multicast(const struct vxlan_dev *vxlan)
base-commit: 05b5019b01fb9443b09ae4ed34af1135a80a84c8
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v4 2/7] vxlan: vnifilter: reject VNIs outside the 24-bit space
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 1/7] vxlan: vnifilter: validate the VXLAN_VNIFILTER_ENTRY nest Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 3/7] vxlan: vnifilter: clamp the dumped VNI range to the request limit Ali Firas
` (5 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
VXLAN_VNIFILTER_ENTRY_START and VXLAN_VNIFILTER_ENTRY_END are bare
NLA_U32, so neither is bounded before vxlan_process_vni_filter() hands
them to vxlan_vni_add_del():
int v, err = 0;
...
for (v = start_vni; v <= end_vni; v++)
v is int and end_vni is __u32, so the comparison is done unsigned. A
request carrying only START=0xffffffff has vni_start == vni_end ==
0xffffffff and looks like a single VNI; v is then -1, the comparison
promotes it to 0xffffffff and passes, v++ makes v 0, and the loop walks
the space upwards from there, creating a VNI node and a per-CPU stats
block per iteration under rtnl_lock. Any range ending at 0xffffffff
behaves the same way.
Separately, a VNI at or above VXLAN_N_VID is accepted and stored even
though the VXLAN header carries only 24 bits: vxlan_vni_field() shifts
without masking, so such an entry keeps its own rhashtable slot while
being truncated on the wire.
Range-validate both attributes against the 24-bit space, as vxlan_mdb.c
already does for its own VNI attributes. With the nest now linked to
this policy, an out-of-range endpoint is rejected during netlink policy
validation, before vxlan_process_vni_filter() runs and before anything
is allocated. How many VNIs a single in-range request may span is a
separate question, bounded by the next patch; that limit is not a policy
check and does run in the handler.
Make the loop counter u32 as well. With the range bounded it is no
longer what keeps the loop finite, but it drops the undefined signed
overflow past INT_MAX and matches the u32 vni that vxlan_vni_add() and
vxlan_vni_del() already take.
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: no functional change; rebased onto net-next.
drivers/net/vxlan/vxlan_vnifilter.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index 124ba47758e9..9e15f4de75c9 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -491,9 +491,15 @@ static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cb
return err;
}
+static const struct netlink_range_validation vni_filter_vni_range = {
+ .max = VXLAN_N_VID - 1,
+};
+
static const struct nla_policy vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX + 1] = {
- [VXLAN_VNIFILTER_ENTRY_START] = { .type = NLA_U32 },
- [VXLAN_VNIFILTER_ENTRY_END] = { .type = NLA_U32 },
+ [VXLAN_VNIFILTER_ENTRY_START] = NLA_POLICY_FULL_RANGE(NLA_U32,
+ &vni_filter_vni_range),
+ [VXLAN_VNIFILTER_ENTRY_END] = NLA_POLICY_FULL_RANGE(NLA_U32,
+ &vni_filter_vni_range),
[VXLAN_VNIFILTER_ENTRY_GROUP] = NLA_POLICY_EXACT_LEN(sizeof_field(struct iphdr, daddr)),
[VXLAN_VNIFILTER_ENTRY_GROUP6] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
};
@@ -914,7 +920,8 @@ static int vxlan_vni_add_del(struct vxlan_dev *vxlan, __u32 start_vni,
int cmd, struct netlink_ext_ack *extack)
{
struct vxlan_vni_group *vg;
- int v, err = 0;
+ int err = 0;
+ u32 v;
vg = rtnl_dereference(vxlan->vnigrp);
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v4 3/7] vxlan: vnifilter: clamp the dumped VNI range to the request limit
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 1/7] vxlan: vnifilter: validate the VXLAN_VNIFILTER_ENTRY nest Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 2/7] vxlan: vnifilter: reject VNIs outside the 24-bit space Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 4/7] vxlan: vnifilter: bound the number of VNIs one request may touch Ali Firas
` (4 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
vxlan_vnifilter_dump_dev() coalesces a contiguous run of VNIs sharing a
remote into one VXLAN_VNIFILTER_ENTRY, and packs as many entries into a
netlink message as the skb holds, with no bound on either. A later patch
bounds a single request to VXLAN_VNI_FILTER_MSG_MAX VNIs summed over its
entries; without a matching bound on the dump, a device holding more than
that -- populated by several requests -- would dump a run, or a message,
that the input path then refuses on replay.
Introduce VXLAN_VNI_FILTER_MSG_MAX here and clamp the dump to it first, so
the series never passes through a commit where the kernel reports a range
its own input path rejects. Bound the two ways the dump can exceed the
limit:
- end a coalesced run once it reaches the limit, in the merge condition,
even when the next VNI is contiguous and shares the remote; and
- carry a per-message VNI budget, ending the message once its entries
would sum past the limit, the same way the loop already ends it when
the skb is full.
cb->args[1] continues to count the VNI nodes already dumped and is advanced
only when a completed entry is written, so the budget break and the
skb-full break share one resume path; a run stays a gapless block, so the
dump never drops a VNI and never emits one twice.
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: moved before the input cap; now introduces
VXLAN_VNI_FILTER_MSG_MAX and adds a per-message VNI budget (v3 clamped
per entry only), so the dump never emits a message the input path
rejects.
drivers/net/vxlan/vxlan_vnifilter.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index 9e15f4de75c9..5beec29eb84a 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -17,6 +17,13 @@
#include "vxlan_private.h"
+/* The dump coalesces a contiguous run of VNIs into entries, and packs entries
+ * into netlink messages, of at most this many VNIs each, so every message the
+ * dump emits stays within what the input path will accept on replay. A later
+ * patch bounds a single RTM_NEWTUNNEL/RTM_DELTUNNEL request to the same number.
+ */
+#define VXLAN_VNI_FILTER_MSG_MAX 4096
+
static inline int vxlan_vni_cmp(struct rhashtable_compare_arg *arg,
const void *ptr)
{
@@ -342,6 +349,7 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
struct nlmsghdr *nlh;
int idx = 0, s_idx;
bool dump_stats;
+ u32 vnis = 0;
int err = 0;
if (cb->args[2] != dev->ifindex) {
@@ -388,15 +396,29 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
continue;
}
if (!dump_stats && vnirange(vend, v) == 1 &&
+ vnirange(vbegin, v) < VXLAN_VNI_FILTER_MSG_MAX &&
vxlan_addr_equal(&v->remote_ip, &vend->remote_ip)) {
goto update_end;
} else {
+ u32 sz = vnirange(vbegin, vend) + 1;
+
+ /* End this message on its VNI budget the same way we
+ * end it when the skb is full, so a dumped message
+ * never sums to more VNIs than the input path accepts
+ * in one request. Resume re-emits this run as the
+ * first entry of the next message.
+ */
+ if (vnis + sz > VXLAN_VNI_FILTER_MSG_MAX) {
+ err = -EMSGSIZE;
+ break;
+ }
if (!vxlan_fill_vni_filter_entry(skb, vbegin, vend,
dump_stats)) {
err = -EMSGSIZE;
break;
}
- idx += vnirange(vbegin, vend) + 1;
+ vnis += sz;
+ idx += sz;
vbegin = v;
}
update_end:
@@ -404,7 +426,10 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
}
if (!err && vbegin) {
- if (!vxlan_fill_vni_filter_entry(skb, vbegin, vend, dump_stats))
+ if (vnis + vnirange(vbegin, vend) + 1 > VXLAN_VNI_FILTER_MSG_MAX)
+ err = -EMSGSIZE;
+ else if (!vxlan_fill_vni_filter_entry(skb, vbegin, vend,
+ dump_stats))
err = -EMSGSIZE;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v4 4/7] vxlan: vnifilter: bound the number of VNIs one request may touch
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
` (2 preceding siblings ...)
2026-10-14 12:38 ` [PATCH net-next v4 3/7] vxlan: vnifilter: clamp the dumped VNI range to the request limit Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 5/7] vxlan: vnifilter: account per-VNI memory to memcg Ali Firas
` (3 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
A single RTM_NEWTUNNEL or RTM_DELTUNNEL message can ask for the whole
24-bit space in one range. vxlan_vni_add_del() then walks it one VNI at
a time under rtnl_lock, holding the lock for the length of the walk.
That walk is the cost being bounded, not the memory: an add allocates a
VNI node and a per-CPU stats block per VNI, a delete creates neither,
but both walk the same span and hold rtnl the same way, so both are
bounded.
The span of one VXLAN_VNIFILTER_ENTRY is not the quantity to bound. An
entry carrying just START and END is 20 bytes on the wire and a message
may carry many of them, vxlan_process_vni_filter() being called once per
entry, so bounding each entry alone would still let one message ask for
thousands of times the limit. Sum the spans of every entry and reject
the message as a whole in vxlan_vnifilter_check_msg(), before the
dispatch loop: entries are applied and notified one at a time, so a
limit enforced during dispatch would return an error only after every
preceding entry had been acted on. The range extraction is factored
into vxlan_vni_filter_entry_range() so the count and the range later
acted on cannot drift.
The limit, VXLAN_VNI_FILTER_MSG_MAX (4096), is the one the preceding
patch introduced for the dump; it follows the usable VLAN ID space,
since vnifilter is mainly used on bridged devices where the VNI is
derived from the VLAN. It bounds one request, not how many VNIs a
device may hold: the whole space can still be installed in more than
one request, and a
device holding it is still torn down in one step by
vxlan_vnigroup_uninit(), which is device teardown, not a netlink
message, and is not subject to this cap.
This is a policy narrowing of what a single message may ask for, not a
fix for a crash or corruption, and is not a backport candidate.
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: use the constant the dump patch introduces; rebased.
drivers/net/vxlan/vxlan_vnifilter.c | 80 ++++++++++++++++++++++++++---
1 file changed, 72 insertions(+), 8 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index 5beec29eb84a..2999dd536625 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -971,13 +971,79 @@ static int vxlan_vni_add_del(struct vxlan_dev *vxlan, __u32 start_vni,
return err;
}
+/* Derive the VNI range one VXLAN_VNIFILTER_ENTRY selects. Shared so that the
+ * count taken by vxlan_vnifilter_check_msg() cannot drift from the range
+ * vxlan_process_vni_filter() then acts on.
+ */
+static void vxlan_vni_filter_entry_range(struct nlattr **vattrs, u32 *vni_start,
+ u32 *vni_end)
+{
+ *vni_start = 0;
+ *vni_end = 0;
+
+ if (vattrs[VXLAN_VNIFILTER_ENTRY_START]) {
+ *vni_start = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_START]);
+ *vni_end = *vni_start;
+ }
+
+ if (vattrs[VXLAN_VNIFILTER_ENTRY_END])
+ *vni_end = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_END]);
+}
+
+/* Reject a request touching more than VXLAN_VNI_FILTER_MSG_MAX VNIs before any
+ * of its entries is acted on. Both add and delete walk the span one VNI at a
+ * time under rtnl_lock, so both are bounded. Entries are applied one at a time
+ * and each one notifies as it goes, so a limit checked inside the dispatch loop
+ * would leave the entries ahead of the offending one already applied.
+ */
+static int vxlan_vnifilter_check_msg(const struct nlmsghdr *nlh,
+ struct netlink_ext_ack *extack)
+{
+ struct nlattr *vattrs[VXLAN_VNIFILTER_ENTRY_MAX + 1];
+ struct nlattr *attr;
+ u32 vnis = 0;
+ int err, rem;
+
+ nlmsg_for_each_attr_type(attr, VXLAN_VNIFILTER_ENTRY, nlh,
+ sizeof(struct tunnel_msg), rem) {
+ u32 vni_start, vni_end;
+
+ err = nla_parse_nested(vattrs, VXLAN_VNIFILTER_ENTRY_MAX, attr,
+ vni_filter_entry_policy, extack);
+ if (err)
+ return err;
+
+ vxlan_vni_filter_entry_range(vattrs, &vni_start, &vni_end);
+
+ /* A start above the end selects no VNI and costs nothing;
+ * leave it behaving as it does today.
+ */
+ if (vni_end < vni_start)
+ continue;
+
+ /* vni_filter_entry_policy has already bounded both endpoints
+ * below VXLAN_N_VID, so one entry adds at most VXLAN_N_VID and
+ * vnis cannot wrap before the test below rejects it.
+ */
+ vnis += vni_end - vni_start + 1;
+ if (vnis > VXLAN_VNI_FILTER_MSG_MAX) {
+ NL_SET_ERR_MSG_ATTR_FMT(extack, attr,
+ "Request asks for more than %u VNIs",
+ VXLAN_VNI_FILTER_MSG_MAX);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int vxlan_process_vni_filter(struct vxlan_dev *vxlan,
struct nlattr *nlvnifilter,
int cmd, struct netlink_ext_ack *extack)
{
struct nlattr *vattrs[VXLAN_VNIFILTER_ENTRY_MAX + 1];
const struct vxlan_config *cfg;
- u32 vni_start = 0, vni_end = 0;
+ u32 vni_start, vni_end;
union vxlan_addr group;
int err;
@@ -988,13 +1054,7 @@ static int vxlan_process_vni_filter(struct vxlan_dev *vxlan,
if (err)
return err;
- if (vattrs[VXLAN_VNIFILTER_ENTRY_START]) {
- vni_start = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_START]);
- vni_end = vni_start;
- }
-
- if (vattrs[VXLAN_VNIFILTER_ENTRY_END])
- vni_end = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_END]);
+ vxlan_vni_filter_entry_range(vattrs, &vni_start, &vni_end);
if (!vni_start && !vni_end) {
NL_SET_ERR_MSG_ATTR(extack, nlvnifilter,
@@ -1104,6 +1164,10 @@ static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!(cfg->flags & VXLAN_F_VNIFILTER))
return -EOPNOTSUPP;
+ err = vxlan_vnifilter_check_msg(nlh, extack);
+ if (err)
+ return err;
+
nlmsg_for_each_attr_type(attr, VXLAN_VNIFILTER_ENTRY, nlh,
sizeof(*tmsg), rem) {
err = vxlan_process_vni_filter(vxlan, attr, nlh->nlmsg_type,
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v4 5/7] vxlan: vnifilter: account per-VNI memory to memcg
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
` (3 preceding siblings ...)
2026-10-14 12:38 ` [PATCH net-next v4 4/7] vxlan: vnifilter: bound the number of VNIs one request may touch Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 6/7] vxlan: vnifilter: account the default FDB entry " Ali Firas
` (2 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
vxlan_vni_alloc() allocates a struct vxlan_vni_node and a per-CPU stats
block for every VNI, both with plain GFP_KERNEL, so neither is charged
to the cgroup of the process that created the VNI. A netdevice's own
struct and its Tx/Rx queues are already GFP_KERNEL_ACCOUNT in
alloc_netdev_mqs() (commit c948f51c1654 ("memcg: enable accounting for
net_device and Tx/Rx queues")), so these per-VNI allocations are an
unaccounted part of a device that a cgroup can grow one VNI at a time.
Charge both to the caller's cgroup with GFP_KERNEL_ACCOUNT in
vxlan_vni_alloc(). __GFP_ACCOUNT only charges an allocation made from a
task in a non-root memcg, so the sole caller, which already handles a
NULL return, is unaffected outside a memcg.
The charge lands in the caller's memcg: adding VNIs from inside one
moves each node into the accounted slab and raises the cgroup's per-CPU
memory. This covers the node and its stats only; a VNI carrying a group
or remote also installs a default FDB entry, whose allocations are not
charged here and are accounted by the next patch.
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: reworded to cover the node and stats only; the
c948f51c1654 reference narrowed to net_device and its Tx/Rx queues;
rebased.
drivers/net/vxlan/vxlan_vnifilter.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index 2999dd536625..4a631fcdf23a 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -825,10 +825,11 @@ static struct vxlan_vni_node *vxlan_vni_alloc(struct vxlan_dev *vxlan,
{
struct vxlan_vni_node *vninode;
- vninode = kzalloc_obj(*vninode);
+ vninode = kzalloc_obj(*vninode, GFP_KERNEL_ACCOUNT);
if (!vninode)
return NULL;
- vninode->stats = netdev_alloc_pcpu_stats(struct vxlan_vni_stats_pcpu);
+ vninode->stats = __netdev_alloc_pcpu_stats(struct vxlan_vni_stats_pcpu,
+ GFP_KERNEL_ACCOUNT);
if (!vninode->stats) {
kfree(vninode);
return NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v4 6/7] vxlan: vnifilter: account the default FDB entry to memcg
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
` (4 preceding siblings ...)
2026-10-14 12:38 ` [PATCH net-next v4 5/7] vxlan: vnifilter: account per-VNI memory to memcg Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 7/7] selftests: net: test the vxlan vnifilter request limit and dump replay Ali Firas
2026-10-14 12:45 ` [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory netdev-bot+sinfo
7 siblings, 1 reply; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
A VNI added through the vnifilter interface with a group or remote
installs a default FDB entry for that VNI: vxlan_vni_update_group()
calls vxlan_update_default_fdb_entry(), which calls vxlan_fdb_update()
and vxlan_fdb_create(). The entry allocates a struct vxlan_fdb and, per
remote, a struct vxlan_rdst plus its per-CPU dst cache, all with
GFP_ATOMIC and none charged to a memory cgroup.
The previous patch accounts the per-VNI node and its stats; these FDB
objects are the rest of what one vnifilter request allocates per VNI.
Charge them to the caller, as commit c948f51c1654 ("memcg: enable
accounting for net_device and Tx/Rx queues") and commit e2c8d550a973
("netfilter: ebtables: account ebt_table_info to kmemcg") do: the
lifetime of this memory is the net namespace, not the allocating task,
so the OOM killer cannot reclaim it and it must be charged to the cgroup
of the task whose request allocates it.
Thread a gfp argument through vxlan_fdb_update() to
vxlan_fdb_alloc()/vxlan_fdb_append() on both paths it can take -- the
create path (vxlan_fdb_update_create() -> vxlan_fdb_create()) and the
path that changes an existing entry's remote
(vxlan_fdb_update_existing()) -- and a second gfp through
vxlan_update_default_fdb_entry(), so each caller chooses it. Every
non-vnifilter caller of vxlan_fdb_update() -- vxlan_fdb_add(),
vxlan_snoop(), vxlan_dev_create(), vxlan_changelink() and the switchdev
vxlan_fdb_external_learn_add() -- keeps plain GFP_ATOMIC, so the data
path and unrelated callers are unchanged. dst_cache_init() already takes
a gfp argument, so no change outside the driver is needed.
A per-request add or change of a VNI's remote (RTM_NEWTUNNEL, via
vxlan_vni_update_group()) passes GFP_NOWAIT | __GFP_ACCOUNT. These
allocations run under the hash spinlock and cannot sleep, but a
configuration path does not need the atomic reserves GFP_ATOMIC grants,
and GFP_NOWAIT makes the memcg charge hard-bounded rather than
force-charged: a cgroup at its limit fails the add or change there with
-ENOMEM instead of pushing memory.current past memory.max. The failure
is clean -- the new entry is allocated before the old is freed, so an
add that fails leaves the existing entry intact and returns the error;
no established FDB state is destroyed and no false success is returned.
Creating a VNI is gated the same way by the previous patch's node and
stats (GFP_KERNEL_ACCOUNT, hard-bounded). Measured on production builds
at 2 and 8 vCPU in an 8 MiB cgroup: over-limit adds and changes return
-ENOMEM and memory.current does not exceed memory.max.
The device-wide default-remote change (RTM_NEWLINK, via
vxlan_vnilist_update_group()) keeps GFP_ATOMIC | __GFP_ACCOUNT. That
walk touches every VNI inheriting the device default in one message,
outside the per-request cap, and its existing error unwind re-installs
entries; hard-bounding it would turn a cgroup limit into a mid-walk
failure that the unwind cannot cleanly reverse. Bounding and unwinding
that pre-existing walk is left to a separate change; here it stays
force-charged, as before this series, and is charged to the task
issuing the RTM_NEWLINK.
This adds no new failure path on the data or learning paths: their
allocations already existed and keep GFP_ATOMIC; only the vnifilter
configuration path gains an -ENOMEM return, which its callers already
propagate.
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: new patch.
drivers/net/vxlan/vxlan_core.c | 47 ++++++++++++++++-------------
drivers/net/vxlan/vxlan_private.h | 7 +++--
drivers/net/vxlan/vxlan_vnifilter.c | 14 ++++++---
3 files changed, 39 insertions(+), 29 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 278d41f58d89..7991b544af5a 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -577,7 +577,7 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
/* Add/update destinations for multicast */
static int vxlan_fdb_append(struct vxlan_fdb *f,
union vxlan_addr *ip, __be16 port, __be32 vni,
- __u32 ifindex, struct vxlan_rdst **rdp)
+ __u32 ifindex, struct vxlan_rdst **rdp, gfp_t gfp)
{
struct vxlan_rdst *rd;
@@ -585,14 +585,14 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
if (rd)
return 0;
- rd = kmalloc_obj(*rd, GFP_ATOMIC);
+ rd = kmalloc_obj(*rd, gfp);
if (rd == NULL)
return -ENOMEM;
/* The driver can work correctly without a dst cache, so do not treat
* dst cache initialization errors as fatal.
*/
- dst_cache_init(&rd->dst_cache, GFP_ATOMIC | __GFP_NOWARN);
+ dst_cache_init(&rd->dst_cache, gfp | __GFP_NOWARN);
rd->remote_ip = *ip;
rd->remote_port = port;
@@ -779,11 +779,11 @@ static int vxlan_gpe_gro_complete(struct sock *sk, struct sk_buff *skb, int nhof
static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, const u8 *mac,
__u16 state, __be32 src_vni,
- __u16 ndm_flags)
+ __u16 ndm_flags, gfp_t gfp)
{
struct vxlan_fdb *f;
- f = kmalloc_obj(*f, GFP_ATOMIC);
+ f = kmalloc_obj(*f, gfp);
if (!f)
return NULL;
memset(&f->key, 0, sizeof(f->key));
@@ -869,7 +869,7 @@ int vxlan_fdb_create(struct vxlan_dev *vxlan,
__u16 state, __be16 port, __be32 src_vni,
__be32 vni, __u32 ifindex, __u16 ndm_flags,
u32 nhid, struct vxlan_fdb **fdb,
- struct netlink_ext_ack *extack)
+ struct netlink_ext_ack *extack, gfp_t gfp)
{
const struct vxlan_config *cfg = rcu_dereference_rtnl(vxlan->cfg);
struct vxlan_rdst *rd = NULL;
@@ -881,14 +881,14 @@ int vxlan_fdb_create(struct vxlan_dev *vxlan,
return -ENOSPC;
netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
- f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags);
+ f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags, gfp);
if (!f)
return -ENOMEM;
if (nhid)
rc = vxlan_fdb_nh_update(vxlan, f, nhid, extack);
else
- rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+ rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd, gfp);
if (rc < 0)
goto errout;
@@ -984,7 +984,7 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
__u32 ifindex, __u16 ndm_flags,
struct vxlan_fdb *f, u32 nhid,
bool swdev_notify,
- struct netlink_ext_ack *extack)
+ struct netlink_ext_ack *extack, gfp_t gfp)
{
__u16 fdb_flags = (ndm_flags & ~NTF_USE);
struct vxlan_rdst *rd = NULL;
@@ -1047,7 +1047,8 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
if ((flags & NLM_F_APPEND) &&
(is_multicast_ether_addr(f->key.eth_addr) ||
is_zero_ether_addr(f->key.eth_addr))) {
- rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
+ rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd,
+ gfp);
if (rc < 0)
return rc;
@@ -1088,7 +1089,7 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
__be16 port, __be32 src_vni, __be32 vni,
__u32 ifindex, __u16 ndm_flags, u32 nhid,
bool swdev_notify,
- struct netlink_ext_ack *extack)
+ struct netlink_ext_ack *extack, gfp_t gfp)
{
__u16 fdb_flags = (ndm_flags & ~NTF_USE);
struct vxlan_fdb *f;
@@ -1101,7 +1102,7 @@ static int vxlan_fdb_update_create(struct vxlan_dev *vxlan,
netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
rc = vxlan_fdb_create(vxlan, mac, ip, state, port, src_vni,
- vni, ifindex, fdb_flags, nhid, &f, extack);
+ vni, ifindex, fdb_flags, nhid, &f, extack, gfp);
if (rc < 0)
return rc;
@@ -1124,7 +1125,7 @@ int vxlan_fdb_update(struct vxlan_dev *vxlan,
__be16 port, __be32 src_vni, __be32 vni,
__u32 ifindex, __u16 ndm_flags, u32 nhid,
bool swdev_notify,
- struct netlink_ext_ack *extack)
+ struct netlink_ext_ack *extack, gfp_t gfp)
{
struct vxlan_fdb *f;
@@ -1138,7 +1139,8 @@ int vxlan_fdb_update(struct vxlan_dev *vxlan,
return vxlan_fdb_update_existing(vxlan, ip, state, flags, port,
vni, ifindex, ndm_flags, f,
- nhid, swdev_notify, extack);
+ nhid, swdev_notify, extack,
+ gfp);
} else {
if (!(flags & NLM_F_CREATE))
return -ENOENT;
@@ -1146,7 +1148,7 @@ int vxlan_fdb_update(struct vxlan_dev *vxlan,
return vxlan_fdb_update_create(vxlan, mac, ip, state, flags,
port, src_vni, vni, ifindex,
ndm_flags, nhid, swdev_notify,
- extack);
+ extack, gfp);
}
}
@@ -1287,7 +1289,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags,
port, src_vni, vni, ifindex,
ndm->ndm_flags | NTF_VXLAN_ADDED_BY_USER,
- nhid, true, extack);
+ nhid, true, extack, GFP_ATOMIC);
spin_unlock_bh(&vxlan->hash_lock);
if (!err)
@@ -1507,7 +1509,8 @@ static enum skb_drop_reason vxlan_snoop(struct net_device *dev,
cfg->dst_port,
vni,
cfg->vni,
- ifindex, NTF_SELF, 0, true, NULL);
+ ifindex, NTF_SELF, 0, true, NULL,
+ GFP_ATOMIC);
spin_unlock(&vxlan->hash_lock);
}
@@ -4154,7 +4157,7 @@ static int vxlan_dev_create(struct net *net, struct net_device *dev,
cfg->vni,
cfg->vni,
cfg->remote_ifindex,
- NTF_SELF, 0, true, extack);
+ NTF_SELF, 0, true, extack, GFP_ATOMIC);
spin_unlock_bh(&vxlan->hash_lock);
if (err)
goto unlink;
@@ -4617,7 +4620,8 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
cfg->dst_port,
conf.vni, conf.vni,
conf.remote_ifindex,
- NTF_SELF, 0, true, extack);
+ NTF_SELF, 0, true, extack,
+ GFP_ATOMIC);
if (err) {
spin_unlock_bh(&vxlan->hash_lock);
if (lowerdev_changed)
@@ -4652,7 +4656,8 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
&cfg->remote_ip,
conf.remote_ifindex,
cfg->remote_ifindex,
- NULL);
+ NULL,
+ GFP_ATOMIC | __GFP_ACCOUNT);
if (lowerdev_changed)
netdev_adjacent_change_abort(vxlan->lowerdev,
lowerdev, dev);
@@ -4972,7 +4977,7 @@ vxlan_fdb_external_learn_add(struct net_device *dev,
fdb_info->remote_vni,
fdb_info->remote_ifindex,
NTF_USE | NTF_SELF | NTF_EXT_LEARNED,
- 0, false, extack);
+ 0, false, extack, GFP_ATOMIC);
spin_unlock_bh(&vxlan->hash_lock);
return err;
diff --git a/drivers/net/vxlan/vxlan_private.h b/drivers/net/vxlan/vxlan_private.h
index f0ee85f83732..b5a80ed3eff2 100644
--- a/drivers/net/vxlan/vxlan_private.h
+++ b/drivers/net/vxlan/vxlan_private.h
@@ -192,7 +192,7 @@ int vxlan_fdb_create(struct vxlan_dev *vxlan,
__u16 state, __be16 port, __be32 src_vni,
__be32 vni, __u32 ifindex, __u16 ndm_flags,
u32 nhid, struct vxlan_fdb **fdb,
- struct netlink_ext_ack *extack);
+ struct netlink_ext_ack *extack, gfp_t gfp);
int __vxlan_fdb_delete(struct vxlan_dev *vxlan,
const unsigned char *addr, union vxlan_addr ip,
__be16 port, __be32 src_vni, __be32 vni,
@@ -202,7 +202,8 @@ int vxlan_fdb_update(struct vxlan_dev *vxlan,
__u16 state, __u16 flags,
__be16 port, __be32 src_vni, __be32 vni,
__u32 ifindex, __u16 ndm_flags, u32 nhid,
- bool swdev_notify, struct netlink_ext_ack *extack);
+ bool swdev_notify, struct netlink_ext_ack *extack,
+ gfp_t gfp);
void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
const struct vxlan_config *cfg,
__be32 default_vni, struct vxlan_rdst *rdst, bool did_rsc);
@@ -229,7 +230,7 @@ int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *remote_ip,
u32 old_ifindex, u32 new_ifindex,
- struct netlink_ext_ack *extack);
+ struct netlink_ext_ack *extack, gfp_t gfp);
int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *new_remote_ip,
diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
index 4a631fcdf23a..4b43674cceff 100644
--- a/drivers/net/vxlan/vxlan_vnifilter.c
+++ b/drivers/net/vxlan/vxlan_vnifilter.c
@@ -553,7 +553,7 @@ int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
const union vxlan_addr *old_remote_ip,
const union vxlan_addr *remote_ip,
u32 old_ifindex, u32 new_ifindex,
- struct netlink_ext_ack *extack)
+ struct netlink_ext_ack *extack, gfp_t gfp)
{
const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
int err = 0;
@@ -575,7 +575,8 @@ int vxlan_update_default_fdb_entry(struct vxlan_dev *vxlan, __be32 vni,
vni,
vni,
new_ifindex,
- NTF_SELF, 0, true, extack);
+ NTF_SELF, 0, true, extack,
+ gfp);
if (err && extack) {
spin_unlock_bh(&vxlan->hash_lock);
return err;
@@ -636,7 +637,8 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
oldrip, newrip,
cfg->remote_ifindex,
cfg->remote_ifindex,
- extack);
+ extack,
+ GFP_NOWAIT | __GFP_ACCOUNT);
if (ret)
goto out;
@@ -707,7 +709,8 @@ int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
ret = vxlan_update_default_fdb_entry(vxlan, vent->vni,
oldrip, newrip,
old_ifindex, new_ifindex,
- extack);
+ extack,
+ GFP_ATOMIC | __GFP_ACCOUNT);
if (ret)
goto err_unwind;
}
@@ -729,7 +732,8 @@ int vxlan_vnilist_update_group(struct vxlan_dev *vxlan,
vxlan_update_default_fdb_entry(vxlan, vent->vni,
newrip, oldrip,
new_ifindex, old_ifindex,
- NULL);
+ NULL,
+ GFP_ATOMIC | __GFP_ACCOUNT);
}
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH net-next v4 7/7] selftests: net: test the vxlan vnifilter request limit and dump replay
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
` (5 preceding siblings ...)
2026-10-14 12:38 ` [PATCH net-next v4 6/7] vxlan: vnifilter: account the default FDB entry " Ali Firas
@ 2026-10-14 12:38 ` Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:45 ` [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory netdev-bot+sinfo
7 siblings, 1 reply; 14+ messages in thread
From: Ali Firas @ 2026-10-14 12:38 UTC (permalink / raw)
To: netdev, idosch
Cc: kuba, pabeni, davem, edumazet, andrew+netdev, horms, razor, roopa,
shuah, linux-kselftest, linux-kernel, Ali Firas
Extend the vnifilter tests for the request-size limit, the 24-bit VNI
range, and the dump/replay round trip the limit requires.
The API test gains: the largest accepted add and one VNI past it; a
rejected oversized add and a rejected multi-entry add whose entries are
each under the limit but sum over it, each checked to install nothing
(the range is asserted absent first, since vxlan_vni_add() folds an
existing VNI into the update path and would return 0 either way). The cap
is symmetric, so it also checks a maximum-size delete accepted and a
max+1 delete rejected, with every VNI in the max+1 range installed first
so the refusal can only come from the cap; a within-cap delete of a
never-installed range, which must fail on the missing VNI; an inverted
range accepted as a no-op; and the 24-bit bound exercised through END,
not only START.
bridge(8) places one VXLAN_VNIFILTER_ENTRY per comma-separated item into
a single message, so the multi-entry case is reachable without a
hand-built netlink message.
vxlan_vnifilter_dump_replay() builds a contiguous run twice the limit
from two requests, then replays every range the dump reports into a
second device and requires all to be accepted and the two dumps to
match. Without the dump clamp the run dumps as one over-limit entry that
replay rejects; with it the run dumps as limit-sized entries that
replay.
vxlan_vnifilter_api() had no teardown of its own device and namespace;
add veth-host and the test netns to cleanup(), which runs on EXIT, so a
failing case does not leave them or its entries behind.
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Assisted-by: LLM
Signed-off-by: Ali Firas <alishmery18@gmail.com>
---
v4: assert the dump is non-empty before replay, so
the replay case cannot pass vacuously; rebased.
.../selftests/net/test_vxlan_vnifiltering.sh | 119 +++++++++++++++++-
1 file changed, 118 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
index 6fb5af013dac..bb35e89d2d03 100755
--- a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
+++ b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
@@ -84,6 +84,7 @@ ret=0
# all tests in this script. Can be overridden with -t option
TESTS="
vxlan_vnifilter_api
+ vxlan_vnifilter_dump_replay
vxlan_vnifilter_datapath
vxlan_vnifilter_datapath_pervni
vxlan_vnifilter_datapath_mgroup
@@ -139,8 +140,9 @@ check_vm_connectivity() {
cleanup() {
ip link del veth-hv-1 2>/dev/null || true
ip link del vethhv-11 vethhv-12 vethhv-21 vethhv-22 2>/dev/null || true
+ ip link del veth-host 2>/dev/null || true
- cleanup_ns $hv_1 $hv_2 $vm_11 $vm_21 $vm_12 $vm_22 $vm_31 $vm_32
+ cleanup_ns $hv_1 $hv_2 $vm_11 $vm_21 $vm_12 $vm_22 $vm_31 $vm_32 $testns
}
trap cleanup EXIT
@@ -347,6 +349,121 @@ vxlan_vnifilter_api()
# change vxlan vnifilter flag
run_cmd "ip -netns $testns link set dev vxlan-ext1 type vxlan external novnifilter"
log_test $? 2 "Cannot unset vnifilter flag on a device"
+
+ # A single request may add at most 4096 VNIs. bridge(8) puts one
+ # VXLAN_VNIFILTER_ENTRY per comma-separated item into a single message,
+ # so both the single-entry and the multi-entry paths are reachable here.
+
+ # The largest accepted add, and one VNI more rejected.
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 10000-14095"
+ log_test $? 0 "Add a request of the maximum VNI count"
+
+ # The rejected oversized add must install nothing. Assert the range is
+ # absent first: vxlan_vni_add() folds an already-present VNI into the
+ # update path and returns 0, so a later probe cannot tell "installed
+ # nothing" from "installed part" unless it started absent.
+ run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 20000"
+ log_test $? 1 "VNI 20000 absent before the oversized add"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 20000-24096"
+ log_test $? 255 "Cannot add a request over the maximum VNI count"
+ run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 20000"
+ log_test $? 1 "The rejected oversized add installed nothing"
+
+ # Two entries each under the limit but summing over it: the per-message
+ # total is what is bounded, not the span of one entry. This is the shape
+ # a per-entry check would have let through.
+ run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 30000"
+ log_test $? 1 "VNI 30000 absent before the oversized multi-entry add"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 30000-32047,32048-34097"
+ log_test $? 255 "Cannot add a multi-entry request summing over the maximum"
+ run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 30000"
+ log_test $? 1 "The rejected multi-entry add installed nothing"
+
+ # The cap is symmetric: a delete may touch at most the maximum too.
+ # Install a maximum-size range and the VNI past it, so the max+1 delete
+ # below has every VNI present and can only be refused by the cap, not by
+ # a missing VNI.
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 40000-44095"
+ log_test $? 0 "Populate a maximum-size range to delete"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 44096"
+ log_test $? 0 "Add the VNI past the maximum range"
+ run_cmd "bridge -netns $testns vni del dev vxlan-ext1 vni 40000-44096"
+ log_test $? 255 "Cannot delete a request over the maximum VNI count"
+ run_cmd "bridge -netns $testns vni del dev vxlan-ext1 vni 40000-44095"
+ log_test $? 0 "Delete a request of the maximum VNI count"
+ run_cmd "bridge -netns $testns vni del dev vxlan-ext1 vni 44096"
+ log_test $? 0 "Delete the VNI past the maximum range"
+
+ # A within-cap delete of a never-installed range reaches the handler and
+ # fails there on the missing VNI, not on the cap.
+ run_cmd "bridge -netns $testns vni del dev vxlan-ext1 vni 50000-50010"
+ log_test $? 255 "Cannot delete a range that was never installed"
+
+ # A start above the end selects nothing and is accepted as a no-op.
+ # Use a VNI no earlier case installs, so the absence check is meaningful.
+ run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 55000"
+ log_test $? 1 "VNI 55000 absent before the inverted range"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 55000-50000"
+ log_test $? 0 "An inverted range is accepted as a no-op"
+ run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 55000"
+ log_test $? 1 "The inverted range installed nothing"
+
+ # The VXLAN header carries 24 bits. The bound is on both endpoints, so a
+ # range whose END alone leaves the space is rejected too.
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 16777215"
+ log_test $? 0 "Add the highest VNI the header can carry"
+ run_cmd "bridge -netns $testns vni del dev vxlan-ext1 vni 16777215"
+ log_test $? 0 "Delete the highest VNI the header can carry"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 16777215-16777216"
+ log_test $? 255 "Cannot add a range whose END leaves the 24-bit space"
+ run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 100-4294967295"
+ log_test $? 255 "Cannot add a range whose END wraps past the 24-bit space"
+}
+
+# A device may hold a contiguous run longer than one request's limit, built
+# from several requests. The dump coalesces it, so the dump must break the run
+# into entries each no larger than the limit, or the configuration it reports
+# cannot be replayed. Install such a run, then feed every range the dump
+# reports back into a second device and require all to be accepted.
+vxlan_vnifilter_dump_replay()
+{
+ local opts="external vnifilter local 172.16.0.1 dev veth-testns"
+ local range rc=0 src_ranges dst_ranges
+
+ cleanup_vnifilter_api &>/dev/null
+ setup_vnifilter_api
+
+ # The destination is on a different dstport so re-adding the same VNIs
+ # does not collide with the source under vxlan_vni_in_use().
+ run_cmd "ip -netns $testns link add vxlan-src type vxlan $opts dstport 4789"
+ log_test $? 0 "dump/replay: create source device"
+ run_cmd "ip -netns $testns link add vxlan-dst type vxlan $opts dstport 4790"
+ log_test $? 0 "dump/replay: create destination device"
+
+ # 8192 contiguous VNIs sharing the default remote: one run, twice the
+ # limit, installed in two accepted requests.
+ run_cmd "bridge -netns $testns vni add dev vxlan-src vni 10000-14095"
+ run_cmd "bridge -netns $testns vni add dev vxlan-src vni 14096-18191"
+ log_test $? 0 "dump/replay: populate a run larger than the limit"
+
+ # Assert the dump is non-empty before replaying it, so an empty or
+ # failed dump cannot let the replay check below pass without testing
+ # anything.
+ src_ranges=$(bridge -netns $testns vni show dev vxlan-src | \
+ grep -oE '[0-9]+-[0-9]+|[0-9]{2,}' | sort)
+ test -n "$src_ranges"
+ log_test $? 0 "dump/replay: source dump is non-empty"
+
+ for range in $src_ranges; do
+ bridge -netns $testns vni add dev vxlan-dst vni "$range" \
+ 2>/dev/null || rc=$?
+ done
+ log_test $rc 0 "dump/replay: every dumped entry is accepted on replay"
+
+ dst_ranges=$(bridge -netns $testns vni show dev vxlan-dst | \
+ grep -oE '[0-9]+-[0-9]+|[0-9]{2,}' | sort)
+ [ "$src_ranges" = "$dst_ranges" ]
+ log_test $? 0 "dump/replay: source and destination dump the same ranges"
}
# Sanity test vnifilter datapath
--
2.53.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
` (6 preceding siblings ...)
2026-10-14 12:38 ` [PATCH net-next v4 7/7] selftests: net: test the vxlan vnifilter request limit and dump replay Ali Firas
@ 2026-10-14 12:45 ` netdev-bot+sinfo
7 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sinfo @ 2026-10-14 12:45 UTC (permalink / raw)
To: Ali Firas
Cc: netdev, idosch, kuba, pabeni, davem, edumazet, andrew+netdev,
horms, razor, roopa, shuah, linux-kselftest, linux-kernel
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v4 2/7] vxlan: vnifilter: reject VNIs outside the 24-bit space
2026-10-14 12:38 ` [PATCH net-next v4 2/7] vxlan: vnifilter: reject VNIs outside the 24-bit space Ali Firas
@ 2026-10-18 13:16 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:16 UTC (permalink / raw)
To: alishmery18
Cc: netdev, idosch, kuba, pabeni, davem, edumazet, andrew+netdev,
horms, razor, roopa, shuah, linux-kselftest, linux-kernel
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] This patch fixes long-standing defects in vxlan_vni_add_del() and
vni_filter_entry_policy, but it has no Fixes: tag and is posted to…
--
vxlan: vnifilter: reject VNIs outside the 24-bit space
This patch adds NLA_POLICY_FULL_RANGE() checks to
VXLAN_VNIFILTER_ENTRY_START and VXLAN_VNIFILTER_ENTRY_END, which limits
both to VXLAN_N_VID - 1. It also changes the loop counter in
vxlan_vni_add_del() from int to u32, so a range that ends at 0xffffffff
can no longer wrap.
> How many VNIs a single in-range request may span is a
> separate question, bounded by the next patch; that limit is not a policy
> check and does run in the handler.
[ ... ]
> Assisted-by: LLM
> Signed-off-by: Ali Firas <alishmery18@gmail.com>
>
> ---
> v4: no functional change; rebased onto net-next.
[Severity: Low]
Should this patch have a Fixes: tag and go to net instead of net-next?
The int loop counter and the plain NLA_U32 policy entries seem to date
from commit f9c4bb0b245c ("vxlan: vni filtering support on collect
metadata device"), which was merged in v5.18:
int v, err = 0;
...
for (v = start_vni; v <= end_vni; v++) {
Since then, a request that carries only
VXLAN_VNIFILTER_ENTRY_START=0xffffffff passes this check in
vxlan_process_vni_filter():
if (!vni_start && !vni_end) {
The loop in vxlan_vni_add_del() then visits 0xffffffff, 0, 1, and so on.
Each pass allocates a vxlan_vni_node and a per-CPU stats block under
rtnl_lock, and the loop only stops on an error such as -E2BIG from the
rhashtable or -ENOMEM. VNIs at or above VXLAN_N_VID are also stored,
while vxlan_vni_field() truncates them on the wire.
Anyone with CAP_NET_ADMIN over the netns can reach this, including root
in a user namespace.
Without a Fixes: tag, will the 24-bit aliasing fix and the signed
overflow fix reach stable kernels?
A backport would also need the preceding commit "vxlan: vnifilter:
validate the VXLAN_VNIFILTER_ENTRY nest". Without its NLA_POLICY_NESTED()
link, the new range policy is only applied per entry, by the
nla_parse_nested() call in vxlan_process_vni_filter().
The commit message also says the span is "bounded by the next patch".
The next patch in the series looks like "vxlan: vnifilter: clamp the
dumped VNI range to the request limit". The cap itself is in "vxlan:
vnifilter: bound the number of VNIs one request may touch", and that
patch says it is not a backport candidate.
Could the reference be corrected so backporters get accurate dependency
information?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014123814.388557-1-alishmery18%40gmail.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v4 3/7] vxlan: vnifilter: clamp the dumped VNI range to the request limit
2026-10-14 12:38 ` [PATCH net-next v4 3/7] vxlan: vnifilter: clamp the dumped VNI range to the request limit Ali Firas
@ 2026-10-18 13:16 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:16 UTC (permalink / raw)
To: alishmery18
Cc: netdev, idosch, kuba, pabeni, davem, edumazet, andrew+netdev,
horms, razor, roopa, shuah, linux-kselftest, linux-kernel
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The comment above VXLAN_VNI_FILTER_MSG_MAX in
drivers/net/vxlan/vxlan_vnifilter.c (lines 20-24) describes the order…
--
vxlan: vnifilter: clamp the dumped VNI range to the request limit
This commit adds VXLAN_VNI_FILTER_MSG_MAX and limits
vxlan_vnifilter_dump_dev() in two ways. A coalesced run of VNIs ends once
it reaches the limit, and each netlink message has a VNI budget. As a
result, no dumped message holds more VNIs than the input path accepts in
one request after a later patch in the series.
> diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
> index 9e15f4de75c99..5beec29eb84a8 100644
> --- a/drivers/net/vxlan/vxlan_vnifilter.c
> +++ b/drivers/net/vxlan/vxlan_vnifilter.c
> @@ -17,6 +17,13 @@
>
> #include "vxlan_private.h"
>
> +/* The dump coalesces a contiguous run of VNIs into entries, and packs entries
> + * into netlink messages, of at most this many VNIs each, so every message the
> + * dump emits stays within what the input path will accept on replay. A later
> + * patch bounds a single RTM_NEWTUNNEL/RTM_DELTUNNEL request to the same number.
> + */
> +#define VXLAN_VNI_FILTER_MSG_MAX 4096
[Severity: Low]
This isn't a bug, but will the "A later patch bounds a single
RTM_NEWTUNNEL/RTM_DELTUNNEL request to the same number" sentence go stale
once the series is merged?
At the end of the series this comment is unchanged. By then, the commit
"vxlan: vnifilter: bound the number of VNIs one request may touch" has
added the request cap. vxlan_vnifilter_process() calls
vxlan_vnifilter_check_msg(), which does this:
if (vnis > VXLAN_VNI_FILTER_MSG_MAX) {
Once merged, "a later patch" no longer points to anything. The comment
also doesn't say where the input-side limit is enforced.
Could the comment describe the invariant instead? For example, "must
match the per-request limit enforced by vxlan_vnifilter_check_msg()".
Another option is to move that sentence into the patch that adds the
cap.
The dump and input paths agree in the final tree, so this is only about
the comment text.
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014123814.388557-1-alishmery18%40gmail.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v4 4/7] vxlan: vnifilter: bound the number of VNIs one request may touch
2026-10-14 12:38 ` [PATCH net-next v4 4/7] vxlan: vnifilter: bound the number of VNIs one request may touch Ali Firas
@ 2026-10-18 13:16 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:16 UTC (permalink / raw)
To: alishmery18
Cc: netdev, idosch, kuba, pabeni, davem, edumazet, andrew+netdev,
horms, razor, roopa, shuah, linux-kselftest, linux-kernel
Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.
Low priority / nit picks for your consideration:
- [Low] The comment above VXLAN_VNI_FILTER_MSG_MAX in
drivers/net/vxlan/vxlan_vnifilter.c says: "A later patch bounds a…
--
vxlan: vnifilter: bound the number of VNIs one request may touch
This commit adds vxlan_vnifilter_check_msg(). It adds up the VNI spans of
every VXLAN_VNIFILTER_ENTRY in an RTM_NEWTUNNEL or RTM_DELTUNNEL request.
If the total is more than VXLAN_VNI_FILTER_MSG_MAX, the whole message is
rejected before any entry is applied. The range extraction is moved into
vxlan_vni_filter_entry_range() so the check and the dispatch path use the
same logic.
> diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
> index 5beec29eb84a8..2999dd536625e 100644
> --- a/drivers/net/vxlan/vxlan_vnifilter.c
> +++ b/drivers/net/vxlan/vxlan_vnifilter.c
[ ... ]
> +/* Reject a request touching more than VXLAN_VNI_FILTER_MSG_MAX VNIs before any
> + * of its entries is acted on. Both add and delete walk the span one VNI at a
> + * time under rtnl_lock, so both are bounded. Entries are applied one at a time
> + * and each one notifies as it goes, so a limit checked inside the dispatch loop
> + * would leave the entries ahead of the offending one already applied.
> + */
> +static int vxlan_vnifilter_check_msg(const struct nlmsghdr *nlh,
> + struct netlink_ext_ack *extack)
[Severity: Low]
This isn't a bug, but should the comment above VXLAN_VNI_FILTER_MSG_MAX
be updated now that this function exists?
The preceding patch added this to the top of vxlan_vnifilter.c:
/* The dump coalesces a contiguous run of VNIs into entries, and packs entries
* into netlink messages, of at most this many VNIs each, so every message the
* dump emits stays within what the input path will accept on replay. A later
* patch bounds a single RTM_NEWTUNNEL/RTM_DELTUNNEL request to the same number.
*/
#define VXLAN_VNI_FILTER_MSG_MAX 4096
This commit is the later patch that sentence refers to. Once it is
applied, the comment still describes the per-request limit as future work.
The text is also the same at the end of the series.
Could the last sentence say that vxlan_vnifilter_check_msg() applies the
same bound to a single request?
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014123814.388557-1-alishmery18%40gmail.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v4 6/7] vxlan: vnifilter: account the default FDB entry to memcg
2026-10-14 12:38 ` [PATCH net-next v4 6/7] vxlan: vnifilter: account the default FDB entry " Ali Firas
@ 2026-10-18 13:16 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:16 UTC (permalink / raw)
To: alishmery18
Cc: netdev, idosch, kuba, pabeni, davem, edumazet, andrew+netdev,
horms, razor, roopa, shuah, linux-kselftest, linux-kernel
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 (1) · Low: 2
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] This patch adds a deliberate, deterministic -ENOMEM to the VNI
create path: vxlan_vni_update_group() calls…
- [Low] Commit message inaccuracy.
- [Low] In vxlan_fdb_update_existing() (drivers/net/vxlan/vxlan_core.c),
f->state and f->flags are overwritten before vxlan_fdb_append(), which…
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but the
RTM_NEWNEIGH path vxlan_fdb_add() still allocates the same objects…
--
vxlan: vnifilter: account the default FDB entry to memcg
This patch adds a gfp_t argument to vxlan_fdb_update() and
vxlan_update_default_fdb_entry(). The argument is passed down to the
struct vxlan_fdb, struct vxlan_rdst and dst_cache allocations. The
per-VNI RTM_NEWTUNNEL path uses GFP_NOWAIT | __GFP_ACCOUNT, the
device-wide RTM_NEWLINK walk uses GFP_ATOMIC | __GFP_ACCOUNT, and all
other callers keep GFP_ATOMIC.
> diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
> index 278d41f58d895..7991b544af5a4 100644
> --- a/drivers/net/vxlan/vxlan_core.c
> +++ b/drivers/net/vxlan/vxlan_core.c
[ ... ]
> @@ -1047,7 +1047,8 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,
> if ((flags & NLM_F_APPEND) &&
> (is_multicast_ether_addr(f->key.eth_addr) ||
> is_zero_ether_addr(f->key.eth_addr))) {
> - rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd);
> + rc = vxlan_fdb_append(f, ip, port, vni, ifindex, &rd,
> + gfp);
>
> if (rc < 0)
> return rc;
[Severity: Low]
The vnifilter change path now passes GFP_NOWAIT | __GFP_ACCOUNT, so this
append can fail once the memcg is at its limit. By that point,
vxlan_fdb_update_existing() has already overwritten f->state and f->flags:
if (!(fdb_flags & NTF_EXT_LEARNED) ||
!(f->flags & NTF_VXLAN_ADDED_BY_USER)) {
if (f->state != state) {
f->state = state;
notify = 1;
}
if (f->flags != fdb_flags) {
f->flags = fdb_flags;
notify = 1;
}
}
On the vxlan_vni_update_group(create=false) ->
vxlan_update_default_fdb_entry() path, fdb_flags is NTF_SELF without
NTF_EXT_LEARNED. So the existing all-zeros entry always has its state and
flags reset. For example, a user-set NTF_VXLAN_ADDED_BY_USER is dropped.
If vxlan_fdb_append() then returns -ENOMEM, the return rc path does not
restore these fields, and no RTM_NEWNEIGH is sent.
Could the state/flags update move to after a successful append, or be
rolled back here? This ordering is older than this patch, but the failure
is now deterministic. The commit message also says "no established FDB
state is destroyed", which doesn't quite hold for these fields.
[ ... ]
> @@ -1287,7 +1289,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
> err = vxlan_fdb_update(vxlan, addr, &ip, ndm->ndm_state, flags,
> port, src_vni, vni, ifindex,
> ndm->ndm_flags | NTF_VXLAN_ADDED_BY_USER,
> - nhid, true, extack);
> + nhid, true, extack, GFP_ATOMIC);
> spin_unlock_bh(&vxlan->hash_lock);
[Severity: Medium]
This isn't a bug introduced by this patch, but this RTM_NEWNEIGH path
still allocates the same struct vxlan_fdb, struct vxlan_rdst and per-CPU
dst_cache without charging them to a memcg.
With NLM_F_APPEND on the all-zeros MAC or a multicast MAC, each distinct
(ip, port, vni, ifindex) adds a new rdst plus dst_cache:
vxlan_fdb_add()
vxlan_fdb_update(..., GFP_ATOMIC)
vxlan_fdb_update_existing()
vxlan_fdb_append()
This path never reaches the cfg->addrmax check in vxlan_fdb_create(). A
task with CAP_NET_ADMIN in the netns can keep growing this memory
uncharged, including by appending to the vnifilter default entries that
this patch now charges.
The commit message limits the scope to vnifilter, so this may be planned
as a follow-up. Would it make sense to account this path as well?
[ ... ]
> @@ -4652,7 +4656,8 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
> &cfg->remote_ip,
> conf.remote_ifindex,
> cfg->remote_ifindex,
> - NULL);
> + NULL,
> + GFP_ATOMIC | __GFP_ACCOUNT);
> if (lowerdev_changed)
> netdev_adjacent_change_abort(vxlan->lowerdev,
> lowerdev, dev);
[Severity: Low]
The commit message says:
The device-wide default-remote change (RTM_NEWLINK, via
vxlan_vnilist_update_group()) keeps GFP_ATOMIC | __GFP_ACCOUNT.
...
here it stays force-charged, as before this series, and is charged to
the task issuing the RTM_NEWLINK.
Before this patch, vxlan_fdb_alloc() and vxlan_fdb_append() hard-coded
GFP_ATOMIC without __GFP_ACCOUNT, so nothing on the
vxlan_vnilist_update_group() walk was charged. Isn't the accounting, and
the force-charging, new behaviour added by this patch rather than kept?
The message also doesn't mention this vxlan_changelink() rollback call,
which now gets GFP_ATOMIC | __GFP_ACCOUNT. The rollback re-creates the
conf.vni default entry as accounted. vxlan_dev_create() and the forward
vxlan_fdb_update() call in vxlan_changelink() create the same kind of
entry unaccounted. Is that inconsistency intended?
[ ... ]
> diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
> index 4a631fcdf23ab..4b43674cceff0 100644
> --- a/drivers/net/vxlan/vxlan_vnifilter.c
> +++ b/drivers/net/vxlan/vxlan_vnifilter.c
[ ... ]
> @@ -636,7 +637,8 @@ static int vxlan_vni_update_group(struct vxlan_dev *vxlan,
> oldrip, newrip,
> cfg->remote_ifindex,
> cfg->remote_ifindex,
> - extack);
> + extack,
> + GFP_NOWAIT | __GFP_ACCOUNT);
> if (ret)
> goto out;
[Severity: High]
With GFP_NOWAIT | __GFP_ACCOUNT, try_charge_memcg() fails without reclaim
once the memcg is at its limit. That means this call can now routinely
return -ENOMEM on the create path. Does vxlan_vni_add() handle that
failure?
By the time vxlan_vni_update_group() runs, the node is already published:
drivers/net/vxlan/vxlan_vnifilter.c:vxlan_vni_add() {
...
err = rhashtable_lookup_insert_fast(&vg->vni_hash,
&vninode->vnode,
vxlan_vni_rht_params);
...
__vxlan_vni_add_list(vxlan, vg, vninode);
if (vxlan->dev->flags & IFF_UP)
vxlan_vs_add_del_vninode(vxlan, vninode, false);
err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed,
extack);
vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL);
return err;
}
On failure, goto out skips recording vninode->remote_ip and skips the
IGMP join. The node still stays in vni_hash, vni_list and the socket VNI
hash. RTM_NEWTUNNEL is sent anyway, while the requester gets -ENOMEM. The
VNI then receives traffic but has no default all-zeros FDB entry.
Suppose the request is retried without a group while cfg->remote_ip is
set. vxlan_vni_add() finds the node and calls vxlan_vni_update() ->
vxlan_vni_update_group(create=false). old_remote_ip is still any, so
oldrip and newrip both point at &cfg->remote_ip, and this check returns 0:
if (!create && oldrip && newrip && vxlan_addr_equal(oldrip, newrip))
return 0;
Wouldn't the retry report success without ever installing the default FDB
entry? Deleting and re-adding the VNI seems to be the only way to recover.
For a range add, vxlan_vni_add_del() also stops at the first error. The
failing VNI and all VNIs added before it stay installed.
The missing unwind in vxlan_vni_add() predates this patch. It was hard to
hit while GFP_ATOMIC forced the charge through. The commit message says:
The failure
is clean -- the new entry is allocated before the old is freed, so an
add that fails leaves the existing entry intact and returns the error;
no established FDB state is destroyed and no false success is returned.
Creating a VNI is gated the same way by the previous patch's node and
stats (GFP_KERNEL_ACCOUNT, hard-bounded).
Should vxlan_vni_add() unlink and free the node, and skip the
notification, when vxlan_vni_update_group() fails, before this path
switches to GFP_NOWAIT?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014123814.388557-1-alishmery18%40gmail.com
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH net-next v4 7/7] selftests: net: test the vxlan vnifilter request limit and dump replay
2026-10-14 12:38 ` [PATCH net-next v4 7/7] selftests: net: test the vxlan vnifilter request limit and dump replay Ali Firas
@ 2026-10-18 13:16 ` netdev-bot+sashiko
0 siblings, 0 replies; 14+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:16 UTC (permalink / raw)
To: alishmery18
Cc: netdev, idosch, kuba, pabeni, davem, edumazet, andrew+netdev,
horms, razor, roopa, shuah, linux-kselftest, linux-kernel
Thank you for your contribution! Sashiko AI review found 5 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 4 (1)
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] In vxlan_vnifilter_dump_replay()
(tools/testing/selftests/net/test_vxlan_vnifiltering.sh), the exit…
- [Low] Each new 'absent before' / 'installed nothing' probe in
vxlan_vnifilter_api() runs `bridge -netns $testns vni show dev vxlan-…
- [Low] vxlan_vnifilter_dump_replay() replays the dump one range at a
time, each in its own `bridge vni add` (lines 457-460), using ranges…
- [Low] The 24-bit bound cases in vxlan_vnifilter_api() do not isolate
the START half of vni_filter_entry_policy, and one case cannot tell…
- [Low] In vxlan_vnifilter_dump_replay(), the replay result variable `rc`
is overwritten by run_cmd() before the replay loop.
Pre-existing issues:
- [Low] The comment on VXLAN_VNI_FILTER_MSG_MAX in
drivers/net/vxlan/vxlan_vnifilter.c (lines 20-24) still says 'A later…
--
selftests: net: test the vxlan vnifilter request limit and dump replay
This extends test_vxlan_vnifiltering.sh to cover the per-request VNI cap
on add and delete and the 24-bit VNI bound. It also adds a dump/replay
test that builds a contiguous run twice the limit and replays the dumped
ranges into a second device. The cleanup() handler now also removes
veth-host and the test netns.
> diff --git a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
> index 6fb5af013dacf..bb35e89d2d036 100755
> --- a/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
> +++ b/tools/testing/selftests/net/test_vxlan_vnifiltering.sh
[ ... ]
> @@ -347,6 +349,121 @@ vxlan_vnifilter_api()
> # change vxlan vnifilter flag
> run_cmd "ip -netns $testns link set dev vxlan-ext1 type vxlan external novnifilter"
> log_test $? 2 "Cannot unset vnifilter flag on a device"
> +
> + # A single request may add at most 4096 VNIs. bridge(8) puts one
> + # VXLAN_VNIFILTER_ENTRY per comma-separated item into a single message,
> + # so both the single-entry and the multi-entry paths are reachable here.
[Severity: Low]
This problem was not introduced by this patch, but the comment on
VXLAN_VNI_FILTER_MSG_MAX in drivers/net/vxlan/vxlan_vnifilter.c still
describes the request cap as future work:
drivers/net/vxlan/vxlan_vnifilter.c:
* dump emits stays within what the input path will accept on replay. A later
* patch bounds a single RTM_NEWTUNNEL/RTM_DELTUNNEL request to the same number.
*/
#define VXLAN_VNI_FILTER_MSG_MAX 4096
That cap is already in the tree. vxlan_vnifilter_process() calls
vxlan_vnifilter_check_msg() before it applies any entry:
err = vxlan_vnifilter_check_msg(nlh, extack);
if (err)
return err;
Could the "A later patch" sentence be updated, since this selftest is
exercising that cap?
> +
> + # The largest accepted add, and one VNI more rejected.
> + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 10000-14095"
> + log_test $? 0 "Add a request of the maximum VNI count"
> +
> + # The rejected oversized add must install nothing. Assert the range is
> + # absent first: vxlan_vni_add() folds an already-present VNI into the
> + # update path and returns 0, so a later probe cannot tell "installed
> + # nothing" from "installed part" unless it started absent.
> + run_cmd "bridge -netns $testns vni show dev vxlan-ext1 | grep -qw 20000"
> + log_test $? 1 "VNI 20000 absent before the oversized add"
[Severity: Low]
Can this probe pass when bridge vni show itself fails?
run_cmd() evaluates the whole pipeline and returns its status:
out=$(eval $cmd $stderr)
rc=$?
That status comes from grep. Neither this script nor lib.sh sets
pipefail. If bridge vni show fails, grep reads no input and exits 1, which
is the value log_test expects.
The same pattern is used for each of the "absent before" and "installed
nothing" probes for 20000, 30000 and 55000. That means these probes cannot
tell a VNI that is absent from a show that failed.
The src_ranges and dst_ranges captures in vxlan_vnifilter_dump_replay() also
drop the exit status of bridge.
Would it make sense to check the exit status of bridge vni show on its own,
or to set pipefail for these probes?
> + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 20000-24096"
> + log_test $? 255 "Cannot add a request over the maximum VNI count"
[ ... ]
> + # The VXLAN header carries 24 bits. The bound is on both endpoints, so a
> + # range whose END alone leaves the space is rejected too.
> + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 16777215"
> + log_test $? 0 "Add the highest VNI the header can carry"
> + run_cmd "bridge -netns $testns vni del dev vxlan-ext1 vni 16777215"
> + log_test $? 0 "Delete the highest VNI the header can carry"
> + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 16777215-16777216"
> + log_test $? 255 "Cannot add a range whose END leaves the 24-bit space"
> + run_cmd "bridge -netns $testns vni add dev vxlan-ext1 vni 100-4294967295"
> + log_test $? 255 "Cannot add a range whose END wraps past the 24-bit space"
[Severity: Low]
Does the 100-4294967295 case depend on the END range policy? Its span is
4294967196 VNIs, so vxlan_vnifilter_check_msg() would reject it with
-EINVAL even if the END bound in vni_filter_entry_policy were removed:
vnis += vni_end - vni_start + 1;
if (vnis > VXLAN_VNI_FILTER_MSG_MAX) {
The test comment ("The bound is on both endpoints") and the commit message
("exercised through END, not only START") suggest that an out-of-range
START is tested. No such case exists here or elsewhere under
tools/testing/selftests.
A single VNI such as 16777216 has no END attribute. That gives a span of
one, so check_msg accepts it, and only the START policy keeps it out of
vxlan_vni_add_del():
[VXLAN_VNIFILTER_ENTRY_START] = NLA_POLICY_FULL_RANGE(NLA_U32,
&vni_filter_vni_range),
If START=END=0xffffffff ever got past that policy, this loop would wrap
under rtnl_lock:
for (v = start_vni; v <= end_vni; v++) {
Could a case like "vni add ... vni 16777216" be added so a regression in
the START bound is caught?
> +}
> +
> +# A device may hold a contiguous run longer than one request's limit, built
> +# from several requests. The dump coalesces it, so the dump must break the run
> +# into entries each no larger than the limit, or the configuration it reports
> +# cannot be replayed. Install such a run, then feed every range the dump
> +# reports back into a second device and require all to be accepted.
> +vxlan_vnifilter_dump_replay()
> +{
> + local opts="external vnifilter local 172.16.0.1 dev veth-testns"
> + local range rc=0 src_ranges dst_ranges
[ ... ]
> + # 8192 contiguous VNIs sharing the default remote: one run, twice the
> + # limit, installed in two accepted requests.
> + run_cmd "bridge -netns $testns vni add dev vxlan-src vni 10000-14095"
> + run_cmd "bridge -netns $testns vni add dev vxlan-src vni 14096-18191"
> + log_test $? 0 "dump/replay: populate a run larger than the limit"
[Severity: Medium]
Is the status of the first populate command lost here? The $? passed to
log_test is only the status of the 14096-18191 add.
If the 10000-14095 add fails, vxlan-src holds exactly 4096 VNIs. In that
case vxlan_vnifilter_dump_dev() never reaches the clamp:
if (!dump_stats && vnirange(vend, v) == 1 &&
vnirange(vbegin, v) < VXLAN_VNI_FILTER_MSG_MAX &&
The dump is then a single limit-sized entry. The non-empty check, the
replay loop and the src/dst comparison all pass, whether or not the dump
clamp exists.
The v4 note says the non-empty check was added so the replay case cannot
pass vacuously, but this path still does.
There is a related gap. src_ranges is never compared against the expected
split (10000-14095 and 14096-18191). Both the replay input and the expected
result come from the same source dump.
A resume regression in vxlan_vnifilter_dump_dev() could drop or repeat VNIs
at the 4096 boundary, or lose the second message:
if (!err && vbegin) {
if (vnis + vnirange(vbegin, vend) + 1 > VXLAN_VNI_FILTER_MSG_MAX)
err = -EMSGSIZE;
Wouldn't that produce the same wrong ranges on both devices and still
pass?
Could each populate command get its own log_test, and could src_ranges be
checked against the literal expected ranges?
> +
> + # Assert the dump is non-empty before replaying it, so an empty or
> + # failed dump cannot let the replay check below pass without testing
> + # anything.
> + src_ranges=$(bridge -netns $testns vni show dev vxlan-src | \
> + grep -oE '[0-9]+-[0-9]+|[0-9]{2,}' | sort)
> + test -n "$src_ranges"
> + log_test $? 0 "dump/replay: source dump is non-empty"
> +
> + for range in $src_ranges; do
> + bridge -netns $testns vni add dev vxlan-dst vni "$range" \
> + 2>/dev/null || rc=$?
> + done
[Severity: Low]
This loop replays one range per bridge vni add, using ranges parsed from
the text output of bridge vni show. That output loses netlink message
boundaries, so the per-message VNI budget in vxlan_vnifilter_dump_dev() is
never tested:
if (vnis + sz > VXLAN_VNI_FILTER_MSG_MAX) {
err = -EMSGSIZE;
break;
}
vxlan_vnifilter_check_msg() caps the sum across all entries in a request.
Suppose that budget were removed and the merge clamp kept. The 8192-VNI
run would be dumped as 10000-14095 and 14096-18191 in one message, and that
message would be rejected if replayed as a single request.
Each range would still replay on its own here, the dumps would match, and
the test would pass. Is the per-message half of the dump guarantee meant
to be covered by this test?
> + log_test $rc 0 "dump/replay: every dumped entry is accepted on replay"
[Severity: Low]
Can rc be non-zero here even when every replay add succeeded?
run_cmd() assigns rc=$? without declaring it local. Because bash scoping is
dynamic, that assignment writes to the local rc in
vxlan_vnifilter_dump_replay(). After the 14096-18191 populate run_cmd, rc
holds that command's exit status.
The replay loop only assigns rc when an add fails. So if the populate
failed, this line also reports FAIL even when all replays succeeded, and
the rc=0 initializer has no effect.
Would resetting rc=0 just before the loop, or using a separate variable,
avoid this?
> +
> + dst_ranges=$(bridge -netns $testns vni show dev vxlan-dst | \
> + grep -oE '[0-9]+-[0-9]+|[0-9]{2,}' | sort)
> + [ "$src_ranges" = "$dst_ranges" ]
> + log_test $? 0 "dump/replay: source and destination dump the same ranges"
> }
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014123814.388557-1-alishmery18%40gmail.com
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-10-18 13:16 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14 12:38 [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 1/7] vxlan: vnifilter: validate the VXLAN_VNIFILTER_ENTRY nest Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 2/7] vxlan: vnifilter: reject VNIs outside the 24-bit space Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 3/7] vxlan: vnifilter: clamp the dumped VNI range to the request limit Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 4/7] vxlan: vnifilter: bound the number of VNIs one request may touch Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 5/7] vxlan: vnifilter: account per-VNI memory to memcg Ali Firas
2026-10-14 12:38 ` [PATCH net-next v4 6/7] vxlan: vnifilter: account the default FDB entry " Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:38 ` [PATCH net-next v4 7/7] selftests: net: test the vxlan vnifilter request limit and dump replay Ali Firas
2026-10-18 13:16 ` netdev-bot+sashiko
2026-10-14 12:45 ` [PATCH net-next v4 0/7] vxlan: vnifilter: bound a single request and account per-VNI memory netdev-bot+sinfo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox