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