* [PATCH net-next 01/13] net/mlx5e: Assign a random MAC to any netdev with a zero MAC address
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 02/13] net/mlx5: E-switch, do not leave an unpaired devcom registered Tariq Toukan
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5e_set_netdev_dev_addr() falls back to a random MAC only when the
queried address is all-zeros AND the device is not a vport group
manager. A vport group manager that comes up with a zero MAC is
therefore left with an invalid all-zero address.
The vport_group_manager exception is unnecessary: a zero MAC is always
invalid, regardless of device type. Drop the condition and assign a
random MAC whenever the queried address is zero, so every netdev comes
up with a valid address.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index fc110a7d16e8..b0765f07cc3a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -5430,8 +5430,7 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
u8 addr[ETH_ALEN];
mlx5_query_mac_address(priv->mdev, addr);
- if (is_zero_ether_addr(addr) &&
- !MLX5_CAP_GEN(priv->mdev, vport_group_manager)) {
+ if (is_zero_ether_addr(addr)) {
eth_hw_addr_random(netdev);
mlx5_core_info(priv->mdev, "Assigned random MAC address %pM\n", netdev->dev_addr);
return;
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 02/13] net/mlx5: E-switch, do not leave an unpaired devcom registered
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 01/13] net/mlx5e: Assign a random MAC to any netdev with a zero MAC address Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 03/13] net/mlx5: LAG, allocate v2p_map dynamically Tariq Toukan
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
If the initial PAIR event fails, the eswitch offloads devcom component
stays registered until eswitch teardown even though no peer was ever
paired. devcom is optional, so this is not a functional bug - but a
registered component that reflects no actual pairing is incorrect state
to keep around.
Release it when the initial pairing fails.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index eb74b6260168..e7d92d9bde16 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -3548,6 +3548,7 @@ static int mlx5_esw_offloads_devcom_event(int event,
void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw,
const struct mlx5_devcom_match_attr *attr)
{
+ int err;
int i;
for (i = 0; i < MLX5_MAX_PORTS; i++)
@@ -3572,10 +3573,12 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw,
if (!esw->devcom)
return;
- mlx5_devcom_send_event(esw->devcom,
- ESW_OFFLOADS_DEVCOM_PAIR,
- ESW_OFFLOADS_DEVCOM_UNPAIR,
- esw);
+ err = mlx5_devcom_send_event(esw->devcom,
+ ESW_OFFLOADS_DEVCOM_PAIR,
+ ESW_OFFLOADS_DEVCOM_UNPAIR,
+ esw);
+ if (err)
+ mlx5_esw_offloads_devcom_cleanup(esw);
}
void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 03/13] net/mlx5: LAG, allocate v2p_map dynamically
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 01/13] net/mlx5e: Assign a random MAC to any netdev with a zero MAC address Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 02/13] net/mlx5: E-switch, do not leave an unpaired devcom registered Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 04/13] net/mlx5: LAG, allocate port-indexed scratch buffers dynamically Tariq Toukan
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
v2p_map was a fixed array sized MLX5_MAX_PORTS *
MLX5_LAG_MAX_HASH_BUCKETS embedded in struct mlx5_lag. Turn it into a
pointer allocated in mlx5_lag_dev_alloc() once ldev->ports is known,
sized by the actual port count, and free it in mlx5_ldev_free(). The
ldev->ports / ldev->buckets initialization is moved up so the allocation
can use it.
The matching scratch buffer in mlx5_modify_lag() is converted from a
MLX5_MAX_PORTS-sized stack array to a kcalloc() of the same extent, with
the trailing teardown reworked through a goto so the buffer is freed on
every path. The memcpy() that previously relied on sizeof() of the stack
array now uses the explicit ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS
span.
No functional change; this removes v2p_map's dependency on
MLX5_MAX_PORTS.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 38 ++++++++++++++-----
.../net/ethernet/mellanox/mlx5/core/lag/lag.h | 2 +-
2 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index c655f6e32e9b..00b0159cb422 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -308,6 +308,7 @@ static void mlx5_ldev_free(struct kref *ref)
cancel_work_sync(&ldev->speed_update_work);
destroy_workqueue(ldev->wq);
mutex_destroy(&ldev->lock);
+ kfree(ldev->v2p_map);
kfree(ldev);
}
@@ -330,11 +331,16 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
if (!ldev)
return NULL;
+ ldev->ports = MLX5_CAP_GEN(dev, num_lag_ports);
+ ldev->buckets = 1;
+ ldev->v2p_map = kcalloc(ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS,
+ sizeof(*ldev->v2p_map), GFP_KERNEL);
+ if (!ldev->v2p_map)
+ goto err_v2p_map;
+
ldev->wq = create_singlethread_workqueue("mlx5_lag");
- if (!ldev->wq) {
- kfree(ldev);
- return NULL;
- }
+ if (!ldev->wq)
+ goto err_wq;
kref_init(&ldev->ref);
mutex_init(&ldev->lock);
@@ -358,10 +364,13 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev)
mlx5_core_err(dev, "Failed to init multipath lag err=%d\n",
err);
- ldev->ports = MLX5_CAP_GEN(dev, num_lag_ports);
- ldev->buckets = 1;
-
return ldev;
+
+err_wq:
+ kfree(ldev->v2p_map);
+err_v2p_map:
+ kfree(ldev);
+ return NULL;
}
int mlx5_lag_dev_get_netdev_idx(struct mlx5_lag *ldev,
@@ -853,8 +862,8 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
struct lag_tracker *tracker)
{
int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
- u8 ports[MLX5_MAX_PORTS * MLX5_LAG_MAX_HASH_BUCKETS] = {};
struct mlx5_core_dev *dev0;
+ u8 *ports;
int idx;
int err;
int i;
@@ -864,6 +873,12 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
return;
dev0 = mlx5_lag_pf(ldev, first_idx)->dev;
+
+ ports = kcalloc(ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS,
+ sizeof(*ports), GFP_KERNEL);
+ if (!ports)
+ return;
+
mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets, ports);
mlx5_ldev_for_each(i, 0, ldev) {
@@ -876,9 +891,10 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
mlx5_core_err(dev0,
"Failed to modify LAG (%d)\n",
err);
- return;
+ goto out;
}
- memcpy(ldev->v2p_map, ports, sizeof(ports));
+ memcpy(ldev->v2p_map, ports,
+ ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS);
mlx5_lag_print_mapping(dev0, ldev, tracker,
ldev->mode_flags);
@@ -899,6 +915,8 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
ndev);
dev_put(ndev);
}
+out:
+ kfree(ports);
}
static int mlx5_lag_set_port_sel_mode(struct mlx5_lag *ldev,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
index e9f0ef83ce1d..8552792b9035 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
@@ -85,7 +85,7 @@ struct mlx5_lag {
u8 ports;
u8 buckets;
int mode_changes_in_progress;
- u8 v2p_map[MLX5_MAX_PORTS * MLX5_LAG_MAX_HASH_BUCKETS];
+ u8 *v2p_map;
struct kref ref;
struct xarray pfs;
struct lag_tracker tracker;
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 04/13] net/mlx5: LAG, allocate port-indexed scratch buffers dynamically
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (2 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 03/13] net/mlx5: LAG, allocate v2p_map dynamically Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 05/13] net/mlx5: LAG, drop per-port scratch array in drop-rule setup Tariq Toukan
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_lag_print_mapping(), mlx5_infer_tx_affinity_mapping() and
lag_active_port_bits() each used a MLX5_MAX_PORTS-sized stack buffer to
hold per-port working state. Allocate these buffers with
kcalloc(ldev->ports, ...) instead so they track the actual port count
and no longer depend on MLX5_MAX_PORTS.
lag_active_port_bits() can now fail on allocation, so it returns int and
propagates -ENOMEM; a non-negative return is the active-port bitmask as
before. Its two callers, mlx5_cmd_create_lag() and _mlx5_modify_lag(),
check for a negative return and bail out, then narrow the value back
into the u8 they hand to the device.
This removes these buffers' dependency on MLX5_MAX_PORTS.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 100 ++++++++++++++----
1 file changed, 80 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 00b0159cb422..93ead5664152 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -63,19 +63,25 @@ static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
return MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY;
}
-static u8 lag_active_port_bits(struct mlx5_lag *ldev,
- struct lag_tracker *tracker)
+static int lag_active_port_bits(struct mlx5_lag *ldev,
+ struct lag_tracker *tracker)
{
- u8 enabled_ports[MLX5_MAX_PORTS] = {};
u8 active_port = 0;
+ u8 *enabled_ports;
int num_enabled;
int idx;
+ enabled_ports = kcalloc(ldev->ports, sizeof(*enabled_ports),
+ GFP_KERNEL);
+ if (!enabled_ports)
+ return -ENOMEM;
+
mlx5_infer_tx_enabled(tracker, ldev, enabled_ports,
&num_enabled);
for (idx = 0; idx < num_enabled; idx++)
active_port |= BIT_MASK(enabled_ports[idx]);
+ kfree(enabled_ports);
return active_port;
}
@@ -105,13 +111,21 @@ static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, struct mlx5_lag *ldev,
MLX5_SET(lagc, lag_ctx, tx_remap_affinity_1, ports[idx0]);
MLX5_SET(lagc, lag_ctx, tx_remap_affinity_2, ports[idx1]);
break;
- case MLX5_LAG_PORT_SELECT_MODE_PORT_SELECT_FT:
+ case MLX5_LAG_PORT_SELECT_MODE_PORT_SELECT_FT: {
+ u8 active_port;
+ int ret;
+
if (!MLX5_CAP_PORT_SELECTION(dev, port_select_flow_table_bypass))
break;
- MLX5_SET(lagc, lag_ctx, active_port,
- lag_active_port_bits(ldev, tracker));
+ ret = lag_active_port_bits(ldev, tracker);
+ if (ret < 0)
+ return ret;
+
+ active_port = ret;
+ MLX5_SET(lagc, lag_ctx, active_port, active_port);
break;
+ }
default:
break;
}
@@ -240,22 +254,31 @@ static void mlx5_lag_print_mapping(struct mlx5_core_dev *dev,
struct lag_tracker *tracker,
unsigned long flags)
{
- char buf[MLX5_MAX_PORTS * 10 + 1] = {};
- u8 enabled_ports[MLX5_MAX_PORTS] = {};
+ u8 *enabled_ports = NULL;
int written = 0;
int num_enabled;
+ char *buf;
int idx;
int err;
int i;
int j;
+ buf = kcalloc(ldev->ports * 10 + 1, sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return;
+
if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &flags)) {
+ enabled_ports = kcalloc(ldev->ports, sizeof(*enabled_ports),
+ GFP_KERNEL);
+ if (!enabled_ports)
+ goto free_buf;
+
mlx5_infer_tx_enabled(tracker, ldev, enabled_ports,
&num_enabled);
for (i = 0; i < num_enabled; i++) {
err = scnprintf(buf + written, 4, "%d, ", enabled_ports[i] + 1);
if (err != 3)
- return;
+ goto free_enabled;
written += err;
}
buf[written - 2] = 0;
@@ -267,12 +290,17 @@ static void mlx5_lag_print_mapping(struct mlx5_core_dev *dev,
err = scnprintf(buf + written, 10,
" port %d:%d", i + 1, ldev->v2p_map[idx]);
if (err != 9)
- return;
+ goto free_enabled;
written += err;
}
}
mlx5_core_info(dev, "lag map:%s\n", buf);
}
+
+free_enabled:
+ kfree(enabled_ports);
+free_buf:
+ kfree(buf);
}
static int mlx5_lag_netdev_event(struct notifier_block *this,
@@ -668,20 +696,28 @@ static bool __mlx5_lag_is_sd_active(struct mlx5_lag *ldev,
* If there are ports that are disabled fill the relevant slots
* with mapping that points to active ports.
*/
-static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
- struct mlx5_lag *ldev,
- u8 buckets,
- u8 *ports)
+static int mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
+ struct mlx5_lag *ldev,
+ u8 buckets,
+ u8 *ports)
{
- int disabled[MLX5_MAX_PORTS] = {};
- int enabled[MLX5_MAX_PORTS] = {};
int disabled_ports_num = 0;
int enabled_ports_num = 0;
+ int *disabled;
+ int *enabled;
+ int err = 0;
int idx;
u32 rand;
int i;
int j;
+ enabled = kcalloc(ldev->ports, sizeof(*enabled), GFP_KERNEL);
+ disabled = kcalloc(ldev->ports, sizeof(*disabled), GFP_KERNEL);
+ if (!enabled || !disabled) {
+ err = -ENOMEM;
+ goto out;
+ }
+
mlx5_ldev_for_each(i, 0, ldev) {
if (tracker->netdev_state[i].tx_enabled &&
tracker->netdev_state[i].link_up)
@@ -704,7 +740,7 @@ static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
/* If all ports are disabled/enabled keep native mapping */
if (enabled_ports_num == ldev->ports ||
disabled_ports_num == ldev->ports)
- return;
+ goto out;
/* Go over the disabled ports and for each assign a random active port */
for (i = 0; i < disabled_ports_num; i++) {
@@ -717,6 +753,11 @@ static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker,
mlx5_lag_xa_to_dev_idx(ldev, rand_xa_idx) + 1;
}
}
+
+out:
+ kfree(enabled);
+ kfree(disabled);
+ return err;
}
static bool mlx5_lag_has_drop_rule(struct mlx5_lag *ldev)
@@ -816,7 +857,10 @@ static int _mlx5_modify_lag(struct mlx5_lag *ldev,
!MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table_bypass))
return ret;
- active_ports = lag_active_port_bits(ldev, tracker);
+ ret = lag_active_port_bits(ldev, tracker);
+ if (ret < 0)
+ return ret;
+ active_ports = ret;
return mlx5_cmd_modify_active_port(dev0, active_ports);
}
@@ -879,7 +923,14 @@ void mlx5_modify_lag(struct mlx5_lag *ldev,
if (!ports)
return;
- mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets, ports);
+ err = mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets,
+ ports);
+ if (err) {
+ mlx5_core_err(dev0,
+ "mlx5_infer_tx_affinity_mapping failed, err = %d\n",
+ err);
+ goto out;
+ }
mlx5_ldev_for_each(i, 0, ldev) {
for (j = 0; j < ldev->buckets; j++) {
@@ -1045,7 +1096,16 @@ int mlx5_activate_lag(struct mlx5_lag *ldev,
return err;
if (mode != MLX5_LAG_MODE_MPESW) {
- mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets, ldev->v2p_map);
+ err = mlx5_infer_tx_affinity_mapping(tracker, ldev,
+ ldev->buckets,
+ ldev->v2p_map);
+ if (err) {
+ mlx5_core_err(dev0,
+ "mlx5_infer_tx_affinity_mapping failed, err = %d\n",
+ err);
+ return err;
+ }
+
if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &flags)) {
err = mlx5_lag_port_sel_create(ldev, tracker->hash_type,
ldev->v2p_map);
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 05/13] net/mlx5: LAG, drop per-port scratch array in drop-rule setup
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (3 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 04/13] net/mlx5: LAG, allocate port-indexed scratch buffers dynamically Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 06/13] net/mlx5: LAG, size debugfs buffers by port count Tariq Toukan
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_lag_drop_rule_setup() walks the per-port tracker state, but does so
through a per-port scratch array, mlx5_lag_drop_rule_setup() collects
the disabled ports to create a per-port drop rule.
Walk the tracker state inline removing its MLX5_MAX_PORTS dependency.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/lag/lag.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 93ead5664152..4648371f9914 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -792,11 +792,8 @@ static void mlx5_lag_drop_rule_cleanup(struct mlx5_lag *ldev)
static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev,
struct lag_tracker *tracker)
{
- u8 disabled_ports[MLX5_MAX_PORTS] = {};
struct mlx5_core_dev *dev;
struct lag_func *pf;
- int disabled_index;
- int num_disabled;
int err;
int i;
@@ -808,11 +805,11 @@ static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev,
if (!ldev->tracker.has_inactive)
return;
- mlx5_infer_tx_disabled(tracker, ldev, disabled_ports, &num_disabled);
-
- for (i = 0; i < num_disabled; i++) {
- disabled_index = disabled_ports[i];
- pf = mlx5_lag_pf(ldev, disabled_index);
+ mlx5_ldev_for_each(i, 0, ldev) {
+ if (tracker->netdev_state[i].tx_enabled &&
+ tracker->netdev_state[i].link_up)
+ continue;
+ pf = mlx5_lag_pf(ldev, i);
dev = pf->dev;
err = mlx5_esw_acl_ingress_vport_drop_rule_create(dev->priv.eswitch,
MLX5_VPORT_UPLINK);
@@ -820,7 +817,8 @@ static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev,
pf->has_drop = true;
else
mlx5_core_err(dev,
- "Failed to create lag drop rule, error: %d", err);
+ "Failed to create lag drop rule, error: %d",
+ err);
}
}
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 06/13] net/mlx5: LAG, size debugfs buffers by port count
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (4 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 05/13] net/mlx5: LAG, drop per-port scratch array in drop-rule setup Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 07/13] net/mlx5e: TC, anchor peer-flow reverse index on the duplicated flow Tariq Toukan
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
debugfs mapping_show() uses constant MLX5_MAX_PORTS to size ports array.
Instead, allocate dynamically using actual number of ports.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
index e9b8d79d2d21..44296789d656 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
@@ -101,14 +101,18 @@ static int flags_show(struct seq_file *file, void *priv)
static int mapping_show(struct seq_file *file, void *priv)
{
struct mlx5_core_dev *dev = file->private;
- u8 ports[MLX5_MAX_PORTS] = {};
struct mlx5_lag *ldev;
bool hash = false;
bool lag_active;
int i, idx = 0;
int num_ports;
+ u8 *ports;
ldev = mlx5_lag_dev(dev);
+ ports = kcalloc(ldev->ports, sizeof(*ports), GFP_KERNEL);
+ if (!ports)
+ return -ENOMEM;
+
mutex_lock(&ldev->lock);
lag_active = __mlx5_lag_is_active(ldev);
if (lag_active) {
@@ -123,8 +127,10 @@ static int mapping_show(struct seq_file *file, void *priv)
}
}
mutex_unlock(&ldev->lock);
- if (!lag_active)
+ if (!lag_active) {
+ kfree(ports);
return -EINVAL;
+ }
for (i = 0; i < num_ports; i++) {
if (hash)
@@ -133,6 +139,7 @@ static int mapping_show(struct seq_file *file, void *priv)
seq_printf(file, "%d:%d\n", i + 1, ports[i]);
}
+ kfree(ports);
return 0;
}
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 07/13] net/mlx5e: TC, anchor peer-flow reverse index on the duplicated flow
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (5 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 06/13] net/mlx5: LAG, size debugfs buffers by port count Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 08/13] net/mlx5e: TC, track peer flows in a vhca_id xarray Tariq Toukan
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
A TC eswitch flow offloaded to a shared FDB is duplicated onto every
peer eswitch. Besides the forward list of duplicates on the origin flow
(mlx5e_tc_flow.peer_flows), the eswitch keeps a reverse index,
esw->offloads.peer_flows[], an array of per-peer list heads keyed by the
peer's LAG sequence number, used to tear down a peer's duplicates when
it is removed.
That reverse index was anchored on the origin: since one origin can have
a duplicate on every peer, the origin carried per-peer storage sized to
the max port count - a peer[MLX5_MAX_PORTS] array of list nodes plus a
peer_used bitmap - and each duplicate stored its peer_index.
Anchor it on the duplicate instead, which belongs to a single peer. Give
each flow one list node, mlx5e_tc_flow.peer, and place the duplicate -
not the origin - on its peer's list through it; add a peer_orig back-ref
so del can reach the origin from the duplicate. One node then replaces
the origin's per-peer array, and del unlinks the duplicate directly, so
peer[], peer_used and peer_index are dropped.
The per-peer list heads remain the fixed esw->offloads.peer_flows[]
array keyed by the LAG sequence number - that array is replaced in the
next patch. No functional change.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../ethernet/mellanox/mlx5/core/en/tc_priv.h | 14 ++---
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 59 ++++++++-----------
2 files changed, 29 insertions(+), 44 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
index 7bfe7cdc5770..1ceebab4ce08 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
@@ -97,18 +97,14 @@ struct mlx5e_tc_flow {
struct encap_flow_item encaps[MLX5_MAX_FLOW_FWD_VPORTS];
struct mlx5e_hairpin_entry *hpe; /* attached hairpin instance */
struct list_head hairpin; /* flows sharing the same hairpin */
- struct list_head peer[MLX5_MAX_PORTS]; /* flows with peer flow */
- DECLARE_BITMAP(peer_used, MLX5_MAX_PORTS); /* tracks populated peer
- * slots
- */
+ struct list_head peer; /* dup: node in origin esw's peer_flows */
struct list_head unready; /* flows not ready to be offloaded (e.g
* due to missing route)
*/
- struct list_head peer_flows; /* flows on peer */
- int peer_index; /* peer-flow index pinned at add time, used at del
- * time so removal is independent of LAG state
- * changes between add and del.
- */
+
+ /* origin: its dups; dup: node on that list */
+ struct list_head peer_flows;
+ struct mlx5e_tc_flow *peer_orig; /* dup: back-ref to origin flow */
struct net_device *orig_dev; /* netdev adding flow first */
int tmp_entry_index;
struct list_head tmp_list; /* temporary flow list used by neigh update */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index b290beb4369a..fae4f8625da4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -2116,43 +2116,35 @@ void mlx5e_put_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list)
mlx5e_flow_put(priv, flow);
}
-static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow,
- int peer_index)
+static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *peer_flow)
{
- struct mlx5_eswitch *esw = flow->priv->mdev->priv.eswitch;
- struct mlx5e_tc_flow *peer_flow;
- struct mlx5e_tc_flow *tmp;
-
- if (!flow_flag_test(flow, ESWITCH) ||
- !flow_flag_test(flow, DUP))
- return;
+ struct mlx5e_tc_flow *flow = peer_flow->peer_orig;
+ struct mlx5_eswitch *esw;
+ esw = flow->priv->mdev->priv.eswitch;
mutex_lock(&esw->offloads.peer_mutex);
- list_del(&flow->peer[peer_index]);
- clear_bit(peer_index, flow->peer_used);
+ list_del(&peer_flow->peer);
mutex_unlock(&esw->offloads.peer_mutex);
- list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows) {
- if (peer_index != peer_flow->peer_index)
- continue;
-
- list_del(&peer_flow->peer_flows);
- if (refcount_dec_and_test(&peer_flow->refcnt)) {
- mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow);
- kfree(peer_flow);
- }
- }
-
+ list_del(&peer_flow->peer_flows);
if (list_empty(&flow->peer_flows))
flow_flag_clear(flow, DUP);
+
+ if (refcount_dec_and_test(&peer_flow->refcnt)) {
+ mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow);
+ kfree(peer_flow);
+ }
}
static void mlx5e_tc_del_fdb_peers_flow(struct mlx5e_tc_flow *flow)
{
- int i;
+ struct mlx5e_tc_flow *peer_flow, *tmp;
- for_each_set_bit(i, flow->peer_used, MLX5_MAX_PORTS)
- mlx5e_tc_del_fdb_peer_flow(flow, i);
+ if (!flow_flag_test(flow, ESWITCH) || !flow_flag_test(flow, DUP))
+ return;
+
+ list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows)
+ mlx5e_tc_del_fdb_peer_flow(peer_flow);
}
static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
@@ -4639,12 +4631,11 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
goto out;
}
- peer_flow->peer_index = i;
+ peer_flow->peer_orig = flow;
list_add_tail(&peer_flow->peer_flows, &flow->peer_flows);
flow_flag_set(flow, DUP);
mutex_lock(&esw->offloads.peer_mutex);
- list_add_tail(&flow->peer[i], &esw->offloads.peer_flows[i]);
- set_bit(i, flow->peer_used);
+ list_add_tail(&peer_flow->peer, &esw->offloads.peer_flows[i]);
mutex_unlock(&esw->offloads.peer_mutex);
out:
@@ -5539,21 +5530,19 @@ int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags)
void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw)
{
- struct mlx5_devcom_comp_dev *devcom;
- struct mlx5_devcom_comp_dev *pos;
- struct mlx5e_tc_flow *flow, *tmp;
+ struct mlx5_devcom_comp_dev *devcom = esw->devcom, *pos;
+ struct mlx5e_tc_flow *peer_flow, *tmp_peer_flow;
struct mlx5_eswitch *peer_esw;
int i;
- devcom = esw->devcom;
-
mlx5_devcom_for_each_peer_entry(devcom, peer_esw, pos) {
i = mlx5_lag_get_dev_seq(peer_esw->dev);
if (i < 0)
continue;
- list_for_each_entry_safe(flow, tmp, &esw->offloads.peer_flows[i], peer[i])
- mlx5e_tc_del_fdb_peers_flow(flow);
+ list_for_each_entry_safe(peer_flow, tmp_peer_flow,
+ &esw->offloads.peer_flows[i], peer)
+ mlx5e_tc_del_fdb_peer_flow(peer_flow);
}
}
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 08/13] net/mlx5e: TC, track peer flows in a vhca_id xarray
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (6 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 07/13] net/mlx5e: TC, anchor peer-flow reverse index on the duplicated flow Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 09/13] net/mlx5: E-switch, derive manager vport from device capability Tariq Toukan
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The per-peer reverse index lived in a fixed esw->offloads.peer_flows[]
array of list heads indexed by the peer's LAG sequence number, capping a
shared FDB at MLX5_MAX_PORTS members.
Replace the array with an xarray keyed by the peer vhca_id. Each entry
is a heap-allocated list head that chains the flows duplicated to that
peer via their peer node. This lifts the MLX5_MAX_PORTS cap: the number
of peers is bounded only by the number of distinct vhca_ids.
The lifetime of the duplicated peer flows list_head follows the devcom
pairing of the two eswitches:
- pair (mlx5_esw_offloads_pair): kzalloc_obj + INIT_LIST_HEAD +
xa_store the dup_peer_flows under the peer's vhca_id.
- add (mlx5e_tc_add_fdb_peer_flow): xa_load the dup_peer_flows and
list_add the duplicated flow's peer node.
- del (mlx5e_tc_del_fdb_peer_flow): list_del that node.
- flush (mlx5e_tc_clean_fdb_peer_flows): xa_for_each dup_peer_flows,
drop every duplicated flow on it; called from unpair.
- unpair (mlx5_esw_offloads_unpair): xa_erase + kfree the
dup_peer_flows.
So a dup_peer_flows is created when the local eswitch pairs with a peer
over devcom and freed when they unpair.
No functional change.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../net/ethernet/mellanox/mlx5/core/en_tc.c | 22 +++++++---------
.../net/ethernet/mellanox/mlx5/core/eswitch.h | 2 +-
.../mellanox/mlx5/core/eswitch_offloads.c | 26 ++++++++++++++++---
3 files changed, 34 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index fae4f8625da4..c99e824b4c6d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -4596,12 +4596,13 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
unsigned long flow_flags,
struct mlx5_eswitch *peer_esw)
{
+ u16 peer_vhca_id = MLX5_CAP_GEN(peer_esw->dev, vhca_id);
struct mlx5e_priv *priv = flow->priv, *peer_priv;
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
struct mlx5e_tc_flow_parse_attr *parse_attr;
- int i = mlx5_lag_get_dev_seq(peer_esw->dev);
struct mlx5e_rep_priv *peer_urpriv;
+ struct list_head *dup_peer_flows;
struct mlx5e_tc_flow *peer_flow;
struct mlx5_core_dev *in_mdev;
int err = 0;
@@ -4634,8 +4635,11 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,
peer_flow->peer_orig = flow;
list_add_tail(&peer_flow->peer_flows, &flow->peer_flows);
flow_flag_set(flow, DUP);
+ dup_peer_flows = xa_load(&esw->offloads.peer_flows, peer_vhca_id);
+ if (!dup_peer_flows)
+ return -ENODEV;
mutex_lock(&esw->offloads.peer_mutex);
- list_add_tail(&peer_flow->peer, &esw->offloads.peer_flows[i]);
+ list_add_tail(&peer_flow->peer, dup_peer_flows);
mutex_unlock(&esw->offloads.peer_mutex);
out:
@@ -5530,20 +5534,14 @@ int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags)
void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw)
{
- struct mlx5_devcom_comp_dev *devcom = esw->devcom, *pos;
struct mlx5e_tc_flow *peer_flow, *tmp_peer_flow;
- struct mlx5_eswitch *peer_esw;
- int i;
-
- mlx5_devcom_for_each_peer_entry(devcom, peer_esw, pos) {
- i = mlx5_lag_get_dev_seq(peer_esw->dev);
- if (i < 0)
- continue;
+ struct list_head *dup_peer_flows;
+ unsigned long index;
+ xa_for_each(&esw->offloads.peer_flows, index, dup_peer_flows)
list_for_each_entry_safe(peer_flow, tmp_peer_flow,
- &esw->offloads.peer_flows[i], peer)
+ dup_peer_flows, peer)
mlx5e_tc_del_fdb_peer_flow(peer_flow);
- }
}
void mlx5e_tc_reoffload_flows_work(struct work_struct *work)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index 8b1f93b13ea9..e9cbcd73b23f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -319,7 +319,7 @@ struct mlx5_esw_offload {
struct mlx5_flow_handle *vport_rx_drop_rule;
struct mlx5_flow_table *ft_ipsec_tx_pol;
struct xarray vport_reps;
- struct list_head peer_flows[MLX5_MAX_PORTS];
+ struct xarray peer_flows;
struct mutex peer_mutex;
struct mutex encap_tbl_lock; /* protects encap_tbl */
DECLARE_HASHTABLE(encap_tbl, 8);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index e7d92d9bde16..c712848b202d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -3383,10 +3383,15 @@ static void mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch *esw,
static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw,
struct mlx5_eswitch *peer_esw)
{
+ struct list_head *dup_peer_flows;
+
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
mlx5e_tc_clean_fdb_peer_flows(esw);
#endif
mlx5_esw_offloads_rep_event_unpair(esw, peer_esw);
+ dup_peer_flows = xa_erase(&esw->offloads.peer_flows,
+ MLX5_CAP_GEN(peer_esw->dev, vhca_id));
+ kfree(dup_peer_flows);
esw_del_fdb_peer_miss_rules(esw, peer_esw->dev);
}
@@ -3394,6 +3399,7 @@ static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
struct mlx5_eswitch *peer_esw)
{
const struct mlx5_eswitch_rep_ops *ops;
+ struct list_head *dup_peer_flows;
struct mlx5_eswitch_rep *rep;
unsigned long i;
u8 rep_type;
@@ -3403,6 +3409,20 @@ static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
if (err)
return err;
+ dup_peer_flows = kzalloc_obj(*dup_peer_flows);
+ if (!dup_peer_flows) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ INIT_LIST_HEAD(dup_peer_flows);
+ err = xa_err(xa_store(&esw->offloads.peer_flows,
+ MLX5_CAP_GEN(peer_esw->dev, vhca_id),
+ dup_peer_flows, GFP_KERNEL));
+ if (err) {
+ kfree(dup_peer_flows);
+ goto err_out;
+ }
+
mlx5_esw_for_each_rep(esw, i, rep) {
for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
ops = esw->offloads.rep_ops[rep_type];
@@ -3549,10 +3569,8 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw,
const struct mlx5_devcom_match_attr *attr)
{
int err;
- int i;
- for (i = 0; i < MLX5_MAX_PORTS; i++)
- INIT_LIST_HEAD(&esw->offloads.peer_flows[i]);
+ xa_init(&esw->offloads.peer_flows);
mutex_init(&esw->offloads.peer_mutex);
if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
@@ -3595,6 +3613,8 @@ void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
xa_destroy(&esw->paired);
xa_destroy(&esw->fdb_table.offloads.peer_miss_rules);
esw->devcom = NULL;
+ WARN_ON_ONCE(!xa_empty(&esw->offloads.peer_flows));
+ xa_destroy(&esw->offloads.peer_flows);
}
bool mlx5_esw_offloads_devcom_is_ready(struct mlx5_eswitch *esw)
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 09/13] net/mlx5: E-switch, derive manager vport from device capability
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (7 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 08/13] net/mlx5e: TC, track peer flows in a vhca_id xarray Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 10/13] net/mlx5: LAG, don't print port mapping to debugfs in MPESW mode Tariq Toukan
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_eswitch_manager_vport() hardcoded the e-switch manager vport as
either the ECPF or the host PF. Read esw_manager_vport_number from the
e-switch capability when esw_manager_vport_number_valid is set, so the
manager vport can be a VF - a prerequisite for VFs acting as e-switch
managers. Keep the previous mapping as fallback when the capability does
not report a number.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 11 +++++++++--
include/linux/mlx5/eswitch.h | 3 +++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index fc197d1dc9df..e7561f0f89b0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -2460,13 +2460,20 @@ static int mlx5_esw_vports_init(struct mlx5_eswitch *esw)
}
}
- if (mlx5_ecpf_vport_exists(dev) ||
- mlx5_core_is_ecpf_esw_manager(dev)) {
+ if (mlx5_ecpf_vport_exists(dev)) {
err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_ECPF);
if (err)
goto err;
idx++;
}
+
+ if (!xa_load(&esw->vports, esw->manager_vport)) {
+ err = mlx5_esw_vport_alloc(esw, idx, esw->manager_vport);
+ if (err)
+ goto err;
+ idx++;
+ }
+
err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_UPLINK);
if (err)
goto err;
diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h
index a0dd162baa78..03d3620141c8 100644
--- a/include/linux/mlx5/eswitch.h
+++ b/include/linux/mlx5/eswitch.h
@@ -222,6 +222,9 @@ static inline bool is_mdev_switchdev_mode(struct mlx5_core_dev *dev)
/* The returned number is valid only when the dev is eswitch manager. */
static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev)
{
+ if (MLX5_CAP_ESW(dev, esw_manager_vport_number_valid))
+ return MLX5_CAP_ESW(dev, esw_manager_vport_number);
+
return mlx5_core_is_ecpf_esw_manager(dev) ?
MLX5_VPORT_ECPF : MLX5_VPORT_HOST_PF;
}
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 10/13] net/mlx5: LAG, don't print port mapping to debugfs in MPESW mode
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (8 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 09/13] net/mlx5: E-switch, derive manager vport from device capability Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 11/13] net/mlx5: LAG, drop stale esw_shared_ingress_acl gate from shared FDB Tariq Toukan
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The mapping debugfs file dumps the LAG virtual-to-physical port mapping.
In MPESW mode the LAG does not own that mapping - port selection is
driven by user steering rules, not by the LAG - so the dumped values are
meaningless.
Treat MPESW as if LAG is inactive and don't print anything to the user.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
index 44296789d656..b6125c7bd91b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
@@ -114,7 +114,8 @@ static int mapping_show(struct seq_file *file, void *priv)
return -ENOMEM;
mutex_lock(&ldev->lock);
- lag_active = __mlx5_lag_is_active(ldev);
+ lag_active = __mlx5_lag_is_active(ldev) &&
+ ldev->mode != MLX5_LAG_MODE_MPESW;
if (lag_active) {
if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &ldev->mode_flags)) {
mlx5_infer_tx_enabled(&ldev->tracker, ldev, ports,
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 11/13] net/mlx5: LAG, drop stale esw_shared_ingress_acl gate from shared FDB
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (9 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 10/13] net/mlx5: LAG, don't print port mapping to debugfs in MPESW mode Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 12/13] net/mlx5: E-switch, correct stale VF/PF wording in esw-allowed comments Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 13/13] net/mlx5: E-switch, disable host functions for a non PF e-switch manager Tariq Toukan
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
The shared-FDB support check still requires the esw_shared_ingress_acl
capability. That capability backed the merged uplink ingress ACL, where
the slave uplink's ingress-ACL root was pointed at the master's
(esw_set_uplink_slave_ingress_root()). That handling was removed in
commit 82e86a6c7109 ("net/mlx5: E-switch, remove special uplink ingress
ACL handling") once both uplinks were tagged with the same reserved
metadata (MLX5_ESW_METADATA_RSVD_UPLINK) - a single FDB rule then
matches traffic from either uplink, with no shared ingress ACL involved.
The capability check was left behind and has been dead since: the driver
programs no shared ingress ACL, yet the check still keeps otherwise
shared-FDB-capable devices out of shared FDB. Drop it.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
index 6b4ad3c53f2f..c2185c3d7f6f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c
@@ -35,8 +35,7 @@ bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter)
if (is_mdev_switchdev_mode(dev0) &&
mlx5_eswitch_vport_match_metadata_enabled(dev0->priv.eswitch) &&
- mlx5_esw_offloads_devcom_is_ready(dev0->priv.eswitch) &&
- MLX5_CAP_ESW(dev0, esw_shared_ingress_acl))
+ mlx5_esw_offloads_devcom_is_ready(dev0->priv.eswitch))
ret = true;
return ret;
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 12/13] net/mlx5: E-switch, correct stale VF/PF wording in esw-allowed comments
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (10 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 11/13] net/mlx5: LAG, drop stale esw_shared_ingress_acl gate from shared FDB Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
2026-09-23 10:38 ` [PATCH net-next 13/13] net/mlx5: E-switch, disable host functions for a non PF e-switch manager Tariq Toukan
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_esw_hold() and mlx5_eswitch_unblock_ipsec() bail out on
!mlx5_esw_allowed(), and their comments explained that as "a VF has no
eswitch" / "core dev is not a PF". New FW will let a VF act as a nested
e-switch manager - such a VF has an eswitch and passes
mlx5_esw_allowed() - so that equivalence no longer holds. Reword the
comments to describe the actual condition, the device is not an e-switch
manager, with no functional change.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index e7561f0f89b0..6f3676c86d3d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -2958,7 +2958,7 @@ bool mlx5_esw_hold(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
- /* e.g. VF doesn't have eswitch so nothing to do */
+ /* Not an eswitch manager, so there is no mode lock to take */
if (!mlx5_esw_allowed(esw))
return true;
@@ -3106,7 +3106,7 @@ void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev)
struct mlx5_eswitch *esw = dev->priv.eswitch;
if (!mlx5_esw_allowed(esw))
- /* Failure means no eswitch => core dev is not a PF */
+ /* Not an eswitch manager, so nothing was blocked */
return;
mutex_lock(&esw->state_lock);
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH net-next 13/13] net/mlx5: E-switch, disable host functions for a non PF e-switch manager
2026-09-23 10:38 [PATCH net-next 00/13] net/mlx5: Preparations for nested E-switch Tariq Toukan
` (11 preceding siblings ...)
2026-09-23 10:38 ` [PATCH net-next 12/13] net/mlx5: E-switch, correct stale VF/PF wording in esw-allowed comments Tariq Toukan
@ 2026-09-23 10:38 ` Tariq Toukan
12 siblings, 0 replies; 14+ messages in thread
From: Tariq Toukan @ 2026-09-23 10:38 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
netdev, Paolo Abeni
Cc: Akiva Goldberger, Cosmin Ratiu, Gal Pressman, Leon Romanovsky,
open list, linux-rdma, Mark Bloch, Moshe Shemesh, Or Har-Toov,
Saeed Mahameed, Shay Drory, Tariq Toukan
From: Shay Drory <shayd@nvidia.com>
mlx5_esw_host_functions_enabled() only treated host functions as
disabled for an ECPF manager.
To support a non PF acting as an e-switch manager, add a check for a non
PF e-switch manager that treats host functions as disabled. This will
avoid allocating a host-PF vport in mlx5_esw_vports_init().
With host functions disabled for non PF, its e-switch is the expected
manager + uplink only.
Signed-off-by: Shay Drory <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Akiva Goldberger <agoldberger@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
index 6f3676c86d3d..2d289fb1353b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
@@ -1241,6 +1241,11 @@ static int mlx5_esw_host_functions_enabled_query(struct mlx5_eswitch *esw)
struct mlx5_esw_pf_info host_pf_info;
const u32 *query_host_out;
+ if (!mlx5_core_is_pf(esw->dev)) {
+ esw->esw_funcs.host_funcs_disabled = true;
+ return 0;
+ }
+
if (!mlx5_core_is_ecpf_esw_manager(esw->dev))
return 0;
--
2.44.0
^ permalink raw reply [flat|nested] 14+ messages in thread