net/mlx5: Allow blocking encap changes in eswitch
authorLeon Romanovsky <leonro@nvidia.com>
Thu, 13 Apr 2023 12:29:26 +0000 (15:29 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 18 Apr 2023 01:55:25 +0000 (18:55 -0700)
Existing eswitch encap option enables header encapsulation. Unfortunately
currently available hardware isn't able to perform double encapsulation,
which can happen once IPsec packet offload tunnel mode is used together
with encap mode set to BASIC.

So as a solution for misconfiguration, provide an option to block encap
changes, which will be used for IPsec packet offload.

Reviewed-by: Emeel Hakim <ehakim@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c

index 19e9a77..e9d68fd 100644 (file)
@@ -263,6 +263,7 @@ struct mlx5_esw_offload {
        const struct mlx5_eswitch_rep_ops *rep_ops[NUM_REP_TYPES];
        u8 inline_mode;
        atomic64_t num_flows;
+       u64 num_block_encap;
        enum devlink_eswitch_encap_mode encap;
        struct ida vport_metadata_ida;
        unsigned int host_number; /* ECPF supports one external host */
@@ -748,6 +749,9 @@ void mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw,
                                              struct mlx5_eswitch *slave_esw);
 int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
 
+bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev);
+void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev);
+
 static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
 {
        if (mlx5_esw_allowed(esw))
@@ -761,6 +765,7 @@ mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw)
 {
        return esw->fdb_table.offloads.slow_fdb;
 }
+
 #else  /* CONFIG_MLX5_ESWITCH */
 /* eswitch API stubs */
 static inline int  mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
@@ -805,6 +810,15 @@ mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw)
 {
        return 0;
 }
+
+static inline bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
+{
+       return true;
+}
+
+static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
+{
+}
 #endif /* CONFIG_MLX5_ESWITCH */
 
 #endif /* __MLX5_ESWITCH_H__ */
index 48036df..b6e2709 100644 (file)
@@ -3586,6 +3586,47 @@ int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
        return err;
 }
 
+bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
+{
+       struct devlink *devlink = priv_to_devlink(dev);
+       struct mlx5_eswitch *esw;
+
+       devl_lock(devlink);
+       esw = mlx5_devlink_eswitch_get(devlink);
+       if (IS_ERR(esw)) {
+               devl_unlock(devlink);
+               /* Failure means no eswitch => not possible to change encap */
+               return true;
+       }
+
+       down_write(&esw->mode_lock);
+       if (esw->mode != MLX5_ESWITCH_LEGACY &&
+           esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
+               up_write(&esw->mode_lock);
+               devl_unlock(devlink);
+               return false;
+       }
+
+       esw->offloads.num_block_encap++;
+       up_write(&esw->mode_lock);
+       devl_unlock(devlink);
+       return true;
+}
+
+void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
+{
+       struct devlink *devlink = priv_to_devlink(dev);
+       struct mlx5_eswitch *esw;
+
+       esw = mlx5_devlink_eswitch_get(devlink);
+       if (IS_ERR(esw))
+               return;
+
+       down_write(&esw->mode_lock);
+       esw->offloads.num_block_encap--;
+       up_write(&esw->mode_lock);
+}
+
 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
                                        enum devlink_eswitch_encap_mode encap,
                                        struct netlink_ext_ack *extack)
@@ -3627,6 +3668,13 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
                goto unlock;
        }
 
+       if (esw->offloads.num_block_encap) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Can't set encapsulation when IPsec SA and/or policies are configured");
+               err = -EOPNOTSUPP;
+               goto unlock;
+       }
+
        esw_destroy_offloads_fdb_tables(esw);
 
        esw->offloads.encap = encap;