Commit 920a33cd authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Paolo Abeni
Browse files

net: bridge: move DSA master bridging restriction to DSA



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: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Acked-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 0498277e
Loading
Loading
Loading
Loading
+0 −20
Original line number Diff line number Diff line
@@ -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,
+44 −0
Original line number Diff line number Diff line
@@ -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)
{
@@ -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;