/**
 * @file IxEthDB_p.h
 *
 * @brief Private MAC learning API
 *
 * @par
 * IXP400 SW Release version 2.0
 *
 * -- Copyright Notice --
 *
 * @par
 * Copyright 2001-2005, Intel Corporation.
 * All rights reserved.
 *
 * @par
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Intel Corporation nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * @par
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * @par
 * -- End of Copyright Notice --
 */

#ifndef IxEthDB_p_H
#define IxEthDB_p_H

#include <IxTypes.h>
#include <IxOsal.h>
#include <IxEthDB.h>
#include <IxNpeMh.h>
#include <IxEthDBPortDefs.h>

#include "IxEthDBMessages_p.h"
#include "IxEthDBLog_p.h"

#if (CPU==SIMSPARCSOLARIS)

/* when running unit tests intLock() won't protect the event queue so we lock it manually */
#define TEST_FIXTURE_LOCK_EVENT_QUEUE   { ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER); }
#define TEST_FIXTURE_UNLOCK_EVENT_QUEUE { ixOsalMutexUnlock(&eventQueueLock); }

#else

#define TEST_FIXTURE_LOCK_EVENT_QUEUE   /* nothing */
#define TEST_FIXTURE_UNLOCK_EVENT_QUEUE /* nothing */

#endif /* #if(CPU==SIMSPARCSOLARIS) */

#ifndef IX_UNIT_TEST

#define TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER /* nothing */
#define TEST_FIXTURE_MARK_OVERFLOW_EVENT              /* nothing */

#else

extern int dbAccessCounter;
extern int overflowEvent;

#define TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER { dbAccessCounter++; }
#define TEST_FIXTURE_MARK_OVERFLOW_EVENT              { overflowEvent = 1; }

#endif

/* code readability markers */
#define __mempool__      /* memory pool marker */
#define __lock__         /* hash write locking marker */
#define __smartpointer__ /* smart pointer marker - warning: use only clone() when duplicating! */
#define __alignment__    /* marker for data used only as alignment zones */

/* constants */
#define IX_ETH_DB_NPE_TIMEOUT (100) /* NPE response timeout, in ms */

/**
 * number of hash table buckets
 * it should be at least 8x the predicted number of entries for performance
 * each bucket needs 8 bytes
 */
#define NUM_BUCKETS (8192)

/**
 * number of hash table buckets to preload when incrementing bucket iterator
 * = two cache lines
 */
#define IX_ETHDB_CACHE_LINE_AHEAD (2)

#define IX_ETHDB_BUCKETPTR_AHEAD  ((IX_ETHDB_CACHE_LINE_AHEAD * IX_OSAL_CACHE_LINE_SIZE)/sizeof(void *))

#define IX_ETHDB_BUCKET_INDEX_MASK   (((IX_OSAL_CACHE_LINE_SIZE)/sizeof(void *)) - 1)

/* locks */
#define MAX_LOCKS (20) /**< maximum number of locks used simultaneously, do not tamper with */

/* learning tree constants */
#define INITIAL_ELT_SIZE    (8)                              /**< initial byte size of tree (empty unused root size) */
#define MAX_ELT_SIZE        (512)                            /**< maximum number of entries (includes unused root) */
#define MAX_GW_SIZE         (32)                             /**< maximum number of gateway entries (including unused root) */
#define MAX_FW_SIZE         (32)                             /**< maximum number of firewall entries (including unused root) */
#define ELT_ENTRY_SIZE      (8)                              /**< entry size, in bytes */
#define ELT_ROOT_OFFSET     (ELT_ENTRY_SIZE)                 /**< tree root offset, in bytes - node preceeding root is unused */
#define FULL_ELT_BYTE_SIZE  (MAX_ELT_SIZE * ELT_ENTRY_SIZE)  /**< full size of tree, in bytes, including unused root */
#define FULL_GW_BYTE_SIZE   (MAX_GW_SIZE * ELT_ENTRY_SIZE)   /**< full size of gateway list, in bytes, including unused root */
#define FULL_FW_BYTE_SIZE   (MAX_FW_SIZE * ELT_ENTRY_SIZE)   /**< full size of firewall table, in bytes, including unused root */

/* maximum size of the VLAN table:
 * 4096 bits (one per VLAN)
 * 8 bits in one byte
 * interleaved VLAN membership and VLAN TTI (*2) */
#define FULL_VLAN_BYTE_SIZE (4096 / 8 * 2)

/* upper 9 bits used as set index, lower 3 bits as byte index */
#define VLAN_SET_OFFSET(vlanID) ((vlanID) >> 3)
#define VLAN_SET_MASK(vlanID)   (0x7 - ((vlanID) & 0x7))

/* Update zone definitions */
#define NPE_TREE_MEM_SIZE (4096) /* ((511 entries + 1 unused root) * 8 bytes/entry) */

/* check the above value, we rely on 4k */
#if NPE_TREE_MEM_SIZE != 4096
    #error NPE_TREE_MEM_SIZE is not defined to 4096 bytes!
#endif

/* Size Filtering limits (Jumbo frame filtering) */
#define IX_ETHDB_MAX_FRAME_SIZE     65535 /* other ports than NPE ports */
#define IX_ETHDB_MIN_FRAME_SIZE         1 /* other ports than NPE ports */
#define IX_ETHDB_MAX_NPE_FRAME_SIZE 16320 /* NPE ports firmware limit */
#define IX_ETHDB_MIN_NPE_FRAME_SIZE     1 /* NPE ports firmware limit */
#define IX_ETHDB_DEFAULT_FRAME_SIZE  1522

/* memory management pool sizes  */

/*
 * Note:
 *
 * NODE_POOL_SIZE controls the maximum number of elements in the database at any one time.
 * It should be large enough to cover all the search trees of all the ports simultaneously.
 *
 * MAC_POOL_SIZE should be higher than NODE_POOL_SIZE by at least the total number of MAC addresses
 * possible to be held at any time in all the ports.
 *
 * TREE_POOL_SIZE should follow the same guideline as for MAC_POOL_SIZE.
 *
 * The database structure described here (2000/4000/4000) is enough for two NPEs holding at most 511
 * entries each plus one PCI NIC holding at most 900 entries.
 */

#define NODE_POOL_SIZE (2000) /**< number of HashNode objects - also master number of elements in the database; each entry has 16 bytes */
#define MAC_POOL_SIZE  (4000) /**< number of MacDescriptor objects; each entry has 28 bytes */
#define TREE_POOL_SIZE (4000) /**< number of MacTreeNode objects; each entry has 16 bytes */

/* retry policies */
#define BUSY_RETRY_ENABLED (TRUE)  /**< if set to TRUE the API will retry automatically calls returning BUSY */
#define FOREVER_RETRY      (TRUE)  /**< if set to TRUE the API will retry forever BUSY calls */
#define MAX_RETRIES        (400)   /**< upper retry limit - used only when FOREVER_RETRY is FALSE */
#define BUSY_RETRY_YIELD   (5)     /**< ticks to yield for every failed retry */

/* event management */
#define EVENT_QUEUE_SIZE       (500) /**< size of the sink collecting events from the Message Handler FIFO */
#define EVENT_PROCESSING_LIMIT (100)  /**< batch processing control size (how many events are extracted from the queue at once) */

/* MAC descriptors */
#define STATIC_ENTRY  (TRUE)
#define DYNAMIC_ENTRY (FALSE)

/* age reset on next maintenance - incrementing by 1 will reset to 0 */
#define AGE_RESET (0xFFFFFFFF)

/* dependency maps */
#define EMPTY_DEPENDENCY_MAP (0)

/* trees */
#define RIGHT (1)
#define LEFT  (-1)

/* macros */
#define IX_ETH_DB_CHECK_PORT_EXISTS(portID) \
{ \
    if ((portID) >= IX_ETH_DB_NUMBER_OF_PORTS) \
    { \
        return IX_ETH_DB_INVALID_PORT; \
    } \
}

#define IX_ETH_DB_CHECK_PORT_INITIALIZED(portID) \
{ \
    if ((portID) >= IX_ETH_DB_NUMBER_OF_PORTS) \
    { \
        return IX_ETH_DB_INVALID_PORT; \
    } \
    else \
    { \
        if (!ixEthDBPortInfo[portID].initialized) \
        { \
            return IX_ETH_DB_PORT_UNINITIALIZED; \
        } \
    } \
}

