/* * 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 #include #include #include #include #include #include #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_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); 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]); } } } }