1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3 #include <linux/mlx5/device.h>
4 #include <net/psp.h>
5 #include <linux/psp.h>
6 #include "mlx5_core.h"
7 #include "psp.h"
8 #include "lib/crypto.h"
9 #include "en_accel/psp.h"
10 #include "fs_core.h"
11
12 enum accel_fs_psp_type {
13 ACCEL_FS_PSP4,
14 ACCEL_FS_PSP6,
15 ACCEL_FS_PSP_NUM_TYPES,
16 };
17
18 enum accel_psp_syndrome {
19 PSP_OK = 0,
20 PSP_ICV_FAIL,
21 PSP_BAD_TRAILER,
22 };
23
24 struct mlx5e_psp_tx {
25 struct mlx5_flow_namespace *ns;
26 struct mlx5_flow_table *ft;
27 struct mlx5_flow_group *fg;
28 struct mlx5_flow_handle *rule;
29 struct mutex mutex; /* Protect PSP TX steering */
30 u32 refcnt;
31 };
32
33 struct mlx5e_psp_rx_err {
34 struct mlx5_flow_table *ft;
35 struct mlx5_flow_handle *rule;
36 struct mlx5_flow_handle *drop_rule;
37 struct mlx5_modify_hdr *copy_modify_hdr;
38 };
39
40 struct mlx5e_accel_fs_psp_prot {
41 struct mlx5_flow_table *ft;
42 struct mlx5_flow_group *miss_group;
43 struct mlx5_flow_handle *miss_rule;
44 struct mlx5_flow_destination default_dest;
45 struct mlx5e_psp_rx_err rx_err;
46 u32 refcnt;
47 struct mutex prot_mutex; /* protect ESP4/ESP6 protocol */
48 struct mlx5_flow_handle *def_rule;
49 };
50
51 struct mlx5e_accel_fs_psp {
52 struct mlx5e_accel_fs_psp_prot fs_prot[ACCEL_FS_PSP_NUM_TYPES];
53 };
54
55 struct mlx5e_psp_fs {
56 struct mlx5_core_dev *mdev;
57 struct mlx5e_psp_tx *tx_fs;
58 /* Rx manage */
59 struct mlx5e_flow_steering *fs;
60 struct mlx5e_accel_fs_psp *rx_fs;
61 };
62
63 /* PSP RX flow steering */
fs_psp2tt(enum accel_fs_psp_type i)64 static enum mlx5_traffic_types fs_psp2tt(enum accel_fs_psp_type i)
65 {
66 if (i == ACCEL_FS_PSP4)
67 return MLX5_TT_IPV4_UDP;
68
69 return MLX5_TT_IPV6_UDP;
70 }
71
accel_psp_fs_rx_err_del_rules(struct mlx5e_psp_fs * fs,struct mlx5e_psp_rx_err * rx_err)72 static void accel_psp_fs_rx_err_del_rules(struct mlx5e_psp_fs *fs,
73 struct mlx5e_psp_rx_err *rx_err)
74 {
75 if (rx_err->drop_rule) {
76 mlx5_del_flow_rules(rx_err->drop_rule);
77 rx_err->drop_rule = NULL;
78 }
79
80 if (rx_err->rule) {
81 mlx5_del_flow_rules(rx_err->rule);
82 rx_err->rule = NULL;
83 }
84
85 if (rx_err->copy_modify_hdr) {
86 mlx5_modify_header_dealloc(fs->mdev, rx_err->copy_modify_hdr);
87 rx_err->copy_modify_hdr = NULL;
88 }
89 }
90
accel_psp_fs_rx_err_destroy_ft(struct mlx5e_psp_fs * fs,struct mlx5e_psp_rx_err * rx_err)91 static void accel_psp_fs_rx_err_destroy_ft(struct mlx5e_psp_fs *fs,
92 struct mlx5e_psp_rx_err *rx_err)
93 {
94 accel_psp_fs_rx_err_del_rules(fs, rx_err);
95
96 if (rx_err->ft) {
97 mlx5_destroy_flow_table(rx_err->ft);
98 rx_err->ft = NULL;
99 }
100 }
101
accel_psp_setup_syndrome_match(struct mlx5_flow_spec * spec,enum accel_psp_syndrome syndrome)102 static void accel_psp_setup_syndrome_match(struct mlx5_flow_spec *spec,
103 enum accel_psp_syndrome syndrome)
104 {
105 void *misc_params_2;
106
107 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
108 misc_params_2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
109 MLX5_SET_TO_ONES(fte_match_set_misc2, misc_params_2, psp_syndrome);
110 misc_params_2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
111 MLX5_SET(fte_match_set_misc2, misc_params_2, psp_syndrome, syndrome);
112 }
113
accel_psp_fs_rx_err_add_rule(struct mlx5e_psp_fs * fs,struct mlx5e_accel_fs_psp_prot * fs_prot,struct mlx5e_psp_rx_err * rx_err)114 static int accel_psp_fs_rx_err_add_rule(struct mlx5e_psp_fs *fs,
115 struct mlx5e_accel_fs_psp_prot *fs_prot,
116 struct mlx5e_psp_rx_err *rx_err)
117 {
118 u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
119 struct mlx5_core_dev *mdev = fs->mdev;
120 struct mlx5_flow_act flow_act = {};
121 struct mlx5_modify_hdr *modify_hdr;
122 struct mlx5_flow_handle *fte;
123 struct mlx5_flow_spec *spec;
124 int err = 0;
125
126 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
127 if (!spec)
128 return -ENOMEM;
129
130 /* Action to copy 7 bit psp_syndrome to regB[23:29] */
131 MLX5_SET(copy_action_in, action, action_type, MLX5_ACTION_TYPE_COPY);
132 MLX5_SET(copy_action_in, action, src_field, MLX5_ACTION_IN_FIELD_PSP_SYNDROME);
133 MLX5_SET(copy_action_in, action, src_offset, 0);
134 MLX5_SET(copy_action_in, action, length, 7);
135 MLX5_SET(copy_action_in, action, dst_field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
136 MLX5_SET(copy_action_in, action, dst_offset, 23);
137
138 modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL,
139 1, action);
140 if (IS_ERR(modify_hdr)) {
141 err = PTR_ERR(modify_hdr);
142 mlx5_core_err(mdev,
143 "fail to alloc psp copy modify_header_id err=%d\n", err);
144 goto out_spec;
145 }
146
147 accel_psp_setup_syndrome_match(spec, PSP_OK);
148 /* create fte */
149 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR |
150 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
151 flow_act.modify_hdr = modify_hdr;
152 fte = mlx5_add_flow_rules(rx_err->ft, spec, &flow_act,
153 &fs_prot->default_dest, 1);
154 if (IS_ERR(fte)) {
155 err = PTR_ERR(fte);
156 mlx5_core_err(mdev, "fail to add psp rx err copy rule err=%d\n", err);
157 goto out;
158 }
159 rx_err->rule = fte;
160
161 /* add default drop rule */
162 memset(spec, 0, sizeof(*spec));
163 memset(&flow_act, 0, sizeof(flow_act));
164 /* create fte */
165 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
166 fte = mlx5_add_flow_rules(rx_err->ft, spec, &flow_act, NULL, 0);
167 if (IS_ERR(fte)) {
168 err = PTR_ERR(fte);
169 mlx5_core_err(mdev, "fail to add psp rx err drop rule err=%d\n", err);
170 goto out_drop_rule;
171 }
172 rx_err->drop_rule = fte;
173 rx_err->copy_modify_hdr = modify_hdr;
174
175 goto out_spec;
176
177 out_drop_rule:
178 mlx5_del_flow_rules(rx_err->rule);
179 rx_err->rule = NULL;
180 out:
181 mlx5_modify_header_dealloc(mdev, modify_hdr);
182 out_spec:
183 kfree(spec);
184 return err;
185 }
186
accel_psp_fs_rx_err_create_ft(struct mlx5e_psp_fs * fs,struct mlx5e_accel_fs_psp_prot * fs_prot,struct mlx5e_psp_rx_err * rx_err)187 static int accel_psp_fs_rx_err_create_ft(struct mlx5e_psp_fs *fs,
188 struct mlx5e_accel_fs_psp_prot *fs_prot,
189 struct mlx5e_psp_rx_err *rx_err)
190 {
191 struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs->fs, false);
192 struct mlx5_flow_table_attr ft_attr = {};
193 struct mlx5_flow_table *ft;
194 int err;
195
196 ft_attr.max_fte = 2;
197 ft_attr.autogroup.max_num_groups = 2;
198 ft_attr.level = MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL; // MLX5E_ACCEL_FS_TCP_FT_LEVEL
199 ft_attr.prio = MLX5E_NIC_PRIO;
200 ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
201 if (IS_ERR(ft)) {
202 err = PTR_ERR(ft);
203 mlx5_core_err(fs->mdev, "fail to create psp rx inline ft err=%d\n", err);
204 return err;
205 }
206
207 rx_err->ft = ft;
208 err = accel_psp_fs_rx_err_add_rule(fs, fs_prot, rx_err);
209 if (err)
210 goto out_err;
211
212 return 0;
213
214 out_err:
215 mlx5_destroy_flow_table(ft);
216 rx_err->ft = NULL;
217 return err;
218 }
219
accel_psp_fs_rx_fs_destroy(struct mlx5e_accel_fs_psp_prot * fs_prot)220 static void accel_psp_fs_rx_fs_destroy(struct mlx5e_accel_fs_psp_prot *fs_prot)
221 {
222 if (fs_prot->def_rule) {
223 mlx5_del_flow_rules(fs_prot->def_rule);
224 fs_prot->def_rule = NULL;
225 }
226
227 if (fs_prot->miss_rule) {
228 mlx5_del_flow_rules(fs_prot->miss_rule);
229 fs_prot->miss_rule = NULL;
230 }
231
232 if (fs_prot->miss_group) {
233 mlx5_destroy_flow_group(fs_prot->miss_group);
234 fs_prot->miss_group = NULL;
235 }
236
237 if (fs_prot->ft) {
238 mlx5_destroy_flow_table(fs_prot->ft);
239 fs_prot->ft = NULL;
240 }
241 }
242
setup_fte_udp_psp(struct mlx5_flow_spec * spec,u16 udp_port)243 static void setup_fte_udp_psp(struct mlx5_flow_spec *spec, u16 udp_port)
244 {
245 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
246 MLX5_SET(fte_match_set_lyr_2_4, spec->match_criteria, udp_dport, 0xffff);
247 MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, udp_dport, udp_port);
248 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, spec->match_criteria, ip_protocol);
249 MLX5_SET(fte_match_set_lyr_2_4, spec->match_value, ip_protocol, IPPROTO_UDP);
250 }
251
accel_psp_fs_rx_create_ft(struct mlx5e_psp_fs * fs,struct mlx5e_accel_fs_psp_prot * fs_prot)252 static int accel_psp_fs_rx_create_ft(struct mlx5e_psp_fs *fs,
253 struct mlx5e_accel_fs_psp_prot *fs_prot)
254 {
255 struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(fs->fs, false);
256 u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
257 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
258 struct mlx5_modify_hdr *modify_hdr = NULL;
259 struct mlx5_flow_table_attr ft_attr = {};
260 struct mlx5_flow_destination dest = {};
261 struct mlx5_core_dev *mdev = fs->mdev;
262 struct mlx5_flow_group *miss_group;
263 MLX5_DECLARE_FLOW_ACT(flow_act);
264 struct mlx5_flow_handle *rule;
265 struct mlx5_flow_spec *spec;
266 struct mlx5_flow_table *ft;
267 u32 *flow_group_in;
268 int err = 0;
269
270 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
271 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
272 if (!flow_group_in || !spec) {
273 err = -ENOMEM;
274 goto out;
275 }
276
277 /* Create FT */
278 ft_attr.max_fte = 2;
279 ft_attr.level = MLX5E_ACCEL_FS_ESP_FT_LEVEL;
280 ft_attr.prio = MLX5E_NIC_PRIO;
281 ft_attr.autogroup.num_reserved_entries = 1;
282 ft_attr.autogroup.max_num_groups = 1;
283 ft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr);
284 if (IS_ERR(ft)) {
285 err = PTR_ERR(ft);
286 mlx5_core_err(mdev, "fail to create psp rx ft err=%d\n", err);
287 goto out_err;
288 }
289 fs_prot->ft = ft;
290
291 /* Create miss_group */
292 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ft->max_fte - 1);
293 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ft->max_fte - 1);
294 miss_group = mlx5_create_flow_group(ft, flow_group_in);
295 if (IS_ERR(miss_group)) {
296 err = PTR_ERR(miss_group);
297 mlx5_core_err(mdev, "fail to create psp rx miss_group err=%d\n", err);
298 goto out_err;
299 }
300 fs_prot->miss_group = miss_group;
301
302 /* Create miss rule */
303 rule = mlx5_add_flow_rules(ft, spec, &flow_act, &fs_prot->default_dest, 1);
304 if (IS_ERR(rule)) {
305 err = PTR_ERR(rule);
306 mlx5_core_err(mdev, "fail to create psp rx miss_rule err=%d\n", err);
307 goto out_err;
308 }
309 fs_prot->miss_rule = rule;
310
311 /* Add default Rx psp rule */
312 setup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);
313 flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;
314 /* Set bit[31, 30] PSP marker */
315 /* Set bit[29-23] psp_syndrome is set in error FT */
316 #define MLX5E_PSP_MARKER_BIT (BIT(30) | BIT(31))
317 MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
318 MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B);
319 MLX5_SET(set_action_in, action, data, MLX5E_PSP_MARKER_BIT);
320 MLX5_SET(set_action_in, action, offset, 0);
321 MLX5_SET(set_action_in, action, length, 32);
322
323 modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_KERNEL, 1, action);
324 if (IS_ERR(modify_hdr)) {
325 err = PTR_ERR(modify_hdr);
326 mlx5_core_err(mdev, "fail to alloc psp set modify_header_id err=%d\n", err);
327 modify_hdr = NULL;
328 goto out_err;
329 }
330
331 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
332 MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT |
333 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
334 flow_act.modify_hdr = modify_hdr;
335 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
336 dest.ft = fs_prot->rx_err.ft;
337 rule = mlx5_add_flow_rules(fs_prot->ft, spec, &flow_act, &dest, 1);
338 if (IS_ERR(rule)) {
339 err = PTR_ERR(rule);
340 mlx5_core_err(mdev,
341 "fail to add psp rule Rx decryption, err=%d, flow_act.action = %#04X\n",
342 err, flow_act.action);
343 goto out_err;
344 }
345
346 fs_prot->def_rule = rule;
347 goto out;
348
349 out_err:
350 accel_psp_fs_rx_fs_destroy(fs_prot);
351 out:
352 kvfree(flow_group_in);
353 kvfree(spec);
354 return err;
355 }
356
accel_psp_fs_rx_destroy(struct mlx5e_psp_fs * fs,enum accel_fs_psp_type type)357 static int accel_psp_fs_rx_destroy(struct mlx5e_psp_fs *fs, enum accel_fs_psp_type type)
358 {
359 struct mlx5e_accel_fs_psp_prot *fs_prot;
360 struct mlx5e_accel_fs_psp *accel_psp;
361
362 accel_psp = fs->rx_fs;
363
364 /* The netdev unreg already happened, so all offloaded rule are already removed */
365 fs_prot = &accel_psp->fs_prot[type];
366
367 accel_psp_fs_rx_fs_destroy(fs_prot);
368
369 accel_psp_fs_rx_err_destroy_ft(fs, &fs_prot->rx_err);
370
371 return 0;
372 }
373
accel_psp_fs_rx_create(struct mlx5e_psp_fs * fs,enum accel_fs_psp_type type)374 static int accel_psp_fs_rx_create(struct mlx5e_psp_fs *fs, enum accel_fs_psp_type type)
375 {
376 struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs->fs, false);
377 struct mlx5e_accel_fs_psp_prot *fs_prot;
378 struct mlx5e_accel_fs_psp *accel_psp;
379 int err;
380
381 accel_psp = fs->rx_fs;
382 fs_prot = &accel_psp->fs_prot[type];
383
384 fs_prot->default_dest = mlx5_ttc_get_default_dest(ttc, fs_psp2tt(type));
385
386 err = accel_psp_fs_rx_err_create_ft(fs, fs_prot, &fs_prot->rx_err);
387 if (err)
388 return err;
389
390 err = accel_psp_fs_rx_create_ft(fs, fs_prot);
391 if (err)
392 accel_psp_fs_rx_err_destroy_ft(fs, &fs_prot->rx_err);
393
394 return err;
395 }
396
accel_psp_fs_rx_ft_get(struct mlx5e_psp_fs * fs,enum accel_fs_psp_type type)397 static int accel_psp_fs_rx_ft_get(struct mlx5e_psp_fs *fs, enum accel_fs_psp_type type)
398 {
399 struct mlx5e_accel_fs_psp_prot *fs_prot;
400 struct mlx5_flow_destination dest = {};
401 struct mlx5e_accel_fs_psp *accel_psp;
402 struct mlx5_ttc_table *ttc;
403 int err = 0;
404
405 if (!fs || !fs->rx_fs)
406 return -EINVAL;
407
408 ttc = mlx5e_fs_get_ttc(fs->fs, false);
409 accel_psp = fs->rx_fs;
410 fs_prot = &accel_psp->fs_prot[type];
411 mutex_lock(&fs_prot->prot_mutex);
412 if (fs_prot->refcnt++)
413 goto out;
414
415 /* create FT */
416 err = accel_psp_fs_rx_create(fs, type);
417 if (err) {
418 fs_prot->refcnt--;
419 goto out;
420 }
421
422 /* connect */
423 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
424 dest.ft = fs_prot->ft;
425 mlx5_ttc_fwd_dest(ttc, fs_psp2tt(type), &dest);
426
427 out:
428 mutex_unlock(&fs_prot->prot_mutex);
429 return err;
430 }
431
accel_psp_fs_rx_ft_put(struct mlx5e_psp_fs * fs,enum accel_fs_psp_type type)432 static void accel_psp_fs_rx_ft_put(struct mlx5e_psp_fs *fs, enum accel_fs_psp_type type)
433 {
434 struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(fs->fs, false);
435 struct mlx5e_accel_fs_psp_prot *fs_prot;
436 struct mlx5e_accel_fs_psp *accel_psp;
437
438 accel_psp = fs->rx_fs;
439 fs_prot = &accel_psp->fs_prot[type];
440 mutex_lock(&fs_prot->prot_mutex);
441 if (--fs_prot->refcnt)
442 goto out;
443
444 /* disconnect */
445 mlx5_ttc_fwd_default_dest(ttc, fs_psp2tt(type));
446
447 /* remove FT */
448 accel_psp_fs_rx_destroy(fs, type);
449
450 out:
451 mutex_unlock(&fs_prot->prot_mutex);
452 }
453
accel_psp_fs_cleanup_rx(struct mlx5e_psp_fs * fs)454 static void accel_psp_fs_cleanup_rx(struct mlx5e_psp_fs *fs)
455 {
456 struct mlx5e_accel_fs_psp_prot *fs_prot;
457 struct mlx5e_accel_fs_psp *accel_psp;
458 enum accel_fs_psp_type i;
459
460 if (!fs->rx_fs)
461 return;
462
463 accel_psp = fs->rx_fs;
464 for (i = 0; i < ACCEL_FS_PSP_NUM_TYPES; i++) {
465 fs_prot = &accel_psp->fs_prot[i];
466 mutex_destroy(&fs_prot->prot_mutex);
467 WARN_ON(fs_prot->refcnt);
468 }
469 kfree(fs->rx_fs);
470 fs->rx_fs = NULL;
471 }
472
accel_psp_fs_init_rx(struct mlx5e_psp_fs * fs)473 static int accel_psp_fs_init_rx(struct mlx5e_psp_fs *fs)
474 {
475 struct mlx5e_accel_fs_psp_prot *fs_prot;
476 struct mlx5e_accel_fs_psp *accel_psp;
477 enum accel_fs_psp_type i;
478
479 accel_psp = kzalloc(sizeof(*accel_psp), GFP_KERNEL);
480 if (!accel_psp)
481 return -ENOMEM;
482
483 for (i = 0; i < ACCEL_FS_PSP_NUM_TYPES; i++) {
484 fs_prot = &accel_psp->fs_prot[i];
485 mutex_init(&fs_prot->prot_mutex);
486 }
487
488 fs->rx_fs = accel_psp;
489
490 return 0;
491 }
492
mlx5_accel_psp_fs_cleanup_rx_tables(struct mlx5e_priv * priv)493 void mlx5_accel_psp_fs_cleanup_rx_tables(struct mlx5e_priv *priv)
494 {
495 int i;
496
497 if (!priv->psp)
498 return;
499
500 for (i = 0; i < ACCEL_FS_PSP_NUM_TYPES; i++)
501 accel_psp_fs_rx_ft_put(priv->psp->fs, i);
502 }
503
mlx5_accel_psp_fs_init_rx_tables(struct mlx5e_priv * priv)504 int mlx5_accel_psp_fs_init_rx_tables(struct mlx5e_priv *priv)
505 {
506 struct mlx5e_psp_fs *fs;
507 int err, i;
508
509 if (!priv->psp)
510 return 0;
511
512 fs = priv->psp->fs;
513 for (i = 0; i < ACCEL_FS_PSP_NUM_TYPES; i++) {
514 err = accel_psp_fs_rx_ft_get(fs, i);
515 if (err)
516 goto out_err;
517 }
518
519 return 0;
520
521 out_err:
522 i--;
523 while (i >= 0) {
524 accel_psp_fs_rx_ft_put(fs, i);
525 --i;
526 }
527
528 return err;
529 }
530
accel_psp_fs_tx_create_ft_table(struct mlx5e_psp_fs * fs)531 static int accel_psp_fs_tx_create_ft_table(struct mlx5e_psp_fs *fs)
532 {
533 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
534 struct mlx5_flow_table_attr ft_attr = {};
535 struct mlx5_core_dev *mdev = fs->mdev;
536 struct mlx5_flow_act flow_act = {};
537 u32 *in, *mc, *outer_headers_c;
538 struct mlx5_flow_handle *rule;
539 struct mlx5_flow_spec *spec;
540 struct mlx5e_psp_tx *tx_fs;
541 struct mlx5_flow_table *ft;
542 struct mlx5_flow_group *fg;
543 int err = 0;
544
545 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
546 in = kvzalloc(inlen, GFP_KERNEL);
547 if (!spec || !in) {
548 err = -ENOMEM;
549 goto out;
550 }
551
552 ft_attr.max_fte = 1;
553 #define MLX5E_PSP_PRIO 0
554 ft_attr.prio = MLX5E_PSP_PRIO;
555 #define MLX5E_PSP_LEVEL 0
556 ft_attr.level = MLX5E_PSP_LEVEL;
557 ft_attr.autogroup.max_num_groups = 1;
558
559 tx_fs = fs->tx_fs;
560 ft = mlx5_create_flow_table(tx_fs->ns, &ft_attr);
561 if (IS_ERR(ft)) {
562 err = PTR_ERR(ft);
563 mlx5_core_err(mdev, "PSP: fail to add psp tx flow table, err = %d\n", err);
564 goto out;
565 }
566
567 mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
568 outer_headers_c = MLX5_ADDR_OF(fte_match_param, mc, outer_headers);
569 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
570 MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, udp_dport);
571 MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
572 fg = mlx5_create_flow_group(ft, in);
573 if (IS_ERR(fg)) {
574 err = PTR_ERR(fg);
575 mlx5_core_err(mdev, "PSP: fail to add psp tx flow group, err = %d\n", err);
576 goto err_create_fg;
577 }
578
579 setup_fte_udp_psp(spec, PSP_DEFAULT_UDP_PORT);
580 flow_act.crypto.type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_PSP;
581 flow_act.flags |= FLOW_ACT_NO_APPEND;
582 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW |
583 MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT;
584 rule = mlx5_add_flow_rules(ft, spec, &flow_act, NULL, 0);
585 if (IS_ERR(rule)) {
586 err = PTR_ERR(rule);
587 mlx5_core_err(mdev, "PSP: fail to add psp tx flow rule, err = %d\n", err);
588 goto err_add_flow_rule;
589 }
590
591 tx_fs->ft = ft;
592 tx_fs->fg = fg;
593 tx_fs->rule = rule;
594 goto out;
595
596 err_add_flow_rule:
597 mlx5_destroy_flow_group(fg);
598 err_create_fg:
599 mlx5_destroy_flow_table(ft);
600 out:
601 kvfree(in);
602 kvfree(spec);
603 return err;
604 }
605
accel_psp_fs_tx_destroy(struct mlx5e_psp_tx * tx_fs)606 static void accel_psp_fs_tx_destroy(struct mlx5e_psp_tx *tx_fs)
607 {
608 if (!tx_fs->ft)
609 return;
610
611 mlx5_del_flow_rules(tx_fs->rule);
612 mlx5_destroy_flow_group(tx_fs->fg);
613 mlx5_destroy_flow_table(tx_fs->ft);
614 }
615
accel_psp_fs_tx_ft_get(struct mlx5e_psp_fs * fs)616 static int accel_psp_fs_tx_ft_get(struct mlx5e_psp_fs *fs)
617 {
618 struct mlx5e_psp_tx *tx_fs = fs->tx_fs;
619 int err = 0;
620
621 mutex_lock(&tx_fs->mutex);
622 if (tx_fs->refcnt++)
623 goto out;
624
625 err = accel_psp_fs_tx_create_ft_table(fs);
626 if (err)
627 tx_fs->refcnt--;
628 out:
629 mutex_unlock(&tx_fs->mutex);
630 return err;
631 }
632
accel_psp_fs_tx_ft_put(struct mlx5e_psp_fs * fs)633 static void accel_psp_fs_tx_ft_put(struct mlx5e_psp_fs *fs)
634 {
635 struct mlx5e_psp_tx *tx_fs = fs->tx_fs;
636
637 mutex_lock(&tx_fs->mutex);
638 if (--tx_fs->refcnt)
639 goto out;
640
641 accel_psp_fs_tx_destroy(tx_fs);
642 out:
643 mutex_unlock(&tx_fs->mutex);
644 }
645
accel_psp_fs_cleanup_tx(struct mlx5e_psp_fs * fs)646 static void accel_psp_fs_cleanup_tx(struct mlx5e_psp_fs *fs)
647 {
648 struct mlx5e_psp_tx *tx_fs = fs->tx_fs;
649
650 if (!tx_fs)
651 return;
652
653 mutex_destroy(&tx_fs->mutex);
654 WARN_ON(tx_fs->refcnt);
655 kfree(tx_fs);
656 fs->tx_fs = NULL;
657 }
658
accel_psp_fs_init_tx(struct mlx5e_psp_fs * fs)659 static int accel_psp_fs_init_tx(struct mlx5e_psp_fs *fs)
660 {
661 struct mlx5_flow_namespace *ns;
662 struct mlx5e_psp_tx *tx_fs;
663
664 ns = mlx5_get_flow_namespace(fs->mdev, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC);
665 if (!ns)
666 return -EOPNOTSUPP;
667
668 tx_fs = kzalloc(sizeof(*tx_fs), GFP_KERNEL);
669 if (!tx_fs)
670 return -ENOMEM;
671
672 mutex_init(&tx_fs->mutex);
673 tx_fs->ns = ns;
674 fs->tx_fs = tx_fs;
675 return 0;
676 }
677
mlx5_accel_psp_fs_cleanup_tx_tables(struct mlx5e_priv * priv)678 void mlx5_accel_psp_fs_cleanup_tx_tables(struct mlx5e_priv *priv)
679 {
680 if (!priv->psp)
681 return;
682
683 accel_psp_fs_tx_ft_put(priv->psp->fs);
684 }
685
mlx5_accel_psp_fs_init_tx_tables(struct mlx5e_priv * priv)686 int mlx5_accel_psp_fs_init_tx_tables(struct mlx5e_priv *priv)
687 {
688 if (!priv->psp)
689 return 0;
690
691 return accel_psp_fs_tx_ft_get(priv->psp->fs);
692 }
693
mlx5e_accel_psp_fs_cleanup(struct mlx5e_psp_fs * fs)694 static void mlx5e_accel_psp_fs_cleanup(struct mlx5e_psp_fs *fs)
695 {
696 accel_psp_fs_cleanup_rx(fs);
697 accel_psp_fs_cleanup_tx(fs);
698 kfree(fs);
699 }
700
mlx5e_accel_psp_fs_init(struct mlx5e_priv * priv)701 static struct mlx5e_psp_fs *mlx5e_accel_psp_fs_init(struct mlx5e_priv *priv)
702 {
703 struct mlx5e_psp_fs *fs;
704 int err = 0;
705
706 fs = kzalloc(sizeof(*fs), GFP_KERNEL);
707 if (!fs)
708 return ERR_PTR(-ENOMEM);
709
710 fs->mdev = priv->mdev;
711 err = accel_psp_fs_init_tx(fs);
712 if (err)
713 goto err_tx;
714
715 fs->fs = priv->fs;
716 err = accel_psp_fs_init_rx(fs);
717 if (err)
718 goto err_rx;
719
720 return fs;
721
722 err_rx:
723 accel_psp_fs_cleanup_tx(fs);
724 err_tx:
725 kfree(fs);
726 return ERR_PTR(err);
727 }
728
729 static int
mlx5e_psp_set_config(struct psp_dev * psd,struct psp_dev_config * conf,struct netlink_ext_ack * extack)730 mlx5e_psp_set_config(struct psp_dev *psd, struct psp_dev_config *conf,
731 struct netlink_ext_ack *extack)
732 {
733 return 0; /* TODO: this should actually do things to the device */
734 }
735
736 static int
mlx5e_psp_generate_key_spi(struct mlx5_core_dev * mdev,enum mlx5_psp_gen_spi_in_key_size keysz,unsigned int keysz_bytes,struct psp_key_parsed * key)737 mlx5e_psp_generate_key_spi(struct mlx5_core_dev *mdev,
738 enum mlx5_psp_gen_spi_in_key_size keysz,
739 unsigned int keysz_bytes,
740 struct psp_key_parsed *key)
741 {
742 u32 out[MLX5_ST_SZ_DW(psp_gen_spi_out) + MLX5_ST_SZ_DW(key_spi)] = {};
743 u32 in[MLX5_ST_SZ_DW(psp_gen_spi_in)] = {};
744 void *outkey;
745 int err;
746
747 WARN_ON_ONCE(keysz_bytes > PSP_MAX_KEY);
748
749 MLX5_SET(psp_gen_spi_in, in, opcode, MLX5_CMD_OP_PSP_GEN_SPI);
750 MLX5_SET(psp_gen_spi_in, in, key_size, keysz);
751 MLX5_SET(psp_gen_spi_in, in, num_of_spi, 1);
752 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
753 if (err)
754 return err;
755
756 outkey = MLX5_ADDR_OF(psp_gen_spi_out, out, key_spi);
757 key->spi = cpu_to_be32(MLX5_GET(key_spi, outkey, spi));
758 memcpy(key->key, MLX5_ADDR_OF(key_spi, outkey, key) + 32 - keysz_bytes,
759 keysz_bytes);
760
761 return 0;
762 }
763
764 static int
mlx5e_psp_rx_spi_alloc(struct psp_dev * psd,u32 version,struct psp_key_parsed * assoc,struct netlink_ext_ack * extack)765 mlx5e_psp_rx_spi_alloc(struct psp_dev *psd, u32 version,
766 struct psp_key_parsed *assoc,
767 struct netlink_ext_ack *extack)
768 {
769 struct mlx5e_priv *priv = netdev_priv(psd->main_netdev);
770 enum mlx5_psp_gen_spi_in_key_size keysz;
771 u8 keysz_bytes;
772
773 switch (version) {
774 case PSP_VERSION_HDR0_AES_GCM_128:
775 keysz = MLX5_PSP_GEN_SPI_IN_KEY_SIZE_128;
776 keysz_bytes = 16;
777 break;
778 case PSP_VERSION_HDR0_AES_GCM_256:
779 keysz = MLX5_PSP_GEN_SPI_IN_KEY_SIZE_256;
780 keysz_bytes = 32;
781 break;
782 default:
783 return -EINVAL;
784 }
785
786 return mlx5e_psp_generate_key_spi(priv->mdev, keysz, keysz_bytes, assoc);
787 }
788
789 struct psp_key {
790 u32 id;
791 };
792
mlx5e_psp_assoc_add(struct psp_dev * psd,struct psp_assoc * pas,struct netlink_ext_ack * extack)793 static int mlx5e_psp_assoc_add(struct psp_dev *psd, struct psp_assoc *pas,
794 struct netlink_ext_ack *extack)
795 {
796 struct mlx5e_priv *priv = netdev_priv(psd->main_netdev);
797 struct mlx5_core_dev *mdev = priv->mdev;
798 struct psp_key_parsed *tx = &pas->tx;
799 struct mlx5e_psp *psp = priv->psp;
800 struct psp_key *nkey;
801 int err;
802
803 mdev = priv->mdev;
804 nkey = (struct psp_key *)pas->drv_data;
805
806 err = mlx5_create_encryption_key(mdev, tx->key,
807 psp_key_size(pas->version),
808 MLX5_ACCEL_OBJ_PSP_KEY,
809 &nkey->id);
810 if (err) {
811 mlx5_core_err(mdev, "Failed to create encryption key (err = %d)\n", err);
812 return err;
813 }
814
815 atomic_inc(&psp->tx_key_cnt);
816 return 0;
817 }
818
mlx5e_psp_assoc_del(struct psp_dev * psd,struct psp_assoc * pas)819 static void mlx5e_psp_assoc_del(struct psp_dev *psd, struct psp_assoc *pas)
820 {
821 struct mlx5e_priv *priv = netdev_priv(psd->main_netdev);
822 struct mlx5e_psp *psp = priv->psp;
823 struct psp_key *nkey;
824
825 nkey = (struct psp_key *)pas->drv_data;
826 mlx5_destroy_encryption_key(priv->mdev, nkey->id);
827 atomic_dec(&psp->tx_key_cnt);
828 }
829
mlx5e_psp_rotate_key(struct mlx5_core_dev * mdev)830 static int mlx5e_psp_rotate_key(struct mlx5_core_dev *mdev)
831 {
832 u32 in[MLX5_ST_SZ_DW(psp_rotate_key_in)] = {};
833 u32 out[MLX5_ST_SZ_DW(psp_rotate_key_out)];
834
835 MLX5_SET(psp_rotate_key_in, in, opcode,
836 MLX5_CMD_OP_PSP_ROTATE_KEY);
837
838 return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
839 }
840
841 static int
mlx5e_psp_key_rotate(struct psp_dev * psd,struct netlink_ext_ack * exack)842 mlx5e_psp_key_rotate(struct psp_dev *psd, struct netlink_ext_ack *exack)
843 {
844 struct mlx5e_priv *priv = netdev_priv(psd->main_netdev);
845
846 /* no support for protecting against external rotations */
847 psd->generation = 0;
848
849 return mlx5e_psp_rotate_key(priv->mdev);
850 }
851
852 static struct psp_dev_ops mlx5_psp_ops = {
853 .set_config = mlx5e_psp_set_config,
854 .rx_spi_alloc = mlx5e_psp_rx_spi_alloc,
855 .tx_key_add = mlx5e_psp_assoc_add,
856 .tx_key_del = mlx5e_psp_assoc_del,
857 .key_rotate = mlx5e_psp_key_rotate,
858 };
859
mlx5e_psp_unregister(struct mlx5e_priv * priv)860 void mlx5e_psp_unregister(struct mlx5e_priv *priv)
861 {
862 if (!priv->psp || !priv->psp->psp)
863 return;
864
865 psp_dev_unregister(priv->psp->psp);
866 }
867
mlx5e_psp_register(struct mlx5e_priv * priv)868 void mlx5e_psp_register(struct mlx5e_priv *priv)
869 {
870 /* FW Caps missing */
871 if (!priv->psp)
872 return;
873
874 priv->psp->caps.assoc_drv_spc = sizeof(u32);
875 priv->psp->caps.versions = 1 << PSP_VERSION_HDR0_AES_GCM_128;
876 if (MLX5_CAP_PSP(priv->mdev, psp_crypto_esp_aes_gcm_256_encrypt) &&
877 MLX5_CAP_PSP(priv->mdev, psp_crypto_esp_aes_gcm_256_decrypt))
878 priv->psp->caps.versions |= 1 << PSP_VERSION_HDR0_AES_GCM_256;
879
880 priv->psp->psp = psp_dev_create(priv->netdev, &mlx5_psp_ops,
881 &priv->psp->caps, NULL);
882 if (IS_ERR(priv->psp->psp))
883 mlx5_core_err(priv->mdev, "PSP failed to register due to %pe\n",
884 priv->psp->psp);
885 }
886
mlx5e_psp_init(struct mlx5e_priv * priv)887 int mlx5e_psp_init(struct mlx5e_priv *priv)
888 {
889 struct mlx5_core_dev *mdev = priv->mdev;
890 struct mlx5e_psp_fs *fs;
891 struct mlx5e_psp *psp;
892 int err;
893
894 if (!mlx5_is_psp_device(mdev)) {
895 mlx5_core_dbg(mdev, "PSP offload not supported\n");
896 return 0;
897 }
898
899 if (!MLX5_CAP_ETH(mdev, swp)) {
900 mlx5_core_dbg(mdev, "SWP not supported\n");
901 return 0;
902 }
903
904 if (!MLX5_CAP_ETH(mdev, swp_csum)) {
905 mlx5_core_dbg(mdev, "SWP checksum not supported\n");
906 return 0;
907 }
908
909 if (!MLX5_CAP_ETH(mdev, swp_csum_l4_partial)) {
910 mlx5_core_dbg(mdev, "SWP L4 partial checksum not supported\n");
911 return 0;
912 }
913
914 if (!MLX5_CAP_ETH(mdev, swp_lso)) {
915 mlx5_core_dbg(mdev, "PSP LSO not supported\n");
916 return 0;
917 }
918
919 psp = kzalloc(sizeof(*psp), GFP_KERNEL);
920 if (!psp)
921 return -ENOMEM;
922
923 priv->psp = psp;
924 fs = mlx5e_accel_psp_fs_init(priv);
925 if (IS_ERR(fs)) {
926 err = PTR_ERR(fs);
927 goto out_err;
928 }
929
930 psp->fs = fs;
931
932 mlx5_core_dbg(priv->mdev, "PSP attached to netdevice\n");
933 return 0;
934
935 out_err:
936 priv->psp = NULL;
937 kfree(psp);
938 return err;
939 }
940
mlx5e_psp_cleanup(struct mlx5e_priv * priv)941 void mlx5e_psp_cleanup(struct mlx5e_priv *priv)
942 {
943 struct mlx5e_psp *psp = priv->psp;
944
945 if (!psp)
946 return;
947
948 WARN_ON(atomic_read(&psp->tx_key_cnt));
949 mlx5e_accel_psp_fs_cleanup(psp->fs);
950 priv->psp = NULL;
951 kfree(psp);
952 }
953