File Index
Files and directories
Sign in
FILE

ipsec_fs_roce.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/lib/ipsec_fs_roce.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
  3
  4#include "fs_core.h"
  5#include "fs_cmd.h"
  6#include "en.h"
  7#include "lib/ipsec_fs_roce.h"
  8#include "mlx5_core.h"
  9#include <linux/random.h>
 10
 11struct mlx5_ipsec_miss {
 12	struct mlx5_flow_group *group;
 13	struct mlx5_flow_handle *rule;
 14};
 15
 16struct mlx5_ipsec_rx_roce {
 17	struct mlx5_flow_group *g;
 18	struct mlx5_flow_table *ft;
 19	struct mlx5_flow_handle *rule;
 20	struct mlx5_ipsec_miss roce_miss;
 21	struct mlx5_flow_table *nic_master_ft;
 22	struct mlx5_flow_group *nic_master_group;
 23	struct mlx5_flow_handle *nic_master_rule;
 24	struct mlx5_flow_table *goto_alias_ft;
 25	u32 alias_id;
 26	char key[ACCESS_KEY_LEN];
 27
 28	struct mlx5_flow_table *ft_rdma;
 29	struct mlx5_flow_namespace *ns_rdma;
 30};
 31
 32struct mlx5_ipsec_tx_roce {
 33	struct mlx5_flow_group *g;
 34	struct mlx5_flow_table *ft;
 35	struct mlx5_flow_handle *rule;
 36	struct mlx5_flow_table *goto_alias_ft;
 37	u32 alias_id;
 38	char key[ACCESS_KEY_LEN];
 39	struct mlx5_flow_namespace *ns;
 40};
 41
 42struct mlx5_ipsec_fs {
 43	struct mlx5_ipsec_rx_roce ipv4_rx;
 44	struct mlx5_ipsec_rx_roce ipv6_rx;
 45	struct mlx5_ipsec_tx_roce tx;
 46	struct mlx5_devcom_comp_dev **devcom;
 47};
 48
 49static void ipsec_fs_roce_setup_udp_dport(struct mlx5_flow_spec *spec,
 50					  u16 dport)
 51{
 52	spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
 53	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
 54	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_UDP);
 55	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.udp_dport);
 56	MLX5_SET(fte_match_param, spec->match_value, outer_headers.udp_dport, dport);
 57}
 58
 59static bool ipsec_fs_create_alias_supported_one(struct mlx5_core_dev *mdev)
 60{
 61	u64 obj_allowed = MLX5_CAP_GEN_2_64(mdev, allowed_object_for_other_vhca_access);
 62	u32 obj_supp = MLX5_CAP_GEN_2(mdev, cross_vhca_object_to_object_supported);
 63
 64	if (!(obj_supp &
 65	    MLX5_CROSS_VHCA_OBJ_TO_OBJ_SUPPORTED_LOCAL_FLOW_TABLE_TO_REMOTE_FLOW_TABLE_MISS))
 66		return false;
 67
 68	if (!(obj_allowed & MLX5_ALLOWED_OBJ_FOR_OTHER_VHCA_ACCESS_FLOW_TABLE))
 69		return false;
 70
 71	return true;
 72}
 73
 74static bool ipsec_fs_create_alias_supported(struct mlx5_core_dev *mdev,
 75					    struct mlx5_core_dev *master_mdev)
 76{
 77	if (ipsec_fs_create_alias_supported_one(mdev) &&
 78	    ipsec_fs_create_alias_supported_one(master_mdev))
 79		return true;
 80
 81	return false;
 82}
 83
 84static int ipsec_fs_create_aliased_ft(struct mlx5_core_dev *ibv_owner,
 85				      struct mlx5_core_dev *ibv_allowed,
 86				      struct mlx5_flow_table *ft,
 87				      u32 *obj_id, char *alias_key, bool from_event)
 88{
 89	u32 aliased_object_id = (ft->type << FT_ID_FT_TYPE_OFFSET) | ft->id;
 90	u16 vhca_id_to_be_accessed = MLX5_CAP_GEN(ibv_owner, vhca_id);
 91	struct mlx5_cmd_allow_other_vhca_access_attr allow_attr = {};
 92	struct mlx5_cmd_alias_obj_create_attr alias_attr = {};
 93	int ret;
 94	int i;
 95
 96	if (!ipsec_fs_create_alias_supported(ibv_owner, ibv_allowed))
 97		return -EOPNOTSUPP;
 98
 99	for (i = 0; i < ACCESS_KEY_LEN; i++)
100		if (!from_event)
101			alias_key[i] = get_random_u64() & 0xFF;
102
103	memcpy(allow_attr.access_key, alias_key, ACCESS_KEY_LEN);
104	allow_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
105	allow_attr.obj_id = aliased_object_id;
106
107	if (!from_event) {
108		ret = mlx5_cmd_allow_other_vhca_access(ibv_owner, &allow_attr);
109		if (ret) {
110			mlx5_core_err(ibv_owner, "Failed to allow other vhca access err=%d\n",
111				      ret);
112			return ret;
113		}
114	}
115
116	memcpy(alias_attr.access_key, alias_key, ACCESS_KEY_LEN);
117	alias_attr.obj_id = aliased_object_id;
118	alias_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
119	alias_attr.vhca_id = vhca_id_to_be_accessed;
120	ret = mlx5_cmd_alias_obj_create(ibv_allowed, &alias_attr, obj_id);
121	if (ret) {
122		mlx5_core_err(ibv_allowed, "Failed to create alias object err=%d\n",
123			      ret);
124		return ret;
125	}
126
127	return 0;
128}
129
130static int
131ipsec_fs_roce_rx_rule_setup(struct mlx5_core_dev *mdev,
132			    struct mlx5_flow_destination *default_dst,
133			    struct mlx5_ipsec_rx_roce *roce)
134{
135	bool is_mpv_slave = mlx5_core_is_mp_slave(mdev);
136	struct mlx5_flow_destination dst = {};
137	MLX5_DECLARE_FLOW_ACT(flow_act);
138	struct mlx5_flow_handle *rule;
139	struct mlx5_flow_spec *spec;
140	int err = 0;
141
142	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
143	if (!spec)
144		return -ENOMEM;
145
146	ipsec_fs_roce_setup_udp_dport(spec, ROCE_V2_UDP_DPORT);
147
148	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
149	if (is_mpv_slave) {
150		dst.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
151		dst.ft = roce->goto_alias_ft;
152	} else {
153		dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
154		dst.ft = roce->ft_rdma;
155	}
156	rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, &dst, 1);
157	if (IS_ERR(rule)) {
158		err = PTR_ERR(rule);
159		mlx5_core_err(mdev, "Fail to add RX RoCE IPsec rule err=%d\n",
160			      err);
161		goto out;
162	}
163
164	roce->rule = rule;
165
166	memset(spec, 0, sizeof(*spec));
167	if (default_dst->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
168		flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
169	rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, default_dst, 1);
170	if (IS_ERR(rule)) {
171		err = PTR_ERR(rule);
172		mlx5_core_err(mdev, "Fail to add RX RoCE IPsec miss rule err=%d\n",
173			      err);
174		goto fail_add_default_rule;
175	}
176
177	roce->roce_miss.rule = rule;
178
179	if (!is_mpv_slave)
180		goto out;
181
182	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
183	if (default_dst->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
184		flow_act.flags &= ~FLOW_ACT_IGNORE_FLOW_LEVEL;
185	dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
186	dst.ft = roce->ft_rdma;
187	rule = mlx5_add_flow_rules(roce->nic_master_ft, NULL, &flow_act, &dst,
188				   1);
189	if (IS_ERR(rule)) {
190		err = PTR_ERR(rule);
191		mlx5_core_err(mdev, "Fail to add RX RoCE IPsec rule for alias err=%d\n",
192			      err);
193		goto fail_add_nic_master_rule;
194	}
195	roce->nic_master_rule = rule;
196
197	kvfree(spec);
198	return 0;
199
200fail_add_nic_master_rule:
201	mlx5_del_flow_rules(roce->roce_miss.rule);
202fail_add_default_rule:
203	mlx5_del_flow_rules(roce->rule);
204out:
205	kvfree(spec);
206	return err;
207}
208
209static int ipsec_fs_roce_tx_rule_setup(struct mlx5_core_dev *mdev,
210				       struct mlx5_ipsec_tx_roce *roce,
211				       struct mlx5_flow_table *pol_ft)
212{
213	struct mlx5_flow_destination dst = {};
214	MLX5_DECLARE_FLOW_ACT(flow_act);
215	struct mlx5_flow_handle *rule;
216	int err = 0;
217
218	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
219	dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
220	dst.ft = pol_ft;
221	rule = mlx5_add_flow_rules(roce->ft, NULL, &flow_act, &dst,
222				   1);
223	if (IS_ERR(rule)) {
224		err = PTR_ERR(rule);
225		mlx5_core_err(mdev, "Fail to add TX RoCE IPsec rule err=%d\n",
226			      err);
227		goto out;
228	}
229	roce->rule = rule;
230
231out:
232	return err;
233}
234
235static int ipsec_fs_roce_tx_mpv_rule_setup(struct mlx5_core_dev *mdev,
236					   struct mlx5_ipsec_tx_roce *roce,
237					   struct mlx5_flow_table *pol_ft)
238{
239	struct mlx5_flow_destination dst = {};
240	MLX5_DECLARE_FLOW_ACT(flow_act);
241	struct mlx5_flow_handle *rule;
242	struct mlx5_flow_spec *spec;
243	int err = 0;
244
245	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
246	if (!spec)
247		return -ENOMEM;
248
249	spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
250	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters.source_vhca_port);
251	MLX5_SET(fte_match_param, spec->match_value, misc_parameters.source_vhca_port,
252		 MLX5_CAP_GEN(mdev, native_port_num));
253
254	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
255	dst.type = MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE;
256	dst.ft = roce->goto_alias_ft;
257	rule = mlx5_add_flow_rules(roce->ft, spec, &flow_act, &dst, 1);
258	if (IS_ERR(rule)) {
259		err = PTR_ERR(rule);
260		mlx5_core_err(mdev, "Fail to add TX RoCE IPsec rule err=%d\n",
261			      err);
262		goto out;
263	}
264	roce->rule = rule;
265
266	/* No need for miss rule, since on miss we go to next PRIO, in which
267	 * if master is configured, he will catch the traffic to go to his
268	 * encryption table.
269	 */
270
271out:
272	kvfree(spec);
273	return err;
274}
275
276#define MLX5_TX_ROCE_GROUP_SIZE BIT(0)
277#define MLX5_IPSEC_RDMA_TX_FT_LEVEL 0
278#define MLX5_IPSEC_NIC_GOTO_ALIAS_FT_LEVEL 3 /* Since last used level in NIC ipsec is 2 */
279
280static int ipsec_fs_roce_tx_mpv_create_ft(struct mlx5_core_dev *mdev,
281					  struct mlx5_ipsec_tx_roce *roce,
282					  struct mlx5_flow_table *pol_ft,
283					  struct mlx5e_priv *peer_priv,
284					  bool from_event)
285{
286	struct mlx5_flow_namespace *roce_ns, *nic_ns;
287	struct mlx5_flow_table_attr ft_attr = {};
288	struct mlx5_flow_table next_ft;
289	struct mlx5_flow_table *ft;
290	int err;
291
292	roce_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_RDMA_TX_IPSEC);
293	if (!roce_ns)
294		return -EOPNOTSUPP;
295
296	nic_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC);
297	if (!nic_ns)
298		return -EOPNOTSUPP;
299
300	err = ipsec_fs_create_aliased_ft(mdev, peer_priv->mdev, pol_ft, &roce->alias_id, roce->key,
301					 from_event);
302	if (err)
303		return err;
304
305	next_ft.id = roce->alias_id;
306	ft_attr.max_fte = 1;
307	ft_attr.next_ft = &next_ft;
308	ft_attr.level = MLX5_IPSEC_NIC_GOTO_ALIAS_FT_LEVEL;
309	ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
310	ft = mlx5_create_flow_table(nic_ns, &ft_attr);
311	if (IS_ERR(ft)) {
312		err = PTR_ERR(ft);
313		mlx5_core_err(mdev, "Fail to create RoCE IPsec goto alias ft err=%d\n", err);
314		goto destroy_alias;
315	}
316
317	roce->goto_alias_ft = ft;
318
319	memset(&ft_attr, 0, sizeof(ft_attr));
320	ft_attr.max_fte = 1;
321	ft_attr.level = MLX5_IPSEC_RDMA_TX_FT_LEVEL;
322	ft = mlx5_create_flow_table(roce_ns, &ft_attr);
323	if (IS_ERR(ft)) {
324		err = PTR_ERR(ft);
325		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx ft err=%d\n", err);
326		goto destroy_alias_ft;
327	}
328
329	roce->ft = ft;
330
331	return 0;
332
333destroy_alias_ft:
334	mlx5_destroy_flow_table(roce->goto_alias_ft);
335destroy_alias:
336	mlx5_cmd_alias_obj_destroy(peer_priv->mdev, roce->alias_id,
337				   MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
338	return err;
339}
340
341static int ipsec_fs_roce_tx_mpv_create_group_rules(struct mlx5_core_dev *mdev,
342						   struct mlx5_ipsec_tx_roce *roce,
343						   struct mlx5_flow_table *pol_ft,
344						   u32 *in)
345{
346	struct mlx5_flow_group *g;
347	int ix = 0;
348	int err;
349	u8 *mc;
350
351	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
352	MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters.source_vhca_port);
353	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_MISC_PARAMETERS);
354
355	MLX5_SET_CFG(in, start_flow_index, ix);
356	ix += MLX5_TX_ROCE_GROUP_SIZE;
357	MLX5_SET_CFG(in, end_flow_index, ix - 1);
358	g = mlx5_create_flow_group(roce->ft, in);
359	if (IS_ERR(g)) {
360		err = PTR_ERR(g);
361		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx group err=%d\n", err);
362		return err;
363	}
364	roce->g = g;
365
366	err = ipsec_fs_roce_tx_mpv_rule_setup(mdev, roce, pol_ft);
367	if (err) {
368		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx rules err=%d\n", err);
369		goto destroy_group;
370	}
371
372	return 0;
373
374destroy_group:
375	mlx5_destroy_flow_group(roce->g);
376	return err;
377}
378
379static int ipsec_fs_roce_tx_mpv_create(struct mlx5_core_dev *mdev,
380				       struct mlx5_ipsec_fs *ipsec_roce,
381				       struct mlx5_flow_table *pol_ft,
382				       u32 *in, bool from_event)
383{
384	struct mlx5_devcom_comp_dev *tmp = NULL;
385	struct mlx5_ipsec_tx_roce *roce;
386	struct mlx5e_priv *peer_priv;
387	int err;
388
389	if (!mlx5_devcom_for_each_peer_begin(*ipsec_roce->devcom))
390		return -EOPNOTSUPP;
391
392	peer_priv = mlx5_devcom_get_next_peer_data(*ipsec_roce->devcom, &tmp);
393	if (!peer_priv || !peer_priv->ipsec) {
394		mlx5_core_err(mdev, "IPsec not supported on master device\n");
395		err = -EOPNOTSUPP;
396		goto release_peer;
397	}
398
399	roce = &ipsec_roce->tx;
400
401	err = ipsec_fs_roce_tx_mpv_create_ft(mdev, roce, pol_ft, peer_priv, from_event);
402	if (err) {
403		mlx5_core_err(mdev, "Fail to create RoCE IPsec tables err=%d\n", err);
404		goto release_peer;
405	}
406
407	err = ipsec_fs_roce_tx_mpv_create_group_rules(mdev, roce, pol_ft, in);
408	if (err) {
409		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx group/rule err=%d\n", err);
410		goto destroy_tables;
411	}
412
413	mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
414	return 0;
415
416destroy_tables:
417	mlx5_destroy_flow_table(roce->ft);
418	mlx5_destroy_flow_table(roce->goto_alias_ft);
419	mlx5_cmd_alias_obj_destroy(peer_priv->mdev, roce->alias_id,
420				   MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
421release_peer:
422	mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
423	return err;
424}
425
426static void roce_rx_mpv_destroy_tables(struct mlx5_core_dev *mdev, struct mlx5_ipsec_rx_roce *roce)
427{
428	mlx5_destroy_flow_table(roce->goto_alias_ft);
429	mlx5_cmd_alias_obj_destroy(mdev, roce->alias_id,
430				   MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
431	mlx5_destroy_flow_group(roce->nic_master_group);
432	mlx5_destroy_flow_table(roce->nic_master_ft);
433}
434
435#define MLX5_RX_ROCE_GROUP_SIZE BIT(0)
436#define MLX5_IPSEC_RX_IPV4_FT_LEVEL 3
437#define MLX5_IPSEC_RX_IPV6_FT_LEVEL 2
438
439static int ipsec_fs_roce_rx_mpv_create(struct mlx5_core_dev *mdev,
440				       struct mlx5_ipsec_fs *ipsec_roce,
441				       struct mlx5_flow_namespace *ns,
442				       u32 family, u32 level, u32 prio)
443{
444	struct mlx5_flow_namespace *roce_ns, *nic_ns;
445	struct mlx5_flow_table_attr ft_attr = {};
446	struct mlx5_devcom_comp_dev *tmp = NULL;
447	struct mlx5_ipsec_rx_roce *roce;
448	struct mlx5_flow_table next_ft;
449	struct mlx5_flow_table *ft;
450	struct mlx5_flow_group *g;
451	struct mlx5e_priv *peer_priv;
452	int ix = 0;
453	u32 *in;
454	int err;
455
456	roce = (family == AF_INET) ? &ipsec_roce->ipv4_rx :
457				     &ipsec_roce->ipv6_rx;
458
459	if (!mlx5_devcom_for_each_peer_begin(*ipsec_roce->devcom))
460		return -EOPNOTSUPP;
461
462	peer_priv = mlx5_devcom_get_next_peer_data(*ipsec_roce->devcom, &tmp);
463	if (!peer_priv || !peer_priv->ipsec) {
464		mlx5_core_err(mdev, "IPsec not supported on master device\n");
465		err = -EOPNOTSUPP;
466		goto release_peer;
467	}
468
469	roce_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_RDMA_RX_IPSEC);
470	if (!roce_ns) {
471		err = -EOPNOTSUPP;
472		goto release_peer;
473	}
474
475	nic_ns = mlx5_get_flow_namespace(peer_priv->mdev, MLX5_FLOW_NAMESPACE_KERNEL);
476	if (!nic_ns) {
477		err = -EOPNOTSUPP;
478		goto release_peer;
479	}
480
481	in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
482	if (!in) {
483		err = -ENOMEM;
484		goto release_peer;
485	}
486
487	ft_attr.level = (family == AF_INET) ? MLX5_IPSEC_RX_IPV4_FT_LEVEL :
488					      MLX5_IPSEC_RX_IPV6_FT_LEVEL;
489	ft_attr.max_fte = 1;
490	ft = mlx5_create_flow_table(roce_ns, &ft_attr);
491	if (IS_ERR(ft)) {
492		err = PTR_ERR(ft);
493		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at rdma master err=%d\n", err);
494		goto free_in;
495	}
496
497	roce->ft_rdma = ft;
498
499	ft_attr.max_fte = 1;
500	ft_attr.prio = prio;
501	ft_attr.level = level + 2;
502	ft = mlx5_create_flow_table(nic_ns, &ft_attr);
503	if (IS_ERR(ft)) {
504		err = PTR_ERR(ft);
505		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at NIC master err=%d\n", err);
506		goto destroy_ft_rdma;
507	}
508	roce->nic_master_ft = ft;
509
510	MLX5_SET_CFG(in, start_flow_index, ix);
511	ix += 1;
512	MLX5_SET_CFG(in, end_flow_index, ix - 1);
513	g = mlx5_create_flow_group(roce->nic_master_ft, in);
514	if (IS_ERR(g)) {
515		err = PTR_ERR(g);
516		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx group aliased err=%d\n", err);
517		goto destroy_nic_master_ft;
518	}
519	roce->nic_master_group = g;
520
521	err = ipsec_fs_create_aliased_ft(peer_priv->mdev, mdev, roce->nic_master_ft,
522					 &roce->alias_id, roce->key, false);
523	if (err) {
524		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx alias FT err=%d\n", err);
525		goto destroy_group;
526	}
527
528	next_ft.id = roce->alias_id;
529	ft_attr.max_fte = 1;
530	ft_attr.prio = prio;
531	ft_attr.level = roce->ft->level + 1;
532	ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
533	ft_attr.next_ft = &next_ft;
534	ft = mlx5_create_flow_table(ns, &ft_attr);
535	if (IS_ERR(ft)) {
536		err = PTR_ERR(ft);
537		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at NIC slave err=%d\n", err);
538		goto destroy_alias;
539	}
540	roce->goto_alias_ft = ft;
541
542	kvfree(in);
543	mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
544	return 0;
545
546destroy_alias:
547	mlx5_cmd_alias_obj_destroy(mdev, roce->alias_id,
548				   MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
549destroy_group:
550	mlx5_destroy_flow_group(roce->nic_master_group);
551destroy_nic_master_ft:
552	mlx5_destroy_flow_table(roce->nic_master_ft);
553destroy_ft_rdma:
554	mlx5_destroy_flow_table(roce->ft_rdma);
555free_in:
556	kvfree(in);
557release_peer:
558	mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
559	return err;
560}
561
562void mlx5_ipsec_fs_roce_tx_destroy(struct mlx5_ipsec_fs *ipsec_roce,
563				   struct mlx5_core_dev *mdev)
564{
565	struct mlx5_devcom_comp_dev *tmp = NULL;
566	struct mlx5_ipsec_tx_roce *tx_roce;
567	struct mlx5e_priv *peer_priv;
568
569	if (!ipsec_roce)
570		return;
571
572	tx_roce = &ipsec_roce->tx;
573
574	if (!tx_roce->ft)
575		return; /* Incase RoCE was cleaned from MPV event flow */
576
577	mlx5_del_flow_rules(tx_roce->rule);
578	mlx5_destroy_flow_group(tx_roce->g);
579	mlx5_destroy_flow_table(tx_roce->ft);
580
581	if (!mlx5_core_is_mp_slave(mdev))
582		return;
583
584	if (!mlx5_devcom_for_each_peer_begin(*ipsec_roce->devcom))
585		return;
586
587	peer_priv = mlx5_devcom_get_next_peer_data(*ipsec_roce->devcom, &tmp);
588	if (!peer_priv) {
589		mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
590		return;
591	}
592
593	mlx5_destroy_flow_table(tx_roce->goto_alias_ft);
594	mlx5_cmd_alias_obj_destroy(peer_priv->mdev, tx_roce->alias_id,
595				   MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
596	mlx5_devcom_for_each_peer_end(*ipsec_roce->devcom);
597	tx_roce->ft = NULL;
598}
599
600int mlx5_ipsec_fs_roce_tx_create(struct mlx5_core_dev *mdev,
601				 struct mlx5_ipsec_fs *ipsec_roce,
602				 struct mlx5_flow_table *pol_ft,
603				 bool from_event)
604{
605	struct mlx5_flow_table_attr ft_attr = {};
606	struct mlx5_ipsec_tx_roce *roce;
607	struct mlx5_flow_table *ft;
608	struct mlx5_flow_group *g;
609	int ix = 0;
610	int err;
611	u32 *in;
612
613	if (!ipsec_roce)
614		return 0;
615
616	roce = &ipsec_roce->tx;
617
618	in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
619	if (!in)
620		return -ENOMEM;
621
622	if (mlx5_core_is_mp_slave(mdev)) {
623		err = ipsec_fs_roce_tx_mpv_create(mdev, ipsec_roce, pol_ft, in, from_event);
624		goto free_in;
625	}
626
627	ft_attr.max_fte = 1;
628	ft_attr.prio = 1;
629	ft_attr.level = MLX5_IPSEC_RDMA_TX_FT_LEVEL;
630	ft = mlx5_create_flow_table(roce->ns, &ft_attr);
631	if (IS_ERR(ft)) {
632		err = PTR_ERR(ft);
633		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx ft err=%d\n", err);
634		goto free_in;
635	}
636
637	roce->ft = ft;
638
639	MLX5_SET_CFG(in, start_flow_index, ix);
640	ix += MLX5_TX_ROCE_GROUP_SIZE;
641	MLX5_SET_CFG(in, end_flow_index, ix - 1);
642	g = mlx5_create_flow_group(ft, in);
643	if (IS_ERR(g)) {
644		err = PTR_ERR(g);
645		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx group err=%d\n", err);
646		goto destroy_table;
647	}
648	roce->g = g;
649
650	err = ipsec_fs_roce_tx_rule_setup(mdev, roce, pol_ft);
651	if (err) {
652		mlx5_core_err(mdev, "Fail to create RoCE IPsec tx rules err=%d\n", err);
653		goto destroy_group;
654	}
655
656	kvfree(in);
657	return 0;
658
659destroy_group:
660	mlx5_destroy_flow_group(roce->g);
661destroy_table:
662	mlx5_destroy_flow_table(ft);
663free_in:
664	kvfree(in);
665	return err;
666}
667
668struct mlx5_flow_table *mlx5_ipsec_fs_roce_ft_get(struct mlx5_ipsec_fs *ipsec_roce, u32 family)
669{
670	struct mlx5_ipsec_rx_roce *rx_roce;
671
672	if (!ipsec_roce)
673		return NULL;
674
675	rx_roce = (family == AF_INET) ? &ipsec_roce->ipv4_rx :
676					&ipsec_roce->ipv6_rx;
677
678	return rx_roce->ft;
679}
680
681void mlx5_ipsec_fs_roce_rx_destroy(struct mlx5_ipsec_fs *ipsec_roce, u32 family,
682				   struct mlx5_core_dev *mdev)
683{
684	bool is_mpv_slave = mlx5_core_is_mp_slave(mdev);
685	struct mlx5_ipsec_rx_roce *rx_roce;
686
687	if (!ipsec_roce)
688		return;
689
690	rx_roce = (family == AF_INET) ? &ipsec_roce->ipv4_rx :
691					&ipsec_roce->ipv6_rx;
692	if (!rx_roce->ft)
693		return; /* Incase RoCE was cleaned from MPV event flow */
694
695	if (is_mpv_slave)
696		mlx5_del_flow_rules(rx_roce->nic_master_rule);
697	mlx5_del_flow_rules(rx_roce->roce_miss.rule);
698	mlx5_del_flow_rules(rx_roce->rule);
699	if (is_mpv_slave)
700		roce_rx_mpv_destroy_tables(mdev, rx_roce);
701	mlx5_destroy_flow_table(rx_roce->ft_rdma);
702	mlx5_destroy_flow_group(rx_roce->roce_miss.group);
703	mlx5_destroy_flow_group(rx_roce->g);
704	mlx5_destroy_flow_table(rx_roce->ft);
705	rx_roce->ft = NULL;
706}
707
708int mlx5_ipsec_fs_roce_rx_create(struct mlx5_core_dev *mdev,
709				 struct mlx5_ipsec_fs *ipsec_roce,
710				 struct mlx5_flow_namespace *ns,
711				 struct mlx5_flow_destination *default_dst,
712				 u32 family, u32 level, u32 prio)
713{
714	bool is_mpv_slave = mlx5_core_is_mp_slave(mdev);
715	struct mlx5_flow_table_attr ft_attr = {};
716	struct mlx5_ipsec_rx_roce *roce;
717	struct mlx5_flow_table *ft;
718	struct mlx5_flow_group *g;
719	void *outer_headers_c;
720	int ix = 0;
721	u32 *in;
722	int err;
723	u8 *mc;
724
725	if (!ipsec_roce)
726		return 0;
727
728	roce = (family == AF_INET) ? &ipsec_roce->ipv4_rx :
729				     &ipsec_roce->ipv6_rx;
730
731	ft_attr.max_fte = 2;
732	ft_attr.level = level;
733	ft_attr.prio = prio;
734	ft = mlx5_create_flow_table(ns, &ft_attr);
735	if (IS_ERR(ft)) {
736		err = PTR_ERR(ft);
737		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx ft at nic err=%d\n", err);
738		return err;
739	}
740
741	roce->ft = ft;
742
743	in = kvzalloc(MLX5_ST_SZ_BYTES(create_flow_group_in), GFP_KERNEL);
744	if (!in) {
745		err = -ENOMEM;
746		goto fail_nomem;
747	}
748
749	mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
750	outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
751	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
752	MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
753
754	MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
755	MLX5_SET_CFG(in, start_flow_index, ix);
756	ix += MLX5_RX_ROCE_GROUP_SIZE;
757	MLX5_SET_CFG(in, end_flow_index, ix - 1);
758	g = mlx5_create_flow_group(ft, in);
759	if (IS_ERR(g)) {
760		err = PTR_ERR(g);
761		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx group at nic err=%d\n", err);
762		goto fail_group;
763	}
764	roce->g = g;
765
766	memset(in, 0, MLX5_ST_SZ_BYTES(create_flow_group_in));
767	MLX5_SET_CFG(in, start_flow_index, ix);
768	ix += MLX5_RX_ROCE_GROUP_SIZE;
769	MLX5_SET_CFG(in, end_flow_index, ix - 1);
770	g = mlx5_create_flow_group(ft, in);
771	if (IS_ERR(g)) {
772		err = PTR_ERR(g);
773		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx miss group at nic err=%d\n", err);
774		goto fail_mgroup;
775	}
776	roce->roce_miss.group = g;
777
778	if (is_mpv_slave) {
779		err = ipsec_fs_roce_rx_mpv_create(mdev, ipsec_roce, ns, family, level, prio);
780		if (err) {
781			mlx5_core_err(mdev, "Fail to create RoCE IPsec rx alias err=%d\n", err);
782			goto fail_mpv_create;
783		}
784	} else {
785		memset(&ft_attr, 0, sizeof(ft_attr));
786		if (family == AF_INET)
787			ft_attr.level = 1;
788		ft_attr.max_fte = 1;
789		ft = mlx5_create_flow_table(roce->ns_rdma, &ft_attr);
790		if (IS_ERR(ft)) {
791			err = PTR_ERR(ft);
792			mlx5_core_err(mdev,
793				      "Fail to create RoCE IPsec rx ft at rdma err=%d\n", err);
794			goto fail_rdma_table;
795		}
796
797		roce->ft_rdma = ft;
798	}
799
800	err = ipsec_fs_roce_rx_rule_setup(mdev, default_dst, roce);
801	if (err) {
802		mlx5_core_err(mdev, "Fail to create RoCE IPsec rx rules err=%d\n", err);
803		goto fail_setup_rule;
804	}
805
806	kvfree(in);
807	return 0;
808
809fail_setup_rule:
810	if (is_mpv_slave)
811		roce_rx_mpv_destroy_tables(mdev, roce);
812	mlx5_destroy_flow_table(roce->ft_rdma);
813fail_mpv_create:
814fail_rdma_table:
815	mlx5_destroy_flow_group(roce->roce_miss.group);
816fail_mgroup:
817	mlx5_destroy_flow_group(roce->g);
818fail_group:
819	kvfree(in);
820fail_nomem:
821	mlx5_destroy_flow_table(roce->ft);
822	return err;
823}
824
825bool mlx5_ipsec_fs_is_mpv_roce_supported(struct mlx5_core_dev *mdev)
826{
827	if (!mlx5_core_mp_enabled(mdev))
828		return true;
829
830	if (ipsec_fs_create_alias_supported_one(mdev))
831		return true;
832
833	return false;
834}
835
836void mlx5_ipsec_fs_roce_cleanup(struct mlx5_ipsec_fs *ipsec_roce)
837{
838	kfree(ipsec_roce);
839}
840
841struct mlx5_ipsec_fs *mlx5_ipsec_fs_roce_init(struct mlx5_core_dev *mdev,
842					      struct mlx5_devcom_comp_dev **devcom)
843{
844	struct mlx5_ipsec_fs *roce_ipsec;
845	struct mlx5_flow_namespace *ns;
846
847	ns = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_RDMA_RX_IPSEC);
848	if (!ns) {
849		mlx5_core_err(mdev, "Failed to get RoCE rx ns\n");
850		return NULL;
851	}
852
853	roce_ipsec = kzalloc(sizeof(*roce_ipsec), GFP_KERNEL);
854	if (!roce_ipsec)
855		return NULL;
856
857	roce_ipsec->ipv4_rx.ns_rdma = ns;
858	roce_ipsec->ipv6_rx.ns_rdma = ns;
859
860	ns = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_RDMA_TX_IPSEC);
861	if (!ns) {
862		mlx5_core_err(mdev, "Failed to get RoCE tx ns\n");
863		goto err_tx;
864	}
865
866	roce_ipsec->tx.ns = ns;
867
868	roce_ipsec->devcom = devcom;
869
870	return roce_ipsec;
871
872err_tx:
873	kfree(roce_ipsec);
874	return NULL;
875}
~/ Read-only file preview.