Skip to content

Commit

Permalink
net: bridge: move DSA master bridging restriction to DSA
Browse files Browse the repository at this point in the history
When DSA gains support for multiple CPU ports in a LAG, it will become
mandatory to monitor the changeupper events for the DSA master.

In fact, there are already some restrictions to be imposed in that area,
namely that a DSA master cannot be a bridge port except in some special
circumstances.

Centralize the restrictions at the level of the DSA layer as a
preliminary step.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Vladimir Oltean authored and Paolo Abeni committed Aug 23, 2022
1 parent 0498277 commit 920a33c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 20 deletions.
20 changes: 0 additions & 20 deletions net/bridge/br_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,26 +568,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
!is_valid_ether_addr(dev->dev_addr))
return -EINVAL;

/* Also don't allow bridging of net devices that are DSA masters, since
* the bridge layer rx_handler prevents the DSA fake ethertype handler
* to be invoked, so we don't get the chance to strip off and parse the
* DSA switch tag protocol header (the bridge layer just returns
* RX_HANDLER_CONSUMED, stopping RX processing for these frames).
* The only case where that would not be an issue is when bridging can
* already be offloaded, such as when the DSA master is itself a DSA
* or plain switchdev port, and is bridged only with other ports from
* the same hardware device.
*/
if (netdev_uses_dsa(dev)) {
list_for_each_entry(p, &br->port_list, list) {
if (!netdev_port_same_parent_id(dev, p->dev)) {
NL_SET_ERR_MSG(extack,
"Cannot do software bridging with a DSA master");
return -EINVAL;
}
}
}

/* No bridging of bridges */
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) {
NL_SET_ERR_MSG(extack,
Expand Down
44 changes: 44 additions & 0 deletions net/dsa/slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -2699,6 +2699,46 @@ dsa_slave_prechangeupper_sanity_check(struct net_device *dev,
return NOTIFY_DONE;
}

/* Don't allow bridging of DSA masters, since the bridge layer rx_handler
* prevents the DSA fake ethertype handler to be invoked, so we don't get the
* chance to strip off and parse the DSA switch tag protocol header (the bridge
* layer just returns RX_HANDLER_CONSUMED, stopping RX processing for these
* frames).
* The only case where that would not be an issue is when bridging can already
* be offloaded, such as when the DSA master is itself a DSA or plain switchdev
* port, and is bridged only with other ports from the same hardware device.
*/
static int
dsa_bridge_prechangelower_sanity_check(struct net_device *new_lower,
struct netdev_notifier_changeupper_info *info)
{
struct net_device *br = info->upper_dev;
struct netlink_ext_ack *extack;
struct net_device *lower;
struct list_head *iter;

if (!netif_is_bridge_master(br))
return NOTIFY_DONE;

if (!info->linking)
return NOTIFY_DONE;

extack = netdev_notifier_info_to_extack(&info->info);

netdev_for_each_lower_dev(br, lower, iter) {
if (!netdev_uses_dsa(new_lower) && !netdev_uses_dsa(lower))
continue;

if (!netdev_port_same_parent_id(lower, new_lower)) {
NL_SET_ERR_MSG(extack,
"Cannot do software bridging with a DSA master");
return notifier_from_errno(-EINVAL);
}
}

return NOTIFY_DONE;
}

static int dsa_slave_netdevice_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
Expand All @@ -2713,6 +2753,10 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
if (notifier_to_errno(err))
return err;

err = dsa_bridge_prechangelower_sanity_check(dev, info);
if (notifier_to_errno(err))
return err;

err = dsa_slave_prechangeupper(dev, ptr);
if (notifier_to_errno(err))
return err;
Expand Down

0 comments on commit 920a33c

Please sign in to comment.