/* single NPE check */
#define IX_ETH_DB_CHECK_SINGLE_NPE(portID) \
    if (ixEthDBSingleEthNpeCheck(portID) != IX_ETH_DB_SUCCESS) \
    { \
        WARNING_LOG("EthDB: port ID %d is unavailable\n",(UINT32) portID); \
        \
        return IX_ETH_DB_INVALID_PORT; \
    }

/* feature check */
#define IX_ETH_DB_CHECK_FEATURE(portID, feature) \
    if ((ixEthDBPortInfo[portID].featureStatus & feature) == 0) \
    { \
        return IX_ETH_DB_FEATURE_UNAVAILABLE; \
    }

/* busy retrying */
#define BUSY_RETRY(functionCall) \
    { \
        UINT32 retries = 0; \
        IxEthDBStatus br_result; \
        \
        while ((br_result = functionCall) == IX_ETH_DB_BUSY \
            && BUSY_RETRY_ENABLED && (FOREVER_RETRY || ++retries < MAX_RETRIES)) { ixOsalSleep(BUSY_RETRY_YIELD); }; \
        \
        if ((!FOREVER_RETRY && retries == MAX_RETRIES) || (br_result == IX_ETH_DB_FAIL)) \
        {\
            ERROR_LOG("Ethernet Learning Database Error: BUSY_RETRY failed at %s:%d\n", __FILE__, __LINE__); \
        }\
    }

#define BUSY_RETRY_WITH_RESULT(functionCall, brwr_result) \
    { \
        UINT32 retries = 0; \
        \
        while ((brwr_result = functionCall) == IX_ETH_DB_BUSY \
            && BUSY_RETRY_ENABLED && (FOREVER_RETRY || ++retries < MAX_RETRIES)) { ixOsalSleep(BUSY_RETRY_YIELD); }; \
        \
        if ((!FOREVER_RETRY && retries == MAX_RETRIES) || (brwr_result == IX_ETH_DB_FAIL)) \
        {\
            ERROR_LOG("Ethernet Learning Database Error: BUSY_RETRY_WITH_RESULT failed at %s:%d\n", __FILE__, __LINE__); \
        }\
    }

/* iterators */
#define IS_ITERATOR_VALID(iteratorPtr) ((iteratorPtr)->node != NULL)

/* dependency port maps */

/* Warning: if port indexing starts from 1 replace (portID) with (portID - 1) in DEPENDENCY_MAP (and make sure IX_ETH_DB_NUMBER_OF_PORTS is big enough) */

/* gives an empty dependency map */
#define SET_EMPTY_DEPENDENCY_MAP(map)      { int i = 0; for (; i < 32 ; i++) map[i] = 0; }

#define IS_EMPTY_DEPENDENCY_MAP(result, map)       { int i = 0 ; result = TRUE; for (; i < 32 ; i++) if (map[i] != 0) { result = FALSE; break; }}

/**
 * gives a map consisting only of 'portID'
 */
#define SET_DEPENDENCY_MAP(map, portID)    {SET_EMPTY_DEPENDENCY_MAP(map); map[portID >> 3] = 1 << (portID & 0x7);}

/**
 * gives a map resulting from joining map1 and map2
 */
#define JOIN_MAPS(map, map1, map2)         { int i = 0; for (; i < 32 ; i++) map[i] = map1[i] | map2[i]; }

/**
 * gives the map resulting from joining portID and map
 */
#define JOIN_PORT_TO_MAP(map, portID)      { map[portID >> 3] |= 1 << (portID & 0x7); }

/**
 * gives the map resulting from excluding portID from map
 */
#define EXCLUDE_PORT_FROM_MAP(map, portID) { map[portID >> 3] &= ~(1 << (portID & 0x7); }

/**
 * returns TRUE if map1 is a subset of map2 and FALSE otherwise
 */
#define IS_MAP_SUBSET(result, map1, map2)  { int i = 0; result = TRUE; for (; i < 32 ; i++) if ((map1[i] | map2[i]) != map2[i]) result = FALSE; }

