1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/mutex.h>
34#include <linux/mlx5/driver.h>
35
36#include "mlx5_core.h"
37#include "fs_core.h"
38#include "fs_cmd.h"
39#include "diag/fs_tracepoint.h"
40
41#define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
42 sizeof(struct init_tree_node))
43
44#define ADD_PRIO(num_prios_val, min_level_val, num_levels_val, caps_val,\
45 ...) {.type = FS_TYPE_PRIO,\
46 .min_ft_level = min_level_val,\
47 .num_levels = num_levels_val,\
48 .num_leaf_prios = num_prios_val,\
49 .caps = caps_val,\
50 .children = (struct init_tree_node[]) {__VA_ARGS__},\
51 .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
52}
53
54#define ADD_MULTIPLE_PRIO(num_prios_val, num_levels_val, ...)\
55 ADD_PRIO(num_prios_val, 0, num_levels_val, {},\
56 __VA_ARGS__)\
57
58#define ADD_NS(...) {.type = FS_TYPE_NAMESPACE,\
59 .children = (struct init_tree_node[]) {__VA_ARGS__},\
60 .ar_size = INIT_TREE_NODE_ARRAY_SIZE(__VA_ARGS__) \
61}
62
63#define INIT_CAPS_ARRAY_SIZE(...) (sizeof((long[]){__VA_ARGS__}) /\
64 sizeof(long))
65
66#define FS_CAP(cap) (__mlx5_bit_off(flow_table_nic_cap, cap))
67
68#define FS_REQUIRED_CAPS(...) {.arr_sz = INIT_CAPS_ARRAY_SIZE(__VA_ARGS__), \
69 .caps = (long[]) {__VA_ARGS__} }
70
71#define FS_CHAINING_CAPS FS_REQUIRED_CAPS(FS_CAP(flow_table_properties_nic_receive.flow_modify_en), \
72 FS_CAP(flow_table_properties_nic_receive.modify_root), \
73 FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), \
74 FS_CAP(flow_table_properties_nic_receive.flow_table_modify))
75
76#define LEFTOVERS_NUM_LEVELS 1
77#define LEFTOVERS_NUM_PRIOS 1
78
79#define BY_PASS_PRIO_NUM_LEVELS 1
80#define BY_PASS_MIN_LEVEL (ETHTOOL_MIN_LEVEL + MLX5_BY_PASS_NUM_PRIOS +\
81 LEFTOVERS_NUM_PRIOS)
82
83#define ETHTOOL_PRIO_NUM_LEVELS 1
84#define ETHTOOL_NUM_PRIOS 11
85#define ETHTOOL_MIN_LEVEL (KERNEL_MIN_LEVEL + ETHTOOL_NUM_PRIOS)
86
87#define KERNEL_NIC_PRIO_NUM_LEVELS 5
88#define KERNEL_NIC_NUM_PRIOS 1
89
90#define KERNEL_MIN_LEVEL (KERNEL_NIC_PRIO_NUM_LEVELS + 1)
91
92#define ANCHOR_NUM_LEVELS 1
93#define ANCHOR_NUM_PRIOS 1
94#define ANCHOR_MIN_LEVEL (BY_PASS_MIN_LEVEL + 1)
95
96#define OFFLOADS_MAX_FT 1
97#define OFFLOADS_NUM_PRIOS 1
98#define OFFLOADS_MIN_LEVEL (ANCHOR_MIN_LEVEL + 1)
99
100#define LAG_PRIO_NUM_LEVELS 1
101#define LAG_NUM_PRIOS 1
102#define LAG_MIN_LEVEL (OFFLOADS_MIN_LEVEL + 1)
103
104struct node_caps {
105 size_t arr_sz;
106 long *caps;
107};
108
109static struct init_tree_node {
110 enum fs_node_type type;
111 struct init_tree_node *children;
112 int ar_size;
113 struct node_caps caps;
114 int min_ft_level;
115 int num_leaf_prios;
116 int prio;
117 int num_levels;
118} root_fs = {
119 .type = FS_TYPE_NAMESPACE,
120 .ar_size = 7,
121 .children = (struct init_tree_node[]) {
122 ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0,
123 FS_CHAINING_CAPS,
124 ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS,
125 BY_PASS_PRIO_NUM_LEVELS))),
126 ADD_PRIO(0, LAG_MIN_LEVEL, 0,
127 FS_CHAINING_CAPS,
128 ADD_NS(ADD_MULTIPLE_PRIO(LAG_NUM_PRIOS,
129 LAG_PRIO_NUM_LEVELS))),
130 ADD_PRIO(0, OFFLOADS_MIN_LEVEL, 0, {},
131 ADD_NS(ADD_MULTIPLE_PRIO(OFFLOADS_NUM_PRIOS, OFFLOADS_MAX_FT))),
132 ADD_PRIO(0, ETHTOOL_MIN_LEVEL, 0,
133 FS_CHAINING_CAPS,
134 ADD_NS(ADD_MULTIPLE_PRIO(ETHTOOL_NUM_PRIOS,
135 ETHTOOL_PRIO_NUM_LEVELS))),
136 ADD_PRIO(0, KERNEL_MIN_LEVEL, 0, {},
137 ADD_NS(ADD_MULTIPLE_PRIO(1, 1),
138 ADD_MULTIPLE_PRIO(KERNEL_NIC_NUM_PRIOS,
139 KERNEL_NIC_PRIO_NUM_LEVELS))),
140 ADD_PRIO(0, BY_PASS_MIN_LEVEL, 0,
141 FS_CHAINING_CAPS,
142 ADD_NS(ADD_MULTIPLE_PRIO(LEFTOVERS_NUM_PRIOS, LEFTOVERS_NUM_LEVELS))),
143 ADD_PRIO(0, ANCHOR_MIN_LEVEL, 0, {},
144 ADD_NS(ADD_MULTIPLE_PRIO(ANCHOR_NUM_PRIOS, ANCHOR_NUM_LEVELS))),
145 }
146};
147
148enum fs_i_mutex_lock_class {
149 FS_MUTEX_GRANDPARENT,
150 FS_MUTEX_PARENT,
151 FS_MUTEX_CHILD
152};
153
154static const struct rhashtable_params rhash_fte = {
155 .key_len = FIELD_SIZEOF(struct fs_fte, val),
156 .key_offset = offsetof(struct fs_fte, val),
157 .head_offset = offsetof(struct fs_fte, hash),
158 .automatic_shrinking = true,
159 .min_size = 1,
160};
161
162static const struct rhashtable_params rhash_fg = {
163 .key_len = FIELD_SIZEOF(struct mlx5_flow_group, mask),
164 .key_offset = offsetof(struct mlx5_flow_group, mask),
165 .head_offset = offsetof(struct mlx5_flow_group, hash),
166 .automatic_shrinking = true,
167 .min_size = 1,
168
169};
170
171static void del_rule(struct fs_node *node);
172static void del_flow_table(struct fs_node *node);
173static void del_flow_group(struct fs_node *node);
174static void del_fte(struct fs_node *node);
175static bool mlx5_flow_dests_cmp(struct mlx5_flow_destination *d1,
176 struct mlx5_flow_destination *d2);
177static struct mlx5_flow_rule *
178find_flow_rule(struct fs_fte *fte,
179 struct mlx5_flow_destination *dest);
180
181static void tree_init_node(struct fs_node *node,
182 unsigned int refcount,
183 void (*remove_func)(struct fs_node *))
184{
185 atomic_set(&node->refcount, refcount);
186 INIT_LIST_HEAD(&node->list);
187 INIT_LIST_HEAD(&node->children);
188 mutex_init(&node->lock);
189 node->remove_func = remove_func;
190}
191
192static void tree_add_node(struct fs_node *node, struct fs_node *parent)
193{
194 if (parent)
195 atomic_inc(&parent->refcount);
196 node->parent = parent;
197
198
199 if (!parent)
200 node->root = node;
201 else
202 node->root = parent->root;
203}
204
205static void tree_get_node(struct fs_node *node)
206{
207 atomic_inc(&node->refcount);
208}
209
210static void nested_lock_ref_node(struct fs_node *node,
211 enum fs_i_mutex_lock_class class)
212{
213 if (node) {
214 mutex_lock_nested(&node->lock, class);
215 atomic_inc(&node->refcount);
216 }
217}
218
219static void lock_ref_node(struct fs_node *node)
220{
221 if (node) {
222 mutex_lock(&node->lock);
223 atomic_inc(&node->refcount);
224 }
225}
226
227static void unlock_ref_node(struct fs_node *node)
228{
229 if (node) {
230 atomic_dec(&node->refcount);
231 mutex_unlock(&node->lock);
232 }
233}
234
235static void tree_put_node(struct fs_node *node)
236{
237 struct fs_node *parent_node = node->parent;
238
239 lock_ref_node(parent_node);
240 if (atomic_dec_and_test(&node->refcount)) {
241 if (parent_node)
242 list_del_init(&node->list);
243 if (node->remove_func)
244 node->remove_func(node);
245 kfree(node);
246 node = NULL;
247 }
248 unlock_ref_node(parent_node);
249 if (!node && parent_node)
250 tree_put_node(parent_node);
251}
252
253static int tree_remove_node(struct fs_node *node)
254{
255 if (atomic_read(&node->refcount) > 1) {
256 atomic_dec(&node->refcount);
257 return -EEXIST;
258 }
259 tree_put_node(node);
260 return 0;
261}
262
263static struct fs_prio *find_prio(struct mlx5_flow_namespace *ns,
264 unsigned int prio)
265{
266 struct fs_prio *iter_prio;
267
268 fs_for_each_prio(iter_prio, ns) {
269 if (iter_prio->prio == prio)
270 return iter_prio;
271 }
272
273 return NULL;
274}
275
276static bool check_last_reserved(const u32 *match_criteria)
277{
278 char *match_criteria_reserved =
279 MLX5_ADDR_OF(fte_match_param, match_criteria, MLX5_FTE_MATCH_PARAM_RESERVED);
280
281 return !match_criteria_reserved[0] &&
282 !memcmp(match_criteria_reserved, match_criteria_reserved + 1,
283 MLX5_FLD_SZ_BYTES(fte_match_param,
284 MLX5_FTE_MATCH_PARAM_RESERVED) - 1);
285}
286
287static bool check_valid_mask(u8 match_criteria_enable, const u32 *match_criteria)
288{
289 if (match_criteria_enable & ~(
290 (1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) |
291 (1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) |
292 (1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS)))
293 return false;
294
295 if (!(match_criteria_enable &
296 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS)) {
297 char *fg_type_mask = MLX5_ADDR_OF(fte_match_param,
298 match_criteria, outer_headers);
299
300 if (fg_type_mask[0] ||
301 memcmp(fg_type_mask, fg_type_mask + 1,
302 MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4) - 1))
303 return false;
304 }
305
306 if (!(match_criteria_enable &
307 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS)) {
308 char *fg_type_mask = MLX5_ADDR_OF(fte_match_param,
309 match_criteria, misc_parameters);
310
311 if (fg_type_mask[0] ||
312 memcmp(fg_type_mask, fg_type_mask + 1,
313 MLX5_ST_SZ_BYTES(fte_match_set_misc) - 1))
314 return false;
315 }
316
317 if (!(match_criteria_enable &
318 1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS)) {
319 char *fg_type_mask = MLX5_ADDR_OF(fte_match_param,
320 match_criteria, inner_headers);
321
322 if (fg_type_mask[0] ||
323 memcmp(fg_type_mask, fg_type_mask + 1,
324 MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4) - 1))
325 return false;
326 }
327
328 return check_last_reserved(match_criteria);
329}
330
331static bool check_valid_spec(const struct mlx5_flow_spec *spec)
332{
333 int i;
334
335 if (!check_valid_mask(spec->match_criteria_enable, spec->match_criteria)) {
336 pr_warn("mlx5_core: Match criteria given mismatches match_criteria_enable\n");
337 return false;
338 }
339
340 for (i = 0; i < MLX5_ST_SZ_DW_MATCH_PARAM; i++)
341 if (spec->match_value[i] & ~spec->match_criteria[i]) {
342 pr_warn("mlx5_core: match_value differs from match_criteria\n");
343 return false;
344 }
345
346 return check_last_reserved(spec->match_value);
347}
348
349static struct mlx5_flow_root_namespace *find_root(struct fs_node *node)
350{
351 struct fs_node *root;
352 struct mlx5_flow_namespace *ns;
353
354 root = node->root;
355
356 if (WARN_ON(root->type != FS_TYPE_NAMESPACE)) {
357 pr_warn("mlx5: flow steering node is not in tree or garbaged\n");
358 return NULL;
359 }
360
361 ns = container_of(root, struct mlx5_flow_namespace, node);
362 return container_of(ns, struct mlx5_flow_root_namespace, ns);
363}
364
365static inline struct mlx5_core_dev *get_dev(struct fs_node *node)
366{
367 struct mlx5_flow_root_namespace *root = find_root(node);
368
369 if (root)
370 return root->dev;
371 return NULL;
372}
373
374static void del_flow_table(struct fs_node *node)
375{
376 struct mlx5_flow_table *ft;
377 struct mlx5_core_dev *dev;
378 struct fs_prio *prio;
379 int err;
380
381 fs_get_obj(ft, node);
382 dev = get_dev(&ft->node);
383
384 err = mlx5_cmd_destroy_flow_table(dev, ft);
385 if (err)
386 mlx5_core_warn(dev, "flow steering can't destroy ft\n");
387 ida_destroy(&ft->fte_allocator);
388 rhltable_destroy(&ft->fgs_hash);
389 fs_get_obj(prio, ft->node.parent);
390 prio->num_ft--;
391}
392
393static void del_rule(struct fs_node *node)
394{
395 struct mlx5_flow_rule *rule;
396 struct mlx5_flow_table *ft;
397 struct mlx5_flow_group *fg;
398 struct fs_fte *fte;
399 int modify_mask;
400 struct mlx5_core_dev *dev = get_dev(node);
401 int err;
402 bool update_fte = false;
403
404 fs_get_obj(rule, node);
405 fs_get_obj(fte, rule->node.parent);
406 fs_get_obj(fg, fte->node.parent);
407 fs_get_obj(ft, fg->node.parent);
408 trace_mlx5_fs_del_rule(rule);
409 list_del(&rule->node.list);
410 if (rule->sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
411 mutex_lock(&rule->dest_attr.ft->lock);
412 list_del(&rule->next_ft);
413 mutex_unlock(&rule->dest_attr.ft->lock);
414 }
415
416 if (rule->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER &&
417 --fte->dests_size) {
418 modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION);
419 fte->action &= ~MLX5_FLOW_CONTEXT_ACTION_COUNT;
420 update_fte = true;
421 goto out;
422 }
423
424 if ((fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
425 --fte->dests_size) {
426 modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST),
427 update_fte = true;
428 }
429out:
430 if (update_fte && fte->dests_size) {
431 err = mlx5_cmd_update_fte(dev, ft, fg->id, modify_mask, fte);
432 if (err)
433 mlx5_core_warn(dev,
434 "%s can't del rule fg id=%d fte_index=%d\n",
435 __func__, fg->id, fte->index);
436 }
437}
438
439static void destroy_fte(struct fs_fte *fte, struct mlx5_flow_group *fg)
440{
441 struct mlx5_flow_table *ft;
442 int ret;
443
444 ret = rhashtable_remove_fast(&fg->ftes_hash, &fte->hash, rhash_fte);
445 WARN_ON(ret);
446 fte->status = 0;
447 fs_get_obj(ft, fg->node.parent);
448 ida_simple_remove(&ft->fte_allocator, fte->index);
449}
450
451static void del_fte(struct fs_node *node)
452{
453 struct mlx5_flow_table *ft;
454 struct mlx5_flow_group *fg;
455 struct mlx5_core_dev *dev;
456 struct fs_fte *fte;
457 int err;
458
459 fs_get_obj(fte, node);
460 fs_get_obj(fg, fte->node.parent);
461 fs_get_obj(ft, fg->node.parent);
462 trace_mlx5_fs_del_fte(fte);
463
464 dev = get_dev(&ft->node);
465 err = mlx5_cmd_delete_fte(dev, ft,
466 fte->index);
467 if (err)
468 mlx5_core_warn(dev,
469 "flow steering can't delete fte in index %d of flow group id %d\n",
470 fte->index, fg->id);
471
472 destroy_fte(fte, fg);
473}
474
475static void del_flow_group(struct fs_node *node)
476{
477 struct mlx5_flow_group *fg;
478 struct mlx5_flow_table *ft;
479 struct mlx5_core_dev *dev;
480 int err;
481
482 fs_get_obj(fg, node);
483 fs_get_obj(ft, fg->node.parent);
484 dev = get_dev(&ft->node);
485 trace_mlx5_fs_del_fg(fg);
486
487 if (ft->autogroup.active)
488 ft->autogroup.num_groups--;
489
490 rhashtable_destroy(&fg->ftes_hash);
491 err = rhltable_remove(&ft->fgs_hash,
492 &fg->hash,
493 rhash_fg);
494 WARN_ON(err);
495 if (mlx5_cmd_destroy_flow_group(dev, ft, fg->id))
496 mlx5_core_warn(dev, "flow steering can't destroy fg %d of ft %d\n",
497 fg->id, ft->id);
498}
499
500static struct fs_fte *alloc_fte(struct mlx5_flow_act *flow_act,
501 u32 *match_value,
502 unsigned int index)
503{
504 struct fs_fte *fte;
505
506 fte = kzalloc(sizeof(*fte), GFP_KERNEL);
507 if (!fte)
508 return ERR_PTR(-ENOMEM);
509
510 memcpy(fte->val, match_value, sizeof(fte->val));
511 fte->node.type = FS_TYPE_FLOW_ENTRY;
512 fte->flow_tag = flow_act->flow_tag;
513 fte->index = index;
514 fte->action = flow_act->action;
515 fte->encap_id = flow_act->encap_id;
516 fte->modify_id = flow_act->modify_id;
517
518 return fte;
519}
520
521static struct mlx5_flow_group *alloc_flow_group(u32 *create_fg_in)
522{
523 struct mlx5_flow_group *fg;
524 void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
525 create_fg_in, match_criteria);
526 u8 match_criteria_enable = MLX5_GET(create_flow_group_in,
527 create_fg_in,
528 match_criteria_enable);
529 int ret;
530
531 fg = kzalloc(sizeof(*fg), GFP_KERNEL);
532 if (!fg)
533 return ERR_PTR(-ENOMEM);
534
535 ret = rhashtable_init(&fg->ftes_hash, &rhash_fte);
536 if (ret) {
537 kfree(fg);
538 return ERR_PTR(ret);
539 }
540 fg->mask.match_criteria_enable = match_criteria_enable;
541 memcpy(&fg->mask.match_criteria, match_criteria,
542 sizeof(fg->mask.match_criteria));
543 fg->node.type = FS_TYPE_FLOW_GROUP;
544 fg->start_index = MLX5_GET(create_flow_group_in, create_fg_in,
545 start_flow_index);
546 fg->max_ftes = MLX5_GET(create_flow_group_in, create_fg_in,
547 end_flow_index) - fg->start_index + 1;
548 return fg;
549}
550
551static struct mlx5_flow_table *alloc_flow_table(int level, u16 vport, int max_fte,
552 enum fs_flow_table_type table_type,
553 enum fs_flow_table_op_mod op_mod,
554 u32 flags)
555{
556 struct mlx5_flow_table *ft;
557 int ret;
558
559 ft = kzalloc(sizeof(*ft), GFP_KERNEL);
560 if (!ft)
561 return ERR_PTR(-ENOMEM);
562
563 ret = rhltable_init(&ft->fgs_hash, &rhash_fg);
564 if (ret) {
565 kfree(ft);
566 return ERR_PTR(ret);
567 }
568
569 ft->level = level;
570 ft->node.type = FS_TYPE_FLOW_TABLE;
571 ft->op_mod = op_mod;
572 ft->type = table_type;
573 ft->vport = vport;
574 ft->max_fte = max_fte;
575 ft->flags = flags;
576 INIT_LIST_HEAD(&ft->fwd_rules);
577 mutex_init(&ft->lock);
578 ida_init(&ft->fte_allocator);
579
580 return ft;
581}
582
583
584
585
586
587static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node *root,
588 struct list_head *start,
589 bool reverse)
590{
591#define list_advance_entry(pos, reverse) \
592 ((reverse) ? list_prev_entry(pos, list) : list_next_entry(pos, list))
593
594#define list_for_each_advance_continue(pos, head, reverse) \
595 for (pos = list_advance_entry(pos, reverse); \
596 &pos->list != (head); \
597 pos = list_advance_entry(pos, reverse))
598
599 struct fs_node *iter = list_entry(start, struct fs_node, list);
600 struct mlx5_flow_table *ft = NULL;
601
602 if (!root)
603 return NULL;
604
605 list_for_each_advance_continue(iter, &root->children, reverse) {
606 if (iter->type == FS_TYPE_FLOW_TABLE) {
607 fs_get_obj(ft, iter);
608 return ft;
609 }
610 ft = find_closest_ft_recursive(iter, &iter->children, reverse);
611 if (ft)
612 return ft;
613 }
614
615 return ft;
616}
617
618
619
620
621
622static struct mlx5_flow_table *find_closest_ft(struct fs_prio *prio, bool reverse)
623{
624 struct mlx5_flow_table *ft = NULL;
625 struct fs_node *curr_node;
626 struct fs_node *parent;
627
628 parent = prio->node.parent;
629 curr_node = &prio->node;
630 while (!ft && parent) {
631 ft = find_closest_ft_recursive(parent, &curr_node->list, reverse);
632 curr_node = parent;
633 parent = curr_node->parent;
634 }
635 return ft;
636}
637
638
639static struct mlx5_flow_table *find_next_chained_ft(struct fs_prio *prio)
640{
641 return find_closest_ft(prio, false);
642}
643
644
645static struct mlx5_flow_table *find_prev_chained_ft(struct fs_prio *prio)
646{
647 return find_closest_ft(prio, true);
648}
649
650static int connect_fts_in_prio(struct mlx5_core_dev *dev,
651 struct fs_prio *prio,
652 struct mlx5_flow_table *ft)
653{
654 struct mlx5_flow_table *iter;
655 int i = 0;
656 int err;
657
658 fs_for_each_ft(iter, prio) {
659 i++;
660 err = mlx5_cmd_modify_flow_table(dev,
661 iter,
662 ft);
663 if (err) {
664 mlx5_core_warn(dev, "Failed to modify flow table %d\n",
665 iter->id);
666
667 if (i > 1)
668 WARN_ON(true);
669 return err;
670 }
671 }
672 return 0;
673}
674
675
676static int connect_prev_fts(struct mlx5_core_dev *dev,
677 struct mlx5_flow_table *ft,
678 struct fs_prio *prio)
679{
680 struct mlx5_flow_table *prev_ft;
681
682 prev_ft = find_prev_chained_ft(prio);
683 if (prev_ft) {
684 struct fs_prio *prev_prio;
685
686 fs_get_obj(prev_prio, prev_ft->node.parent);
687 return connect_fts_in_prio(dev, prev_prio, ft);
688 }
689 return 0;
690}
691
692static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio
693 *prio)
694{
695 struct mlx5_flow_root_namespace *root = find_root(&prio->node);
696 int min_level = INT_MAX;
697 int err;
698
699 if (root->root_ft)
700 min_level = root->root_ft->level;
701
702 if (ft->level >= min_level)
703 return 0;
704
705 err = mlx5_cmd_update_root_ft(root->dev, ft, root->underlay_qpn);
706 if (err)
707 mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
708 ft->id);
709 else
710 root->root_ft = ft;
711
712 return err;
713}
714
715static int _mlx5_modify_rule_destination(struct mlx5_flow_rule *rule,
716 struct mlx5_flow_destination *dest)
717{
718 struct mlx5_flow_table *ft;
719 struct mlx5_flow_group *fg;
720 struct fs_fte *fte;
721 int modify_mask = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
722 int err = 0;
723
724 fs_get_obj(fte, rule->node.parent);
725 if (!(fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
726 return -EINVAL;
727 lock_ref_node(&fte->node);
728 fs_get_obj(fg, fte->node.parent);
729 fs_get_obj(ft, fg->node.parent);
730
731 memcpy(&rule->dest_attr, dest, sizeof(*dest));
732 err = mlx5_cmd_update_fte(get_dev(&ft->node),
733 ft, fg->id,
734 modify_mask,
735 fte);
736 unlock_ref_node(&fte->node);
737
738 return err;
739}
740
741int mlx5_modify_rule_destination(struct mlx5_flow_handle *handle,
742 struct mlx5_flow_destination *new_dest,
743 struct mlx5_flow_destination *old_dest)
744{
745 int i;
746
747 if (!old_dest) {
748 if (handle->num_rules != 1)
749 return -EINVAL;
750 return _mlx5_modify_rule_destination(handle->rule[0],
751 new_dest);
752 }
753
754 for (i = 0; i < handle->num_rules; i++) {
755 if (mlx5_flow_dests_cmp(new_dest, &handle->rule[i]->dest_attr))
756 return _mlx5_modify_rule_destination(handle->rule[i],
757 new_dest);
758 }
759
760 return -EINVAL;
761}
762
763
764static int connect_fwd_rules(struct mlx5_core_dev *dev,
765 struct mlx5_flow_table *new_next_ft,
766 struct mlx5_flow_table *old_next_ft)
767{
768 struct mlx5_flow_destination dest;
769 struct mlx5_flow_rule *iter;
770 int err = 0;
771
772
773
774
775 if (!new_next_ft || !old_next_ft)
776 return 0;
777
778 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
779 dest.ft = new_next_ft;
780
781 mutex_lock(&old_next_ft->lock);
782 list_splice_init(&old_next_ft->fwd_rules, &new_next_ft->fwd_rules);
783 mutex_unlock(&old_next_ft->lock);
784 list_for_each_entry(iter, &new_next_ft->fwd_rules, next_ft) {
785 err = _mlx5_modify_rule_destination(iter, &dest);
786 if (err)
787 pr_err("mlx5_core: failed to modify rule to point on flow table %d\n",
788 new_next_ft->id);
789 }
790 return 0;
791}
792
793static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft,
794 struct fs_prio *prio)
795{
796 struct mlx5_flow_table *next_ft;
797 int err = 0;
798
799
800
801 if (list_empty(&prio->node.children)) {
802 err = connect_prev_fts(dev, ft, prio);
803 if (err)
804 return err;
805
806 next_ft = find_next_chained_ft(prio);
807 err = connect_fwd_rules(dev, ft, next_ft);
808 if (err)
809 return err;
810 }
811
812 if (MLX5_CAP_FLOWTABLE(dev,
813 flow_table_properties_nic_receive.modify_root))
814 err = update_root_ft_create(ft, prio);
815 return err;
816}
817
818static void list_add_flow_table(struct mlx5_flow_table *ft,
819 struct fs_prio *prio)
820{
821 struct list_head *prev = &prio->node.children;
822 struct mlx5_flow_table *iter;
823
824 fs_for_each_ft(iter, prio) {
825 if (iter->level > ft->level)
826 break;
827 prev = &iter->node.list;
828 }
829 list_add(&ft->node.list, prev);
830}
831
832static struct mlx5_flow_table *__mlx5_create_flow_table(struct mlx5_flow_namespace *ns,
833 struct mlx5_flow_table_attr *ft_attr,
834 enum fs_flow_table_op_mod op_mod,
835 u16 vport)
836{
837 struct mlx5_flow_root_namespace *root = find_root(&ns->node);
838 struct mlx5_flow_table *next_ft = NULL;
839 struct fs_prio *fs_prio = NULL;
840 struct mlx5_flow_table *ft;
841 int log_table_sz;
842 int err;
843
844 if (!root) {
845 pr_err("mlx5: flow steering failed to find root of namespace\n");
846 return ERR_PTR(-ENODEV);
847 }
848
849 mutex_lock(&root->chain_lock);
850 fs_prio = find_prio(ns, ft_attr->prio);
851 if (!fs_prio) {
852 err = -EINVAL;
853 goto unlock_root;
854 }
855 if (ft_attr->level >= fs_prio->num_levels) {
856 err = -ENOSPC;
857 goto unlock_root;
858 }
859
860
861
862 ft_attr->level += fs_prio->start_level;
863 ft = alloc_flow_table(ft_attr->level,
864 vport,
865 ft_attr->max_fte ? roundup_pow_of_two(ft_attr->max_fte) : 0,
866 root->table_type,
867 op_mod, ft_attr->flags);
868 if (IS_ERR(ft)) {
869 err = PTR_ERR(ft);
870 goto unlock_root;
871 }
872
873 tree_init_node(&ft->node, 1, del_flow_table);
874 log_table_sz = ft->max_fte ? ilog2(ft->max_fte) : 0;
875 next_ft = find_next_chained_ft(fs_prio);
876 err = mlx5_cmd_create_flow_table(root->dev, ft->vport, ft->op_mod, ft->type,
877 ft->level, log_table_sz, next_ft, &ft->id,
878 ft->flags);
879 if (err)
880 goto free_ft;
881
882 err = connect_flow_table(root->dev, ft, fs_prio);
883 if (err)
884 goto destroy_ft;
885 lock_ref_node(&fs_prio->node);
886 tree_add_node(&ft->node, &fs_prio->node);
887 list_add_flow_table(ft, fs_prio);
888 fs_prio->num_ft++;
889 unlock_ref_node(&fs_prio->node);
890 mutex_unlock(&root->chain_lock);
891 return ft;
892destroy_ft:
893 mlx5_cmd_destroy_flow_table(root->dev, ft);
894free_ft:
895 ida_destroy(&ft->fte_allocator);
896 kfree(ft);
897unlock_root:
898 mutex_unlock(&root->chain_lock);
899 return ERR_PTR(err);
900}
901
902struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,
903 struct mlx5_flow_table_attr *ft_attr)
904{
905 return __mlx5_create_flow_table(ns, ft_attr, FS_FT_OP_MOD_NORMAL, 0);
906}
907
908struct mlx5_flow_table *mlx5_create_vport_flow_table(struct mlx5_flow_namespace *ns,
909 int prio, int max_fte,
910 u32 level, u16 vport)
911{
912 struct mlx5_flow_table_attr ft_attr = {};
913
914 ft_attr.max_fte = max_fte;
915 ft_attr.level = level;
916 ft_attr.prio = prio;
917
918 return __mlx5_create_flow_table(ns, &ft_attr, FS_FT_OP_MOD_NORMAL, vport);
919}
920
921struct mlx5_flow_table*
922mlx5_create_lag_demux_flow_table(struct mlx5_flow_namespace *ns,
923 int prio, u32 level)
924{
925 struct mlx5_flow_table_attr ft_attr = {};
926
927 ft_attr.level = level;
928 ft_attr.prio = prio;
929 return __mlx5_create_flow_table(ns, &ft_attr, FS_FT_OP_MOD_LAG_DEMUX, 0);
930}
931EXPORT_SYMBOL(mlx5_create_lag_demux_flow_table);
932
933struct mlx5_flow_table*
934mlx5_create_auto_grouped_flow_table(struct mlx5_flow_namespace *ns,
935 int prio,
936 int num_flow_table_entries,
937 int max_num_groups,
938 u32 level,
939 u32 flags)
940{
941 struct mlx5_flow_table_attr ft_attr = {};
942 struct mlx5_flow_table *ft;
943
944 if (max_num_groups > num_flow_table_entries)
945 return ERR_PTR(-EINVAL);
946
947 ft_attr.max_fte = num_flow_table_entries;
948 ft_attr.prio = prio;
949 ft_attr.level = level;
950 ft_attr.flags = flags;
951
952 ft = mlx5_create_flow_table(ns, &ft_attr);
953 if (IS_ERR(ft))
954 return ft;
955
956 ft->autogroup.active = true;
957 ft->autogroup.required_groups = max_num_groups;
958
959 return ft;
960}
961EXPORT_SYMBOL(mlx5_create_auto_grouped_flow_table);
962
963
964static struct mlx5_flow_group *create_flow_group_common(struct mlx5_flow_table *ft,
965 u32 *fg_in,
966 struct list_head
967 *prev_fg,
968 bool is_auto_fg)
969{
970 struct mlx5_flow_group *fg;
971 struct mlx5_core_dev *dev = get_dev(&ft->node);
972 int err;
973
974 if (!dev)
975 return ERR_PTR(-ENODEV);
976
977 fg = alloc_flow_group(fg_in);
978 if (IS_ERR(fg))
979 return fg;
980
981 err = rhltable_insert(&ft->fgs_hash, &fg->hash, rhash_fg);
982 if (err)
983 goto err_free_fg;
984
985 err = mlx5_cmd_create_flow_group(dev, ft, fg_in, &fg->id);
986 if (err)
987 goto err_remove_fg;
988
989 if (ft->autogroup.active)
990 ft->autogroup.num_groups++;
991
992 tree_init_node(&fg->node, !is_auto_fg, del_flow_group);
993 tree_add_node(&fg->node, &ft->node);
994
995 list_add(&fg->node.list, prev_fg);
996
997 trace_mlx5_fs_add_fg(fg);
998 return fg;
999
1000err_remove_fg:
1001 WARN_ON(rhltable_remove(&ft->fgs_hash,
1002 &fg->hash,
1003 rhash_fg));
1004err_free_fg:
1005 rhashtable_destroy(&fg->ftes_hash);
1006 kfree(fg);
1007
1008 return ERR_PTR(err);
1009}
1010
1011struct mlx5_flow_group *mlx5_create_flow_group(struct mlx5_flow_table *ft,
1012 u32 *fg_in)
1013{
1014 void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1015 fg_in, match_criteria);
1016 u8 match_criteria_enable = MLX5_GET(create_flow_group_in,
1017 fg_in,
1018 match_criteria_enable);
1019 struct mlx5_flow_group *fg;
1020
1021 if (!check_valid_mask(match_criteria_enable, match_criteria))
1022 return ERR_PTR(-EINVAL);
1023
1024 if (ft->autogroup.active)
1025 return ERR_PTR(-EPERM);
1026
1027 lock_ref_node(&ft->node);
1028 fg = create_flow_group_common(ft, fg_in, ft->node.children.prev, false);
1029 unlock_ref_node(&ft->node);
1030
1031 return fg;
1032}
1033
1034static struct mlx5_flow_rule *alloc_rule(struct mlx5_flow_destination *dest)
1035{
1036 struct mlx5_flow_rule *rule;
1037
1038 rule = kzalloc(sizeof(*rule), GFP_KERNEL);
1039 if (!rule)
1040 return NULL;
1041
1042 INIT_LIST_HEAD(&rule->next_ft);
1043 rule->node.type = FS_TYPE_FLOW_DEST;
1044 if (dest)
1045 memcpy(&rule->dest_attr, dest, sizeof(*dest));
1046
1047 return rule;
1048}
1049
1050static struct mlx5_flow_handle *alloc_handle(int num_rules)
1051{
1052 struct mlx5_flow_handle *handle;
1053
1054 handle = kzalloc(sizeof(*handle) + sizeof(handle->rule[0]) *
1055 num_rules, GFP_KERNEL);
1056 if (!handle)
1057 return NULL;
1058
1059 handle->num_rules = num_rules;
1060
1061 return handle;
1062}
1063
1064static void destroy_flow_handle(struct fs_fte *fte,
1065 struct mlx5_flow_handle *handle,
1066 struct mlx5_flow_destination *dest,
1067 int i)
1068{
1069 for (; --i >= 0;) {
1070 if (atomic_dec_and_test(&handle->rule[i]->node.refcount)) {
1071 fte->dests_size--;
1072 list_del(&handle->rule[i]->node.list);
1073 kfree(handle->rule[i]);
1074 }
1075 }
1076 kfree(handle);
1077}
1078
1079static struct mlx5_flow_handle *
1080create_flow_handle(struct fs_fte *fte,
1081 struct mlx5_flow_destination *dest,
1082 int dest_num,
1083 int *modify_mask,
1084 bool *new_rule)
1085{
1086 struct mlx5_flow_handle *handle;
1087 struct mlx5_flow_rule *rule = NULL;
1088 static int count = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_FLOW_COUNTERS);
1089 static int dst = BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST);
1090 int type;
1091 int i = 0;
1092
1093 handle = alloc_handle((dest_num) ? dest_num : 1);
1094 if (!handle)
1095 return ERR_PTR(-ENOMEM);
1096
1097 do {
1098 if (dest) {
1099 rule = find_flow_rule(fte, dest + i);
1100 if (rule) {
1101 atomic_inc(&rule->node.refcount);
1102 goto rule_found;
1103 }
1104 }
1105
1106 *new_rule = true;
1107 rule = alloc_rule(dest + i);
1108 if (!rule)
1109 goto free_rules;
1110
1111
1112
1113
1114 tree_init_node(&rule->node, 1, del_rule);
1115 if (dest &&
1116 dest[i].type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
1117 list_add(&rule->node.list, &fte->node.children);
1118 else
1119 list_add_tail(&rule->node.list, &fte->node.children);
1120 if (dest) {
1121 fte->dests_size++;
1122
1123 type = dest[i].type ==
1124 MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1125 *modify_mask |= type ? count : dst;
1126 }
1127rule_found:
1128 handle->rule[i] = rule;
1129 } while (++i < dest_num);
1130
1131 return handle;
1132
1133free_rules:
1134 destroy_flow_handle(fte, handle, dest, i);
1135 return ERR_PTR(-ENOMEM);
1136}
1137
1138
1139static struct mlx5_flow_handle *
1140add_rule_fte(struct fs_fte *fte,
1141 struct mlx5_flow_group *fg,
1142 struct mlx5_flow_destination *dest,
1143 int dest_num,
1144 bool update_action)
1145{
1146 struct mlx5_flow_handle *handle;
1147 struct mlx5_flow_table *ft;
1148 int modify_mask = 0;
1149 int err;
1150 bool new_rule = false;
1151
1152 handle = create_flow_handle(fte, dest, dest_num, &modify_mask,
1153 &new_rule);
1154 if (IS_ERR(handle) || !new_rule)
1155 goto out;
1156
1157 if (update_action)
1158 modify_mask |= BIT(MLX5_SET_FTE_MODIFY_ENABLE_MASK_ACTION);
1159
1160 fs_get_obj(ft, fg->node.parent);
1161 if (!(fte->status & FS_FTE_STATUS_EXISTING))
1162 err = mlx5_cmd_create_fte(get_dev(&ft->node),
1163 ft, fg->id, fte);
1164 else
1165 err = mlx5_cmd_update_fte(get_dev(&ft->node),
1166 ft, fg->id, modify_mask, fte);
1167 if (err)
1168 goto free_handle;
1169
1170 fte->status |= FS_FTE_STATUS_EXISTING;
1171
1172out:
1173 return handle;
1174
1175free_handle:
1176 destroy_flow_handle(fte, handle, dest, handle->num_rules);
1177 return ERR_PTR(err);
1178}
1179
1180static struct fs_fte *create_fte(struct mlx5_flow_group *fg,
1181 u32 *match_value,
1182 struct mlx5_flow_act *flow_act)
1183{
1184 struct mlx5_flow_table *ft;
1185 struct fs_fte *fte;
1186 int index;
1187 int ret;
1188
1189 fs_get_obj(ft, fg->node.parent);
1190 index = ida_simple_get(&ft->fte_allocator, fg->start_index,
1191 fg->start_index + fg->max_ftes,
1192 GFP_KERNEL);
1193 if (index < 0)
1194 return ERR_PTR(index);
1195
1196 fte = alloc_fte(flow_act, match_value, index);
1197 if (IS_ERR(fte)) {
1198 ret = PTR_ERR(fte);
1199 goto err_alloc;
1200 }
1201 ret = rhashtable_insert_fast(&fg->ftes_hash, &fte->hash, rhash_fte);
1202 if (ret)
1203 goto err_hash;
1204
1205 return fte;
1206
1207err_hash:
1208 kfree(fte);
1209err_alloc:
1210 ida_simple_remove(&ft->fte_allocator, index);
1211 return ERR_PTR(ret);
1212}
1213
1214static struct mlx5_flow_group *create_autogroup(struct mlx5_flow_table *ft,
1215 u8 match_criteria_enable,
1216 u32 *match_criteria)
1217{
1218 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1219 struct list_head *prev = &ft->node.children;
1220 unsigned int candidate_index = 0;
1221 struct mlx5_flow_group *fg;
1222 void *match_criteria_addr;
1223 unsigned int group_size = 0;
1224 u32 *in;
1225
1226 if (!ft->autogroup.active)
1227 return ERR_PTR(-ENOENT);
1228
1229 in = kvzalloc(inlen, GFP_KERNEL);
1230 if (!in)
1231 return ERR_PTR(-ENOMEM);
1232
1233 if (ft->autogroup.num_groups < ft->autogroup.required_groups)
1234
1235 group_size = ft->max_fte / (ft->autogroup.required_groups + 1);
1236
1237
1238 if (group_size == 0)
1239 group_size = 1;
1240
1241
1242 fs_for_each_fg(fg, ft) {
1243 if (candidate_index + group_size > fg->start_index)
1244 candidate_index = fg->start_index + fg->max_ftes;
1245 else
1246 break;
1247 prev = &fg->node.list;
1248 }
1249
1250 if (candidate_index + group_size > ft->max_fte) {
1251 fg = ERR_PTR(-ENOSPC);
1252 goto out;
1253 }
1254
1255 MLX5_SET(create_flow_group_in, in, match_criteria_enable,
1256 match_criteria_enable);
1257 MLX5_SET(create_flow_group_in, in, start_flow_index, candidate_index);
1258 MLX5_SET(create_flow_group_in, in, end_flow_index, candidate_index +
1259 group_size - 1);
1260 match_criteria_addr = MLX5_ADDR_OF(create_flow_group_in,
1261 in, match_criteria);
1262 memcpy(match_criteria_addr, match_criteria,
1263 MLX5_ST_SZ_BYTES(fte_match_param));
1264
1265 fg = create_flow_group_common(ft, in, prev, true);
1266out:
1267 kvfree(in);
1268 return fg;
1269}
1270
1271static bool mlx5_flow_dests_cmp(struct mlx5_flow_destination *d1,
1272 struct mlx5_flow_destination *d2)
1273{
1274 if (d1->type == d2->type) {
1275 if ((d1->type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
1276 d1->vport_num == d2->vport_num) ||
1277 (d1->type == MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE &&
1278 d1->ft == d2->ft) ||
1279 (d1->type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
1280 d1->tir_num == d2->tir_num))
1281 return true;
1282 }
1283
1284 return false;
1285}
1286
1287static struct mlx5_flow_rule *find_flow_rule(struct fs_fte *fte,
1288 struct mlx5_flow_destination *dest)
1289{
1290 struct mlx5_flow_rule *rule;
1291
1292 list_for_each_entry(rule, &fte->node.children, node.list) {
1293 if (mlx5_flow_dests_cmp(&rule->dest_attr, dest))
1294 return rule;
1295 }
1296 return NULL;
1297}
1298
1299static bool check_conflicting_actions(u32 action1, u32 action2)
1300{
1301 u32 xored_actions = action1 ^ action2;
1302
1303
1304 if (action1 == MLX5_FLOW_CONTEXT_ACTION_COUNT ||
1305 action2 == MLX5_FLOW_CONTEXT_ACTION_COUNT)
1306 return false;
1307
1308 if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP |
1309 MLX5_FLOW_CONTEXT_ACTION_ENCAP |
1310 MLX5_FLOW_CONTEXT_ACTION_DECAP))
1311 return true;
1312
1313 return false;
1314}
1315
1316static int check_conflicting_ftes(struct fs_fte *fte, const struct mlx5_flow_act *flow_act)
1317{
1318 if (check_conflicting_actions(flow_act->action, fte->action)) {
1319 mlx5_core_warn(get_dev(&fte->node),
1320 "Found two FTEs with conflicting actions\n");
1321 return -EEXIST;
1322 }
1323
1324 if (fte->flow_tag != flow_act->flow_tag) {
1325 mlx5_core_warn(get_dev(&fte->node),
1326 "FTE flow tag %u already exists with different flow tag %u\n",
1327 fte->flow_tag,
1328 flow_act->flow_tag);
1329 return -EEXIST;
1330 }
1331
1332 return 0;
1333}
1334
1335static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
1336 u32 *match_value,
1337 struct mlx5_flow_act *flow_act,
1338 struct mlx5_flow_destination *dest,
1339 int dest_num,
1340 struct fs_fte *fte)
1341{
1342 struct mlx5_flow_handle *handle;
1343 struct mlx5_flow_table *ft;
1344 int i;
1345
1346 if (fte) {
1347 int old_action;
1348 int ret;
1349
1350 nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD);
1351 ret = check_conflicting_ftes(fte, flow_act);
1352 if (ret) {
1353 handle = ERR_PTR(ret);
1354 goto unlock_fte;
1355 }
1356
1357 old_action = fte->action;
1358 fte->action |= flow_act->action;
1359 handle = add_rule_fte(fte, fg, dest, dest_num,
1360 old_action != flow_act->action);
1361 if (IS_ERR(handle)) {
1362 fte->action = old_action;
1363 goto unlock_fte;
1364 } else {
1365 trace_mlx5_fs_set_fte(fte, false);
1366 goto add_rules;
1367 }
1368 }
1369 fs_get_obj(ft, fg->node.parent);
1370
1371 fte = create_fte(fg, match_value, flow_act);
1372 if (IS_ERR(fte))
1373 return (void *)fte;
1374 tree_init_node(&fte->node, 0, del_fte);
1375 nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD);
1376 handle = add_rule_fte(fte, fg, dest, dest_num, false);
1377 if (IS_ERR(handle)) {
1378 unlock_ref_node(&fte->node);
1379 destroy_fte(fte, fg);
1380 kfree(fte);
1381 return handle;
1382 }
1383
1384 tree_add_node(&fte->node, &fg->node);
1385
1386 list_add_tail(&fte->node.list, &fg->node.children);
1387 trace_mlx5_fs_set_fte(fte, true);
1388add_rules:
1389 for (i = 0; i < handle->num_rules; i++) {
1390 if (atomic_read(&handle->rule[i]->node.refcount) == 1) {
1391 tree_add_node(&handle->rule[i]->node, &fte->node);
1392 trace_mlx5_fs_add_rule(handle->rule[i]);
1393 }
1394 }
1395unlock_fte:
1396 unlock_ref_node(&fte->node);
1397 return handle;
1398}
1399
1400struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handle)
1401{
1402 struct mlx5_flow_rule *dst;
1403 struct fs_fte *fte;
1404
1405 fs_get_obj(fte, handle->rule[0]->node.parent);
1406
1407 fs_for_each_dst(dst, fte) {
1408 if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
1409 return dst->dest_attr.counter;
1410 }
1411
1412 return NULL;
1413}
1414
1415static bool counter_is_valid(struct mlx5_fc *counter, u32 action)
1416{
1417 if (!(action & MLX5_FLOW_CONTEXT_ACTION_COUNT))
1418 return !counter;
1419
1420 if (!counter)
1421 return false;
1422
1423 return (action & (MLX5_FLOW_CONTEXT_ACTION_DROP |
1424 MLX5_FLOW_CONTEXT_ACTION_FWD_DEST));
1425}
1426
1427static bool dest_is_valid(struct mlx5_flow_destination *dest,
1428 u32 action,
1429 struct mlx5_flow_table *ft)
1430{
1431 if (dest && (dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER))
1432 return counter_is_valid(dest->counter, action);
1433
1434 if (!(action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
1435 return true;
1436
1437 if (!dest || ((dest->type ==
1438 MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) &&
1439 (dest->ft->level <= ft->level)))
1440 return false;
1441 return true;
1442}
1443
1444static struct mlx5_flow_handle *
1445try_add_to_existing_fg(struct mlx5_flow_table *ft,
1446 struct mlx5_flow_spec *spec,
1447 struct mlx5_flow_act *flow_act,
1448 struct mlx5_flow_destination *dest,
1449 int dest_num)
1450{
1451 struct mlx5_flow_group *g;
1452 struct mlx5_flow_handle *rule = ERR_PTR(-ENOENT);
1453 struct rhlist_head *tmp, *list;
1454 struct match_list {
1455 struct list_head list;
1456 struct mlx5_flow_group *g;
1457 } match_list, *iter;
1458 LIST_HEAD(match_head);
1459
1460 rcu_read_lock();
1461
1462 list = rhltable_lookup(&ft->fgs_hash, spec, rhash_fg);
1463 rhl_for_each_entry_rcu(g, tmp, list, hash) {
1464 struct match_list *curr_match;
1465
1466 if (likely(list_empty(&match_head))) {
1467 match_list.g = g;
1468 list_add_tail(&match_list.list, &match_head);
1469 continue;
1470 }
1471 curr_match = kmalloc(sizeof(*curr_match), GFP_ATOMIC);
1472
1473 if (!curr_match) {
1474 rcu_read_unlock();
1475 rule = ERR_PTR(-ENOMEM);
1476 goto free_list;
1477 }
1478 curr_match->g = g;
1479 list_add_tail(&curr_match->list, &match_head);
1480 }
1481 rcu_read_unlock();
1482
1483
1484 list_for_each_entry(iter, &match_head, list) {
1485 struct fs_fte *fte;
1486
1487 g = iter->g;
1488 nested_lock_ref_node(&g->node, FS_MUTEX_PARENT);
1489 fte = rhashtable_lookup_fast(&g->ftes_hash, spec->match_value,
1490 rhash_fte);
1491 if (fte) {
1492 rule = add_rule_fg(g, spec->match_value,
1493 flow_act, dest, dest_num, fte);
1494 unlock_ref_node(&g->node);
1495 goto free_list;
1496 }
1497 unlock_ref_node(&g->node);
1498 }
1499
1500
1501
1502
1503 list_for_each_entry(iter, &match_head, list) {
1504 g = iter->g;
1505
1506 nested_lock_ref_node(&g->node, FS_MUTEX_PARENT);
1507 rule = add_rule_fg(g, spec->match_value,
1508 flow_act, dest, dest_num, NULL);
1509 if (!IS_ERR(rule) || PTR_ERR(rule) != -ENOSPC) {
1510 unlock_ref_node(&g->node);
1511 goto free_list;
1512 }
1513 unlock_ref_node(&g->node);
1514 }
1515
1516free_list:
1517 if (!list_empty(&match_head)) {
1518 struct match_list *match_tmp;
1519
1520
1521
1522
1523
1524 list_del(&list_first_entry(&match_head, typeof(*iter), list)->list);
1525 list_for_each_entry_safe(iter, match_tmp, &match_head, list) {
1526 list_del(&iter->list);
1527 kfree(iter);
1528 }
1529 }
1530
1531 return rule;
1532}
1533
1534static struct mlx5_flow_handle *
1535_mlx5_add_flow_rules(struct mlx5_flow_table *ft,
1536 struct mlx5_flow_spec *spec,
1537 struct mlx5_flow_act *flow_act,
1538 struct mlx5_flow_destination *dest,
1539 int dest_num)
1540
1541{
1542 struct mlx5_flow_group *g;
1543 struct mlx5_flow_handle *rule;
1544 int i;
1545
1546 if (!check_valid_spec(spec))
1547 return ERR_PTR(-EINVAL);
1548
1549 for (i = 0; i < dest_num; i++) {
1550 if (!dest_is_valid(&dest[i], flow_act->action, ft))
1551 return ERR_PTR(-EINVAL);
1552 }
1553
1554 nested_lock_ref_node(&ft->node, FS_MUTEX_GRANDPARENT);
1555 rule = try_add_to_existing_fg(ft, spec, flow_act, dest, dest_num);
1556 if (!IS_ERR(rule))
1557 goto unlock;
1558
1559 g = create_autogroup(ft, spec->match_criteria_enable,
1560 spec->match_criteria);
1561 if (IS_ERR(g)) {
1562 rule = (void *)g;
1563 goto unlock;
1564 }
1565
1566 rule = add_rule_fg(g, spec->match_value, flow_act, dest,
1567 dest_num, NULL);
1568 if (IS_ERR(rule)) {
1569
1570
1571
1572 unlock_ref_node(&ft->node);
1573 tree_get_node(&g->node);
1574 tree_remove_node(&g->node);
1575 return rule;
1576 }
1577unlock:
1578 unlock_ref_node(&ft->node);
1579 return rule;
1580}
1581
1582static bool fwd_next_prio_supported(struct mlx5_flow_table *ft)
1583{
1584 return ((ft->type == FS_FT_NIC_RX) &&
1585 (MLX5_CAP_FLOWTABLE(get_dev(&ft->node), nic_rx_multi_path_tirs)));
1586}
1587
1588struct mlx5_flow_handle *
1589mlx5_add_flow_rules(struct mlx5_flow_table *ft,
1590 struct mlx5_flow_spec *spec,
1591 struct mlx5_flow_act *flow_act,
1592 struct mlx5_flow_destination *dest,
1593 int dest_num)
1594{
1595 struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1596 struct mlx5_flow_destination gen_dest;
1597 struct mlx5_flow_table *next_ft = NULL;
1598 struct mlx5_flow_handle *handle = NULL;
1599 u32 sw_action = flow_act->action;
1600 struct fs_prio *prio;
1601
1602 fs_get_obj(prio, ft->node.parent);
1603 if (flow_act->action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
1604 if (!fwd_next_prio_supported(ft))
1605 return ERR_PTR(-EOPNOTSUPP);
1606 if (dest)
1607 return ERR_PTR(-EINVAL);
1608 mutex_lock(&root->chain_lock);
1609 next_ft = find_next_chained_ft(prio);
1610 if (next_ft) {
1611 gen_dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1612 gen_dest.ft = next_ft;
1613 dest = &gen_dest;
1614 dest_num = 1;
1615 flow_act->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1616 } else {
1617 mutex_unlock(&root->chain_lock);
1618 return ERR_PTR(-EOPNOTSUPP);
1619 }
1620 }
1621
1622 handle = _mlx5_add_flow_rules(ft, spec, flow_act, dest, dest_num);
1623
1624 if (sw_action == MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO) {
1625 if (!IS_ERR_OR_NULL(handle) &&
1626 (list_empty(&handle->rule[0]->next_ft))) {
1627 mutex_lock(&next_ft->lock);
1628 list_add(&handle->rule[0]->next_ft,
1629 &next_ft->fwd_rules);
1630 mutex_unlock(&next_ft->lock);
1631 handle->rule[0]->sw_action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
1632 }
1633 mutex_unlock(&root->chain_lock);
1634 }
1635 return handle;
1636}
1637EXPORT_SYMBOL(mlx5_add_flow_rules);
1638
1639void mlx5_del_flow_rules(struct mlx5_flow_handle *handle)
1640{
1641 int i;
1642
1643 for (i = handle->num_rules - 1; i >= 0; i--)
1644 tree_remove_node(&handle->rule[i]->node);
1645 kfree(handle);
1646}
1647EXPORT_SYMBOL(mlx5_del_flow_rules);
1648
1649
1650static struct mlx5_flow_table *find_next_ft(struct mlx5_flow_table *ft)
1651{
1652 struct fs_prio *prio;
1653
1654 fs_get_obj(prio, ft->node.parent);
1655
1656 if (!list_is_last(&ft->node.list, &prio->node.children))
1657 return list_next_entry(ft, node.list);
1658 return find_next_chained_ft(prio);
1659}
1660
1661static int update_root_ft_destroy(struct mlx5_flow_table *ft)
1662{
1663 struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1664 struct mlx5_flow_table *new_root_ft = NULL;
1665
1666 if (root->root_ft != ft)
1667 return 0;
1668
1669 new_root_ft = find_next_ft(ft);
1670 if (new_root_ft) {
1671 int err = mlx5_cmd_update_root_ft(root->dev, new_root_ft,
1672 root->underlay_qpn);
1673
1674 if (err) {
1675 mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n",
1676 ft->id);
1677 return err;
1678 }
1679 }
1680 root->root_ft = new_root_ft;
1681 return 0;
1682}
1683
1684
1685
1686
1687static int disconnect_flow_table(struct mlx5_flow_table *ft)
1688{
1689 struct mlx5_core_dev *dev = get_dev(&ft->node);
1690 struct mlx5_flow_table *next_ft;
1691 struct fs_prio *prio;
1692 int err = 0;
1693
1694 err = update_root_ft_destroy(ft);
1695 if (err)
1696 return err;
1697
1698 fs_get_obj(prio, ft->node.parent);
1699 if (!(list_first_entry(&prio->node.children,
1700 struct mlx5_flow_table,
1701 node.list) == ft))
1702 return 0;
1703
1704 next_ft = find_next_chained_ft(prio);
1705 err = connect_fwd_rules(dev, next_ft, ft);
1706 if (err)
1707 return err;
1708
1709 err = connect_prev_fts(dev, next_ft, prio);
1710 if (err)
1711 mlx5_core_warn(dev, "Failed to disconnect flow table %d\n",
1712 ft->id);
1713 return err;
1714}
1715
1716int mlx5_destroy_flow_table(struct mlx5_flow_table *ft)
1717{
1718 struct mlx5_flow_root_namespace *root = find_root(&ft->node);
1719 int err = 0;
1720
1721 mutex_lock(&root->chain_lock);
1722 err = disconnect_flow_table(ft);
1723 if (err) {
1724 mutex_unlock(&root->chain_lock);
1725 return err;
1726 }
1727 if (tree_remove_node(&ft->node))
1728 mlx5_core_warn(get_dev(&ft->node), "Flow table %d wasn't destroyed, refcount > 1\n",
1729 ft->id);
1730 mutex_unlock(&root->chain_lock);
1731
1732 return err;
1733}
1734EXPORT_SYMBOL(mlx5_destroy_flow_table);
1735
1736void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
1737{
1738 if (tree_remove_node(&fg->node))
1739 mlx5_core_warn(get_dev(&fg->node), "Flow group %d wasn't destroyed, refcount > 1\n",
1740 fg->id);
1741}
1742
1743struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
1744 enum mlx5_flow_namespace_type type)
1745{
1746 struct mlx5_flow_steering *steering = dev->priv.steering;
1747 struct mlx5_flow_root_namespace *root_ns;
1748 int prio;
1749 struct fs_prio *fs_prio;
1750 struct mlx5_flow_namespace *ns;
1751
1752 if (!steering)
1753 return NULL;
1754
1755 switch (type) {
1756 case MLX5_FLOW_NAMESPACE_BYPASS:
1757 case MLX5_FLOW_NAMESPACE_LAG:
1758 case MLX5_FLOW_NAMESPACE_OFFLOADS:
1759 case MLX5_FLOW_NAMESPACE_ETHTOOL:
1760 case MLX5_FLOW_NAMESPACE_KERNEL:
1761 case MLX5_FLOW_NAMESPACE_LEFTOVERS:
1762 case MLX5_FLOW_NAMESPACE_ANCHOR:
1763 prio = type;
1764 break;
1765 case MLX5_FLOW_NAMESPACE_FDB:
1766 if (steering->fdb_root_ns)
1767 return &steering->fdb_root_ns->ns;
1768 else
1769 return NULL;
1770 case MLX5_FLOW_NAMESPACE_ESW_EGRESS:
1771 if (steering->esw_egress_root_ns)
1772 return &steering->esw_egress_root_ns->ns;
1773 else
1774 return NULL;
1775 case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
1776 if (steering->esw_ingress_root_ns)
1777 return &steering->esw_ingress_root_ns->ns;
1778 else
1779 return NULL;
1780 case MLX5_FLOW_NAMESPACE_SNIFFER_RX:
1781 if (steering->sniffer_rx_root_ns)
1782 return &steering->sniffer_rx_root_ns->ns;
1783 else
1784 return NULL;
1785 case MLX5_FLOW_NAMESPACE_SNIFFER_TX:
1786 if (steering->sniffer_tx_root_ns)
1787 return &steering->sniffer_tx_root_ns->ns;
1788 else
1789 return NULL;
1790 default:
1791 return NULL;
1792 }
1793
1794 root_ns = steering->root_ns;
1795 if (!root_ns)
1796 return NULL;
1797
1798 fs_prio = find_prio(&root_ns->ns, prio);
1799 if (!fs_prio)
1800 return NULL;
1801
1802 ns = list_first_entry(&fs_prio->node.children,
1803 typeof(*ns),
1804 node.list);
1805
1806 return ns;
1807}
1808EXPORT_SYMBOL(mlx5_get_flow_namespace);
1809
1810static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
1811 unsigned int prio, int num_levels)
1812{
1813 struct fs_prio *fs_prio;
1814
1815 fs_prio = kzalloc(sizeof(*fs_prio), GFP_KERNEL);
1816 if (!fs_prio)
1817 return ERR_PTR(-ENOMEM);
1818
1819 fs_prio->node.type = FS_TYPE_PRIO;
1820 tree_init_node(&fs_prio->node, 1, NULL);
1821 tree_add_node(&fs_prio->node, &ns->node);
1822 fs_prio->num_levels = num_levels;
1823 fs_prio->prio = prio;
1824 list_add_tail(&fs_prio->node.list, &ns->node.children);
1825
1826 return fs_prio;
1827}
1828
1829static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
1830 *ns)
1831{
1832 ns->node.type = FS_TYPE_NAMESPACE;
1833
1834 return ns;
1835}
1836
1837static struct mlx5_flow_namespace *fs_create_namespace(struct fs_prio *prio)
1838{
1839 struct mlx5_flow_namespace *ns;
1840
1841 ns = kzalloc(sizeof(*ns), GFP_KERNEL);
1842 if (!ns)
1843 return ERR_PTR(-ENOMEM);
1844
1845 fs_init_namespace(ns);
1846 tree_init_node(&ns->node, 1, NULL);
1847 tree_add_node(&ns->node, &prio->node);
1848 list_add_tail(&ns->node.list, &prio->node.children);
1849
1850 return ns;
1851}
1852
1853static int create_leaf_prios(struct mlx5_flow_namespace *ns, int prio,
1854 struct init_tree_node *prio_metadata)
1855{
1856 struct fs_prio *fs_prio;
1857 int i;
1858
1859 for (i = 0; i < prio_metadata->num_leaf_prios; i++) {
1860 fs_prio = fs_create_prio(ns, prio++, prio_metadata->num_levels);
1861 if (IS_ERR(fs_prio))
1862 return PTR_ERR(fs_prio);
1863 }
1864 return 0;
1865}
1866
1867#define FLOW_TABLE_BIT_SZ 1
1868#define GET_FLOW_TABLE_CAP(dev, offset) \
1869 ((be32_to_cpu(*((__be32 *)(dev->caps.hca_cur[MLX5_CAP_FLOW_TABLE]) + \
1870 offset / 32)) >> \
1871 (32 - FLOW_TABLE_BIT_SZ - (offset & 0x1f))) & FLOW_TABLE_BIT_SZ)
1872static bool has_required_caps(struct mlx5_core_dev *dev, struct node_caps *caps)
1873{
1874 int i;
1875
1876 for (i = 0; i < caps->arr_sz; i++) {
1877 if (!GET_FLOW_TABLE_CAP(dev, caps->caps[i]))
1878 return false;
1879 }
1880 return true;
1881}
1882
1883static int init_root_tree_recursive(struct mlx5_flow_steering *steering,
1884 struct init_tree_node *init_node,
1885 struct fs_node *fs_parent_node,
1886 struct init_tree_node *init_parent_node,
1887 int prio)
1888{
1889 int max_ft_level = MLX5_CAP_FLOWTABLE(steering->dev,
1890 flow_table_properties_nic_receive.
1891 max_ft_level);
1892 struct mlx5_flow_namespace *fs_ns;
1893 struct fs_prio *fs_prio;
1894 struct fs_node *base;
1895 int i;
1896 int err;
1897
1898 if (init_node->type == FS_TYPE_PRIO) {
1899 if ((init_node->min_ft_level > max_ft_level) ||
1900 !has_required_caps(steering->dev, &init_node->caps))
1901 return 0;
1902
1903 fs_get_obj(fs_ns, fs_parent_node);
1904 if (init_node->num_leaf_prios)
1905 return create_leaf_prios(fs_ns, prio, init_node);
1906 fs_prio = fs_create_prio(fs_ns, prio, init_node->num_levels);
1907 if (IS_ERR(fs_prio))
1908 return PTR_ERR(fs_prio);
1909 base = &fs_prio->node;
1910 } else if (init_node->type == FS_TYPE_NAMESPACE) {
1911 fs_get_obj(fs_prio, fs_parent_node);
1912 fs_ns = fs_create_namespace(fs_prio);
1913 if (IS_ERR(fs_ns))
1914 return PTR_ERR(fs_ns);
1915 base = &fs_ns->node;
1916 } else {
1917 return -EINVAL;
1918 }
1919 prio = 0;
1920 for (i = 0; i < init_node->ar_size; i++) {
1921 err = init_root_tree_recursive(steering, &init_node->children[i],
1922 base, init_node, prio);
1923 if (err)
1924 return err;
1925 if (init_node->children[i].type == FS_TYPE_PRIO &&
1926 init_node->children[i].num_leaf_prios) {
1927 prio += init_node->children[i].num_leaf_prios;
1928 }
1929 }
1930
1931 return 0;
1932}
1933
1934static int init_root_tree(struct mlx5_flow_steering *steering,
1935 struct init_tree_node *init_node,
1936 struct fs_node *fs_parent_node)
1937{
1938 int i;
1939 struct mlx5_flow_namespace *fs_ns;
1940 int err;
1941
1942 fs_get_obj(fs_ns, fs_parent_node);
1943 for (i = 0; i < init_node->ar_size; i++) {
1944 err = init_root_tree_recursive(steering, &init_node->children[i],
1945 &fs_ns->node,
1946 init_node, i);
1947 if (err)
1948 return err;
1949 }
1950 return 0;
1951}
1952
1953static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_flow_steering *steering,
1954 enum fs_flow_table_type
1955 table_type)
1956{
1957 struct mlx5_flow_root_namespace *root_ns;
1958 struct mlx5_flow_namespace *ns;
1959
1960
1961 root_ns = kvzalloc(sizeof(*root_ns), GFP_KERNEL);
1962 if (!root_ns)
1963 return NULL;
1964
1965 root_ns->dev = steering->dev;
1966 root_ns->table_type = table_type;
1967
1968 ns = &root_ns->ns;
1969 fs_init_namespace(ns);
1970 mutex_init(&root_ns->chain_lock);
1971 tree_init_node(&ns->node, 1, NULL);
1972 tree_add_node(&ns->node, NULL);
1973
1974 return root_ns;
1975}
1976
1977static void set_prio_attrs_in_prio(struct fs_prio *prio, int acc_level);
1978
1979static int set_prio_attrs_in_ns(struct mlx5_flow_namespace *ns, int acc_level)
1980{
1981 struct fs_prio *prio;
1982
1983 fs_for_each_prio(prio, ns) {
1984
1985 set_prio_attrs_in_prio(prio, acc_level);
1986 acc_level += prio->num_levels;
1987 }
1988 return acc_level;
1989}
1990
1991static void set_prio_attrs_in_prio(struct fs_prio *prio, int acc_level)
1992{
1993 struct mlx5_flow_namespace *ns;
1994 int acc_level_ns = acc_level;
1995
1996 prio->start_level = acc_level;
1997 fs_for_each_ns(ns, prio)
1998
1999 acc_level_ns = set_prio_attrs_in_ns(ns, acc_level);
2000 if (!prio->num_levels)
2001 prio->num_levels = acc_level_ns - prio->start_level;
2002 WARN_ON(prio->num_levels < acc_level_ns - prio->start_level);
2003}
2004
2005static void set_prio_attrs(struct mlx5_flow_root_namespace *root_ns)
2006{
2007 struct mlx5_flow_namespace *ns = &root_ns->ns;
2008 struct fs_prio *prio;
2009 int start_level = 0;
2010
2011 fs_for_each_prio(prio, ns) {
2012 set_prio_attrs_in_prio(prio, start_level);
2013 start_level += prio->num_levels;
2014 }
2015}
2016
2017#define ANCHOR_PRIO 0
2018#define ANCHOR_SIZE 1
2019#define ANCHOR_LEVEL 0
2020static int create_anchor_flow_table(struct mlx5_flow_steering *steering)
2021{
2022 struct mlx5_flow_namespace *ns = NULL;
2023 struct mlx5_flow_table_attr ft_attr = {};
2024 struct mlx5_flow_table *ft;
2025
2026 ns = mlx5_get_flow_namespace(steering->dev, MLX5_FLOW_NAMESPACE_ANCHOR);
2027 if (WARN_ON(!ns))
2028 return -EINVAL;
2029
2030 ft_attr.max_fte = ANCHOR_SIZE;
2031 ft_attr.level = ANCHOR_LEVEL;
2032 ft_attr.prio = ANCHOR_PRIO;
2033
2034 ft = mlx5_create_flow_table(ns, &ft_attr);
2035 if (IS_ERR(ft)) {
2036 mlx5_core_err(steering->dev, "Failed to create last anchor flow table");
2037 return PTR_ERR(ft);
2038 }
2039 return 0;
2040}
2041
2042static int init_root_ns(struct mlx5_flow_steering *steering)
2043{
2044 steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX);
2045 if (!steering->root_ns)
2046 goto cleanup;
2047
2048 if (init_root_tree(steering, &root_fs, &steering->root_ns->ns.node))
2049 goto cleanup;
2050
2051 set_prio_attrs(steering->root_ns);
2052
2053 if (create_anchor_flow_table(steering))
2054 goto cleanup;
2055
2056 return 0;
2057
2058cleanup:
2059 mlx5_cleanup_fs(steering->dev);
2060 return -ENOMEM;
2061}
2062
2063static void clean_tree(struct fs_node *node)
2064{
2065 if (node) {
2066 struct fs_node *iter;
2067 struct fs_node *temp;
2068
2069 list_for_each_entry_safe(iter, temp, &node->children, list)
2070 clean_tree(iter);
2071 tree_remove_node(node);
2072 }
2073}
2074
2075static void cleanup_root_ns(struct mlx5_flow_root_namespace *root_ns)
2076{
2077 if (!root_ns)
2078 return;
2079
2080 clean_tree(&root_ns->ns.node);
2081}
2082
2083void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
2084{
2085 struct mlx5_flow_steering *steering = dev->priv.steering;
2086
2087 cleanup_root_ns(steering->root_ns);
2088 cleanup_root_ns(steering->esw_egress_root_ns);
2089 cleanup_root_ns(steering->esw_ingress_root_ns);
2090 cleanup_root_ns(steering->fdb_root_ns);
2091 cleanup_root_ns(steering->sniffer_rx_root_ns);
2092 cleanup_root_ns(steering->sniffer_tx_root_ns);
2093 mlx5_cleanup_fc_stats(dev);
2094 kfree(steering);
2095}
2096
2097static int init_sniffer_tx_root_ns(struct mlx5_flow_steering *steering)
2098{
2099 struct fs_prio *prio;
2100
2101 steering->sniffer_tx_root_ns = create_root_ns(steering, FS_FT_SNIFFER_TX);
2102 if (!steering->sniffer_tx_root_ns)
2103 return -ENOMEM;
2104
2105
2106 prio = fs_create_prio(&steering->sniffer_tx_root_ns->ns, 0, 1);
2107 if (IS_ERR(prio)) {
2108 cleanup_root_ns(steering->sniffer_tx_root_ns);
2109 return PTR_ERR(prio);
2110 }
2111 return 0;
2112}
2113
2114static int init_sniffer_rx_root_ns(struct mlx5_flow_steering *steering)
2115{
2116 struct fs_prio *prio;
2117
2118 steering->sniffer_rx_root_ns = create_root_ns(steering, FS_FT_SNIFFER_RX);
2119 if (!steering->sniffer_rx_root_ns)
2120 return -ENOMEM;
2121
2122
2123 prio = fs_create_prio(&steering->sniffer_rx_root_ns->ns, 0, 1);
2124 if (IS_ERR(prio)) {
2125 cleanup_root_ns(steering->sniffer_rx_root_ns);
2126 return PTR_ERR(prio);
2127 }
2128 return 0;
2129}
2130
2131static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
2132{
2133 struct fs_prio *prio;
2134
2135 steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB);
2136 if (!steering->fdb_root_ns)
2137 return -ENOMEM;
2138
2139 prio = fs_create_prio(&steering->fdb_root_ns->ns, 0, 1);
2140 if (IS_ERR(prio))
2141 goto out_err;
2142
2143 prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
2144 if (IS_ERR(prio))
2145 goto out_err;
2146
2147 set_prio_attrs(steering->fdb_root_ns);
2148 return 0;
2149
2150out_err:
2151 cleanup_root_ns(steering->fdb_root_ns);
2152 steering->fdb_root_ns = NULL;
2153 return PTR_ERR(prio);
2154}
2155
2156static int init_ingress_acl_root_ns(struct mlx5_flow_steering *steering)
2157{
2158 struct fs_prio *prio;
2159
2160 steering->esw_egress_root_ns = create_root_ns(steering, FS_FT_ESW_EGRESS_ACL);
2161 if (!steering->esw_egress_root_ns)
2162 return -ENOMEM;
2163
2164
2165 prio = fs_create_prio(&steering->esw_egress_root_ns->ns, 0,
2166 MLX5_TOTAL_VPORTS(steering->dev));
2167 return PTR_ERR_OR_ZERO(prio);
2168}
2169
2170static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering)
2171{
2172 struct fs_prio *prio;
2173
2174 steering->esw_ingress_root_ns = create_root_ns(steering, FS_FT_ESW_INGRESS_ACL);
2175 if (!steering->esw_ingress_root_ns)
2176 return -ENOMEM;
2177
2178
2179 prio = fs_create_prio(&steering->esw_ingress_root_ns->ns, 0,
2180 MLX5_TOTAL_VPORTS(steering->dev));
2181 return PTR_ERR_OR_ZERO(prio);
2182}
2183
2184int mlx5_init_fs(struct mlx5_core_dev *dev)
2185{
2186 struct mlx5_flow_steering *steering;
2187 int err = 0;
2188
2189 err = mlx5_init_fc_stats(dev);
2190 if (err)
2191 return err;
2192
2193 steering = kzalloc(sizeof(*steering), GFP_KERNEL);
2194 if (!steering)
2195 return -ENOMEM;
2196 steering->dev = dev;
2197 dev->priv.steering = steering;
2198
2199 if ((((MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_ETH) &&
2200 (MLX5_CAP_GEN(dev, nic_flow_table))) ||
2201 ((MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_IB) &&
2202 MLX5_CAP_GEN(dev, ipoib_enhanced_offloads))) &&
2203 MLX5_CAP_FLOWTABLE_NIC_RX(dev, ft_support)) {
2204 err = init_root_ns(steering);
2205 if (err)
2206 goto err;
2207 }
2208
2209 if (MLX5_CAP_GEN(dev, eswitch_flow_table)) {
2210 if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ft_support)) {
2211 err = init_fdb_root_ns(steering);
2212 if (err)
2213 goto err;
2214 }
2215 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) {
2216 err = init_egress_acl_root_ns(steering);
2217 if (err)
2218 goto err;
2219 }
2220 if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) {
2221 err = init_ingress_acl_root_ns(steering);
2222 if (err)
2223 goto err;
2224 }
2225 }
2226
2227 if (MLX5_CAP_FLOWTABLE_SNIFFER_RX(dev, ft_support)) {
2228 err = init_sniffer_rx_root_ns(steering);
2229 if (err)
2230 goto err;
2231 }
2232
2233 if (MLX5_CAP_FLOWTABLE_SNIFFER_TX(dev, ft_support)) {
2234 err = init_sniffer_tx_root_ns(steering);
2235 if (err)
2236 goto err;
2237 }
2238
2239 return 0;
2240err:
2241 mlx5_cleanup_fs(dev);
2242 return err;
2243}
2244
2245int mlx5_fs_add_rx_underlay_qpn(struct mlx5_core_dev *dev, u32 underlay_qpn)
2246{
2247 struct mlx5_flow_root_namespace *root = dev->priv.steering->root_ns;
2248
2249 root->underlay_qpn = underlay_qpn;
2250 return 0;
2251}
2252EXPORT_SYMBOL(mlx5_fs_add_rx_underlay_qpn);
2253
2254int mlx5_fs_remove_rx_underlay_qpn(struct mlx5_core_dev *dev, u32 underlay_qpn)
2255{
2256 struct mlx5_flow_root_namespace *root = dev->priv.steering->root_ns;
2257
2258 root->underlay_qpn = 0;
2259 return 0;
2260}
2261EXPORT_SYMBOL(mlx5_fs_remove_rx_underlay_qpn);
2262