| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/04 09:34 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch exclusively modifies the Mellanox mlx5 driver (drivers/net/ethernet/mellanox/mlx5/*) to add PSP hardware GRO and decapsulation support, along with related flow tag and TC offload blocking changes. This is a vendor-specific SmartNIC driver that requires physical PCIe hardware not emulated in standard QEMU, so it cannot be meaningfully fuzzed in a virtualized environment.",
"WorthFuzzing": false
} |
| 1/1 | 2026/08/04 09:34 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit e44da41198827803cc60b3d0d6e5ca1c80ca4e99\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Aug 4 09:34:13 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h\nindex 4973fb473ff02..a802f80d90bea 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h\n@@ -98,6 +98,7 @@ enum {\n #if defined(CONFIG_MLX5_EN_PSP)\n \tMLX5E_ACCEL_FS_PSP_FT_LEVEL = MLX5E_INNER_TTC_FT_LEVEL + 1,\n \tMLX5E_ACCEL_FS_PSP_ERR_FT_LEVEL,\n+\tMLX5E_ACCEL_FS_PSP_DECAP_FT_LEVEL,\n \tMLX5E_ACCEL_FS_PSP_RX_FT_LEVEL,\n #endif\n };\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h\nindex 3f212e46fc2f9..a0bb19cc956df 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h\n@@ -218,6 +218,28 @@ static inline void mlx5e_accel_tx_finish(struct mlx5e_txqsq *sq,\n #endif\n }\n \n+static inline int mlx5e_accel_block_tc_offload(struct mlx5_core_dev *mdev)\n+{\n+\tint ret = 0;\n+\n+\tmutex_lock(\u0026mdev-\u003eoffload_block.lock);\n+\tif (mdev-\u003eoffload_block.num_accel)\n+\t\tret = -EBUSY;\n+\telse\n+\t\tmdev-\u003eoffload_block.num_tc++;\n+\tmutex_unlock(\u0026mdev-\u003eoffload_block.lock);\n+\n+\treturn ret;\n+}\n+\n+static inline void mlx5e_accel_unblock_tc_offload(struct mlx5_core_dev *mdev)\n+{\n+\tmutex_lock(\u0026mdev-\u003eoffload_block.lock);\n+\tif (!WARN_ON_ONCE(!mdev-\u003eoffload_block.num_tc))\n+\t\tmdev-\u003eoffload_block.num_tc--;\n+\tmutex_unlock(\u0026mdev-\u003eoffload_block.lock);\n+}\n+\n static inline int mlx5e_accel_init_rx(struct mlx5e_priv *priv)\n {\n \treturn mlx5e_ktls_init_rx(priv);\n@@ -229,6 +251,15 @@ static inline void mlx5e_accel_cleanup_rx(struct mlx5e_priv *priv)\n \tmlx5_accel_psp_fs_cleanup_rx_tables(priv);\n }\n \n+static inline int mlx5e_accel_update_rx(struct mlx5e_priv *priv)\n+{\n+#ifdef CONFIG_MLX5_EN_PSP\n+\treturn mlx5e_psp_update_rx(priv);\n+#else\n+\treturn 0;\n+#endif\n+}\n+\n static inline int mlx5e_accel_init_tx(struct mlx5e_priv *priv)\n {\n \treturn mlx5e_ktls_init_tx(priv);\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h\nnew file mode 100644\nindex 0000000000000..d422f96ffced0\n--- /dev/null\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h\n@@ -0,0 +1,45 @@\n+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */\n+/* Copyright (c) 2026, NVIDIA CORPORATION \u0026 AFFILIATES. All rights reserved. */\n+\n+#ifndef __MLX5E_FLOW_TAG_H__\n+#define __MLX5E_FLOW_TAG_H__\n+\n+#include \u003clinux/bits.h\u003e\n+#include \u003clinux/kernel.h\u003e\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/mlx5/device.h\u003e\n+\n+/* Unified accel flow_tag layout in CQE sop_drop_qpn [23:0]:\n+ *\n+ * [23:21] = protocol ID (3 bits):\n+ * 0 = none (default)\n+ * 1 = IPsec\n+ * 2 = MACsec\n+ * 3 = PSP (HW decrypted, PSP header present)\n+ * 4 = PSP decap (HW decrypted \u0026 decapsulated)\n+ * 5-7 = reserved\n+ * [20:17] = PSP version (4 bits, valid when proto == PSP decap)\n+ * 16 = reserved\n+ * [15:0] = used by other subsystems (e.g. TC).\n+ */\n+#define MLX5E_ACCEL_FLOW_TAG_PROTO_MASK\t\tGENMASK(23, 21)\n+#define MLX5E_ACCEL_FLOW_TAG_PROTO_NONE\t\t(0 \u003c\u003c 21)\n+#define MLX5E_ACCEL_FLOW_TAG_PROTO_IPSEC\t(1 \u003c\u003c 21)\n+#define MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC\t(2 \u003c\u003c 21)\n+#define MLX5E_ACCEL_FLOW_TAG_PROTO_PSP\t\t(3 \u003c\u003c 21)\n+#define MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP\t(4 \u003c\u003c 21)\n+\n+#define MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT\t17\n+#define MLX5E_ACCEL_FLOW_TAG_PSP_VER_MASK\t(0xF \u003c\u003c MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT)\n+\n+static inline u32 mlx5e_accel_flow_tag(struct mlx5_cqe64 *cqe)\n+{\n+\treturn be32_to_cpu(cqe-\u003esop_drop_qpn) \u0026 0xFFFFFF;\n+}\n+\n+static inline u32 mlx5e_accel_flow_tag_proto(struct mlx5_cqe64 *cqe)\n+{\n+\treturn mlx5e_accel_flow_tag(cqe) \u0026 MLX5E_ACCEL_FLOW_TAG_PROTO_MASK;\n+}\n+\n+#endif /* __MLX5E_FLOW_TAG_H__ */\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c\nindex 329608c59313b..081cb2f31be01 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c\n@@ -4,6 +4,8 @@\n #include \u003clinux/netdevice.h\u003e\n #include \"en.h\"\n #include \"en/fs.h\"\n+#include \"en_accel/en_accel.h\"\n+#include \"en_accel/flow_tag.h\"\n #include \"eswitch.h\"\n #include \"ipsec.h\"\n #include \"fs_core.h\"\n@@ -189,7 +191,7 @@ static void ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,\n \t\t\t\t misc_parameters_2.metadata_reg_c_2);\n \t\tMLX5_SET(fte_match_param, spec-\u003ematch_value,\n \t\t\t misc_parameters_2.metadata_reg_c_2,\n-\t\t\t sa_entry-\u003eipsec_obj_id | BIT(31));\n+\t\t\t sa_entry-\u003eipsec_obj_id);\n \n \t\tspec-\u003ematch_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;\n \t}\n@@ -2065,7 +2067,7 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)\n \tif (!attrs-\u003edrop) {\n \t\tif (rx != ipsec-\u003erx_esw)\n \t\t\terr = setup_modify_header(ipsec, attrs-\u003etype,\n-\t\t\t\t\t\t sa_entry-\u003eipsec_obj_id | BIT(31),\n+\t\t\t\t\t\t sa_entry-\u003eipsec_obj_id,\n \t\t\t\t\t\t XFRM_DEV_OFFLOAD_IN, \u0026flow_act);\n \t\telse\n \t\t\terr = mlx5_esw_ipsec_rx_setup_modify_header(sa_entry, \u0026flow_act);\n@@ -2098,6 +2100,10 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)\n \t\tflow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP;\n \telse\n \t\tflow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;\n+\tif (!attrs-\u003edrop \u0026\u0026 rx != ipsec-\u003erx_esw) {\n+\t\tspec-\u003eflow_context.flags |= FLOW_CONTEXT_HAS_TAG;\n+\t\tspec-\u003eflow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_IPSEC;\n+\t}\n \tdest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;\n \tdest[0].ft = rx-\u003eft.status;\n \tdest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;\n@@ -2574,53 +2580,19 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)\n \t}\n }\n \n-#ifdef CONFIG_MLX5_ESWITCH\n-static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)\n-{\n-\tstruct mlx5_eswitch *esw = mdev-\u003epriv.eswitch;\n-\tint err = 0;\n-\n-\tif (esw) {\n-\t\terr = mlx5_esw_lock(esw);\n-\t\tif (err)\n-\t\t\treturn err;\n-\t}\n-\n-\tif (mdev-\u003enum_block_ipsec) {\n-\t\terr = -EBUSY;\n-\t\tgoto unlock;\n-\t}\n-\n-\tmdev-\u003enum_block_tc++;\n-\n-unlock:\n-\tif (esw)\n-\t\tmlx5_esw_unlock(esw);\n-\n-\treturn err;\n-}\n-#else\n-static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)\n-{\n-\tif (mdev-\u003enum_block_ipsec)\n-\t\treturn -EBUSY;\n-\n-\tmdev-\u003enum_block_tc++;\n-\treturn 0;\n-}\n-#endif\n-\n-static void mlx5e_ipsec_unblock_tc_offload(struct mlx5_core_dev *mdev)\n+static bool accel_ipsec_should_block_tc(struct mlx5e_ipsec_sa_entry *sa_entry)\n {\n-\tmdev-\u003enum_block_tc--;\n+\treturn sa_entry-\u003eattrs.type == XFRM_DEV_OFFLOAD_PACKET ||\n+\t\tsa_entry-\u003eattrs.dir == XFRM_DEV_OFFLOAD_IN;\n }\n \n int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)\n {\n+\tbool block_tc = accel_ipsec_should_block_tc(sa_entry);\n \tint err;\n \n-\tif (sa_entry-\u003eattrs.type == XFRM_DEV_OFFLOAD_PACKET) {\n-\t\terr = mlx5e_ipsec_block_tc_offload(sa_entry-\u003eipsec-\u003emdev);\n+\tif (block_tc) {\n+\t\terr = mlx5e_accel_block_tc_offload(sa_entry-\u003eipsec-\u003emdev);\n \t\tif (err)\n \t\t\treturn err;\n \t}\n@@ -2636,8 +2608,8 @@ int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)\n \treturn 0;\n \n err_out:\n-\tif (sa_entry-\u003eattrs.type == XFRM_DEV_OFFLOAD_PACKET)\n-\t\tmlx5e_ipsec_unblock_tc_offload(sa_entry-\u003eipsec-\u003emdev);\n+\tif (block_tc)\n+\t\tmlx5e_accel_unblock_tc_offload(sa_entry-\u003eipsec-\u003emdev);\n \treturn err;\n }\n \n@@ -2651,8 +2623,8 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)\n \tif (ipsec_rule-\u003epkt_reformat)\n \t\tmlx5_packet_reformat_dealloc(mdev, ipsec_rule-\u003epkt_reformat);\n \n-\tif (sa_entry-\u003eattrs.type == XFRM_DEV_OFFLOAD_PACKET)\n-\t\tmlx5e_ipsec_unblock_tc_offload(mdev);\n+\tif (accel_ipsec_should_block_tc(sa_entry))\n+\t\tmlx5e_accel_unblock_tc_offload(mdev);\n \n \tif (sa_entry-\u003eattrs.dir == XFRM_DEV_OFFLOAD_OUT) {\n \t\ttx_ft_put(sa_entry-\u003eipsec, sa_entry-\u003eattrs.type);\n@@ -2686,7 +2658,7 @@ int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)\n {\n \tint err;\n \n-\terr = mlx5e_ipsec_block_tc_offload(pol_entry-\u003eipsec-\u003emdev);\n+\terr = mlx5e_accel_block_tc_offload(pol_entry-\u003eipsec-\u003emdev);\n \tif (err)\n \t\treturn err;\n \n@@ -2701,7 +2673,7 @@ int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)\n \treturn 0;\n \n err_out:\n-\tmlx5e_ipsec_unblock_tc_offload(pol_entry-\u003eipsec-\u003emdev);\n+\tmlx5e_accel_unblock_tc_offload(pol_entry-\u003eipsec-\u003emdev);\n \treturn err;\n }\n \n@@ -2712,7 +2684,7 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)\n \n \tmlx5_del_flow_rules(ipsec_rule-\u003erule);\n \n-\tmlx5e_ipsec_unblock_tc_offload(pol_entry-\u003eipsec-\u003emdev);\n+\tmlx5e_accel_unblock_tc_offload(pol_entry-\u003eipsec-\u003emdev);\n \n \tif (pol_entry-\u003eattrs.dir == XFRM_DEV_OFFLOAD_IN) {\n \t\trx_ft_put_policy(pol_entry-\u003eipsec,\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h\nindex 45b0d19e735cb..6dea5978a40e8 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h\n@@ -38,10 +38,9 @@\n #include \u003cnet/xfrm.h\u003e\n #include \"en.h\"\n #include \"en/txrx.h\"\n+#include \"en_accel/flow_tag.h\"\n \n-/* Bit31: IPsec marker, Bit30: reserved, Bit29-24: IPsec syndrome, Bit23-0: IPsec obj id */\n-#define MLX5_IPSEC_METADATA_MARKER(metadata) ((((metadata) \u003e\u003e 30) \u0026 0x3) == 0x2)\n-#define MLX5_IPSEC_METADATA_SYNDROM(metadata) (((metadata) \u003e\u003e 24) \u0026 GENMASK(5, 0))\n+/* IPsec obj id in ft_metadata bits[23:0] */\n #define MLX5_IPSEC_METADATA_HANDLE(metadata) ((metadata) \u0026 GENMASK(23, 0))\n \n struct mlx5e_accel_tx_ipsec_state {\n@@ -74,7 +73,9 @@ static inline unsigned int mlx5e_ipsec_tx_ids_len(struct mlx5e_accel_tx_ipsec_st\n \n static inline bool mlx5_ipsec_is_rx_flow(struct mlx5_cqe64 *cqe)\n {\n-\treturn MLX5_IPSEC_METADATA_MARKER(be32_to_cpu(cqe-\u003eft_metadata));\n+\tu32 proto = mlx5e_accel_flow_tag_proto(cqe);\n+\n+\treturn proto == MLX5E_ACCEL_FLOW_TAG_PROTO_IPSEC;\n }\n \n static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg)\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c\nindex daff53ba7d09f..aa7a28954861b 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c\n@@ -10,6 +10,7 @@\n #include \"en.h\"\n #include \"lib/aso.h\"\n #include \"lib/crypto.h\"\n+#include \"en_accel/en_accel.h\"\n #include \"en_accel/macsec.h\"\n \n #define MLX5_MACSEC_EPN_SCOPE_MID 0x80000000L\n@@ -324,6 +325,8 @@ static void mlx5e_macsec_cleanup_sa_fs(struct mlx5e_macsec *macsec,\n \tmlx5_macsec_fs_del_rule(macsec-\u003emdev-\u003emacsec_fs, sa-\u003emacsec_rule, action, netdev,\n \t\t\t\tfs_id);\n \tsa-\u003emacsec_rule = NULL;\n+\tif (!is_tx)\n+\t\tmlx5e_accel_unblock_tc_offload(macsec-\u003emdev);\n }\n \n static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,\n@@ -343,6 +346,7 @@ static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,\n \tconst struct macsec_tx_sc *tx_sc = \u0026ctx-\u003esecy-\u003etx_sc;\n \tstruct mlx5_macsec_rule_attrs rule_attrs;\n \tunion mlx5_macsec_rule *macsec_rule;\n+\tint err = 0;\n \n \tif (is_tx \u0026\u0026 tx_sc-\u003eencoding_sa != sa-\u003eassoc_num)\n \t\treturn 0;\n@@ -353,13 +357,26 @@ static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,\n \trule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :\n \t\t\t\t MLX5_ACCEL_MACSEC_ACTION_DECRYPT;\n \n+\tif (!is_tx) {\n+\t\terr = mlx5e_accel_block_tc_offload(priv-\u003emdev);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n \tmacsec_rule = mlx5_macsec_fs_add_rule(macsec_fs, ctx, \u0026rule_attrs, fs_id);\n-\tif (!macsec_rule)\n-\t\treturn -ENOMEM;\n+\tif (!macsec_rule) {\n+\t\terr = -ENOMEM;\n+\t\tgoto out_unblock_tc;\n+\t}\n \n \tsa-\u003emacsec_rule = macsec_rule;\n \n \treturn 0;\n+\n+out_unblock_tc:\n+\tif (!is_tx)\n+\t\tmlx5e_accel_unblock_tc_offload(priv-\u003emdev);\n+\treturn err;\n }\n \n static int mlx5e_macsec_init_sa(struct macsec_context *ctx,\n@@ -735,12 +752,12 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)\n \t * a non-NULL md_dst with uninitialised contents.\n \t */\n \terr = xa_alloc(\u0026macsec-\u003esc_xarray, \u0026sc_xarray_element-\u003efs_id, sc_xarray_element,\n-\t\t XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL);\n+\t\t XA_LIMIT(1, MLX5_MACSEC_RX_FS_ID_MAX), GFP_KERNEL);\n \tif (err) {\n \t\tif (err == -EBUSY)\n \t\t\tnetdev_err(ctx-\u003enetdev,\n \t\t\t\t \"MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\\n\",\n-\t\t\t\t MLX5_MACEC_RX_FS_ID_MAX);\n+\t\t\t\t MLX5_MACSEC_RX_FS_ID_MAX);\n \t\tgoto destroy_md_dst;\n \t}\n \n@@ -1137,7 +1154,12 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,\n \tstruct mlx5e_macsec_sa *rx_sa;\n \tstruct list_head *list;\n \tint i, err = 0;\n+\tbool block_tc;\n \n+\t/* Best-effort TC block across the operation, to prevent a mistimed TC\n+\t * filter add from preventing the 2nd loop from happening.\n+\t */\n+\tblock_tc = mlx5e_accel_block_tc_offload(priv-\u003emdev) == 0;\n \n \tlist = \u0026macsec_device-\u003emacsec_rx_sc_list_head;\n \tlist_for_each_entry_safe(rx_sc, tmp, list, rx_sc_list_element) {\n@@ -1168,6 +1190,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,\n \n \tmemcpy(macsec_device-\u003edev_addr, dev-\u003edev_addr, dev-\u003eaddr_len);\n out:\n+\tif (block_tc)\n+\t\tmlx5e_accel_unblock_tc_offload(priv-\u003emdev);\n \treturn err;\n }\n \n@@ -1700,7 +1724,7 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev,\n \tif (!macsec)\n \t\treturn;\n \n-\tfs_id = MLX5_MACSEC_RX_METADAT_HANDLE(macsec_meta_data);\n+\tfs_id = MLX5_MACSEC_RX_METADATA_HANDLE(macsec_meta_data);\n \n \trcu_read_lock();\n \tsc_xarray_element = xa_load(\u0026macsec-\u003esc_xarray, fs_id);\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h\nindex 27df72e23106d..571624f2db151 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h\n@@ -9,6 +9,7 @@\n #include \u003clinux/mlx5/driver.h\u003e\n #include \u003cnet/macsec.h\u003e\n #include \u003cnet/dst_metadata.h\u003e\n+#include \"en_accel/flow_tag.h\"\n #include \"lib/macsec_fs.h\"\n \n struct mlx5e_priv;\n@@ -31,7 +32,9 @@ static inline bool mlx5e_macsec_skb_is_offload(struct sk_buff *skb)\n \n static inline bool mlx5e_macsec_is_rx_flow(struct mlx5_cqe64 *cqe)\n {\n-\treturn MLX5_MACSEC_METADATA_MARKER(be32_to_cpu(cqe-\u003eft_metadata));\n+\tu32 proto = mlx5e_accel_flow_tag_proto(cqe);\n+\n+\treturn proto == MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC;\n }\n \n void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c\nindex 73b232379263a..ad8dbd8c2f279 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c\n@@ -6,7 +6,9 @@\n #include \"mlx5_core.h\"\n #include \"psp.h\"\n #include \"lib/crypto.h\"\n+#include \"en_accel/en_accel.h\"\n #include \"en_accel/psp.h\"\n+#include \"en_accel/psp_rxtx.h\"\n #include \"fs_core.h\"\n \n enum accel_fs_psp_type {\n@@ -21,6 +23,13 @@ enum accel_psp_syndrome {\n \tPSP_BAD_TRAILER,\n };\n \n+static const u8 psp_supported_versions[] = {\n+\tPSP_VERSION_HDR0_AES_GCM_128,\n+\tPSP_VERSION_HDR0_AES_GCM_256,\n+};\n+\n+#define MLX5E_PSP_NUM_SUPPORTED_VERSIONS ARRAY_SIZE(psp_supported_versions)\n+\n struct mlx5e_psp_tx_table {\n \tstruct mlx5_flow_namespace *ns;\n \tstruct mlx5_flow_table *ft;\n@@ -41,7 +50,7 @@ struct mlx5e_psp_rx_decrypt_table {\n \tstruct mlx5_flow_table *ft;\n \tstruct mlx5_flow_group *miss_group;\n \tstruct mlx5_flow_handle *miss_rule;\n-\tstruct mlx5_modify_hdr *rx_modify_hdr;\n+\tstruct mlx5_modify_hdr *modify_hdr;\n \tstruct mlx5_flow_handle *rule;\n };\n \n@@ -52,6 +61,15 @@ struct mlx5e_psp_rx_table {\n \tstruct mlx5_flow_handle *udp_rules[ACCEL_FS_PSP_NUM_TYPES];\n };\n \n+struct mlx5e_psp_rx_decap_table {\n+\tstruct mlx5_flow_table *ft;\n+\tstruct mlx5_flow_group *drop_group;\n+\tstruct mlx5_modify_hdr *modify_hdr;\n+\tstruct mlx5_pkt_reformat *reformat;\n+\tstruct mlx5_flow_handle *rule[MLX5E_PSP_NUM_SUPPORTED_VERSIONS];\n+\tstruct mlx5_flow_handle *unsupported_rule;\n+};\n+\n struct mlx5e_psp_fs {\n \tstruct mlx5_core_dev *mdev;\n \tstruct mlx5_fc *tx_counter;\n@@ -63,12 +81,23 @@ struct mlx5e_psp_fs {\n \tstruct mlx5_fc *rx_auth_fail_counter;\n \tstruct mlx5_fc *rx_err_counter;\n \tstruct mlx5_fc *rx_bad_counter;\n+\t/* When set, steering is configured to decapsulate PSP (remove UDP+PSP\n+\t * headers and PSP trailer) and hand off the SPI in cqe.ft_metadata.\n+\t */\n+\tbool decap_enabled;\n \n \tstruct mlx5e_psp_rx_decrypt_table decrypt[ACCEL_FS_PSP_NUM_TYPES];\n \tstruct mlx5e_psp_rx_check_table check;\n+\tstruct mlx5e_psp_rx_decap_table decap;\n \tstruct mlx5e_psp_rx_table rx;\n };\n \n+static bool shampo_enabled(struct mlx5e_priv *priv)\n+{\n+\treturn priv-\u003echannels.params.packet_merge.type ==\n+\t\tMLX5E_PACKET_MERGE_SHAMPO;\n+}\n+\n /* PSP RX flow steering */\n static enum mlx5_traffic_types fs_psp2tt(enum accel_fs_psp_type i)\n {\n@@ -110,6 +139,15 @@ static void accel_psp_fs_del_flow_rule(struct mlx5_flow_handle **rule)\n \t}\n }\n \n+static void accel_psp_fs_dealloc_modify_hdr(struct mlx5_core_dev *dev,\n+\t\t\t\t\t struct mlx5_modify_hdr **modhdr)\n+{\n+\tif (*modhdr) {\n+\t\tmlx5_modify_header_dealloc(dev, *modhdr);\n+\t\t*modhdr = NULL;\n+\t}\n+}\n+\n static int accel_psp_fs_create_miss_group(struct mlx5_flow_table *ft,\n \t\t\t\t\t struct mlx5_flow_group **group)\n {\n@@ -402,15 +440,161 @@ int accel_psp_fs_rx_check_ft_create(struct mlx5e_psp_fs *fs,\n \treturn err;\n }\n \n+static\n+void accel_psp_fs_rx_decap_ft_destroy(struct mlx5e_psp_fs *fs,\n+\t\t\t\t struct mlx5e_psp_rx_decap_table *decap)\n+{\n+\tint i;\n+\n+\taccel_psp_fs_del_flow_rule(\u0026decap-\u003eunsupported_rule);\n+\tfor (i = 0; i \u003c MLX5E_PSP_NUM_SUPPORTED_VERSIONS; i++)\n+\t\taccel_psp_fs_del_flow_rule(\u0026decap-\u003erule[i]);\n+\tif (decap-\u003ereformat) {\n+\t\tmlx5_packet_reformat_dealloc(fs-\u003emdev, decap-\u003ereformat);\n+\t\tdecap-\u003ereformat = NULL;\n+\t}\n+\taccel_psp_fs_dealloc_modify_hdr(fs-\u003emdev, \u0026decap-\u003emodify_hdr);\n+\taccel_psp_fs_destroy_flow_group(\u0026decap-\u003edrop_group);\n+\taccel_psp_fs_destroy_ft(\u0026decap-\u003eft);\n+}\n+\n+static void setup_fte_psp_version(struct mlx5_flow_spec *spec, u8 version)\n+{\n+\tvoid *misc_params_6;\n+\n+\tmemset(spec, 0, sizeof(*spec));\n+\tspec-\u003ematch_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_6;\n+\tmisc_params_6 = MLX5_ADDR_OF(fte_match_param, spec-\u003ematch_criteria,\n+\t\t\t\t misc_parameters_6);\n+\tMLX5_SET_TO_ONES(fte_match_set_misc6, misc_params_6, psp_version);\n+\tmisc_params_6 = MLX5_ADDR_OF(fte_match_param, spec-\u003ematch_value,\n+\t\t\t\t misc_parameters_6);\n+\tMLX5_SET(fte_match_set_misc6, misc_params_6, psp_version, version);\n+}\n+\n+static\n+int accel_psp_fs_rx_decap_ft_create(struct mlx5e_psp_fs *fs,\n+\t\t\t\t struct mlx5e_psp_rx_decap_table *decap)\n+{\n+\tu8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};\n+\tstruct mlx5_pkt_reformat_params reformat_params = {};\n+\tstruct mlx5_flow_table_attr ft_attr = {};\n+\tstruct mlx5_flow_destination dest = {};\n+\tstruct mlx5_core_dev *mdev = fs-\u003emdev;\n+\tstruct mlx5_pkt_reformat *reformat;\n+\tstruct mlx5_modify_hdr *modify_hdr;\n+\tstruct mlx5_flow_handle *rule;\n+\tstruct mlx5_flow_spec *spec;\n+\tint i, err = 0;\n+\n+\tspec = kvzalloc_obj(*spec);\n+\tif (!spec)\n+\t\treturn -ENOMEM;\n+\n+\t/* Create FT */\n+\tft_attr.max_fte = 1 + MLX5E_PSP_NUM_SUPPORTED_VERSIONS;\n+\tft_attr.level = MLX5E_ACCEL_FS_PSP_DECAP_FT_LEVEL;\n+\tft_attr.prio = MLX5E_NIC_PRIO;\n+\tft_attr.autogroup.num_reserved_entries = 1;\n+\terr = accel_psp_fs_create_ft(fs, \u0026ft_attr, \u0026decap-\u003eft);\n+\tif (err) {\n+\t\tmlx5_core_err(mdev, \"fail to create psp decap rx ft err=%d\\n\",\n+\t\t\t err);\n+\t\tgoto out_spec;\n+\t}\n+\n+\t/* Create drop group */\n+\terr = accel_psp_fs_create_miss_group(decap-\u003eft, \u0026decap-\u003edrop_group);\n+\tif (err) {\n+\t\tmlx5_core_err(mdev,\n+\t\t\t \"fail to create psp decap rx drop_group err=%d\\n\",\n+\t\t\t err);\n+\t\tgoto out_err;\n+\t}\n+\n+\t/* Add default drop rule */\n+\terr = accel_psp_add_drop_rule(decap-\u003eft, NULL, fs-\u003erx_bad_counter,\n+\t\t\t\t \u0026decap-\u003eunsupported_rule);\n+\tif (err) {\n+\t\tmlx5_core_err(mdev,\n+\t\t\t \"fail to create psp decap unsupported versions drop rule err=%d\\n\",\n+\t\t\t err);\n+\t\tgoto out_err;\n+\t}\n+\n+\t/* modify_hdr: copy SPI from REG_C_0 to REG_B */\n+\tMLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);\n+\tMLX5_SET(copy_action_in, action, src_field,\n+\t\t MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);\n+\tMLX5_SET(copy_action_in, action, src_offset, 0);\n+\tMLX5_SET(copy_action_in, action, length, 0); /* 0 = 32 bits */\n+\tMLX5_SET(copy_action_in, action, dst_field,\n+\t\t MLX5_ACTION_IN_FIELD_METADATA_REG_B);\n+\tMLX5_SET(copy_action_in, action, dst_offset, 0);\n+\n+\tmodify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,\n+\t\t\t\t\t 1, action);\n+\tif (IS_ERR(modify_hdr)) {\n+\t\terr = PTR_ERR(modify_hdr);\n+\t\tgoto out_err;\n+\t}\n+\tdecap-\u003emodify_hdr = modify_hdr;\n+\n+\t/* pkt_reformat: decap PSP transport */\n+\treformat_params.type = MLX5_REFORMAT_TYPE_REMOVE_PSP_TRANSPORT;\n+\treformat = mlx5_packet_reformat_alloc(mdev, \u0026reformat_params,\n+\t\t\t\t\t MLX5_FLOW_NAMESPACE_KERNEL);\n+\tif (IS_ERR(reformat)) {\n+\t\terr = PTR_ERR(reformat);\n+\t\tgoto out_err;\n+\t}\n+\tdecap-\u003ereformat = reformat;\n+\n+\tfor (i = 0; i \u003c MLX5E_PSP_NUM_SUPPORTED_VERSIONS; i++) {\n+\t\tu8 version = psp_supported_versions[i];\n+\t\tstruct mlx5_flow_act flow_act = {};\n+\n+\t\t/* match(version) =\u003e decap, copy SPI, fwd to rx FT */\n+\t\tsetup_fte_psp_version(spec, version);\n+\n+\t\t/*\n+\t\t * Override the flow tag set in the decrypt table with\n+\t\t * the decap PSP marker and version.\n+\t\t */\n+\t\tspec-\u003eflow_context.flags = FLOW_CONTEXT_HAS_TAG;\n+\t\tspec-\u003eflow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP |\n+\t\t\t((u32)version \u003c\u003c MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT);\n+\n+\t\tflow_act.action = MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |\n+\t\t\tMLX5_FLOW_CONTEXT_ACTION_MOD_HDR |\n+\t\t\tMLX5_FLOW_CONTEXT_ACTION_FWD_DEST;\n+\t\tflow_act.pkt_reformat = reformat;\n+\t\tflow_act.modify_hdr = modify_hdr;\n+\t\tdest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;\n+\t\tdest.ft = fs-\u003erx.ft;\n+\n+\t\trule = mlx5_add_flow_rules(decap-\u003eft, spec, \u0026flow_act, \u0026dest, 1);\n+\t\tif (IS_ERR(rule)) {\n+\t\t\terr = PTR_ERR(rule);\n+\t\t\tgoto out_err;\n+\t\t}\n+\t\tdecap-\u003erule[i] = rule;\n+\t}\n+\tgoto out_spec;\n+\n+out_err:\n+\taccel_psp_fs_rx_decap_ft_destroy(fs, decap);\n+out_spec:\n+\tkvfree(spec);\n+\treturn err;\n+}\n+\n static void\n accel_psp_fs_rx_decrypt_ft_destroy(struct mlx5e_psp_fs *fs,\n \t\t\t\t struct mlx5e_psp_rx_decrypt_table *decrypt)\n {\n \taccel_psp_fs_del_flow_rule(\u0026decrypt-\u003erule);\n-\tif (decrypt-\u003erx_modify_hdr) {\n-\t\tmlx5_modify_header_dealloc(fs-\u003emdev, decrypt-\u003erx_modify_hdr);\n-\t\tdecrypt-\u003erx_modify_hdr = NULL;\n-\t}\n+\taccel_psp_fs_dealloc_modify_hdr(fs-\u003emdev, \u0026decrypt-\u003emodify_hdr);\n \taccel_psp_fs_del_flow_rule(\u0026decrypt-\u003emiss_rule);\n \taccel_psp_fs_destroy_flow_group(\u0026decrypt-\u003emiss_group);\n \taccel_psp_fs_destroy_ft(\u0026decrypt-\u003eft);\n@@ -431,11 +615,11 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,\n \t\t\t\t struct mlx5_flow_destination *default_dest)\n {\n \tu8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};\n-\tstruct mlx5_modify_hdr *modify_hdr = NULL;\n \tstruct mlx5_flow_table_attr ft_attr = {};\n \tstruct mlx5_flow_destination dest = {};\n \tstruct mlx5_core_dev *mdev = fs-\u003emdev;\n \tMLX5_DECLARE_FLOW_ACT(flow_act);\n+\tstruct mlx5_modify_hdr *modhdr;\n \tstruct mlx5_flow_handle *rule;\n \tstruct mlx5_flow_spec *spec;\n \tint err = 0;\n@@ -479,30 +663,36 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,\n \t}\n \tdecrypt-\u003emiss_rule = rule;\n \n-\t/* Add PSP RX decrypt rule */\n-\tsetup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);\n-\tflow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;\n-\t/* Set bit[31, 30] PSP marker */\n-#define MLX5E_PSP_MARKER_BIT (BIT(30) | BIT(31))\n-\tMLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);\n-\tMLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);\n-\tMLX5_SET(set_action_in, action, data, MLX5E_PSP_MARKER_BIT);\n-\tMLX5_SET(set_action_in, action, offset, 0);\n-\tMLX5_SET(set_action_in, action, length, 32);\n-\n-\tmodify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL, 1, action);\n-\tif (IS_ERR(modify_hdr)) {\n-\t\terr = PTR_ERR(modify_hdr);\n-\t\tmlx5_core_err(mdev, \"fail to alloc psp set modify_header_id err=%d\\n\", err);\n-\t\tmodify_hdr = NULL;\n+\t/* Create modify_hdr to copy SPI to REG_C_0 */\n+\tMLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);\n+\tMLX5_SET(copy_action_in, action, src_field,\n+\t\t MLX5_ACTION_IN_FIELD_PSP_HEADER_1);\n+\tMLX5_SET(copy_action_in, action, src_offset, 0);\n+\tMLX5_SET(copy_action_in, action, length, 0); /* 0 = 32 bits */\n+\tMLX5_SET(copy_action_in, action, dst_field,\n+\t\t MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);\n+\tMLX5_SET(copy_action_in, action, dst_offset, 0);\n+\n+\tmodhdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL, 1,\n+\t\t\t\t\t action);\n+\tif (IS_ERR(modhdr)) {\n+\t\terr = PTR_ERR(modhdr);\n \t\tgoto out_err;\n \t}\n-\tdecrypt-\u003erx_modify_hdr = modify_hdr;\n+\tdecrypt-\u003emodify_hdr = modhdr;\n \n-\tflow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |\n-\t\t\t MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |\n-\t\t\t MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;\n-\tflow_act.modify_hdr = modify_hdr;\n+\t/* Add PSP RX decrypt rule */\n+\tsetup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);\n+\n+\t/* Set PSP marker via flow_tag */\n+\tspec-\u003eflow_context.flags = FLOW_CONTEXT_HAS_TAG;\n+\tspec-\u003eflow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_PSP;\n+\n+\tflow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;\n+\tflow_act.action = MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |\n+\t\tMLX5_FLOW_CONTEXT_ACTION_MOD_HDR |\n+\t\tMLX5_FLOW_CONTEXT_ACTION_FWD_DEST;\n+\tflow_act.modify_hdr = modhdr;\n \tdest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;\n \tdest.ft = fs-\u003echeck.ft;\n \trule = mlx5_add_flow_rules(decrypt-\u003eft, spec, \u0026flow_act, \u0026dest, 1);\n@@ -523,9 +713,50 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,\n \treturn err;\n }\n \n+static int accel_psp_fs_rx_reconfigure(struct mlx5e_psp_fs *fs,\n+\t\t\t\t bool decap_wanted)\n+{\n+\tbool decap_supported =\n+\t\tMLX5_CAP_FLOWTABLE(fs-\u003emdev,\n+\t\t\t\t flow_table_properties_nic_receive.reformat_del_psp_transport);\n+\tbool decap_enable = decap_wanted \u0026\u0026 decap_supported;\n+\tstruct mlx5_flow_destination dest = {};\n+\tint err;\n+\n+\t/* Create the decap table if needed. */\n+\tif (decap_enable \u0026\u0026 !fs-\u003edecap.ft) {\n+\t\terr = accel_psp_fs_rx_decap_ft_create(fs, \u0026fs-\u003edecap);\n+\t\tif (err) {\n+\t\t\tmlx5_core_warn(fs-\u003emdev,\n+\t\t\t\t \"Failed to create PSP decapsulation rules (err %d), HW GRO for PSP unavailable\",\n+\t\t\t\t err);\n+\t\t\tdecap_enable = false;\n+\t\t}\n+\t}\n+\tif (decap_enable == fs-\u003edecap_enabled)\n+\t\treturn 0;\n+\n+\t/* Redirect traffic to the correct table. */\n+\tdest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;\n+\tdest.ft = decap_enable ? fs-\u003edecap.ft : fs-\u003erx.ft;\n+\terr = mlx5_modify_rule_destination(fs-\u003echeck.rule, \u0026dest, NULL);\n+\tif (err)\n+\t\tgoto out_destroy_ft;\n+\n+\tfs-\u003edecap_enabled = decap_enable;\n+\n+\treturn 0;\n+\n+out_destroy_ft:\n+\tif (decap_enable)\n+\t\taccel_psp_fs_rx_decap_ft_destroy(fs, \u0026fs-\u003edecap);\n+\treturn err;\n+}\n+\n static void accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs)\n {\n \tstruct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs-\u003efs, false);\n+\tbool tc_blocked = fs-\u003erx.ft;\n \tint i;\n \n \t/* disconnect */\n@@ -534,19 +765,29 @@ static void accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs)\n \t\taccel_psp_fs_rx_decrypt_ft_destroy(fs, \u0026fs-\u003edecrypt[i]);\n \t}\n \taccel_psp_fs_rx_check_ft_destroy(\u0026fs-\u003echeck);\n+\taccel_psp_fs_rx_decap_ft_destroy(fs, \u0026fs-\u003edecap);\n \taccel_psp_fs_rx_ft_destroy(\u0026fs-\u003erx);\n+\tif (tc_blocked)\n+\t\tmlx5e_accel_unblock_tc_offload(fs-\u003emdev);\n }\n \n static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,\n+\t\t\t\t bool decap_enable,\n \t\t\t\t struct netlink_ext_ack *extack)\n {\n \tstruct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs-\u003efs, false);\n \tint i, err;\n \n+\terr = mlx5e_accel_block_tc_offload(fs-\u003emdev);\n+\tif (err) {\n+\t\tNL_SET_ERR_MSG(extack, \"TC offload active, cannot enable PSP\");\n+\t\treturn err;\n+\t}\n+\n \terr = accel_psp_fs_rx_ft_create(fs, \u0026fs-\u003erx);\n \tif (err) {\n \t\tNL_SET_ERR_MSG(extack, \"Failed creating RX steering table\");\n-\t\treturn err;\n+\t\tgoto err_unblock_tc;\n \t}\n \n \terr = accel_psp_fs_rx_check_ft_create(fs, \u0026fs-\u003echeck);\n@@ -573,6 +814,12 @@ static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,\n \t\tmlx5_ttc_fwd_dest(ttc, fs_psp2tt(i), \u0026dest);\n \t}\n \n+\terr = accel_psp_fs_rx_reconfigure(fs, decap_enable);\n+\tif (err) {\n+\t\tNL_SET_ERR_MSG(extack, \"Failed RX steering config for HW GRO\");\n+\t\tgoto err_decrypt_ft;\n+\t}\n+\n \treturn 0;\n \n err_decrypt_ft:\n@@ -583,6 +830,8 @@ static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,\n \taccel_psp_fs_rx_check_ft_destroy(\u0026fs-\u003echeck);\n err_ft:\n \taccel_psp_fs_rx_ft_destroy(\u0026fs-\u003erx);\n+err_unblock_tc:\n+\tmlx5e_accel_unblock_tc_offload(fs-\u003emdev);\n \treturn err;\n }\n \n@@ -839,7 +1088,8 @@ static int accel_psp_fs_create(struct mlx5e_priv *priv,\n {\n \tint err;\n \n-\terr = accel_psp_fs_rx_create(priv-\u003epsp-\u003efs, extack);\n+\terr = accel_psp_fs_rx_create(priv-\u003epsp-\u003efs, shampo_enabled(priv),\n+\t\t\t\t extack);\n \tif (err)\n \t\treturn err;\n \n@@ -1116,3 +1366,14 @@ void mlx5e_psp_cleanup(struct mlx5e_priv *priv)\n \tpriv-\u003epsp = NULL;\n \tkfree(psp);\n }\n+\n+int mlx5e_psp_update_rx(struct mlx5e_priv *priv)\n+{\n+\tstruct mlx5e_psp *psp = priv-\u003epsp;\n+\n+\tnetdev_assert_locked(priv-\u003enetdev);\n+\tif (!psp || !psp-\u003efs-\u003echeck.ft)\n+\t\treturn 0;\n+\n+\treturn accel_psp_fs_rx_reconfigure(psp-\u003efs, shampo_enabled(priv));\n+}\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h\nindex 3f441e7dd55ac..76f6c69de0e91 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h\n@@ -49,6 +49,7 @@ int mlx5e_psp_register(struct mlx5e_priv *priv);\n void mlx5e_psp_unregister(struct mlx5e_priv *priv);\n int mlx5e_psp_init(struct mlx5e_priv *priv);\n void mlx5e_psp_cleanup(struct mlx5e_priv *priv);\n+int mlx5e_psp_update_rx(struct mlx5e_priv *priv);\n #else\n static inline void mlx5_accel_psp_fs_cleanup_rx_tables(struct mlx5e_priv *priv) { }\n static inline void mlx5_accel_psp_fs_cleanup_tx_tables(struct mlx5e_priv *priv) { }\n@@ -61,5 +62,6 @@ static inline int mlx5e_psp_register(struct mlx5e_priv *priv) { return 0; }\n static inline void mlx5e_psp_unregister(struct mlx5e_priv *priv) { }\n static inline int mlx5e_psp_init(struct mlx5e_priv *priv) { return 0; }\n static inline void mlx5e_psp_cleanup(struct mlx5e_priv *priv) { }\n+static inline int mlx5e_psp_update_rx(struct mlx5e_priv *priv) { return 0; }\n #endif /* CONFIG_MLX5_EN_PSP */\n #endif /* __MLX5E_ACCEL_PSP_H__ */\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c\nindex 348fd7a962615..2beffee14278d 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c\n@@ -118,10 +118,25 @@ bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *\n {\n \tstruct mlx5e_priv *priv = netdev_priv(netdev);\n \tu16 dev_id = priv-\u003epsp-\u003epsd-\u003eid;\n-\tbool strip_icv = true;\n-\tu8 generation = 0;\n+\tstruct psp_skb_ext *pse;\n+\n+\tif (mlx5e_psp_is_decap(cqe)) {\n+\t\t/* UDP + PSP headers and PSP trailer removed by HW.\n+\t\t * Construct the PSP extension from CQE metadata.\n+\t\t */\n+\t\tpse = skb_ext_add(skb, SKB_EXT_PSP);\n+\t\tif (unlikely(!pse))\n+\t\t\tgoto drop;\n+\n+\t\tpse-\u003espi = mlx5e_psp_get_spi(cqe);\n+\t\tpse-\u003eversion = mlx5e_psp_get_version(cqe);\n+\t\tpse-\u003edev_id = dev_id;\n+\t\tpse-\u003egeneration = 0;\n+\t\tskb-\u003edecrypted = 1;\n+\t\treturn false;\n+\t}\n \n-\tif (psp_dev_rcv(skb, dev_id, generation, strip_icv))\n+\tif (psp_dev_rcv(skb, dev_id, 0, true))\n \t\tgoto drop;\n \n \tskb-\u003edecrypted = 1;\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h\nindex 2b080c39cc37e..41b60259b3bc6 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h\n@@ -9,10 +9,7 @@\n #include \u003cnet/psp.h\u003e\n #include \"en.h\"\n #include \"en/txrx.h\"\n-\n-/* Bit30: PSP marker, Bit22-0: PSP obj id */\n-#define MLX5_PSP_METADATA_MARKER(metadata) ((((metadata) \u003e\u003e 30) \u0026 0x3) == 0x3)\n-#define MLX5_PSP_METADATA_HANDLE(metadata) ((metadata) \u0026 GENMASK(22, 0))\n+#include \"en_accel/flow_tag.h\"\n \n struct mlx5e_accel_tx_psp_state {\n \tu32 tailen;\n@@ -82,7 +79,29 @@ static inline unsigned int mlx5e_psp_tx_ids_len(struct mlx5e_accel_tx_psp_state\n \n static inline bool mlx5e_psp_is_rx_flow(struct mlx5_cqe64 *cqe)\n {\n-\treturn MLX5_PSP_METADATA_MARKER(be32_to_cpu(cqe-\u003eft_metadata));\n+\tu32 proto = mlx5e_accel_flow_tag_proto(cqe);\n+\n+\treturn proto == MLX5E_ACCEL_FLOW_TAG_PROTO_PSP ||\n+\t\tproto == MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP;\n+\n+}\n+\n+static inline bool mlx5e_psp_is_decap(struct mlx5_cqe64 *cqe)\n+{\n+\tu32 proto = mlx5e_accel_flow_tag_proto(cqe);\n+\n+\treturn proto == MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP;\n+}\n+\n+static inline u8 mlx5e_psp_get_version(struct mlx5_cqe64 *cqe)\n+{\n+\treturn (mlx5e_accel_flow_tag(cqe) \u0026 MLX5E_ACCEL_FLOW_TAG_PSP_VER_MASK) \u003e\u003e\n+\t\tMLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT;\n+}\n+\n+static inline __be32 mlx5e_psp_get_spi(struct mlx5_cqe64 *cqe)\n+{\n+\treturn cqe-\u003eft_metadata;\n }\n \n bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,\n@@ -110,6 +129,21 @@ static inline bool mlx5e_psp_is_rx_flow(struct mlx5_cqe64 *cqe)\n \treturn false;\n }\n \n+static inline bool mlx5e_psp_is_decap(struct mlx5_cqe64 *cqe)\n+{\n+\treturn false;\n+}\n+\n+static inline u8 mlx5e_psp_get_version(struct mlx5_cqe64 *cqe)\n+{\n+\treturn 0;\n+}\n+\n+static inline __be32 mlx5e_psp_get_spi(struct mlx5_cqe64 *cqe)\n+{\n+\treturn 0;\n+}\n+\n static inline bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev,\n \t\t\t\t\t\t struct sk_buff *skb,\n \t\t\t\t\t\t struct mlx5_cqe64 *cqe)\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c\nindex 3b9d42c7e9c28..3c6ef500d0fb3 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c\n@@ -6286,7 +6286,13 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)\n \n static int mlx5e_update_nic_rx(struct mlx5e_priv *priv)\n {\n-\treturn mlx5e_refresh_tirs(priv-\u003emdev, false, false);\n+\tint err;\n+\n+\terr = mlx5e_refresh_tirs(priv-\u003emdev, false, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn mlx5e_accel_update_rx(priv);\n }\n \n static const struct mlx5e_profile mlx5e_nic_profile = {\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c\nindex fb7110b1b6834..c7eaab3f7967b 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c\n@@ -2221,6 +2221,33 @@ static bool mlx5e_hw_gro_skb_has_enough_space(struct sk_buff *skb,\n \t\treturn page_size * nr_frags + data_bcnt \u003c= GRO_LEGACY_MAX_SIZE;\n }\n \n+static bool mlx5e_hw_gro_psp_match(struct sk_buff *skb, struct mlx5_cqe64 *cqe)\n+{\n+#ifdef CONFIG_MLX5_EN_PSP\n+\tstruct psp_skb_ext *pse = skb_ext_find(skb, SKB_EXT_PSP);\n+\tbool is_psp = mlx5e_psp_is_rx_flow(cqe);\n+\n+\tif (likely(!is_psp \u0026\u0026 !pse))\n+\t\treturn true;\n+\n+\t/* No match on PSP status change (no crypto -\u003e crypto or vice-versa). */\n+\tif (unlikely(is_psp != !!pse))\n+\t\treturn false;\n+\n+\t/* SPI and version are only available in CQE metadata for decap flows.\n+\t * Non-decap PSP cannot be matched here, force a flush.\n+\t */\n+\tif (unlikely(!mlx5e_psp_is_decap(cqe)))\n+\t\treturn false;\n+\n+\t/* No match on security parameters change. */\n+\treturn pse-\u003espi == mlx5e_psp_get_spi(cqe) \u0026\u0026\n+\t\tpse-\u003eversion == mlx5e_psp_get_version(cqe);\n+#else\n+\treturn true;\n+#endif\n+}\n+\n static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)\n {\n \tu16 data_bcnt\t\t= mpwrq_get_cqe_byte_cnt(cqe) - cqe-\u003eshampo.header_size;\n@@ -2258,8 +2285,9 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq\n \tdata_offset = wqe_offset \u0026 (page_size - 1);\n \tpage_idx = wqe_offset \u003e\u003e rq-\u003empwqe.page_shift;\n \tif (*skb \u0026\u0026\n-\t !(match \u0026\u0026 mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt,\n-\t\t\t\t\t\t\t page_size))) {\n+\t !(match \u0026\u0026\n+\t mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt, page_size) \u0026\u0026\n+\t mlx5e_hw_gro_psp_match(*skb, cqe))) {\n \t\tmatch = false;\n \t\tmlx5e_shampo_flush_skb(rq, cqe, match);\n \t}\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c\nindex 1bc7b9019124a..70195fcddfc82 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c\n@@ -4811,14 +4811,14 @@ static bool is_flow_rule_duplicate_allowed(struct net_device *dev,\n \treturn netif_is_lag_port(dev) \u0026\u0026 rpriv \u0026\u0026 rpriv-\u003erep-\u003evport != MLX5_VPORT_UPLINK;\n }\n \n-/* As IPsec and TC order is not aligned between software and hardware-offload,\n- * either IPsec offload or TC offload, not both, is allowed for a specific interface.\n+/* TC offload and accel protocols can overwrite each other's flow_tag with\n+ * steering rules and they cannot simultaneously operate on the same interface.\n+ * Additionally, as IPsec and TC order is not aligned between software and\n+ * hardware-offload, only one is allowed for a specific interface.\n */\n-static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx5e_priv *priv)\n+static bool is_tc_accel_check_needed(struct net_device *filter,\n+\t\t\t\t struct mlx5e_priv *priv)\n {\n-\tif (!IS_ENABLED(CONFIG_MLX5_EN_IPSEC))\n-\t\treturn false;\n-\n \tif (filter != priv-\u003enetdev)\n \t\treturn false;\n \n@@ -4828,27 +4828,35 @@ static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx\n \treturn true;\n }\n \n-static int mlx5e_tc_block_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)\n+static int mlx5e_tc_block_accel_offload(struct net_device *filter,\n+\t\t\t\t\tstruct mlx5e_priv *priv)\n {\n \tstruct mlx5_core_dev *mdev = priv-\u003emdev;\n+\tint ret = 0;\n \n-\tif (!is_tc_ipsec_order_check_needed(filter, priv))\n+\tif (!is_tc_accel_check_needed(filter, priv))\n \t\treturn 0;\n \n-\tif (mdev-\u003enum_block_tc)\n-\t\treturn -EBUSY;\n-\n-\tmdev-\u003enum_block_ipsec++;\n+\tmutex_lock(\u0026mdev-\u003eoffload_block.lock);\n+\tif (mdev-\u003eoffload_block.num_tc)\n+\t\tret = -EBUSY;\n+\telse\n+\t\tmdev-\u003eoffload_block.num_accel++;\n+\tmutex_unlock(\u0026mdev-\u003eoffload_block.lock);\n \n-\treturn 0;\n+\treturn ret;\n }\n \n-static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)\n+static void mlx5e_tc_unblock_accel_offload(struct net_device *filter,\n+\t\t\t\t\t struct mlx5e_priv *priv)\n {\n-\tif (!is_tc_ipsec_order_check_needed(filter, priv))\n+\tif (!is_tc_accel_check_needed(filter, priv))\n \t\treturn;\n \n-\tpriv-\u003emdev-\u003enum_block_ipsec--;\n+\tmutex_lock(\u0026priv-\u003emdev-\u003eoffload_block.lock);\n+\tif (!WARN_ON_ONCE(!priv-\u003emdev-\u003eoffload_block.num_accel))\n+\t\tpriv-\u003emdev-\u003eoffload_block.num_accel--;\n+\tmutex_unlock(\u0026priv-\u003emdev-\u003eoffload_block.lock);\n }\n \n int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,\n@@ -4863,7 +4871,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,\n \tif (!mlx5_esw_hold(priv-\u003emdev))\n \t\treturn -EBUSY;\n \n-\terr = mlx5e_tc_block_ipsec_offload(dev, priv);\n+\terr = mlx5e_tc_block_accel_offload(dev, priv);\n \tif (err)\n \t\tgoto esw_release;\n \n@@ -4912,7 +4920,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,\n err_free:\n \tmlx5e_flow_put(priv, flow);\n out:\n-\tmlx5e_tc_unblock_ipsec_offload(dev, priv);\n+\tmlx5e_tc_unblock_accel_offload(dev, priv);\n \tmlx5_esw_put(priv-\u003emdev);\n esw_release:\n \tmlx5_esw_release(priv-\u003emdev);\n@@ -4955,7 +4963,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,\n \ttrace_mlx5e_delete_flower(f);\n \tmlx5e_flow_put(priv, flow);\n \n-\tmlx5e_tc_unblock_ipsec_offload(dev, priv);\n+\tmlx5e_tc_unblock_accel_offload(dev, priv);\n \tmlx5_esw_put(priv-\u003emdev);\n \treturn 0;\n \ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h\nindex e1b8cb78369f1..53b6043e33d22 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h\n@@ -36,6 +36,7 @@\n #include \u003cnet/pkt_cls.h\u003e\n #include \"en.h\"\n #include \"eswitch.h\"\n+#include \"en_accel/flow_tag.h\"\n #include \"en/tc_ct.h\"\n #include \"en/tc_tun.h\"\n #include \"en/tc/int_port.h\"\n@@ -370,11 +371,13 @@ struct mlx5e_tc_table *mlx5e_tc_table_alloc(void);\n void mlx5e_tc_table_free(struct mlx5e_tc_table *tc);\n static inline bool mlx5e_cqe_regb_chain(struct mlx5_cqe64 *cqe)\n {\n-\tu32 chain, reg_b;\n+\tu32 flow_tag, reg_b, chain;\n \n+\tflow_tag = mlx5e_accel_flow_tag_proto(cqe);\n \treg_b = be32_to_cpu(cqe-\u003eft_metadata);\n \n-\tif (reg_b \u003e\u003e (MLX5E_TC_TABLE_CHAIN_TAG_BITS + ESW_ZONE_ID_BITS))\n+\tif (flow_tag != MLX5E_ACCEL_FLOW_TAG_PROTO_NONE ||\n+\t (reg_b \u003e\u003e (MLX5E_TC_TABLE_CHAIN_TAG_BITS + ESW_ZONE_ID_BITS)))\n \t\treturn false;\n \n \tchain = reg_b \u0026 MLX5E_TC_TABLE_CHAIN_TAG_MASK;\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c\nindex efc5167493c12..b8e9021027e96 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c\n@@ -8,6 +8,7 @@\n #include \u003clinux/mlx5/macsec.h\u003e\n #include \"fs_core.h\"\n #include \"lib/macsec_fs.h\"\n+#include \"en_accel/flow_tag.h\"\n #include \"mlx5_core.h\"\n \n /* MACsec TX flow steering */\n@@ -45,9 +46,6 @@\n #define MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI 0x8\n #define MLX5_SECTAG_HEADER_SIZE_WITH_SCI (MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI + MACSEC_SCI_LEN)\n \n-/* MACsec fs_id handling for steering */\n-#define macsec_fs_set_rx_fs_id(fs_id) ((fs_id) | BIT(30))\n-\n struct mlx5_sectag_header {\n \t__be16 ethertype;\n \tu8 tci_an;\n@@ -1757,11 +1755,10 @@ macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,\n \trx_tables = \u0026rx_fs-\u003etables;\n \tft_crypto = \u0026rx_tables-\u003eft_crypto;\n \n-\t/* Set bit[31 - 30] macsec marker - 0x01 */\n \t/* Set bit[15-0] fs id */\n \tMLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);\n \tMLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);\n-\tMLX5_SET(set_action_in, action, data, macsec_fs_set_rx_fs_id(fs_id));\n+\tMLX5_SET(set_action_in, action, data, fs_id);\n \tMLX5_SET(set_action_in, action, offset, 0);\n \tMLX5_SET(set_action_in, action, length, 32);\n \n@@ -1778,6 +1775,9 @@ macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,\n \t/* Rx crypto table with SCI rule */\n \tmacsec_fs_rx_setup_fte(spec, \u0026flow_act, attrs, true);\n \n+\tspec-\u003eflow_context.flags |= FLOW_CONTEXT_HAS_TAG;\n+\tspec-\u003eflow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC;\n+\n \tflow_act.modify_hdr = modify_hdr;\n \tflow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |\n \t\t\t MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |\n@@ -1803,6 +1803,9 @@ macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,\n \n \t\tmacsec_fs_rx_setup_fte(spec, \u0026flow_act, attrs, false);\n \n+\t\tspec-\u003eflow_context.flags |= FLOW_CONTEXT_HAS_TAG;\n+\t\tspec-\u003eflow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC;\n+\n \t\tflow_act.modify_hdr = modify_hdr;\n \t\tflow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |\n \t\t\t\t MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |\n@@ -2160,8 +2163,8 @@ static int mlx5_macsec_fs_add_roce_rule_rx(struct mlx5_macsec_fs *macsec_fs, u32\n \n \tspec-\u003ematch_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;\n \tMLX5_SET_TO_ONES(fte_match_param, spec-\u003ematch_criteria, misc_parameters_2.metadata_reg_c_5);\n-\tMLX5_SET(fte_match_param, spec-\u003ematch_value, misc_parameters_2.metadata_reg_c_5,\n-\t\t macsec_fs_set_rx_fs_id(fs_id));\n+\tMLX5_SET(fte_match_param, spec-\u003ematch_value,\n+\t\t misc_parameters_2.metadata_reg_c_5, fs_id);\n \tflow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;\n \tnew_rule = mlx5_add_flow_rules(rx_fs-\u003eroce.ft_macsec_op_check, spec, \u0026flow_act,\n \t\t\t\t NULL, 0);\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h\nindex 15acaff436417..b8b8b412d5c3e 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h\n@@ -6,11 +6,10 @@\n \n #ifdef CONFIG_MLX5_MACSEC\n \n-/* Bit31 - 30: MACsec marker, Bit15-0: MACsec id */\n-#define MLX5_MACEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */\n-#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACEC_RX_FS_ID_MAX\n-#define MLX5_MACSEC_METADATA_MARKER(metadata) ((((metadata) \u003e\u003e 30) \u0026 0x3) == 0x1)\n-#define MLX5_MACSEC_RX_METADAT_HANDLE(metadata) ((metadata) \u0026 MLX5_MACSEC_RX_FS_ID_MASK)\n+/* MACsec fs_id in ft_metadata bits[15:0] */\n+#define MLX5_MACSEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */\n+#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACSEC_RX_FS_ID_MAX\n+#define MLX5_MACSEC_RX_METADATA_HANDLE(metadata) ((metadata) \u0026 MLX5_MACSEC_RX_FS_ID_MASK)\n \n /* MACsec TX flow steering */\n #define MLX5_ETH_WQE_FT_META_MACSEC_MASK \\\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c\nindex 643b4aac20336..406c0f7e63d81 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c\n@@ -1810,6 +1810,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)\n \tlockdep_register_key(\u0026dev-\u003elock_key);\n \tmutex_init(\u0026dev-\u003eintf_state_mutex);\n \tlockdep_set_class(\u0026dev-\u003eintf_state_mutex, \u0026dev-\u003elock_key);\n+\tmutex_init(\u0026dev-\u003eoffload_block.lock);\n \tmutex_init(\u0026dev-\u003emlx5e_res.uplink_netdev_lock);\n \tmutex_init(\u0026dev-\u003ewc_state_lock);\n \n@@ -1898,6 +1899,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)\n \tmutex_destroy(\u0026priv-\u003ealloc_mutex);\n \tmutex_destroy(\u0026priv-\u003ebfregs.wc_head.lock);\n \tmutex_destroy(\u0026priv-\u003ebfregs.reg_head.lock);\n+\tmutex_destroy(\u0026dev-\u003eoffload_block.lock);\n \tmutex_destroy(\u0026dev-\u003eintf_state_mutex);\n \tlockdep_unregister_key(\u0026dev-\u003elock_key);\n \treturn err;\n@@ -1925,6 +1927,7 @@ void mlx5_mdev_uninit(struct mlx5_core_dev *dev)\n \tmutex_destroy(\u0026priv-\u003ebfregs.reg_head.lock);\n \tmutex_destroy(\u0026dev-\u003ewc_state_lock);\n \tmutex_destroy(\u0026dev-\u003emlx5e_res.uplink_netdev_lock);\n+\tmutex_destroy(\u0026dev-\u003eoffload_block.lock);\n \tmutex_destroy(\u0026dev-\u003eintf_state_mutex);\n \tlockdep_unregister_key(\u0026dev-\u003elock_key);\n }\ndiff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h\nindex b1871c0821d0b..2d9bc752e431e 100644\n--- a/include/linux/mlx5/driver.h\n+++ b/include/linux/mlx5/driver.h\n@@ -788,8 +788,11 @@ struct mlx5_core_dev {\n \tu32 vsc_addr;\n \tstruct mlx5_hv_vhca\t*hv_vhca;\n \tstruct mlx5_hwmon\t*hwmon;\n-\tu64\t\t\tnum_block_tc;\n-\tu64\t\t\tnum_block_ipsec;\n+\tstruct {\n+\t\tstruct mutex lock;\n+\t\tu64 num_tc;\n+\t\tu64 num_accel;\n+\t} offload_block;\n #ifdef CONFIG_MLX5_MACSEC\n \tstruct mlx5_macsec_fs *macsec_fs;\n \t/* MACsec notifier chain to sync MACsec core and IB database */\ndiff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py\nindex 315648a770d00..9b899723a635a 100755\n--- a/tools/testing/selftests/drivers/net/psp.py\n+++ b/tools/testing/selftests/drivers/net/psp.py\n@@ -16,11 +16,12 @@ from lib.py import ksft_run, ksft_exit, ksft_pr\n from lib.py import ksft_true, ksft_eq, ksft_ne, ksft_gt, ksft_raises\n from lib.py import ksft_not_none\n from lib.py import ksft_variants, KsftNamedVariant\n-from lib.py import KsftSkipEx, KsftFailEx\n+from lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx\n from lib.py import NetDrvEpEnv, NetDrvContEnv\n-from lib.py import Netlink, NlError, PSPFamily, RtnlFamily\n+from lib.py import Netlink, NlError, NetdevFamily, PSPFamily, RtnlFamily\n from lib.py import NetNSEnter\n from lib.py import bkg, rand_port, wait_port_listen\n+from lib.py import bkg, ethtool, rand_port, wait_port_listen, CmdExitFailure\n from lib.py import ip\n \n \n@@ -30,15 +31,25 @@ def _get_outq(s):\n return struct.unpack(\"I\", outq)[0]\n \n \n+def _recv_exact(sock, n):\n+ buf = b''\n+ while len(buf) \u003c n:\n+ chunk = sock.recv(n - len(buf))\n+ if not chunk:\n+ break\n+ buf += chunk\n+ return buf\n+\n+\n def _send_with_ack(cfg, msg):\n- cfg.comm_sock.send(msg)\n- response = cfg.comm_sock.recv(4)\n+ cfg.comm_sock.sendall(msg)\n+ response = _recv_exact(cfg.comm_sock, 4)\n if response != b'ack\\0':\n raise RuntimeError(\"Unexpected server response\", response)\n \n \n def _remote_read_len(cfg):\n- cfg.comm_sock.send(b'read len\\0')\n+ cfg.comm_sock.sendall(b'read len\\0')\n return int(cfg.comm_sock.recv(1024)[:-1].decode('utf-8'))\n \n \n@@ -97,7 +108,7 @@ def _send_careful(cfg, s, rounds):\n def _check_data_rx(cfg, exp_len):\n read_len = -1\n for _ in range(30):\n- cfg.comm_sock.send(b'read len\\0')\n+ cfg.comm_sock.sendall(b'read len\\0')\n read_len = int(cfg.comm_sock.recv(1024)[:-1].decode('utf-8'))\n if read_len == exp_len:\n break\n@@ -583,6 +594,108 @@ def _get_psp_ver_ip_variants():\n for ipv in (\"4\", \"6\"):\n yield KsftNamedVariant(f\"v{ver}_ip{ipv}\", ver, ipv)\n \n+def _enable_local_hw_gro(cfg):\n+ cfg.require_cmd(\"ethtool\")\n+ feat = ethtool(f\"-k {cfg.ifname}\", json=True)[0]\n+ gro = feat.get(\"rx-gro-hw\")\n+ if not gro or \"active\" not in gro or \"fixed\" not in gro:\n+ raise KsftSkipEx(\"HW GRO feature not reported by ethtool\")\n+ if gro[\"fixed\"] and not gro[\"active\"]:\n+ raise KsftXfailEx(\"HW GRO not supported by device\")\n+ if not gro[\"active\"]:\n+ try:\n+ ethtool(f\"-K {cfg.ifname} rx-gro-hw on\")\n+ except CmdExitFailure as e:\n+ raise KsftSkipEx(\"Cannot enable HW GRO via ethtool\") from e\n+ defer(ethtool, f\"-K {cfg.ifname} rx-gro-hw off\")\n+ feat = ethtool(f\"-k {cfg.ifname}\", json=True)[0]\n+ gro = feat.get(\"rx-gro-hw\", {})\n+ if not gro.get(\"active\"):\n+ raise KsftSkipEx(\"HW GRO failed to activate\")\n+\n+\n+def _remote_send(cfg, size):\n+ cfg.comm_sock.sendall(b'data send\\0' + struct.pack('!I', size))\n+ response = _recv_exact(cfg.comm_sock, 4)\n+ if response != b'ack\\0':\n+ raise RuntimeError(\"Unexpected server response to data send\", response)\n+\n+\n+def _recv_all(s, expected, timeout=20):\n+ s.settimeout(timeout)\n+ total = 0\n+ try:\n+ while total \u003c expected:\n+ data = s.recv(min(65536, expected - total))\n+ if not data:\n+ break\n+ total += len(data)\n+ except socket.timeout:\n+ raise RuntimeError(\n+ f\"Timed out receiving data: got {total}/{expected} bytes \"\n+ f\"(responder may have failed to send)\")\n+ if total \u003c expected:\n+ raise RuntimeError(\n+ f\"Short read: got {total}/{expected} bytes \"\n+ f\"(responder connection closed early)\")\n+ return total\n+\n+\n+def _data_hw_gro(cfg, version, ipver):\n+ \"\"\" Test PSP data transfer with HW GRO enabled \"\"\"\n+ _init_psp_dev(cfg)\n+ # Version 0 is required by spec, don't let it skip\n+ if version:\n+ name = cfg.pspnl.consts[\"version\"].entries_by_val[version].name\n+ if name not in cfg.psp_info['psp-versions-cap']:\n+ raise KsftSkipEx(\"PSP version not supported\", name)\n+\n+ _enable_local_hw_gro(cfg)\n+\n+ s = _make_psp_conn(cfg, version, ipver)\n+ try:\n+ rx_assoc = cfg.pspnl.rx_assoc({\"version\": version,\n+ \"dev-id\": cfg.psp_dev_id,\n+ \"sock-fd\": s.fileno()})\n+ rx = rx_assoc['rx-key']\n+ tx = _spi_xchg(s, rx)\n+ cfg.pspnl.tx_assoc({\"dev-id\": cfg.psp_dev_id,\n+ \"version\": version,\n+ \"tx-key\": tx,\n+ \"sock-fd\": s.fileno()})\n+\n+ try:\n+ before = cfg.netnl.qstats_get({\"ifindex\": cfg.ifindex}, dump=True)[0]\n+ except NlError as e:\n+ if e.error == errno.EOPNOTSUPP:\n+ raise KsftSkipEx(\"qstats not supported by the device\") from e\n+ raise\n+ if ('rx-hw-gro-packets' not in before or\n+ 'rx-hw-gro-wire-packets' not in before):\n+ raise KsftSkipEx(\"rx-hw-gro-packets counter not available\")\n+\n+ # Remote sends data in 8KB chunks; GSO on remote TX segments them,\n+ # HW GRO reassembles on local RX\n+ data_len = 10 * 65536\n+ _remote_send(cfg, data_len)\n+ recv_len = _recv_all(s, data_len)\n+ ksft_eq(recv_len, data_len)\n+\n+ cfg.wait_hw_stats_settle()\n+ after = cfg.netnl.qstats_get({\"ifindex\": cfg.ifindex}, dump=True)[0]\n+ ksft_gt(after['rx-hw-gro-packets'],\n+ before['rx-hw-gro-packets'])\n+ ksft_gt(after['rx-hw-gro-wire-packets'],\n+ before['rx-hw-gro-wire-packets'])\n+ finally:\n+ _close_psp_conn(cfg, s)\n+\n+@ksft_variants(_get_psp_ver_ip_variants())\n+def data_hw_gro(cfg, version, ipver):\n+ \"\"\" Test PSP data transfer with HW GRO enabled \"\"\"\n+ cfg.require_ipver(ipver)\n+ _data_hw_gro(cfg, version, ipver)\n+\n \n def _get_ip_variants():\n for ipv in (\"4\", \"6\"):\n@@ -937,7 +1050,6 @@ def _setup_psp_attributes(cfg):\n cfg.psp_dev_peer_nsid = _get_nsid(cfg.netns.name)\n \n \n-\n def main() -\u003e None:\n \"\"\" Ksft boiler plate main \"\"\"\n \n@@ -954,6 +1066,7 @@ def main() -\u003e None:\n \n with env as cfg:\n cfg.pspnl = PSPFamily()\n+ cfg.netnl = NetdevFamily()\n \n if has_cont:\n _setup_psp_attributes(cfg)\n@@ -973,7 +1086,7 @@ def main() -\u003e None:\n cfg.comm_port),\n timeout=1)\n \n- cases = [data_basic_send, data_mss_adjust]\n+ cases = [data_basic_send, data_hw_gro, data_mss_adjust]\n \n if has_cont:\n cases += [\n@@ -990,7 +1103,7 @@ def main() -\u003e None:\n case_pfx={\"dev_\", \"data_\", \"assoc_\", \"removal_\"},\n args=(cfg, ))\n \n- cfg.comm_sock.send(b\"exit\\0\")\n+ cfg.comm_sock.sendall(b\"exit\\0\")\n cfg.comm_sock.close()\n finally:\n if srv and (srv.stdout or srv.stderr):\ndiff --git a/tools/testing/selftests/drivers/net/psp_responder.c b/tools/testing/selftests/drivers/net/psp_responder.c\nindex a26e7628bbb13..9a675bf449f5f 100644\n--- a/tools/testing/selftests/drivers/net/psp_responder.c\n+++ b/tools/testing/selftests/drivers/net/psp_responder.c\n@@ -1,5 +1,6 @@\n // SPDX-License-Identifier: GPL-2.0\n \n+#include \u003cerrno.h\u003e\n #include \u003cstdio.h\u003e\n #include \u003cstring.h\u003e\n #include \u003csys/poll.h\u003e\n@@ -118,6 +119,34 @@ static void send_str(int sock, int value)\n \tsend(sock, buf, ret + 1, MSG_WAITALL);\n }\n \n+static int send_data(int sock, size_t len)\n+{\n+\tchar sbuf[8192] = {0};\n+\tssize_t sent;\n+\n+\twhile (len \u003e 0) {\n+\t\tsize_t chunk = len;\n+\n+\t\tif (chunk \u003e sizeof(sbuf))\n+\t\t\tchunk = sizeof(sbuf);\n+\n+\t\tsent = send(sock, sbuf, chunk, MSG_NOSIGNAL);\n+\t\tif (sent \u003c 0) {\n+\t\t\tif (errno == EINTR)\n+\t\t\t\tcontinue;\n+\t\t\tfprintf(stderr, \"ERR: %s: %s\\n\", __func__,\n+\t\t\t\tstrerror(errno));\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (sent == 0) {\n+\t\t\tfprintf(stderr, \"ERR: %s: peer closed\\n\", __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tlen -= sent;\n+\t}\n+\treturn 0;\n+}\n+\n static void\n run_session(struct ynl_sock *ys, struct opts *opts,\n \t int server_sock, int comm_sock)\n@@ -185,22 +214,22 @@ run_session(struct ynl_sock *ys, struct opts *opts,\n \t\t\t}\n \n \t\t\toff += n;\n-\t\t\tn = off;\n \n #define __consume(sz)\t\t\t\t\t\t\\\n \t\t({\t\t\t\t\t\t\\\n-\t\t\tif (n == (sz)) {\t\t\t\\\n-\t\t\t\toff = 0;\t\t\t\\\n-\t\t\t} else {\t\t\t\t\\\n-\t\t\t\toff -= (sz);\t\t\t\\\n-\t\t\t\tmemmove(buf, \u0026buf[(sz)], off);\t\\\n-\t\t\t}\t\t\t\t\t\\\n+\t\t\toff -= (sz);\t\t\t\t\\\n+\t\t\tmemmove(buf, \u0026buf[(sz)], off);\t\t\\\n \t\t})\n \n-#define cmd(_name)\t\t\t\t\t\t\t\\\n+/* Only match once the command and its _extra_sz byte payload are both\n+ * buffered, otherwise a split read would consume the name and strand\n+ * the payload, desynchronizing the parser for good.\n+ */\n+#define cmd(_name, _extra_sz)\t\t\t\t\t\t\\\n \t\t({\t\t\t\t\t\t\t\\\n \t\t\tssize_t sz = sizeof(_name);\t\t\t\\\n-\t\t\tbool match = n \u003e= sz \u0026\u0026\t!memcmp(buf, _name, sz); \\\n+\t\t\tbool match = off \u003e= sz + (_extra_sz) \u0026\u0026\t\t\\\n+\t\t\t\t!memcmp(buf, _name, sz);\t\t\\\n \t\t\t\t\t\t\t\t\t\\\n \t\t\tif (match) {\t\t\t\t\t\\\n \t\t\t\tdbg(\"command: \" _name \"\\n\");\t\t\\\n@@ -213,10 +242,10 @@ run_session(struct ynl_sock *ys, struct opts *opts,\n \t\t\tdo {\n \t\t\t\tconsumed = false;\n \n-\t\t\t\tif (cmd(\"read len\"))\n+\t\t\t\tif (cmd(\"read len\", 0))\n \t\t\t\t\tsend_str(comm_sock, data_read);\n \n-\t\t\t\tif (cmd(\"data echo\")) {\n+\t\t\t\tif (cmd(\"data echo\", 0)) {\n \t\t\t\t\tif (data_sock \u003e= 0)\n \t\t\t\t\t\tsend(data_sock, \"echo\", 5,\n \t\t\t\t\t\t MSG_WAITALL);\n@@ -224,7 +253,27 @@ run_session(struct ynl_sock *ys, struct opts *opts,\n \t\t\t\t\t\tfprintf(stderr, \"WARN: echo but no data sock\\n\");\n \t\t\t\t\tsend_ack(comm_sock);\n \t\t\t\t}\n-\t\t\t\tif (cmd(\"data close\")) {\n+\t\t\t\tif (cmd(\"data send\", 4)) {\n+\t\t\t\t\t__u32 len;\n+\n+\t\t\t\t\tmemcpy(\u0026len, buf, sizeof(len));\n+\t\t\t\t\t__consume(sizeof(len));\n+\t\t\t\t\tlen = ntohl(len);\n+\n+\t\t\t\t\tif (data_sock \u003c 0) {\n+\t\t\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\t\t\"WARN: send but no data sock\\n\");\n+\t\t\t\t\t\tsend_err(comm_sock);\n+\t\t\t\t\t\tcontinue;\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tsend_ack(comm_sock);\n+\t\t\t\t\tif (send_data(data_sock, len))\n+\t\t\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\t\t\"WARN: send incomplete for %u bytes\\n\",\n+\t\t\t\t\t\t\tlen);\n+\t\t\t\t}\n+\t\t\t\tif (cmd(\"data close\", 0)) {\n \t\t\t\t\tif (data_sock \u003e= 0) {\n \t\t\t\t\t\tclose(data_sock);\n \t\t\t\t\t\tdata_sock = -1;\n@@ -233,26 +282,22 @@ run_session(struct ynl_sock *ys, struct opts *opts,\n \t\t\t\t\t\trace_close = true;\n \t\t\t\t\t}\n \t\t\t\t}\n-\t\t\t\tif (cmd(\"conn psp\")) {\n+\t\t\t\tif (cmd(\"conn psp\", 2)) {\n \t\t\t\t\tif (accept_cfg != ACCEPT_CFG_NONE)\n \t\t\t\t\t\tfprintf(stderr, \"WARN: old conn config still set!\\n\");\n \t\t\t\t\taccept_cfg = ACCEPT_CFG_PSP;\n \t\t\t\t\tsend_ack(comm_sock);\n \t\t\t\t\t/* next two bytes are versions */\n-\t\t\t\t\tif (off \u003e= 2) {\n-\t\t\t\t\t\tmemcpy(\u0026psp_vers, buf, 2);\n-\t\t\t\t\t\t__consume(2);\n-\t\t\t\t\t} else {\n-\t\t\t\t\t\tfprintf(stderr, \"WARN: short conn psp command!\\n\");\n-\t\t\t\t\t}\n+\t\t\t\t\tmemcpy(\u0026psp_vers, buf, 2);\n+\t\t\t\t\t__consume(2);\n \t\t\t\t}\n-\t\t\t\tif (cmd(\"conn clr\")) {\n+\t\t\t\tif (cmd(\"conn clr\", 0)) {\n \t\t\t\t\tif (accept_cfg != ACCEPT_CFG_NONE)\n \t\t\t\t\t\tfprintf(stderr, \"WARN: old conn config still set!\\n\");\n \t\t\t\t\taccept_cfg = ACCEPT_CFG_CLEAR;\n \t\t\t\t\tsend_ack(comm_sock);\n \t\t\t\t}\n-\t\t\t\tif (cmd(\"exit\"))\n+\t\t\t\tif (cmd(\"exit\", 0))\n \t\t\t\t\tshould_quit = true;\n #undef cmd\n \n"
} |
| 2/1 | 2026/08/04 09:34 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch exclusively modifies the Mellanox mlx5 driver (drivers/net/ethernet/mellanox/mlx5/*) to add PSP hardware GRO and decapsulation support, along with related flow tag and TC offload blocking changes. This is a vendor-specific SmartNIC driver that requires physical PCIe hardware not emulated in standard QEMU, so it cannot be meaningfully fuzzed in a virtualized environment.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit e44da41198827803cc60b3d0d6e5ca1c80ca4e99
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Aug 4 09:34:13 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
index 4973fb473ff02..a802f80d90bea 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/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
index 3f212e46fc2f9..a0bb19cc956df 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h
@@ -218,6 +218,28 @@ static inline void mlx5e_accel_tx_finish(struct mlx5e_txqsq *sq,
#endif
}
+static inline int mlx5e_accel_block_tc_offload(struct mlx5_core_dev *mdev)
+{
+ int ret = 0;
+
+ mutex_lock(&mdev->offload_block.lock);
+ if (mdev->offload_block.num_accel)
+ ret = -EBUSY;
+ else
+ mdev->offload_block.num_tc++;
+ mutex_unlock(&mdev->offload_block.lock);
+
+ return ret;
+}
+
+static inline void mlx5e_accel_unblock_tc_offload(struct mlx5_core_dev *mdev)
+{
+ mutex_lock(&mdev->offload_block.lock);
+ if (!WARN_ON_ONCE(!mdev->offload_block.num_tc))
+ mdev->offload_block.num_tc--;
+ mutex_unlock(&mdev->offload_block.lock);
+}
+
static inline int mlx5e_accel_init_rx(struct mlx5e_priv *priv)
{
return mlx5e_ktls_init_rx(priv);
@@ -229,6 +251,15 @@ static inline void mlx5e_accel_cleanup_rx(struct mlx5e_priv *priv)
mlx5_accel_psp_fs_cleanup_rx_tables(priv);
}
+static inline int mlx5e_accel_update_rx(struct mlx5e_priv *priv)
+{
+#ifdef CONFIG_MLX5_EN_PSP
+ return mlx5e_psp_update_rx(priv);
+#else
+ return 0;
+#endif
+}
+
static inline int mlx5e_accel_init_tx(struct mlx5e_priv *priv)
{
return mlx5e_ktls_init_tx(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h
new file mode 100644
index 0000000000000..d422f96ffced0
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5E_FLOW_TAG_H__
+#define __MLX5E_FLOW_TAG_H__
+
+#include <linux/bits.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mlx5/device.h>
+
+/* Unified accel flow_tag layout in CQE sop_drop_qpn [23:0]:
+ *
+ * [23:21] = protocol ID (3 bits):
+ * 0 = none (default)
+ * 1 = IPsec
+ * 2 = MACsec
+ * 3 = PSP (HW decrypted, PSP header present)
+ * 4 = PSP decap (HW decrypted & decapsulated)
+ * 5-7 = reserved
+ * [20:17] = PSP version (4 bits, valid when proto == PSP decap)
+ * 16 = reserved
+ * [15:0] = used by other subsystems (e.g. TC).
+ */
+#define MLX5E_ACCEL_FLOW_TAG_PROTO_MASK GENMASK(23, 21)
+#define MLX5E_ACCEL_FLOW_TAG_PROTO_NONE (0 << 21)
+#define MLX5E_ACCEL_FLOW_TAG_PROTO_IPSEC (1 << 21)
+#define MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC (2 << 21)
+#define MLX5E_ACCEL_FLOW_TAG_PROTO_PSP (3 << 21)
+#define MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP (4 << 21)
+
+#define MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT 17
+#define MLX5E_ACCEL_FLOW_TAG_PSP_VER_MASK (0xF << MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT)
+
+static inline u32 mlx5e_accel_flow_tag(struct mlx5_cqe64 *cqe)
+{
+ return be32_to_cpu(cqe->sop_drop_qpn) & 0xFFFFFF;
+}
+
+static inline u32 mlx5e_accel_flow_tag_proto(struct mlx5_cqe64 *cqe)
+{
+ return mlx5e_accel_flow_tag(cqe) & MLX5E_ACCEL_FLOW_TAG_PROTO_MASK;
+}
+
+#endif /* __MLX5E_FLOW_TAG_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
index 329608c59313b..081cb2f31be01 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c
@@ -4,6 +4,8 @@
#include <linux/netdevice.h>
#include "en.h"
#include "en/fs.h"
+#include "en_accel/en_accel.h"
+#include "en_accel/flow_tag.h"
#include "eswitch.h"
#include "ipsec.h"
#include "fs_core.h"
@@ -189,7 +191,7 @@ static void ipsec_rx_rule_add_match_obj(struct mlx5e_ipsec_sa_entry *sa_entry,
misc_parameters_2.metadata_reg_c_2);
MLX5_SET(fte_match_param, spec->match_value,
misc_parameters_2.metadata_reg_c_2,
- sa_entry->ipsec_obj_id | BIT(31));
+ sa_entry->ipsec_obj_id);
spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
}
@@ -2065,7 +2067,7 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
if (!attrs->drop) {
if (rx != ipsec->rx_esw)
err = setup_modify_header(ipsec, attrs->type,
- sa_entry->ipsec_obj_id | BIT(31),
+ sa_entry->ipsec_obj_id,
XFRM_DEV_OFFLOAD_IN, &flow_act);
else
err = mlx5_esw_ipsec_rx_setup_modify_header(sa_entry, &flow_act);
@@ -2098,6 +2100,10 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
else
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+ if (!attrs->drop && rx != ipsec->rx_esw) {
+ spec->flow_context.flags |= FLOW_CONTEXT_HAS_TAG;
+ spec->flow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_IPSEC;
+ }
dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[0].ft = rx->ft.status;
dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
@@ -2574,53 +2580,19 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)
}
}
-#ifdef CONFIG_MLX5_ESWITCH
-static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
-{
- struct mlx5_eswitch *esw = mdev->priv.eswitch;
- int err = 0;
-
- if (esw) {
- err = mlx5_esw_lock(esw);
- if (err)
- return err;
- }
-
- if (mdev->num_block_ipsec) {
- err = -EBUSY;
- goto unlock;
- }
-
- mdev->num_block_tc++;
-
-unlock:
- if (esw)
- mlx5_esw_unlock(esw);
-
- return err;
-}
-#else
-static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
-{
- if (mdev->num_block_ipsec)
- return -EBUSY;
-
- mdev->num_block_tc++;
- return 0;
-}
-#endif
-
-static void mlx5e_ipsec_unblock_tc_offload(struct mlx5_core_dev *mdev)
+static bool accel_ipsec_should_block_tc(struct mlx5e_ipsec_sa_entry *sa_entry)
{
- mdev->num_block_tc--;
+ return sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET ||
+ sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN;
}
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
{
+ bool block_tc = accel_ipsec_should_block_tc(sa_entry);
int err;
- if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET) {
- err = mlx5e_ipsec_block_tc_offload(sa_entry->ipsec->mdev);
+ if (block_tc) {
+ err = mlx5e_accel_block_tc_offload(sa_entry->ipsec->mdev);
if (err)
return err;
}
@@ -2636,8 +2608,8 @@ int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
return 0;
err_out:
- if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
- mlx5e_ipsec_unblock_tc_offload(sa_entry->ipsec->mdev);
+ if (block_tc)
+ mlx5e_accel_unblock_tc_offload(sa_entry->ipsec->mdev);
return err;
}
@@ -2651,8 +2623,8 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
if (ipsec_rule->pkt_reformat)
mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat);
- if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
- mlx5e_ipsec_unblock_tc_offload(mdev);
+ if (accel_ipsec_should_block_tc(sa_entry))
+ mlx5e_accel_unblock_tc_offload(mdev);
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) {
tx_ft_put(sa_entry->ipsec, sa_entry->attrs.type);
@@ -2686,7 +2658,7 @@ int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
{
int err;
- err = mlx5e_ipsec_block_tc_offload(pol_entry->ipsec->mdev);
+ err = mlx5e_accel_block_tc_offload(pol_entry->ipsec->mdev);
if (err)
return err;
@@ -2701,7 +2673,7 @@ int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
return 0;
err_out:
- mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
+ mlx5e_accel_unblock_tc_offload(pol_entry->ipsec->mdev);
return err;
}
@@ -2712,7 +2684,7 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
mlx5_del_flow_rules(ipsec_rule->rule);
- mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
+ mlx5e_accel_unblock_tc_offload(pol_entry->ipsec->mdev);
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) {
rx_ft_put_policy(pol_entry->ipsec,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
index 45b0d19e735cb..6dea5978a40e8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.h
@@ -38,10 +38,9 @@
#include <net/xfrm.h>
#include "en.h"
#include "en/txrx.h"
+#include "en_accel/flow_tag.h"
-/* Bit31: IPsec marker, Bit30: reserved, Bit29-24: IPsec syndrome, Bit23-0: IPsec obj id */
-#define MLX5_IPSEC_METADATA_MARKER(metadata) ((((metadata) >> 30) & 0x3) == 0x2)
-#define MLX5_IPSEC_METADATA_SYNDROM(metadata) (((metadata) >> 24) & GENMASK(5, 0))
+/* IPsec obj id in ft_metadata bits[23:0] */
#define MLX5_IPSEC_METADATA_HANDLE(metadata) ((metadata) & GENMASK(23, 0))
struct mlx5e_accel_tx_ipsec_state {
@@ -74,7 +73,9 @@ static inline unsigned int mlx5e_ipsec_tx_ids_len(struct mlx5e_accel_tx_ipsec_st
static inline bool mlx5_ipsec_is_rx_flow(struct mlx5_cqe64 *cqe)
{
- return MLX5_IPSEC_METADATA_MARKER(be32_to_cpu(cqe->ft_metadata));
+ u32 proto = mlx5e_accel_flow_tag_proto(cqe);
+
+ return proto == MLX5E_ACCEL_FLOW_TAG_PROTO_IPSEC;
}
static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
index daff53ba7d09f..aa7a28954861b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -10,6 +10,7 @@
#include "en.h"
#include "lib/aso.h"
#include "lib/crypto.h"
+#include "en_accel/en_accel.h"
#include "en_accel/macsec.h"
#define MLX5_MACSEC_EPN_SCOPE_MID 0x80000000L
@@ -324,6 +325,8 @@ static void mlx5e_macsec_cleanup_sa_fs(struct mlx5e_macsec *macsec,
mlx5_macsec_fs_del_rule(macsec->mdev->macsec_fs, sa->macsec_rule, action, netdev,
fs_id);
sa->macsec_rule = NULL;
+ if (!is_tx)
+ mlx5e_accel_unblock_tc_offload(macsec->mdev);
}
static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
@@ -343,6 +346,7 @@ static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,
const struct macsec_tx_sc *tx_sc = &ctx->secy->tx_sc;
struct mlx5_macsec_rule_attrs rule_attrs;
union mlx5_macsec_rule *macsec_rule;
+ int err = 0;
if (is_tx && tx_sc->encoding_sa != sa->assoc_num)
return 0;
@@ -353,13 +357,26 @@ static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,
rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
+ if (!is_tx) {
+ err = mlx5e_accel_block_tc_offload(priv->mdev);
+ if (err)
+ return err;
+ }
+
macsec_rule = mlx5_macsec_fs_add_rule(macsec_fs, ctx, &rule_attrs, fs_id);
- if (!macsec_rule)
- return -ENOMEM;
+ if (!macsec_rule) {
+ err = -ENOMEM;
+ goto out_unblock_tc;
+ }
sa->macsec_rule = macsec_rule;
return 0;
+
+out_unblock_tc:
+ if (!is_tx)
+ mlx5e_accel_unblock_tc_offload(priv->mdev);
+ return err;
}
static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
@@ -735,12 +752,12 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)
* a non-NULL md_dst with uninitialised contents.
*/
err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element,
- XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL);
+ XA_LIMIT(1, MLX5_MACSEC_RX_FS_ID_MAX), GFP_KERNEL);
if (err) {
if (err == -EBUSY)
netdev_err(ctx->netdev,
"MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n",
- MLX5_MACEC_RX_FS_ID_MAX);
+ MLX5_MACSEC_RX_FS_ID_MAX);
goto destroy_md_dst;
}
@@ -1137,7 +1154,12 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
struct mlx5e_macsec_sa *rx_sa;
struct list_head *list;
int i, err = 0;
+ bool block_tc;
+ /* Best-effort TC block across the operation, to prevent a mistimed TC
+ * filter add from preventing the 2nd loop from happening.
+ */
+ block_tc = mlx5e_accel_block_tc_offload(priv->mdev) == 0;
list = &macsec_device->macsec_rx_sc_list_head;
list_for_each_entry_safe(rx_sc, tmp, list, rx_sc_list_element) {
@@ -1168,6 +1190,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
memcpy(macsec_device->dev_addr, dev->dev_addr, dev->addr_len);
out:
+ if (block_tc)
+ mlx5e_accel_unblock_tc_offload(priv->mdev);
return err;
}
@@ -1700,7 +1724,7 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev,
if (!macsec)
return;
- fs_id = MLX5_MACSEC_RX_METADAT_HANDLE(macsec_meta_data);
+ fs_id = MLX5_MACSEC_RX_METADATA_HANDLE(macsec_meta_data);
rcu_read_lock();
sc_xarray_element = xa_load(&macsec->sc_xarray, fs_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
index 27df72e23106d..571624f2db151 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.h
@@ -9,6 +9,7 @@
#include <linux/mlx5/driver.h>
#include <net/macsec.h>
#include <net/dst_metadata.h>
+#include "en_accel/flow_tag.h"
#include "lib/macsec_fs.h"
struct mlx5e_priv;
@@ -31,7 +32,9 @@ static inline bool mlx5e_macsec_skb_is_offload(struct sk_buff *skb)
static inline bool mlx5e_macsec_is_rx_flow(struct mlx5_cqe64 *cqe)
{
- return MLX5_MACSEC_METADATA_MARKER(be32_to_cpu(cqe->ft_metadata));
+ u32 proto = mlx5e_accel_flow_tag_proto(cqe);
+
+ return proto == MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC;
}
void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
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 73b232379263a..ad8dbd8c2f279 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.c
@@ -6,7 +6,9 @@
#include "mlx5_core.h"
#include "psp.h"
#include "lib/crypto.h"
+#include "en_accel/en_accel.h"
#include "en_accel/psp.h"
+#include "en_accel/psp_rxtx.h"
#include "fs_core.h"
enum accel_fs_psp_type {
@@ -21,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;
@@ -41,7 +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 *rx_modify_hdr;
+ struct mlx5_modify_hdr *modify_hdr;
struct mlx5_flow_handle *rule;
};
@@ -52,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;
@@ -63,12 +81,23 @@ 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;
};
+static bool shampo_enabled(struct mlx5e_priv *priv)
+{
+ return priv->channels.params.packet_merge.type ==
+ MLX5E_PACKET_MERGE_SHAMPO;
+}
+
/* PSP RX flow steering */
static enum mlx5_traffic_types fs_psp2tt(enum accel_fs_psp_type i)
{
@@ -110,6 +139,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)
{
@@ -402,15 +440,161 @@ 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);
+}
+
+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 = MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP |
+ ((u32)version << MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT);
+
+ 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);
- if (decrypt->rx_modify_hdr) {
- mlx5_modify_header_dealloc(fs->mdev, decrypt->rx_modify_hdr);
- decrypt->rx_modify_hdr = NULL;
- }
+ 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);
@@ -431,11 +615,11 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
struct mlx5_flow_destination *default_dest)
{
u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
- struct mlx5_modify_hdr *modify_hdr = NULL;
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;
@@ -479,30 +663,36 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
}
decrypt->miss_rule = rule;
- /* Add PSP RX decrypt rule */
- setup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);
- flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;
- /* Set bit[31, 30] PSP marker */
-#define MLX5E_PSP_MARKER_BIT (BIT(30) | BIT(31))
- MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
- MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
- MLX5_SET(set_action_in, action, data, MLX5E_PSP_MARKER_BIT);
- MLX5_SET(set_action_in, action, offset, 0);
- MLX5_SET(set_action_in, action, length, 32);
-
- modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL, 1, action);
- if (IS_ERR(modify_hdr)) {
- err = PTR_ERR(modify_hdr);
- mlx5_core_err(mdev, "fail to alloc psp set modify_header_id err=%d\n", err);
- modify_hdr = NULL;
+ /* 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->rx_modify_hdr = modify_hdr;
+ decrypt->modify_hdr = modhdr;
- flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
- MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
- MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
- flow_act.modify_hdr = modify_hdr;
+ /* Add PSP RX decrypt rule */
+ setup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);
+
+ /* Set PSP marker via flow_tag */
+ spec->flow_context.flags = FLOW_CONTEXT_HAS_TAG;
+ spec->flow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_PSP;
+
+ flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;
+ 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);
@@ -523,9 +713,50 @@ accel_psp_fs_rx_decrypt_ft_create(struct mlx5e_psp_fs *fs,
return err;
}
+static int 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;
+
+ /* 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) {
+ mlx5_core_warn(fs->mdev,
+ "Failed to create PSP decapsulation rules (err %d), HW GRO for PSP unavailable",
+ err);
+ decap_enable = false;
+ }
+ }
+ if (decap_enable == fs->decap_enabled)
+ return 0;
+
+ /* 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_destroy_ft;
+
+ fs->decap_enabled = decap_enable;
+
+ return 0;
+
+out_destroy_ft:
+ if (decap_enable)
+ accel_psp_fs_rx_decap_ft_destroy(fs, &fs->decap);
+ return 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);
+ bool tc_blocked = fs->rx.ft;
int i;
/* disconnect */
@@ -534,19 +765,29 @@ 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);
}
static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,
+ bool decap_enable,
struct netlink_ext_ack *extack)
{
struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs->fs, false);
int i, err;
+ err = mlx5e_accel_block_tc_offload(fs->mdev);
+ if (err) {
+ NL_SET_ERR_MSG(extack, "TC offload active, cannot enable PSP");
+ return err;
+ }
+
err = accel_psp_fs_rx_ft_create(fs, &fs->rx);
if (err) {
NL_SET_ERR_MSG(extack, "Failed creating RX steering table");
- return err;
+ goto err_unblock_tc;
}
err = accel_psp_fs_rx_check_ft_create(fs, &fs->check);
@@ -573,6 +814,12 @@ static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,
mlx5_ttc_fwd_dest(ttc, fs_psp2tt(i), &dest);
}
+ err = accel_psp_fs_rx_reconfigure(fs, decap_enable);
+ if (err) {
+ NL_SET_ERR_MSG(extack, "Failed RX steering config for HW GRO");
+ goto err_decrypt_ft;
+ }
+
return 0;
err_decrypt_ft:
@@ -583,6 +830,8 @@ static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs,
accel_psp_fs_rx_check_ft_destroy(&fs->check);
err_ft:
accel_psp_fs_rx_ft_destroy(&fs->rx);
+err_unblock_tc:
+ mlx5e_accel_unblock_tc_offload(fs->mdev);
return err;
}
@@ -839,7 +1088,8 @@ static int accel_psp_fs_create(struct mlx5e_priv *priv,
{
int err;
- err = accel_psp_fs_rx_create(priv->psp->fs, extack);
+ err = accel_psp_fs_rx_create(priv->psp->fs, shampo_enabled(priv),
+ extack);
if (err)
return err;
@@ -1116,3 +1366,14 @@ void mlx5e_psp_cleanup(struct mlx5e_priv *priv)
priv->psp = NULL;
kfree(psp);
}
+
+int mlx5e_psp_update_rx(struct mlx5e_priv *priv)
+{
+ struct mlx5e_psp *psp = priv->psp;
+
+ netdev_assert_locked(priv->netdev);
+ if (!psp || !psp->fs->check.ft)
+ return 0;
+
+ return accel_psp_fs_rx_reconfigure(psp->fs, shampo_enabled(priv));
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h
index 3f441e7dd55ac..76f6c69de0e91 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp.h
@@ -49,6 +49,7 @@ int mlx5e_psp_register(struct mlx5e_priv *priv);
void mlx5e_psp_unregister(struct mlx5e_priv *priv);
int mlx5e_psp_init(struct mlx5e_priv *priv);
void mlx5e_psp_cleanup(struct mlx5e_priv *priv);
+int mlx5e_psp_update_rx(struct mlx5e_priv *priv);
#else
static inline void mlx5_accel_psp_fs_cleanup_rx_tables(struct mlx5e_priv *priv) { }
static inline void mlx5_accel_psp_fs_cleanup_tx_tables(struct mlx5e_priv *priv) { }
@@ -61,5 +62,6 @@ static inline int mlx5e_psp_register(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_psp_unregister(struct mlx5e_priv *priv) { }
static inline int mlx5e_psp_init(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_psp_cleanup(struct mlx5e_priv *priv) { }
+static inline int mlx5e_psp_update_rx(struct mlx5e_priv *priv) { return 0; }
#endif /* CONFIG_MLX5_EN_PSP */
#endif /* __MLX5E_ACCEL_PSP_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
index 348fd7a962615..2beffee14278d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c
@@ -118,10 +118,25 @@ bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *
{
struct mlx5e_priv *priv = netdev_priv(netdev);
u16 dev_id = priv->psp->psd->id;
- bool strip_icv = true;
- u8 generation = 0;
+ struct psp_skb_ext *pse;
+
+ if (mlx5e_psp_is_decap(cqe)) {
+ /* UDP + PSP headers and PSP trailer removed by HW.
+ * Construct the PSP extension from CQE metadata.
+ */
+ pse = skb_ext_add(skb, SKB_EXT_PSP);
+ if (unlikely(!pse))
+ goto drop;
+
+ pse->spi = mlx5e_psp_get_spi(cqe);
+ pse->version = mlx5e_psp_get_version(cqe);
+ pse->dev_id = dev_id;
+ pse->generation = 0;
+ skb->decrypted = 1;
+ return false;
+ }
- if (psp_dev_rcv(skb, dev_id, generation, strip_icv))
+ if (psp_dev_rcv(skb, dev_id, 0, true))
goto drop;
skb->decrypted = 1;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h
index 2b080c39cc37e..41b60259b3bc6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.h
@@ -9,10 +9,7 @@
#include <net/psp.h>
#include "en.h"
#include "en/txrx.h"
-
-/* Bit30: PSP marker, Bit22-0: PSP obj id */
-#define MLX5_PSP_METADATA_MARKER(metadata) ((((metadata) >> 30) & 0x3) == 0x3)
-#define MLX5_PSP_METADATA_HANDLE(metadata) ((metadata) & GENMASK(22, 0))
+#include "en_accel/flow_tag.h"
struct mlx5e_accel_tx_psp_state {
u32 tailen;
@@ -82,7 +79,29 @@ static inline unsigned int mlx5e_psp_tx_ids_len(struct mlx5e_accel_tx_psp_state
static inline bool mlx5e_psp_is_rx_flow(struct mlx5_cqe64 *cqe)
{
- return MLX5_PSP_METADATA_MARKER(be32_to_cpu(cqe->ft_metadata));
+ u32 proto = mlx5e_accel_flow_tag_proto(cqe);
+
+ return proto == MLX5E_ACCEL_FLOW_TAG_PROTO_PSP ||
+ proto == MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP;
+
+}
+
+static inline bool mlx5e_psp_is_decap(struct mlx5_cqe64 *cqe)
+{
+ u32 proto = mlx5e_accel_flow_tag_proto(cqe);
+
+ return proto == MLX5E_ACCEL_FLOW_TAG_PROTO_PSP_DECAP;
+}
+
+static inline u8 mlx5e_psp_get_version(struct mlx5_cqe64 *cqe)
+{
+ return (mlx5e_accel_flow_tag(cqe) & MLX5E_ACCEL_FLOW_TAG_PSP_VER_MASK) >>
+ MLX5E_ACCEL_FLOW_TAG_PSP_VER_SHIFT;
+}
+
+static inline __be32 mlx5e_psp_get_spi(struct mlx5_cqe64 *cqe)
+{
+ return cqe->ft_metadata;
}
bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
@@ -110,6 +129,21 @@ static inline bool mlx5e_psp_is_rx_flow(struct mlx5_cqe64 *cqe)
return false;
}
+static inline bool mlx5e_psp_is_decap(struct mlx5_cqe64 *cqe)
+{
+ return false;
+}
+
+static inline u8 mlx5e_psp_get_version(struct mlx5_cqe64 *cqe)
+{
+ return 0;
+}
+
+static inline __be32 mlx5e_psp_get_spi(struct mlx5_cqe64 *cqe)
+{
+ return 0;
+}
+
static inline bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb,
struct mlx5_cqe64 *cqe)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 3b9d42c7e9c28..3c6ef500d0fb3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -6286,7 +6286,13 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
static int mlx5e_update_nic_rx(struct mlx5e_priv *priv)
{
- return mlx5e_refresh_tirs(priv->mdev, false, false);
+ int err;
+
+ err = mlx5e_refresh_tirs(priv->mdev, false, false);
+ if (err)
+ return err;
+
+ return mlx5e_accel_update_rx(priv);
}
static const struct mlx5e_profile mlx5e_nic_profile = {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index fb7110b1b6834..c7eaab3f7967b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -2221,6 +2221,33 @@ static bool mlx5e_hw_gro_skb_has_enough_space(struct sk_buff *skb,
return page_size * nr_frags + data_bcnt <= GRO_LEGACY_MAX_SIZE;
}
+static bool mlx5e_hw_gro_psp_match(struct sk_buff *skb, struct mlx5_cqe64 *cqe)
+{
+#ifdef CONFIG_MLX5_EN_PSP
+ struct psp_skb_ext *pse = skb_ext_find(skb, SKB_EXT_PSP);
+ bool is_psp = mlx5e_psp_is_rx_flow(cqe);
+
+ if (likely(!is_psp && !pse))
+ return true;
+
+ /* No match on PSP status change (no crypto -> crypto or vice-versa). */
+ if (unlikely(is_psp != !!pse))
+ return false;
+
+ /* SPI and version are only available in CQE metadata for decap flows.
+ * Non-decap PSP cannot be matched here, force a flush.
+ */
+ if (unlikely(!mlx5e_psp_is_decap(cqe)))
+ return false;
+
+ /* No match on security parameters change. */
+ return pse->spi == mlx5e_psp_get_spi(cqe) &&
+ pse->version == mlx5e_psp_get_version(cqe);
+#else
+ return true;
+#endif
+}
+
static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
{
u16 data_bcnt = mpwrq_get_cqe_byte_cnt(cqe) - cqe->shampo.header_size;
@@ -2258,8 +2285,9 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
data_offset = wqe_offset & (page_size - 1);
page_idx = wqe_offset >> rq->mpwqe.page_shift;
if (*skb &&
- !(match && mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt,
- page_size))) {
+ !(match &&
+ mlx5e_hw_gro_skb_has_enough_space(*skb, data_bcnt, page_size) &&
+ mlx5e_hw_gro_psp_match(*skb, cqe))) {
match = false;
mlx5e_shampo_flush_skb(rq, cqe, match);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 1bc7b9019124a..70195fcddfc82 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -4811,14 +4811,14 @@ static bool is_flow_rule_duplicate_allowed(struct net_device *dev,
return netif_is_lag_port(dev) && rpriv && rpriv->rep->vport != MLX5_VPORT_UPLINK;
}
-/* As IPsec and TC order is not aligned between software and hardware-offload,
- * either IPsec offload or TC offload, not both, is allowed for a specific interface.
+/* TC offload and accel protocols can overwrite each other's flow_tag with
+ * steering rules and they cannot simultaneously operate on the same interface.
+ * Additionally, as IPsec and TC order is not aligned between software and
+ * hardware-offload, only one is allowed for a specific interface.
*/
-static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx5e_priv *priv)
+static bool is_tc_accel_check_needed(struct net_device *filter,
+ struct mlx5e_priv *priv)
{
- if (!IS_ENABLED(CONFIG_MLX5_EN_IPSEC))
- return false;
-
if (filter != priv->netdev)
return false;
@@ -4828,27 +4828,35 @@ static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx
return true;
}
-static int mlx5e_tc_block_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
+static int mlx5e_tc_block_accel_offload(struct net_device *filter,
+ struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
+ int ret = 0;
- if (!is_tc_ipsec_order_check_needed(filter, priv))
+ if (!is_tc_accel_check_needed(filter, priv))
return 0;
- if (mdev->num_block_tc)
- return -EBUSY;
-
- mdev->num_block_ipsec++;
+ mutex_lock(&mdev->offload_block.lock);
+ if (mdev->offload_block.num_tc)
+ ret = -EBUSY;
+ else
+ mdev->offload_block.num_accel++;
+ mutex_unlock(&mdev->offload_block.lock);
- return 0;
+ return ret;
}
-static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
+static void mlx5e_tc_unblock_accel_offload(struct net_device *filter,
+ struct mlx5e_priv *priv)
{
- if (!is_tc_ipsec_order_check_needed(filter, priv))
+ if (!is_tc_accel_check_needed(filter, priv))
return;
- priv->mdev->num_block_ipsec--;
+ mutex_lock(&priv->mdev->offload_block.lock);
+ if (!WARN_ON_ONCE(!priv->mdev->offload_block.num_accel))
+ priv->mdev->offload_block.num_accel--;
+ mutex_unlock(&priv->mdev->offload_block.lock);
}
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
@@ -4863,7 +4871,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (!mlx5_esw_hold(priv->mdev))
return -EBUSY;
- err = mlx5e_tc_block_ipsec_offload(dev, priv);
+ err = mlx5e_tc_block_accel_offload(dev, priv);
if (err)
goto esw_release;
@@ -4912,7 +4920,7 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
err_free:
mlx5e_flow_put(priv, flow);
out:
- mlx5e_tc_unblock_ipsec_offload(dev, priv);
+ mlx5e_tc_unblock_accel_offload(dev, priv);
mlx5_esw_put(priv->mdev);
esw_release:
mlx5_esw_release(priv->mdev);
@@ -4955,7 +4963,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
trace_mlx5e_delete_flower(f);
mlx5e_flow_put(priv, flow);
- mlx5e_tc_unblock_ipsec_offload(dev, priv);
+ mlx5e_tc_unblock_accel_offload(dev, priv);
mlx5_esw_put(priv->mdev);
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
index e1b8cb78369f1..53b6043e33d22 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
@@ -36,6 +36,7 @@
#include <net/pkt_cls.h>
#include "en.h"
#include "eswitch.h"
+#include "en_accel/flow_tag.h"
#include "en/tc_ct.h"
#include "en/tc_tun.h"
#include "en/tc/int_port.h"
@@ -370,11 +371,13 @@ struct mlx5e_tc_table *mlx5e_tc_table_alloc(void);
void mlx5e_tc_table_free(struct mlx5e_tc_table *tc);
static inline bool mlx5e_cqe_regb_chain(struct mlx5_cqe64 *cqe)
{
- u32 chain, reg_b;
+ u32 flow_tag, reg_b, chain;
+ flow_tag = mlx5e_accel_flow_tag_proto(cqe);
reg_b = be32_to_cpu(cqe->ft_metadata);
- if (reg_b >> (MLX5E_TC_TABLE_CHAIN_TAG_BITS + ESW_ZONE_ID_BITS))
+ if (flow_tag != MLX5E_ACCEL_FLOW_TAG_PROTO_NONE ||
+ (reg_b >> (MLX5E_TC_TABLE_CHAIN_TAG_BITS + ESW_ZONE_ID_BITS)))
return false;
chain = reg_b & MLX5E_TC_TABLE_CHAIN_TAG_MASK;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
index efc5167493c12..b8e9021027e96 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.c
@@ -8,6 +8,7 @@
#include <linux/mlx5/macsec.h>
#include "fs_core.h"
#include "lib/macsec_fs.h"
+#include "en_accel/flow_tag.h"
#include "mlx5_core.h"
/* MACsec TX flow steering */
@@ -45,9 +46,6 @@
#define MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI 0x8
#define MLX5_SECTAG_HEADER_SIZE_WITH_SCI (MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI + MACSEC_SCI_LEN)
-/* MACsec fs_id handling for steering */
-#define macsec_fs_set_rx_fs_id(fs_id) ((fs_id) | BIT(30))
-
struct mlx5_sectag_header {
__be16 ethertype;
u8 tci_an;
@@ -1757,11 +1755,10 @@ macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,
rx_tables = &rx_fs->tables;
ft_crypto = &rx_tables->ft_crypto;
- /* Set bit[31 - 30] macsec marker - 0x01 */
/* Set bit[15-0] fs id */
MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
- MLX5_SET(set_action_in, action, data, macsec_fs_set_rx_fs_id(fs_id));
+ MLX5_SET(set_action_in, action, data, fs_id);
MLX5_SET(set_action_in, action, offset, 0);
MLX5_SET(set_action_in, action, length, 32);
@@ -1778,6 +1775,9 @@ macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,
/* Rx crypto table with SCI rule */
macsec_fs_rx_setup_fte(spec, &flow_act, attrs, true);
+ spec->flow_context.flags |= FLOW_CONTEXT_HAS_TAG;
+ spec->flow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC;
+
flow_act.modify_hdr = modify_hdr;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
@@ -1803,6 +1803,9 @@ macsec_fs_rx_add_rule(struct mlx5_macsec_fs *macsec_fs,
macsec_fs_rx_setup_fte(spec, &flow_act, attrs, false);
+ spec->flow_context.flags |= FLOW_CONTEXT_HAS_TAG;
+ spec->flow_context.flow_tag = MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC;
+
flow_act.modify_hdr = modify_hdr;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
@@ -2160,8 +2163,8 @@ static int mlx5_macsec_fs_add_roce_rule_rx(struct mlx5_macsec_fs *macsec_fs, u32
spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_5);
- MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_5,
- macsec_fs_set_rx_fs_id(fs_id));
+ MLX5_SET(fte_match_param, spec->match_value,
+ misc_parameters_2.metadata_reg_c_5, fs_id);
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
new_rule = mlx5_add_flow_rules(rx_fs->roce.ft_macsec_op_check, spec, &flow_act,
NULL, 0);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h
index 15acaff436417..b8b8b412d5c3e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/macsec_fs.h
@@ -6,11 +6,10 @@
#ifdef CONFIG_MLX5_MACSEC
-/* Bit31 - 30: MACsec marker, Bit15-0: MACsec id */
-#define MLX5_MACEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */
-#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACEC_RX_FS_ID_MAX
-#define MLX5_MACSEC_METADATA_MARKER(metadata) ((((metadata) >> 30) & 0x3) == 0x1)
-#define MLX5_MACSEC_RX_METADAT_HANDLE(metadata) ((metadata) & MLX5_MACSEC_RX_FS_ID_MASK)
+/* MACsec fs_id in ft_metadata bits[15:0] */
+#define MLX5_MACSEC_RX_FS_ID_MAX USHRT_MAX /* Must be power of two */
+#define MLX5_MACSEC_RX_FS_ID_MASK MLX5_MACSEC_RX_FS_ID_MAX
+#define MLX5_MACSEC_RX_METADATA_HANDLE(metadata) ((metadata) & MLX5_MACSEC_RX_FS_ID_MASK)
/* MACsec TX flow steering */
#define MLX5_ETH_WQE_FT_META_MACSEC_MASK \
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 643b4aac20336..406c0f7e63d81 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -1810,6 +1810,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
lockdep_register_key(&dev->lock_key);
mutex_init(&dev->intf_state_mutex);
lockdep_set_class(&dev->intf_state_mutex, &dev->lock_key);
+ mutex_init(&dev->offload_block.lock);
mutex_init(&dev->mlx5e_res.uplink_netdev_lock);
mutex_init(&dev->wc_state_lock);
@@ -1898,6 +1899,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)
mutex_destroy(&priv->alloc_mutex);
mutex_destroy(&priv->bfregs.wc_head.lock);
mutex_destroy(&priv->bfregs.reg_head.lock);
+ mutex_destroy(&dev->offload_block.lock);
mutex_destroy(&dev->intf_state_mutex);
lockdep_unregister_key(&dev->lock_key);
return err;
@@ -1925,6 +1927,7 @@ void mlx5_mdev_uninit(struct mlx5_core_dev *dev)
mutex_destroy(&priv->bfregs.reg_head.lock);
mutex_destroy(&dev->wc_state_lock);
mutex_destroy(&dev->mlx5e_res.uplink_netdev_lock);
+ mutex_destroy(&dev->offload_block.lock);
mutex_destroy(&dev->intf_state_mutex);
lockdep_unregister_key(&dev->lock_key);
}
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index b1871c0821d0b..2d9bc752e431e 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -788,8 +788,11 @@ struct mlx5_core_dev {
u32 vsc_addr;
struct mlx5_hv_vhca *hv_vhca;
struct mlx5_hwmon *hwmon;
- u64 num_block_tc;
- u64 num_block_ipsec;
+ struct {
+ struct mutex lock;
+ u64 num_tc;
+ u64 num_accel;
+ } offload_block;
#ifdef CONFIG_MLX5_MACSEC
struct mlx5_macsec_fs *macsec_fs;
/* MACsec notifier chain to sync MACsec core and IB database */
diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py
index 315648a770d00..9b899723a635a 100755
--- a/tools/testing/selftests/drivers/net/psp.py
+++ b/tools/testing/selftests/drivers/net/psp.py
@@ -16,11 +16,12 @@ from lib.py import ksft_run, ksft_exit, ksft_pr
from lib.py import ksft_true, ksft_eq, ksft_ne, ksft_gt, ksft_raises
from lib.py import ksft_not_none
from lib.py import ksft_variants, KsftNamedVariant
-from lib.py import KsftSkipEx, KsftFailEx
+from lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
from lib.py import NetDrvEpEnv, NetDrvContEnv
-from lib.py import Netlink, NlError, PSPFamily, RtnlFamily
+from lib.py import Netlink, NlError, NetdevFamily, PSPFamily, RtnlFamily
from lib.py import NetNSEnter
from lib.py import bkg, rand_port, wait_port_listen
+from lib.py import bkg, ethtool, rand_port, wait_port_listen, CmdExitFailure
from lib.py import ip
@@ -30,15 +31,25 @@ def _get_outq(s):
return struct.unpack("I", outq)[0]
+def _recv_exact(sock, n):
+ buf = b''
+ while len(buf) < n:
+ chunk = sock.recv(n - len(buf))
+ if not chunk:
+ break
+ buf += chunk
+ return buf
+
+
def _send_with_ack(cfg, msg):
- cfg.comm_sock.send(msg)
- response = cfg.comm_sock.recv(4)
+ cfg.comm_sock.sendall(msg)
+ response = _recv_exact(cfg.comm_sock, 4)
if response != b'ack\0':
raise RuntimeError("Unexpected server response", response)
def _remote_read_len(cfg):
- cfg.comm_sock.send(b'read len\0')
+ cfg.comm_sock.sendall(b'read len\0')
return int(cfg.comm_sock.recv(1024)[:-1].decode('utf-8'))
@@ -97,7 +108,7 @@ def _send_careful(cfg, s, rounds):
def _check_data_rx(cfg, exp_len):
read_len = -1
for _ in range(30):
- cfg.comm_sock.send(b'read len\0')
+ cfg.comm_sock.sendall(b'read len\0')
read_len = int(cfg.comm_sock.recv(1024)[:-1].decode('utf-8'))
if read_len == exp_len:
break
@@ -583,6 +594,108 @@ def _get_psp_ver_ip_variants():
for ipv in ("4", "6"):
yield KsftNamedVariant(f"v{ver}_ip{ipv}", ver, ipv)
+def _enable_local_hw_gro(cfg):
+ cfg.require_cmd("ethtool")
+ feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+ gro = feat.get("rx-gro-hw")
+ if not gro or "active" not in gro or "fixed" not in gro:
+ raise KsftSkipEx("HW GRO feature not reported by ethtool")
+ if gro["fixed"] and not gro["active"]:
+ raise KsftXfailEx("HW GRO not supported by device")
+ if not gro["active"]:
+ try:
+ ethtool(f"-K {cfg.ifname} rx-gro-hw on")
+ except CmdExitFailure as e:
+ raise KsftSkipEx("Cannot enable HW GRO via ethtool") from e
+ defer(ethtool, f"-K {cfg.ifname} rx-gro-hw off")
+ feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+ gro = feat.get("rx-gro-hw", {})
+ if not gro.get("active"):
+ raise KsftSkipEx("HW GRO failed to activate")
+
+
+def _remote_send(cfg, size):
+ cfg.comm_sock.sendall(b'data send\0' + struct.pack('!I', size))
+ response = _recv_exact(cfg.comm_sock, 4)
+ if response != b'ack\0':
+ raise RuntimeError("Unexpected server response to data send", response)
+
+
+def _recv_all(s, expected, timeout=20):
+ s.settimeout(timeout)
+ total = 0
+ try:
+ while total < expected:
+ data = s.recv(min(65536, expected - total))
+ if not data:
+ break
+ total += len(data)
+ except socket.timeout:
+ raise RuntimeError(
+ f"Timed out receiving data: got {total}/{expected} bytes "
+ f"(responder may have failed to send)")
+ if total < expected:
+ raise RuntimeError(
+ f"Short read: got {total}/{expected} bytes "
+ f"(responder connection closed early)")
+ return total
+
+
+def _data_hw_gro(cfg, version, ipver):
+ """ Test PSP data transfer with HW GRO enabled """
+ _init_psp_dev(cfg)
+ # Version 0 is required by spec, don't let it skip
+ if version:
+ name = cfg.pspnl.consts["version"].entries_by_val[version].name
+ if name not in cfg.psp_info['psp-versions-cap']:
+ raise KsftSkipEx("PSP version not supported", name)
+
+ _enable_local_hw_gro(cfg)
+
+ s = _make_psp_conn(cfg, version, ipver)
+ try:
+ rx_assoc = cfg.pspnl.rx_assoc({"version": version,
+ "dev-id": cfg.psp_dev_id,
+ "sock-fd": s.fileno()})
+ rx = rx_assoc['rx-key']
+ tx = _spi_xchg(s, rx)
+ cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id,
+ "version": version,
+ "tx-key": tx,
+ "sock-fd": s.fileno()})
+
+ try:
+ before = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
+ except NlError as e:
+ if e.error == errno.EOPNOTSUPP:
+ raise KsftSkipEx("qstats not supported by the device") from e
+ raise
+ if ('rx-hw-gro-packets' not in before or
+ 'rx-hw-gro-wire-packets' not in before):
+ raise KsftSkipEx("rx-hw-gro-packets counter not available")
+
+ # Remote sends data in 8KB chunks; GSO on remote TX segments them,
+ # HW GRO reassembles on local RX
+ data_len = 10 * 65536
+ _remote_send(cfg, data_len)
+ recv_len = _recv_all(s, data_len)
+ ksft_eq(recv_len, data_len)
+
+ cfg.wait_hw_stats_settle()
+ after = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
+ ksft_gt(after['rx-hw-gro-packets'],
+ before['rx-hw-gro-packets'])
+ ksft_gt(after['rx-hw-gro-wire-packets'],
+ before['rx-hw-gro-wire-packets'])
+ finally:
+ _close_psp_conn(cfg, s)
+
+@ksft_variants(_get_psp_ver_ip_variants())
+def data_hw_gro(cfg, version, ipver):
+ """ Test PSP data transfer with HW GRO enabled """
+ cfg.require_ipver(ipver)
+ _data_hw_gro(cfg, version, ipver)
+
def _get_ip_variants():
for ipv in ("4", "6"):
@@ -937,7 +1050,6 @@ def _setup_psp_attributes(cfg):
cfg.psp_dev_peer_nsid = _get_nsid(cfg.netns.name)
-
def main() -> None:
""" Ksft boiler plate main """
@@ -954,6 +1066,7 @@ def main() -> None:
with env as cfg:
cfg.pspnl = PSPFamily()
+ cfg.netnl = NetdevFamily()
if has_cont:
_setup_psp_attributes(cfg)
@@ -973,7 +1086,7 @@ def main() -> None:
cfg.comm_port),
timeout=1)
- cases = [data_basic_send, data_mss_adjust]
+ cases = [data_basic_send, data_hw_gro, data_mss_adjust]
if has_cont:
cases += [
@@ -990,7 +1103,7 @@ def main() -> None:
case_pfx={"dev_", "data_", "assoc_", "removal_"},
args=(cfg, ))
- cfg.comm_sock.send(b"exit\0")
+ cfg.comm_sock.sendall(b"exit\0")
cfg.comm_sock.close()
finally:
if srv and (srv.stdout or srv.stderr):
diff --git a/tools/testing/selftests/drivers/net/psp_responder.c b/tools/testing/selftests/drivers/net/psp_responder.c
index a26e7628bbb13..9a675bf449f5f 100644
--- a/tools/testing/selftests/drivers/net/psp_responder.c
+++ b/tools/testing/selftests/drivers/net/psp_responder.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/poll.h>
@@ -118,6 +119,34 @@ static void send_str(int sock, int value)
send(sock, buf, ret + 1, MSG_WAITALL);
}
+static int send_data(int sock, size_t len)
+{
+ char sbuf[8192] = {0};
+ ssize_t sent;
+
+ while (len > 0) {
+ size_t chunk = len;
+
+ if (chunk > sizeof(sbuf))
+ chunk = sizeof(sbuf);
+
+ sent = send(sock, sbuf, chunk, MSG_NOSIGNAL);
+ if (sent < 0) {
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "ERR: %s: %s\n", __func__,
+ strerror(errno));
+ return -1;
+ }
+ if (sent == 0) {
+ fprintf(stderr, "ERR: %s: peer closed\n", __func__);
+ return -1;
+ }
+ len -= sent;
+ }
+ return 0;
+}
+
static void
run_session(struct ynl_sock *ys, struct opts *opts,
int server_sock, int comm_sock)
@@ -185,22 +214,22 @@ run_session(struct ynl_sock *ys, struct opts *opts,
}
off += n;
- n = off;
#define __consume(sz) \
({ \
- if (n == (sz)) { \
- off = 0; \
- } else { \
- off -= (sz); \
- memmove(buf, &buf[(sz)], off); \
- } \
+ off -= (sz); \
+ memmove(buf, &buf[(sz)], off); \
})
-#define cmd(_name) \
+/* Only match once the command and its _extra_sz byte payload are both
+ * buffered, otherwise a split read would consume the name and strand
+ * the payload, desynchronizing the parser for good.
+ */
+#define cmd(_name, _extra_sz) \
({ \
ssize_t sz = sizeof(_name); \
- bool match = n >= sz && !memcmp(buf, _name, sz); \
+ bool match = off >= sz + (_extra_sz) && \
+ !memcmp(buf, _name, sz); \
\
if (match) { \
dbg("command: " _name "\n"); \
@@ -213,10 +242,10 @@ run_session(struct ynl_sock *ys, struct opts *opts,
do {
consumed = false;
- if (cmd("read len"))
+ if (cmd("read len", 0))
send_str(comm_sock, data_read);
- if (cmd("data echo")) {
+ if (cmd("data echo", 0)) {
if (data_sock >= 0)
send(data_sock, "echo", 5,
MSG_WAITALL);
@@ -224,7 +253,27 @@ run_session(struct ynl_sock *ys, struct opts *opts,
fprintf(stderr, "WARN: echo but no data sock\n");
send_ack(comm_sock);
}
- if (cmd("data close")) {
+ if (cmd("data send", 4)) {
+ __u32 len;
+
+ memcpy(&len, buf, sizeof(len));
+ __consume(sizeof(len));
+ len = ntohl(len);
+
+ if (data_sock < 0) {
+ fprintf(stderr,
+ "WARN: send but no data sock\n");
+ send_err(comm_sock);
+ continue;
+ }
+
+ send_ack(comm_sock);
+ if (send_data(data_sock, len))
+ fprintf(stderr,
+ "WARN: send incomplete for %u bytes\n",
+ len);
+ }
+ if (cmd("data close", 0)) {
if (data_sock >= 0) {
close(data_sock);
data_sock = -1;
@@ -233,26 +282,22 @@ run_session(struct ynl_sock *ys, struct opts *opts,
race_close = true;
}
}
- if (cmd("conn psp")) {
+ if (cmd("conn psp", 2)) {
if (accept_cfg != ACCEPT_CFG_NONE)
fprintf(stderr, "WARN: old conn config still set!\n");
accept_cfg = ACCEPT_CFG_PSP;
send_ack(comm_sock);
/* next two bytes are versions */
- if (off >= 2) {
- memcpy(&psp_vers, buf, 2);
- __consume(2);
- } else {
- fprintf(stderr, "WARN: short conn psp command!\n");
- }
+ memcpy(&psp_vers, buf, 2);
+ __consume(2);
}
- if (cmd("conn clr")) {
+ if (cmd("conn clr", 0)) {
if (accept_cfg != ACCEPT_CFG_NONE)
fprintf(stderr, "WARN: old conn config still set!\n");
accept_cfg = ACCEPT_CFG_CLEAR;
send_ack(comm_sock);
}
- if (cmd("exit"))
+ if (cmd("exit", 0))
should_quit = true;
#undef cmd
|
| 3/2 | 2026/08/04 09:34 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27435 output: 119 thoughts: 1363 Thoughts: **WorthFuzzing=false: Mellanox mlx5 Driver - Not Fuzzable in Standard QEMU** Okay, so I've got this patch series modifying the Mellanox mlx5 driver to support PSP hardware GRO/decapsulation. It's adding new features, modifying existing functions related to TC offload, introducing a unified flow tag, and updating several files (`ipsec_fs.c`, `macsec.c`, `psp.c`, `en_rx.c`, `en_tc.c`) to accommodate these changes. There are also associated tests in `psp.py` and `psp_responder.c`. I'm seeing changes across a bunch of core Mellanox files. The code is focused in `drivers/net/ethernet/mellanox/mlx5/core/en_accel/`. This is a pretty clear indication it's related to the ConnectX-4/5/6/7 network cards, a high-end SmartNIC. Now, I need to figure out if this is worth fuzzing. The instructions say to return `WorthFuzzing=false` if the changes are in vendor-specific PCIe switch, SmartNIC, or GPU drivers that require physical hardware not emulated in standard QEMU. That's the key. Let me think⦠Is `mlx5` a vendor-specific SmartNIC driver? Yes, absolutely. It's *the* Mellanox ConnectX driver. And does QEMU emulate Mellanox ConnectX-4+ NICs? Nope. QEMU has some emulation, but it's not relevant here. So, no standard QEMU emulation exists for `mlx5`, period. I recall that Syzkaller usually doesn't fuzz hardware drivers unless there's software emulation or vDPA. This seems to be ethernet acceleration for IPsec/MACsec/PSP, which, as I see it, requires the physical NIC. Let's make sure, once again. Checking carefully, I don't see any QEMU emulation for `mlx5` in the standard QEMU. Given all of that, the answer is `WorthFuzzing=false`. The `mlx5` driver is a vendor-specific PCIe driver (a SmartNIC driver, specifically) that relies on physical Mellanox hardware which is not emulated in standard QEMU. And I've double-checked, the changes are all in `mlx5` and selftests that rely on that. I'm confident about that. I will call `set-results` with `WorthFuzzing=false`. |
| 4/2 | 2026/08/04 09:34 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch exclusively modifies the Mellanox mlx5 driver (drivers/net/ethernet/mellanox/mlx5/*) to add PSP hardware GRO and decapsulation support, along with related flow tag and TC offload blocking changes. This is a vendor-specific SmartNIC driver that requires physical PCIe hardware not emulated in standard QEMU, so it cannot be meaningfully fuzzed in a virtualized environment.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch exclusively modifies the Mellanox mlx5 driver (drivers/net/ethernet/mellanox/mlx5/*) to add PSP hardware GRO and decapsulation support, along with related flow tag and TC offload blocking changes. This is a vendor-specific SmartNIC driver that requires physical PCIe hardware not emulated in standard QEMU, so it cannot be meaningfully fuzzed in a virtualized environment.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|