Commit fca1971a authored by Jaroslava Fiedlerova's avatar Jaroslava Fiedlerova

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
parents 1d479b2a 90bdcaaf
Branches unavailable
2025.w14 2025.w13
No related merge requests found
......@@ -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"
......
# - 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)
......@@ -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
......
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; \
......
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()
This diff is collapsed.
/*
* 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
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)
/*
* 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;
}
This diff is collapsed.
......@@ -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.
......
......@@ -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"
......
......@@ -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()
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})
/*
* 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;
}
/*
* 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 */
/*
* 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();
}
/*
* 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 */
/*
* 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;
}
/*
* 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 */
/*
* 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;
}
/*
* 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 */
This diff is collapsed.
/*
* 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 */
/*
* 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;
}
/*
* 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 */
/*
* 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;
}
/*
* 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 */
/*
* 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);
}
/*
* 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 */
This diff is collapsed.
/*
* 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 */
/*
* 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;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment