1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */
3 
4 #include <linux/netdevice.h>
5 #include "en.h"
6 #include "en/fs.h"
7 #include "ipsec.h"
8 #include "fs_core.h"
9 
10 #define NUM_IPSEC_FTE BIT(15)
11 
12 enum accel_fs_esp_type {
13 	ACCEL_FS_ESP4,
14 	ACCEL_FS_ESP6,
15 	ACCEL_FS_ESP_NUM_TYPES,
16 };
17 
18 struct mlx5e_ipsec_rx_err {
19 	struct mlx5_flow_table *ft;
20 	struct mlx5_flow_handle *rule;
21 	struct mlx5_modify_hdr *copy_modify_hdr;
22 };
23 
24 struct mlx5e_accel_fs_esp_prot {
25 	struct mlx5_flow_table *ft;
26 	struct mlx5_flow_group *miss_group;
27 	struct mlx5_flow_handle *miss_rule;
28 	struct mlx5_flow_destination default_dest;
29 	struct mlx5e_ipsec_rx_err rx_err;
30 	u32 refcnt;
31 	struct mutex prot_mutex; /* protect ESP4/ESP6 protocol */
32 };
33 
34 struct mlx5e_accel_fs_esp {
35 	struct mlx5e_accel_fs_esp_prot fs_prot[ACCEL_FS_ESP_NUM_TYPES];
36 };
37 
38 struct mlx5e_ipsec_tx {
39 	struct mlx5_flow_namespace *ns;
40 	struct mlx5_flow_table *ft;
41 	struct mutex mutex; /* Protect IPsec TX steering */
42 	u32 refcnt;
43 };
44 
45 /* IPsec RX flow steering */
46 static enum mlx5_traffic_types fs_esp2tt(enum accel_fs_esp_type i)
47 {
48 	if (i == ACCEL_FS_ESP4)
49 		return MLX5_TT_IPV4_IPSEC_ESP;
50 	return MLX5_TT_IPV6_IPSEC_ESP;
51 }
52 
53 static int rx_err_add_rule(struct mlx5e_priv *priv,
54 			   struct mlx5e_accel_fs_esp_prot *fs_prot,
55 			   struct mlx5e_ipsec_rx_err *rx_err)
56 {
57 	u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
58 	struct mlx5_core_dev *mdev = priv->mdev;
59 	struct mlx5_flow_act flow_act = {};
60 	struct mlx5_modify_hdr *modify_hdr;
61 	struct mlx5_flow_handle *fte;
62 	struct mlx5_flow_spec *spec;
63 	int err;
64 
65 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
66 	if (!spec)
67 		return -ENOMEM;
68 
69 	/* Action to copy 7 bit ipsec_syndrome to regB[24:30] */
70 	MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
71 	MLX5_SET(copy_action_in, action, src_field, MLX5_ACTION_IN_FIELD_IPSEC_SYNDROME);
72 	MLX5_SET(copy_action_in, action, src_offset, 0);
73 	MLX5_SET(copy_action_in, action, length, 7);
74 	MLX5_SET(copy_action_in, action, dst_field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
75 	MLX5_SET(copy_action_in, action, dst_offset, 24);
76 
77 	modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,
78 					      1, action);
79 
80 	if (IS_ERR(modify_hdr)) {
81 		err = PTR_ERR(modify_hdr);
82 		netdev_err(priv->netdev,
83 			   "fail to alloc ipsec copy modify_header_id err=%d\n", err);
84 		goto out_spec;
85 	}
86 
87 	/* create fte */
88 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
89 			  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
90 	flow_act.modify_hdr = modify_hdr;
91 	fte = mlx5_add_flow_rules(rx_err->ft, spec, &flow_act,
92 				  &fs_prot->default_dest, 1);
93 	if (IS_ERR(fte)) {
94 		err = PTR_ERR(fte);
95 		netdev_err(priv->netdev, "fail to add ipsec rx err copy rule err=%d\n", err);
96 		goto out;
97 	}
98 
99 	kvfree(spec);
100 	rx_err->rule = fte;
101 	rx_err->copy_modify_hdr = modify_hdr;
102 	return 0;
103 
104 out:
105 	mlx5_modify_header_dealloc(mdev, modify_hdr);
106 out_spec:
107 	kvfree(spec);
108 	return err;
109 }
110 
111 static int rx_fs_create(struct mlx5e_priv *priv,
112 			struct mlx5e_accel_fs_esp_prot *fs_prot)
113 {
114 	int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
115 	struct mlx5_flow_table *ft = fs_prot->ft;
116 	struct mlx5_flow_group *miss_group;
117 	struct mlx5_flow_handle *miss_rule;
118 	MLX5_DECLARE_FLOW_ACT(flow_act);
119 	struct mlx5_flow_spec *spec;
120 	u32 *flow_group_in;
121 	int err = 0;
122 
123 	flow_group_in = kvzalloc(inlen, GFP_KERNEL);
124 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
125 	if (!flow_group_in || !spec) {
126 		err = -ENOMEM;
127 		goto out;
128 	}
129 
130 	/* Create miss_group */
131 	MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ft->max_fte - 1);
132 	MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ft->max_fte - 1);
133 	miss_group = mlx5_create_flow_group(ft, flow_group_in);
134 	if (IS_ERR(miss_group)) {
135 		err = PTR_ERR(miss_group);
136 		netdev_err(priv->netdev, "fail to create ipsec rx miss_group err=%d\n", err);
137 		goto out;
138 	}
139 	fs_prot->miss_group = miss_group;
140 
141 	/* Create miss rule */
142 	miss_rule = mlx5_add_flow_rules(ft, spec, &flow_act, &fs_prot->default_dest, 1);
143 	if (IS_ERR(miss_rule)) {
144 		mlx5_destroy_flow_group(fs_prot->miss_group);
145 		err = PTR_ERR(miss_rule);
146 		netdev_err(priv->netdev, "fail to create ipsec rx miss_rule err=%d\n", err);
147 		goto out;
148 	}
149 	fs_prot->miss_rule = miss_rule;
150 out:
151 	kvfree(flow_group_in);
152 	kvfree(spec);
153 	return err;
154 }
155 
156 static void rx_destroy(struct mlx5e_priv *priv, enum accel_fs_esp_type type)
157 {
158 	struct mlx5e_accel_fs_esp_prot *fs_prot;
159 	struct mlx5e_accel_fs_esp *accel_esp;
160 
161 	accel_esp = priv->ipsec->rx_fs;
162 
163 	/* The netdev unreg already happened, so all offloaded rule are already removed */
164 	fs_prot = &accel_esp->fs_prot[type];
165 
166 	mlx5_del_flow_rules(fs_prot->miss_rule);
167 	mlx5_destroy_flow_group(fs_prot->miss_group);
168 	mlx5_destroy_flow_table(fs_prot->ft);
169 
170 	mlx5_del_flow_rules(fs_prot->rx_err.rule);
171 	mlx5_modify_header_dealloc(priv->mdev, fs_prot->rx_err.copy_modify_hdr);
172 	mlx5_destroy_flow_table(fs_prot->rx_err.ft);
173 }
174 
175 static int rx_create(struct mlx5e_priv *priv, enum accel_fs_esp_type type)
176 {
177 	struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(priv->fs, false);
178 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(priv->fs, false);
179 	struct mlx5_flow_table_attr ft_attr = {};
180 	struct mlx5e_accel_fs_esp_prot *fs_prot;
181 	struct mlx5e_accel_fs_esp *accel_esp;
182 	struct mlx5_flow_table *ft;
183 	int err;
184 
185 	accel_esp = priv->ipsec->rx_fs;
186 	fs_prot = &accel_esp->fs_prot[type];
187 	fs_prot->default_dest =
188 		mlx5_ttc_get_default_dest(ttc, fs_esp2tt(type));
189 
190 	ft_attr.max_fte = 1;
191 	ft_attr.autogroup.max_num_groups = 1;
192 	ft_attr.level = MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL;
193 	ft_attr.prio = MLX5E_NIC_PRIO;
194 	ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
195 	if (IS_ERR(ft))
196 		return PTR_ERR(ft);
197 
198 	fs_prot->rx_err.ft = ft;
199 	err = rx_err_add_rule(priv, fs_prot, &fs_prot->rx_err);
200 	if (err)
201 		goto err_add;
202 
203 	/* Create FT */
204 	ft_attr.max_fte = NUM_IPSEC_FTE;
205 	ft_attr.level = MLX5E_ACCEL_FS_ESP_FT_LEVEL;
206 	ft_attr.prio = MLX5E_NIC_PRIO;
207 	ft_attr.autogroup.num_reserved_entries = 1;
208 	ft_attr.autogroup.max_num_groups = 1;
209 	ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
210 	if (IS_ERR(ft)) {
211 		err = PTR_ERR(ft);
212 		goto err_fs_ft;
213 	}
214 	fs_prot->ft = ft;
215 
216 	err = rx_fs_create(priv, fs_prot);
217 	if (err)
218 		goto err_fs;
219 
220 	return 0;
221 
222 err_fs:
223 	mlx5_destroy_flow_table(fs_prot->ft);
224 err_fs_ft:
225 	mlx5_del_flow_rules(fs_prot->rx_err.rule);
226 	mlx5_modify_header_dealloc(priv->mdev, fs_prot->rx_err.copy_modify_hdr);
227 err_add:
228 	mlx5_destroy_flow_table(fs_prot->rx_err.ft);
229 	return err;
230 }
231 
232 static int rx_ft_get(struct mlx5e_priv *priv, enum accel_fs_esp_type type)
233 {
234 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(priv->fs, false);
235 	struct mlx5e_accel_fs_esp_prot *fs_prot;
236 	struct mlx5_flow_destination dest = {};
237 	struct mlx5e_accel_fs_esp *accel_esp;
238 	int err = 0;
239 
240 	accel_esp = priv->ipsec->rx_fs;
241 	fs_prot = &accel_esp->fs_prot[type];
242 	mutex_lock(&fs_prot->prot_mutex);
243 	if (fs_prot->refcnt)
244 		goto skip;
245 
246 	/* create FT */
247 	err = rx_create(priv, type);
248 	if (err)
249 		goto out;
250 
251 	/* connect */
252 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
253 	dest.ft = fs_prot->ft;
254 	mlx5_ttc_fwd_dest(ttc, fs_esp2tt(type), &dest);
255 
256 skip:
257 	fs_prot->refcnt++;
258 out:
259 	mutex_unlock(&fs_prot->prot_mutex);
260 	return err;
261 }
262 
263 static void rx_ft_put(struct mlx5e_priv *priv, enum accel_fs_esp_type type)
264 {
265 	struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(priv->fs, false);
266 	struct mlx5e_accel_fs_esp_prot *fs_prot;
267 	struct mlx5e_accel_fs_esp *accel_esp;
268 
269 	accel_esp = priv->ipsec->rx_fs;
270 	fs_prot = &accel_esp->fs_prot[type];
271 	mutex_lock(&fs_prot->prot_mutex);
272 	fs_prot->refcnt--;
273 	if (fs_prot->refcnt)
274 		goto out;
275 
276 	/* disconnect */
277 	mlx5_ttc_fwd_default_dest(ttc, fs_esp2tt(type));
278 
279 	/* remove FT */
280 	rx_destroy(priv, type);
281 
282 out:
283 	mutex_unlock(&fs_prot->prot_mutex);
284 }
285 
286 /* IPsec TX flow steering */
287 static int tx_create(struct mlx5e_priv *priv)
288 {
289 	struct mlx5_flow_table_attr ft_attr = {};
290 	struct mlx5e_ipsec *ipsec = priv->ipsec;
291 	struct mlx5_flow_table *ft;
292 	int err;
293 
294 	ft_attr.max_fte = NUM_IPSEC_FTE;
295 	ft_attr.autogroup.max_num_groups = 1;
296 	ft = mlx5_create_auto_grouped_flow_table(ipsec->tx_fs->ns, &ft_attr);
297 	if (IS_ERR(ft)) {
298 		err = PTR_ERR(ft);
299 		netdev_err(priv->netdev, "fail to create ipsec tx ft err=%d\n", err);
300 		return err;
301 	}
302 	ipsec->tx_fs->ft = ft;
303 	return 0;
304 }
305 
306 static int tx_ft_get(struct mlx5e_priv *priv)
307 {
308 	struct mlx5e_ipsec_tx *tx_fs = priv->ipsec->tx_fs;
309 	int err = 0;
310 
311 	mutex_lock(&tx_fs->mutex);
312 	if (tx_fs->refcnt)
313 		goto skip;
314 
315 	err = tx_create(priv);
316 	if (err)
317 		goto out;
318 skip:
319 	tx_fs->refcnt++;
320 out:
321 	mutex_unlock(&tx_fs->mutex);
322 	return err;
323 }
324 
325 static void tx_ft_put(struct mlx5e_priv *priv)
326 {
327 	struct mlx5e_ipsec_tx *tx_fs = priv->ipsec->tx_fs;
328 
329 	mutex_lock(&tx_fs->mutex);
330 	tx_fs->refcnt--;
331 	if (tx_fs->refcnt)
332 		goto out;
333 
334 	mlx5_destroy_flow_table(tx_fs->ft);
335 out:
336 	mutex_unlock(&tx_fs->mutex);
337 }
338 
339 static void setup_fte_common(struct mlx5_accel_esp_xfrm_attrs *attrs,
340 			     u32 ipsec_obj_id,
341 			     struct mlx5_flow_spec *spec,
342 			     struct mlx5_flow_act *flow_act)
343 {
344 	u8 ip_version = attrs->is_ipv6 ? 6 : 4;
345 
346 	spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS | MLX5_MATCH_MISC_PARAMETERS;
347 
348 	/* ip_version */
349 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_version);
350 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_version, ip_version);
351 
352 	/* Non fragmented */
353 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.frag);
354 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.frag, 0);
355 
356 	/* ESP header */
357 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ip_protocol);
358 	MLX5_SET(fte_match_param, spec->match_value, outer_headers.ip_protocol, IPPROTO_ESP);
359 
360 	/* SPI number */
361 	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters.outer_esp_spi);
362 	MLX5_SET(fte_match_param, spec->match_value,
363 		 misc_parameters.outer_esp_spi, attrs->spi);
364 
365 	if (ip_version == 4) {
366 		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
367 				    outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4),
368 		       &attrs->saddr.a4, 4);
369 		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
370 				    outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
371 		       &attrs->daddr.a4, 4);
372 		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
373 				 outer_headers.src_ipv4_src_ipv6.ipv4_layout.ipv4);
374 		MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
375 				 outer_headers.dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
376 	} else {
377 		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
378 				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
379 		       &attrs->saddr.a6, 16);
380 		memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value,
381 				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
382 		       &attrs->daddr.a6, 16);
383 		memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
384 				    outer_headers.src_ipv4_src_ipv6.ipv6_layout.ipv6),
385 		       0xff, 16);
386 		memset(MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
387 				    outer_headers.dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
388 		       0xff, 16);
389 	}
390 
391 	flow_act->crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_IPSEC;
392 	flow_act->crypto.obj_id = ipsec_obj_id;
393 	flow_act->flags |= FLOW_ACT_NO_APPEND;
394 }
395 
396 static int rx_add_rule(struct mlx5e_priv *priv,
397 		       struct mlx5e_ipsec_sa_entry *sa_entry)
398 {
399 	u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
400 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
401 	struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
402 	u32 ipsec_obj_id = sa_entry->ipsec_obj_id;
403 	struct mlx5_modify_hdr *modify_hdr = NULL;
404 	struct mlx5e_accel_fs_esp_prot *fs_prot;
405 	struct mlx5_flow_destination dest = {};
406 	struct mlx5e_accel_fs_esp *accel_esp;
407 	struct mlx5_flow_act flow_act = {};
408 	struct mlx5_flow_handle *rule;
409 	enum accel_fs_esp_type type;
410 	struct mlx5_flow_spec *spec;
411 	int err = 0;
412 
413 	accel_esp = priv->ipsec->rx_fs;
414 	type = attrs->is_ipv6 ? ACCEL_FS_ESP6 : ACCEL_FS_ESP4;
415 	fs_prot = &accel_esp->fs_prot[type];
416 
417 	err = rx_ft_get(priv, type);
418 	if (err)
419 		return err;
420 
421 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
422 	if (!spec) {
423 		err = -ENOMEM;
424 		goto out_err;
425 	}
426 
427 	setup_fte_common(attrs, ipsec_obj_id, spec, &flow_act);
428 
429 	/* Set bit[31] ipsec marker */
430 	/* Set bit[23-0] ipsec_obj_id */
431 	MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
432 	MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
433 	MLX5_SET(set_action_in, action, data, (ipsec_obj_id | BIT(31)));
434 	MLX5_SET(set_action_in, action, offset, 0);
435 	MLX5_SET(set_action_in, action, length, 32);
436 
437 	modify_hdr = mlx5_modify_header_alloc(priv->mdev, MLX5_FLOW_NAMESPACE_KERNEL,
438 					      1, action);
439 	if (IS_ERR(modify_hdr)) {
440 		err = PTR_ERR(modify_hdr);
441 		netdev_err(priv->netdev,
442 			   "fail to alloc ipsec set modify_header_id err=%d\n", err);
443 		modify_hdr = NULL;
444 		goto out_err;
445 	}
446 
447 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
448 			  MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
449 			  MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
450 	dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
451 	flow_act.modify_hdr = modify_hdr;
452 	dest.ft = fs_prot->rx_err.ft;
453 	rule = mlx5_add_flow_rules(fs_prot->ft, spec, &flow_act, &dest, 1);
454 	if (IS_ERR(rule)) {
455 		err = PTR_ERR(rule);
456 		netdev_err(priv->netdev, "fail to add ipsec rule attrs->action=0x%x, err=%d\n",
457 			   attrs->action, err);
458 		goto out_err;
459 	}
460 
461 	ipsec_rule->rule = rule;
462 	ipsec_rule->set_modify_hdr = modify_hdr;
463 	goto out;
464 
465 out_err:
466 	if (modify_hdr)
467 		mlx5_modify_header_dealloc(priv->mdev, modify_hdr);
468 	rx_ft_put(priv, type);
469 
470 out:
471 	kvfree(spec);
472 	return err;
473 }
474 
475 static int tx_add_rule(struct mlx5e_priv *priv,
476 		       struct mlx5e_ipsec_sa_entry *sa_entry)
477 {
478 	struct mlx5_flow_act flow_act = {};
479 	struct mlx5_flow_handle *rule;
480 	struct mlx5_flow_spec *spec;
481 	int err = 0;
482 
483 	err = tx_ft_get(priv);
484 	if (err)
485 		return err;
486 
487 	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
488 	if (!spec) {
489 		err = -ENOMEM;
490 		goto out;
491 	}
492 
493 	setup_fte_common(&sa_entry->attrs, sa_entry->ipsec_obj_id, spec,
494 			 &flow_act);
495 
496 	/* Add IPsec indicator in metadata_reg_a */
497 	spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
498 	MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_a,
499 		 MLX5_ETH_WQE_FT_META_IPSEC);
500 	MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_a,
501 		 MLX5_ETH_WQE_FT_META_IPSEC);
502 
503 	flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW |
504 			  MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT;
505 	rule = mlx5_add_flow_rules(priv->ipsec->tx_fs->ft, spec, &flow_act, NULL, 0);
506 	if (IS_ERR(rule)) {
507 		err = PTR_ERR(rule);
508 		netdev_err(priv->netdev, "fail to add ipsec rule attrs->action=0x%x, err=%d\n",
509 				sa_entry->attrs.action, err);
510 		goto out;
511 	}
512 
513 	sa_entry->ipsec_rule.rule = rule;
514 
515 out:
516 	kvfree(spec);
517 	if (err)
518 		tx_ft_put(priv);
519 	return err;
520 }
521 
522 int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_priv *priv,
523 				  struct mlx5e_ipsec_sa_entry *sa_entry)
524 {
525 	if (sa_entry->attrs.action == MLX5_ACCEL_ESP_ACTION_ENCRYPT)
526 		return tx_add_rule(priv, sa_entry);
527 
528 	return rx_add_rule(priv, sa_entry);
529 }
530 
531 void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_priv *priv,
532 				   struct mlx5e_ipsec_sa_entry *sa_entry)
533 {
534 	struct mlx5e_ipsec_rule *ipsec_rule = &sa_entry->ipsec_rule;
535 	struct mlx5_core_dev *mdev = mlx5e_ipsec_sa2dev(sa_entry);
536 
537 	mlx5_del_flow_rules(ipsec_rule->rule);
538 
539 	if (sa_entry->attrs.action == MLX5_ACCEL_ESP_ACTION_ENCRYPT) {
540 		tx_ft_put(priv);
541 		return;
542 	}
543 
544 	mlx5_modify_header_dealloc(mdev, ipsec_rule->set_modify_hdr);
545 	rx_ft_put(priv,
546 		  sa_entry->attrs.is_ipv6 ? ACCEL_FS_ESP6 : ACCEL_FS_ESP4);
547 }
548 
549 void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
550 {
551 	struct mlx5e_accel_fs_esp_prot *fs_prot;
552 	struct mlx5e_accel_fs_esp *accel_esp;
553 	enum accel_fs_esp_type i;
554 
555 	if (!ipsec->rx_fs)
556 		return;
557 
558 	mutex_destroy(&ipsec->tx_fs->mutex);
559 	WARN_ON(ipsec->tx_fs->refcnt);
560 	kfree(ipsec->tx_fs);
561 
562 	accel_esp = ipsec->rx_fs;
563 	for (i = 0; i < ACCEL_FS_ESP_NUM_TYPES; i++) {
564 		fs_prot = &accel_esp->fs_prot[i];
565 		mutex_destroy(&fs_prot->prot_mutex);
566 		WARN_ON(fs_prot->refcnt);
567 	}
568 	kfree(ipsec->rx_fs);
569 }
570 
571 int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
572 {
573 	struct mlx5e_accel_fs_esp_prot *fs_prot;
574 	struct mlx5e_accel_fs_esp *accel_esp;
575 	struct mlx5_flow_namespace *ns;
576 	enum accel_fs_esp_type i;
577 	int err = -ENOMEM;
578 
579 	ns = mlx5_get_flow_namespace(ipsec->mdev,
580 				     MLX5_FLOW_NAMESPACE_EGRESS_IPSEC);
581 	if (!ns)
582 		return -EOPNOTSUPP;
583 
584 	ipsec->tx_fs = kzalloc(sizeof(*ipsec->tx_fs), GFP_KERNEL);
585 	if (!ipsec->tx_fs)
586 		return -ENOMEM;
587 
588 	ipsec->rx_fs = kzalloc(sizeof(*ipsec->rx_fs), GFP_KERNEL);
589 	if (!ipsec->rx_fs)
590 		goto err_rx;
591 
592 	mutex_init(&ipsec->tx_fs->mutex);
593 	ipsec->tx_fs->ns = ns;
594 
595 	accel_esp = ipsec->rx_fs;
596 	for (i = 0; i < ACCEL_FS_ESP_NUM_TYPES; i++) {
597 		fs_prot = &accel_esp->fs_prot[i];
598 		mutex_init(&fs_prot->prot_mutex);
599 	}
600 
601 	return 0;
602 
603 err_rx:
604 	kfree(ipsec->tx_fs);
605 	return err;
606 }
607