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
291 lines
9.9 KiB
C
291 lines
9.9 KiB
C
/*
|
|
* 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]);
|
|
}
|
|
}
|
|
}
|
|
}
|