From da63bf9f9ff83f2e1a4b88292e086475519e1c2a Mon Sep 17 00:00:00 2001 From: Teodora Date: Sat, 15 Feb 2025 17:23:42 +0100 Subject: [PATCH] M-plane integration - initial commit --- cmake_targets/build_oai | 6 +- radio/fhi_72/CMakeLists.txt | 12 ++- radio/fhi_72/mplane/CMakeLists.txt | 64 ++++++++++++++ radio/fhi_72/mplane/init-mplane.c | 131 ++++++++++++++++++++++++++++ radio/fhi_72/mplane/init-mplane.h | 30 +++++++ radio/fhi_72/mplane/ru-mplane-api.h | 95 ++++++++++++++++++++ radio/fhi_72/oran_isolate.c | 61 +++++++------ 7 files changed, 363 insertions(+), 36 deletions(-) create mode 100644 radio/fhi_72/mplane/CMakeLists.txt create mode 100644 radio/fhi_72/mplane/init-mplane.c create mode 100644 radio/fhi_72/mplane/init-mplane.h create mode 100644 radio/fhi_72/mplane/ru-mplane-api.h diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index d92e488e90..003527056f 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -99,7 +99,7 @@ Options: USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default) Adds this RF board support (in external packages installation and in compilation) -t | --transport - Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g + Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g, oran_fhlib_5g_mplane -P | --phy_simulators Makes the unitary tests Layer 1 simulators -s | --check @@ -304,6 +304,10 @@ function main() { TARGET_LIST="$TARGET_LIST $2" CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON" ;; + "oran_fhlib_5g_mplane") + TARGET_LIST="$TARGET_LIST $2" + CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON" + ;; "None") ;; *) diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index dd31db27f2..8b047a9316 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -30,15 +30,19 @@ endif() add_compile_options(-Wno-packed-not-aligned) set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") -target_link_libraries(oran_fhlib_5g PRIVATE xran::xran) -target_link_libraries(oran_fhlib_5g PRIVATE ${dpdk_LINK_LIBRARIES}) +target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) -target_link_libraries(oran_fhlib_5g PRIVATE pthread dl rt m numa) -target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB}) add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON) +message(STATUS "Building FHI72 CUS library") + set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oran_fhlib_5g POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_boolean_option(OAI_FHI72_MPLANE OFF "Activate OAI's FHI 7.2 M-plane support" OFF) +if(OAI_FHI72_MPLANE) + add_subdirectory(mplane) +endif() diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt new file mode 100644 index 0000000000..7cc53dd40f --- /dev/null +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -0,0 +1,64 @@ +add_library(oran_fhlib_5g_mplane MODULE + ../oran_isolate.c + ../oaioran.c + ../oran-config.c + ../oran-init.c +) +add_dependencies(oran_fhlib_5g_mplane oran_fhlib_5g) + +if(xran_VERSION VERSION_EQUAL 5.1.4) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE E_RELEASE) +elseif(xran_VERSION VERSION_EQUAL 6.1.1) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE F_RELEASE) +endif() + +# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress +# alignment 1 of 'struct XYZ' is less than 2 +add_compile_options(-Wno-packed-not-aligned) + +set_target_properties(oran_fhlib_5g_mplane PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") +target_link_libraries(oran_fhlib_5g_mplane PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) +target_include_directories(oran_fhlib_5g_mplane PRIVATE ${dpdk_INCLUDE_DIRS}) + +target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE) + +################################################### + +target_sources(oran_fhlib_5g_mplane PRIVATE + init-mplane.c +) + +pkg_check_modules(libyang REQUIRED libyang) +pkg_check_modules(libnetconf2 REQUIRED libnetconf2) + +if(libyang_VERSION VERSION_LESS_EQUAL 1.0.240 AND libnetconf2_VERSION VERSION_LESS_EQUAL 1.1.46) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE MPLANE_V1) +elseif((libyang_VERSION VERSION_GREATER 1.0.240 AND libyang_VERSION VERSION_LESS 2.1.4)) + message(FATAL_ERROR "Minimum libyang v2 subversion required is v2.1.4, but found ${libyang_VERSION}") +elseif((libnetconf2_VERSION VERSION_GREATER 1.1.46 AND libnetconf2_VERSION VERSION_LESS 2.1.25)) + message(FATAL_ERROR "Minimum libnetconf2 v2 subversion required is v2.1.25, but found ${libnetconf2_VERSION}") +elseif((libyang_VERSION VERSION_GREATER_EQUAL 2.1.4 AND libyang_VERSION VERSION_LESS_EQUAL 2.1.111) AND (libnetconf2_VERSION VERSION_GREATER_EQUAL 2.1.25 AND libnetconf2_VERSION VERSION_LESS_EQUAL 2.1.37)) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE MPLANE_V2) +else() + message(FATAL_ERROR "Unknown libyang version ${libyang_VERSION} and libnetconf2 version ${libnetconf2_VERSION}") +endif() + +target_include_directories(oran_fhlib_5g_mplane PRIVATE ${libyang_INCLUDE_DIRS} ${libnetconf2_INCLUDE_DIRS}) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE ${libyang_LDFLAGS} ${libyang_LINK_LIBRARIES} ${libnetconf2_LINK_LIBRARIES}) + +pkg_check_modules(libssh REQUIRED libssh) +target_include_directories(oran_fhlib_5g_mplane PRIVATE ${libssh_INCLUDE_DIRS}) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE ${libssh_LINK_LIBRARIES}) + +find_package(LibXml2 REQUIRED) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE LibXml2::LibXml2) + +set(YANG_MODELS "${CMAKE_SOURCE_DIR}/radio/fhi_72/mplane/yang/models") +target_compile_definitions(oran_fhlib_5g_mplane PRIVATE YANG_MODELS="${YANG_MODELS}") + +message(STATUS "Building FHI72 CUSM library") + +set_target_properties(oran_fhlib_5g_mplane PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +add_custom_command(TARGET oran_fhlib_5g_mplane POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g_mplane.so liboai_transpro.so + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c new file mode 100644 index 0000000000..31988f3dba --- /dev/null +++ b/radio/fhi_72/mplane/init-mplane.c @@ -0,0 +1,131 @@ +/* + * 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 "init-mplane.h" +#include "radio/fhi_72/oran-params.h" + +#include +#include + +static void lnc2_print_clb(NC_VERB_LEVEL level, const char *msg) +{ + switch (level) { + case NC_VERB_ERROR: + MP_LOG_I("[LIBNETCONF2] ERROR: %s.\n", msg); + break; + case NC_VERB_WARNING: + MP_LOG_I("[LIBNETCONF2] WARNING: %s.\n", msg); + break; + case NC_VERB_VERBOSE: + MP_LOG_I("[LIBNETCONF2] VERBOSE: %s.\n", msg); + break; + case NC_VERB_DEBUG: + case NC_VERB_DEBUG_LOWLVL: + MP_LOG_I("[LIBNETCONF2] DEBUG: %s.\n", msg); + break; + default: + assert(false && "[LIBNETCONF2] Unknown log level."); + } +} + +static void ly_print_clb(LY_LOG_LEVEL level, const char *msg, const char *path) +{ + switch (level) { + case LY_LLERR: + MP_LOG_I("[LIBYANG] ERROR: %s (path: %s).\n", msg, path); + break; + case LY_LLWRN: + MP_LOG_I("[LIBYANG] WARNING: %s (path: %s).\n", msg, path); + break; + case LY_LLVRB: + MP_LOG_I("[LIBYANG] VERBOSE: %s (path: %s).\n", msg, path); + break; + case LY_LLDBG: + MP_LOG_I("[LIBYANG] DEBUG: %s (path: %s).\n", msg, path); + break; + default: + assert(false && "[LIBYANG] Unknown log level."); + } +} + +static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name) +{ + /* the config module does not know const-correctness... */ + int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name); + DevAssert(idx >= 0); + return &pd[idx]; +} + +bool init_mplane(ru_session_list_t *ru_session_list) +{ + paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC; + int nump = sizeofArray(fhip); + int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN); + if (ret <= 0) { + MP_LOG_I("Problem reading section \"%s\".\n", CONFIG_STRING_ORAN); + return false; + } + + ru_session_list->du_key_pair = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->strlistptr; + int num_keys = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->numelt; + AssertError(num_keys == 2, return false, "[MPLANE] Expected {pub-key-path, priv-key-path}. Loaded {%s, %s}.\n", ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]); + + char **ru_ip_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->strlistptr; + int num_rus = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->numelt; + char **du_mac_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr; + int num_dus = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt; + int32_t *vlan_tag = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->iptr; + int num_vlan_tags = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->numelt; + + AssertError(num_dus == num_vlan_tags, return false, "[MPLANE] Number of DU MAC addresses should be equal to the number of VLAN tags.\n"); + + int num_cu_planes = num_dus / num_rus; + + ru_session_list->num_rus = num_rus; + ru_session_list->ru_session = calloc(num_rus, sizeof(ru_session_t)); + for (size_t i = 0; i < num_rus; i++) { + ru_session_t *ru_session = &ru_session_list->ru_session[i]; + ru_session->session = NULL; + ru_session->ru_ip_add = calloc(strlen(ru_ip_addrs[i]) + 1, sizeof(char)); + memcpy(ru_session->ru_ip_add, ru_ip_addrs[i], strlen(ru_ip_addrs[i]) + 1); + + // store DU MAC addresses and VLAN tags + ru_session->ru_mplane_config.num_cu_planes = num_cu_planes; + ru_session->ru_mplane_config.du_mac_addr = calloc_or_fail(num_cu_planes, sizeof(char*)); + ru_session->ru_mplane_config.vlan_tag = calloc_or_fail(num_cu_planes, sizeof(int32_t)); + for (int j = 0; j < num_cu_planes; j++) { + const int idx = i*num_cu_planes+j; + ru_session->ru_mplane_config.du_mac_addr[j] = calloc(1, strlen(du_mac_addr[idx]) + 1); + memcpy(ru_session->ru_mplane_config.du_mac_addr[j], du_mac_addr[idx], strlen(du_mac_addr[idx]) + 1); + ru_session->ru_mplane_config.vlan_tag[j] = vlan_tag[idx]; + } + } + + nc_client_init(); + int keypair_ret = nc_client_ssh_add_keypair(ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]); + AssertError(keypair_ret == 0, return false, "[MPLANE] Unable to add DU ssh key pair.\n"); + + // logs for netconf2 and yang libraries + nc_set_print_clb(lnc2_print_clb); + ly_set_log_clb(ly_print_clb, 1); + + return true; +} diff --git a/radio/fhi_72/mplane/init-mplane.h b/radio/fhi_72/mplane/init-mplane.h new file mode 100644 index 0000000000..ee558fd77d --- /dev/null +++ b/radio/fhi_72/mplane/init-mplane.h @@ -0,0 +1,30 @@ +/* + * 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 OAI_MPLANE_H +#define OAI_MPLANE_H + +#include "ru-mplane-api.h" +#include "radio/COMMON/common_lib.h" + +bool init_mplane(ru_session_list_t *ru_session_list); + +#endif /* OAI_MPLANE_H */ diff --git a/radio/fhi_72/mplane/ru-mplane-api.h b/radio/fhi_72/mplane/ru-mplane-api.h new file mode 100644 index 0000000000..4b3b1719c1 --- /dev/null +++ b/radio/fhi_72/mplane/ru-mplane-api.h @@ -0,0 +1,95 @@ +/* + * 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 RU_MPLANE_API_H +#define RU_MPLANE_API_H + +#include +#include +#include + +#include "common/utils/LOG/log.h" + +#define MP_LOG_I(x, args...) LOG_I(HW, "[MPLANE] " x, ##args) +#define MP_LOG_W(x, args...) LOG_W(HW, "[MPLANE] " x, ##args) + +typedef struct { + bool ptp_state; + bool rx_carrier_state; + bool tx_carrier_state; + // to be extended with any notification callback + +} ru_notif_t; + +typedef struct { + char *ru_mac_addr; + uint32_t mtu; + int16_t iq_width; + uint8_t prach_offset; + + // DU sends to RU and xran + uint16_t du_port_bitmask; + uint16_t band_sector_bitmask; + uint16_t ccid_bitmask; + uint16_t ru_port_bitmask; + + // DU retrieves from RU, and sends to xran + uint8_t du_port; + uint8_t band_sector; + uint8_t ccid; + uint8_t ru_port; + +} xran_mplane_t; + +typedef struct { + size_t num; + char **name; +} uplane_info_t; + +typedef struct { + size_t num_cu_planes; + char **du_mac_addr; // one or two VF(s) for CU-planes + int32_t *vlan_tag; // one or two VF(s) for CU-planes + char *interface_name; + uplane_info_t tx_endpoints; + uplane_info_t rx_endpoints; + uplane_info_t tx_carriers; + uplane_info_t rx_carriers; + +} ru_mplane_config_t; + +typedef struct { + char *ru_ip_add; + ru_mplane_config_t ru_mplane_config; + void *session; + xran_mplane_t xran_mplane; + ru_notif_t ru_notif; + +} ru_session_t; + +typedef struct { + size_t num_rus; + ru_session_t *ru_session; + char **du_key_pair; + +} ru_session_list_t; + +#endif /* RU_MPLANE_API_H */ diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index d3f4fa1796..0221892c37 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -39,6 +39,10 @@ // line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api #include "../../app/src/common.h" +#ifdef OAI_MPLANE +#include "mplane/init-mplane.h" +#endif + typedef struct { eth_state_t e; rru_config_msg_type_t last_msg; @@ -279,7 +283,32 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d openair0_config_t *openair0_cfg, eth_params_t *eth_params) { - oran_eth_state_t *eth; + oran_eth_state_t *eth = calloc_or_fail(1, sizeof(*eth)); + + struct xran_fh_init fh_init = {0}; + struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0}; + + bool success = false; +#ifdef OAI_MPLANE + ru_session_list_t ru_session_list = {0}; + success = init_mplane(&ru_session_list); + AssertFatal(success, "[MPLANE] Cannot initialize M-plane.\n"); +#else + success = get_xran_config(openair0_cfg, &fh_init, fh_config); + AssertFatal(success, "cannot get configuration for xran\n"); +#endif + + LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX); + eth->oran_priv = oai_oran_initialize(&fh_init, fh_config); + AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul"); + // create message queues for ORAN sync + + initNotifiedFIFO(&oran_sync_fifo); + + eth->e.flags = ETH_RAW_IF4p5_MODE; + eth->e.compression = NO_COMPRESS; + eth->e.if_name = eth_params->local_if_name; + eth->last_msg = (rru_config_msg_type_t)-1; device->Mod_id = 0; device->transp_type = ETHERNET_TP; @@ -290,43 +319,13 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d device->trx_stop_func = trx_oran_stop; device->trx_set_freq_func = trx_oran_set_freq; device->trx_set_gains_func = trx_oran_set_gains; - device->trx_write_func = trx_oran_write_raw; device->trx_read_func = trx_oran_read_raw; - device->trx_ctlsend_func = trx_oran_ctlsend; device->trx_ctlrecv_func = trx_oran_ctlrecv; - device->get_internal_parameter = get_internal_parameter; - - eth = (oran_eth_state_t *)calloc(1, sizeof(oran_eth_state_t)); - if (eth == NULL) { - AssertFatal(0 == 1, "out of memory\n"); - } - - eth->e.flags = ETH_RAW_IF4p5_MODE; - eth->e.compression = NO_COMPRESS; - eth->e.if_name = eth_params->local_if_name; - eth->oran_priv = NULL; // define_oran_pointer(); device->priv = eth; device->openair0_cfg = &openair0_cfg[0]; - eth->last_msg = (rru_config_msg_type_t)-1; - - LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX); - - initNotifiedFIFO(&oran_sync_fifo); - - struct xran_fh_init fh_init = {0}; - struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0}; -#ifndef OAI_MPLANE_SUPPORT - bool success = get_xran_config(openair0_cfg, &fh_init, fh_config); - AssertFatal(success, "cannot get configuration for xran\n"); -#else - /* TODO: M-plane integration */ -#endif - eth->oran_priv = oai_oran_initialize(&fh_init, fh_config); - AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul"); - // create message queues for ORAN sync return 0; }