net: bridge: update BROPT_VLAN_ENABLED before notifying switchdev in br_vlan_filter_toggle

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2037335

commit f7cdb3ecc9b7f609082fc89e5b79d66858504899
Author: Vladimir Oltean <vladimir.oltean@nxp.com>
Date:   Mon Jul 26 19:55:28 2021 +0300

    net: bridge: update BROPT_VLAN_ENABLED before notifying switchdev in br_vlan_filter_toggle

    SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING is notified by the bridge from
    two places:
    - nbp_vlan_init(), during bridge port creation
    - br_vlan_filter_toggle(), during a netlink/sysfs/ioctl change requested
      by user space

    If a switchdev driver uses br_vlan_enabled(br_dev) inside its handler
    for the SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING attribute notifier,
    different things will be seen depending on whether the bridge calls from
    the first path or the second:
    - in nbp_vlan_init(), br_vlan_enabled() reflects the current state of
      the bridge
    - in br_vlan_filter_toggle(), br_vlan_enabled() reflects the past state
      of the bridge

    This can lead in some cases to complications in driver implementation,
    which can be avoided if these could reliably use br_vlan_enabled().

    Nothing seems to depend on this behavior, and it seems overall more
    straightforward for br_vlan_enabled() to return the proper value even
    during the SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING notifier, so
    temporarily enable the bridge option, then revert it if the switchdev
    notifier failed.

    Cc: Roopa Prabhu <roopa@nvidia.com>
    Cc: Nikolay Aleksandrov <nikolay@nvidia.com>
    Cc: Ido Schimmel <idosch@nvidia.com>
    Cc: Jiri Pirko <jiri@nvidia.com>
    Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
This commit is contained in:
Ivan Vecera 2022-01-05 16:14:36 +01:00
parent def6c352f2
commit 6d9f848adb
1 changed files with 7 additions and 4 deletions

View File

@ -840,11 +840,14 @@ int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val,
if (br_opt_get(br, BROPT_VLAN_ENABLED) == !!val)
return 0;
err = switchdev_port_attr_set(br->dev, &attr, extack);
if (err && err != -EOPNOTSUPP)
return err;
br_opt_toggle(br, BROPT_VLAN_ENABLED, !!val);
err = switchdev_port_attr_set(br->dev, &attr, extack);
if (err && err != -EOPNOTSUPP) {
br_opt_toggle(br, BROPT_VLAN_ENABLED, !val);
return err;
}
br_manage_promisc(br);
recalculate_group_addr(br);
br_recalculate_fwd_mask(br);