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