/**
 * returns TRUE is portID is part of map and FALSE otherwise
 */
#define IS_PORT_INCLUDED(portID, map)      ((map[portID >> 3] & (1 << (portID & 0x7))) != 0)

/**
 * returns the difference between map1 and map2 (ports included in map1 and not included in map2)
 */
#define DIFF_MAPS(map, map1, map2)         { int i = 0; for (; i < 32 ; i++) map[i] = map1[i] ^ (map1[i] & map2[i]); }

/**
 * returns TRUE if the maps collide (have at least one port in common) and FALSE otherwise
 */
#define MAPS_COLLIDE(result, map1, map2)   { int i = 0; result = FALSE; for (; i < 32 ; i++) if ((map1[i] & map2[i]) != 0) result = TRUE; }

/* size (number of ports) of a dependency map */
#define GET_MAP_SIZE(map, size)            { int i = 0, b = 0; size = 0; for (; i < 32 ; i++) { char y = map[i]; for (; b < 8 && (y >>= 1); b++) size += (y & 1); }}

/* copy map2 into map1 */
#define COPY_DEPENDENCY_MAP(map1, map2)    { memcpy (map1, map2, sizeof (map1)); }

/* definition of a port map size/port number which cannot be reached (we support at most 32 ports) */
#define MAX_PORT_SIZE   (0xFF)
#define MAX_PORT_NUMBER (0xFF)

#define IX_ETH_DB_CHECK_REFERENCE(ptr)   { if ((ptr) == NULL) { return IX_ETH_DB_INVALID_ARG; } }
#define IX_ETH_DB_CHECK_MAP(portID, map) { if (!IS_PORT_INCLUDED(portID, map)) { return IX_ETH_DB_INVALID_ARG; } }

/* event queue macros */
#define EVENT_QUEUE_WRAP(offset)            ((offset) >= EVENT_QUEUE_SIZE ? (offset) - EVENT_QUEUE_SIZE : (offset))

#define CAN_ENQUEUE(eventQueuePtr)          ((eventQueuePtr)->length < EVENT_QUEUE_SIZE)

#define QUEUE_HEAD(eventQueuePtr)           (&(eventQueuePtr)->queue[EVENT_QUEUE_WRAP((eventQueuePtr)->base + (eventQueuePtr)->length)])

#define QUEUE_TAIL(eventQueuePtr)           (&(eventQueuePtr)->queue[(eventQueuePtr)->base])

#define PUSH_UPDATE_QUEUE(eventQueuePtr)    { (eventQueuePtr)->length++; }

#define SHIFT_UPDATE_QUEUE(eventQueuePtr) \
        { \
            (eventQueuePtr)->base = EVENT_QUEUE_WRAP((eventQueuePtr)->base + 1); \
            (eventQueuePtr)->length--; \
        }

#define RESET_QUEUE(eventQueuePtr) \
    { \
        (eventQueuePtr)->base   = 0; \
        (eventQueuePtr)->length = 0; \
    }

/* node stack macros - used to browse a tree without using a recursive function */
#define NODE_STACK_INIT(stack)               { (stack)->nodeCount = 0; }
#define NODE_STACK_PUSH(stack, node, offset) { (stack)->nodes[(stack)->nodeCount] = (node); (stack)->offsets[(stack)->nodeCount++] = (offset); }
#define NODE_STACK_POP(stack, node, offset)  { (node) = (stack)->nodes[--(stack)->nodeCount]; offset = (stack)->offsets[(stack)->nodeCount]; }
#define NODE_STACK_NONEMPTY(stack)           ((stack)->nodeCount != 0)

#ifndef IX_NDEBUG
#define IX_ETH_DB_NPE_MSG_HISTORY_DEPTH (100)
#define LOG_NPE_MSG(msg) \
    do { \
        UINT32 npeMsgHistoryIndex = (npeMsgHistoryLen++) % IX_ETH_DB_NPE_MSG_HISTORY_DEPTH; \
        npeMsgHistory[npeMsgHistoryIndex][0] = msg.data[0]; \
        npeMsgHistory[npeMsgHistoryIndex][1] = msg.data[1]; \
    } while (0);
