acl_field.c (57736B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: acl_field.c 8 * 9 * Purpose: 10 * Field Processor specific functionality for ACL 11 */ 12 13 14 #if defined(INCLUDE_ACL) 15 16 #include <shared/bsl.h> 17 18 #include <assert.h> 19 20 #include <shared/alloc.h> 21 #include <sal/core/libc.h> 22 #include <sal/core/sync.h> 23 #include <sal/appl/io.h> 24 25 #include <bcm/error.h> 26 #include <bcmx/field.h> 27 #include <bcmx/port.h> 28 29 #include <appl/acl/acl.h> 30 31 #include "acl_util.h" 32 #include "acl_field.h" 33 34 /* Macros */ 35 36 #define ACL_PRIO_ENTRY_DEFAULT 1024 37 #define ACL_PRIO_GROUP_DEFAULT 16 38 39 /* 40 * Macro: 41 * ACL_FIELD_IS_INIT (internal) 42 * Purpose: 43 * Confirm that the ACL field functions are initialized. 44 * 45 * Parameters: 46 * 47 * Notes: 48 * Results in return(BCM_E_UNAVAIL), or return(BCM_E_INIT) if fails. 49 */ 50 #define ACL_FIELD_IS_INIT() do { \ 51 if (acl_field_control == NULL) { \ 52 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, \ 53 (BSL_META("ACL Error: ACL Field not initialized\n"))); \ 54 return BCM_E_INIT; \ 55 } \ 56 } while (0) 57 58 /* Local typedefs */ 59 60 /* 61 * Typedef: _acl_field_range_t 62 * 63 * Purpose: 64 */ 65 typedef struct _acl_field_range_check_s _acl_field_range_check_t; 66 67 struct _acl_field_range_check_s { 68 bcm_field_range_t range_id; /* Range Check ID */ 69 int references; /* Number of entries using range */ 70 _acl_field_range_check_t *next; /* for linked-lists */ 71 }; 72 73 /* 74 * Typedef: _acl_field_entry_t 75 * 76 * Purpose: 77 */ 78 typedef struct _acl_field_entry_s { 79 bcm_field_entry_t eid; /* Entry ID */ 80 bcma_acl_rule_t *rule; /* Corresponding rule */ 81 int prio; /* entry priority */ 82 _acl_field_range_check_t *range; /* Range checker, if needed */ 83 struct _acl_field_entry_s *next; /* for linked-lists */ 84 } _acl_field_entry_t; 85 86 /* 87 * Typedef: _acl_field_group_t 88 * 89 * Purpose: 90 * Field specific device-wide parameters for ACL. 91 */ 92 typedef struct _acl_field_group_s { 93 bcm_field_group_t gid; /* Group ID */ 94 bcm_field_qset_t qset; /* Qualifier Set */ 95 int prio_least; /* Lowest priority used. */ 96 struct _acl_field_entry_s *entry_list; /* List of group's entries */ 97 struct _acl_field_group_s *next; /* for linked-lists */ 98 } _acl_field_group_t; 99 100 /* 101 * Typedef: _acl_field_control_t 102 * 103 * Purpose: 104 * Field specific device-wide parameters for ACL. 105 */ 106 typedef struct _acl_field_control_s { 107 int prio_prev;/* priority used for most recent group*/ 108 _acl_field_group_t *group_list;/* groups */ 109 _acl_field_range_check_t *ranges; /* Range checkers defined on device */ 110 } _acl_field_control_t; 111 112 113 /* Local Prototypes */ 114 STATIC int _acl_field_group_create(_acl_field_control_t *control, 115 bcm_field_qset_t qset, 116 _acl_field_group_t **ret_group); 117 STATIC int _acl_field_group_remove_all(void); 118 STATIC int _acl_field_group_destroy_all(void); 119 STATIC int _acl_field_group_destroy(_acl_field_control_t *control, 120 bcm_field_group_t gid); 121 122 123 STATIC int _acl_field_entry_create(_acl_field_group_t *group, 124 bcma_acl_t *list, 125 bcma_acl_rule_t *rule); 126 STATIC int _acl_field_entry_qualify_vlan(_acl_field_group_t *group, 127 bcma_acl_rule_t *rule, 128 bcm_field_entry_t eid, 129 _acl_field_entry_t *entry); 130 #define _ACL_FIELD_L4_SRC 1 131 #define _ACL_FIELD_L4_DST 2 132 133 STATIC int _acl_field_range_check_create(uint32 flags, bcm_l4_port_t port_min, 134 bcm_l4_port_t port_max, 135 _acl_field_range_check_t **range_p); 136 STATIC int _acl_field_range_check_find(uint32 flags, bcm_l4_port_t port_min, 137 bcm_l4_port_t port_max, 138 _acl_field_range_check_t **range_p) ; 139 STATIC int _acl_field_range_check_destroy(_acl_field_entry_t *entry); 140 141 STATIC int _acl_field_entry_qualify_l4srcport(_acl_field_group_t *group, 142 bcma_acl_rule_t *rule, 143 bcm_field_entry_t eid, 144 _acl_field_entry_t *entry); 145 STATIC int _acl_field_entry_qualify_l4dstport(_acl_field_group_t *group, 146 bcma_acl_rule_t *rule, 147 bcm_field_entry_t eid, 148 _acl_field_entry_t *entry); 149 150 STATIC _acl_field_entry_t *_acl_field_entry_alloc(bcma_acl_rule_t *rule, 151 bcm_field_entry_t eid, 152 _acl_field_group_t *group); 153 154 STATIC int _acl_field_entry_remove_all( _acl_field_group_t *group); 155 STATIC int _acl_field_entry_remove(_acl_field_group_t *group, 156 bcm_field_entry_t eid); 157 STATIC int _acl_field_entry_destroy_all(_acl_field_group_t *group); 158 STATIC int _acl_field_entry_destroy(_acl_field_group_t *group, 159 bcm_field_entry_t eid); 160 161 STATIC int _acl_field_entry_action_add(bcma_acl_rule_t *rule, 162 bcm_field_entry_t eid); 163 164 165 STATIC int _acl_field_rule_qset_get(bcma_acl_rule_t *rule, 166 bcm_field_qset_t *qset); 167 STATIC int _acl_field_rule_entry_find(bcma_acl_rule_id_t rule_id, 168 _acl_field_group_t **group_p, 169 bcm_field_entry_t *eid); 170 171 #ifdef BROADCOM_DEBUG 172 STATIC int _acl_field_group_show(_acl_field_group_t *group); 173 STATIC int _acl_field_entry_show(_acl_field_entry_t *entry); 174 #endif /* BROADCOM_DEBUG */ 175 176 177 /* ACL Field Control Globals */ 178 179 static _acl_field_control_t *acl_field_control; 180 181 182 /* ACL Field Function Definitions */ 183 184 185 /* Section: Constructor and destructor for ACL module */ 186 187 /* 188 * Function: _acl_field_init 189 * 190 * Purpose: 191 * Initialize the ACL Field sub-module. 192 * 193 * Parameters: 194 * 195 * Returns: 196 * BCM_E_NONE - Success 197 * BCM_E_MEMORY - ACL field control allocation failure 198 */ 199 int 200 _acl_field_init(void) 201 { 202 int retval = BCM_E_NONE; 203 _acl_field_control_t *field_control; 204 205 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 206 (BSL_META("ACL _acl_field_init()\n"))); 207 208 /* Detach first if ACL has been previously initialized. */ 209 if (acl_field_control != NULL) { 210 BCM_IF_ERROR_RETURN(_acl_field_detach()); 211 } 212 213 /* Allocate and initalize Field Control struct. */ 214 field_control = sal_alloc(sizeof(_acl_field_control_t), 215 "ACL Field Control"); 216 if (field_control == NULL) { 217 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 218 (BSL_META("ACL Error: allocation failure for ACL Field control.\n"))); 219 return BCM_E_MEMORY; 220 } 221 sal_memset(field_control, 0, sizeof(_acl_field_control_t)); 222 223 /* Initialize the local group info. */ 224 field_control->prio_prev = ACL_PRIO_GROUP_DEFAULT; 225 field_control->group_list = NULL; 226 227 acl_field_control = field_control; 228 229 return retval; 230 } 231 232 /* 233 * Function: _acl_field_detach 234 * 235 * Purpose: 236 * Remove any lists and free lock and control. 237 * 238 * Parameters: 239 * 240 * Returns: 241 * BCM_E_NONE - Success 242 * BCM_E_PARAM - Device not initialized 243 */ 244 int 245 _acl_field_detach(void) 246 { 247 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 248 (BSL_META("ACL _acl_field_detach()\n"))); 249 250 if (acl_field_control == NULL) { 251 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 252 (BSL_META("ACL Error: detaching that is not initialized.\n"))); 253 return BCM_E_PARAM; 254 } 255 256 if (BCM_FAILURE(_acl_field_group_destroy_all())) { 257 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 258 (BSL_META("ACL Error: Failure in _acl_field_group_destroy_all()\n"))); 259 } 260 261 sal_free(acl_field_control); 262 acl_field_control = NULL; 263 264 return BCM_E_NONE; 265 } 266 267 /* 268 * Function: 269 * _acl_field_group_create 270 * 271 * Purpose: 272 * Create a new Field group with priority (slice) lower than the last one. 273 * 274 * Parameters: 275 * control - field control struct 276 * qset - Qualifier set 277 * ret_group - (OUT) pointer to newly created group 278 * 279 * Returns: 280 * BCM_E_NONE - Success 281 * BCM_E_MEMORY - _acl_field_group_t allocation failure 282 * BCM_E_XXX - from bcmx_field_group_create() 283 */ 284 STATIC int 285 _acl_field_group_create(_acl_field_control_t *field_control, 286 bcm_field_qset_t qset, 287 _acl_field_group_t **ret_group) 288 { 289 bcm_field_group_t gid; 290 int retval; 291 _acl_field_group_t *group; 292 _acl_field_group_t *iter; 293 294 assert(field_control != NULL); 295 assert(ret_group != NULL); 296 297 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 298 (BSL_META("ACL _acl_field_group_create()\n"))); 299 300 /* Allocate a ACL field group. */ 301 group = sal_alloc(sizeof(_acl_field_group_t), "ACL field group"); 302 if (group == NULL) { 303 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 304 (BSL_META("ACL Error: Allocation error for ACL field group\n"))); 305 return BCM_E_MEMORY; 306 } 307 sal_memset(group, 0, sizeof(_acl_field_group_t)); 308 group->prio_least = ACL_PRIO_ENTRY_DEFAULT; 309 310 /* Create the actual Field group. */ 311 retval = BCM_E_RESOURCE; 312 313 assert(field_control->prio_prev <= ACL_PRIO_GROUP_DEFAULT); 314 while (field_control->prio_prev > 0 && BCM_FAILURE(retval)) { 315 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 316 (BSL_META("ACL Calling FP group create pri=%d\n"), 317 field_control->prio_prev)); 318 retval = bcmx_field_group_create_mode(qset, --field_control->prio_prev, 319 bcmFieldGroupModeAuto, &gid); 320 } 321 if (BCM_FAILURE(retval)){ 322 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 323 (BSL_META("ACL Error: Group creation error (prio=%d, gid=%d)\n"), 324 field_control->prio_prev, gid)); 325 return retval; 326 } 327 328 group->gid = gid; 329 iter = field_control->group_list; 330 331 /* Put it at head if there are no groups. */ 332 if (iter == NULL) { 333 field_control->group_list = group; 334 *ret_group = group; 335 return BCM_E_NONE; 336 } 337 338 /* Put the group at the tail of the control group list.*/ 339 while (iter->next != NULL) { 340 iter = iter->next; 341 } 342 343 iter->next = group; 344 *ret_group = group; 345 346 return BCM_E_NONE; 347 } 348 349 /* 350 * Function: 351 * _acl_field_group_remove_all 352 * 353 * Purpose: 354 * Destroy all Field group used by ACL. 355 * 356 * Parameters: 357 * none 358 * 359 * Returns: 360 * BCM_E_NONE - Success 361 * BCM_E_NOT_FOUND - Group ID not found 362 * BCM_E_XXX - From bcmx_field_entry_remove() 363 */ 364 STATIC int 365 _acl_field_group_remove_all(void) { 366 int retval; 367 _acl_field_group_t *group; 368 369 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 370 (BSL_META("ACL _acl_field_group_remove_all()\n"))); 371 assert(acl_field_control != NULL); 372 373 /* Traverse the group list, removing all entries in each group. */ 374 group = acl_field_control->group_list; 375 while (group != NULL) { 376 /* Remove any entries in group.*/ 377 retval = _acl_field_entry_remove_all(group); 378 if (BCM_FAILURE(retval)) { 379 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 380 (BSL_META("ACL Error: Failed to remove entries in group ID=%d\n"), 381 group->gid)); 382 return retval; 383 } 384 group = group->next; 385 } 386 387 return BCM_E_NONE; 388 } 389 390 /* 391 * Function: 392 * _acl_field_group_destroy_all 393 * 394 * Purpose: 395 * Destroy all Field groups used by ACL. This deallocates all software 396 * strutures for field groups and their entries. 397 * 398 * Parameters: 399 * none 400 * 401 * Returns: 402 * BCM_E_NONE - Success 403 * BCM_E_NOT_FOUND - Group ID not found 404 * BCM_E_XXX - from _acl_field_group_destroy() 405 */ 406 STATIC int 407 _acl_field_group_destroy_all(void) { 408 int retval; 409 410 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 411 (BSL_META("ACL _acl_field_group_destroy_all()\n"))); 412 assert(acl_field_control != NULL); 413 414 while (acl_field_control->group_list != NULL) { 415 retval = _acl_field_group_destroy(acl_field_control, 416 acl_field_control->group_list->gid); 417 if (BCM_FAILURE(retval)) { 418 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 419 (BSL_META("ACL Error: _acl_field_group_destroy_all() failure\n"))); 420 return retval; 421 } 422 } 423 424 return BCM_E_NONE; 425 } 426 427 /* 428 * Function: 429 * _acl_field_group_destroy 430 * 431 * Purpose: 432 * Destroy a Field group used by ACL. This deallocates the field group and 433 * entry structures while leaving the hardware programming alone. 434 * 435 * Parameters: 436 * control - ACL field control info 437 * gid - group to be destroyed 438 * 439 * Returns: 440 * BCM_E_NONE - Success 441 * BCM_E_NOT_FOUND - Group ID not found 442 * BCM_E_XXX - from bcmx_field_group_destroy() 443 */ 444 STATIC int 445 _acl_field_group_destroy(_acl_field_control_t *control, 446 bcm_field_group_t gid) { 447 int retval; 448 _acl_field_group_t *group; 449 _acl_field_group_t *prev = NULL; 450 451 452 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 453 (BSL_META("ACL _acl_field_group_destroy(gid=%d)\n"), 454 gid)); 455 assert(control != NULL); 456 457 /* If the group list is empty, group ID can't be found. */ 458 if (control->group_list == NULL) { 459 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 460 (BSL_META("ACL Error: No groups available to delete?\n"))); 461 return BCM_E_NOT_FOUND; 462 } 463 /* Scan group list, looking for matching Group ID. */ 464 group = control->group_list; 465 466 while (group != NULL) { 467 if (group->gid == gid) { 468 /* Destroy any entries in group.*/ 469 retval = _acl_field_entry_destroy_all(group); 470 if (BCM_FAILURE(retval)) { 471 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 472 (BSL_META("ACL Error: Failed to destroy entries in group ID=%d\n"), 473 group->gid)); 474 return retval; 475 } 476 477 /* Destroy the group itself.*/ 478 if (prev == NULL) { 479 control->group_list = group->next; 480 } else { 481 prev->next = group->next; 482 } 483 sal_free(group); 484 485 retval = bcmx_field_group_destroy(gid); 486 if (BCM_FAILURE(retval)) { 487 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 488 (BSL_META("ACL Error: group ID=%d not destroyed\n"), 489 gid)); 490 return retval; 491 } 492 return BCM_E_NONE; 493 } 494 495 prev = group; 496 group = group->next; 497 } 498 499 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 500 (BSL_META("ACL Error: group ID=%d not found to be destroyed\n"), 501 gid)); 502 return BCM_E_NOT_FOUND; 503 } 504 505 #define _ACL_FIELD_ENTRY_CREATE_RECOVER(_rv_,_grp_) \ 506 do { \ 507 if ((_rv_) < 0) { \ 508 _acl_field_entry_destroy_all(_grp_); \ 509 return (_rv_); \ 510 } \ 511 } while (0); 512 513 /* 514 * Function: _acl_field_entry_create 515 * 516 * Purpose: 517 * 518 * Parameters: 519 * group - ACL field group 520 * list - ACL list that contains rule 521 * rule - ACL rule 522 * 523 * Returns: 524 * BCM_E_NONE - Success 525 * BCM_E_MEMORY - Field entry allocation failure 526 */ 527 STATIC int 528 _acl_field_entry_create(_acl_field_group_t *group, 529 bcma_acl_t *list, 530 bcma_acl_rule_t *rule) 531 { 532 int retval; 533 bcm_field_entry_t eid; 534 _acl_field_entry_t *entry; 535 bcm_mac_t mac_mask = _BCMA_ACL_MAC_ALL_ONES; 536 bcmx_lplist_t lplist_full; 537 538 assert(group != NULL); 539 assert(list != NULL); 540 assert(rule != NULL); 541 542 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 543 (BSL_META("ACL _acl_field_entry_create(gid=%d, list_id=%d, rule_id=%d)\n"), 544 group->gid, list->list_id, rule->rule_id)); 545 ACL_FIELD_IS_INIT(); 546 BCM_IF_ERROR_RETURN(bcmx_field_entry_create(group->gid, &eid)); 547 548 /* Set the priority of the entry. */ 549 retval = bcmx_field_entry_prio_set(eid, --group->prio_least); 550 if (BCM_FAILURE(retval)) { 551 bcmx_field_entry_destroy(eid); 552 return retval; 553 } 554 555 bcmx_lplist_init(&lplist_full, 0, 0); 556 bcmx_port_lplist_populate(&lplist_full, BCMX_PORT_LP_ALL); 557 558 entry = _acl_field_entry_alloc(rule, eid, group); 559 if (entry == NULL) { 560 bcmx_lplist_free(&lplist_full); 561 bcmx_field_entry_destroy(eid); 562 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 563 (BSL_META("ACL Error: _acl_field_entry_t allocation failure\n"))); 564 return BCM_E_MEMORY; 565 } 566 567 /* Add actions to entry. */ 568 retval = _acl_field_entry_action_add(rule, eid); 569 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 570 571 /* Add logical port qualification, if needed. */ 572 if (!bcmx_lplist_eq(&list->lplist, &lplist_full)) { 573 retval = bcmx_field_qualify_InPorts(eid, list->lplist); 574 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 575 } 576 577 /* Qualify on Source MAC. */ 578 if (rule->flags & BCMA_ACL_RULE_SRC_MAC) { 579 retval = bcmx_field_qualify_SrcMac(eid, rule->src_mac, mac_mask); 580 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 581 } 582 583 /* Qualify on Destination MAC */ 584 if (rule->flags & BCMA_ACL_RULE_DST_MAC) { 585 retval = bcmx_field_qualify_DstMac(eid, rule->dst_mac, mac_mask); 586 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 587 } 588 589 /* Qualify on Source IPv4 */ 590 if (rule->flags & BCMA_ACL_RULE_SRC_IP4) { 591 retval = bcmx_field_qualify_SrcIp(eid, rule->src_ip, 592 rule->src_ip_mask); 593 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 594 } 595 596 /* Qualify on Destination IPv4 */ 597 if (rule->flags & BCMA_ACL_RULE_DST_IP4) { 598 retval = bcmx_field_qualify_DstIp(eid, rule->dst_ip, rule->dst_ip_mask); 599 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 600 } 601 602 /* Qualify on SrcIp6 */ 603 if (rule->flags & BCMA_ACL_RULE_SRC_IP6) { 604 retval = bcmx_field_qualify_SrcIp6(eid, rule->src_ip6, 605 rule->src_ip6_mask); 606 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 607 } 608 609 /* Qualify on DstIp6 */ 610 if (rule->flags & BCMA_ACL_RULE_DST_IP6) { 611 retval = bcmx_field_qualify_DstIp6(eid, rule->dst_ip6, 612 rule->dst_ip6_mask); 613 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 614 } 615 616 /* Qualify on Ethertype. */ 617 if (rule->flags & BCMA_ACL_RULE_ETHERTYPE) { 618 retval = bcmx_field_qualify_EtherType(eid, rule->ether_type, 619 ACL_MASK_ETHERTYPE); 620 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 621 } 622 623 /* Qualify on IP Protocol. */ 624 if (rule->flags & BCMA_ACL_RULE_IPPROTOCOL) { 625 retval = bcmx_field_qualify_IpProtocol(eid, rule->ip_protocol, 626 ACL_MASK_IPPROTOCOL); 627 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 628 } 629 630 /* For qualifiers that have ranges, */ 631 632 /* Qualify on VLAN range. */ 633 if (rule->flags & BCMA_ACL_RULE_VLAN) { 634 retval = _acl_field_entry_qualify_vlan(group, rule, eid, entry); 635 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 636 } 637 638 /* Qualify on L4 Source Port range. */ 639 if (rule->flags & BCMA_ACL_RULE_L4_SRC_PORT) { 640 retval = _acl_field_entry_qualify_l4srcport(group, rule, eid, entry); 641 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 642 } 643 644 /* Qualify on L4 Destination Port range. */ 645 if (rule->flags & BCMA_ACL_RULE_L4_DST_PORT) { 646 retval =_acl_field_entry_qualify_l4dstport(group, rule, eid, entry); 647 _ACL_FIELD_ENTRY_CREATE_RECOVER(retval, group); 648 } 649 650 bcmx_lplist_free(&lplist_full); 651 return BCM_E_NONE; 652 } 653 #undef _ACL_FIELD_ENTRY_CREATE_RECOVER 654 655 /* 656 * Function: _acl_field_entry_qualify_vlan 657 * 658 * Purpose: 659 * Qualify on VLAN range. 660 * 661 * Parameters: 662 * group - ACL field group 663 * rule - ACL rule 664 * eid - Entry ID 665 * entry - 666 * 667 * Returns: 668 * BCM_E_NONE - Success 669 * BCM_E_MEMORY - Field entry allocation failure 670 */ 671 STATIC int 672 _acl_field_entry_qualify_vlan(_acl_field_group_t *group, bcma_acl_rule_t *rule, 673 bcm_field_entry_t eid, _acl_field_entry_t *entry) 674 { 675 acl_node_t *list; 676 acl_node_t *node_cur; 677 int count; 678 int idx; 679 bcm_field_entry_t eid_copy; 680 int retval; 681 _acl_rule_link_t *rule_link; 682 683 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 684 (BSL_META("ACL _acl_field_entry_qualify_vlan(gid=%d, rule_id=%d)\n"), 685 group->gid, rule->rule_id)); 686 /* Get list of range data/mask pairs. */ 687 acl_range_to_list(rule->vlan_min, rule->vlan_max, &list, &count); 688 node_cur = list; 689 690 /* Qualify on first element with entry that already exists. */ 691 BCM_IF_ERROR_RETURN(bcmx_field_qualify_OuterVlan(eid, list->data, 692 list->mask)); 693 node_cur = node_cur->next; 694 695 for (idx = 1; idx < count; idx++) { 696 /* Create enough entries to cover range. */ 697 BCM_IF_ERROR_RETURN(bcmx_field_entry_copy(eid, &eid_copy)); 698 entry = _acl_field_entry_alloc(rule, eid_copy, group); 699 if (entry == NULL) { 700 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 701 (BSL_META("ACL Error: _acl_field_entry_t allocation failure\n"))); 702 return BCM_E_MEMORY; 703 } 704 705 /* Qualify on entries with each data/mask pair from list. */ 706 retval = bcmx_field_qualify_OuterVlan(eid_copy, node_cur->data, 707 node_cur->mask); 708 if (BCM_FAILURE(retval)) { 709 rule_link = _acl_rule_link_find(rule->rule_id); 710 rule_link->entries--; 711 sal_free(entry); 712 return retval; 713 } 714 node_cur = node_cur->next; 715 } 716 717 /* Destroy list */ 718 return acl_range_destroy(list, count); 719 } 720 721 /* 722 * Function: _acl_field_entry_qualify_l4srcport 723 * 724 * Purpose: 725 * Qualify on L4 Source Port range. 726 * 727 * Parameters: 728 * group - ACL field group 729 * rule - ACL rule 730 * eid - Entry ID 731 * entry - ACL field entry 732 * 733 * Returns: 734 * BCM_E_NONE - Success 735 * BCM_E_MEMORY - Field entry allocation failure 736 */ 737 STATIC int 738 _acl_field_entry_qualify_l4srcport(_acl_field_group_t *group, 739 bcma_acl_rule_t *rule, 740 bcm_field_entry_t eid, 741 _acl_field_entry_t *entry) 742 { 743 _acl_field_range_check_t *range; 744 acl_node_t *list; 745 acl_node_t *node_cur; 746 int count, org_count; 747 int idx, rule_idx; 748 bcm_field_entry_t eid_copy, eid_cur=0; 749 _acl_rule_link_t *rule_link; 750 _acl_field_entry_t *entry_start; 751 int rv = BCM_E_NONE; 752 753 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 754 (BSL_META("ACL _acl_field_entry_qualify_l4srcport(gid=%d, rule_id=%d)\n"), 755 group->gid, rule->rule_id)); 756 757 /* Create the necessary Field range checker. */ 758 rv = _acl_field_range_check_create(BCM_FIELD_RANGE_SRCPORT, 759 rule->src_port_min, 760 rule->src_port_max, &range); 761 if (rv == BCM_E_NONE) { 762 entry->range = range; 763 764 /* Qualify the entry on that range checker. */ 765 return bcmx_field_qualify_RangeCheck(eid, range->range_id, 0); 766 } 767 768 /* Create ranger failed */ 769 770 /* Get list of range data/mask pairs. */ 771 acl_range_to_list(rule->src_port_min, rule->src_port_max, &list, 772 &count); 773 /* Get the original total number of entries for this rule */ 774 rule_link = _acl_rule_link_find(rule->rule_id); 775 org_count = rule_link->entries; 776 /* Move to the first entry pointer */ 777 entry_start = group->entry_list; 778 while (entry_start != NULL) { 779 if (entry_start->rule->rule_id == rule->rule_id) { 780 eid_cur = entry_start->eid; 781 break; 782 } 783 else { 784 entry_start = entry_start->next; 785 } 786 } 787 788 for (rule_idx = 0; rule_idx < org_count; rule_idx++) { 789 node_cur = list; 790 791 /* Qualify on first element with entry that already exists. */ 792 rv = bcmx_field_qualify_L4SrcPort(eid_cur, 793 list->data, list->mask); 794 if (rv < 0) { 795 goto srcport_error; 796 } 797 node_cur = node_cur->next; 798 799 for (idx = 1; idx < count; idx++) { 800 /* Create enough entries to cover range. */ 801 rv = bcmx_field_entry_copy(eid_cur, &eid_copy); 802 if (rv < 0) { 803 goto srcport_error; 804 } 805 entry = _acl_field_entry_alloc(rule, eid_copy, group); 806 if (entry == NULL) { 807 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 808 (BSL_META("ACL Error: _acl_field_entry_t allocation failure\n"))); 809 rv = BCM_E_MEMORY; 810 goto srcport_error; 811 } 812 813 /* Qualify on entries with each data/mask pair from list. */ 814 rv = bcmx_field_qualify_L4SrcPort(eid_copy, node_cur->data, 815 node_cur->mask); 816 if (rv < 0) { 817 goto srcport_error; 818 } 819 820 node_cur = node_cur->next; 821 } 822 if (entry_start->next != NULL) { 823 entry_start = entry_start->next; 824 eid_cur = entry_start->eid; 825 } 826 } 827 828 829 /* Destroy list */ 830 return acl_range_destroy(list, count); 831 832 srcport_error : 833 acl_range_destroy(list, count); 834 return rv; 835 } 836 837 /* 838 * Function: _acl_field_range_check_create 839 * 840 * Purpose: 841 * 842 * Parameters: 843 * flags - Direction flags (source/destination) 844 * port_min - minimum L4 port value 845 * port_max - maximum L4 port value 846 * range_p - (OUT) pointer to ACL range created by this function 847 * 848 * Returns: 849 * BCM_E_NONE - Success 850 * BCM_E_MEMORY - Field range allocation failure 851 */ 852 853 STATIC int 854 _acl_field_range_check_create(uint32 flags, bcm_l4_port_t port_min, 855 bcm_l4_port_t port_max, 856 _acl_field_range_check_t **range_p) 857 { 858 bcm_field_range_t range_id; 859 int retval; 860 861 assert(range_p != NULL); 862 863 /* Check for existing range checker that matches. */ 864 retval = _acl_field_range_check_find(flags, port_min, port_max, range_p); 865 if (BCM_SUCCESS(retval)) { 866 (*range_p)->references += 1; 867 return BCM_E_NONE; 868 } 869 870 /* Create new Field range checker. */ 871 BCM_IF_ERROR_RETURN( 872 bcmx_field_range_create(&range_id, flags, port_min, port_max)); 873 874 /* Create the ACL range node */ 875 *range_p = sal_alloc(sizeof(_acl_field_range_check_t), 876 "ACL FIELD range check"); 877 if (*range_p == NULL) { 878 bcmx_field_range_destroy(range_id); 879 return BCM_E_MEMORY; 880 } 881 882 /* Initialize range check values. */ 883 (*range_p)->range_id = range_id; 884 (*range_p)->references = 1; 885 (*range_p)->next = acl_field_control->ranges; 886 887 return BCM_E_NONE; 888 } 889 890 STATIC int 891 _acl_field_range_check_find(uint32 flags, bcm_l4_port_t port_min, 892 bcm_l4_port_t port_max, 893 _acl_field_range_check_t **range_p) 894 { 895 uint32 flags_temp; 896 bcm_l4_port_t port_min_temp; 897 bcm_l4_port_t port_max_temp; 898 _acl_field_range_check_t *range; 899 900 /* Traverse list of range checkers while looking for a match. */ 901 for (range = acl_field_control->ranges; range != NULL; range = range->next) 902 { 903 /* Get the min, max & flags from Field. */ 904 BCM_IF_ERROR_RETURN( 905 bcmx_field_range_get(range->range_id, &flags_temp, &port_min_temp, 906 &port_max_temp)); 907 /* If flags, min, and max match, return this range. */ 908 if (flags_temp == flags && port_max_temp == port_max && 909 port_min_temp == port_min) { 910 *range_p = range; 911 return BCM_E_NONE; 912 } 913 } 914 915 return BCM_E_NOT_FOUND; 916 } 917 918 /* 919 * Function: _acl_field_range_check_destroy 920 * 921 * Purpose: 922 * 923 * 924 * Parameters: 925 * group - ACL field group 926 * rule - ACL rule 927 * eid - Entry ID 928 * entry - ACL field entry 929 * 930 * Returns: 931 * BCM_E_NONE - Success 932 * BCM_E_MEMORY - Field entry allocation failure 933 */ 934 STATIC int 935 _acl_field_range_check_destroy(_acl_field_entry_t *entry) { 936 _acl_field_range_check_t *range_cur, *range_prev = NULL; 937 938 if (entry->range == NULL) { 939 return BCM_E_NOT_FOUND; 940 } 941 942 /* Decrement reference count. If non-zero, just return. */ 943 entry->range->references--; 944 if (entry->range->references > 0) { 945 entry->range = NULL; 946 return BCM_E_NONE; 947 } 948 949 /* Find the range in the control's list. */ 950 for (range_cur = acl_field_control->ranges; 951 range_cur != NULL; 952 range_cur = range_cur->next) { 953 if (range_cur->range_id == entry->range->range_id) { 954 break; 955 } 956 range_prev = range_cur; 957 } 958 959 if (range_cur == NULL || range_cur->references != 0) { 960 return BCM_E_INTERNAL; 961 } 962 963 /* Point around range node. */ 964 if (range_prev == NULL) { 965 acl_field_control->ranges = range_cur->next; 966 } else { 967 range_prev->next = range_cur->next; 968 } 969 970 entry->range = NULL; 971 bcmx_field_range_destroy(range_cur->range_id); 972 sal_free(range_cur); 973 974 return BCM_E_NONE; 975 } 976 977 /* 978 * Function: _acl_field_entry_qualify_l4dstport 979 * 980 * Purpose: 981 * Qualify on L4 Source Port range. 982 * 983 * Parameters: 984 * group - ACL field group 985 * rule - ACL rule 986 * eid - Entry ID 987 * entry - ACL field entry 988 * 989 * Returns: 990 * BCM_E_NONE - Success 991 * BCM_E_MEMORY - Field entry allocation failure 992 */ 993 STATIC int 994 _acl_field_entry_qualify_l4dstport(_acl_field_group_t *group, 995 bcma_acl_rule_t *rule, 996 bcm_field_entry_t eid, 997 _acl_field_entry_t *entry) 998 { 999 _acl_field_range_check_t *range; 1000 acl_node_t *list; 1001 acl_node_t *node_cur; 1002 int count, org_count; 1003 int idx, rule_idx; 1004 bcm_field_entry_t eid_copy, eid_cur=0; 1005 _acl_rule_link_t *rule_link; 1006 _acl_field_entry_t *entry_start; 1007 int rv = BCM_E_NONE; 1008 1009 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1010 (BSL_META("ACL _acl_field_entry_qualify_l4dstport(gid=%d, rule_id=%d)\n"), 1011 group->gid, rule->rule_id)); 1012 /* Create the necessary Field range checker. */ 1013 rv = _acl_field_range_check_create(BCM_FIELD_RANGE_DSTPORT, 1014 rule->dst_port_min, 1015 rule->dst_port_max, &range); 1016 if (rv == BCM_E_NONE) { 1017 entry->range = range; 1018 1019 /* Qualify the entry on that range checker. */ 1020 return bcmx_field_qualify_RangeCheck(eid, range->range_id, 0); 1021 } 1022 1023 /* Create ranger failed */ 1024 1025 /* Get list of range data/mask pairs. */ 1026 acl_range_to_list(rule->dst_port_min, rule->dst_port_max, &list, 1027 &count); 1028 /* Get the original total number of entries for this rule */ 1029 rule_link = _acl_rule_link_find(rule->rule_id); 1030 org_count = rule_link->entries; 1031 /* Move to the first entry pointer */ 1032 entry_start = group->entry_list; 1033 while (entry_start != NULL) { 1034 if (entry_start->rule->rule_id == rule->rule_id) { 1035 eid_cur = entry_start->eid; 1036 break; 1037 } 1038 else { 1039 entry_start = entry_start->next; 1040 } 1041 } 1042 for (rule_idx = 0; rule_idx < org_count; rule_idx++) { 1043 node_cur = list; 1044 1045 /* Qualify on first element with entry that already exists. */ 1046 rv = bcmx_field_qualify_L4DstPort(eid_cur, 1047 list->data, list->mask); 1048 if (rv < 0) { 1049 goto dstport_error; 1050 } 1051 node_cur = node_cur->next; 1052 1053 for (idx = 1; idx < count; idx++) { 1054 /* Create enough entries to cover range. */ 1055 rv = bcmx_field_entry_copy(eid_cur, &eid_copy); 1056 if (rv < 0) { 1057 goto dstport_error; 1058 } 1059 entry = _acl_field_entry_alloc(rule, eid_copy, group); 1060 if (entry == NULL) { 1061 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1062 (BSL_META("ACL Error: _acl_field_entry_t allocation failure\n"))); 1063 rv = BCM_E_MEMORY; 1064 goto dstport_error; 1065 } 1066 1067 /* Qualify on entries with each data/mask pair from list. */ 1068 rv = bcmx_field_qualify_L4DstPort(eid_copy, node_cur->data, 1069 node_cur->mask); 1070 if (rv < 0) { 1071 goto dstport_error; 1072 } 1073 1074 node_cur = node_cur->next; 1075 } 1076 if (entry_start->next != NULL) { 1077 entry_start = entry_start->next; 1078 eid_cur = entry_start->eid; 1079 } 1080 } 1081 1082 /* Destroy list */ 1083 return acl_range_destroy(list, count); 1084 1085 dstport_error : 1086 acl_range_destroy(list, count); 1087 return rv; 1088 } 1089 1090 /* 1091 * Function: _acl_field_entry_alloc 1092 * 1093 * Purpose: 1094 * 1095 * Parameters: 1096 * rule - ACL rule 1097 * eid - Entry ID 1098 * group - ACL field group 1099 * 1100 * Returns: 1101 * BCM_E_NONE - Success 1102 * BCM_E_MEMORY - Field entry allocation failure 1103 */ 1104 STATIC _acl_field_entry_t* 1105 _acl_field_entry_alloc(bcma_acl_rule_t *rule, bcm_field_entry_t eid, 1106 _acl_field_group_t *group) 1107 { 1108 _acl_field_entry_t *entry; 1109 _acl_rule_link_t *rule_link; 1110 1111 assert(rule != NULL); 1112 assert(group != NULL); 1113 1114 rule_link = _acl_rule_link_find(rule->rule_id); 1115 if (rule_link == NULL) { 1116 return NULL; 1117 } 1118 1119 entry = sal_alloc(sizeof(_acl_field_entry_t), "ACL Field Entry"); 1120 if (entry == NULL) { 1121 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1122 (BSL_META("ACL Error: _acl_field_entry_t allocation failure\n"))); 1123 return entry; 1124 } 1125 sal_memset(entry, 0, sizeof(_acl_field_entry_t)); 1126 1127 entry->eid = eid; 1128 entry->rule = rule; 1129 entry->prio = group->prio_least; 1130 entry->next = group->entry_list; 1131 group->entry_list = entry; 1132 1133 rule_link->entries++; 1134 1135 return entry; 1136 } 1137 1138 /* 1139 * Function: 1140 * _acl_field_entry_remove_all 1141 * 1142 * Purpose: 1143 * Remove all entries in a group from hardware. 1144 * 1145 * Parameters: 1146 * group - group to have entries removed 1147 * 1148 * Returns: 1149 * BCM_E_NONE - Success 1150 * BCM_E_XXX - From bcmx_field_entry_remove() 1151 */ 1152 STATIC int 1153 _acl_field_entry_remove_all(_acl_field_group_t *group) 1154 { 1155 int retval; 1156 _acl_field_entry_t *entry; 1157 1158 assert(group != NULL); 1159 1160 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1161 (BSL_META("ACL _acl_field_entry_remove_all(gid=%d)\n"), 1162 group->gid)); 1163 entry = group->entry_list; 1164 while (entry != NULL) { 1165 retval = bcmx_field_entry_remove(entry->eid); 1166 if (BCM_FAILURE(retval)) { 1167 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1168 (BSL_META("ACL Error: Entry ID=%d not removed\n"), 1169 entry->eid)); 1170 return retval; 1171 } 1172 entry = entry->next; 1173 } 1174 1175 return BCM_E_NONE; 1176 } 1177 1178 /* 1179 * Function: 1180 * _acl_field_entry_remove 1181 * 1182 * Purpose: 1183 * 1184 * Parameters: 1185 * 1186 * Returns: 1187 */ 1188 STATIC int 1189 _acl_field_entry_remove(_acl_field_group_t *group, 1190 bcm_field_entry_t eid) 1191 { 1192 int retval; 1193 _acl_field_entry_t *entry; 1194 1195 assert(group != NULL); 1196 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1197 (BSL_META("ACL _acl_field_entry_remove(gid=%d, eid=%d)\n"), 1198 group->gid, eid)); 1199 1200 /* Scan entry list, looking for matching Entry ID. */ 1201 entry = group->entry_list; 1202 while (entry != NULL) { 1203 if (entry->eid == eid) { 1204 /* Found it so remove it.*/ 1205 retval = bcmx_field_entry_remove(eid); 1206 if (BCM_FAILURE(retval)) { 1207 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1208 (BSL_META("ACL Error: Entry ID=%d not removed\n"), 1209 eid)); 1210 return retval; 1211 } 1212 return BCM_E_NONE; 1213 } 1214 entry = entry->next; 1215 } 1216 1217 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1218 (BSL_META("ACL Error: Entry ID=%d not found to be removed\n"), 1219 eid)); 1220 return BCM_E_NOT_FOUND; 1221 } 1222 1223 /* 1224 * Function: 1225 * _acl_field_entry_destroy_all 1226 * 1227 * Purpose: 1228 * 1229 * Parameters: 1230 * 1231 * Returns: 1232 */ 1233 STATIC int 1234 _acl_field_entry_destroy_all(_acl_field_group_t *group) 1235 { 1236 int retval; 1237 1238 assert(group != NULL); 1239 1240 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1241 (BSL_META("ACL _acl_field_entry_destroy_all(gid=%d)\n"), 1242 group->gid)); 1243 1244 while (group->entry_list != NULL) { 1245 retval = _acl_field_entry_destroy(group, group->entry_list->eid); 1246 if (BCM_FAILURE(retval)) { 1247 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1248 (BSL_META("ACL Error: _acl_field_entry_destroy() failure\n"))); 1249 return retval; 1250 } 1251 } 1252 1253 return BCM_E_NONE; 1254 } 1255 1256 /* 1257 * Function: 1258 * _acl_field_entry_destroy 1259 * 1260 * Purpose: 1261 * 1262 * Parameters: 1263 * 1264 * Returns: 1265 */ 1266 STATIC int 1267 _acl_field_entry_destroy(_acl_field_group_t *group, 1268 bcm_field_entry_t eid) 1269 { 1270 int retval; 1271 _acl_field_entry_t *entry; 1272 _acl_field_entry_t *prev = NULL; 1273 1274 assert(group != NULL); 1275 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1276 (BSL_META("ACL _acl_field_entry_destroy(gid=%d, eid=%d)\n"), 1277 group->gid, eid)); 1278 1279 /* If the entry list is empty, Entry ID can't be found. */ 1280 if (group->entry_list == NULL) { 1281 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1282 (BSL_META("ACL Error: No entries available to delete?\n"))); 1283 return BCM_E_NOT_FOUND; 1284 } 1285 1286 /* If entry is head of list, point around it and delete. */ 1287 if (group->entry_list->eid == eid) { 1288 entry = group->entry_list; 1289 group->entry_list = group->entry_list->next; 1290 sal_free(entry); 1291 1292 retval = bcmx_field_entry_destroy(eid); 1293 if (BCM_FAILURE(retval)) { 1294 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1295 (BSL_META("ACL Error: Entry ID=%d not destroyed\n"), 1296 eid)); 1297 return retval; 1298 } 1299 return BCM_E_NONE; 1300 } 1301 1302 /* Scan entry list, looking for matching Entry ID. */ 1303 entry = group->entry_list->next; 1304 prev = group->entry_list; 1305 while (entry != NULL) { 1306 if (entry->eid == eid) { 1307 /* Found it so destroy it.*/ 1308 prev->next = entry->next; 1309 1310 /* Destroy range checker if needed. */ 1311 if (entry->range != NULL) { 1312 _acl_field_range_check_destroy(entry); 1313 } 1314 1315 sal_free(entry); 1316 1317 retval = bcmx_field_entry_destroy(eid); 1318 if (BCM_FAILURE(retval)) { 1319 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1320 (BSL_META("ACL Error: Entry ID=%d not destroyed\n"), 1321 eid)); 1322 return retval; 1323 } 1324 return BCM_E_NONE; 1325 } 1326 prev = entry; 1327 entry = entry->next; 1328 } 1329 1330 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1331 (BSL_META("ACL Error: Entry ID=%d not found to be destroyed\n"), 1332 eid)); 1333 return BCM_E_NOT_FOUND; 1334 } 1335 1336 /* 1337 * Function: 1338 * _acl_field_entry_action_add 1339 * 1340 * Purpose: 1341 * Extract a rule's actions and add them to the Field entry. 1342 * 1343 * Parameters: 1344 * rule - ACL rule 1345 * eid - Field entry ID 1346 * 1347 * Returns: 1348 */ 1349 STATIC int 1350 _acl_field_entry_action_add(bcma_acl_rule_t *rule, 1351 bcm_field_entry_t eid) 1352 { 1353 assert(rule); 1354 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1355 (BSL_META("ACL _acl_field_entry_action_add(rule_id=%d, eid=%d)\n"), 1356 rule->rule_id, eid)); 1357 1358 /* Add Log if needed. */ 1359 if (rule->actions.flags & BCMA_ACL_ACTION_LOG) { 1360 BCM_IF_ERROR_RETURN( 1361 bcmx_field_action_add(eid, bcmFieldActionCopyToCpu, 0, 0)); 1362 } 1363 1364 /* Add Deny if needed. */ 1365 if (rule->actions.flags & BCMA_ACL_ACTION_DENY) { 1366 BCM_IF_ERROR_RETURN( 1367 bcmx_field_action_add(eid, bcmFieldActionDrop, 0, 0)); 1368 } 1369 1370 /* Add Redirect if needed. */ 1371 if (rule->actions.flags & BCMA_ACL_ACTION_REDIR) { 1372 BCM_IF_ERROR_RETURN( 1373 bcmx_field_action_add(eid, bcmFieldActionRedirect, 1374 rule->actions.redir_port, 0)); 1375 } 1376 1377 /* Add Mirror if needed. */ 1378 if (rule->actions.flags & BCMA_ACL_ACTION_MIRROR) { 1379 BCM_IF_ERROR_RETURN( 1380 bcmx_field_action_add(eid, bcmFieldActionMirrorIngress, 1381 rule->actions.mirror_port, 0)); 1382 } 1383 /* Do nothing for Permit. It's enough to have the entry match and prevent 1384 * later entries from matching. */ 1385 1386 return BCM_E_NONE; 1387 } 1388 1389 /* Section: Validation and Installation */ 1390 1391 #define _ACL_FIELD_MERGE_RECOVER(_op_) \ 1392 do { int _rv_; \ 1393 if ((_rv_ = (_op_)) < 0) { \ 1394 _acl_field_uninstall(); \ 1395 return _rv_; \ 1396 } \ 1397 } while(0); 1398 /* 1399 * Function: _acl_field_merge 1400 * 1401 * Purpose: 1402 * Build a solution ready to install in the hardware. The main purpose of 1403 * this is to test if the current set of ACLs will fit in hardware. 1404 * 1405 * Parameters: 1406 * 1407 * Returns: 1408 * BCM_E_NONE - Success 1409 * BCM_E_RESOURCE - Not enough hardware resources (groups) to support the 1410 * current ACLs. 1411 */ 1412 int 1413 _acl_field_merge(_acl_control_t *acl_control) 1414 { 1415 int retval; 1416 _acl_link_t *acl_link; 1417 bcma_acl_rule_t *rule; 1418 bcm_field_qset_t qset; 1419 _acl_field_group_t *group; 1420 bcmx_lplist_t lplist_full; 1421 _acl_rule_link_t *rule_link; 1422 1423 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1424 (BSL_META("ACL _acl_field_merge()\n"))); 1425 ACL_FIELD_IS_INIT(); 1426 1427 assert(acl_control != NULL); 1428 bcmx_lplist_init(&lplist_full, 0, 0); 1429 bcmx_port_lplist_populate(&lplist_full, BCMX_PORT_LP_ALL); 1430 1431 /* For each ACL */ 1432 for (acl_link = _acl_first(acl_control); 1433 acl_link != NULL; 1434 acl_link = _acl_next(acl_control)) 1435 { 1436 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1437 (BSL_META("ACL Merging ACL ID=%d\n"), 1438 acl_link->list->list_id)); 1439 1440 /* Start at first group. */ 1441 group = acl_field_control->group_list; 1442 1443 /* For each rule in list...*/ 1444 for (rule = _acl_rule_first(acl_link); 1445 rule != NULL; 1446 rule = _acl_rule_next(acl_link)) 1447 { 1448 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1449 (BSL_META("ACL Merging Rule ID=%d\n"), 1450 rule->rule_id)); 1451 /* Initialization of total number field entries used by this rule */ 1452 rule_link = _acl_rule_link_find(rule->rule_id); 1453 rule_link->entries = 0; 1454 1455 /* If current group can not support rule, try: 1456 * 1. add necessary qualifiers to current group if possible. 1457 * 2. Try the next group. 1458 * 3. Try creating a new group. 1459 * 4. If no groups are left, return error for resources. 1460 */ 1461 _ACL_FIELD_MERGE_RECOVER(_acl_field_rule_qset_get(rule, &qset)); 1462 if (!bcmx_lplist_eq(&acl_link->list->lplist, &lplist_full)) { 1463 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyInPorts); 1464 } 1465 1466 retval = BCM_E_RESOURCE; 1467 1468 while (group != NULL) { 1469 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1470 (BSL_META("ACL Setting group ID=%d\n"), 1471 group->gid)); 1472 retval = bcmx_field_group_set(group->gid, qset); 1473 1474 if (BCM_SUCCESS(retval)) { 1475 break; 1476 } 1477 1478 group = group->next; 1479 } 1480 1481 if (BCM_FAILURE(retval)) { 1482 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1483 (BSL_META("ACL Creating another group\n"))); 1484 retval = _acl_field_group_create(acl_field_control, qset, 1485 &group); 1486 if (BCM_FAILURE(retval)) { 1487 bcmx_lplist_free(&lplist_full); 1488 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1489 (BSL_META("ACL Error: Can't create group for rule_id=%d\n"), 1490 rule->rule_id)); 1491 return retval; 1492 } 1493 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1494 (BSL_META("ACL Group (gid=%d) created.\n"), 1495 group->gid)); 1496 } 1497 1498 /* Create FP entry(s) in current group to support rule.*/ 1499 retval =_acl_field_entry_create(group, acl_link->list, rule); 1500 1501 if (retval == BCM_E_CONFIG || retval == BCM_E_RESOURCE) { 1502 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1503 (BSL_META("ACL Creating another group\n"))); 1504 retval = _acl_field_group_create(acl_field_control, qset, 1505 &group); 1506 if (BCM_FAILURE(retval)) { 1507 bcmx_lplist_free(&lplist_full); 1508 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1509 (BSL_META("ACL Error: Can't create group for rule_id=%d\n"), 1510 rule->rule_id)); 1511 return retval; 1512 } 1513 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1514 (BSL_META("ACL Group (gid=%d) created.\n"), 1515 group->gid)); 1516 _ACL_FIELD_MERGE_RECOVER( 1517 _acl_field_entry_create(group, acl_link->list, rule)); 1518 } else { 1519 _ACL_FIELD_MERGE_RECOVER(retval); 1520 } 1521 } 1522 } 1523 1524 bcmx_lplist_free(&lplist_full); 1525 return BCM_E_NONE; 1526 } 1527 #undef _ACL_FIELD_MERGE_RECOVER 1528 1529 /* 1530 * Function: 1531 * _acl_field_rule_qset_get 1532 * 1533 * Purpose: 1534 * Calculate the Qset needed to support a rule. 1535 * 1536 * Parameters: 1537 * 1538 * Returns: 1539 * BCM_E_NONE - Success 1540 */ 1541 STATIC int 1542 _acl_field_rule_qset_get(bcma_acl_rule_t *rule, bcm_field_qset_t *qset) 1543 { 1544 assert(rule != NULL); 1545 assert(qset != NULL); 1546 1547 BCM_FIELD_QSET_INIT(*qset); 1548 1549 if (rule->flags & BCMA_ACL_RULE_L4_SRC_PORT || 1550 rule->flags & BCMA_ACL_RULE_L4_DST_PORT) { 1551 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyRangeCheck); 1552 } 1553 1554 if (rule->flags & BCMA_ACL_RULE_SRC_MAC) { 1555 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifySrcMac); 1556 } 1557 1558 if (rule->flags & BCMA_ACL_RULE_DST_MAC) { 1559 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyDstMac); 1560 } 1561 1562 if (rule->flags & BCMA_ACL_RULE_SRC_IP4) { 1563 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifySrcIp); 1564 } 1565 1566 if (rule->flags & BCMA_ACL_RULE_DST_IP4) { 1567 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyDstIp); 1568 } 1569 1570 if (rule->flags & BCMA_ACL_RULE_SRC_IP6) { 1571 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifySrcIp6); 1572 } 1573 1574 if (rule->flags & BCMA_ACL_RULE_DST_IP6) { 1575 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyDstIp6); 1576 } 1577 1578 if (rule->flags & BCMA_ACL_RULE_VLAN) { 1579 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyOuterVlan); 1580 } 1581 1582 if (rule->flags & BCMA_ACL_RULE_IPPROTOCOL) { 1583 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyIpProtocol); 1584 } 1585 1586 if (rule->flags & BCMA_ACL_RULE_ETHERTYPE) { 1587 BCM_FIELD_QSET_ADD(*qset, bcmFieldQualifyEtherType); 1588 } 1589 1590 return BCM_E_NONE; 1591 } 1592 1593 /* 1594 * Function: _acl_field_install 1595 * 1596 * Purpose: 1597 * Write current ACL solution to hardware. Take working solution calculated 1598 * by bcma_acl_merge() and commit it to hardware. This may be an expensive 1599 * operation if multiple rules must be shuffled to maintain atomicity. 1600 * 1601 * Parameters: 1602 * 1603 * Returns: 1604 * BCM_E_XXX - from bcmx_field_entry_install() 1605 * BCM_E_NONE - Success 1606 */ 1607 int 1608 _acl_field_install(void) 1609 { 1610 int retval; 1611 _acl_field_group_t *group; 1612 _acl_field_entry_t *entry; 1613 1614 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1615 (BSL_META("ACL _acl_field_install()\n"))); 1616 ACL_FIELD_IS_INIT(); 1617 1618 assert(acl_field_control != NULL); 1619 1620 /* For each group. */ 1621 for (group = acl_field_control->group_list; 1622 group != NULL; 1623 group = group->next) 1624 { 1625 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1626 (BSL_META("ACL: Installing Group ID=%d\n"), 1627 group->gid)); 1628 /* For each entry in group. */ 1629 for (entry = group->entry_list; entry != NULL; entry = entry->next) { 1630 /* Install the entry */ 1631 LOG_VERBOSE(BSL_LS_APPL_ACCESSCTRLLIST, 1632 (BSL_META("ACL: Installing Entry ID=%d\n"), 1633 entry->eid)); 1634 retval = bcmx_field_entry_install(entry->eid); 1635 if (BCM_FAILURE(retval)) { 1636 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1637 (BSL_META("ACL Error: ACL Field Entry ID=%d install failure.\n"), 1638 entry->eid)); 1639 return retval; 1640 } 1641 } 1642 } 1643 1644 return BCM_E_NONE; 1645 } 1646 1647 /* 1648 * Function: _acl_field_uninstall 1649 * 1650 * Purpose: 1651 * Remove the current set of ACLs from the hardware. This will also destroy 1652 * the field groups and entries in software. Since the field groups and 1653 * entries can always be reconstituted from the ACL rules. 1654 * 1655 * Parameters: 1656 * none 1657 * 1658 * Returns: 1659 * BCM_E_NONE 1660 */ 1661 int 1662 _acl_field_uninstall(void) 1663 { 1664 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1665 (BSL_META("ACL _acl_field_uninstall()\n"))); 1666 ACL_FIELD_IS_INIT(); 1667 1668 /* Remove the Field groups and entries from hardware. */ 1669 if (BCM_FAILURE(_acl_field_group_remove_all())) { 1670 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1671 (BSL_META("ACL Error: Failure in _acl_field_group_remove_all()\n"))); 1672 } 1673 1674 /* Deallocate the Field groups and entries from software. */ 1675 if (BCM_FAILURE(_acl_field_group_destroy_all())) { 1676 LOG_ERROR(BSL_LS_APPL_ACCESSCTRLLIST, 1677 (BSL_META("ACL Error: Failure in _acl_field_group_destroy_all()\n"))); 1678 } 1679 1680 return BCM_E_NONE; 1681 } 1682 1683 /* 1684 * Function: _acl_field_rule_remove 1685 * 1686 * Purpose: 1687 * Remove a single rule from hardware. In pratice this may mean removing 1688 * several Field entries. 1689 * 1690 * Parameters: 1691 * rule_id - ACL rule to remove from Field hardware 1692 * 1693 * Returns: 1694 * BCM_E_NONE - Success 1695 * BCM_E_NOT_FOUND - Rule ID not found 1696 */ 1697 int 1698 _acl_field_rule_remove(bcma_acl_rule_id_t rule_id) 1699 { 1700 int retval; 1701 _acl_field_group_t *group_cur; 1702 bcm_field_entry_t eid; 1703 1704 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1705 (BSL_META("ACL _acl_field_rule_remove(rule_id=%d)\n"), 1706 rule_id)); 1707 ACL_FIELD_IS_INIT(); 1708 1709 /* While there are still Field entries that support the Rule ID */ 1710 1711 retval = _acl_field_rule_entry_find(rule_id, &group_cur, &eid); 1712 while (BCM_SUCCESS(retval)) { 1713 /* Remove entry from hardware. */ 1714 BCM_IF_ERROR_RETURN(_acl_field_entry_destroy(group_cur, eid)); 1715 BCM_IF_ERROR_RETURN(_acl_field_entry_remove(group_cur, eid)); 1716 1717 retval = _acl_field_rule_entry_find(rule_id, &group_cur, 1718 &eid); 1719 } 1720 1721 if (retval != BCM_E_NOT_FOUND) { 1722 return retval; 1723 } 1724 1725 return BCM_E_NONE; 1726 } 1727 1728 /* 1729 * Function: _acl_field_rule_entry_find 1730 * 1731 * Purpose: 1732 * Find a Field Entry, along with its group, that supports a Rule ID. 1733 * 1734 * Parameters: 1735 * rule_id - rule ID to find 1736 * group - (OUT) ACL Field group that has entries supporting rule 1737 * eid - (OUT) Entry ID that supports rule 1738 * 1739 * Returns: 1740 * BCM_E_NONE - Success 1741 * BCM_E_NOT_FOUND - Rule ID not found 1742 */ 1743 STATIC int 1744 _acl_field_rule_entry_find(bcma_acl_rule_id_t rule_id, 1745 _acl_field_group_t **group_p, 1746 bcm_field_entry_t *eid) 1747 { 1748 _acl_field_entry_t *entry; 1749 1750 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1751 (BSL_META("ACL _acl_field_rule_entry_find(rule_id=%d)\n"), 1752 rule_id)); 1753 1754 /* For each group. */ 1755 for (*group_p = acl_field_control->group_list; 1756 *group_p != NULL; 1757 *group_p = (*group_p)->next) 1758 { 1759 /* For each entry in group. */ 1760 for (entry = (*group_p)->entry_list; entry != NULL; entry = entry->next) 1761 { 1762 /* If entry references rule. */ 1763 if (entry->rule->rule_id == rule_id) { 1764 *eid = entry->eid; 1765 return BCM_E_NONE; 1766 } 1767 } 1768 } 1769 1770 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1771 (BSL_META("ACL END _acl_field_rule_entry_find(rule_id=%d) NOT FOUND\n"), 1772 rule_id)); 1773 return BCM_E_NOT_FOUND; 1774 } 1775 1776 #ifdef BROADCOM_DEBUG 1777 1778 /* 1779 * Function: _acl_field_show 1780 * 1781 * Purpose: 1782 * Display the Field specific data for ACL. 1783 * 1784 * Parameters: 1785 * 1786 * Returns: 1787 * BCM_E_NONE - Success 1788 * BCM_E_XXX - return value from _acl_field_group_show() 1789 */ 1790 int 1791 _acl_field_show(void) { 1792 _acl_field_group_t *group; 1793 int group_count = 0; 1794 1795 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1796 (BSL_META("ACL _acl_field_show()\n"))); 1797 ACL_FIELD_IS_INIT(); 1798 1799 group = acl_field_control->group_list; 1800 while (group != NULL) { 1801 group = group->next; 1802 group_count++; 1803 } 1804 1805 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1806 (BSL_META("acl_field={group_numb=%d, "), 1807 group_count)); 1808 1809 /* Show groups used by ACLs. */ 1810 group = acl_field_control->group_list; 1811 1812 while (group != NULL) { 1813 BCM_IF_ERROR_RETURN(_acl_field_group_show(group)); 1814 group = group->next; 1815 } 1816 1817 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1818 (BSL_META("}\n"))); 1819 1820 return BCM_E_NONE; 1821 } 1822 1823 /* 1824 * Function: _acl_field_group_show 1825 * 1826 * Purpose: 1827 * Display a single access control list. 1828 * 1829 * Parameters: 1830 * group - group to desplay 1831 * 1832 * Returns: 1833 * BCM_E_NONE - Success 1834 * BCM_E_NOT_FOUND - List ID not found 1835 * BCM_E_XXX - return value from bcma_acl_rule_show() 1836 */ 1837 STATIC int 1838 _acl_field_group_show(_acl_field_group_t *group) 1839 { 1840 _acl_field_entry_t *entry; 1841 1842 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1843 (BSL_META("ACL _acl_field_group_show(gid=%d)\n"), 1844 group->gid)); 1845 assert(group != NULL); 1846 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1847 (BSL_META("\tgroup={gid=%d,\n"), 1848 group->gid)); 1849 1850 /* Show entries in this group.*/ 1851 entry = group->entry_list; 1852 while (entry != NULL) { 1853 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1854 (BSL_META("\t\t"))); 1855 BCM_IF_ERROR_RETURN(_acl_field_entry_show(entry)); 1856 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1857 (BSL_META("\n"))); 1858 entry = entry->next; 1859 } 1860 1861 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1862 (BSL_META("\t},\n"))); 1863 1864 return BCM_E_NONE; 1865 } 1866 1867 /* 1868 * Function: _acl_field_entry_show 1869 * 1870 * Purpose: 1871 * Display a single entry. 1872 * 1873 * Parameters: 1874 * entry - Field entry struct 1875 * 1876 * Returns: 1877 * BCM_E_NONE - Success 1878 */ 1879 STATIC int 1880 _acl_field_entry_show(_acl_field_entry_t *entry) 1881 { 1882 1883 assert(entry != NULL); 1884 LOG_DEBUG(BSL_LS_APPL_ACCESSCTRLLIST, 1885 (BSL_META("ACL _acl_field_entry_show(eid=%d)\n"), 1886 entry->eid)); 1887 LOG_INFO(BSL_LS_APPL_ACCESSCTRLLIST, 1888 (BSL_META("entry={eid=%d, rule_id=%d, pri=%d},"), 1889 entry->eid, 1890 entry->rule->rule_id, entry->prio)); 1891 1892 return BCM_E_NONE; 1893 } 1894 #endif /* BROADCOM_DEBUG */ 1895 #endif /* INCLUDE_ACL */