net: dsa: propagate extack to port_lag_join
authorVladimir Oltean <vladimir.oltean@nxp.com>
Sun, 11 Sep 2022 01:07:03 +0000 (04:07 +0300)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 20 Sep 2022 08:32:36 +0000 (10:32 +0200)
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>
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/ocelot/felix.c
drivers/net/dsa/qca/qca8k-common.c
drivers/net/dsa/qca/qca8k.h
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_net.c
include/net/dsa.h
include/soc/mscc/ocelot.h
net/dsa/dsa_priv.h
net/dsa/port.c
net/dsa/switch.c

index 6f4ea39ab466f4c1faefc19a0bfca6a46fa51ce0..5f178faa110f12d19c5f7eeb6d66a36b4c963a5d 100644 (file)
@@ -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);
index c73ef5f7aa64fbeaa8f89c21210b05c8c6b004cc..82dcc21a71725693fb506e4d56b8996acdd3f384 100644 (file)
@@ -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,
index bba95613e218375ab19b8a746f08288116d9f091..fb45b598847be47c799a642753b4356ba0281ef7 100644 (file)
@@ -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);
index e36ecc9777f437bcfc5f414335bef9ac8937abad..0b7a5cb12321670aba0575e5c5532340bd833c90 100644 (file)
@@ -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);
 
index 874fb2a5874e2c615154a15ba9372dfe80c5076d..5c18f89869756928c1ebf606e460637cae3386b8 100644 (file)
@@ -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);
 
index 2979fb1ba0f7a7c9983224a65b4ddf6c338d1ed9..50858cc10fef6b77791c9e682cbd7d2bbfc6a285 100644 (file)
@@ -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))
index 3f717c3fcba0058ef52e8fc85ae0d95c563eb59c..1c80e75b3cadbfe9bf55a66d35ea91b5d810b3eb 100644 (file)
@@ -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);
 
index 355cfdedc43bd4a39de7b5e790e454012cbba79c..ea19e8ef1f6102c35e4d395b142ced4d04b5595d 100644 (file)
@@ -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);
index d252a04ed725aecf6c64546ebc1214bef21a12dc..f0ae54d0435e5178c9f6790aa6b4758210a401af 100644 (file)
@@ -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_* */
index e557b42de9f231884f485af45846bcab8acf76b6..98f7fa0cdd5ccabee5ad8136149ab8e449ad29f8 100644 (file)
@@ -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;
index 4dfd68cf61c5a32184c1408816431a5cf80cafcd..c2cb15e213240f6e48d09d01c165db92d0dd0e4e 100644 (file)
@@ -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;
 }