From: Cosmin Ratiu <[email protected]>

Introduce an additional steering table for PSP transport mode
decapsulation, containing:
- one rule per supported PSP version which does:
  - transport mode decap (removes UDP+PSP headers and PSP trailer)
    - recomputes iph->tot_len
    - recomputes IP checksum
    - reparses packet headers
  - copy SPI into reg_b (which ends up as cqe.ft_metadata)
  - set a decap marker and the PSP version in the flow_tag, so the RX
    handler can make sense of the packet
- default drop rule for unsupported PSP versions (per PSP spec).

Packets are forwarded to the previously added rx table, where:
- one rule forwards UDP traffic to the UDP default destination.
- default rule forwards traffic to the TTC table.

The reason is to avoid steering loops. If packets were to be injected
into the TTC directly after rx_decap, it may be possible to create a
steering loop with RX packets of the form IP|UDP|PSP|UDP|PSP...
The rx flow table guarantees that packets go through PSP steering at
most once.

The steering mode is saved in a new field 'fs.decap_enabled'.
Updating the mode is done through accel_psp_fs_rx_reconfigure(), which
creates the decap steering table if needed and possible. It then uses an
atomic rule update to redirect traffic to the new table.
This is now invoked with decap_wanted == false.
The intention is for failures creating the new table to not block
feature reconfig/PSP toggling. Decap table creation and traffic
redirection failures therefore result in a warning that PSP HW GRO will
not work.
Nothing happens on older HW/FW without the ability to decapsulate PSP
transport.

An upcoming patch will add dynamic reconfiguration of PSP steering based
on HW GRO.

Signed-off-by: Cosmin Ratiu <[email protected]>
Reviewed-by: Dragos Tatulea <[email protected]>
Signed-off-by: Tariq Toukan <[email protected]>
---
 .../net/ethernet/mellanox/mlx5/core/en/fs.h   |   1 +
 .../mellanox/mlx5/core/en_accel/psp.c         | 249 +++++++++++++++++-
 2 files changed, 248 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h 
b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
index 4973fb473ff0..a802f80d90be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
@@ -98,6 +98,7 @@ enum {
 #if defined(CONFIG_MLX5_EN_PSP)
        MLX5E_ACCEL_FS_PSP_FT_LEVEL = MLX5E_INNER_TTC_FT_LEVEL + 1,
        MLX5E_ACCEL_FS_PSP_ERR_FT_LEVEL,
+       MLX5E_ACCEL_FS_PSP_DECAP_FT_LEVEL,
        MLX5E_ACCEL_FS_PSP_RX_FT_LEVEL,
 #endif
 };
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c
index 20d7f14fb4ac..84133cbf8689 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c
@@ -23,6 +23,13 @@ enum accel_psp_syndrome {
        PSP_BAD_TRAILER,
 };
 
+static const u8 psp_supported_versions[] = {
+       PSP_VERSION_HDR0_AES_GCM_128,
+       PSP_VERSION_HDR0_AES_GCM_256,
+};
+
+#define MLX5E_PSP_NUM_SUPPORTED_VERSIONS ARRAY_SIZE(psp_supported_versions)
+
 struct mlx5e_psp_tx_table {
        struct mlx5_flow_namespace *ns;
        struct mlx5_flow_table *ft;
@@ -43,6 +50,7 @@ struct mlx5e_psp_rx_decrypt_table {
        struct mlx5_flow_table *ft;
        struct mlx5_flow_group *miss_group;
        struct mlx5_flow_handle *miss_rule;
+       struct mlx5_modify_hdr *modify_hdr;
        struct mlx5_flow_handle *rule;
 };
 
@@ -53,6 +61,15 @@ struct mlx5e_psp_rx_table {
        struct mlx5_flow_handle *udp_rules[ACCEL_FS_PSP_NUM_TYPES];
 };
 
+struct mlx5e_psp_rx_decap_table {
+       struct mlx5_flow_table *ft;
+       struct mlx5_flow_group *drop_group;
+       struct mlx5_modify_hdr *modify_hdr;
+       struct mlx5_pkt_reformat *reformat;
+       struct mlx5_flow_handle *rule[MLX5E_PSP_NUM_SUPPORTED_VERSIONS];
+       struct mlx5_flow_handle *unsupported_rule;
+};
+
 struct mlx5e_psp_fs {
        struct mlx5_core_dev *mdev;
        struct mlx5_fc *tx_counter;
@@ -64,9 +81,14 @@ struct mlx5e_psp_fs {
        struct mlx5_fc *rx_auth_fail_counter;
        struct mlx5_fc *rx_err_counter;
        struct mlx5_fc *rx_bad_counter;
+       /* When set, steering is configured to decapsulate PSP (remove UDP+PSP
+        * headers and PSP trailer) and hand off the SPI in cqe.ft_metadata.
+        */
+       bool decap_enabled;
 
        struct mlx5e_psp_rx_decrypt_table decrypt[ACCEL_FS_PSP_NUM_TYPES];
        struct mlx5e_psp_rx_check_table check;
+       struct mlx5e_psp_rx_decap_table decap;
        struct mlx5e_psp_rx_table rx;
 };
 
@@ -111,6 +133,15 @@ static void accel_psp_fs_del_flow_rule(struct 
mlx5_flow_handle **rule)
        }
 }
 
