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