Re: [Bridge] [PATCH net-next v3 05/15] net: bridge: mcast: factor out port group del
On Mon, 7 Sep 2020 00:29:10 +0300 Nikolay Aleksandrov wrote: > >> @@ -1641,16 +1647,7 @@ br_multicast_leave_group(struct net_bridge *br, > >>if (p->flags & MDB_PG_FLAGS_PERMANENT) > >>break; > >> > >> - rcu_assign_pointer(*pp, p->next); > >> - hlist_del_init(>mglist); > >> - del_timer(>timer); > >> - kfree_rcu(p, rcu); > >> - br_mdb_notify(br->dev, port, group, RTM_DELMDB, > >> -p->flags | MDB_PG_FLAGS_FAST_LEAVE); > > > > And here we'll loose MDB_PG_FLAGS_FAST_LEAVE potentially? > > Good catch, we will lose the fast leave indeed. > This is a 1 line change to set the flag before notifying. Would you prefer > me to send a v4 or a follow up for it? I think it's cleaner if you send a v4. But not rush, I was planning to apply this tomorrow morning PST, anyway.
Re: [Bridge] [PATCH net-next v3 05/15] net: bridge: mcast: factor out port group del
On 9/7/20 12:29 AM, Nikolay Aleksandrov wrote: On 9/6/20 11:56 PM, Jakub Kicinski wrote: On Sat, 5 Sep 2020 11:24:00 +0300 Nikolay Aleksandrov wrote: @@ -843,24 +843,11 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) if (!p->port || p->port->dev->ifindex != entry->ifindex) continue; - if (!hlist_empty(>src_list)) { - err = -EINVAL; - goto unlock; - } - if (p->port->state == BR_STATE_DISABLED) goto unlock; - __mdb_entry_fill_flags(entry, p->flags); Just from staring at the code it's unclear why the list_empty() check and this __mdb_entry_fill_flags() are removed as well. The hlist_empty check is added by patch 01 temporarily for correctness. Otherwise I'd have to edit all open-coded pg del places and add src delete code and then remove it here. Obviously if I do a v4, I'll just move this patch before adding the hlist_empty in the first place. :-) __mdb_entry_fill_flags() are called by __mdb_fill_info() which is the only function used to fill an mdb both for dumping and notifications after patch 08. - rcu_assign_pointer(*pp, p->next); - hlist_del_init(>mglist); - del_timer(>timer); - kfree_rcu(p, rcu); + br_multicast_del_pg(mp, p, pp); err = 0; - - if (!mp->ports && !mp->host_joined && - netif_running(br->dev)) - mod_timer(>timer, jiffies); break; +void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, + struct net_bridge_port_group *pg, + struct net_bridge_port_group __rcu **pp) +{ + struct net_bridge *br = pg->port->br; + struct net_bridge_group_src *ent; + struct hlist_node *tmp; + + rcu_assign_pointer(*pp, pg->next); + hlist_del_init(>mglist); + del_timer(>timer); + hlist_for_each_entry_safe(ent, tmp, >src_list, node) + br_multicast_del_group_src(ent); + br_mdb_notify(br->dev, pg->port, >addr, RTM_DELMDB, pg->flags); + kfree_rcu(pg, rcu); + + if (!mp->ports && !mp->host_joined && netif_running(br->dev)) + mod_timer(>timer, jiffies); +} @@ -1641,16 +1647,7 @@ br_multicast_leave_group(struct net_bridge *br, if (p->flags & MDB_PG_FLAGS_PERMANENT) break; - rcu_assign_pointer(*pp, p->next); - hlist_del_init(>mglist); - del_timer(>timer); - kfree_rcu(p, rcu); - br_mdb_notify(br->dev, port, group, RTM_DELMDB, - p->flags | MDB_PG_FLAGS_FAST_LEAVE); And here we'll loose MDB_PG_FLAGS_FAST_LEAVE potentially? Good catch, we will lose the fast leave indeed. This is a 1 line change to set the flag before notifying. Would you prefer me to send a v4 or a follow up for it? Thanks, Nik - if (!mp->ports && !mp->host_joined && - netif_running(br->dev)) - mod_timer(>timer, jiffies); + br_multicast_del_pg(mp, p, pp);
Re: [Bridge] [PATCH net-next v3 05/15] net: bridge: mcast: factor out port group del
On 9/6/20 11:56 PM, Jakub Kicinski wrote: On Sat, 5 Sep 2020 11:24:00 +0300 Nikolay Aleksandrov wrote: @@ -843,24 +843,11 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) if (!p->port || p->port->dev->ifindex != entry->ifindex) continue; - if (!hlist_empty(>src_list)) { - err = -EINVAL; - goto unlock; - } - if (p->port->state == BR_STATE_DISABLED) goto unlock; - __mdb_entry_fill_flags(entry, p->flags); Just from staring at the code it's unclear why the list_empty() check and this __mdb_entry_fill_flags() are removed as well. The hlist_empty check is added by patch 01 temporarily for correctness. Otherwise I'd have to edit all open-coded pg del places and add src delete code and then remove it here. __mdb_entry_fill_flags() are called by __mdb_fill_info() which is the only function used to fill an mdb both for dumping and notifications after patch 08. - rcu_assign_pointer(*pp, p->next); - hlist_del_init(>mglist); - del_timer(>timer); - kfree_rcu(p, rcu); + br_multicast_del_pg(mp, p, pp); err = 0; - - if (!mp->ports && !mp->host_joined && - netif_running(br->dev)) - mod_timer(>timer, jiffies); break; +void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp) +{ + struct net_bridge *br = pg->port->br; + struct net_bridge_group_src *ent; + struct hlist_node *tmp; + + rcu_assign_pointer(*pp, pg->next); + hlist_del_init(>mglist); + del_timer(>timer); + hlist_for_each_entry_safe(ent, tmp, >src_list, node) + br_multicast_del_group_src(ent); + br_mdb_notify(br->dev, pg->port, >addr, RTM_DELMDB, pg->flags); + kfree_rcu(pg, rcu); + + if (!mp->ports && !mp->host_joined && netif_running(br->dev)) + mod_timer(>timer, jiffies); +} @@ -1641,16 +1647,7 @@ br_multicast_leave_group(struct net_bridge *br, if (p->flags & MDB_PG_FLAGS_PERMANENT) break; - rcu_assign_pointer(*pp, p->next); - hlist_del_init(>mglist); - del_timer(>timer); - kfree_rcu(p, rcu); - br_mdb_notify(br->dev, port, group, RTM_DELMDB, - p->flags | MDB_PG_FLAGS_FAST_LEAVE); And here we'll loose MDB_PG_FLAGS_FAST_LEAVE potentially? Good catch, we will lose the fast leave indeed. This is a 1 line change to set the flag before notifying. Would you prefer me to send a v4 or a follow up for it? Thanks, Nik - if (!mp->ports && !mp->host_joined && - netif_running(br->dev)) - mod_timer(>timer, jiffies); + br_multicast_del_pg(mp, p, pp);
Re: [Bridge] [PATCH net-next v3 05/15] net: bridge: mcast: factor out port group del
On Sat, 5 Sep 2020 11:24:00 +0300 Nikolay Aleksandrov wrote: > @@ -843,24 +843,11 @@ static int __br_mdb_del(struct net_bridge *br, struct > br_mdb_entry *entry) > if (!p->port || p->port->dev->ifindex != entry->ifindex) > continue; > > - if (!hlist_empty(>src_list)) { > - err = -EINVAL; > - goto unlock; > - } > - > if (p->port->state == BR_STATE_DISABLED) > goto unlock; > > - __mdb_entry_fill_flags(entry, p->flags); Just from staring at the code it's unclear why the list_empty() check and this __mdb_entry_fill_flags() are removed as well. > - rcu_assign_pointer(*pp, p->next); > - hlist_del_init(>mglist); > - del_timer(>timer); > - kfree_rcu(p, rcu); > + br_multicast_del_pg(mp, p, pp); > err = 0; > - > - if (!mp->ports && !mp->host_joined && > - netif_running(br->dev)) > - mod_timer(>timer, jiffies); > break; > +void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, > + struct net_bridge_port_group *pg, > + struct net_bridge_port_group __rcu **pp) > +{ > + struct net_bridge *br = pg->port->br; > + struct net_bridge_group_src *ent; > + struct hlist_node *tmp; > + > + rcu_assign_pointer(*pp, pg->next); > + hlist_del_init(>mglist); > + del_timer(>timer); > + hlist_for_each_entry_safe(ent, tmp, >src_list, node) > + br_multicast_del_group_src(ent); > + br_mdb_notify(br->dev, pg->port, >addr, RTM_DELMDB, pg->flags); > + kfree_rcu(pg, rcu); > + > + if (!mp->ports && !mp->host_joined && netif_running(br->dev)) > + mod_timer(>timer, jiffies); > +} > @@ -1641,16 +1647,7 @@ br_multicast_leave_group(struct net_bridge *br, > if (p->flags & MDB_PG_FLAGS_PERMANENT) > break; > > - rcu_assign_pointer(*pp, p->next); > - hlist_del_init(>mglist); > - del_timer(>timer); > - kfree_rcu(p, rcu); > - br_mdb_notify(br->dev, port, group, RTM_DELMDB, > - p->flags | MDB_PG_FLAGS_FAST_LEAVE); And here we'll loose MDB_PG_FLAGS_FAST_LEAVE potentially? > - if (!mp->ports && !mp->host_joined && > - netif_running(br->dev)) > - mod_timer(>timer, jiffies); > + br_multicast_del_pg(mp, p, pp);
[Bridge] [PATCH net-next v3 05/15] net: bridge: mcast: factor out port group del
In order to avoid future errors and reduce code duplication we should factor out the port group del sequence. This allows us to have one function which takes care of all details when removing a port group. Signed-off-by: Nikolay Aleksandrov --- net/bridge/br_mdb.c | 15 +- net/bridge/br_multicast.c | 59 +++ net/bridge/br_private.h | 3 ++ 3 files changed, 32 insertions(+), 45 deletions(-) diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 76fce1dac4a5..9dc12ce61018 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -843,24 +843,11 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) if (!p->port || p->port->dev->ifindex != entry->ifindex) continue; - if (!hlist_empty(>src_list)) { - err = -EINVAL; - goto unlock; - } - if (p->port->state == BR_STATE_DISABLED) goto unlock; - __mdb_entry_fill_flags(entry, p->flags); - rcu_assign_pointer(*pp, p->next); - hlist_del_init(>mglist); - del_timer(>timer); - kfree_rcu(p, rcu); + br_multicast_del_pg(mp, p, pp); err = 0; - - if (!mp->ports && !mp->host_joined && - netif_running(br->dev)) - mod_timer(>timer, jiffies); break; } diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 4fdc1a7ba627..72b32398e279 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -173,14 +173,32 @@ static void br_multicast_del_group_src(struct net_bridge_group_src *src) queue_work(system_long_wq, >src_gc_work); } -static void br_multicast_del_pg(struct net_bridge *br, - struct net_bridge_port_group *pg) +void br_multicast_del_pg(struct net_bridge_mdb_entry *mp, +struct net_bridge_port_group *pg, +struct net_bridge_port_group __rcu **pp) +{ + struct net_bridge *br = pg->port->br; + struct net_bridge_group_src *ent; + struct hlist_node *tmp; + + rcu_assign_pointer(*pp, pg->next); + hlist_del_init(>mglist); + del_timer(>timer); + hlist_for_each_entry_safe(ent, tmp, >src_list, node) + br_multicast_del_group_src(ent); + br_mdb_notify(br->dev, pg->port, >addr, RTM_DELMDB, pg->flags); + kfree_rcu(pg, rcu); + + if (!mp->ports && !mp->host_joined && netif_running(br->dev)) + mod_timer(>timer, jiffies); +} + +static void br_multicast_find_del_pg(struct net_bridge *br, +struct net_bridge_port_group *pg) { struct net_bridge_mdb_entry *mp; struct net_bridge_port_group *p; struct net_bridge_port_group __rcu **pp; - struct net_bridge_group_src *ent; - struct hlist_node *tmp; mp = br_mdb_ip_get(br, >addr); if (WARN_ON(!mp)) @@ -192,19 +210,7 @@ static void br_multicast_del_pg(struct net_bridge *br, if (p != pg) continue; - rcu_assign_pointer(*pp, p->next); - hlist_del_init(>mglist); - del_timer(>timer); - hlist_for_each_entry_safe(ent, tmp, >src_list, node) - br_multicast_del_group_src(ent); - br_mdb_notify(br->dev, p->port, >addr, RTM_DELMDB, - p->flags); - kfree_rcu(p, rcu); - - if (!mp->ports && !mp->host_joined && - netif_running(br->dev)) - mod_timer(>timer, jiffies); - + br_multicast_del_pg(mp, pg, pp); return; } @@ -221,7 +227,7 @@ static void br_multicast_port_group_expired(struct timer_list *t) hlist_unhashed(>mglist) || pg->flags & MDB_PG_FLAGS_PERMANENT) goto out; - br_multicast_del_pg(br, pg); + br_multicast_find_del_pg(br, pg); out: spin_unlock(>multicast_lock); @@ -615,7 +621,7 @@ static void br_multicast_group_src_expired(struct timer_list *t) br_multicast_del_group_src(src); if (!hlist_empty(>src_list)) goto out; - br_multicast_del_pg(br, pg); + br_multicast_find_del_pg(br, pg); } out: spin_unlock(>multicast_lock); @@ -1086,7 +1092,7 @@ void br_multicast_del_port(struct net_bridge_port *port) /* Take care of the remaining groups, only perm ones should be left */ spin_lock_bh(>multicast_lock); hlist_for_each_entry_safe(pg, n, >mglist, mglist) - br_multicast_del_pg(br, pg); + br_multicast_find_del_pg(br, pg); spin_unlock_bh(>multicast_lock);