Commit 2e359b00 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Paolo Abeni

net: dsa: propagate extack to port_lag_join

Drivers could refuse to offload a LAG configuration for a variety of
reasons, mainly having to do with its TX type. Additionally, since DSA
masters may now also be LAG interfaces, and this will translate into a
call to port_lag_join on the CPU ports, there may be extra restrictions
there. Propagate the netlink extack to this DSA method in order for
drivers to give a meaningful error message back to the user.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 13eccc1b
...@@ -6593,14 +6593,17 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, ...@@ -6593,14 +6593,17 @@ static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port,
static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
struct dsa_lag lag, struct dsa_lag lag,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_chip *chip = ds->priv;
struct dsa_port *dp; struct dsa_port *dp;
int members = 0; int members = 0;
if (!mv88e6xxx_has_lag(chip)) if (!mv88e6xxx_has_lag(chip)) {
NL_SET_ERR_MSG_MOD(extack, "Chip does not support LAG offload");
return false; return false;
}
if (!lag.id) if (!lag.id)
return false; return false;
...@@ -6609,14 +6612,20 @@ static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds, ...@@ -6609,14 +6612,20 @@ static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
/* Includes the port joining the LAG */ /* Includes the port joining the LAG */
members++; members++;
if (members > 8) if (members > 8) {
NL_SET_ERR_MSG_MOD(extack,
"Cannot offload more than 8 LAG ports");
return false; return false;
}
/* We could potentially relax this to include active /* We could potentially relax this to include active
* backup in the future. * backup in the future.
*/ */
if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
NL_SET_ERR_MSG_MOD(extack,
"Can only offload LAG using hash TX type");
return false; return false;
}
/* Ideally we would also validate that the hash type matches /* Ideally we would also validate that the hash type matches
* the hardware. Alas, this is always set to unknown on team * the hardware. Alas, this is always set to unknown on team
...@@ -6769,12 +6778,13 @@ static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port) ...@@ -6769,12 +6778,13 @@ static int mv88e6xxx_port_lag_change(struct dsa_switch *ds, int port)
static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port, static int mv88e6xxx_port_lag_join(struct dsa_switch *ds, int port,
struct dsa_lag lag, struct dsa_lag lag,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_chip *chip = ds->priv;
int err, id; int err, id;
if (!mv88e6xxx_lag_can_offload(ds, lag, info)) if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* DSA LAG IDs are one-based */ /* DSA LAG IDs are one-based */
...@@ -6827,12 +6837,13 @@ static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index, ...@@ -6827,12 +6837,13 @@ static int mv88e6xxx_crosschip_lag_change(struct dsa_switch *ds, int sw_index,
static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index, static int mv88e6xxx_crosschip_lag_join(struct dsa_switch *ds, int sw_index,
int port, struct dsa_lag lag, int port, struct dsa_lag lag,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
struct mv88e6xxx_chip *chip = ds->priv; struct mv88e6xxx_chip *chip = ds->priv;
int err; int err;
if (!mv88e6xxx_lag_can_offload(ds, lag, info)) if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
......
...@@ -861,11 +861,12 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port, ...@@ -861,11 +861,12 @@ static void felix_bridge_leave(struct dsa_switch *ds, int port,
static int felix_lag_join(struct dsa_switch *ds, int port, static int felix_lag_join(struct dsa_switch *ds, int port,
struct dsa_lag lag, struct dsa_lag lag,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
struct ocelot *ocelot = ds->priv; struct ocelot *ocelot = ds->priv;
return ocelot_port_lag_join(ocelot, port, lag.dev, info); return ocelot_port_lag_join(ocelot, port, lag.dev, info, extack);
} }
static int felix_lag_leave(struct dsa_switch *ds, int port, static int felix_lag_leave(struct dsa_switch *ds, int port,
......
...@@ -1017,7 +1017,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port, ...@@ -1017,7 +1017,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
static bool qca8k_lag_can_offload(struct dsa_switch *ds, static bool qca8k_lag_can_offload(struct dsa_switch *ds,
struct dsa_lag lag, struct dsa_lag lag,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
struct dsa_port *dp; struct dsa_port *dp;
int members = 0; int members = 0;
...@@ -1029,15 +1030,24 @@ static bool qca8k_lag_can_offload(struct dsa_switch *ds, ...@@ -1029,15 +1030,24 @@ static bool qca8k_lag_can_offload(struct dsa_switch *ds,
/* Includes the port joining the LAG */ /* Includes the port joining the LAG */
members++; members++;
if (members > QCA8K_NUM_PORTS_FOR_LAG) if (members > QCA8K_NUM_PORTS_FOR_LAG) {
NL_SET_ERR_MSG_MOD(extack,
"Cannot offload more than 4 LAG ports");
return false; return false;
}
if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
NL_SET_ERR_MSG_MOD(extack,
"Can only offload LAG using hash TX type");
return false; return false;
}
if (info->hash_type != NETDEV_LAG_HASH_L2 && if (info->hash_type != NETDEV_LAG_HASH_L2 &&
info->hash_type != NETDEV_LAG_HASH_L23) info->hash_type != NETDEV_LAG_HASH_L23) {
NL_SET_ERR_MSG_MOD(extack,
"Can only offload L2 or L2+L3 TX hash");
return false; return false;
}
return true; return true;
} }
...@@ -1160,11 +1170,12 @@ static int qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, ...@@ -1160,11 +1170,12 @@ static int qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port,
} }
int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
int ret; int ret;
if (!qca8k_lag_can_offload(ds, lag, info)) if (!qca8k_lag_can_offload(ds, lag, info, extack))
return -EOPNOTSUPP; return -EOPNOTSUPP;
ret = qca8k_lag_setup_hash(ds, lag, info); ret = qca8k_lag_setup_hash(ds, lag, info);
......
...@@ -512,7 +512,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port, ...@@ -512,7 +512,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
/* Common port LAG function */ /* Common port LAG function */
int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag, int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct dsa_lag lag,
struct netdev_lag_upper_info *info); struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack);
int qca8k_port_lag_leave(struct dsa_switch *ds, int port, int qca8k_port_lag_leave(struct dsa_switch *ds, int port,
struct dsa_lag lag); struct dsa_lag lag);
......
...@@ -2132,10 +2132,14 @@ static void ocelot_migrate_lag_fdbs(struct ocelot *ocelot, ...@@ -2132,10 +2132,14 @@ static void ocelot_migrate_lag_fdbs(struct ocelot *ocelot,
int ocelot_port_lag_join(struct ocelot *ocelot, int port, int ocelot_port_lag_join(struct ocelot *ocelot, int port,
struct net_device *bond, struct net_device *bond,
struct netdev_lag_upper_info *info) struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack)
{ {
if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
NL_SET_ERR_MSG_MOD(extack,
"Can only offload LAG using hash TX type");
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
mutex_lock(&ocelot->fwd_domain_lock); mutex_lock(&ocelot->fwd_domain_lock);
......
...@@ -1412,11 +1412,10 @@ static int ocelot_netdevice_lag_join(struct net_device *dev, ...@@ -1412,11 +1412,10 @@ static int ocelot_netdevice_lag_join(struct net_device *dev,
int port = priv->port.index; int port = priv->port.index;
int err; int err;
err = ocelot_port_lag_join(ocelot, port, bond, info); err = ocelot_port_lag_join(ocelot, port, bond, info, extack);
if (err == -EOPNOTSUPP) { if (err == -EOPNOTSUPP)
NL_SET_ERR_MSG_MOD(extack, "Offloading not supported"); /* Offloading not supported, fall back to software LAG */
return 0; return 0;
}
bridge_dev = netdev_master_upper_dev_get(bond); bridge_dev = netdev_master_upper_dev_get(bond);
if (!bridge_dev || !netif_is_bridge_master(bridge_dev)) if (!bridge_dev || !netif_is_bridge_master(bridge_dev))
......
...@@ -1094,7 +1094,8 @@ struct dsa_switch_ops { ...@@ -1094,7 +1094,8 @@ struct dsa_switch_ops {
int port); int port);
int (*crosschip_lag_join)(struct dsa_switch *ds, int sw_index, int (*crosschip_lag_join)(struct dsa_switch *ds, int sw_index,
int port, struct dsa_lag lag, int port, struct dsa_lag lag,
struct netdev_lag_upper_info *info); struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack);
int (*crosschip_lag_leave)(struct dsa_switch *ds, int sw_index, int (*crosschip_lag_leave)(struct dsa_switch *ds, int sw_index,
int port, struct dsa_lag lag); int port, struct dsa_lag lag);
...@@ -1169,7 +1170,8 @@ struct dsa_switch_ops { ...@@ -1169,7 +1170,8 @@ struct dsa_switch_ops {
int (*port_lag_change)(struct dsa_switch *ds, int port); int (*port_lag_change)(struct dsa_switch *ds, int port);
int (*port_lag_join)(struct dsa_switch *ds, int port, int (*port_lag_join)(struct dsa_switch *ds, int port,
struct dsa_lag lag, struct dsa_lag lag,
struct netdev_lag_upper_info *info); struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack);
int (*port_lag_leave)(struct dsa_switch *ds, int port, int (*port_lag_leave)(struct dsa_switch *ds, int port,
struct dsa_lag lag); struct dsa_lag lag);
......
...@@ -1229,7 +1229,8 @@ int ocelot_port_mdb_del(struct ocelot *ocelot, int port, ...@@ -1229,7 +1229,8 @@ int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
const struct net_device *bridge); const struct net_device *bridge);
int ocelot_port_lag_join(struct ocelot *ocelot, int port, int ocelot_port_lag_join(struct ocelot *ocelot, int port,
struct net_device *bond, struct net_device *bond,
struct netdev_lag_upper_info *info); struct netdev_lag_upper_info *info,
struct netlink_ext_ack *extack);
void ocelot_port_lag_leave(struct ocelot *ocelot, int port, void ocelot_port_lag_leave(struct ocelot *ocelot, int port,
struct net_device *bond); struct net_device *bond);
void ocelot_port_lag_change(struct ocelot *ocelot, int port, bool lag_tx_active); void ocelot_port_lag_change(struct ocelot *ocelot, int port, bool lag_tx_active);
......
...@@ -88,6 +88,7 @@ struct dsa_notifier_lag_info { ...@@ -88,6 +88,7 @@ struct dsa_notifier_lag_info {
const struct dsa_port *dp; const struct dsa_port *dp;
struct dsa_lag lag; struct dsa_lag lag;
struct netdev_lag_upper_info *info; struct netdev_lag_upper_info *info;
struct netlink_ext_ack *extack;
}; };
/* DSA_NOTIFIER_VLAN_* */ /* DSA_NOTIFIER_VLAN_* */
......
...@@ -635,6 +635,7 @@ int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev, ...@@ -635,6 +635,7 @@ int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev,
struct dsa_notifier_lag_info info = { struct dsa_notifier_lag_info info = {
.dp = dp, .dp = dp,
.info = uinfo, .info = uinfo,
.extack = extack,
}; };
struct net_device *bridge_dev; struct net_device *bridge_dev;
int err; int err;
......
...@@ -507,12 +507,12 @@ static int dsa_switch_lag_join(struct dsa_switch *ds, ...@@ -507,12 +507,12 @@ static int dsa_switch_lag_join(struct dsa_switch *ds,
{ {
if (info->dp->ds == ds && ds->ops->port_lag_join) if (info->dp->ds == ds && ds->ops->port_lag_join)
return ds->ops->port_lag_join(ds, info->dp->index, info->lag, return ds->ops->port_lag_join(ds, info->dp->index, info->lag,
info->info); info->info, info->extack);
if (info->dp->ds != ds && ds->ops->crosschip_lag_join) if (info->dp->ds != ds && ds->ops->crosschip_lag_join)
return ds->ops->crosschip_lag_join(ds, info->dp->ds->index, return ds->ops->crosschip_lag_join(ds, info->dp->ds->index,
info->dp->index, info->lag, info->dp->index, info->lag,
info->info); info->info, info->extack);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment