mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: julius@bairaktaris.de
Cc: razor@blackwall.org, idosch@nvidia.com, andrew@lunn.ch,
	olteanv@gmail.com, netdev@vger.kernel.org,
	bridge@lists.linux.dev, davem@davemloft.net, edumazet@kernel.org,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next 1/2] net: bridge: switchdev: add br_switchdev_fdb_find_port()
Date: Mon, 09 Nov 2026 11:28:15 +0000	[thread overview]
Message-ID: <179422369502.994134.8555421343624613660@kernel.org> (raw)
In-Reply-To: <92a9adba8020449a269bb8941698ea6849b4c372.1794134495.git.julius@bairaktaris.de>

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 1 · Low: 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] br_switchdev_fdb_find_port() has a kernel-doc that says it
  returns NULL when "switchdev is not notified of" the entry.
- [Low] Concern: br_switchdev_fdb_find_port() is exported, declared in
  include/linux/if_bridge.h and given a stub there, but nothing in the…

--

net: bridge: switchdev: add br_switchdev_fdb_find_port()

This commit adds br_switchdev_fdb_find_port(), an exported RCU lookup
that returns the port of a non-local bridge FDB entry that switchdev is
notified of. The filter in br_switchdev_fdb_notify() moves into a new
helper, br_switchdev_fdb_notifies(), and both functions use it.

> diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
> index 75673b8bffcb8..e050b7e698fc9 100644
> --- a/include/linux/if_bridge.h
> +++ b/include/linux/if_bridge.h
> @@ -201,6 +201,19 @@ static inline int br_mst_get_state(const struct net_device *dev, u16 msti,
>  }
>  #endif
>  
> +#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_NET_SWITCHDEV)
> +struct net_device *br_switchdev_fdb_find_port(const struct net_device *br_dev,
> +					      const unsigned char *addr,
> +					      u16 vid);

[Severity: Low]
This isn't a bug, but nothing in this patch calls the newly exported
br_switchdev_fdb_find_port().

The only user seems to come in the next patch of the series, "net: dsa:
fix host fdb refcount when a bridge fdb entry roams". That patch calls it
from dsa_user_bridge_host_fdb_wanted() in net/dsa/user.c:

    brport = br_switchdev_fdb_find_port(bridge->dev, addr, vid);

Could the commit message name that consumer?

> +#else

[ ... ]

> diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
> index 10f3aea6a1f82..02ca1cbcfede0 100644
> --- a/net/bridge/br_switchdev.c
> +++ b/net/bridge/br_switchdev.c

[ ... ]

> @@ -156,9 +152,58 @@ br_switchdev_fdb_notify(struct net_bridge *br,
>  	 * Drivers don't know how to deal with these, so don't notify them to
>  	 * avoid confusing them.
>  	 */
> -	if (test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags) &&
> -	    !test_bit(BR_FDB_STATIC, &fdb->flags) &&
> -	    !test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags))
> +	return !test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags) ||
> +	       test_bit(BR_FDB_STATIC, &fdb->flags) ||
> +	       test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags);
> +}
> +
> +/**
> + * br_switchdev_fdb_find_port - find the port of an entry switchdev knows of
> + * @br_dev: the bridge device
> + * @addr: the MAC address of the entry
> + * @vid: the VLAN of the entry
> + *
> + * Must be called under RCU; the device is valid until the read-side critical
> + * section ends.
> + *
> + * Return: the port of the non-local entry for @addr and @vid, or NULL if
> + * there is none or switchdev is not notified of it.
> + */
> +struct net_device *br_switchdev_fdb_find_port(const struct net_device *br_dev,
> +					      const unsigned char *addr,
> +					      u16 vid)
> +{
> +	const struct net_bridge_port *p;
> +	struct net_bridge_fdb_entry *f;
> +
> +	RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "suspicious use outside RCU");
> +
> +	if (!netif_is_bridge_master(br_dev))
> +		return NULL;
> +
> +	f = br_fdb_find_rcu(netdev_priv(br_dev), addr, vid);
> +	if (!f || test_bit(BR_FDB_LOCAL, &f->flags) ||
> +	    !br_switchdev_fdb_notifies(f))
> +		return NULL;
> +
> +	/* learned by a switchdev driver, which is not notified back */
> +	if (test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags) &&
> +	    !test_bit(BR_FDB_ADDED_BY_USER, &f->flags))
> +		return NULL;

