[PATCH net-next 07/13] net/mlx5e: TC, anchor peer-flow reverse index on the duplicated flow
flat view
COOLING13d
IN NET-NEXT: 2 (0M)
From: Tariq Toukan <tariqt@nvidia.com>
Date: 2026-09-23 10:40:59
Also in:
linux-rdma, lkml
Subsystem:
mellanox ethernet driver (mlx5e), mellanox mlx5 core vpi driver, networking drivers, the rest · Maintainers:
Saeed Mahameed, Tariq Toukan, Mark Bloch, Leon Romanovsky, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
2 review trailers; queued in net-next as 675956237b38 on 2026-09-29.
From: Shay Drory <redacted> 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 <redacted> Reviewed-by: Moshe Shemesh <redacted> Reviewed-by: Akiva Goldberger <redacted> 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