+static void accel_psp_fs_dealloc_modify_hdr(struct mlx5_core_dev *dev,
+                                           struct mlx5_modify_hdr **modhdr)
+{
+       if (*modhdr) {
+               mlx5_modify_header_dealloc(dev, *modhdr);
+               *modhdr = NULL;
+       }
+}
+
 static int accel_psp_fs_create_miss_group(struct mlx5_flow_table *ft,
                                          struct mlx5_flow_group **group)
 {
@@ -403,11 +434,164 @@ int accel_psp_fs_rx_check_ft_create(struct mlx5e_psp_fs 
*fs,
        return err;
 }
 
+static
+void accel_psp_fs_rx_decap_ft_destroy(struct mlx5e_psp_fs *fs,
+                                     struct mlx5e_psp_rx_decap_table *decap)
+{
+       int i;
+
+       accel_psp_fs_del_flow_rule(&decap->unsupported_rule);
+       for (i = 0; i < MLX5E_PSP_NUM_SUPPORTED_VERSIONS; i++)
+               accel_psp_fs_del_flow_rule(&decap->rule[i]);
+       if (decap->reformat) {
+               mlx5_packet_reformat_dealloc(fs->mdev, decap->reformat);
+               decap->reformat = NULL;
+       }
+       accel_psp_fs_dealloc_modify_hdr(fs->mdev, &decap->modify_hdr);
+       accel_psp_fs_destroy_flow_group(&decap->drop_group);
+       accel_psp_fs_destroy_ft(&decap->ft);
+       fs->decap_enabled = false;
+}
+
+static void setup_fte_psp_version(struct mlx5_flow_spec *spec, u8 version)
+{
+       void *misc_params_6;
+
+       memset(spec, 0, sizeof(*spec));
+       spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_6;
+       misc_params_6 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+                                    misc_parameters_6);
+       MLX5_SET_TO_ONES(fte_match_set_misc6, misc_params_6, psp_version);
+       misc_params_6 = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+                                    misc_parameters_6);
+       MLX5_SET(fte_match_set_misc6, misc_params_6, psp_version, version);
+}
+
+static
+int accel_psp_fs_rx_decap_ft_create(struct mlx5e_psp_fs *fs,
+                                   struct mlx5e_psp_rx_decap_table *decap)
+{
+       u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
+       struct mlx5_pkt_reformat_params reformat_params = {};
+       struct mlx5_flow_table_attr ft_attr = {};
+       struct mlx5_flow_destination dest = {};
+       struct mlx5_core_dev *mdev = fs->mdev;
+       struct mlx5_pkt_reformat *reformat;
+       struct mlx5_modify_hdr *modify_hdr;
+       struct mlx5_flow_handle *rule;
+       struct mlx5_flow_spec *spec;
+       int i, err = 0;
+
+       spec = kvzalloc_obj(*spec);
+       if (!spec)
+               return -ENOMEM;
+
+       /* Create FT */
+       ft_attr.max_fte = 1 + MLX5E_PSP_NUM_SUPPORTED_VERSIONS;
+       ft_attr.level = MLX5E_ACCEL_FS_PSP_DECAP_FT_LEVEL;
+       ft_attr.prio = MLX5E_NIC_PRIO;
+       ft_attr.autogroup.num_reserved_entries = 1;
+       err = accel_psp_fs_create_ft(fs, &ft_attr, &decap->ft);
+       if (err) {
+               mlx5_core_err(mdev, "fail to create psp decap rx ft err=%d\n",
+                             err);
+               goto out_spec;
+       }
+
+       /* Create drop group */
+       err = accel_psp_fs_create_miss_group(decap->ft, &decap->drop_group);
+       if (err) {
+               mlx5_core_err(mdev,
+                             "fail to create psp decap rx drop_group err=%d\n",
+                             err);
+               goto out_err;
+       }
+
+       /* Add default drop rule */
+       err = accel_psp_add_drop_rule(decap->ft, NULL, fs->rx_bad_counter,
+                                     &decap->unsupported_rule);
+       if (err) {
+               mlx5_core_err(mdev,
+                             "fail to create psp decap unsupported versions 
drop rule err=%d\n",
+                             err);
+               goto out_err;
+       }
+
+       /* modify_hdr: copy SPI from REG_C_0 to REG_B */
+       MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
+       MLX5_SET(copy_action_in, action, src_field,
+                MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
+       MLX5_SET(copy_action_in, action, src_offset, 0);
+       MLX5_SET(copy_action_in, action, length, 0);  /* 0 = 32 bits */
+       MLX5_SET(copy_action_in, action, dst_field,
+                MLX5_ACTION_IN_FIELD_METADATA_REG_B);
+       MLX5_SET(copy_action_in, action, dst_offset, 0);
+
+       modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,
+                                             1, action);
+       if (IS_ERR(modify_hdr)) {
+               err = PTR_ERR(modify_hdr);
+               goto out_err;
+       }
+       decap->modify_hdr = modify_hdr;
+
+       /* pkt_reformat: decap PSP transport */
+       reformat_params.type = MLX5_REFORMAT_TYPE_REMOVE_PSP_TRANSPORT;
+       reformat = mlx5_packet_reformat_alloc(mdev, &reformat_params,
+                                             MLX5_FLOW_NAMESPACE_KERNEL);
+       if (IS_ERR(reformat)) {
+               err = PTR_ERR(reformat);
+               goto out_err;
+       }
+       decap->reformat = reformat;
+
+       for (i = 0; i < MLX5E_PSP_NUM_SUPPORTED_VERSIONS; i++) {
+               u8 version = psp_supported_versions[i];
+               struct mlx5_flow_act flow_act = {};
+
+               /* match(version) => decap, copy SPI, fwd to rx FT */
+               setup_fte_psp_version(spec, version);
+
+               /*
+                * Override the flow tag set in the decrypt table with
+                * the decap PSP marker and version.
+                */
+               spec->flow_context.flags = FLOW_CONTEXT_HAS_TAG;
+               spec->flow_context.flow_tag =
+                       FIELD_PREP(MLX5E_ACCEL_FLOW_TAG_PROTO_MASK,
+                                  MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP) |
+                       FIELD_PREP(MLX5E_ACCEL_FLOW_TAG_PSP_VER_MASK, version);
+
+               flow_act.action = MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
+                       MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
+                       MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+               flow_act.pkt_reformat = reformat;
+               flow_act.modify_hdr = modify_hdr;
+               dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+               dest.ft = fs->rx.ft;
+
+               rule = mlx5_add_flow_rules(decap->ft, spec, &flow_act, &dest, 
1);
+               if (IS_ERR(rule)) {
+                       err = PTR_ERR(rule);
+                       goto out_err;
+               }
+               decap->rule[i] = rule;
+       }
+       goto out_spec;
+
+out_err:
+       accel_psp_fs_rx_decap_ft_destroy(fs, decap);
+out_spec:
+       kvfree(spec);
+       return err;
+}
+
 static void
 accel_psp_fs_rx_decrypt_ft_destroy(struct mlx5e_psp_fs *fs,
                                   struct mlx5e_psp_rx_decrypt_table *decrypt)
 {
        accel_psp_fs_del_flow_rule(&decrypt->rule);
+       accel_psp_fs_dealloc_modify_hdr(fs->mdev, &decrypt->modify_hdr);
        accel_psp_fs_del_flow_rule(&decrypt->miss_rule);
        accel_psp_fs_destroy_flow_group(&decrypt->miss_group);
        accel_psp_fs_destroy_ft(&decrypt->ft);
@@ -427,10 +611,12 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
                                  struct mlx5e_psp_rx_decrypt_table *decrypt,
                                  struct mlx5_flow_destination *default_dest)
 {
+       u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
        struct mlx5_flow_table_attr ft_attr = {};
        struct mlx5_flow_destination dest = {};
        struct mlx5_core_dev *mdev = fs->mdev;
        MLX5_DECLARE_FLOW_ACT(flow_act);
+       struct mlx5_modify_hdr *modhdr;
        struct mlx5_flow_handle *rule;
        struct mlx5_flow_spec *spec;
        int err = 0;
@@ -474,6 +660,24 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
        }
        decrypt->miss_rule = rule;
 
