Skip to content

Commit d156953

Browse files
Jianbo Liukuba-moo
authored andcommitted
net/mlx5e: Modify and restore TC rules for IPSec TX rules
After IPsec policy/state TX rules are added, any TC flow rule, which forwards packets to uplink, is modified to forward to IPsec TX tables. As these tables are destroyed dynamically, whenever there is no reference to them, the destinations of this kind of rules must be restored to uplink. There is a special case for packet encapsulation, as the packet_reformat_id in the extended destination is used to reformat packets, but only for the VPORT destination. To forward packet to IPsec table and do encapsulation in one FTE, move the packet_reformat_id to flow context, instead of using the extended destination. As a limitation, multiple encapsulations with table forwarding, and one together with other VPORT destinations, are not allowed, so add a check when offloading TC rules. TC rules are not allowed before IPsec TX rule is added, so only need to restore TC rules after flush IPSec TX rules. As they are saved in the vport_rep rhashtables, we walk all the rules in the rhashtables, and find TC rules with destinations pointing to IPsec tables, and modify them one by one. To avoid concurrent issue, this handling is done under the protection of eswitch mode_lock. Signed-off-by: Jianbo Liu <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]> Link: https://lore.kernel.org/r/7bcb2c7e2ecf0e0d06b095c8dcc6a37ea7f02faf.1690802064.git.leon@kernel.org Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 366e462 commit d156953

File tree

5 files changed

+154
-4
lines changed

5 files changed

+154
-4
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,10 @@ static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
755755

756756
mlx5_eswitch_unblock_mode_lock(ipsec->mdev);
757757

758-
if (tx == ipsec->tx_esw)
758+
if (tx == ipsec->tx_esw) {
759+
mlx5_esw_ipsec_restore_dest_uplink(ipsec->mdev);
759760
ipsec_esw_tx_ft_policy_set(ipsec->mdev, NULL);
761+
}
760762

761763
tx_destroy(ipsec, tx, ipsec->roce);
762764

drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include "eswitch.h"
66
#include "en_accel/ipsec.h"
77
#include "esw/ipsec_fs.h"
8+
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
9+
#include "en/tc_priv.h"
10+
#endif
811

912
enum {
1013
MLX5_ESW_IPSEC_RX_POL_FT_LEVEL,
@@ -267,3 +270,56 @@ void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
267270
attr->cnt_level = MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL;
268271
attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
269272
}
273+
274+
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
275+
static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw,
276+
struct mlx5e_tc_flow *flow)
277+
{
278+
struct mlx5_esw_flow_attr *esw_attr;
279+
struct mlx5_flow_attr *attr;
280+
int err;
281+
282+
attr = flow->attr;
283+
esw_attr = attr->esw_attr;
284+
if (esw_attr->out_count - esw_attr->split_count > 1)
285+
return 0;
286+
287+
err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr,
288+
esw_attr->out_count - 1);
289+
290+
return err;
291+
}
292+
#endif
293+
294+
void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
295+
{
296+
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
297+
struct mlx5_eswitch *esw = mdev->priv.eswitch;
298+
struct mlx5_eswitch_rep *rep;
299+
struct mlx5e_rep_priv *rpriv;
300+
struct rhashtable_iter iter;
301+
struct mlx5e_tc_flow *flow;
302+
unsigned long i;
303+
int err;
304+
305+
xa_for_each(&esw->offloads.vport_reps, i, rep) {
306+
rpriv = rep->rep_data[REP_ETH].priv;
307+
if (!rpriv || !rpriv->netdev)
308+
continue;
309+
310+
rhashtable_walk_enter(&rpriv->tc_ht, &iter);
311+
rhashtable_walk_start(&iter);
312+
while ((flow = rhashtable_walk_next(&iter)) != NULL) {
313+
if (IS_ERR(flow))
314+
continue;
315+
316+
err = mlx5_esw_ipsec_modify_flow_dests(esw, flow);
317+
if (err)
318+
mlx5_core_warn_once(mdev,
319+
"Faided to modify flow dests for IPsec");
320+
}
321+
rhashtable_walk_stop(&iter);
322+
rhashtable_walk_exit(&iter);
323+
}
324+
#endif
325+
}

drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
2424
u32 *ipsec_obj_id);
2525
void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
2626
struct mlx5e_ipsec_tx_create_attr *attr);
27+
void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev);
2728
#else
2829
static inline void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
2930
struct mlx5e_ipsec_rx *rx) {}
@@ -60,5 +61,7 @@ static inline int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv,
6061

6162
static inline void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
6263
struct mlx5e_ipsec_tx_create_attr *attr) {}
64+
65+
static inline void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev) {}
6366
#endif /* CONFIG_MLX5_ESWITCH */
6467
#endif /* __MLX5_ESW_IPSEC_FS_H__ */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,8 @@ mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw)
811811
return esw->fdb_table.offloads.slow_fdb;
812812
}
813813

