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: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Родитель
13eccc1bbb
Коммит
2e359b00a1
|
@ -6593,14 +6593,17 @@ out:
|
|||
|
||||
static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
|
||||
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 dsa_port *dp;
|
||||
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;
|
||||
}
|
||||
|
||||
if (!lag.id)
|
||||
return false;
|
||||
|
@ -6609,14 +6612,20 @@ static bool mv88e6xxx_lag_can_offload(struct dsa_switch *ds,
|
|||
/* Includes the port joining the LAG */
|
||||
members++;
|
||||
|
||||
if (members > 8)
|
||||
if (members > 8) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Cannot offload more than 8 LAG ports");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We could potentially relax this to include active
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* Ideally we would also validate that the hash type matches
|
||||
* 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)
|
|||
|
||||
static int mv88e6xxx_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)
|
||||
{
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
int err, id;
|
||||
|
||||
if (!mv88e6xxx_lag_can_offload(ds, lag, info))
|
||||
if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* DSA LAG IDs are one-based */
|
||||
|
@ -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,
|
||||
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;
|
||||
int err;
|
||||
|
||||
if (!mv88e6xxx_lag_can_offload(ds, lag, info))
|
||||
if (!mv88e6xxx_lag_can_offload(ds, lag, info, extack))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
|
|
|
@ -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,
|
||||
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;
|
||||
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
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;
|
||||
int members = 0;
|
||||
|
@ -1029,15 +1030,24 @@ static bool qca8k_lag_can_offload(struct dsa_switch *ds,
|
|||
/* Includes the port joining the LAG */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 true;
|
||||
}
|
||||
|
@ -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,
|
||||
struct netdev_lag_upper_info *info)
|
||||
struct netdev_lag_upper_info *info,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!qca8k_lag_can_offload(ds, lag, info))
|
||||
if (!qca8k_lag_can_offload(ds, lag, info, extack))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = qca8k_lag_setup_hash(ds, lag, info);
|
||||
|
|
|
@ -512,7 +512,8 @@ int qca8k_port_vlan_del(struct dsa_switch *ds, int port,
|
|||
|
||||
/* Common port LAG function */
|
||||
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,
|
||||
struct dsa_lag lag);
|
||||
|
||||
|
|
|
@ -2132,10 +2132,14 @@ static void ocelot_migrate_lag_fdbs(struct ocelot *ocelot,
|
|||
|
||||
int ocelot_port_lag_join(struct ocelot *ocelot, int port,
|
||||
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;
|
||||
}
|
||||
|
||||
mutex_lock(&ocelot->fwd_domain_lock);
|
||||
|
||||
|
|
|
@ -1412,11 +1412,10 @@ static int ocelot_netdevice_lag_join(struct net_device *dev,
|
|||
int port = priv->port.index;
|
||||
int err;
|
||||
|
||||
err = ocelot_port_lag_join(ocelot, port, bond, info);
|
||||
if (err == -EOPNOTSUPP) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Offloading not supported");
|
||||
err = ocelot_port_lag_join(ocelot, port, bond, info, extack);
|
||||
if (err == -EOPNOTSUPP)
|
||||
/* Offloading not supported, fall back to software LAG */
|
||||
return 0;
|
||||
}
|
||||
|
||||
bridge_dev = netdev_master_upper_dev_get(bond);
|
||||
if (!bridge_dev || !netif_is_bridge_master(bridge_dev))
|
||||
|
|
|
@ -1094,7 +1094,8 @@ struct dsa_switch_ops {
|
|||
int port);
|
||||
int (*crosschip_lag_join)(struct dsa_switch *ds, int sw_index,
|
||||
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 port, struct dsa_lag lag);
|
||||
|
||||
|
@ -1169,7 +1170,8 @@ struct dsa_switch_ops {
|
|||
int (*port_lag_change)(struct dsa_switch *ds, int port);
|
||||
int (*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 (*port_lag_leave)(struct dsa_switch *ds, int port,
|
||||
struct dsa_lag lag);
|
||||
|
||||
|
|
|
@ -1229,7 +1229,8 @@ int ocelot_port_mdb_del(struct ocelot *ocelot, int port,
|
|||
const struct net_device *bridge);
|
||||
int ocelot_port_lag_join(struct ocelot *ocelot, int port,
|
||||
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,
|
||||
struct net_device *bond);
|
||||
void ocelot_port_lag_change(struct ocelot *ocelot, int port, bool lag_tx_active);
|
||||
|
|
|
@ -88,6 +88,7 @@ struct dsa_notifier_lag_info {
|
|||
const struct dsa_port *dp;
|
||||
struct dsa_lag lag;
|
||||
struct netdev_lag_upper_info *info;
|
||||
struct netlink_ext_ack *extack;
|
||||
};
|
||||
|
||||
/* DSA_NOTIFIER_VLAN_* */
|
||||
|
|
|
@ -635,6 +635,7 @@ int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev,
|
|||
struct dsa_notifier_lag_info info = {
|
||||
.dp = dp,
|
||||
.info = uinfo,
|
||||
.extack = extack,
|
||||
};
|
||||
struct net_device *bridge_dev;
|
||||
int err;
|
||||
|
|
|
@ -507,12 +507,12 @@ static int dsa_switch_lag_join(struct dsa_switch *ds,
|
|||
{
|
||||
if (info->dp->ds == ds && ds->ops->port_lag_join)
|
||||
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)
|
||||
return ds->ops->crosschip_lag_join(ds, info->dp->ds->index,
|
||||
info->dp->index, info->lag,
|
||||
info->info);
|
||||
info->info, info->extack);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче