Message ID | 90a8ca8aea4d81378b29d75d9e562433e0d5c7ff.1734540770.git.petrm@nvidia.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 3abd45122c72d6a66a52d41a65586fdf7ab40ef7 |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | bridge: Handle changes in VLAN_FLAG_BRIDGE_BINDING | expand |
On 12/18/24 19:15, Petr Machata wrote: > 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: Petr Machata <petrm@nvidia.com> > Reviewed-by: Ido Schimmel <idosch@nvidia.com> > --- > net/bridge/br.c | 7 +++++++ > net/bridge/br_private.h | 9 +++++++++ > net/bridge/br_vlan.c | 24 ++++++++++++++++++++++++ > 3 files changed, 40 insertions(+) > > diff --git a/net/bridge/br.c b/net/bridge/br.c > index 2cab878e0a39..183fcb362f9e 100644 > --- a/net/bridge/br.c > +++ b/net/bridge/br.c > @@ -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) > diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h > index 9853cfbb9d14..29d6ec45cf41 100644 > --- a/net/bridge/br_private.h > +++ b/net/bridge/br_private.h > @@ -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; > diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c > index b728b71e693f..d9a69ec9affe 100644 > --- a/net/bridge/br_vlan.c > +++ b/net/bridge/br_vlan.c > @@ -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) > { Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
diff --git a/net/bridge/br.c b/net/bridge/br.c index 2cab878e0a39..183fcb362f9e 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -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) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 9853cfbb9d14..29d6ec45cf41 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -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; diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index b728b71e693f..d9a69ec9affe 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -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) {