11762f132SJianbo Liu // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
21762f132SJianbo Liu // Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
31762f132SJianbo Liu 
41762f132SJianbo Liu #include "fs_core.h"
51762f132SJianbo Liu #include "eswitch.h"
61762f132SJianbo Liu #include "en_accel/ipsec.h"
71762f132SJianbo Liu #include "esw/ipsec_fs.h"
8d1569537SJianbo Liu #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
9d1569537SJianbo Liu #include "en/tc_priv.h"
10d1569537SJianbo Liu #endif
111762f132SJianbo Liu 
121762f132SJianbo Liu enum {
131762f132SJianbo Liu 	MLX5_ESW_IPSEC_RX_POL_FT_LEVEL,
141762f132SJianbo Liu 	MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL,
151762f132SJianbo Liu 	MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL,
161762f132SJianbo Liu };
171762f132SJianbo Liu 
18c6c2bf5dSJianbo Liu enum {
19c6c2bf5dSJianbo Liu 	MLX5_ESW_IPSEC_TX_POL_FT_LEVEL,
20c6c2bf5dSJianbo Liu 	MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL,
21c6c2bf5dSJianbo Liu 	MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL,
22c6c2bf5dSJianbo Liu };
23c6c2bf5dSJianbo Liu 
mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec * ipsec,struct mlx5e_ipsec_rx_create_attr * attr)241762f132SJianbo Liu void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
251762f132SJianbo Liu 				       struct mlx5e_ipsec_rx_create_attr *attr)
261762f132SJianbo Liu {
271762f132SJianbo Liu 	attr->prio = FDB_CRYPTO_INGRESS;
281762f132SJianbo Liu 	attr->pol_level = MLX5_ESW_IPSEC_RX_POL_FT_LEVEL;
291762f132SJianbo Liu 	attr->sa_level = MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL;
301762f132SJianbo Liu 	attr->status_level = MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL;
311762f132SJianbo Liu 	attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
321762f132SJianbo Liu }
331762f132SJianbo Liu 
mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec * ipsec,struct mlx5_flow_destination * dest)341762f132SJianbo Liu int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
351762f132SJianbo Liu 					   struct mlx5_flow_destination *dest)
361762f132SJianbo Liu {
371762f132SJianbo Liu 	dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
381762f132SJianbo Liu 	dest->ft = mlx5_chains_get_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0);
391762f132SJianbo Liu 
401762f132SJianbo Liu 	return 0;
411762f132SJianbo Liu }
4291bafc63SJianbo Liu 
mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry * sa_entry,struct mlx5_flow_act * flow_act)4391bafc63SJianbo Liu int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
4491bafc63SJianbo Liu 					  struct mlx5_flow_act *flow_act)
4591bafc63SJianbo Liu {
4691bafc63SJianbo Liu 	u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
4791bafc63SJianbo Liu 	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
4891bafc63SJianbo Liu 	struct mlx5_core_dev *mdev = ipsec->mdev;
4991bafc63SJianbo Liu 	struct mlx5_modify_hdr *modify_hdr;
5091bafc63SJianbo Liu 	u32 mapped_id;
5191bafc63SJianbo Liu 	int err;
5291bafc63SJianbo Liu 
5391bafc63SJianbo Liu 	err = xa_alloc_bh(&ipsec->rx_esw->ipsec_obj_id_map, &mapped_id,
5491bafc63SJianbo Liu 			  xa_mk_value(sa_entry->ipsec_obj_id),
5591bafc63SJianbo Liu 			  XA_LIMIT(1, ESW_IPSEC_RX_MAPPED_ID_MASK), 0);
5691bafc63SJianbo Liu 	if (err)
5791bafc63SJianbo Liu 		return err;
5891bafc63SJianbo Liu 
5991bafc63SJianbo Liu 	/* reuse tunnel bits for ipsec,
6091bafc63SJianbo Liu 	 * tun_id is always 0 and tun_opts is mapped to ipsec_obj_id.
6191bafc63SJianbo Liu 	 */
6291bafc63SJianbo Liu 	MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
6391bafc63SJianbo Liu 	MLX5_SET(set_action_in, action, field,
6491bafc63SJianbo Liu 		 MLX5_ACTION_IN_FIELD_METADATA_REG_C_1);
6591bafc63SJianbo Liu 	MLX5_SET(set_action_in, action, offset, ESW_ZONE_ID_BITS);
6691bafc63SJianbo Liu 	MLX5_SET(set_action_in, action, length,
6791bafc63SJianbo Liu 		 ESW_TUN_ID_BITS + ESW_TUN_OPTS_BITS);
6891bafc63SJianbo Liu 	MLX5_SET(set_action_in, action, data, mapped_id);
6991bafc63SJianbo Liu 
7091bafc63SJianbo Liu 	modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_FDB,
7191bafc63SJianbo Liu 					      1, action);
7291bafc63SJianbo Liu 	if (IS_ERR(modify_hdr)) {
7391bafc63SJianbo Liu 		err = PTR_ERR(modify_hdr);
7491bafc63SJianbo Liu 		goto err_header_alloc;
7591bafc63SJianbo Liu 	}
7691bafc63SJianbo Liu 
7791bafc63SJianbo Liu 	sa_entry->rx_mapped_id = mapped_id;
7891bafc63SJianbo Liu 	flow_act->modify_hdr = modify_hdr;
7991bafc63SJianbo Liu 	flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
8091bafc63SJianbo Liu 
8191bafc63SJianbo Liu 	return 0;
8291bafc63SJianbo Liu 
8391bafc63SJianbo Liu err_header_alloc:
8491bafc63SJianbo Liu 	xa_erase_bh(&ipsec->rx_esw->ipsec_obj_id_map, mapped_id);
8591bafc63SJianbo Liu 	return err;
8691bafc63SJianbo Liu }
8791bafc63SJianbo Liu 
mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry * sa_entry)8891bafc63SJianbo Liu void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry)
8991bafc63SJianbo Liu {
9091bafc63SJianbo Liu 	struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
9191bafc63SJianbo Liu 
9291bafc63SJianbo Liu 	if (sa_entry->rx_mapped_id)
9391bafc63SJianbo Liu 		xa_erase_bh(&ipsec->rx_esw->ipsec_obj_id_map,
9491bafc63SJianbo Liu 			    sa_entry->rx_mapped_id);
9591bafc63SJianbo Liu }
9691bafc63SJianbo Liu 
mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv * priv,u32 id,u32 * ipsec_obj_id)9791bafc63SJianbo Liu int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
9891bafc63SJianbo Liu 					  u32 *ipsec_obj_id)
9991bafc63SJianbo Liu {
10091bafc63SJianbo Liu 	struct mlx5e_ipsec *ipsec = priv->ipsec;
10191bafc63SJianbo Liu 	void *val;
10291bafc63SJianbo Liu 
10391bafc63SJianbo Liu 	val = xa_load(&ipsec->rx_esw->ipsec_obj_id_map, id);
10491bafc63SJianbo Liu 	if (!val)
10591bafc63SJianbo Liu 		return -ENOENT;
10691bafc63SJianbo Liu 
10791bafc63SJianbo Liu 	*ipsec_obj_id = xa_to_value(val);
10891bafc63SJianbo Liu 
10991bafc63SJianbo Liu 	return 0;
11091bafc63SJianbo Liu }
111c6c2bf5dSJianbo Liu 
mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec * ipsec,struct mlx5e_ipsec_tx_create_attr * attr)112c6c2bf5dSJianbo Liu void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
113c6c2bf5dSJianbo Liu 				       struct mlx5e_ipsec_tx_create_attr *attr)
114c6c2bf5dSJianbo Liu {
115c6c2bf5dSJianbo Liu 	attr->prio = FDB_CRYPTO_EGRESS;
116c6c2bf5dSJianbo Liu 	attr->pol_level = MLX5_ESW_IPSEC_TX_POL_FT_LEVEL;
117c6c2bf5dSJianbo Liu 	attr->sa_level = MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL;
118c6c2bf5dSJianbo Liu 	attr->cnt_level = MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL;
119c6c2bf5dSJianbo Liu 	attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
120c6c2bf5dSJianbo Liu }
121d1569537SJianbo Liu 
122d1569537SJianbo Liu #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch * esw,struct mlx5e_tc_flow * flow)123d1569537SJianbo Liu static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw,
124d1569537SJianbo Liu 					    struct mlx5e_tc_flow *flow)
125d1569537SJianbo Liu {
126d1569537SJianbo Liu 	struct mlx5_esw_flow_attr *esw_attr;
127d1569537SJianbo Liu 	struct mlx5_flow_attr *attr;
128d1569537SJianbo Liu 	int err;
129d1569537SJianbo Liu 
130d1569537SJianbo Liu 	attr = flow->attr;
131d1569537SJianbo Liu 	esw_attr = attr->esw_attr;
132d1569537SJianbo Liu 	if (esw_attr->out_count - esw_attr->split_count > 1)
133d1569537SJianbo Liu 		return 0;
134d1569537SJianbo Liu 
135d1569537SJianbo Liu 	err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr,
136d1569537SJianbo Liu 					      esw_attr->out_count - 1);
137d1569537SJianbo Liu 
138d1569537SJianbo Liu 	return err;
139d1569537SJianbo Liu }
140d1569537SJianbo Liu #endif
141d1569537SJianbo Liu 
mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev * mdev)142d1569537SJianbo Liu void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
143d1569537SJianbo Liu {
144d1569537SJianbo Liu #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
145d1569537SJianbo Liu 	struct mlx5_eswitch *esw = mdev->priv.eswitch;
146d1569537SJianbo Liu 	struct mlx5_eswitch_rep *rep;
147d1569537SJianbo Liu 	struct mlx5e_rep_priv *rpriv;
148d1569537SJianbo Liu 	struct rhashtable_iter iter;
149d1569537SJianbo Liu 	struct mlx5e_tc_flow *flow;
150d1569537SJianbo Liu 	unsigned long i;
151d1569537SJianbo Liu 	int err;
152d1569537SJianbo Liu 
153d1569537SJianbo Liu 	xa_for_each(&esw->offloads.vport_reps, i, rep) {
154d1569537SJianbo Liu 		rpriv = rep->rep_data[REP_ETH].priv;
155*ba888f1fSSaeed Mahameed 		if (!rpriv || !rpriv->netdev)
156d1569537SJianbo Liu 			continue;
157d1569537SJianbo Liu 
158d1569537SJianbo Liu 		rhashtable_walk_enter(&rpriv->tc_ht, &iter);
159d1569537SJianbo Liu 		rhashtable_walk_start(&iter);
160d1569537SJianbo Liu 		while ((flow = rhashtable_walk_next(&iter)) != NULL) {
161d1569537SJianbo Liu 			if (IS_ERR(flow))
162d1569537SJianbo Liu 				continue;
163d1569537SJianbo Liu 
164d1569537SJianbo Liu 			err = mlx5_esw_ipsec_modify_flow_dests(esw, flow);
165d1569537SJianbo Liu 			if (err)
166d1569537SJianbo Liu 				mlx5_core_warn_once(mdev,
167d7cea02aSColin Ian King 						    "Failed to modify flow dests for IPsec");
168d1569537SJianbo Liu 		}
169d1569537SJianbo Liu 		rhashtable_walk_stop(&iter);
170d1569537SJianbo Liu 		rhashtable_walk_exit(&iter);
171d1569537SJianbo Liu 	}
172d1569537SJianbo Liu #endif
173d1569537SJianbo Liu }
174