#else
#define LOG_NPE_MSG() /* nothing */
#endif

/* ----------- Data -------------- */

/* typedefs */

typedef UINT32 (*HashFunction)(void *entity);
typedef BOOL (*MatchFunction)(void *reference, void *entry);
typedef void (*FreeFunction)(void *entry);

/**
 * basic component of a hash table
 */
typedef struct HashNode_t
{
    void *data;                                 /**< specific data */
    struct HashNode_t *next;                    /**< used for bucket chaining */

    __mempool__ struct HashNode_t *nextFree;    /**< memory pool management */

    __lock__ IxOsalFastMutex lock;              /**< node lock */
} HashNode;

/**
 * @brief hash table iterator definition
 *
 * an iterator is an object which can be used
 * to browse a hash table
 */
typedef struct
{
    UINT32 bucketIndex;     /**< index of the currently iterated bucket */
    HashNode *previousNode; /**< reference to the previously iterated node within the current bucket */
    HashNode *node;         /**< reference to the currently iterated node */
} HashIterator;

/**
 * definition of a MAC descriptor (a database record)
 */

typedef enum
{
    IX_ETH_DB_WIFI_AP_TO_STA = 0x0,
    IX_ETH_DB_WIFI_AP_TO_AP  = 0x1
} IxEthDBWiFiRecordType;

typedef union
{
    struct
    {
        UINT32 age;
        BOOL staticEntry; /**< TRUE if this address is static (doesn't age) */
    } filteringData;

    struct
    {
        UINT32 age;
        BOOL staticEntry;
        UINT32 ieee802_1qTag;
      } filteringVlanData;

    struct
    {
        IxEthDBWiFiRecordType type;  /**< AP_TO_AP (0x1) or AP_TO_STA (0x0) */
        UINT32 gwAddressIndex; /**< used only when linearizing the entries for NPE usage */
        UINT8 gwMacAddress[IX_IEEE803_MAC_ADDRESS_SIZE];

        __alignment__ UINT8 reserved2[2];
    } wifiData;
} IxEthDBRecordData;

typedef struct MacDescriptor_t
{
    UINT8 macAddress[IX_IEEE803_MAC_ADDRESS_SIZE];

    __alignment__ UINT8 reserved1[2];

    UINT32 portID;
    IxEthDBRecordType type;
    IxEthDBRecordData recordData;

    /* used for internal operations, such as NPE linearization */
    void *internal;

    /* custom user data */
    void *user;

    __mempool__ struct MacDescriptor_t *nextFree;   /**< memory pool management */
    __smartpointer__ UINT32 refCount;               /**< smart pointer reference counter */
} MacDescriptor;

/**
 * hash table definition
 */
typedef struct
{
    HashNode *hashBuckets[NUM_BUCKETS];
    UINT32 numBuckets;

    __lock__ IxOsalFastMutex bucketLocks[NUM_BUCKETS];

    HashFunction entryHashFunction;
    MatchFunction *matchFunctions;
    FreeFunction freeFunction;
} HashTable;

typedef enum
{
    IX_ETH_DB_MAC_KEY       = 1,
    IX_ETH_DB_MAC_PORT_KEY  = 2,
    IX_ETH_DB_MAC_VLAN_KEY  = 3,
    IX_ETH_DB_MAX_KEY_INDEX = 3
} IxEthDBSearchKeyType;

typedef struct MacTreeNode_t
{
    __smartpointer__  MacDescriptor *descriptor;
    struct MacTreeNode_t *left, *right;

    __mempool__ struct MacTreeNode_t *nextFree;
} MacTreeNode;

typedef IxEthDBStatus (*IxEthDBPortUpdateHandler)(IxEthDBPortId portID, IxEthDBRecordType type);

typedef void (*IxEthDBNoteWriteFn)(void *address, MacTreeNode *node);

