1 /*-
2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: stable/12/sys/dev/mlx5/mlx5_core/mlx5_fs_tree.c 372305 2022-07-29 17:11:01Z git2svn $
26 */
27
28 #include <linux/module.h>
29 #include <dev/mlx5/driver.h>
30 #include "mlx5_core.h"
31 #include "fs_core.h"
32 #include <linux/string.h>
33 #include <linux/compiler.h>
34
35 #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
36 sizeof(struct init_tree_node))
37
38 #define ADD_PRIO(name_val, flags_val, min_level_val, max_ft_val, caps_val, \
39 ...) {.type = FS_TYPE_PRIO,\
40 .name = name_val,\
41 .min_ft_level = min_level_val,\
42 .flags = flags_val,\
43 .max_ft = max_ft_val,\
44 .caps = caps_val,\
45 .children = (struct init_tree_node[]) {__VA_ARGS__},\
46 .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
47 }
48
49 #define ADD_FT_PRIO(name_val, flags_val, max_ft_val, ...)\
50 ADD_PRIO(name_val, flags_val, 0, max_ft_val, {},\
51 __VA_ARGS__)\
52
53 #define ADD_NS(name_val, ...) {.type = FS_TYPE_NAMESPACE,\
54 .name = name_val,\
55 .children = (struct init_tree_node[]) {__VA_ARGS__},\
56 .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
57 }
58
59 #define INIT_CAPS_ARRAY_SIZE(...) (sizeof((long[]){__VA_ARGS__}) /\
60 sizeof(long))
61
62 #define FS_CAP(cap) (__mlx5_bit_off(flow_table_nic_cap, cap))
63
64 #define FS_REQUIRED_CAPS(...) {.arr_sz = INIT_CAPS_ARRAY_SIZE(__VA_ARGS__), \
65 .caps = (long[]) {__VA_ARGS__}}
66
67 #define BYPASS_MAX_FT 5
68 #define BYPASS_PRIO_MAX_FT 1
69 #define KERNEL_MAX_FT 3
70 #define LEFTOVER_MAX_FT 1
71 #define KENREL_MIN_LEVEL 3
72 #define LEFTOVER_MIN_LEVEL KENREL_MIN_LEVEL + 1
73 #define BYPASS_MIN_LEVEL MLX5_NUM_BYPASS_FTS + LEFTOVER_MIN_LEVEL
74 struct node_caps {
75 size_t arr_sz;
76 long *caps;
77 };
78
79 struct init_tree_node {
80 enum fs_type type;
81 const char *name;
82 struct init_tree_node *children;
83 int ar_size;
84 struct node_caps caps;
85 u8 flags;
86 int min_ft_level;
87 int prio;
88 int max_ft;
89 } root_fs = {
90 .type = FS_TYPE_NAMESPACE,
91 .name = "root",
92 .ar_size = 3,
93 .children = (struct init_tree_node[]) {
94 ADD_PRIO("by_pass_prio", 0, BYPASS_MIN_LEVEL, 0,
95 FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en),
96 FS_CAP(flow_table_properties_nic_receive.modify_root)),
97 ADD_NS("by_pass_ns",
98 ADD_FT_PRIO("prio0", 0,
99 BYPASS_PRIO_MAX_FT),
100 ADD_FT_PRIO("prio1", 0,
101 BYPASS_PRIO_MAX_FT),
102 ADD_FT_PRIO("prio2", 0,
103 BYPASS_PRIO_MAX_FT),
104 ADD_FT_PRIO("prio3", 0,
105 BYPASS_PRIO_MAX_FT),
106 ADD_FT_PRIO("prio4", 0,
107 BYPASS_PRIO_MAX_FT),
108 ADD_FT_PRIO("prio5", 0,
109 BYPASS_PRIO_MAX_FT),
110 ADD_FT_PRIO("prio6", 0,
111 BYPASS_PRIO_MAX_FT),
112 ADD_FT_PRIO("prio7", 0,
113 BYPASS_PRIO_MAX_FT),
114 ADD_FT_PRIO("prio-mcast", 0,
115 BYPASS_PRIO_MAX_FT))),
116 ADD_PRIO("kernel_prio", 0, KENREL_MIN_LEVEL, 0, {},
117 ADD_NS("kernel_ns",
118 ADD_FT_PRIO("prio_kernel-0", 0,
119 KERNEL_MAX_FT))),
120 ADD_PRIO("leftovers_prio", MLX5_CORE_FS_PRIO_SHARED,
121 LEFTOVER_MIN_LEVEL, 0,
122 FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en),
123 FS_CAP(flow_table_properties_nic_receive.modify_root)),
124 ADD_NS("leftover_ns",
125 ADD_FT_PRIO("leftovers_prio-0",
126 MLX5_CORE_FS_PRIO_SHARED,
127 LEFTOVER_MAX_FT)))
128 }
129 };
130
131 /* Tree creation functions */
132
find_root(struct fs_base * node)133 static struct mlx5_flow_root_namespace *find_root(struct fs_base *node)
134 {
135 struct fs_base *parent;
136
137 /* Make sure we only read it once while we go up the tree */
138 while ((parent = node->parent))
139 node = parent;
140
141 if (node->type != FS_TYPE_NAMESPACE) {
142 return NULL;
143 }
144
145 return container_of(container_of(node,
146 struct mlx5_flow_namespace,
147 base),
148 struct mlx5_flow_root_namespace,
149 ns);
150 }
151
fs_get_dev(struct fs_base * node)152 static inline struct mlx5_core_dev *fs_get_dev(struct fs_base *node)
153 {
154 struct mlx5_flow_root_namespace *root = find_root(node);
155
156 if (root)
157 return root->dev;
158 return NULL;
159 }
160
fs_init_node(struct fs_base * node,unsigned int refcount)161 static void fs_init_node(struct fs_base *node,
162 unsigned int refcount)
163 {
164 kref_init(&node->refcount);
165 atomic_set(&node->users_refcount, refcount);
166 init_completion(&node->complete);
167 INIT_LIST_HEAD(&node->list);
168 mutex_init(&node->lock);
169 }
170
_fs_add_node(struct fs_base * node,const char * name,struct fs_base * parent)171 static void _fs_add_node(struct fs_base *node,
172 const char *name,
173 struct fs_base *parent)
174 {
175 if (parent)
176 atomic_inc(&parent->users_refcount);
177 node->name = kstrdup_const(name, GFP_KERNEL);
178 node->parent = parent;
179 }
180
fs_add_node(struct fs_base * node,struct fs_base * parent,const char * name,unsigned int refcount)181 static void fs_add_node(struct fs_base *node,
182 struct fs_base *parent, const char *name,
183 unsigned int refcount)
184 {
185 fs_init_node(node, refcount);
186 _fs_add_node(node, name, parent);
187 }
188
189 static void _fs_put(struct fs_base *node, void (*kref_cb)(struct kref *kref),
190 bool parent_locked);
191
192 static void fs_del_dst(struct mlx5_flow_rule *dst);
193 static void _fs_del_ft(struct mlx5_flow_table *ft);
194 static void fs_del_fg(struct mlx5_flow_group *fg);
195 static void fs_del_fte(struct fs_fte *fte);
196
cmd_remove_node(struct fs_base * base)197 static void cmd_remove_node(struct fs_base *base)
198 {
199 switch (base->type) {
200 case FS_TYPE_FLOW_DEST:
201 fs_del_dst(container_of(base, struct mlx5_flow_rule, base));
202 break;
203 case FS_TYPE_FLOW_TABLE:
204 _fs_del_ft(container_of(base, struct mlx5_flow_table, base));
205 break;
206 case FS_TYPE_FLOW_GROUP:
207 fs_del_fg(container_of(base, struct mlx5_flow_group, base));
208 break;
209 case FS_TYPE_FLOW_ENTRY:
210 fs_del_fte(container_of(base, struct fs_fte, base));
211 break;
212 default:
213 break;
214 }
215 }
216
__fs_remove_node(struct kref * kref)217 static void __fs_remove_node(struct kref *kref)
218 {
219 struct fs_base *node = container_of(kref, struct fs_base, refcount);
220
221 if (node->parent)
222 mutex_lock(&node->parent->lock);
223 mutex_lock(&node->lock);
224 cmd_remove_node(node);
225 mutex_unlock(&node->lock);
226 complete(&node->complete);
227 if (node->parent) {
228 mutex_unlock(&node->parent->lock);
229 _fs_put(node->parent, _fs_remove_node, false);
230 }
231 }
232
_fs_remove_node(struct kref * kref)233 void _fs_remove_node(struct kref *kref)
234 {
235 struct fs_base *node = container_of(kref, struct fs_base, refcount);
236
237 __fs_remove_node(kref);
238 kfree_const(node->name);
239 kfree(node);
240 }
241
fs_get(struct fs_base * node)242 static void fs_get(struct fs_base *node)
243 {
244 atomic_inc(&node->users_refcount);
245 }
246
_fs_put(struct fs_base * node,void (* kref_cb)(struct kref * kref),bool parent_locked)247 static void _fs_put(struct fs_base *node, void (*kref_cb)(struct kref *kref),
248 bool parent_locked)
249 {
250 struct fs_base *parent_node = node->parent;
251
252 if (parent_node && !parent_locked)
253 mutex_lock(&parent_node->lock);
254 if (atomic_dec_and_test(&node->users_refcount)) {
255 if (parent_node) {
256 /*remove from parent's list*/
257 list_del_init(&node->list);
258 mutex_unlock(&parent_node->lock);
259 }
260 kref_put(&node->refcount, kref_cb);
261 if (parent_node && parent_locked)
262 mutex_lock(&parent_node->lock);
263 } else if (parent_node && !parent_locked) {
264 mutex_unlock(&parent_node->lock);
265 }
266 }
267
fs_put(struct fs_base * node)268 static void fs_put(struct fs_base *node)
269 {
270 _fs_put(node, __fs_remove_node, false);
271 }
272
fs_put_parent_locked(struct fs_base * node)273 static void fs_put_parent_locked(struct fs_base *node)
274 {
275 _fs_put(node, __fs_remove_node, true);
276 }
277
fs_remove_node(struct fs_base * node)278 static void fs_remove_node(struct fs_base *node)
279 {
280 fs_put(node);
281 wait_for_completion(&node->complete);
282 kfree_const(node->name);
283 kfree(node);
284 }
285
fs_remove_node_parent_locked(struct fs_base * node)286 static void fs_remove_node_parent_locked(struct fs_base *node)
287 {
288 fs_put_parent_locked(node);
289 wait_for_completion(&node->complete);
290 kfree_const(node->name);
291 kfree(node);
292 }
293
fs_alloc_fte(u8 action,u32 flow_tag,u32 * match_value,unsigned int index)294 static struct fs_fte *fs_alloc_fte(u8 action,
295 u32 flow_tag,
296 u32 *match_value,
297 unsigned int index)
298 {
299 struct fs_fte *fte;
300
301
302 fte = kzalloc(sizeof(*fte), GFP_KERNEL);
303 if (!fte)
304 return ERR_PTR(-ENOMEM);
305
306 memcpy(fte->val, match_value, sizeof(fte->val));
307 fte->base.type = FS_TYPE_FLOW_ENTRY;
308 fte->dests_size = 0;
309 fte->flow_tag = flow_tag;
310 fte->index = index;
311 INIT_LIST_HEAD(&fte->dests);
312 fte->action = action;
313
314 return fte;
315 }
316
alloc_star_ft_entry(struct mlx5_flow_table * ft,struct mlx5_flow_group * fg,u32 * match_value,unsigned int index)317 static struct fs_fte *alloc_star_ft_entry(struct mlx5_flow_table *ft,
318 struct mlx5_flow_group *fg,
319 u32 *match_value,
320 unsigned int index)
321 {
322 int err;
323 struct fs_fte *fte;
324 struct mlx5_flow_rule *dst;
325
326 if (fg->num_ftes == fg->max_ftes)
327 return ERR_PTR(-ENOSPC);
328
329 fte = fs_alloc_fte(MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
330 MLX5_FS_DEFAULT_FLOW_TAG, match_value, index);
331 if (IS_ERR(fte))
332 return fte;
333
334 /*create dst*/
335 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
336 if (!dst) {
337 err = -ENOMEM;
338 goto free_fte;
339 }
340
341 fte->base.parent = &fg->base;
342 fte->dests_size = 1;
343 dst->dest_attr.type = MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE;
344 dst->base.parent = &fte->base;
345 list_add(&dst->base.list, &fte->dests);
346 /* assumed that the callee creates the star rules sorted by index */
347 list_add_tail(&fte->base.list, &fg->ftes);
348 fg->num_ftes++;
349
350 return fte;
351
352 free_fte:
353 kfree(fte);
354 return ERR_PTR(err);
355 }
356
357 /* assume that fte can't be changed */
free_star_fte_entry(struct fs_fte * fte)358 static void free_star_fte_entry(struct fs_fte *fte)
359 {
360 struct mlx5_flow_group *fg;
361 struct mlx5_flow_rule *dst, *temp;
362
363 fs_get_parent(fg, fte);
364
365 list_for_each_entry_safe(dst, temp, &fte->dests, base.list) {
366 fte->dests_size--;
367 list_del(&dst->base.list);
368 kfree(dst);
369 }
370
371 list_del(&fte->base.list);
372 fg->num_ftes--;
373 kfree(fte);
374 }
375
fs_alloc_fg(u32 * create_fg_in)376 static struct mlx5_flow_group *fs_alloc_fg(u32 *create_fg_in)
377 {
378 struct mlx5_flow_group *fg;
379 void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
380 create_fg_in, match_criteria);
381 u8 match_criteria_enable = MLX5_GET(create_flow_group_in,
382 create_fg_in,
383 match_criteria_enable);
384 fg = kzalloc(sizeof(*fg), GFP_KERNEL);
385 if (!fg)
386 return ERR_PTR(-ENOMEM);
387
388 INIT_LIST_HEAD(&fg->ftes);
389 fg->mask.match_criteria_enable = match_criteria_enable;
390 memcpy(&fg->mask.match_criteria, match_criteria,
391 sizeof(fg->mask.match_criteria));
392 fg->base.type = FS_TYPE_FLOW_GROUP;
393 fg->start_index = MLX5_GET(create_flow_group_in, create_fg_in,
394 start_flow_index);
395 fg->max_ftes = MLX5_GET(create_flow_group_in, create_fg_in,
396 end_flow_index) - fg->start_index + 1;
397 return fg;
398 }
399
400 static struct mlx5_flow_table *find_next_ft(struct fs_prio *prio);
401 static struct mlx5_flow_table *find_prev_ft(struct mlx5_flow_table *curr,
402 struct fs_prio *prio);
403
404 /* assumed src_ft and dst_ft can't be freed */
fs_set_star_rule(struct mlx5_core_dev * dev,struct mlx5_flow_table * src_ft,struct mlx5_flow_table * dst_ft)405 static int fs_set_star_rule(struct mlx5_core_dev *dev,
406 struct mlx5_flow_table *src_ft,
407 struct mlx5_flow_table *dst_ft)
408 {
409 struct mlx5_flow_rule *src_dst;
410 struct fs_fte *src_fte;
411 int err = 0;
412 u32 *match_value;
413 int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
414
415 src_dst = list_first_entry(&src_ft->star_rule.fte->dests,
416 struct mlx5_flow_rule, base.list);
417 match_value = mlx5_vzalloc(match_len);
418 if (!match_value) {
419 mlx5_core_warn(dev, "failed to allocate inbox\n");
420 return -ENOMEM;
421 }
422 /*Create match context*/
423
424 fs_get_parent(src_fte, src_dst);
425
426 src_dst->dest_attr.ft = dst_ft;
427 if (dst_ft) {
428 err = mlx5_cmd_fs_set_fte(dev,
429 src_ft->vport,
430 &src_fte->status,
431 match_value, src_ft->type,
432 src_ft->id, src_fte->index,
433 src_ft->star_rule.fg->id,
434 src_fte->flow_tag,
435 src_fte->action,
436 src_fte->dests_size,
437 &src_fte->dests);
438 if (err)
439 goto free;
440
441 fs_get(&dst_ft->base);
442 } else {
443 mlx5_cmd_fs_delete_fte(dev,
444 src_ft->vport,
445 &src_fte->status,
446 src_ft->type, src_ft->id,
447 src_fte->index);
448 }
449
450 free:
451 kvfree(match_value);
452 return err;
453 }
454
connect_prev_fts(struct fs_prio * locked_prio,struct fs_prio * prev_prio,struct mlx5_flow_table * next_ft)455 static int connect_prev_fts(struct fs_prio *locked_prio,
456 struct fs_prio *prev_prio,
457 struct mlx5_flow_table *next_ft)
458 {
459 struct mlx5_flow_table *iter;
460 int err = 0;
461 struct mlx5_core_dev *dev = fs_get_dev(&prev_prio->base);
462
463 if (!dev)
464 return -ENODEV;
465
466 mutex_lock(&prev_prio->base.lock);
467 fs_for_each_ft(iter, prev_prio) {
468 struct mlx5_flow_rule *src_dst =
469 list_first_entry(&iter->star_rule.fte->dests,
470 struct mlx5_flow_rule, base.list);
471 struct mlx5_flow_table *prev_ft = src_dst->dest_attr.ft;
472
473 if (prev_ft == next_ft)
474 continue;
475
476 err = fs_set_star_rule(dev, iter, next_ft);
477 if (err) {
478 mlx5_core_warn(dev,
479 "mlx5: flow steering can't connect prev and next\n");
480 goto unlock;
481 } else {
482 /* Assume ft's prio is locked */
483 if (prev_ft) {
484 struct fs_prio *prio;
485
486 fs_get_parent(prio, prev_ft);
487 if (prio == locked_prio)
488 fs_put_parent_locked(&prev_ft->base);
489 else
490 fs_put(&prev_ft->base);
491 }
492 }
493 }
494
495 unlock:
496 mutex_unlock(&prev_prio->base.lock);
497 return 0;
498 }
499
create_star_rule(struct mlx5_flow_table * ft,struct fs_prio * prio)500 static int create_star_rule(struct mlx5_flow_table *ft, struct fs_prio *prio)
501 {
502 struct mlx5_flow_group *fg;
503 int err;
504 u32 *fg_in;
505 u32 *match_value;
506 struct mlx5_flow_table *next_ft;
507 struct mlx5_flow_table *prev_ft;
508 struct mlx5_flow_root_namespace *root = find_root(&prio->base);
509 int fg_inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
510 int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
511
512 fg_in = mlx5_vzalloc(fg_inlen);
513 if (!fg_in) {
514 mlx5_core_warn(root->dev, "failed to allocate inbox\n");
515 return -ENOMEM;
516 }
517
518 match_value = mlx5_vzalloc(match_len);
519 if (!match_value) {
520 mlx5_core_warn(root->dev, "failed to allocate inbox\n");
521 kvfree(fg_in);
522 return -ENOMEM;
523 }
524
525 MLX5_SET(create_flow_group_in, fg_in, start_flow_index, ft->max_fte);
526 MLX5_SET(create_flow_group_in, fg_in, end_flow_index, ft->max_fte);
527 fg = fs_alloc_fg(fg_in);
528 if (IS_ERR(fg)) {
529 err = PTR_ERR(fg);
530 goto out;
531 }
532 ft->star_rule.fg = fg;
533 err = mlx5_cmd_fs_create_fg(fs_get_dev(&prio->base),
534 fg_in, ft->vport, ft->type,
535 ft->id,
536 &fg->id);
537 if (err)
538 goto free_fg;
539
540 ft->star_rule.fte = alloc_star_ft_entry(ft, fg,
541 match_value,
542 ft->max_fte);
543 if (IS_ERR(ft->star_rule.fte))
544 goto free_star_rule;
545
546 mutex_lock(&root->fs_chain_lock);
547 next_ft = find_next_ft(prio);
548 err = fs_set_star_rule(root->dev, ft, next_ft);
549 if (err) {
550 mutex_unlock(&root->fs_chain_lock);
551 goto free_star_rule;
552 }
553 if (next_ft) {
554 struct fs_prio *parent;
555
556 fs_get_parent(parent, next_ft);
557 fs_put(&next_ft->base);
558 }
559 prev_ft = find_prev_ft(ft, prio);
560 if (prev_ft) {
561 struct fs_prio *prev_parent;
562
563 fs_get_parent(prev_parent, prev_ft);
564
565 err = connect_prev_fts(NULL, prev_parent, ft);
566 if (err) {
567 mutex_unlock(&root->fs_chain_lock);
568 goto destroy_chained_star_rule;
569 }
570 fs_put(&prev_ft->base);
571 }
572 mutex_unlock(&root->fs_chain_lock);
573 kvfree(fg_in);
574 kvfree(match_value);
575
576 return 0;
577
578 destroy_chained_star_rule:
579 fs_set_star_rule(fs_get_dev(&prio->base), ft, NULL);
580 if (next_ft)
581 fs_put(&next_ft->base);
582 free_star_rule:
583 free_star_fte_entry(ft->star_rule.fte);
584 mlx5_cmd_fs_destroy_fg(fs_get_dev(&ft->base), ft->vport,
585 ft->type, ft->id,
586 fg->id);
587 free_fg:
588 kfree(fg);
589 out:
590 kvfree(fg_in);
591 kvfree(match_value);
592 return err;
593 }
594
destroy_star_rule(struct mlx5_flow_table * ft,struct fs_prio * prio)595 static void destroy_star_rule(struct mlx5_flow_table *ft, struct fs_prio *prio)
596 {
597 int err;
598 struct mlx5_flow_root_namespace *root;
599 struct mlx5_core_dev *dev = fs_get_dev(&prio->base);
600 struct mlx5_flow_table *prev_ft, *next_ft;
601 struct fs_prio *prev_prio;
602
603 WARN_ON(!dev);
604
605 root = find_root(&prio->base);
606 if (!root)
607 mlx5_core_err(dev,
608 "flow steering failed to find root of priority %s",
609 prio->base.name);
610
611 /* In order to ensure atomic deletion, first update
612 * prev ft to point on the next ft.
613 */
614 mutex_lock(&root->fs_chain_lock);
615 prev_ft = find_prev_ft(ft, prio);
616 next_ft = find_next_ft(prio);
617 if (prev_ft) {
618 fs_get_parent(prev_prio, prev_ft);
619 /*Prev is connected to ft, only if ft is the first(last) in the prio*/
620 err = connect_prev_fts(prio, prev_prio, next_ft);
621 if (err)
622 mlx5_core_warn(root->dev,
623 "flow steering can't connect prev and next of flow table\n");
624 fs_put(&prev_ft->base);
625 }
626
627 err = fs_set_star_rule(root->dev, ft, NULL);
628 /*One put is for fs_get in find next ft*/
629 if (next_ft) {
630 fs_put(&next_ft->base);
631 if (!err)
632 fs_put(&next_ft->base);
633 }
634
635 mutex_unlock(&root->fs_chain_lock);
636 err = mlx5_cmd_fs_destroy_fg(dev, ft->vport, ft->type, ft->id,
637 ft->star_rule.fg->id);
638 if (err)
639 mlx5_core_warn(dev,
640 "flow steering can't destroy star entry group(index:%d) of ft:%s\n", ft->star_rule.fg->start_index,
641 ft->base.name);
642 free_star_fte_entry(ft->star_rule.fte);
643
644 kfree(ft->star_rule.fg);
645 ft->star_rule.fg = NULL;
646 }
647
find_prio(struct mlx5_flow_namespace * ns,unsigned int prio)648 static struct fs_prio *find_prio(struct mlx5_flow_namespace *ns,
649 unsigned int prio)
650 {
651 struct fs_prio *iter_prio;
652
653 fs_for_each_prio(iter_prio, ns) {
654 if (iter_prio->prio == prio)
655 return iter_prio;
656 }
657
658 return NULL;
659 }
660
661 static unsigned int _alloc_new_level(struct fs_prio *prio,
662 struct mlx5_flow_namespace *match);
663
__alloc_new_level(struct mlx5_flow_namespace * ns,struct fs_prio * prio)664 static unsigned int __alloc_new_level(struct mlx5_flow_namespace *ns,
665 struct fs_prio *prio)
666 {
667 unsigned int level = 0;
668 struct fs_prio *p;
669
670 if (!ns)
671 return 0;
672
673 mutex_lock(&ns->base.lock);
674 fs_for_each_prio(p, ns) {
675 if (p != prio)
676 level += p->max_ft;
677 else
678 break;
679 }
680 mutex_unlock(&ns->base.lock);
681
682 fs_get_parent(prio, ns);
683 if (prio)
684 WARN_ON(prio->base.type != FS_TYPE_PRIO);
685
686 return level + _alloc_new_level(prio, ns);
687 }
688
689 /* Called under lock of priority, hence locking all upper objects */
_alloc_new_level(struct fs_prio * prio,struct mlx5_flow_namespace * match)690 static unsigned int _alloc_new_level(struct fs_prio *prio,
691 struct mlx5_flow_namespace *match)
692 {
693 struct mlx5_flow_namespace *ns;
694 struct fs_base *it;
695 unsigned int level = 0;
696
697 if (!prio)
698 return 0;
699
700 mutex_lock(&prio->base.lock);
701 fs_for_each_ns_or_ft_reverse(it, prio) {
702 if (it->type == FS_TYPE_NAMESPACE) {
703 struct fs_prio *p;
704
705 fs_get_obj(ns, it);
706
707 if (match != ns) {
708 mutex_lock(&ns->base.lock);
709 fs_for_each_prio(p, ns)
710 level += p->max_ft;
711 mutex_unlock(&ns->base.lock);
712 } else {
713 break;
714 }
715 } else {
716 struct mlx5_flow_table *ft;
717
718 fs_get_obj(ft, it);
719 mutex_unlock(&prio->base.lock);
720 return level + ft->level + 1;
721 }
722 }
723
724 fs_get_parent(ns, prio);
725 mutex_unlock(&prio->base.lock);
726 return __alloc_new_level(ns, prio) + level;
727 }
728
alloc_new_level(struct fs_prio * prio)729 static unsigned int alloc_new_level(struct fs_prio *prio)
730 {
731 return _alloc_new_level(prio, NULL);
732 }
733
update_root_ft_create(struct mlx5_flow_root_namespace * root,struct mlx5_flow_table * ft)734 static int update_root_ft_create(struct mlx5_flow_root_namespace *root,
735 struct mlx5_flow_table *ft)
736 {
737 int err = 0;
738 int min_level = INT_MAX;
739
740 if (root->root_ft)
741 min_level = root->root_ft->level;
742
743 if (ft->level < min_level)
744 err = mlx5_cmd_update_root_ft(root->dev, ft->type,
745 ft->id);
746 else
747 return err;
748
749 if (err)
750 mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
751 ft->id);
752 else
753 root->root_ft = ft;
754
755 return err;
756 }
757
_create_ft_common(struct mlx5_flow_namespace * ns,u16 vport,struct fs_prio * fs_prio,int max_fte,const char * name)758 static struct mlx5_flow_table *_create_ft_common(struct mlx5_flow_namespace *ns,
759 u16 vport,
760 struct fs_prio *fs_prio,
761 int max_fte,
762 const char *name)
763 {
764 struct mlx5_flow_table *ft;
765 int err;
766 int log_table_sz;
767 int ft_size;
768 char gen_name[20];
769 struct mlx5_flow_root_namespace *root = find_root(&ns->base);
770 struct mlx5_core_dev *dev = fs_get_dev(&ns->base);
771
772 if (!root) {
773 mlx5_core_err(dev,
774 "flow steering failed to find root of namespace %s",
775 ns->base.name);
776 return ERR_PTR(-ENODEV);
777 }
778
779 if (fs_prio->num_ft == fs_prio->max_ft)
780 return ERR_PTR(-ENOSPC);
781
782 ft = kzalloc(sizeof(*ft), GFP_KERNEL);
783 if (!ft)
784 return ERR_PTR(-ENOMEM);
785
786 fs_init_node(&ft->base, 1);
787 INIT_LIST_HEAD(&ft->fgs);
788
789 /* Temporarily WA until we expose the level set in the API */
790 if (root->table_type == FS_FT_ESW_EGRESS_ACL ||
791 root->table_type == FS_FT_ESW_INGRESS_ACL)
792 ft->level = 0;
793 else
794 ft->level = alloc_new_level(fs_prio);
795
796 ft->base.type = FS_TYPE_FLOW_TABLE;
797 ft->vport = vport;
798 ft->type = root->table_type;
799 /*Two entries are reserved for star rules*/
800 ft_size = roundup_pow_of_two(max_fte + 2);
801 /*User isn't aware to those rules*/
802 ft->max_fte = ft_size - 2;
803 log_table_sz = ilog2(ft_size);
804 err = mlx5_cmd_fs_create_ft(root->dev, ft->vport, ft->type,
805 ft->level, log_table_sz, &ft->id);
806 if (err)
807 goto free_ft;
808
809 err = create_star_rule(ft, fs_prio);
810 if (err)
811 goto del_ft;
812
813 if ((root->table_type == FS_FT_NIC_RX) && MLX5_CAP_FLOWTABLE(root->dev,
814 flow_table_properties_nic_receive.modify_root)) {
815 err = update_root_ft_create(root, ft);
816 if (err)
817 goto destroy_star_rule;
818 }
819
820 if (!name || !strlen(name)) {
821 snprintf(gen_name, 20, "flow_table_%u", ft->id);
822 _fs_add_node(&ft->base, gen_name, &fs_prio->base);
823 } else {
824 _fs_add_node(&ft->base, name, &fs_prio->base);
825 }
826 list_add_tail(&ft->base.list, &fs_prio->objs);
827 fs_prio->num_ft++;
828
829 return ft;
830
831 destroy_star_rule:
832 destroy_star_rule(ft, fs_prio);
833 del_ft:
834 mlx5_cmd_fs_destroy_ft(root->dev, ft->vport, ft->type, ft->id);
835 free_ft:
836 kfree(ft);
837 return ERR_PTR(err);
838 }
839
create_ft_common(struct mlx5_flow_namespace * ns,u16 vport,unsigned int prio,int max_fte,const char * name)840 static struct mlx5_flow_table *create_ft_common(struct mlx5_flow_namespace *ns,
841 u16 vport,
842 unsigned int prio,
843 int max_fte,
844 const char *name)
845 {
846 struct fs_prio *fs_prio = NULL;
847 fs_prio = find_prio(ns, prio);
848 if (!fs_prio)
849 return ERR_PTR(-EINVAL);
850
851 return _create_ft_common(ns, vport, fs_prio, max_fte, name);
852 }
853
854
855 static struct mlx5_flow_table *find_first_ft_in_ns(struct mlx5_flow_namespace *ns,
856 struct list_head *start);
857
858 static struct mlx5_flow_table *find_first_ft_in_prio(struct fs_prio *prio,
859 struct list_head *start);
860
mlx5_create_autogrouped_shared_flow_table(struct fs_prio * fs_prio)861 static struct mlx5_flow_table *mlx5_create_autogrouped_shared_flow_table(struct fs_prio *fs_prio)
862 {
863 struct mlx5_flow_table *ft;
864
865 ft = find_first_ft_in_prio(fs_prio, &fs_prio->objs);
866 if (ft) {
867 ft->shared_refcount++;
868 return ft;
869 }
870
871 return NULL;
872 }
873
mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace * ns,int prio,const char * name,int num_flow_table_entries,int max_num_groups)874 struct mlx5_flow_table *mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns,
875 int prio,
876 const char *name,
877 int num_flow_table_entries,
878 int max_num_groups)
879 {
880 struct mlx5_flow_table *ft = NULL;
881 struct fs_prio *fs_prio;
882 bool is_shared_prio;
883
884 fs_prio = find_prio(ns, prio);
885 if (!fs_prio)
886 return ERR_PTR(-EINVAL);
887
888 is_shared_prio = fs_prio->flags & MLX5_CORE_FS_PRIO_SHARED;
889 if (is_shared_prio) {
890 mutex_lock(&fs_prio->shared_lock);
891 ft = mlx5_create_autogrouped_shared_flow_table(fs_prio);
892 }
893
894 if (ft)
895 goto return_ft;
896
897 ft = create_ft_common(ns, 0, prio, num_flow_table_entries,
898 name);
899 if (IS_ERR(ft))
900 goto return_ft;
901
902 ft->autogroup.active = true;
903 ft->autogroup.max_types = max_num_groups;
904 if (is_shared_prio)
905 ft->shared_refcount = 1;
906
907 return_ft:
908 if (is_shared_prio)
909 mutex_unlock(&fs_prio->shared_lock);
910 return ft;
911 }
912 EXPORT_SYMBOL(mlx5_create_auto_grouped_flow_table);
913
mlx5_create_vport_flow_table(struct mlx5_flow_namespace * ns,u16 vport,int prio,const char * name,int num_flow_table_entries)914 struct mlx5_flow_table *mlx5_create_vport_flow_table(struct mlx5_flow_namespace *ns,
915 u16 vport,
916 int prio,
917 const char *name,
918 int num_flow_table_entries)
919 {
920 return create_ft_common(ns, vport, prio, num_flow_table_entries, name);
921 }
922 EXPORT_SYMBOL(mlx5_create_vport_flow_table);
923
mlx5_create_flow_table(struct mlx5_flow_namespace * ns,int prio,const char * name,int num_flow_table_entries)924 struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,
925 int prio,
926 const char *name,
927 int num_flow_table_entries)
928 {
929 return create_ft_common(ns, 0, prio, num_flow_table_entries, name);
930 }
931 EXPORT_SYMBOL(mlx5_create_flow_table);
932
_fs_del_ft(struct mlx5_flow_table * ft)933 static void _fs_del_ft(struct mlx5_flow_table *ft)
934 {
935 int err;
936 struct mlx5_core_dev *dev = fs_get_dev(&ft->base);
937 struct fs_prio *prio;
938
939 err = mlx5_cmd_fs_destroy_ft(dev, ft->vport, ft->type, ft->id);
940 if (err)
941 mlx5_core_warn(dev, "flow steering can't destroy ft %s\n",
942 ft->base.name);
943
944 fs_get_parent(prio, ft);
945 prio->num_ft--;
946 }
947
update_root_ft_destroy(struct mlx5_flow_root_namespace * root,struct mlx5_flow_table * ft)948 static int update_root_ft_destroy(struct mlx5_flow_root_namespace *root,
949 struct mlx5_flow_table *ft)
950 {
951 int err = 0;
952 struct fs_prio *prio;
953 struct mlx5_flow_table *next_ft = NULL;
954 struct mlx5_flow_table *put_ft = NULL;
955
956 if (root->root_ft != ft)
957 return 0;
958
959 fs_get_parent(prio, ft);
960 /*Assuming objs containis only flow tables and
961 * flow tables are sorted by level.
962 */
963 if (!list_is_last(&ft->base.list, &prio->objs)) {
964 next_ft = list_next_entry(ft, base.list);
965 } else {
966 next_ft = find_next_ft(prio);
967 put_ft = next_ft;
968 }
969
970 if (next_ft) {
971 err = mlx5_cmd_update_root_ft(root->dev, next_ft->type,
972 next_ft->id);
973 if (err)
974 mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
975 ft->id);
976 }
977 if (!err)
978 root->root_ft = next_ft;
979
980 if (put_ft)
981 fs_put(&put_ft->base);
982
983 return err;
984 }
985
986 /*Objects in the same prio are destroyed in the reverse order they were createrd*/
mlx5_destroy_flow_table(struct mlx5_flow_table * ft)987 int mlx5_destroy_flow_table(struct mlx5_flow_table *ft)
988 {
989 int err = 0;
990 struct fs_prio *prio;
991 struct mlx5_flow_root_namespace *root;
992 bool is_shared_prio;
993 struct mlx5_core_dev *dev;
994
995 fs_get_parent(prio, ft);
996 root = find_root(&prio->base);
997 dev = fs_get_dev(&prio->base);
998
999 if (!root) {
1000 mlx5_core_err(dev,
1001 "flow steering failed to find root of priority %s",
1002 prio->base.name);
1003 return -ENODEV;
1004 }
1005
1006 is_shared_prio = prio->flags & MLX5_CORE_FS_PRIO_SHARED;
1007 if (is_shared_prio) {
1008 mutex_lock(&prio->shared_lock);
1009 if (ft->shared_refcount > 1) {
1010 --ft->shared_refcount;
1011 fs_put(&ft->base);
1012 mutex_unlock(&prio->shared_lock);
1013 return 0;
1014 }
1015 }
1016
1017 mutex_lock(&prio->base.lock);
1018 mutex_lock(&ft->base.lock);
1019
1020 err = update_root_ft_destroy(root, ft);
1021 if (err)
1022 goto unlock_ft;
1023
1024 /* delete two last entries */
1025 destroy_star_rule(ft, prio);
1026
1027 mutex_unlock(&ft->base.lock);
1028 fs_remove_node_parent_locked(&ft->base);
1029 mutex_unlock(&prio->base.lock);
1030 if (is_shared_prio)
1031 mutex_unlock(&prio->shared_lock);
1032
1033 return err;
1034
1035 unlock_ft:
1036 mutex_unlock(&ft->base.lock);
1037 mutex_unlock(&prio->base.lock);
1038 if (is_shared_prio)
1039 mutex_unlock(&prio->shared_lock);
1040
1041 return err;
1042 }
1043 EXPORT_SYMBOL(mlx5_destroy_flow_table);
1044
fs_create_fg(struct mlx5_core_dev * dev,struct mlx5_flow_table * ft,struct list_head * prev,u32 * fg_in,int refcount)1045 static struct mlx5_flow_group *fs_create_fg(struct mlx5_core_dev *dev,
1046 struct mlx5_flow_table *ft,
1047 struct list_head *prev,
1048 u32 *fg_in,
1049 int refcount)
1050 {
1051 struct mlx5_flow_group *fg;
1052 int err;
1053 unsigned int end_index;
1054 char name[20];
1055
1056 fg = fs_alloc_fg(fg_in);
1057 if (IS_ERR(fg))
1058 return fg;
1059
1060 end_index = fg->start_index + fg->max_ftes - 1;
1061 err = mlx5_cmd_fs_create_fg(dev, fg_in,
1062 ft->vport, ft->type, ft->id,
1063 &fg->id);
1064 if (err)
1065 goto free_fg;
1066
1067 mutex_lock(&ft->base.lock);
1068 if (ft->autogroup.active)
1069 ft->autogroup.num_types++;
1070
1071 snprintf(name, sizeof(name), "group_%u", fg->id);
1072 /*Add node to tree*/
1073 fs_add_node(&fg->base, &ft->base, name, refcount);
1074 /*Add node to group list*/
1075 list_add(&fg->base.list, prev);
1076 mutex_unlock(&ft->base.lock);
1077
1078 return fg;
1079
1080 free_fg:
1081 kfree(fg);
1082 return ERR_PTR(err);
1083 }
1084
mlx5_create_flow_group(struct mlx5_flow_table * ft,u32 * in)1085 struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft,
1086 u32 *in)
1087 {
1088 struct mlx5_flow_group *fg;
1089 struct mlx5_core_dev *dev = fs_get_dev(&ft->base);
1090
1091 if (!dev)
1092 return ERR_PTR(-ENODEV);
1093
1094 if (ft->autogroup.active)
1095 return ERR_PTR(-EPERM);
1096
1097 fg = fs_create_fg(dev, ft, ft->fgs.prev, in, 1);
1098
1099 return fg;
1100 }
1101 EXPORT_SYMBOL(mlx5_create_flow_group);
1102
1103 /*Group is destoyed when all the rules in the group were removed*/
fs_del_fg(struct mlx5_flow_group * fg)1104 static void fs_del_fg(struct mlx5_flow_group *fg)
1105 {
1106 struct mlx5_flow_table *parent_ft;
1107 struct mlx5_core_dev *dev;
1108
1109 fs_get_parent(parent_ft, fg);
1110 dev = fs_get_dev(&parent_ft->base);
1111 WARN_ON(!dev);
1112
1113 if (parent_ft->autogroup.active)
1114 parent_ft->autogroup.num_types--;
1115
1116 if (mlx5_cmd_fs_destroy_fg(dev, parent_ft->vport,
1117 parent_ft->type,
1118 parent_ft->id, fg->id))
1119 mlx5_core_warn(dev, "flow steering can't destroy fg\n");
1120 }
1121
mlx5_destroy_flow_group(struct mlx5_flow_group * fg)1122 void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
1123 {
1124 fs_remove_node(&fg->base);
1125 }
1126 EXPORT_SYMBOL(mlx5_destroy_flow_group);
1127
_fs_match_exact_val(void * mask,void * val1,void * val2,size_t size)1128 static bool _fs_match_exact_val(void *mask, void *val1, void *val2, size_t size)
1129 {
1130 unsigned int i;
1131
1132 /* TODO: optimize by comparing 64bits when possible */
1133 for (i = 0; i < size; i++, mask++, val1++, val2++)
1134 if ((*((u8 *)val1) & (*(u8 *)mask)) !=
1135 ((*(u8 *)val2) & (*(u8 *)mask)))
1136 return false;
1137
1138 return true;
1139 }
1140
fs_match_exact_val(struct mlx5_core_fs_mask * mask,void * val1,void * val2)1141 bool fs_match_exact_val(struct mlx5_core_fs_mask *mask,
1142 void *val1, void *val2)
1143 {
1144 if (mask->match_criteria_enable &
1145 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) {
1146 void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
1147 val1, outer_headers);
1148 void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
1149 val2, outer_headers);
1150 void *fte_mask = MLX5_ADDR_OF(fte_match_param,
1151 mask->match_criteria, outer_headers);
1152
1153 if (!_fs_match_exact_val(fte_mask, fte_match1, fte_match2,
1154 MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
1155 return false;
1156 }
1157
1158 if (mask->match_criteria_enable &
1159 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) {
1160 void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
1161 val1, misc_parameters);
1162 void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
1163 val2, misc_parameters);
1164 void *fte_mask = MLX5_ADDR_OF(fte_match_param,
1165 mask->match_criteria, misc_parameters);
1166
1167 if (!_fs_match_exact_val(fte_mask, fte_match1, fte_match2,
1168 MLX5_ST_SZ_BYTES(fte_match_set_misc)))
1169 return false;
1170 }
1171 if (mask->match_criteria_enable &
1172 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS) {
1173 void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
1174 val1, inner_headers);
1175 void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
1176 val2, inner_headers);
1177 void *fte_mask = MLX5_ADDR_OF(fte_match_param,
1178 mask->match_criteria, inner_headers);
1179
1180 if (!_fs_match_exact_val(fte_mask, fte_match1, fte_match2,
1181 MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
1182 return false;
1183 }
1184 return true;
1185 }
1186
fs_match_exact_mask(u8 match_criteria_enable1,u8 match_criteria_enable2,void * mask1,void * mask2)1187 bool fs_match_exact_mask(u8 match_criteria_enable1,
1188 u8 match_criteria_enable2,
1189 void *mask1, void *mask2)
1190 {
1191 return match_criteria_enable1 == match_criteria_enable2 &&
1192 !memcmp(mask1, mask2, MLX5_ST_SZ_BYTES(fte_match_param));
1193 }
1194
1195 static struct mlx5_flow_table *find_first_ft_in_ns_reverse(struct mlx5_flow_namespace *ns,
1196 struct list_head *start);
1197
_find_first_ft_in_prio_reverse(struct fs_prio * prio,struct list_head * start)1198 static struct mlx5_flow_table *_find_first_ft_in_prio_reverse(struct fs_prio *prio,
1199 struct list_head *start)
1200 {
1201 struct fs_base *it = container_of(start, struct fs_base, list);
1202
1203 if (!prio)
1204 return NULL;
1205
1206 fs_for_each_ns_or_ft_continue_reverse(it, prio) {
1207 struct mlx5_flow_namespace *ns;
1208 struct mlx5_flow_table *ft;
1209
1210 if (it->type == FS_TYPE_FLOW_TABLE) {
1211 fs_get_obj(ft, it);
1212 fs_get(&ft->base);
1213 return ft;
1214 }
1215
1216 fs_get_obj(ns, it);
1217 WARN_ON(ns->base.type != FS_TYPE_NAMESPACE);
1218
1219 ft = find_first_ft_in_ns_reverse(ns, &ns->prios);
1220 if (ft)
1221 return ft;
1222 }
1223
1224 return NULL;
1225 }
1226
find_first_ft_in_prio_reverse(struct fs_prio * prio,struct list_head * start)1227 static struct mlx5_flow_table *find_first_ft_in_prio_reverse(struct fs_prio *prio,
1228 struct list_head *start)
1229 {
1230 struct mlx5_flow_table *ft;
1231
1232 if (!prio)
1233 return NULL;
1234
1235 mutex_lock(&prio->base.lock);
1236 ft = _find_first_ft_in_prio_reverse(prio, start);
1237 mutex_unlock(&prio->base.lock);
1238
1239 return ft;
1240 }
1241
find_first_ft_in_ns_reverse(struct mlx5_flow_namespace * ns,struct list_head * start)1242 static struct mlx5_flow_table *find_first_ft_in_ns_reverse(struct mlx5_flow_namespace *ns,
1243 struct list_head *start)
1244 {
1245 struct fs_prio *prio;
1246
1247 if (!ns)
1248 return NULL;
1249
1250 fs_get_obj(prio, container_of(start, struct fs_base, list));
1251 mutex_lock(&ns->base.lock);
1252 fs_for_each_prio_continue_reverse(prio, ns) {
1253 struct mlx5_flow_table *ft;
1254
1255 ft = find_first_ft_in_prio_reverse(prio, &prio->objs);
1256 if (ft) {
1257 mutex_unlock(&ns->base.lock);
1258 return ft;
1259 }
1260 }
1261 mutex_unlock(&ns->base.lock);
1262
1263 return NULL;
1264 }
1265
1266 /* Returned a held ft, assumed curr is protected, assumed curr's parent is
1267 * locked
1268 */
find_prev_ft(struct mlx5_flow_table * curr,struct fs_prio * prio)1269 static struct mlx5_flow_table *find_prev_ft(struct mlx5_flow_table *curr,
1270 struct fs_prio *prio)
1271 {
1272 struct mlx5_flow_table *ft = NULL;
1273 struct fs_base *curr_base;
1274
1275 if (!curr)
1276 return NULL;
1277
1278 /* prio has either namespace or flow-tables, but not both */
1279 if (!list_empty(&prio->objs) &&
1280 list_first_entry(&prio->objs, struct mlx5_flow_table, base.list) !=
1281 curr)
1282 return NULL;
1283
1284 while (!ft && prio) {
1285 struct mlx5_flow_namespace *ns;
1286
1287 fs_get_parent(ns, prio);
1288 ft = find_first_ft_in_ns_reverse(ns, &prio->base.list);
1289 curr_base = &ns->base;
1290 fs_get_parent(prio, ns);
1291
1292 if (prio && !ft)
1293 ft = find_first_ft_in_prio_reverse(prio,
1294 &curr_base->list);
1295 }
1296 return ft;
1297 }
1298
_find_first_ft_in_prio(struct fs_prio * prio,struct list_head * start)1299 static struct mlx5_flow_table *_find_first_ft_in_prio(struct fs_prio *prio,
1300 struct list_head *start)
1301 {
1302 struct fs_base *it = container_of(start, struct fs_base, list);
1303
1304 if (!prio)
1305 return NULL;
1306
1307 fs_for_each_ns_or_ft_continue(it, prio) {
1308 struct mlx5_flow_namespace *ns;
1309 struct mlx5_flow_table *ft;
1310
1311 if (it->type == FS_TYPE_FLOW_TABLE) {
1312 fs_get_obj(ft, it);
1313 fs_get(&ft->base);
1314 return ft;
1315 }
1316
1317 fs_get_obj(ns, it);
1318 WARN_ON(ns->base.type != FS_TYPE_NAMESPACE);
1319
1320 ft = find_first_ft_in_ns(ns, &ns->prios);
1321 if (ft)
1322 return ft;
1323 }
1324
1325 return NULL;
1326 }
1327
find_first_ft_in_prio(struct fs_prio * prio,struct list_head * start)1328 static struct mlx5_flow_table *find_first_ft_in_prio(struct fs_prio *prio,
1329 struct list_head *start)
1330 {
1331 struct mlx5_flow_table *ft;
1332
1333 if (!prio)
1334 return NULL;
1335
1336 mutex_lock(&prio->base.lock);
1337 ft = _find_first_ft_in_prio(prio, start);
1338 mutex_unlock(&prio->base.lock);
1339
1340 return ft;
1341 }
1342
find_first_ft_in_ns(struct mlx5_flow_namespace * ns,struct list_head * start)1343 static struct mlx5_flow_table *find_first_ft_in_ns(struct mlx5_flow_namespace *ns,
1344 struct list_head *start)
1345 {
1346 struct fs_prio *prio;
1347
1348 if (!ns)
1349 return NULL;
1350
1351 fs_get_obj(prio, container_of(start, struct fs_base, list));
1352 mutex_lock(&ns->base.lock);
1353 fs_for_each_prio_continue(prio, ns) {
1354 struct mlx5_flow_table *ft;
1355
1356 ft = find_first_ft_in_prio(prio, &prio->objs);
1357 if (ft) {
1358 mutex_unlock(&ns->base.lock);
1359 return ft;
1360 }
1361 }
1362 mutex_unlock(&ns->base.lock);
1363
1364 return NULL;
1365 }
1366
1367 /* returned a held ft, assumed curr is protected, assumed curr's parent is
1368 * locked
1369 */
find_next_ft(struct fs_prio * prio)1370 static struct mlx5_flow_table *find_next_ft(struct fs_prio *prio)
1371 {
1372 struct mlx5_flow_table *ft = NULL;
1373 struct fs_base *curr_base;
1374
1375 while (!ft && prio) {
1376 struct mlx5_flow_namespace *ns;
1377
1378 fs_get_parent(ns, prio);
1379 ft = find_first_ft_in_ns(ns, &prio->base.list);
1380 curr_base = &ns->base;
1381 fs_get_parent(prio, ns);
1382
1383 if (!ft && prio)
1384 ft = _find_first_ft_in_prio(prio, &curr_base->list);
1385 }
1386 return ft;
1387 }
1388
1389
1390 /* called under ft mutex lock */
create_autogroup(struct mlx5_flow_table * ft,u8 match_criteria_enable,u32 * match_criteria)1391 static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
1392 u8 match_criteria_enable,
1393 u32 *match_criteria)
1394 {
1395 unsigned int group_size;
1396 unsigned int candidate_index = 0;
1397 struct mlx5_flow_group *g;
1398 struct mlx5_flow_group *ret;
1399 struct list_head *prev = &ft->fgs;
1400 struct mlx5_core_dev *dev;
1401 u32 *in;
1402 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1403 void *match_criteria_addr;
1404
1405 if (!ft->autogroup.active)
1406 return ERR_PTR(-ENOENT);
1407
1408 dev = fs_get_dev(&ft->base);
1409 if (!dev)
1410 return ERR_PTR(-ENODEV);
1411
1412 in = mlx5_vzalloc(inlen);
1413 if (!in) {
1414 mlx5_core_warn(dev, "failed to allocate inbox\n");
1415 return ERR_PTR(-ENOMEM);
1416 }
1417
1418
1419 if (ft->autogroup.num_types < ft->autogroup.max_types)
1420 group_size = ft->max_fte / (ft->autogroup.max_types + 1);
1421 else
1422 group_size = 1;
1423
1424 if (group_size == 0) {
1425 mlx5_core_warn(dev,
1426 "flow steering can't create group size of 0\n");
1427 ret = ERR_PTR(-EINVAL);
1428 goto out;
1429 }
1430
1431 /* sorted by start_index */
1432 fs_for_each_fg(g, ft) {
1433 if (candidate_index + group_size > g->start_index)
1434 candidate_index = g->start_index + g->max_ftes;
1435 else
1436 break;
1437 prev = &g->base.list;
1438 }
1439
1440 if (candidate_index + group_size > ft->max_fte) {
1441 ret = ERR_PTR(-ENOSPC);
1442 goto out;
1443 }
1444
1445 MLX5_SET(create_flow_group_in, in, match_criteria_enable,
1446 match_criteria_enable);
1447 MLX5_SET(create_flow_group_in, in, start_flow_index, candidate_index);
1448 MLX5_SET(create_flow_group_in, in, end_flow_index, candidate_index +
1449 group_size - 1);
1450 match_criteria_addr = MLX5_ADDR_OF(create_flow_group_in,
1451 in, match_criteria);
1452 memcpy(match_criteria_addr, match_criteria,
1453 MLX5_ST_SZ_BYTES(fte_match_param));
1454
1455 ret = fs_create_fg(dev, ft, prev, in, 0);
1456 out:
1457 kvfree(in);
1458 return ret;
1459 }
1460
get_ns_with_notifiers(struct fs_base * node)1461 static struct mlx5_flow_namespace *get_ns_with_notifiers(struct fs_base *node)
1462 {
1463 struct mlx5_flow_namespace *ns = NULL;
1464
1465 while (node && (node->type != FS_TYPE_NAMESPACE ||
1466 list_empty(&container_of(node, struct
1467 mlx5_flow_namespace,
1468 base)->list_notifiers)))
1469 node = node->parent;
1470
1471 if (node)
1472 fs_get_obj(ns, node);
1473
1474 return ns;
1475 }
1476
1477
1478 /*Assumption- fte is locked*/
call_to_add_rule_notifiers(struct mlx5_flow_rule * dst,struct fs_fte * fte)1479 static void call_to_add_rule_notifiers(struct mlx5_flow_rule *dst,
1480 struct fs_fte *fte)
1481 {
1482 struct mlx5_flow_namespace *ns;
1483 struct mlx5_flow_handler *iter_handler;
1484 struct fs_client_priv_data *iter_client;
1485 void *data;
1486 bool is_new_rule = list_first_entry(&fte->dests,
1487 struct mlx5_flow_rule,
1488 base.list) == dst;
1489 int err;
1490
1491 ns = get_ns_with_notifiers(&fte->base);
1492 if (!ns)
1493 return;
1494
1495 down_read(&ns->notifiers_rw_sem);
1496 list_for_each_entry(iter_handler, &ns->list_notifiers,
1497 list) {
1498 if (iter_handler->add_dst_cb) {
1499 data = NULL;
1500 mutex_lock(&dst->clients_lock);
1501 list_for_each_entry(
1502 iter_client, &dst->clients_data, list) {
1503 if (iter_client->fs_handler == iter_handler) {
1504 data = iter_client->client_dst_data;
1505 break;
1506 }
1507 }
1508 mutex_unlock(&dst->clients_lock);
1509 err = iter_handler->add_dst_cb(dst,
1510 is_new_rule,
1511 NULL,
1512 iter_handler->client_context);
1513 if (err)
1514 break;
1515 }
1516 }
1517 up_read(&ns->notifiers_rw_sem);
1518 }
1519
call_to_del_rule_notifiers(struct mlx5_flow_rule * dst,struct fs_fte * fte)1520 static void call_to_del_rule_notifiers(struct mlx5_flow_rule *dst,
1521 struct fs_fte *fte)
1522 {
1523 struct mlx5_flow_namespace *ns;
1524 struct mlx5_flow_handler *iter_handler;
1525 struct fs_client_priv_data *iter_client;
1526 void *data;
1527 bool ctx_changed = (fte->dests_size == 0);
1528
1529 ns = get_ns_with_notifiers(&fte->base);
1530 if (!ns)
1531 return;
1532 down_read(&ns->notifiers_rw_sem);
1533 list_for_each_entry(iter_handler, &ns->list_notifiers,
1534 list) {
1535 data = NULL;
1536 mutex_lock(&dst->clients_lock);
1537 list_for_each_entry(iter_client, &dst->clients_data, list) {
1538 if (iter_client->fs_handler == iter_handler) {
1539 data = iter_client->client_dst_data;
1540 break;
1541 }
1542 }
1543 mutex_unlock(&dst->clients_lock);
1544 if (iter_handler->del_dst_cb) {
1545 iter_handler->del_dst_cb(dst, ctx_changed, data,
1546 iter_handler->client_context);
1547 }
1548 }
1549 up_read(&ns->notifiers_rw_sem);
1550 }
1551
1552 /* fte should not be deleted while calling this function */
_fs_add_dst_fte(struct fs_fte * fte,struct mlx5_flow_group * fg,struct mlx5_flow_destination * dest)1553 static struct mlx5_flow_rule *_fs_add_dst_fte(struct fs_fte *fte,
1554 struct mlx5_flow_group *fg,
1555 struct mlx5_flow_destination *dest)
1556 {
1557 struct mlx5_flow_table *ft;
1558 struct mlx5_flow_rule *dst;
1559 int err;
1560
1561 dst = kzalloc(sizeof(*dst), GFP_KERNEL);
1562 if (!dst)
1563 return ERR_PTR(-ENOMEM);
1564
1565 memcpy(&dst->dest_attr, dest, sizeof(*dest));
1566 dst->base.type = FS_TYPE_FLOW_DEST;
1567 INIT_LIST_HEAD(&dst->clients_data);
1568 mutex_init(&dst->clients_lock);
1569 fs_get_parent(ft, fg);
1570 /*Add dest to dests list- added as first element after the head*/
1571 list_add_tail(&dst->base.list, &fte->dests);
1572 fte->dests_size++;
1573 err = mlx5_cmd_fs_set_fte(fs_get_dev(&ft->base),
1574 ft->vport,
1575 &fte->status,
1576 fte->val, ft->type,
1577 ft->id, fte->index, fg->id, fte->flow_tag,
1578 fte->action, fte->dests_size, &fte->dests);
1579 if (err)
1580 goto free_dst;
1581
1582 list_del(&dst->base.list);
1583
1584 return dst;
1585
1586 free_dst:
1587 list_del(&dst->base.list);
1588 kfree(dst);
1589 fte->dests_size--;
1590 return ERR_PTR(err);
1591 }
1592
get_dest_name(struct mlx5_flow_destination * dest)1593 static char *get_dest_name(struct mlx5_flow_destination *dest)
1594 {
1595 char *name = kzalloc(sizeof(char) * 20, GFP_KERNEL);
1596
1597 switch (dest->type) {
1598 case MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE:
1599 snprintf(name, 20, "dest_%s_%u", "flow_table",
1600 dest->ft->id);
1601 return name;
1602 case MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT:
1603 snprintf(name, 20, "dest_%s_%u", "vport",
1604 dest->vport_num);
1605 return name;
1606 case MLX5_FLOW_CONTEXT_DEST_TYPE_TIR:
1607 snprintf(name, 20, "dest_%s_%u", "tir", dest->tir_num);
1608 return name;
1609 default:
1610 kfree(name);
1611 return NULL;
1612 }
1613 }
1614
1615 /* assumed fg is locked */
fs_get_free_fg_index(struct mlx5_flow_group * fg,struct list_head ** prev)1616 static unsigned int fs_get_free_fg_index(struct mlx5_flow_group *fg,
1617 struct list_head **prev)
1618 {
1619 struct fs_fte *fte;
1620 unsigned int start = fg->start_index;
1621
1622 if (prev)
1623 *prev = &fg->ftes;
1624
1625 /* assumed list is sorted by index */
1626 fs_for_each_fte(fte, fg) {
1627 if (fte->index != start)
1628 return start;
1629 start++;
1630 if (prev)
1631 *prev = &fte->base.list;
1632 }
1633
1634 return start;
1635 }
1636
1637
fs_create_fte(struct mlx5_flow_group * fg,u32 * match_value,u8 action,u32 flow_tag,struct list_head ** prev)1638 static struct fs_fte *fs_create_fte(struct mlx5_flow_group *fg,
1639 u32 *match_value,
1640 u8 action,
1641 u32 flow_tag,
1642 struct list_head **prev)
1643 {
1644 struct fs_fte *fte;
1645 int index = 0;
1646
1647 index = fs_get_free_fg_index(fg, prev);
1648 fte = fs_alloc_fte(action, flow_tag, match_value, index);
1649 if (IS_ERR(fte))
1650 return fte;
1651
1652 return fte;
1653 }
1654
add_rule_to_tree(struct mlx5_flow_rule * rule,struct fs_fte * fte)1655 static void add_rule_to_tree(struct mlx5_flow_rule *rule,
1656 struct fs_fte *fte)
1657 {
1658 char *dest_name;
1659
1660 dest_name = get_dest_name(&rule->dest_attr);
1661 fs_add_node(&rule->base, &fte->base, dest_name, 1);
1662 /* re-add to list, since fs_add_node reset our list */
1663 list_add_tail(&rule->base.list, &fte->dests);
1664 kfree(dest_name);
1665 call_to_add_rule_notifiers(rule, fte);
1666 }
1667
fs_del_dst(struct mlx5_flow_rule * dst)1668 static void fs_del_dst(struct mlx5_flow_rule *dst)
1669 {
1670 struct mlx5_flow_table *ft;
1671 struct mlx5_flow_group *fg;
1672 struct fs_fte *fte;
1673 u32 *match_value;
1674 struct mlx5_core_dev *dev = fs_get_dev(&dst->base);
1675 int match_len = MLX5_ST_SZ_BYTES(fte_match_param);
1676 int err;
1677
1678 WARN_ON(!dev);
1679
1680 match_value = mlx5_vzalloc(match_len);
1681 if (!match_value) {
1682 mlx5_core_warn(dev, "failed to allocate inbox\n");
1683 return;
1684 }
1685
1686 fs_get_parent(fte, dst);
1687 fs_get_parent(fg, fte);
1688 mutex_lock(&fg->base.lock);
1689 memcpy(match_value, fte->val, sizeof(fte->val));
1690 /* ft can't be changed as fg is locked */
1691 fs_get_parent(ft, fg);
1692 list_del(&dst->base.list);
1693 fte->dests_size--;
1694 if (fte->dests_size) {
1695 err = mlx5_cmd_fs_set_fte(dev, ft->vport,
1696 &fte->status, match_value, ft->type,
1697 ft->id, fte->index, fg->id,
1698 fte->flow_tag, fte->action,
1699 fte->dests_size, &fte->dests);
1700 if (err) {
1701 mlx5_core_warn(dev, "%s can't delete dst %s\n",
1702 __func__, dst->base.name);
1703 goto err;
1704 }
1705 }
1706 call_to_del_rule_notifiers(dst, fte);
1707 err:
1708 mutex_unlock(&fg->base.lock);
1709 kvfree(match_value);
1710 }
1711
fs_del_fte(struct fs_fte * fte)1712 static void fs_del_fte(struct fs_fte *fte)
1713 {
1714 struct mlx5_flow_table *ft;
1715 struct mlx5_flow_group *fg;
1716 int err;
1717 struct mlx5_core_dev *dev;
1718
1719 fs_get_parent(fg, fte);
1720 fs_get_parent(ft, fg);
1721
1722 dev = fs_get_dev(&ft->base);
1723 WARN_ON(!dev);
1724
1725 err = mlx5_cmd_fs_delete_fte(dev, ft->vport, &fte->status,
1726 ft->type, ft->id, fte->index);
1727 if (err)
1728 mlx5_core_warn(dev, "flow steering can't delete fte %s\n",
1729 fte->base.name);
1730
1731 fg->num_ftes--;
1732 }
1733
1734 /* assuming parent fg is locked */
1735 /* Add dst algorithm */
fs_add_dst_fg(struct mlx5_flow_group * fg,u32 * match_value,u8 action,u32 flow_tag,struct mlx5_flow_destination * dest)1736 static struct mlx5_flow_rule *fs_add_dst_fg(struct mlx5_flow_group *fg,
1737 u32 *match_value,
1738 u8 action,
1739 u32 flow_tag,
1740 struct mlx5_flow_destination *dest)
1741 {
1742 struct fs_fte *fte;
1743 struct mlx5_flow_rule *dst;
1744 struct mlx5_flow_table *ft;
1745 struct list_head *prev;
1746 char fte_name[20];
1747
1748 mutex_lock(&fg->base.lock);
1749 fs_for_each_fte(fte, fg) {
1750 /* TODO: Check of size against PRM max size */
1751 mutex_lock(&fte->base.lock);
1752 if (fs_match_exact_val(&fg->mask, match_value, &fte->val) &&
1753 action == fte->action && flow_tag == fte->flow_tag) {
1754 dst = _fs_add_dst_fte(fte, fg, dest);
1755 mutex_unlock(&fte->base.lock);
1756 if (IS_ERR(dst))
1757 goto unlock_fg;
1758 goto add_rule;
1759 }
1760 mutex_unlock(&fte->base.lock);
1761 }
1762
1763 fs_get_parent(ft, fg);
1764 if (fg->num_ftes == fg->max_ftes) {
1765 dst = ERR_PTR(-ENOSPC);
1766 goto unlock_fg;
1767 }
1768
1769 fte = fs_create_fte(fg, match_value, action, flow_tag, &prev);
1770 if (IS_ERR(fte)) {
1771 dst = (void *)fte;
1772 goto unlock_fg;
1773 }
1774 dst = _fs_add_dst_fte(fte, fg, dest);
1775 if (IS_ERR(dst)) {
1776 kfree(fte);
1777 goto unlock_fg;
1778 }
1779
1780 fg->num_ftes++;
1781
1782 snprintf(fte_name, sizeof(fte_name), "fte%u", fte->index);
1783 /* Add node to tree */
1784 fs_add_node(&fte->base, &fg->base, fte_name, 0);
1785 list_add(&fte->base.list, prev);
1786 add_rule:
1787 add_rule_to_tree(dst, fte);
1788 unlock_fg:
1789 mutex_unlock(&fg->base.lock);
1790 return dst;
1791 }
1792
fs_add_dst_ft(struct mlx5_flow_table * ft,u8 match_criteria_enable,u32 * match_criteria,u32 * match_value,u8 action,u32 flow_tag,struct mlx5_flow_destination * dest)1793 static struct mlx5_flow_rule *fs_add_dst_ft(struct mlx5_flow_table *ft,
1794 u8 match_criteria_enable,
1795 u32 *match_criteria,
1796 u32 *match_value,
1797 u8 action, u32 flow_tag,
1798 struct mlx5_flow_destination *dest)
1799 {
1800 /*? where dst_entry is allocated*/
1801 struct mlx5_flow_group *g;
1802 struct mlx5_flow_rule *dst;
1803
1804 fs_get(&ft->base);
1805 mutex_lock(&ft->base.lock);
1806 fs_for_each_fg(g, ft)
1807 if (fs_match_exact_mask(g->mask.match_criteria_enable,
1808 match_criteria_enable,
1809 g->mask.match_criteria,
1810 match_criteria)) {
1811 mutex_unlock(&ft->base.lock);
1812
1813 dst = fs_add_dst_fg(g, match_value,
1814 action, flow_tag, dest);
1815 if (PTR_ERR(dst) && PTR_ERR(dst) != -ENOSPC)
1816 goto unlock;
1817 }
1818 mutex_unlock(&ft->base.lock);
1819
1820 g = create_autogroup(ft, match_criteria_enable, match_criteria);
1821 if (IS_ERR(g)) {
1822 dst = (void *)g;
1823 goto unlock;
1824 }
1825
1826 dst = fs_add_dst_fg(g, match_value,
1827 action, flow_tag, dest);
1828 if (IS_ERR(dst)) {
1829 /* Remove assumes refcount > 0 and autogroup creates a group
1830 * with a refcount = 0.
1831 */
1832 fs_get(&g->base);
1833 fs_remove_node(&g->base);
1834 goto unlock;
1835 }
1836
1837 unlock:
1838 fs_put(&ft->base);
1839 return dst;
1840 }
1841
1842 struct mlx5_flow_rule *
mlx5_add_flow_rule(struct mlx5_flow_table * ft,u8 match_criteria_enable,u32 * match_criteria,u32 * match_value,u32 action,u32 flow_tag,struct mlx5_flow_destination * dest)1843 mlx5_add_flow_rule(struct mlx5_flow_table *ft,
1844 u8 match_criteria_enable,
1845 u32 *match_criteria,
1846 u32 *match_value,
1847 u32 action,
1848 u32 flow_tag,
1849 struct mlx5_flow_destination *dest)
1850 {
1851 struct mlx5_flow_rule *dst;
1852 struct mlx5_flow_namespace *ns;
1853
1854 ns = get_ns_with_notifiers(&ft->base);
1855 if (ns)
1856 down_read(&ns->dests_rw_sem);
1857 dst = fs_add_dst_ft(ft, match_criteria_enable, match_criteria,
1858 match_value, action, flow_tag, dest);
1859 if (ns)
1860 up_read(&ns->dests_rw_sem);
1861
1862 return dst;
1863
1864
1865 }
1866 EXPORT_SYMBOL(mlx5_add_flow_rule);
1867
mlx5_del_flow_rule(struct mlx5_flow_rule * dst)1868 void mlx5_del_flow_rule(struct mlx5_flow_rule *dst)
1869 {
1870 struct mlx5_flow_namespace *ns;
1871
1872 ns = get_ns_with_notifiers(&dst->base);
1873 if (ns)
1874 down_read(&ns->dests_rw_sem);
1875 fs_remove_node(&dst->base);
1876 if (ns)
1877 up_read(&ns->dests_rw_sem);
1878 }
1879 EXPORT_SYMBOL(mlx5_del_flow_rule);
1880
1881 #define MLX5_CORE_FS_ROOT_NS_NAME "root"
1882 #define MLX5_CORE_FS_ESW_EGRESS_ACL "esw_egress_root"
1883 #define MLX5_CORE_FS_ESW_INGRESS_ACL "esw_ingress_root"
1884 #define MLX5_CORE_FS_FDB_ROOT_NS_NAME "fdb_root"
1885 #define MLX5_CORE_FS_SNIFFER_RX_ROOT_NS_NAME "sniffer_rx_root"
1886 #define MLX5_CORE_FS_SNIFFER_TX_ROOT_NS_NAME "sniffer_tx_root"
1887 #define MLX5_CORE_FS_PRIO_MAX_FT 4
1888 #define MLX5_CORE_FS_PRIO_MAX_NS 1
1889
fs_create_prio(struct mlx5_flow_namespace * ns,unsigned prio,int max_ft,const char * name,u8 flags)1890 static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
1891 unsigned prio, int max_ft,
1892 const char *name, u8 flags)
1893 {
1894 struct fs_prio *fs_prio;
1895
1896 fs_prio = kzalloc(sizeof(*fs_prio), GFP_KERNEL);
1897 if (!fs_prio)
1898 return ERR_PTR(-ENOMEM);
1899
1900 fs_prio->base.type = FS_TYPE_PRIO;
1901 fs_add_node(&fs_prio->base, &ns->base, name, 1);
1902 fs_prio->max_ft = max_ft;
1903 fs_prio->max_ns = MLX5_CORE_FS_PRIO_MAX_NS;
1904 fs_prio->prio = prio;
1905 fs_prio->flags = flags;
1906 list_add_tail(&fs_prio->base.list, &ns->prios);
1907 INIT_LIST_HEAD(&fs_prio->objs);
1908 mutex_init(&fs_prio->shared_lock);
1909
1910 return fs_prio;
1911 }
1912
cleanup_root_ns(struct mlx5_core_dev * dev)1913 static void cleanup_root_ns(struct mlx5_core_dev *dev)
1914 {
1915 struct mlx5_flow_root_namespace *root_ns = dev->root_ns;
1916 struct fs_prio *iter_prio;
1917
1918 if (!root_ns)
1919 return;
1920
1921 /* stage 1 */
1922 fs_for_each_prio(iter_prio, &root_ns->ns) {
1923 struct mlx5_flow_namespace *iter_ns;
1924
1925 fs_for_each_ns(iter_ns, iter_prio) {
1926 while (!list_empty(&iter_ns->prios)) {
1927 struct fs_base *iter_prio2 =
1928 list_first_entry(&iter_ns->prios,
1929 struct fs_base,
1930 list);
1931
1932 fs_remove_node(iter_prio2);
1933 }
1934 }
1935 }
1936
1937 /* stage 2 */
1938 fs_for_each_prio(iter_prio, &root_ns->ns) {
1939 while (!list_empty(&iter_prio->objs)) {
1940 struct fs_base *iter_ns =
1941 list_first_entry(&iter_prio->objs,
1942 struct fs_base,
1943 list);
1944
1945 fs_remove_node(iter_ns);
1946 }
1947 }
1948 /* stage 3 */
1949 while (!list_empty(&root_ns->ns.prios)) {
1950 struct fs_base *iter_prio =
1951 list_first_entry(&root_ns->ns.prios,
1952 struct fs_base,
1953 list);
1954
1955 fs_remove_node(iter_prio);
1956 }
1957
1958 fs_remove_node(&root_ns->ns.base);
1959 dev->root_ns = NULL;
1960 }
1961
cleanup_single_prio_root_ns(struct mlx5_core_dev * dev,struct mlx5_flow_root_namespace * root_ns)1962 static void cleanup_single_prio_root_ns(struct mlx5_core_dev *dev,
1963 struct mlx5_flow_root_namespace *root_ns)
1964 {
1965 struct fs_base *prio;
1966
1967 if (!root_ns)
1968 return;
1969
1970 if (!list_empty(&root_ns->ns.prios)) {
1971 prio = list_first_entry(&root_ns->ns.prios,
1972 struct fs_base,
1973 list);
1974 fs_remove_node(prio);
1975 }
1976 fs_remove_node(&root_ns->ns.base);
1977 root_ns = NULL;
1978 }
1979
mlx5_cleanup_fs(struct mlx5_core_dev * dev)1980 void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
1981 {
1982 cleanup_root_ns(dev);
1983 cleanup_single_prio_root_ns(dev, dev->sniffer_rx_root_ns);
1984 cleanup_single_prio_root_ns(dev, dev->sniffer_tx_root_ns);
1985 cleanup_single_prio_root_ns(dev, dev->fdb_root_ns);
1986 cleanup_single_prio_root_ns(dev, dev->esw_egress_root_ns);
1987 cleanup_single_prio_root_ns(dev, dev->esw_ingress_root_ns);
1988 }
1989
fs_init_namespace(struct mlx5_flow_namespace * ns)1990 static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
1991 *ns)
1992 {
1993 ns->base.type = FS_TYPE_NAMESPACE;
1994 init_rwsem(&ns->dests_rw_sem);
1995 init_rwsem(&ns->notifiers_rw_sem);
1996 INIT_LIST_HEAD(&ns->prios);
1997 INIT_LIST_HEAD(&ns->list_notifiers);
1998
1999 return ns;
2000 }
2001
create_root_ns(struct mlx5_core_dev * dev,enum fs_ft_type table_type,char * name)2002 static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_core_dev *dev,
2003 enum fs_ft_type
2004 table_type,
2005 char *name)
2006 {
2007 struct mlx5_flow_root_namespace *root_ns;
2008 struct mlx5_flow_namespace *ns;
2009
2010 /* create the root namespace */
2011 root_ns = mlx5_vzalloc(sizeof(*root_ns));
2012 if (!root_ns)
2013 goto err;
2014
2015 root_ns->dev = dev;
2016 root_ns->table_type = table_type;
2017 mutex_init(&root_ns->fs_chain_lock);
2018
2019 ns = &root_ns->ns;
2020 fs_init_namespace(ns);
2021 fs_add_node(&ns->base, NULL, name, 1);
2022
2023 return root_ns;
2024 err:
2025 return NULL;
2026 }
2027
init_fdb_root_ns(struct mlx5_core_dev * dev)2028 static int init_fdb_root_ns(struct mlx5_core_dev *dev)
2029 {
2030 struct fs_prio *prio;
2031
2032 dev->fdb_root_ns = create_root_ns(dev, FS_FT_FDB,
2033 MLX5_CORE_FS_FDB_ROOT_NS_NAME);
2034 if (!dev->fdb_root_ns)
2035 return -ENOMEM;
2036
2037 /* create 1 prio*/
2038 prio = fs_create_prio(&dev->fdb_root_ns->ns, 0, 1, "fdb_prio", 0);
2039 if (IS_ERR(prio))
2040 return PTR_ERR(prio);
2041 else
2042 return 0;
2043 }
2044
2045 #define MAX_VPORTS 128
2046
init_egress_acl_root_ns(struct mlx5_core_dev * dev)2047 static int init_egress_acl_root_ns(struct mlx5_core_dev *dev)
2048 {
2049 struct fs_prio *prio;
2050
2051 dev->esw_egress_root_ns = create_root_ns(dev, FS_FT_ESW_EGRESS_ACL,
2052 MLX5_CORE_FS_ESW_EGRESS_ACL);
2053 if (!dev->esw_egress_root_ns)
2054 return -ENOMEM;
2055
2056 /* create 1 prio*/
2057 prio = fs_create_prio(&dev->esw_egress_root_ns->ns, 0, MAX_VPORTS,
2058 "esw_egress_prio", 0);
2059 if (IS_ERR(prio))
2060 return PTR_ERR(prio);
2061 else
2062 return 0;
2063 }
2064
init_ingress_acl_root_ns(struct mlx5_core_dev * dev)2065 static int init_ingress_acl_root_ns(struct mlx5_core_dev *dev)
2066 {
2067 struct fs_prio *prio;
2068
2069 dev->esw_ingress_root_ns = create_root_ns(dev, FS_FT_ESW_INGRESS_ACL,
2070 MLX5_CORE_FS_ESW_INGRESS_ACL);
2071 if (!dev->esw_ingress_root_ns)
2072 return -ENOMEM;
2073
2074 /* create 1 prio*/
2075 prio = fs_create_prio(&dev->esw_ingress_root_ns->ns, 0, MAX_VPORTS,
2076 "esw_ingress_prio", 0);
2077 if (IS_ERR(prio))
2078 return PTR_ERR(prio);
2079 else
2080 return 0;
2081 }
2082
init_sniffer_rx_root_ns(struct mlx5_core_dev * dev)2083 static int init_sniffer_rx_root_ns(struct mlx5_core_dev *dev)
2084 {
2085 struct fs_prio *prio;
2086
2087 dev->sniffer_rx_root_ns = create_root_ns(dev, FS_FT_SNIFFER_RX,
2088 MLX5_CORE_FS_SNIFFER_RX_ROOT_NS_NAME);
2089 if (!dev->sniffer_rx_root_ns)
2090 return -ENOMEM;
2091
2092 /* create 1 prio*/
2093 prio = fs_create_prio(&dev->sniffer_rx_root_ns->ns, 0, 1,
2094 "sniffer_prio", 0);
2095 if (IS_ERR(prio))
2096 return PTR_ERR(prio);
2097 else
2098 return 0;
2099 }
2100
2101
init_sniffer_tx_root_ns(struct mlx5_core_dev * dev)2102 static int init_sniffer_tx_root_ns(struct mlx5_core_dev *dev)
2103 {
2104 struct fs_prio *prio;
2105
2106 dev->sniffer_tx_root_ns = create_root_ns(dev, FS_FT_SNIFFER_TX,
2107 MLX5_CORE_FS_SNIFFER_TX_ROOT_NS_NAME);
2108 if (!dev->sniffer_tx_root_ns)
2109 return -ENOMEM;
2110
2111 /* create 1 prio*/
2112 prio = fs_create_prio(&dev->sniffer_tx_root_ns->ns, 0, 1,
2113 "sniffer_prio", 0);
2114 if (IS_ERR(prio))
2115 return PTR_ERR(prio);
2116 else
2117 return 0;
2118 }
2119
fs_create_namespace(struct fs_prio * prio,const char * name)2120 static struct mlx5_flow_namespace *fs_create_namespace(struct fs_prio *prio,
2121 const char *name)
2122 {
2123 struct mlx5_flow_namespace *ns;
2124
2125 ns = kzalloc(sizeof(*ns), GFP_KERNEL);
2126 if (!ns)
2127 return ERR_PTR(-ENOMEM);
2128
2129 fs_init_namespace(ns);
2130 fs_add_node(&ns->base, &prio->base, name, 1);
2131 list_add_tail(&ns->base.list, &prio->objs);
2132
2133 return ns;
2134 }
2135
2136 #define FLOW_TABLE_BIT_SZ 1
2137 #define GET_FLOW_TABLE_CAP(dev, offset) \
2138 ((be32_to_cpu(*((__be32 *)(dev->hca_caps_cur[MLX5_CAP_FLOW_TABLE]) + \
2139 offset / 32)) >> \
2140 (32 - FLOW_TABLE_BIT_SZ - (offset & 0x1f))) & FLOW_TABLE_BIT_SZ)
2141
has_required_caps(struct mlx5_core_dev * dev,struct node_caps * caps)2142 static bool has_required_caps(struct mlx5_core_dev *dev, struct node_caps *caps)
2143 {
2144 int i;
2145
2146 for (i = 0; i < caps->arr_sz; i++) {
2147 if (!GET_FLOW_TABLE_CAP(dev, caps->caps[i]))
2148 return false;
2149 }
2150 return true;
2151 }
2152
_init_root_tree(struct mlx5_core_dev * dev,int max_ft_level,struct init_tree_node * node,struct fs_base * base_parent,struct init_tree_node * tree_parent)2153 static int _init_root_tree(struct mlx5_core_dev *dev, int max_ft_level,
2154 struct init_tree_node *node, struct fs_base *base_parent,
2155 struct init_tree_node *tree_parent)
2156 {
2157 struct mlx5_flow_namespace *fs_ns;
2158 struct fs_prio *fs_prio;
2159 int priority;
2160 struct fs_base *base;
2161 int i;
2162 int err = 0;
2163
2164 if (node->type == FS_TYPE_PRIO) {
2165 if ((node->min_ft_level > max_ft_level) ||
2166 !has_required_caps(dev, &node->caps))
2167 goto out;
2168
2169 fs_get_obj(fs_ns, base_parent);
2170 priority = node - tree_parent->children;
2171 fs_prio = fs_create_prio(fs_ns, priority,
2172 node->max_ft,
2173 node->name, node->flags);
2174 if (IS_ERR(fs_prio)) {
2175 err = PTR_ERR(fs_prio);
2176 goto out;
2177 }
2178 base = &fs_prio->base;
2179 } else if (node->type == FS_TYPE_NAMESPACE) {
2180 fs_get_obj(fs_prio, base_parent);
2181 fs_ns = fs_create_namespace(fs_prio, node->name);
2182 if (IS_ERR(fs_ns)) {
2183 err = PTR_ERR(fs_ns);
2184 goto out;
2185 }
2186 base = &fs_ns->base;
2187 } else {
2188 return -EINVAL;
2189 }
2190 for (i = 0; i < node->ar_size; i++) {
2191 err = _init_root_tree(dev, max_ft_level, &node->children[i], base,
2192 node);
2193 if (err)
2194 break;
2195 }
2196 out:
2197 return err;
2198 }
2199
init_root_tree(struct mlx5_core_dev * dev,int max_ft_level,struct init_tree_node * node,struct fs_base * parent)2200 static int init_root_tree(struct mlx5_core_dev *dev, int max_ft_level,
2201 struct init_tree_node *node, struct fs_base *parent)
2202 {
2203 int i;
2204 struct mlx5_flow_namespace *fs_ns;
2205 int err = 0;
2206
2207 fs_get_obj(fs_ns, parent);
2208 for (i = 0; i < node->ar_size; i++) {
2209 err = _init_root_tree(dev, max_ft_level,
2210 &node->children[i], &fs_ns->base, node);
2211 if (err)
2212 break;
2213 }
2214 return err;
2215 }
2216
2217 static int sum_max_ft_in_prio(struct fs_prio *prio);
sum_max_ft_in_ns(struct mlx5_flow_namespace * ns)2218 static int sum_max_ft_in_ns(struct mlx5_flow_namespace *ns)
2219 {
2220 struct fs_prio *prio;
2221 int sum = 0;
2222
2223 fs_for_each_prio(prio, ns) {
2224 sum += sum_max_ft_in_prio(prio);
2225 }
2226 return sum;
2227 }
2228
sum_max_ft_in_prio(struct fs_prio * prio)2229 static int sum_max_ft_in_prio(struct fs_prio *prio)
2230 {
2231 int sum = 0;
2232 struct fs_base *it;
2233 struct mlx5_flow_namespace *ns;
2234
2235 if (prio->max_ft)
2236 return prio->max_ft;
2237
2238 fs_for_each_ns_or_ft(it, prio) {
2239 if (it->type == FS_TYPE_FLOW_TABLE)
2240 continue;
2241
2242 fs_get_obj(ns, it);
2243 sum += sum_max_ft_in_ns(ns);
2244 }
2245 prio->max_ft = sum;
2246 return sum;
2247 }
2248
set_max_ft(struct mlx5_flow_namespace * ns)2249 static void set_max_ft(struct mlx5_flow_namespace *ns)
2250 {
2251 struct fs_prio *prio;
2252
2253 if (!ns)
2254 return;
2255
2256 fs_for_each_prio(prio, ns)
2257 sum_max_ft_in_prio(prio);
2258 }
2259
init_root_ns(struct mlx5_core_dev * dev)2260 static int init_root_ns(struct mlx5_core_dev *dev)
2261 {
2262 int max_ft_level = MLX5_CAP_FLOWTABLE(dev,
2263 flow_table_properties_nic_receive.
2264 max_ft_level);
2265
2266 dev->root_ns = create_root_ns(dev, FS_FT_NIC_RX,
2267 MLX5_CORE_FS_ROOT_NS_NAME);
2268 if (IS_ERR_OR_NULL(dev->root_ns))
2269 goto err;
2270
2271
2272 if (init_root_tree(dev, max_ft_level, &root_fs, &dev->root_ns->ns.base))
2273 goto err;
2274
2275 set_max_ft(&dev->root_ns->ns);
2276
2277 return 0;
2278 err:
2279 return -ENOMEM;
2280 }
2281
mlx5_get_match_criteria_enable(struct mlx5_flow_rule * rule)2282 u8 mlx5_get_match_criteria_enable(struct mlx5_flow_rule *rule)
2283 {
2284 struct fs_base *pbase;
2285 struct mlx5_flow_group *fg;
2286
2287 pbase = rule->base.parent;
2288 WARN_ON(!pbase);
2289 pbase = pbase->parent;
2290 WARN_ON(!pbase);
2291
2292 fs_get_obj(fg, pbase);
2293 return fg->mask.match_criteria_enable;
2294 }
2295
mlx5_get_match_value(u32 * match_value,struct mlx5_flow_rule * rule)2296 void mlx5_get_match_value(u32 *match_value,
2297 struct mlx5_flow_rule *rule)
2298 {
2299 struct fs_base *pbase;
2300 struct fs_fte *fte;
2301
2302 pbase = rule->base.parent;
2303 WARN_ON(!pbase);
2304 fs_get_obj(fte, pbase);
2305
2306 memcpy(match_value, fte->val, sizeof(fte->val));
2307 }
2308
mlx5_get_match_criteria(u32 * match_criteria,struct mlx5_flow_rule * rule)2309 void mlx5_get_match_criteria(u32 *match_criteria,
2310 struct mlx5_flow_rule *rule)
2311 {
2312 struct fs_base *pbase;
2313 struct mlx5_flow_group *fg;
2314
2315 pbase = rule->base.parent;
2316 WARN_ON(!pbase);
2317 pbase = pbase->parent;
2318 WARN_ON(!pbase);
2319
2320 fs_get_obj(fg, pbase);
2321 memcpy(match_criteria, &fg->mask.match_criteria,
2322 sizeof(fg->mask.match_criteria));
2323 }
2324
mlx5_init_fs(struct mlx5_core_dev * dev)2325 int mlx5_init_fs(struct mlx5_core_dev *dev)
2326 {
2327 int err;
2328
2329 if (MLX5_CAP_GEN(dev, nic_flow_table)) {
2330 err = init_root_ns(dev);
2331 if (err)
2332 goto err;
2333 }
2334
2335 err = init_fdb_root_ns(dev);
2336 if (err)
2337 goto err;
2338
2339 err = init_egress_acl_root_ns(dev);
2340 if (err)
2341 goto err;
2342
2343 err = init_ingress_acl_root_ns(dev);
2344 if (err)
2345 goto err;
2346
2347 err = init_sniffer_tx_root_ns(dev);
2348 if (err)
2349 goto err;
2350
2351 err = init_sniffer_rx_root_ns(dev);
2352 if (err)
2353 goto err;
2354
2355 return 0;
2356 err:
2357 mlx5_cleanup_fs(dev);
2358 return err;
2359 }
2360
mlx5_get_flow_namespace(struct mlx5_core_dev * dev,enum mlx5_flow_namespace_type type)2361 struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
2362 enum mlx5_flow_namespace_type type)
2363 {
2364 struct mlx5_flow_root_namespace *root_ns = dev->root_ns;
2365 int prio;
2366 static struct fs_prio *fs_prio;
2367 struct mlx5_flow_namespace *ns;
2368
2369 switch (type) {
2370 case MLX5_FLOW_NAMESPACE_BYPASS:
2371 prio = 0;
2372 break;
2373 case MLX5_FLOW_NAMESPACE_KERNEL:
2374 prio = 1;
2375 break;
2376 case MLX5_FLOW_NAMESPACE_LEFTOVERS:
2377 prio = 2;
2378 break;
2379 case MLX5_FLOW_NAMESPACE_FDB:
2380 if (dev->fdb_root_ns)
2381 return &dev->fdb_root_ns->ns;
2382 else
2383 return NULL;
2384 case MLX5_FLOW_NAMESPACE_ESW_EGRESS:
2385 if (dev->esw_egress_root_ns)
2386 return &dev->esw_egress_root_ns->ns;
2387 else
2388 return NULL;
2389 case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
2390 if (dev->esw_ingress_root_ns)
2391 return &dev->esw_ingress_root_ns->ns;
2392 else
2393 return NULL;
2394 case MLX5_FLOW_NAMESPACE_SNIFFER_RX:
2395 if (dev->sniffer_rx_root_ns)
2396 return &dev->sniffer_rx_root_ns->ns;
2397 else
2398 return NULL;
2399 case MLX5_FLOW_NAMESPACE_SNIFFER_TX:
2400 if (dev->sniffer_tx_root_ns)
2401 return &dev->sniffer_tx_root_ns->ns;
2402 else
2403 return NULL;
2404 default:
2405 return NULL;
2406 }
2407
2408 if (!root_ns)
2409 return NULL;
2410
2411 fs_prio = find_prio(&root_ns->ns, prio);
2412 if (!fs_prio)
2413 return NULL;
2414
2415 ns = list_first_entry(&fs_prio->objs,
2416 typeof(*ns),
2417 base.list);
2418
2419 return ns;
2420 }
2421 EXPORT_SYMBOL(mlx5_get_flow_namespace);
2422
2423
mlx5_set_rule_private_data(struct mlx5_flow_rule * rule,struct mlx5_flow_handler * fs_handler,void * client_data)2424 int mlx5_set_rule_private_data(struct mlx5_flow_rule *rule,
2425 struct mlx5_flow_handler *fs_handler,
2426 void *client_data)
2427 {
2428 struct fs_client_priv_data *priv_data;
2429
2430 mutex_lock(&rule->clients_lock);
2431 /*Check that hanlder isn't exists in the list already*/
2432 list_for_each_entry(priv_data, &rule->clients_data, list) {
2433 if (priv_data->fs_handler == fs_handler) {
2434 priv_data->client_dst_data = client_data;
2435 goto unlock;
2436 }
2437 }
2438 priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
2439 if (!priv_data) {
2440 mutex_unlock(&rule->clients_lock);
2441 return -ENOMEM;
2442 }
2443
2444 priv_data->client_dst_data = client_data;
2445 priv_data->fs_handler = fs_handler;
2446 list_add(&priv_data->list, &rule->clients_data);
2447
2448 unlock:
2449 mutex_unlock(&rule->clients_lock);
2450
2451 return 0;
2452 }
2453
remove_from_clients(struct mlx5_flow_rule * rule,bool ctx_changed,void * client_data,void * context)2454 static int remove_from_clients(struct mlx5_flow_rule *rule,
2455 bool ctx_changed,
2456 void *client_data,
2457 void *context)
2458 {
2459 struct fs_client_priv_data *iter_client;
2460 struct fs_client_priv_data *temp_client;
2461 struct mlx5_flow_handler *handler = (struct
2462 mlx5_flow_handler*)context;
2463
2464 mutex_lock(&rule->clients_lock);
2465 list_for_each_entry_safe(iter_client, temp_client,
2466 &rule->clients_data, list) {
2467 if (iter_client->fs_handler == handler) {
2468 list_del(&iter_client->list);
2469 kfree(iter_client);
2470 break;
2471 }
2472 }
2473 mutex_unlock(&rule->clients_lock);
2474
2475 return 0;
2476 }
2477
mlx5_register_rule_notifier(struct mlx5_core_dev * dev,enum mlx5_flow_namespace_type ns_type,rule_event_fn add_cb,rule_event_fn del_cb,void * context)2478 struct mlx5_flow_handler *mlx5_register_rule_notifier(struct mlx5_core_dev *dev,
2479 enum mlx5_flow_namespace_type ns_type,
2480 rule_event_fn add_cb,
2481 rule_event_fn del_cb,
2482 void *context)
2483 {
2484 struct mlx5_flow_namespace *ns;
2485 struct mlx5_flow_handler *handler;
2486
2487 ns = mlx5_get_flow_namespace(dev, ns_type);
2488 if (!ns)
2489 return ERR_PTR(-EINVAL);
2490
2491 handler = kzalloc(sizeof(*handler), GFP_KERNEL);
2492 if (!handler)
2493 return ERR_PTR(-ENOMEM);
2494
2495 handler->add_dst_cb = add_cb;
2496 handler->del_dst_cb = del_cb;
2497 handler->client_context = context;
2498 handler->ns = ns;
2499 down_write(&ns->notifiers_rw_sem);
2500 list_add_tail(&handler->list, &ns->list_notifiers);
2501 up_write(&ns->notifiers_rw_sem);
2502
2503 return handler;
2504 }
2505
2506 static void iterate_rules_in_ns(struct mlx5_flow_namespace *ns,
2507 rule_event_fn add_rule_cb,
2508 void *context);
2509
mlx5_unregister_rule_notifier(struct mlx5_flow_handler * handler)2510 void mlx5_unregister_rule_notifier(struct mlx5_flow_handler *handler)
2511 {
2512 struct mlx5_flow_namespace *ns = handler->ns;
2513
2514 /*Remove from dst's clients*/
2515 down_write(&ns->dests_rw_sem);
2516 down_write(&ns->notifiers_rw_sem);
2517 iterate_rules_in_ns(ns, remove_from_clients, handler);
2518 list_del(&handler->list);
2519 up_write(&ns->notifiers_rw_sem);
2520 up_write(&ns->dests_rw_sem);
2521 kfree(handler);
2522 }
2523
iterate_rules_in_ft(struct mlx5_flow_table * ft,rule_event_fn add_rule_cb,void * context)2524 static void iterate_rules_in_ft(struct mlx5_flow_table *ft,
2525 rule_event_fn add_rule_cb,
2526 void *context)
2527 {
2528 struct mlx5_flow_group *iter_fg;
2529 struct fs_fte *iter_fte;
2530 struct mlx5_flow_rule *iter_rule;
2531 int err = 0;
2532 bool is_new_rule;
2533
2534 mutex_lock(&ft->base.lock);
2535 fs_for_each_fg(iter_fg, ft) {
2536 mutex_lock(&iter_fg->base.lock);
2537 fs_for_each_fte(iter_fte, iter_fg) {
2538 mutex_lock(&iter_fte->base.lock);
2539 is_new_rule = true;
2540 fs_for_each_dst(iter_rule, iter_fte) {
2541 fs_get(&iter_rule->base);
2542 err = add_rule_cb(iter_rule,
2543 is_new_rule,
2544 NULL,
2545 context);
2546 fs_put_parent_locked(&iter_rule->base);
2547 if (err)
2548 break;
2549 is_new_rule = false;
2550 }
2551 mutex_unlock(&iter_fte->base.lock);
2552 if (err)
2553 break;
2554 }
2555 mutex_unlock(&iter_fg->base.lock);
2556 if (err)
2557 break;
2558 }
2559 mutex_unlock(&ft->base.lock);
2560 }
2561
iterate_rules_in_prio(struct fs_prio * prio,rule_event_fn add_rule_cb,void * context)2562 static void iterate_rules_in_prio(struct fs_prio *prio,
2563 rule_event_fn add_rule_cb,
2564 void *context)
2565 {
2566 struct fs_base *it;
2567
2568 mutex_lock(&prio->base.lock);
2569 fs_for_each_ns_or_ft(it, prio) {
2570 if (it->type == FS_TYPE_FLOW_TABLE) {
2571 struct mlx5_flow_table *ft;
2572
2573 fs_get_obj(ft, it);
2574 iterate_rules_in_ft(ft, add_rule_cb, context);
2575 } else {
2576 struct mlx5_flow_namespace *ns;
2577
2578 fs_get_obj(ns, it);
2579 iterate_rules_in_ns(ns, add_rule_cb, context);
2580 }
2581 }
2582 mutex_unlock(&prio->base.lock);
2583 }
2584
iterate_rules_in_ns(struct mlx5_flow_namespace * ns,rule_event_fn add_rule_cb,void * context)2585 static void iterate_rules_in_ns(struct mlx5_flow_namespace *ns,
2586 rule_event_fn add_rule_cb,
2587 void *context)
2588 {
2589 struct fs_prio *iter_prio;
2590
2591 mutex_lock(&ns->base.lock);
2592 fs_for_each_prio(iter_prio, ns) {
2593 iterate_rules_in_prio(iter_prio, add_rule_cb, context);
2594 }
2595 mutex_unlock(&ns->base.lock);
2596 }
2597
mlx5_flow_iterate_existing_rules(struct mlx5_flow_namespace * ns,rule_event_fn add_rule_cb,void * context)2598 void mlx5_flow_iterate_existing_rules(struct mlx5_flow_namespace *ns,
2599 rule_event_fn add_rule_cb,
2600 void *context)
2601 {
2602 down_write(&ns->dests_rw_sem);
2603 down_read(&ns->notifiers_rw_sem);
2604 iterate_rules_in_ns(ns, add_rule_cb, context);
2605 up_read(&ns->notifiers_rw_sem);
2606 up_write(&ns->dests_rw_sem);
2607 }
2608
2609
mlx5_del_flow_rules_list(struct mlx5_flow_rules_list * rules_list)2610 void mlx5_del_flow_rules_list(struct mlx5_flow_rules_list *rules_list)
2611 {
2612 struct mlx5_flow_rule_node *iter_node;
2613 struct mlx5_flow_rule_node *temp_node;
2614
2615 list_for_each_entry_safe(iter_node, temp_node, &rules_list->head, list) {
2616 list_del(&iter_node->list);
2617 kfree(iter_node);
2618 }
2619
2620 kfree(rules_list);
2621 }
2622
2623 #define ROCEV1_ETHERTYPE 0x8915
set_rocev1_rules(struct list_head * rules_list)2624 static int set_rocev1_rules(struct list_head *rules_list)
2625 {
2626 struct mlx5_flow_rule_node *rocev1_rule;
2627
2628 rocev1_rule = kzalloc(sizeof(*rocev1_rule), GFP_KERNEL);
2629 if (!rocev1_rule)
2630 return -ENOMEM;
2631
2632 rocev1_rule->match_criteria_enable =
2633 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS;
2634 MLX5_SET(fte_match_set_lyr_2_4, rocev1_rule->match_criteria, ethertype,
2635 0xffff);
2636 MLX5_SET(fte_match_set_lyr_2_4, rocev1_rule->match_value, ethertype,
2637 ROCEV1_ETHERTYPE);
2638
2639 list_add_tail(&rocev1_rule->list, rules_list);
2640
2641 return 0;
2642 }
2643
2644 #define ROCEV2_UDP_PORT 4791
set_rocev2_rules(struct list_head * rules_list)2645 static int set_rocev2_rules(struct list_head *rules_list)
2646 {
2647 struct mlx5_flow_rule_node *ipv4_rule;
2648 struct mlx5_flow_rule_node *ipv6_rule;
2649
2650 ipv4_rule = kzalloc(sizeof(*ipv4_rule), GFP_KERNEL);
2651 if (!ipv4_rule)
2652 return -ENOMEM;
2653
2654 ipv6_rule = kzalloc(sizeof(*ipv6_rule), GFP_KERNEL);
2655 if (!ipv6_rule) {
2656 kfree(ipv4_rule);
2657 return -ENOMEM;
2658 }
2659
2660 ipv4_rule->match_criteria_enable =
2661 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS;
2662 MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_criteria, ethertype,
2663 0xffff);
2664 MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_value, ethertype,
2665 0x0800);
2666 MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_criteria, ip_protocol,
2667 0xff);
2668 MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_value, ip_protocol,
2669 IPPROTO_UDP);
2670 MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_criteria, udp_dport,
2671 0xffff);
2672 MLX5_SET(fte_match_set_lyr_2_4, ipv4_rule->match_value, udp_dport,
2673 ROCEV2_UDP_PORT);
2674
2675 ipv6_rule->match_criteria_enable =
2676 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS;
2677 MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_criteria, ethertype,
2678 0xffff);
2679 MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_value, ethertype,
2680 0x86dd);
2681 MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_criteria, ip_protocol,
2682 0xff);
2683 MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_value, ip_protocol,
2684 IPPROTO_UDP);
2685 MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_criteria, udp_dport,
2686 0xffff);
2687 MLX5_SET(fte_match_set_lyr_2_4, ipv6_rule->match_value, udp_dport,
2688 ROCEV2_UDP_PORT);
2689
2690 list_add_tail(&ipv4_rule->list, rules_list);
2691 list_add_tail(&ipv6_rule->list, rules_list);
2692
2693 return 0;
2694 }
2695
2696
get_roce_flow_rules(u8 roce_mode)2697 struct mlx5_flow_rules_list *get_roce_flow_rules(u8 roce_mode)
2698 {
2699 int err = 0;
2700 struct mlx5_flow_rules_list *rules_list =
2701 kzalloc(sizeof(*rules_list), GFP_KERNEL);
2702
2703 if (!rules_list)
2704 return NULL;
2705
2706 INIT_LIST_HEAD(&rules_list->head);
2707
2708 if (roce_mode & MLX5_ROCE_VERSION_1_CAP) {
2709 err = set_rocev1_rules(&rules_list->head);
2710 if (err)
2711 goto free_list;
2712 }
2713 if (roce_mode & MLX5_ROCE_VERSION_2_CAP)
2714 err = set_rocev2_rules(&rules_list->head);
2715 if (err)
2716 goto free_list;
2717
2718 return rules_list;
2719
2720 free_list:
2721 mlx5_del_flow_rules_list(rules_list);
2722 return NULL;
2723 }
2724