[Severity: Medium]
Does this filter match the kernel-doc above? The kernel-doc says NULL is
returned when "switchdev is not notified of" the entry.

The commit message also says the caller uses it to "ignore the entries
whose deletion it will not be notified of". Several cases seem to
contradict both statements.

The comment "learned by a switchdev driver, which is not notified back"
only holds for the addition. br_switchdev_fdb_notifies() returns true for
BR_FDB_ADDED_BY_EXT_LEARN entries. So a flush, a delete-by-port or
__br_fdb_delete() still sends SWITCHDEV_FDB_DEL_TO_DEVICE for them,
because those paths go through fdb_delete(br, f, true).

A software-learned entry has already had SWITCHDEV_FDB_ADD_TO_DEVICE
sent. Suppose a driver then reports the same addr/vid with
SWITCHDEV_FDB_ADD_TO_BRIDGE. The existing-entry branch of
br_fdb_external_learn_add() does:

    if (test_and_set_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags)) {

It leaves BR_FDB_ADDED_BY_USER clear. This helper then returns NULL for
an entry that switchdev already knows about.

Replay also skips the filter. br_switchdev_fdb_replay_one() notifies
every fdb_list entry without calling br_switchdev_fdb_notifies():

    br_switchdev_fdb_populate(br, &item, fdb, ctx);

    err = nb->notifier_call(nb, action, &item);

Locked entries and user "master dynamic" entries are therefore notified
on replay, but this helper reports them as not notified.

The opposite case looks more concerning. A user-added extern_learn entry
(bridge fdb add ... master extern_learn) goes through
__br_fdb_add()->br_fdb_external_learn_add(..., false, true). It gets
BR_FDB_ADDED_BY_USER | BR_FDB_ADDED_BY_EXT_LEARN and passes this filter.

Any switchdev driver can then delete that entry without a DEL_TO_DEVICE
notification:

br_switchdev_event(SWITCHDEV_FDB_DEL_TO_BRIDGE)
  br_fdb_external_learn_del(br, p, addr, vid, false)
    fdb_delete(br, fdb, false)

br_fdb_external_learn_del() only checks BR_FDB_ADDED_BY_EXT_LEARN, not
the port:

    if (fdb && test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags))
        fdb_delete(br, fdb, swdev_notify);

With the DSA consumer from the next patch, consider a user port that
holds a host address for such an entry on a foreign port. Would it ever
get an event telling it to drop that address? The address seems to stay
on the CPU port until a later event for that addr/vid, or until the port
leaves the bridge.

Should the kernel-doc and commit message describe what the filter really
guarantees, or should the filter change to match the stated contract?

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/cover.1794134495.git.julius%40bairaktaris.de

  reply	other threads:[~2026-11-09 11:28 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-08 11:16 [PATCH net-next 0/2] net: dsa: fix host fdb refcount when an entry roams Julius Bairaktaris
2026-11-08 11:16 ` [PATCH net-next 1/2] net: bridge: switchdev: add br_switchdev_fdb_find_port() Julius Bairaktaris
2026-11-09 11:28   ` netdev-bot+sashiko [this message]
2026-11-08 11:16 ` [PATCH net-next 2/2] net: dsa: fix host fdb refcount when a bridge fdb entry roams Julius Bairaktaris
2026-11-09 11:28   ` netdev-bot+sashiko
2026-11-08 11:22 ` [PATCH net-next 0/2] net: dsa: fix host fdb refcount when an " netdev-bot+sinfo
2026-11-08 11:47 ` Julius Bairaktaris

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=179422369502.994134.8555421343624613660@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=andrew@lunn.ch \
    --cc=bridge@lists.linux.dev \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=julius@bairaktaris.de \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=olteanv@gmail.com \
    --cc=pabeni@redhat.com \
    --cc=razor@blackwall.org \
    /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

all inboxes | Powered by JetHome®