All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.