* [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs
@ 2026-09-17 17:54 Tariq Toukan
2026-09-17 17:54 ` [PATCH net 1/7] net/mlx5e: ipsec: Block eswitch mode changes during policy creation Tariq Toukan
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
Hi,
This series by Cosmin fixes several mlx5e offload issues:
- Block eswitch mode changes before accessing the IPsec context during
policy and SA creation.
- Tie TC eswitch and IPsec-blocking references to flow destruction,
covering bulk cleanup and flows with outstanding references.
- Track MACsec hardware-object ownership explicitly and delete remaining
SecYs during driver cleanup.
- Serialize TC/IPsec exclusion counters with a dedicated mutex.
- Prevent SHAMPO from merging PSP packets.
Regards,
Tariq
Cosmin Ratiu (7):
net/mlx5e: ipsec: Block eswitch mode changes during policy creation
net/mlx5e: ipsec: Block eswitch mode changes before accessing
priv->ipsec
net/mlx5e: tc: Tie esw & accel blocking refs to the flow's lifetime
net/mlx5e: macsec: Track hardware object ownership for SA teardown
net/mlx5e: macsec: Delete remaining SecYs during cleanup
net/mlx5e: Serialize TC and IPsec offload exclusion counters
net/mlx5e: shampo: Do not merge PSP packets
.../mellanox/mlx5/core/en_accel/ipsec.c | 55 +++++++++++-----
.../mellanox/mlx5/core/en_accel/ipsec_fs.c | 47 ++++---------
.../mellanox/mlx5/core/en_accel/macsec.c | 60 +++++++++++------
.../net/ethernet/mellanox/mlx5/core/en_rx.c | 15 ++++-
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 66 ++++++++++++-------
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 23 ++-----
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 11 ++--
.../mellanox/mlx5/core/eswitch_offloads.c | 7 +-
.../net/ethernet/mellanox/mlx5/core/main.c | 3 +
include/linux/mlx5/driver.h | 7 +-
10 files changed, 172 insertions(+), 122 deletions(-)
base-commit: c9151088f1674fd29ff26a20f5fc687acf53a2f0
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 1/7] net/mlx5e: ipsec: Block eswitch mode changes during policy creation
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
2026-09-17 17:54 ` [PATCH net 2/7] net/mlx5e: ipsec: Block eswitch mode changes before accessing priv->ipsec Tariq Toukan
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
Eswitch mode changes can tear down the IPsec context while policy
creation is accessing it. The mode-blocking reference acquired when
creating a flow table comes too late: the table lookup already accesses
the IPsec context before taking that reference.
Block mode changes before checking the IPsec context and validating the
policy. Release the temporary reference after successful setup, when the
flow table holds its own reference, or after unwinding on failure.
Unfortunately, simply using mlx5_eswitch_block_mode() for this would
introduce a regression where:
1. An offloaded inbound IPsec policy is added on the uplink.
2. A TC flower rule is added on a VF representor.
3. Another uplink IPsec policy using the same RX tables is added.
Before this change, the 3rd rule would reuse an existing RX/TX table
from 1 and would avoid an mlx5_eswitch_block_mode() check in
rx_get()/tx_get(). After this change, the temporary mode block added
would reject the 3rd rule because esw->user_count > 0.
To avoid that, I was forced to separate the mode blocking from the TC
check by introducing a check_users argument to
mlx5_eswitch_block_mode().
Fixes: a5b8ca9471d3 ("net/mlx5e: Add XFRM policy offload logic")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../mellanox/mlx5/core/en_accel/ipsec.c | 23 +++++++++++++++----
.../mellanox/mlx5/core/en_accel/ipsec_fs.c | 4 ++--
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 11 +++++----
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 10 +++++---
.../mellanox/mlx5/core/eswitch_offloads.c | 7 +++---
5 files changed, 36 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index db260e3d1412..841ecdc2c4d9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -806,7 +806,7 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
goto err_xfrm;
}
- err = mlx5_eswitch_block_mode(priv->mdev);
+ err = mlx5_eswitch_block_mode(priv->mdev, true);
if (err)
goto unblock_ipsec;
@@ -1266,18 +1266,28 @@ static int mlx5e_xfrm_add_policy(struct xfrm_policy *x,
int err;
priv = netdev_priv(netdev);
+ /* Block esw mode changes until the policy holds its own block. */
+ err = mlx5_eswitch_block_mode(priv->mdev, false);
+ if (err) {
+ NL_SET_ERR_MSG_MOD(extack, "Eswitch busy, can't add policy");
+ return err;
+ }
+
if (!priv->ipsec) {
NL_SET_ERR_MSG_MOD(extack, "Device doesn't support IPsec packet offload");
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto unblock_mode;
}
err = mlx5e_xfrm_validate_policy(priv->mdev, x, extack);
if (err)
- return err;
+ goto unblock_mode;
pol_entry = kzalloc_obj(*pol_entry);
- if (!pol_entry)
- return -ENOMEM;
+ if (!pol_entry) {
+ err = -ENOMEM;
+ goto unblock_mode;
+ }
pol_entry->x = x;
pol_entry->ipsec = priv->ipsec;
@@ -1293,6 +1303,7 @@ static int mlx5e_xfrm_add_policy(struct xfrm_policy *x,
goto err_fs;
x->xdo.offload_handle = (unsigned long)pol_entry;
+ mlx5_eswitch_unblock_mode(priv->mdev);
return 0;
err_fs:
@@ -1300,6 +1311,8 @@ static int mlx5e_xfrm_add_policy(struct xfrm_policy *x,
ipsec_busy:
kfree(pol_entry);
NL_SET_ERR_MSG_MOD(extack, "Device failed to offload this policy");
+unblock_mode:
+ mlx5_eswitch_unblock_mode(priv->mdev);
return err;
}
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 329608c59313..5c72656c623f 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
@@ -1127,7 +1127,7 @@ static int rx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (rx->ft.refcnt)
goto skip;
- err = mlx5_eswitch_block_mode(mdev);
+ err = mlx5_eswitch_block_mode(mdev, true);
if (err)
return err;
@@ -1416,7 +1416,7 @@ static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (tx->ft.refcnt)
goto skip;
- err = mlx5_eswitch_block_mode(mdev);
+ err = mlx5_eswitch_block_mode(mdev, true);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index fc197d1dc9df..0b48cc7a6734 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -3005,21 +3005,22 @@ void mlx5_esw_put(struct mlx5_core_dev *mdev)
/**
* mlx5_esw_try_lock() - Take a write lock on esw mode lock.
* @esw: eswitch device.
+ * @check_users: reject the lock if eswitch users exist.
*
* Should be called by esw mode change routine.
*
* Return:
- * * 0 - esw mode if successfully locked and refcount is 0.
- * * -EBUSY - refcount is not 0.
- * * -EINVAL - In the middle of switching mode or lock is already held.
+ * * >= 0 - esw mode if successfully locked.
+ * * -EBUSY - mode change in progress or users exist with check_users set.
+ * * -EINVAL - lock is already held.
*/
-int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
+int mlx5_esw_try_lock(struct mlx5_eswitch *esw, bool check_users)
{
if (down_write_trylock(&esw->mode_lock) == 0)
return -EINVAL;
if (esw->eswitch_operation_in_progress ||
- atomic64_read(&esw->user_count) > 0) {
+ (check_users && atomic64_read(&esw->user_count) > 0)) {
up_write(&esw->mode_lock);
return -EBUSY;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 8b1f93b13ea9..4a9a1656f6db 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -946,7 +946,7 @@ bool mlx5_esw_hold(struct mlx5_core_dev *dev);
void mlx5_esw_release(struct mlx5_core_dev *dev);
void mlx5_esw_get(struct mlx5_core_dev *dev);
void mlx5_esw_put(struct mlx5_core_dev *dev);
-int mlx5_esw_try_lock(struct mlx5_eswitch *esw);
+int mlx5_esw_try_lock(struct mlx5_eswitch *esw, bool check_users);
int mlx5_esw_lock(struct mlx5_eswitch *esw);
void mlx5_esw_unlock(struct mlx5_eswitch *esw);
@@ -970,7 +970,7 @@ bool mlx5_eswitch_is_peer(struct mlx5_eswitch *esw,
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev, bool from_fdb);
void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev);
-int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev);
+int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev, bool check_users);
void mlx5_eswitch_unblock_mode(struct mlx5_core_dev *dev);
static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
@@ -1081,7 +1081,11 @@ static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
{
}
-static inline int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev) { return 0; }
+static inline int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev,
+ bool check_users)
+{
+ return 0;
+}
static inline void mlx5_eswitch_unblock_mode(struct mlx5_core_dev *dev) {}
static inline bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index eb74b6260168..996490e11625 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -4343,7 +4343,7 @@ static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
return 0;
}
-int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev)
+int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev, bool check_users)
{
struct mlx5_eswitch *esw = dev->priv.eswitch;
int err;
@@ -4351,8 +4351,7 @@ int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev)
if (!mlx5_esw_allowed(esw))
return 0;
- /* Take TC into account */
- err = mlx5_esw_try_lock(esw);
+ err = mlx5_esw_try_lock(esw, check_users);
if (err < 0)
return err;
@@ -4485,7 +4484,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
return 0;
mlx5_lag_disable_change(esw->dev);
- err = mlx5_esw_try_lock(esw);
+ err = mlx5_esw_try_lock(esw, true);
if (err < 0) {
NL_SET_ERR_MSG_MOD(extack, "Can't change mode, E-Switch is busy");
goto enable_lag;
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 2/7] net/mlx5e: ipsec: Block eswitch mode changes before accessing priv->ipsec
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
2026-09-17 17:54 ` [PATCH net 1/7] net/mlx5e: ipsec: Block eswitch mode changes during policy creation Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
2026-09-17 17:54 ` [PATCH net 3/7] net/mlx5e: tc: Tie esw & accel blocking refs to the flow's lifetime Tariq Toukan
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
mlx5e_xfrm_add_state() reads priv->ipsec and validates mode-dependent
capabilities before blocking eswitch mode changes. A concurrent profile
change can free the saved IPsec context and cause use-after-free.
Move the mode block before the first context access and release it on
all error paths. Keep the atomic acquire-placeholder path exempt, since
it creates no hardware state and cannot take sleeping locks.
Fixes: 22239eb258bc ("net/mlx5e: Prevent tunnel reformat when tunnel mode not allowed")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../mellanox/mlx5/core/en_accel/ipsec.c | 34 ++++++++++++-------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 841ecdc2c4d9..1488faece80e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -771,6 +771,7 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
+ bool is_acq = x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ;
struct mlx5e_ipsec_sa_entry *sa_entry = NULL;
bool allow_tunnel_mode = false;
struct mlx5e_ipsec *ipsec;
@@ -779,20 +780,30 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
int err;
priv = netdev_priv(dev);
- if (!priv->ipsec)
- return -EOPNOTSUPP;
+ if (!is_acq) {
+ err = mlx5_eswitch_block_mode(priv->mdev, true);
+ if (err)
+ return err;
+ }
ipsec = priv->ipsec;
- gfp = (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ) ? GFP_ATOMIC : GFP_KERNEL;
+ if (!ipsec) {
+ err = -EOPNOTSUPP;
+ goto unblock_mode;
+ }
+
+ gfp = is_acq ? GFP_ATOMIC : GFP_KERNEL;
sa_entry = kzalloc_obj(*sa_entry, gfp);
- if (!sa_entry)
- return -ENOMEM;
+ if (!sa_entry) {
+ err = -ENOMEM;
+ goto unblock_mode;
+ }
sa_entry->x = x;
sa_entry->dev = dev;
sa_entry->ipsec = ipsec;
/* Check if this SA is originated from acquire flow temporary SA */
- if (x->xso.flags & XFRM_DEV_OFFLOAD_FLAG_ACQ) {
+ if (is_acq) {
x->xso.offload_handle = (unsigned long)sa_entry;
return 0;
}
@@ -806,10 +817,6 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
goto err_xfrm;
}
- err = mlx5_eswitch_block_mode(priv->mdev, true);
- if (err)
- goto unblock_ipsec;
-
if (x->props.mode == XFRM_MODE_TUNNEL &&
x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
allow_tunnel_mode = mlx5e_ipsec_fs_tunnel_allowed(sa_entry);
@@ -817,7 +824,7 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
NL_SET_ERR_MSG_MOD(extack,
"Packet offload tunnel mode is disabled due to encap settings");
err = -EINVAL;
- goto unblock_mode;
+ goto unblock_ipsec;
}
}
@@ -893,12 +900,13 @@ static int mlx5e_xfrm_add_state(struct net_device *dev,
unblock_encap:
if (allow_tunnel_mode)
mlx5_eswitch_unblock_encap(priv->mdev);
-unblock_mode:
- mlx5_eswitch_unblock_mode(priv->mdev);
unblock_ipsec:
mlx5_eswitch_unblock_ipsec(priv->mdev);
err_xfrm:
kfree(sa_entry);
+unblock_mode:
+ if (!is_acq)
+ mlx5_eswitch_unblock_mode(priv->mdev);
NL_SET_ERR_MSG_WEAK_MOD(extack, "Device failed to offload this state");
return err;
}
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 3/7] net/mlx5e: tc: Tie esw & accel blocking refs to the flow's lifetime
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
2026-09-17 17:54 ` [PATCH net 1/7] net/mlx5e: ipsec: Block eswitch mode changes during policy creation Tariq Toukan
2026-09-17 17:54 ` [PATCH net 2/7] net/mlx5e: ipsec: Block eswitch mode changes before accessing priv->ipsec Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
2026-09-17 17:54 ` [PATCH net 4/7] net/mlx5e: macsec: Track hardware object ownership for SA teardown Tariq Toukan
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
TC flow creation acquires an esw user ref and, where required, an
IPsec-blocking reference. mlx5e_delete_flower() releases these, but
bulk cleanup (mlx5e_tc_nic_cleanup -> _mlx5e_tc_del_flow) destroys the
remaining flows without releasing either.
When bulk cleanup runs during suspend, the core device survives with
stale counters, which can prevent subsequent eswitch mode changes and
IPsec offload.
For the same reason, two more bugs are that the refs are dropped in
mlx5e_delete_flower(), before the flow is actually freed, leaving a
window of time where:
- a racing esw mode change could pull the rug from underneath the
existing flow, leading to use after free.
- new IPsec objects might be installed, violating the restriction of
mutual exclusion between TC and IPsec.
To fix these issues, this patch moves the reference acquisitions in
mlx5e_alloc_flow(), before the HW objects are actually allocated, and
moves the reference dropping to mlx5e_tc_del_flow(), after the HW
objects are deallocated.
Fixes: 7dc84de98bab ("net/mlx5: E-Switch, Protect changing mode while adding rules")
Fixes: c8e350e62fc5 ("net/mlx5e: Make TC and IPsec offloads mutually exclusive on a netdev")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 48 ++++++++++++-------
1 file changed, 30 insertions(+), 18 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index b290beb4369a..44fc421e7b8c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -603,6 +603,10 @@ struct mlx5e_hairpin_entry {
static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow);
+static int mlx5e_tc_block_ipsec_offload(struct net_device *filter,
+ struct mlx5e_priv *priv);
+static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter,
+ struct mlx5e_priv *priv);
struct mlx5e_tc_flow *mlx5e_flow_get(struct mlx5e_tc_flow *flow)
{
@@ -2158,13 +2162,16 @@ static void mlx5e_tc_del_fdb_peers_flow(struct mlx5e_tc_flow *flow)
static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow)
{
+ struct net_device *filter_dev = flow->attr->parse_attr->filter_dev;
+ bool peer = flow_flag_test(flow, PEER);
+
if (mlx5e_is_eswitch_flow(flow)) {
struct mlx5_devcom_comp_dev *devcom = flow->priv->mdev->priv.eswitch->devcom;
- if (flow_flag_test(flow, PEER) ||
+ if (peer ||
!mlx5_devcom_for_each_peer_begin(devcom)) {
mlx5e_tc_del_fdb_flow(priv, flow);
- return;
+ goto out;
}
mlx5e_tc_del_fdb_peers_flow(flow);
@@ -2173,6 +2180,11 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
} else {
mlx5e_tc_del_nic_flow(priv, flow);
}
+out:
+ if (!peer) {
+ mlx5e_tc_unblock_ipsec_offload(filter_dev, flow->priv);
+ mlx5_esw_put(flow->priv->mdev);
+ }
}
static bool flow_requires_tunnel_mapping(u32 chain, struct flow_cls_offload *f)
@@ -4463,6 +4475,7 @@ mlx5_free_flow_attr_actions(struct mlx5e_tc_flow *flow, struct mlx5_flow_attr *a
static int
mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
struct flow_cls_offload *f, unsigned long flow_flags,
+ struct net_device *filter_dev,
struct mlx5e_tc_flow_parse_attr **__parse_attr,
struct mlx5e_tc_flow **__flow)
{
@@ -4497,11 +4510,23 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size,
init_completion(&flow->init_done);
init_completion(&flow->del_hw_done);
+ parse_attr->filter_dev = filter_dev;
+ attr->parse_attr = parse_attr;
+ /* Non-peer flows own the reservations until final destruction. */
+ if (!flow_flag_test(flow, PEER)) {
+ err = mlx5e_tc_block_ipsec_offload(filter_dev, priv);
+ if (err)
+ goto err_free_attr;
+ mlx5_esw_get(priv->mdev);
+ }
+
*__flow = flow;
*__parse_attr = parse_attr;
return 0;
+err_free_attr:
+ kfree(attr);
err_free:
kfree(flow);
kvfree(parse_attr);
@@ -4558,11 +4583,10 @@ __mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_ESWITCH);
attr_size = sizeof(struct mlx5_esw_flow_attr);
err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
- &parse_attr, &flow);
+ filter_dev, &parse_attr, &flow);
if (err)
goto out;
- parse_attr->filter_dev = filter_dev;
mlx5e_flow_esw_attr_init(flow->attr,
priv, parse_attr,
f, in_rep, in_mdev);
@@ -4712,7 +4736,7 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv,
mlx5e_tc_del_fdb_peers_flow(flow);
mlx5_devcom_for_each_peer_end(devcom);
clean_flow:
- mlx5e_tc_del_fdb_flow(priv, flow);
+ mlx5e_flow_put(priv, flow);
return err;
}
@@ -4739,11 +4763,10 @@ mlx5e_add_nic_flow(struct mlx5e_priv *priv,
flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_NIC);
attr_size = sizeof(struct mlx5_nic_flow_attr);
err = mlx5e_alloc_flow(priv, attr_size, f, flow_flags,
- &parse_attr, &flow);
+ filter_dev, &parse_attr, &flow);
if (err)
goto out;
- parse_attr->filter_dev = filter_dev;
mlx5e_flow_attr_init(flow->attr, parse_attr, f);
err = parse_cls_flower(flow->priv, flow, &parse_attr->spec,
@@ -4865,12 +4888,6 @@ 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);
- if (err)
- goto esw_release;
-
- mlx5_esw_get(priv->mdev);
-
rcu_read_lock();
flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params);
if (flow) {
@@ -4914,9 +4931,6 @@ 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);
- mlx5_esw_put(priv->mdev);
-esw_release:
mlx5_esw_release(priv->mdev);
return err;
}
@@ -4957,8 +4971,6 @@ 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);
- mlx5_esw_put(priv->mdev);
return 0;
errout:
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 4/7] net/mlx5e: macsec: Track hardware object ownership for SA teardown
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
` (2 preceding siblings ...)
2026-09-17 17:54 ` [PATCH net 3/7] net/mlx5e: tc: Tie esw & accel blocking refs to the flow's lifetime Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
2026-09-17 17:54 ` [PATCH net 5/7] net/mlx5e: macsec: Delete remaining SecYs during cleanup Tariq Toukan
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
A driver MACsec SA can exist without a hardware MACsec object. Adding
an inactive RX SA or a TX SA while the SecY is non-operational creates
the encryption key but skips MACsec object creation. RX SA deactivation
also destroys the hardware object while retaining the driver SA and
its object ID.
TX SA deletion and the SA teardown performed by RX SC and SecY deletion
unconditionally destroy the hardware object. This can issue a destroy
command with an unallocated zero ID or an ID that has already been
destroyed and potentially reused. Failed RX SA activation can leave
the same stale-ID state after steering creation unwinds.
Track hardware object creation separately from SA activity. Set the
ownership flag after successful creation, clear it on destruction and
creation unwind, and check it before destroying the object during SA
cleanup. This preserves destruction of objects retained by inactive
TX SAs while avoiding destruction of unowned objects.
Fixes: 8ff0ac5be144 ("net/mlx5: Add MACsec offload Tx command support")
Fixes: aae3454e4d4c ("net/mlx5e: Add MACsec offload Rx command support")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
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 daff53ba7d09..20eec345b36c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -58,6 +58,7 @@ struct mlx5e_macsec_async_work {
struct mlx5e_macsec_sa {
bool active;
+ bool macsec_obj_created;
u8 assoc_num;
u32 macsec_obj_id;
u32 enc_key_id;
@@ -331,7 +332,10 @@ static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
struct net_device *netdev, u32 fs_id)
{
mlx5e_macsec_cleanup_sa_fs(macsec, sa, is_tx, netdev, fs_id);
- mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
+ if (sa->macsec_obj_created) {
+ mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
+ sa->macsec_obj_created = false;
+ }
}
static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,
@@ -396,6 +400,7 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
if (err)
goto destroy_macsec_object;
}
+ sa->macsec_obj_created = true;
return 0;
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 5/7] net/mlx5e: macsec: Delete remaining SecYs during cleanup
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
` (3 preceding siblings ...)
2026-09-17 17:54 ` [PATCH net 4/7] net/mlx5e: macsec: Track hardware object ownership for SA teardown Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
2026-09-17 17:54 ` [PATCH net 6/7] net/mlx5e: Serialize TC and IPsec offload exclusion counters Tariq Toukan
2026-09-17 17:54 ` [PATCH net 7/7] net/mlx5e: shampo: Do not merge PSP packets Tariq Toukan
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
Suspend invokes MACsec cleanup without unregistering the netdev, so
offloaded SecYs may still exist. Cleanup frees their owning context
without deleting them, leaking driver state, encryption keys, MACsec
objects and steering resources.
This change deletes all remaining SecYs, which releases all HW objects
and avoids leaks.
But this only fixes resource teardown. On resume, the macsec driver may
still potentially have a lot of state it considers offloaded, but the
resumed device will have a clean slate. Fixing that is outside the scope
of this patch.
Fixes: 3fd3fb6b6b88 ("net/mlx5e: Move MACsec initialization from profile init stage to profile enable stage")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../mellanox/mlx5/core/en_accel/macsec.c | 53 ++++++++++++-------
1 file changed, 35 insertions(+), 18 deletions(-)
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 20eec345b36c..84ce388d3846 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -1238,33 +1238,21 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
return err;
}
-static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
+static void macsec_del_secy(struct mlx5e_macsec *macsec,
+ struct mlx5e_macsec_device *macsec_device)
{
- struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
- struct mlx5e_macsec_device *macsec_device;
+ struct net_device *netdev = (struct net_device *)macsec_device->netdev;
struct mlx5e_macsec_rx_sc *rx_sc, *tmp;
struct mlx5e_macsec_sa *tx_sa;
- struct mlx5e_macsec *macsec;
struct list_head *list;
- int err = 0;
int i;
- mutex_lock(&priv->macsec->lock);
- macsec = priv->macsec;
- macsec_device = mlx5e_macsec_get_macsec_device_context(macsec, ctx);
- if (!macsec_device) {
- netdev_err(ctx->netdev, "MACsec offload: Failed to find device context\n");
- err = -EINVAL;
-
- goto out;
- }
-
for (i = 0; i < MACSEC_NUM_AN; ++i) {
tx_sa = macsec_device->tx_sa[i];
if (!tx_sa)
continue;
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
+ mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, netdev, 0);
mlx5_destroy_encryption_key(macsec->mdev, tx_sa->enc_key_id);
kfree(tx_sa);
macsec_device->tx_sa[i] = NULL;
@@ -1272,7 +1260,7 @@ static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
list = &macsec_device->macsec_rx_sc_list_head;
list_for_each_entry_safe(rx_sc, tmp, list, rx_sc_list_element)
- macsec_del_rxsc_ctx(macsec, rx_sc, ctx->secy->netdev);
+ macsec_del_rxsc_ctx(macsec, rx_sc, netdev);
kfree(macsec_device->dev_addr);
macsec_device->dev_addr = NULL;
@@ -1280,7 +1268,24 @@ static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
list_del_rcu(&macsec_device->macsec_device_list_element);
--macsec->num_of_devices;
kfree(macsec_device);
+}
+
+static int mlx5e_macsec_del_secy(struct macsec_context *ctx)
+{
+ struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
+ struct mlx5e_macsec *macsec = priv->macsec;
+ struct mlx5e_macsec_device *macsec_device;
+ int err = 0;
+ mutex_lock(&macsec->lock);
+ macsec_device = mlx5e_macsec_get_macsec_device_context(macsec, ctx);
+ if (!macsec_device) {
+ netdev_err(ctx->netdev, "MACsec offload: Failed to find device context\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ macsec_del_secy(macsec, macsec_device);
out:
mutex_unlock(&macsec->lock);
@@ -1796,6 +1801,7 @@ int mlx5e_macsec_init(struct mlx5e_priv *priv)
void mlx5e_macsec_cleanup(struct mlx5e_priv *priv)
{
+ struct mlx5e_macsec_device *macsec_device, *tmp;
struct mlx5e_macsec *macsec = priv->macsec;
struct mlx5_core_dev *mdev = priv->mdev;
@@ -1803,9 +1809,20 @@ void mlx5e_macsec_cleanup(struct mlx5e_priv *priv)
return;
mlx5_notifier_unregister(mdev, &macsec->nb);
- mlx5_macsec_fs_cleanup(mdev->macsec_fs);
destroy_workqueue(macsec->wq);
+
+ mutex_lock(&macsec->lock);
+ list_for_each_entry_safe(macsec_device, tmp,
+ &macsec->macsec_device_list_head,
+ macsec_device_list_element)
+ macsec_del_secy(macsec, macsec_device);
+ mutex_unlock(&macsec->lock);
+
+ xa_destroy(&macsec->sc_xarray);
+ mlx5_macsec_fs_cleanup(mdev->macsec_fs);
+ mdev->macsec_fs = NULL;
mlx5e_macsec_aso_cleanup(&macsec->aso, mdev);
mutex_destroy(&macsec->lock);
kfree(macsec);
+ priv->macsec = NULL;
}
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 6/7] net/mlx5e: Serialize TC and IPsec offload exclusion counters
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
` (4 preceding siblings ...)
2026-09-17 17:54 ` [PATCH net 5/7] net/mlx5e: macsec: Delete remaining SecYs during cleanup Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
2026-09-17 17:54 ` [PATCH net 7/7] net/mlx5e: shampo: Do not merge PSP packets Tariq Toukan
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
The counters enforcing TC and IPsec packet offload mutual exclusion are
not consistently serialized. The IPsec add path conditionally takes the
eswitch write lock, but neither release path takes it. The TC add path
only holds the eswitch read lock, and devices without an eswitch cannot
rely on that lock at all.
Concurrent read-modify-write operations on the same counter can lose an
update. A stale nonzero count can keep rejecting offload requests after
the last user has gone, while an undercount can allow conflicting
offloads to coexist.
Move the counters into mdev->offload_block and protect all checks,
increments and decrements with a dedicated mutex. Keep the
opposing-counter check and reservation in the same critical section,
independent of eswitch availability. Initialize the lock for the core
device lifetime and add warnings for unbalanced releases. Remove the
now-unused mlx5_esw_lock() helper.
Fixes: c8e350e62fc5 ("net/mlx5e: Make TC and IPsec offloads mutually exclusive on a netdev")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../mellanox/mlx5/core/en_accel/ipsec_fs.c | 43 ++++++-------------
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 18 +++++---
.../net/ethernet/mellanox/mlx5/core/eswitch.c | 12 ------
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 1 -
.../net/ethernet/mellanox/mlx5/core/main.c | 3 ++
include/linux/mlx5/driver.h | 7 ++-
6 files changed, 32 insertions(+), 52 deletions(-)
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 5c72656c623f..2b856d0db917 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
@@ -2574,45 +2574,26 @@ 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;
- }
+ int ret = 0;
- 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;
+ mutex_lock(&mdev->offload_block.lock);
+ if (mdev->offload_block.num_block_ipsec)
+ ret = -EBUSY;
+ else
+ mdev->offload_block.num_block_tc++;
+ mutex_unlock(&mdev->offload_block.lock);
- mdev->num_block_tc++;
- return 0;
+ return ret;
}
-#endif
static void mlx5e_ipsec_unblock_tc_offload(struct mlx5_core_dev *mdev)
{
- mdev->num_block_tc--;
+ mutex_lock(&mdev->offload_block.lock);
+ if (!WARN_ON_ONCE(!mdev->offload_block.num_block_tc))
+ mdev->offload_block.num_block_tc--;
+ mutex_unlock(&mdev->offload_block.lock);
}
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 44fc421e7b8c..89463d18880c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -4856,16 +4856,19 @@ static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx
static int mlx5e_tc_block_ipsec_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))
return 0;
- if (mdev->num_block_tc)
- return -EBUSY;
-
- mdev->num_block_ipsec++;
+ mutex_lock(&mdev->offload_block.lock);
+ if (mdev->offload_block.num_block_tc)
+ ret = -EBUSY;
+ else
+ mdev->offload_block.num_block_ipsec++;
+ 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)
@@ -4873,7 +4876,10 @@ static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter, struct mlx
if (!is_tc_ipsec_order_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_block_ipsec))
+ priv->mdev->offload_block.num_block_ipsec--;
+ mutex_unlock(&priv->mdev->offload_block.lock);
}
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 0b48cc7a6734..989ca26e8851 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -3028,18 +3028,6 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw, bool check_users)
return esw->mode;
}
-int mlx5_esw_lock(struct mlx5_eswitch *esw)
-{
- down_write(&esw->mode_lock);
-
- if (esw->eswitch_operation_in_progress) {
- up_write(&esw->mode_lock);
- return -EBUSY;
- }
-
- return 0;
-}
-
/**
* mlx5_esw_unlock() - Release write lock on esw mode lock
* @esw: eswitch device.
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 4a9a1656f6db..d52146cff496 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -947,7 +947,6 @@ void mlx5_esw_release(struct mlx5_core_dev *dev);
void mlx5_esw_get(struct mlx5_core_dev *dev);
void mlx5_esw_put(struct mlx5_core_dev *dev);
int mlx5_esw_try_lock(struct mlx5_eswitch *esw, bool check_users);
-int mlx5_esw_lock(struct mlx5_eswitch *esw);
void mlx5_esw_unlock(struct mlx5_eswitch *esw);
void esw_vport_change_handle_locked(struct mlx5_vport *vport);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 5f28d906c35b..46b34c80c458 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);
@@ -1901,6 +1902,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;
@@ -1928,6 +1930,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 83d0a83bbfbc..4e207bf49c31 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_block_tc;
+ u64 num_block_ipsec;
+ } offload_block;
#ifdef CONFIG_MLX5_MACSEC
struct mlx5_macsec_fs *macsec_fs;
/* MACsec notifier chain to sync MACsec core and IB database */
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net 7/7] net/mlx5e: shampo: Do not merge PSP packets
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
` (5 preceding siblings ...)
2026-09-17 17:54 ` [PATCH net 6/7] net/mlx5e: Serialize TC and IPsec offload exclusion counters Tariq Toukan
@ 2026-09-17 17:54 ` Tariq Toukan
6 siblings, 0 replies; 8+ messages in thread
From: Tariq Toukan @ 2026-09-17 17:54 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni, Sabrina Dubroca
Cc: Boris Pismenny, Carolina Jubran, Cosmin Ratiu, Daniel Zahka,
Dragos Tatulea, Emeel Hakim, Gal Pressman, Jianbo Liu,
Leon Romanovsky, open list, linux-rdma, Lior Nahmanson,
Mark Bloch, Parav Pandit, Raed Salem, Rahul Rameshbabu,
Roi Dayan, Saeed Mahameed, Steffen Klassert, Tariq Toukan
From: Cosmin Ratiu <cratiu@nvidia.com>
PSP packets are UDP-encapsulated, and enabling HW GRO (SHAMPO in mlx5)
makes it possible to merge those packets in a silly way:
IP|UDP1|PSP1|payload1|UDP2|PSP2|payload2|...
That happens because the HW GRO machinery doesn't know about PSP and
considers it part of the UDP payload.
This patch enforces no match in SW.
Fixes: 29d7f433fcec ("net/mlx5e: Add Rx data path offload")
Signed-off-by: Cosmin Ratiu <cratiu@nvidia.com>
Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 7bd0606a5253..5e07cc8586f6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -2224,6 +2224,16 @@ 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
+ /* PSP packets cannot be merged. */
+ return !mlx5e_psp_is_rx_flow(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;
@@ -2266,8 +2276,9 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq
}
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);
}
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-17 18:12 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17 17:54 [PATCH net 0/7] net/mlx5e: Fix offload lifetime, cleanup and exclusion bugs Tariq Toukan
2026-09-17 17:54 ` [PATCH net 1/7] net/mlx5e: ipsec: Block eswitch mode changes during policy creation Tariq Toukan
2026-09-17 17:54 ` [PATCH net 2/7] net/mlx5e: ipsec: Block eswitch mode changes before accessing priv->ipsec Tariq Toukan
2026-09-17 17:54 ` [PATCH net 3/7] net/mlx5e: tc: Tie esw & accel blocking refs to the flow's lifetime Tariq Toukan
2026-09-17 17:54 ` [PATCH net 4/7] net/mlx5e: macsec: Track hardware object ownership for SA teardown Tariq Toukan
2026-09-17 17:54 ` [PATCH net 5/7] net/mlx5e: macsec: Delete remaining SecYs during cleanup Tariq Toukan
2026-09-17 17:54 ` [PATCH net 6/7] net/mlx5e: Serialize TC and IPsec offload exclusion counters Tariq Toukan
2026-09-17 17:54 ` [PATCH net 7/7] net/mlx5e: shampo: Do not merge PSP packets Tariq Toukan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®