openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 */