[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <YlPk4GGqcAGCEZ4s@shredder>
Date: Mon, 11 Apr 2022 11:20:48 +0300
From: Ido Schimmel <idosch@...sch.org>
To: Nikolay Aleksandrov <razor@...ckwall.org>
Cc: netdev@...r.kernel.org, roopa@...dia.com, kuba@...nel.org,
davem@...emloft.net, bridge@...ts.linux-foundation.org
Subject: Re: [PATCH net-next 2/6] net: bridge: fdb: add support for
fine-grained flushing
On Sat, Apr 09, 2022 at 01:58:53PM +0300, Nikolay Aleksandrov wrote:
> Add the ability to specify exactly which fdbs to be flushed. They are
> described by a new structure - net_bridge_fdb_flush_desc. Currently it
> can match on port/bridge ifindex, vlan id and fdb flags. It is used to
> describe the existing dynamic fdb flush operation.
>
> Signed-off-by: Nikolay Aleksandrov <razor@...ckwall.org>
> ---
> net/bridge/br_fdb.c | 36 +++++++++++++++++++++++++++++-------
> net/bridge/br_netlink.c | 9 +++++++--
> net/bridge/br_private.h | 10 +++++++++-
> net/bridge/br_sysfs_br.c | 6 +++++-
> 4 files changed, 50 insertions(+), 11 deletions(-)
>
> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
> index 6ccda68bd473..4b0bf88c4121 100644
> --- a/net/bridge/br_fdb.c
> +++ b/net/bridge/br_fdb.c
> @@ -558,18 +558,40 @@ void br_fdb_cleanup(struct work_struct *work)
> mod_delayed_work(system_long_wq, &br->gc_work, work_delay);
> }
>
> -/* Completely flush all dynamic entries in forwarding database.*/
> -void br_fdb_flush(struct net_bridge *br)
> +static bool __fdb_flush_matches(const struct net_bridge *br,
> + const struct net_bridge_fdb_entry *f,
> + const struct net_bridge_fdb_flush_desc *desc)
> +{
> + const struct net_bridge_port *dst = READ_ONCE(f->dst);
> + int port_ifidx, br_ifidx = br->dev->ifindex;
> +
> + port_ifidx = dst ? dst->dev->ifindex : 0;
> +
> + return (!desc->vlan_id || desc->vlan_id == f->key.vlan_id) &&
> + (!desc->port_ifindex ||
> + (desc->port_ifindex == port_ifidx ||
> + (!dst && desc->port_ifindex == br_ifidx))) &&
> + (!desc->flags_mask ||
> + ((f->flags & desc->flags_mask) == desc->flags));
I find this easier to read:
port_ifidx = dst ? dst->dev->ifindex : br_ifidx;
if (desc->vlan_id && desc->vlan_id != f->key.vlan_id)
return false;
if (desc->port_ifindex && desc->port_ifindex != port_ifidx)
return false;
if (desc->flags_mask && (f->flags & desc->flags_mask) != desc->flags)
return false;
return true;
> +}
> +
> +/* Flush forwarding database entries matching the description */
> +void br_fdb_flush(struct net_bridge *br,
> + const struct net_bridge_fdb_flush_desc *desc)
> {
> struct net_bridge_fdb_entry *f;
> - struct hlist_node *tmp;
>
> - spin_lock_bh(&br->hash_lock);
> - hlist_for_each_entry_safe(f, tmp, &br->fdb_list, fdb_node) {
> - if (!test_bit(BR_FDB_STATIC, &f->flags))
> + rcu_read_lock();
> + hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
> + if (!__fdb_flush_matches(br, f, desc))
> + continue;
> +
> + spin_lock_bh(&br->hash_lock);
> + if (!hlist_unhashed(&f->fdb_node))
> fdb_delete(br, f, true);
> + spin_unlock_bh(&br->hash_lock);
> }
> - spin_unlock_bh(&br->hash_lock);
> + rcu_read_unlock();
> }
>
> /* Flush all entries referring to a specific port.
> diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
> index fe2211d4c0c7..6e6dce6880c9 100644
> --- a/net/bridge/br_netlink.c
> +++ b/net/bridge/br_netlink.c
> @@ -1366,8 +1366,13 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
> br_recalculate_fwd_mask(br);
> }
>
> - if (data[IFLA_BR_FDB_FLUSH])
> - br_fdb_flush(br);
> + if (data[IFLA_BR_FDB_FLUSH]) {
> + struct net_bridge_fdb_flush_desc desc = {
> + .flags_mask = BR_FDB_STATIC
> + };
> +
> + br_fdb_flush(br, &desc);
I wanted to ask why you are not doing the same for IFLA_BRPORT_FLUSH,
but then I read the implementation of br_fdb_delete_by_port() and
remembered the comment in the cover letter regarding fdb_delete vs
fdb_delete_local. Probably best to note it in the commit message
> + }
>
> #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
> if (data[IFLA_BR_MCAST_ROUTER]) {
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 6e62af2e07e9..e6930e9ee69d 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -274,6 +274,13 @@ struct net_bridge_fdb_entry {
> struct rcu_head rcu;
> };
>
> +struct net_bridge_fdb_flush_desc {
> + unsigned long flags;
> + unsigned long flags_mask;
> + int port_ifindex;
> + u16 vlan_id;
> +};
> +
> #define MDB_PG_FLAGS_PERMANENT BIT(0)
> #define MDB_PG_FLAGS_OFFLOAD BIT(1)
> #define MDB_PG_FLAGS_FAST_LEAVE BIT(2)
> @@ -759,7 +766,8 @@ int br_fdb_init(void);
> void br_fdb_fini(void);
> int br_fdb_hash_init(struct net_bridge *br);
> void br_fdb_hash_fini(struct net_bridge *br);
> -void br_fdb_flush(struct net_bridge *br);
> +void br_fdb_flush(struct net_bridge *br,
> + const struct net_bridge_fdb_flush_desc *desc);
> void br_fdb_find_delete_local(struct net_bridge *br,
> const struct net_bridge_port *p,
> const unsigned char *addr, u16 vid);
> diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
> index 3f7ca88c2aa3..612e367fff20 100644
> --- a/net/bridge/br_sysfs_br.c
> +++ b/net/bridge/br_sysfs_br.c
> @@ -344,7 +344,11 @@ static DEVICE_ATTR_RW(group_addr);
> static int set_flush(struct net_bridge *br, unsigned long val,
> struct netlink_ext_ack *extack)
> {
> - br_fdb_flush(br);
> + struct net_bridge_fdb_flush_desc desc = {
> + .flags_mask = BR_FDB_STATIC
> + };
> +
> + br_fdb_flush(br, &desc);
> return 0;
> }
>
> --
> 2.35.1
>
Powered by blists - more mailing lists