+       /* Create modify_hdr to copy SPI to REG_C_0 */
+       MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
+       MLX5_SET(copy_action_in, action, src_field,
+                MLX5_ACTION_IN_FIELD_PSP_HEADER_1);
+       MLX5_SET(copy_action_in, action, src_offset, 0);
+       MLX5_SET(copy_action_in, action, length, 0);  /* 0 = 32 bits */
+       MLX5_SET(copy_action_in, action, dst_field,
+                MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
+       MLX5_SET(copy_action_in, action, dst_offset, 0);
+
+       modhdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL, 1,
+                                         action);
+       if (IS_ERR(modhdr)) {
+               err = PTR_ERR(modhdr);
+               goto out_err;
+       }
+       decrypt->modify_hdr = modhdr;
+
        /* Add PSP RX decrypt rule */
        setup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);
 
@@ -484,8 +688,10 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
                           MLX5E_ACCEL_FLOW_TAG_PROTO_PSP);
 
        flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;
-       flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
-                         MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT;
+       flow_act.action = MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
+               MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
+               MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       flow_act.modify_hdr = modhdr;
        dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
        dest.ft = fs->check.ft;
        rule = mlx5_add_flow_rules(decrypt->ft, spec, &flow_act, &dest, 1);
@@ -506,6 +712,42 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
        return err;
 }
 
