Merge branch 'integration_2025_w13' into 'develop'
Integration: `2025.w13` Closes #923, #924, #928, and #925 See merge request oai/openairinterface5g!3345 * !3300 Allow RSRP report handling in phy-test mode * !3318 Improve handling of some pointers causing potential segfault * !3321 DLSCH scheduler LOGs assertion prevention in case of HARQ disabled * !3335 Other compilation improvements * !3338 prevent access to NULL pointer in RELEASE_IE_FROMLIST * !3337 Fix for wrong NSA init at UE * !3339 fix NTN regression by correctly setting cellBarredNTN_r17 for NTN band again * !3340 NR UE: fix nr_pbch_channel_estimation() * !3260 Shared memory realtime radio simulation * !3341 rfsimulator: apply deadlock detection only if more than one client is connected * !3343 K-offset updated with configured sub carrier spacing * !3331 Add documentation for Foxconn RU * !3216 FHI72: Management plane support * !3295 Fix SRS report TLV unpack
This commit is contained in:
+4
-4
@@ -450,7 +450,7 @@ add_library(f1ap
|
||||
${F1AP_DIR}/f1ap_handlers.c
|
||||
${F1AP_DIR}/f1ap_itti_messaging.c)
|
||||
target_include_directories(f1ap PUBLIC F1AP_DIR)
|
||||
target_link_libraries(f1ap PUBLIC asn1_f1ap L2_NR)
|
||||
target_link_libraries(f1ap PUBLIC asn1_f1ap GTPV1U)
|
||||
target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE f1ap_lib)
|
||||
target_include_directories(f1ap PRIVATE ${F1AP_DIR}/lib)
|
||||
|
||||
@@ -1351,7 +1351,7 @@ target_link_libraries(L2_UE PRIVATE GTPV1U)
|
||||
target_link_libraries(L2_UE PRIVATE asn1_lte_rrc_hdrs)
|
||||
|
||||
add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} )
|
||||
target_link_libraries(NR_L2_UE PRIVATE f1ap nr_rlc)
|
||||
target_link_libraries(NR_L2_UE PRIVATE nr_rlc)
|
||||
target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common nr_ue_power_procedures nr_ue_ra_procedures)
|
||||
target_link_libraries(NR_L2_UE PRIVATE nr_nas)
|
||||
|
||||
@@ -1885,14 +1885,14 @@ add_executable(nr-uesoftmodem
|
||||
${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c
|
||||
${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE
|
||||
-Wl,--start-group
|
||||
nr_rrc SECURITY UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB
|
||||
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB NFAPI_PNF_LIB
|
||||
NFAPI_USER_LIB MISC_NFAPI_NR_LIB
|
||||
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB
|
||||
ITTI SIMU shlib_loader
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
<images>oai-gnb oai-nr-ue</images>
|
||||
</testCase>
|
||||
<testCase id="800813">
|
||||
<class>Create_Workspace</class>
|
||||
@@ -134,7 +134,7 @@
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
<images>oai-gnb oai-nr-ue</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
|
||||
@@ -86,8 +86,7 @@ services:
|
||||
cap_drop:
|
||||
- ALL
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: -E --rfsim --log_config.global_log_options level,nocolor,time
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
USE_ADDITIONAL_OPTIONS: -E --log_config.global_log_options level,nocolor,time --device.name vrtsim --vrtsim.role server --vrtsim.timescale 0.5
|
||||
depends_on:
|
||||
- oai-ext-dn
|
||||
networks:
|
||||
@@ -95,11 +94,13 @@ services:
|
||||
ipv4_address: 192.168.71.140
|
||||
volumes:
|
||||
- ../../conf_files/gnb.sa.band66.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
- tmp_data:/tmp/
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-softmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
ipc: host
|
||||
oai-nr-ue:
|
||||
image: ${REGISTRY:-oaisoftwarealliance}/${NRUE_IMG:-oai-nr-ue}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-nr-ue
|
||||
@@ -109,7 +110,7 @@ services:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: -E --rfsim -r 106 --numerology 1 --uicc0.imsi 208990100001100 --band 66 -C 2169090000 --CO -400000000 --ssb 378 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
|
||||
USE_ADDITIONAL_OPTIONS: -E -r 106 --numerology 1 --uicc0.imsi 208990100001100 --band 66 -C 2169090000 --CO -400000000 --ssb 378 --log_config.global_log_options level,nocolor,time --device.name vrtsim
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
@@ -119,11 +120,13 @@ services:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
- tmp_data:/tmp/
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
ipc: host
|
||||
|
||||
networks:
|
||||
public_net:
|
||||
@@ -142,3 +145,6 @@ networks:
|
||||
- subnet: 192.168.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
|
||||
volumes:
|
||||
tmp_data:
|
||||
|
||||
@@ -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")
|
||||
;;
|
||||
*)
|
||||
@@ -485,7 +489,7 @@ function main() {
|
||||
# add some default libraries that should always be built
|
||||
# for eNB, gNB, UEs, simulators
|
||||
if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then
|
||||
TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml"
|
||||
TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim"
|
||||
fi
|
||||
|
||||
mkdir -p $DIR/$BUILD_DIR/build
|
||||
@@ -504,12 +508,6 @@ function main() {
|
||||
echo_info "Built Doxygen based documentation. The documentation file is located here: $DIR/$BUILD_DIR/build/doc/html/index.html"
|
||||
fi
|
||||
|
||||
# TODO: once we got the CMakeLists.txt file done for the ORAN files, remove the following lines
|
||||
if [[ $TARGET_LIST =~ "oran_fhlib_5g" ]]; then
|
||||
rm -f liboai_transpro.so
|
||||
ln -s liboran_fhlib_5g.so liboai_transpro.so
|
||||
fi
|
||||
|
||||
if [ "$UE" = 1 ] ; then
|
||||
|
||||
echo_info "Compiling UE specific part"
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# - Try to find the LibXml2 xml processing library
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBXML2_FOUND - System has LibXml2
|
||||
# LIBXML2_INCLUDE_DIR - The LibXml2 include directory
|
||||
# LIBXML2_LIBRARIES - The libraries needed to use LibXml2
|
||||
# LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2
|
||||
# LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2006-2009 Kitware, Inc.
|
||||
# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distributed this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_LIBXML libxml-2.0)
|
||||
SET(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})
|
||||
|
||||
FIND_PATH(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h
|
||||
HINTS
|
||||
${PC_LIBXML_INCLUDEDIR}
|
||||
${PC_LIBXML_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES libxml2
|
||||
)
|
||||
|
||||
FIND_LIBRARY(LIBXML2_LIBRARIES NAMES xml2 libxml2
|
||||
HINTS
|
||||
${PC_LIBXML_LIBDIR}
|
||||
${PC_LIBXML_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
FIND_PROGRAM(LIBXML2_XMLLINT_EXECUTABLE xmllint)
|
||||
# for backwards compat. with KDE 4.0.x:
|
||||
SET(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}")
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE)
|
||||
|
||||
@@ -75,7 +75,6 @@ endif()
|
||||
|
||||
find_path(xran_INCLUDE_DIR
|
||||
NAMES
|
||||
xran_common.h
|
||||
xran_compression.h
|
||||
xran_cp_api.h
|
||||
xran_ecpri_owd_measurements.h
|
||||
@@ -84,7 +83,7 @@ find_path(xran_INCLUDE_DIR
|
||||
xran_pkt_up.h
|
||||
xran_sync_api.h
|
||||
HINTS ${xran_LOCATION}
|
||||
PATH_SUFFIXES api include
|
||||
PATH_SUFFIXES api
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
find_library(xran_LIBRARY
|
||||
@@ -127,16 +126,19 @@ find_package_handle_standard_args(xran
|
||||
VERSION_VAR xran_VERSION
|
||||
)
|
||||
|
||||
# in proper usage of cmake, include directory should only contain "api", but not header files under "src" directory;
|
||||
# however, we use xran_dev_get_ctx() and xran_dev_get_ctx_by_id() functions which are defined in xran_common.h;
|
||||
# since xran_common.h is under "src" directory, we have to include it in ${xran_INCLUDE_DIRS}
|
||||
if(xran_FOUND)
|
||||
set(xran_LIBRARIES ${xran_LIBRARY})
|
||||
set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR})
|
||||
set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR} ${xran_INCLUDE_DIR}/../src)
|
||||
endif()
|
||||
|
||||
if(xran_FOUND AND NOT TARGET xran::xran)
|
||||
add_library(xran::xran UNKNOWN IMPORTED)
|
||||
set_target_properties(xran::xran PROPERTIES
|
||||
IMPORTED_LOCATION "${xran_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIR}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIRS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -546,7 +546,10 @@ check_install_additional_tools (){
|
||||
libforms-bin \
|
||||
libforms-dev \
|
||||
libxft-dev \
|
||||
xmlstarlet"
|
||||
xmlstarlet \
|
||||
libpcre3-dev \
|
||||
libssh-dev \
|
||||
libxml2-dev"
|
||||
elif [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]] || [[ "$OS_DISTRO" == "rocky" ]] || [[ "$OS_DISTRO" == "fedora" ]]; then
|
||||
PACKAGE_LIST="\
|
||||
doxygen \
|
||||
@@ -556,7 +559,10 @@ check_install_additional_tools (){
|
||||
libXft-devel \
|
||||
xforms \
|
||||
xforms-devel \
|
||||
xmlstarlet"
|
||||
xmlstarlet \
|
||||
pcre-devel \
|
||||
libssh-devel \
|
||||
libxml2-devel"
|
||||
fi
|
||||
$SUDO $INSTALLER install -y $PACKAGE_LIST $optional_packages
|
||||
}
|
||||
|
||||
@@ -21,3 +21,4 @@ if (ENABLE_TESTS)
|
||||
endif()
|
||||
add_subdirectory(barrier)
|
||||
add_subdirectory(actor)
|
||||
add_subdirectory(shm_iq_channel)
|
||||
|
||||
+19
-11
@@ -52,6 +52,13 @@
|
||||
|
||||
// main log variables
|
||||
|
||||
/** @defgroup _max_length Maximum Length of LOG
|
||||
* @ingroup _macro
|
||||
* @brief the macros that describe the maximum length of LOG
|
||||
* @{*/
|
||||
|
||||
#define MAX_LOG_TOTAL 16384 /*!< \brief the maximum length of a log */
|
||||
|
||||
// Fixme: a better place to be shure it is called
|
||||
void read_cpu_hardware (void) __attribute__ ((constructor));
|
||||
#if !defined(__arm__) && !defined(__aarch64__)
|
||||
@@ -877,31 +884,32 @@ static void log_output_memory(log_component_t *c, const char *file, const char *
|
||||
* correctly. It was not a big problem because in practice MAX_LOG_TOTAL is
|
||||
* big enough so that the buffer is never full.
|
||||
*/
|
||||
char log_buffer[MAX_LOG_TOTAL];
|
||||
static_assert(4 * MAX_LOG_TOTAL <= 65536, "log buffer limited to 64kB, please reduce MAX_LOG_TOTAL\n");
|
||||
char log_buffer[4 * MAX_LOG_TOTAL];
|
||||
|
||||
// make sure that for log trace the extra info is only printed once, reset when the level changes
|
||||
if (level < OAILOG_TRACE) {
|
||||
int n = log_header(c, log_buffer+len, MAX_LOG_TOTAL, file, func, line, level);
|
||||
int n = log_header(c, log_buffer+len, sizeof(log_buffer), file, func, line, level);
|
||||
if (n > 0) {
|
||||
len += n;
|
||||
if (len > MAX_LOG_TOTAL) {
|
||||
len = MAX_LOG_TOTAL;
|
||||
if (len > sizeof(log_buffer)) {
|
||||
len = sizeof(log_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
int n = vsnprintf(log_buffer+len, MAX_LOG_TOTAL-len, format, args);
|
||||
int n = vsnprintf(log_buffer+len, sizeof(log_buffer)-len, format, args);
|
||||
if (n > 0) {
|
||||
len += n;
|
||||
if (len > MAX_LOG_TOTAL) {
|
||||
len = MAX_LOG_TOTAL;
|
||||
if (len > sizeof(log_buffer)) {
|
||||
len = sizeof(log_buffer);
|
||||
}
|
||||
}
|
||||
if (!((g_log->flag) & FLAG_NOCOLOR)) {
|
||||
int n = snprintf(log_buffer+len, MAX_LOG_TOTAL-len, "%s", log_level_highlight_end[level]);
|
||||
int n = snprintf(log_buffer+len, sizeof(log_buffer)-len, "%s", log_level_highlight_end[level]);
|
||||
if (n > 0) {
|
||||
len += n;
|
||||
if (len > MAX_LOG_TOTAL) {
|
||||
len = MAX_LOG_TOTAL;
|
||||
if (len > sizeof(log_buffer)) {
|
||||
len = sizeof(log_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -941,7 +949,7 @@ static void log_output_memory(log_component_t *c, const char *file, const char *
|
||||
}
|
||||
}
|
||||
}else{
|
||||
AssertFatal(len >= 0 && len <= MAX_LOG_TOTAL, "Bad len %d\n", len);
|
||||
AssertFatal(len >= 0 && len <= sizeof(log_buffer), "Bad len %d\n", len);
|
||||
if (write(fileno(c->stream), log_buffer, len)) {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +65,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup _max_length Maximum Length of LOG
|
||||
* @ingroup _macro
|
||||
* @brief the macros that describe the maximum length of LOG
|
||||
* @{*/
|
||||
|
||||
#define MAX_LOG_TOTAL 16384 /*!< \brief the maximum length of a log */
|
||||
/** @}*/
|
||||
|
||||
/** @defgroup _log_level Message levels defined by LOG
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
add_library(actor actor.c)
|
||||
target_include_directories(actor PUBLIC ./)
|
||||
target_link_libraries(actor PUBLIC thread-pool)
|
||||
# Only include header files due to issues with ODR in threadPool binaries
|
||||
target_include_directories(actor PUBLIC ./ ../threadPool/)
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -78,6 +78,10 @@
|
||||
// Prints an error if ID not found in list.
|
||||
#define RELEASE_IE_FROMLIST(SOURCE, TARGET, FIELD) \
|
||||
do { \
|
||||
if (!TARGET) { \
|
||||
LOG_E(NR_MAC, "Target list not present, impossible to release element\n"); \
|
||||
break; \
|
||||
} \
|
||||
for (int iI = 0; iI < SOURCE->list.count; iI++) { \
|
||||
long eL = *SOURCE->list.array[iI]; \
|
||||
int iJ; \
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
add_library(shm_td_iq_channel shm_td_iq_channel.c)
|
||||
target_include_directories(shm_td_iq_channel PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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 "shm_td_iq_channel.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "assertions.h"
|
||||
#include "utils.h"
|
||||
#include "common/utils/threadPool/pthread_utils.h"
|
||||
|
||||
#define CIRCULAR_BUFFER_SIZE (30720 * 14 * 20)
|
||||
|
||||
typedef struct {
|
||||
int magic;
|
||||
int num_antennas_tx;
|
||||
int num_antennas_rx;
|
||||
uint64_t timestamp;
|
||||
bool is_connected;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
} ShmTDIQChannelData;
|
||||
|
||||
typedef struct ShmTDIQChannel_s {
|
||||
IQChannelType type;
|
||||
ShmTDIQChannelData *data;
|
||||
uint64_t last_timestamp;
|
||||
char name[256];
|
||||
sample_t *tx_iq_data;
|
||||
sample_t *rx_iq_data;
|
||||
} ShmTDIQChannel;
|
||||
|
||||
ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant)
|
||||
{
|
||||
// Create shared memory segment
|
||||
int fd = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
AssertFatal(fd != -1, "shm_open failed: %s\n", strerror(errno));
|
||||
size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * num_tx_ant;
|
||||
size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * num_rx_ant;
|
||||
size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size;
|
||||
|
||||
// Set the size of the shared memory segment
|
||||
int res = ftruncate(fd, total_size);
|
||||
AssertFatal(res != -1, "ftruncate failed: %s\n", strerror(errno));
|
||||
|
||||
// Map shared memory segment to address space
|
||||
ShmTDIQChannelData *shm_ptr = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
AssertFatal(shm_ptr != MAP_FAILED, "mmap failed: %s\n", strerror(errno));
|
||||
|
||||
// Initialize shared memory
|
||||
memset(shm_ptr, 0, total_size);
|
||||
shm_ptr->num_antennas_tx = num_tx_ant;
|
||||
shm_ptr->num_antennas_rx = num_rx_ant;
|
||||
shm_ptr->is_connected = false;
|
||||
ShmTDIQChannel *channel = calloc_or_fail(1, sizeof(ShmTDIQChannel));
|
||||
strncpy(channel->name, name, sizeof(channel->name) - 1);
|
||||
channel->tx_iq_data = (sample_t *)(shm_ptr + 1);
|
||||
channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t);
|
||||
channel->data = shm_ptr;
|
||||
channel->type = IQ_CHANNEL_TYPE_SERVER;
|
||||
channel->last_timestamp = 0;
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
pthread_condattr_t cond_attr;
|
||||
int ret = pthread_mutexattr_init(&mutex_attr);
|
||||
AssertFatal(ret == 0, "pthread_mutexattr_init() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
ret = pthread_condattr_init(&cond_attr);
|
||||
AssertFatal(ret == 0, "pthread_condattr_init() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
ret = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
|
||||
AssertFatal(ret == 0, "pthread_mutexattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
ret = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
|
||||
AssertFatal(ret == 0, "pthread_condattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
ret = pthread_mutex_init(&shm_ptr->mutex, &mutex_attr);
|
||||
AssertFatal(ret == 0, "pthread_mutex_init() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
ret = pthread_cond_init(&shm_ptr->cond, &cond_attr);
|
||||
AssertFatal(ret == 0, "pthread_cond_init() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
shm_ptr->magic = SHM_MAGIC_NUMBER;
|
||||
close(fd);
|
||||
return channel;
|
||||
}
|
||||
|
||||
ShmTDIQChannel *shm_td_iq_channel_connect(const char *name, int timeout_in_seconds)
|
||||
{
|
||||
// Create shared memory segment
|
||||
int fd = -1;
|
||||
while (timeout_in_seconds > 0 && fd == -1) {
|
||||
fd = shm_open(name, O_RDWR, S_IRUSR | S_IWUSR);
|
||||
timeout_in_seconds--;
|
||||
printf("Waiting for server to create shared memory segment\n");
|
||||
sleep(1);
|
||||
}
|
||||
AssertFatal(fd != -1, "shm_open() failed: errno %d, %s", errno, strerror(errno));
|
||||
|
||||
struct stat buf;
|
||||
fstat(fd, &buf);
|
||||
size_t total_size = buf.st_size;
|
||||
|
||||
// Map shared memory segment to address space
|
||||
ShmTDIQChannelData *shm_ptr = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (shm_ptr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ShmTDIQChannel *channel = calloc_or_fail(1, sizeof(ShmTDIQChannel));
|
||||
channel->data = shm_ptr;
|
||||
channel->tx_iq_data = (sample_t *)(shm_ptr + 1);
|
||||
size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * channel->data->num_antennas_tx;
|
||||
channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t);
|
||||
channel->type = IQ_CHANNEL_TYPE_CLIENT;
|
||||
channel->last_timestamp = 0;
|
||||
while (shm_ptr->magic != SHM_MAGIC_NUMBER) {
|
||||
printf("Waiting for server to initialize shared memory\n");
|
||||
sleep(1);
|
||||
}
|
||||
shm_ptr->is_connected = true;
|
||||
close(fd);
|
||||
return channel;
|
||||
}
|
||||
|
||||
IQChannelErrorType shm_td_iq_channel_tx(ShmTDIQChannel *channel,
|
||||
uint64_t timestamp,
|
||||
uint64_t num_samples,
|
||||
int antenna,
|
||||
const sample_t *tx_iq_data)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
if (data->is_connected == false) {
|
||||
return CHANNEL_ERROR_NOT_CONNECTED;
|
||||
}
|
||||
// timestamp in the past
|
||||
uint64_t current_time = data->timestamp;
|
||||
if (timestamp < current_time) {
|
||||
return CHANNEL_ERROR_TOO_LATE;
|
||||
}
|
||||
// timestamp is too far in the future
|
||||
if (timestamp - current_time + num_samples >= CIRCULAR_BUFFER_SIZE) {
|
||||
return CHANNEL_ERROR_TOO_EARLY;
|
||||
}
|
||||
|
||||
sample_t *base_ptr;
|
||||
if (channel->type == IQ_CHANNEL_TYPE_CLIENT) {
|
||||
base_ptr = channel->rx_iq_data + antenna * CIRCULAR_BUFFER_SIZE;
|
||||
} else {
|
||||
base_ptr = channel->tx_iq_data + antenna * CIRCULAR_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
uint64_t first_sample = timestamp % CIRCULAR_BUFFER_SIZE;
|
||||
uint64_t last_sample = first_sample + num_samples - 1;
|
||||
if (last_sample >= CIRCULAR_BUFFER_SIZE) {
|
||||
size_t num_samples_first_copy = CIRCULAR_BUFFER_SIZE - first_sample;
|
||||
memcpy(base_ptr + first_sample, tx_iq_data, num_samples_first_copy * sizeof(sample_t));
|
||||
memcpy(base_ptr, tx_iq_data + num_samples_first_copy, (num_samples - num_samples_first_copy) * sizeof(sample_t));
|
||||
} else {
|
||||
memcpy(base_ptr + first_sample, tx_iq_data, num_samples * sizeof(sample_t));
|
||||
}
|
||||
return CHANNEL_NO_ERROR;
|
||||
}
|
||||
|
||||
IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
|
||||
uint64_t timestamp,
|
||||
uint64_t num_samples,
|
||||
int antenna,
|
||||
sample_t *tx_iq_data)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
if (data->is_connected == false) {
|
||||
return CHANNEL_ERROR_NOT_CONNECTED;
|
||||
}
|
||||
// timestamp in the future
|
||||
uint64_t current_time = data->timestamp;
|
||||
if (timestamp > current_time) {
|
||||
return CHANNEL_ERROR_TOO_EARLY;
|
||||
}
|
||||
// timestamp is too far in the past
|
||||
if (current_time - timestamp >= CIRCULAR_BUFFER_SIZE) {
|
||||
return CHANNEL_ERROR_TOO_LATE;
|
||||
}
|
||||
|
||||
sample_t *base_ptr;
|
||||
if (channel->type == IQ_CHANNEL_TYPE_CLIENT) {
|
||||
base_ptr = channel->tx_iq_data + antenna * CIRCULAR_BUFFER_SIZE;
|
||||
} else {
|
||||
base_ptr = channel->rx_iq_data + antenna * CIRCULAR_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
uint64_t first_sample = timestamp % CIRCULAR_BUFFER_SIZE;
|
||||
uint64_t last_sample = first_sample + num_samples - 1;
|
||||
if (last_sample >= CIRCULAR_BUFFER_SIZE) {
|
||||
size_t num_samples_first_copy = CIRCULAR_BUFFER_SIZE - first_sample;
|
||||
memcpy(tx_iq_data, base_ptr + first_sample, num_samples_first_copy * sizeof(sample_t));
|
||||
memcpy(tx_iq_data + num_samples_first_copy, base_ptr, (num_samples - num_samples_first_copy) * sizeof(sample_t));
|
||||
} else {
|
||||
memcpy(tx_iq_data, base_ptr + first_sample, num_samples * sizeof(sample_t));
|
||||
}
|
||||
return CHANNEL_NO_ERROR;
|
||||
}
|
||||
|
||||
void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
if (channel->type != IQ_CHANNEL_TYPE_SERVER) {
|
||||
return;
|
||||
}
|
||||
if (data->is_connected == false) {
|
||||
return;
|
||||
}
|
||||
mutexlock(data->mutex);
|
||||
data->timestamp += num_samples;
|
||||
condbroadcast(data->cond);
|
||||
mutexunlock(data->mutex);
|
||||
}
|
||||
|
||||
void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
if (data->is_connected == false) {
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
|
||||
size_t current_timestamp = data->timestamp;
|
||||
if (current_timestamp >= timestamp) {
|
||||
return;
|
||||
}
|
||||
mutexlock(data->mutex);
|
||||
while (current_timestamp < timestamp) {
|
||||
condwait(data->cond, data->mutex);
|
||||
current_timestamp = data->timestamp;
|
||||
}
|
||||
mutexunlock(data->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
return data->timestamp;
|
||||
}
|
||||
|
||||
bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel)
|
||||
{
|
||||
return channel->data->is_connected;
|
||||
}
|
||||
|
||||
void shm_td_iq_channel_destroy(ShmTDIQChannel *channel)
|
||||
{
|
||||
ShmTDIQChannelData *data = channel->data;
|
||||
size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_tx;
|
||||
size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_rx;
|
||||
size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size;
|
||||
munmap(data, total_size);
|
||||
if (channel->type == IQ_CHANNEL_TYPE_SERVER) {
|
||||
shm_unlink(channel->name);
|
||||
}
|
||||
free(channel);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 SHM_IQ_CHANNEL_H
|
||||
#define SHM_IQ_CHANNEL_H
|
||||
|
||||
#include "../threadPool/pthread_utils.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define SHM_MAGIC_NUMBER 0x12345678
|
||||
|
||||
/**
|
||||
* ShmTdIqChannel is a shared memory bidirectional time domain IQ channel with a single clock
|
||||
* source. The server (clock source) shall create the channel while the client should connect to
|
||||
* it.
|
||||
*
|
||||
* To write samples, send them via a pointer passed to shm_td_iq_channel_tx.
|
||||
* To read samples, receive them via a pointer passed to shm_td_iq_channel_rx. You can either wait until
|
||||
* the sample are available using shm_td_iq_channel_wait or poll using shm_td_iq_channel_rx until the return
|
||||
* value is not CHANNEL_ERROR_TOO_EARLY.
|
||||
* To indicate that samples are ready to be read by the client, call shm_td_iq_channel_produce_samples
|
||||
* (server only).
|
||||
*
|
||||
* The timestamps used in the API are in absolute samples from the time the client/server connection started.
|
||||
*/
|
||||
|
||||
typedef enum IQChannelType { IQ_CHANNEL_TYPE_SERVER, IQ_CHANNEL_TYPE_CLIENT } IQChannelType;
|
||||
typedef uint32_t sample_t;
|
||||
typedef enum IQChannelErrorType {
|
||||
CHANNEL_NO_ERROR,
|
||||
CHANNEL_ERROR_TOO_LATE,
|
||||
CHANNEL_ERROR_TOO_EARLY,
|
||||
CHANNEL_ERROR_NOT_CONNECTED
|
||||
} IQChannelErrorType;
|
||||
|
||||
typedef struct ShmTDIQChannel_s ShmTDIQChannel;
|
||||
|
||||
/**
|
||||
* @brief Creates a shared memory IQ channel.
|
||||
*
|
||||
* @param name The name of the shared memory segment.
|
||||
* @param num_tx_ant The number of TX antennas.
|
||||
* @param num_rx_ant The number of RX antennas.
|
||||
* @return A pointer to the created ShmTDIQChannel structure.
|
||||
*/
|
||||
ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant);
|
||||
|
||||
/**
|
||||
* @brief Connects to an existing shared memory IQ channel.
|
||||
*
|
||||
* @param name The name of the shared memory segment.
|
||||
* @param timeout_in_seconds The timeout in seconds for the connection attempt.
|
||||
* @return A pointer to the connected ShmTDIQChannel structure.
|
||||
*/
|
||||
ShmTDIQChannel *shm_td_iq_channel_connect(const char *name, int timeout_in_seconds);
|
||||
|
||||
/**
|
||||
* @brief Transmit data in the channel
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
* @param timestamp The timestamp for which to get the TX IQ data slot.
|
||||
* @param num_samples The number of samples to write.
|
||||
* @param antenna The antenna index.
|
||||
* @param tx_iq_data The TX IQ data to write.
|
||||
*
|
||||
* @return CHANNEL_NO_ERROR if successful, error type otherwise
|
||||
*/
|
||||
IQChannelErrorType shm_td_iq_channel_tx(ShmTDIQChannel *channel,
|
||||
uint64_t timestamp,
|
||||
uint64_t num_samples,
|
||||
int antenna,
|
||||
const sample_t *tx_iq_data);
|
||||
|
||||
/**
|
||||
* @brief Receive iq data from the channel
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
* @param timestamp The timestamp for which to get the RX IQ data slot.
|
||||
* @param num_samples The number of samples to read.
|
||||
* @param antenna The antenna index.
|
||||
* @param tx_iq_data pointer to the RX IQ data slot.
|
||||
* @return CHANNEL_NO_ERROR if successful, error type otherwise
|
||||
*/
|
||||
IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
|
||||
uint64_t timestamp,
|
||||
uint64_t num_samples,
|
||||
int antenna,
|
||||
sample_t *tx_iq_data);
|
||||
|
||||
/**
|
||||
* @brief Advances the time in the channel by specified number of samples
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
* @param num_symbols The number of samples to produce.
|
||||
*/
|
||||
void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, uint64_t num_samples);
|
||||
|
||||
/**
|
||||
* @brief Wait until sample at the specified timestamp is available
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
*/
|
||||
void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp);
|
||||
|
||||
/**
|
||||
* @brief Checks if the IQ channel is connected.
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
* @return True if the channel is connected, false otherwise.
|
||||
*/
|
||||
bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel);
|
||||
|
||||
/**
|
||||
* @brief Destroys the shared memory IQ channel.
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
*/
|
||||
void shm_td_iq_channel_destroy(ShmTDIQChannel *channel);
|
||||
|
||||
/**
|
||||
* @brief Returns current sample
|
||||
*
|
||||
* @param channel The ShmTDIQChannel structure.
|
||||
*
|
||||
* @return Current time as sample count since beginning of transmission
|
||||
*/
|
||||
uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
add_executable(test_shm_td_iq_channel test_shm_td_iq_channel.c)
|
||||
target_link_libraries(test_shm_td_iq_channel shm_td_iq_channel minimal_lib pthread)
|
||||
add_dependencies(tests test_shm_td_iq_channel)
|
||||
# Commented out due to issues with ASAN in the unit test docker container
|
||||
#add_test(test_shm_td_iq_channel ./test_shm_td_iq_channel)
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include "assertions.h"
|
||||
|
||||
#define SHM_CHANNEL_NAME "shm_iq_channel_test_file"
|
||||
#include "shm_td_iq_channel.h"
|
||||
|
||||
void server(void);
|
||||
int client(void);
|
||||
|
||||
enum { MODE_SERVER, MODE_CLIENT, MODE_FORK };
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int mode = MODE_FORK;
|
||||
if (argc == 2) {
|
||||
if (strcmp(argv[1], "server") == 0) {
|
||||
mode = MODE_SERVER;
|
||||
} else if (strcmp(argv[1], "client") == 0) {
|
||||
mode = MODE_CLIENT;
|
||||
}
|
||||
} else if (argc > 2) {
|
||||
printf("Usage: %s [server|client]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
switch (mode) {
|
||||
case MODE_SERVER:
|
||||
server();
|
||||
break;
|
||||
case MODE_CLIENT:
|
||||
return client();
|
||||
break;
|
||||
case MODE_FORK: {
|
||||
char file[256];
|
||||
snprintf(file, sizeof(file), "/dev/shm/%s", SHM_CHANNEL_NAME);
|
||||
remove(file);
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
server();
|
||||
} else {
|
||||
return client();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int num_updates = 50;
|
||||
const int num_samples_per_update = 30720;
|
||||
void *produce_symbols(void *arg)
|
||||
{
|
||||
ShmTDIQChannel *channel = (ShmTDIQChannel *)arg;
|
||||
for (int i = 0; i < num_updates; i++) {
|
||||
shm_td_iq_channel_produce_samples(channel, num_samples_per_update);
|
||||
usleep(20000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void server(void)
|
||||
{
|
||||
int num_ant_tx = 1;
|
||||
int num_ant_rx = 1;
|
||||
ShmTDIQChannel *channel = shm_td_iq_channel_create(SHM_CHANNEL_NAME, num_ant_tx, num_ant_rx);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (shm_td_iq_channel_is_connected(channel)) {
|
||||
printf("Server connected\n");
|
||||
break;
|
||||
}
|
||||
printf("Waiting for client\n");
|
||||
sleep(1);
|
||||
}
|
||||
AssertFatal(shm_td_iq_channel_is_connected(channel), "Server failed to connect\n");
|
||||
|
||||
pthread_t producer_thread;
|
||||
int ret = pthread_create(&producer_thread, NULL, produce_symbols, channel);
|
||||
AssertFatal(ret == 0, "pthread_create() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
|
||||
uint64_t timestamp = 0;
|
||||
int iq_contents = 0;
|
||||
while (timestamp < num_samples_per_update * num_updates) {
|
||||
shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update);
|
||||
uint64_t target_timestamp = timestamp + num_samples_per_update;
|
||||
timestamp += num_samples_per_update;
|
||||
uint32_t iq_data[num_samples_per_update];
|
||||
for (int i = 0; i < num_samples_per_update; i++) {
|
||||
iq_data[i] = iq_contents;
|
||||
}
|
||||
int result = shm_td_iq_channel_tx(channel, target_timestamp, num_samples_per_update, 0, iq_data);
|
||||
AssertFatal(result == CHANNEL_NO_ERROR, "Failed to write data\n");
|
||||
iq_contents++;
|
||||
}
|
||||
|
||||
printf("Finished writing data\n");
|
||||
|
||||
ret = pthread_join(producer_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join() failed: errno %d, %s\n", errno, strerror(errno));
|
||||
shm_td_iq_channel_destroy(channel);
|
||||
}
|
||||
|
||||
int client(void)
|
||||
{
|
||||
int total_errors = 0;
|
||||
ShmTDIQChannel *channel = shm_td_iq_channel_connect(SHM_CHANNEL_NAME, 10);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (shm_td_iq_channel_is_connected(channel)) {
|
||||
printf("Client connected\n");
|
||||
break;
|
||||
}
|
||||
printf("Waiting for server\n");
|
||||
sleep(1);
|
||||
}
|
||||
AssertFatal(shm_td_iq_channel_is_connected(channel), "Client failed to connect\n");
|
||||
|
||||
uint64_t timestamp = 0;
|
||||
int iq_contents = 0;
|
||||
|
||||
while (timestamp < num_samples_per_update * num_updates) {
|
||||
shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update);
|
||||
// Server starts producing from second slot
|
||||
if (timestamp > num_samples_per_update) {
|
||||
uint64_t target_timestamp = timestamp - num_samples_per_update;
|
||||
uint32_t iq_data[num_samples_per_update];
|
||||
int result = shm_td_iq_channel_rx(channel, target_timestamp, num_samples_per_update, 0, iq_data);
|
||||
AssertFatal(result == CHANNEL_NO_ERROR, "Failed to read data\n");
|
||||
int num_errors = 0;
|
||||
for (int i = 0; i < num_samples_per_update; i++) {
|
||||
if (iq_data[i] != iq_contents) {
|
||||
num_errors++;
|
||||
}
|
||||
}
|
||||
if (num_errors) {
|
||||
printf("Found %d errors, value = %d, reference = %d\n", num_errors, iq_data[0], iq_contents);
|
||||
total_errors += num_errors;
|
||||
}
|
||||
iq_contents++;
|
||||
}
|
||||
timestamp += num_samples_per_update;
|
||||
}
|
||||
|
||||
printf("Finished reading data\n");
|
||||
shm_td_iq_channel_destroy(channel);
|
||||
return total_errors;
|
||||
}
|
||||
+849
-17
@@ -72,6 +72,7 @@ tested any RU without S-plane. Radio units we are testing/integrating:
|
||||
|LiteON RU |01.00.08/02.00.03 |
|
||||
|Benetel 650 |RAN650-1v1.0.4-dda1bf5|
|
||||
|Benetel 550 CAT-A|RAN550-1v1.0.4-605a25a|
|
||||
|Foxconn RPQN |v3.1.15q.551_rc10 |
|
||||
|
||||
Tested libxran releases:
|
||||
|
||||
@@ -671,6 +672,40 @@ The RU configuration is stored in `/etc/rumanager.conf`. The required modificati
|
||||
|
||||
At this stage, RU must be rebooted so the changes apply.
|
||||
|
||||
### Foxconn RPQN RU
|
||||
|
||||
**Version v3.1.15q.551_rc10**
|
||||
|
||||
The OAI configuration file [`gnb.sa.band78.273prb.fhi72.4X4-foxconn.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4X4-foxconn.conf) corresponds to:
|
||||
- TDD pattern `DDDSU`, 2.5ms
|
||||
- Bandwidth 100MHz
|
||||
- MTU 8000
|
||||
|
||||
#### RU configuration
|
||||
|
||||
After switching on or rebooting the RU, the `/home/root/test/init_rrh_config_enable_cuplane` script should be run.
|
||||
|
||||
The RU configuration file is located in `/home/root/test/RRHconfig_xran.xml`. The required modifications:
|
||||
1. `RRH_DST_MAC_ADDR`
|
||||
2. `RRH_SRC_MAC_ADDR`
|
||||
3. `RRH_EAXC_ID_TYPE1`
|
||||
4. `RRH_EAXC_ID_TYPE3`
|
||||
5. `RRH_CMPR_HDR_PRESENT` -> `0`
|
||||
6. `RRH_C_PLANE_VLAN_TAG`
|
||||
7. `RRH_U_PLANE_VLAN_TAG`
|
||||
8. `RRH_LO_FREQUENCY_KHZ` -> `3750000, 0`
|
||||
9. `RRH_DISABLE_USING_CAL_TABLES` -> `YES`
|
||||
10. `RRH_TX_ATTENUATION` -> must be larger than 10dB
|
||||
11. `RRH_RX_ATTENUATION` -> must be lower than 30dB
|
||||
|
||||
RU must be rebooted so the changes apply.
|
||||
|
||||
**Note**
|
||||
|
||||
- The RU was tested with the `2024.w30` tag of OAI.
|
||||
- The measured throughput was **520 Mbps DL** and **40 Mbps UL**.
|
||||
- With newer OAI versions, throughput degrades. This issue is currently under investigation.
|
||||
|
||||
## Configure Network Interfaces and DPDK VFs
|
||||
|
||||
The 7.2 fronthaul uses the xran library, which requires DPDK. In this step, we
|
||||
@@ -942,10 +977,8 @@ Edit the sample OAI gNB configuration file and check following parameters:
|
||||
including the advantages and disadvantages of each mode, refer to
|
||||
[Memory in DPDK](https://www.dpdk.org/memory-in-dpdk-part-2-deep-dive-into-iova/)
|
||||
* `owdm_enable`: used for eCPRI One-Way Delay Measurements; it depends if the RU supports it; if not set to 1 (enabled), default value is 0 (disabled)
|
||||
* `fh_config`: parameters that need to match RU parameters
|
||||
* timing parameters (starting with `T`) depend on the RU: `Tadv_cp_dl` is a
|
||||
single number, the rest pairs of numbers `(x, y)` specifying minimum and
|
||||
maximum delays
|
||||
* `fh_config`
|
||||
* DU delay profile (`T1a` and `Ta4`): pairs of numbers `(x, y)` specifying minimum and maximum delays
|
||||
* `ru_config`: RU-specific configuration:
|
||||
* `iq_width`: Width of DL/UL IQ samples: if 16, no compression, if <16, applies
|
||||
compression
|
||||
@@ -966,7 +999,7 @@ Layer mapping (eAxC offsets) happens as follows:
|
||||
**Note**
|
||||
|
||||
- At the moment, OAI is compatible with CAT A O-RU only. Therefore, SRS is not supported.
|
||||
- XRAN retreives DU MAC address with `rte_eth_macaddr_get()` function. Hence, `fhi_72.du_addr` parameter is not taken into account.
|
||||
- XRAN retrieves DU MAC address with `rte_eth_macaddr_get()` function. Hence, `fhi_72.du_addr` parameter is not taken into account.
|
||||
|
||||
# Start and Operation of OAI gNB
|
||||
|
||||
@@ -1094,10 +1127,10 @@ fhi_72 = {
|
||||
// mtu
|
||||
fh_config = (
|
||||
{
|
||||
// timing, ru_config, prach_config of RU1
|
||||
// DU delay profile, ru_config, prach_config of RU1
|
||||
},
|
||||
{
|
||||
// timing, ru_config, prach_config of RU2
|
||||
// DU delay profile, ru_config, prach_config of RU2
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -1121,11 +1154,6 @@ fhi_72 = {
|
||||
fh_config = (
|
||||
# RAN650 #1
|
||||
{
|
||||
Tadv_cp_dl = 125;
|
||||
T2a_cp_dl = (259, 500);
|
||||
T2a_cp_ul = (25, 500);
|
||||
T2a_up = (134, 375);
|
||||
Ta3 = (152, 160);
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
@@ -1137,11 +1165,6 @@ fhi_72 = {
|
||||
},
|
||||
# RAN650 #2
|
||||
{
|
||||
Tadv_cp_dl = 125;
|
||||
T2a_cp_dl = (259, 500);
|
||||
T2a_cp_ul = (25, 500);
|
||||
T2a_up = (134, 375);
|
||||
Ta3 = (152, 160);
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
@@ -1185,6 +1208,815 @@ Note the eight entries after `avg_IO`.
|
||||
|
||||
You should be able to connect a UE now.
|
||||
|
||||
|
||||
# OAI Management Plane
|
||||
We support Configuration Management in OAI gNB, where gNB configures CU-planes, interfaces, TX/RX antennas, and TX/RX carriers for the RU.
|
||||
The reference specifications:
|
||||
* `O-RAN.WG4.MP.0-v05.00`
|
||||
* `O-RAN.WG4.MP-YANGs-v04.00`
|
||||
|
||||
## M-plane prerequisites
|
||||
Before proceeding, please make sure you have a support for 7.2 interface, as described in [Prerequisites](#prerequisites).
|
||||
|
||||
### DHCP server
|
||||
The M-plane requires a DHCP server, where the M-plane connection can be established over untagged or tagged VLAN. We tested with untagged (the default VLAN is 1).
|
||||
Please modify `/etc/dhcp/dhcpd.conf` configuration based on your testbed.
|
||||
|
||||
<details>
|
||||
<summary>Example DHCP server configuration</summary>
|
||||
|
||||
```
|
||||
class "vendor-class" {
|
||||
match option vendor-class-identifier;
|
||||
}
|
||||
subclass "vendor-class" "o-ran-ru2/Benetel" {
|
||||
vendor-option-space VC;
|
||||
}
|
||||
option space VC;
|
||||
option VC.server-address code 129 = array of ip-address;
|
||||
option VC.server-fqdn code 130 = string;
|
||||
# Netconf client IP address - DHCP option 43
|
||||
option VC.server-address 192.168.80.1;
|
||||
option VC.server-fqdn "o_du_1.operator.com";
|
||||
set vendor-string = option vendor-class-identifier;
|
||||
# option 143 - DHCPv4 SZTP Redirect Option (RFC8572)
|
||||
# 2 bytes of URI's length + URI
|
||||
option sztp code 143 = { unsigned integer 16, string };
|
||||
option sztp 15 "https://192.168.80.1";
|
||||
# port is optional in URI, e.g. "https://192.168.80.1:222"
|
||||
#option sztp 20 "https://192.168.80.1:2222";
|
||||
subnet 192.168.80.0 netmask 255.255.255.0 {
|
||||
option routers 192.168.80.1;
|
||||
option subnet-mask 255.255.255.0;
|
||||
option domain-name "oai.com";
|
||||
option domain-name-servers 172.21.3.100;
|
||||
host benetel_ru {
|
||||
# RU MAC address
|
||||
hardware ethernet <ru-mac-address>;
|
||||
# RU IP address
|
||||
fixed-address <desired-ru-ip-address>;
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
Please, configure the interface as:
|
||||
```bash
|
||||
sudo ip address add 192.168.80.1/24 dev <interface>
|
||||
```
|
||||
|
||||
### Mandatory packages
|
||||
* On Fedora (we haven't yet tested RHEL):
|
||||
```bash
|
||||
sudo dnf install pcre-devel libssh-devel libxml2-devel libyang2-devel libnetconf2-devel
|
||||
```
|
||||
|
||||
* On Ubuntu:
|
||||
```bash
|
||||
sudo apt-get install libpcre3-dev libssh-dev libxml2-dev
|
||||
```
|
||||
|
||||
On Ubuntu, please note: `sudo apt-get install libyang2-dev libnetconf2-dev` will install unsupported versions (i.e. v2.0.112/v2.0.24 for `libyang2-dev`/`libnetconf2-dev`, but minimum required are v2.1.4/v2.1.25).
|
||||
Therefore, please compile these libraries from source, as following:
|
||||
|
||||
<details>
|
||||
<summary>Installing latest v2 libyang2 and libnetconf2 libraries</summary>
|
||||
|
||||
```
|
||||
rm -rf /tmp/build_mplane_v2
|
||||
mkdir /tmp/build_mplane_v2
|
||||
|
||||
# libyang
|
||||
cd /tmp/build_mplane_v2
|
||||
git clone https://github.com/CESNET/libyang.git
|
||||
cd libyang
|
||||
git checkout v2.1.111
|
||||
mkdir build && cd build
|
||||
cmake -DENABLE_TESTS=OFF \
|
||||
-DENABLE_VALGRIND_TESTS=OFF \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||
-DCMAKE_INSTALL_RPATH=/usr/local/lib \
|
||||
-DPLUGINS_DIR=/usr/local/lib/libyang \
|
||||
-DPLUGINS_DIR_EXTENSIONS=/usr/local/lib/libyang/extensions \
|
||||
-DPLUGINS_DIR_TYPES=/usr/local/lib/libyang/types \
|
||||
-DYANG_MODULE_DIR=/usr/local/share/yang/modules/libyang ..
|
||||
make -j8
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
#libnetconf
|
||||
cd /tmp/build_mplane_v2
|
||||
git clone https://github.com/CESNET/libnetconf2.git
|
||||
cd libnetconf2
|
||||
git checkout v2.1.37
|
||||
mkdir build && cd build
|
||||
cmake -DENABLE_TESTS=OFF \
|
||||
-DENABLE_EXAMPLES=OFF \
|
||||
-DENABLE_VALGRIND_TESTS=OFF \
|
||||
-DCLIENT_SEARCH_DIR=/usr/local/share/yang/modules \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||
-DCMAKE_INSTALL_RPATH=/usr/local/lib \
|
||||
-DLIBYANG_INCLUDE_DIR=/usr/local/include \
|
||||
-DLIBYANG_LIBRARY=/usr/local/lib/libyang.so \
|
||||
-DLY_VERSION_PATH=/usr/local/include \
|
||||
-DYANG_MODULE_DIR=/usr/local/share/yang/modules/libnetconf2 ..
|
||||
make -j8
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
# to uninstall libraries
|
||||
# cd /tmp/build_mplane_v2/libyang/build && sudo make uninstall
|
||||
# cd /tmp/build_mplane_v2/libnetconf2/build && sudo make uninstall
|
||||
# cd
|
||||
# rm -rf /tmp/build_mplane_v2
|
||||
```
|
||||
</details>
|
||||
|
||||
If you would like to install these libraries in the custom path, please replace `/usr/local` default path to e.g. `/opt/mplane-v2`.
|
||||
|
||||
## Benetel O-RU
|
||||
Note: Only v1.2.2 RAN550 and RAN650 have been successfully tested.
|
||||
|
||||
### One time steps
|
||||
Connect to the RU as user `root`, enable the mplane service, and reboot:
|
||||
```bash
|
||||
ssh root@<ru-ip-address>
|
||||
systemctl enable mplane
|
||||
reboot
|
||||
```
|
||||
Once the mplane service is successfully enabled on the RU, two new users are being added in `/etc/passwd`:
|
||||
```bash
|
||||
...
|
||||
oranbenetel:x:1000:1000::/home/oranbenetel:/bin/sh
|
||||
oranext:x:1001:1001::/home/oranext:/bin/sh
|
||||
```
|
||||
Create `oranbenetel` home directory:
|
||||
```bash
|
||||
mkdir /home/oranbenetel && chown oranbenetel:oranbenetel /home/oranbenetel
|
||||
```
|
||||
Connect to the RU as user `oranbenetel`, generate ssh keys, and copy DU public key into RU for NETCONF authentication:
|
||||
```bash
|
||||
ssh oranbenetel@<ru-ip-address>
|
||||
ssh-keygen
|
||||
echo "<DU-pub-key>" >> ~/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
|
||||
## gNB configuration
|
||||
The reference gNB configuration file for one Benetel RAN550:
|
||||
[`gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf)
|
||||
The reference DU configuration file for two Benetel RAN650:
|
||||
[gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf)
|
||||
|
||||
In order to run gNB/DU with M-plane, we need to modify the `fhi_72` section in the configuration file.
|
||||
Example for one RU:
|
||||
```bash
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1"); # one VF can be used as well
|
||||
system_core = 0;
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
du_key_pair = ("<path-to>/.ssh/id_rsa.pub", "<path-to>/.ssh/id_rsa");
|
||||
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67"); # only one needed if one VF configured
|
||||
vlan_tag = (9, 9); # only one needed if one VF configured
|
||||
ru_ip_addr = ("192.168.80.9");
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
Ta4 = (0, 200);
|
||||
});
|
||||
};
|
||||
```
|
||||
Example for two RUs:
|
||||
```bash
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1", "0000:c3:11.2", "0000:c3:11.3"); # two VFs can be used as well
|
||||
system_core = 0;
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
du_key_pair = ("/home/oaicicd/.ssh/id_rsa.pub", "/home/oaicicd/.ssh/id_rsa");
|
||||
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); # only two needed if two VFs configured
|
||||
vlan_tag = (9, 9, 11, 11); # only two needed if two VFs configured
|
||||
ru_ip_addr = ("192.168.80.9", "192.168.80.10");
|
||||
fh_config = (
|
||||
# RAN550 #1
|
||||
{
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
Ta4 = (0, 200);
|
||||
},
|
||||
# RAN550 #2
|
||||
{
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
Ta4 = (0, 200);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
* `fhi_72` :
|
||||
* `dpdk_devices`: [*]
|
||||
* `system_core`: [*]
|
||||
* `io_core`: [*]
|
||||
* `worker_cores`: [*]
|
||||
* `file_prefix`: [*]
|
||||
* `du_key_pair`: ssh public and private keys to authenticate RU with NETCONF
|
||||
* `du_addr`: DU MAC address(es) to create CU-plane interface(s) in the RU
|
||||
* `vlan_tag`: VLAN U and C plane tags to create CU-plane interface(s) in the RU
|
||||
* `ru_ip_addr`: RU IP address to connect to the RU via M-plane
|
||||
* `dpdk_mem_size`: [*]
|
||||
* `dpdk_iova_mode`: [*]
|
||||
* `owdm_enable`: [*]
|
||||
* `fh_config`: only DU delay profile (`T1a` and `Ta4`)
|
||||
|
||||
[*] see [Configure OAI gNB](#configure-oai-gnb) for more details
|
||||
|
||||
The following parameters are retrieved from the RU and forwarded to the xran:
|
||||
* `MTU`
|
||||
* `RU MAC address`
|
||||
* `IQ compression`: if RU supports multiple, the first value in the list is taken; please note that the same value is used for PxSCH/PRACH
|
||||
* `PRACH offset`: hardcoded based on the RU vendor (i.e. for Benetel `max(Nrx,Ntx)`)
|
||||
|
||||
## Build and compile gNB
|
||||
The following cmake options are available:
|
||||
* `OAI_FHI72` = CUS support
|
||||
* `OAI_FHI72_MPLANE` = M support
|
||||
|
||||
Compiled libraries:
|
||||
* `OAI_FHI72` <=> `oran_fhlib_5g`
|
||||
* `OAI_FHI72` && `OAI_FHI72_MPLANE` <=> `oran_fhlib_5g` (CUS) && `oran_fhlib_5g_mplane` (CUSM)
|
||||
|
||||
### Using build_oai script
|
||||
```bash
|
||||
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
|
||||
cd ~/openairinterface5g/cmake_targets/
|
||||
./build_oai -I # if you never installed OAI, use this command once before the next line
|
||||
./build_oai --install-optional-packages # for pcre/libpcre3, libssh, and libxml2 library installation
|
||||
./build_oai --gNB --ninja -t oran_fhlib_5g_mplane --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
|
||||
# if libyang2 and libnetconf2 are installed in `/opt/mplane-v2`, please use the following command:
|
||||
PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig ./build_oai --gNB --ninja -t oran_fhlib_5g_mplane --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
|
||||
```
|
||||
|
||||
### Using cmake directly
|
||||
```bash
|
||||
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
|
||||
cd ~/openairinterface5g/
|
||||
mkdir build && cd build
|
||||
cmake .. -GNinja -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
|
||||
# if libyang2 and libnetconf2 are installed in `/opt/mplane-v2`, please use the following command:
|
||||
PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig cmake .. -GNinja -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
|
||||
ninja nr-softmodem oran_fhlib_5g_mplane params_libconfig
|
||||
```
|
||||
|
||||
## Start the gNB
|
||||
Run the `nr-softmodem` from the build directory:
|
||||
```bash
|
||||
cd ~/openairinterface5g/cmake_targets/ran_build/build
|
||||
sudo ./nr-softmodem -O <mplane-configuration file> --thread-pool <list of non isolated cpus>
|
||||
```
|
||||
|
||||
**Warning**: Make sure that the configuration file you add after the `-O` option is adapted to your machine, especially to its isolated cores.
|
||||
|
||||
M-plane sequence diagram:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant dhcp as DHCP server
|
||||
participant du as O-DU
|
||||
participant ru as O-RU
|
||||
|
||||
dhcp->ru: 1. Transport Layer Initialization
|
||||
note over dhcp,ru: (a) perform VLAN scan (untagged or tagged VLAN)<br/>(b) DHCP assigns IP address to RU<br/>(c) DHCP sends DU IP address to RU
|
||||
|
||||
du->ru: 2. NETCONF/SSH connect
|
||||
|
||||
du->>ru: 3. DU retrieves RU info
|
||||
note left of du: <get>
|
||||
|
||||
note over du: Check if RU is PTP synced
|
||||
|
||||
du->>ru: 4. DU subscribes to all RU notifications
|
||||
note left of du: <subscribe>
|
||||
|
||||
du->>ru: 5. DU updates the supervision timer
|
||||
note left of du: <supervision-watchdog-reset>
|
||||
|
||||
note over du: Store RU MAC, MTU, IQ bitwidth, and PRACH offset info for xran
|
||||
|
||||
note over du: Store all the RU U-plane info - interface name, TX/RX carrier, and TX/RX endpoint names
|
||||
|
||||
du->>ru: 6. DU loads yang models
|
||||
note left of du: <get-schema>
|
||||
note right of ru: ietf-netconf-monitoring.yang
|
||||
|
||||
du->>ru: 7. DU performs CU-plane configuration
|
||||
note left of du: <edit-config>
|
||||
|
||||
note over ru: (1) o-ran-interface.yang - create new interface with VLAN tag, DU and RU MAC addresses<br/>(2)(opt.) o-ran-transceiver.yang - for file upload<br/>(3) o-ran-processing-elements.yang - element with which RU ports should be assigned<br/>(4) o-ran-uplane-conf.yang<br/>#8193;(4a) low-level-tx/rx-endpoints - PxSCH, PRACH<br/>#8193;(4b) tx/rx-array-carriers - center frequency, BW, gain, ACTIVE,...<br/>#8193;(4c) low-level-tx/rx-links - mapping endpoints, carriers and processing element<br/>#8193;(4d)(opt.) if CAT B, SRS configuration<br/>#8193;(4e)(opt.) TDD configuration
|
||||
|
||||
du->>ru: 8. DU checks if CU-plane configuration is valid
|
||||
note left of du: <validate>
|
||||
|
||||
du->>ru: 9. If valid, DU commits the changes
|
||||
note left of du: <commit>
|
||||
|
||||
du->>ru: 10. DU retrieves RU states
|
||||
note right of ru: ietf-hardware.yang
|
||||
note left of du: <get>
|
||||
note over ru: admin-state, power-state, oper-state,<br/>availability-state, usage-state
|
||||
|
||||
ru->>du: 11. RU notifies DU about the configuration change
|
||||
|
||||
note over du: DU configures xran
|
||||
|
||||
du->ru: 12. DU and RU exchange packets
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>4x4 MIMO and 100MHz BW with Benetel 550 RU example run</summary>
|
||||
|
||||
```
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <connect> with username "oranbenetel" and port ID "830".
|
||||
[HW] [MPLANE] Successfuly connected to RU "192.168.80.9" with username "oranbenetel" and port ID "830".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get> operational datastore.
|
||||
[HW] [MPLANE] Successfully retrieved operational datastore from RU "192.168.80.9".
|
||||
[HW] [MPLANE] RU is already PTP synchronized.
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <subscribe> with stream "NETCONF" and filter "(null)".
|
||||
[HW] [MPLANE] RPC reply = OK.
|
||||
[HW] [MPLANE] Successfully subscribed to all notifications from RU "192.168.80.9".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = "<supervision-watchdog-reset xmlns="urn:o-ran:supervision:1.0">
|
||||
<supervision-notification-interval>65535</supervision-notification-interval>
|
||||
<guard-timer-overhead>65535</guard-timer-overhead>
|
||||
</supervision-watchdog-reset>".
|
||||
[HW] [MPLANE] Successfully updated supervision timer to (65535+65535)[s] for RU "192.168.80.9".
|
||||
[HW] [MPLANE] Watchdog timer answer:
|
||||
<next-update-at xmlns="urn:o-ran:supervision:1.0">2025-03-30T08:52:31+02:00</next-update-at>
|
||||
|
||||
[HW] [MPLANE] Interface MTU 1500 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.
|
||||
[HW] [MPLANE] IQ bitwidth 16 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9.
|
||||
[HW] [MPLANE] Storing the following information to forward to xran:
|
||||
RU MAC address 8c:1f:64:d1:11:c0
|
||||
MTU 9600
|
||||
IQ bitwidth 9
|
||||
PRACH offset 4
|
||||
DU port bitmask 61440
|
||||
Band sector bitmask 3840
|
||||
CC ID bitmask 240
|
||||
RU port ID bitmask 15
|
||||
DU port ID 0
|
||||
Band sector ID 0
|
||||
CC ID 0
|
||||
RU port ID 0
|
||||
[HW] [MPLANE] Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-metadata".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "yang".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-inet-types".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-types".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-schema-mount".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-structure-ext".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-datastores".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-acm".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-factory-default".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo-factory-default".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-library".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo-monitoring".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo-plugind".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-with-defaults".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-notifications".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-origin".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-monitoring".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-nmda".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "nc-notifications".
|
||||
[HW] [MPLANE] [LIBYANG] ERROR: Data model "notifications" not found in local searchdirs. (path: (null)).
|
||||
[HW] [MPLANE] [LIBYANG] ERROR: Loading "notifications" module failed. (path: (null)).
|
||||
[HW] [MPLANE] [LIBYANG] ERROR: Parsing module "nc-notifications" failed. (path: (null)).
|
||||
[HW] [MPLANE] Unable to load module "nc-notifications" from RU "192.168.80.9".
|
||||
[HW] [MPLANE] Unable to load all yang modules from operational datastore for RU "192.168.80.9". Using yang models present in "models" subfolder.
|
||||
[HW] [MPLANE] Successfully loaded all yang modules for RU "192.168.80.9".
|
||||
[HW] [MPLANE] The VLAN tags for C and U plane for the RU "192.168.80.9" are the same. Therefore, configuring one common interface and one processing element.
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <edit-config>:
|
||||
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
|
||||
<interface>
|
||||
<name>INTERFACE_0</name>
|
||||
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:l2vlan</type>
|
||||
<enabled>true</enabled>
|
||||
<mac-address xmlns="urn:o-ran:interfaces:1.0">8c:1f:64:d1:11:c0</mac-address>
|
||||
<base-interface xmlns="urn:o-ran:interfaces:1.0">eth0</base-interface>
|
||||
<vlan-id xmlns="urn:o-ran:interfaces:1.0">9</vlan-id>
|
||||
</interface>
|
||||
</interfaces>
|
||||
<processing-elements xmlns="urn:o-ran:processing-element:1.0">
|
||||
<transport-session-type>ETH-INTERFACE</transport-session-type>
|
||||
<ru-elements>
|
||||
<name>PLANE_0</name>
|
||||
<transport-flow>
|
||||
<interface-name>INTERFACE_0</interface-name>
|
||||
<eth-flow>
|
||||
<ru-mac-address>8c:1f:64:d1:11:c0</ru-mac-address>
|
||||
<vlan-id>9</vlan-id>
|
||||
<o-du-mac-address>00:11:22:33:44:66</o-du-mac-address>
|
||||
</eth-flow>
|
||||
</transport-flow>
|
||||
</ru-elements>
|
||||
</processing-elements>
|
||||
<user-plane-configuration xmlns="urn:o-ran:uplane-conf:1.0">
|
||||
<low-level-tx-links>
|
||||
<name>PdschLink0</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<tx-array-carrier>TxArray0</tx-array-carrier>
|
||||
<low-level-tx-endpoint>LowLevelTxEndpoint0</low-level-tx-endpoint>
|
||||
</low-level-tx-links>
|
||||
<low-level-tx-links>
|
||||
<name>PdschLink1</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<tx-array-carrier>TxArray0</tx-array-carrier>
|
||||
<low-level-tx-endpoint>LowLevelTxEndpoint1</low-level-tx-endpoint>
|
||||
</low-level-tx-links>
|
||||
<low-level-tx-links>
|
||||
<name>PdschLink2</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<tx-array-carrier>TxArray0</tx-array-carrier>
|
||||
<low-level-tx-endpoint>LowLevelTxEndpoint2</low-level-tx-endpoint>
|
||||
</low-level-tx-links>
|
||||
<low-level-tx-links>
|
||||
<name>PdschLink3</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<tx-array-carrier>TxArray0</tx-array-carrier>
|
||||
<low-level-tx-endpoint>LowLevelTxEndpoint3</low-level-tx-endpoint>
|
||||
</low-level-tx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PuschLink0</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxEndpoint0</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PrachLink0</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxPrachEndpoint0</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PuschLink1</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxEndpoint1</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PrachLink1</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxPrachEndpoint1</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PuschLink2</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxEndpoint2</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PrachLink2</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxPrachEndpoint2</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PuschLink3</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxEndpoint3</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-rx-links>
|
||||
<name>PrachLink3</name>
|
||||
<processing-element>PLANE_0</processing-element>
|
||||
<rx-array-carrier>RxArray0</rx-array-carrier>
|
||||
<low-level-rx-endpoint>LowLevelRxPrachEndpoint3</low-level-rx-endpoint>
|
||||
</low-level-rx-links>
|
||||
<low-level-tx-endpoints>
|
||||
<name>LowLevelTxEndpoint0</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>0</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-tx-endpoints>
|
||||
<low-level-tx-endpoints>
|
||||
<name>LowLevelTxEndpoint1</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>1</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-tx-endpoints>
|
||||
<low-level-tx-endpoints>
|
||||
<name>LowLevelTxEndpoint2</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>2</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-tx-endpoints>
|
||||
<low-level-tx-endpoints>
|
||||
<name>LowLevelTxEndpoint3</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>3</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-tx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxEndpoint0</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>0</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxPrachEndpoint0</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>4</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxEndpoint1</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>1</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxPrachEndpoint1</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>5</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxEndpoint2</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>2</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxPrachEndpoint2</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>6</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxEndpoint3</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>3</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<low-level-rx-endpoints>
|
||||
<name>LowLevelRxPrachEndpoint3</name>
|
||||
<compression>
|
||||
<iq-bitwidth>9</iq-bitwidth>
|
||||
<compression-type>STATIC</compression-type>
|
||||
</compression>
|
||||
<cp-length>0</cp-length>
|
||||
<cp-length-other>0</cp-length-other>
|
||||
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
|
||||
<e-axcid>
|
||||
<o-du-port-bitmask>61440</o-du-port-bitmask>
|
||||
<band-sector-bitmask>3840</band-sector-bitmask>
|
||||
<ccid-bitmask>240</ccid-bitmask>
|
||||
<ru-port-bitmask>15</ru-port-bitmask>
|
||||
<eaxc-id>7</eaxc-id>
|
||||
</e-axcid>
|
||||
</low-level-rx-endpoints>
|
||||
<tx-array-carriers>
|
||||
<name>TxArray0</name>
|
||||
<absolute-frequency-center>663360</absolute-frequency-center>
|
||||
<center-of-channel-bandwidth>3950400000</center-of-channel-bandwidth>
|
||||
<channel-bandwidth>100000000</channel-bandwidth>
|
||||
<active>ACTIVE</active>
|
||||
<gain>0.0</gain>
|
||||
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
|
||||
<downlink-sfn-offset>0</downlink-sfn-offset>
|
||||
</tx-array-carriers>
|
||||
<rx-array-carriers>
|
||||
<name>RxArray0</name>
|
||||
<absolute-frequency-center>663360</absolute-frequency-center>
|
||||
<center-of-channel-bandwidth>3950400000</center-of-channel-bandwidth>
|
||||
<channel-bandwidth>100000000</channel-bandwidth>
|
||||
<active>ACTIVE</active>
|
||||
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
|
||||
<downlink-sfn-offset>0</downlink-sfn-offset>
|
||||
<gain-correction>0.0</gain-correction>
|
||||
<n-ta-offset>0</n-ta-offset>
|
||||
</rx-array-carriers>
|
||||
</user-plane-configuration>
|
||||
|
||||
[HW] [MPLANE] RPC reply = OK.
|
||||
[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.80.9".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <validate> candidate datastore.
|
||||
[HW] [MPLANE] RPC reply = OK.
|
||||
[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9".
|
||||
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <commit> candidate datastore.
|
||||
[HW] [MPLANE] RPC reply = OK.
|
||||
[HW] [MPLANE] Successfully commited CU-planes configuration into running datastore for RU "192.168.80.9".
|
||||
[HW] [MPLANE] Usage state = "idle" for RU "192.168.80.9".
|
||||
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.049085102+00:00)
|
||||
{
|
||||
"o-ran-uplane-conf:rx-array-carriers-state-change": {
|
||||
"rx-array-carriers": [
|
||||
{
|
||||
"name": "RxArray0",
|
||||
"state": "BUSY"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.058136880+00:00)
|
||||
{
|
||||
"o-ran-uplane-conf:tx-array-carriers-state-change": {
|
||||
"tx-array-carriers": [
|
||||
{
|
||||
"name": "TxArray0",
|
||||
"state": "BUSY"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.078776163+00:00)
|
||||
{
|
||||
"o-ran-uplane-conf:rx-array-carriers-state-change": {
|
||||
"rx-array-carriers": [
|
||||
{
|
||||
"name": "RxArray0",
|
||||
"state": "READY"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.093039138+00:00)
|
||||
{
|
||||
"o-ran-uplane-conf:tx-array-carriers-state-change": {
|
||||
"tx-array-carriers": [
|
||||
{
|
||||
"name": "TxArray0",
|
||||
"state": "READY"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.452751936+00:00)
|
||||
{
|
||||
"ietf-netconf-notifications:netconf-config-change": {
|
||||
"changed-by": {
|
||||
"username": "root",
|
||||
"session-id": 0
|
||||
},
|
||||
"datastore": "running",
|
||||
"edit": [
|
||||
{
|
||||
"target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']",
|
||||
"operation": "create"
|
||||
},
|
||||
{
|
||||
"target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']/name",
|
||||
"operation": "create"
|
||||
},
|
||||
...
|
||||
}
|
||||
|
||||
[HW] [MPLANE] RU "192.168.80.9" is now ready.
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
Note: If you wish to run the fronthaul without M-plane, no need for recompilation, as the library `oran_fhlib_5g` already exists.
|
||||
The only mandatory step is to link `oran_fhlib_5g` to `oai_transpro` library.
|
||||
```bash
|
||||
cd ~/openairinterface5g/cmake_targets/ran_build/build
|
||||
rm liboai_transpro.so
|
||||
ln -s liboran_fhlib_5g.so liboai_transpro.so
|
||||
sudo ./nr-softmodem -O <without-mplane-configuration file> --thread-pool <list of non isolated cpus>
|
||||
```
|
||||
|
||||
|
||||
# Contact in case of questions
|
||||
|
||||
You can ask your question on the [mailing lists](https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/MailingList).
|
||||
|
||||
@@ -118,6 +118,7 @@ Some directories under `radio` contain READMEs:
|
||||
- [BladeRF](../radio/BLADERF/README)
|
||||
- [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md)
|
||||
- [fhi_72](../radio/fhi_72/README.md)
|
||||
- [vrtsim](../radio/vrtsim/README.md)
|
||||
|
||||
The other SDRs (AW2S, LimeSDR, ...) have no READMEs.
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ COPY --from=gnb-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
COPY --from=gnb-base \
|
||||
|
||||
@@ -69,6 +69,7 @@ COPY --from=gnb-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
COPY --from=gnb-base \
|
||||
|
||||
@@ -110,6 +110,7 @@ COPY --from=gnb-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_rrc.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_o1.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
# Now we are copying from builder-image the UHD files.
|
||||
|
||||
@@ -75,6 +75,7 @@ COPY --from=nr-ue-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
COPY --from=nr-ue-base \
|
||||
|
||||
@@ -72,6 +72,7 @@ COPY --from=nr-ue-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
COPY --from=nr-ue-base \
|
||||
|
||||
@@ -110,6 +110,7 @@ COPY --from=nr-ue-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ciUE.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
# Now we are copying from builder-image the UHD files.
|
||||
|
||||
+15
-11
@@ -872,18 +872,22 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
if (*update_ntn_system_information) {
|
||||
*update_ntn_system_information = false;
|
||||
|
||||
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
UE->timing_advance = fp->samples_per_subframe * UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
*timing_advance +=
|
||||
fp->get_samples_slot_timestamp(slot_nr,
|
||||
fp,
|
||||
UE->ntn_config_message->ntn_config_params.cell_specific_k_offset - *ntn_koffset);
|
||||
*ntn_koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
UE->timing_advance = fp->samples_per_subframe * total_ta_ms;
|
||||
|
||||
int mu = fp->numerology_index;
|
||||
int koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
if (*ntn_koffset != koffset) {
|
||||
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
|
||||
*timing_advance += fp->get_samples_slot_timestamp(slot_nr, fp, (koffset - *ntn_koffset) << mu);
|
||||
*ntn_koffset = koffset;
|
||||
}
|
||||
|
||||
LOG_I(PHY,
|
||||
"cell_specific_k_offset = %d ms, ntn_total_time_advance_ms = %f ms (%d samples)\n",
|
||||
"k_offset = %d ms (%d slots), ntn_total_time_advance_ms = %f ms (%d samples)\n",
|
||||
*ntn_koffset,
|
||||
UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms,
|
||||
*ntn_koffset << mu,
|
||||
total_ta_ms,
|
||||
UE->timing_advance);
|
||||
}
|
||||
}
|
||||
@@ -1080,7 +1084,7 @@ void *UE_thread(void *arg)
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
update_ntn_system_information = true;
|
||||
nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset;
|
||||
nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset << fp->numerology_index;
|
||||
}
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
@@ -1214,7 +1218,7 @@ void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconf
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(i);
|
||||
mac->if_module = nr_ue_if_module_init(i);
|
||||
AssertFatal(mac->if_module, "can not initialize IF module\n");
|
||||
if (!IS_SA_MODE(get_softmodem_params()) || !get_softmodem_params()->sl_mode) {
|
||||
if (!IS_SA_MODE(get_softmodem_params()) && !get_softmodem_params()->sl_mode) {
|
||||
init_nsa_message(&rrc_inst[i], reconfig_file, rbconfig_file);
|
||||
nr_rlc_activate_srb0(mac_inst[i].crnti, NULL, send_srb0_rrc);
|
||||
}
|
||||
|
||||
@@ -309,11 +309,8 @@ uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg,
|
||||
nfapi_nr_srs_indication_t *srs_ind = (nfapi_nr_srs_indication_t *)msg;
|
||||
for (uint8_t pdu_idx = 0; pdu_idx < srs_ind->number_of_pdus; pdu_idx++) {
|
||||
nfapi_nr_srs_indication_pdu_t *pdu = &srs_ind->pdu_list[pdu_idx];
|
||||
nfapi_srs_report_tlv_t *report_tlv = &pdu->report_tlv;
|
||||
for (int i = 0; i < (report_tlv->length + 3) / 4; i++) {
|
||||
if (!pull32(pDataMsg, &report_tlv->value[i], data_end)) {
|
||||
return 0;
|
||||
}
|
||||
if (!unpack_nr_srs_report_tlv_value(&pdu->report_tlv, pDataMsg, data_end)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
#include "PHY/INIT/phy_init.h"
|
||||
#include "PHY/INIT/nr_phy_init.h"
|
||||
#include "PHY/LTE_TRANSPORT/transport_proto.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "openair1/SCHED_NR/fapi_nr_l1.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "openair1/PHY/defs_gNB.h"
|
||||
|
||||
@@ -36,6 +36,18 @@ uint8_t pull8(uint8_t **in, uint8_t *out, uint8_t *end);
|
||||
uint8_t pulls8(uint8_t **in, int8_t *out, uint8_t *end);
|
||||
uint8_t pull16(uint8_t **in, uint16_t *out, uint8_t *end);
|
||||
uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end);
|
||||
|
||||
/*! \brief Pull an arbitrary amount of bytes ( 0 to 4 ) into an uint32_t
|
||||
* \param length the amount of bytes to pull
|
||||
* \param in the buffer from where to pull the bytes
|
||||
* \param out a pointer to the destination uint32_t
|
||||
* \param end a pointer to the end of the buffer in
|
||||
*
|
||||
* This function is used to pull `length` amount of bytes from `in` into `out`.
|
||||
* Used where pulling the full 32 bits would cause the `in` pointer to go over `end`.
|
||||
* It's currently used to pull the last bytes of a payload where the buffer does not contain padding at the end.
|
||||
*/
|
||||
uint8_t pullx32(uint8_t length, uint8_t **in, uint32_t *out, uint8_t *end);
|
||||
uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end);
|
||||
uint8_t pulls32(uint8_t **in, int32_t *out, uint8_t *end);
|
||||
|
||||
|
||||
@@ -259,6 +259,31 @@ uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end)
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pullx32(uint8_t length, uint8_t **in, uint32_t *out, uint8_t *end)
|
||||
{
|
||||
uint8_t *pIn = *in;
|
||||
if (length > 4) {
|
||||
NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s Can't pull more than 4 bytes (%d) into a uint32_t\n", __FUNCTION__, length);
|
||||
on_error();
|
||||
return 0;
|
||||
}
|
||||
if ((end - pIn) >= length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN
|
||||
*out |= ((uint32_t)pIn[i] << (8 * i));
|
||||
#else
|
||||
*out = ((uint32_t)pIn[i] << (8 * (length - 1 - i)));
|
||||
#endif
|
||||
}
|
||||
(*in) += length;
|
||||
return length;
|
||||
} else {
|
||||
NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__);
|
||||
on_error();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end)
|
||||
{
|
||||
uint8_t *pIn = *in;
|
||||
|
||||
@@ -50,6 +50,7 @@ uint8_t pack_nr_uci_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
|
||||
uint8_t unpack_nr_uci_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config);
|
||||
uint8_t pack_nr_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *config);
|
||||
uint8_t unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config);
|
||||
uint8_t unpack_nr_srs_report_tlv_value(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end);
|
||||
uint8_t pack_nr_rach_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *config);
|
||||
uint8_t unpack_nr_rach_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config);
|
||||
#endif // OPENAIRINTERFACE_NR_FAPI_P7_H
|
||||
|
||||
@@ -2300,6 +2300,28 @@ uint8_t pack_nr_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t unpack_nr_srs_report_tlv_value(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end)
|
||||
{
|
||||
#ifndef ENABLE_AERIAL
|
||||
for (int i = 0; i < (report_tlv->length + 3) / 4; i++) {
|
||||
if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const uint16_t last_idx = ((report_tlv->length + 3) / 4) - 1;
|
||||
for (int i = 0; i < last_idx; i++) {
|
||||
if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Pull last bytes according to how much padding it would need to be 32-bit aligned
|
||||
const uint8_t padding = get_tlv_padding(report_tlv->length);
|
||||
pullx32(4 - padding, ppReadPackedMsg, &report_tlv->value[last_idx], end);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t unpack_nr_srs_report_tlv(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end) {
|
||||
|
||||
if(!(pull16(ppReadPackedMsg, &report_tlv->tag, end) &&
|
||||
@@ -2307,10 +2329,8 @@ static uint8_t unpack_nr_srs_report_tlv(nfapi_srs_report_tlv_t *report_tlv, uint
|
||||
return 0;
|
||||
}
|
||||
#ifndef ENABLE_AERIAL
|
||||
for (int i = 0; i < (report_tlv->length + 3) / 4; i++) {
|
||||
if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) {
|
||||
return 0;
|
||||
}
|
||||
if (!unpack_nr_srs_report_tlv_value(report_tlv, ppReadPackedMsg, end)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
@@ -2684,6 +2684,18 @@ void dump_uci_indication(const nfapi_nr_uci_indication_t *msg)
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_srs_report_tlv(const nfapi_srs_report_tlv_t* tlv, int depth)
|
||||
{
|
||||
depth++;
|
||||
INDENTED_PRINTF("TAG = 0x%02x\n", tlv->tag);
|
||||
INDENTED_PRINTF("LENGTH = 0x%02x\n", tlv->length);
|
||||
INDENTED_PRINTF("VALUE = ");
|
||||
for (int i = 0; i < ((tlv->length + 3) / 4); ++i) {
|
||||
printf("0x%04x ", tlv->value[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dump_srs_indication(const nfapi_nr_srs_indication_t *msg)
|
||||
{
|
||||
int depth = 0;
|
||||
@@ -2704,7 +2716,7 @@ void dump_srs_indication(const nfapi_nr_srs_indication_t *msg)
|
||||
INDENTED_PRINTF("Timing advance offset in nanoseconds = 0x%02x\n", pdu->timing_advance_offset_nsec);
|
||||
INDENTED_PRINTF("SRS usage = 0x%02x\n", pdu->srs_usage);
|
||||
INDENTED_PRINTF("Report Type = 0x%02x\n", pdu->report_type);
|
||||
/* call to dump_srs_report_tlv */
|
||||
dump_srs_report_tlv(&pdu->report_tlv, depth);
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include "NR_BCCH-BCH-Message.h"
|
||||
#include "NR_ServingCellConfigCommon.h"
|
||||
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "SCHED_NR/phy_frame_config_nr.h"
|
||||
|
||||
#include "NR_MIB.h"
|
||||
|
||||
@@ -24,11 +24,14 @@
|
||||
|
||||
static void fil_srs_indication_report_tlv(nfapi_srs_report_tlv_t *tlv)
|
||||
{
|
||||
tlv->tag = rand16_range(0,3);
|
||||
tlv->length = rand32_range(0,sizeof(tlv->value));
|
||||
for (int i = 0; i < (tlv->length + 3) / 4; ++i) {
|
||||
tlv->tag = rand16_range(0, 3);
|
||||
tlv->length = rand32_range(1, sizeof(tlv->value));
|
||||
const uint16_t last_idx = ((tlv->length + 3) / 4) - 1;
|
||||
for (int i = 0; i < last_idx; ++i) {
|
||||
tlv->value[i] = rand32();
|
||||
}
|
||||
const uint8_t num_bytes = 4 - get_tlv_padding(tlv->length);
|
||||
tlv->value[last_idx] = rand32_range(0, 1 << (8 * num_bytes));
|
||||
}
|
||||
|
||||
static void fill_srs_indication_PDU(nfapi_nr_srs_indication_pdu_t *pdu)
|
||||
|
||||
@@ -575,8 +575,8 @@ c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp,
|
||||
|
||||
DEBUG_PBCH("PBCH DMRS Correlation : gNB_id %d , OFDM size %d, Ncp=%d, k=%u symbol %d\n",
|
||||
proc->gNB_id,
|
||||
ue->frame_parms.ofdm_symbol_size,
|
||||
ue->frame_parms.Ncp,
|
||||
fp->ofdm_symbol_size,
|
||||
fp->Ncp,
|
||||
k,
|
||||
symbol);
|
||||
|
||||
@@ -590,8 +590,8 @@ c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp,
|
||||
c16_t *pil = pilot;
|
||||
const c16_t *rxF = &rxdataF[aarx][symbol_offset + k];
|
||||
|
||||
DEBUG_PBCH("pbch ch est pilot RB_DL %d\n", ue->frame_parms.N_RB_DL);
|
||||
DEBUG_PBCH("k %u, first_carrier %d\n", k, ue->frame_parms.first_carrier_offset);
|
||||
DEBUG_PBCH("pbch ch est pilot RB_DL %d\n", fp->N_RB_DL);
|
||||
DEBUG_PBCH("k %u, first_carrier %d\n", k, fp->first_carrier_offset);
|
||||
|
||||
// Treat first 2 pilots specially (left edge)
|
||||
computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15);
|
||||
@@ -769,7 +769,7 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp,
|
||||
multaddRealVectorComplexScalar(fr, ch, dl_ch, 16);
|
||||
pil++;
|
||||
re_offset = (re_offset + 4) % fp->ofdm_symbol_size;
|
||||
dl_ch += 24;
|
||||
dl_ch += 12;
|
||||
|
||||
for (int pilot_cnt = 3; pilot_cnt < (3 * num_rbs); pilot_cnt += 3) {
|
||||
// if (pilot_cnt == 30)
|
||||
@@ -779,7 +779,7 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp,
|
||||
if (dmrss == 1 && pilot_cnt == 12) {
|
||||
pilot_cnt=48;
|
||||
re_offset = (re_offset + 144) % fp->ofdm_symbol_size;
|
||||
dl_ch += 288;
|
||||
dl_ch += 144;
|
||||
}
|
||||
ch = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
DEBUG_PBCH("pilot %u: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n",
|
||||
|
||||
@@ -50,6 +50,7 @@ typedef enum {
|
||||
#define CHANMODEL_FREE_RSQRT_6 1<<1
|
||||
#define CHANMODEL_FREE_RSQRT_NTAPS 1<<2
|
||||
#define CHANMODEL_FREE_AMPS 1<<3
|
||||
#define SHR3 (jz = jsr, jsr ^= (jsr << 13), jsr ^= (jsr >> 17), jsr ^= (jsr << 5), jz + jsr)
|
||||
|
||||
typedef enum {
|
||||
CORR_LEVEL_LOW,
|
||||
|
||||
@@ -6,13 +6,14 @@ add_library(e2_ran_func_cuup STATIC
|
||||
O-RAN/ran_func_kpm_subs.c
|
||||
O-RAN/ran_func_rc.c
|
||||
O-RAN/ran_func_rc_subs.c
|
||||
../flexric/src/sm/rc_sm/ie/rc_data_ie.c
|
||||
CUSTOMIZED/ran_func_gtp.c # GTP SM not yet implemented in CU-UP
|
||||
CUSTOMIZED/ran_func_pdcp.c
|
||||
CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data
|
||||
../flexric/test/rnd/fill_rnd_data_tc.c
|
||||
)
|
||||
|
||||
target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj sm_common_ie_obj ds)
|
||||
target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj e2sm_rc_ir_obj sm_common_ie_obj ds alg)
|
||||
target_compile_definitions(e2_ran_func_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_CUUP)
|
||||
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
||||
#include "asn1_msg.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h"
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "nr_mac.h"
|
||||
#include "nr_mac_common.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include <limits.h>
|
||||
#include <executables/softmodem-common.h>
|
||||
@@ -2431,6 +2432,19 @@ uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config,
|
||||
return n_antenna_port;
|
||||
}
|
||||
|
||||
static int binomial(int n, int k)
|
||||
{
|
||||
if (k > n - k)
|
||||
k = n - k;
|
||||
int c = 1;
|
||||
for (int i = 1; i <= k; i++, n--) {
|
||||
if (c / i > UINT_MAX/n) // return 0 on overflow
|
||||
return 0;
|
||||
c = c / i * n + c % i * n / i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// #define DEBUG_SRS_RESOURCE_IND
|
||||
uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers,
|
||||
NR_PUSCH_Config_t *pusch_Config,
|
||||
@@ -3422,21 +3436,6 @@ uint8_t get_pusch_mcs_table(long *mcs_Table,
|
||||
}
|
||||
|
||||
|
||||
int binomial(int n, int k) {
|
||||
int c = 1, i;
|
||||
|
||||
if (k > n-k)
|
||||
k = n-k;
|
||||
|
||||
for (i = 1; i <= k; i++, n--) {
|
||||
if (c/i > UINT_MAX/n) // return 0 on overflow
|
||||
return 0;
|
||||
|
||||
c = c / i * n + c % i * n / i;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* extract PTRS values from RC and validate it based upon 38.214 5.1.6.3 */
|
||||
bool set_dl_ptrs_values(NR_PTRS_DownlinkConfig_t *ptrs_config,
|
||||
uint16_t rbSize,uint8_t mcsIndex, uint8_t mcsTable,
|
||||
@@ -4357,127 +4356,132 @@ bool set_ul_ptrs_values(NR_PTRS_UplinkConfig_t *ul_ptrs_config,
|
||||
}
|
||||
|
||||
//! Calculating number of bits set
|
||||
uint8_t number_of_bits_set(uint8_t buf) {
|
||||
static uint8_t number_of_bits_set(uint8_t buf)
|
||||
{
|
||||
uint8_t nb_of_bits_set = 0;
|
||||
uint8_t mask = 0xff;
|
||||
uint8_t index = 0;
|
||||
|
||||
for (index=7; (buf & mask) && (index>=0) ; index--){
|
||||
if (buf & (1<<index))
|
||||
for (int index = 7; (buf & mask) && (index >= 0); index--) {
|
||||
if (buf & (1 << index))
|
||||
nb_of_bits_set++;
|
||||
|
||||
mask>>=1;
|
||||
mask >>= 1;
|
||||
}
|
||||
return nb_of_bits_set;
|
||||
}
|
||||
|
||||
void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t nb_resources,
|
||||
nr_csi_report_t *csi_report) {
|
||||
|
||||
static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t nb_resources, nr_csi_report_t *csi_report)
|
||||
{
|
||||
if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) {
|
||||
if (NULL != csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1;
|
||||
if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1;
|
||||
else
|
||||
/*! From Spec 38.331
|
||||
* nrofReportedRS
|
||||
* The number (N) of measured RS resources to be reported per report setting in a non-group-based report. N <= N_max, where N_max is either 2 or 4 depending on UE
|
||||
* The number (N) of measured RS resources to be reported per report setting in a non-group-based report.
|
||||
* N <= N_max, where N_max is either 2 or 4 depending on UE
|
||||
* capability. FFS: The signaling mechanism for the gNB to select a subset of N beams for the UE to measure and report.
|
||||
* When the field is absent the UE applies the value 1
|
||||
*/
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri= 1;
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri = 1;
|
||||
} else
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri= 2;
|
||||
csi_report->CSI_report_bitlen.nb_ssbri_cri = 2;
|
||||
|
||||
if (nb_resources) {
|
||||
csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources));
|
||||
csi_report->CSI_report_bitlen.rsrp_bitlen = 7; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen =4; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP
|
||||
} else {
|
||||
csi_report->CSI_report_bitlen.cri_ssbri_bitlen =0;
|
||||
csi_report->CSI_report_bitlen.cri_ssbri_bitlen = 0;
|
||||
csi_report->CSI_report_bitlen.rsrp_bitlen = 0;
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen =0;
|
||||
csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
nr_csi_report_t *csi_report)
|
||||
static uint8_t compute_ri_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, nr_csi_report_t *csi_report)
|
||||
{
|
||||
|
||||
struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig;
|
||||
uint8_t nb_allowed_ri, ri_bitlen;
|
||||
uint8_t ri_restriction = 0;
|
||||
|
||||
if (codebookConfig == NULL) {
|
||||
csi_report->csi_meas_bitlen.ri_bitlen = 0;
|
||||
return ri_restriction;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL;
|
||||
struct NR_CodebookConfig__codebookType__type1 *type1 = NULL;
|
||||
if (codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1)
|
||||
type1 = codebookConfig->codebookType.choice.type1;
|
||||
else
|
||||
LOG_E(NR_MAC, "Only type1 codebook configuration is supported\n");
|
||||
if (type1 && type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel)
|
||||
type1single = type1->subType.choice.typeI_SinglePanel;
|
||||
else
|
||||
LOG_E(NR_MAC, "Only type1 single panel codebook configuration is supported\n");
|
||||
|
||||
if (!type1single)
|
||||
return -1;
|
||||
|
||||
uint8_t ri_restriction = type1single->typeI_SinglePanel_ri_Restriction.buf[0];
|
||||
|
||||
// codebook type1 single panel
|
||||
if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel == codebookConfig->codebookType.choice.type1->subType.present) {
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel;
|
||||
if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) {
|
||||
|
||||
ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0];
|
||||
|
||||
if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) {
|
||||
nb_allowed_ri = number_of_bits_set(ri_restriction);
|
||||
ri_bitlen = ceil(log2(nb_allowed_ri));
|
||||
// from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel
|
||||
ri_bitlen = ri_bitlen < 1 ? ri_bitlen : 1;
|
||||
csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen;
|
||||
}
|
||||
if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) {
|
||||
if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present ==
|
||||
NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) {
|
||||
// 4 ports
|
||||
nb_allowed_ri = number_of_bits_set(ri_restriction);
|
||||
ri_bitlen = ceil(log2(nb_allowed_ri));
|
||||
|
||||
ri_bitlen = ri_bitlen < 1 ? ri_bitlen : 1; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel
|
||||
// from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel
|
||||
ri_bitlen = ri_bitlen < 2 ? ri_bitlen : 2;
|
||||
csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen;
|
||||
}
|
||||
if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo){
|
||||
if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present ==
|
||||
NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) {
|
||||
// 4 ports
|
||||
|
||||
ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0];
|
||||
|
||||
nb_allowed_ri = number_of_bits_set(ri_restriction);
|
||||
ri_bitlen = ceil(log2(nb_allowed_ri));
|
||||
|
||||
ri_bitlen = ri_bitlen < 2 ? ri_bitlen : 2; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel
|
||||
csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen;
|
||||
}
|
||||
else {
|
||||
// more than 4 ports
|
||||
|
||||
ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0];
|
||||
|
||||
nb_allowed_ri = number_of_bits_set(ri_restriction);
|
||||
ri_bitlen = ceil(log2(nb_allowed_ri));
|
||||
|
||||
csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen;
|
||||
}
|
||||
}
|
||||
return ri_restriction;
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"Other configurations not yet implemented\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t ri_restriction,
|
||||
nr_csi_report_t *csi_report) {
|
||||
|
||||
struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig;
|
||||
for(int i=0; i<8; i++) {
|
||||
if (codebookConfig == NULL || ((ri_restriction>>i)&0x01) == 0)
|
||||
csi_report->csi_meas_bitlen.li_bitlen[i]=0;
|
||||
else {
|
||||
// codebook type1 single panel
|
||||
if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel==codebookConfig->codebookType.choice.type1->subType.present)
|
||||
csi_report->csi_meas_bitlen.li_bitlen[i]=ceil(log2(i+1))<2?ceil(log2(i+1)):2;
|
||||
// more than 4 ports
|
||||
nb_allowed_ri = number_of_bits_set(ri_restriction);
|
||||
ri_bitlen = ceil(log2(nb_allowed_ri));
|
||||
csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen;
|
||||
}
|
||||
}
|
||||
return ri_restriction;
|
||||
}
|
||||
|
||||
static void compute_li_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t ri_restriction, nr_csi_report_t *csi_report)
|
||||
{
|
||||
struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig;
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if (codebookConfig == NULL || ((ri_restriction >> i) & 0x01) == 0)
|
||||
csi_report->csi_meas_bitlen.li_bitlen[i] = 0;
|
||||
else {
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL;
|
||||
struct NR_CodebookConfig__codebookType__type1 *type1 = NULL;
|
||||
if (codebookConfig && codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1)
|
||||
type1 = codebookConfig->codebookType.choice.type1;
|
||||
else
|
||||
AssertFatal(1==0,"Other configurations not yet implemented\n");
|
||||
LOG_E(NR_MAC, "Only type1 codebook configuration is supported\n");
|
||||
if (type1 && type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel)
|
||||
type1single = type1->subType.choice.typeI_SinglePanel;
|
||||
else
|
||||
LOG_E(NR_MAC, "Only type1 single panel codebook configuration is supported\n");
|
||||
// codebook type1 single panel
|
||||
if (type1single)
|
||||
csi_report->csi_meas_bitlen.li_bitlen[i] = ceil(log2(i + 1)) < 2 ? ceil(log2(i + 1)) : 2;
|
||||
else
|
||||
csi_report->csi_meas_bitlen.li_bitlen[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2,
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo) {
|
||||
|
||||
static void get_n1n2_o1o2_singlepanel(int *n1,
|
||||
int *n2,
|
||||
int *o1,
|
||||
int *o2,
|
||||
const struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo)
|
||||
{
|
||||
// Table 5.2.2.2.1-2 in 38.214 for supported configurations
|
||||
switch(morethantwo->n1_n2.present){
|
||||
case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction):
|
||||
@@ -4559,7 +4563,7 @@ void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2,
|
||||
*o2 = 1;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Not supported configuration for n1_n2 in codebook configuration");
|
||||
AssertFatal(false, "Not supported configuration for n1_n2 in codebook configuration");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4691,15 +4695,13 @@ static void set_bitlen_size_singlepanel(CSI_Meas_bitlen_t *csi_bitlen, int n1, i
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Invalid rank in x1 x2 bit length computation\n");
|
||||
AssertFatal(false, "Invalid rank in x1 x2 bit length computation\n");
|
||||
}
|
||||
csi_bitlen->pmi_x1_bitlen[i] = csi_bitlen->pmi_i11_bitlen[i] + csi_bitlen->pmi_i12_bitlen[i] + csi_bitlen->pmi_i13_bitlen[i];
|
||||
}
|
||||
|
||||
|
||||
void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t ri_restriction,
|
||||
nr_csi_report_t *csi_report)
|
||||
static void compute_pmi_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t ri_restriction, nr_csi_report_t *csi_report)
|
||||
{
|
||||
NR_CodebookConfig_t *codebookConfig = csi_reportconfig->codebookConfig;
|
||||
for(int i = 0; i < 8; i++) {
|
||||
@@ -4731,45 +4733,51 @@ void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
}
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"Type1 Multi-panel Codebook Config not yet implemented\n");
|
||||
AssertFatal(false, "Type1 Multi-panel Codebook Config not yet implemented\n");
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"Type2 Codebook Config not yet implemented\n");
|
||||
AssertFatal(false, "Type2 Codebook Config not yet implemented\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t ri_restriction,
|
||||
nr_csi_report_t *csi_report) {
|
||||
static void compute_cqi_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t ri_restriction, nr_csi_report_t *csi_report)
|
||||
{
|
||||
NR_CodebookConfig_t *codebookConfig = csi_reportconfig->codebookConfig;
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL;
|
||||
struct NR_CodebookConfig__codebookType__type1 *type1 = NULL;
|
||||
if (codebookConfig && codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1)
|
||||
type1 = codebookConfig->codebookType.choice.type1;
|
||||
else
|
||||
LOG_E(NR_MAC, "Only type1 codebook configuration is supported\n");
|
||||
if (type1 && type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel)
|
||||
type1single = type1->subType.choice.typeI_SinglePanel;
|
||||
else
|
||||
LOG_E(NR_MAC, "Only type1 single panel codebook configuration is supported\n");
|
||||
|
||||
struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig;
|
||||
struct NR_CSI_ReportConfig__reportFreqConfiguration *freq_config = csi_reportconfig->reportFreqConfiguration;
|
||||
if (!freq_config
|
||||
|| *freq_config->cqi_FormatIndicator != NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI) {
|
||||
LOG_E(NR_MAC, "Only wide-band CQI reporting is supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (*freq_config->cqi_FormatIndicator == NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI) {
|
||||
for(int i=0; i<8; i++) {
|
||||
if ((ri_restriction>>i)&0x01) {
|
||||
csi_report->csi_meas_bitlen.cqi_bitlen[i] = 4;
|
||||
if(codebookConfig != NULL) {
|
||||
if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel == codebookConfig->codebookType.choice.type1->subType.present){
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel;
|
||||
if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) {
|
||||
if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present >
|
||||
NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) {
|
||||
// more than 4 antenna ports
|
||||
if (i > 4)
|
||||
csi_report->csi_meas_bitlen.cqi_bitlen[i] += 4; // CQI for second TB
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 8; i++) {
|
||||
if ((ri_restriction >> i) & 0x01) {
|
||||
csi_report->csi_meas_bitlen.cqi_bitlen[i] = 4;
|
||||
if (!type1single)
|
||||
continue;
|
||||
if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) {
|
||||
if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present >
|
||||
NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) {
|
||||
// more than 4 antenna ports
|
||||
if (i > 4)
|
||||
csi_report->csi_meas_bitlen.cqi_bitlen[i] += 4; // CQI for second TB
|
||||
}
|
||||
}
|
||||
else
|
||||
csi_report->csi_meas_bitlen.cqi_bitlen[i] = 0;
|
||||
}
|
||||
} else
|
||||
csi_report->csi_meas_bitlen.cqi_bitlen[i] = 0;
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"Sub-band CQI reporting not yet supported");
|
||||
}
|
||||
|
||||
//!TODO : same function can be written to handle csi_resources
|
||||
@@ -4779,12 +4787,16 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report
|
||||
uint8_t nb_resources = 0;
|
||||
NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type;
|
||||
NR_CSI_ResourceConfigId_t csi_ResourceConfigId;
|
||||
struct NR_CSI_ResourceConfig *csi_resourceconfig;
|
||||
NR_CSI_ResourceConfig_t *csi_resourceconfig;
|
||||
|
||||
if (!csi_MeasConfig->csi_ReportConfigToAddModList) {
|
||||
LOG_E(NR_MAC, "csi_ReportConfigToAddModList is NULL, not expected\n");
|
||||
return;
|
||||
}
|
||||
// for each CSI measurement report configuration (list of CSI-ReportConfig)
|
||||
LOG_D(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count);
|
||||
for (csi_report_id = 0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) {
|
||||
struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
|
||||
NR_CSI_ReportConfig_t *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
|
||||
// MAC structure for CSI measurement reports (per UE and per report)
|
||||
nr_csi_report_t *csi_report = &csi_report_template[csi_report_id];
|
||||
// csi-ResourceConfigId of a CSI-ResourceConfig included in the configuration
|
||||
@@ -4848,18 +4860,18 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report
|
||||
compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
break;
|
||||
case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI):
|
||||
csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources));
|
||||
csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report);
|
||||
compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report);
|
||||
|
||||
@@ -290,33 +290,6 @@ bool set_ul_ptrs_values(NR_PTRS_UplinkConfig_t *ul_ptrs_config,
|
||||
@returns transformPrecoding value */
|
||||
long get_transformPrecoding(const NR_UE_UL_BWP_t *current_UL_BWP, nr_dci_format_t dci_format, uint8_t configuredGrant);
|
||||
|
||||
uint8_t number_of_bits_set(uint8_t buf);
|
||||
|
||||
void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t nb_resources,
|
||||
nr_csi_report_t *csi_report);
|
||||
|
||||
uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
nr_csi_report_t *csi_report);
|
||||
|
||||
void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t ri_restriction,
|
||||
nr_csi_report_t *csi_report);
|
||||
|
||||
void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2,
|
||||
struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo);
|
||||
|
||||
void get_x1x2_bitlen_singlepanel(int n1, int n2, int o1, int o2,
|
||||
int *x1, int *x2, int rank, int codebook_mode);
|
||||
|
||||
void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t ri_restriction,
|
||||
nr_csi_report_t *csi_report);
|
||||
|
||||
void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig,
|
||||
uint8_t ri_restriction,
|
||||
nr_csi_report_t *csi_report);
|
||||
|
||||
void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report_t *csi_report_template);
|
||||
|
||||
uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report);
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#define SPEED_OF_LIGHT 299792458
|
||||
|
||||
#include "mac_defs.h"
|
||||
#include <NR_MAC_gNB/mac_proto.h>
|
||||
#include "NR_MAC_UE/mac_proto.h"
|
||||
#include "NR_MAC-CellGroupConfig.h"
|
||||
#include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
@@ -306,6 +305,13 @@ void configure_ntn_ta(module_id_t module_id, ntn_timing_advance_componets_t *ntn
|
||||
ntn_ta->ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3;
|
||||
}
|
||||
ntn_ta->ntn_params_changed = true;
|
||||
|
||||
LOG_D(NR_MAC,
|
||||
"SIB19 Rxd. k_offset:%ld, N_Common_Ta:%f,drift:%f,N_UE_TA:%f \n",
|
||||
ntn_ta->cell_specific_k_offset,
|
||||
ntn_ta->N_common_ta_adj,
|
||||
ntn_ta->ntn_ta_commondrift,
|
||||
ntn_ta->N_UE_TA_adj);
|
||||
}
|
||||
|
||||
static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP)
|
||||
|
||||
@@ -649,9 +649,9 @@ static inline double GET_COMPLETE_TIME_ADVANCE_MS(const ntn_timing_advance_compo
|
||||
return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj;
|
||||
}
|
||||
|
||||
static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta)
|
||||
static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta, int scs)
|
||||
{
|
||||
return NR_UE_CAPABILITY_SLOT_RX_TO_TX + ntn_ta->cell_specific_k_offset;
|
||||
return NR_UE_CAPABILITY_SLOT_RX_TO_TX + (ntn_ta->cell_specific_k_offset << scs);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
||||
@@ -415,6 +415,8 @@ void get_monitoring_period_offset(const NR_SearchSpace_t *ss, int *period, int *
|
||||
|
||||
bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per_frame, const NR_SearchSpace_t *ss)
|
||||
{
|
||||
if (!ss)
|
||||
return false;
|
||||
const int duration = ss->duration ? *ss->duration : 1;
|
||||
bool monitor = false;
|
||||
int period, offset;
|
||||
|
||||
@@ -927,10 +927,10 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac,
|
||||
const uint16_t feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset;
|
||||
|
||||
if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) {
|
||||
AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing),
|
||||
"PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld).\n",
|
||||
feedback_ti,
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta));
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing));
|
||||
// set the harq status at MAC for feedback
|
||||
const int tpc[] = {-1, 0, 1, 3};
|
||||
set_harq_status(mac,
|
||||
@@ -1220,11 +1220,11 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac,
|
||||
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing);
|
||||
const uint16_t feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset;
|
||||
|
||||
AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing),
|
||||
"PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld). Min feedback time set in config "
|
||||
"file (min_rxtxtime).\n",
|
||||
feedback_ti,
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta));
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing));
|
||||
|
||||
// set the harq status at MAC for feedback
|
||||
const int tpc[] = {-1, 0, 1, 3};
|
||||
|
||||
@@ -1037,9 +1037,11 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger
|
||||
return;
|
||||
}
|
||||
|
||||
AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
int scs = mac->current_UL_BWP->scs;
|
||||
AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(&mac->ntn_ta, scs),
|
||||
"Slot offset between DCI and aperiodic SRS (%d) needs to be higher than DURATION_RX_TO_TX (%ld)\n",
|
||||
slot_offset, GET_DURATION_RX_TO_TX(&mac->ntn_ta));
|
||||
slot_offset,
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, scs));
|
||||
int n_slots_frame = mac->frame_structure.numb_slots_frame;
|
||||
int sched_slot = (slot + slot_offset) % n_slots_frame;
|
||||
if (!is_ul_slot(sched_slot, &mac->frame_structure)) {
|
||||
@@ -1563,23 +1565,24 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
|
||||
AssertFatal(1 == 0, "Invalid numerology %i\n", mu);
|
||||
}
|
||||
|
||||
AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
"Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
|
||||
AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
|
||||
"Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to "
|
||||
"%ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
|
||||
k2,
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta));
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu));
|
||||
|
||||
*slot_tx = (current_slot + k2 + delta) % slots_per_frame;
|
||||
*frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER;
|
||||
} else {
|
||||
|
||||
AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
"Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
|
||||
AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
|
||||
"Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in "
|
||||
"gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n",
|
||||
k2,
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta));
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
|
||||
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu));
|
||||
|
||||
if (k2 < 0) { // This can happen when a false DCI is received
|
||||
LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2);
|
||||
@@ -2203,7 +2206,7 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t
|
||||
add_slots++;
|
||||
}
|
||||
nr_timer_setup(&ra->response_window_timer,
|
||||
ra->response_window_setup_time + add_slots + GET_DURATION_RX_TO_TX(&mac->ntn_ta),
|
||||
ra->response_window_setup_time + add_slots + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mac->current_DL_BWP->scs),
|
||||
1);
|
||||
nr_timer_start(&ra->response_window_timer);
|
||||
} else if (ra->ra_type == RA_2_STEP) {
|
||||
|
||||
@@ -1032,9 +1032,9 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
harq->round,
|
||||
nr_get_rv(harq->round % 4),
|
||||
harq->ndi,
|
||||
pucch->timing_indicator,
|
||||
pucch->frame,
|
||||
pucch->ul_slot,
|
||||
pucch ? pucch->timing_indicator : 0,
|
||||
pucch ? pucch->frame : 0,
|
||||
pucch ? pucch->ul_slot : 0,
|
||||
sched_pdsch->pucch_allocation,
|
||||
sched_ctrl->tpc1);
|
||||
|
||||
@@ -1222,7 +1222,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
dci_payload.ndi,
|
||||
dci_payload.rv,
|
||||
dci_payload.tpc,
|
||||
pucch->timing_indicator);
|
||||
pucch ? pucch->timing_indicator : 0);
|
||||
|
||||
const int rnti_type = TYPE_C_RNTI_;
|
||||
fill_dci_pdu_rel15(&UE->sc_info,
|
||||
|
||||
@@ -650,6 +650,11 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
// verify if report with current id has been scheduled for this frame and slot
|
||||
if ((n_slots_frame*frame + slot - offset)%period == 0) {
|
||||
reportQuantity_type = csi_report->reportQuantity_type;
|
||||
// phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP
|
||||
if (get_softmodem_params()->phy_test
|
||||
&& reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP
|
||||
&& reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP)
|
||||
continue;
|
||||
LOG_D(MAC,"SFN/SF:%d/%d reportQuantity type = %d\n",frame,slot,reportQuantity_type);
|
||||
switch(reportQuantity_type) {
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
|
||||
@@ -869,8 +874,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, frame_t frame, slot_t slot, c
|
||||
}
|
||||
free(uci_234->harq.harq_payload);
|
||||
}
|
||||
/* phy-test has hardcoded allocation, so no use to handle CSI reports */
|
||||
if ((uci_234->pduBitmap >> 2) & 0x01 && !get_softmodem_params()->phy_test) {
|
||||
if ((uci_234->pduBitmap >> 2) & 0x01) {
|
||||
LOG_D(NR_MAC, "CSI CRC %d\n", uci_234->csi_part1.csi_part1_crc);
|
||||
if (uci_234->csi_part1.csi_part1_crc != 1) {
|
||||
// API to parse the csi report and store it into sched_ctrl
|
||||
|
||||
@@ -337,8 +337,6 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP,
|
||||
unsigned char drx_cmd,
|
||||
unsigned char *ue_cont_res_id);
|
||||
|
||||
int binomial(int n, int k);
|
||||
|
||||
/* \brief Function to indicate a received SDU on ULSCH.
|
||||
@param Mod_id Instance ID of gNB
|
||||
@param CC_id Component carrier index
|
||||
|
||||
@@ -2460,17 +2460,6 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc,
|
||||
|
||||
asn1cSeqAdd(&sib1->si_SchedulingInfo->schedulingInfoList.list,schedulingInfo);*/
|
||||
|
||||
const NR_FreqBandIndicatorNR_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
|
||||
if (is_ntn_band(band)) {
|
||||
sib1->nonCriticalExtension = CALLOC(1, sizeof(struct NR_SIB1_v1610_IEs));
|
||||
sib1->nonCriticalExtension->nonCriticalExtension = CALLOC(1, sizeof(struct NR_SIB1_v1630_IEs));
|
||||
sib1->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension = CALLOC(1, sizeof(struct NR_SIB1_v1700_IEs));
|
||||
// If cell provides NTN access, set cellBarredNTN to notBarred.
|
||||
struct NR_SIB1_v1700_IEs *sib1_v1700 = sib1->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension;
|
||||
sib1_v1700->cellBarredNTN_r17 = CALLOC(1, sizeof(long));
|
||||
*sib1_v1700->cellBarredNTN_r17 = NR_SIB1_v1700_IEs__cellBarredNTN_r17_notBarred;
|
||||
}
|
||||
|
||||
// servingCellConfigCommon
|
||||
asn1cCalloc(sib1->servingCellConfigCommon, ServCellCom);
|
||||
NR_BWP_DownlinkCommon_t *initialDownlinkBWP = &ServCellCom->downlinkConfigCommon.initialDownlinkBWP;
|
||||
@@ -2485,6 +2474,7 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc,
|
||||
frequencyInfoDL->frequencyBandList.list.array[i];
|
||||
}
|
||||
|
||||
const NR_FreqBandIndicatorNR_t band = *frequencyInfoDL->frequencyBandList.list.array[0];
|
||||
frequency_range_t frequency_range = get_freq_range_from_band(band);
|
||||
sib1->servingCellConfigCommon->downlinkConfigCommon.frequencyInfoDL.offsetToPointA = get_ssb_offset_to_pointA(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB,
|
||||
scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
|
||||
@@ -2712,6 +2702,12 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc,
|
||||
asn1cSeqAdd(&si_schedulinginfo2_r17->sib_MappingInfo_r17.list, sib_type_info);
|
||||
asn1cSeqAdd(&sib_v17_scheduling_info->schedulingInfoList2_r17.list, si_schedulinginfo2_r17);
|
||||
sib1_1700->si_SchedulingInfo_v1700 = sib_v17_scheduling_info;
|
||||
|
||||
if (is_ntn_band(band)) {
|
||||
// If cell provides NTN access, set cellBarredNTN to notBarred.
|
||||
sib1_1700->cellBarredNTN_r17 = CALLOC(1, sizeof(long));
|
||||
*sib1_1700->cellBarredNTN_r17 = NR_SIB1_v1700_IEs__cellBarredNTN_r17_notBarred;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,3 +37,8 @@ add_boolean_option(OAI_USRP OFF "Activate OAI's USRP driver" OFF)
|
||||
if(OAI_USRP)
|
||||
add_subdirectory(USRP)
|
||||
endif()
|
||||
|
||||
add_boolean_option(VRTSIM_RADIO ON "Activate OAI's shared memory radio driver" OFF)
|
||||
if(VRTSIM_RADIO)
|
||||
add_subdirectory(vrtsim)
|
||||
endif()
|
||||
|
||||
@@ -30,18 +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})
|
||||
|
||||
# TODO: can be removed?
|
||||
target_include_directories(oran_fhlib_5g PRIVATE ${xran_INCLUDE_DIRS}/../src/)
|
||||
|
||||
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()
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
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
|
||||
connect-mplane.c
|
||||
rpc-send-recv.c
|
||||
get-mplane.c
|
||||
subscribe-mplane.c
|
||||
config-mplane.c
|
||||
ru-mplane-api.c
|
||||
xml/get-xml.c
|
||||
yang/get-yang.c
|
||||
yang/create-yang-config.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})
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 "config-mplane.h"
|
||||
#include "rpc-send-recv.h"
|
||||
#include "yang/get-yang.h"
|
||||
#include "yang/create-yang-config.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <nc_client.h>
|
||||
|
||||
bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
struct nc_rpc *rpc;
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
NC_DATASTORE target = NC_DATASTORE_CANDIDATE;
|
||||
NC_RPC_EDIT_DFLTOP op = NC_RPC_EDIT_DFLTOP_MERGE;
|
||||
NC_RPC_EDIT_TESTOPT test = NC_RPC_EDIT_TESTOPT_UNKNOWN;
|
||||
NC_RPC_EDIT_ERROPT err = NC_RPC_EDIT_ERROPT_UNKNOWN;
|
||||
|
||||
bool success = false;
|
||||
|
||||
struct ly_ctx *ctx = NULL;
|
||||
success = load_yang_models(ru_session, buffer, &ctx);
|
||||
AssertError(success, return false, "[MPLANE] Unable to continue.\n");
|
||||
|
||||
char *content = NULL;
|
||||
success = configure_ru_from_yang(&ctx, ru_session, oai, num_rus, &content);
|
||||
AssertError(success, return false, "[MPLANE] Unable to create content for <edit-config> RPC.\n");
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <edit-config>:\n%s\n", ru_session->ru_ip_add, content);
|
||||
rpc = nc_rpc_edit(target, op, test, err, content, param);
|
||||
AssertError(rpc != NULL, return false, "[MPLANE] <edit-config> RPC creation failed.\n");
|
||||
|
||||
success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
|
||||
AssertError(success, return false, "[MPLANE] Failed to edit configuration for the candidate datastore.\n");
|
||||
|
||||
MP_LOG_I("Successfully edited the candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
free(content);
|
||||
#ifdef MPLANE_V1
|
||||
ly_ctx_destroy(ctx, NULL);
|
||||
#elif defined MPLANE_V2
|
||||
ly_ctx_destroy(ctx);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_config_mplane(ru_session_t *ru_session)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
struct nc_rpc *rpc;
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
char *src_start = NULL;
|
||||
NC_DATASTORE source = NC_DATASTORE_CANDIDATE;
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <validate> candidate datastore.\n", ru_session->ru_ip_add);
|
||||
rpc = nc_rpc_validate(source, src_start, param);
|
||||
AssertError(rpc != NULL, return false, "[MPLANE] <validate> RPC creation failed.\n");
|
||||
|
||||
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
|
||||
AssertError(success, return false, "[MPLANE] Failed to validate candidate datastore.\n");
|
||||
|
||||
MP_LOG_I("Successfully validated candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool commit_config_mplane(ru_session_t *ru_session)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
struct nc_rpc *rpc;
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
int confirmed = 0;
|
||||
int32_t confirm_timeout = 0;
|
||||
char *persist = NULL, *persist_id = NULL;
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <commit> candidate datastore.\n", ru_session->ru_ip_add);
|
||||
rpc = nc_rpc_commit(confirmed, confirm_timeout, persist, persist_id, param);
|
||||
AssertError(rpc != NULL, return false, "[MPLANE] <commit> RPC creation failed.\n");
|
||||
|
||||
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
|
||||
AssertError(success, return false, "[MPLANE] Failed to commit candidate datastore.\n");
|
||||
|
||||
MP_LOG_I("Successfully commited CU-planes configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 CONFIGURE_MPLANE_H
|
||||
#define CONFIGURE_MPLANE_H
|
||||
|
||||
#include "ru-mplane-api.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
|
||||
bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus);
|
||||
|
||||
bool validate_config_mplane(ru_session_t *ru_session);
|
||||
|
||||
bool commit_config_mplane(ru_session_t *ru_session);
|
||||
|
||||
#endif /* CONFIGURE_MPLANE_H */
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 "connect-mplane.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <nc_client.h>
|
||||
|
||||
static int my_auth_hostkey_check(const char *hostname, ssh_session session, void *priv)
|
||||
{
|
||||
(void)hostname;
|
||||
(void)session;
|
||||
(void)priv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool connect_mplane(ru_session_t *ru_session)
|
||||
{
|
||||
int port = NC_PORT_SSH;
|
||||
char *user = "oranbenetel";
|
||||
|
||||
nc_client_ssh_set_username(user);
|
||||
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); // ssh-key identification
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
|
||||
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
|
||||
|
||||
nc_client_ssh_set_auth_hostkey_check_clb(my_auth_hostkey_check, "DATA"); // host-key identification
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <connect> with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port);
|
||||
ru_session->session = nc_connect_ssh(ru_session->ru_ip_add, port, NULL);
|
||||
AssertError(ru_session->session != NULL, return false, "[MPLANE] RU IP address %s unreachable. Maybe M-plane is disabled on the RU?\n", ru_session->ru_ip_add);
|
||||
|
||||
MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void disconnect_mplane(void *rus_disconnect)
|
||||
{
|
||||
ru_session_list_t *ru_session_list = (ru_session_list_t *)rus_disconnect;
|
||||
|
||||
for (size_t i = 0; i <ru_session_list->num_rus; i++) {
|
||||
ru_session_t *ru_session = &ru_session_list->ru_session[i];
|
||||
if (ru_session->session == NULL)
|
||||
continue;
|
||||
MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
nc_session_free(ru_session->session, NULL);
|
||||
ru_session->session = NULL;
|
||||
}
|
||||
|
||||
nc_client_destroy();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 CONNECT_MPLANE_H
|
||||
#define CONNECT_MPLANE_H
|
||||
|
||||
#include "ru-mplane-api.h"
|
||||
|
||||
bool connect_mplane(ru_session_t *ru_session);
|
||||
|
||||
void disconnect_mplane(void *rus_disconnect);
|
||||
|
||||
#endif /* CONNECT_MPLANE_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 "get-mplane.h"
|
||||
#include "rpc-send-recv.h"
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
bool get_mplane(ru_session_t *ru_session, char **answer)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
struct nc_rpc *rpc;
|
||||
char *filter = NULL; // e.g. "/o-ran-delay-management:delay-management";
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <get> operational datastore.\n", ru_session->ru_ip_add);
|
||||
rpc = nc_rpc_get(filter, wd, param);
|
||||
AssertError(rpc != NULL, return false, "[MPLANE] <get> RPC creation failed.\n");
|
||||
|
||||
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, answer);
|
||||
AssertError(success, return false, "[MPLANE] Unable to retrieve operational datastore.\n");
|
||||
|
||||
MP_LOG_I("Successfully retrieved operational datastore from RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 GET_MPLANE_H
|
||||
#define GET_MPLANE_H
|
||||
|
||||
#include "ru-mplane-api.h"
|
||||
|
||||
bool get_mplane(ru_session_t *ru_session, char **answer);
|
||||
|
||||
#endif /* GET_MPLANE_H */
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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 "get-mplane.h"
|
||||
#include "subscribe-mplane.h"
|
||||
#include "config-mplane.h"
|
||||
#include "xml/get-xml.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <nc_client.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
char *operational_ds = NULL;
|
||||
success = get_mplane(ru_session, &operational_ds);
|
||||
AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via get_mplane().\n");
|
||||
|
||||
bool ptp_state = false;
|
||||
const char *sync_state = get_ru_xml_node(operational_ds, "sync-state");
|
||||
if (strcmp(sync_state, "LOCKED") == 0) {
|
||||
MP_LOG_I("RU is already PTP synchronized.\n");
|
||||
ptp_state = true;
|
||||
}
|
||||
|
||||
/* 1) as per M-plane spec, RU must be in supervised mode,
|
||||
where stream = NULL && filter = "/o-ran-supervision:supervision-notification";
|
||||
2) additionally, we want to subscribe to PTP state change,
|
||||
where stream = NULL && filter = "/o-ran-sync:synchronization-state-change";
|
||||
=> since more than one subscription at the time within one session is not possible, we will subscribe to all notifications */
|
||||
const char *stream = "NETCONF";
|
||||
const char *filter = NULL;
|
||||
ru_session->ru_notif.ptp_state = ptp_state;
|
||||
success = subscribe_mplane(ru_session, stream, filter, (void *)&ru_session->ru_notif);
|
||||
AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via subscribe_mplane().\n");
|
||||
|
||||
// when subscribed to the supervision notification, the watchdog timer needs to be updated
|
||||
char *watchdog_answer = NULL;
|
||||
success = update_timer_mplane(ru_session, &watchdog_answer);
|
||||
AssertError(success, return false, "[MPLANE] Unable to update the watchdog timer. RU will do a reset after default supervision timer of (60+10)[s] expires.\n");
|
||||
MP_LOG_I("Watchdog timer answer: \n\t%s\n", watchdog_answer);
|
||||
|
||||
// save RU info for xran
|
||||
const int max_num_ant = max(oai->tx_num_channels/num_rus, oai->rx_num_channels/num_rus);
|
||||
success = get_config_for_xran(operational_ds, max_num_ant, &ru_session->xran_mplane);
|
||||
AssertError(success, return false, "[MPLANE] Unable to retrieve required info for xran from RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
// save the U-plane info
|
||||
success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config);
|
||||
AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n");
|
||||
|
||||
if (ru_session->ru_notif.ptp_state) {
|
||||
success = edit_config_mplane(ru_session, operational_ds, oai, num_rus);
|
||||
AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n");
|
||||
|
||||
success = validate_config_mplane(ru_session);
|
||||
AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n");
|
||||
|
||||
success = commit_config_mplane(ru_session);
|
||||
AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n");
|
||||
}
|
||||
|
||||
const char *usage_state = get_ru_xml_node(operational_ds, "usage-state");
|
||||
MP_LOG_I("Usage state = \"%s\" for RU \"%s\".\n", usage_state, ru_session->ru_ip_add);
|
||||
if (strcmp(usage_state, "busy") == 0) { // carriers are already activated
|
||||
ru_session->ru_notif.rx_carrier_state = true;
|
||||
ru_session->ru_notif.tx_carrier_state = true;
|
||||
ru_session->ru_notif.config_change = true;
|
||||
} else {
|
||||
ru_session->ru_notif.rx_carrier_state = false;
|
||||
ru_session->ru_notif.tx_carrier_state = false;
|
||||
ru_session->ru_notif.config_change = false;
|
||||
}
|
||||
|
||||
free(operational_ds);
|
||||
free(watchdog_answer);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus);
|
||||
|
||||
#endif /* OAI_MPLANE_H */
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* 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 "rpc-send-recv.h"
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
static bool recv_v1(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
|
||||
{
|
||||
struct nc_reply *reply;
|
||||
struct nc_reply_data *data_rpl;
|
||||
struct nc_reply_error *error;
|
||||
LYD_FORMAT output_format = LYD_XML;
|
||||
uint32_t ly_wd;
|
||||
|
||||
while (1) {
|
||||
msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, 0, &reply);
|
||||
if (msgtype == NC_MSG_ERROR) {
|
||||
AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n");
|
||||
} else if (msgtype == NC_MSG_WOULDBLOCK) {
|
||||
AssertError(false, return false, "[MPLANE] Timeout for receiving a reply expired.\n");
|
||||
} else if (msgtype == NC_MSG_NOTIF) {
|
||||
/* read again */
|
||||
continue;
|
||||
} else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
|
||||
/* unexpected message, try reading again to get the correct reply */
|
||||
MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n");
|
||||
nc_reply_free(reply);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (reply->type) {
|
||||
case NC_RPL_OK:
|
||||
MP_LOG_I("RPC reply = OK.\n");
|
||||
break;
|
||||
case NC_RPL_DATA:
|
||||
data_rpl = (struct nc_reply_data *)reply;
|
||||
|
||||
switch (wd_mode) {
|
||||
case NC_WD_ALL:
|
||||
ly_wd = LYP_WD_ALL;
|
||||
break;
|
||||
case NC_WD_ALL_TAG:
|
||||
ly_wd = LYP_WD_ALL_TAG;
|
||||
break;
|
||||
case NC_WD_TRIM:
|
||||
ly_wd = LYP_WD_TRIM;
|
||||
break;
|
||||
case NC_WD_EXPLICIT:
|
||||
ly_wd = LYP_WD_EXPLICIT;
|
||||
break;
|
||||
default:
|
||||
ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN
|
||||
break;
|
||||
}
|
||||
|
||||
if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) {
|
||||
AssertError((!data_rpl->data || (data_rpl->data->schema->nodetype != LYS_RPC) || (data_rpl->data->child == NULL)
|
||||
|| (data_rpl->data->child->schema->nodetype != LYS_ANYXML)), return false, "[MPLANE] Cannot get schema.\n");
|
||||
|
||||
struct lyd_node_anydata *any = (struct lyd_node_anydata *)data_rpl->data->child;
|
||||
switch (any->value_type) {
|
||||
case LYD_ANYDATA_CONSTSTRING:
|
||||
case LYD_ANYDATA_STRING:
|
||||
*answer = strdup(any->value.str);
|
||||
break;
|
||||
case LYD_ANYDATA_DATATREE:
|
||||
lyd_print_mem(answer, any->value.tree, output_format, LYP_WITHSIBLINGS);
|
||||
break;
|
||||
case LYD_ANYDATA_XML:
|
||||
lyxml_print_mem(answer, any->value.xml, LYXML_PRINT_SIBLINGS);
|
||||
break;
|
||||
default:
|
||||
AssertError(false, return false, "[MPLANE] Unknown yang type.\n");
|
||||
}
|
||||
break;
|
||||
} else if (nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG || nc_rpc_get_type(rpc) == NC_RPC_GET) {
|
||||
const char *tag = nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG ? "config" : "data";
|
||||
char *buffer = NULL;
|
||||
lyd_print_mem(&buffer, data_rpl->data, output_format, LYP_WITHSIBLINGS | LYP_NETCONF | ly_wd);
|
||||
*answer = calloc(strlen(buffer)+128, sizeof(char));
|
||||
sprintf(*answer, "<%s xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n%s</%s>", tag, buffer, tag);
|
||||
} else {
|
||||
AssertError(false, return false, "[MPLANE] Unknown RPC type.\n");
|
||||
}
|
||||
|
||||
break;
|
||||
case NC_RPL_ERROR:
|
||||
error = (struct nc_reply_error *)reply;
|
||||
for (int i = 0; i < error->count; ++i) {
|
||||
const struct nc_err *err = &error->err[i];
|
||||
MP_LOG_I("RPC reply = ERROR\n\
|
||||
\ttype: %s\n\
|
||||
\ttag: %s\n\
|
||||
\tseverity: %s\n\
|
||||
\tapp-tag: %s\n\
|
||||
\tpath: %s\n\
|
||||
\tmessage: %s\n\
|
||||
\tSID: %s\n",
|
||||
err->type,
|
||||
err->tag,
|
||||
err->severity,
|
||||
err->apptag,
|
||||
err->path,
|
||||
err->message,
|
||||
err->sid);
|
||||
|
||||
for (int j = 0; j < err->attr_count; ++j) {
|
||||
MP_LOG_I("\tbad-attr #%d: %s\n", j + 1, err->attr[j]);
|
||||
}
|
||||
for (int j = 0; j < err->elem_count; ++j) {
|
||||
MP_LOG_I("\tbad-elem #%d: %s\n", j + 1, err->elem[j]);
|
||||
}
|
||||
for (int j = 0; j < err->ns_count; ++j) {
|
||||
MP_LOG_I("\tbad-ns #%d: %s\n", j + 1, err->ns[j]);
|
||||
}
|
||||
for (int j = 0; j < err->other_count; ++j) {
|
||||
char *str = NULL;
|
||||
lyxml_print_mem(&str, err->other[j], 0);
|
||||
MP_LOG_I("\tother #%d:\n%s\n", j + 1, str);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
AssertError(false, return false, "[MPLANE] Unable to continue.\n");
|
||||
break;
|
||||
default:
|
||||
AssertError(false, return false, "[MPLANE] Internal error.\n");
|
||||
nc_reply_free(reply);
|
||||
}
|
||||
nc_reply_free(reply);
|
||||
|
||||
return true;
|
||||
}
|
||||
#elif defined MPLANE_V2
|
||||
static bool recv_v2(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
|
||||
{
|
||||
struct lyd_node *envp, *op, *err;
|
||||
LYD_FORMAT output_format = LYD_XML;
|
||||
uint32_t ly_wd;
|
||||
|
||||
while (1) {
|
||||
msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, &envp, &op);
|
||||
if (msgtype == NC_MSG_ERROR) {
|
||||
AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n");
|
||||
} else if (msgtype == NC_MSG_WOULDBLOCK) {
|
||||
AssertError(false, return false, "[MPLANE] Timeout for receiving a reply for RPC expired.\n");
|
||||
} else if (msgtype == NC_MSG_NOTIF) { // for SUBSCRIBE
|
||||
/* read again */
|
||||
continue;
|
||||
} else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
|
||||
/* unexpected message, try reading again to get the correct reply */
|
||||
MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n");
|
||||
lyd_free_tree(envp);
|
||||
lyd_free_tree(op);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* get functionality */
|
||||
if (op) {
|
||||
/* data reply */
|
||||
if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) {
|
||||
/* special case */
|
||||
if (!lyd_child(op) || (lyd_child(op)->schema->nodetype != LYS_ANYXML)) {
|
||||
AssertError(false, return false, "[MPLANE] Cannot get schema.");
|
||||
}
|
||||
struct lyd_node_any *any = (struct lyd_node_any *)lyd_child(op);
|
||||
switch (any->value_type) {
|
||||
case LYD_ANYDATA_STRING:
|
||||
case LYD_ANYDATA_XML:
|
||||
*answer = strdup(any->value.str);
|
||||
break;
|
||||
case LYD_ANYDATA_DATATREE:
|
||||
lyd_print_mem(answer, any->value.tree, output_format, LYD_PRINT_WITHSIBLINGS);
|
||||
break;
|
||||
default:
|
||||
AssertError(false, return false, "[MPLANE] Unexpected yang type.");
|
||||
}
|
||||
} else {
|
||||
switch (wd_mode) {
|
||||
case NC_WD_ALL:
|
||||
ly_wd = LYD_PRINT_WD_ALL;
|
||||
break;
|
||||
case NC_WD_ALL_TAG:
|
||||
ly_wd = LYD_PRINT_WD_ALL_TAG;
|
||||
break;
|
||||
case NC_WD_TRIM:
|
||||
ly_wd = LYD_PRINT_WD_TRIM;
|
||||
break;
|
||||
case NC_WD_EXPLICIT:
|
||||
ly_wd = LYD_PRINT_WD_EXPLICIT;
|
||||
break;
|
||||
default:
|
||||
ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN
|
||||
break;
|
||||
}
|
||||
lyd_print_mem(answer, lyd_child(op), output_format, LYD_PRINT_WITHSIBLINGS | ly_wd);
|
||||
}
|
||||
/* edit/validate/commit functionalities */
|
||||
} else if (!strcmp(LYD_NAME(lyd_child(envp)), "ok")) {
|
||||
MP_LOG_I("RPC reply = OK.\n");
|
||||
} else {
|
||||
LY_LIST_FOR(lyd_child(envp), err) {
|
||||
struct lyd_node *type, *tag, *severity, *app_tag, *path, *er_msg, *info = NULL;
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &type);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &tag);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-severity", &severity);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &app_tag);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &path);
|
||||
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &er_msg);
|
||||
|
||||
MP_LOG_I("RPC reply = ERROR\n\
|
||||
\ttype: %s\n\
|
||||
\ttag: %s\n\
|
||||
\tseverity: %s\n\
|
||||
\tapp-tag: %s\n\
|
||||
\tpath: %s\n\
|
||||
\tmessage: %s\n",
|
||||
(type ? ((struct lyd_node_opaq *)type)->value : NULL),
|
||||
(tag ? ((struct lyd_node_opaq *)tag)->value : NULL),
|
||||
(severity ? ((struct lyd_node_opaq *)severity)->value : NULL),
|
||||
(app_tag ? ((struct lyd_node_opaq *)app_tag)->value : NULL),
|
||||
(path ? ((struct lyd_node_opaq *)path)->value : NULL),
|
||||
(er_msg ? ((struct lyd_node_opaq *)er_msg)->value : NULL));
|
||||
|
||||
info = lyd_child(err);
|
||||
while (!lyd_find_sibling_opaq_next(info, "error-info", &info)) {
|
||||
char *str = NULL;
|
||||
lyd_print_mem(&str, lyd_child(info), output_format, LYD_PRINT_WITHSIBLINGS);
|
||||
MP_LOG_I("\tinfo: %s\n", str);
|
||||
info = info->next;
|
||||
free(str);
|
||||
}
|
||||
lyd_free_tree(type);
|
||||
lyd_free_tree(tag);
|
||||
lyd_free_tree(severity);
|
||||
lyd_free_tree(app_tag);
|
||||
lyd_free_tree(path);
|
||||
lyd_free_tree(er_msg);
|
||||
lyd_free_tree(info);
|
||||
}
|
||||
lyd_free_tree(envp);
|
||||
lyd_free_tree(op);
|
||||
AssertError(false, return false, "[MPLANE] Unable to continue.\n");
|
||||
}
|
||||
|
||||
lyd_free_tree(envp);
|
||||
lyd_free_tree(op);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
|
||||
{
|
||||
uint64_t msgid;
|
||||
NC_MSG_TYPE msgtype;
|
||||
|
||||
msgtype = nc_send_rpc(session, rpc, 1000, &msgid);
|
||||
if (msgtype == NC_MSG_ERROR) {
|
||||
AssertError(false, return false, "[MPLANE] Failed to send the RPC.\n");
|
||||
} else if (msgtype == NC_MSG_WOULDBLOCK) {
|
||||
AssertError(false, return false, "[MPLANE] Timeout for sending the RPC expired.\n");
|
||||
}
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
return recv_v1(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer);
|
||||
#elif defined MPLANE_V2
|
||||
return recv_v2(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer);
|
||||
#else
|
||||
AssertError(false, return false, "[MPLANE] Unknown M-plane version found. Tried \"MPLANE_V1\" and \"MPLANE_V2\".\n");
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 RPC_SEND_RECEIVE_MPLANE_H
|
||||
#define RPC_SEND_RECEIVE_MPLANE_H
|
||||
|
||||
#include "ru-mplane-api.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <nc_client.h>
|
||||
|
||||
#define CLI_RPC_REPLY_TIMEOUT 60000 // time [ms] to wait for server reply
|
||||
|
||||
bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer);
|
||||
|
||||
#endif /* RPC_SEND_RECEIVE_MPLANE_H */
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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 "ru-mplane-api.h"
|
||||
#include "xml/get-xml.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void free_match_list(char **match_list, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
free(match_list[i]);
|
||||
}
|
||||
free(match_list);
|
||||
}
|
||||
|
||||
static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant)
|
||||
{
|
||||
if (interface_mtu == 1500) {
|
||||
MP_LOG_I("Interface MTU %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.\n", interface_mtu);
|
||||
xran_mplane->mtu = 9600;
|
||||
} else {
|
||||
xran_mplane->mtu = interface_mtu;
|
||||
}
|
||||
|
||||
if (first_iq_width != 9) {
|
||||
MP_LOG_I("IQ bitwidth %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9.\n", first_iq_width);
|
||||
xran_mplane->iq_width = 9;
|
||||
} else {
|
||||
xran_mplane->iq_width = first_iq_width;
|
||||
}
|
||||
|
||||
xran_mplane->prach_offset = max_num_ant;
|
||||
}
|
||||
|
||||
bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane)
|
||||
{
|
||||
/* some O-RU vendors are not fully compliant as per M-plane specifications */
|
||||
const char *ru_vendor = get_ru_xml_node(buffer, "mfg-name");
|
||||
|
||||
// RU MAC
|
||||
xran_mplane->ru_mac_addr = get_ru_xml_node(buffer, "mac-address"); // TODO: support for VVDN, as it defines multiple MAC addresses
|
||||
|
||||
// MTU
|
||||
const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "interface-mtu"));
|
||||
|
||||
// IQ bitwidth
|
||||
char **match_list = NULL;
|
||||
size_t count = 0;
|
||||
get_ru_xml_list(buffer, "iq-bitwidth", &match_list, &count);
|
||||
const int16_t first_iq_width = (int16_t)atoi((char *)match_list[0]);
|
||||
free_match_list(match_list, count);
|
||||
|
||||
// PRACH offset
|
||||
// xran_mplane->prach_offset
|
||||
|
||||
// DU port ID bitmask
|
||||
xran_mplane->du_port_bitmask = 0xf000;
|
||||
// Band sector bitmask
|
||||
xran_mplane->band_sector_bitmask = 0x0f00;
|
||||
// CC ID bitmask
|
||||
xran_mplane->ccid_bitmask = 0x00f0;
|
||||
// RU port ID bitmask
|
||||
xran_mplane->ru_port_bitmask = 0x000f;
|
||||
|
||||
// DU port ID
|
||||
xran_mplane->du_port = 0;
|
||||
// Band sector
|
||||
xran_mplane->band_sector = 0;
|
||||
// CC ID
|
||||
xran_mplane->ccid = 0;
|
||||
// RU port ID
|
||||
xran_mplane->ru_port = 0;
|
||||
|
||||
if (strcasecmp(ru_vendor, "BENETEL") == 0 /* || strcmp(ru_vendor, "VVDN-LPRU") == 0 || strcmp(ru_vendor, "Metanoia") == 0 */) {
|
||||
fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant);
|
||||
} else {
|
||||
AssertError(false, return false, "[MPLANE] %s RU currently not supported.\n", ru_vendor);
|
||||
}
|
||||
|
||||
MP_LOG_I("Storing the following information to forward to xran:\n\
|
||||
RU MAC address %s\n\
|
||||
MTU %d\n\
|
||||
IQ bitwidth %d\n\
|
||||
PRACH offset %d\n\
|
||||
DU port bitmask %d\n\
|
||||
Band sector bitmask %d\n\
|
||||
CC ID bitmask %d\n\
|
||||
RU port ID bitmask %d\n\
|
||||
DU port ID %d\n\
|
||||
Band sector ID %d\n\
|
||||
CC ID %d\n\
|
||||
RU port ID %d\n",
|
||||
xran_mplane->ru_mac_addr,
|
||||
xran_mplane->mtu,
|
||||
xran_mplane->iq_width,
|
||||
xran_mplane->prach_offset,
|
||||
xran_mplane->du_port_bitmask,
|
||||
xran_mplane->band_sector_bitmask,
|
||||
xran_mplane->ccid_bitmask,
|
||||
xran_mplane->ru_port_bitmask,
|
||||
xran_mplane->du_port,
|
||||
xran_mplane->band_sector,
|
||||
xran_mplane->ccid,
|
||||
xran_mplane->ru_port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config)
|
||||
{
|
||||
// Interface name
|
||||
ru_mplane_config->interface_name = get_ru_xml_node(buffer, "interface");
|
||||
|
||||
// PDSCH
|
||||
uplane_info_t *tx_end = &ru_mplane_config->tx_endpoints;
|
||||
get_ru_xml_list(buffer, "static-low-level-tx-endpoints", &tx_end->name, &tx_end->num);
|
||||
AssertError(tx_end->name != NULL, return false, "[MPLANE] Cannot get TX endpoint names.\n");
|
||||
|
||||
// TX carriers
|
||||
uplane_info_t *tx_carriers = &ru_mplane_config->tx_carriers;
|
||||
get_ru_xml_list(buffer, "tx-arrays", &tx_carriers->name, &tx_carriers->num);
|
||||
AssertError(tx_carriers->name != NULL, return false, "[MPLANE] Cannot get TX carrier names.\n");
|
||||
|
||||
// PUSCH and PRACH
|
||||
uplane_info_t *rx_end = &ru_mplane_config->rx_endpoints;
|
||||
get_ru_xml_list(buffer, "static-low-level-rx-endpoints", &rx_end->name, &rx_end->num);
|
||||
AssertError(rx_end->name != NULL, return false, "[MPLANE] Cannot get RX endpoint names.\n");
|
||||
|
||||
// RX carriers
|
||||
uplane_info_t *rx_carriers = &ru_mplane_config->rx_carriers;
|
||||
get_ru_xml_list(buffer, "rx-arrays", &rx_carriers->name, &rx_carriers->num);
|
||||
AssertError(rx_carriers->name != NULL, return false, "[MPLANE] Cannot get RX carrier names.\n");
|
||||
|
||||
MP_LOG_I("Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
bool config_change;
|
||||
// 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;
|
||||
|
||||
bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane);
|
||||
|
||||
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config);
|
||||
|
||||
#endif /* RU_MPLANE_API_H */
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 "subscribe-mplane.h"
|
||||
#include "rpc-send-recv.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
#include <nc_client.h>
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
static void recv_notif_v1(const struct nc_notif *notif, ru_notif_t *answer)
|
||||
{
|
||||
const char *node_name = notif->tree->child->attr->name;
|
||||
const char *value = notif->tree->child->attr->value_str;
|
||||
if (strcmp(node_name, "sync-state")) {
|
||||
if (strcmp(value, "LOCKED") == 0) {
|
||||
answer->ptp_state = true;
|
||||
} else {
|
||||
answer->ptp_state = false;
|
||||
}
|
||||
}
|
||||
|
||||
// carriers state - to be filled
|
||||
}
|
||||
|
||||
static void notif_clb_v1(struct nc_session *session, const struct nc_notif *notif)
|
||||
{
|
||||
ru_notif_t *answer = nc_session_get_data(session);
|
||||
LYD_FORMAT output_format = LYD_JSON;
|
||||
|
||||
char *subs_reply = NULL;
|
||||
lyd_print_mem(&subs_reply, notif->tree, output_format, LYP_WITHSIBLINGS);
|
||||
MP_LOG_I("\nReceived notification at (%s)\n%s\n", notif->datetime, subs_reply);
|
||||
|
||||
recv_notif_v1(notif, answer);
|
||||
}
|
||||
#elif MPLANE_V2
|
||||
static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer)
|
||||
{
|
||||
const char *notif = op->schema->name;
|
||||
|
||||
if (strcmp(notif, "synchronization-state-change") == 0) {
|
||||
const char *value = lyd_get_value(op->child);
|
||||
if (strcmp(value, "LOCKED") == 0) {
|
||||
answer->ptp_state = true;
|
||||
} else { // "FREERUN" or "HOLDOVER"
|
||||
answer->ptp_state = false;
|
||||
}
|
||||
} else if (strcmp(notif, "rx-array-carriers-state-change") == 0) {
|
||||
const char *value = lyd_get_value(lyd_child(op->child)->next);
|
||||
if (strcmp(value, "READY") == 0) {
|
||||
answer->rx_carrier_state = true;
|
||||
} else { // "DISABLED" or "BUSY"
|
||||
answer->rx_carrier_state = false;
|
||||
}
|
||||
} else if (strcmp(notif, "tx-array-carriers-state-change") == 0) {
|
||||
const char *value = lyd_get_value(lyd_child(op->child)->next);
|
||||
if (strcmp(value, "READY") == 0) {
|
||||
answer->tx_carrier_state = true;
|
||||
} else { // "DISABLED" or "BUSY"
|
||||
answer->tx_carrier_state = false;
|
||||
}
|
||||
} else if (strcmp(notif, "netconf-config-change") == 0) {
|
||||
answer->config_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op, void *user_data)
|
||||
{
|
||||
ru_notif_t *answer = (ru_notif_t *)user_data;
|
||||
LYD_FORMAT output_format = LYD_JSON;
|
||||
|
||||
char *subs_reply = NULL;
|
||||
lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS);
|
||||
const char *ru_ip_add = nc_session_get_host(session);
|
||||
MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply);
|
||||
|
||||
recv_notif_v2((struct lyd_node_inner *)op, answer);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
struct nc_rpc *rpc;
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
char *start_time = NULL, *stop_time = NULL;
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <subscribe> with stream \"%s\" and filter \"%s\".\n", ru_session->ru_ip_add, stream, filter);
|
||||
rpc = nc_rpc_subscribe(stream, NULL, start_time, stop_time, param);
|
||||
AssertError(rpc != NULL, return false, "[MPLANE] <subscribe> RPC creation failed.\n");
|
||||
|
||||
/* create notification thread so that notifications can immediately be received */
|
||||
#ifdef MPLANE_V1
|
||||
if (!nc_session_ntf_thread_running(ru_session->session)) {
|
||||
nc_session_set_data(ru_session->session, answer);
|
||||
int ret = nc_recv_notif_dispatch(ru_session->session, notif_clb_v1);
|
||||
AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n");
|
||||
} else {
|
||||
MP_LOG_I("Notification thread is already running for RU %s.\n", ru_session->ru_ip_add);
|
||||
}
|
||||
#elif MPLANE_V2
|
||||
int ret = nc_recv_notif_dispatch_data(ru_session->session, notif_clb_v2, answer, NULL);
|
||||
AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n");
|
||||
#endif
|
||||
|
||||
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
|
||||
AssertError(success, return false, "[MPLANE] Failed to subscribe to: stream \"%s\", filter \"%s\".\n", stream, filter);
|
||||
|
||||
MP_LOG_I("Successfully subscribed to all notifications from RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_timer_mplane(ru_session_t *ru_session, char **answer)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
struct nc_rpc *rpc;
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
const char *content = "<supervision-watchdog-reset xmlns=\"urn:o-ran:supervision:1.0\">\n\
|
||||
<supervision-notification-interval>65535</supervision-notification-interval>\n\
|
||||
<guard-timer-overhead>65535</guard-timer-overhead>\n\
|
||||
</supervision-watchdog-reset>";
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = \"%s\".\n", ru_session->ru_ip_add, content);
|
||||
rpc = nc_rpc_act_generic_xml(content, param);
|
||||
AssertError(rpc != NULL, return false, "[MPLANE] <supervision-watchdog-reset> RPC creation failed.\n");
|
||||
|
||||
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, answer);
|
||||
AssertError(success, return false, "[MPLANE] Failed to update the watchdog timer.\n");
|
||||
|
||||
MP_LOG_I("Successfully updated supervision timer to (65535+65535)[s] for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
nc_rpc_free(rpc);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -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 SUBSCRIBE_MPLANE_H
|
||||
#define SUBSCRIBE_MPLANE_H
|
||||
|
||||
#include "ru-mplane-api.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer);
|
||||
|
||||
bool update_timer_mplane(ru_session_t *ru_session, char **answer);
|
||||
|
||||
#endif /* SUBSCRIBE_MPLANE_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
|
||||
*/
|
||||
|
||||
#include "get-xml.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <string.h>
|
||||
|
||||
static char *find_ru_xml_node(xmlNode *node, const char *filter)
|
||||
{
|
||||
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
|
||||
if (cur_node->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
|
||||
if (strcmp((const char *)cur_node->name, filter) == 0) {
|
||||
xmlNode *target_node = cur_node;
|
||||
|
||||
for(xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
|
||||
if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) {
|
||||
target_node = cur_node2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (char *)xmlNodeGetContent(target_node);
|
||||
}
|
||||
char *answer = find_ru_xml_node(cur_node->children, filter);
|
||||
if (answer != NULL) {
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_ru_xml_node(const char *buffer, const char *filter)
|
||||
{
|
||||
// Initialize the xml file
|
||||
size_t len = strlen(buffer) + 1;
|
||||
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
|
||||
xmlNode *root_element = xmlDocGetRootElement(doc);
|
||||
|
||||
return find_ru_xml_node(root_element->children, filter);
|
||||
}
|
||||
|
||||
static void find_ru_xml_list(xmlNode *node, const char *filter, char ***match_list, size_t *count)
|
||||
{
|
||||
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
|
||||
if (cur_node->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
if (strcmp((const char *)cur_node->name, filter) == 0) {
|
||||
xmlNode *name_node = NULL;
|
||||
|
||||
for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
|
||||
if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) {
|
||||
name_node = cur_node2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const char *content = (const char *)xmlNodeGetContent(name_node ? name_node : cur_node);
|
||||
if (content) {
|
||||
*match_list = realloc(*match_list, (*count + 1) * sizeof(char *));
|
||||
(*match_list)[*count] = strdup(content);
|
||||
(*count)++;
|
||||
}
|
||||
}
|
||||
find_ru_xml_list(cur_node->children, filter, match_list, count);
|
||||
}
|
||||
}
|
||||
|
||||
void get_ru_xml_list(const char *buffer, const char *filter, char ***match_list, size_t *count)
|
||||
{
|
||||
// Initialize the xml file
|
||||
size_t len = strlen(buffer) + 1;
|
||||
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
|
||||
xmlNode *root_element = xmlDocGetRootElement(doc);
|
||||
|
||||
find_ru_xml_list(root_element->children, filter, match_list, count);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 GET_MPLANE_INFO_XML_H
|
||||
#define GET_MPLANE_INFO_XML_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief retrieves the node value that matches filter.
|
||||
*
|
||||
* @param[in] buffer Buffer in xml format.
|
||||
* @param[in] filter The node name (matching criteria).
|
||||
* @return Expected one string that matches the node name.
|
||||
*/
|
||||
char *get_ru_xml_node(const char *buffer, const char *filter);
|
||||
|
||||
/**
|
||||
* @brief retrieves the node values that matches filter.
|
||||
*
|
||||
* @param[in] buffer Buffer in xml format.
|
||||
* @param[in] filter The node name (matching criteria).
|
||||
* @param[out] match_list Resulting list containing node values.
|
||||
* @param[out] count The number of nodes that match criteria.
|
||||
* @return Void.
|
||||
*/
|
||||
void get_ru_xml_list(const char *buffer, const char *filter, char ***match_list, size_t *count);
|
||||
|
||||
#endif /* GET_MPLANE_INFO_XML_H */
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* 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 "create-yang-config.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
|
||||
#define VERIFY_SUCCESS(var, message, args...) AssertError(var, return false, message, ##args)
|
||||
|
||||
#ifdef MPLANE_V2
|
||||
static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
|
||||
{
|
||||
LY_ERR ret = LY_SUCCESS;
|
||||
|
||||
ret = lyd_new_path(NULL, *ctx, "/ietf-interfaces:interfaces", NULL, 0, root);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"interfaces\" node.\n");
|
||||
|
||||
struct lyd_node *interface_node = NULL;
|
||||
ret = lyd_new_list(*root, NULL, "interface", 0, &interface_node, int_name);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"interface\" node.\n");
|
||||
|
||||
struct lyd_node *type_node = NULL;
|
||||
ret = lyd_new_term(interface_node, NULL, "type", "iana-if-type:l2vlan", 0, &type_node);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"type\" node.\n");
|
||||
|
||||
ret = lyd_new_term(interface_node, NULL, "enabled", "true", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"enabled\" node.\n");
|
||||
|
||||
const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented(*ctx, "o-ran-interfaces");
|
||||
VERIFY_SUCCESS(oran_int_mod != NULL, "[MPLANE] Failed to get \"o-ran-interfaces\" module.\n");
|
||||
|
||||
struct lyd_node *base_int = NULL;
|
||||
ret = lyd_new_term(interface_node, oran_int_mod, "base-interface", ru_session->ru_mplane_config.interface_name, 0, &base_int);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"base-interface\" node with name \"%s\".\n", ru_session->ru_mplane_config.interface_name);
|
||||
|
||||
struct lyd_node *vlan_id = NULL;
|
||||
char vlan_tag_str[8];
|
||||
snprintf(vlan_tag_str, sizeof(vlan_tag_str), "%d", ru_session->ru_mplane_config.vlan_tag[idx]);
|
||||
ret = lyd_new_term(interface_node, oran_int_mod, "vlan-id", vlan_tag_str, 0, &vlan_id);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"vlan-id\" node with \"%d\".\n", ru_session->ru_mplane_config.vlan_tag[idx]);
|
||||
|
||||
struct lyd_node *ru_mac_addr = NULL;
|
||||
ret = lyd_new_term(interface_node, oran_int_mod, "mac-address", ru_session->xran_mplane.ru_mac_addr, 0, &ru_mac_addr);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"mac-address\" node with \"%s\".\n", ru_session->xran_mplane.ru_mac_addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
|
||||
{
|
||||
LY_ERR ret = LY_SUCCESS;
|
||||
|
||||
ret = lyd_new_path(NULL, *ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"processing-elements\" node.\n");
|
||||
|
||||
ret = lyd_new_term(*root, NULL, "transport-session-type", "ETH-INTERFACE", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"transport-session-type\" node.\n");
|
||||
|
||||
struct lyd_node *ru_elem_node = NULL;
|
||||
char plane_name[8];
|
||||
snprintf(plane_name, sizeof(plane_name), "PLANE_%ld", idx);
|
||||
ret = lyd_new_list(*root, NULL, "ru-elements", 0, &ru_elem_node, plane_name);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-elements\" node.\n");
|
||||
|
||||
struct lyd_node *transp_flow = NULL;
|
||||
ret = lyd_new_inner(ru_elem_node, NULL, "transport-flow", 0, &transp_flow);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"transport-flow\" node.\n");
|
||||
|
||||
ret = lyd_new_term(transp_flow, NULL, "interface-name", int_name, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"interface-name\" node.\n");
|
||||
|
||||
struct lyd_node *eth_flow = NULL;
|
||||
ret = lyd_new_inner(transp_flow, NULL, "eth-flow", 0, ð_flow);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eth-flow\" node.\n");
|
||||
|
||||
char vlan_tag_str[8];
|
||||
snprintf(vlan_tag_str, sizeof(vlan_tag_str), "%d", ru_session->ru_mplane_config.vlan_tag[idx]);
|
||||
ret = lyd_new_term(eth_flow, NULL, "vlan-id", vlan_tag_str, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"vlan-id\" node.\n");
|
||||
|
||||
ret = lyd_new_term(eth_flow, NULL, "ru-mac-address", ru_session->xran_mplane.ru_mac_addr, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-mac-address\" node.\n");
|
||||
|
||||
ret = lyd_new_term(eth_flow, NULL, "o-du-mac-address", ru_session->ru_mplane_config.du_mac_addr[idx], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-mac-address\" node.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx, struct lyd_node **root)
|
||||
{
|
||||
LY_ERR ret = LY_SUCCESS;
|
||||
|
||||
ret = lyd_new_term(*root, NULL, "cp-length", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length\" node.\n");
|
||||
|
||||
ret = lyd_new_term(*root, NULL, "cp-length-other", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length-other\" node.\n");
|
||||
|
||||
// to we actually store this from DU config file?
|
||||
ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"offset-to-absolute-frequency-center\" node.\n");
|
||||
|
||||
struct lyd_node *compression_node = NULL;
|
||||
ret = lyd_new_inner(*root, NULL, "compression", 0, &compression_node);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression\" node.\n");
|
||||
|
||||
char iq_width_str[8];
|
||||
snprintf(iq_width_str, sizeof(iq_width_str), "%d", xran_mplane->iq_width);
|
||||
ret = lyd_new_term(compression_node, NULL, "iq-bitwidth", iq_width_str, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"iq-bitwidth\" node.\n");
|
||||
|
||||
if (xran_mplane->iq_width < 16) {
|
||||
ret = lyd_new_term(compression_node, NULL, "compression-type", "STATIC", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-type\" node.\n");
|
||||
|
||||
// ret = lyd_new_term(compression_node, NULL, "compression-method", "BLOCK_FLOATING_POINT", 0, NULL);
|
||||
// VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-method\" node.\n");
|
||||
}
|
||||
|
||||
struct lyd_node *eaxc_conf = NULL;
|
||||
ret = lyd_new_inner(*root, NULL, "e-axcid", 0, &eaxc_conf);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"e-axcid\" node.\n");
|
||||
|
||||
char eaxc_id[8];
|
||||
snprintf(eaxc_id, sizeof(eaxc_id), "%ld", idx);
|
||||
ret = lyd_new_term(eaxc_conf, NULL, "eaxc-id", eaxc_id, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eaxc-id\" node.\n");
|
||||
|
||||
char du_port_bitmask[16];
|
||||
snprintf(du_port_bitmask, sizeof(du_port_bitmask), "%d", xran_mplane->du_port_bitmask);
|
||||
ret = lyd_new_term(eaxc_conf, NULL, "o-du-port-bitmask", du_port_bitmask, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-port-bitmask\" node.\n");
|
||||
|
||||
char band_sector_bitmask[8];
|
||||
snprintf(band_sector_bitmask, sizeof(band_sector_bitmask), "%d", xran_mplane->band_sector_bitmask);
|
||||
ret = lyd_new_term(eaxc_conf, NULL, "band-sector-bitmask", band_sector_bitmask, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"band-sector-bitmask\" node.\n");
|
||||
|
||||
char ccid_bitmask[8];
|
||||
snprintf(ccid_bitmask, sizeof(ccid_bitmask), "%d", xran_mplane->ccid_bitmask);
|
||||
ret = lyd_new_term(eaxc_conf, NULL, "ccid-bitmask", ccid_bitmask, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ccid-bitmask\" node.\n");
|
||||
|
||||
char ru_port_bitmask[8];
|
||||
snprintf(ru_port_bitmask, sizeof(ru_port_bitmask), "%d", xran_mplane->ru_port_bitmask);
|
||||
ret = lyd_new_term(eaxc_conf, NULL, "ru-port-bitmask", ru_port_bitmask, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-port-bitmask\" node.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root)
|
||||
{
|
||||
LY_ERR ret = LY_SUCCESS;
|
||||
bool success = true;
|
||||
|
||||
ret = lyd_new_path(NULL, *ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"user-plane-configuration\" node.\n");
|
||||
|
||||
if (ru_session->ru_mplane_config.rx_carriers.num != 1 || ru_session->ru_mplane_config.tx_carriers.num !=1)
|
||||
MP_LOG_I("Only one carrier supported at the moment.\n");
|
||||
|
||||
// RX carriers
|
||||
struct lyd_node *rx_carrier_node = NULL;
|
||||
ret = lyd_new_list(*root, NULL, "rx-array-carriers", 0, &rx_carrier_node, ru_session->ru_mplane_config.rx_carriers.name[0]);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carriers\" node.\n");
|
||||
|
||||
char rx_freq[16];
|
||||
snprintf(rx_freq, sizeof(rx_freq), "%.0f", oai->rx_freq[0]);
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "center-of-channel-bandwidth", rx_freq, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"center-of-channel-bandwidth\" node.\n");
|
||||
|
||||
char rx_arfcn[16];
|
||||
snprintf(rx_arfcn, sizeof(rx_arfcn), "%d", to_nrarfcn(oai->nr_band, oai->rx_freq[0], oai->nr_scs_for_raster, oai->rx_bw));
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "absolute-frequency-center", rx_arfcn, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"absolute-frequency-center\" node.\n");
|
||||
|
||||
char rx_bw[16];
|
||||
snprintf(rx_bw, sizeof(rx_bw), "%.0f", oai->rx_bw);
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "channel-bandwidth", rx_bw, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n");
|
||||
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-radio-frame-offset\" node.\n");
|
||||
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n");
|
||||
|
||||
// oai->rx_gain_offset is this the correction? if yes, test it later
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "gain-correction", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain-correction\" node.\n");
|
||||
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "n-ta-offset", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"n-ta-offset\" node.\n");
|
||||
|
||||
ret = lyd_new_term(rx_carrier_node, NULL, "active", "ACTIVE", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
|
||||
|
||||
// TX carriers
|
||||
struct lyd_node *tx_carrier_node = NULL;
|
||||
ret = lyd_new_list(*root, NULL, "tx-array-carriers", 0, &tx_carrier_node, ru_session->ru_mplane_config.tx_carriers.name[0]);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-array-carriers\" node.\n");
|
||||
|
||||
char tx_freq[16];
|
||||
snprintf(tx_freq, sizeof(tx_freq), "%.0f", oai->tx_freq[0]);
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "center-of-channel-bandwidth", tx_freq, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"center-of-channel-bandwidth\" node.\n");
|
||||
|
||||
char tx_arfcn[16];
|
||||
snprintf(tx_arfcn, sizeof(tx_arfcn), "%d", to_nrarfcn(oai->nr_band, oai->tx_freq[0], oai->nr_scs_for_raster, oai->tx_bw));
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "absolute-frequency-center", tx_arfcn, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"absolute-frequency-center\" node.\n");
|
||||
|
||||
char tx_bw[16];
|
||||
snprintf(tx_bw, sizeof(tx_bw), "%.0f", oai->tx_bw);
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "channel-bandwidth", tx_bw, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n");
|
||||
|
||||
// oai->tx_gain to be tested
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "gain", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain\" node.\n");
|
||||
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-radio-frame-offset\" node.\n");
|
||||
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n");
|
||||
|
||||
ret = lyd_new_term(tx_carrier_node, NULL, "active", "ACTIVE", 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
|
||||
|
||||
// PUSCH & PRACH endpoints
|
||||
const size_t num_rx_ch = oai->rx_num_channels / num_rus;
|
||||
for (size_t i = 0; i < num_rx_ch; i++) {
|
||||
struct lyd_node *pusch_node = NULL;
|
||||
ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &pusch_node, ru_session->ru_mplane_config.rx_endpoints.name[i]);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n");
|
||||
|
||||
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pusch_node);
|
||||
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[i]);
|
||||
|
||||
const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2);
|
||||
struct lyd_node *prach_node = NULL;
|
||||
ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &prach_node, ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n");
|
||||
|
||||
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i + ru_session->xran_mplane.prach_offset, &prach_node);
|
||||
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]);
|
||||
}
|
||||
|
||||
// PDSCH endpoints
|
||||
const size_t num_tx_ch = oai->tx_num_channels / num_rus;
|
||||
for (size_t i = 0; i < num_tx_ch; i++) {
|
||||
struct lyd_node *pdsch_node = NULL;
|
||||
ret = lyd_new_list(*root, NULL, "low-level-tx-endpoints", 0, &pdsch_node, ru_session->ru_mplane_config.tx_endpoints.name[i]);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoints\" node.\n");
|
||||
|
||||
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pdsch_node);
|
||||
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-tx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.tx_endpoints.name[i]);
|
||||
}
|
||||
|
||||
// PUSCH and PRACH links
|
||||
for (size_t i = 0; i < num_rx_ch; i++) {
|
||||
// PUSCH
|
||||
struct lyd_node *pusch_link_node = NULL;
|
||||
char pusch_link[16];
|
||||
snprintf(pusch_link, sizeof(pusch_link), "%s%ld", "PuschLink", i);
|
||||
ret = lyd_new_list(*root, NULL, "low-level-rx-links", 0, &pusch_link_node, pusch_link);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-links\" node.\n");
|
||||
|
||||
ret = lyd_new_term(pusch_link_node, NULL, "processing-element", u_proc_elem, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n");
|
||||
|
||||
ret = lyd_new_term(pusch_link_node, NULL, "rx-array-carrier", ru_session->ru_mplane_config.rx_carriers.name[0], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carrier\" node.\n");
|
||||
|
||||
ret = lyd_new_term(pusch_link_node, NULL, "low-level-rx-endpoint", ru_session->ru_mplane_config.rx_endpoints.name[i], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoint\" node.\n");
|
||||
|
||||
// PRACH
|
||||
struct lyd_node *prach_link_node = NULL;
|
||||
char prach_link[16];
|
||||
snprintf(prach_link, sizeof(prach_link), "%s%ld", "PrachLink", i);
|
||||
ret = lyd_new_list(*root, NULL, "low-level-rx-links", 0, &prach_link_node, prach_link);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-links\" node.\n");
|
||||
|
||||
ret = lyd_new_term(prach_link_node, NULL, "processing-element", u_proc_elem, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n");
|
||||
|
||||
ret = lyd_new_term(prach_link_node, NULL, "rx-array-carrier", ru_session->ru_mplane_config.rx_carriers.name[0], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carrier\" node.\n");
|
||||
|
||||
const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2);
|
||||
ret = lyd_new_term(prach_link_node, NULL, "low-level-rx-endpoint", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoint\" node.\n");
|
||||
}
|
||||
|
||||
// PDSCH links
|
||||
for (size_t i = 0; i < num_tx_ch; i++) {
|
||||
struct lyd_node *pdsch_link_node = NULL;
|
||||
char pdsch_link[16];
|
||||
snprintf(pdsch_link, sizeof(pdsch_link), "%s%ld", "PdschLink", i);
|
||||
ret = lyd_new_list(*root, NULL, "low-level-tx-links", 0, &pdsch_link_node, pdsch_link);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-links\" node.\n");
|
||||
|
||||
ret = lyd_new_term(pdsch_link_node, NULL, "processing-element", u_proc_elem, 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n");
|
||||
|
||||
ret = lyd_new_term(pdsch_link_node, NULL, "tx-array-carrier", ru_session->ru_mplane_config.tx_carriers.name[0], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-array-carrier\" node.\n");
|
||||
|
||||
ret = lyd_new_term(pdsch_link_node, NULL, "low-level-tx-endpoint", ru_session->ru_mplane_config.tx_endpoints.name[i], 0, NULL);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoint\" node.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
VERIFY_SUCCESS(success, "[MPLANE] To be implemented and tested.\n");
|
||||
#elif defined MPLANE_V2
|
||||
const ru_mplane_config_t *ru_config = &ru_session->ru_mplane_config;
|
||||
size_t num_cu_planes = ru_config->num_cu_planes;
|
||||
if (num_cu_planes == 2 && ru_config->vlan_tag[0] == ru_config->vlan_tag[1]) {
|
||||
MP_LOG_I("The VLAN tags for C and U plane for the RU \"%s\" are the same. Therefore, configuring one common interface and one processing element.\n", ru_session->ru_ip_add);
|
||||
num_cu_planes = 1;
|
||||
}
|
||||
|
||||
struct lyd_node *all_merge = NULL;
|
||||
LY_ERR ret = LY_SUCCESS;
|
||||
|
||||
for (size_t i = 0; i < num_cu_planes; i++) {
|
||||
// <ietf-interfaces>
|
||||
struct lyd_node *cu_interface = NULL;
|
||||
char int_name[12];
|
||||
snprintf(int_name, sizeof(int_name), "INTERFACE_%ld", i);
|
||||
success = create_cu_interface_v2(ctx, ru_session, i, int_name, &cu_interface);
|
||||
VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane interface.\n");
|
||||
|
||||
// <o-ran-processing-element>
|
||||
struct lyd_node *proc_elem = NULL;
|
||||
success = create_proc_elem_v2(ctx, ru_session, i, int_name, &proc_elem);
|
||||
VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane processing element.\n");
|
||||
|
||||
ret = lyd_merge_siblings(&all_merge, cu_interface, 0);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface.\n");
|
||||
ret = lyd_merge_siblings(&all_merge, proc_elem, 0);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge processing element.\n");
|
||||
|
||||
lyd_free_tree(cu_interface);
|
||||
lyd_free_tree(proc_elem);
|
||||
}
|
||||
|
||||
// <o-ran-uplane-conf>
|
||||
struct lyd_node *uplane_conf = NULL;
|
||||
success = create_uplane_conf_v2(ctx, ru_session, oai, num_rus, "PLANE_0", &uplane_conf);
|
||||
VERIFY_SUCCESS(success, "[MPLANE] Cannot create U-plane configuration.\n");
|
||||
|
||||
ret = lyd_merge_siblings(&uplane_conf, all_merge, 0);
|
||||
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n");
|
||||
|
||||
lyd_print_mem(result, uplane_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS);
|
||||
|
||||
lyd_free_siblings(all_merge);
|
||||
lyd_free_siblings(uplane_conf);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 CREATE_MPLANE_YANG_CONFIG_H
|
||||
#define CREATE_MPLANE_YANG_CONFIG_H
|
||||
|
||||
#include "../ru-mplane-api.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result);
|
||||
|
||||
#endif /* CREATE_MPLANE_YANG_CONFIG_H */
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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 "get-yang.h"
|
||||
#include "../rpc-send-recv.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
|
||||
static bool store_schemas(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx)
|
||||
{
|
||||
int timeout = CLI_RPC_REPLY_TIMEOUT;
|
||||
NC_WD_MODE wd = NC_WD_ALL;
|
||||
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
|
||||
LYS_INFORMAT ly_format = LYS_IN_YANG;
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
*ctx = ly_ctx_new(NULL, 0);
|
||||
#elif defined MPLANE_V2
|
||||
ly_ctx_new(NULL, 0, ctx);
|
||||
#endif
|
||||
|
||||
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
|
||||
if (strcmp((const char *)cur_node->name, "schema") == 0) {
|
||||
|
||||
xmlNode *name_node = xmlFirstElementChild(cur_node);
|
||||
char *module_name = (char *)xmlNodeGetContent(name_node);
|
||||
xmlNode *revision_node = xmlNextElementSibling(name_node);
|
||||
char *module_revision = (char *)xmlNodeGetContent(revision_node);
|
||||
xmlNode *format_node = xmlNextElementSibling(revision_node);
|
||||
char *module_format = (char *)xmlNodeGetContent(format_node);
|
||||
|
||||
if (strcmp(module_format, "yang") != 0)
|
||||
continue;
|
||||
|
||||
MP_LOG_I("RPC request to RU \"%s\" = <get-schema> for module \"%s\".\n", ru_session->ru_ip_add, module_name);
|
||||
struct nc_rpc *get_schema_rpc = nc_rpc_getschema(module_name, module_revision, "yang", param);
|
||||
char *schema_data = NULL;
|
||||
bool success = rpc_send_recv((struct nc_session *)ru_session->session, get_schema_rpc, wd, timeout, &schema_data);
|
||||
AssertError(success, return false, "[MPLANE] Unable to get schema for module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add);
|
||||
|
||||
if (schema_data) {
|
||||
#ifdef MPLANE_V1
|
||||
const struct lys_module *mod = lys_parse_mem(*ctx, schema_data, ly_format);
|
||||
#elif defined MPLANE_V2
|
||||
struct lys_module *mod = NULL;
|
||||
lys_parse_mem(*ctx, schema_data, ly_format, &mod);
|
||||
#endif
|
||||
free(schema_data);
|
||||
if (!mod) {
|
||||
MP_LOG_W("Unable to load module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add);
|
||||
nc_rpc_free(get_schema_rpc);
|
||||
ly_ctx_destroy(*ctx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
nc_rpc_free(get_schema_rpc);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_from_operational_ds(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx)
|
||||
{
|
||||
for (xmlNode *schemas_node = node; schemas_node; schemas_node = schemas_node->next) {
|
||||
if(schemas_node->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
if (strcmp((const char *)schemas_node->name, "schemas") == 0) {
|
||||
return store_schemas(schemas_node->children, ru_session, ctx);
|
||||
} else {
|
||||
bool success = load_from_operational_ds(schemas_node->children, ru_session, ctx);
|
||||
if (success)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx)
|
||||
{
|
||||
// Initialize the xml file
|
||||
size_t len = strlen(buffer) + 1;
|
||||
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
|
||||
xmlNode *root_element = xmlDocGetRootElement(doc);
|
||||
|
||||
bool success = load_from_operational_ds(root_element->children, ru_session, ctx);
|
||||
if (success) {
|
||||
MP_LOG_I("Successfully loaded all yang modules from operational datastore for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
return true;
|
||||
} else {
|
||||
MP_LOG_W("Unable to load all yang modules from operational datastore for RU \"%s\". Using yang models present in \"models\" subfolder.\n", ru_session->ru_ip_add);
|
||||
}
|
||||
|
||||
/* ideally, we should load the yang models from the operational datastore, but the issues are following:
|
||||
1) the yang models order is not good - the dependancy models have to be loaded first
|
||||
2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) */
|
||||
const char *yang_dir = YANG_MODELS;
|
||||
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf"};
|
||||
|
||||
#ifdef MPLANE_V1
|
||||
*ctx = ly_ctx_new(yang_dir, 0);
|
||||
AssertError(*ctx != NULL, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx));
|
||||
#elif defined MPLANE_V2
|
||||
LY_ERR ret = ly_ctx_new(yang_dir, 0, ctx);
|
||||
AssertError(ret == LY_SUCCESS, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx));
|
||||
#endif
|
||||
|
||||
const size_t num_models = sizeof(yang_models) / sizeof(yang_models[0]);
|
||||
for (size_t i = 0; i < num_models; ++i) {
|
||||
#ifdef MPLANE_V1
|
||||
const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL);
|
||||
AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]);
|
||||
#elif defined MPLANE_V2
|
||||
const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL, NULL);
|
||||
AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_LOG_I("Successfully loaded all yang modules for RU \"%s\".\n", ru_session->ru_ip_add);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 GET_MPLANE_YANG_MODELS_H
|
||||
#define GET_MPLANE_YANG_MODELS_H
|
||||
|
||||
#include "../ru-mplane-api.h"
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx);
|
||||
|
||||
#endif /* GET_MPLANE_YANG_MODELS_H */
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
module iana-hardware {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:iana-hardware";
|
||||
prefix ianahw;
|
||||
|
||||
organization "IANA";
|
||||
contact
|
||||
" Internet Assigned Numbers Authority
|
||||
Postal: ICANN
|
||||
12025 Waterfront Drive, Suite 300
|
||||
Los Angeles, CA 90094-2536
|
||||
United States of America
|
||||
Tel: +1 310 301 5800
|
||||
E-Mail: iana@iana.org>";
|
||||
|
||||
description
|
||||
"IANA-defined identities for hardware class.
|
||||
The latest revision of this YANG module can be obtained from
|
||||
the IANA website.
|
||||
Requests for new values should be made to IANA via
|
||||
email (iana@iana.org).
|
||||
Copyright (c) 2018 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
The initial version of this YANG module is part of RFC 8348;
|
||||
see the RFC itself for full legal notices.";
|
||||
reference
|
||||
"https://www.iana.org/assignments/yang-parameters";
|
||||
|
||||
revision 2018-03-13 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 8348: A YANG Data Model for Hardware Management";
|
||||
}
|
||||
|
||||
/*
|
||||
* Identities
|
||||
*/
|
||||
|
||||
identity hardware-class {
|
||||
description
|
||||
"This identity is the base for all hardware class
|
||||
identifiers.";
|
||||
}
|
||||
|
||||
identity unknown {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is unknown
|
||||
to the server.";
|
||||
}
|
||||
|
||||
identity chassis {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is an
|
||||
overall container for networking equipment. Any class of
|
||||
physical component, except a stack, may be contained within a
|
||||
chassis; a chassis may only be contained within a stack.";
|
||||
}
|
||||
|
||||
identity backplane {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of device for aggregating and forwarding networking traffic,
|
||||
such as a shared backplane in a modular ethernet switch. Note
|
||||
that an implementation may model a backplane as a single
|
||||
physical component, which is actually implemented as multiple
|
||||
discrete physical components (within a chassis or stack).";
|
||||
}
|
||||
|
||||
identity container {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is capable
|
||||
of containing one or more removable physical entities,
|
||||
possibly of different types. For example, each (empty or
|
||||
full) slot in a chassis will be modeled as a container. Note
|
||||
that all removable physical components should be modeled
|
||||
within a container component, such as field-replaceable
|
||||
modules, fans, or power supplies. Note that all known
|
||||
containers should be modeled by the agent, including empty
|
||||
containers.";
|
||||
}
|
||||
|
||||
identity power-supply {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is a
|
||||
power-supplying component.";
|
||||
}
|
||||
|
||||
identity fan {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is a fan or
|
||||
other heat-reduction component.";
|
||||
}
|
||||
|
||||
identity sensor {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of sensor, such as a temperature sensor within a router
|
||||
chassis.";
|
||||
}
|
||||
|
||||
identity module {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of self-contained sub-system. If a module component is
|
||||
removable, then it should be modeled within a container
|
||||
component; otherwise, it should be modeled directly within
|
||||
another physical component (e.g., a chassis or another
|
||||
module).";
|
||||
}
|
||||
|
||||
identity port {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of networking port capable of receiving and/or transmitting
|
||||
networking traffic.";
|
||||
}
|
||||
|
||||
identity stack {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of super-container (possibly virtual) intended to group
|
||||
together multiple chassis entities. A stack may be realized
|
||||
by a virtual cable, a real interconnect cable attached to
|
||||
multiple chassis, or multiple interconnect cables. A stack
|
||||
should not be modeled within any other physical components,
|
||||
but a stack may be contained within another stack. Only
|
||||
chassis components should be contained within a stack.";
|
||||
}
|
||||
|
||||
identity cpu {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of central processing unit.";
|
||||
}
|
||||
|
||||
identity energy-object {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of energy object, i.e., it is a piece of equipment that is
|
||||
part of or attached to a communications network that is
|
||||
monitored, it is controlled, or it aids in the management of
|
||||
another device for Energy Management.";
|
||||
}
|
||||
|
||||
identity battery {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of battery.";
|
||||
}
|
||||
|
||||
identity storage-drive {
|
||||
base ianahw:hardware-class;
|
||||
description
|
||||
"This identity is applicable if the hardware class is some sort
|
||||
of component with data storage capability as its main
|
||||
functionality, e.g., hard disk drive (HDD), solid-state device
|
||||
(SSD), solid-state hybrid drive (SSHD), object storage device
|
||||
(OSD), or other.";
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+1141
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,860 @@
|
||||
module ietf-ip {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
|
||||
prefix ip;
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization
|
||||
"IETF NETMOD (Network Modeling) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
|
||||
WG List: <mailto:netmod@ietf.org>
|
||||
Editor: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>";
|
||||
description
|
||||
"This module contains a collection of YANG definitions for
|
||||
managing IP implementations.
|
||||
Copyright (c) 2018 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(https://trustee.ietf.org/license-info).
|
||||
This version of this YANG module is part of RFC 8344; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2018-02-22 {
|
||||
description
|
||||
"Updated to support NMDA.";
|
||||
reference
|
||||
"RFC 8344: A YANG Data Model for IP Management";
|
||||
}
|
||||
|
||||
revision 2014-06-16 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 7277: A YANG Data Model for IP Management";
|
||||
}
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
feature ipv4-non-contiguous-netmasks {
|
||||
description
|
||||
"Indicates support for configuring non-contiguous
|
||||
subnet masks.";
|
||||
}
|
||||
|
||||
feature ipv6-privacy-autoconf {
|
||||
description
|
||||
"Indicates support for privacy extensions for stateless address
|
||||
autoconfiguration in IPv6.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
*/
|
||||
|
||||
typedef ip-address-origin {
|
||||
type enumeration {
|
||||
enum other {
|
||||
description
|
||||
"None of the following.";
|
||||
}
|
||||
|
||||
enum static {
|
||||
description
|
||||
"Indicates that the address has been statically
|
||||
configured -- for example, using the Network Configuration
|
||||
Protocol (NETCONF) or a command line interface.";
|
||||
}
|
||||
enum dhcp {
|
||||
description
|
||||
"Indicates an address that has been assigned to this
|
||||
system by a DHCP server.";
|
||||
}
|
||||
enum link-layer {
|
||||
description
|
||||
"Indicates an address created by IPv6 stateless
|
||||
autoconfiguration that embeds a link-layer address in its
|
||||
interface identifier.";
|
||||
}
|
||||
enum random {
|
||||
description
|
||||
"Indicates an address chosen by the system at
|
||||
random, e.g., an IPv4 address within 169.254/16, a
|
||||
temporary address as described in RFC 4941, or a
|
||||
semantically opaque address as described in RFC 7217.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6
|
||||
RFC 7217: A Method for Generating Semantically Opaque
|
||||
Interface Identifiers with IPv6 Stateless
|
||||
Address Autoconfiguration (SLAAC)";
|
||||
}
|
||||
}
|
||||
description
|
||||
"The origin of an address.";
|
||||
}
|
||||
|
||||
typedef neighbor-origin {
|
||||
type enumeration {
|
||||
enum other {
|
||||
description
|
||||
"None of the following.";
|
||||
}
|
||||
enum static {
|
||||
description
|
||||
"Indicates that the mapping has been statically
|
||||
configured -- for example, using NETCONF or a command line
|
||||
interface.";
|
||||
}
|
||||
|
||||
enum dynamic {
|
||||
description
|
||||
"Indicates that the mapping has been dynamically resolved
|
||||
using, for example, IPv4 ARP or the IPv6 Neighbor
|
||||
Discovery protocol.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"The origin of a neighbor entry.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data nodes
|
||||
*/
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
description
|
||||
"IP parameters on interfaces.
|
||||
If an interface is not capable of running IP, the server
|
||||
must not allow the client to configure these parameters.";
|
||||
|
||||
container ipv4 {
|
||||
presence
|
||||
"Enables IPv4 unless the 'enabled' leaf
|
||||
(which defaults to 'true') is set to 'false'";
|
||||
description
|
||||
"Parameters for the IPv4 address family.";
|
||||
|
||||
leaf enabled {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Controls whether IPv4 is enabled or disabled on this
|
||||
interface. When IPv4 is enabled, this interface is
|
||||
connected to an IPv4 stack, and the interface can send
|
||||
and receive IPv4 packets.";
|
||||
}
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Controls IPv4 packet forwarding of datagrams received by,
|
||||
but not addressed to, this interface. IPv4 routers
|
||||
forward datagrams. IPv4 hosts do not (except those
|
||||
source-routed via the host).";
|
||||
}
|
||||
|
||||
leaf mtu {
|
||||
type uint16 {
|
||||
range "68..max";
|
||||
}
|
||||
units "octets";
|
||||
description
|
||||
"The size, in octets, of the largest IPv4 packet that the
|
||||
interface will send and receive.
|
||||
The server may restrict the allowed values for this leaf,
|
||||
depending on the interface's type.
|
||||
If this leaf is not configured, the operationally used MTU
|
||||
depends on the interface's type.";
|
||||
reference
|
||||
"RFC 791: Internet Protocol";
|
||||
}
|
||||
list address {
|
||||
key "ip";
|
||||
description
|
||||
"The list of IPv4 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
description
|
||||
"The IPv4 address on the interface.";
|
||||
}
|
||||
choice subnet {
|
||||
mandatory true;
|
||||
description
|
||||
"The subnet can be specified as a prefix length or,
|
||||
if the server supports non-contiguous netmasks, as
|
||||
a netmask.";
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..32";
|
||||
}
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf netmask {
|
||||
if-feature ipv4-non-contiguous-netmasks;
|
||||
type yang:dotted-quad;
|
||||
description
|
||||
"The subnet specified as a netmask.";
|
||||
}
|
||||
}
|
||||
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
}
|
||||
list neighbor {
|
||||
key "ip";
|
||||
description
|
||||
"A list of mappings from IPv4 addresses to
|
||||
link-layer addresses.
|
||||
Entries in this list in the intended configuration are
|
||||
used as static entries in the ARP Cache.
|
||||
In the operational state, this list represents the ARP
|
||||
Cache.";
|
||||
reference
|
||||
"RFC 826: An Ethernet Address Resolution Protocol";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
description
|
||||
"The IPv4 address of the neighbor node.";
|
||||
}
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The link-layer address of the neighbor node.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container ipv6 {
|
||||
presence
|
||||
"Enables IPv6 unless the 'enabled' leaf
|
||||
(which defaults to 'true') is set to 'false'";
|
||||
description
|
||||
"Parameters for the IPv6 address family.";
|
||||
|
||||
leaf enabled {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Controls whether IPv6 is enabled or disabled on this
|
||||
interface. When IPv6 is enabled, this interface is
|
||||
connected to an IPv6 stack, and the interface can send
|
||||
and receive IPv6 packets.";
|
||||
}
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Controls IPv6 packet forwarding of datagrams received by,
|
||||
but not addressed to, this interface. IPv6 routers
|
||||
forward datagrams. IPv6 hosts do not (except those
|
||||
source-routed via the host).";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 6.2.1, IsRouter";
|
||||
}
|
||||
leaf mtu {
|
||||
type uint32 {
|
||||
range "1280..max";
|
||||
}
|
||||
units "octets";
|
||||
description
|
||||
"The size, in octets, of the largest IPv6 packet that the
|
||||
interface will send and receive.
|
||||
The server may restrict the allowed values for this leaf,
|
||||
depending on the interface's type.
|
||||
If this leaf is not configured, the operationally used MTU
|
||||
depends on the interface's type.";
|
||||
reference
|
||||
"RFC 8200: Internet Protocol, Version 6 (IPv6)
|
||||
Specification
|
||||
Section 5";
|
||||
}
|
||||
|
||||
list address {
|
||||
key "ip";
|
||||
description
|
||||
"The list of IPv6 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
description
|
||||
"The IPv6 address on the interface.";
|
||||
}
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..128";
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
leaf status {
|
||||
type enumeration {
|
||||
enum preferred {
|
||||
description
|
||||
"This is a valid address that can appear as the
|
||||
destination or source address of a packet.";
|
||||
}
|
||||
enum deprecated {
|
||||
description
|
||||
"This is a valid but deprecated address that should
|
||||
no longer be used as a source address in new
|
||||
communications, but packets addressed to such an
|
||||
address are processed as expected.";
|
||||
}
|
||||
enum invalid {
|
||||
description
|
||||
"This isn't a valid address, and it shouldn't appear
|
||||
as the destination or source address of a packet.";
|
||||
}
|
||||
|
||||
enum inaccessible {
|
||||
description
|
||||
"The address is not accessible because the interface
|
||||
to which this address is assigned is not
|
||||
operational.";
|
||||
}
|
||||
enum unknown {
|
||||
description
|
||||
"The status cannot be determined for some reason.";
|
||||
}
|
||||
enum tentative {
|
||||
description
|
||||
"The uniqueness of the address on the link is being
|
||||
verified. Addresses in this state should not be
|
||||
used for general communication and should only be
|
||||
used to determine the uniqueness of the address.";
|
||||
}
|
||||
enum duplicate {
|
||||
description
|
||||
"The address has been determined to be non-unique on
|
||||
the link and so must not be used.";
|
||||
}
|
||||
enum optimistic {
|
||||
description
|
||||
"The address is available for use, subject to
|
||||
restrictions, while its uniqueness on a link is
|
||||
being verified.";
|
||||
}
|
||||
}
|
||||
config false;
|
||||
description
|
||||
"The status of an address. Most of the states correspond
|
||||
to states from the IPv6 Stateless Address
|
||||
Autoconfiguration protocol.";
|
||||
reference
|
||||
"RFC 4293: Management Information Base for the
|
||||
Internet Protocol (IP)
|
||||
- IpAddressStatusTC
|
||||
RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
}
|
||||
}
|
||||
|
||||
list neighbor {
|
||||
key "ip";
|
||||
description
|
||||
"A list of mappings from IPv6 addresses to
|
||||
link-layer addresses.
|
||||
Entries in this list in the intended configuration are
|
||||
used as static entries in the Neighbor Cache.
|
||||
In the operational state, this list represents the
|
||||
Neighbor Cache.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
description
|
||||
"The IPv6 address of the neighbor node.";
|
||||
}
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
mandatory true;
|
||||
description
|
||||
"The link-layer address of the neighbor node.
|
||||
In the operational state, if the neighbor's 'state' leaf
|
||||
is 'incomplete', this leaf is not instantiated.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
config false;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
leaf is-router {
|
||||
type empty;
|
||||
config false;
|
||||
description
|
||||
"Indicates that the neighbor node acts as a router.";
|
||||
}
|
||||
|
||||
leaf state {
|
||||
type enumeration {
|
||||
enum incomplete {
|
||||
description
|
||||
"Address resolution is in progress, and the
|
||||
link-layer address of the neighbor has not yet been
|
||||
determined.";
|
||||
}
|
||||
enum reachable {
|
||||
description
|
||||
"Roughly speaking, the neighbor is known to have been
|
||||
reachable recently (within tens of seconds ago).";
|
||||
}
|
||||
enum stale {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, but
|
||||
until traffic is sent to the neighbor no attempt
|
||||
should be made to verify its reachability.";
|
||||
}
|
||||
enum delay {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
traffic has recently been sent to the neighbor.
|
||||
Rather than probe the neighbor immediately, however,
|
||||
delay sending probes for a short while in order to
|
||||
give upper-layer protocols a chance to provide
|
||||
reachability confirmation.";
|
||||
}
|
||||
enum probe {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
unicast Neighbor Solicitation probes are being sent
|
||||
to verify reachability.";
|
||||
}
|
||||
}
|
||||
config false;
|
||||
description
|
||||
"The Neighbor Unreachability Detection state of this
|
||||
entry.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 7.3.2";
|
||||
}
|
||||
}
|
||||
|
||||
leaf dup-addr-detect-transmits {
|
||||
type uint32;
|
||||
default 1;
|
||||
description
|
||||
"The number of consecutive Neighbor Solicitation messages
|
||||
sent while performing Duplicate Address Detection on a
|
||||
tentative address. A value of zero indicates that
|
||||
Duplicate Address Detection is not performed on
|
||||
tentative addresses. A value of one indicates a single
|
||||
transmission with no follow-up retransmissions.";
|
||||
reference
|
||||
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
}
|
||||
container autoconf {
|
||||
description
|
||||
"Parameters to control the autoconfiguration of IPv6
|
||||
addresses, as described in RFC 4862.";
|
||||
reference
|
||||
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
|
||||
leaf create-global-addresses {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"If enabled, the host creates global addresses as
|
||||
described in RFC 4862.";
|
||||
reference
|
||||
"RFC 4862: IPv6 Stateless Address Autoconfiguration
|
||||
Section 5.5";
|
||||
}
|
||||
leaf create-temporary-addresses {
|
||||
if-feature ipv6-privacy-autoconf;
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"If enabled, the host creates temporary addresses as
|
||||
described in RFC 4941.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6";
|
||||
}
|
||||
|
||||
leaf temporary-valid-lifetime {
|
||||
if-feature ipv6-privacy-autoconf;
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 604800;
|
||||
description
|
||||
"The time period during which the temporary address
|
||||
is valid.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6
|
||||
- TEMP_VALID_LIFETIME";
|
||||
}
|
||||
leaf temporary-preferred-lifetime {
|
||||
if-feature ipv6-privacy-autoconf;
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 86400;
|
||||
description
|
||||
"The time period during which the temporary address is
|
||||
preferred.";
|
||||
reference
|
||||
"RFC 4941: Privacy Extensions for Stateless Address
|
||||
Autoconfiguration in IPv6
|
||||
- TEMP_PREFERRED_LIFETIME";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy operational state data nodes
|
||||
*/
|
||||
|
||||
augment "/if:interfaces-state/if:interface" {
|
||||
status deprecated;
|
||||
description
|
||||
"Data nodes for the operational state of IP on interfaces.";
|
||||
|
||||
container ipv4 {
|
||||
presence
|
||||
"Present if IPv4 is enabled on this interface";
|
||||
config false;
|
||||
status deprecated;
|
||||
description
|
||||
"Interface-specific parameters for the IPv4 address family.";
|
||||
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
status deprecated;
|
||||
description
|
||||
"Indicates whether IPv4 packet forwarding is enabled or
|
||||
disabled on this interface.";
|
||||
}
|
||||
leaf mtu {
|
||||
type uint16 {
|
||||
range "68..max";
|
||||
}
|
||||
units "octets";
|
||||
status deprecated;
|
||||
description
|
||||
"The size, in octets, of the largest IPv4 packet that the
|
||||
interface will send and receive.";
|
||||
reference
|
||||
"RFC 791: Internet Protocol";
|
||||
}
|
||||
list address {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"The list of IPv4 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv4 address on the interface.";
|
||||
}
|
||||
choice subnet {
|
||||
status deprecated;
|
||||
description
|
||||
"The subnet can be specified as a prefix length or,
|
||||
if the server supports non-contiguous netmasks, as
|
||||
a netmask.";
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..32";
|
||||
}
|
||||
status deprecated;
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf netmask {
|
||||
if-feature ipv4-non-contiguous-netmasks;
|
||||
type yang:dotted-quad;
|
||||
status deprecated;
|
||||
description
|
||||
"The subnet specified as a netmask.";
|
||||
}
|
||||
}
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
}
|
||||
list neighbor {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"A list of mappings from IPv4 addresses to
|
||||
link-layer addresses.
|
||||
This list represents the ARP Cache.";
|
||||
reference
|
||||
"RFC 826: An Ethernet Address Resolution Protocol";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv4-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv4 address of the neighbor node.";
|
||||
}
|
||||
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
status deprecated;
|
||||
description
|
||||
"The link-layer address of the neighbor node.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container ipv6 {
|
||||
presence
|
||||
"Present if IPv6 is enabled on this interface";
|
||||
config false;
|
||||
status deprecated;
|
||||
description
|
||||
"Parameters for the IPv6 address family.";
|
||||
|
||||
leaf forwarding {
|
||||
type boolean;
|
||||
default false;
|
||||
status deprecated;
|
||||
description
|
||||
"Indicates whether IPv6 packet forwarding is enabled or
|
||||
disabled on this interface.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 6.2.1, IsRouter";
|
||||
}
|
||||
leaf mtu {
|
||||
type uint32 {
|
||||
range "1280..max";
|
||||
}
|
||||
units "octets";
|
||||
status deprecated;
|
||||
description
|
||||
"The size, in octets, of the largest IPv6 packet that the
|
||||
interface will send and receive.";
|
||||
reference
|
||||
"RFC 8200: Internet Protocol, Version 6 (IPv6)
|
||||
Specification
|
||||
Section 5";
|
||||
}
|
||||
list address {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"The list of IPv6 addresses on the interface.";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv6 address on the interface.";
|
||||
}
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range "0..128";
|
||||
}
|
||||
mandatory true;
|
||||
status deprecated;
|
||||
description
|
||||
"The length of the subnet prefix.";
|
||||
}
|
||||
leaf origin {
|
||||
type ip-address-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this address.";
|
||||
}
|
||||
leaf status {
|
||||
type enumeration {
|
||||
enum preferred {
|
||||
description
|
||||
"This is a valid address that can appear as the
|
||||
destination or source address of a packet.";
|
||||
}
|
||||
enum deprecated {
|
||||
description
|
||||
"This is a valid but deprecated address that should
|
||||
no longer be used as a source address in new
|
||||
communications, but packets addressed to such an
|
||||
address are processed as expected.";
|
||||
}
|
||||
enum invalid {
|
||||
description
|
||||
"This isn't a valid address, and it shouldn't appear
|
||||
as the destination or source address of a packet.";
|
||||
}
|
||||
|
||||
enum inaccessible {
|
||||
description
|
||||
"The address is not accessible because the interface
|
||||
to which this address is assigned is not
|
||||
operational.";
|
||||
}
|
||||
enum unknown {
|
||||
description
|
||||
"The status cannot be determined for some reason.";
|
||||
}
|
||||
enum tentative {
|
||||
description
|
||||
"The uniqueness of the address on the link is being
|
||||
verified. Addresses in this state should not be
|
||||
used for general communication and should only be
|
||||
used to determine the uniqueness of the address.";
|
||||
}
|
||||
enum duplicate {
|
||||
description
|
||||
"The address has been determined to be non-unique on
|
||||
the link and so must not be used.";
|
||||
}
|
||||
enum optimistic {
|
||||
description
|
||||
"The address is available for use, subject to
|
||||
restrictions, while its uniqueness on a link is
|
||||
being verified.";
|
||||
}
|
||||
}
|
||||
status deprecated;
|
||||
description
|
||||
"The status of an address. Most of the states correspond
|
||||
to states from the IPv6 Stateless Address
|
||||
Autoconfiguration protocol.";
|
||||
reference
|
||||
"RFC 4293: Management Information Base for the
|
||||
Internet Protocol (IP)
|
||||
- IpAddressStatusTC
|
||||
RFC 4862: IPv6 Stateless Address Autoconfiguration";
|
||||
}
|
||||
}
|
||||
|
||||
list neighbor {
|
||||
key "ip";
|
||||
status deprecated;
|
||||
description
|
||||
"A list of mappings from IPv6 addresses to
|
||||
link-layer addresses.
|
||||
This list represents the Neighbor Cache.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
|
||||
|
||||
leaf ip {
|
||||
type inet:ipv6-address-no-zone;
|
||||
status deprecated;
|
||||
description
|
||||
"The IPv6 address of the neighbor node.";
|
||||
}
|
||||
leaf link-layer-address {
|
||||
type yang:phys-address;
|
||||
status deprecated;
|
||||
description
|
||||
"The link-layer address of the neighbor node.";
|
||||
}
|
||||
leaf origin {
|
||||
type neighbor-origin;
|
||||
status deprecated;
|
||||
description
|
||||
"The origin of this neighbor entry.";
|
||||
}
|
||||
leaf is-router {
|
||||
type empty;
|
||||
status deprecated;
|
||||
description
|
||||
"Indicates that the neighbor node acts as a router.";
|
||||
}
|
||||
leaf state {
|
||||
type enumeration {
|
||||
enum incomplete {
|
||||
description
|
||||
"Address resolution is in progress, and the
|
||||
link-layer address of the neighbor has not yet been
|
||||
determined.";
|
||||
}
|
||||
enum reachable {
|
||||
description
|
||||
"Roughly speaking, the neighbor is known to have been
|
||||
reachable recently (within tens of seconds ago).";
|
||||
}
|
||||
enum stale {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, but
|
||||
until traffic is sent to the neighbor no attempt
|
||||
should be made to verify its reachability.";
|
||||
}
|
||||
enum delay {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
traffic has recently been sent to the neighbor.
|
||||
Rather than probe the neighbor immediately, however,
|
||||
delay sending probes for a short while in order to
|
||||
give upper-layer protocols a chance to provide
|
||||
reachability confirmation.";
|
||||
}
|
||||
enum probe {
|
||||
description
|
||||
"The neighbor is no longer known to be reachable, and
|
||||
unicast Neighbor Solicitation probes are being sent
|
||||
to verify reachability.";
|
||||
}
|
||||
}
|
||||
status deprecated;
|
||||
description
|
||||
"The Neighbor Unreachability Detection state of this
|
||||
entry.";
|
||||
reference
|
||||
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
|
||||
Section 7.3.2";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
module o-ran-compression-factors {
|
||||
yang-version 1.1;
|
||||
namespace "urn:o-ran:compression-factors:1.0";
|
||||
prefix "o-ran-compression-factors";
|
||||
|
||||
|
||||
organization "O-RAN Alliance";
|
||||
|
||||
contact
|
||||
"www.o-ran.org";
|
||||
|
||||
description
|
||||
"This module defines the module capabilities for
|
||||
the O-RAN Radio Unit U-Plane configuration.
|
||||
|
||||
Copyright 2020 the O-RAN Alliance.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the above disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the above disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the Members of the O-RAN Alliance nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.";
|
||||
|
||||
revision "2020-08-10" {
|
||||
description
|
||||
"version 4.0.0
|
||||
|
||||
1) supporting compression types per endpoint
|
||||
2) adding feature for configurable fs-offset for compression";
|
||||
|
||||
reference "ORAN-WG4.M.0-v04.00";
|
||||
}
|
||||
|
||||
revision "2020-04-17" {
|
||||
description
|
||||
"version 3.0.0
|
||||
|
||||
1) adding selective RE sending compression types";
|
||||
|
||||
reference "ORAN-WG4.M.0-v03.00";
|
||||
}
|
||||
|
||||
revision "2019-07-03" {
|
||||
description
|
||||
"version 1.1.0
|
||||
|
||||
1) changes related to compression bitwidth presentation";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
revision "2019-02-04" {
|
||||
description
|
||||
"version 1.0.0
|
||||
|
||||
1) imported model from xRAN
|
||||
2) changed namespace and reference from xran to o-ran";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
feature CONFIGURABLE-FS-OFFSET {
|
||||
description
|
||||
"Presence of this feature means that O-RU supports configurable fs-offset for compression.";
|
||||
}
|
||||
|
||||
grouping compression-method-grouping {
|
||||
description
|
||||
"Grouping for compression method.";
|
||||
|
||||
leaf iq-bitwidth {
|
||||
type uint8;
|
||||
description
|
||||
"Bitwidth to be used in compression";
|
||||
}
|
||||
|
||||
leaf compression-method {
|
||||
type enumeration {
|
||||
enum NO_COMPRESSION {
|
||||
description
|
||||
"No compression will be used";
|
||||
}
|
||||
enum BLOCK_FLOATING_POINT {
|
||||
description
|
||||
"Block floating point compression and decompression will be used";
|
||||
}
|
||||
|
||||
enum BLOCK_SCALING {
|
||||
description
|
||||
"Block scaling compression and decompresion will be used";
|
||||
}
|
||||
|
||||
enum U_LAW {
|
||||
description
|
||||
"u-Law compression and decompresion method will be used";
|
||||
}
|
||||
|
||||
enum BEAMSPACE {
|
||||
description
|
||||
"Beamspace compression and decompression will be used";
|
||||
}
|
||||
|
||||
enum MODULATION {
|
||||
description
|
||||
"Modulation compression and decompression will be used";
|
||||
}
|
||||
enum BLOCK-FLOATING-POINT-SELECTIVE-RE-SENDING {
|
||||
description
|
||||
"block floating point with selective re sending
|
||||
compression and decompression will be used";
|
||||
}
|
||||
enum MODULATION-COMPRESSION-SELECTIVE-RE-SENDING {
|
||||
description
|
||||
"modulation compression with selective re sending
|
||||
compression and decompression will be used";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Compresion method which can be supported by the O-RU";
|
||||
}
|
||||
}
|
||||
|
||||
grouping compression-formats {
|
||||
description
|
||||
"Grouping deicated to list compression formats as choice";
|
||||
|
||||
choice compression-format {
|
||||
description
|
||||
"Choice of compression format for particular element";
|
||||
|
||||
case no-compresison {
|
||||
description "Compression for beam weights is not supported.";
|
||||
}
|
||||
case block-floating-point {
|
||||
description "Block floating point compression and decompression is supported.";
|
||||
|
||||
leaf exponent {
|
||||
type uint8 {
|
||||
range "4";
|
||||
}
|
||||
description "Exponent bit width size in number of bits used when encoding in udCompParam.";
|
||||
}
|
||||
}
|
||||
|
||||
case block-floating-point-selective-re-sending {
|
||||
description
|
||||
"Block floating point with selective re sending compression and decompression is supported.";
|
||||
|
||||
leaf sres-exponent {
|
||||
type uint8 {
|
||||
range "4";
|
||||
}
|
||||
description "Exponent bit width size in number of bits used when encoding in udCompParam.";
|
||||
}
|
||||
}
|
||||
|
||||
case block-scaling {
|
||||
description "Block scaling compression and decompresion is supported.";
|
||||
leaf block-scalar {
|
||||
type uint8;
|
||||
description
|
||||
"Common scaler for compressed PRB";
|
||||
}
|
||||
}
|
||||
|
||||
case u-law {
|
||||
description "u-Law compression and decompresion method is supported.";
|
||||
leaf comp-bit-width {
|
||||
type uint8 {
|
||||
range "0..15";
|
||||
}
|
||||
description "Bit with for u-law compression";
|
||||
}
|
||||
leaf comp-shift {
|
||||
type uint8 {
|
||||
range "0..15";
|
||||
}
|
||||
description
|
||||
"the shift applied to the entire PRB";
|
||||
}
|
||||
}
|
||||
|
||||
case beam-space-compression {
|
||||
description "Beamspace compression and decompression is supported. Applies to beamforming weights only.";
|
||||
leaf-list active-beam-space-coeficient-mask {
|
||||
type uint8;
|
||||
description
|
||||
"active beamspace coefficient indices associated with the compressed beamforming vector";
|
||||
}
|
||||
leaf block-scaler {
|
||||
type uint8;
|
||||
description
|
||||
"Common scaler for compressed beamforming coefficients";
|
||||
}
|
||||
}
|
||||
|
||||
case modulation-compression {
|
||||
description "Modulation compression and decompression is supported.";
|
||||
leaf csf {
|
||||
type uint8 {
|
||||
range "0..1";
|
||||
}
|
||||
description "Constallation shift flag";
|
||||
}
|
||||
|
||||
leaf mod-comp-scaler {
|
||||
type uint16 {
|
||||
range "0..32767";
|
||||
}
|
||||
description "Modulation compression scaler value.";
|
||||
}
|
||||
}
|
||||
|
||||
case modulation-compression-selective-re-sending {
|
||||
description "Modulation compression with selective re sending and decompression is supported.";
|
||||
leaf sres-csf {
|
||||
type uint8 {
|
||||
range "0..1";
|
||||
}
|
||||
description "Constallation shift flag";
|
||||
}
|
||||
|
||||
leaf sres-mod-comp-scaler {
|
||||
type uint16 {
|
||||
range "0..32767";
|
||||
}
|
||||
description "Modulation compression scaler value.";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
grouping compression-params {
|
||||
description
|
||||
"Parameters to define compression";
|
||||
|
||||
leaf compression-type {
|
||||
type enumeration {
|
||||
enum STATIC {
|
||||
description
|
||||
"Indicates that static compression method will be used (both compression and IQ bitwidth)";
|
||||
}
|
||||
enum DYNAMIC {
|
||||
description
|
||||
"Indicates that dynamic compression method will be used";
|
||||
}
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"Compression type that O-DU wants to be supported";
|
||||
}
|
||||
|
||||
// *********** TO BE REMOVED ***********
|
||||
leaf bitwidth {
|
||||
when "../compression-type = 'STATIC'";
|
||||
type uint8;
|
||||
status deprecated;
|
||||
description
|
||||
"Bitwidth to be used in compression.
|
||||
This has since been replaced in M-Plane version
|
||||
2.0.0 with the iq-bitwidth schema node";
|
||||
}
|
||||
// *************************************
|
||||
|
||||
uses compression-formats;
|
||||
}
|
||||
|
||||
grouping compression-parameters {
|
||||
description
|
||||
"Parameters used to define description type";
|
||||
|
||||
leaf iq-bitwidth {
|
||||
type uint8;
|
||||
description
|
||||
"Bitwidth to be used in compression";
|
||||
}
|
||||
|
||||
uses compression-formats;
|
||||
}
|
||||
|
||||
grouping format-of-iq-sample {
|
||||
description
|
||||
"Indicates module capabilities about IQ samples";
|
||||
|
||||
leaf dynamic-compression-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if radio supports dynamic compression method";
|
||||
}
|
||||
|
||||
leaf realtime-variable-bit-width-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if O-RU supports realtime variable bit with";
|
||||
}
|
||||
|
||||
list compression-method-supported {
|
||||
uses compression-parameters;
|
||||
|
||||
description
|
||||
"List of supported compression methods by O-RU
|
||||
Note: if O-RU supports different compression methods per endpoint
|
||||
then please refer do endpoints to have information what
|
||||
exactly is supported on a paticular endpoint";
|
||||
}
|
||||
|
||||
leaf syminc-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if symbol number increment command in a C-Plane is
|
||||
supported or not";
|
||||
}
|
||||
|
||||
leaf regularization-factor-se-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if regularizationFactor in section type 5 is
|
||||
supported(true) or not(false)";
|
||||
}
|
||||
|
||||
leaf little-endian-supported {
|
||||
type boolean;
|
||||
default false;
|
||||
|
||||
description
|
||||
"All O-RUs support bigendian byte order. This node informs if module supports the
|
||||
the optional capability for little endian byte order for C/U plane data flows.
|
||||
|
||||
Note - little endian support does not invalidate bigendian support.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
grouping compression-details {
|
||||
description "";
|
||||
|
||||
leaf iq-bitwidth {
|
||||
type uint8;
|
||||
description
|
||||
"Bitwidth to be used in compression";
|
||||
}
|
||||
|
||||
uses compression-params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
module o-ran-interfaces {
|
||||
yang-version 1.1;
|
||||
namespace "urn:o-ran:interfaces:1.0";
|
||||
prefix "o-ran-int";
|
||||
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix "inet";
|
||||
}
|
||||
|
||||
import iana-if-type {
|
||||
prefix "ianaift";
|
||||
}
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix "if";
|
||||
}
|
||||
|
||||
import ietf-ip {
|
||||
prefix "ip";
|
||||
}
|
||||
|
||||
import ietf-hardware {
|
||||
prefix "hw";
|
||||
}
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix "yang";
|
||||
}
|
||||
|
||||
import iana-hardware {
|
||||
prefix "ianahw";
|
||||
}
|
||||
|
||||
organization "O-RAN Alliance";
|
||||
|
||||
contact
|
||||
"www.o-ran.org";
|
||||
|
||||
description
|
||||
"This module defines the YANG definitions for managng the O-RAN
|
||||
interfaces.
|
||||
|
||||
Copyright 2020 the O-RAN Alliance.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the above disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the above disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the Members of the O-RAN Alliance nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.";
|
||||
|
||||
revision "2020-04-17" {
|
||||
description
|
||||
"version 1.2.0
|
||||
|
||||
1) updated descriptions to clarify operation when vlan-tagging is false";
|
||||
|
||||
reference "ORAN-WG4.M.0-v03.00";
|
||||
}
|
||||
revision "2019-07-03" {
|
||||
description
|
||||
"version 1.1.0
|
||||
|
||||
1) increasing max elements for user plane DSCP markings to 64
|
||||
2) re-organizing layout to facilitate cross-WG adoption, whilst ensuring
|
||||
nodes are syntactically and semantically equivalent";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
revision "2019-02-04" {
|
||||
description
|
||||
"version 1.0.0
|
||||
|
||||
1) imported model from xRAN
|
||||
2) changed namespace and reference from xran to o-ran";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
feature UDPIP-BASED-CU-PLANE {
|
||||
description
|
||||
"This feature indicates that the RU supports the UDP/IP based transport
|
||||
for the CU plane.";
|
||||
}
|
||||
|
||||
feature ALIASMAC-BASED-CU-PLANE {
|
||||
description
|
||||
"This feature indicates that the RU supports the alias MAC address
|
||||
based transport for the CU plane.";
|
||||
}
|
||||
|
||||
|
||||
typedef pcp {
|
||||
type uint8 {
|
||||
range "0..7";
|
||||
}
|
||||
description
|
||||
"Priority Code Point. PCP is a 3-bit field that refers to the
|
||||
class of service applied to a VLAN tagged frame. The
|
||||
field specifies a priority value between 0 and 7, these values
|
||||
can be used by quality of service (QoS) to prioritize
|
||||
different classes of traffic.";
|
||||
reference
|
||||
"IEEE 802.1Q-2014: Virtual Bridged Local Area Networks";
|
||||
}
|
||||
|
||||
grouping cos-marking {
|
||||
description
|
||||
"Configuration data for CU Plane ethernet CoS marking.
|
||||
This grouping is only applicable to an interface when vlan-tagging is
|
||||
set to TRUE for that interface. In other cases, it may be ignored.";
|
||||
container class-of-service {
|
||||
description
|
||||
"CoS Configuration";
|
||||
leaf u-plane-marking {
|
||||
type pcp;
|
||||
default 7;
|
||||
description
|
||||
"Marking used for default u-plane flows.
|
||||
7 represents highest priority for u-plane marking";
|
||||
}
|
||||
leaf c-plane-marking {
|
||||
type pcp;
|
||||
default 7;
|
||||
description "7 represents highest priority for c-plane marking";
|
||||
}
|
||||
leaf m-plane-marking {
|
||||
type pcp;
|
||||
default 2;
|
||||
description "2 represents highest excellent effort for m-plane marking";
|
||||
}
|
||||
leaf s-plane-marking {
|
||||
type pcp;
|
||||
default 7;
|
||||
description "7 represents highest priority for s-plane marking";
|
||||
}
|
||||
leaf other-marking {
|
||||
type pcp;
|
||||
default 1;
|
||||
description "1 represents best effort for other marking";
|
||||
}
|
||||
list enhanced-uplane-markings{
|
||||
key "up-marking-name";
|
||||
max-elements 4;
|
||||
description
|
||||
"list of mappings for enhanced (non-default) u-plane markings";
|
||||
leaf up-marking-name {
|
||||
type string;
|
||||
description "The name of the marking";
|
||||
}
|
||||
leaf enhanced-marking {
|
||||
type pcp;
|
||||
description "the enhanced u-plane marking";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping dscp-marking {
|
||||
description
|
||||
"Configuration data for CU Plane DSCP marking";
|
||||
container diffserv-markings {
|
||||
description
|
||||
"DSCP Configuration";
|
||||
leaf u-plane-marking {
|
||||
type inet:dscp;
|
||||
default 46;
|
||||
description
|
||||
"Marking used for default u-plane flows.
|
||||
46 represents expedited forwarding";
|
||||
}
|
||||
leaf c-plane-marking {
|
||||
type inet:dscp;
|
||||
default 46;
|
||||
description "46 represents expedited forwarding";
|
||||
}
|
||||
leaf s-plane-marking {
|
||||
type inet:dscp;
|
||||
default 46;
|
||||
description "46 represents expedited forwarding";
|
||||
}
|
||||
leaf other-marking {
|
||||
type inet:dscp;
|
||||
default 0;
|
||||
description "0 represents best effort forwarding";
|
||||
}
|
||||
list enhanced-uplane-markings{
|
||||
key up-marking-name;
|
||||
max-elements 64;
|
||||
description
|
||||
"list of mappings for enhanced (non-default) u-plane markings";
|
||||
leaf up-marking-name {
|
||||
type string;
|
||||
description "The name of the marking";
|
||||
}
|
||||
leaf enhanced-marking {
|
||||
type inet:dscp;
|
||||
description "the enhanced u-plane marking";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cross Working Group Augmentations Follow
|
||||
|
||||
// Cross Working Group augmentations for basic Ethernet leafs
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "if:type = 'ianaift:ethernetCsmacd'" {
|
||||
description "Applies to Ethernet interfaces";
|
||||
}
|
||||
description
|
||||
"Augment the interface model with parameters for
|
||||
base Ethernet interface";
|
||||
|
||||
leaf l2-mtu {
|
||||
type uint16 {
|
||||
range "64 .. 65535";
|
||||
}
|
||||
units bytes;
|
||||
default 1500;
|
||||
description
|
||||
"The maximum size of layer 2 frames that may be transmitted
|
||||
or received on the interface (excluding any FCS overhead).
|
||||
For Ethernet interfaces it also excludes the
|
||||
4-8 byte overhead of any known (i.e. explicitly matched by
|
||||
a child sub-interface) 801.1Q VLAN tags.";
|
||||
}
|
||||
leaf vlan-tagging {
|
||||
type boolean;
|
||||
default true;
|
||||
description
|
||||
"Indicates if VLAN tagging is used.
|
||||
Default true is used to enable equipment to autonomously discover that
|
||||
it is connected to a trunk port.
|
||||
|
||||
This may be set to false, for example, when the O-RU is directly
|
||||
connected to the O-DU. In such cases, native Ethernet frames may be
|
||||
used across the O-RAN interface, i.e., any PCP markings defined
|
||||
in the cos-markings grouping are NOT used by the O-RU and any default
|
||||
value or configured value using those leafs may be ignored by the O-RAN
|
||||
equipment.";
|
||||
}
|
||||
uses cos-marking;
|
||||
}
|
||||
|
||||
// Cross Working Group augmentation for l2vlan interfaces for VLAN definition
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "if:type = 'ianaift:l2vlan'";
|
||||
description "augments for VLAN definition";
|
||||
leaf base-interface {
|
||||
type if:interface-ref;
|
||||
must "/if:interfaces/if:interface[if:name = current()]"
|
||||
+ "/o-ran-int:vlan-tagging = 'true'" {
|
||||
description
|
||||
"The base interface must have VLAN tagging enabled.";
|
||||
}
|
||||
description
|
||||
"The base interface for the VLAN sub-interafce.";
|
||||
}
|
||||
leaf vlan-id {
|
||||
type uint16 {
|
||||
range "1..4094";
|
||||
}
|
||||
description
|
||||
"The VLAN-ID.";
|
||||
}
|
||||
}
|
||||
|
||||
// Cross Working Group augmention for both ethernetCsmacd and l2vlan interfaces
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "(if:type = 'ianaift:ethernetCsmacd') or
|
||||
(if:type = 'ianaift:l2vlan')" {
|
||||
description "Applies to ethernetCsmacd and l2vlan interfaces";
|
||||
}
|
||||
description
|
||||
"Augment the interface model with parameters for all
|
||||
both ethernetCsmacd and l2vlan interfaces.";
|
||||
leaf last-cleared {
|
||||
type yang:date-and-time;
|
||||
config false;
|
||||
description
|
||||
"Timestamp of the last time the interface counters were
|
||||
cleared.";
|
||||
}
|
||||
}
|
||||
|
||||
// Cross Working Group augmention to ietf-ip covering DSCP for M-Plane
|
||||
|
||||
augment "/if:interfaces/if:interface/ip:ipv4" {
|
||||
description "augments for IPv4 based M-Plane transport";
|
||||
leaf m-plane-marking {
|
||||
type inet:dscp;
|
||||
default 18;
|
||||
description "18 represents AF21 or 'immediate traffic'";
|
||||
}
|
||||
}
|
||||
augment "/if:interfaces/if:interface/ip:ipv6" {
|
||||
description "augments for IPv6 based M-Plane transport";
|
||||
leaf m-plane-marking {
|
||||
type inet:dscp;
|
||||
default 18;
|
||||
description "18 represents AF21 or 'immediate traffic'";
|
||||
}
|
||||
}
|
||||
|
||||
// WG4 Specific Augmentations Follow
|
||||
|
||||
// WG4 Augmentation for basic Ethernet leafs
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
if-feature ALIASMAC-BASED-CU-PLANE;
|
||||
when "if:type = 'ianaift:ethernetCsmacd'" {
|
||||
description
|
||||
"Applies to WG4 Ethernet interfaces for alias MAC based CU-Plane";
|
||||
}
|
||||
description
|
||||
"Augment the interface model with parameters for
|
||||
base Ethernet interface";
|
||||
|
||||
leaf-list alias-macs {
|
||||
type yang:mac-address;
|
||||
description
|
||||
"Augments interfaces with range of alias MAC addresses.";
|
||||
}
|
||||
}
|
||||
|
||||
// WG4 Augmention for both ethernetCsmacd and l2vlan interfaces
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "(if:type = 'ianaift:ethernetCsmacd') or
|
||||
(if:type = 'ianaift:l2vlan')" {
|
||||
description "Applies to ethernetCsmacd and l2vlan interfaces";
|
||||
}
|
||||
description
|
||||
"Augment the interface model with parameters for all
|
||||
both ethernetCsmacd and l2vlan interfaces.";
|
||||
leaf mac-address {
|
||||
type yang:mac-address;
|
||||
description
|
||||
"The MAC address of the interface.";
|
||||
}
|
||||
container port-reference {
|
||||
description
|
||||
"a port reference used by other O-RAN modules";
|
||||
leaf port-name {
|
||||
type leafref {
|
||||
path '/hw:hardware/hw:component/hw:name';
|
||||
}
|
||||
must "derived-from-or-self(deref(current())/../hw:class, 'ianahw:port')";
|
||||
// TAKE NOTE - depending on version of pyang, this may generate various
|
||||
// warnings, e.g., warning: XPath for "port-name" does not exist
|
||||
description
|
||||
"O-RAN interfaces use a reference to a physical port component.
|
||||
|
||||
In this case, the component name referenced must be of class type
|
||||
port, i.e., when /hw:hardware/hw:component/hw:class is derived from
|
||||
ianahw:port";
|
||||
}
|
||||
leaf port-number {
|
||||
type uint8;
|
||||
description
|
||||
"A number allocated by the server which identifies a port.
|
||||
Port number value is 0 to N-1 where N is number of ports
|
||||
in the device.
|
||||
|
||||
This value is fixed for the lifetime of the equipment, i.e., cannot be
|
||||
changed during equipment reboots.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WG4 specific augmention to ietf-ip covering DSCP for CUS Plane
|
||||
|
||||
augment "/if:interfaces/if:interface/ip:ipv4" {
|
||||
if-feature UDPIP-BASED-CU-PLANE;
|
||||
description "augments for IPv4 based CUS transport";
|
||||
uses dscp-marking;
|
||||
}
|
||||
augment "/if:interfaces/if:interface/ip:ipv6" {
|
||||
if-feature UDPIP-BASED-CU-PLANE;
|
||||
description "augments for IPv6 based CUS transport";
|
||||
uses dscp-marking;
|
||||
}
|
||||
|
||||
// Other Working Group Specific Augmentations Follow Here
|
||||
|
||||
|
||||
rpc reset-interface-counters {
|
||||
description
|
||||
"Management plane triggered restart of the interface counters.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,840 @@
|
||||
module o-ran-module-cap {
|
||||
yang-version 1.1;
|
||||
namespace "urn:o-ran:module-cap:1.0";
|
||||
prefix "o-ran-module-cap";
|
||||
|
||||
import o-ran-compression-factors {
|
||||
prefix "cf";
|
||||
revision-date 2020-08-10;
|
||||
}
|
||||
|
||||
organization "O-RAN Alliance";
|
||||
|
||||
contact
|
||||
"www.o-ran.org";
|
||||
|
||||
description
|
||||
"This module defines the module capabilities for
|
||||
the O-RAN Radio Unit.
|
||||
|
||||
Copyright 2020 the O-RAN Alliance.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the above disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the above disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the Members of the O-RAN Alliance nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.";
|
||||
|
||||
revision "2020-08-10" {
|
||||
description
|
||||
"version 4.0.0
|
||||
|
||||
1) added RO capability to expose O-RU's ability to support udCompLen record in U-Plane section header fields
|
||||
2) feature indicating support for static PRACH configuration introduced
|
||||
3) feature indicating support for static SRS configuration introduced
|
||||
4) feature indicating support for TDD pattern configuration introduced
|
||||
5) backward compatible change to introduce new O-RU's features related
|
||||
to Section Description Priority to serve for CUS-Plane C";
|
||||
|
||||
reference "ORAN-WG4.M.0-v04.00";
|
||||
}
|
||||
|
||||
revision "2020-04-17" {
|
||||
description
|
||||
"version 3.0.0
|
||||
|
||||
1) Adding optional little endian support
|
||||
2) Added support for Dynamic Spectrum Sharing feature
|
||||
3) Enable number-of-ru-ports to be different between dl and ul
|
||||
4) Enable regularizationFactor to be signalled outside of section type 6
|
||||
5) Enable PRACH preamble formats supported to be signalled by O-RU
|
||||
6) adding support for selective RE sending
|
||||
7) supporting new section extension for grouping multiple ports
|
||||
8) signalling to enable O-RU to ndicate is requires unique ecpri sequence id
|
||||
for eAxC_IDs serving for UL and DL for the same carrier component";
|
||||
|
||||
reference "ORAN-WG4.M.0-v03.00";
|
||||
}
|
||||
|
||||
revision "2019-07-03" {
|
||||
description
|
||||
"version 1.1.0
|
||||
|
||||
1) backward compatible change to introduce new RW leafs for use in
|
||||
constraints in uplane-config and laa models.
|
||||
2) removing unnecessary relations to band 46 in uplink";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
revision "2019-02-04" {
|
||||
description
|
||||
"version 1.0.0
|
||||
|
||||
1) imported model from xRAN
|
||||
2) changed namespace and reference from xran to o-ran";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
feature LAA {
|
||||
description
|
||||
"Indicates that the Radio Unit supports LAA.";
|
||||
}
|
||||
|
||||
feature EAXC-ID-GROUP-SUPPORTED {
|
||||
description
|
||||
"indicates that the Radio Unit supports EAXC-ID-GROUP-SUPPORTED.";
|
||||
}
|
||||
|
||||
feature TRANSPORT-FRAGMENTATION {
|
||||
description
|
||||
"This leaf is used to indicate whether the O-RU supports O-RAN Radio Transport Fragmentation";
|
||||
}
|
||||
|
||||
feature DSS_LTE_NR {
|
||||
description
|
||||
"Indicates that the Radio Unit supports Dynamic Spectrum Sharing between LTE and NR.";
|
||||
}
|
||||
|
||||
feature PRACH-STATIC-CONFIGURATION-SUPPORTED {
|
||||
description
|
||||
"This leaf is used to indicate O-RU's support for configuration of PRACH (Physical Random Access Channel) pattern in the static manner, so that PRACH U-Plane traffic can be processed by RU without receiving C-Plane messages conveying the PRACH configuration.";
|
||||
}
|
||||
|
||||
feature SRS-STATIC-CONFIGURATION-SUPPORTED {
|
||||
description
|
||||
"This leaf is used to indicate O-RU's support for configuration of SRS (Sounding Reference Signal Channel) pattern in the static manner, so that SRS U-Plane traffic can be processed by RU without receiving C-Plane messages conveying the SRS configuration.";
|
||||
}
|
||||
|
||||
feature CONFIGURABLE-TDD-PATTERN-SUPPORTED {
|
||||
description
|
||||
"This leaf is used to indicate O-RU's support for configurable TDD pattern.";
|
||||
}
|
||||
|
||||
typedef sub-band-string {
|
||||
type string {
|
||||
pattern [ABCD];
|
||||
}
|
||||
description "Sub bands definition";
|
||||
}
|
||||
|
||||
typedef scs-config-type {
|
||||
type enumeration {
|
||||
enum KHZ_15 {
|
||||
value 0;
|
||||
description
|
||||
"15kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_30 {
|
||||
value 1;
|
||||
description
|
||||
"30kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_60 {
|
||||
value 2;
|
||||
description
|
||||
"60kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_120 {
|
||||
value 3;
|
||||
description
|
||||
"120kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_240 {
|
||||
value 4;
|
||||
description
|
||||
"240kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_1_25 {
|
||||
value 12;
|
||||
description
|
||||
"1,25kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_3_75 {
|
||||
value 13;
|
||||
description
|
||||
"3.75kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_5 {
|
||||
value 14;
|
||||
description
|
||||
"5kHz sub carrier spacing";
|
||||
}
|
||||
enum KHZ_7_5 {
|
||||
value 15;
|
||||
description
|
||||
"7.5kHz sub carrier spacing";
|
||||
}
|
||||
}
|
||||
|
||||
description
|
||||
"Scs configuration type definition";
|
||||
}
|
||||
|
||||
grouping compression-method-grouping {
|
||||
description
|
||||
"Grouping for compression method.";
|
||||
|
||||
leaf compression-method {
|
||||
type enumeration {
|
||||
enum BLOCK_FLOATING_POINT {
|
||||
description
|
||||
"Block floating point compression and decompression will be used";
|
||||
}
|
||||
|
||||
enum BLOCK_SCALING {
|
||||
description
|
||||
"Block scaling compression and decompresion will be used";
|
||||
}
|
||||
|
||||
enum U_LAW {
|
||||
description
|
||||
"u-Law compression and decompresion method will be used";
|
||||
}
|
||||
|
||||
enum BEAMSPACE {
|
||||
description
|
||||
"Beamspace compression and decompression will be used";
|
||||
}
|
||||
|
||||
enum MODULATION {
|
||||
description
|
||||
"Modulation compression and decompression will be used";
|
||||
}
|
||||
|
||||
enum BLOCK-FLOATING-POINT-SELECTIVE-RE-SENDING {
|
||||
description
|
||||
"block floating point with selective re sending
|
||||
compression and decompression will be used";
|
||||
}
|
||||
enum MODULATION-COMPRESSION-SELECTIVE-RE-SENDING {
|
||||
description
|
||||
"modulation compression with selective re sending
|
||||
compression and decompression will be used";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Compresion method which can be supported by the O-RU.
|
||||
An O-RU may further refine the applicability of compression
|
||||
methods per endpoint using o-ran-uplane-conf.yang model";
|
||||
}
|
||||
}
|
||||
|
||||
grouping sub-band-max-min-ul-dl-frequency {
|
||||
description
|
||||
"Grouping for defining max and min supported frequency - dl and ul.";
|
||||
|
||||
leaf max-supported-frequency-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum supported downlink frequency in the
|
||||
LAA subband. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf min-supported-frequency-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Minimum supported downlink frequency in the
|
||||
LAA subband. Value unit is Hz.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping format-of-iq-sample {
|
||||
description
|
||||
"Indicates module capabilities about IQ samples";
|
||||
|
||||
leaf dynamic-compression-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if radio supports dynamic compression method";
|
||||
}
|
||||
|
||||
leaf realtime-variable-bit-width-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if O-RU supports realtime variable bit with";
|
||||
}
|
||||
|
||||
list compression-method-supported {
|
||||
uses cf:compression-details;
|
||||
|
||||
leaf-list fs-offset {
|
||||
if-feature cf:CONFIGURABLE-FS-OFFSET;
|
||||
type uint8;
|
||||
default 0;
|
||||
description
|
||||
"List of fs offset values supported with this IQ format / compression method;
|
||||
fs-offset adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format.
|
||||
Please refer to CU-Plane specification for details";
|
||||
}
|
||||
|
||||
description
|
||||
"List of supported compression methods by O-RU
|
||||
Note: if O-RU supports different compression methods per endpoint
|
||||
then please refer to endpoints to have information what
|
||||
exactly is supported on paticular endpoint";
|
||||
}
|
||||
|
||||
leaf variable-bit-width-per-channel-supported {
|
||||
when "/module-capability/ru-capabilities/format-of-iq-sample/realtime-variable-bit-width-supported = 'true'";
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if variable bit width per channel is supported or not";
|
||||
}
|
||||
|
||||
leaf syminc-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if symbol number increment command in a C-Plane is
|
||||
supported or not";
|
||||
}
|
||||
|
||||
leaf regularization-factor-se-supported {
|
||||
type boolean;
|
||||
|
||||
description
|
||||
"Informs if regularizationFactor in section type 5 is
|
||||
supported(true) or not(false)";
|
||||
}
|
||||
|
||||
leaf little-endian-supported {
|
||||
type boolean;
|
||||
default false;
|
||||
|
||||
description
|
||||
"All O-RUs support bigendian byte order. This node informs if module supports the
|
||||
the optional capability for little endian byte order for C/U plane data flows.
|
||||
|
||||
Note - little endian support does not invalidate bigendian support.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
grouping scs-a-b {
|
||||
description
|
||||
"Grouping for scs-a and scs-b";
|
||||
leaf scs-a{
|
||||
type scs-config-type;
|
||||
description
|
||||
"Sub-carrier spacing configuration";
|
||||
}
|
||||
leaf scs-b{
|
||||
type scs-config-type;
|
||||
description
|
||||
"Sub-carrier spacing configuration";
|
||||
}
|
||||
}
|
||||
|
||||
grouping ul-mixed-num-required-guard-rbs {
|
||||
description
|
||||
"Required number of guard resource blocks for the combination of
|
||||
subcarrier spacing values for uplink";
|
||||
uses scs-a-b;
|
||||
leaf number-of-guard-rbs-ul{
|
||||
type uint8;
|
||||
description
|
||||
"This value indicates the required number of guard resource blocks
|
||||
between the mixed numerologies, the RB using scs-a and the RB
|
||||
using scs-b. It's number is based on scs-a";
|
||||
}
|
||||
}
|
||||
|
||||
grouping dl-mixed-num-required-guard-rbs {
|
||||
description
|
||||
"Required number of guard resource blocks for the combination of
|
||||
subcarrier spacing values for uplink";
|
||||
uses scs-a-b;
|
||||
leaf number-of-guard-rbs-dl{
|
||||
type uint8;
|
||||
description
|
||||
"This value indicates the required number of guard resource blocks
|
||||
between the mixed numerologies, the RB using scs-a and the RB
|
||||
using scs-b. It's number is based on scs-a";
|
||||
}
|
||||
}
|
||||
|
||||
grouping ru-capabilities {
|
||||
description
|
||||
"Structure representing set of capabilities.";
|
||||
|
||||
leaf ru-supported-category {
|
||||
type enumeration {
|
||||
enum CAT_A {
|
||||
description
|
||||
"Informs that precoding is not supported in O-RU";
|
||||
}
|
||||
enum CAT_B {
|
||||
description
|
||||
"Informs that precoding is supported in O-RU";
|
||||
}
|
||||
}
|
||||
|
||||
description
|
||||
"Informs about which category O-RU supports";
|
||||
}
|
||||
|
||||
leaf number-of-ru-ports {
|
||||
type uint8;
|
||||
status deprecated;
|
||||
description
|
||||
"Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration)
|
||||
- the number of O-RU ports is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports.
|
||||
For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when PUSCH and PRACH are processed in the different endpoints.
|
||||
In case there are specific endpoints that support non-time-managed traffic only
|
||||
- the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic.";
|
||||
}
|
||||
leaf number-of-ru-ports-ul {
|
||||
type uint8;
|
||||
description
|
||||
"Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration)
|
||||
- the number of O-RU ports for uplink is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports.
|
||||
For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when PUSCH and PRACH are processed in the different endpoints.
|
||||
In case there are specific endpoints that support non-time-managed traffic only
|
||||
- the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic.";
|
||||
}
|
||||
leaf number-of-ru-ports-dl {
|
||||
type uint8;
|
||||
description
|
||||
"Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration)
|
||||
- the number of O-RU ports for downlink is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports.
|
||||
For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when SSB and non-SSB are processed in the different endpoints.
|
||||
In case there are specific endpoints that support non-time-managed traffic only
|
||||
- the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic.";
|
||||
}
|
||||
|
||||
leaf number-of-spatial-streams {
|
||||
type uint8;
|
||||
description
|
||||
"This value indicates the number of spatial streams supported at O-RU for DL and UL.
|
||||
For DL, it is same as the number of antenna ports specified in 3GPP TS38.214, Section 5.2 and 3GPP TS36.213, Section 5.2.";
|
||||
}
|
||||
|
||||
leaf max-power-per-pa-antenna {
|
||||
type decimal64{
|
||||
fraction-digits 4;
|
||||
}
|
||||
description
|
||||
"This value indicates Maximum Power per PA per antenna. Value unit is dBm.";
|
||||
}
|
||||
|
||||
leaf min-power-per-pa-antenna {
|
||||
type decimal64{
|
||||
fraction-digits 4;
|
||||
}
|
||||
description
|
||||
"This value indicates Minimum Power per PA per antenna. Value unit is dBm.";
|
||||
}
|
||||
|
||||
leaf fronthaul-split-option {
|
||||
type uint8 {
|
||||
range "7";
|
||||
}
|
||||
description
|
||||
"This value indicates the Fronthaul Split Option, i.e., 2 or 7 in this release.";
|
||||
}
|
||||
|
||||
container format-of-iq-sample {
|
||||
description
|
||||
"Indicates module capabilities about IQ samples";
|
||||
|
||||
uses format-of-iq-sample;
|
||||
}
|
||||
|
||||
list ul-mixed-num-required-guard-rbs {
|
||||
key "scs-a scs-b";
|
||||
description
|
||||
"List of required number of guard resource blocks
|
||||
for the combination of subcarrier spacing values for downlink";
|
||||
|
||||
uses ul-mixed-num-required-guard-rbs;
|
||||
}
|
||||
list dl-mixed-num-required-guard-rbs {
|
||||
key "scs-a scs-b";
|
||||
description
|
||||
"List of required number of guard resource blocks
|
||||
for the combination of subcarrier spacing values for uplink";
|
||||
|
||||
uses dl-mixed-num-required-guard-rbs;
|
||||
}
|
||||
|
||||
leaf energy-saving-by-transmission-blanks {
|
||||
type boolean;
|
||||
mandatory true;
|
||||
description
|
||||
"Parameter informs if unit supports energy saving by transmission blanking";
|
||||
}
|
||||
container eaxcid-grouping-capabilities {
|
||||
if-feature o-ran-module-cap:EAXC-ID-GROUP-SUPPORTED;
|
||||
description
|
||||
"a container with parameters for eaxcid grouping";
|
||||
leaf max-num-tx-eaxc-id-groups {
|
||||
type uint8;
|
||||
description
|
||||
"Maximum number of configurable tx-eaxc-id-group supported by O-RU.";
|
||||
}
|
||||
leaf max-num-tx-eaxc-ids-per-group {
|
||||
type uint8;
|
||||
description
|
||||
"Maximum number of member-tx-eaxc-id in single tx-eaxc-id-group supported by O-RU.";
|
||||
}
|
||||
leaf max-num-rx-eaxc-id-groups {
|
||||
type uint8;
|
||||
description
|
||||
"the maximum number of groups with the eAxC IDs those are assigned to low-level-rx-links.";
|
||||
}
|
||||
leaf max-num-rx-eaxc-ids-per-group {
|
||||
type uint8;
|
||||
description
|
||||
"the maximum number of eAxC IDs per rx-eaxc-id-group.";
|
||||
}
|
||||
}
|
||||
|
||||
leaf dynamic-transport-delay-management-supported {
|
||||
type boolean;
|
||||
mandatory true;
|
||||
description
|
||||
"Parameter informs if unit supports dynamic transport delay management through eCPRI Msg 5";
|
||||
}
|
||||
|
||||
leaf support-only-unique-ecpri-seqid-per-eaxc {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Parameter informs if O-RU expects unique ecpri sequence id for eAxC_IDs serving
|
||||
for UL and DL for the same carrier component.
|
||||
|
||||
Note: If this is set to TRUE, the O-DU can decide to either use different eAxC_IDs for UL and
|
||||
DL or can generate unique sequence ID per eAxC_ID.
|
||||
|
||||
TAKE NOTE: This leaf is backwards compatible from an O-RU persepctive BUT an O-RU that
|
||||
sets this leaf to TRUE may result in incompatibilities when operating with an O-DU
|
||||
designed according to the O-RAN CUS-Plane Specification v02.00, e.g., if the O-DU is
|
||||
incapable of using different eAxC values between UL and DL";
|
||||
}
|
||||
|
||||
container coupling-methods {
|
||||
description
|
||||
"O-RU's capabilities related to supported C-Plane and U-Plane coupling methods";
|
||||
|
||||
leaf coupling-via-frequency-and-time {
|
||||
type boolean;
|
||||
description
|
||||
"Coupling via frequency and time; see methods of coupling of C-plane and U-plane in CUS-Plane specification";
|
||||
}
|
||||
|
||||
leaf coupling-via-frequency-and-time-with-priorities {
|
||||
type boolean;
|
||||
description
|
||||
"Coupling via Frequency and time with priorities; see methods of coupling of C-plane and U-plane in CUS-Plane specification.
|
||||
Note: If coupling-via-frequency-and-time-with-priorities is 'true' then coupling-via-frequency-and-time shall also be 'true'.";
|
||||
}
|
||||
}
|
||||
|
||||
leaf ud-comp-len-supported {
|
||||
type boolean;
|
||||
description
|
||||
"This property informs if O-RU supports optional field udCompLen in U-Plane messages.
|
||||
Only in case this leaf is present and its value is TRUE, O-RU supports U-Plane messages
|
||||
containing udCompLen field in section header.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping sub-band-info {
|
||||
description "container for collection of leafs for LAA subband 46";
|
||||
list sub-band-frequency-ranges {
|
||||
key sub-band;
|
||||
description "frequency information on a per sub-band basis";
|
||||
leaf sub-band {
|
||||
type sub-band-string;
|
||||
description "Sub band when band 46";
|
||||
}
|
||||
uses sub-band-max-min-ul-dl-frequency;
|
||||
}
|
||||
leaf number-of-laa-scarriers {
|
||||
type uint8;
|
||||
description
|
||||
"This value indicates the number of LAA secondary carriers supported at O-RU.";
|
||||
}
|
||||
|
||||
leaf maximum-laa-buffer-size {
|
||||
type uint16;
|
||||
description
|
||||
"Maximum O-RU buffer size in Kilobytes (KB) per CC. This parameter is
|
||||
needed at the O-DU to know how much data can be sent in advance
|
||||
and stored at the O-RU to address the LBT uncertainity.";
|
||||
}
|
||||
|
||||
leaf maximum-processing-time {
|
||||
type uint16;
|
||||
units microseconds;
|
||||
description
|
||||
"Maximum O-RU Processing time in microseconds at the O-RU to handle the
|
||||
received/transmitted packets from/to the O-DU. This parameter is
|
||||
needed at the O-DU to determine the time where it needs to send
|
||||
the data to the O-RU.";
|
||||
}
|
||||
|
||||
leaf self-configure {
|
||||
type boolean;
|
||||
description "This value indicates that the O-RU can manage the contention window locally. ";
|
||||
}
|
||||
}
|
||||
|
||||
grouping support-for-dl {
|
||||
description
|
||||
"Grouping for DL specific parameters";
|
||||
|
||||
leaf max-supported-frequency-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum supported downlink frequency. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf min-supported-frequency-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Minimum supported downlink frequency. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf max-supported-bandwidth-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum total downlink bandwidth in module. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf max-num-carriers-dl {
|
||||
type uint32;
|
||||
description
|
||||
"This value indicates Maximum number of downlink carriers in module.";
|
||||
}
|
||||
|
||||
leaf max-carrier-bandwidth-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum bandwidth per downlink carrier. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf min-carrier-bandwidth-dl {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Minimum bandwidth per downlink carrier. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf-list supported-technology-dl {
|
||||
type enumeration{
|
||||
enum LTE {
|
||||
description "LTE is supported in DL path.";
|
||||
}
|
||||
enum NR {
|
||||
description "NR is supported in DL path.";
|
||||
}
|
||||
enum DSS_LTE_NR {
|
||||
if-feature DSS_LTE_NR;
|
||||
description
|
||||
"DSS is supported in the DL, which implicitly means LTE and NR are also
|
||||
BOTH supported in the DL.";
|
||||
}
|
||||
}
|
||||
min-elements 1;
|
||||
description
|
||||
"This list provides information regarding technologies supported in DL path";
|
||||
}
|
||||
}
|
||||
|
||||
grouping support-for-ul {
|
||||
description
|
||||
"Grouping for UL specific parameters";
|
||||
|
||||
leaf max-supported-frequency-ul {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum supported uplink frequency. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf min-supported-frequency-ul {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Minimum supported uplink frequency. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf max-supported-bandwidth-ul {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum total uplink bandwidth in module. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf max-num-carriers-ul {
|
||||
type uint32;
|
||||
description
|
||||
"This value indicates Maximum number of uplink carriers in module.";
|
||||
}
|
||||
|
||||
leaf max-carrier-bandwidth-ul {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Maximum bandwidth per uplink carrier. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf min-carrier-bandwidth-ul {
|
||||
type uint64;
|
||||
description
|
||||
"This value indicates Minimum bandwidth per uplink carrier. Value unit is Hz.";
|
||||
}
|
||||
|
||||
leaf-list supported-technology-ul {
|
||||
type enumeration{
|
||||
enum LTE {
|
||||
description "LTE is supported in UL path.";
|
||||
}
|
||||
enum NR {
|
||||
description "NR is supported in UL path.";
|
||||
}
|
||||
enum DSS_LTE_NR {
|
||||
if-feature DSS_LTE_NR;
|
||||
description
|
||||
"DSS is supported in the UL, which implicitly means LTE and NR are also
|
||||
BOTH supported in the UL.";
|
||||
}
|
||||
}
|
||||
min-elements 1;
|
||||
description
|
||||
"This list provides information regarding technologies supported in UL path";
|
||||
}
|
||||
}
|
||||
|
||||
grouping band-capabilities {
|
||||
description
|
||||
"Capabilities that are needed to be defined per each band";
|
||||
|
||||
leaf band-number {
|
||||
type uint16;
|
||||
description
|
||||
"Band number";
|
||||
}
|
||||
|
||||
container sub-band-info {
|
||||
when "../band-number = '46'";
|
||||
if-feature "o-ran-module-cap:LAA";
|
||||
description "container for collection of leafs for LAA subband 46";
|
||||
uses sub-band-info;
|
||||
}
|
||||
|
||||
uses support-for-dl;
|
||||
uses support-for-ul;
|
||||
|
||||
leaf max-num-component-carriers {
|
||||
type uint8;
|
||||
description "maximum number of component carriers supported by the O-RU";
|
||||
}
|
||||
|
||||
leaf max-num-bands {
|
||||
type uint16;
|
||||
description "maximum number of bands supported by the O-RU";
|
||||
}
|
||||
|
||||
leaf max-num-sectors {
|
||||
type uint8;
|
||||
description "maximum number of sectors supported by the O-RU";
|
||||
}
|
||||
|
||||
leaf max-power-per-antenna {
|
||||
type decimal64{
|
||||
fraction-digits 4;
|
||||
}
|
||||
description
|
||||
"This value indicates Maximum Power per band per antenna. Value unit is dBm.";
|
||||
}
|
||||
|
||||
leaf min-power-per-antenna {
|
||||
type decimal64{
|
||||
fraction-digits 4;
|
||||
}
|
||||
description
|
||||
"This value indicates Minimum Power per band per antenna. Value unit is dBm.";
|
||||
}
|
||||
|
||||
leaf codebook-configuration_ng {
|
||||
type uint8;
|
||||
description
|
||||
"This parameter informs the precoder codebook_ng that are used for precoding";
|
||||
}
|
||||
|
||||
leaf codebook-configuration_n1 {
|
||||
type uint8;
|
||||
description
|
||||
"This parameter informs the precoder codebook_n1 that are used for precoding";
|
||||
}
|
||||
|
||||
leaf codebook-configuration_n2 {
|
||||
type uint8;
|
||||
description
|
||||
"This parameter informs the precoder codebook_n2 that are used for precoding";
|
||||
}
|
||||
}
|
||||
|
||||
container module-capability {
|
||||
|
||||
description
|
||||
"module capability object responsible for providing module capability.";
|
||||
|
||||
container ru-capabilities {
|
||||
config false;
|
||||
description
|
||||
"Structure representing set of capabilities.";
|
||||
|
||||
uses ru-capabilities;
|
||||
}
|
||||
|
||||
list band-capabilities {
|
||||
key band-number;
|
||||
config false;
|
||||
description
|
||||
"Capabilities that are needed to be defined per each band";
|
||||
|
||||
uses band-capabilities;
|
||||
}
|
||||
container rw-sub-band-info {
|
||||
if-feature "o-ran-module-cap:LAA";
|
||||
description "config true leafrefs for use as constraints for config true leafs";
|
||||
leaf rw-number-of-laa-scarriers {
|
||||
type leafref {
|
||||
path "/module-capability/band-capabilities/sub-band-info/number-of-laa-scarriers";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This value indicates the number of LAA secondary carriers supported at O-RU.";
|
||||
}
|
||||
leaf rw-self-configure {
|
||||
type leafref {
|
||||
path "/module-capability/band-capabilities/sub-band-info/self-configure";
|
||||
require-instance false;
|
||||
}
|
||||
description
|
||||
"This value indicates that the O-RU can manage the contention window locally.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
module o-ran-processing-element {
|
||||
yang-version 1.1;
|
||||
namespace "urn:o-ran:processing-element:1.0";
|
||||
prefix "o-ran-elements";
|
||||
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix "inet";
|
||||
}
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix "if";
|
||||
}
|
||||
|
||||
import ietf-ip {
|
||||
prefix "ip";
|
||||
}
|
||||
|
||||
import o-ran-interfaces {
|
||||
prefix "o-ran-int";
|
||||
}
|
||||
|
||||
organization "O-RAN Alliance";
|
||||
|
||||
contact
|
||||
"www.o-ran.org";
|
||||
|
||||
description
|
||||
"This module defines the YANG definitions for mapping of transport flows to
|
||||
processing elements. Three options are supported:
|
||||
i) virtual MAC based mapping
|
||||
ii) MAC addrress + VLAN-ID based mapping
|
||||
iii) UDP/IP based mapping
|
||||
|
||||
Copyright 2020 the O-RAN Alliance.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the above disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the above disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the Members of the O-RAN Alliance nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.";
|
||||
|
||||
revision "2020-04-17" {
|
||||
description
|
||||
"version 3.0.0
|
||||
|
||||
1) added new enum SHARED-CELL-ETH-INTERFACE in
|
||||
transport-session-type and new containers north-eth-flow and
|
||||
south-eth-flow to enable Shared cell scenario.";
|
||||
|
||||
reference "ORAN-WG4.M.0-v03.00";
|
||||
}
|
||||
|
||||
revision "2019-07-03" {
|
||||
description
|
||||
"version 1.1.0
|
||||
|
||||
1) added new leaf to enable O-RU to report the maximum number of
|
||||
transport flows it can support, e.g., due to restrictions on number
|
||||
of VLAN-IDs when ethernet type transport is used.";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
revision "2019-02-04" {
|
||||
description
|
||||
"version 1.0.0
|
||||
|
||||
1) imported model from xRAN
|
||||
2) changed namespace and reference from xran to o-ran";
|
||||
|
||||
reference "ORAN-WG4.M.0-v01.00";
|
||||
}
|
||||
|
||||
feature SHARED_CELL {
|
||||
description
|
||||
"Presence of feature indicates that this O-RU is capable to support
|
||||
shared cell.";
|
||||
}
|
||||
// groupings
|
||||
|
||||
grouping pe-group {
|
||||
leaf maximum-number-of-transport-flows {
|
||||
type uint16 {
|
||||
range "1..4094";
|
||||
}
|
||||
config false;
|
||||
default 4094;
|
||||
description
|
||||
"The maximum number of transport flows that can be supported by an O-RU";
|
||||
}
|
||||
leaf transport-session-type {
|
||||
type enumeration {
|
||||
enum ETH-INTERFACE {
|
||||
description "VLAN based CUS Transport ";
|
||||
}
|
||||
enum UDPIP-INTERFACE {
|
||||
description "UDP/IP based CUS Transport ";
|
||||
}
|
||||
enum ALIASMAC-INTERFACE{
|
||||
description "Alias MAC address based CUS Transport ";
|
||||
}
|
||||
enum SHARED-CELL-ETH-INTERFACE {
|
||||
if-feature "SHARED_CELL";
|
||||
description "VLAN based CUS Transport used for Shared Cell scenario";
|
||||
}
|
||||
}
|
||||
default ETH-INTERFACE;
|
||||
description
|
||||
"the type of transport session used for identifying different processing
|
||||
elements";
|
||||
}
|
||||
container enhanced-uplane-mapping {
|
||||
presence "indicates that enhanced uplane mapping is used";
|
||||
description "a mapping table for enhanced user plane marking";
|
||||
list uplane-mapping {
|
||||
key "up-marking-name";
|
||||
description
|
||||
"a mapping between up-link name and o-ran-interfaces:up-marking-name";
|
||||
leaf up-marking-name {
|
||||
type string;
|
||||
description "a unique up marking name that is used for enhanced up marking";
|
||||
}
|
||||
choice up-markings {
|
||||
description
|
||||
"U-Plane markings";
|
||||
case ethernet {
|
||||
when "(../../transport-session-type = 'ALIASMAC-INTERFACE') or
|
||||
(../../transport-session-type = 'ETH-INTERFACE') or
|
||||
(../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE')";
|
||||
leaf up-cos-name {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface/o-ran-int:class-of-service/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name";
|
||||
}
|
||||
description "the Ethernet U-plane transport marking as defined in o-ran-interfaces";
|
||||
}
|
||||
}
|
||||
case ipv4 {
|
||||
when "(../../transport-session-type = 'UDPIP-INTERFACE')";
|
||||
leaf upv4-dscp-name {
|
||||
if-feature o-ran-int:UDPIP-BASED-CU-PLANE;
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface/ip:ipv4/o-ran-int:diffserv-markings/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name";
|
||||
}
|
||||
description "the IPv4 U-plane transport marking as defined in o-ran-interfaces";
|
||||
}
|
||||
}
|
||||
case ipv6 {
|
||||
when "(../../transport-session-type = 'UDPIP-INTERFACE')";
|
||||
leaf upv6-dscp-name {
|
||||
if-feature o-ran-int:UDPIP-BASED-CU-PLANE;
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface/ip:ipv6/o-ran-int:diffserv-markings/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name";
|
||||
}
|
||||
description "the IPv6 U-plane transport marking as defined in o-ran-interfaces";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
list ru-elements {
|
||||
key "name";
|
||||
description
|
||||
"the list of transport definitions for each processing element";
|
||||
leaf name {
|
||||
type string {
|
||||
length "1..255";
|
||||
}
|
||||
description
|
||||
"A name that is unique across the O-RU that identifies a processing
|
||||
element instance.
|
||||
|
||||
This name may be used in fault management to refer to a fault source
|
||||
or affected object";
|
||||
}
|
||||
container transport-flow {
|
||||
description
|
||||
"container for the transport-flow used for CU plane";
|
||||
leaf interface-name {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface/if:name";
|
||||
}
|
||||
description "the interface name ";
|
||||
}
|
||||
container aliasmac-flow {
|
||||
when "../../../transport-session-type = 'ALIASMAC-INTERFACE'";
|
||||
if-feature o-ran-int:ALIASMAC-BASED-CU-PLANE;
|
||||
description "leafs for virtual mac type data flows";
|
||||
leaf ru-aliasmac-address {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:alias-macs";
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"O-RU's alias MAC address used for alias MAC based flow";
|
||||
}
|
||||
leaf vlan-id {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
|
||||
}
|
||||
description
|
||||
"O-RU's VLAN-ID used for alias MAC based flow";
|
||||
}
|
||||
leaf o-du-mac-address {
|
||||
type yang:mac-address;
|
||||
mandatory true;
|
||||
description
|
||||
"O-DU's MAC address used for alias MAC based flow";
|
||||
}
|
||||
}
|
||||
container eth-flow {
|
||||
when "../../../transport-session-type = 'ETH-INTERFACE'";
|
||||
description "leafs for mac + vlan-id type data flows";
|
||||
leaf ru-mac-address {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address";
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"O-RU's MAC address used for Ethernet based flow";
|
||||
}
|
||||
leaf vlan-id {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"O-RU's VLAN-ID used for Ethernet based flow";
|
||||
}
|
||||
leaf o-du-mac-address {
|
||||
type yang:mac-address;
|
||||
mandatory true;
|
||||
description
|
||||
"O-DU's MAC address used for Ethernet based flow";
|
||||
}
|
||||
}
|
||||
container udpip-flow {
|
||||
when "../../../transport-session-type = 'UDPIP-INTERFACE'";
|
||||
description "leafs for UDP/IP type data flows";
|
||||
choice address {
|
||||
leaf ru-ipv4-address {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/ip:ipv4/ip:address/ip:ip";
|
||||
}
|
||||
description "O-RU's IPv4 address";
|
||||
}
|
||||
leaf ru-ipv6-address {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/ip:ipv6/ip:address/ip:ip";
|
||||
}
|
||||
description "O-RU's IPv6 address";
|
||||
}
|
||||
mandatory true;
|
||||
description "choice of O-RU IPv4 or IPv6 address";
|
||||
}
|
||||
leaf o-du-ip-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
description "O-DU's IPv address";
|
||||
}
|
||||
leaf ru-ephemeral-udp-port {
|
||||
type inet:port-number;
|
||||
mandatory true;
|
||||
description
|
||||
"ephemeral port used by O-RU";
|
||||
}
|
||||
leaf o-du-ephemeral-udp-port {
|
||||
type inet:port-number;
|
||||
mandatory true;
|
||||
description
|
||||
"ephemeral port used by O-DU";
|
||||
}
|
||||
leaf ecpri-destination-udp {
|
||||
type inet:port-number;
|
||||
mandatory true;
|
||||
description "the well known UDP port number used by eCPRI";
|
||||
// fixme - add in a default when allocated by IANA
|
||||
}
|
||||
}
|
||||
container north-eth-flow {
|
||||
when "../../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE'";
|
||||
if-feature "SHARED_CELL";
|
||||
description "leafs for mac + vlan-id type data flows";
|
||||
leaf ru-mac-address {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address";
|
||||
}
|
||||
description
|
||||
"O-RU's MAC address used for Ethernet based flow";
|
||||
}
|
||||
leaf vlan-id {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
|
||||
}
|
||||
description
|
||||
"O-RU's VLAN-ID used for Ethernet based flow";
|
||||
}
|
||||
leaf north-node-mac-address {
|
||||
type yang:mac-address;
|
||||
description
|
||||
"North-node's MAC address used for Ethernet based flow";
|
||||
}
|
||||
}
|
||||
container south-eth-flow {
|
||||
when "../../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE'";
|
||||
if-feature "SHARED_CELL";
|
||||
description "leafs for mac + vlan-id type data flows";
|
||||
leaf ru-mac-address {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address";
|
||||
}
|
||||
description
|
||||
"O-RU's MAC address used for Ethernet based flow";
|
||||
}
|
||||
leaf vlan-id {
|
||||
type leafref {
|
||||
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
|
||||
}
|
||||
description
|
||||
"O-RU's VLAN-ID used for Ethernet based flow";
|
||||
}
|
||||
leaf south-node-mac-address {
|
||||
type yang:mac-address;
|
||||
description
|
||||
"south-node's MAC address used for Ethernet based flow";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// top level container
|
||||
|
||||
container processing-elements {
|
||||
description
|
||||
"a model defining the mapping between transport flows and arbitrary
|
||||
O-RAN processing elements. A processing element may be then defined for
|
||||
handling connectivity or delay procedures, or defined with a corresponding
|
||||
eaxcid for CU plane operations";
|
||||
uses pe-group;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+12
-12
@@ -90,7 +90,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
|
||||
rx_sym = callback_tag->symbol & 0xFF;
|
||||
uint32_t ru_id = callback_tag->oXuId;
|
||||
|
||||
LOG_D(NR_PHY,
|
||||
LOG_D(HW,
|
||||
"rx_callback frame %d, subframe %d, slot %d, second %lld, rx_sym %d ru_id %d\n",
|
||||
frame,
|
||||
subframe,
|
||||
@@ -127,7 +127,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
|
||||
rx_RU[ru_id][slot2] = 1;
|
||||
if (last_frame > 0 && frame > 0
|
||||
&& ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023))))
|
||||
LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2);
|
||||
LOG_E(HW, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2);
|
||||
for (int i = 0; i < num_ports; i++) {
|
||||
if (rx_RU[i][slot2] == 0)
|
||||
return;
|
||||
@@ -142,16 +142,16 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
|
||||
info->tti = tti;
|
||||
info->sl = slot2;
|
||||
info->f = frame;
|
||||
LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
|
||||
LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
|
||||
pushNotifiedFIFO(&oran_sync_fifo, req);
|
||||
#else
|
||||
LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
|
||||
LOG_D(HW, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
|
||||
oran_sync_info.tti = tti;
|
||||
oran_sync_info.sl = slot2;
|
||||
oran_sync_info.f = frame;
|
||||
#endif
|
||||
} else
|
||||
LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
|
||||
LOG_E(HW, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
|
||||
last_slot = slot2;
|
||||
last_frame = frame;
|
||||
} // rx_sym == 7
|
||||
@@ -289,7 +289,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
|
||||
while ((f = pollNotifiedFIFO(&oran_sync_fifo)) != NULL) {
|
||||
oran_sync_info_t *old_info = NotifiedFifoData(res);
|
||||
oran_sync_info_t *new_info = NotifiedFifoData(f);
|
||||
LOG_E(PHY, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl);
|
||||
LOG_E(HW, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl);
|
||||
delNotifiedFIFO_elt(res);
|
||||
res = f;
|
||||
}
|
||||
@@ -305,14 +305,14 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
|
||||
uint32_t tti_in = oran_sync_info.tti;
|
||||
|
||||
static int last_slot = -1;
|
||||
LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot);
|
||||
LOG_D(HW, "oran slot %d, last_slot %d\n", *slot, last_slot);
|
||||
int cnt = 0;
|
||||
// while (*slot == last_slot) {
|
||||
while (tti_in == oran_sync_info.tti) {
|
||||
//*slot = oran_sync_info.sl;
|
||||
cnt++;
|
||||
}
|
||||
LOG_D(PHY, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot);
|
||||
LOG_D(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot);
|
||||
last_slot = *slot;
|
||||
#endif
|
||||
// return(0);
|
||||
@@ -380,9 +380,9 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
|
||||
int16_t payload_len = 0;
|
||||
|
||||
|
||||
LOG_D(PHY, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
|
||||
LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
|
||||
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
|
||||
LOG_D(PHY,
|
||||
LOG_D(HW,
|
||||
"prbMap[%d] : PRBstart %d nPRBs %d\n",
|
||||
idxElm,
|
||||
pRbMap->prbMap[idxElm].nRBStart,
|
||||
@@ -436,7 +436,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
|
||||
} // vv_inf
|
||||
if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) {
|
||||
for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
|
||||
LOG_I(NR_PHY,
|
||||
LOG_I(HW,
|
||||
"[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n",
|
||||
"o-du ",
|
||||
o_xu_id,
|
||||
@@ -448,7 +448,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
|
||||
x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L,
|
||||
x_counters[o_xu_id].Total_msgs_rcvd);
|
||||
for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++)
|
||||
LOG_I(NR_PHY,
|
||||
LOG_I(HW,
|
||||
"[%s%d][pusch%d %7ld prach%d %7ld]\n",
|
||||
"o_du",
|
||||
o_xu_id,
|
||||
|
||||
+110
-26
@@ -32,6 +32,10 @@
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifdef OAI_MPLANE
|
||||
#include "mplane/ru-mplane-api.h"
|
||||
#endif
|
||||
|
||||
static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn)
|
||||
{
|
||||
printf("\
|
||||
@@ -522,6 +526,38 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef OAI_MPLANE
|
||||
static bool set_fh_eaxcid_conf_mplane(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat, const ru_session_list_t *ru_session_list)
|
||||
{
|
||||
xran_mplane_t *xran_mplane = &ru_session_list->ru_session[0].xran_mplane;
|
||||
switch (cat) {
|
||||
case XRAN_CATEGORY_A:
|
||||
eaxcid_conf->mask_cuPortId = xran_mplane->du_port_bitmask;
|
||||
eaxcid_conf->mask_bandSectorId = xran_mplane->band_sector_bitmask;
|
||||
eaxcid_conf->mask_ccId = xran_mplane->ccid_bitmask;
|
||||
eaxcid_conf->mask_ruPortId = xran_mplane->ru_port_bitmask;
|
||||
eaxcid_conf->bit_cuPortId = xran_mplane->du_port;
|
||||
eaxcid_conf->bit_bandSectorId = xran_mplane->band_sector; // total number of band sectors supported by O-RU should be retrieved by M-plane - <max-num-bands> && <max-num-sectors>
|
||||
eaxcid_conf->bit_ccId = xran_mplane->ccid; // total number of CC supported by O-RU should be retrieved by M-plane - <max-num-component-carriers>
|
||||
eaxcid_conf->bit_ruPortId = xran_mplane->ru_port;
|
||||
break;
|
||||
case XRAN_CATEGORY_B:
|
||||
eaxcid_conf->mask_cuPortId = 0xf000;
|
||||
eaxcid_conf->mask_bandSectorId = 0x0c00;
|
||||
eaxcid_conf->mask_ccId = 0x0300;
|
||||
eaxcid_conf->mask_ruPortId = 0x000f;
|
||||
eaxcid_conf->bit_cuPortId = 12;
|
||||
eaxcid_conf->bit_bandSectorId = 10;
|
||||
eaxcid_conf->bit_ccId = 8;
|
||||
eaxcid_conf->bit_ruPortId = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat)
|
||||
{
|
||||
/* CUS specification, section 3.1.3.1.6
|
||||
@@ -540,8 +576,8 @@ static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran
|
||||
eaxcid_conf->mask_ccId = 0x00f0;
|
||||
eaxcid_conf->mask_ruPortId = 0x000f;
|
||||
eaxcid_conf->bit_cuPortId = 0;
|
||||
eaxcid_conf->bit_bandSectorId = 0; // total number of band sectors supported by O-RU should be retreived by M-plane - <max-num-bands> && <max-num-sectors>
|
||||
eaxcid_conf->bit_ccId = 0; // total number of CC supported by O-RU should be retreived by M-plane - <max-num-component-carriers>
|
||||
eaxcid_conf->bit_bandSectorId = 0; // total number of band sectors supported by O-RU should be retrieved by M-plane - <max-num-bands> && <max-num-sectors>
|
||||
eaxcid_conf->bit_ccId = 0; // total number of CC supported by O-RU should be retrieved by M-plane - <max-num-component-carriers>
|
||||
eaxcid_conf->bit_ruPortId = 0;
|
||||
break;
|
||||
case XRAN_CATEGORY_B:
|
||||
@@ -560,6 +596,7 @@ static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr)
|
||||
{
|
||||
@@ -573,7 +610,7 @@ uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_cat)
|
||||
static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xran_category xran_cat)
|
||||
{
|
||||
memset(fh_init, 0, sizeof(*fh_init));
|
||||
|
||||
@@ -606,30 +643,46 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca
|
||||
const int nfh = sizeofArray(FHconfigs);
|
||||
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
|
||||
|
||||
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
|
||||
#ifdef OAI_MPLANE
|
||||
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
|
||||
int num_rus = ru_session_list->num_rus;
|
||||
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
|
||||
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
|
||||
return false;
|
||||
if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf, xran_cat, ru_session_list))
|
||||
return false;
|
||||
/* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be
|
||||
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
|
||||
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
|
||||
fh_init->mtu = ru_session_list->ru_session[0].xran_mplane.mtu; // we suppose that each RU supports the same MTU size
|
||||
|
||||
int num_ru_addr = (fh_init->io_cfg.one_vf_cu_plane) ? num_rus : 2*num_rus;
|
||||
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
|
||||
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
|
||||
for (int i = 0; i < num_rus; i++) {
|
||||
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
|
||||
for (int j = 0; j < num_ru_addr/num_rus; j++) {
|
||||
if (get_ether_addr(ru_session_list->ru_session[i].xran_mplane.ru_mac_addr, &ea[i+j]) == NULL) {
|
||||
printf("could not read ethernet address '%s' for RU!\n", ru_session_list->ru_session[i].xran_mplane.ru_mac_addr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
|
||||
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
|
||||
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
|
||||
return false;
|
||||
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat))
|
||||
return false;
|
||||
|
||||
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
|
||||
fh_init->dpdkBasebandFecMode = 0; // DPDK Baseband FEC device mode (0-SW, 1-HW); not used in xran
|
||||
fh_init->dpdkBasebandDevice = NULL; // DPDK Baseband device address; not used in xran
|
||||
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
|
||||
it is necessary */
|
||||
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
|
||||
/* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be
|
||||
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
|
||||
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
|
||||
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
|
||||
|
||||
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
|
||||
|
||||
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
|
||||
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
|
||||
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
|
||||
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
|
||||
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
|
||||
for (int i = 0; i < num_ru_addr; ++i) {
|
||||
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
|
||||
if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) {
|
||||
@@ -637,7 +690,14 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fh_init->dpdkBasebandFecMode = 0; // DPDK Baseband FEC device mode (0-SW, 1-HW); not used in xran
|
||||
fh_init->dpdkBasebandDevice = NULL; // DPDK Baseband device address; not used in xran
|
||||
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
|
||||
it is necessary */
|
||||
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
|
||||
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
|
||||
fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec
|
||||
|
||||
#ifdef F_RELEASE
|
||||
@@ -656,7 +716,8 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca
|
||||
// this is a hack
|
||||
int g_kbar;
|
||||
|
||||
static bool set_fh_prach_config(const openair0_config_t *oai0,
|
||||
static bool set_fh_prach_config(void *mplane_api,
|
||||
const openair0_config_t *oai0,
|
||||
const uint32_t max_num_ant,
|
||||
const paramdef_t *prachp,
|
||||
int nprach,
|
||||
@@ -692,8 +753,13 @@ static bool set_fh_prach_config(const openair0_config_t *oai0,
|
||||
xran assumes PRACH offset >= max(Ntx, Nrx). However, we made a workaround that xran supports PRACH eAxC IDs same as PUSCH eAxC IDs.
|
||||
This is achieved with is_prach and filter_id parameters in the patch.
|
||||
Please note that this approach only applies to the RUs that support this functionality, e.g. LITEON RU. */
|
||||
#ifdef OAI_MPLANE
|
||||
xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api;
|
||||
prach_config->eAxC_offset = xran_mplane->prach_offset;
|
||||
#else
|
||||
uint8_t offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr;
|
||||
prach_config->eAxC_offset = (offset != 0) ? offset : max_num_ant;
|
||||
#endif
|
||||
|
||||
g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr;
|
||||
|
||||
@@ -722,17 +788,24 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_ru_config(const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config)
|
||||
static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config)
|
||||
{
|
||||
ru_config->xranTech = XRAN_RAN_5GNR; // 5GNR or LTE
|
||||
ru_config->xranCat = xran_cat; // mode: Catergory A or Category B
|
||||
ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC; // dynamic or static udCompHdr handling
|
||||
#ifdef OAI_MPLANE
|
||||
xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api;
|
||||
ru_config->iqWidth = xran_mplane->iq_width;
|
||||
ru_config->iqWidth_PRACH = xran_mplane->iq_width;
|
||||
#else
|
||||
ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr; // IQ bit width
|
||||
AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n");
|
||||
ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method
|
||||
ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr; // IQ bit width for PRACH
|
||||
AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n");
|
||||
#endif
|
||||
ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method
|
||||
ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method for PRACH
|
||||
|
||||
AssertFatal(fftSize > 0, "FFT size cannot be 0\n");
|
||||
ru_config->fftSize = fftSize; // FFT Size
|
||||
ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; // order of bytes in int16_t in buffer; big or little endian
|
||||
@@ -757,7 +830,7 @@ static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint1
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
|
||||
static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
|
||||
{
|
||||
AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n");
|
||||
AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus);
|
||||
@@ -839,22 +912,22 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat,
|
||||
#endif
|
||||
fh_config->puschMaskEnable = 0; // enable PUSCH mask; only used if id = O_RU
|
||||
fh_config->puschMaskSlot = 0; // specific which slot PUSCH channel masked; only used if id = O_RU
|
||||
fh_config->cp_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_CP_VLAN_TAG)->uptr; // C-plane VLAN tag; not used in xran; needed for M-plane
|
||||
fh_config->up_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_UP_VLAN_TAG)->uptr; // U-plane VLAN tag; not used in xran; needed for M-plane
|
||||
fh_config->cp_vlan_tag = 0; // C-plane VLAN tag; not used in xran; needed for M-plane
|
||||
fh_config->up_vlan_tag = 0; // U-plane VLAN tag; not used in xran; needed for M-plane
|
||||
fh_config->debugStop = 0; // enable auto stop; only used if id = O_RU
|
||||
fh_config->debugStopCount = 0; // enable auto stop after number of Tx packets; not used in xran
|
||||
fh_config->DynamicSectionEna = 0; // enable dynamic C-Plane section allocation
|
||||
fh_config->GPS_Alpha = 0; // refers to alpha as defined in section 9.7.2 of ORAN spec. this value should be alpha*(1/1.2288ns), range 0 - 1e7 (ns); offset_nsec = (pConf->GPS_Beta - offset_sec * 100) * 1e7 + pConf->GPS_Alpha
|
||||
fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100
|
||||
|
||||
if (!set_fh_prach_config(oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf))
|
||||
if (!set_fh_prach_config(mplane_api, oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf))
|
||||
return false;
|
||||
/* SRS only used if XRAN_CATEGORY_B
|
||||
Note: srs_config->eAxC_offset >= prach_config->eAxC_offset + PRACH */
|
||||
// fh_config->srs_conf = {0};
|
||||
if (!set_fh_frame_config(oai0, &fh_config->frame_conf))
|
||||
return false;
|
||||
if (!set_fh_ru_config(rup, oai0->split7.fftSize, nru, xran_cat, &fh_config->ru_conf))
|
||||
if (!set_fh_ru_config(mplane_api, rup, oai0->split7.fftSize, nru, xran_cat, &fh_config->ru_conf))
|
||||
return false;
|
||||
|
||||
fh_config->bbdev_enc = NULL; // call back to poll BBDev encoder
|
||||
@@ -889,24 +962,35 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_xran_config(const openair0_config_t *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config)
|
||||
bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config)
|
||||
{
|
||||
/* This xran integration release is only valid for O-RU CAT A.
|
||||
Therefore, each FH parameter is hardcoded to CAT A.
|
||||
If you are interested in CAT B, please be aware that parameters of fh_init and fh_config structs must be modified accordingly. */
|
||||
enum xran_category xran_cat = XRAN_CATEGORY_A;
|
||||
|
||||
if (!set_fh_init(fh_init, xran_cat)) {
|
||||
if (!set_fh_init(mplane_api, fh_init, xran_cat)) {
|
||||
printf("could not read FHI 7.2/ORAN config\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef OAI_MPLANE
|
||||
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
|
||||
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
|
||||
if (!set_fh_config(o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
|
||||
xran_mplane_t *xran_mplane = &ru_session_list->ru_session[o_xu_id].xran_mplane;
|
||||
if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
|
||||
MP_LOG_I("could not read FHI 7.2/RU-specific config\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
|
||||
if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
|
||||
printf("could not read FHI 7.2/RU-specific config\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ struct xran_fh_init;
|
||||
struct xran_fh_config;
|
||||
struct openair0_config;
|
||||
|
||||
bool get_xran_config(const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config);
|
||||
bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config);
|
||||
|
||||
void print_fh_init(const struct xran_fh_init *fh_init);
|
||||
void print_fh_config(const struct xran_fh_config *fh_config);
|
||||
|
||||
@@ -443,7 +443,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
|
||||
pi->prach_tag = tag;
|
||||
pi->pusch_tag = tag;
|
||||
#ifdef E_RELEASE
|
||||
LOG_W(PHY, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n");
|
||||
LOG_W(HW, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n");
|
||||
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
|
||||
#elif defined F_RELEASE
|
||||
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
|
||||
|
||||
@@ -31,8 +31,12 @@
|
||||
#define ORAN_CONFIG_SYSTEM_CORE "system_core"
|
||||
#define ORAN_CONFIG_IO_CORE "io_core"
|
||||
#define ORAN_CONFIG_WORKER_CORES "worker_cores"
|
||||
#define ORAN_CONFIG_RU_ADDR "ru_addr"
|
||||
#define ORAN_CONFIG_MTU "mtu"
|
||||
#define ORAN_CONFIG_DU_KEYPAIR "du_key_pair" // only needed for M-plane
|
||||
#define ORAN_CONFIG_DU_ADDR "du_addr" // only needed for M-plane
|
||||
#define ORAN_CONFIG_VLAN_TAG "vlan_tag" // only needed for M-plane
|
||||
#define ORAN_CONFIG_RU_ADDR "ru_addr" // not needed if M-plane used
|
||||
#define ORAN_CONFIG_RU_IP_ADDR "ru_ip_addr" // only needed for M-plane
|
||||
#define ORAN_CONFIG_MTU "mtu" // not needed if M-plane used
|
||||
#define ORAN_CONFIG_FILE_PREFIX "file_prefix"
|
||||
#define ORAN_CONFIG_NETHPERPORT "eth_lines"
|
||||
#define ORAN_CONFIG_NETHSPEED "eth_speed"
|
||||
@@ -48,7 +52,11 @@
|
||||
{ORAN_CONFIG_SYSTEM_CORE, "DPDK control threads core\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
{ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \
|
||||
{ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_CONFIG_DU_KEYPAIR, "DU keypair for RU authentication\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_VLAN_TAG, "VLAN tag\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
|
||||
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_RU_IP_ADDR, "IP addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \
|
||||
{ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \
|
||||
{ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \
|
||||
@@ -70,6 +78,10 @@
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s3a = { config_checkstr_assign_integer, \
|
||||
{"PA", "VA"}, {0, 1}, 2} }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
@@ -84,8 +96,6 @@
|
||||
#define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul"
|
||||
#define ORAN_FH_CONFIG_T1A_UP "T1a_up"
|
||||
#define ORAN_FH_CONFIG_TA4 "Ta4"
|
||||
#define ORAN_FH_CONFIG_CP_VLAN_TAG "cp_vlan_tag"
|
||||
#define ORAN_FH_CONFIG_UP_VLAN_TAG "up_vlan_tag"
|
||||
|
||||
#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n"
|
||||
|
||||
@@ -95,15 +105,13 @@
|
||||
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_CP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
{ORAN_FH_CONFIG_UP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#define CONFIG_STRING_ORAN_RU "ru_config"
|
||||
|
||||
#define ORAN_RU_CONFIG_IQWIDTH "iq_width"
|
||||
#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach"
|
||||
#define ORAN_RU_CONFIG_IQWIDTH "iq_width" // not needed if M-plane used
|
||||
#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" // not needed if M-plane used
|
||||
|
||||
// clang-format off
|
||||
#define ORAN_RU_DESC {\
|
||||
@@ -114,7 +122,7 @@
|
||||
|
||||
#define CONFIG_STRING_ORAN_PRACH "prach_config"
|
||||
|
||||
#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset"
|
||||
#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset" // not needed if M-plane used
|
||||
#define ORAN_PRACH_CONFIG_KBAR "kbar"
|
||||
|
||||
// clang-format off
|
||||
|
||||
+90
-37
@@ -39,11 +39,17 @@
|
||||
// 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"
|
||||
#include "mplane/connect-mplane.h"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
eth_state_t e;
|
||||
rru_config_msg_type_t last_msg;
|
||||
int capabilities_sent;
|
||||
void *oran_priv;
|
||||
void *mplane_priv;
|
||||
} oran_eth_state_t;
|
||||
|
||||
notifiedFIFO_t oran_sync_fifo;
|
||||
@@ -76,6 +82,10 @@ int trx_oran_stop(openair0_device *device)
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
oran_eth_state_t *s = device->priv;
|
||||
xran_stop(s->oran_priv);
|
||||
#ifdef OAI_MPLANE
|
||||
printf("[MPLANE] Stopping M-plane.\n");
|
||||
disconnect_mplane(s->mplane_priv);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -204,11 +214,11 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
int f, sl;
|
||||
LOG_D(PHY, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
||||
LOG_D(HW, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
||||
start_meas(&ru->rx_fhaul);
|
||||
int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl);
|
||||
stop_meas(&ru->rx_fhaul);
|
||||
LOG_D(PHY, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
||||
LOG_D(HW, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
||||
if (ret != 0) {
|
||||
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl);
|
||||
}
|
||||
@@ -221,7 +231,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
|
||||
if (proc->first_rx == 0) {
|
||||
if (proc->tti_rx != *slot) {
|
||||
LOG_E(PHY,
|
||||
LOG_E(HW,
|
||||
"Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n",
|
||||
proc->frame_rx,
|
||||
proc->tti_rx,
|
||||
@@ -231,7 +241,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
}
|
||||
|
||||
if (proc->frame_rx != *frame) {
|
||||
LOG_E(PHY,
|
||||
LOG_E(HW,
|
||||
"Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n",
|
||||
proc->frame_rx,
|
||||
proc->tti_rx,
|
||||
@@ -241,10 +251,10 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
}
|
||||
} else {
|
||||
proc->first_rx = 0;
|
||||
LOG_I(PHY, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
|
||||
LOG_I(HW, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
|
||||
*frame = proc->frame_rx;
|
||||
*slot = proc->tti_rx;
|
||||
LOG_I(PHY, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
|
||||
LOG_I(HW, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +289,80 @@ __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");
|
||||
|
||||
bool ru_configured[ru_session_list.num_rus];
|
||||
for (size_t i = 0; i < ru_session_list.num_rus; i++) {
|
||||
ru_session_t *ru_session = &ru_session_list.ru_session[i];
|
||||
ru_configured[i] = connect_mplane(ru_session);
|
||||
if (!ru_configured[i]) {
|
||||
continue;
|
||||
}
|
||||
ru_configured[i] = manage_ru(ru_session, openair0_cfg, ru_session_list.num_rus);
|
||||
}
|
||||
|
||||
bool all_ok = true;
|
||||
bool ru_ready[ru_session_list.num_rus];
|
||||
for (size_t i = 0; i < ru_session_list.num_rus; i++) {
|
||||
if (!ru_configured[i]) {
|
||||
MP_LOG_I("RU with IP %s couldn't be configured.\n", ru_session_list.ru_session[i].ru_ip_add);
|
||||
all_ok = false;
|
||||
}
|
||||
ru_ready[i] = false;
|
||||
}
|
||||
|
||||
if (!all_ok) {
|
||||
disconnect_mplane((void *)&ru_session_list);
|
||||
AssertFatal(false, "[MPLANE] Stopping M-plane.\n");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
sleep(1);
|
||||
bool all_rus_ready = true;
|
||||
for (int i = 0; i < ru_session_list.num_rus; i++) {
|
||||
ru_session_t *ru_session = &ru_session_list.ru_session[i];
|
||||
if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) {
|
||||
MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add);
|
||||
ru_ready[i] = true;
|
||||
} else {
|
||||
all_rus_ready = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_rus_ready) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
eth->mplane_priv = (void *)&ru_session_list;
|
||||
|
||||
success = get_xran_config((void *)&ru_session_list, openair0_cfg, &fh_init, fh_config);
|
||||
AssertFatal(success, "[MPLANE] Cannot configure xran with M-plane info.\n");
|
||||
#else
|
||||
success = get_xran_config(NULL, 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 +373,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;
|
||||
}
|
||||
|
||||
@@ -1004,7 +1004,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
||||
t->nextRxTstamp + nsamps);
|
||||
flushInput(t, 3, nsamps);
|
||||
}
|
||||
if (t->hanging_workaround && loops++ > 10 && t->role == SIMU_ROLE_SERVER) {
|
||||
if (t->hanging_workaround && loops++ > 10 && t->role == SIMU_ROLE_SERVER && nb_ue > 1) {
|
||||
// Just start producing samples. The clients will catch up.
|
||||
have_to_wait = false;
|
||||
LOG_W(HW,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
add_library(vrtsim MODULE vrtsim.c noise_device.c)
|
||||
set_target_properties(vrtsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor)
|
||||
add_dependencies(vrtsim generate_T)
|
||||
@@ -0,0 +1,25 @@
|
||||
# Overview
|
||||
|
||||
This implements a shared memory realtime and near-realtime radio interface.
|
||||
This is performed using `shm_td_iq_channel` which handles the shared memory
|
||||
interface.
|
||||
|
||||
# Limitations
|
||||
|
||||
- Only 1gNB to 1nrUE: gNB as a server, UE as a client.
|
||||
- Server only accepts connections during device bringup. This means that
|
||||
restarting the client will not make it reconnect, the server has to be
|
||||
restarted as well.
|
||||
|
||||
# Usage
|
||||
|
||||
On the UE and gNB: use `device.name vrtsim` command line argument.
|
||||
|
||||
Additionally on gNB use `vrtsim.role server` and optionally
|
||||
`vrtsim.timescale <timescale>` to set the timescale. Timescale 1.0
|
||||
is the default and means realtime.
|
||||
|
||||
Channel modelling can be enabled by adding `vrtsim.chanmod 1` to the
|
||||
command line and should work the same as channel modelling in rfsimulator,
|
||||
see rfsimulator [documentation](../rfsimulator/README.md), provided that your
|
||||
CPU is fast enough.
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 <pthread.h>
|
||||
#include <errno.h>
|
||||
#include "noise_device.h"
|
||||
|
||||
// Use block size equal to cache size
|
||||
#define BLOCK_SIZE (64 / sizeof(float)) // 4 bytes per float
|
||||
// Use a power of 2 for block size length
|
||||
#define NUM_BLOCKS (8192)
|
||||
#define NOISE_VECTOR_LENGTH (BLOCK_SIZE * NUM_BLOCKS)
|
||||
|
||||
static struct {
|
||||
pthread_t noise_device_thread;
|
||||
float noise[NOISE_VECTOR_LENGTH] __attribute__((aligned(64)));
|
||||
float noise_power;
|
||||
bool running;
|
||||
} state;
|
||||
|
||||
static uint32_t jz, jsr = 123456789;
|
||||
static uint32_t random_uint(void)
|
||||
{
|
||||
return SHR3;
|
||||
}
|
||||
|
||||
static void generate_one_block_noise(int write_block_index, float noise_power)
|
||||
{
|
||||
// Generate noise vector
|
||||
float block[BLOCK_SIZE];
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
block[i] = noise_power * gaussZiggurat(0, 1);
|
||||
}
|
||||
// Write block to noise vector
|
||||
memcpy(state.noise + write_block_index * BLOCK_SIZE, block, sizeof(block));
|
||||
}
|
||||
|
||||
void *noise_device_thread_function(void *arg)
|
||||
{
|
||||
while (state.running) {
|
||||
// Generate noise vector
|
||||
generate_one_block_noise(random_uint() % NUM_BLOCKS, state.noise_power);
|
||||
usleep(10000);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_noise_device(float noise_power)
|
||||
{
|
||||
for (int i = 0; i < NUM_BLOCKS; i++) {
|
||||
generate_one_block_noise(i, noise_power);
|
||||
}
|
||||
int ret = pthread_create(&state.noise_device_thread, NULL, noise_device_thread_function, NULL);
|
||||
AssertFatal(ret == 0, "pthread_create failed: %d, errno %d (%s)\n", ret, errno, strerror(errno));
|
||||
}
|
||||
|
||||
void free_noise_device(void)
|
||||
{
|
||||
state.running = false;
|
||||
pthread_join(state.noise_device_thread, NULL);
|
||||
}
|
||||
|
||||
void get_noise_vector(float *noise_vector, int length)
|
||||
{
|
||||
int start_block = random_uint() % NUM_BLOCKS;
|
||||
while (length > 0) {
|
||||
int copy_size = min(length, (NUM_BLOCKS - start_block) * BLOCK_SIZE);
|
||||
memcpy(noise_vector, &state.noise[start_block * BLOCK_SIZE], copy_size * sizeof(float));
|
||||
start_block = 0;
|
||||
length -= copy_size;
|
||||
noise_vector += copy_size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 NOISE_DEVICE_H
|
||||
#define NOISE_DEVICE_H
|
||||
|
||||
#include "SIMULATION/TOOLS/sim.h"
|
||||
|
||||
void init_noise_device(float noise_power);
|
||||
void free_noise_device(void);
|
||||
void get_noise_vector(float *noise_vector, int length);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
* 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 <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <common/utils/assertions.h>
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include <common/utils/load_module_shlib.h>
|
||||
#include <common/utils/telnetsrv/telnetsrv.h>
|
||||
#include <common/config/config_userapi.h>
|
||||
#include "common_lib.h"
|
||||
#include "shm_td_iq_channel.h"
|
||||
#include "SIMULATION/TOOLS/sim.h"
|
||||
#include "actor.h"
|
||||
#include "noise_device.h"
|
||||
#include "simde/x86/avx512.h"
|
||||
|
||||
// Simulator role
|
||||
typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role;
|
||||
|
||||
#define NUM_CHANMOD_THREADS 1
|
||||
|
||||
#define ROLE_CLIENT_STRING "client"
|
||||
#define ROLE_SERVER_STRING "server"
|
||||
|
||||
#define VRTSIM_SECTION "vrtsim"
|
||||
#define TIME_SCALE_HLP \
|
||||
"sample time scale. 1.0 means realtime. Values > 1 mean faster than realtime. Values < 1 mean slower than realtime\n"
|
||||
|
||||
// clang-format off
|
||||
#define VRTSIM_PARAMS_DESC \
|
||||
{ \
|
||||
{"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "vrtsim_channel", TYPE_STRING, 0}, \
|
||||
{"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \
|
||||
{"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \
|
||||
{"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
typedef struct histogram_s {
|
||||
uint64_t diff[30];
|
||||
int num_samples;
|
||||
int min_samples;
|
||||
double range;
|
||||
} histogram_t;
|
||||
|
||||
// Information about the peer
|
||||
typedef struct peer_info_s {
|
||||
int num_rx_antennas;
|
||||
} peer_info_t;
|
||||
|
||||
typedef struct tx_timing_s {
|
||||
uint64_t tx_samples_late;
|
||||
uint64_t tx_early;
|
||||
uint64_t tx_samples_total;
|
||||
double average_tx_budget;
|
||||
histogram_t tx_histogram;
|
||||
} tx_timing_t;
|
||||
|
||||
typedef struct {
|
||||
int role;
|
||||
char channel_name[40];
|
||||
ShmTDIQChannel *channel;
|
||||
uint64_t last_received_sample;
|
||||
pthread_t timing_thread;
|
||||
bool run_timing_thread;
|
||||
double timescale;
|
||||
double sample_rate;
|
||||
uint64_t rx_samples_late;
|
||||
uint64_t rx_early;
|
||||
uint64_t rx_samples_total;
|
||||
tx_timing_t *tx_timing;
|
||||
peer_info_t peer_info;
|
||||
int chanmod;
|
||||
double rx_freq;
|
||||
double tx_bw;
|
||||
int tx_num_channels;
|
||||
int rx_num_channels;
|
||||
channel_desc_t *channel_desc;
|
||||
Actor_t *channel_modelling_actors;
|
||||
} vrtsim_state_t;
|
||||
|
||||
static void histogram_add(histogram_t *histogram, double diff)
|
||||
{
|
||||
histogram->num_samples++;
|
||||
if (histogram->num_samples >= histogram->min_samples) {
|
||||
int bin = min(sizeofArray(histogram->diff) - 1, max(0, (int)(diff / histogram->range * sizeofArray(histogram->diff))));
|
||||
histogram->diff[bin]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void histogram_print(histogram_t *histogram)
|
||||
{
|
||||
LOG_I(HW, "VRTSIM: TX budget histogram: %d samples\n", histogram->num_samples);
|
||||
float bin_size = histogram->range / sizeofArray(histogram->diff);
|
||||
float bin_start = 0;
|
||||
for (int i = 0; i < sizeofArray(histogram->diff); i++) {
|
||||
LOG_I(HW, "Bin %d\t[%.1f - %.1fuS]:\t\t%lu\n", i, bin_start, bin_start + bin_size, histogram->diff[i]);
|
||||
bin_start += bin_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void histogram_merge(histogram_t *dest, histogram_t *src)
|
||||
{
|
||||
for (int i = 0; i < sizeofArray(dest->diff); i++) {
|
||||
dest->diff[i] += src->diff[i];
|
||||
}
|
||||
dest->num_samples += src->num_samples;
|
||||
}
|
||||
|
||||
static void load_channel_model(vrtsim_state_t *vrtsim_state)
|
||||
{
|
||||
load_channellist(vrtsim_state->tx_num_channels,
|
||||
vrtsim_state->peer_info.num_rx_antennas,
|
||||
vrtsim_state->sample_rate,
|
||||
vrtsim_state->rx_freq,
|
||||
vrtsim_state->tx_bw);
|
||||
char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model";
|
||||
vrtsim_state->channel_desc = find_channel_desc_fromname(model_name);
|
||||
random_channel(vrtsim_state->channel_desc, 0);
|
||||
AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name);
|
||||
}
|
||||
|
||||
static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state)
|
||||
{
|
||||
char *channel_name = NULL;
|
||||
char *role = NULL;
|
||||
paramdef_t vrtsim_params[] = VRTSIM_PARAMS_DESC;
|
||||
int ret = config_get(config_get_if(), vrtsim_params, sizeofArray(vrtsim_params), VRTSIM_SECTION);
|
||||
AssertFatal(ret >= 0, "configuration couldn't be performed\n");
|
||||
strncpy(vrtsim_state->channel_name, channel_name, sizeof(vrtsim_state->channel_name) - 1);
|
||||
if (strncmp(role, ROLE_CLIENT_STRING, strlen(ROLE_CLIENT_STRING)) == 0) {
|
||||
vrtsim_state->role = ROLE_CLIENT;
|
||||
} else if (strncmp(role, ROLE_SERVER_STRING, strlen(ROLE_SERVER_STRING)) == 0) {
|
||||
vrtsim_state->role = ROLE_SERVER;
|
||||
} else {
|
||||
AssertFatal(false, "Invalid role configuration\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void *vrtsim_timing_job(void *arg)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = arg;
|
||||
struct timespec timestamp;
|
||||
if (clock_gettime(CLOCK_REALTIME, ×tamp)) {
|
||||
LOG_E(UTIL, "clock_gettime failed\n");
|
||||
exit(1);
|
||||
}
|
||||
double leftover_samples = 0;
|
||||
while (vrtsim_state->run_timing_thread) {
|
||||
struct timespec current_time;
|
||||
if (clock_gettime(CLOCK_REALTIME, ¤t_time)) {
|
||||
LOG_E(UTIL, "clock_gettime failed\n");
|
||||
exit(1);
|
||||
}
|
||||
uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec);
|
||||
timestamp = current_time;
|
||||
double samples_to_produce = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
|
||||
|
||||
// Attempt to correct compounding rounding error
|
||||
leftover_samples += samples_to_produce - (uint64_t)samples_to_produce;
|
||||
if (leftover_samples > 1.0f) {
|
||||
samples_to_produce += 1;
|
||||
leftover_samples -= 1;
|
||||
}
|
||||
shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce);
|
||||
usleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges peer information between the server and the client.
|
||||
*
|
||||
* This function sets up a Unix domain socket server, waits for a client to connect,
|
||||
* and exchanges peer information (number of RX antennas) with the client.
|
||||
*
|
||||
* @param peer_info The peer information to send to the client.
|
||||
* @return The peer information received from the client.
|
||||
*
|
||||
* @note This function will block until a client connects and the information is exchanged.
|
||||
*/
|
||||
static peer_info_t server_exchange_peer_info(peer_info_t peer_info)
|
||||
{
|
||||
int server_fd, client_fd;
|
||||
|
||||
// Create a Unix domain socket
|
||||
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
AssertFatal(server_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Bind the socket to a file path
|
||||
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||
strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1);
|
||||
unlink(addr.sun_path); // Ensure the path does not already exist
|
||||
int ret = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
AssertFatal(ret == 0, "bind() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Listen for incoming connections
|
||||
ret = listen(server_fd, 1);
|
||||
AssertFatal(ret == 0, "listen() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Accept a connection from a client
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
|
||||
AssertFatal(client_fd >= 0, "accept() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Send the antenna info to the server
|
||||
ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0);
|
||||
AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
ssize_t bytes_received = recv(client_fd, &peer_info, sizeof(peer_info), 0);
|
||||
AssertFatal(bytes_received == sizeof(peer_info), "recv() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
LOG_I(HW, "Received client info: RX %d\n", peer_info.num_rx_antennas);
|
||||
|
||||
// Close the client and server sockets
|
||||
close(client_fd);
|
||||
close(server_fd);
|
||||
return peer_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges peer information between the client and the server.
|
||||
*
|
||||
* This function connects to a Unix domain socket server, exchanges peer information
|
||||
* (number of RX antennas) with the server, and returns the peer information received
|
||||
* from the server.
|
||||
*
|
||||
* @param peer_info The peer information to send to the server.
|
||||
* @return The peer information received from the server.
|
||||
*
|
||||
* @note This function will block until the information is exchanged.
|
||||
*/
|
||||
static peer_info_t client_exchange_peer_info(peer_info_t peer_info)
|
||||
{
|
||||
int client_fd;
|
||||
|
||||
// Create a Unix domain socket
|
||||
client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
AssertFatal(client_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Connect to the server
|
||||
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||
strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1);
|
||||
int ret = -1;
|
||||
int tries = 0;
|
||||
while (ret != 0 && tries < 10) {
|
||||
ret = connect(client_fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
tries++;
|
||||
sleep(1);
|
||||
}
|
||||
AssertFatal(ret == 0, "connect() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
peer_info_t peer_info_received;
|
||||
ssize_t bytes_received = recv(client_fd, &peer_info_received, sizeof(peer_info_received), 0);
|
||||
AssertFatal(bytes_received == sizeof(peer_info_received), "recv() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
// Send the antenna info to the server
|
||||
ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0);
|
||||
AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
|
||||
LOG_I(HW, "Received peer info: RX %d\n", peer_info_received.num_rx_antennas);
|
||||
|
||||
// Close the client socket
|
||||
close(client_fd);
|
||||
return peer_info_received;
|
||||
}
|
||||
|
||||
static int vrtsim_connect(openair0_device *device)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
// Exchange peer info
|
||||
peer_info_t peer_info = {.num_rx_antennas = device->openair0_cfg[0].rx_num_channels};
|
||||
if (vrtsim_state->role == ROLE_SERVER) {
|
||||
vrtsim_state->peer_info = server_exchange_peer_info(peer_info);
|
||||
} else {
|
||||
vrtsim_state->peer_info = client_exchange_peer_info(peer_info);
|
||||
}
|
||||
|
||||
// Handle channel modelling after number of RX antennas are known
|
||||
int num_tx_stats = 1;
|
||||
if (vrtsim_state->chanmod) {
|
||||
vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->peer_info.num_rx_antennas, sizeof(Actor_t));
|
||||
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
|
||||
init_actor(&vrtsim_state->channel_modelling_actors[i], "chanmod", -1);
|
||||
}
|
||||
load_channel_model(vrtsim_state);
|
||||
num_tx_stats = vrtsim_state->peer_info.num_rx_antennas;
|
||||
}
|
||||
vrtsim_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t));
|
||||
for (int i = 0; i < num_tx_stats; i++) {
|
||||
vrtsim_state->tx_timing[i].tx_histogram.min_samples = 100;
|
||||
// Set the histogram range to 3000uS. Anything above that is not interesting
|
||||
vrtsim_state->tx_timing[i].tx_histogram.range = 3000.0;
|
||||
}
|
||||
|
||||
// Setup a shared memory channel
|
||||
if (vrtsim_state->role == ROLE_SERVER) {
|
||||
vrtsim_state->channel = shm_td_iq_channel_create(vrtsim_state->channel_name,
|
||||
vrtsim_state->peer_info.num_rx_antennas,
|
||||
device->openair0_cfg[0].rx_num_channels);
|
||||
vrtsim_state->run_timing_thread = true;
|
||||
while (!shm_td_iq_channel_is_connected(vrtsim_state->channel)) {
|
||||
LOG_I(HW, "Waiting for client\n");
|
||||
sleep(1);
|
||||
}
|
||||
int ret = pthread_create(&vrtsim_state->timing_thread, NULL, vrtsim_timing_job, vrtsim_state);
|
||||
AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
} else {
|
||||
vrtsim_state->channel = shm_td_iq_channel_connect(vrtsim_state->channel_name, 10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vrtsim_write_internal(vrtsim_state_t *vrtsim_state,
|
||||
openair0_timestamp timestamp,
|
||||
c16_t *samples,
|
||||
int nsamps,
|
||||
int aarx,
|
||||
int flags,
|
||||
int stats_index)
|
||||
{
|
||||
tx_timing_t *tx_timing = &vrtsim_state->tx_timing[stats_index];
|
||||
|
||||
uint64_t sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel);
|
||||
int64_t diff = timestamp - sample;
|
||||
double budget = diff / (vrtsim_state->sample_rate / 1e6);
|
||||
tx_timing->average_tx_budget = .05 * budget + .95 * tx_timing->average_tx_budget;
|
||||
histogram_add(&tx_timing->tx_histogram, budget);
|
||||
|
||||
int ret = shm_td_iq_channel_tx(vrtsim_state->channel, timestamp, nsamps, aarx, (sample_t *)samples);
|
||||
|
||||
if (ret == CHANNEL_ERROR_TOO_LATE) {
|
||||
tx_timing->tx_samples_late += nsamps;
|
||||
} else if (ret == CHANNEL_ERROR_TOO_EARLY) {
|
||||
tx_timing->tx_early += 1;
|
||||
}
|
||||
tx_timing->tx_samples_total += nsamps;
|
||||
|
||||
return nsamps;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
vrtsim_state_t *vrtsim_state;
|
||||
openair0_timestamp timestamp;
|
||||
c16_t *samples[4];
|
||||
int nsamps;
|
||||
int nbAnt;
|
||||
int flags;
|
||||
int aarx;
|
||||
} channel_modelling_args_t;
|
||||
|
||||
static void perform_channel_modelling(void *arg)
|
||||
{
|
||||
channel_modelling_args_t *channel_modelling_args = arg;
|
||||
int nsamps = channel_modelling_args->nsamps;
|
||||
int aarx = channel_modelling_args->aarx;
|
||||
int nb_tx_ant = channel_modelling_args->nbAnt;
|
||||
c16_t **input_samples = (c16_t **)channel_modelling_args->samples;
|
||||
|
||||
int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t));
|
||||
cf_t samples[aligned_nsamps] __attribute__((aligned(64)));
|
||||
// Apply noise from global settings
|
||||
get_noise_vector((float *)samples, nsamps * 2);
|
||||
|
||||
channel_desc_t *channel_desc = channel_modelling_args->vrtsim_state->channel_desc;
|
||||
const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0);
|
||||
|
||||
// Convert channel impulse response to float + apply pathloss
|
||||
cf_t channel_impulse_response[nb_tx_ant][channel_desc->channel_length];
|
||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||
const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)];
|
||||
for (int i = 0; i < channel_desc->channel_length; i++) {
|
||||
channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear;
|
||||
channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear;
|
||||
}
|
||||
}
|
||||
|
||||
for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
|
||||
for (int i = 0; i < nsamps; i++) {
|
||||
cf_t *impulse_response = channel_impulse_response[aatx];
|
||||
for (int l = 0; l < channel_desc->channel_length; l++) {
|
||||
int idx = i - l;
|
||||
// TODO: Use AVX512 for this
|
||||
// TODO: What are the previously sent samples (for impulse response)
|
||||
if (idx >= 0) {
|
||||
c16_t tx_input = input_samples[aatx][idx];
|
||||
samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i;
|
||||
samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to c16_t
|
||||
c16_t samples_out[aligned_nsamps] __attribute__((aligned(64)));
|
||||
#if defined(__AVX512F__)
|
||||
for (int i = 0; i < aligned_nsamps / 8; i++) {
|
||||
simde__m512 *in = (simde__m512 *)&samples[i * 8];
|
||||
simde__m256i *out = (simde__m256i *)&samples_out[i * 8];
|
||||
*out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in));
|
||||
}
|
||||
#elif defined(__AVX2__)
|
||||
for (int i = 0; i < aligned_nsamps / 4; i++) {
|
||||
simde__m256 *in = (simde__m256 *)&samples[i * 4];
|
||||
simde__m128i *out = (simde__m128i *)&samples_out[i * 4];
|
||||
*out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in));
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < nsamps; i++) {
|
||||
samples_out[i].r = lroundf(samples[i].r);
|
||||
samples_out[i].i = lroundf(samples[i].i);
|
||||
}
|
||||
#endif
|
||||
|
||||
vrtsim_write_internal(channel_modelling_args->vrtsim_state,
|
||||
channel_modelling_args->timestamp,
|
||||
samples_out,
|
||||
channel_modelling_args->nsamps,
|
||||
aarx,
|
||||
channel_modelling_args->flags,
|
||||
aarx);
|
||||
}
|
||||
|
||||
static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
|
||||
openair0_timestamp timestamp,
|
||||
void **samplesVoid,
|
||||
int nsamps,
|
||||
int nbAnt,
|
||||
int flags)
|
||||
{
|
||||
for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) {
|
||||
notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling);
|
||||
channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task);
|
||||
args->vrtsim_state = vrtsim_state;
|
||||
args->timestamp = timestamp;
|
||||
args->nsamps = nsamps;
|
||||
args->nbAnt = nbAnt;
|
||||
args->flags = flags;
|
||||
args->aarx = aarx;
|
||||
for (int i = 0; i < nbAnt; i++) {
|
||||
args->samples[i] = samplesVoid[i];
|
||||
}
|
||||
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
|
||||
}
|
||||
return nsamps;
|
||||
}
|
||||
|
||||
static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags)
|
||||
{
|
||||
timestamp -= device->openair0_cfg->command_line_sample_advance;
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
return vrtsim_state->chanmod ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags)
|
||||
: vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0);
|
||||
}
|
||||
|
||||
static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps);
|
||||
int ret = shm_td_iq_channel_rx(vrtsim_state->channel, vrtsim_state->last_received_sample, nsamps, 0, samplesVoid[0]);
|
||||
if (ret == CHANNEL_ERROR_TOO_LATE) {
|
||||
vrtsim_state->rx_samples_late += nsamps;
|
||||
} else if (ret == CHANNEL_ERROR_TOO_EARLY) {
|
||||
vrtsim_state->rx_early += 1;
|
||||
}
|
||||
vrtsim_state->rx_samples_total += nsamps;
|
||||
*ptimestamp = vrtsim_state->last_received_sample;
|
||||
vrtsim_state->last_received_sample += nsamps;
|
||||
return nsamps;
|
||||
}
|
||||
|
||||
static void vrtsim_end(openair0_device *device)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
if (vrtsim_state->role == ROLE_SERVER) {
|
||||
vrtsim_state->run_timing_thread = false;
|
||||
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
tx_timing_t *tx_timing = vrtsim_state->tx_timing;
|
||||
if (vrtsim_state->chanmod) {
|
||||
for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
|
||||
shutdown_actor(&vrtsim_state->channel_modelling_actors[i]);
|
||||
}
|
||||
free(vrtsim_state->channel_modelling_actors);
|
||||
for (int i = 1; i < vrtsim_state->peer_info.num_rx_antennas; i++) {
|
||||
histogram_merge(&tx_timing->tx_histogram, &tx_timing[i].tx_histogram);
|
||||
tx_timing->tx_early += tx_timing[i].tx_early;
|
||||
tx_timing->tx_samples_late += tx_timing[i].tx_samples_late;
|
||||
tx_timing->average_tx_budget += tx_timing[i].average_tx_budget;
|
||||
tx_timing->tx_samples_total += tx_timing[i].tx_samples_total;
|
||||
}
|
||||
tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas;
|
||||
}
|
||||
// produce 1 second of extra samples so threads can finish
|
||||
shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate);
|
||||
sleep(1);
|
||||
shm_td_iq_channel_destroy(vrtsim_state->channel);
|
||||
|
||||
LOG_I(HW,
|
||||
"VRTSIM: Realtime issues: TX %.2f%%, RX %.2f%%\n",
|
||||
tx_timing->tx_samples_late / (float)tx_timing->tx_samples_total * 100,
|
||||
vrtsim_state->rx_samples_late / (float)vrtsim_state->rx_samples_total * 100);
|
||||
LOG_I(HW,
|
||||
"VRTSIM: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n",
|
||||
tx_timing->tx_early,
|
||||
vrtsim_state->rx_early);
|
||||
LOG_I(HW, "VRTSIM: Average TX budget %.3lf uS\n", tx_timing->average_tx_budget);
|
||||
histogram_print(&tx_timing->tx_histogram);
|
||||
free(vrtsim_state->tx_timing);
|
||||
}
|
||||
|
||||
static int vrtsim_stub(openair0_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int vrtsim_stub2(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vrtsim_set_freq(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
vrtsim_state_t *s = device->priv;
|
||||
s->rx_freq = openair0_cfg->rx_freq[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = calloc_or_fail(1, sizeof(vrtsim_state_t));
|
||||
vrtsim_readconfig(vrtsim_state);
|
||||
LOG_I(HW,
|
||||
"Running as %s\n",
|
||||
vrtsim_state->role == ROLE_SERVER ? "server: waiting for client to connect" : "client: will connect to a vrtsim server");
|
||||
device->trx_start_func = vrtsim_connect;
|
||||
device->trx_reset_stats_func = vrtsim_stub;
|
||||
device->trx_end_func = vrtsim_end;
|
||||
device->trx_stop_func = vrtsim_stub;
|
||||
device->trx_set_freq_func = vrtsim_set_freq;
|
||||
device->trx_set_gains_func = vrtsim_stub2;
|
||||
device->trx_write_func = vrtsim_write;
|
||||
device->trx_read_func = vrtsim_read;
|
||||
|
||||
device->type = RFSIMULATOR;
|
||||
device->openair0_cfg = &openair0_cfg[0];
|
||||
device->priv = vrtsim_state;
|
||||
device->trx_write_init = vrtsim_stub;
|
||||
vrtsim_state->last_received_sample = 0;
|
||||
vrtsim_state->sample_rate = openair0_cfg->sample_rate;
|
||||
vrtsim_state->rx_freq = openair0_cfg->rx_freq[0];
|
||||
vrtsim_state->tx_bw = openair0_cfg->tx_bw;
|
||||
vrtsim_state->tx_num_channels = openair0_cfg->tx_num_channels;
|
||||
vrtsim_state->rx_num_channels = openair0_cfg->rx_num_channels;
|
||||
|
||||
if (vrtsim_state->chanmod) {
|
||||
init_channelmod();
|
||||
int noise_power_dBFS = get_noise_power_dBFS();
|
||||
int16_t noise_power = noise_power_dBFS == INVALID_DBFS_VALUE ? 0 : (int16_t)(32767.0 / powf(10.0, .05 * -noise_power_dBFS));
|
||||
init_noise_device(noise_power);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
Active_gNBs = ( "gNB-OAI-DU");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_DU_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI-DU";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
|
||||
|
||||
nr_cellid = 1;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
pusch_AntennaPorts = 8;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
sib1_tda = 15;
|
||||
force_UL256qam_off = 1;
|
||||
maxMIMO_layers = 2;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
# n_TimingAdvanceOffset = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 3950.4 MHz
|
||||
# selected SSB frequency = 3950.4 MHz
|
||||
absoluteFrequencySSB = 663360;
|
||||
dl_frequencyBand = 77;
|
||||
# frequency point A = 3901.26 MHz
|
||||
dl_absoluteFrequencyPointA = 660084;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 273;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 77;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 273;
|
||||
pMax = 23;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 1099;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 152;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 0;
|
||||
preambleReceivedTargetPower = -100;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 8;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 3;
|
||||
#ra_ReponseWindow
|
||||
#1,2,4,8,10,20,40,80
|
||||
ra_ResponseWindow = 5;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 2;
|
||||
p0_NominalWithGrant = -96;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 0;
|
||||
p0_nominal = -96;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 0x1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5;
|
||||
nrofDownlinkSlots = 3;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = 10;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "f1";
|
||||
local_n_if_name = "enp193s0f0";
|
||||
local_n_address = "172.21.16.51";
|
||||
remote_n_address = "172.21.6.90";
|
||||
local_n_portc = 500;
|
||||
local_n_portd = 2153;
|
||||
remote_n_portc = 501;
|
||||
remote_n_portd = 2153;
|
||||
pusch_TargetSNRx10 = 120;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
dl_bler_target_upper = .35;
|
||||
dl_bler_target_lower = .15;
|
||||
ul_bler_target_upper = .35;
|
||||
ul_bler_target_lower = .15;
|
||||
pusch_FailureThres = 100;
|
||||
ul_max_mcs = 28;
|
||||
min_grant_prb = 1;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 100;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = 10;
|
||||
max_ldpc_iterations = 10;
|
||||
tx_amp_backoff_dB = 12; # needs to match O-RU configuration
|
||||
L1_rx_thread_core = 8;
|
||||
L1_tx_thread_core = 10; # relevant after merge of l1_tx_thread
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 8;
|
||||
nb_rx = 8;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 9;
|
||||
sl_ahead = 10;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:01:01.0", "0000:01:01.1", "0000:01:01.2", "0000:01:01.3"); # two VFs can be used as well
|
||||
system_core = 0;
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa");
|
||||
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69");
|
||||
vlan_tag = (5, 5, 6, 6);
|
||||
ru_ip_addr = ("192.168.80.5", "192.168.80.6");
|
||||
fh_config = (
|
||||
# RAN650 #1
|
||||
{
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
Ta4 = (0, 200);
|
||||
},
|
||||
# RAN650 #2
|
||||
{
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
Ta4 = (0, 200);
|
||||
});
|
||||
};
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
Active_gNBs = ( "gNB-OAI");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
|
||||
|
||||
nr_cellid = 1;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
maxMIMO_layers = 2;
|
||||
pusch_AntennaPorts = 4;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
sib1_tda = 15;
|
||||
# force_UL256qam_off = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
# n_TimingAdvanceOffset = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 3350.01 MHz
|
||||
# selected SSB frequency = 3349.92 MHz
|
||||
absoluteFrequencySSB = 623328;
|
||||
dl_frequencyBand = 78;
|
||||
# frequency point A = 3300.87 MHz
|
||||
dl_absoluteFrequencyPointA = 620058;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 273;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 78;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 273;
|
||||
pMax = 23;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 1099;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 152;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 0;
|
||||
preambleReceivedTargetPower = -100;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 8;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 3;
|
||||
#ra_ReponseWindow
|
||||
#1,2,4,8,10,20,40,80
|
||||
ra_ResponseWindow = 5;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 2;
|
||||
p0_NominalWithGrant = -96;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 0;
|
||||
p0_nominal = -96;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 0x1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 6;
|
||||
nrofDownlinkSlots = 7;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 2;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = 0;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 180;
|
||||
pucch_TargetSNRx10 = 220;
|
||||
dl_bler_target_upper = .35;
|
||||
dl_bler_target_lower = .15;
|
||||
ul_bler_target_upper = .35;
|
||||
ul_bler_target_lower = .15;
|
||||
pusch_FailureThres = 1000;
|
||||
ul_max_mcs = 28;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 100;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = 10;
|
||||
max_ldpc_iterations = 15;
|
||||
tx_amp_backoff_dB = 12; # needs to match O-RU configuration
|
||||
L1_rx_thread_core = 8;
|
||||
L1_tx_thread_core = 10;
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 4;
|
||||
nb_rx = 4;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 9;
|
||||
sl_ahead = 10;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well
|
||||
system_core = 0;
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa");
|
||||
du_addr = ("00:11:22:33:44:68","00:11:22:33:44:69");
|
||||
vlan_tag = (11, 11);
|
||||
ru_ip_addr = ("192.168.80.10");
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (419, 470);
|
||||
T1a_cp_ul = (285, 336);
|
||||
T1a_up = (294, 345);
|
||||
Ta4 = (0, 200);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,271 @@
|
||||
Active_gNBs = ( "oai-du");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "oai-du";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
|
||||
|
||||
nr_cellid = 1;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pdsch_AntennaPorts_N1 = 2;
|
||||
maxMIMO_layers = 2;
|
||||
pusch_AntennaPorts = 4;
|
||||
do_CSIRS = 1;
|
||||
do_SRS = 0;
|
||||
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# selected SSB frequency = 3748.80 MHz
|
||||
absoluteFrequencySSB = 649920;
|
||||
dl_frequencyBand = 78;
|
||||
# frequency point A = 3700.86 MHz
|
||||
dl_absoluteFrequencyPointA = 646724;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 273;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
#this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart))
|
||||
initialDLBWPlocationAndBandwidth = 1099;
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 12;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 78;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 273;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 1099;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 151;# testMAC 158; OAI gNB 98
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 12;
|
||||
preambleReceivedTargetPower = -96;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 6;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 1;
|
||||
#ra_ReponseWindow
|
||||
#1,2,4,8,10,20,40,80
|
||||
ra_ResponseWindow = 5;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3;
|
||||
#oneHalf (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 1;
|
||||
p0_NominalWithGrant = -90;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 40;
|
||||
p0_nominal = -90;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5; #6;
|
||||
nrofDownlinkSlots = 3; #7;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1; #2;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = 0;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 120;
|
||||
pucch_TargetSNRx10 = 260;
|
||||
ul_bler_target_upper = .35;
|
||||
ul_bler_target_lower = .15;
|
||||
pusch_FailureThres = 100;
|
||||
ul_max_mcs = 28;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 130;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = 10;
|
||||
max_ldpc_iterations = 15;
|
||||
tx_amp_backoff_dB = 24; # needs to match O-RU configuration
|
||||
L1_rx_thread_core = 8;
|
||||
L1_tx_thread_core = 10;
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 4;
|
||||
nb_rx = 4;
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 9;
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1");
|
||||
system_core = 0;
|
||||
io_core = 1;
|
||||
worker_cores = (2);
|
||||
ru_addr = ("6c:ad:ad:00:04:dc", "6c:ad:ad:00:04:dc");
|
||||
mtu = 8000;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
T1a_up = (96, 196);
|
||||
Ta4 = (0, 75);
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
};
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user