blob: 98f50bec53a04fd97f5f5f2354d9f128f03bb049 [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_worker.c
* @brief Initialization and message handler functions for the BAL Core
* worker thread including all core FSM initialization.
*
* @addtogroup ctrlr
*/
/*@{*/
/* Project includes */
#include <bcmos_system.h>
#include <bal_api.h>
#include <bal_msg.h>
#include <bal_osmsg.h>
#include "bal_worker.h"
#include "acc_term_fsm.h"
#include "flow_fsm.h"
#include "group_fsm.h"
#include "sub_term_fsm.h"
#include "tm_sched_fsm.h"
#include "tm_queue_fsm.h"
#include "fsm_common.h"
#include "bal_api_worker.h"
#include "bal_obj_msg_pack_unpack.h"
#include "bal_dpp_acc_term.h"
#include "rsc_mgr.h"
#include <arpa/inet.h>
#ifdef ENABLE_LOG
#include <bcm_dev_log.h>
/*
* @brief The logging device id for the core
*/
extern dev_log_id log_id_core;
#endif
/* Local function declarations */
static void core_mgmt_msg_handler(bcmos_module_id module_id, bcmos_msg *msg);
static bcmos_errno process_mgmt_msg(void *msg_payload);
static bcmos_errno process_util_msg(void *msg_payload);
static int _bal_mgmt_rx_handler(long data);
static bcmos_errno process_packet_object(void *msg_payload);
/*
* @brief The BAL core management queue. These are the queues through which the core
* converses with the Public API. The remote endpoint of these queues are the
* BAL API backend.
*/
static bcmos_msg_queue core_mgmt_queue;
static bcmos_msg_queue core_api_queue;
static bcmos_msg_queue core_api_ind_queue;
bcmos_msg_queue *p_bal_core_queue;
bcmos_msg_queue *p_bal_core_to_api_queue;
bcmos_msg_queue *p_bal_core_to_api_ind_queue;
/*
* @brief The rx thread for management message reception
*/
static bcmos_task rx_mgmt_thread;
/*****************************************************************************/
/**
* @brief Initialize the worker thread
*
* A Worker module function that initializes all of the data structures and
* FSMs associated with the BAL core. This function called from bal_core_init
* during BAL core startup.
*
*****************************************************************************/
void core_worker_thread_init(void)
{
/*
* Initialize all of the worker thread hosted FSMs and the resource manager
*/
rsc_mgr_init();
tm_queue_fsm_init();
tm_sched_fsm_init();
access_terminal_fsm_init();
flow_fsm_init();
sub_term_fsm_init();
group_fsm_init();
return;
}
/*****************************************************************************/
/**
* @brief Finish the worker thread
*
* A Worker module function that un-initializes all of the data structures and
* FSMs associated with the BAL core. This function called from bal_core_init
* during BAL core cleanup on exit.
*
*****************************************************************************/
void core_worker_thread_finish(void)
{
/*
* Un-initialize the worker thread owned data structures. etc.
*/
bcmos_msg_unregister(BCMBAL_MGMT_MSG, 0, BCMOS_MODULE_ID_WORKER_MGMT);
bcmos_msg_unregister(BCMBAL_MAC_UTIL_MSG, 0, BCMOS_MODULE_ID_WORKER_MGMT);
bcmos_task_destroy(&rx_mgmt_thread);
sub_term_fsm_finish();
flow_fsm_finish();
group_fsm_finish();
tm_sched_fsm_finish();
tm_queue_fsm_finish();
bcmos_msg_queue_destroy(&core_mgmt_queue);
if (p_bal_core_to_api_queue == &core_api_queue)
bcmos_msg_queue_destroy(p_bal_core_to_api_queue);
if (p_bal_core_to_api_ind_queue == &core_api_ind_queue)
bcmos_msg_queue_destroy(p_bal_core_to_api_ind_queue);
return;
}
/*****************************************************************************/
/**
* @brief The BAL core management message queue init
*
* A initialization function for the worker module.
* It creates message queues for communication with API layer and UTILS
*
* @param mgmt_queue_info A pointer to the ip:port addresses required for the msg queues.
* The ip:port addresses can be NULL in BAL_MONOLITHIC mode. In this case
* inter-thread queues will be used for communication.
*
* @returns bcmos_errno
*
*****************************************************************************/
bcmos_errno core_msg_queue_init(mgmt_queue_addr_ports *mgmt_queue_info)
{
bcmos_msg_queue_parm msg_q_p = {};
bcmos_errno ret;
do
{
/* Create core queue. BAL core listens on this queue
* for public API calls and indications from the UTils
*/
msg_q_p.name = "mgmt_rx_q";
if (NULL != mgmt_queue_info->core_mgmt_ip_port)
{
/* The queue allows sending from core_mgmt_ip_port and receiving at core_mgmt_ip_port */
msg_q_p.local_ep_address = mgmt_queue_info->core_mgmt_ip_port;
msg_q_p.remote_ep_address = mgmt_queue_info->core_mgmt_ip_port;
msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
}
else
{
msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_LOCAL;
}
ret = bcmos_msg_queue_create(&core_mgmt_queue, &msg_q_p);
if (BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_core, "Couldn't create rx mgmt queue\n");
break;
}
p_bal_core_queue = &core_mgmt_queue;
#ifdef BAL_MONOLITHIC
if (NULL == mgmt_queue_info->core_mgmt_ip_port)
p_balapi_to_core_queue = p_bal_core_queue;
#endif
/* Now create a TX queue for sending replies from the core to API.
* Only do it if using socket transport. In case of inter-thread queues
* it will be created by API layer
*/
if (NULL != mgmt_queue_info->balapi_mgmt_ip_port)
{
uint16_t portnum;
char *p_portnum_str;
char balapi_ind_port_str[256];
msg_q_p.name = "mgmt_to_api_q";
msg_q_p.local_ep_address = NULL;
msg_q_p.remote_ep_address = mgmt_queue_info->balapi_mgmt_ip_port;
msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
ret = bcmos_msg_queue_create(&core_api_queue, &msg_q_p);
if (BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_core, "Couldn't create tx mgmt queue\n");
break;
}
p_bal_core_to_api_queue = &core_api_queue;
/*
* make a copy of the user chosen bal api mgmt port
*/
strcpy(balapi_ind_port_str, mgmt_queue_info->balapi_mgmt_ip_port);
/* Find the port number */
p_portnum_str = strchr(balapi_ind_port_str, ':') + 1;
/* convert to an integer and increment it by one */
portnum = atoi(p_portnum_str) + 1;
/* create the new string defining the BAL API indication port */
sprintf(p_portnum_str,"%d", portnum);
/* Create core->API indication queue
*/
msg_q_p.name = "mgmt_ind_q";
/* Set up the management IP:port access parameters to allow the core to send indications to
* the BAL public API - this is a TX queue only!.
*/
msg_q_p.local_ep_address = NULL;
msg_q_p.remote_ep_address = balapi_ind_port_str;
msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
ret = bcmos_msg_queue_create(&core_api_ind_queue, &msg_q_p);
if (BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_core, "Couldn't create the core tx indication queue\n");
break;
}
BCM_LOG(DEBUG, log_id_core, "Created the core tx indication queue\n");
p_bal_core_to_api_ind_queue = &core_api_ind_queue;
}
} while (0);
return ret;
}
/*****************************************************************************/
/**
* @brief The BAL core management worker module init
*
* A initialization function for the worker module.
* It registers for messages that this module is expected to process.
*
* @returns bcmos_errno
*
*****************************************************************************/
bcmos_errno _bal_worker_mgmt_module_init(long data)
{
bcmos_task_parm task_p = {};
bcmos_errno ret = BCM_ERR_OK;
do
{
/* Create Mgmt RX thread */
task_p.name = "mgmt_mgmt_rx";
task_p.priority = TASK_PRIORITY_IPC_RX;
task_p.handler = _bal_mgmt_rx_handler;
task_p.data = (long)p_bal_core_queue;
ret = bcmos_task_create(&rx_mgmt_thread, &task_p);
if (ret)
{
BCM_LOG(ERROR, log_id_core, "Couldn't create Mgmt RX thread\n");
break;
}
/* Register the message types to be handled by the mgmt module
*/
bcmos_msg_register(BCMBAL_MGMT_MSG, 0, BCMOS_MODULE_ID_WORKER_MGMT, core_mgmt_msg_handler);
bcmos_msg_register(BCMBAL_MAC_UTIL_MSG, 0, BCMOS_MODULE_ID_WORKER_MGMT, core_util_msg_handler);
}
while(0);
return ret;
}
/*****************************************************************************/
/**
* @brief Mgmt RX handler
*
* This handler is executed in the context of an RX thread. It's purpose
* is to dispatch the message received here to the module that has registered
* to process this message. The message is then processed in the context
* of the thread to which that module is attached.
*
* @param data A pointer to the received message
*
* @returns 0 on success, -EINVAL on failure
*
*****************************************************************************/
static int _bal_mgmt_rx_handler(long data)
{
bcmos_msg_queue *rxq = (bcmos_msg_queue *)data;
bcmos_task *my_task = bcmos_task_current();
void *payload;
bcmos_msg *msg;
bcmos_errno ret = BCM_ERR_OK;
while (!my_task->destroy_request)
{
payload = NULL;
ret = bcmbal_msg_recv(rxq, BCMOS_WAIT_FOREVER, &payload);
if (ret)
{
/* Unexpected failure */
BCM_LOG(ERROR, log_id_core, "bcmbal_msg_recv() -> %s\n", bcmos_strerror(ret));
continue;
}
/* Message received */
BCM_LOG(DEBUG, log_id_core, "bcmbal_msg_recv(%p) -> %s\n", payload, bcmos_strerror(ret));
/*
* Got a message, so now dispatch it. This will result in one
* of the modules (registered for the message being processed)
* executing its message callback handler.
*
*/
msg = bcmbal_bcmos_hdr_get(payload);
ret = bcmos_msg_dispatch(msg, BCMOS_MSG_SEND_AUTO_FREE);
if (ret)
{
BCM_LOG(ERROR, log_id_core,
"Couldn't dispatch message %d:%d\n",
(int)msg->type, (int)msg->instance);
}
}
my_task->destroyed = BCMOS_TRUE;
return (BCM_ERR_OK == ret) ? 0 : -EINVAL;
}
/*****************************************************************************/
/**
* @brief The BAL core management message handler
*
* A function that handlers messages received from the
* BAL public API via an RX thread.
*
* This function executes in the context of the worker thread.
*
* @param module_id The index of the module that this message handler
* is associated with.
*
* @param msg A pointer to the received message to be processed
*
*****************************************************************************/
static void core_mgmt_msg_handler(bcmos_module_id module_id, bcmos_msg *msg)
{
void *msg_payload;
/* Parameter checks */
BUG_ON(NULL == msg);
/*
* @to-do
* validate the message major and minor version is correct
*/
/*
* Point to the message payload for further processing
*/
msg_payload = bcmbal_payload_ptr_get(bcmbal_bal_hdr_get_by_bcmos_hdr(msg));
/*
* These are messages from the BAL Public API or the UTILS
*
* - call into appropriate FSM
*
*/
BCM_LOG(DEBUG, log_id_core, "Received a mgmt message (payload at %p)\n", msg_payload);
if(BCMBAL_MGMT_MSG == bcmbal_type_major_get(msg_payload) &&
BAL_SUBSYSTEM_PUBLIC_API == bcmbal_sender_get(msg_payload))
{
/* Process the message */
process_mgmt_msg(msg_payload);
}
else
{
BCM_LOG(FATAL, log_id_core, "message received with wrong major type/subsystem combination (%d/\%d)\n",
bcmbal_type_major_get(msg_payload),
bcmbal_sender_get(msg_payload));
BUG_ON(BCMOS_TRUE);
}
}
/*****************************************************************************/
/**
* @brief The BAL core management message processing function
*
* A Worker module function that handles messages received from the
* BAL public API or UTILs via an RX thread.
*
* This function executes in the context of the worker thread
*
* @param msg_payload A pointer to the message to be processed
*
* @returns bcmos_errno
*
*****************************************************************************/
static bcmos_errno process_mgmt_msg(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK;
bcmbal_obj_id objtype;
BCM_LOG(DEBUG, log_id_core, "Processing a management message\n");
objtype = bcmbal_msg_id_obj_get(msg_payload);
/*
* Process the message based on the type of BAL object and sender
* in the message.
*/
switch(objtype)
{
case BCMBAL_OBJ_ID_FLOW:
{
ret = process_flow_object(msg_payload);
break;
}
case BCMBAL_OBJ_ID_GROUP:
{
ret = process_group_object(msg_payload);
break;
}
case BCMBAL_OBJ_ID_ACCESS_TERMINAL:
{
ret = process_access_terminal_object(msg_payload);
break;
}
case BCMBAL_OBJ_ID_INTERFACE:
{
ret = process_interface_object(msg_payload);
break;
}
case BCMBAL_OBJ_ID_SUBSCRIBER_TERMINAL:
{
ret = process_subscriber_terminal_object(msg_payload);
break;
}
case BCMBAL_OBJ_ID_PACKET:
{
ret = process_packet_object(msg_payload);
/* We respond to the BAL public API backend with a result. We always
* send a complete msg_payload back to the API, but the data portion
* of the object is only relevant when a GET or GET-STATS has been requested.
*/
mgmt_msg_send_balapi_rsp(ret, msg_payload, ((bcmbal_obj *)msg_payload)->type, log_id_core);
break;
}
case BCMBAL_OBJ_ID_TM_SCHED:
{
ret = process_tm_sched_object(msg_payload);
break;
}
case BCMBAL_OBJ_ID_TM_QUEUE:
{
ret = process_tm_queue_object(msg_payload);
break;
}
default:
{
BCM_LOG(ERROR, log_id_core,
"Unsupported object detected in management message\n");
ret = BCM_ERR_NOT_SUPPORTED;
/* We respond to the BAL public API backend with a result. We always
* send a complete msg_payload back to the API, but the data portion
* of the object is only relevant when a GET or GET-STATS has been requested.
*/
mgmt_msg_send_balapi_rsp(ret, msg_payload, ((bcmbal_obj *)msg_payload)->type, log_id_core);
break;
}
}
bcmbal_msg_free(msg_payload);
return ret;
}
/*****************************************************************************/
/**
* @brief The BAL core util message handler
*
* A function that handlers messages received from the
* BAL utils via an RX thread.
*
* This function executes in the context of the worker thread.
*
* @param module_id The index of the module that this message handler
* is associated with.
*
* @param msg A pointer to the received message to be processed
*
*****************************************************************************/
void core_util_msg_handler(bcmos_module_id module_id, bcmos_msg *msg)
{
void *msg_payload;
/* Parameter checks */
BUG_ON(NULL == msg);
/*
* @to-do
* validate the message major and minor version is correct
*/
/*
* Point to the message payload for further processing
*/
msg_payload = bcmbal_payload_ptr_get(bcmbal_bal_hdr_get_by_bcmos_hdr(msg));
/*
* These are messages from the BAL Utils
*
* - call into appropriate FSM
*
*/
BCM_LOG(DEBUG, log_id_core, "Received a Util message (payload at %p)\n", msg_payload);
if(BCMBAL_MAC_UTIL_MSG == bcmbal_type_major_get(msg_payload) &&
BAL_SUBSYSTEM_MAC_UTIL == bcmbal_sender_get(msg_payload))
{
/* Process the message */
process_util_msg(msg_payload);
}
else
{
BCM_LOG(FATAL, log_id_core, "message received with wrong major type/subsystem combination (%d/\%d)\n",
bcmbal_type_major_get(msg_payload),
bcmbal_sender_get(msg_payload));
BUG_ON(BCMOS_TRUE);
}
}
/*****************************************************************************/
/**
* @brief The BAL core util message processing function
*
* A Worker module function that handles messages received from the
* BAL utils via an RX thread.
*
* This function executes in the context of the worker thread
*
* @param msg_payload A pointer to the message to be processed
*
* @returns bcmos_errno
*
*****************************************************************************/
static bcmos_errno process_util_msg(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK;
bcmbal_obj_id objtype;
BCM_LOG(DEBUG, log_id_core, "Processing a util message\n");
objtype = bcmbal_msg_id_obj_get(msg_payload);
/*
* Process the util message based on the type of BAL object
* in the message.
*/
switch(objtype)
{
case BCMBAL_OBJ_ID_FLOW:
{
ret = process_flow_util_msg(msg_payload);
break;
}
case BCMBAL_OBJ_ID_GROUP:
{
ret = process_group_util_msg(msg_payload);
break;
}
case BCMBAL_OBJ_ID_ACCESS_TERMINAL:
{
ret = process_access_terminal_util_msg(msg_payload);
break;
}
case BCMBAL_OBJ_ID_INTERFACE:
{
ret = process_interface_util_msg(msg_payload);
break;
}
case BCMBAL_OBJ_ID_SUBSCRIBER_TERMINAL:
{
ret = process_subscriber_terminal_util_msg(msg_payload);
break;
}
case BCMBAL_OBJ_ID_TM_SCHED:
{
ret = process_tm_sched_util_msg(msg_payload);
break;
}
default:
{
BCM_LOG(ERROR, log_id_core,
"Unsupported object detected in message received from util\n");
ret = BCM_ERR_NOT_SUPPORTED;
break;
}
}
/*
* Free the message after processing
*/
bcmbal_msg_free(msg_payload);
return ret;
}
/*****************************************************************************/
/**
* @brief The BAL core "packet send" message processing function
*
* A Worker module function that handles packet send messages received from the
* BAL public API via an RX thread.
*
* This function executes in the context of the worker thread
*
* @param msg_payload A pointer to the message to be processed
*
* @returns bcmos_errno
*
*****************************************************************************/
static bcmos_errno process_packet_object(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK;
uint8_t *p_user_pkt;
uint16_t user_pkt_len;
uint8_t dst_port_id;
bcmos_bool b_port_id_is_nni;
bcmbal_packet_cfg *p_packet_obj;
uint16_t tunnel_tag_vlan_id = 0;
BCM_LOG(DEBUG, log_id_core, "Processing a \"Packet send\" message\n");
p_packet_obj = (bcmbal_packet_cfg *)msg_payload;
/* Extract the length of the user packet to be proxied */
user_pkt_len = p_packet_obj->data.pkt.len;
/* Derive a pointer to the user packet */
p_user_pkt = p_packet_obj->data.pkt.val;
BCM_LOG(DEBUG, log_id_core, "user packet first 12 bytes %02X%02X%02X%02X%02X%02X %02X%02X%02X%02X%02X%02X\n",
p_user_pkt[0], p_user_pkt[1], p_user_pkt[2], p_user_pkt[3], p_user_pkt[4], p_user_pkt[5],
p_user_pkt[6], p_user_pkt[7], p_user_pkt[8], p_user_pkt[9], p_user_pkt[10], p_user_pkt[11]);
/* Is this packet destined to an NNI or PON port? */
b_port_id_is_nni = (BCMBAL_DEST_TYPE_NNI == p_packet_obj->key.packet_send_dest.type) ?
BCMOS_TRUE : BCMOS_FALSE;
/*
* Process the message based on the type of BAL object
* in the message.
*/
switch(p_packet_obj->hdr.hdr.obj_type)
{
case BCMBAL_OBJ_ID_PACKET:
{
dst_port_id = (BCMOS_TRUE == b_port_id_is_nni) ?
(p_packet_obj->key.packet_send_dest.u.nni.int_id) :
(p_packet_obj->key.packet_send_dest.u.sub_term.int_id);
if(BCMOS_FALSE == b_port_id_is_nni)
{
/*
* Packets destined to a PON interface require a tunnel tag
*
* Get the svc_port_id for the first flow on the subscriber terminal (if there is one)
*/
if(BCM_ERR_OK != svc_port_id_for_sub_term_ds_flow_get(p_packet_obj->key.packet_send_dest.u.sub_term.int_id,
p_packet_obj->key.packet_send_dest.u.sub_term.sub_term_id,
p_packet_obj->key.packet_send_dest.u.sub_term.sub_term_uni,
&tunnel_tag_vlan_id))
{
BCM_LOG(ERROR,
log_id_core,
"Packet send could not find any downstream FLOW to send packet for sub_term_id %d (PON %d)\n",
p_packet_obj->key.packet_send_dest.u.sub_term.sub_term_id,
p_packet_obj->key.packet_send_dest.u.sub_term.int_id);
ret = BCM_ERR_NOENT;
break;
}
}
ret = sw_util_pkt_send(dst_port_id,
(b_port_id_is_nni ? REASON_SEND_TO_NNI : REASON_SEND_TO_PON),
p_user_pkt,
user_pkt_len,
(int)tunnel_tag_vlan_id);
}
break;
default:
{
BCM_LOG(ERROR, log_id_core,
"Unsupported object detected in \"packet send\" message\n");
ret = BCM_ERR_NOT_SUPPORTED;
}
break;
}
/*
* NOTE: DO NOT free the message after processing here. It is freed in the calling function
*/
return ret;
}
/*@}*/