814+
int mlx5_eswitch_restore_ipsec_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule,
815+
struct mlx5_esw_flow_attr *esw_attr, int attr_idx);
814816
#else /* CONFIG_MLX5_ESWITCH */
815817
/* eswitch API stubs */
816818
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }

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

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,10 +424,51 @@ esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 l
424424
mlx5_chains_put_table(chains, chain, prio, level);
425425
}
426426

427+
static bool esw_same_vhca_id(struct mlx5_core_dev *mdev1, struct mlx5_core_dev *mdev2)
428+
{
429+
return MLX5_CAP_GEN(mdev1, vhca_id) == MLX5_CAP_GEN(mdev2, vhca_id);
430+
}
431+
432+
static bool esw_setup_uplink_fwd_ipsec_needed(struct mlx5_eswitch *esw,
433+
struct mlx5_esw_flow_attr *esw_attr,
434+
int attr_idx)
435+
{
436+
if (esw->offloads.ft_ipsec_tx_pol &&
437+
esw_attr->dests[attr_idx].rep &&
438+
esw_attr->dests[attr_idx].rep->vport == MLX5_VPORT_UPLINK &&
439+
/* To be aligned with software, encryption is needed only for tunnel device */
440+
(esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) &&
441+
esw_attr->dests[attr_idx].rep != esw_attr->in_rep &&
442+
esw_same_vhca_id(esw_attr->dests[attr_idx].mdev, esw->dev))
443+
return true;
444+
445+
return false;
446+
}
447+
448+
static bool esw_flow_dests_fwd_ipsec_check(struct mlx5_eswitch *esw,
449+
struct mlx5_esw_flow_attr *esw_attr)
450+
{
451+
int i;
452+
453+
if (!esw->offloads.ft_ipsec_tx_pol)
454+
return true;
455+
456+
for (i = 0; i < esw_attr->split_count; i++)
457+
if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i))
458+
return false;
459+
460+
for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
461+
if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i) &&
462+
(esw_attr->out_count - esw_attr->split_count > 1))
463+
return false;
464+
465+
return true;
466+
}
467+
427468
static void
428-
esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
429-
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
430-
int attr_idx, int dest_idx, bool pkt_reformat)
469+
esw_setup_dest_fwd_vport(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
470+
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
471+
int attr_idx, int dest_idx, bool pkt_reformat)
431472
{
432473
dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
433474
dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport;
@@ -449,6 +490,33 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f
449490
}
450491
}
451492

493+
static void
494+
esw_setup_dest_fwd_ipsec(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
495+
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
496+
int attr_idx, int dest_idx, bool pkt_reformat)
497+
{
498+
dest[dest_idx].ft = esw->offloads.ft_ipsec_tx_pol;
499+
dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
500+
if (pkt_reformat &&
501+
esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) {
502+
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
503+
flow_act->pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
504+
}
505+
}
506+
507+
static void
508+
esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
509+
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
510+
int attr_idx, int dest_idx, bool pkt_reformat)
511+
{
512+
if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, attr_idx))
513+
esw_setup_dest_fwd_ipsec(dest, flow_act, esw, esw_attr,
514+
attr_idx, dest_idx, pkt_reformat);
515+
else
516+
esw_setup_dest_fwd_vport(dest, flow_act, esw, esw_attr,
517+
attr_idx, dest_idx, pkt_reformat);
518+
}
519+
452520
static int
453521
esw_setup_vport_dests(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
454522
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
@@ -575,6 +643,9 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
575643
if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
576644
return ERR_PTR(-EOPNOTSUPP);
577645

646+
if (!esw_flow_dests_fwd_ipsec_check(esw, esw_attr))
647+
return ERR_PTR(-EOPNOTSUPP);
648+
578649
dest = kcalloc(MLX5_MAX_FLOW_FWD_VPORTS + 1, sizeof(*dest), GFP_KERNEL);
579650
if (!dest)
580651
return ERR_PTR(-ENOMEM);
@@ -4374,3 +4445,19 @@ int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
43744445
mutex_unlock(&esw->state_lock);
43754446
return err;
43764447
}
4448+
4449+
int
4450+
mlx5_eswitch_restore_ipsec_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule,
4451+
struct mlx5_esw_flow_attr *esw_attr, int attr_idx)
4452+
{
4453+
struct mlx5_flow_destination new_dest = {};
4454+
struct mlx5_flow_destination old_dest = {};
4455+
4456+
if (!esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, attr_idx))
4457+
return 0;
4458+
4459+
esw_setup_dest_fwd_ipsec(&old_dest, NULL, esw, esw_attr, attr_idx, 0, false);
4460+
esw_setup_dest_fwd_vport(&new_dest, NULL, esw, esw_attr, attr_idx, 0, false);
4461+
4462+
return mlx5_modify_rule_destination(rule, &new_dest, &old_dest);
4463+
}

0 commit comments

Comments
 (0)