+static void accel_psp_fs_rx_reconfigure(struct mlx5e_psp_fs *fs,
+                                       bool decap_wanted)
+{
+       bool decap_supported =
+               MLX5_CAP_FLOWTABLE(fs->mdev,
+                                  
flow_table_properties_nic_receive.reformat_del_psp_transport);
+       bool decap_enable = decap_wanted && decap_supported;
+       struct mlx5_flow_destination dest = {};
+       int err;
+
+       if (decap_enable == fs->decap_enabled)
+               return;
+
+       /* Create the decap table if needed. */
+       if (decap_enable && !fs->decap.ft) {
+               err = accel_psp_fs_rx_decap_ft_create(fs, &fs->decap);
+               if (err)
+                       goto out_err;
+       }
+
+       /* Redirect traffic to the correct table. */
+       dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+       dest.ft = decap_enable ? fs->decap.ft : fs->rx.ft;
+       err = mlx5_modify_rule_destination(fs->check.rule, &dest, NULL);
+       if (err)
+               goto out_err;
+
+       fs->decap_enabled = decap_enable;
+       return;
+
+out_err:
+       mlx5_core_warn(fs->mdev,
+                      "Failed to create/modify PSP decapsulation rules (err 
%d), HW GRO for PSP unavailable\n",
+                      err);
+}
+
 static void accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs)
 {
        struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs->fs, false);
@@ -518,6 +760,7 @@ static void accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs)
                accel_psp_fs_rx_decrypt_ft_destroy(fs, &fs->decrypt[i]);
        }
        accel_psp_fs_rx_check_ft_destroy(&fs->check);
+       accel_psp_fs_rx_decap_ft_destroy(fs, &fs->decap);
        accel_psp_fs_rx_ft_destroy(&fs->rx);
        if (tc_blocked)
                mlx5e_accel_unblock_tc_offload(fs->mdev);
@@ -565,6 +808,8 @@ static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,
                mlx5_ttc_fwd_dest(ttc, fs_psp2tt(i), &dest);
        }
 
+       accel_psp_fs_rx_reconfigure(fs, false);
+
        return 0;
 
 err_decrypt_ft:
-- 
2.44.0


Reply via email to