On Tue, 2026-09-08 at 09:52 +0300, Tariq Toukan wrote:
> Hi,
>
> Ingress PSP packets cannot be merged by the HW-GRO HW state machine
> because they are not decapsulated and the current HW-GRO state
> machine
> does not understand PSP.
>
> This series by Cosmin decapsulates PSP packets in steering, which
> allows
> the now-decapsulated PSP packets (== TCP) to go through HW-GRO and be
> aggregated. The SPI and PSP version from the PSP header are handed
> off
> to the driver in the CQE metadata fields. They are used to terminate
> the
> HW GRO session on mismatch, and are required to construct the skb
> extension which is used higher up in the stack.
>
> Some preparatory work needed to happen to allow that:
> - All accel protocol markers were moved away from ft_metadata into
> flow_tag
> - Mutual exclusion between TC and accel protocols was added. Trying
> to
> configure both IPsec and TC at the same time for example is now
> detected at config time instead of doing weird things at runtime.
>
> kperf tests on a pair of CX7 NICs with 200Gbps link speed:
>
> Streams Gbps no HW-GRO Gbps HW-GRO Speedup
> ------- -------------- ----------- -------
> 1 28 58 2.07x
> 2 67 102 1.52x
> 4 136 180 1.32x
> 8 175 183 1.05x
>
> Regards,
> Tariq
>
> Some internal Sashiko findings, plus Cosmin's comments:
>
> > + cfg.wait_hw_stats_settle()
> > + after = cfg.netnl.qstats_get({"ifindex": cfg.ifindex},
> > dump=True)[0]
> Could this lead to flaky test failures on multiqueue NICs?
> By hardcoding the netlink dump array access to index [0], the test
> statically
> verifies statistics for the first queue only. Since the test sends
> traffic over
> an ephemeral random port, Receive Side Scaling (RSS) will hash this
> 4-tuple and
> could deliver the flow to any active RX queue. If the flow lands on a
> queue
> other than queue 0, will the test fail to observe the hardware GRO
> packet
> increments?
>
> [CR] The premise is wrong. [0] is not queue 0, it's the result for
> the
> requested dev.
>
> > @@ -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);
> Does removing the BIT(30) marker from the MACsec fs_id metadata cause
> a
> regression by exposing RoCE MACsec to an aliasing issue?
> By removing BIT(30) from the fs_id in this patch, the fs_id written
> to
> METADATA_REG_B becomes a small integer (e.g., 1, 2).
> Later in mlx5_macsec_fs_add_roce_rule_rx(), the hardware rule
> ft_macsec_op_check enforces MACsec on RoCE traffic by matching
> metadata_reg_c_5 exactly against this same fs_id value.
> Could any unencrypted packet that has its REG_B set to this small
> integer
> by another NIC feature (such as TC rules setting packet marks, or PSP
> IPsec
> decryption) falsely pass the MACsec check and bypass encryption
> enforcement?
>
> [CR] Preexisting, TC rules could set the fsid to the the previous
> value even before.
> 'PSP IPsec' decryption doesn't make sense.
>
> > @@ -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);
> Does removing the BIT(30) marker allow metadata collisions in the
> hardware
> RoCE datapath?
> If an administrator configures a benign TC rule that sets a mark
> equal to
> the MACsec fs_id (which is just a 16-bit integer), could an attacker
> send
> unauthenticated RoCE traffic that matches the TC mark, falsely
> setting the
> metadata and bypassing the MACsec hardware authentication checks?
>
> [CR] This series makes TC and MACsec mutually exclusive.
>
> > @@ -2160,8 +2167,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);
> By matching on the bare fs_id without the BIT(30) marker in
> metadata_reg_c_5, is this RoCE datapath rule now susceptible to the
> TC
> mark collision issue?
>
> [CR] See above.
>
> > @@ -1778,6 +1775,11 @@ 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 =
> > + FIELD_PREP(MLX5E_ACCEL_FLOW_TAG_PROTO_MASK,
> > + MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC);
> Can adding FLOW_CONTEXT_HAS_TAG to the shared MACsec crypto table
> corrupt
> RoCE Queue Pair Numbers (QPN)?
> This unconditionally adds a flow tag to the shared ft_crypto table,
> which
> processes both Ethernet and RoCE MACsec traffic. When
> FLOW_CONTEXT_HAS_TAG
> is set, the hardware writes the flow tag into the sop_drop_qpn field
> of
> the CQE.
> Will this cause the mlx5_ib driver to read the MACsec tag (value 2)
> instead
> of the actual destination QPN for RDMA traffic, breaking RoCE
> delivery?
>
> [CR] The flow_tag is only given for Eth CQEs. For RoCE/RDMA, that CQE
> field is the QPN, and therefore mlx5_ib is unaffected.
>
> > @@ -1803,6 +1805,11 @@ 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 =
> > + FIELD_PREP(MLX5E_ACCEL_FLOW_TAG_PROTO_MASK
> > ,
> > +
> > MLX5E_ACCEL_FLOW_TAG_PROTO_MACSEC);
> Is it safe to set the flow tag on the shared crypto table here as
> well?
> This risks corrupting the destination QPN for RoCE traffic as
> mentioned
> above.
>
> [CR] Same as above, QPN isn't corrupted, those CQEs don't carry
> flow_tag.
>
> > @@ -1717,7 +1717,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);
> This is a pre-existing issue, but can this xa_load() race with an
> immediate
> kfree() during deletion, causing a use-after-free?
> In the deletion path, mlx5e_macsec_del_rxsc() calls xa_erase() and
> then
> immediately frees the element without an RCU grace period:
> mlx5e_macsec_del_rxsc() {
> ...
> xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element-
> >fs_id);
> dst_release(&rx_sc->md_dst->dst);
> kfree(rx_sc->sc_xarray_element);
> ...
> }
> Since mlx5e_macsec_offload_handle_rx_skb() retrieves
> sc_xarray_element
> locklessly under rcu_read_lock() via xa_load(), would a concurrent
> deletion
> result in dereferencing freed memory?
>
> [CR] Preexisting.
>
> > +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++;
> This isn't a bug, but does the new naming here swap the semantics of
> the
> variables?
> In the original logic, num_block_tc counted the number of blockers on
> TC
> (which are IPsec/accel rules). By renaming it to num_tc,
> mlx5e_accel_block_tc_offload() now increments num_tc when an accel
> rule
> is added.
> Would it be clearer to keep "block" in the names, e.g., num_block_tc,
> so
> it doesn't look like num_tc is tracking the number of TC rules?
>
> [CR] Intentional, "offload_block.num_{tc, accel}" sounds better.
>
> > +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++;
> Are the semantic meanings of the num_tc and num_accel variables
> inverted?
> When an Accel rule is added here in mlx5e_accel_block_tc_offload(),
> it
> increments num_tc.
>
> [CR] Same thing, it's an intentional rename.
>
> > @@ -384,6 +429,215 @@ static void fill_transportlayer(void *buf,
> > int seq_offset, int ack_offset,
> [ ... ]
> > +static char psp_scratch[L2_HLEN_MAX + IP_MAXPACKET +
> > PSP_ENCAP_LEN];
> [ ... ]
> > +/* Encapsulates & encrypts @pkt with PSP transport mode into
> > psp_scratch.
> > + * Returns the scratch buffer and updates *@lenp.
> > + */
> > +static char *psp_encapsulate(const char *pkt, int *lenp)
> > +{
> [ ... ]
> > + memcpy(psp_scratch, pkt, len);
> > +
> > + if (proto == PF_INET) {
> > + struct iphdr *iph = (struct iphdr *)(psp_scratch +
> > ETH_HLEN);
> Does this code violate strict aliasing rules?
> Since psp_scratch is declared as a character array, casting it to an
> incompatible structure pointer like struct iphdr * (and later struct
> ipv6hdr *
> and struct udphdr *) violates C11 strict aliasing rules.
> Because the tools/ directory assumes standard -fstrict-aliasing
> optimizations
> are active, could this cause the compiler to incorrectly reorder or
> optimize
> away memory writes to these headers, potentially resulting in
> malformed
> packets and spurious test failures?
>
> [CR] Maybe, but there are already 20+ similar things in the file.
>
> V4:
> - Removed dead mlx5_esw_lock() (Daniel).
> - Rebased on top of f225a7317c18 ("selftests: drv-net: split gro.py
> into one test per coalescing mode") (Daniel).
> - Dropped the gro_lib.py extraction, made obsolete by above change.
> - Fixed some typos (Aleksandr).
> - Added CONFIG_INET_PSP=y to the test config (Daniel).
>
> V3:
> https://lore.kernel.org/netdev/[email protected]/
> - Cleared fs->decap_enabled on config down (Daniel).
> - Made decap support optional (don't fail device reconfig on errors).
> - Used bitfield ops for accel protos & psp ver (Daniel).
> - Renamed psp_responder off -> len (Jakub).
> - Dedicated HW GRO PSP test (Jakub).
> - Extended HW GRO test coverage (Jakub).
>
> V2:
> https://lore.kernel.org/netdev/[email protected]/
> - Use XFail in patch 13 (Jakub).
>
> V1:
> https://lore.kernel.org/all/[email protected]/
>
> Cosmin Ratiu (14):
> net/mlx5e: Generalize TC <-> IPsec mutual exclusion
> net/mlx5e: ipsec: Block TC offload when IPsec is enabled
> net/mlx5e: psp: Block TC offload when PSP is enabled
> net/mlx5e: macsec: Block TC offload when MACsec is enabled
> net/mlx5e: psp: Move RX marker from ft_metadata to flow_tag
> net/mlx5e: ipsec: Move RX marker from ft_metadata to flow_tag
> net/mlx5e: macsec: Move RX marker from ft_metadata to flow_tag
> net/mlx5e: psp: Handle HW-decapsulated RX PSP packets
> net/mlx5e: psp: Add an rx_decap steering table
> net/mlx5e: shampo: Flush session on PSP mismatch
> net/mlx5e: psp: Dynamically reconfigure based on SHAMPO mode
> selftests: drv-net: psp: Extract shared helpers into psp_lib.py
> selftests: net: gro: Add PSP encapsulation and encryption
> selftests: drv-net: Add PSP HW GRO conformance tests
>
> .../net/ethernet/mellanox/mlx5/core/en/fs.h | 1 +
> .../mellanox/mlx5/core/en_accel/en_accel.h | 27 ++
> .../mellanox/mlx5/core/en_accel/flow_tag.h | 49 +++
> .../mellanox/mlx5/core/en_accel/ipsec_fs.c | 72 ++--
> .../mellanox/mlx5/core/en_accel/ipsec_rxtx.h | 8 +-
> .../mellanox/mlx5/core/en_accel/macsec.c | 34 +-
> .../mellanox/mlx5/core/en_accel/macsec.h | 4 +-
> .../mellanox/mlx5/core/en_accel/psp.c | 316 ++++++++++++++--
> .../mellanox/mlx5/core/en_accel/psp.h | 2 +
> .../mellanox/mlx5/core/en_accel/psp_rxtx.c | 21 +-
> .../mellanox/mlx5/core/en_accel/psp_rxtx.h | 44 ++-
> .../net/ethernet/mellanox/mlx5/core/en_main.c | 10 +-
> .../net/ethernet/mellanox/mlx5/core/en_rx.c | 32 +-
> .../net/ethernet/mellanox/mlx5/core/en_tc.c | 46 ++-
> .../net/ethernet/mellanox/mlx5/core/en_tc.h | 7 +-
> .../net/ethernet/mellanox/mlx5/core/eswitch.c | 12 -
> .../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 -
> .../mellanox/mlx5/core/lib/macsec_fs.c | 21 +-
> .../mellanox/mlx5/core/lib/macsec_fs.h | 9 +-
> .../net/ethernet/mellanox/mlx5/core/main.c | 3 +
> include/linux/mlx5/driver.h | 7 +-
> tools/testing/selftests/drivers/net/Makefile | 1 +
> .../testing/selftests/drivers/net/gro_lib.py | 15 +-
> .../testing/selftests/drivers/net/hw/Makefile | 17 +
> tools/testing/selftests/drivers/net/hw/config | 1 +
> .../selftests/drivers/net/hw/psp_gro.py | 157 ++++++++
> tools/testing/selftests/drivers/net/psp.py | 77 ++--
> .../testing/selftests/drivers/net/psp_lib.py | 57 +++
> tools/testing/selftests/net/lib/Makefile | 16 +
> tools/testing/selftests/net/lib/gro.c | 337
> +++++++++++++++++-
> 30 files changed, 1198 insertions(+), 206 deletions(-)
> create mode 100644
> drivers/net/ethernet/mellanox/mlx5/core/en_accel/flow_tag.h
> create mode 100755 tools/testing/selftests/drivers/net/hw/psp_gro.py
> create mode 100644 tools/testing/selftests/drivers/net/psp_lib.py
>
>
> base-commit: bc6fe9d301d59fe5cb236d646abe792bffae5fa6
Replying here instead of the individual messages, to make it easier to
read.
I read and understood the various bits and feedback from Daniel and
from Sashiko.
Some useful findings, everything possible will be addressed in the next
version, and there will be a net series with fixes for the TC exclusion
and macsec issues raised by Sashiko. This will unfortunately add a week
or so at least of dependency.
Cosmin.