typedef struct
{
    BOOL updateEnabled;                         /**< TRUE if updates are enabled for port */
    BOOL userControlled;                        /**< TRUE if the user has manually used ixEthDBPortUpdateEnableSet */
    BOOL treeInitialized;                       /**< TRUE if the NPE has received an initial tree */
    IxEthDBPortUpdateHandler updateHandler;     /**< port update handler routine */
    void *npeUpdateZone;                        /**< port update memory zone */
    void *npeGwUpdateZone;                      /**< port update memory zone for gateways */
    void *vlanUpdateZone;                       /**< port update memory zone for VLAN tables */
    MacTreeNode *searchTree;                    /**< internal search tree, in MacTreeNode representation */
    BOOL searchTreePendingWrite;                /**< TRUE if searchTree holds a tree pending write to the port */
} PortUpdateMethod;

typedef struct
{
    IxEthDBPortId portID;                   /**< port ID */
    BOOL enabled;                           /**< TRUE if the port is enabled */
    BOOL agingEnabled;                      /**< TRUE if aging on this port is enabled */
    BOOL initialized;
    IxEthDBPortMap dependencyPortMap;       /**< dependency port map for this port */
    PortUpdateMethod updateMethod;          /**< update method structure */
    BOOL macAddressUploaded;                /**< TRUE if the MAC address was uploaded into the port */
    UINT32 maxRxFrameSize;                  /**< maximum Rx frame size for this port */
    UINT32 maxTxFrameSize;                  /**< maximum Rx frame size for this port */

    UINT8 bbsid[6];
    __alignment__ UINT8 reserved[2];
    UINT32 frameControlDurationID;          /**< Frame Control - Duration/ID WiFi control */

    IxEthDBVlanTag vlanTag;                  /**< default VLAN tag for port */
    IxEthDBPriorityTable priorityTable;     /**< QoS <=> internal priority mapping */
    IxEthDBVlanSet vlanMembership;
    IxEthDBVlanSet transmitTaggingInfo;
    IxEthDBFrameFilter frameFilter;
    IxEthDBTaggingAction taggingAction;

    UINT32 npeFrameFilter;
    UINT32 npeTaggingAction;

    IxEthDBFirewallMode firewallMode;
    BOOL srcAddressFilterEnabled;

    BOOL stpBlocked;

    IxEthDBFeature featureCapability;
    IxEthDBFeature featureStatus;

    UINT32 ixEthDBTrafficClassAQMAssignments[IX_IEEE802_1Q_QOS_PRIORITY_COUNT];

    UINT32 ixEthDBTrafficClassCount;

    UINT32 ixEthDBTrafficClassAvailable;



    __lock__ IxOsalMutex npeAckLock;
} PortInfo;

/* list of port information structures indexed on port Ids */
extern IX_ETH_DB_PUBLIC PortInfo ixEthDBPortInfo[IX_ETH_DB_NUMBER_OF_PORTS];

typedef enum
{
    IX_ETH_DB_ADD_FILTERING_RECORD    = 0xFF0001,
    IX_ETH_DB_REMOVE_FILTERING_RECORD = 0xFF0002
} PortEventType;

typedef struct
{
    UINT32 eventType;
    IxEthDBPortId portID;
    IxEthDBMacAddr macAddr;
    BOOL staticEntry;
} PortEvent;

typedef struct
{
    PortEvent queue[EVENT_QUEUE_SIZE];
    UINT32 base;
    UINT32 length;
} PortEventQueue;

typedef struct
{
    IxEthDBPortId portID; /**< originating port */
    MacDescriptor *macDescriptors[MAX_ELT_SIZE]; /**< addresses to be synced into db */
    UINT32 addressCount; /**< number of addresses */
} TreeSyncInfo;

typedef struct
{
    MacTreeNode *nodes[MAX_ELT_SIZE];
    UINT32 offsets[MAX_ELT_SIZE];
    UINT32 nodeCount;
} MacTreeNodeStack;

/* Prototypes */

/* ----------- Memory management -------------- */

IX_ETH_DB_PUBLIC void ixEthDBInitMemoryPools(void);

IX_ETH_DB_PUBLIC HashNode* ixEthDBAllocHashNode(void);
IX_ETH_DB_PUBLIC void ixEthDBFreeHashNode(HashNode *);

