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