diff --git a/include/net/dsa.h b/include/net/dsa.h index 04e93bafb7bd7318be1595c9e1494d5bda717acc..4e60d2610f208b5b9c628092ec403b6d7bd0757c 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -536,6 +536,12 @@ struct dsa_switch_ops { void (*get_regs)(struct dsa_switch *ds, int port, struct ethtool_regs *regs, void *p); + /* + * Upper device tracking. + */ + int (*port_prechangeupper)(struct dsa_switch *ds, int port, + struct netdev_notifier_changeupper_info *info); + /* * Bridge integration */ diff --git a/net/dsa/slave.c b/net/dsa/slave.c index c6806eef906f931043615b902452623577aecc06..59c80052e95037e9d45d1b6ce6970f67b036392d 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -2032,10 +2032,22 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb, switch (event) { case NETDEV_PRECHANGEUPPER: { struct netdev_notifier_changeupper_info *info = ptr; + struct dsa_switch *ds; + struct dsa_port *dp; + int err; if (!dsa_slave_dev_check(dev)) return dsa_prevent_bridging_8021q_upper(dev, ptr); + dp = dsa_slave_to_port(dev); + ds = dp->ds; + + if (ds->ops->port_prechangeupper) { + err = ds->ops->port_prechangeupper(ds, dp->index, info); + if (err) + return notifier_from_errno(err); + } + if (is_vlan_dev(info->upper_dev)) return dsa_slave_check_8021q_upper(dev, ptr); break;