IX_ETH_DB_PUBLIC __smartpointer__ MacDescriptor* ixEthDBAllocMacDescriptor(void);
IX_ETH_DB_PUBLIC __smartpointer__ MacDescriptor* ixEthDBCloneMacDescriptor(MacDescriptor *macDescriptor);
IX_ETH_DB_PUBLIC __smartpointer__ void ixEthDBFreeMacDescriptor(MacDescriptor *);

IX_ETH_DB_PUBLIC __smartpointer__ MacTreeNode* ixEthDBAllocMacTreeNode(void);
IX_ETH_DB_PUBLIC __smartpointer__ MacTreeNode* ixEthDBCloneMacTreeNode(MacTreeNode *);
IX_ETH_DB_PUBLIC __smartpointer__ void ixEthDBFreeMacTreeNode(MacTreeNode *);

IX_ETH_DB_PUBLIC void ixEthDBPoolFreeMacTreeNode(MacTreeNode *);
IX_ETH_DB_PUBLIC UINT32 ixEthDBSearchTreeUsageGet(MacTreeNode *tree);
IX_ETH_DB_PUBLIC int ixEthDBShowMemoryStatus(void);

/* Hash Table */
IX_ETH_DB_PUBLIC void ixEthDBInitHash(HashTable *hashTable, UINT32 numBuckets, HashFunction entryHashFunction, MatchFunction *matchFunctions, FreeFunction freeFunction);

IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBAddHashEntry(HashTable *hashTable, void *entry);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBRemoveHashEntry(HashTable *hashTable, int keyType, void *reference);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBSearchHashEntry(HashTable *hashTable, int keyType, void *reference, HashNode **searchResult);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPeekHashEntry(HashTable *hashTable, int keyType, void *reference);
IX_ETH_DB_PUBLIC void ixEthDBReleaseHashNode(HashNode *node);

IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBInitHashIterator(HashTable *hashTable, HashIterator *iterator);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBIncrementHashIterator(HashTable *hashTable, HashIterator *iterator);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBRemoveEntryAtHashIterator(HashTable *hashTable, HashIterator *iterator);
IX_ETH_DB_PUBLIC void ixEthDBReleaseHashIterator(HashIterator *iterator);

/* API Support */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPortAddressSet(IxEthDBPortId portID, IxEthDBMacAddr *macAddr);
IX_ETH_DB_PUBLIC void ixEthDBMaximumFrameSizeAckCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);

/* DB Core functions */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBInit(void);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBAdd(MacDescriptor *newRecordTemplate, IxEthDBPortMap updateTrigger);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBRemove(MacDescriptor *templateRecord, IxEthDBPortMap updateTrigger);
IX_ETH_DB_PUBLIC HashNode* ixEthDBSearch(IxEthDBMacAddr *macAddress, IxEthDBRecordType typeFilter);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPeek(IxEthDBMacAddr *macAddress, IxEthDBRecordType typeFilter);

/* Learning support */
IX_ETH_DB_PUBLIC UINT32 ixEthDBAddressCompare(UINT8 *mac1, UINT8 *mac2);
IX_ETH_DB_PUBLIC BOOL ixEthDBAddressMatch(void *reference, void *entry);
IX_ETH_DB_PUBLIC UINT32 ixEthDBEntryXORHash(void *macDescriptor);
IX_ETH_DB_PUBLIC UINT32 ixEthDBKeyXORHash(void *macAddress);

/* Port updates */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBNPEUpdateHandler(IxEthDBPortId portID, IxEthDBRecordType type);
IX_ETH_DB_PUBLIC void ixEthDBUpdatePortLearningTrees(IxEthDBPortMap triggerPorts);
IX_ETH_DB_PUBLIC void ixEthDBNPEAccessRequest(IxEthDBPortId portID);
IX_ETH_DB_PUBLIC void ixEthDBUpdateLock(void);
IX_ETH_DB_PUBLIC void ixEthDBUpdateUnlock(void);
IX_ETH_DB_PUBLIC MacTreeNode* ixEthDBQuery(MacTreeNode *searchTree, IxEthDBPortMap query, IxEthDBRecordType recordFilter, UINT32 maximumEntries);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBFirewallUpdate(IxEthDBPortId portID, void *address, UINT32 epDelta);

