mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
308 lines
9.9 KiB
C
308 lines
9.9 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
#include "wls_pnf.h"
|
|
|
|
#include <rte_eal.h>
|
|
#include <rte_string_fns.h>
|
|
#include <rte_common.h>
|
|
#include <rte_lcore.h>
|
|
#include <rte_debug.h>
|
|
#include <pnf_p7.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "wls_lib.h"
|
|
#include "pnf.h"
|
|
#include "nr_nfapi_p7.h"
|
|
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h"
|
|
|
|
// A copy of the PNF P7 config is needed for the message processing thread, in other transport mechanisms where P7 is handled in a
|
|
// different thread, the config is passed to it upon the thread creation
|
|
nfapi_pnf_p7_config_t *wls_pnf_p7_config = NULL;
|
|
|
|
void wls_pnf_set_p7_config(void *p7_config)
|
|
{
|
|
wls_pnf_p7_config = (nfapi_pnf_p7_config_t *)p7_config;
|
|
}
|
|
|
|
static WLS_MAC_CTX g_phy_wls;
|
|
uint8_t phy_dpdk_init(void);
|
|
uint8_t phy_wls_init(const char *dev_name, uint64_t nWlsMacMemSize, uint64_t nWlsPhyMemSize);
|
|
void phy_mac_recv();
|
|
void wls_mac_print_stats(void);
|
|
|
|
pnf_t *_this = NULL;
|
|
|
|
static PWLS_MAC_CTX wls_mac_get_ctx(void)
|
|
{
|
|
return &g_phy_wls;
|
|
}
|
|
|
|
static nfapi_pnf_config_t *cfg;
|
|
|
|
void *wls_fapi_pnf_nr_start_thread(void *ptr)
|
|
{
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN WLS PNF NFAPI start thread %s\n", __FUNCTION__);
|
|
cfg = (nfapi_pnf_config_t *)ptr;
|
|
wls_fapi_nr_pnf_start();
|
|
return (void *)0;
|
|
}
|
|
|
|
void wls_pnf_close(pthread_t p5_thread)
|
|
{
|
|
_this->terminate = 1;
|
|
WLS_WakeUp(wls_mac_get_ctx()->hWls);
|
|
pthread_join(p5_thread, NULL);
|
|
if (WLS_Close(wls_mac_get_ctx()->hWls) != 0) {
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] WLS_CLose call failed...\n");
|
|
} else {
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] WLS_CLose called successfully...\n");
|
|
}
|
|
rte_eal_cleanup();
|
|
}
|
|
|
|
void wls_fapi_nr_pnf_stop()
|
|
{
|
|
AssertFatal(cfg->nr_stop_req, "STOP.request Handler should be set!");
|
|
nfapi_nr_stop_request_scf_t req = {0};
|
|
req.header.phy_id = 0;
|
|
req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST;
|
|
cfg->nr_stop_req(cfg, 0, &req);
|
|
}
|
|
|
|
int wls_fapi_nr_pnf_start()
|
|
{
|
|
int64_t ret;
|
|
// Verify that config is not null
|
|
if (cfg == 0)
|
|
return -1;
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__);
|
|
|
|
_this = (pnf_t *)(cfg);
|
|
_this->terminate = 0;
|
|
// Init PNF config
|
|
nfapi_pnf_phy_config_t *phy = malloc_or_fail(sizeof(nfapi_pnf_phy_config_t));
|
|
memset(phy, 0, sizeof(nfapi_pnf_phy_config_t));
|
|
|
|
phy->state = NFAPI_PNF_PHY_IDLE;
|
|
phy->phy_id = 0;
|
|
phy->next = (_this->_public).phys;
|
|
(_this->_public).phys = phy;
|
|
_this->_public.state = NFAPI_PNF_RUNNING;
|
|
|
|
// DPDK init
|
|
ret = phy_dpdk_init();
|
|
if (!ret) {
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "[PNF] DPDK Init - Failed\n");
|
|
return false;
|
|
}
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] DPDK Init - Done\n");
|
|
|
|
// WLS init
|
|
ret = phy_wls_init(WLS_DEV_NAME, WLS_MAC_MEMORY_SIZE, WLS_PHY_MEMORY_SIZE);
|
|
if (!ret) {
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "[PNF] WLS Init - Failed\n");
|
|
return false;
|
|
}
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] WLS Init - Done\n");
|
|
|
|
// Start Receiving loop from the VNF
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "Start Receiving loop from the VNF\n");
|
|
phy_mac_recv();
|
|
// Should never get here, to be removed, align with present implementation of PNF loop
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] Exiting...\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
uint8_t phy_dpdk_init(void)
|
|
{
|
|
unsigned long i;
|
|
char *argv[] = {"OAI_PNF", "--proc-type=primary", "--file-prefix", WLS_DEV_NAME, "--iova-mode=pa", "--no-pci"};
|
|
int argc = RTE_DIM(argv);
|
|
/* initialize EAL first */
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] Calling rte_eal_init: ");
|
|
|
|
for (i = 0; i < RTE_DIM(argv); i++) {
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s ", argv[i]);
|
|
}
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n");
|
|
|
|
if (rte_eal_init(argc, argv) < 0)
|
|
rte_panic("Cannot init EAL\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
uint8_t phy_wls_init(const char *dev_name, uint64_t nWlsMacMemSize, uint64_t nWlsPhyMemSize)
|
|
// uint8_t phy_wls_init(const char *dev_name, uint64_t nBlockSize)
|
|
{
|
|
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
|
|
pWls->nTotalAllocCnt = 0;
|
|
pWls->nTotalFreeCnt = 0;
|
|
pWls->nTotalUlBufAllocCnt = 0;
|
|
pWls->nTotalUlBufFreeCnt = 0;
|
|
pWls->nTotalDlBufAllocCnt = 0;
|
|
pWls->nTotalDlBufFreeCnt = 0;
|
|
|
|
pWls->hWls = WLS_Open(dev_name, WLS_SLAVE_CLIENT, &nWlsMacMemSize, &nWlsPhyMemSize);
|
|
if (pWls->hWls) {
|
|
/* allocate chuck of memory */
|
|
if (WLS_Alloc(pWls->hWls, nWlsMacMemSize + nWlsPhyMemSize) != NULL) {
|
|
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "WLS Memory allocated successfully\n");
|
|
} else {
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unable to alloc WLS Memory\n");
|
|
return false;
|
|
}
|
|
} else {
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "can't open WLS instance");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len)
|
|
{
|
|
int packed_len = cfg->pack_func(msg, msg_len, pnf->tx_message_buffer, sizeof(pnf->tx_message_buffer), &pnf->_public.codec_config);
|
|
|
|
if (packed_len < 0) {
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed (%d)\n", packed_len);
|
|
return false;
|
|
}
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "fapi_nr_p5_message_pack succeeded having packed %d bytes\n", packed_len);
|
|
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "in msg, msg_len is %d\n", msg->message_length);
|
|
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
|
|
|
|
|
|
return wls_send_fapi_msg(pWls, msg->message_id, packed_len, pnf->tx_message_buffer);
|
|
}
|
|
|
|
bool wls_pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *msg, uint32_t msg_len)
|
|
{
|
|
UNUSED(msg_len);
|
|
if (pnf_p7->terminate) {
|
|
// don't send any further P7 messages after terminating
|
|
return false;
|
|
}
|
|
if (!isFAPIMessageIDValid(msg->message_id)) {
|
|
return false;
|
|
}
|
|
|
|
// if it's an nFAPI message, ignore
|
|
if ((msg->message_id == NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC || msg->message_id == NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC
|
|
|| msg->message_id == NFAPI_NR_PHY_MSG_TYPE_TIMING_INFO)) {
|
|
return false;
|
|
}
|
|
|
|
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
|
|
int num_avail_blocks = WLS_NumBlocks(pWls->hWls);
|
|
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks);
|
|
while (num_avail_blocks < 2) {
|
|
num_avail_blocks = WLS_NumBlocks(pWls->hWls);
|
|
if (_this->terminate) {
|
|
return false;
|
|
}
|
|
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks);
|
|
}
|
|
/* get PA blocks for header and msg */
|
|
const uint64_t pa_hdr = dequeueBlock(pWls);
|
|
AssertFatal(pa_hdr, "WLS_DequeueBlock failed for pa_hdr\n");
|
|
const uint64_t pa_msg = dequeueBlock(pWls);
|
|
AssertFatal(pa_msg, "WLS_DequeueBlock failed for pa_msg\n");
|
|
p_fapi_api_queue_elem_t headerElem = WLS_PA2VA(pWls->hWls, pa_hdr);
|
|
AssertFatal(headerElem, "WLS_PA2VA failed for headerElem\n");
|
|
p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, pa_msg);
|
|
AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n");
|
|
const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle
|
|
fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2);
|
|
memcpy((uint8_t *)(headerElem + 1), wls_header, 2);
|
|
|
|
const int packed_len = ((nfapi_pnf_p7_config_t *)pnf_p7)->pack_func(msg, (fapiMsgElem + 1), NFAPI_MAX_PACKED_MESSAGE_SIZE, NULL);
|
|
|
|
if (packed_len < 0) {
|
|
NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p7_message_pack failed (%d)\n", packed_len);
|
|
return false;
|
|
}
|
|
fill_fapi_list_elem(fapiMsgElem, NULL, msg->message_id, 1, packed_len + NFAPI_HEADER_LENGTH);
|
|
const uint8_t retval = wls_msg_send(pWls->hWls, headerElem);
|
|
return retval;
|
|
}
|
|
|
|
static void procPhyMessages(uint32_t msg_size, void *msg_buf, uint16_t msg_id)
|
|
{
|
|
|
|
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "[PHY] Received Msg ID 0x%02x Length %d\n", msg_id, msg_size);
|
|
if (msg_buf == NULL || _this == NULL) {
|
|
AssertFatal(msg_buf != NULL && _this != NULL, "%s: NULL parameters\n", __FUNCTION__);
|
|
}
|
|
// Add the size of the header to the message_size, because the size in the header does not include the header length
|
|
msg_size += NFAPI_NR_P5_HEADER_LENGTH;
|
|
switch (msg_id) {
|
|
case NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST:
|
|
pnf_nr_handle_p5_message(_this, msg_buf, msg_size);
|
|
break;
|
|
case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: {
|
|
pnf_nr_handle_p7_message(msg_buf, msg_size, (pnf_p7_t *)wls_pnf_p7_config, 0);
|
|
break;
|
|
}
|
|
default:
|
|
printf("\n Unknown Msg ID 0x%02x\n", msg_id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void phy_mac_recv()
|
|
{
|
|
/* Number of Memory blocks to get */
|
|
uint32_t msgSize;
|
|
uint16_t msgType;
|
|
uint16_t flags;
|
|
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
|
|
// This flag is used to determine whether to return the received blocks to the PNF
|
|
bool to_return = false;
|
|
while (_this->terminate == 0) {
|
|
int numMsgToGet = WLS_Wait(pWls->hWls);
|
|
if (numMsgToGet == 0 || _this->terminate) {
|
|
continue;
|
|
}
|
|
uint64_t PAs[numMsgToGet];
|
|
uint8_t pa_idx = 0;
|
|
while (numMsgToGet--) {
|
|
PAs[pa_idx] = WLS_Get(pWls->hWls, &msgSize, &msgType, &flags);
|
|
pa_idx++;
|
|
}
|
|
for (int i = 0; i < pa_idx; i++) {
|
|
p_fapi_api_queue_elem_t msg = WLS_PA2VA(pWls->hWls, PAs[i]);
|
|
if (msg->msg_type != FAPI_VENDOR_MSG_HEADER_IND) {
|
|
uint8_t *msgt = (uint8_t *)(msg + 1);
|
|
uint32_t len = msgt[7] | (msgt[6] << 8) | (msgt[5] << 16) | (msgt[4] << 24);
|
|
procPhyMessages(len, (void *)(msg + 1), msg->msg_type);
|
|
} else {
|
|
// We check the header block to determine if it's the OAI VNF, if so, we're required to return the pages for enqueueing
|
|
if (!to_return) {
|
|
uint8_t *msgt = (uint8_t *)(msg + 1);
|
|
if (msgt[1] == 0xff) {
|
|
to_return = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// A STOP.indication might have been processed, which set's terminate to 1
|
|
// don't return pages in that case
|
|
if (_this->terminate) {
|
|
break;
|
|
}
|
|
if (to_return) {
|
|
// We only return the pages to be enqueued in case we're using the OAI VNF,
|
|
// The Radisys O-DU handles enqueueing the blocks differently, and also doesn't handle receiving a single block
|
|
for (int i = 0; i < pa_idx; i++) {
|
|
wls_return_msg_to_master(pWls, PAs[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|