Skip to content

Commit 2a1f176

Browse files
w1ldptrSaeed Mahameed
authored and
Saeed Mahameed
committed
net/mlx5e: Refactor neigh update for concurrent execution
In order to remove dependency on rtnl lock and allow neigh update workqueue task to execute concurrently with tc, refactor mlx5e_rep_neigh_update() for concurrent execution: - Lock encap table when accessing encap entry to prevent concurrent changes. To do this properly, the initial encap state check is moved from mlx5e_rep_neigh_update() into mlx5e_rep_update_flows() to be performed under encap_tbl_lock protection. - Wait for encap to be fully initialized before accessing it by means of 'res_ready' completion. - Add mlx5e_take_all_encap_flows() helper which is used to construct a temporary list of flows and efi indexes that is used to access current encap data in flow which can be attached to multiple encaps simultaneously. Release the flows from temporary list after encap_tbl_lock critical section. This is necessary because mlx5e_flow_put() can't be called while holding encap_tbl_lock. - Modify mlx5e_tc_encap_flows_add() and mlx5e_tc_encap_flows_del() to work with user-provided list of flows built by mlx5e_take_all_encap_flows(), instead of traversing encap flow list directly. This is first step in complex neigh update refactoring, which is finished by following commit in this series. Signed-off-by: Vlad Buslov <[email protected]> Reviewed-by: Roi Dayan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 6a06c2f commit 2a1f176

File tree

3 files changed

+59
-38
lines changed

3 files changed

+59
-38
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_rep.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -595,12 +595,26 @@ static void mlx5e_rep_update_flows(struct mlx5e_priv *priv,
595595
unsigned char ha[ETH_ALEN])
596596
{
597597
struct ethhdr *eth = (struct ethhdr *)e->encap_header;
598+
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
599+
bool encap_connected;
600+
LIST_HEAD(flow_list);
598601

599602
ASSERT_RTNL();
600603

604+
/* wait for encap to be fully initialized */
605+
wait_for_completion(&e->res_ready);
606+
607+
mutex_lock(&esw->offloads.encap_tbl_lock);
608+
encap_connected = !!(e->flags & MLX5_ENCAP_ENTRY_VALID);
609+
if (e->compl_result || (encap_connected == neigh_connected &&
610+
ether_addr_equal(e->h_dest, ha)))
611+
goto unlock;
612+
613+
mlx5e_take_all_encap_flows(e, &flow_list);
614+
601615
if ((e->flags & MLX5_ENCAP_ENTRY_VALID) &&
602616
(!neigh_connected || !ether_addr_equal(e->h_dest, ha)))
603-
mlx5e_tc_encap_flows_del(priv, e);
617+
mlx5e_tc_encap_flows_del(priv, e, &flow_list);
604618

605619
if (neigh_connected && !(e->flags & MLX5_ENCAP_ENTRY_VALID)) {
606620
ether_addr_copy(e->h_dest, ha);
@@ -610,8 +624,11 @@ static void mlx5e_rep_update_flows(struct mlx5e_priv *priv,
610624
*/
611625
ether_addr_copy(eth->h_source, e->route_dev->dev_addr);
612626

613-
mlx5e_tc_encap_flows_add(priv, e);
627+
mlx5e_tc_encap_flows_add(priv, e, &flow_list);
614628
}
629+
unlock:
630+
mutex_unlock(&esw->offloads.encap_tbl_lock);
631+
mlx5e_put_encap_flow_list(priv, &flow_list);
615632
}
616633

617634
static void mlx5e_rep_neigh_update(struct work_struct *work)
@@ -623,7 +640,6 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
623640
unsigned char ha[ETH_ALEN];
624641
struct mlx5e_priv *priv;
625642
bool neigh_connected;
626-
bool encap_connected;
627643
u8 nud_state, dead;
628644

629645
rtnl_lock();
@@ -645,13 +661,8 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
645661
if (!mlx5e_encap_take(e))
646662
continue;
647663

648-
encap_connected = !!(e->flags & MLX5_ENCAP_ENTRY_VALID);
649664
priv = netdev_priv(e->out_dev);
650-
651-
if (encap_connected != neigh_connected ||
652-
!ether_addr_equal(e->h_dest, ha))
653-
mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
654-
665+
mlx5e_rep_update_flows(priv, e, neigh_connected, ha);
655666
mlx5e_encap_put(priv, e);
656667
}
657668
mlx5e_rep_neigh_entry_release(nhe);

drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct mlx5e_tc_flow {
126126
struct list_head hairpin; /* flows sharing the same hairpin */
127127
struct list_head peer; /* flows with peer flow */
128128
struct list_head unready; /* flows not ready to be offloaded (e.g due to missing route) */
129+
int tmp_efi_index;
129130
struct list_head tmp_list; /* temporary flow list used by neigh update */
130131
refcount_t refcnt;
131132
struct rcu_head rcu_head;
@@ -1291,11 +1292,11 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
12911292
}
12921293

12931294
void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
1294-
struct mlx5e_encap_entry *e)
1295+
struct mlx5e_encap_entry *e,
1296+
struct list_head *flow_list)
12951297
{
12961298
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
12971299
struct mlx5_esw_flow_attr slow_attr, *esw_attr;
1298-
struct encap_flow_item *efi, *tmp;
12991300
struct mlx5_flow_handle *rule;
13001301
struct mlx5_flow_spec *spec;
13011302
struct mlx5e_tc_flow *flow;
@@ -1314,19 +1315,15 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
13141315
e->flags |= MLX5_ENCAP_ENTRY_VALID;
13151316
mlx5e_rep_queue_neigh_stats_work(priv);
13161317

1317-
list_for_each_entry_safe(efi, tmp, &e->flows, list) {
1318+
list_for_each_entry(flow, flow_list, tmp_list) {
13181319
bool all_flow_encaps_valid = true;
13191320
int i;
13201321

1321-
flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
1322-
if (IS_ERR(mlx5e_flow_get(flow)))
1323-
continue;
1324-
13251322
esw_attr = flow->esw_attr;
13261323
spec = &esw_attr->parse_attr->spec;
13271324

1328-
esw_attr->dests[efi->index].encap_id = e->encap_id;
1329-
esw_attr->dests[efi->index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
1325+
esw_attr->dests[flow->tmp_efi_index].encap_id = e->encap_id;
1326+
esw_attr->dests[flow->tmp_efi_index].flags |= MLX5_ESW_DEST_ENCAP_VALID;
13301327
/* Flow can be associated with multiple encap entries.
13311328
* Before offloading the flow verify that all of them have
13321329
* a valid neighbour.
@@ -1341,63 +1338,53 @@ void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
13411338
}
13421339
/* Do not offload flows with unresolved neighbors */
13431340
if (!all_flow_encaps_valid)
1344-
goto loop_cont;
1341+
continue;
13451342
/* update from slow path rule to encap rule */
13461343
rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, esw_attr);
13471344
if (IS_ERR(rule)) {
13481345
err = PTR_ERR(rule);
13491346
mlx5_core_warn(priv->mdev, "Failed to update cached encapsulation flow, %d\n",
13501347
err);
1351-
goto loop_cont;
1348+
continue;
13521349
}
13531350

13541351
mlx5e_tc_unoffload_from_slow_path(esw, flow, &slow_attr);
13551352
flow->rule[0] = rule;
13561353
/* was unset when slow path rule removed */
13571354
flow_flag_set(flow, OFFLOADED);
1358-
1359-
loop_cont:
1360-
mlx5e_flow_put(priv, flow);
13611355
}
13621356
}
13631357

13641358
void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
1365-
struct mlx5e_encap_entry *e)
1359+
struct mlx5e_encap_entry *e,
1360+
struct list_head *flow_list)
13661361
{
13671362
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
13681363
struct mlx5_esw_flow_attr slow_attr;
1369-
struct encap_flow_item *efi, *tmp;
13701364
struct mlx5_flow_handle *rule;
13711365
struct mlx5_flow_spec *spec;
13721366
struct mlx5e_tc_flow *flow;
13731367
int err;
13741368

1375-
list_for_each_entry_safe(efi, tmp, &e->flows, list) {
1376-
flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
1377-
if (IS_ERR(mlx5e_flow_get(flow)))
1378-
continue;
1379-
1369+
list_for_each_entry(flow, flow_list, tmp_list) {
13801370
spec = &flow->esw_attr->parse_attr->spec;
13811371

13821372
/* update from encap rule to slow path rule */
13831373
rule = mlx5e_tc_offload_to_slow_path(esw, flow, spec, &slow_attr);
13841374
/* mark the flow's encap dest as non-valid */
1385-
flow->esw_attr->dests[efi->index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
1375+
flow->esw_attr->dests[flow->tmp_efi_index].flags &= ~MLX5_ESW_DEST_ENCAP_VALID;
13861376

13871377
if (IS_ERR(rule)) {
13881378
err = PTR_ERR(rule);
13891379
mlx5_core_warn(priv->mdev, "Failed to update slow path (encap) flow, %d\n",
13901380
err);
1391-
goto loop_cont;
1381+
continue;
13921382
}
13931383

13941384
mlx5e_tc_unoffload_fdb_rules(esw, flow, flow->esw_attr);
13951385
flow->rule[0] = rule;
13961386
/* was unset when fast path rule removed */
13971387
flow_flag_set(flow, OFFLOADED);
1398-
1399-
loop_cont:
1400-
mlx5e_flow_put(priv, flow);
14011388
}
14021389

14031390
/* we know that the encap is valid */
@@ -1413,8 +1400,26 @@ static struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow)
14131400
return flow->nic_attr->counter;
14141401
}
14151402

1403+
/* Takes reference to all flows attached to encap and adds the flows to
1404+
* flow_list using 'tmp_list' list_head in mlx5e_tc_flow.
1405+
*/
1406+
void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *flow_list)
1407+
{
1408+
struct encap_flow_item *efi;
1409+
struct mlx5e_tc_flow *flow;
1410+
1411+
list_for_each_entry(efi, &e->flows, list) {
1412+
flow = container_of(efi, struct mlx5e_tc_flow, encaps[efi->index]);
1413+
if (IS_ERR(mlx5e_flow_get(flow)))
1414+
continue;
1415+
1416+
flow->tmp_efi_index = efi->index;
1417+
list_add(&flow->tmp_list, flow_list);
1418+
}
1419+
}
1420+
14161421
/* Iterate over tmp_list of flows attached to flow_list head. */
1417-
static void mlx5e_put_encap_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list)
1422+
void mlx5e_put_encap_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list)
14181423
{
14191424
struct mlx5e_tc_flow *flow, *tmp;
14201425

drivers/net/ethernet/mellanox/mlx5/core/en_tc.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,17 @@ void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv,
7272

7373
struct mlx5e_encap_entry;
7474
void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
75-
struct mlx5e_encap_entry *e);
75+
struct mlx5e_encap_entry *e,
76+
struct list_head *flow_list);
7677
void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
77-
struct mlx5e_encap_entry *e);
78+
struct mlx5e_encap_entry *e,
79+
struct list_head *flow_list);
7880
bool mlx5e_encap_take(struct mlx5e_encap_entry *e);
7981
void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e);
8082

83+
void mlx5e_take_all_encap_flows(struct mlx5e_encap_entry *e, struct list_head *flow_list);
84+
void mlx5e_put_encap_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list);
85+
8186
struct mlx5e_neigh_hash_entry;
8287
void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe);
8388

0 commit comments

Comments
 (0)