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 u32 uid = 0; 92 int err; 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 void prestera_acl_ruleset_keymask_set(struct prestera_acl_ruleset *ruleset, 129 void *keymask) 130 { 131 ruleset->keymask = kmemdup(keymask, ACL_KEYMASK_SIZE, GFP_KERNEL); 132 } 133 134 int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset) 135 { 136 u32 vtcam_id; 137 int err; 138 139 if (ruleset->offload) 140 return -EEXIST; 141 142 err = prestera_acl_vtcam_id_get(ruleset->acl, 0, 143 ruleset->keymask, &vtcam_id); 144 if (err) 145 return err; 146 147 ruleset->vtcam_id = vtcam_id; 148 ruleset->offload = true; 149 return 0; 150 } 151 152 static void prestera_acl_ruleset_destroy(struct prestera_acl_ruleset *ruleset) 153 { 154 struct prestera_acl *acl = ruleset->acl; 155 u8 uid = ruleset->pcl_id & PRESTERA_ACL_KEYMASK_PCL_ID_USER; 156 157 rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node, 158 prestera_acl_ruleset_ht_params); 159 160 if (ruleset->offload) 161 WARN_ON(prestera_acl_vtcam_id_put(acl, ruleset->vtcam_id)); 162 163 idr_remove(&acl->uid, uid); 164 165 rhashtable_destroy(&ruleset->rule_ht); 166 kfree(ruleset->keymask); 167 kfree(ruleset); 168 } 169 170 static struct prestera_acl_ruleset * 171 __prestera_acl_ruleset_lookup(struct prestera_acl *acl, 172 struct prestera_flow_block *block) 173 { 174 struct prestera_acl_ruleset_ht_key ht_key; 175 176 memset(&ht_key, 0, sizeof(ht_key)); 177 ht_key.block = block; 178 return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key, 179 prestera_acl_ruleset_ht_params); 180 } 181 182 struct prestera_acl_ruleset * 183 prestera_acl_ruleset_lookup(struct prestera_acl *acl, 184 struct prestera_flow_block *block) 185 { 186 struct prestera_acl_ruleset *ruleset; 187 188 ruleset = __prestera_acl_ruleset_lookup(acl, block); 189 if (!ruleset) 190 return ERR_PTR(-ENOENT); 191 192 refcount_inc(&ruleset->refcount); 193 return ruleset; 194 } 195 196 struct prestera_acl_ruleset * 197 prestera_acl_ruleset_get(struct prestera_acl *acl, 198 struct prestera_flow_block *block) 199 { 200 struct prestera_acl_ruleset *ruleset; 201 202 ruleset = __prestera_acl_ruleset_lookup(acl, block); 203 if (ruleset) { 204 refcount_inc(&ruleset->refcount); 205 return ruleset; 206 } 207 208 return prestera_acl_ruleset_create(acl, block); 209 } 210 211 void prestera_acl_ruleset_put(struct prestera_acl_ruleset *ruleset) 212 { 213 if (!refcount_dec_and_test(&ruleset->refcount)) 214 return; 215 216 prestera_acl_ruleset_destroy(ruleset); 217 } 218 219 int prestera_acl_ruleset_bind(struct prestera_acl_ruleset *ruleset, 220 struct prestera_port *port) 221 { 222 struct prestera_acl_iface iface = { 223 .type = PRESTERA_ACL_IFACE_TYPE_PORT, 224 .port = port 225 }; 226 227 return prestera_hw_vtcam_iface_bind(port->sw, &iface, ruleset->vtcam_id, 228 ruleset->pcl_id); 229 } 230 231 int prestera_acl_ruleset_unbind(struct prestera_acl_ruleset *ruleset, 232 struct prestera_port *port) 233 { 234 struct prestera_acl_iface iface = { 235 .type = PRESTERA_ACL_IFACE_TYPE_PORT, 236 .port = port 237 }; 238 239 return prestera_hw_vtcam_iface_unbind(port->sw, &iface, 240 ruleset->vtcam_id); 241 } 242 243 static int prestera_acl_ruleset_block_bind(struct prestera_acl_ruleset *ruleset, 244 struct prestera_flow_block *block) 245 { 246 struct prestera_flow_block_binding *binding; 247 int err; 248 249 block->ruleset_zero = ruleset; 250 list_for_each_entry(binding, &block->binding_list, list) { 251 err = prestera_acl_ruleset_bind(ruleset, binding->port); 252 if (err) 253 goto rollback; 254 } 255 return 0; 256 257 rollback: 258 list_for_each_entry_continue_reverse(binding, &block->binding_list, 259 list) 260 err = prestera_acl_ruleset_unbind(ruleset, binding->port); 261 block->ruleset_zero = NULL; 262 263 return err; 264 } 265 266 static void 267 prestera_acl_ruleset_block_unbind(struct prestera_acl_ruleset *ruleset, 268 struct prestera_flow_block *block) 269 { 270 struct prestera_flow_block_binding *binding; 271 272 list_for_each_entry(binding, &block->binding_list, list) 273 prestera_acl_ruleset_unbind(ruleset, binding->port); 274 block->ruleset_zero = NULL; 275 } 276 277 void 278 prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule, u16 pcl_id) 279 { 280 struct prestera_acl_match *r_match = &rule->re_key.match; 281 __be16 pcl_id_mask = htons(PRESTERA_ACL_KEYMASK_PCL_ID); 282 __be16 pcl_id_key = htons(pcl_id); 283 284 rule_match_set(r_match->key, PCL_ID, pcl_id_key); 285 rule_match_set(r_match->mask, PCL_ID, pcl_id_mask); 286 } 287 288 struct prestera_acl_rule * 289 prestera_acl_rule_lookup(struct prestera_acl_ruleset *ruleset, 290 unsigned long cookie) 291 { 292 return rhashtable_lookup_fast(&ruleset->rule_ht, &cookie, 293 prestera_acl_rule_ht_params); 294 } 295 296 bool prestera_acl_ruleset_is_offload(struct prestera_acl_ruleset *ruleset) 297 { 298 return ruleset->offload; 299 } 300 301 struct prestera_acl_rule * 302 prestera_acl_rule_create(struct prestera_acl_ruleset *ruleset, 303 unsigned long cookie) 304 { 305 struct prestera_acl_rule *rule; 306 307 rule = kzalloc(sizeof(*rule), GFP_KERNEL); 308 if (!rule) 309 return ERR_PTR(-ENOMEM); 310 311 rule->ruleset = ruleset; 312 rule->cookie = cookie; 313 314 refcount_inc(&ruleset->refcount); 315 316 return rule; 317 } 318 319 void prestera_acl_rule_priority_set(struct prestera_acl_rule *rule, 320 u32 priority) 321 { 322 rule->priority = priority; 323 } 324 325 void prestera_acl_rule_destroy(struct prestera_acl_rule *rule) 326 { 327 prestera_acl_ruleset_put(rule->ruleset); 328 kfree(rule); 329 } 330 331 int prestera_acl_rule_add(struct prestera_switch *sw, 332 struct prestera_acl_rule *rule) 333 { 334 int err; 335 struct prestera_acl_ruleset *ruleset = rule->ruleset; 336 struct prestera_flow_block *block = ruleset->ht_key.block; 337 338 /* try to add rule to hash table first */ 339 err = rhashtable_insert_fast(&ruleset->rule_ht, &rule->ht_node, 340 prestera_acl_rule_ht_params); 341 if (err) 342 goto err_ht_insert; 343 344 prestera_acl_rule_keymask_pcl_id_set(rule, ruleset->pcl_id); 345 rule->re_arg.vtcam_id = ruleset->vtcam_id; 346 rule->re_key.prio = rule->priority; 347 348 /* setup counter */ 349 rule->re_arg.count.valid = true; 350 rule->re_arg.count.client = PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0; 351 352 rule->re = prestera_acl_rule_entry_find(sw->acl, &rule->re_key); 353 err = WARN_ON(rule->re) ? -EEXIST : 0; 354 if (err) 355 goto err_rule_add; 356 357 rule->re = prestera_acl_rule_entry_create(sw->acl, &rule->re_key, 358 &rule->re_arg); 359 err = !rule->re ? -EINVAL : 0; 360 if (err) 361 goto err_rule_add; 362 363 /* bind the block (all ports) to chain index 0 */ 364 if (!ruleset->rule_count) { 365 err = prestera_acl_ruleset_block_bind(ruleset, block); 366 if (err) 367 goto err_acl_block_bind; 368 } 369 370 list_add_tail(&rule->list, &sw->acl->rules); 371 ruleset->rule_count++; 372 return 0; 373 374 err_acl_block_bind: 375 prestera_acl_rule_entry_destroy(sw->acl, rule->re); 376 err_rule_add: 377 rule->re = NULL; 378 rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, 379 prestera_acl_rule_ht_params); 380 err_ht_insert: 381 return err; 382 } 383 384 void prestera_acl_rule_del(struct prestera_switch *sw, 385 struct prestera_acl_rule *rule) 386 { 387 struct prestera_acl_ruleset *ruleset = rule->ruleset; 388 struct prestera_flow_block *block = ruleset->ht_key.block; 389 390 rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node, 391 prestera_acl_rule_ht_params); 392 ruleset->rule_count--; 393 list_del(&rule->list); 394 395 prestera_acl_rule_entry_destroy(sw->acl, rule->re); 396 397 /* unbind block (all ports) */ 398 if (!ruleset->rule_count) 399 prestera_acl_ruleset_block_unbind(ruleset, block); 400 } 401 402 int prestera_acl_rule_get_stats(struct prestera_acl *acl, 403 struct prestera_acl_rule *rule, 404 u64 *packets, u64 *bytes, u64 *last_use) 405 { 406 u64 current_packets; 407 u64 current_bytes; 408 int err; 409 410 err = prestera_counter_stats_get(acl->sw->counter, 411 rule->re->counter.block, 412 rule->re->counter.id, 413 ¤t_packets, ¤t_bytes); 414 if (err) 415 return err; 416 417 *packets = current_packets; 418 *bytes = current_bytes; 419 *last_use = jiffies; 420 421 return 0; 422 } 423 424 struct prestera_acl_rule_entry * 425 prestera_acl_rule_entry_find(struct prestera_acl *acl, 426 struct prestera_acl_rule_entry_key *key) 427 { 428 return rhashtable_lookup_fast(&acl->acl_rule_entry_ht, key, 429 __prestera_acl_rule_entry_ht_params); 430 } 431 432 static int __prestera_acl_rule_entry2hw_del(struct prestera_switch *sw, 433 struct prestera_acl_rule_entry *e) 434 { 435 return prestera_hw_vtcam_rule_del(sw, e->vtcam_id, e->hw_id); 436 } 437 438 static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw, 439 struct prestera_acl_rule_entry *e) 440 { 441 struct prestera_acl_hw_action_info act_hw[PRESTERA_ACL_RULE_ACTION_MAX]; 442 int act_num; 443 444 memset(&act_hw, 0, sizeof(act_hw)); 445 act_num = 0; 446 447 /* accept */ 448 if (e->accept.valid) { 449 act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_ACCEPT; 450 act_num++; 451 } 452 /* drop */ 453 if (e->drop.valid) { 454 act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_DROP; 455 act_num++; 456 } 457 /* trap */ 458 if (e->trap.valid) { 459 act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_TRAP; 460 act_num++; 461 } 462 /* counter */ 463 if (e->counter.block) { 464 act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_COUNT; 465 act_hw[act_num].count.id = e->counter.id; 466 act_num++; 467 } 468 469 return prestera_hw_vtcam_rule_add(sw, e->vtcam_id, e->key.prio, 470 e->key.match.key, e->key.match.mask, 471 act_hw, act_num, &e->hw_id); 472 } 473 474 static void 475 __prestera_acl_rule_entry_act_destruct(struct prestera_switch *sw, 476 struct prestera_acl_rule_entry *e) 477 { 478 /* counter */ 479 prestera_counter_put(sw->counter, e->counter.block, e->counter.id); 480 } 481 482 void prestera_acl_rule_entry_destroy(struct prestera_acl *acl, 483 struct prestera_acl_rule_entry *e) 484 { 485 int ret; 486 487 rhashtable_remove_fast(&acl->acl_rule_entry_ht, &e->ht_node, 488 __prestera_acl_rule_entry_ht_params); 489 490 ret = __prestera_acl_rule_entry2hw_del(acl->sw, e); 491 WARN_ON(ret && ret != -ENODEV); 492 493 __prestera_acl_rule_entry_act_destruct(acl->sw, e); 494 kfree(e); 495 } 496 497 static int 498 __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw, 499 struct prestera_acl_rule_entry *e, 500 struct prestera_acl_rule_entry_arg *arg) 501 { 502 /* accept */ 503 e->accept.valid = arg->accept.valid; 504 /* drop */ 505 e->drop.valid = arg->drop.valid; 506 /* trap */ 507 e->trap.valid = arg->trap.valid; 508 /* counter */ 509 if (arg->count.valid) { 510 int err; 511 512 err = prestera_counter_get(sw->counter, arg->count.client, 513 &e->counter.block, 514 &e->counter.id); 515 if (err) 516 goto err_out; 517 } 518 519 return 0; 520 521 err_out: 522 __prestera_acl_rule_entry_act_destruct(sw, e); 523 return -EINVAL; 524 } 525 526 struct prestera_acl_rule_entry * 527 prestera_acl_rule_entry_create(struct prestera_acl *acl, 528 struct prestera_acl_rule_entry_key *key, 529 struct prestera_acl_rule_entry_arg *arg) 530 { 531 struct prestera_acl_rule_entry *e; 532 int err; 533 534 e = kzalloc(sizeof(*e), GFP_KERNEL); 535 if (!e) 536 goto err_kzalloc; 537 538 memcpy(&e->key, key, sizeof(*key)); 539 e->vtcam_id = arg->vtcam_id; 540 err = __prestera_acl_rule_entry_act_construct(acl->sw, e, arg); 541 if (err) 542 goto err_act_construct; 543 544 err = __prestera_acl_rule_entry2hw_add(acl->sw, e); 545 if (err) 546 goto err_hw_add; 547 548 err = rhashtable_insert_fast(&acl->acl_rule_entry_ht, &e->ht_node, 549 __prestera_acl_rule_entry_ht_params); 550 if (err) 551 goto err_ht_insert; 552 553 return e; 554 555 err_ht_insert: 556 WARN_ON(__prestera_acl_rule_entry2hw_del(acl->sw, e)); 557 err_hw_add: 558 __prestera_acl_rule_entry_act_destruct(acl->sw, e); 559 err_act_construct: 560 kfree(e); 561 err_kzalloc: 562 return NULL; 563 } 564 565 static int __prestera_acl_vtcam_id_try_fit(struct prestera_acl *acl, u8 lookup, 566 void *keymask, u32 *vtcam_id) 567 { 568 struct prestera_acl_vtcam *vtcam; 569 int i; 570 571 list_for_each_entry(vtcam, &acl->vtcam_list, list) { 572 if (lookup != vtcam->lookup) 573 continue; 574 575 if (!keymask && !vtcam->is_keymask_set) 576 goto vtcam_found; 577 578 if (!(keymask && vtcam->is_keymask_set)) 579 continue; 580 581 /* try to fit with vtcam keymask */ 582 for (i = 0; i < __PRESTERA_ACL_RULE_MATCH_TYPE_MAX; i++) { 583 __be32 __keymask = ((__be32 *)keymask)[i]; 584 585 if (!__keymask) 586 /* vtcam keymask in not interested */ 587 continue; 588 589 if (__keymask & ~vtcam->keymask[i]) 590 /* keymask does not fit the vtcam keymask */ 591 break; 592 } 593 594 if (i == __PRESTERA_ACL_RULE_MATCH_TYPE_MAX) 595 /* keymask fits vtcam keymask, return it */ 596 goto vtcam_found; 597 } 598 599 /* nothing is found */ 600 return -ENOENT; 601 602 vtcam_found: 603 refcount_inc(&vtcam->refcount); 604 *vtcam_id = vtcam->id; 605 return 0; 606 } 607 608 int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, 609 void *keymask, u32 *vtcam_id) 610 { 611 struct prestera_acl_vtcam *vtcam; 612 u32 new_vtcam_id; 613 int err; 614 615 /* find the vtcam that suits keymask. We do not expect to have 616 * a big number of vtcams, so, the list type for vtcam list is 617 * fine for now 618 */ 619 list_for_each_entry(vtcam, &acl->vtcam_list, list) { 620 if (lookup != vtcam->lookup) 621 continue; 622 623 if (!keymask && !vtcam->is_keymask_set) { 624 refcount_inc(&vtcam->refcount); 625 goto vtcam_found; 626 } 627 628 if (keymask && vtcam->is_keymask_set && 629 !memcmp(keymask, vtcam->keymask, sizeof(vtcam->keymask))) { 630 refcount_inc(&vtcam->refcount); 631 goto vtcam_found; 632 } 633 } 634 635 /* vtcam not found, try to create new one */ 636 vtcam = kzalloc(sizeof(*vtcam), GFP_KERNEL); 637 if (!vtcam) 638 return -ENOMEM; 639 640 err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id, 641 PRESTERA_HW_VTCAM_DIR_INGRESS); 642 if (err) { 643 kfree(vtcam); 644 645 /* cannot create new, try to fit into existing vtcam */ 646 if (__prestera_acl_vtcam_id_try_fit(acl, lookup, 647 keymask, &new_vtcam_id)) 648 return err; 649 650 *vtcam_id = new_vtcam_id; 651 return 0; 652 } 653 654 vtcam->id = new_vtcam_id; 655 vtcam->lookup = lookup; 656 if (keymask) { 657 memcpy(vtcam->keymask, keymask, sizeof(vtcam->keymask)); 658 vtcam->is_keymask_set = true; 659 } 660 refcount_set(&vtcam->refcount, 1); 661 list_add_rcu(&vtcam->list, &acl->vtcam_list); 662 663 vtcam_found: 664 *vtcam_id = vtcam->id; 665 return 0; 666 } 667 668 int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id) 669 { 670 struct prestera_acl_vtcam *vtcam; 671 int err; 672 673 list_for_each_entry(vtcam, &acl->vtcam_list, list) { 674 if (vtcam_id != vtcam->id) 675 continue; 676 677 if (!refcount_dec_and_test(&vtcam->refcount)) 678 return 0; 679 680 err = prestera_hw_vtcam_destroy(acl->sw, vtcam->id); 681 if (err && err != -ENODEV) { 682 refcount_set(&vtcam->refcount, 1); 683 return err; 684 } 685 686 list_del(&vtcam->list); 687 kfree(vtcam); 688 return 0; 689 } 690 691 return -ENOENT; 692 } 693 694 int prestera_acl_init(struct prestera_switch *sw) 695 { 696 struct prestera_acl *acl; 697 int err; 698 699 acl = kzalloc(sizeof(*acl), GFP_KERNEL); 700 if (!acl) 701 return -ENOMEM; 702 703 acl->sw = sw; 704 INIT_LIST_HEAD(&acl->rules); 705 INIT_LIST_HEAD(&acl->vtcam_list); 706 idr_init(&acl->uid); 707 708 err = rhashtable_init(&acl->acl_rule_entry_ht, 709 &__prestera_acl_rule_entry_ht_params); 710 if (err) 711 goto err_acl_rule_entry_ht_init; 712 713 err = rhashtable_init(&acl->ruleset_ht, 714 &prestera_acl_ruleset_ht_params); 715 if (err) 716 goto err_ruleset_ht_init; 717 718 sw->acl = acl; 719 720 return 0; 721 722 err_ruleset_ht_init: 723 rhashtable_destroy(&acl->acl_rule_entry_ht); 724 err_acl_rule_entry_ht_init: 725 kfree(acl); 726 return err; 727 } 728 729 void prestera_acl_fini(struct prestera_switch *sw) 730 { 731 struct prestera_acl *acl = sw->acl; 732 733 WARN_ON(!idr_is_empty(&acl->uid)); 734 idr_destroy(&acl->uid); 735 736 WARN_ON(!list_empty(&acl->vtcam_list)); 737 WARN_ON(!list_empty(&acl->rules)); 738 739 rhashtable_destroy(&acl->ruleset_ht); 740 rhashtable_destroy(&acl->acl_rule_entry_ht); 741 742 kfree(acl); 743 } 744