Implementation of PNF using WLS as message transport

The common library exposes functions for the PNF to return the received blocks to the VNF for it to call WLS_Enqueue on them.
This is done in order to ensure the Blocks are returned after processing, also preventing the Dequeueing of blocks that are still being used, i.e. the internal value is not -1
All saved blocks are to be enqueued at the reception of a SLOT.indication by the VNF

Additionally, the definition of NFAPI_MAX_PACKED_MESSAGE_SIZE was moved to nfapi_interface.h and removed from the other headers, this is done to allow to set the maximum message size when using WLS by only changing the value in one place

Fixup fapi_nr_message_header_unpack call in nfapi_hex_parser
This commit is contained in:
Rúben Soares Silva
2025-07-11 10:01:26 +01:00
parent 9b71f1d324
commit 3d34917626
25 changed files with 698 additions and 39 deletions
+28 -1
View File
@@ -63,6 +63,12 @@
#include "executables/lte-softmodem.h"
#include "nfapi/open-nFAPI/pnf/inc/pnf_p7.h"
#ifdef ENABLE_WLS
#include <nr_fapi_p5.h>
#include <nr_fapi_p7.h>
#include "nfapi/oai_integration/wls_integration/include/wls_pnf.h"
#endif
#ifdef ENABLE_SOCKET
#include <socket/include/socket_pnf.h>
#endif
@@ -1752,6 +1758,15 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf
p7_config->codec_config.unpack_vendor_extension_tlv = &pnf_nr_phy_unpack_vendor_extension_tlv;
p7_config->codec_config.pack_vendor_extension_tlv = &pnf_nr_phy_pack_vendor_extention_tlv;
#ifdef ENABLE_WLS
p7_config->unpack_func = &fapi_nr_p7_message_unpack;
p7_config->hdr_unpack_func = &fapi_nr_p7_message_header_unpack;
p7_config->pack_func = &fapi_nr_p7_message_pack;
p7_config->send_p7_msg = &wls_pnf_nr_send_p7_message;
// pass p7_config to WLS handler
wls_pnf_set_p7_config(p7_config);
#endif
#ifdef ENABLE_SOCKET
p7_config->unpack_func = &nfapi_nr_p7_message_unpack;
p7_config->hdr_unpack_func = &nfapi_nr_p7_message_header_unpack;
@@ -1806,10 +1821,11 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf
usleep(50000);
printf("[PNF] waiting for OAI to be started\n");
}
#ifndef ENABLE_WLS
printf("[PNF] Sending PNF_START_RESP\n");
nfapi_nr_send_pnf_start_resp(config, p7_config->phy_id);
printf("[PNF] Sending first P7 slot indication\n");
#endif
#if 1
nfapi_pnf_p7_slot_ind(p7_config, p7_config->phy_id, 0, 0);
printf("[PNF] Sent first P7 slot ind\n");
@@ -2192,6 +2208,17 @@ void configure_nr_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_add
config->codec_config.unpack_p4_p5_vendor_extension = &pnf_nr_sim_unpack_p4_p5_vendor_extension;
config->codec_config.pack_p4_p5_vendor_extension = &pnf_nr_sim_pack_p4_p5_vendor_extension;
#ifdef ENABLE_WLS
printf("WLS MODE PNF\n");
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating WLS PNF NFAPI start thread %s\n", __FUNCTION__);
// Assume it's the FAPI handler, change from within the PNF if it's not the case
config->unpack_func = &fapi_nr_p5_message_unpack;
config->hdr_unpack_func = &fapi_nr_message_header_unpack;
config->pack_func = &fapi_nr_p5_message_pack;
config->send_p5_msg = &wls_pnf_nr_send_p5_message;
//wls_fapi_pnf_nr_start_thread(config);
threadCreate(&pnf_p5_init_and_receive_pthread, wls_fapi_pnf_nr_start_thread, config, "NFAPI_WLS_PNF", -1, OAI_PRIORITY_RT_MAX);
#endif
#ifdef ENABLE_SOCKET
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating PNF NFAPI start thread %s\n", __FUNCTION__);
@@ -0,0 +1,21 @@
message(STATUS "Building with support for WLS")
add_library(wls_integration_lib
wls_pnf.c
wls_common.c
)
find_library(WLS_LIB wls REQUIRED)
message(STATUS " wls library found in ${WLS_LIB}")
find_library(hugetlbfs_LIB hugetlbfs REQUIRED)
message(STATUS " hugetlbfs library found in ${hugetlbfs_LIB}")
pkg_check_modules(dpdk REQUIRED libdpdk=20.11.3)
target_link_libraries(wls_integration_lib PRIVATE ${dpdk_LINK_LIBRARIES})
target_include_directories(wls_integration_lib PRIVATE ${dpdk_INCLUDE_DIRS})
target_include_directories(wls_integration_lib PRIVATE include/)
target_compile_definitions(wls_integration_lib PUBLIC ENABLE_WLS)
target_link_libraries(wls_integration_lib PRIVATE NFAPI_LIB NFAPI_USER_LIB)
target_link_libraries(wls_integration_lib PRIVATE nr_fapi_p5 nr_fapi_p7)
target_link_libraries(wls_integration_lib PRIVATE "${WLS_LIB}" "${hugetlbfs_LIB}")
@@ -0,0 +1,108 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef OPENAIRINTERFACE_WLS_COMMON_H
#define OPENAIRINTERFACE_WLS_COMMON_H
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "wls_lib.h"
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h"
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h"
#define WLS_DEV_NAME "wls"
#define WLS_MAC_MEMORY_SIZE 0x7F000000
#define WLS_PHY_MEMORY_SIZE 0x7F000000
#define MAX_NUM_LOCATIONS (508)
#define MIN_DL_BUF_LOCATIONS (0) /* Used for stats collection 0-49 */
#define MIN_UL_BUF_LOCATIONS (MIN_DL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 50-99 */
#define MAX_DL_BUF_LOCATIONS (MIN_DL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 0-49 */
#define MAX_UL_BUF_LOCATIONS (MIN_UL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 50-99 */
#define ALLOC_TRACK_SIZE ( 16384 )
typedef struct {
uint64_t *values;
uint16_t values_size;
uint16_t values_count;
}pa_store_t;
/* ----- WLS Operation --- */
#define FAPI_VENDOR_MSG_HEADER_IND 0x1A
// Linked list header present at the top of all messages
typedef struct _fapi_api_queue_elem {
struct _fapi_api_queue_elem *p_next;
// p_tx_data_elm_list used for TX_DATA.request processing
struct _fapi_api_queue_elem *p_tx_data_elm_list;
uint8_t msg_type;
uint8_t num_message_in_block;
uint32_t msg_len;
uint32_t align_offset;
uint64_t time_stamp;
} fapi_api_queue_elem_t,
*p_fapi_api_queue_elem_t;
typedef struct wls_mac_mem_array
{
void **ppFreeBlock;
void *pStorage;
void *pEndOfStorage;
uint32_t nBlockSize;
uint32_t nBlockCount;
} WLS_MAC_MEM_SRUCT, *PWLS_MAC_MEM_SRUCT;
typedef struct wls_mac_ctx
{
void *hWls;
void *pWlsMemBase;
void *pWlsMemBaseUsable;
WLS_MAC_MEM_SRUCT sWlsStruct;
uint64_t nTotalMemorySize;
uint64_t nTotalMemorySizeUsable;
uint32_t nBlockSize;
uint32_t nTotalBlocks;
uint32_t nAllocBlocks;
uint32_t nTotalAllocCnt;
uint32_t nTotalFreeCnt;
uint32_t nTotalUlBufAllocCnt;
uint32_t nTotalUlBufFreeCnt;
uint32_t nTotalDlBufAllocCnt;
uint32_t nTotalDlBufFreeCnt;
// Support for FAPI Translator
uint32_t nPartitionMemSize;
void *pPartitionMemBase;
volatile pthread_mutex_t lock;
volatile pthread_mutex_t lock_alloc;
} WLS_MAC_CTX, *PWLS_MAC_CTX;
void fill_fapi_list_elem(p_fapi_api_queue_elem_t currElem, p_fapi_api_queue_elem_t nextElem, const uint8_t msgType, const uint8_t numMsgInBlock, const uint32_t alignOffset);
uint64_t dequeueBlock(PWLS_MAC_CTX pWls);
void wls_return_msg_to_master(PWLS_MAC_CTX pWls, const uint64_t msg_PA);
uint8_t wls_send_fapi_msg(PWLS_MAC_CTX pWls, const uint16_t message_id, const int packed_len, const uint8_t *message );
uint8_t wls_msg_send(PWLS_MAC_CTX pWls, p_fapi_api_queue_elem_t currMsg);
#endif //OPENAIRINTERFACE_WLS_COMMON_H
@@ -0,0 +1,33 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef OPENAIRINTERFACE_WLS_PNF_H
#define OPENAIRINTERFACE_WLS_PNF_H
#include "nfapi_pnf_interface.h"
#include "pnf.h"
#include "wls_common.h"
bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len);
bool wls_pnf_nr_send_p7_message(pnf_p7_t* pnf_p7,nfapi_nr_p7_message_header_t *msg, uint32_t msg_len);
void *wls_fapi_pnf_nr_start_thread(void *ptr);
int wls_fapi_nr_pnf_start();
void wls_pnf_set_p7_config(void *p7_config);
#endif // OPENAIRINTERFACE_WLS_PNF_H
@@ -0,0 +1,118 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "wls_common.h"
void fill_fapi_list_elem(p_fapi_api_queue_elem_t currElem, p_fapi_api_queue_elem_t nextElem, const uint8_t msgType, const uint8_t numMsgInBlock, const uint32_t alignOffset)
{
currElem->msg_type = msgType;
currElem->num_message_in_block = numMsgInBlock;
currElem->align_offset = alignOffset;
currElem->msg_len = numMsgInBlock * alignOffset;
currElem->p_next = nextElem;
currElem->p_tx_data_elm_list = NULL;
currElem->time_stamp = 0;
}
uint64_t dequeueBlock(PWLS_MAC_CTX pWls)
{
uint64_t pa = WLS_DequeueBlock(pWls->hWls);
AssertFatal(pa, "WLS_DequeueBlock failed for pa_hdr\n");
unsigned long* va = WLS_PA2VA(pWls->hWls, pa);
AssertFatal(va, "WLS_PA2VA failed for headerElem\n");
while (*va != -1) {
pa = WLS_DequeueBlock(pWls->hWls);
AssertFatal(pa, "WLS_DequeueBlock failed for pa_hdr\n");
va = WLS_PA2VA(pWls->hWls, pa);
}
return pa;
}
uint8_t wls_msg_send(PWLS_MAC_CTX pWls, p_fapi_api_queue_elem_t currMsg)
{
uint32_t msgLen = 0;
AssertFatal(currMsg, "currMsg can't be NULL");
AssertFatal(currMsg->p_next, "There needs to be at least 2 blocks to send!");
msgLen = currMsg->msg_len + sizeof(fapi_api_queue_elem_t);
// Send the first block
if (WLS_Put(pWls, WLS_VA2PA(pWls, currMsg), msgLen, currMsg->msg_type, WLS_SG_FIRST) != 0) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failure in sending the header block\n");
return false;
}
// Iterate over the linked list, until a NULL block or a block set to 0xFFFFFFFFFFFFFFFF ( invalid )
while (((currMsg = currMsg->p_next)) && (uint64_t)(currMsg) != -1) {
msgLen = currMsg->msg_len + sizeof(fapi_api_queue_elem_t);
/* Send the block with appropriate flags, either WLS_SG_NEXT or WLS_SG_LAST */
const unsigned short flags = currMsg->p_next != NULL ? WLS_SG_NEXT : WLS_SG_LAST;
if (WLS_Put(pWls, WLS_VA2PA(pWls, currMsg), msgLen, currMsg->msg_type, flags) != 0) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failure in sending the message block\n");
return false;
}
}
return true;
}
void wls_return_msg_to_master(PWLS_MAC_CTX pWls,const uint64_t msg_PA)
{
p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, msg_PA);
AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n");
const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle
// No need to return the message contents, just the block
fill_fapi_list_elem(fapiMsgElem, NULL, FAPI_VENDOR_MSG_HEADER_IND, 1, 2);
memcpy((uint8_t *)(fapiMsgElem + 1), wls_header, 2);
const uint32_t msgLen = fapiMsgElem->msg_len + sizeof(fapi_api_queue_elem_t);
/* Send the block with appropriate only WLS_SG_FIRST flag, since we send only 1 block*/
if (WLS_Put(pWls->hWls, msg_PA, msgLen, FAPI_VENDOR_MSG_HEADER_IND, WLS_SG_FIRST) != 0) {
NFAPI_TRACE(NFAPI_TRACE_ERROR,"Failure in sending block back to master\n");
}
}
uint8_t wls_send_fapi_msg(PWLS_MAC_CTX pWls, const uint16_t message_id, const int packed_len, const uint8_t *message)
{
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);
NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks);
}
/* get PA blocks for header and msg */
uint64_t pa_hdr = dequeueBlock(pWls);
AssertFatal(pa_hdr, "WLS_DequeueBlock failed for pa_hdr\n");
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");
fill_fapi_list_elem(fapiMsgElem, NULL, message_id, 1, packed_len + NFAPI_HEADER_LENGTH);
memcpy((uint8_t *)(fapiMsgElem + 1), message, packed_len + NFAPI_HEADER_LENGTH);
uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle
if (NFAPI_MODE == NFAPI_MODE_VNF) {
// Use the opaque handle to signal to our PNF to not progress the FAPI PNF state machine
wls_header[1] = 0xff;
}
fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2);
memcpy((uint8_t *)(headerElem + 1), wls_header, 2);
uint8_t retval = wls_msg_send(pWls->hWls, headerElem);
return retval;
}
@@ -0,0 +1,290 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#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 "pnf.h"
#include "nr_nfapi_p7.h"
#include "nr_fapi_p5.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;
}
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 = (nfapi_pnf_phy_config_t *)malloc(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_VARIABLE(msg_len);
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);
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) {
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;
}
}
}
}
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]);
}
}
}
}