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