/* Init/unload */
IX_ETH_DB_PUBLIC void ixEthDBPortSetAckCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBEventProcessorInit(void);
IX_ETH_DB_PUBLIC void ixEthDBPortInit(IxEthDBPortId portID);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPortEnable(IxEthDBPortId portID);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPortDisable(IxEthDBPortId portID);
IX_ETH_DB_PUBLIC void ixEthDBNPEUpdateAreasInit(void);
IX_ETH_DB_PUBLIC UINT32 ixEthDBMatchMethodsRegister(MatchFunction *matchFunctions);
IX_ETH_DB_PUBLIC UINT32 ixEthDBRecordSerializeMethodsRegister(void);
IX_ETH_DB_PUBLIC UINT32 ixEthDBUpdateTypeRegister(BOOL *typeArray);
IX_ETH_DB_PUBLIC void ixEthDBNPEUpdateAreasUnload(void);
IX_ETH_DB_PUBLIC void ixEthDBFeatureCapabilityScan(void);
IX_ETH_DB_PUBLIC UINT32 ixEthDBKeyTypeRegister(UINT32 *keyType);

/* Event processing */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBDefaultEventCallbackEnable(IxEthDBPortId portID, BOOL enable);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID);
IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);

/* NPE adaptor */
IX_ETH_DB_PUBLIC void ixEthDBGetMacDatabaseCbk(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
IX_ETH_DB_PUBLIC void ixEthDBNpeMsgAck(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
IX_ETH_DB_PUBLIC void ixEthDBNPESyncScan(IxEthDBPortId portID, void *eltBaseAddress, UINT32 eltSize);
IX_ETH_DB_PUBLIC void ixEthDBNPETreeWrite(IxEthDBRecordType type, UINT32 totalSize, void *baseAddress, MacTreeNode *tree, UINT32 *blocks, UINT32 *startIndex);
IX_ETH_DB_PUBLIC void ixEthDBNPEGatewayNodeWrite(void *address, MacTreeNode *node);

/* Other public API functions */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPortUpdateEnableSet(IxEthDBPortId portID, BOOL enableUpdate);

/* Maximum Tx/Rx public functions */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBFilteringPortMaximumRxFrameSizeSet(IxEthDBPortId portID, UINT32 maximumRxFrameSize);
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBFilteringPortMaximumTxFrameSizeSet(IxEthDBPortId portID, UINT32 maximumTxFrameSize);

/* VLAN-related */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPortVlanTableSet(IxEthDBPortId portID, IxEthDBVlanSet portVlanTable, IxEthDBVlanSet vlanSet);

/* Record search */
IX_ETH_DB_PUBLIC BOOL ixEthDBAddressRecordMatch(void *untypedReference, void *untypedEntry);
IX_ETH_DB_PUBLIC BOOL ixEthDBVlanRecordMatch(void *untypedReference, void *untypedEntry);
IX_ETH_DB_PUBLIC BOOL ixEthDBPortRecordMatch(void *untypedReference, void *untypedEntry);
IX_ETH_DB_PUBLIC BOOL ixEthDBNullMatch(void *reference, void *entry);
IX_ETH_DB_PUBLIC HashNode* ixEthDBPortSearch(IxEthDBMacAddr *macAddress, IxEthDBPortId portID, IxEthDBRecordType typeFilter);
IX_ETH_DB_PUBLIC HashNode* ixEthDBVlanSearch(IxEthDBMacAddr *macAddress, IxEthDBVlanId vlanID, IxEthDBRecordType typeFilter);

/* Utilities */
IX_ETH_DB_PUBLIC const char* mac2string(const unsigned char *mac);
IX_ETH_DB_PUBLIC void showHashInfo(void);
IX_ETH_DB_PUBLIC int ixEthDBAnalyzeHash(void);
IX_ETH_DB_PUBLIC const char* errorString(IxEthDBStatus error);
IX_ETH_DB_PUBLIC int numHashElements(void);
IX_ETH_DB_PUBLIC void zapHashtable(void);
IX_ETH_DB_PUBLIC BOOL ixEthDBCheckSingleBitValue(UINT32 value);

/* Single Eth NPE Check */
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBSingleEthNpeCheck(IxEthDBPortId portId);

#endif /* IxEthDB_p_H */

