From: netdev-bot+sashiko@kernel.org
To: edumazet@google.com
Cc: davem@davemloft.net, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, andrew+netdev@lunn.ch, idosch@nvidia.com,
kuniyu@google.com, netdev@vger.kernel.org,
eric.dumazet@gmail.com
Subject: Re: [PATCH v2 net-next 2/8] vxlan: vnifilter: use list_for_each_entry_rcu() in vxlan_vnifilter_dump_dev()
Date: Tue, 08 Sep 2026 18:03:53 +0000 [thread overview]
Message-ID: <178889063307.219967.14381012776534349065@kernel.org> (raw)
In-Reply-To: <20260906180111.1973188-3-edumazet@google.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 2 · Low: 0 (2)
- [Medium] The commit message's first justification is factually wrong
for this tree: vxlan_vnifilter_dump_dev() does NOT run "without RTNL".
- [Medium] The paginated RTM_GETTUNNEL dump resumes with pure ordinal
cursors: cb->args[0] is the position of the vxlan device in the netdev…
Pre-existing issues:
- [Low] Claim: vxlan_vnifilter_dump_dev() reads vg->num_vnis
(drivers/net/vxlan/vxlan_vnifilter.c:355) with a plain, unannotated…
- [Low] Claim: the dump reads v->remote_ip (a multi-word union
vxlan_addr) via vxlan_addr_equal() in vxlan_vnifilter_dump_dev()…
--
vxlan: vnifilter: use list_for_each_entry_rcu() in vxlan_vnifilter_dump_dev()
The patch converts the vg->vni_list walk in vxlan_vnifilter_dump_dev() from
list_for_each_entry_safe() to list_for_each_entry_rcu(), and clears
cb->args[1] on the two early returns so a stale VNI offset is not carried
over to the next device in a paginated RTM_GETTUNNEL dump.
A few questions below.
> vxlan_vnifilter_dump_dev() runs under rcu_read_lock() without RTNL when
> dumping VNI filter entries via RTM_GETTUNNEL.
>
> 1) Currently it traverses vg->vni_list using list_for_each_entry_safe(),
> which performs raw pointer accesses without RCU dereference barriers.
> Since concurrent RTNL writers modify vg->vni_list using list_add_rcu()
> and list_del_rcu(), use list_for_each_entry_rcu() instead.
[Severity: Medium]
Is the "without RTNL" part of this description accurate for this tree?
RTM_GETTUNNEL is registered in vxlan_vnifilter_rtnl_msg_handlers[] with a
flags value of 0, i.e. without RTNL_FLAG_DUMP_UNLOCKED:
drivers/net/vxlan/vxlan_vnifilter.c:
static const struct rtnl_msg_handler vxlan_vnifilter_rtnl_msg_handlers[] = {
{THIS_MODULE, PF_BRIDGE, RTM_GETTUNNEL, NULL, vxlan_vnifilter_dump, 0},
rtnetlink_dump_start() then routes the dump through rtnl_dumpit(), which
holds RTNL for the whole callback:
net/core/rtnetlink.c:rtnl_dumpit() {
const bool needs_lock = !(cb->flags & RTNL_FLAG_DUMP_UNLOCKED);
...
if (needs_lock)
rtnl_lock();
err = dumpit(skb, cb);
if (needs_lock)
rtnl_unlock();
}
The writers of vg->vni_list (__vxlan_vni_add_list() and
__vxlan_vni_del_list(), reached from the RTM_NEWTUNNEL/RTM_DELTUNNEL doit
handlers, which are also registered with flags 0, and from
vxlan_vnigroup_uninit()) run under RTNL as well.
So the previous list_for_each_entry_safe() walk appears to already have
been serialized against those writers, which would make item 1 RCU hygiene
or preparation for a future unlocked dump rather than a fix for a live
race. Item 2 does look like a real fix, since RTNL is dropped between dump
pages. Could the changelog be adjusted so that the Fixes: tag is not read
as covering an RCU list-traversal race that cannot happen today?
> diff --git a/drivers/net/vxlan/vxlan_vnifilter.c b/drivers/net/vxlan/vxlan_vnifilter.c
> index dd94085e08865..fdf25d01bc1fb 100644
> --- a/drivers/net/vxlan/vxlan_vnifilter.c
> +++ b/drivers/net/vxlan/vxlan_vnifilter.c
[ ... ]
> @@ -342,13 +342,17 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
> bool dump_stats;
> int err = 0;
>
> - if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER))
> + if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER)) {
> + cb->args[1] = 0;
> return -EINVAL;
> + }
>
> /* RCU needed because of the vni locking rules (rcu || rtnl) */
> vg = rcu_dereference(vxlan->vnigrp);
> - if (!vg || !vg->num_vnis)
> + if (!vg || !vg->num_vnis) {
> + cb->args[1] = 0;
> return 0;
> + }
[Severity: Low]
This isn't a bug introduced by this patch, but a note on the plain read of
vg->num_vnis in vxlan_vnifilter_dump_dev() while this early return is being
touched.
The counter is updated non-atomically after the RCU list publish/unlink:
drivers/net/vxlan/vxlan_vnifilter.c:__vxlan_vni_add_list() {
list_add_rcu(&v->vlist, hpos);
vg->num_vnis++;
}
drivers/net/vxlan/vxlan_vnifilter.c:__vxlan_vni_del_list() {
list_del_rcu(&v->vlist);
vg->num_vnis--;
}
As shown above, both the dump and these writers currently run under RTNL,
so there is no concurrency and no torn read today. Should this dump ever be
converted to RTNL_FLAG_DUMP_UNLOCKED, would this read need READ_ONCE(), or
could the num_vnis test simply be dropped now that the traversal itself is
RCU-safe?
>
> tmsg = nlmsg_data(cb->nlh);
> dump_stats = !!(tmsg->flags & TUNNEL_MSG_FLAG_STATS);
[ ... ]
> @@ -362,7 +366,7 @@ static int vxlan_vnifilter_dump_dev(const struct net_device *dev,
> new_tmsg->family = PF_BRIDGE;
> new_tmsg->ifindex = dev->ifindex;
>
> - list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
> + list_for_each_entry_rcu(v, &vg->vni_list, vlist) {
> if (idx < s_idx) {
> idx++;
> continue;
[Severity: Medium]
Can the same "silently skipping its first N VNIs" symptom still be reached
through device and VNI list churn between dump pages, so that clearing
cb->args[1] on the early returns is not sufficient?
Both cursors are pure ordinals. In vxlan_vnifilter_dump() the device is
matched by position:
for_each_netdev_rcu(net, dev) {
if (!netif_is_vxlan(dev))
continue;
if (idx < s_idx)
goto skip;
err = vxlan_vnifilter_dump_dev(dev, skb, cb);
and in vxlan_vnifilter_dump_dev() the VNI is matched by position:
list_for_each_entry_rcu(v, &vg->vni_list, vlist) {
if (idx < s_idx) {
idx++;
continue;
}
...
cb->args[1] = err ? idx : 0;
RTNL is released at the end of each rtnl_dumpit() invocation, so with vxlan
devices [D0, D1, D2] and a page ending mid-D1 (cb->args[0] = 1,
cb->args[1] = 40):
- D0 is deleted between recvmsg() rounds
- enumeration becomes [D1, D2]
- position 1 is now D2, so D1's remaining VNIs are never emitted
- vxlan_vnifilter_dump_dev(D2) is entered with s_idx = 40 and drops D2's
first 40 VNI entries
The new cb->args[1] = 0 statements do not help here because dump_dev() is
never called for the device the offset belonged to. bridge vni add/del
between pages shifts the VNI ordinals in the same way.
Additionally, unlike other rtnetlink dumps over the same netdev list, no
generation counter is recorded and NLM_F_DUMP_INTR is never set, so the
skipping or duplication is invisible to user space:
net/core/rtnetlink.c:rtnl_dump_ifinfo() {
cb->seq = tgt_net->dev_base_seq;
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
}
Would keying the VNI offset to the device ifindex rather than its list
position, plus a cb->seq generation with nl_dump_check_consistent(), be the
more robust fix?
[Severity: Low]
This is a pre-existing issue and not introduced by this patch, but while the
traversal is being made RCU-aware: the loop body reads the multi-word
v->remote_ip union without any annotation, both here
if (!dump_stats && vnirange(vend, v) == 1 &&
vxlan_addr_equal(&v->remote_ip, &vend->remote_ip)) {
and in vxlan_fill_vni_filter_entry(), while the writer replaces it in place:
drivers/net/vxlan/vxlan_vnifilter.c:vxlan_vni_update_group() {
if (group)
memcpy(&vninode->remote_ip, group, sizeof(vninode->remote_ip));
}
Since both paths hold RTNL as shown above, a torn value cannot be observed
by this dump today. If the dump becomes unlocked, would the in-place memcpy
of remote_ip need to be replaced by something RCU-safe so that a mismatched
sa_family and address pair cannot be emitted or used for range coalescing?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260906180111.1973188-1-edumazet%40google.com
next prev parent reply other threads:[~2026-09-08 18:03 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-06 18:01 [PATCH v2 net-next 0/8] vxlan: convert configuration to RCU and drop RTNL in vxlan_fill_info() Eric Dumazet
2026-09-06 18:01 ` [PATCH v2 net-next 1/8] vxlan: initialize _md in vxlan_xmit_one() Eric Dumazet
2026-09-06 18:01 ` [PATCH v2 net-next 2/8] vxlan: vnifilter: use list_for_each_entry_rcu() in vxlan_vnifilter_dump_dev() Eric Dumazet
2026-09-08 18:03 ` netdev-bot+sashiko [this message]
2026-09-06 18:01 ` [PATCH v2 net-next 3/8] vxlan: pass vxlan_config pointer to helper functions Eric Dumazet
2026-09-06 18:01 ` [PATCH v2 net-next 4/8] vxlan: move VXLAN_F_MDB to struct vxlan_dev flags Eric Dumazet
2026-09-06 18:01 ` [PATCH v2 net-next 5/8] vxlan: dynamically allocate struct vxlan_config Eric Dumazet
2026-09-08 18:03 ` netdev-bot+sashiko
2026-09-10 1:35 ` Jakub Kicinski
2026-09-11 2:15 ` Eric Dumazet
2026-09-06 18:01 ` [PATCH v2 net-next 6/8] vxlan: convert configuration to RCU protection Eric Dumazet
2026-09-08 18:03 ` netdev-bot+sashiko
2026-09-06 18:01 ` [PATCH v2 net-next 7/8] vxlan: remove default_dst and use vxlan_config and lowerdev Eric Dumazet
2026-09-08 18:03 ` netdev-bot+sashiko
2026-09-06 18:01 ` [PATCH v2 net-next 8/8] vxlan: no longer rely on RTNL in vxlan_fill_info() Eric Dumazet
2026-09-08 18:03 ` netdev-bot+sashiko
2026-09-10 1:40 ` [PATCH v2 net-next 0/8] vxlan: convert configuration to RCU and drop " patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178889063307.219967.14381012776534349065@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=eric.dumazet@gmail.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox