1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies */
3
4 #include "mlx5_core.h"
5 #include "fs_core.h"
6 #include "fs_cmd.h"
7 #include "mlx5dr.h"
8 #include "fs_dr.h"
9
mlx5_dr_is_fw_table(u32 flags)10 static bool mlx5_dr_is_fw_table(u32 flags)
11 {
12 if (flags & MLX5_FLOW_TABLE_TERMINATION)
13 return true;
14
15 return false;
16 }
17
mlx5_cmd_dr_update_root_ft(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,u32 underlay_qpn,bool disconnect)18 static int mlx5_cmd_dr_update_root_ft(struct mlx5_flow_root_namespace *ns,
19 struct mlx5_flow_table *ft,
20 u32 underlay_qpn,
21 bool disconnect)
22 {
23 return mlx5_fs_cmd_get_fw_cmds()->update_root_ft(ns, ft, underlay_qpn,
24 disconnect);
25 }
26
set_miss_action(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,struct mlx5_flow_table * next_ft)27 static int set_miss_action(struct mlx5_flow_root_namespace *ns,
28 struct mlx5_flow_table *ft,
29 struct mlx5_flow_table *next_ft)
30 {
31 struct mlx5dr_action *old_miss_action;
32 struct mlx5dr_action *action = NULL;
33 struct mlx5dr_table *next_tbl;
34 int err;
35
36 next_tbl = next_ft ? next_ft->fs_dr_table.dr_table : NULL;
37 if (next_tbl) {
38 action = mlx5dr_action_create_dest_table(next_tbl);
39 if (!action)
40 return -EINVAL;
41 }
42 old_miss_action = ft->fs_dr_table.miss_action;
43 err = mlx5dr_table_set_miss_action(ft->fs_dr_table.dr_table, action);
44 if (err && action) {
45 err = mlx5dr_action_destroy(action);
46 if (err)
47 mlx5_core_err(ns->dev,
48 "Failed to destroy action (%d)\n", err);
49 action = NULL;
50 }
51 ft->fs_dr_table.miss_action = action;
52 if (old_miss_action) {
53 err = mlx5dr_action_destroy(old_miss_action);
54 if (err)
55 mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n",
56 err);
57 }
58
59 return err;
60 }
61
mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,unsigned int size,struct mlx5_flow_table * next_ft)62 static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns,
63 struct mlx5_flow_table *ft,
64 unsigned int size,
65 struct mlx5_flow_table *next_ft)
66 {
67 struct mlx5dr_table *tbl;
68 u32 flags;
69 int err;
70
71 if (mlx5_dr_is_fw_table(ft->flags))
72 return mlx5_fs_cmd_get_fw_cmds()->create_flow_table(ns, ft,
73 size,
74 next_ft);
75 flags = ft->flags;
76 /* turn off encap/decap if not supported for sw-str by fw */
77 if (!MLX5_CAP_FLOWTABLE(ns->dev, sw_owner_reformat_supported))
78 flags = ft->flags & ~(MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
79 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
80
81 tbl = mlx5dr_table_create(ns->fs_dr_domain.dr_domain, ft->level, flags);
82 if (!tbl) {
83 mlx5_core_err(ns->dev, "Failed creating dr flow_table\n");
84 return -EINVAL;
85 }
86
87 ft->fs_dr_table.dr_table = tbl;
88 ft->id = mlx5dr_table_get_id(tbl);
89
90 if (next_ft) {
91 err = set_miss_action(ns, ft, next_ft);
92 if (err) {
93 mlx5dr_table_destroy(tbl);
94 ft->fs_dr_table.dr_table = NULL;
95 return err;
96 }
97 }
98
99 ft->max_fte = INT_MAX;
100
101 return 0;
102 }
103
mlx5_cmd_dr_destroy_flow_table(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft)104 static int mlx5_cmd_dr_destroy_flow_table(struct mlx5_flow_root_namespace *ns,
105 struct mlx5_flow_table *ft)
106 {
107 struct mlx5dr_action *action = ft->fs_dr_table.miss_action;
108 int err;
109
110 if (mlx5_dr_is_fw_table(ft->flags))
111 return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_table(ns, ft);
112
113 err = mlx5dr_table_destroy(ft->fs_dr_table.dr_table);
114 if (err) {
115 mlx5_core_err(ns->dev, "Failed to destroy flow_table (%d)\n",
116 err);
117 return err;
118 }
119 if (action) {
120 err = mlx5dr_action_destroy(action);
121 if (err) {
122 mlx5_core_err(ns->dev, "Failed to destroy action(%d)\n",
123 err);
124 return err;
125 }
126 }
127
128 return err;
129 }
130
mlx5_cmd_dr_modify_flow_table(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,struct mlx5_flow_table * next_ft)131 static int mlx5_cmd_dr_modify_flow_table(struct mlx5_flow_root_namespace *ns,
132 struct mlx5_flow_table *ft,
133 struct mlx5_flow_table *next_ft)
134 {
135 if (mlx5_dr_is_fw_table(ft->flags))
136 return mlx5_fs_cmd_get_fw_cmds()->modify_flow_table(ns, ft, next_ft);
137
138 return set_miss_action(ns, ft, next_ft);
139 }
140
mlx5_cmd_dr_create_flow_group(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,u32 * in,struct mlx5_flow_group * fg)141 static int mlx5_cmd_dr_create_flow_group(struct mlx5_flow_root_namespace *ns,
142 struct mlx5_flow_table *ft,
143 u32 *in,
144 struct mlx5_flow_group *fg)
145 {
146 struct mlx5dr_matcher *matcher;
147 u32 priority = MLX5_GET(create_flow_group_in, in,
148 start_flow_index);
149 u8 match_criteria_enable = MLX5_GET(create_flow_group_in,
150 in,
151 match_criteria_enable);
152 struct mlx5dr_match_parameters mask;
153
154 if (mlx5_dr_is_fw_table(ft->flags))
155 return mlx5_fs_cmd_get_fw_cmds()->create_flow_group(ns, ft, in,
156 fg);
157
158 mask.match_buf = MLX5_ADDR_OF(create_flow_group_in,
159 in, match_criteria);
160 mask.match_sz = sizeof(fg->mask.match_criteria);
161
162 matcher = mlx5dr_matcher_create(ft->fs_dr_table.dr_table,
163 priority,
164 match_criteria_enable,
165 &mask);
166 if (!matcher) {
167 mlx5_core_err(ns->dev, "Failed creating matcher\n");
168 return -EINVAL;
169 }
170
171 fg->fs_dr_matcher.dr_matcher = matcher;
172 return 0;
173 }
174
mlx5_cmd_dr_destroy_flow_group(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,struct mlx5_flow_group * fg)175 static int mlx5_cmd_dr_destroy_flow_group(struct mlx5_flow_root_namespace *ns,
176 struct mlx5_flow_table *ft,
177 struct mlx5_flow_group *fg)
178 {
179 if (mlx5_dr_is_fw_table(ft->flags))
180 return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_group(ns, ft, fg);
181
182 return mlx5dr_matcher_destroy(fg->fs_dr_matcher.dr_matcher);
183 }
184
create_vport_action(struct mlx5dr_domain * domain,struct mlx5_flow_rule * dst)185 static struct mlx5dr_action *create_vport_action(struct mlx5dr_domain *domain,
186 struct mlx5_flow_rule *dst)
187 {
188 struct mlx5_flow_destination *dest_attr = &dst->dest_attr;
189
190 return mlx5dr_action_create_dest_vport(domain, dest_attr->vport.num,
191 dest_attr->vport.flags &
192 MLX5_FLOW_DEST_VPORT_VHCA_ID,
193 dest_attr->vport.vhca_id);
194 }
195
create_ft_action(struct mlx5dr_domain * domain,struct mlx5_flow_rule * dst)196 static struct mlx5dr_action *create_ft_action(struct mlx5dr_domain *domain,
197 struct mlx5_flow_rule *dst)
198 {
199 struct mlx5_flow_table *dest_ft = dst->dest_attr.ft;
200
201 if (mlx5_dr_is_fw_table(dest_ft->flags))
202 return mlx5dr_action_create_dest_flow_fw_table(domain, dest_ft);
203 return mlx5dr_action_create_dest_table(dest_ft->fs_dr_table.dr_table);
204 }
205
create_action_push_vlan(struct mlx5dr_domain * domain,struct mlx5_fs_vlan * vlan)206 static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domain,
207 struct mlx5_fs_vlan *vlan)
208 {
209 u16 n_ethtype = vlan->ethtype;
210 u8 prio = vlan->prio;
211 u16 vid = vlan->vid;
212 u32 vlan_hdr;
213
214 vlan_hdr = (u32)n_ethtype << 16 | (u32)(prio) << 12 | (u32)vid;
215 return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr));
216 }
217
contain_vport_reformat_action(struct mlx5_flow_rule * dst)218 static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst)
219 {
220 return dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
221 dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
222 }
223
224 #define MLX5_FLOW_CONTEXT_ACTION_MAX 20
mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,struct mlx5_flow_group * group,struct fs_fte * fte)225 static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
226 struct mlx5_flow_table *ft,
227 struct mlx5_flow_group *group,
228 struct fs_fte *fte)
229 {
230 struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain;
231 struct mlx5dr_action_dest *term_actions;
232 struct mlx5dr_match_parameters params;
233 struct mlx5_core_dev *dev = ns->dev;
234 struct mlx5dr_action **fs_dr_actions;
235 struct mlx5dr_action *tmp_action;
236 struct mlx5dr_action **actions;
237 bool delay_encap_set = false;
238 struct mlx5dr_rule *rule;
239 struct mlx5_flow_rule *dst;
240 int fs_dr_num_actions = 0;
241 int num_term_actions = 0;
242 int num_actions = 0;
243 size_t match_sz;
244 int err = 0;
245 int i;
246
247 if (mlx5_dr_is_fw_table(ft->flags))
248 return mlx5_fs_cmd_get_fw_cmds()->create_fte(ns, ft, group, fte);
249
250 actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions),
251 GFP_KERNEL);
252 if (!actions) {
253 err = -ENOMEM;
254 goto out_err;
255 }
256
257 fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX,
258 sizeof(*fs_dr_actions), GFP_KERNEL);
259 if (!fs_dr_actions) {
260 err = -ENOMEM;
261 goto free_actions_alloc;
262 }
263
264 term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX,
265 sizeof(*term_actions), GFP_KERNEL);
266 if (!term_actions) {
267 err = -ENOMEM;
268 goto free_fs_dr_actions_alloc;
269 }
270
271 match_sz = sizeof(fte->val);
272
273 /* Drop reformat action bit if destination vport set with reformat */
274 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
275 list_for_each_entry(dst, &fte->node.children, node.list) {
276 if (!contain_vport_reformat_action(dst))
277 continue;
278
279 fte->action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
280 break;
281 }
282 }
283
284 /* The order of the actions are must to be keep, only the following
285 * order is supported by SW steering:
286 * TX: modify header -> push vlan -> encap
287 * RX: decap -> pop vlan -> modify header
288 */
289 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
290 enum mlx5dr_action_reformat_type decap_type =
291 DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2;
292
293 tmp_action = mlx5dr_action_create_packet_reformat(domain,
294 decap_type,
295 0, 0, 0,
296 NULL);
297 if (!tmp_action) {
298 err = -ENOMEM;
299 goto free_actions;
300 }
301 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
302 actions[num_actions++] = tmp_action;
303 }
304
305 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) {
306 bool is_decap = fte->action.pkt_reformat->reformat_type ==
307 MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
308
309 if (is_decap)
310 actions[num_actions++] =
311 fte->action.pkt_reformat->action.dr_action;
312 else
313 delay_encap_set = true;
314 }
315
316 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) {
317 tmp_action =
318 mlx5dr_action_create_pop_vlan();
319 if (!tmp_action) {
320 err = -ENOMEM;
321 goto free_actions;
322 }
323 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
324 actions[num_actions++] = tmp_action;
325 }
326
327 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2) {
328 tmp_action =
329 mlx5dr_action_create_pop_vlan();
330 if (!tmp_action) {
331 err = -ENOMEM;
332 goto free_actions;
333 }
334 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
335 actions[num_actions++] = tmp_action;
336 }
337
338 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
339 actions[num_actions++] =
340 fte->action.modify_hdr->action.dr_action;
341
342 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
343 tmp_action = create_action_push_vlan(domain, &fte->action.vlan[0]);
344 if (!tmp_action) {
345 err = -ENOMEM;
346 goto free_actions;
347 }
348 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
349 actions[num_actions++] = tmp_action;
350 }
351
352 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
353 tmp_action = create_action_push_vlan(domain, &fte->action.vlan[1]);
354 if (!tmp_action) {
355 err = -ENOMEM;
356 goto free_actions;
357 }
358 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
359 actions[num_actions++] = tmp_action;
360 }
361
362 if (delay_encap_set)
363 actions[num_actions++] =
364 fte->action.pkt_reformat->action.dr_action;
365
366 /* The order of the actions below is not important */
367
368 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_DROP) {
369 tmp_action = mlx5dr_action_create_drop();
370 if (!tmp_action) {
371 err = -ENOMEM;
372 goto free_actions;
373 }
374 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
375 term_actions[num_term_actions++].dest = tmp_action;
376 }
377
378 if (fte->flow_context.flow_tag) {
379 tmp_action =
380 mlx5dr_action_create_tag(fte->flow_context.flow_tag);
381 if (!tmp_action) {
382 err = -ENOMEM;
383 goto free_actions;
384 }
385 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
386 actions[num_actions++] = tmp_action;
387 }
388
389 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
390 list_for_each_entry(dst, &fte->node.children, node.list) {
391 enum mlx5_flow_destination_type type = dst->dest_attr.type;
392 u32 id;
393
394 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
395 num_term_actions >= MLX5_FLOW_CONTEXT_ACTION_MAX) {
396 err = -ENOSPC;
397 goto free_actions;
398 }
399
400 if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
401 continue;
402
403 switch (type) {
404 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
405 tmp_action = create_ft_action(domain, dst);
406 if (!tmp_action) {
407 err = -ENOMEM;
408 goto free_actions;
409 }
410 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
411 term_actions[num_term_actions++].dest = tmp_action;
412 break;
413 case MLX5_FLOW_DESTINATION_TYPE_VPORT:
414 tmp_action = create_vport_action(domain, dst);
415 if (!tmp_action) {
416 err = -ENOMEM;
417 goto free_actions;
418 }
419 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
420 term_actions[num_term_actions].dest = tmp_action;
421
422 if (dst->dest_attr.vport.flags &
423 MLX5_FLOW_DEST_VPORT_REFORMAT_ID)
424 term_actions[num_term_actions].reformat =
425 dst->dest_attr.vport.pkt_reformat->action.dr_action;
426
427 num_term_actions++;
428 break;
429 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM:
430 id = dst->dest_attr.ft_num;
431 tmp_action = mlx5dr_action_create_dest_table_num(domain,
432 id);
433 if (!tmp_action) {
434 err = -ENOMEM;
435 goto free_actions;
436 }
437 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
438 term_actions[num_term_actions++].dest = tmp_action;
439 break;
440 case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER:
441 id = dst->dest_attr.sampler_id;
442 tmp_action = mlx5dr_action_create_flow_sampler(domain,
443 id);
444 if (!tmp_action) {
445 err = -ENOMEM;
446 goto free_actions;
447 }
448 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
449 term_actions[num_term_actions++].dest = tmp_action;
450 break;
451 default:
452 err = -EOPNOTSUPP;
453 goto free_actions;
454 }
455 }
456 }
457
458 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
459 list_for_each_entry(dst, &fte->node.children, node.list) {
460 u32 id;
461
462 if (dst->dest_attr.type !=
463 MLX5_FLOW_DESTINATION_TYPE_COUNTER)
464 continue;
465
466 if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
467 err = -ENOSPC;
468 goto free_actions;
469 }
470
471 id = dst->dest_attr.counter_id;
472 tmp_action =
473 mlx5dr_action_create_flow_counter(id);
474 if (!tmp_action) {
475 err = -ENOMEM;
476 goto free_actions;
477 }
478
479 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
480 actions[num_actions++] = tmp_action;
481 }
482 }
483
484 params.match_sz = match_sz;
485 params.match_buf = (u64 *)fte->val;
486 if (num_term_actions == 1) {
487 if (term_actions->reformat)
488 actions[num_actions++] = term_actions->reformat;
489
490 actions[num_actions++] = term_actions->dest;
491 } else if (num_term_actions > 1) {
492 bool ignore_flow_level =
493 !!(fte->action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL);
494 u32 flow_source = fte->flow_context.flow_source;
495
496 tmp_action = mlx5dr_action_create_mult_dest_tbl(domain,
497 term_actions,
498 num_term_actions,
499 ignore_flow_level,
500 flow_source);
501 if (!tmp_action) {
502 err = -EOPNOTSUPP;
503 goto free_actions;
504 }
505 fs_dr_actions[fs_dr_num_actions++] = tmp_action;
506 actions[num_actions++] = tmp_action;
507 }
508
509 rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher,
510 ¶ms,
511 num_actions,
512 actions,
513 fte->flow_context.flow_source);
514 if (!rule) {
515 err = -EINVAL;
516 goto free_actions;
517 }
518
519 kfree(term_actions);
520 kfree(actions);
521
522 fte->fs_dr_rule.dr_rule = rule;
523 fte->fs_dr_rule.num_actions = fs_dr_num_actions;
524 fte->fs_dr_rule.dr_actions = fs_dr_actions;
525
526 return 0;
527
528 free_actions:
529 /* Free in reverse order to handle action dependencies */
530 for (i = fs_dr_num_actions - 1; i >= 0; i--)
531 if (!IS_ERR_OR_NULL(fs_dr_actions[i]))
532 mlx5dr_action_destroy(fs_dr_actions[i]);
533
534 kfree(term_actions);
535 free_fs_dr_actions_alloc:
536 kfree(fs_dr_actions);
537 free_actions_alloc:
538 kfree(actions);
539 out_err:
540 mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err);
541 return err;
542 }
543
mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace * ns,struct mlx5_pkt_reformat_params * params,enum mlx5_flow_namespace_type namespace,struct mlx5_pkt_reformat * pkt_reformat)544 static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
545 struct mlx5_pkt_reformat_params *params,
546 enum mlx5_flow_namespace_type namespace,
547 struct mlx5_pkt_reformat *pkt_reformat)
548 {
549 struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain;
550 struct mlx5dr_action *action;
551 int dr_reformat;
552
553 switch (params->type) {
554 case MLX5_REFORMAT_TYPE_L2_TO_VXLAN:
555 case MLX5_REFORMAT_TYPE_L2_TO_NVGRE:
556 case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
557 dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2;
558 break;
559 case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
560 dr_reformat = DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2;
561 break;
562 case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
563 dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3;
564 break;
565 case MLX5_REFORMAT_TYPE_INSERT_HDR:
566 dr_reformat = DR_ACTION_REFORMAT_TYP_INSERT_HDR;
567 break;
568 case MLX5_REFORMAT_TYPE_REMOVE_HDR:
569 dr_reformat = DR_ACTION_REFORMAT_TYP_REMOVE_HDR;
570 break;
571 default:
572 mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n",
573 params->type);
574 return -EOPNOTSUPP;
575 }
576
577 action = mlx5dr_action_create_packet_reformat(dr_domain,
578 dr_reformat,
579 params->param_0,
580 params->param_1,
581 params->size,
582 params->data);
583 if (!action) {
584 mlx5_core_err(ns->dev, "Failed allocating packet-reformat action\n");
585 return -EINVAL;
586 }
587
588 pkt_reformat->action.dr_action = action;
589
590 return 0;
591 }
592
mlx5_cmd_dr_packet_reformat_dealloc(struct mlx5_flow_root_namespace * ns,struct mlx5_pkt_reformat * pkt_reformat)593 static void mlx5_cmd_dr_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns,
594 struct mlx5_pkt_reformat *pkt_reformat)
595 {
596 mlx5dr_action_destroy(pkt_reformat->action.dr_action);
597 }
598
mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace * ns,u8 namespace,u8 num_actions,void * modify_actions,struct mlx5_modify_hdr * modify_hdr)599 static int mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
600 u8 namespace, u8 num_actions,
601 void *modify_actions,
602 struct mlx5_modify_hdr *modify_hdr)
603 {
604 struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain;
605 struct mlx5dr_action *action;
606 size_t actions_sz;
607
608 actions_sz = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) *
609 num_actions;
610 action = mlx5dr_action_create_modify_header(dr_domain, 0,
611 actions_sz,
612 modify_actions);
613 if (!action) {
614 mlx5_core_err(ns->dev, "Failed allocating modify-header action\n");
615 return -EINVAL;
616 }
617
618 modify_hdr->action.dr_action = action;
619
620 return 0;
621 }
622
mlx5_cmd_dr_modify_header_dealloc(struct mlx5_flow_root_namespace * ns,struct mlx5_modify_hdr * modify_hdr)623 static void mlx5_cmd_dr_modify_header_dealloc(struct mlx5_flow_root_namespace *ns,
624 struct mlx5_modify_hdr *modify_hdr)
625 {
626 mlx5dr_action_destroy(modify_hdr->action.dr_action);
627 }
628
mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,struct fs_fte * fte)629 static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns,
630 struct mlx5_flow_table *ft,
631 struct fs_fte *fte)
632 {
633 struct mlx5_fs_dr_rule *rule = &fte->fs_dr_rule;
634 int err;
635 int i;
636
637 if (mlx5_dr_is_fw_table(ft->flags))
638 return mlx5_fs_cmd_get_fw_cmds()->delete_fte(ns, ft, fte);
639
640 err = mlx5dr_rule_destroy(rule->dr_rule);
641 if (err)
642 return err;
643
644 /* Free in reverse order to handle action dependencies */
645 for (i = rule->num_actions - 1; i >= 0; i--)
646 if (!IS_ERR_OR_NULL(rule->dr_actions[i]))
647 mlx5dr_action_destroy(rule->dr_actions[i]);
648
649 kfree(rule->dr_actions);
650 return 0;
651 }
652
mlx5_cmd_dr_update_fte(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_table * ft,struct mlx5_flow_group * group,int modify_mask,struct fs_fte * fte)653 static int mlx5_cmd_dr_update_fte(struct mlx5_flow_root_namespace *ns,
654 struct mlx5_flow_table *ft,
655 struct mlx5_flow_group *group,
656 int modify_mask,
657 struct fs_fte *fte)
658 {
659 struct fs_fte fte_tmp = {};
660 int ret;
661
662 if (mlx5_dr_is_fw_table(ft->flags))
663 return mlx5_fs_cmd_get_fw_cmds()->update_fte(ns, ft, group, modify_mask, fte);
664
665 /* Backup current dr rule details */
666 fte_tmp.fs_dr_rule = fte->fs_dr_rule;
667 memset(&fte->fs_dr_rule, 0, sizeof(struct mlx5_fs_dr_rule));
668
669 /* First add the new updated rule, then delete the old rule */
670 ret = mlx5_cmd_dr_create_fte(ns, ft, group, fte);
671 if (ret)
672 goto restore_fte;
673
674 ret = mlx5_cmd_dr_delete_fte(ns, ft, &fte_tmp);
675 WARN_ONCE(ret, "dr update fte duplicate rule deletion failed\n");
676 return ret;
677
678 restore_fte:
679 fte->fs_dr_rule = fte_tmp.fs_dr_rule;
680 return ret;
681 }
682
mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace * ns,struct mlx5_flow_root_namespace * peer_ns)683 static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns,
684 struct mlx5_flow_root_namespace *peer_ns)
685 {
686 struct mlx5dr_domain *peer_domain = NULL;
687
688 if (peer_ns)
689 peer_domain = peer_ns->fs_dr_domain.dr_domain;
690 mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain,
691 peer_domain);
692 return 0;
693 }
694
mlx5_cmd_dr_create_ns(struct mlx5_flow_root_namespace * ns)695 static int mlx5_cmd_dr_create_ns(struct mlx5_flow_root_namespace *ns)
696 {
697 ns->fs_dr_domain.dr_domain =
698 mlx5dr_domain_create(ns->dev,
699 MLX5DR_DOMAIN_TYPE_FDB);
700 if (!ns->fs_dr_domain.dr_domain) {
701 mlx5_core_err(ns->dev, "Failed to create dr flow namespace\n");
702 return -EOPNOTSUPP;
703 }
704 return 0;
705 }
706
mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace * ns)707 static int mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace *ns)
708 {
709 return mlx5dr_domain_destroy(ns->fs_dr_domain.dr_domain);
710 }
711
mlx5_fs_dr_is_supported(struct mlx5_core_dev * dev)712 bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev)
713 {
714 return mlx5dr_is_supported(dev);
715 }
716
717 static const struct mlx5_flow_cmds mlx5_flow_cmds_dr = {
718 .create_flow_table = mlx5_cmd_dr_create_flow_table,
719 .destroy_flow_table = mlx5_cmd_dr_destroy_flow_table,
720 .modify_flow_table = mlx5_cmd_dr_modify_flow_table,
721 .create_flow_group = mlx5_cmd_dr_create_flow_group,
722 .destroy_flow_group = mlx5_cmd_dr_destroy_flow_group,
723 .create_fte = mlx5_cmd_dr_create_fte,
724 .update_fte = mlx5_cmd_dr_update_fte,
725 .delete_fte = mlx5_cmd_dr_delete_fte,
726 .update_root_ft = mlx5_cmd_dr_update_root_ft,
727 .packet_reformat_alloc = mlx5_cmd_dr_packet_reformat_alloc,
728 .packet_reformat_dealloc = mlx5_cmd_dr_packet_reformat_dealloc,
729 .modify_header_alloc = mlx5_cmd_dr_modify_header_alloc,
730 .modify_header_dealloc = mlx5_cmd_dr_modify_header_dealloc,
731 .set_peer = mlx5_cmd_dr_set_peer,
732 .create_ns = mlx5_cmd_dr_create_ns,
733 .destroy_ns = mlx5_cmd_dr_destroy_ns,
734 };
735
mlx5_fs_cmd_get_dr_cmds(void)736 const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void)
737 {
738 return &mlx5_flow_cmds_dr;
739 }
740