| /****************************************************************************** |
| * |
| * <: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; |
| } |
| |
| /*@}*/ |