Commit 3abd4512 authored by Petr Machata's avatar Petr Machata Committed by Jakub Kicinski
Browse files

net: bridge: Handle changes in VLAN_FLAG_BRIDGE_BINDING



When bridge binding is enabled on a VLAN netdevice, its link state should
track bridge ports that are members of the corresponding VLAN. This works
for newly-added netdevices. However toggling the option does not have the
effect of enabling or disabling the behavior as appropriate.

In this patch, react to bridge_binding toggles on VLAN uppers.

Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Acked-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/90a8ca8aea4d81378b29d75d9e562433e0d5c7ff.1734540770.git.petrm@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent f284424d
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -51,6 +51,13 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
		}
	}

	if (is_vlan_dev(dev)) {
		struct net_device *real_dev = vlan_dev_real_dev(dev);

		if (netif_is_bridge_master(real_dev))
			br_vlan_vlan_upper_event(real_dev, dev, event);
	}

	/* not a port of a bridge */
	p = br_port_get_rtnl(dev);
	if (!p)
+9 −0
Original line number Diff line number Diff line
@@ -1571,6 +1571,9 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
void br_vlan_port_event(struct net_bridge_port *p, unsigned long event);
int br_vlan_bridge_event(struct net_device *dev, unsigned long event,
			 void *ptr);
void br_vlan_vlan_upper_event(struct net_device *br_dev,
			      struct net_device *vlan_dev,
			      unsigned long event);
int br_vlan_rtnl_init(void);
void br_vlan_rtnl_uninit(void);
void br_vlan_notify(const struct net_bridge *br,
@@ -1802,6 +1805,12 @@ static inline int br_vlan_bridge_event(struct net_device *dev,
	return 0;
}

static inline void br_vlan_vlan_upper_event(struct net_device *br_dev,
					    struct net_device *vlan_dev,
					    unsigned long event)
{
}

static inline int br_vlan_rtnl_init(void)
{
	return 0;
+24 −0
Original line number Diff line number Diff line
@@ -1772,6 +1772,30 @@ int br_vlan_bridge_event(struct net_device *dev, unsigned long event, void *ptr)
	return ret;
}

void br_vlan_vlan_upper_event(struct net_device *br_dev,
			      struct net_device *vlan_dev,
			      unsigned long event)
{
	struct vlan_dev_priv *vlan = vlan_dev_priv(vlan_dev);
	struct net_bridge *br = netdev_priv(br_dev);
	bool bridge_binding;

	switch (event) {
	case NETDEV_CHANGE:
	case NETDEV_UP:
		break;
	default:
		return;
	}

	bridge_binding = vlan->flags & VLAN_FLAG_BRIDGE_BINDING;
	br_vlan_toggle_bridge_binding(br_dev, bridge_binding);
	if (bridge_binding)
		br_vlan_set_vlan_dev_state(br, vlan_dev);
	else if (!bridge_binding && netif_carrier_ok(br_dev))
		netif_carrier_on(vlan_dev);
}

/* Must be protected by RTNL. */
void br_vlan_port_event(struct net_bridge_port *p, unsigned long event)
{