Re: [PATCH v2 net-next 02/11] net: bridge: offload all port flags at once in br_setport

From: Vladimir Oltean
Date: Tue Feb 09 2021 - 15:41:35 EST


On Tue, Feb 09, 2021 at 05:19:27PM +0200, Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.oltean@xxxxxxx>
>
> The br_switchdev_set_port_flag function uses the atomic notifier call
> chain because br_setport runs in an atomic section (under br->lock).
> This is because port flag changes need to be synchronized with the data
> path. But actually the switchdev notifier doesn't need that, only
> br_set_port_flag does. So we can collect all the port flag changes and
> only emit the notification at the end, then revert the changes if the
> switchdev notification failed.
>
> There's also the other aspect: if for example this command:
>
> ip link set swp0 type bridge_slave flood off mcast_flood off learning off
>
> succeeded at configuring BR_FLOOD and BR_MCAST_FLOOD but not at
> BR_LEARNING, there would be no attempt to revert the partial state in
> any way. Arguably, if the user changes more than one flag through the
> same netlink command, this one _should_ be all or nothing, which means
> it should be passed through switchdev as all or nothing.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx>
> ---
(...)
> + spin_lock_bh(&p->br->lock);
> +
> + old_flags = p->flags;
> + br_vlan_tunnel_old = (old_flags & BR_VLAN_TUNNEL) ? true : false;
> +
> + br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
> + br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
> + br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE,
> + BR_MULTICAST_FAST_LEAVE);
> + br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
> + br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
> + br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
> + br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
> + br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST,
> + BR_MULTICAST_TO_UNICAST);
> + br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD);
> + br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
> + br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
> + br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL);
> + br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, BR_NEIGH_SUPPRESS);
> + br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED);
> +
> + changed_mask = old_flags ^ p->flags;
> +
> + spin_unlock_bh(&p->br->lock);
> +
> + err = br_switchdev_set_port_flag(p, p->flags, changed_mask);
> + if (err) {
> + spin_lock_bh(&p->br->lock);
> + p->flags = old_flags;
> + spin_unlock_bh(&p->br->lock);
> return err;
> + }
>

I know it's a bit strange to insert this in the middle of review, but
bear with me.

While I was reworking the patch series to also make sysfs non-atomic,
like this:

-----------------------------[cut here]-----------------------------