summaryrefslogtreecommitdiff
path: root/net/dsa/slave.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa/slave.c')
-rw-r--r--net/dsa/slave.c70
1 files changed, 63 insertions, 7 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index e53c8ca6eb66..c5c81cba8259 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -273,7 +273,7 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
struct dsa_port *dp = dsa_slave_to_port(dev);
int ret;
- if (attr->orig_dev != dev)
+ if (!dsa_port_offloads_netdev(dp, attr->orig_dev))
return -EOPNOTSUPP;
switch (attr->id) {
@@ -333,7 +333,7 @@ static int dsa_slave_vlan_add(struct net_device *dev,
struct switchdev_obj_port_vlan vlan;
int err;
- if (obj->orig_dev != dev)
+ if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
return -EOPNOTSUPP;
if (dsa_port_skip_vlan_configuration(dp))
@@ -378,7 +378,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_MDB:
- if (obj->orig_dev != dev)
+ if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
return -EOPNOTSUPP;
err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
break;
@@ -407,7 +407,7 @@ static int dsa_slave_vlan_del(struct net_device *dev,
struct switchdev_obj_port_vlan *vlan;
int err;
- if (obj->orig_dev != dev)
+ if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
return -EOPNOTSUPP;
if (dsa_port_skip_vlan_configuration(dp))
@@ -435,7 +435,7 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
switch (obj->id) {
case SWITCHDEV_OBJ_ID_PORT_MDB:
- if (obj->orig_dev != dev)
+ if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
return -EOPNOTSUPP;
err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj));
break;
@@ -1907,6 +1907,46 @@ static int dsa_slave_changeupper(struct net_device *dev,
dsa_port_bridge_leave(dp, info->upper_dev);
err = NOTIFY_OK;
}
+ } else if (netif_is_lag_master(info->upper_dev)) {
+ if (info->linking) {
+ err = dsa_port_lag_join(dp, info->upper_dev,
+ info->upper_info);
+ if (err == -EOPNOTSUPP) {
+ NL_SET_ERR_MSG_MOD(info->info.extack,
+ "Offloading not supported");
+ err = 0;
+ }
+ err = notifier_from_errno(err);
+ } else {
+ dsa_port_lag_leave(dp, info->upper_dev);
+ err = NOTIFY_OK;
+ }
+ }
+
+ return err;
+}
+
+static int
+dsa_slave_lag_changeupper(struct net_device *dev,
+ struct netdev_notifier_changeupper_info *info)
+{
+ struct net_device *lower;
+ struct list_head *iter;
+ int err = NOTIFY_DONE;
+ struct dsa_port *dp;
+
+ netdev_for_each_lower_dev(dev, lower, iter) {
+ if (!dsa_slave_dev_check(lower))
+ continue;
+
+ dp = dsa_slave_to_port(lower);
+ if (!dp->lag_dev)
+ /* Software LAG */
+ continue;
+
+ err = dsa_slave_changeupper(lower, info);
+ if (notifier_to_errno(err))
+ break;
}
return err;
@@ -2004,10 +2044,26 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
break;
}
case NETDEV_CHANGEUPPER:
+ if (dsa_slave_dev_check(dev))
+ return dsa_slave_changeupper(dev, ptr);
+
+ if (netif_is_lag_master(dev))
+ return dsa_slave_lag_changeupper(dev, ptr);
+
+ break;
+ case NETDEV_CHANGELOWERSTATE: {
+ struct netdev_notifier_changelowerstate_info *info = ptr;
+ struct dsa_port *dp;
+ int err;
+
if (!dsa_slave_dev_check(dev))
- return NOTIFY_DONE;
+ break;
- return dsa_slave_changeupper(dev, ptr);
+ dp = dsa_slave_to_port(dev);
+
+ err = dsa_port_lag_change(dp, info->lower_state_info);
+ return notifier_from_errno(err);
+ }
}
return NOTIFY_DONE;