blob: cae8d2674c1f1983ecc2fd7624769144a10eadaa [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_epon.c
*
* @brief mac util interfaces definition used by Bal Core for EPON
*
* This file expose the APIs to the core to configure the mac
* with regarding to the operation of access terminal, interface, subscriber terminal and flow.
*
* @addtogroup mac_util
*/
/*@{*/
#include <bal_mac_util.h>
#include <bal_mac_util_epon.h>
#if BAL_EPON_EXCLUDE
#include <bcmolt_user_appl_epon_oam.h>
#include <bal_oam_util.h>
#include <bcmolt_eon.h>
static bcmos_errno mac_util_indication_handle_for_epon_link (bcmolt_devid device_id, bcmolt_msg *p_msg);
static bcmos_errno mac_util_indication_handle_for_epon_ni (bcmolt_devid device_id, bcmolt_msg *p_msg);
/** @brief array stores the list of EPON related auto indications from Maple to subscribe */
static mac_util_ind_obj_and_handlers mac_util_epon_ind_handlers[] =
{
{BCMOLT_OBJ_ID_EPON_LINK, "BCMOLT_OBJ_ID_EPON_LINK", mac_util_indication_handle_for_epon_link},
{BCMOLT_OBJ_ID_EPON_NI, "BCMOLT_OBJ_ID_EPON_NI", mac_util_indication_handle_for_epon_ni}
};
/* epon onu entry structure */
typedef enum
{
OAM_PROVISION_STATE_IDLE = 0, /**< idle - did not start yet */
OAM_PROVISION_STATE_STARTED, /**< started - waiting to configure traffic cb to send bal core flow up indication */
OAM_PROVISION_STATE_COMPLETED, /**< completed successfully */
OAM_PROVISION_STATE_FAIL/**< failed to complete oam provision */
} oam_provision_state;
#define MAC_UTIL_MAX_WAITING_FLOWS_PER_MAC 16
typedef struct epon_onu_list_entry epon_onu_list_entry;
struct epon_onu_list_entry
{
TAILQ_ENTRY(epon_onu_list_entry) next;
bcmbal_subscriber_terminal_key bal_onu_key; /* bal onu key */
bcmos_mac_address mac_address;
oam_provision_state oam_provision_state;
uint8_t waiting_flows_num;
bcmbal_flow_key flow_keys[MAC_UTIL_MAX_WAITING_FLOWS_PER_MAC];
uint32_t tunnel_id;
};
static TAILQ_HEAD(epon_onu_list_head_t, epon_onu_list_entry) epon_onu_list;
/** @todo needs to be ported to the topology stub function */
static bcmolt_devid maple_device_from_interface_get(uint16_t access_int_id)
{
/* For now, all interfaces map to device 0 */
return (bcmolt_devid)0;
}
static void epon_onu_list_add(epon_onu_list_entry *epon_onu_entry);
static epon_onu_list_entry *epon_onu_list_find_by_mac(const bcmos_mac_address *mac_address);
static epon_onu_list_entry *epon_onu_list_find_by_key(bcmbal_subscriber_terminal_key *key);
static void epon_onu_list_remove_by_key(bcmbal_subscriber_terminal_key *key);
static void mac_util_configure_traffic_cb(void *context,
bcmolt_devid device_id,
bcmolt_epon_ni epon_ni,
const bcmos_mac_address *mac_address,
bcmos_errno result);
static void mac_util_unconfigure_traffic_cb(void *context,
bcmolt_devid device_id,
bcmolt_epon_ni epon_ni,
const bcmos_mac_address *mac_address,
bcmos_errno result);
#define _mac_addr_fmt_str "<%02x:%02x:%02x:%02x:%02x:%02x>"
#define _mac_addr_data(mac) \
(mac).u8[0], \
(mac).u8[1], \
(mac).u8[2], \
(mac).u8[3], \
(mac).u8[4], \
(mac).u8[5]
static void mac_util_oam_negotiation_cb(void *context, bcmolt_devid device_id, bcmolt_epon_ni epon_ni, const bcmos_mac_address *mac_address, bcmos_errno result)
{
epon_onu_list_entry *p_onu_entry = context;
uint32_t logical_pon;
bcmos_errno rc;
do
{
rc = bcm_topo_pon_get_physical2logical(device_id, epon_ni, &logical_pon);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"Failed to get logical if from physical if (device_id %d physical %d ) (%s)\n", device_id, epon_ni, bcmos_strerror(rc));
break;
}
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(epon_ni),
"device_id=%u, epon_ni=%u, mac_address=" _mac_addr_fmt_str " result='%s'\n",
device_id, epon_ni, _mac_addr_data(*mac_address), result == BCM_ERR_OK ? "success" : "fail");
mac_util_report_sub_term_event(logical_pon,
p_onu_entry->bal_onu_key.sub_term_id,
(bcmolt_serial_number *)NULL,
BAL_UTIL_OPER_SUB_TERM_ADD,
result,
result == BCM_ERR_OK ? BCMOLT_RESULT_SUCCESS : BCMOLT_RESULT_FAIL,
BCMOLT_ACTIVATION_FAIL_REASON_NONE,
result == BCM_ERR_OK ? p_onu_entry->tunnel_id : BCMBAL_INVALID_TUNNEL_ID);
}
while(0);
}
/**
* @brief get string for the indication object type for epon
*/
static char *mac_util_indication_get_obj_type_str_for_epon (bcmolt_obj_id obj_type)
{
return _mac_util_get_obj_type_str_for_indications (obj_type, mac_util_epon_ind_handlers, BCM_SIZEOFARRAY(mac_util_epon_ind_handlers));
}
/**
* @brief all the maple indication handlers for epon
*
* @param device_id the maple device id generating the current indication
* @param p_msg pointer to the maple indication message
*
*/
bcmos_errno mac_util_handle_all_olt_ind_for_epon (bcmolt_devid device_id, bcmolt_msg *p_msg)
{
int i = 0;
BCM_LOG(DEBUG, log_id_mac_util,
"mac_util_indication_cb received indication obj=%d/%s group=%d subgroup=%d\n",
p_msg->obj_type, mac_util_indication_get_obj_type_str_for_epon(p_msg->obj_type),
p_msg->group, p_msg->subgroup);
for (i=0; i < BCM_SIZEOFARRAY(mac_util_epon_ind_handlers); i++)
{
if (p_msg->obj_type == mac_util_epon_ind_handlers[i].obj_type)
{
return mac_util_epon_ind_handlers[i].ind_handler (device_id, p_msg);
}
}
/* log an error if unhandled */
return BCM_ERR_INTERNAL;
}
/**
* @brief Handler function for Maple auto indications for EPON Link
*
* @param device_id the maple device id generating the current indication
* @param p_msg pointer to the maple indication message
*
* @return bcmos_errno
*/
static bcmos_errno mac_util_indication_handle_for_epon_link (bcmolt_devid device_id, bcmolt_msg *p_msg)
{
bcmos_errno rc = BCM_ERR_OK;
uint32_t logical_pon;
do
{
if (BCMOLT_EPON_LINK_AUTO_ID_MPCP_DISCOVERED == p_msg->subgroup)
{
epon_onu_list_entry *p_onu_entry;
bcmolt_epon_link_mpcp_discovered * p_ind = (bcmolt_epon_link_mpcp_discovered*)p_msg;
rc = bcm_topo_pon_get_physical2logical(device_id, p_ind->key.epon_ni, &logical_pon);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"Failed to get logical if from physical if (device_id %d physical %d ) (%s)\n", device_id, p_ind->key.epon_ni, bcmos_strerror(rc));
break;
}
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(logical_pon),
"llid indication received obj=%d group=%d subgroup=%d err=%d; "
"link_status = %s (%d), llid = (0x%04x) tunnel_id = (0x%08x)\n",
p_msg->obj_type, p_msg->group, p_msg->subgroup, p_msg->err,
p_ind->data.link_info.link_status==BCMOLT_EPON_LINK_STATUS_DISCOVERED ? "Discovered" : "other",
p_ind->data.link_info.link_status,
p_ind->data.link_info.llid,
p_ind->data.link_info.tunnel_id);
if(NULL == (p_onu_entry = epon_onu_list_find_by_mac(&(p_ind->key.mac_address))))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(logical_pon),
"Failed to find epon onu related to received frame captured\n");
rc = BCM_ERR_INTERNAL;
}
else
{
p_onu_entry->tunnel_id = p_ind->data.link_info.tunnel_id;
bal_oam_start_oam_negotiation(device_id,
p_ind->key.epon_ni,
&p_ind->key.mac_address,
mac_util_oam_negotiation_cb,
p_onu_entry);
}
}
}
while(0);
return rc;
}
/**
* @brief Handler function for Maple auto indications for EPON NI
*
* @param device_id the maple device id generating the current indication
* @param p_msg pointer to the maple indication message
*
* @return bcmos_errno
*/
static bcmos_errno mac_util_indication_handle_for_epon_ni (bcmolt_devid device_id, bcmolt_msg *p_msg)
{
bcmos_errno rc = BCM_ERR_OK;
uint32_t logical_pon;
do
{
if (BCMOLT_EPON_NI_AUTO_ID_STATE_CHANGE_COMPLETED == p_msg->subgroup)
{
bcmolt_epon_ni_state_change_completed * p_ind = (bcmolt_epon_ni_state_change_completed *)p_msg;
rc = bcm_topo_pon_get_physical2logical(device_id, p_ind->key.epon_ni, &logical_pon);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"Failed to get logical if from physical if (device_id %d physical %d ) (%s)\n", device_id, p_ind->key.epon_ni, bcmos_strerror(rc));
break;
}
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(logical_pon), "Pon if %d is %s.\n", logical_pon,
BCMOLT_EPON_NI_EN_STATE_ENABLED == p_ind->data.new_state ? "up" : "down");
mac_util_report_if_event(logical_pon, BCMBAL_INTF_TYPE_PON, p_msg->err,
BCMOLT_RESULT_SUCCESS, p_ind->data.new_state);
}
else
{
/* just get the pon key by typecasting to a dummy structure */
bcmolt_epon_ni_key *p_pon_key = &(((bcmolt_epon_ni_state_change_completed*)p_msg)->key);
rc = bcm_topo_pon_get_physical2logical(device_id, p_pon_key->epon_ni, &logical_pon);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"Failed to get logical if from physical if (device_id %d physical %d ) (%s)\n", device_id, p_pon_key->epon_ni, bcmos_strerror(rc));
break;
}
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(logical_pon),
"Unhandled message indication for obj Epon_NI group %d "
"subgroup %d (Ignored)\n", p_msg->group, p_msg->subgroup);
}
}
while(0);
return rc;
}
/**
* @brief Maple auto indication register for specific EPON based indications
*
* @param p_rx_cfg handler config structure
* @param device_id specific device id (for multiple devices support)
* @return bcmos_errno
*/
bcmos_errno mac_util_register_for_epon_auto_indications (struct bcmolt_rx_cfg *p_rx_cfg, bcmolt_devid device_id)
{
return _mac_util_register_for_auto_indications (p_rx_cfg, mac_util_epon_ind_handlers, BCM_SIZEOFARRAY(mac_util_epon_ind_handlers), device_id);
}
#endif /* BAL_EPON_EXCLUDE */
static bcmos_errno mac_util_epon_access_terminal_set(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id,
bcmolt_system_mode system_mode,
bcmolt_nni_speed nni_speed)
{
bcmos_errno rc = BCM_ERR_OK;
bcmolt_device_key key = {};
bcmolt_device_nni_speed nni_speed_cfg;
bcmolt_device_cfg dev_cfg;
rc = maple_access_terminal_set_common(p_acc_term, op_type, device_id);
if (rc != BCM_ERR_OK)
return rc;
BCMOLT_CFG_INIT(&dev_cfg, device, key);
BCMOLT_CFG_PROP_SET(&dev_cfg, device, system_mode, system_mode);
nni_speed_cfg.first_half = nni_speed;
nni_speed_cfg.second_half = nni_speed;
BCMOLT_CFG_PROP_SET(&dev_cfg, device, nni_speed, nni_speed_cfg);
/** @todo with multiple devices the mechanism to configure acces term will change */
rc = bcmolt_cfg_set(device_id, &dev_cfg.hdr);
if (rc != BCM_ERR_OK)
return rc;
return maple_access_terminal_connect_common(device_id);
}
bcmos_errno mac_util_access_terminal_set_for_epon_8_tdma(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__8_X_COEXISTENCE_TDMA,
BCMOLT_NNI_SPEED_GBPS_12P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_4_tdma(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__4_X_COEXISTENCE_TDMA,
BCMOLT_NNI_SPEED_GBPS_12P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_16_1g(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__16_X,
BCMOLT_NNI_SPEED_GBPS_2P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_8_1g(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__8_X,
BCMOLT_NNI_SPEED_GBPS_2P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_4_1g(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__4_X,
BCMOLT_NNI_SPEED_GBPS_2P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_8_10g(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__8_X_10_G,
BCMOLT_NNI_SPEED_GBPS_12P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_4_10g(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__4_X_10_G,
BCMOLT_NNI_SPEED_GBPS_12P5);
}
bcmos_errno mac_util_access_terminal_set_for_epon_2_10g(
acc_term_inst *p_acc_term,
bal_util_oper_acc_term op_type,
bcmolt_devid device_id)
{
return mac_util_epon_access_terminal_set(
p_acc_term,
op_type,
device_id,
BCMOLT_SYSTEM_MODE_EPON__2_X_10_G,
BCMOLT_NNI_SPEED_GBPS_12P5);
}
/**
* @brief Command Set setup routine for interface up to mac application for EPON
*
* This routine is called by if_fsm in the BAL core to initialize the command
* set to up the interface of the mac application. The cmdset actually
* consists of two commands, one is to send the if up request message to the mac
* App and handle the relevant response, the other is to handle the indication message
* from the mac APP when the operation is completed.
*
* @param p_interface_inst Pointer to interface instance
* @param op_type Operation type on access terminal/interface instance
*
* @return bcmos_errno
*
*/
bcmos_errno mac_util_interface_set_for_epon(acc_term_interface *p_interface_inst, bal_util_oper_if op_type)
{
bcmos_errno rc = BCM_ERR_OK;
bcmbal_interface_key intf_key = p_interface_inst->api_req_int_obj_info.key;
bcmolt_devid device_id;
uint32_t physical_if_id;
/* get physical interface from logical interface */
rc = bcm_topo_pon_get_logical2physical(intf_key.intf_id, &device_id, &physical_if_id);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_key.intf_id),
"Failed to get physical if from logical if (%s)\n", bcmos_strerror(rc));
return rc;
}
bcmolt_epon_ni_key key;
bcmolt_epon_ni_cfg cfg;
bcmolt_epon_ni_set_epon_ni_en_state oper;
key.epon_ni = physical_if_id;
BCMOLT_CFG_INIT(&cfg, epon_ni, key);
if (BAL_UTIL_OPER_IF_UP == op_type)
{
BCMOLT_CFG_PROP_SET(&cfg, epon_ni, registration_behavior, BCMOLT_REGISTRATION_BEHAVIOR_NOTIFY_UNKNOWN);
bcmolt_cfg_set(device_id, &cfg.hdr);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_key.intf_id),
"Failed to %s (set) pon interface (%d) - %s, err_text=%s\n",
(BAL_UTIL_OPER_IF_UP == op_type) ? "activate" : "deactivate",
rc, bcmos_strerror(rc), cfg.hdr.hdr.err_text);
return rc;
}
}
BCMOLT_OPER_INIT(&oper, epon_ni, set_epon_ni_en_state, key);
BCMOLT_OPER_PROP_SET(&oper, epon_ni, set_epon_ni_en_state, new_state,
(BAL_UTIL_OPER_IF_UP == op_type ?
BCMOLT_EPON_NI_EN_STATE_ENABLED : BCMOLT_EPON_NI_EN_STATE_DISABLED));
rc = bcmolt_oper_submit(device_id, &oper.hdr);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_key.intf_id),
"Failed to %s (submit) pon interface (%d) - %s, err_text=%s\n",
(BAL_UTIL_OPER_IF_UP == op_type) ? "activate" : "deactivate",
rc, bcmos_strerror(rc), oper.hdr.hdr.err_text);
}
else
{
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_key.intf_id),
"Submitted INTERFACE-%s operation for IF %d\n",
(BAL_UTIL_OPER_IF_UP == op_type) ? "UP" : "DOWN", intf_key.intf_id);
}
return rc;
}
/*---------------------------------------------------------------------------------------------*/
#if BAL_EPON_EXCLUDE
/**
* @brief mac_util_validate_subscriber_terminal_info_for_epon
*
* This routine is used to validate all input attributes required for a sub term setting
* received from core for EPON
*
* @param p_sub_term_req A pointer to a subscriber terminal object
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_validate_subscriber_terminal_info_for_epon(const bcmbal_subscriber_terminal_cfg *p_sub_term_req)
{
if(BCMBAL_STATE_UP == p_sub_term_req->data.admin_state)
{
if (!BCMBAL_CFG_PROP_IS_SET(p_sub_term_req, subscriber_terminal, mac_address))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"mac_address is a mandatory parameter for an epon subscriber terminal, and it is not set\n");
return BCM_ERR_MANDATORY_PARM_IS_MISSING;
}
}
return BCM_ERR_OK;
}
/**
* @brief Command Set setup routine for subscriber terminal connect to mac application for EPON
*
* This routine is called by sub_term_fsm in the BAL core to initialize the command
* set to connect the subscriber terminal of the mac application. The cmdset actually
* consists of two commands, one is to send the sub_term request message to the mac
* App and handle the relevant response, the other is to handle the indication message
* from the mac APP when the operation is completed.
*
* @param p_sub_term_inst A pointer to a subscriber terminal instance
* @param op_type Type of operation being performed on the subscriber terminal instance
* @param is_post_discovery This parameter is ignored for epon
*
* @return bcmos_errno
*/
bcmos_errno mac_util_subscriber_terminal_set_for_epon(sub_term_inst *p_sub_term_inst, bal_util_oper_sub_term op_type, bcmos_bool is_post_discovery)
{
bcmos_errno rc = BCM_ERR_OK;
bcmbal_subscriber_terminal_cfg *p_sub_term_req = &p_sub_term_inst->api_req_sub_term_info;
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"IN : %s pon_id = %d onu_id= %d "
"omci_gem_port = %d\n",
__FUNCTION__,
p_sub_term_req->key.intf_id,
p_sub_term_req->key.sub_term_id, p_sub_term_req->data.svc_port_id);
if ((BAL_UTIL_OPER_SUB_TERM_ADD != op_type)
&& (BAL_UTIL_OPER_SUB_TERM_REMOVE != op_type)
&& (BAL_UTIL_OPER_SUB_TERM_CLEAR != op_type))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"Unsupported operation %d for sub_term %u\n",
op_type, p_sub_term_req->key.sub_term_id);
return BCM_ERR_NOT_SUPPORTED;
}
do
{
bcmolt_devid device_id;
uint32_t physical_if_id;
/* get physical interface from logical interface */
rc = bcm_topo_pon_get_logical2physical (p_sub_term_req->key.intf_id, &device_id, &physical_if_id);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"Failed to get physical if from logical if (%s)\n", bcmos_strerror(rc));
break;
}
epon_onu_list_entry * p_new_epon_onu_entry;
bcmolt_epon_ni_key key;
bcmolt_epon_ni_add_link oper;
key.epon_ni = physical_if_id;
BCMOLT_OPER_INIT(&oper, epon_ni, add_link, key);
if(BAL_UTIL_OPER_SUB_TERM_ADD == op_type)
{
BCMOLT_OPER_PROP_SET(&oper, epon_ni, add_link, mac_address, p_sub_term_req->data.mac_address);
BCMOLT_OPER_PROP_SET(&oper, epon_ni, add_link, rate, BCMOLT_EPON_LINK_RATE_TEN_TEN);
rc = bcmolt_oper_submit(device_id, &oper.hdr);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"Failed to register epon onu epon_ni = %d mac : "_mac_addr_fmt_str" rc = %d (%s), err_text=%s\n",
key.epon_ni, _mac_addr_data(p_sub_term_req->data.mac_address), rc, bcmos_strerror(rc),
oper.hdr.hdr.err_text);
break;
}
/* add the new epon onu to the epon onu list to follow indications and oam sending */
p_new_epon_onu_entry = bcmos_calloc(sizeof(epon_onu_list_entry));
if (NULL == p_new_epon_onu_entry)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"Failed to allocate the epon onu entry\n");
rc = BCM_ERR_NOMEM;
break;
}
memcpy(&p_new_epon_onu_entry->bal_onu_key, &p_sub_term_req->key,
sizeof(bcmbal_subscriber_terminal_key));
p_new_epon_onu_entry->mac_address = p_sub_term_req->data.mac_address;
p_new_epon_onu_entry->oam_provision_state = OAM_PROVISION_STATE_IDLE;
p_new_epon_onu_entry->waiting_flows_num = 0;
epon_onu_list_add(p_new_epon_onu_entry);
}
else
{
mac_util_report_sub_term_event(p_sub_term_req->key.intf_id,
p_sub_term_req->key.sub_term_id,
(bcmolt_serial_number *)NULL,
BAL_UTIL_OPER_SUB_TERM_REMOVE,
BCM_ERR_OK, BCMOLT_RESULT_SUCCESS,
MAC_UTIL_DEACTIVATION_FAIL_REASON_NONE, BCMBAL_INVALID_TUNNEL_ID);
epon_onu_list_remove_by_key(&p_sub_term_req->key);
}
} while (0);
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"OUT : going out of %s rc = %s (%d)\n",
__FUNCTION__,
bcmos_strerror(rc), rc);
return rc;
}
static bcmos_errno maple_us_sla_configure_epon(bcmbal_flow_cfg *flow_entry, bcmos_mac_address *mac)
{
bcmolt_epon_link_key epon_link_key;
bcmolt_epon_link_cfg epon_link_cfg;
bcmolt_upstream_bandwidth_distribution us_bw_dist = {};
bcmolt_devid device_id;
uint32_t physical_if_id;
bcmos_errno rc = BCM_ERR_OK;
/* get physical interface from logical interface */
rc = bcm_topo_pon_get_logical2physical (flow_entry->data.access_int_id, &device_id, &physical_if_id);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(flow_entry->data.access_int_id),
"Failed to get physical if from logical if (%s)\n", bcmos_strerror(rc));
}
else
{
epon_link_key.epon_ni = physical_if_id;
epon_link_key.mac_address = *mac;
BCMOLT_CFG_INIT(&epon_link_cfg, epon_link, epon_link_key);
us_bw_dist.polling_interval_us = BCMOLT_POLLING_INTERVAL_AUTOMATIC;
if (BCMBAL_ATTRIBUTE_PROP_IS_SET(&flow_entry->data.sla, sla, min_rate))
{
us_bw_dist.min_schedulershaper.bandwidth_Kbps = flow_entry->data.sla.min_rate;
}
if (BCMBAL_ATTRIBUTE_PROP_IS_SET(&flow_entry->data.sla, sla, max_rate))
{
us_bw_dist.max_schedulershaper.bandwidth_Kbps = flow_entry->data.sla.max_rate;
}
else
{
us_bw_dist.max_schedulershaper.bandwidth_Kbps = 10000000;
}
us_bw_dist.max_schedulershaper.priority = 7;
BCMOLT_CFG_PROP_SET(&epon_link_cfg, epon_link, upstream_bandwidth, us_bw_dist);
return bcmolt_cfg_set(device_id, &epon_link_cfg.hdr);
}
return rc;
}
/**
* @brief flow set for EPON
*
* @param p_flow_req pointer to flow request structure from core
* @param op_type ADD, REMOVE or CLEAR
* @param p_flow_core local DB flow context passed as a cookie
*
* @return errno error
*/
bcmos_errno mac_util_flow_set_for_epon (bcmbal_flow_cfg *p_flow_req, bal_util_oper_flow op_type, flow_inst *p_flow_core)
{
bcmos_errno rc = BCM_ERR_OK;
epon_onu_list_entry *p_onu_entry;
bcmos_mac_address mac;
bcmbal_subscriber_terminal_key key;
key.intf_id = p_flow_req->data.access_int_id;
key.sub_term_id = p_flow_req->data.sub_term_id;
if(NULL != (p_onu_entry = epon_onu_list_find_by_key(&key)))
{
mac = p_onu_entry->mac_address;
}
else
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"failed to configure flow, "
"subscriber terminal if=%d sub-term id = %d was not found - no such device\n",
p_flow_req->data.access_int_id, p_flow_req->data.sub_term_id);
return BCM_ERR_NOENT;
}
if (BAL_UTIL_OPER_FLOW_ADD == op_type)
{
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id), "add, context is %p\n", p_flow_context);
switch (p_onu_entry->oam_provision_state)
{
case OAM_PROVISION_STATE_IDLE:
{
p_onu_entry->flow_keys[p_onu_entry->waiting_flows_num++] = p_flow_req->key;
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"add p_onu_entry-> %p, waiting flows: %d context is %p\n",
p_onu_entry, p_onu_entry->waiting_flows_num, p_flow_context);
rc = maple_us_sla_configure_epon(p_flow_req, &mac);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"Unable to configure EPON US SLA (%s)\n", bcmos_strerror(rc));
break;
}
p_onu_entry->oam_provision_state = OAM_PROVISION_STATE_STARTED;
bal_oam_configure_traffic(maple_device_from_interface_get(p_flow_req->data.access_int_id),
p_flow_req->data.access_int_id,
&mac,
BCMOS_TRUE,
mac_util_configure_traffic_cb, p_flow_context);
}
break;
case OAM_PROVISION_STATE_STARTED:
{
if (p_onu_entry->waiting_flows_num < MAC_UTIL_MAX_WAITING_FLOWS_PER_MAC)
{
p_onu_entry->flow_keys[p_onu_entry->waiting_flows_num++] = p_flow_req->key;
}
else
{
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"failed to configure flow for that mac, "
"too many flows already waiting for oam configuration\n");
rc = BCM_ERR_INSUFFICIENT_LIST_MEM;
}
}
break;
case OAM_PROVISION_STATE_COMPLETED:
{
mac_util_report_flow_add_success(p_flow_req->key, p_flow_req->data.access_int_id);
}
break;
case OAM_PROVISION_STATE_FAIL:
default:
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"failed to configure oam traffic for that mac,\n"); /* currently no failure indications */
}
break;
}
}
else /* REMOVE or CLEAR FLOW */
{
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"delete p_onu_entry-> %p, waiting flows: %d, provisioned state is %d, context is %p\n",
p_onu_entry,
p_onu_entry->waiting_flows_num,
p_onu_entry->oam_provision_state,
p_flow_context);
switch (p_onu_entry->oam_provision_state)
{
case OAM_PROVISION_STATE_IDLE:
{
mac_util_report_flow_remove_success(p_flow_req->key, p_flow_req->data.access_int_id, op_type);
}
break;
case OAM_PROVISION_STATE_COMPLETED:
{
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"calling bal_oam_configure_traffic w/ \"Disable\" state\n");
bal_oam_configure_traffic(maple_device_from_interface_get(p_flow_req->data.access_int_id),
p_flow_req->data.access_int_id,
&mac,
BCMOS_FALSE,
mac_util_unconfigure_traffic_cb,
p_flow_context);
}
break;
case OAM_PROVISION_STATE_FAIL:
case OAM_PROVISION_STATE_STARTED:
default:
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(key.intf_id),
"failed to unconfigure oam traffic for that mac,\n"); /* currently no failure indications */
}
break;
}
}
return rc;
}
static void mac_util_configure_traffic_cb(void *context,
bcmolt_devid device_id,
bcmolt_epon_ni epon_ni,
const bcmos_mac_address *mac_address,
bcmos_errno result)
{
epon_onu_list_entry *p_onu_entry;
int i;
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(epon_ni),
"configure device_id=%u, epon_ni=%u, mac_address=" _mac_addr_fmt_str " result='%s'\n",
device_id, epon_ni, _mac_addr_data(*mac_address), result == BCM_ERR_OK ? "success" : "fail");
if(NULL == (p_onu_entry = epon_onu_list_find_by_mac(mac_address)))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(epon_ni),
"FAIL - received configure traffic cb for mac that was not configured " _mac_addr_fmt_str "\n",
_mac_addr_data(*mac_address));
return;
}
if (OAM_PROVISION_STATE_STARTED != p_onu_entry->oam_provision_state)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(epon_ni),
"FAIL - received configure traffic cb for mac that is in the wrong state (%d)\n",
p_onu_entry->oam_provision_state);
return;
}
if (result == BCM_ERR_OK)
{
p_onu_entry->oam_provision_state = OAM_PROVISION_STATE_COMPLETED;
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(epon_ni), "Moved ONU to OAM COMPLETED state\n");
for (i=0; i<p_onu_entry->waiting_flows_num; i++)
{
mac_util_report_flow_add_success(p_onu_entry->flow_keys[i], epon_ni);
}
}
else
{
p_onu_entry->oam_provision_state = OAM_PROVISION_STATE_FAIL;
}
p_onu_entry->waiting_flows_num = 0; /* currently we dont send fail indication */
}
/** EPON specific traffic unconfigure; Not used for GPON mode */
static void mac_util_unconfigure_traffic_cb(void *context,
bcmolt_devid device_id,
bcmolt_epon_ni epon_ni,
const bcmos_mac_address *mac_address,
bcmos_errno result)
{
flow_inst *p_flow_core = (flow_inst *)(context);
epon_onu_list_entry *p_onu_entry;
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(epon_ni),
"unconfigure device_id=%u, epon_ni=%u, mac_address=" _mac_addr_fmt_str " result='%s'\n",
device_id,
epon_ni,
_mac_addr_data(*mac_address),
result == BCM_ERR_OK ? "success" : "fail");
/** @todo need to pass on the actual op type (REMOVE or CLEAR) */
mac_util_report_flow_remove_success(p_flow_core->current_flow_info.key, epon_ni, BAL_UTIL_OPER_FLOW_REMOVE);
if(NULL != (p_onu_entry = epon_onu_list_find_by_mac(mac_address)))
{
p_onu_entry->oam_provision_state = OAM_PROVISION_STATE_IDLE;
}
}
/**
* @brief used for epon oam message handling
*
* @param device_id bcm dev id
* @param p_msg oam msg pointer
*/
void bal_proxy_rx_cb_for_epon (bcmolt_devid device_id, bcmolt_msg *p_msg)
{
bcmolt_proxy_rx *proxy_rx = (bcmolt_proxy_rx *)p_msg;
bcmolt_user_appl_eon_process_rx(device_id, proxy_rx);
bcmolt_user_appl_epon_oam_handle_rx(device_id, proxy_rx, bal_oam_proxy_rx_cb);
/** @note the free of p_msg is done in caller function */
}
/**
* @brief init for epon oam and eon
*
*/
static void mac_util_init_oam_for_epon (void)
{
bcmolt_user_appl_epon_oam_init();
bcmolt_user_appl_eon_init();
}
static void epon_onu_list_add(epon_onu_list_entry *epon_onu_entry)
{
TAILQ_INSERT_HEAD(&epon_onu_list, epon_onu_entry, next);
return;
}
static void epon_onu_list_remove_by_key(bcmbal_subscriber_terminal_key *key)
{
epon_onu_list_entry *p_onu_entry = NULL;
if(NULL != (p_onu_entry = epon_onu_list_find_by_key(key)))
{
TAILQ_REMOVE(&epon_onu_list, p_onu_entry, next);
bcmos_free(p_onu_entry);
}
return;
}
static epon_onu_list_entry *epon_onu_list_find_by_mac(const bcmos_mac_address *mac_address)
{
epon_onu_list_entry *p_onu_entry = NULL;
epon_onu_list_entry *current_onu_entry;
TAILQ_FOREACH(current_onu_entry, &epon_onu_list, next)
{
if (memcmp(&current_onu_entry->mac_address, mac_address, sizeof(bcmos_mac_address))==0)
{
p_onu_entry = current_onu_entry;
break;
}
}
return p_onu_entry;
}
static epon_onu_list_entry *epon_onu_list_find_by_key(bcmbal_subscriber_terminal_key *key)
{
epon_onu_list_entry *p_onu_entry = NULL;
epon_onu_list_entry *current_onu_entry;
TAILQ_FOREACH(current_onu_entry, &epon_onu_list, next)
{
if ((current_onu_entry->bal_onu_key.intf_id == key->intf_id) &&
(current_onu_entry->bal_onu_key.sub_term_id == key->sub_term_id))
{
p_onu_entry = current_onu_entry;
break;
}
}
return p_onu_entry;
}
#endif /* BAL_EPON_EXCLUDE */
/*@}*/