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@xxxxxxxxxx> > Reviewed-by: Ido Schimmel <idosch@xxxxxxxxxx> > --- > 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@xxxxxxxxxxxxx>