xref: /openbmc/linux/drivers/net/ethernet/marvell/prestera/prestera_acl.c (revision adefefe5289ceb27bb14cf1cb1cc4e16834c7185)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020-2021 Marvell International Ltd. All rights reserved */
3 
4 #include <linux/rhashtable.h>
5 
6 #include "prestera_acl.h"
7 #include "prestera_flow.h"
8 #include "prestera_hw.h"
9 #include "prestera.h"
10 
11 #define ACL_KEYMASK_SIZE	\
12 	(sizeof(__be32) * __PRESTERA_ACL_RULE_MATCH_TYPE_MAX)
13 
14 struct prestera_acl {
15 	struct prestera_switch *sw;
16 	struct list_head vtcam_list;
17 	struct list_head rules;
18 	struct rhashtable ruleset_ht;
19 	struct rhashtable acl_rule_entry_ht;
20 	struct idr uid;
21 };
22 
23 struct prestera_acl_ruleset_ht_key {
24 	struct prestera_flow_block *block;
25 };
26 
27 struct prestera_acl_rule_entry {
28 	struct rhash_head ht_node;
29 	struct prestera_acl_rule_entry_key key;
30 	u32 hw_id;
31 	u32 vtcam_id;
32 	struct {
33 		struct {
34 			u8 valid:1;
35 		} accept, drop, trap;
36 		struct {
37 			u32 id;
38 			struct prestera_counter_block *block;
39 		} counter;
40 	};
41 };
42 
43 struct prestera_acl_ruleset {
44 	struct rhash_head ht_node; /* Member of acl HT */
45 	struct prestera_acl_ruleset_ht_key ht_key;
46 	struct rhashtable rule_ht;
47 	struct prestera_acl *acl;
48 	unsigned long rule_count;
49 	refcount_t refcount;
50 	void *keymask;
51 	u32 vtcam_id;
52 	u16 pcl_id;
53 	bool offload;
54 };
55 
56 struct prestera_acl_vtcam {
57 	struct list_head list;
58 	__be32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];
59 	refcount_t refcount;
60 	u32 id;
61 	bool is_keymask_set;
62 	u8 lookup;
63 };
64 
65 static const struct rhashtable_params prestera_acl_ruleset_ht_params = {
66 	.key_len = sizeof(struct prestera_acl_ruleset_ht_key),
67 	.key_offset = offsetof(struct prestera_acl_ruleset, ht_key),
68 	.head_offset = offsetof(struct prestera_acl_ruleset, ht_node),
69 	.automatic_shrinking = true,
70 };
71 
72 static const struct rhashtable_params prestera_acl_rule_ht_params = {
73 	.key_len = sizeof(unsigned long),
74 	.key_offset = offsetof(struct prestera_acl_rule, cookie),
75 	.head_offset = offsetof(struct prestera_acl_rule, ht_node),
76 	.automatic_shrinking = true,
77 };
78 
79 static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = {
80 	.key_offset  = offsetof(struct prestera_acl_rule_entry, key),
81 	.head_offset = offsetof(struct prestera_acl_rule_entry, ht_node),
82 	.key_len     = sizeof(struct prestera_acl_rule_entry_key),
83 	.automatic_shrinking = true,
84 };
85 
86 static struct prestera_acl_ruleset *
87 prestera_acl_ruleset_create(struct prestera_acl *acl,
88 			    struct prestera_flow_block *block)
89 {
90 	struct prestera_acl_ruleset *ruleset;
91 	int err;
92 	u32 uid;
93 
94 	ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL);
95 	if (!ruleset)
96 		return ERR_PTR(-ENOMEM);
97 
98 	ruleset->acl = acl;
99 	ruleset->ht_key.block = block;
100 	refcount_set(&ruleset->refcount, 1);
101 
102 	err = rhashtable_init(&ruleset->rule_ht, &prestera_acl_rule_ht_params);
103 	if (err)
104 		goto err_rhashtable_init;
105 
106 	err = idr_alloc_u32(&acl->uid, NULL, &uid, U8_MAX, GFP_KERNEL);
107 	if (err)
108 		goto err_ruleset_create;
109 
110 	/* make pcl-id based on uid */
111 	ruleset->pcl_id = (u8)uid;
112 	err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node,
113 				     prestera_acl_ruleset_ht_params);
114 	if (err)
115 		goto err_ruleset_ht_insert;
116 
117 	return ruleset;
118 
119 err_ruleset_ht_insert:
120 	idr_remove(&acl->uid, uid);
121 err_ruleset_create:
122 	rhashtable_destroy(&ruleset->rule_ht);
123 err_rhashtable_init:
124 	kfree(ruleset);
125 	return ERR_PTR(err);
126 }
127 
128 int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset)
129 {
130 	u32 vtcam_id;
131 	int err;
132 
133 	if (ruleset->offload)
134 		return -EEXIST;
135 
136 	err = prestera_acl_vtcam_id_get(ruleset->acl, 0,
137 					ruleset->keymask, &vtcam_id);
138 	if (err)
139 		return err;
140 
141 	ruleset->vtcam_id = vtcam_id;
142 	ruleset->offload = true;
143 	return 0;
144 }
145 
146 static void prestera_acl_ruleset_destroy(struct prestera_acl_ruleset *ruleset)
147 {
148 	struct prestera_acl *acl = ruleset->acl;
149 	u8 uid = ruleset->pcl_id & PRESTERA_ACL_KEYMASK_PCL_ID_USER;
150 
151 	rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node,
152 			       prestera_acl_ruleset_ht_params);
153 
154 	if (ruleset->offload)
155 		WARN_ON(prestera_acl_vtcam_id_put(acl, ruleset->vtcam_id));
156 
157 	idr_remove(&acl->uid, uid);
158 
159 	rhashtable_destroy(&ruleset->rule_ht);
160 	kfree(ruleset->keymask);
161 	kfree(ruleset);
162 }
163 
164 static struct prestera_acl_ruleset *
165 __prestera_acl_ruleset_lookup(struct prestera_acl *acl,
166 			      struct prestera_flow_block *block)
167 {
168 	struct prestera_acl_ruleset_ht_key ht_key;
169 
170 	memset(&ht_key, 0, sizeof(ht_key));
171 	ht_key.block = block;
172 	return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
173 				      prestera_acl_ruleset_ht_params);
174 }
175 
176 struct prestera_acl_ruleset *
177 prestera_acl_ruleset_lookup(struct prestera_acl *acl,
178 			    struct prestera_flow_block *block)
179 {
180 	struct prestera_acl_ruleset *ruleset;
181 
182 	ruleset = __prestera_acl_ruleset_lookup(acl, block);
183 	if (!ruleset)
184 		return ERR_PTR(-ENOENT);
185 
186 	refcount_inc(&ruleset->refcount);
187 	return ruleset;
188 }
189 
190 struct prestera_acl_ruleset *
191 prestera_acl_ruleset_get(struct prestera_acl *acl,
192 			 struct prestera_flow_block *block)
193 {
194 	struct prestera_acl_ruleset *ruleset;
195 
196 	ruleset = __prestera_acl_ruleset_lookup(acl, block);
197 	if (ruleset) {
198 		refcount_inc(&ruleset->refcount);
199 		return ruleset;
200 	}
201 
202 	return prestera_acl_ruleset_create(acl, block);
203 }
204 
205 void prestera_acl_ruleset_put(struct prestera_acl_ruleset *ruleset)
206 {
207 	if (!refcount_dec_and_test(&ruleset->refcount))
208 		return;
209 
210 	prestera_acl_ruleset_destroy(ruleset);
211 }
212 
213 int prestera_acl_ruleset_bind(struct prestera_acl_ruleset *ruleset,
214 			      struct prestera_port *port)
215 {
216 	struct prestera_acl_iface iface = {
217 		.type = PRESTERA_ACL_IFACE_TYPE_PORT,
218 		.port = port
219 	};
220 
221 	return prestera_hw_vtcam_iface_bind(port->sw, &iface, ruleset->vtcam_id,
222 					    ruleset->pcl_id);
223 }
224 
225 int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset,
226 				struct prestera_port *port)
227 {
228 	struct prestera_acl_iface iface = {
229 		.type = PRESTERA_ACL_IFACE_TYPE_PORT,
230 		.port = port
231 	};
232 
233 	return prestera_hw_vtcam_iface_unbind(port->sw, &iface,
234 					      ruleset->vtcam_id);
235 }
236 
237 static int prestera_acl_ruleset_block_bind(struct prestera_acl_ruleset *ruleset,
238 					   struct prestera_flow_block *block)
239 {
240 	struct prestera_flow_block_binding *binding;
241 	int err;
242 
243 	block->ruleset_zero = ruleset;
244 	list_for_each_entry(binding, &block->binding_list, list) {
245 		err = prestera_acl_ruleset_bind(ruleset, binding->port);
246 		if (err)
247 			goto rollback;
248 	}
249 	return 0;
250 
251 rollback:
252 	list_for_each_entry_continue_reverse(binding, &block->binding_list,
253 					     list)
254 		err = prestera_acl_ruleset_unbind(ruleset, binding->port);
255 	block->ruleset_zero = NULL;
256 
257 	return err;
258 }
259 
260 static void
261 prestera_acl_ruleset_block_unbind(struct prestera_acl_ruleset *ruleset,
262 				  struct prestera_flow_block *block)
263 {
264 	struct prestera_flow_block_binding *binding;
265 
266 	list_for_each_entry(binding, &block->binding_list, list)
267 		prestera_acl_ruleset_unbind(ruleset, binding->port);
268 	block->ruleset_zero = NULL;
269 }
270 
271 void
272 prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, u16 pcl_id)
273 {
274 	struct prestera_acl_match *r_match = &rule->re_key.match;
275 	__be16 pcl_id_mask = htons(PRESTERA_ACL_KEYMASK_PCL_ID);
276 	__be16 pcl_id_key = htons(pcl_id);
277 
278 	rule_match_set(r_match->key, PCL_ID, pcl_id_key);
279 	rule_match_set(r_match->mask, PCL_ID, pcl_id_mask);
280 }
281 
282 struct prestera_acl_rule *
283 prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset,
284 			 unsigned long cookie)
285 {
286 	return rhashtable_lookup_fast(&ruleset->rule_ht, &cookie,
287 				      prestera_acl_rule_ht_params);
288 }
289 
290 bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset)
291 {
292 	return ruleset->offload;
293 }
294 
295 struct prestera_acl_rule *
296 prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset,
297 			 unsigned long cookie)
298 {
299 	struct prestera_acl_rule *rule;
300 
301 	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
302 	if (!rule)
303 		return ERR_PTR(-ENOMEM);
304 
305 	rule->ruleset = ruleset;
306 	rule->cookie = cookie;
307 
308 	refcount_inc(&ruleset->refcount);
309 
310 	return rule;
311 }
312 
313 void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule,
314 				    u32 priority)
315 {
316 	rule->priority = priority;
317 }
318 
319 void prestera_acl_rule_destroy(struct prestera_acl_rule *rule)
320 {
321 	prestera_acl_ruleset_put(rule->ruleset);
322 	kfree(rule);
323 }
324 
325 int prestera_acl_rule_add(struct prestera_switch *sw,
326 			  struct prestera_acl_rule *rule)
327 {
328 	int err;
329 	struct prestera_acl_ruleset *ruleset = rule->ruleset;
330 	struct prestera_flow_block *block = ruleset->ht_key.block;
331 
332 	/* try to add rule to hash table first */
333 	err = rhashtable_insert_fast(&ruleset->rule_ht, &rule->ht_node,
334 				     prestera_acl_rule_ht_params);
335 	if (err)
336 		goto err_ht_insert;
337 
338 	prestera_acl_rule_keymask_pcl_id_set(rule, ruleset->pcl_id);
339 	rule->re_arg.vtcam_id = ruleset->vtcam_id;
340 	rule->re_key.prio = rule->priority;
341 
342 	/* setup counter */
343 	rule->re_arg.count.valid = true;
344 	rule->re_arg.count.client = PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0;
345 
346 	rule->re = prestera_acl_rule_entry_find(sw->acl, &rule->re_key);
347 	err = WARN_ON(rule->re) ? -EEXIST : 0;
348 	if (err)
349 		goto err_rule_add;
350 
351 	rule->re = prestera_acl_rule_entry_create(sw->acl, &rule->re_key,
352 						  &rule->re_arg);
353 	err = !rule->re ? -EINVAL : 0;
354 	if (err)
355 		goto err_rule_add;
356 
357 	/* bind the block (all ports) to chain index 0 */
358 	if (!ruleset->rule_count) {
359 		err = prestera_acl_ruleset_block_bind(ruleset, block);
360 		if (err)
361 			goto err_acl_block_bind;
362 	}
363 
364 	list_add_tail(&rule->list, &sw->acl->rules);
365 	ruleset->rule_count++;
366 	return 0;
367 
368 err_acl_block_bind:
369 	prestera_acl_rule_entry_destroy(sw->acl, rule->re);
370 err_rule_add:
371 	rule->re = NULL;
372 	rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node,
373 			       prestera_acl_rule_ht_params);
374 err_ht_insert:
375 	return err;
376 }
377 
378 void prestera_acl_rule_del(struct prestera_switch *sw,
379 			   struct prestera_acl_rule *rule)
380 {
381 	struct prestera_acl_ruleset *ruleset = rule->ruleset;
382 	struct prestera_flow_block *block = ruleset->ht_key.block;
383 
384 	rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node,
385 			       prestera_acl_rule_ht_params);
386 	ruleset->rule_count--;
387 	list_del(&rule->list);
388 
389 	prestera_acl_rule_entry_destroy(sw->acl, rule->re);
390 
391 	/* unbind block (all ports) */
392 	if (!ruleset->rule_count)
393 		prestera_acl_ruleset_block_unbind(ruleset, block);
394 }
395 
396 int prestera_acl_rule_get_stats(struct prestera_acl *acl,
397 				struct prestera_acl_rule *rule,
398 				u64 *packets, u64 *bytes, u64 *last_use)
399 {
400 	u64 current_packets;
401 	u64 current_bytes;
402 	int err;
403 
404 	err = prestera_counter_stats_get(acl->sw->counter,
405 					 rule->re->counter.block,
406 					 rule->re->counter.id,
407 					 &current_packets, &current_bytes);
408 	if (err)
409 		return err;
410 
411 	*packets = current_packets;
412 	*bytes = current_bytes;
413 	*last_use = jiffies;
414 
415 	return 0;
416 }
417 
418 struct prestera_acl_rule_entry *
419 prestera_acl_rule_entry_find(struct prestera_acl *acl,
420 			     struct prestera_acl_rule_entry_key *key)
421 {
422 	struct prestera_acl_rule_entry *e;
423 
424 	e = rhashtable_lookup_fast(&acl->acl_rule_entry_ht, key,
425 				   __prestera_acl_rule_entry_ht_params);
426 	return IS_ERR(e) ? NULL : e;
427 }
428 
429 static int __prestera_acl_rule_entry2hw_del(struct prestera_switch *sw,
430 					    struct prestera_acl_rule_entry *e)
431 {
432 	return prestera_hw_vtcam_rule_del(sw, e->vtcam_id, e->hw_id);
433 }
434 
435 static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw,
436 					    struct prestera_acl_rule_entry *e)
437 {
438 	struct prestera_acl_hw_action_info act_hw[PRESTERA_ACL_RULE_ACTION_MAX];
439 	int act_num;
440 
441 	memset(&act_hw, 0, sizeof(act_hw));
442 	act_num = 0;
443 
444 	/* accept */
445 	if (e->accept.valid) {
446 		act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_ACCEPT;
447 		act_num++;
448 	}
449 	/* drop */
450 	if (e->drop.valid) {
451 		act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_DROP;
452 		act_num++;
453 	}
454 	/* trap */
455 	if (e->trap.valid) {
456 		act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_TRAP;
457 		act_num++;
458 	}
459 	/* counter */
460 	if (e->counter.block) {
461 		act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_COUNT;
462 		act_hw[act_num].count.id = e->counter.id;
463 		act_num++;
464 	}
465 
466 	return prestera_hw_vtcam_rule_add(sw, e->vtcam_id, e->key.prio,
467 					  e->key.match.key, e->key.match.mask,
468 					  act_hw, act_num, &e->hw_id);
469 }
470 
471 static void
472 __prestera_acl_rule_entry_act_destruct(struct prestera_switch *sw,
473 				       struct prestera_acl_rule_entry *e)
474 {
475 	/* counter */
476 	prestera_counter_put(sw->counter, e->counter.block, e->counter.id);
477 }
478 
479 void prestera_acl_rule_entry_destroy(struct prestera_acl *acl,
480 				     struct prestera_acl_rule_entry *e)
481 {
482 	int ret;
483 
484 	rhashtable_remove_fast(&acl->acl_rule_entry_ht, &e->ht_node,
485 			       __prestera_acl_rule_entry_ht_params);
486 
487 	ret = __prestera_acl_rule_entry2hw_del(acl->sw, e);
488 	WARN_ON(ret && ret != -ENODEV);
489 
490 	__prestera_acl_rule_entry_act_destruct(acl->sw, e);
491 	kfree(e);
492 }
493 
494 static int
495 __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw,
496 					struct prestera_acl_rule_entry *e,
497 					struct prestera_acl_rule_entry_arg *arg)
498 {
499 	/* accept */
500 	e->accept.valid = arg->accept.valid;
501 	/* drop */
502 	e->drop.valid = arg->drop.valid;
503 	/* trap */
504 	e->trap.valid = arg->trap.valid;
505 	/* counter */
506 	if (arg->count.valid) {
507 		int err;
508 
509 		err = prestera_counter_get(sw->counter, arg->count.client,
510 					   &e->counter.block,
511 					   &e->counter.id);
512 		if (err)
513 			goto err_out;
514 	}
515 
516 	return 0;
517 
518 err_out:
519 	__prestera_acl_rule_entry_act_destruct(sw, e);
520 	return -EINVAL;
521 }
522 
523 struct prestera_acl_rule_entry *
524 prestera_acl_rule_entry_create(struct prestera_acl *acl,
525 			       struct prestera_acl_rule_entry_key *key,
526 			       struct prestera_acl_rule_entry_arg *arg)
527 {
528 	struct prestera_acl_rule_entry *e;
529 	int err;
530 
531 	e = kzalloc(sizeof(*e), GFP_KERNEL);
532 	if (!e)
533 		goto err_kzalloc;
534 
535 	memcpy(&e->key, key, sizeof(*key));
536 	e->vtcam_id = arg->vtcam_id;
537 	err = __prestera_acl_rule_entry_act_construct(acl->sw, e, arg);
538 	if (err)
539 		goto err_act_construct;
540 
541 	err = __prestera_acl_rule_entry2hw_add(acl->sw, e);
542 	if (err)
543 		goto err_hw_add;
544 
545 	err = rhashtable_insert_fast(&acl->acl_rule_entry_ht, &e->ht_node,
546 				     __prestera_acl_rule_entry_ht_params);
547 	if (err)
548 		goto err_ht_insert;
549 
550 	return e;
551 
552 err_ht_insert:
553 	WARN_ON(__prestera_acl_rule_entry2hw_del(acl->sw, e));
554 err_hw_add:
555 	__prestera_acl_rule_entry_act_destruct(acl->sw, e);
556 err_act_construct:
557 	kfree(e);
558 err_kzalloc:
559 	return NULL;
560 }
561 
562 int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
563 			      void *keymask, u32 *vtcam_id)
564 {
565 	struct prestera_acl_vtcam *vtcam;
566 	u32 new_vtcam_id;
567 	int err;
568 
569 	/* find the vtcam that suits keymask. We do not expect to have
570 	 * a big number of vtcams, so, the list type for vtcam list is
571 	 * fine for now
572 	 */
573 	list_for_each_entry(vtcam, &acl->vtcam_list, list) {
574 		if (lookup != vtcam->lookup)
575 			continue;
576 
577 		if (!keymask && !vtcam->is_keymask_set) {
578 			refcount_inc(&vtcam->refcount);
579 			goto vtcam_found;
580 		}
581 
582 		if (keymask && vtcam->is_keymask_set &&
583 		    !memcmp(keymask, vtcam->keymask, sizeof(vtcam->keymask))) {
584 			refcount_inc(&vtcam->refcount);
585 			goto vtcam_found;
586 		}
587 	}
588 
589 	/* vtcam not found, try to create new one */
590 	vtcam = kzalloc(sizeof(*vtcam), GFP_KERNEL);
591 	if (!vtcam)
592 		return -ENOMEM;
593 
594 	err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id,
595 				       PRESTERA_HW_VTCAM_DIR_INGRESS);
596 	if (err) {
597 		kfree(vtcam);
598 		return err;
599 	}
600 
601 	vtcam->id = new_vtcam_id;
602 	vtcam->lookup = lookup;
603 	if (keymask) {
604 		memcpy(vtcam->keymask, keymask, sizeof(vtcam->keymask));
605 		vtcam->is_keymask_set = true;
606 	}
607 	refcount_set(&vtcam->refcount, 1);
608 	list_add_rcu(&vtcam->list, &acl->vtcam_list);
609 
610 vtcam_found:
611 	*vtcam_id = vtcam->id;
612 	return 0;
613 }
614 
615 int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id)
616 {
617 	struct prestera_acl_vtcam *vtcam;
618 	int err;
619 
620 	list_for_each_entry(vtcam, &acl->vtcam_list, list) {
621 		if (vtcam_id != vtcam->id)
622 			continue;
623 
624 		if (!refcount_dec_and_test(&vtcam->refcount))
625 			return 0;
626 
627 		err = prestera_hw_vtcam_destroy(acl->sw, vtcam->id);
628 		if (err && err != -ENODEV) {
629 			refcount_set(&vtcam->refcount, 1);
630 			return err;
631 		}
632 
633 		list_del(&vtcam->list);
634 		kfree(vtcam);
635 		return 0;
636 	}
637 
638 	return -ENOENT;
639 }
640 
641 int prestera_acl_init(struct prestera_switch *sw)
642 {
643 	struct prestera_acl *acl;
644 	int err;
645 
646 	acl = kzalloc(sizeof(*acl), GFP_KERNEL);
647 	if (!acl)
648 		return -ENOMEM;
649 
650 	acl->sw = sw;
651 	INIT_LIST_HEAD(&acl->rules);
652 	INIT_LIST_HEAD(&acl->vtcam_list);
653 	idr_init(&acl->uid);
654 
655 	err = rhashtable_init(&acl->acl_rule_entry_ht,
656 			      &__prestera_acl_rule_entry_ht_params);
657 	if (err)
658 		goto err_acl_rule_entry_ht_init;
659 
660 	err = rhashtable_init(&acl->ruleset_ht,
661 			      &prestera_acl_ruleset_ht_params);
662 	if (err)
663 		goto err_ruleset_ht_init;
664 
665 	sw->acl = acl;
666 
667 	return 0;
668 
669 err_ruleset_ht_init:
670 	rhashtable_destroy(&acl->acl_rule_entry_ht);
671 err_acl_rule_entry_ht_init:
672 	kfree(acl);
673 	return err;
674 }
675 
676 void prestera_acl_fini(struct prestera_switch *sw)
677 {
678 	struct prestera_acl *acl = sw->acl;
679 
680 	WARN_ON(!idr_is_empty(&acl->uid));
681 	idr_destroy(&acl->uid);
682 
683 	WARN_ON(!list_empty(&acl->vtcam_list));
684 	WARN_ON(!list_empty(&acl->rules));
685 
686 	rhashtable_destroy(&acl->ruleset_ht);
687 	rhashtable_destroy(&acl->acl_rule_entry_ht);
688 
689 	kfree(acl);
690 }
691