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