blob: 2a84cd0e5a62eb03e0744bfe9d54a8b5925f1aa1 [file] [log] [blame]
/******************************************************************************
*
* <:copyright-BRCM:2016:DUAL/GPL:standard
*
* Copyright (c) 2016 Broadcom
* All Rights Reserved
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed
* to you under the terms of the GNU General Public License version 2
* (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
* with the following added to such license:
*
* As a special exception, the copyright holders of this software give
* you permission to link this software with independent modules, and
* to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from this
* software. The special exception does not apply to any modifications
* of the software.
*
* Not withstanding the above, under no circumstances may you combine
* this software in any way with any other Broadcom software provided
* under a license other than the GPL, without Broadcom's express prior
* written consent.
*
* :>
*
*****************************************************************************/
/**
* @file bal_mac_util_db_apis.c
*
* @brief This file has the wrapper functions and the calls to database API functions.
* These wrapper functions are called by mac util code for DB operations.
*
* @addtogroup mac_util
*/
/*@{*/
#include <bal_mac_util.h>
/**
* @brief flow DB macros
* */
/** @brief max number of flow types stored in the DB.
* @details for now upstream & downstream unicast flows only are stored in the flow DB
* */
#define MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES 2
/** @brief check if flow type key is valid */
#define MAC_UTIL_FLOW_DB_FLOW_TYPE_IS_VALID(_flow_type) \
((_flow_type) >= BCMBAL_FLOW_TYPE_UPSTREAM && \
(_flow_type) <= MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES) \
/**
* @brief maps {flow Id, flow_type} Key pair to an {Index, sub-Index} pair to access a flow entry in the Array DB.
* */
#define MAC_UTIL_FLOW_DB_FLOW_ID_TYPE2ARR_INDEX_SUB_INDEX(_flow_id, _flow_type, _index, _sub_index) \
do \
{ \
(_index) = (_sub_index) = 0; \
if(MAC_UTIL_FLOW_DB_FLOW_ID_IS_VALID(_flow_id)) \
{ \
if(MAC_UTIL_FLOW_DB_FLOW_TYPE_IS_VALID(_flow_type)) \
{ \
(_index) = (_flow_id) - mac_util_flow_id_start_val+1; \
(_sub_index) = (_flow_type) - 1; \
} \
} \
} while (0);
/** @brief lookup an entry from the Array based on flow Id & type key pair */
#define MAC_UTIL_FLOW_DB_ENTRY_GET(_flow_id, _flow_type, _flow_entry) \
do \
{ \
(_flow_entry) = NULL; \
uint32_t _index, _sub_index; \
MAC_UTIL_FLOW_DB_FLOW_ID_TYPE2ARR_INDEX_SUB_INDEX((_flow_id), (_flow_type), (_index), (_sub_index)); \
if (!_index) \
break; \
_flow_entry = mac_util_db_flows_list[_index][_sub_index]; \
} while (0);
/** @brief Get First non-NULL flow entry from the Array */
#define MAC_UTIL_FLOW_DB_ENTRY_GET_FIRST(_p_first) \
do \
{ \
int _i, _j; \
for (_i=1; _i<=BAL_ACC_TERM_MAX_FLOWS; _i++) \
{ \
for (_j=0; _j<MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES; _j++) \
{ \
(_p_first) = mac_util_db_flows_list[_i][_j]; \
if (_p_first) \
break; \
} \
if (_p_first) \
break; \
} \
} while (0)
/** @brief Get Next non-NULL flow entry from the Array */
#define MAC_UTIL_FLOW_DB_ENTRY_GET_NEXT(_p_curr, _pp_next) \
do \
{ \
uint32_t _i, _j, _curr_i, _curr_j; \
*(_pp_next) = NULL; \
if (_p_curr) \
{ \
MAC_UTIL_FLOW_DB_FLOW_ID_TYPE2ARR_INDEX_SUB_INDEX(_p_curr->bal_flow_key.flow_id, _p_curr->bal_flow_key.flow_type, _curr_i, _curr_j);\
for (_i = (_curr_j<MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES-1 ?_curr_i : _curr_i+1); \
_i<=BAL_ACC_TERM_MAX_FLOWS; \
_i++) \
{ \
for (_j= (_curr_j<MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES-1 ? _curr_j+1 : 0); \
_j<MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES; \
_j++) \
{ \
*(_pp_next) = mac_util_db_flows_list[_i][_j]; \
if (*(_pp_next)) \
break; \
} \
if (*(_pp_next)) \
break; \
} \
} \
else \
break; \
} while (0)
/** @brief Set a flow entry in the Array */
#define MAC_UTIL_FLOW_DB_ENTRY_SET(_flow_id, _flow_type, _flow_entry, _rc) \
do \
{ \
uint32_t _index, _sub_index; \
MAC_UTIL_FLOW_DB_FLOW_ID_TYPE2ARR_INDEX_SUB_INDEX((_flow_id), (_flow_type), (_index), (_sub_index)); \
if (!_index) \
{ \
(_rc) = BCM_ERR_NULL; \
break; \
} \
mac_util_db_flows_list[_index][_sub_index] = (_flow_entry); \
} while (0);
/**
* @brief flow Id starting value that can used by SDN User application.
* @details By default the starting flow Id is assumed to be 1.
*/
uint32_t mac_util_flow_id_start_val = 1;
/**
* @brief flow DB Array
* @details This Array is for upstream & downstream flows and can store BAL_ACC_TERM_MAX_FLOWS flows.
* This array is indexed by BAL flow Id.
*
* @note First entry starts at index 1; (0 is not used).
*
* @note Upstream & Downstream flow types of a pair may use the same Flow Id.Hence there is a sub-array
* of each of Flow Id entry. The sub array has upstream flow entry in index 0 and downstream at index 1.
* Hence, a flow entry is accessible by the key pair {flowId, flowtype}.
* */
static flow_list_entry *mac_util_db_flows_list[BAL_ACC_TERM_MAX_FLOWS + 1][MAC_UTIL_FLOW_DB_MAX_FLOW_TYPES];
/*****************************************************************************/
/** Flow DB wrapper Functions */
/** @todo in future with a new DB data structure, these wrapper functions would
* be migrated to call those DB apis.
*/
/*****************************************************************************/
/**
* @brief Allocate a new flow
*
* @return flow_list_entry pointer to a new flow entry
*/
flow_list_entry *_mac_util_db_flow_alloc (void)
{
flow_list_entry *p_flow = NULL;
p_flow = bcmos_calloc(sizeof(flow_list_entry));
/* bcmos_calloc already initializes the memory to 0 */
return p_flow;
}
/**
* @brief Free a flow (free the memory or return it to free pool)
*
* @param pon_if pon interface id
* @param p_entry pointer to a flow entry
*
* @returns bcmos_errno bcm errno
*
* @note it checks if the flow being freed is already removed from flow DB
*/
bcmos_errno _mac_util_db_flow_free (uint32_t pon_if, flow_list_entry *p_entry)
{
bcmos_errno rc = BCM_ERR_OK;
if (!IS_VALID_PON_IF(pon_if))
{
return BCM_ERR_PARM;
}
if (NULL == p_entry)
{
return BCM_ERR_PARM;
}
/* free the memory */
bcmos_free(p_entry);
return rc;
}
/**
* @brief Add an already allocated flow to flow DB
*
* @param pon_if pon interface id
* @param p_entry pointer to a new flow entry
*
* @returns bcmos_errno bcm errno
*
* @todo in proper DB, it should check if the entry is already in the list or not
*/
bcmos_errno _mac_util_db_flow_add (uint32_t pon_if, flow_list_entry *p_entry)
{
bcmos_errno rc = BCM_ERR_OK;
if (!IS_VALID_PON_IF(pon_if))
return BCM_ERR_PARM;
if (!p_entry)
return BCM_ERR_PARM;
MAC_UTIL_FLOW_DB_ENTRY_SET(p_entry->bal_flow_key.flow_id, p_entry->bal_flow_key.flow_type, p_entry, rc);
return rc;
}
/**
* @brief Remove a flow entry from flow DB
*
* @param pon_if pon interface id
* @param p_entry pointer to a flow entry
*
* @returns bcmos_errno bcm errno
*
* @todo this API will be ported to different DB when we have one
*/
bcmos_errno _mac_util_db_flow_remove (uint32_t pon_if, flow_list_entry *p_entry)
{
bcmos_errno rc = BCM_ERR_OK;
if (!IS_VALID_PON_IF(pon_if))
return BCM_ERR_PARM;
if (!p_entry)
return BCM_ERR_PARM;
MAC_UTIL_FLOW_DB_ENTRY_SET(p_entry->bal_flow_key.flow_id, p_entry->bal_flow_key.flow_type, NULL, rc);
return rc;
}
/**
* @brief Lookup a flow based on a flow id and pon if
*
* @param pon_if pon interface id
* @param p_flow_key pointer to flow key
*
* @returns flow_list_entry pointer a flow entry in list
*/
flow_list_entry *_mac_util_db_flow_get_w_flow_key (uint32_t pon_if, bcmbal_flow_key *p_flow_key)
{
flow_list_entry *p_flow = NULL;
if (!IS_VALID_PON_IF(pon_if))
{
return NULL;
}
MAC_UTIL_FLOW_DB_ENTRY_GET(p_flow_key->flow_id, p_flow_key->flow_type, p_flow);
return p_flow;
}
/**
* @brief get next flow based on flow id and pon_if
*
* @param pon_if pon interface id
* @param p_curr_entry pointer to current flow entry
* @param pp_next_entry double pointer to next flow entry
*
* @returns flow_list_entry pointer to next flow entry in DB
*/
flow_list_entry *_mac_util_db_flow_get_next_w_flow_key (uint32_t pon_if, flow_list_entry *p_curr_entry, flow_list_entry **pp_next_entry)
{
flow_list_entry *p_tmp_entry = p_curr_entry;
if (!IS_VALID_PON_IF(pon_if))
{
BCM_LOG(ERROR,log_id_mac_util,"Invalid pon_if %d !", pon_if);
return NULL;
}
/** @note this while loop is to continue to iterate through the DB until an entry with matching pon If is found */
while (1)
{
if (NULL == p_tmp_entry)
{
/* get first flow */
MAC_UTIL_FLOW_DB_ENTRY_GET_FIRST(p_tmp_entry);
if (p_tmp_entry)
{
MAC_UTIL_FLOW_DB_ENTRY_GET_NEXT(p_tmp_entry, pp_next_entry);
if (p_tmp_entry && (pon_if == p_tmp_entry->if_id))
return p_tmp_entry;
}
else
break; /* at the end of list */
}
else
{
if (NULL != *pp_next_entry)
{
p_tmp_entry = *pp_next_entry;
MAC_UTIL_FLOW_DB_ENTRY_GET_NEXT(p_tmp_entry, pp_next_entry);
if (pon_if == p_tmp_entry->if_id)
return p_tmp_entry;
}
else
break; /* at the end of list */
}
}
return NULL;
}
/**
* @brief get next flow based on sub terminal id
*
* @param pon_if pon interface id
* @param sub_term_id sub term id as the key
* @param p_curr_entry pointer to current flow entry
* @param pp_next_entry double pointer to next flow entry
*
* @returns flow_list_entry pointer to next flow entry in DB
*
*/
flow_list_entry *_mac_util_db_flow_get_next_w_sub_term_id (uint32_t pon_if, uint32_t sub_term_id,
flow_list_entry *p_curr_entry, flow_list_entry **pp_next_entry)
{
flow_list_entry *p_tmp_entry = NULL;
if (!IS_VALID_PON_IF(pon_if))
{
BCM_LOG(ERROR,log_id_mac_util,"Invalid pon_if %d !", pon_if);
return NULL;
}
p_tmp_entry = _mac_util_db_flow_get_next_w_flow_key (pon_if, p_curr_entry, pp_next_entry);
while (NULL != p_tmp_entry)
{
if (sub_term_id == p_tmp_entry->sub_term_id)
{
/* found sub_term match */
return p_tmp_entry;
}
/** @note passing tmp entry here because this is a getnext loop internal to this routine */
p_tmp_entry = _mac_util_db_flow_get_next_w_flow_key (pon_if, p_tmp_entry, pp_next_entry);
}
return NULL;
}
/**
* @brief count of flows using a gem port and pon_if
*
* @param pon_if pon interface id
* @param gem_port_id gem port id as the key
* @param p_count pointer to U32 to save count of flows using the same gem port
*
* @returns bcmos_errno bcm errno
*
*/
bcmos_errno _mac_util_db_flow_count_w_gem (uint32_t pon_if, uint16_t gem_port_id, uint32_t *p_count)
{
uint32_t count = 0;
flow_list_entry *p_tmp_entry = NULL;
void *p_rsc_mgr_curr_entry = NULL;
void *p_rsc_mgr_next_entry = NULL;
BUG_ON(NULL == p_count);
if (!IS_VALID_PON_IF(pon_if))
{
BCM_LOG(ERROR,log_id_mac_util,"Invalid pon_if %d !", pon_if);
return BCM_ERR_PARM;
}
p_tmp_entry = _mac_util_db_flow_get_next_w_gem (pon_if, gem_port_id, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
while (NULL != p_tmp_entry)
{
count++;
p_tmp_entry = _mac_util_db_flow_get_next_w_gem (pon_if, gem_port_id, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
}
*p_count = count;
return BCM_ERR_OK;
}
/**
* @brief get next flow based on gem and pon if
*
* @param pon_if pon interface id
* @param gem_port_id gem port id as the key
* @param **pp_rsc_mgr_curr_entry double pointer to current entry in Rsrc Mgr Database
* @param **pp_rsc_mgr_next_entry double pointer to next entry in Rsrc Mgr Database
*
* @returns flow_list_entry pointer to next flow entry in DB
*
* @note this queries resource mgr DB
*/
flow_list_entry *_mac_util_db_flow_get_next_w_gem (uint32_t pon_if, uint16_t gem_port_id,
void **pp_rsc_mgr_curr_entry, void **pp_rsc_mgr_next_entry)
{
flow_inst *p_core_flow_entry = NULL;
flow_list_entry *p_flow_entry = NULL;
if (!IS_VALID_PON_IF(pon_if))
{
BCM_LOG(ERROR,log_id_mac_util,"Invalid pon_if %d !", pon_if);
return NULL;
}
p_core_flow_entry = rsc_mgr_gem_get_next_user_data (pon_if, gem_port_id, pp_rsc_mgr_curr_entry, pp_rsc_mgr_next_entry);
while (NULL != p_core_flow_entry)
{
p_flow_entry = _mac_util_db_flow_get_w_flow_key(pon_if, &p_core_flow_entry->current_flow_info.key);
if (p_flow_entry)
{
/* found gem match */
return p_flow_entry;
}
p_core_flow_entry = rsc_mgr_gem_get_next_user_data (pon_if, gem_port_id, pp_rsc_mgr_curr_entry, pp_rsc_mgr_next_entry);
}
return NULL;
}
/**
* @brief count of flows using an alloc id and pon if
*
* @param pon_if pon interface id
* @param alloc_id alloc id as the key
* @param p_count pointer to U32 that save the count of flows using the same alloc id
*
* @returns bcmos_errno bcm errno
*/
bcmos_errno _mac_util_db_flow_count_w_alloc_id (uint32_t pon_if, uint16_t alloc_id, uint32_t *p_count)
{
uint32_t count = 0;
flow_list_entry *p_tmp_entry = NULL;
void *p_rsc_mgr_curr_entry = NULL;
void *p_rsc_mgr_next_entry = NULL;
BUG_ON( NULL == p_count);
if (!IS_VALID_PON_IF(pon_if))
{
BCM_LOG(ERROR,log_id_mac_util,"Invalid pon_if %d !", pon_if);
return BCM_ERR_PARM;
}
p_tmp_entry = _mac_util_db_flow_get_next_w_alloc_id (pon_if, alloc_id, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
while (NULL != p_tmp_entry)
{
count++;
p_tmp_entry = _mac_util_db_flow_get_next_w_alloc_id (pon_if, alloc_id, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
}
*p_count = count;
return BCM_ERR_OK;
}
/**
* @brief get next flow based on upstream alloc id and pon if
*
* @param pon_if pon interface id
* @param alloc_id alloc id as the key
* @param **pp_rsc_mgr_curr_entry double pointer to current entry in Rsrc Mgr Database
* @param **pp_rsc_mgr_next_entry double pointer to next entry in Rsrc Mgr Database
*
* @returns flow_list_entry pointer to next flow entry in DB
*
* @note this queries resource mgr DB
*/
flow_list_entry *_mac_util_db_flow_get_next_w_alloc_id (uint32_t pon_if, uint16_t alloc_id,
void **pp_rsc_mgr_curr_entry, void **pp_rsc_mgr_next_entry)
{
flow_inst *p_core_flow_entry = NULL;
flow_list_entry *p_flow_entry = NULL;
if (!IS_VALID_PON_IF(pon_if))
{
BCM_LOG(ERROR,log_id_mac_util,"Invalid pon_if %d !", pon_if);
return NULL;
}
p_core_flow_entry = rsc_mgr_alloc_id_get_next_user_data(pon_if, alloc_id, pp_rsc_mgr_curr_entry, pp_rsc_mgr_next_entry);
while (NULL != p_core_flow_entry)
{
p_flow_entry = _mac_util_db_flow_get_w_flow_key(pon_if, &p_core_flow_entry->current_flow_info.key);
if (p_flow_entry)
{
/* found alloc id match */
return p_flow_entry;
}
p_core_flow_entry = rsc_mgr_alloc_id_get_next_user_data(pon_if, alloc_id, pp_rsc_mgr_curr_entry, pp_rsc_mgr_next_entry);
}
return NULL;
}
/*@}*/