Merge remote-tracking branch 'origin/fhi72-mplane' into integration_2025_w13 (!3216)

FHI72: Management plane support

At the moment, tested with Benetel 550 and 650 RUs FW v1.2.2
- support for multiple RUs
- RPCs implemented: <connect>, <subscribe>, <get>, <supervision-watchdog-reset>,
  <edit-config>, <validate>, <commit>, <disconnect>
- read PTP sync status from operational datastore xml
- get vendor name, and for xran store RU MAC, MTU and IQ bitwidth and PRACH
  offset, and transfer this info
- store interface name, low-level-tx/rx-endpoint names, tx/rx-carrier names,...,
  from operational datastore xml
- add reference gNB/DU config files with M-plane support
- update FHI readme
This commit is contained in:
Jaroslava Fiedlerova
2025-03-31 15:29:58 +02:00
47 changed files with 13344 additions and 193 deletions
+5 -7
View File
@@ -99,7 +99,7 @@ Options:
USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default) USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default)
Adds this RF board support (in external packages installation and in compilation) Adds this RF board support (in external packages installation and in compilation)
-t | --transport -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 -P | --phy_simulators
Makes the unitary tests Layer 1 simulators Makes the unitary tests Layer 1 simulators
-s | --check -s | --check
@@ -304,6 +304,10 @@ function main() {
TARGET_LIST="$TARGET_LIST $2" TARGET_LIST="$TARGET_LIST $2"
CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON" 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") "None")
;; ;;
*) *)
@@ -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" echo_info "Built Doxygen based documentation. The documentation file is located here: $DIR/$BUILD_DIR/build/doc/html/index.html"
fi 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 if [ "$UE" = 1 ] ; then
echo_info "Compiling UE specific part" echo_info "Compiling UE specific part"
@@ -1,53 +0,0 @@
# - Try to find the LibXml2 xml processing library
# Once done this will define
#
# LIBXML2_FOUND - System has LibXml2
# LIBXML2_INCLUDE_DIR - The LibXml2 include directory
# LIBXML2_LIBRARIES - The libraries needed to use LibXml2
# LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2
# LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2
#=============================================================================
# Copyright 2006-2009 Kitware, Inc.
# Copyright 2006 Alexander Neundorf <neundorf@kde.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distributed this file outside of CMake, substitute the full
# License text for the above reference.)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PC_LIBXML libxml-2.0)
SET(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})
FIND_PATH(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h
HINTS
${PC_LIBXML_INCLUDEDIR}
${PC_LIBXML_INCLUDE_DIRS}
PATH_SUFFIXES libxml2
)
FIND_LIBRARY(LIBXML2_LIBRARIES NAMES xml2 libxml2
HINTS
${PC_LIBXML_LIBDIR}
${PC_LIBXML_LIBRARY_DIRS}
)
FIND_PROGRAM(LIBXML2_XMLLINT_EXECUTABLE xmllint)
# for backwards compat. with KDE 4.0.x:
SET(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}")
# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE)
+6 -4
View File
@@ -75,7 +75,6 @@ endif()
find_path(xran_INCLUDE_DIR find_path(xran_INCLUDE_DIR
NAMES NAMES
xran_common.h
xran_compression.h xran_compression.h
xran_cp_api.h xran_cp_api.h
xran_ecpri_owd_measurements.h xran_ecpri_owd_measurements.h
@@ -84,7 +83,7 @@ find_path(xran_INCLUDE_DIR
xran_pkt_up.h xran_pkt_up.h
xran_sync_api.h xran_sync_api.h
HINTS ${xran_LOCATION} HINTS ${xran_LOCATION}
PATH_SUFFIXES api include PATH_SUFFIXES api
NO_DEFAULT_PATH NO_DEFAULT_PATH
) )
find_library(xran_LIBRARY find_library(xran_LIBRARY
@@ -127,16 +126,19 @@ find_package_handle_standard_args(xran
VERSION_VAR xran_VERSION 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) if(xran_FOUND)
set(xran_LIBRARIES ${xran_LIBRARY}) set(xran_LIBRARIES ${xran_LIBRARY})
set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR}) set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR} ${xran_INCLUDE_DIR}/../src)
endif() endif()
if(xran_FOUND AND NOT TARGET xran::xran) if(xran_FOUND AND NOT TARGET xran::xran)
add_library(xran::xran UNKNOWN IMPORTED) add_library(xran::xran UNKNOWN IMPORTED)
set_target_properties(xran::xran PROPERTIES set_target_properties(xran::xran PROPERTIES
IMPORTED_LOCATION "${xran_LIBRARY}" IMPORTED_LOCATION "${xran_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIR}" INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIRS}"
) )
endif() endif()
+8 -2
View File
@@ -546,7 +546,10 @@ check_install_additional_tools (){
libforms-bin \ libforms-bin \
libforms-dev \ libforms-dev \
libxft-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 elif [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]] || [[ "$OS_DISTRO" == "rocky" ]] || [[ "$OS_DISTRO" == "fedora" ]]; then
PACKAGE_LIST="\ PACKAGE_LIST="\
doxygen \ doxygen \
@@ -556,7 +559,10 @@ check_install_additional_tools (){
libXft-devel \ libXft-devel \
xforms \ xforms \
xforms-devel \ xforms-devel \
xmlstarlet" xmlstarlet \
pcre-devel \
libssh-devel \
libxml2-devel"
fi fi
$SUDO $INSTALLER install -y $PACKAGE_LIST $optional_packages $SUDO $INSTALLER install -y $PACKAGE_LIST $optional_packages
} }
+19 -11
View File
@@ -52,6 +52,13 @@
// main log variables // 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 // Fixme: a better place to be shure it is called
void read_cpu_hardware (void) __attribute__ ((constructor)); void read_cpu_hardware (void) __attribute__ ((constructor));
#if !defined(__arm__) && !defined(__aarch64__) #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 * correctly. It was not a big problem because in practice MAX_LOG_TOTAL is
* big enough so that the buffer is never full. * 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 // make sure that for log trace the extra info is only printed once, reset when the level changes
if (level < OAILOG_TRACE) { 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) { if (n > 0) {
len += n; len += n;
if (len > MAX_LOG_TOTAL) { if (len > sizeof(log_buffer)) {
len = MAX_LOG_TOTAL; 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) { if (n > 0) {
len += n; len += n;
if (len > MAX_LOG_TOTAL) { if (len > sizeof(log_buffer)) {
len = MAX_LOG_TOTAL; len = sizeof(log_buffer);
} }
} }
if (!((g_log->flag) & FLAG_NOCOLOR)) { 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) { if (n > 0) {
len += n; len += n;
if (len > MAX_LOG_TOTAL) { if (len > sizeof(log_buffer)) {
len = MAX_LOG_TOTAL; len = sizeof(log_buffer);
} }
} }
} }
@@ -941,7 +949,7 @@ static void log_output_memory(log_component_t *c, const char *file, const char *
} }
} }
}else{ }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)) {}; if (write(fileno(c->stream), log_buffer, len)) {};
} }
} }
-6
View File
@@ -65,12 +65,6 @@
extern "C" { extern "C" {
#endif #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 /** @defgroup _log_level Message levels defined by LOG
+814 -17
View File
@@ -977,10 +977,8 @@ Edit the sample OAI gNB configuration file and check following parameters:
including the advantages and disadvantages of each mode, refer to including the advantages and disadvantages of each mode, refer to
[Memory in DPDK](https://www.dpdk.org/memory-in-dpdk-part-2-deep-dive-into-iova/) [Memory in DPDK](https://www.dpdk.org/memory-in-dpdk-part-2-deep-dive-into-iova/)
* `owdm_enable`: used for eCPRI One-Way Delay Measurements; it depends if the RU supports it; if not set to 1 (enabled), default value is 0 (disabled) * `owdm_enable`: used for eCPRI One-Way Delay Measurements; it depends if the RU supports it; if not set to 1 (enabled), default value is 0 (disabled)
* `fh_config`: parameters that need to match RU parameters * `fh_config`
* timing parameters (starting with `T`) depend on the RU: `Tadv_cp_dl` is a * DU delay profile (`T1a` and `Ta4`): pairs of numbers `(x, y)` specifying minimum and maximum delays
single number, the rest pairs of numbers `(x, y)` specifying minimum and
maximum delays
* `ru_config`: RU-specific configuration: * `ru_config`: RU-specific configuration:
* `iq_width`: Width of DL/UL IQ samples: if 16, no compression, if <16, applies * `iq_width`: Width of DL/UL IQ samples: if 16, no compression, if <16, applies
compression compression
@@ -1001,7 +999,7 @@ Layer mapping (eAxC offsets) happens as follows:
**Note** **Note**
- At the moment, OAI is compatible with CAT A O-RU only. Therefore, SRS is not supported. - At the moment, OAI is compatible with CAT A O-RU only. Therefore, SRS is not supported.
- XRAN retreives DU MAC address with `rte_eth_macaddr_get()` function. Hence, `fhi_72.du_addr` parameter is not taken into account. - XRAN retrieves DU MAC address with `rte_eth_macaddr_get()` function. Hence, `fhi_72.du_addr` parameter is not taken into account.
# Start and Operation of OAI gNB # Start and Operation of OAI gNB
@@ -1129,10 +1127,10 @@ fhi_72 = {
// mtu // mtu
fh_config = ( fh_config = (
{ {
// timing, ru_config, prach_config of RU1 // DU delay profile, ru_config, prach_config of RU1
}, },
{ {
// timing, ru_config, prach_config of RU2 // DU delay profile, ru_config, prach_config of RU2
} }
); );
}; };
@@ -1156,11 +1154,6 @@ fhi_72 = {
fh_config = ( fh_config = (
# RAN650 #1 # RAN650 #1
{ {
Tadv_cp_dl = 125;
T2a_cp_dl = (259, 500);
T2a_cp_ul = (25, 500);
T2a_up = (134, 375);
Ta3 = (152, 160);
T1a_cp_dl = (419, 470); T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336); T1a_cp_ul = (285, 336);
T1a_up = (294, 345); T1a_up = (294, 345);
@@ -1172,11 +1165,6 @@ fhi_72 = {
}, },
# RAN650 #2 # RAN650 #2
{ {
Tadv_cp_dl = 125;
T2a_cp_dl = (259, 500);
T2a_cp_ul = (25, 500);
T2a_up = (134, 375);
Ta3 = (152, 160);
T1a_cp_dl = (419, 470); T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336); T1a_cp_ul = (285, 336);
T1a_up = (294, 345); T1a_up = (294, 345);
@@ -1220,6 +1208,815 @@ Note the eight entries after `avg_IO`.
You should be able to connect a UE now. You should be able to connect a UE now.
# OAI Management Plane
We support Configuration Management in OAI gNB, where gNB configures CU-planes, interfaces, TX/RX antennas, and TX/RX carriers for the RU.
The reference specifications:
* `O-RAN.WG4.MP.0-v05.00`
* `O-RAN.WG4.MP-YANGs-v04.00`
## M-plane prerequisites
Before proceeding, please make sure you have a support for 7.2 interface, as described in [Prerequisites](#prerequisites).
### DHCP server
The M-plane requires a DHCP server, where the M-plane connection can be established over untagged or tagged VLAN. We tested with untagged (the default VLAN is 1).
Please modify `/etc/dhcp/dhcpd.conf` configuration based on your testbed.
<details>
<summary>Example DHCP server configuration</summary>
```
class "vendor-class" {
match option vendor-class-identifier;
}
subclass "vendor-class" "o-ran-ru2/Benetel" {
vendor-option-space VC;
}
option space VC;
option VC.server-address code 129 = array of ip-address;
option VC.server-fqdn code 130 = string;
# Netconf client IP address - DHCP option 43
option VC.server-address 192.168.80.1;
option VC.server-fqdn "o_du_1.operator.com";
set vendor-string = option vendor-class-identifier;
# option 143 - DHCPv4 SZTP Redirect Option (RFC8572)
# 2 bytes of URI's length + URI
option sztp code 143 = { unsigned integer 16, string };
option sztp 15 "https://192.168.80.1";
# port is optional in URI, e.g. "https://192.168.80.1:222"
#option sztp 20 "https://192.168.80.1:2222";
subnet 192.168.80.0 netmask 255.255.255.0 {
option routers 192.168.80.1;
option subnet-mask 255.255.255.0;
option domain-name "oai.com";
option domain-name-servers 172.21.3.100;
host benetel_ru {
# RU MAC address
hardware ethernet <ru-mac-address>;
# RU IP address
fixed-address <desired-ru-ip-address>;
}
}
```
</details>
Please, configure the interface as:
```bash
sudo ip address add 192.168.80.1/24 dev <interface>
```
### Mandatory packages
* On Fedora (we haven't yet tested RHEL):
```bash
sudo dnf install pcre-devel libssh-devel libxml2-devel libyang2-devel libnetconf2-devel
```
* On Ubuntu:
```bash
sudo apt-get install libpcre3-dev libssh-dev libxml2-dev
```
On Ubuntu, please note: `sudo apt-get install libyang2-dev libnetconf2-dev` will install unsupported versions (i.e. v2.0.112/v2.0.24 for `libyang2-dev`/`libnetconf2-dev`, but minimum required are v2.1.4/v2.1.25).
Therefore, please compile these libraries from source, as following:
<details>
<summary>Installing latest v2 libyang2 and libnetconf2 libraries</summary>
```
rm -rf /tmp/build_mplane_v2
mkdir /tmp/build_mplane_v2
# libyang
cd /tmp/build_mplane_v2
git clone https://github.com/CESNET/libyang.git
cd libyang
git checkout v2.1.111
mkdir build && cd build
cmake -DENABLE_TESTS=OFF \
-DENABLE_VALGRIND_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_INSTALL_RPATH=/usr/local/lib \
-DPLUGINS_DIR=/usr/local/lib/libyang \
-DPLUGINS_DIR_EXTENSIONS=/usr/local/lib/libyang/extensions \
-DPLUGINS_DIR_TYPES=/usr/local/lib/libyang/types \
-DYANG_MODULE_DIR=/usr/local/share/yang/modules/libyang ..
make -j8
sudo make install
sudo ldconfig
#libnetconf
cd /tmp/build_mplane_v2
git clone https://github.com/CESNET/libnetconf2.git
cd libnetconf2
git checkout v2.1.37
mkdir build && cd build
cmake -DENABLE_TESTS=OFF \
-DENABLE_EXAMPLES=OFF \
-DENABLE_VALGRIND_TESTS=OFF \
-DCLIENT_SEARCH_DIR=/usr/local/share/yang/modules \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DCMAKE_INSTALL_RPATH=/usr/local/lib \
-DLIBYANG_INCLUDE_DIR=/usr/local/include \
-DLIBYANG_LIBRARY=/usr/local/lib/libyang.so \
-DLY_VERSION_PATH=/usr/local/include \
-DYANG_MODULE_DIR=/usr/local/share/yang/modules/libnetconf2 ..
make -j8
sudo make install
sudo ldconfig
# to uninstall libraries
# cd /tmp/build_mplane_v2/libyang/build && sudo make uninstall
# cd /tmp/build_mplane_v2/libnetconf2/build && sudo make uninstall
# cd
# rm -rf /tmp/build_mplane_v2
```
</details>
If you would like to install these libraries in the custom path, please replace `/usr/local` default path to e.g. `/opt/mplane-v2`.
## Benetel O-RU
Note: Only v1.2.2 RAN550 and RAN650 have been successfully tested.
### One time steps
Connect to the RU as user `root`, enable the mplane service, and reboot:
```bash
ssh root@<ru-ip-address>
systemctl enable mplane
reboot
```
Once the mplane service is successfully enabled on the RU, two new users are being added in `/etc/passwd`:
```bash
...
oranbenetel:x:1000:1000::/home/oranbenetel:/bin/sh
oranext:x:1001:1001::/home/oranext:/bin/sh
```
Create `oranbenetel` home directory:
```bash
mkdir /home/oranbenetel && chown oranbenetel:oranbenetel /home/oranbenetel
```
Connect to the RU as user `oranbenetel`, generate ssh keys, and copy DU public key into RU for NETCONF authentication:
```bash
ssh oranbenetel@<ru-ip-address>
ssh-keygen
echo "<DU-pub-key>" >> ~/.ssh/authorized_keys
```
## gNB configuration
The reference gNB configuration file for one Benetel RAN550:
[`gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf)
The reference DU configuration file for two Benetel RAN650:
[gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf)
In order to run gNB/DU with M-plane, we need to modify the `fhi_72` section in the configuration file.
Example for one RU:
```bash
fhi_72 = {
dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1"); # one VF can be used as well
system_core = 0;
io_core = 1;
worker_cores = (2);
du_key_pair = ("<path-to>/.ssh/id_rsa.pub", "<path-to>/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67"); # only one needed if one VF configured
vlan_tag = (9, 9); # only one needed if one VF configured
ru_ip_addr = ("192.168.80.9");
fh_config = ({
T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336);
T1a_up = (294, 345);
Ta4 = (0, 200);
});
};
```
Example for two RUs:
```bash
fhi_72 = {
dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1", "0000:c3:11.2", "0000:c3:11.3"); # two VFs can be used as well
system_core = 0;
io_core = 1;
worker_cores = (2);
du_key_pair = ("/home/oaicicd/.ssh/id_rsa.pub", "/home/oaicicd/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); # only two needed if two VFs configured
vlan_tag = (9, 9, 11, 11); # only two needed if two VFs configured
ru_ip_addr = ("192.168.80.9", "192.168.80.10");
fh_config = (
# RAN550 #1
{
T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336);
T1a_up = (294, 345);
Ta4 = (0, 200);
},
# RAN550 #2
{
T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336);
T1a_up = (294, 345);
Ta4 = (0, 200);
});
};
```
* `fhi_72` :
* `dpdk_devices`: [*]
* `system_core`: [*]
* `io_core`: [*]
* `worker_cores`: [*]
* `file_prefix`: [*]
* `du_key_pair`: ssh public and private keys to authenticate RU with NETCONF
* `du_addr`: DU MAC address(es) to create CU-plane interface(s) in the RU
* `vlan_tag`: VLAN U and C plane tags to create CU-plane interface(s) in the RU
* `ru_ip_addr`: RU IP address to connect to the RU via M-plane
* `dpdk_mem_size`: [*]
* `dpdk_iova_mode`: [*]
* `owdm_enable`: [*]
* `fh_config`: only DU delay profile (`T1a` and `Ta4`)
[*] see [Configure OAI gNB](#configure-oai-gnb) for more details
The following parameters are retrieved from the RU and forwarded to the xran:
* `MTU`
* `RU MAC address`
* `IQ compression`: if RU supports multiple, the first value in the list is taken; please note that the same value is used for PxSCH/PRACH
* `PRACH offset`: hardcoded based on the RU vendor (i.e. for Benetel `max(Nrx,Ntx)`)
## Build and compile gNB
The following cmake options are available:
* `OAI_FHI72` = CUS support
* `OAI_FHI72_MPLANE` = M support
Compiled libraries:
* `OAI_FHI72` <=> `oran_fhlib_5g`
* `OAI_FHI72` && `OAI_FHI72_MPLANE` <=> `oran_fhlib_5g` (CUS) && `oran_fhlib_5g_mplane` (CUSM)
### Using build_oai script
```bash
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
cd ~/openairinterface5g/cmake_targets/
./build_oai -I # if you never installed OAI, use this command once before the next line
./build_oai --install-optional-packages # for pcre/libpcre3, libssh, and libxml2 library installation
./build_oai --gNB --ninja -t oran_fhlib_5g_mplane --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
# if libyang2 and libnetconf2 are installed in `/opt/mplane-v2`, please use the following command:
PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig ./build_oai --gNB --ninja -t oran_fhlib_5g_mplane --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
```
### Using cmake directly
```bash
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
cd ~/openairinterface5g/
mkdir build && cd build
cmake .. -GNinja -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
# if libyang2 and libnetconf2 are installed in `/opt/mplane-v2`, please use the following command:
PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig cmake .. -GNinja -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
ninja nr-softmodem oran_fhlib_5g_mplane params_libconfig
```
## Start the gNB
Run the `nr-softmodem` from the build directory:
```bash
cd ~/openairinterface5g/cmake_targets/ran_build/build
sudo ./nr-softmodem -O <mplane-configuration file> --thread-pool <list of non isolated cpus>
```
**Warning**: Make sure that the configuration file you add after the `-O` option is adapted to your machine, especially to its isolated cores.
M-plane sequence diagram:
```mermaid
sequenceDiagram
participant dhcp as DHCP server
participant du as O-DU
participant ru as O-RU
dhcp->ru: 1. Transport Layer Initialization
note over dhcp,ru: (a) perform VLAN scan (untagged or tagged VLAN)<br/>(b) DHCP assigns IP address to RU<br/>(c) DHCP sends DU IP address to RU
du->ru: 2. NETCONF/SSH connect
du->>ru: 3. DU retrieves RU info
note left of du: <get>
note over du: Check if RU is PTP synced
du->>ru: 4. DU subscribes to all RU notifications
note left of du: <subscribe>
du->>ru: 5. DU updates the supervision timer
note left of du: <supervision-watchdog-reset>
note over du: Store RU MAC, MTU, IQ bitwidth, and PRACH offset info for xran
note over du: Store all the RU U-plane info - interface name, TX/RX carrier, and TX/RX endpoint names
du->>ru: 6. DU loads yang models
note left of du: <get-schema>
note right of ru: ietf-netconf-monitoring.yang
du->>ru: 7. DU performs CU-plane configuration
note left of du: <edit-config>
note over ru: (1) o-ran-interface.yang - create new interface with VLAN tag, DU and RU MAC addresses<br/>(2)(opt.) o-ran-transceiver.yang - for file upload<br/>(3) o-ran-processing-elements.yang - element with which RU ports should be assigned<br/>(4) o-ran-uplane-conf.yang<br/>#8193;(4a) low-level-tx/rx-endpoints - PxSCH, PRACH<br/>#8193;(4b) tx/rx-array-carriers - center frequency, BW, gain, ACTIVE,...<br/>#8193;(4c) low-level-tx/rx-links - mapping endpoints, carriers and processing element<br/>#8193;(4d)(opt.) if CAT B, SRS configuration<br/>#8193;(4e)(opt.) TDD configuration
du->>ru: 8. DU checks if CU-plane configuration is valid
note left of du: <validate>
du->>ru: 9. If valid, DU commits the changes
note left of du: <commit>
du->>ru: 10. DU retrieves RU states
note right of ru: ietf-hardware.yang
note left of du: <get>
note over ru: admin-state, power-state, oper-state,<br/>availability-state, usage-state
ru->>du: 11. RU notifies DU about the configuration change
note over du: DU configures xran
du->ru: 12. DU and RU exchange packets
```
<details>
<summary>4x4 MIMO and 100MHz BW with Benetel 550 RU example run</summary>
```
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <connect> with username "oranbenetel" and port ID "830".
[HW] [MPLANE] Successfuly connected to RU "192.168.80.9" with username "oranbenetel" and port ID "830".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get> operational datastore.
[HW] [MPLANE] Successfully retrieved operational datastore from RU "192.168.80.9".
[HW] [MPLANE] RU is already PTP synchronized.
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <subscribe> with stream "NETCONF" and filter "(null)".
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully subscribed to all notifications from RU "192.168.80.9".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = "<supervision-watchdog-reset xmlns="urn:o-ran:supervision:1.0">
<supervision-notification-interval>65535</supervision-notification-interval>
<guard-timer-overhead>65535</guard-timer-overhead>
</supervision-watchdog-reset>".
[HW] [MPLANE] Successfully updated supervision timer to (65535+65535)[s] for RU "192.168.80.9".
[HW] [MPLANE] Watchdog timer answer:
<next-update-at xmlns="urn:o-ran:supervision:1.0">2025-03-30T08:52:31+02:00</next-update-at>
[HW] [MPLANE] Interface MTU 1500 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.
[HW] [MPLANE] IQ bitwidth 16 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9.
[HW] [MPLANE] Storing the following information to forward to xran:
RU MAC address 8c:1f:64:d1:11:c0
MTU 9600
IQ bitwidth 9
PRACH offset 4
DU port bitmask 61440
Band sector bitmask 3840
CC ID bitmask 240
RU port ID bitmask 15
DU port ID 0
Band sector ID 0
CC ID 0
RU port ID 0
[HW] [MPLANE] Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-metadata".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "yang".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-inet-types".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-types".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-schema-mount".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-structure-ext".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-datastores".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-acm".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-factory-default".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo-factory-default".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-library".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo-monitoring".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "sysrepo-plugind".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-with-defaults".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-notifications".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-origin".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-monitoring".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-netconf-nmda".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "nc-notifications".
[HW] [MPLANE] [LIBYANG] ERROR: Data model "notifications" not found in local searchdirs. (path: (null)).
[HW] [MPLANE] [LIBYANG] ERROR: Loading "notifications" module failed. (path: (null)).
[HW] [MPLANE] [LIBYANG] ERROR: Parsing module "nc-notifications" failed. (path: (null)).
[HW] [MPLANE] Unable to load module "nc-notifications" from RU "192.168.80.9".
[HW] [MPLANE] Unable to load all yang modules from operational datastore for RU "192.168.80.9". Using yang models present in "models" subfolder.
[HW] [MPLANE] Successfully loaded all yang modules for RU "192.168.80.9".
[HW] [MPLANE] The VLAN tags for C and U plane for the RU "192.168.80.9" are the same. Therefore, configuring one common interface and one processing element.
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <edit-config>:
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
<interface>
<name>INTERFACE_0</name>
<type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:l2vlan</type>
<enabled>true</enabled>
<mac-address xmlns="urn:o-ran:interfaces:1.0">8c:1f:64:d1:11:c0</mac-address>
<base-interface xmlns="urn:o-ran:interfaces:1.0">eth0</base-interface>
<vlan-id xmlns="urn:o-ran:interfaces:1.0">9</vlan-id>
</interface>
</interfaces>
<processing-elements xmlns="urn:o-ran:processing-element:1.0">
<transport-session-type>ETH-INTERFACE</transport-session-type>
<ru-elements>
<name>PLANE_0</name>
<transport-flow>
<interface-name>INTERFACE_0</interface-name>
<eth-flow>
<ru-mac-address>8c:1f:64:d1:11:c0</ru-mac-address>
<vlan-id>9</vlan-id>
<o-du-mac-address>00:11:22:33:44:66</o-du-mac-address>
</eth-flow>
</transport-flow>
</ru-elements>
</processing-elements>
<user-plane-configuration xmlns="urn:o-ran:uplane-conf:1.0">
<low-level-tx-links>
<name>PdschLink0</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray0</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint0</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-tx-links>
<name>PdschLink1</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray0</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint1</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-tx-links>
<name>PdschLink2</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray0</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint2</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-tx-links>
<name>PdschLink3</name>
<processing-element>PLANE_0</processing-element>
<tx-array-carrier>TxArray0</tx-array-carrier>
<low-level-tx-endpoint>LowLevelTxEndpoint3</low-level-tx-endpoint>
</low-level-tx-links>
<low-level-rx-links>
<name>PuschLink0</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint0</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink0</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint0</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PuschLink1</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint1</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink1</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint1</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PuschLink2</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint2</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink2</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint2</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PuschLink3</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxEndpoint3</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-rx-links>
<name>PrachLink3</name>
<processing-element>PLANE_0</processing-element>
<rx-array-carrier>RxArray0</rx-array-carrier>
<low-level-rx-endpoint>LowLevelRxPrachEndpoint3</low-level-rx-endpoint>
</low-level-rx-links>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint0</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>0</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint1</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>1</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint2</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>2</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-tx-endpoints>
<name>LowLevelTxEndpoint3</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>3</eaxc-id>
</e-axcid>
</low-level-tx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint0</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>0</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint0</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>4</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint1</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>1</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint1</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>5</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint2</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>2</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint2</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>6</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint3</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>3</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint3</name>
<compression>
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
<ccid-bitmask>240</ccid-bitmask>
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>7</eaxc-id>
</e-axcid>
</low-level-rx-endpoints>
<tx-array-carriers>
<name>TxArray0</name>
<absolute-frequency-center>663360</absolute-frequency-center>
<center-of-channel-bandwidth>3950400000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<gain>0.0</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers>
<rx-array-carriers>
<name>RxArray0</name>
<absolute-frequency-center>663360</absolute-frequency-center>
<center-of-channel-bandwidth>3950400000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
<gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset>
</rx-array-carriers>
</user-plane-configuration>
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.80.9".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <validate> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <commit> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully commited CU-planes configuration into running datastore for RU "192.168.80.9".
[HW] [MPLANE] Usage state = "idle" for RU "192.168.80.9".
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.049085102+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray0",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.058136880+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray0",
"state": "BUSY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.078776163+00:00)
{
"o-ran-uplane-conf:rx-array-carriers-state-change": {
"rx-array-carriers": [
{
"name": "RxArray0",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.093039138+00:00)
{
"o-ran-uplane-conf:tx-array-carriers-state-change": {
"tx-array-carriers": [
{
"name": "TxArray0",
"state": "READY"
}
]
}
}
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.452751936+00:00)
{
"ietf-netconf-notifications:netconf-config-change": {
"changed-by": {
"username": "root",
"session-id": 0
},
"datastore": "running",
"edit": [
{
"target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']",
"operation": "create"
},
{
"target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']/name",
"operation": "create"
},
...
}
[HW] [MPLANE] RU "192.168.80.9" is now ready.
```
</details>
Note: If you wish to run the fronthaul without M-plane, no need for recompilation, as the library `oran_fhlib_5g` already exists.
The only mandatory step is to link `oran_fhlib_5g` to `oai_transpro` library.
```bash
cd ~/openairinterface5g/cmake_targets/ran_build/build
rm liboai_transpro.so
ln -s liboran_fhlib_5g.so liboai_transpro.so
sudo ./nr-softmodem -O <without-mplane-configuration file> --thread-pool <list of non isolated cpus>
```
# Contact in case of questions # Contact in case of questions
You can ask your question on the [mailing lists](https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/MailingList). You can ask your question on the [mailing lists](https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/MailingList).
+8 -7
View File
@@ -30,18 +30,19 @@ endif()
add_compile_options(-Wno-packed-not-aligned) add_compile_options(-Wno-packed-not-aligned)
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") 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 xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa)
target_link_libraries(oran_fhlib_5g PRIVATE ${dpdk_LINK_LIBRARIES})
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) 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) 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}) set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_custom_command(TARGET oran_fhlib_5g POST_BUILD add_custom_command(TARGET oran_fhlib_5g POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 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()
+73
View File
@@ -0,0 +1,73 @@
add_library(oran_fhlib_5g_mplane MODULE
../oran_isolate.c
../oaioran.c
../oran-config.c
../oran-init.c
)
add_dependencies(oran_fhlib_5g_mplane oran_fhlib_5g)
if(xran_VERSION VERSION_EQUAL 5.1.4)
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE E_RELEASE)
elseif(xran_VERSION VERSION_EQUAL 6.1.1)
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE F_RELEASE)
endif()
# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress
# alignment 1 of 'struct XYZ' is less than 2
add_compile_options(-Wno-packed-not-aligned)
set_target_properties(oran_fhlib_5g_mplane PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
target_link_libraries(oran_fhlib_5g_mplane PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa)
target_include_directories(oran_fhlib_5g_mplane PRIVATE ${dpdk_INCLUDE_DIRS})
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE)
###################################################
target_sources(oran_fhlib_5g_mplane PRIVATE
init-mplane.c
connect-mplane.c
rpc-send-recv.c
get-mplane.c
subscribe-mplane.c
config-mplane.c
ru-mplane-api.c
xml/get-xml.c
yang/get-yang.c
yang/create-yang-config.c
)
pkg_check_modules(libyang REQUIRED libyang)
pkg_check_modules(libnetconf2 REQUIRED libnetconf2)
if(libyang_VERSION VERSION_LESS_EQUAL 1.0.240 AND libnetconf2_VERSION VERSION_LESS_EQUAL 1.1.46)
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE MPLANE_V1)
elseif((libyang_VERSION VERSION_GREATER 1.0.240 AND libyang_VERSION VERSION_LESS 2.1.4))
message(FATAL_ERROR "Minimum libyang v2 subversion required is v2.1.4, but found ${libyang_VERSION}")
elseif((libnetconf2_VERSION VERSION_GREATER 1.1.46 AND libnetconf2_VERSION VERSION_LESS 2.1.25))
message(FATAL_ERROR "Minimum libnetconf2 v2 subversion required is v2.1.25, but found ${libnetconf2_VERSION}")
elseif((libyang_VERSION VERSION_GREATER_EQUAL 2.1.4 AND libyang_VERSION VERSION_LESS_EQUAL 2.1.111) AND (libnetconf2_VERSION VERSION_GREATER_EQUAL 2.1.25 AND libnetconf2_VERSION VERSION_LESS_EQUAL 2.1.37))
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE MPLANE_V2)
else()
message(FATAL_ERROR "Unknown libyang version ${libyang_VERSION} and libnetconf2 version ${libnetconf2_VERSION}")
endif()
target_include_directories(oran_fhlib_5g_mplane PRIVATE ${libyang_INCLUDE_DIRS} ${libnetconf2_INCLUDE_DIRS})
target_link_libraries(oran_fhlib_5g_mplane PRIVATE ${libyang_LDFLAGS} ${libyang_LINK_LIBRARIES} ${libnetconf2_LINK_LIBRARIES})
pkg_check_modules(libssh REQUIRED libssh)
target_include_directories(oran_fhlib_5g_mplane PRIVATE ${libssh_INCLUDE_DIRS})
target_link_libraries(oran_fhlib_5g_mplane PRIVATE ${libssh_LINK_LIBRARIES})
find_package(LibXml2 REQUIRED)
target_link_libraries(oran_fhlib_5g_mplane PRIVATE LibXml2::LibXml2)
set(YANG_MODELS "${CMAKE_SOURCE_DIR}/radio/fhi_72/mplane/yang/models")
target_compile_definitions(oran_fhlib_5g_mplane PRIVATE YANG_MODELS="${YANG_MODELS}")
message(STATUS "Building FHI72 CUSM library")
set_target_properties(oran_fhlib_5g_mplane PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_custom_command(TARGET oran_fhlib_5g_mplane POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g_mplane.so liboai_transpro.so
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+117
View File
@@ -0,0 +1,117 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "config-mplane.h"
#include "rpc-send-recv.h"
#include "yang/get-yang.h"
#include "yang/create-yang-config.h"
#include "common/utils/assertions.h"
#include <libyang/libyang.h>
#include <nc_client.h>
bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
NC_DATASTORE target = NC_DATASTORE_CANDIDATE;
NC_RPC_EDIT_DFLTOP op = NC_RPC_EDIT_DFLTOP_MERGE;
NC_RPC_EDIT_TESTOPT test = NC_RPC_EDIT_TESTOPT_UNKNOWN;
NC_RPC_EDIT_ERROPT err = NC_RPC_EDIT_ERROPT_UNKNOWN;
bool success = false;
struct ly_ctx *ctx = NULL;
success = load_yang_models(ru_session, buffer, &ctx);
AssertError(success, return false, "[MPLANE] Unable to continue.\n");
char *content = NULL;
success = configure_ru_from_yang(&ctx, ru_session, oai, num_rus, &content);
AssertError(success, return false, "[MPLANE] Unable to create content for <edit-config> RPC.\n");
MP_LOG_I("RPC request to RU \"%s\" = <edit-config>:\n%s\n", ru_session->ru_ip_add, content);
rpc = nc_rpc_edit(target, op, test, err, content, param);
AssertError(rpc != NULL, return false, "[MPLANE] <edit-config> RPC creation failed.\n");
success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
AssertError(success, return false, "[MPLANE] Failed to edit configuration for the candidate datastore.\n");
MP_LOG_I("Successfully edited the candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
free(content);
#ifdef MPLANE_V1
ly_ctx_destroy(ctx, NULL);
#elif defined MPLANE_V2
ly_ctx_destroy(ctx);
#endif
return true;
}
bool validate_config_mplane(ru_session_t *ru_session)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
char *src_start = NULL;
NC_DATASTORE source = NC_DATASTORE_CANDIDATE;
MP_LOG_I("RPC request to RU \"%s\" = <validate> candidate datastore.\n", ru_session->ru_ip_add);
rpc = nc_rpc_validate(source, src_start, param);
AssertError(rpc != NULL, return false, "[MPLANE] <validate> RPC creation failed.\n");
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
AssertError(success, return false, "[MPLANE] Failed to validate candidate datastore.\n");
MP_LOG_I("Successfully validated candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
return true;
}
bool commit_config_mplane(ru_session_t *ru_session)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
int confirmed = 0;
int32_t confirm_timeout = 0;
char *persist = NULL, *persist_id = NULL;
MP_LOG_I("RPC request to RU \"%s\" = <commit> candidate datastore.\n", ru_session->ru_ip_add);
rpc = nc_rpc_commit(confirmed, confirm_timeout, persist, persist_id, param);
AssertError(rpc != NULL, return false, "[MPLANE] <commit> RPC creation failed.\n");
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
AssertError(success, return false, "[MPLANE] Failed to commit candidate datastore.\n");
MP_LOG_I("Successfully commited CU-planes configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
return true;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef CONFIGURE_MPLANE_H
#define CONFIGURE_MPLANE_H
#include "ru-mplane-api.h"
#include "radio/COMMON/common_lib.h"
bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus);
bool validate_config_mplane(ru_session_t *ru_session);
bool commit_config_mplane(ru_session_t *ru_session);
#endif /* CONFIGURE_MPLANE_H */
+73
View File
@@ -0,0 +1,73 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "connect-mplane.h"
#include "common/utils/assertions.h"
#include <libyang/libyang.h>
#include <nc_client.h>
static int my_auth_hostkey_check(const char *hostname, ssh_session session, void *priv)
{
(void)hostname;
(void)session;
(void)priv;
return 0;
}
bool connect_mplane(ru_session_t *ru_session)
{
int port = NC_PORT_SSH;
char *user = "oranbenetel";
nc_client_ssh_set_username(user);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); // ssh-key identification
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
nc_client_ssh_set_auth_hostkey_check_clb(my_auth_hostkey_check, "DATA"); // host-key identification
MP_LOG_I("RPC request to RU \"%s\" = <connect> with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port);
ru_session->session = nc_connect_ssh(ru_session->ru_ip_add, port, NULL);
AssertError(ru_session->session != NULL, return false, "[MPLANE] RU IP address %s unreachable. Maybe M-plane is disabled on the RU?\n", ru_session->ru_ip_add);
MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port);
return true;
}
void disconnect_mplane(void *rus_disconnect)
{
ru_session_list_t *ru_session_list = (ru_session_list_t *)rus_disconnect;
for (size_t i = 0; i <ru_session_list->num_rus; i++) {
ru_session_t *ru_session = &ru_session_list->ru_session[i];
if (ru_session->session == NULL)
continue;
MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add);
nc_session_free(ru_session->session, NULL);
ru_session->session = NULL;
}
nc_client_destroy();
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef CONNECT_MPLANE_H
#define CONNECT_MPLANE_H
#include "ru-mplane-api.h"
bool connect_mplane(ru_session_t *ru_session);
void disconnect_mplane(void *rus_disconnect);
#endif /* CONNECT_MPLANE_H */
+47
View File
@@ -0,0 +1,47 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "get-mplane.h"
#include "rpc-send-recv.h"
#include "common/utils/assertions.h"
bool get_mplane(ru_session_t *ru_session, char **answer)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
char *filter = NULL; // e.g. "/o-ran-delay-management:delay-management";
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
MP_LOG_I("RPC request to RU \"%s\" = <get> operational datastore.\n", ru_session->ru_ip_add);
rpc = nc_rpc_get(filter, wd, param);
AssertError(rpc != NULL, return false, "[MPLANE] <get> RPC creation failed.\n");
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, answer);
AssertError(success, return false, "[MPLANE] Unable to retrieve operational datastore.\n");
MP_LOG_I("Successfully retrieved operational datastore from RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
return true;
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef GET_MPLANE_H
#define GET_MPLANE_H
#include "ru-mplane-api.h"
bool get_mplane(ru_session_t *ru_session, char **answer);
#endif /* GET_MPLANE_H */
+205
View File
@@ -0,0 +1,205 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "init-mplane.h"
#include "radio/fhi_72/oran-params.h"
#include "get-mplane.h"
#include "subscribe-mplane.h"
#include "config-mplane.h"
#include "xml/get-xml.h"
#include <libyang/libyang.h>
#include <nc_client.h>
static void lnc2_print_clb(NC_VERB_LEVEL level, const char *msg)
{
switch (level) {
case NC_VERB_ERROR:
MP_LOG_I("[LIBNETCONF2] ERROR: %s.\n", msg);
break;
case NC_VERB_WARNING:
MP_LOG_I("[LIBNETCONF2] WARNING: %s.\n", msg);
break;
case NC_VERB_VERBOSE:
MP_LOG_I("[LIBNETCONF2] VERBOSE: %s.\n", msg);
break;
case NC_VERB_DEBUG:
case NC_VERB_DEBUG_LOWLVL:
MP_LOG_I("[LIBNETCONF2] DEBUG: %s.\n", msg);
break;
default:
assert(false && "[LIBNETCONF2] Unknown log level.");
}
}
static void ly_print_clb(LY_LOG_LEVEL level, const char *msg, const char *path)
{
switch (level) {
case LY_LLERR:
MP_LOG_I("[LIBYANG] ERROR: %s (path: %s).\n", msg, path);
break;
case LY_LLWRN:
MP_LOG_I("[LIBYANG] WARNING: %s (path: %s).\n", msg, path);
break;
case LY_LLVRB:
MP_LOG_I("[LIBYANG] VERBOSE: %s (path: %s).\n", msg, path);
break;
case LY_LLDBG:
MP_LOG_I("[LIBYANG] DEBUG: %s (path: %s).\n", msg, path);
break;
default:
assert(false && "[LIBYANG] Unknown log level.");
}
}
static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name)
{
/* the config module does not know const-correctness... */
int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name);
DevAssert(idx >= 0);
return &pd[idx];
}
bool init_mplane(ru_session_list_t *ru_session_list)
{
paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC;
int nump = sizeofArray(fhip);
int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN);
if (ret <= 0) {
MP_LOG_I("Problem reading section \"%s\".\n", CONFIG_STRING_ORAN);
return false;
}
ru_session_list->du_key_pair = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->strlistptr;
int num_keys = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->numelt;
AssertError(num_keys == 2, return false, "[MPLANE] Expected {pub-key-path, priv-key-path}. Loaded {%s, %s}.\n", ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]);
char **ru_ip_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->strlistptr;
int num_rus = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->numelt;
char **du_mac_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
int num_dus = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
int32_t *vlan_tag = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->iptr;
int num_vlan_tags = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->numelt;
AssertError(num_dus == num_vlan_tags, return false, "[MPLANE] Number of DU MAC addresses should be equal to the number of VLAN tags.\n");
int num_cu_planes = num_dus / num_rus;
ru_session_list->num_rus = num_rus;
ru_session_list->ru_session = calloc(num_rus, sizeof(ru_session_t));
for (size_t i = 0; i < num_rus; i++) {
ru_session_t *ru_session = &ru_session_list->ru_session[i];
ru_session->session = NULL;
ru_session->ru_ip_add = calloc(strlen(ru_ip_addrs[i]) + 1, sizeof(char));
memcpy(ru_session->ru_ip_add, ru_ip_addrs[i], strlen(ru_ip_addrs[i]) + 1);
// store DU MAC addresses and VLAN tags
ru_session->ru_mplane_config.num_cu_planes = num_cu_planes;
ru_session->ru_mplane_config.du_mac_addr = calloc_or_fail(num_cu_planes, sizeof(char*));
ru_session->ru_mplane_config.vlan_tag = calloc_or_fail(num_cu_planes, sizeof(int32_t));
for (int j = 0; j < num_cu_planes; j++) {
const int idx = i*num_cu_planes+j;
ru_session->ru_mplane_config.du_mac_addr[j] = calloc(1, strlen(du_mac_addr[idx]) + 1);
memcpy(ru_session->ru_mplane_config.du_mac_addr[j], du_mac_addr[idx], strlen(du_mac_addr[idx]) + 1);
ru_session->ru_mplane_config.vlan_tag[j] = vlan_tag[idx];
}
}
nc_client_init();
int keypair_ret = nc_client_ssh_add_keypair(ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]);
AssertError(keypair_ret == 0, return false, "[MPLANE] Unable to add DU ssh key pair.\n");
// logs for netconf2 and yang libraries
nc_set_print_clb(lnc2_print_clb);
ly_set_log_clb(ly_print_clb, 1);
return true;
}
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus)
{
bool success = false;
char *operational_ds = NULL;
success = get_mplane(ru_session, &operational_ds);
AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via get_mplane().\n");
bool ptp_state = false;
const char *sync_state = get_ru_xml_node(operational_ds, "sync-state");
if (strcmp(sync_state, "LOCKED") == 0) {
MP_LOG_I("RU is already PTP synchronized.\n");
ptp_state = true;
}
/* 1) as per M-plane spec, RU must be in supervised mode,
where stream = NULL && filter = "/o-ran-supervision:supervision-notification";
2) additionally, we want to subscribe to PTP state change,
where stream = NULL && filter = "/o-ran-sync:synchronization-state-change";
=> since more than one subscription at the time within one session is not possible, we will subscribe to all notifications */
const char *stream = "NETCONF";
const char *filter = NULL;
ru_session->ru_notif.ptp_state = ptp_state;
success = subscribe_mplane(ru_session, stream, filter, (void *)&ru_session->ru_notif);
AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via subscribe_mplane().\n");
// when subscribed to the supervision notification, the watchdog timer needs to be updated
char *watchdog_answer = NULL;
success = update_timer_mplane(ru_session, &watchdog_answer);
AssertError(success, return false, "[MPLANE] Unable to update the watchdog timer. RU will do a reset after default supervision timer of (60+10)[s] expires.\n");
MP_LOG_I("Watchdog timer answer: \n\t%s\n", watchdog_answer);
// save RU info for xran
const int max_num_ant = max(oai->tx_num_channels/num_rus, oai->rx_num_channels/num_rus);
success = get_config_for_xran(operational_ds, max_num_ant, &ru_session->xran_mplane);
AssertError(success, return false, "[MPLANE] Unable to retrieve required info for xran from RU \"%s\".\n", ru_session->ru_ip_add);
// save the U-plane info
success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config);
AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n");
if (ru_session->ru_notif.ptp_state) {
success = edit_config_mplane(ru_session, operational_ds, oai, num_rus);
AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n");
success = validate_config_mplane(ru_session);
AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n");
success = commit_config_mplane(ru_session);
AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n");
}
const char *usage_state = get_ru_xml_node(operational_ds, "usage-state");
MP_LOG_I("Usage state = \"%s\" for RU \"%s\".\n", usage_state, ru_session->ru_ip_add);
if (strcmp(usage_state, "busy") == 0) { // carriers are already activated
ru_session->ru_notif.rx_carrier_state = true;
ru_session->ru_notif.tx_carrier_state = true;
ru_session->ru_notif.config_change = true;
} else {
ru_session->ru_notif.rx_carrier_state = false;
ru_session->ru_notif.tx_carrier_state = false;
ru_session->ru_notif.config_change = false;
}
free(operational_ds);
free(watchdog_answer);
return true;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef OAI_MPLANE_H
#define OAI_MPLANE_H
#include "ru-mplane-api.h"
#include "radio/COMMON/common_lib.h"
bool init_mplane(ru_session_list_t *ru_session_list);
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus);
#endif /* OAI_MPLANE_H */
+296
View File
@@ -0,0 +1,296 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "rpc-send-recv.h"
#include "common/utils/assertions.h"
#ifdef MPLANE_V1
static bool recv_v1(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
{
struct nc_reply *reply;
struct nc_reply_data *data_rpl;
struct nc_reply_error *error;
LYD_FORMAT output_format = LYD_XML;
uint32_t ly_wd;
while (1) {
msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, 0, &reply);
if (msgtype == NC_MSG_ERROR) {
AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n");
} else if (msgtype == NC_MSG_WOULDBLOCK) {
AssertError(false, return false, "[MPLANE] Timeout for receiving a reply expired.\n");
} else if (msgtype == NC_MSG_NOTIF) {
/* read again */
continue;
} else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
/* unexpected message, try reading again to get the correct reply */
MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n");
nc_reply_free(reply);
continue;
}
break;
}
switch (reply->type) {
case NC_RPL_OK:
MP_LOG_I("RPC reply = OK.\n");
break;
case NC_RPL_DATA:
data_rpl = (struct nc_reply_data *)reply;
switch (wd_mode) {
case NC_WD_ALL:
ly_wd = LYP_WD_ALL;
break;
case NC_WD_ALL_TAG:
ly_wd = LYP_WD_ALL_TAG;
break;
case NC_WD_TRIM:
ly_wd = LYP_WD_TRIM;
break;
case NC_WD_EXPLICIT:
ly_wd = LYP_WD_EXPLICIT;
break;
default:
ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN
break;
}
if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) {
AssertError((!data_rpl->data || (data_rpl->data->schema->nodetype != LYS_RPC) || (data_rpl->data->child == NULL)
|| (data_rpl->data->child->schema->nodetype != LYS_ANYXML)), return false, "[MPLANE] Cannot get schema.\n");
struct lyd_node_anydata *any = (struct lyd_node_anydata *)data_rpl->data->child;
switch (any->value_type) {
case LYD_ANYDATA_CONSTSTRING:
case LYD_ANYDATA_STRING:
*answer = strdup(any->value.str);
break;
case LYD_ANYDATA_DATATREE:
lyd_print_mem(answer, any->value.tree, output_format, LYP_WITHSIBLINGS);
break;
case LYD_ANYDATA_XML:
lyxml_print_mem(answer, any->value.xml, LYXML_PRINT_SIBLINGS);
break;
default:
AssertError(false, return false, "[MPLANE] Unknown yang type.\n");
}
break;
} else if (nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG || nc_rpc_get_type(rpc) == NC_RPC_GET) {
const char *tag = nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG ? "config" : "data";
char *buffer = NULL;
lyd_print_mem(&buffer, data_rpl->data, output_format, LYP_WITHSIBLINGS | LYP_NETCONF | ly_wd);
*answer = calloc(strlen(buffer)+128, sizeof(char));
sprintf(*answer, "<%s xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n%s</%s>", tag, buffer, tag);
} else {
AssertError(false, return false, "[MPLANE] Unknown RPC type.\n");
}
break;
case NC_RPL_ERROR:
error = (struct nc_reply_error *)reply;
for (int i = 0; i < error->count; ++i) {
const struct nc_err *err = &error->err[i];
MP_LOG_I("RPC reply = ERROR\n\
\ttype: %s\n\
\ttag: %s\n\
\tseverity: %s\n\
\tapp-tag: %s\n\
\tpath: %s\n\
\tmessage: %s\n\
\tSID: %s\n",
err->type,
err->tag,
err->severity,
err->apptag,
err->path,
err->message,
err->sid);
for (int j = 0; j < err->attr_count; ++j) {
MP_LOG_I("\tbad-attr #%d: %s\n", j + 1, err->attr[j]);
}
for (int j = 0; j < err->elem_count; ++j) {
MP_LOG_I("\tbad-elem #%d: %s\n", j + 1, err->elem[j]);
}
for (int j = 0; j < err->ns_count; ++j) {
MP_LOG_I("\tbad-ns #%d: %s\n", j + 1, err->ns[j]);
}
for (int j = 0; j < err->other_count; ++j) {
char *str = NULL;
lyxml_print_mem(&str, err->other[j], 0);
MP_LOG_I("\tother #%d:\n%s\n", j + 1, str);
free(str);
}
}
AssertError(false, return false, "[MPLANE] Unable to continue.\n");
break;
default:
AssertError(false, return false, "[MPLANE] Internal error.\n");
nc_reply_free(reply);
}
nc_reply_free(reply);
return true;
}
#elif defined MPLANE_V2
static bool recv_v2(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
{
struct lyd_node *envp, *op, *err;
LYD_FORMAT output_format = LYD_XML;
uint32_t ly_wd;
while (1) {
msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, &envp, &op);
if (msgtype == NC_MSG_ERROR) {
AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n");
} else if (msgtype == NC_MSG_WOULDBLOCK) {
AssertError(false, return false, "[MPLANE] Timeout for receiving a reply for RPC expired.\n");
} else if (msgtype == NC_MSG_NOTIF) { // for SUBSCRIBE
/* read again */
continue;
} else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
/* unexpected message, try reading again to get the correct reply */
MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n");
lyd_free_tree(envp);
lyd_free_tree(op);
continue;
}
break;
}
/* get functionality */
if (op) {
/* data reply */
if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) {
/* special case */
if (!lyd_child(op) || (lyd_child(op)->schema->nodetype != LYS_ANYXML)) {
AssertError(false, return false, "[MPLANE] Cannot get schema.");
}
struct lyd_node_any *any = (struct lyd_node_any *)lyd_child(op);
switch (any->value_type) {
case LYD_ANYDATA_STRING:
case LYD_ANYDATA_XML:
*answer = strdup(any->value.str);
break;
case LYD_ANYDATA_DATATREE:
lyd_print_mem(answer, any->value.tree, output_format, LYD_PRINT_WITHSIBLINGS);
break;
default:
AssertError(false, return false, "[MPLANE] Unexpected yang type.");
}
} else {
switch (wd_mode) {
case NC_WD_ALL:
ly_wd = LYD_PRINT_WD_ALL;
break;
case NC_WD_ALL_TAG:
ly_wd = LYD_PRINT_WD_ALL_TAG;
break;
case NC_WD_TRIM:
ly_wd = LYD_PRINT_WD_TRIM;
break;
case NC_WD_EXPLICIT:
ly_wd = LYD_PRINT_WD_EXPLICIT;
break;
default:
ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN
break;
}
lyd_print_mem(answer, lyd_child(op), output_format, LYD_PRINT_WITHSIBLINGS | ly_wd);
}
/* edit/validate/commit functionalities */
} else if (!strcmp(LYD_NAME(lyd_child(envp)), "ok")) {
MP_LOG_I("RPC reply = OK.\n");
} else {
LY_LIST_FOR(lyd_child(envp), err) {
struct lyd_node *type, *tag, *severity, *app_tag, *path, *er_msg, *info = NULL;
lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &type);
lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &tag);
lyd_find_sibling_opaq_next(lyd_child(err), "error-severity", &severity);
lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &app_tag);
lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &path);
lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &er_msg);
MP_LOG_I("RPC reply = ERROR\n\
\ttype: %s\n\
\ttag: %s\n\
\tseverity: %s\n\
\tapp-tag: %s\n\
\tpath: %s\n\
\tmessage: %s\n",
(type ? ((struct lyd_node_opaq *)type)->value : NULL),
(tag ? ((struct lyd_node_opaq *)tag)->value : NULL),
(severity ? ((struct lyd_node_opaq *)severity)->value : NULL),
(app_tag ? ((struct lyd_node_opaq *)app_tag)->value : NULL),
(path ? ((struct lyd_node_opaq *)path)->value : NULL),
(er_msg ? ((struct lyd_node_opaq *)er_msg)->value : NULL));
info = lyd_child(err);
while (!lyd_find_sibling_opaq_next(info, "error-info", &info)) {
char *str = NULL;
lyd_print_mem(&str, lyd_child(info), output_format, LYD_PRINT_WITHSIBLINGS);
MP_LOG_I("\tinfo: %s\n", str);
info = info->next;
free(str);
}
lyd_free_tree(type);
lyd_free_tree(tag);
lyd_free_tree(severity);
lyd_free_tree(app_tag);
lyd_free_tree(path);
lyd_free_tree(er_msg);
lyd_free_tree(info);
}
lyd_free_tree(envp);
lyd_free_tree(op);
AssertError(false, return false, "[MPLANE] Unable to continue.\n");
}
lyd_free_tree(envp);
lyd_free_tree(op);
return true;
}
#endif
bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer)
{
uint64_t msgid;
NC_MSG_TYPE msgtype;
msgtype = nc_send_rpc(session, rpc, 1000, &msgid);
if (msgtype == NC_MSG_ERROR) {
AssertError(false, return false, "[MPLANE] Failed to send the RPC.\n");
} else if (msgtype == NC_MSG_WOULDBLOCK) {
AssertError(false, return false, "[MPLANE] Timeout for sending the RPC expired.\n");
}
#ifdef MPLANE_V1
return recv_v1(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer);
#elif defined MPLANE_V2
return recv_v2(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer);
#else
AssertError(false, return false, "[MPLANE] Unknown M-plane version found. Tried \"MPLANE_V1\" and \"MPLANE_V2\".\n");
#endif
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef RPC_SEND_RECEIVE_MPLANE_H
#define RPC_SEND_RECEIVE_MPLANE_H
#include "ru-mplane-api.h"
#include <libyang/libyang.h>
#include <nc_client.h>
#define CLI_RPC_REPLY_TIMEOUT 60000 // time [ms] to wait for server reply
bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer);
#endif /* RPC_SEND_RECEIVE_MPLANE_H */
+157
View File
@@ -0,0 +1,157 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "ru-mplane-api.h"
#include "xml/get-xml.h"
#include "common/utils/assertions.h"
#include <string.h>
static void free_match_list(char **match_list, size_t count)
{
for (size_t i = 0; i < count; i++) {
free(match_list[i]);
}
free(match_list);
}
static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant)
{
if (interface_mtu == 1500) {
MP_LOG_I("Interface MTU %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.\n", interface_mtu);
xran_mplane->mtu = 9600;
} else {
xran_mplane->mtu = interface_mtu;
}
if (first_iq_width != 9) {
MP_LOG_I("IQ bitwidth %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9.\n", first_iq_width);
xran_mplane->iq_width = 9;
} else {
xran_mplane->iq_width = first_iq_width;
}
xran_mplane->prach_offset = max_num_ant;
}
bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane)
{
/* some O-RU vendors are not fully compliant as per M-plane specifications */
const char *ru_vendor = get_ru_xml_node(buffer, "mfg-name");
// RU MAC
xran_mplane->ru_mac_addr = get_ru_xml_node(buffer, "mac-address"); // TODO: support for VVDN, as it defines multiple MAC addresses
// MTU
const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "interface-mtu"));
// IQ bitwidth
char **match_list = NULL;
size_t count = 0;
get_ru_xml_list(buffer, "iq-bitwidth", &match_list, &count);
const int16_t first_iq_width = (int16_t)atoi((char *)match_list[0]);
free_match_list(match_list, count);
// PRACH offset
// xran_mplane->prach_offset
// DU port ID bitmask
xran_mplane->du_port_bitmask = 0xf000;
// Band sector bitmask
xran_mplane->band_sector_bitmask = 0x0f00;
// CC ID bitmask
xran_mplane->ccid_bitmask = 0x00f0;
// RU port ID bitmask
xran_mplane->ru_port_bitmask = 0x000f;
// DU port ID
xran_mplane->du_port = 0;
// Band sector
xran_mplane->band_sector = 0;
// CC ID
xran_mplane->ccid = 0;
// RU port ID
xran_mplane->ru_port = 0;
if (strcasecmp(ru_vendor, "BENETEL") == 0 /* || strcmp(ru_vendor, "VVDN-LPRU") == 0 || strcmp(ru_vendor, "Metanoia") == 0 */) {
fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant);
} else {
AssertError(false, return false, "[MPLANE] %s RU currently not supported.\n", ru_vendor);
}
MP_LOG_I("Storing the following information to forward to xran:\n\
RU MAC address %s\n\
MTU %d\n\
IQ bitwidth %d\n\
PRACH offset %d\n\
DU port bitmask %d\n\
Band sector bitmask %d\n\
CC ID bitmask %d\n\
RU port ID bitmask %d\n\
DU port ID %d\n\
Band sector ID %d\n\
CC ID %d\n\
RU port ID %d\n",
xran_mplane->ru_mac_addr,
xran_mplane->mtu,
xran_mplane->iq_width,
xran_mplane->prach_offset,
xran_mplane->du_port_bitmask,
xran_mplane->band_sector_bitmask,
xran_mplane->ccid_bitmask,
xran_mplane->ru_port_bitmask,
xran_mplane->du_port,
xran_mplane->band_sector,
xran_mplane->ccid,
xran_mplane->ru_port);
return true;
}
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config)
{
// Interface name
ru_mplane_config->interface_name = get_ru_xml_node(buffer, "interface");
// PDSCH
uplane_info_t *tx_end = &ru_mplane_config->tx_endpoints;
get_ru_xml_list(buffer, "static-low-level-tx-endpoints", &tx_end->name, &tx_end->num);
AssertError(tx_end->name != NULL, return false, "[MPLANE] Cannot get TX endpoint names.\n");
// TX carriers
uplane_info_t *tx_carriers = &ru_mplane_config->tx_carriers;
get_ru_xml_list(buffer, "tx-arrays", &tx_carriers->name, &tx_carriers->num);
AssertError(tx_carriers->name != NULL, return false, "[MPLANE] Cannot get TX carrier names.\n");
// PUSCH and PRACH
uplane_info_t *rx_end = &ru_mplane_config->rx_endpoints;
get_ru_xml_list(buffer, "static-low-level-rx-endpoints", &rx_end->name, &rx_end->num);
AssertError(rx_end->name != NULL, return false, "[MPLANE] Cannot get RX endpoint names.\n");
// RX carriers
uplane_info_t *rx_carriers = &ru_mplane_config->rx_carriers;
get_ru_xml_list(buffer, "rx-arrays", &rx_carriers->name, &rx_carriers->num);
AssertError(rx_carriers->name != NULL, return false, "[MPLANE] Cannot get RX carrier names.\n");
MP_LOG_I("Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.\n");
return true;
}
+100
View File
@@ -0,0 +1,100 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef RU_MPLANE_API_H
#define RU_MPLANE_API_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "common/utils/LOG/log.h"
#define MP_LOG_I(x, args...) LOG_I(HW, "[MPLANE] " x, ##args)
#define MP_LOG_W(x, args...) LOG_W(HW, "[MPLANE] " x, ##args)
typedef struct {
bool ptp_state;
bool rx_carrier_state;
bool tx_carrier_state;
bool config_change;
// to be extended with any notification callback
} ru_notif_t;
typedef struct {
char *ru_mac_addr;
uint32_t mtu;
int16_t iq_width;
uint8_t prach_offset;
// DU sends to RU and xran
uint16_t du_port_bitmask;
uint16_t band_sector_bitmask;
uint16_t ccid_bitmask;
uint16_t ru_port_bitmask;
// DU retrieves from RU, and sends to xran
uint8_t du_port;
uint8_t band_sector;
uint8_t ccid;
uint8_t ru_port;
} xran_mplane_t;
typedef struct {
size_t num;
char **name;
} uplane_info_t;
typedef struct {
size_t num_cu_planes;
char **du_mac_addr; // one or two VF(s) for CU-planes
int32_t *vlan_tag; // one or two VF(s) for CU-planes
char *interface_name;
uplane_info_t tx_endpoints;
uplane_info_t rx_endpoints;
uplane_info_t tx_carriers;
uplane_info_t rx_carriers;
} ru_mplane_config_t;
typedef struct {
char *ru_ip_add;
ru_mplane_config_t ru_mplane_config;
void *session;
xran_mplane_t xran_mplane;
ru_notif_t ru_notif;
} ru_session_t;
typedef struct {
size_t num_rus;
ru_session_t *ru_session;
char **du_key_pair;
} ru_session_list_t;
bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane);
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config);
#endif /* RU_MPLANE_API_H */
+160
View File
@@ -0,0 +1,160 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "subscribe-mplane.h"
#include "rpc-send-recv.h"
#include "common/utils/assertions.h"
#include <libyang/libyang.h>
#include <nc_client.h>
#ifdef MPLANE_V1
static void recv_notif_v1(const struct nc_notif *notif, ru_notif_t *answer)
{
const char *node_name = notif->tree->child->attr->name;
const char *value = notif->tree->child->attr->value_str;
if (strcmp(node_name, "sync-state")) {
if (strcmp(value, "LOCKED") == 0) {
answer->ptp_state = true;
} else {
answer->ptp_state = false;
}
}
// carriers state - to be filled
}
static void notif_clb_v1(struct nc_session *session, const struct nc_notif *notif)
{
ru_notif_t *answer = nc_session_get_data(session);
LYD_FORMAT output_format = LYD_JSON;
char *subs_reply = NULL;
lyd_print_mem(&subs_reply, notif->tree, output_format, LYP_WITHSIBLINGS);
MP_LOG_I("\nReceived notification at (%s)\n%s\n", notif->datetime, subs_reply);
recv_notif_v1(notif, answer);
}
#elif MPLANE_V2
static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer)
{
const char *notif = op->schema->name;
if (strcmp(notif, "synchronization-state-change") == 0) {
const char *value = lyd_get_value(op->child);
if (strcmp(value, "LOCKED") == 0) {
answer->ptp_state = true;
} else { // "FREERUN" or "HOLDOVER"
answer->ptp_state = false;
}
} else if (strcmp(notif, "rx-array-carriers-state-change") == 0) {
const char *value = lyd_get_value(lyd_child(op->child)->next);
if (strcmp(value, "READY") == 0) {
answer->rx_carrier_state = true;
} else { // "DISABLED" or "BUSY"
answer->rx_carrier_state = false;
}
} else if (strcmp(notif, "tx-array-carriers-state-change") == 0) {
const char *value = lyd_get_value(lyd_child(op->child)->next);
if (strcmp(value, "READY") == 0) {
answer->tx_carrier_state = true;
} else { // "DISABLED" or "BUSY"
answer->tx_carrier_state = false;
}
} else if (strcmp(notif, "netconf-config-change") == 0) {
answer->config_change = true;
}
}
static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op, void *user_data)
{
ru_notif_t *answer = (ru_notif_t *)user_data;
LYD_FORMAT output_format = LYD_JSON;
char *subs_reply = NULL;
lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS);
const char *ru_ip_add = nc_session_get_host(session);
MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply);
recv_notif_v2((struct lyd_node_inner *)op, answer);
}
#endif
bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
char *start_time = NULL, *stop_time = NULL;
MP_LOG_I("RPC request to RU \"%s\" = <subscribe> with stream \"%s\" and filter \"%s\".\n", ru_session->ru_ip_add, stream, filter);
rpc = nc_rpc_subscribe(stream, NULL, start_time, stop_time, param);
AssertError(rpc != NULL, return false, "[MPLANE] <subscribe> RPC creation failed.\n");
/* create notification thread so that notifications can immediately be received */
#ifdef MPLANE_V1
if (!nc_session_ntf_thread_running(ru_session->session)) {
nc_session_set_data(ru_session->session, answer);
int ret = nc_recv_notif_dispatch(ru_session->session, notif_clb_v1);
AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n");
} else {
MP_LOG_I("Notification thread is already running for RU %s.\n", ru_session->ru_ip_add);
}
#elif MPLANE_V2
int ret = nc_recv_notif_dispatch_data(ru_session->session, notif_clb_v2, answer, NULL);
AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n");
#endif
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
AssertError(success, return false, "[MPLANE] Failed to subscribe to: stream \"%s\", filter \"%s\".\n", stream, filter);
MP_LOG_I("Successfully subscribed to all notifications from RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
return true;
}
bool update_timer_mplane(ru_session_t *ru_session, char **answer)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
const char *content = "<supervision-watchdog-reset xmlns=\"urn:o-ran:supervision:1.0\">\n\
<supervision-notification-interval>65535</supervision-notification-interval>\n\
<guard-timer-overhead>65535</guard-timer-overhead>\n\
</supervision-watchdog-reset>";
MP_LOG_I("RPC request to RU \"%s\" = \"%s\".\n", ru_session->ru_ip_add, content);
rpc = nc_rpc_act_generic_xml(content, param);
AssertError(rpc != NULL, return false, "[MPLANE] <supervision-watchdog-reset> RPC creation failed.\n");
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, answer);
AssertError(success, return false, "[MPLANE] Failed to update the watchdog timer.\n");
MP_LOG_I("Successfully updated supervision timer to (65535+65535)[s] for RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
return true;
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef SUBSCRIBE_MPLANE_H
#define SUBSCRIBE_MPLANE_H
#include "ru-mplane-api.h"
#include <stdbool.h>
bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer);
bool update_timer_mplane(ru_session_t *ru_session, char **answer);
#endif /* SUBSCRIBE_MPLANE_H */
+95
View File
@@ -0,0 +1,95 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "get-xml.h"
#include <libxml/parser.h>
#include <string.h>
static char *find_ru_xml_node(xmlNode *node, const char *filter)
{
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
if (cur_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp((const char *)cur_node->name, filter) == 0) {
xmlNode *target_node = cur_node;
for(xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) {
target_node = cur_node2;
break;
}
}
return (char *)xmlNodeGetContent(target_node);
}
char *answer = find_ru_xml_node(cur_node->children, filter);
if (answer != NULL) {
return answer;
}
}
return NULL;
}
char *get_ru_xml_node(const char *buffer, const char *filter)
{
// Initialize the xml file
size_t len = strlen(buffer) + 1;
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
xmlNode *root_element = xmlDocGetRootElement(doc);
return find_ru_xml_node(root_element->children, filter);
}
static void find_ru_xml_list(xmlNode *node, const char *filter, char ***match_list, size_t *count)
{
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
if (cur_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp((const char *)cur_node->name, filter) == 0) {
xmlNode *name_node = NULL;
for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) {
name_node = cur_node2;
break;
}
}
const char *content = (const char *)xmlNodeGetContent(name_node ? name_node : cur_node);
if (content) {
*match_list = realloc(*match_list, (*count + 1) * sizeof(char *));
(*match_list)[*count] = strdup(content);
(*count)++;
}
}
find_ru_xml_list(cur_node->children, filter, match_list, count);
}
}
void get_ru_xml_list(const char *buffer, const char *filter, char ***match_list, size_t *count)
{
// Initialize the xml file
size_t len = strlen(buffer) + 1;
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
xmlNode *root_element = xmlDocGetRootElement(doc);
find_ru_xml_list(root_element->children, filter, match_list, count);
}
+48
View File
@@ -0,0 +1,48 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef GET_MPLANE_INFO_XML_H
#define GET_MPLANE_INFO_XML_H
#include <stdio.h>
#include <stdbool.h>
/**
* @brief retrieves the node value that matches filter.
*
* @param[in] buffer Buffer in xml format.
* @param[in] filter The node name (matching criteria).
* @return Expected one string that matches the node name.
*/
char *get_ru_xml_node(const char *buffer, const char *filter);
/**
* @brief retrieves the node values that matches filter.
*
* @param[in] buffer Buffer in xml format.
* @param[in] filter The node name (matching criteria).
* @param[out] match_list Resulting list containing node values.
* @param[out] count The number of nodes that match criteria.
* @return Void.
*/
void get_ru_xml_list(const char *buffer, const char *filter, char ***match_list, size_t *count);
#endif /* GET_MPLANE_INFO_XML_H */
@@ -0,0 +1,392 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "create-yang-config.h"
#include "common/utils/nr/nr_common.h"
#define VERIFY_SUCCESS(var, message, args...) AssertError(var, return false, message, ##args)
#ifdef MPLANE_V2
static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_path(NULL, *ctx, "/ietf-interfaces:interfaces", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"interfaces\" node.\n");
struct lyd_node *interface_node = NULL;
ret = lyd_new_list(*root, NULL, "interface", 0, &interface_node, int_name);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"interface\" node.\n");
struct lyd_node *type_node = NULL;
ret = lyd_new_term(interface_node, NULL, "type", "iana-if-type:l2vlan", 0, &type_node);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"type\" node.\n");
ret = lyd_new_term(interface_node, NULL, "enabled", "true", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"enabled\" node.\n");
const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented(*ctx, "o-ran-interfaces");
VERIFY_SUCCESS(oran_int_mod != NULL, "[MPLANE] Failed to get \"o-ran-interfaces\" module.\n");
struct lyd_node *base_int = NULL;
ret = lyd_new_term(interface_node, oran_int_mod, "base-interface", ru_session->ru_mplane_config.interface_name, 0, &base_int);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"base-interface\" node with name \"%s\".\n", ru_session->ru_mplane_config.interface_name);
struct lyd_node *vlan_id = NULL;
char vlan_tag_str[8];
snprintf(vlan_tag_str, sizeof(vlan_tag_str), "%d", ru_session->ru_mplane_config.vlan_tag[idx]);
ret = lyd_new_term(interface_node, oran_int_mod, "vlan-id", vlan_tag_str, 0, &vlan_id);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"vlan-id\" node with \"%d\".\n", ru_session->ru_mplane_config.vlan_tag[idx]);
struct lyd_node *ru_mac_addr = NULL;
ret = lyd_new_term(interface_node, oran_int_mod, "mac-address", ru_session->xran_mplane.ru_mac_addr, 0, &ru_mac_addr);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"mac-address\" node with \"%s\".\n", ru_session->xran_mplane.ru_mac_addr);
return true;
}
static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_path(NULL, *ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"processing-elements\" node.\n");
ret = lyd_new_term(*root, NULL, "transport-session-type", "ETH-INTERFACE", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"transport-session-type\" node.\n");
struct lyd_node *ru_elem_node = NULL;
char plane_name[8];
snprintf(plane_name, sizeof(plane_name), "PLANE_%ld", idx);
ret = lyd_new_list(*root, NULL, "ru-elements", 0, &ru_elem_node, plane_name);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-elements\" node.\n");
struct lyd_node *transp_flow = NULL;
ret = lyd_new_inner(ru_elem_node, NULL, "transport-flow", 0, &transp_flow);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"transport-flow\" node.\n");
ret = lyd_new_term(transp_flow, NULL, "interface-name", int_name, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"interface-name\" node.\n");
struct lyd_node *eth_flow = NULL;
ret = lyd_new_inner(transp_flow, NULL, "eth-flow", 0, &eth_flow);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eth-flow\" node.\n");
char vlan_tag_str[8];
snprintf(vlan_tag_str, sizeof(vlan_tag_str), "%d", ru_session->ru_mplane_config.vlan_tag[idx]);
ret = lyd_new_term(eth_flow, NULL, "vlan-id", vlan_tag_str, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"vlan-id\" node.\n");
ret = lyd_new_term(eth_flow, NULL, "ru-mac-address", ru_session->xran_mplane.ru_mac_addr, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-mac-address\" node.\n");
ret = lyd_new_term(eth_flow, NULL, "o-du-mac-address", ru_session->ru_mplane_config.du_mac_addr[idx], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-mac-address\" node.\n");
return true;
}
static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_term(*root, NULL, "cp-length", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length\" node.\n");
ret = lyd_new_term(*root, NULL, "cp-length-other", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length-other\" node.\n");
// to we actually store this from DU config file?
ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"offset-to-absolute-frequency-center\" node.\n");
struct lyd_node *compression_node = NULL;
ret = lyd_new_inner(*root, NULL, "compression", 0, &compression_node);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression\" node.\n");
char iq_width_str[8];
snprintf(iq_width_str, sizeof(iq_width_str), "%d", xran_mplane->iq_width);
ret = lyd_new_term(compression_node, NULL, "iq-bitwidth", iq_width_str, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"iq-bitwidth\" node.\n");
if (xran_mplane->iq_width < 16) {
ret = lyd_new_term(compression_node, NULL, "compression-type", "STATIC", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-type\" node.\n");
// ret = lyd_new_term(compression_node, NULL, "compression-method", "BLOCK_FLOATING_POINT", 0, NULL);
// VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-method\" node.\n");
}
struct lyd_node *eaxc_conf = NULL;
ret = lyd_new_inner(*root, NULL, "e-axcid", 0, &eaxc_conf);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"e-axcid\" node.\n");
char eaxc_id[8];
snprintf(eaxc_id, sizeof(eaxc_id), "%ld", idx);
ret = lyd_new_term(eaxc_conf, NULL, "eaxc-id", eaxc_id, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eaxc-id\" node.\n");
char du_port_bitmask[16];
snprintf(du_port_bitmask, sizeof(du_port_bitmask), "%d", xran_mplane->du_port_bitmask);
ret = lyd_new_term(eaxc_conf, NULL, "o-du-port-bitmask", du_port_bitmask, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-port-bitmask\" node.\n");
char band_sector_bitmask[8];
snprintf(band_sector_bitmask, sizeof(band_sector_bitmask), "%d", xran_mplane->band_sector_bitmask);
ret = lyd_new_term(eaxc_conf, NULL, "band-sector-bitmask", band_sector_bitmask, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"band-sector-bitmask\" node.\n");
char ccid_bitmask[8];
snprintf(ccid_bitmask, sizeof(ccid_bitmask), "%d", xran_mplane->ccid_bitmask);
ret = lyd_new_term(eaxc_conf, NULL, "ccid-bitmask", ccid_bitmask, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ccid-bitmask\" node.\n");
char ru_port_bitmask[8];
snprintf(ru_port_bitmask, sizeof(ru_port_bitmask), "%d", xran_mplane->ru_port_bitmask);
ret = lyd_new_term(eaxc_conf, NULL, "ru-port-bitmask", ru_port_bitmask, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-port-bitmask\" node.\n");
return true;
}
static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
bool success = true;
ret = lyd_new_path(NULL, *ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"user-plane-configuration\" node.\n");
if (ru_session->ru_mplane_config.rx_carriers.num != 1 || ru_session->ru_mplane_config.tx_carriers.num !=1)
MP_LOG_I("Only one carrier supported at the moment.\n");
// RX carriers
struct lyd_node *rx_carrier_node = NULL;
ret = lyd_new_list(*root, NULL, "rx-array-carriers", 0, &rx_carrier_node, ru_session->ru_mplane_config.rx_carriers.name[0]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carriers\" node.\n");
char rx_freq[16];
snprintf(rx_freq, sizeof(rx_freq), "%.0f", oai->rx_freq[0]);
ret = lyd_new_term(rx_carrier_node, NULL, "center-of-channel-bandwidth", rx_freq, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"center-of-channel-bandwidth\" node.\n");
char rx_arfcn[16];
snprintf(rx_arfcn, sizeof(rx_arfcn), "%d", to_nrarfcn(oai->nr_band, oai->rx_freq[0], oai->nr_scs_for_raster, oai->rx_bw));
ret = lyd_new_term(rx_carrier_node, NULL, "absolute-frequency-center", rx_arfcn, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"absolute-frequency-center\" node.\n");
char rx_bw[16];
snprintf(rx_bw, sizeof(rx_bw), "%.0f", oai->rx_bw);
ret = lyd_new_term(rx_carrier_node, NULL, "channel-bandwidth", rx_bw, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n");
ret = lyd_new_term(rx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-radio-frame-offset\" node.\n");
ret = lyd_new_term(rx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n");
// oai->rx_gain_offset is this the correction? if yes, test it later
ret = lyd_new_term(rx_carrier_node, NULL, "gain-correction", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain-correction\" node.\n");
ret = lyd_new_term(rx_carrier_node, NULL, "n-ta-offset", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"n-ta-offset\" node.\n");
ret = lyd_new_term(rx_carrier_node, NULL, "active", "ACTIVE", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
// TX carriers
struct lyd_node *tx_carrier_node = NULL;
ret = lyd_new_list(*root, NULL, "tx-array-carriers", 0, &tx_carrier_node, ru_session->ru_mplane_config.tx_carriers.name[0]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-array-carriers\" node.\n");
char tx_freq[16];
snprintf(tx_freq, sizeof(tx_freq), "%.0f", oai->tx_freq[0]);
ret = lyd_new_term(tx_carrier_node, NULL, "center-of-channel-bandwidth", tx_freq, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"center-of-channel-bandwidth\" node.\n");
char tx_arfcn[16];
snprintf(tx_arfcn, sizeof(tx_arfcn), "%d", to_nrarfcn(oai->nr_band, oai->tx_freq[0], oai->nr_scs_for_raster, oai->tx_bw));
ret = lyd_new_term(tx_carrier_node, NULL, "absolute-frequency-center", tx_arfcn, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"absolute-frequency-center\" node.\n");
char tx_bw[16];
snprintf(tx_bw, sizeof(tx_bw), "%.0f", oai->tx_bw);
ret = lyd_new_term(tx_carrier_node, NULL, "channel-bandwidth", tx_bw, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n");
// oai->tx_gain to be tested
ret = lyd_new_term(tx_carrier_node, NULL, "gain", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain\" node.\n");
ret = lyd_new_term(tx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-radio-frame-offset\" node.\n");
ret = lyd_new_term(tx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n");
ret = lyd_new_term(tx_carrier_node, NULL, "active", "ACTIVE", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
// PUSCH & PRACH endpoints
const size_t num_rx_ch = oai->rx_num_channels / num_rus;
for (size_t i = 0; i < num_rx_ch; i++) {
struct lyd_node *pusch_node = NULL;
ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &pusch_node, ru_session->ru_mplane_config.rx_endpoints.name[i]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n");
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pusch_node);
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[i]);
const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2);
struct lyd_node *prach_node = NULL;
ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &prach_node, ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n");
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i + ru_session->xran_mplane.prach_offset, &prach_node);
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]);
}
// PDSCH endpoints
const size_t num_tx_ch = oai->tx_num_channels / num_rus;
for (size_t i = 0; i < num_tx_ch; i++) {
struct lyd_node *pdsch_node = NULL;
ret = lyd_new_list(*root, NULL, "low-level-tx-endpoints", 0, &pdsch_node, ru_session->ru_mplane_config.tx_endpoints.name[i]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoints\" node.\n");
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pdsch_node);
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-tx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.tx_endpoints.name[i]);
}
// PUSCH and PRACH links
for (size_t i = 0; i < num_rx_ch; i++) {
// PUSCH
struct lyd_node *pusch_link_node = NULL;
char pusch_link[16];
snprintf(pusch_link, sizeof(pusch_link), "%s%ld", "PuschLink", i);
ret = lyd_new_list(*root, NULL, "low-level-rx-links", 0, &pusch_link_node, pusch_link);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-links\" node.\n");
ret = lyd_new_term(pusch_link_node, NULL, "processing-element", u_proc_elem, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n");
ret = lyd_new_term(pusch_link_node, NULL, "rx-array-carrier", ru_session->ru_mplane_config.rx_carriers.name[0], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carrier\" node.\n");
ret = lyd_new_term(pusch_link_node, NULL, "low-level-rx-endpoint", ru_session->ru_mplane_config.rx_endpoints.name[i], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoint\" node.\n");
// PRACH
struct lyd_node *prach_link_node = NULL;
char prach_link[16];
snprintf(prach_link, sizeof(prach_link), "%s%ld", "PrachLink", i);
ret = lyd_new_list(*root, NULL, "low-level-rx-links", 0, &prach_link_node, prach_link);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-links\" node.\n");
ret = lyd_new_term(prach_link_node, NULL, "processing-element", u_proc_elem, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n");
ret = lyd_new_term(prach_link_node, NULL, "rx-array-carrier", ru_session->ru_mplane_config.rx_carriers.name[0], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carrier\" node.\n");
const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2);
ret = lyd_new_term(prach_link_node, NULL, "low-level-rx-endpoint", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoint\" node.\n");
}
// PDSCH links
for (size_t i = 0; i < num_tx_ch; i++) {
struct lyd_node *pdsch_link_node = NULL;
char pdsch_link[16];
snprintf(pdsch_link, sizeof(pdsch_link), "%s%ld", "PdschLink", i);
ret = lyd_new_list(*root, NULL, "low-level-tx-links", 0, &pdsch_link_node, pdsch_link);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-links\" node.\n");
ret = lyd_new_term(pdsch_link_node, NULL, "processing-element", u_proc_elem, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n");
ret = lyd_new_term(pdsch_link_node, NULL, "tx-array-carrier", ru_session->ru_mplane_config.tx_carriers.name[0], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-array-carrier\" node.\n");
ret = lyd_new_term(pdsch_link_node, NULL, "low-level-tx-endpoint", ru_session->ru_mplane_config.tx_endpoints.name[i], 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoint\" node.\n");
}
return true;
}
#endif
bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result)
{
bool success = false;
#ifdef MPLANE_V1
VERIFY_SUCCESS(success, "[MPLANE] To be implemented and tested.\n");
#elif defined MPLANE_V2
const ru_mplane_config_t *ru_config = &ru_session->ru_mplane_config;
size_t num_cu_planes = ru_config->num_cu_planes;
if (num_cu_planes == 2 && ru_config->vlan_tag[0] == ru_config->vlan_tag[1]) {
MP_LOG_I("The VLAN tags for C and U plane for the RU \"%s\" are the same. Therefore, configuring one common interface and one processing element.\n", ru_session->ru_ip_add);
num_cu_planes = 1;
}
struct lyd_node *all_merge = NULL;
LY_ERR ret = LY_SUCCESS;
for (size_t i = 0; i < num_cu_planes; i++) {
// <ietf-interfaces>
struct lyd_node *cu_interface = NULL;
char int_name[12];
snprintf(int_name, sizeof(int_name), "INTERFACE_%ld", i);
success = create_cu_interface_v2(ctx, ru_session, i, int_name, &cu_interface);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane interface.\n");
// <o-ran-processing-element>
struct lyd_node *proc_elem = NULL;
success = create_proc_elem_v2(ctx, ru_session, i, int_name, &proc_elem);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane processing element.\n");
ret = lyd_merge_siblings(&all_merge, cu_interface, 0);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface.\n");
ret = lyd_merge_siblings(&all_merge, proc_elem, 0);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge processing element.\n");
lyd_free_tree(cu_interface);
lyd_free_tree(proc_elem);
}
// <o-ran-uplane-conf>
struct lyd_node *uplane_conf = NULL;
success = create_uplane_conf_v2(ctx, ru_session, oai, num_rus, "PLANE_0", &uplane_conf);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create U-plane configuration.\n");
ret = lyd_merge_siblings(&uplane_conf, all_merge, 0);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n");
lyd_print_mem(result, uplane_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS);
lyd_free_siblings(all_merge);
lyd_free_siblings(uplane_conf);
#endif
return true;
}
@@ -0,0 +1,32 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef CREATE_MPLANE_YANG_CONFIG_H
#define CREATE_MPLANE_YANG_CONFIG_H
#include "../ru-mplane-api.h"
#include "radio/COMMON/common_lib.h"
#include <libyang/libyang.h>
bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result);
#endif /* CREATE_MPLANE_YANG_CONFIG_H */
+141
View File
@@ -0,0 +1,141 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "get-yang.h"
#include "../rpc-send-recv.h"
#include "common/utils/assertions.h"
#include <libxml/parser.h>
static bool store_schemas(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
NC_WD_MODE wd = NC_WD_ALL;
NC_PARAMTYPE param = NC_PARAMTYPE_CONST;
LYS_INFORMAT ly_format = LYS_IN_YANG;
#ifdef MPLANE_V1
*ctx = ly_ctx_new(NULL, 0);
#elif defined MPLANE_V2
ly_ctx_new(NULL, 0, ctx);
#endif
for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) {
if (strcmp((const char *)cur_node->name, "schema") == 0) {
xmlNode *name_node = xmlFirstElementChild(cur_node);
char *module_name = (char *)xmlNodeGetContent(name_node);
xmlNode *revision_node = xmlNextElementSibling(name_node);
char *module_revision = (char *)xmlNodeGetContent(revision_node);
xmlNode *format_node = xmlNextElementSibling(revision_node);
char *module_format = (char *)xmlNodeGetContent(format_node);
if (strcmp(module_format, "yang") != 0)
continue;
MP_LOG_I("RPC request to RU \"%s\" = <get-schema> for module \"%s\".\n", ru_session->ru_ip_add, module_name);
struct nc_rpc *get_schema_rpc = nc_rpc_getschema(module_name, module_revision, "yang", param);
char *schema_data = NULL;
bool success = rpc_send_recv((struct nc_session *)ru_session->session, get_schema_rpc, wd, timeout, &schema_data);
AssertError(success, return false, "[MPLANE] Unable to get schema for module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add);
if (schema_data) {
#ifdef MPLANE_V1
const struct lys_module *mod = lys_parse_mem(*ctx, schema_data, ly_format);
#elif defined MPLANE_V2
struct lys_module *mod = NULL;
lys_parse_mem(*ctx, schema_data, ly_format, &mod);
#endif
free(schema_data);
if (!mod) {
MP_LOG_W("Unable to load module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add);
nc_rpc_free(get_schema_rpc);
ly_ctx_destroy(*ctx);
return false;
}
}
nc_rpc_free(get_schema_rpc);
}
}
return true;
}
static bool load_from_operational_ds(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx)
{
for (xmlNode *schemas_node = node; schemas_node; schemas_node = schemas_node->next) {
if(schemas_node->type != XML_ELEMENT_NODE)
continue;
if (strcmp((const char *)schemas_node->name, "schemas") == 0) {
return store_schemas(schemas_node->children, ru_session, ctx);
} else {
bool success = load_from_operational_ds(schemas_node->children, ru_session, ctx);
if (success)
return true;
}
}
return false;
}
bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx)
{
// Initialize the xml file
size_t len = strlen(buffer) + 1;
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
xmlNode *root_element = xmlDocGetRootElement(doc);
bool success = load_from_operational_ds(root_element->children, ru_session, ctx);
if (success) {
MP_LOG_I("Successfully loaded all yang modules from operational datastore for RU \"%s\".\n", ru_session->ru_ip_add);
return true;
} else {
MP_LOG_W("Unable to load all yang modules from operational datastore for RU \"%s\". Using yang models present in \"models\" subfolder.\n", ru_session->ru_ip_add);
}
/* ideally, we should load the yang models from the operational datastore, but the issues are following:
1) the yang models order is not good - the dependancy models have to be loaded first
2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) */
const char *yang_dir = YANG_MODELS;
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf"};
#ifdef MPLANE_V1
*ctx = ly_ctx_new(yang_dir, 0);
AssertError(*ctx != NULL, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx));
#elif defined MPLANE_V2
LY_ERR ret = ly_ctx_new(yang_dir, 0, ctx);
AssertError(ret == LY_SUCCESS, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx));
#endif
const size_t num_models = sizeof(yang_models) / sizeof(yang_models[0]);
for (size_t i = 0; i < num_models; ++i) {
#ifdef MPLANE_V1
const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL);
AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]);
#elif defined MPLANE_V2
const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL, NULL);
AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]);
#endif
}
MP_LOG_I("Successfully loaded all yang modules for RU \"%s\".\n", ru_session->ru_ip_add);
return true;
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef GET_MPLANE_YANG_MODELS_H
#define GET_MPLANE_YANG_MODELS_H
#include "../ru-mplane-api.h"
#include <libyang/libyang.h>
bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx);
#endif /* GET_MPLANE_YANG_MODELS_H */
+180
View File
@@ -0,0 +1,180 @@
module iana-hardware {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:iana-hardware";
prefix ianahw;
organization "IANA";
contact
" Internet Assigned Numbers Authority
Postal: ICANN
12025 Waterfront Drive, Suite 300
Los Angeles, CA 90094-2536
United States of America
Tel: +1 310 301 5800
E-Mail: iana@iana.org>";
description
"IANA-defined identities for hardware class.
The latest revision of this YANG module can be obtained from
the IANA website.
Requests for new values should be made to IANA via
email (iana@iana.org).
Copyright (c) 2018 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
The initial version of this YANG module is part of RFC 8348;
see the RFC itself for full legal notices.";
reference
"https://www.iana.org/assignments/yang-parameters";
revision 2018-03-13 {
description
"Initial revision.";
reference
"RFC 8348: A YANG Data Model for Hardware Management";
}
/*
* Identities
*/
identity hardware-class {
description
"This identity is the base for all hardware class
identifiers.";
}
identity unknown {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is unknown
to the server.";
}
identity chassis {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is an
overall container for networking equipment. Any class of
physical component, except a stack, may be contained within a
chassis; a chassis may only be contained within a stack.";
}
identity backplane {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of device for aggregating and forwarding networking traffic,
such as a shared backplane in a modular ethernet switch. Note
that an implementation may model a backplane as a single
physical component, which is actually implemented as multiple
discrete physical components (within a chassis or stack).";
}
identity container {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is capable
of containing one or more removable physical entities,
possibly of different types. For example, each (empty or
full) slot in a chassis will be modeled as a container. Note
that all removable physical components should be modeled
within a container component, such as field-replaceable
modules, fans, or power supplies. Note that all known
containers should be modeled by the agent, including empty
containers.";
}
identity power-supply {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is a
power-supplying component.";
}
identity fan {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is a fan or
other heat-reduction component.";
}
identity sensor {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of sensor, such as a temperature sensor within a router
chassis.";
}
identity module {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of self-contained sub-system. If a module component is
removable, then it should be modeled within a container
component; otherwise, it should be modeled directly within
another physical component (e.g., a chassis or another
module).";
}
identity port {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of networking port capable of receiving and/or transmitting
networking traffic.";
}
identity stack {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of super-container (possibly virtual) intended to group
together multiple chassis entities. A stack may be realized
by a virtual cable, a real interconnect cable attached to
multiple chassis, or multiple interconnect cables. A stack
should not be modeled within any other physical components,
but a stack may be contained within another stack. Only
chassis components should be contained within a stack.";
}
identity cpu {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of central processing unit.";
}
identity energy-object {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of energy object, i.e., it is a piece of equipment that is
part of or attached to a communications network that is
monitored, it is controlled, or it aids in the management of
another device for Energy Management.";
}
identity battery {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of battery.";
}
identity storage-drive {
base ianahw:hardware-class;
description
"This identity is applicable if the hardware class is some sort
of component with data storage capability as its main
functionality, e.g., hard disk drive (HDD), solid-state device
(SSD), solid-state hybrid drive (SSHD), object storage device
(OSD), or other.";
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,860 @@
module ietf-ip {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-ip";
prefix ip;
import ietf-interfaces {
prefix if;
}
import ietf-inet-types {
prefix inet;
}
import ietf-yang-types {
prefix yang;
}
organization
"IETF NETMOD (Network Modeling) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Editor: Martin Bjorklund
<mailto:mbj@tail-f.com>";
description
"This module contains a collection of YANG definitions for
managing IP implementations.
Copyright (c) 2018 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8344; see
the RFC itself for full legal notices.";
revision 2018-02-22 {
description
"Updated to support NMDA.";
reference
"RFC 8344: A YANG Data Model for IP Management";
}
revision 2014-06-16 {
description
"Initial revision.";
reference
"RFC 7277: A YANG Data Model for IP Management";
}
/*
* Features
*/
feature ipv4-non-contiguous-netmasks {
description
"Indicates support for configuring non-contiguous
subnet masks.";
}
feature ipv6-privacy-autoconf {
description
"Indicates support for privacy extensions for stateless address
autoconfiguration in IPv6.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6";
}
/*
* Typedefs
*/
typedef ip-address-origin {
type enumeration {
enum other {
description
"None of the following.";
}
enum static {
description
"Indicates that the address has been statically
configured -- for example, using the Network Configuration
Protocol (NETCONF) or a command line interface.";
}
enum dhcp {
description
"Indicates an address that has been assigned to this
system by a DHCP server.";
}
enum link-layer {
description
"Indicates an address created by IPv6 stateless
autoconfiguration that embeds a link-layer address in its
interface identifier.";
}
enum random {
description
"Indicates an address chosen by the system at
random, e.g., an IPv4 address within 169.254/16, a
temporary address as described in RFC 4941, or a
semantically opaque address as described in RFC 7217.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6
RFC 7217: A Method for Generating Semantically Opaque
Interface Identifiers with IPv6 Stateless
Address Autoconfiguration (SLAAC)";
}
}
description
"The origin of an address.";
}
typedef neighbor-origin {
type enumeration {
enum other {
description
"None of the following.";
}
enum static {
description
"Indicates that the mapping has been statically
configured -- for example, using NETCONF or a command line
interface.";
}
enum dynamic {
description
"Indicates that the mapping has been dynamically resolved
using, for example, IPv4 ARP or the IPv6 Neighbor
Discovery protocol.";
}
}
description
"The origin of a neighbor entry.";
}
/*
* Data nodes
*/
augment "/if:interfaces/if:interface" {
description
"IP parameters on interfaces.
If an interface is not capable of running IP, the server
must not allow the client to configure these parameters.";
container ipv4 {
presence
"Enables IPv4 unless the 'enabled' leaf
(which defaults to 'true') is set to 'false'";
description
"Parameters for the IPv4 address family.";
leaf enabled {
type boolean;
default true;
description
"Controls whether IPv4 is enabled or disabled on this
interface. When IPv4 is enabled, this interface is
connected to an IPv4 stack, and the interface can send
and receive IPv4 packets.";
}
leaf forwarding {
type boolean;
default false;
description
"Controls IPv4 packet forwarding of datagrams received by,
but not addressed to, this interface. IPv4 routers
forward datagrams. IPv4 hosts do not (except those
source-routed via the host).";
}
leaf mtu {
type uint16 {
range "68..max";
}
units "octets";
description
"The size, in octets, of the largest IPv4 packet that the
interface will send and receive.
The server may restrict the allowed values for this leaf,
depending on the interface's type.
If this leaf is not configured, the operationally used MTU
depends on the interface's type.";
reference
"RFC 791: Internet Protocol";
}
list address {
key "ip";
description
"The list of IPv4 addresses on the interface.";
leaf ip {
type inet:ipv4-address-no-zone;
description
"The IPv4 address on the interface.";
}
choice subnet {
mandatory true;
description
"The subnet can be specified as a prefix length or,
if the server supports non-contiguous netmasks, as
a netmask.";
leaf prefix-length {
type uint8 {
range "0..32";
}
description
"The length of the subnet prefix.";
}
leaf netmask {
if-feature ipv4-non-contiguous-netmasks;
type yang:dotted-quad;
description
"The subnet specified as a netmask.";
}
}
leaf origin {
type ip-address-origin;
config false;
description
"The origin of this address.";
}
}
list neighbor {
key "ip";
description
"A list of mappings from IPv4 addresses to
link-layer addresses.
Entries in this list in the intended configuration are
used as static entries in the ARP Cache.
In the operational state, this list represents the ARP
Cache.";
reference
"RFC 826: An Ethernet Address Resolution Protocol";
leaf ip {
type inet:ipv4-address-no-zone;
description
"The IPv4 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
mandatory true;
description
"The link-layer address of the neighbor node.";
}
leaf origin {
type neighbor-origin;
config false;
description
"The origin of this neighbor entry.";
}
}
}
container ipv6 {
presence
"Enables IPv6 unless the 'enabled' leaf
(which defaults to 'true') is set to 'false'";
description
"Parameters for the IPv6 address family.";
leaf enabled {
type boolean;
default true;
description
"Controls whether IPv6 is enabled or disabled on this
interface. When IPv6 is enabled, this interface is
connected to an IPv6 stack, and the interface can send
and receive IPv6 packets.";
}
leaf forwarding {
type boolean;
default false;
description
"Controls IPv6 packet forwarding of datagrams received by,
but not addressed to, this interface. IPv6 routers
forward datagrams. IPv6 hosts do not (except those
source-routed via the host).";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 6.2.1, IsRouter";
}
leaf mtu {
type uint32 {
range "1280..max";
}
units "octets";
description
"The size, in octets, of the largest IPv6 packet that the
interface will send and receive.
The server may restrict the allowed values for this leaf,
depending on the interface's type.
If this leaf is not configured, the operationally used MTU
depends on the interface's type.";
reference
"RFC 8200: Internet Protocol, Version 6 (IPv6)
Specification
Section 5";
}
list address {
key "ip";
description
"The list of IPv6 addresses on the interface.";
leaf ip {
type inet:ipv6-address-no-zone;
description
"The IPv6 address on the interface.";
}
leaf prefix-length {
type uint8 {
range "0..128";
}
mandatory true;
description
"The length of the subnet prefix.";
}
leaf origin {
type ip-address-origin;
config false;
description
"The origin of this address.";
}
leaf status {
type enumeration {
enum preferred {
description
"This is a valid address that can appear as the
destination or source address of a packet.";
}
enum deprecated {
description
"This is a valid but deprecated address that should
no longer be used as a source address in new
communications, but packets addressed to such an
address are processed as expected.";
}
enum invalid {
description
"This isn't a valid address, and it shouldn't appear
as the destination or source address of a packet.";
}
enum inaccessible {
description
"The address is not accessible because the interface
to which this address is assigned is not
operational.";
}
enum unknown {
description
"The status cannot be determined for some reason.";
}
enum tentative {
description
"The uniqueness of the address on the link is being
verified. Addresses in this state should not be
used for general communication and should only be
used to determine the uniqueness of the address.";
}
enum duplicate {
description
"The address has been determined to be non-unique on
the link and so must not be used.";
}
enum optimistic {
description
"The address is available for use, subject to
restrictions, while its uniqueness on a link is
being verified.";
}
}
config false;
description
"The status of an address. Most of the states correspond
to states from the IPv6 Stateless Address
Autoconfiguration protocol.";
reference
"RFC 4293: Management Information Base for the
Internet Protocol (IP)
- IpAddressStatusTC
RFC 4862: IPv6 Stateless Address Autoconfiguration";
}
}
list neighbor {
key "ip";
description
"A list of mappings from IPv6 addresses to
link-layer addresses.
Entries in this list in the intended configuration are
used as static entries in the Neighbor Cache.
In the operational state, this list represents the
Neighbor Cache.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
leaf ip {
type inet:ipv6-address-no-zone;
description
"The IPv6 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
mandatory true;
description
"The link-layer address of the neighbor node.
In the operational state, if the neighbor's 'state' leaf
is 'incomplete', this leaf is not instantiated.";
}
leaf origin {
type neighbor-origin;
config false;
description
"The origin of this neighbor entry.";
}
leaf is-router {
type empty;
config false;
description
"Indicates that the neighbor node acts as a router.";
}
leaf state {
type enumeration {
enum incomplete {
description
"Address resolution is in progress, and the
link-layer address of the neighbor has not yet been
determined.";
}
enum reachable {
description
"Roughly speaking, the neighbor is known to have been
reachable recently (within tens of seconds ago).";
}
enum stale {
description
"The neighbor is no longer known to be reachable, but
until traffic is sent to the neighbor no attempt
should be made to verify its reachability.";
}
enum delay {
description
"The neighbor is no longer known to be reachable, and
traffic has recently been sent to the neighbor.
Rather than probe the neighbor immediately, however,
delay sending probes for a short while in order to
give upper-layer protocols a chance to provide
reachability confirmation.";
}
enum probe {
description
"The neighbor is no longer known to be reachable, and
unicast Neighbor Solicitation probes are being sent
to verify reachability.";
}
}
config false;
description
"The Neighbor Unreachability Detection state of this
entry.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 7.3.2";
}
}
leaf dup-addr-detect-transmits {
type uint32;
default 1;
description
"The number of consecutive Neighbor Solicitation messages
sent while performing Duplicate Address Detection on a
tentative address. A value of zero indicates that
Duplicate Address Detection is not performed on
tentative addresses. A value of one indicates a single
transmission with no follow-up retransmissions.";
reference
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
}
container autoconf {
description
"Parameters to control the autoconfiguration of IPv6
addresses, as described in RFC 4862.";
reference
"RFC 4862: IPv6 Stateless Address Autoconfiguration";
leaf create-global-addresses {
type boolean;
default true;
description
"If enabled, the host creates global addresses as
described in RFC 4862.";
reference
"RFC 4862: IPv6 Stateless Address Autoconfiguration
Section 5.5";
}
leaf create-temporary-addresses {
if-feature ipv6-privacy-autoconf;
type boolean;
default false;
description
"If enabled, the host creates temporary addresses as
described in RFC 4941.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6";
}
leaf temporary-valid-lifetime {
if-feature ipv6-privacy-autoconf;
type uint32;
units "seconds";
default 604800;
description
"The time period during which the temporary address
is valid.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6
- TEMP_VALID_LIFETIME";
}
leaf temporary-preferred-lifetime {
if-feature ipv6-privacy-autoconf;
type uint32;
units "seconds";
default 86400;
description
"The time period during which the temporary address is
preferred.";
reference
"RFC 4941: Privacy Extensions for Stateless Address
Autoconfiguration in IPv6
- TEMP_PREFERRED_LIFETIME";
}
}
}
}
/*
* Legacy operational state data nodes
*/
augment "/if:interfaces-state/if:interface" {
status deprecated;
description
"Data nodes for the operational state of IP on interfaces.";
container ipv4 {
presence
"Present if IPv4 is enabled on this interface";
config false;
status deprecated;
description
"Interface-specific parameters for the IPv4 address family.";
leaf forwarding {
type boolean;
status deprecated;
description
"Indicates whether IPv4 packet forwarding is enabled or
disabled on this interface.";
}
leaf mtu {
type uint16 {
range "68..max";
}
units "octets";
status deprecated;
description
"The size, in octets, of the largest IPv4 packet that the
interface will send and receive.";
reference
"RFC 791: Internet Protocol";
}
list address {
key "ip";
status deprecated;
description
"The list of IPv4 addresses on the interface.";
leaf ip {
type inet:ipv4-address-no-zone;
status deprecated;
description
"The IPv4 address on the interface.";
}
choice subnet {
status deprecated;
description
"The subnet can be specified as a prefix length or,
if the server supports non-contiguous netmasks, as
a netmask.";
leaf prefix-length {
type uint8 {
range "0..32";
}
status deprecated;
description
"The length of the subnet prefix.";
}
leaf netmask {
if-feature ipv4-non-contiguous-netmasks;
type yang:dotted-quad;
status deprecated;
description
"The subnet specified as a netmask.";
}
}
leaf origin {
type ip-address-origin;
status deprecated;
description
"The origin of this address.";
}
}
list neighbor {
key "ip";
status deprecated;
description
"A list of mappings from IPv4 addresses to
link-layer addresses.
This list represents the ARP Cache.";
reference
"RFC 826: An Ethernet Address Resolution Protocol";
leaf ip {
type inet:ipv4-address-no-zone;
status deprecated;
description
"The IPv4 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
status deprecated;
description
"The link-layer address of the neighbor node.";
}
leaf origin {
type neighbor-origin;
status deprecated;
description
"The origin of this neighbor entry.";
}
}
}
container ipv6 {
presence
"Present if IPv6 is enabled on this interface";
config false;
status deprecated;
description
"Parameters for the IPv6 address family.";
leaf forwarding {
type boolean;
default false;
status deprecated;
description
"Indicates whether IPv6 packet forwarding is enabled or
disabled on this interface.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 6.2.1, IsRouter";
}
leaf mtu {
type uint32 {
range "1280..max";
}
units "octets";
status deprecated;
description
"The size, in octets, of the largest IPv6 packet that the
interface will send and receive.";
reference
"RFC 8200: Internet Protocol, Version 6 (IPv6)
Specification
Section 5";
}
list address {
key "ip";
status deprecated;
description
"The list of IPv6 addresses on the interface.";
leaf ip {
type inet:ipv6-address-no-zone;
status deprecated;
description
"The IPv6 address on the interface.";
}
leaf prefix-length {
type uint8 {
range "0..128";
}
mandatory true;
status deprecated;
description
"The length of the subnet prefix.";
}
leaf origin {
type ip-address-origin;
status deprecated;
description
"The origin of this address.";
}
leaf status {
type enumeration {
enum preferred {
description
"This is a valid address that can appear as the
destination or source address of a packet.";
}
enum deprecated {
description
"This is a valid but deprecated address that should
no longer be used as a source address in new
communications, but packets addressed to such an
address are processed as expected.";
}
enum invalid {
description
"This isn't a valid address, and it shouldn't appear
as the destination or source address of a packet.";
}
enum inaccessible {
description
"The address is not accessible because the interface
to which this address is assigned is not
operational.";
}
enum unknown {
description
"The status cannot be determined for some reason.";
}
enum tentative {
description
"The uniqueness of the address on the link is being
verified. Addresses in this state should not be
used for general communication and should only be
used to determine the uniqueness of the address.";
}
enum duplicate {
description
"The address has been determined to be non-unique on
the link and so must not be used.";
}
enum optimistic {
description
"The address is available for use, subject to
restrictions, while its uniqueness on a link is
being verified.";
}
}
status deprecated;
description
"The status of an address. Most of the states correspond
to states from the IPv6 Stateless Address
Autoconfiguration protocol.";
reference
"RFC 4293: Management Information Base for the
Internet Protocol (IP)
- IpAddressStatusTC
RFC 4862: IPv6 Stateless Address Autoconfiguration";
}
}
list neighbor {
key "ip";
status deprecated;
description
"A list of mappings from IPv6 addresses to
link-layer addresses.
This list represents the Neighbor Cache.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)";
leaf ip {
type inet:ipv6-address-no-zone;
status deprecated;
description
"The IPv6 address of the neighbor node.";
}
leaf link-layer-address {
type yang:phys-address;
status deprecated;
description
"The link-layer address of the neighbor node.";
}
leaf origin {
type neighbor-origin;
status deprecated;
description
"The origin of this neighbor entry.";
}
leaf is-router {
type empty;
status deprecated;
description
"Indicates that the neighbor node acts as a router.";
}
leaf state {
type enumeration {
enum incomplete {
description
"Address resolution is in progress, and the
link-layer address of the neighbor has not yet been
determined.";
}
enum reachable {
description
"Roughly speaking, the neighbor is known to have been
reachable recently (within tens of seconds ago).";
}
enum stale {
description
"The neighbor is no longer known to be reachable, but
until traffic is sent to the neighbor no attempt
should be made to verify its reachability.";
}
enum delay {
description
"The neighbor is no longer known to be reachable, and
traffic has recently been sent to the neighbor.
Rather than probe the neighbor immediately, however,
delay sending probes for a short while in order to
give upper-layer protocols a chance to provide
reachability confirmation.";
}
enum probe {
description
"The neighbor is no longer known to be reachable, and
unicast Neighbor Solicitation probes are being sent
to verify reachability.";
}
}
status deprecated;
description
"The Neighbor Unreachability Detection state of this
entry.";
reference
"RFC 4861: Neighbor Discovery for IP version 6 (IPv6)
Section 7.3.2";
}
}
}
}
}
@@ -0,0 +1,368 @@
module o-ran-compression-factors {
yang-version 1.1;
namespace "urn:o-ran:compression-factors:1.0";
prefix "o-ran-compression-factors";
organization "O-RAN Alliance";
contact
"www.o-ran.org";
description
"This module defines the module capabilities for
the O-RAN Radio Unit U-Plane configuration.
Copyright 2020 the O-RAN Alliance.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the above disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the above disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the Members of the O-RAN Alliance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.";
revision "2020-08-10" {
description
"version 4.0.0
1) supporting compression types per endpoint
2) adding feature for configurable fs-offset for compression";
reference "ORAN-WG4.M.0-v04.00";
}
revision "2020-04-17" {
description
"version 3.0.0
1) adding selective RE sending compression types";
reference "ORAN-WG4.M.0-v03.00";
}
revision "2019-07-03" {
description
"version 1.1.0
1) changes related to compression bitwidth presentation";
reference "ORAN-WG4.M.0-v01.00";
}
revision "2019-02-04" {
description
"version 1.0.0
1) imported model from xRAN
2) changed namespace and reference from xran to o-ran";
reference "ORAN-WG4.M.0-v01.00";
}
feature CONFIGURABLE-FS-OFFSET {
description
"Presence of this feature means that O-RU supports configurable fs-offset for compression.";
}
grouping compression-method-grouping {
description
"Grouping for compression method.";
leaf iq-bitwidth {
type uint8;
description
"Bitwidth to be used in compression";
}
leaf compression-method {
type enumeration {
enum NO_COMPRESSION {
description
"No compression will be used";
}
enum BLOCK_FLOATING_POINT {
description
"Block floating point compression and decompression will be used";
}
enum BLOCK_SCALING {
description
"Block scaling compression and decompresion will be used";
}
enum U_LAW {
description
"u-Law compression and decompresion method will be used";
}
enum BEAMSPACE {
description
"Beamspace compression and decompression will be used";
}
enum MODULATION {
description
"Modulation compression and decompression will be used";
}
enum BLOCK-FLOATING-POINT-SELECTIVE-RE-SENDING {
description
"block floating point with selective re sending
compression and decompression will be used";
}
enum MODULATION-COMPRESSION-SELECTIVE-RE-SENDING {
description
"modulation compression with selective re sending
compression and decompression will be used";
}
}
description
"Compresion method which can be supported by the O-RU";
}
}
grouping compression-formats {
description
"Grouping deicated to list compression formats as choice";
choice compression-format {
description
"Choice of compression format for particular element";
case no-compresison {
description "Compression for beam weights is not supported.";
}
case block-floating-point {
description "Block floating point compression and decompression is supported.";
leaf exponent {
type uint8 {
range "4";
}
description "Exponent bit width size in number of bits used when encoding in udCompParam.";
}
}
case block-floating-point-selective-re-sending {
description
"Block floating point with selective re sending compression and decompression is supported.";
leaf sres-exponent {
type uint8 {
range "4";
}
description "Exponent bit width size in number of bits used when encoding in udCompParam.";
}
}
case block-scaling {
description "Block scaling compression and decompresion is supported.";
leaf block-scalar {
type uint8;
description
"Common scaler for compressed PRB";
}
}
case u-law {
description "u-Law compression and decompresion method is supported.";
leaf comp-bit-width {
type uint8 {
range "0..15";
}
description "Bit with for u-law compression";
}
leaf comp-shift {
type uint8 {
range "0..15";
}
description
"the shift applied to the entire PRB";
}
}
case beam-space-compression {
description "Beamspace compression and decompression is supported. Applies to beamforming weights only.";
leaf-list active-beam-space-coeficient-mask {
type uint8;
description
"active beamspace coefficient indices associated with the compressed beamforming vector";
}
leaf block-scaler {
type uint8;
description
"Common scaler for compressed beamforming coefficients";
}
}
case modulation-compression {
description "Modulation compression and decompression is supported.";
leaf csf {
type uint8 {
range "0..1";
}
description "Constallation shift flag";
}
leaf mod-comp-scaler {
type uint16 {
range "0..32767";
}
description "Modulation compression scaler value.";
}
}
case modulation-compression-selective-re-sending {
description "Modulation compression with selective re sending and decompression is supported.";
leaf sres-csf {
type uint8 {
range "0..1";
}
description "Constallation shift flag";
}
leaf sres-mod-comp-scaler {
type uint16 {
range "0..32767";
}
description "Modulation compression scaler value.";
}
}
}
}
grouping compression-params {
description
"Parameters to define compression";
leaf compression-type {
type enumeration {
enum STATIC {
description
"Indicates that static compression method will be used (both compression and IQ bitwidth)";
}
enum DYNAMIC {
description
"Indicates that dynamic compression method will be used";
}
}
mandatory true;
description
"Compression type that O-DU wants to be supported";
}
// *********** TO BE REMOVED ***********
leaf bitwidth {
when "../compression-type = 'STATIC'";
type uint8;
status deprecated;
description
"Bitwidth to be used in compression.
This has since been replaced in M-Plane version
2.0.0 with the iq-bitwidth schema node";
}
// *************************************
uses compression-formats;
}
grouping compression-parameters {
description
"Parameters used to define description type";
leaf iq-bitwidth {
type uint8;
description
"Bitwidth to be used in compression";
}
uses compression-formats;
}
grouping format-of-iq-sample {
description
"Indicates module capabilities about IQ samples";
leaf dynamic-compression-supported {
type boolean;
description
"Informs if radio supports dynamic compression method";
}
leaf realtime-variable-bit-width-supported {
type boolean;
description
"Informs if O-RU supports realtime variable bit with";
}
list compression-method-supported {
uses compression-parameters;
description
"List of supported compression methods by O-RU
Note: if O-RU supports different compression methods per endpoint
then please refer do endpoints to have information what
exactly is supported on a paticular endpoint";
}
leaf syminc-supported {
type boolean;
description
"Informs if symbol number increment command in a C-Plane is
supported or not";
}
leaf regularization-factor-se-supported {
type boolean;
description
"Informs if regularizationFactor in section type 5 is
supported(true) or not(false)";
}
leaf little-endian-supported {
type boolean;
default false;
description
"All O-RUs support bigendian byte order. This node informs if module supports the
the optional capability for little endian byte order for C/U plane data flows.
Note - little endian support does not invalidate bigendian support.";
}
}
grouping compression-details {
description "";
leaf iq-bitwidth {
type uint8;
description
"Bitwidth to be used in compression";
}
uses compression-params;
}
}
@@ -0,0 +1,414 @@
module o-ran-interfaces {
yang-version 1.1;
namespace "urn:o-ran:interfaces:1.0";
prefix "o-ran-int";
import ietf-inet-types {
prefix "inet";
}
import iana-if-type {
prefix "ianaift";
}
import ietf-interfaces {
prefix "if";
}
import ietf-ip {
prefix "ip";
}
import ietf-hardware {
prefix "hw";
}
import ietf-yang-types {
prefix "yang";
}
import iana-hardware {
prefix "ianahw";
}
organization "O-RAN Alliance";
contact
"www.o-ran.org";
description
"This module defines the YANG definitions for managng the O-RAN
interfaces.
Copyright 2020 the O-RAN Alliance.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the above disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the above disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the Members of the O-RAN Alliance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.";
revision "2020-04-17" {
description
"version 1.2.0
1) updated descriptions to clarify operation when vlan-tagging is false";
reference "ORAN-WG4.M.0-v03.00";
}
revision "2019-07-03" {
description
"version 1.1.0
1) increasing max elements for user plane DSCP markings to 64
2) re-organizing layout to facilitate cross-WG adoption, whilst ensuring
nodes are syntactically and semantically equivalent";
reference "ORAN-WG4.M.0-v01.00";
}
revision "2019-02-04" {
description
"version 1.0.0
1) imported model from xRAN
2) changed namespace and reference from xran to o-ran";
reference "ORAN-WG4.M.0-v01.00";
}
feature UDPIP-BASED-CU-PLANE {
description
"This feature indicates that the RU supports the UDP/IP based transport
for the CU plane.";
}
feature ALIASMAC-BASED-CU-PLANE {
description
"This feature indicates that the RU supports the alias MAC address
based transport for the CU plane.";
}
typedef pcp {
type uint8 {
range "0..7";
}
description
"Priority Code Point. PCP is a 3-bit field that refers to the
class of service applied to a VLAN tagged frame. The
field specifies a priority value between 0 and 7, these values
can be used by quality of service (QoS) to prioritize
different classes of traffic.";
reference
"IEEE 802.1Q-2014: Virtual Bridged Local Area Networks";
}
grouping cos-marking {
description
"Configuration data for CU Plane ethernet CoS marking.
This grouping is only applicable to an interface when vlan-tagging is
set to TRUE for that interface. In other cases, it may be ignored.";
container class-of-service {
description
"CoS Configuration";
leaf u-plane-marking {
type pcp;
default 7;
description
"Marking used for default u-plane flows.
7 represents highest priority for u-plane marking";
}
leaf c-plane-marking {
type pcp;
default 7;
description "7 represents highest priority for c-plane marking";
}
leaf m-plane-marking {
type pcp;
default 2;
description "2 represents highest excellent effort for m-plane marking";
}
leaf s-plane-marking {
type pcp;
default 7;
description "7 represents highest priority for s-plane marking";
}
leaf other-marking {
type pcp;
default 1;
description "1 represents best effort for other marking";
}
list enhanced-uplane-markings{
key "up-marking-name";
max-elements 4;
description
"list of mappings for enhanced (non-default) u-plane markings";
leaf up-marking-name {
type string;
description "The name of the marking";
}
leaf enhanced-marking {
type pcp;
description "the enhanced u-plane marking";
}
}
}
}
grouping dscp-marking {
description
"Configuration data for CU Plane DSCP marking";
container diffserv-markings {
description
"DSCP Configuration";
leaf u-plane-marking {
type inet:dscp;
default 46;
description
"Marking used for default u-plane flows.
46 represents expedited forwarding";
}
leaf c-plane-marking {
type inet:dscp;
default 46;
description "46 represents expedited forwarding";
}
leaf s-plane-marking {
type inet:dscp;
default 46;
description "46 represents expedited forwarding";
}
leaf other-marking {
type inet:dscp;
default 0;
description "0 represents best effort forwarding";
}
list enhanced-uplane-markings{
key up-marking-name;
max-elements 64;
description
"list of mappings for enhanced (non-default) u-plane markings";
leaf up-marking-name {
type string;
description "The name of the marking";
}
leaf enhanced-marking {
type inet:dscp;
description "the enhanced u-plane marking";
}
}
}
}
// Cross Working Group Augmentations Follow
// Cross Working Group augmentations for basic Ethernet leafs
augment "/if:interfaces/if:interface" {
when "if:type = 'ianaift:ethernetCsmacd'" {
description "Applies to Ethernet interfaces";
}
description
"Augment the interface model with parameters for
base Ethernet interface";
leaf l2-mtu {
type uint16 {
range "64 .. 65535";
}
units bytes;
default 1500;
description
"The maximum size of layer 2 frames that may be transmitted
or received on the interface (excluding any FCS overhead).
For Ethernet interfaces it also excludes the
4-8 byte overhead of any known (i.e. explicitly matched by
a child sub-interface) 801.1Q VLAN tags.";
}
leaf vlan-tagging {
type boolean;
default true;
description
"Indicates if VLAN tagging is used.
Default true is used to enable equipment to autonomously discover that
it is connected to a trunk port.
This may be set to false, for example, when the O-RU is directly
connected to the O-DU. In such cases, native Ethernet frames may be
used across the O-RAN interface, i.e., any PCP markings defined
in the cos-markings grouping are NOT used by the O-RU and any default
value or configured value using those leafs may be ignored by the O-RAN
equipment.";
}
uses cos-marking;
}
// Cross Working Group augmentation for l2vlan interfaces for VLAN definition
augment "/if:interfaces/if:interface" {
when "if:type = 'ianaift:l2vlan'";
description "augments for VLAN definition";
leaf base-interface {
type if:interface-ref;
must "/if:interfaces/if:interface[if:name = current()]"
+ "/o-ran-int:vlan-tagging = 'true'" {
description
"The base interface must have VLAN tagging enabled.";
}
description
"The base interface for the VLAN sub-interafce.";
}
leaf vlan-id {
type uint16 {
range "1..4094";
}
description
"The VLAN-ID.";
}
}
// Cross Working Group augmention for both ethernetCsmacd and l2vlan interfaces
augment "/if:interfaces/if:interface" {
when "(if:type = 'ianaift:ethernetCsmacd') or
(if:type = 'ianaift:l2vlan')" {
description "Applies to ethernetCsmacd and l2vlan interfaces";
}
description
"Augment the interface model with parameters for all
both ethernetCsmacd and l2vlan interfaces.";
leaf last-cleared {
type yang:date-and-time;
config false;
description
"Timestamp of the last time the interface counters were
cleared.";
}
}
// Cross Working Group augmention to ietf-ip covering DSCP for M-Plane
augment "/if:interfaces/if:interface/ip:ipv4" {
description "augments for IPv4 based M-Plane transport";
leaf m-plane-marking {
type inet:dscp;
default 18;
description "18 represents AF21 or 'immediate traffic'";
}
}
augment "/if:interfaces/if:interface/ip:ipv6" {
description "augments for IPv6 based M-Plane transport";
leaf m-plane-marking {
type inet:dscp;
default 18;
description "18 represents AF21 or 'immediate traffic'";
}
}
// WG4 Specific Augmentations Follow
// WG4 Augmentation for basic Ethernet leafs
augment "/if:interfaces/if:interface" {
if-feature ALIASMAC-BASED-CU-PLANE;
when "if:type = 'ianaift:ethernetCsmacd'" {
description
"Applies to WG4 Ethernet interfaces for alias MAC based CU-Plane";
}
description
"Augment the interface model with parameters for
base Ethernet interface";
leaf-list alias-macs {
type yang:mac-address;
description
"Augments interfaces with range of alias MAC addresses.";
}
}
// WG4 Augmention for both ethernetCsmacd and l2vlan interfaces
augment "/if:interfaces/if:interface" {
when "(if:type = 'ianaift:ethernetCsmacd') or
(if:type = 'ianaift:l2vlan')" {
description "Applies to ethernetCsmacd and l2vlan interfaces";
}
description
"Augment the interface model with parameters for all
both ethernetCsmacd and l2vlan interfaces.";
leaf mac-address {
type yang:mac-address;
description
"The MAC address of the interface.";
}
container port-reference {
description
"a port reference used by other O-RAN modules";
leaf port-name {
type leafref {
path '/hw:hardware/hw:component/hw:name';
}
must "derived-from-or-self(deref(current())/../hw:class, 'ianahw:port')";
// TAKE NOTE - depending on version of pyang, this may generate various
// warnings, e.g., warning: XPath for "port-name" does not exist
description
"O-RAN interfaces use a reference to a physical port component.
In this case, the component name referenced must be of class type
port, i.e., when /hw:hardware/hw:component/hw:class is derived from
ianahw:port";
}
leaf port-number {
type uint8;
description
"A number allocated by the server which identifies a port.
Port number value is 0 to N-1 where N is number of ports
in the device.
This value is fixed for the lifetime of the equipment, i.e., cannot be
changed during equipment reboots.";
}
}
}
// WG4 specific augmention to ietf-ip covering DSCP for CUS Plane
augment "/if:interfaces/if:interface/ip:ipv4" {
if-feature UDPIP-BASED-CU-PLANE;
description "augments for IPv4 based CUS transport";
uses dscp-marking;
}
augment "/if:interfaces/if:interface/ip:ipv6" {
if-feature UDPIP-BASED-CU-PLANE;
description "augments for IPv6 based CUS transport";
uses dscp-marking;
}
// Other Working Group Specific Augmentations Follow Here
rpc reset-interface-counters {
description
"Management plane triggered restart of the interface counters.";
}
}
@@ -0,0 +1,840 @@
module o-ran-module-cap {
yang-version 1.1;
namespace "urn:o-ran:module-cap:1.0";
prefix "o-ran-module-cap";
import o-ran-compression-factors {
prefix "cf";
revision-date 2020-08-10;
}
organization "O-RAN Alliance";
contact
"www.o-ran.org";
description
"This module defines the module capabilities for
the O-RAN Radio Unit.
Copyright 2020 the O-RAN Alliance.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the above disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the above disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the Members of the O-RAN Alliance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.";
revision "2020-08-10" {
description
"version 4.0.0
1) added RO capability to expose O-RU's ability to support udCompLen record in U-Plane section header fields
2) feature indicating support for static PRACH configuration introduced
3) feature indicating support for static SRS configuration introduced
4) feature indicating support for TDD pattern configuration introduced
5) backward compatible change to introduce new O-RU's features related
to Section Description Priority to serve for CUS-Plane C";
reference "ORAN-WG4.M.0-v04.00";
}
revision "2020-04-17" {
description
"version 3.0.0
1) Adding optional little endian support
2) Added support for Dynamic Spectrum Sharing feature
3) Enable number-of-ru-ports to be different between dl and ul
4) Enable regularizationFactor to be signalled outside of section type 6
5) Enable PRACH preamble formats supported to be signalled by O-RU
6) adding support for selective RE sending
7) supporting new section extension for grouping multiple ports
8) signalling to enable O-RU to ndicate is requires unique ecpri sequence id
for eAxC_IDs serving for UL and DL for the same carrier component";
reference "ORAN-WG4.M.0-v03.00";
}
revision "2019-07-03" {
description
"version 1.1.0
1) backward compatible change to introduce new RW leafs for use in
constraints in uplane-config and laa models.
2) removing unnecessary relations to band 46 in uplink";
reference "ORAN-WG4.M.0-v01.00";
}
revision "2019-02-04" {
description
"version 1.0.0
1) imported model from xRAN
2) changed namespace and reference from xran to o-ran";
reference "ORAN-WG4.M.0-v01.00";
}
feature LAA {
description
"Indicates that the Radio Unit supports LAA.";
}
feature EAXC-ID-GROUP-SUPPORTED {
description
"indicates that the Radio Unit supports EAXC-ID-GROUP-SUPPORTED.";
}
feature TRANSPORT-FRAGMENTATION {
description
"This leaf is used to indicate whether the O-RU supports O-RAN Radio Transport Fragmentation";
}
feature DSS_LTE_NR {
description
"Indicates that the Radio Unit supports Dynamic Spectrum Sharing between LTE and NR.";
}
feature PRACH-STATIC-CONFIGURATION-SUPPORTED {
description
"This leaf is used to indicate O-RU's support for configuration of PRACH (Physical Random Access Channel) pattern in the static manner, so that PRACH U-Plane traffic can be processed by RU without receiving C-Plane messages conveying the PRACH configuration.";
}
feature SRS-STATIC-CONFIGURATION-SUPPORTED {
description
"This leaf is used to indicate O-RU's support for configuration of SRS (Sounding Reference Signal Channel) pattern in the static manner, so that SRS U-Plane traffic can be processed by RU without receiving C-Plane messages conveying the SRS configuration.";
}
feature CONFIGURABLE-TDD-PATTERN-SUPPORTED {
description
"This leaf is used to indicate O-RU's support for configurable TDD pattern.";
}
typedef sub-band-string {
type string {
pattern [ABCD];
}
description "Sub bands definition";
}
typedef scs-config-type {
type enumeration {
enum KHZ_15 {
value 0;
description
"15kHz sub carrier spacing";
}
enum KHZ_30 {
value 1;
description
"30kHz sub carrier spacing";
}
enum KHZ_60 {
value 2;
description
"60kHz sub carrier spacing";
}
enum KHZ_120 {
value 3;
description
"120kHz sub carrier spacing";
}
enum KHZ_240 {
value 4;
description
"240kHz sub carrier spacing";
}
enum KHZ_1_25 {
value 12;
description
"1,25kHz sub carrier spacing";
}
enum KHZ_3_75 {
value 13;
description
"3.75kHz sub carrier spacing";
}
enum KHZ_5 {
value 14;
description
"5kHz sub carrier spacing";
}
enum KHZ_7_5 {
value 15;
description
"7.5kHz sub carrier spacing";
}
}
description
"Scs configuration type definition";
}
grouping compression-method-grouping {
description
"Grouping for compression method.";
leaf compression-method {
type enumeration {
enum BLOCK_FLOATING_POINT {
description
"Block floating point compression and decompression will be used";
}
enum BLOCK_SCALING {
description
"Block scaling compression and decompresion will be used";
}
enum U_LAW {
description
"u-Law compression and decompresion method will be used";
}
enum BEAMSPACE {
description
"Beamspace compression and decompression will be used";
}
enum MODULATION {
description
"Modulation compression and decompression will be used";
}
enum BLOCK-FLOATING-POINT-SELECTIVE-RE-SENDING {
description
"block floating point with selective re sending
compression and decompression will be used";
}
enum MODULATION-COMPRESSION-SELECTIVE-RE-SENDING {
description
"modulation compression with selective re sending
compression and decompression will be used";
}
}
description
"Compresion method which can be supported by the O-RU.
An O-RU may further refine the applicability of compression
methods per endpoint using o-ran-uplane-conf.yang model";
}
}
grouping sub-band-max-min-ul-dl-frequency {
description
"Grouping for defining max and min supported frequency - dl and ul.";
leaf max-supported-frequency-dl {
type uint64;
description
"This value indicates Maximum supported downlink frequency in the
LAA subband. Value unit is Hz.";
}
leaf min-supported-frequency-dl {
type uint64;
description
"This value indicates Minimum supported downlink frequency in the
LAA subband. Value unit is Hz.";
}
}
grouping format-of-iq-sample {
description
"Indicates module capabilities about IQ samples";
leaf dynamic-compression-supported {
type boolean;
description
"Informs if radio supports dynamic compression method";
}
leaf realtime-variable-bit-width-supported {
type boolean;
description
"Informs if O-RU supports realtime variable bit with";
}
list compression-method-supported {
uses cf:compression-details;
leaf-list fs-offset {
if-feature cf:CONFIGURABLE-FS-OFFSET;
type uint8;
default 0;
description
"List of fs offset values supported with this IQ format / compression method;
fs-offset adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format.
Please refer to CU-Plane specification for details";
}
description
"List of supported compression methods by O-RU
Note: if O-RU supports different compression methods per endpoint
then please refer to endpoints to have information what
exactly is supported on paticular endpoint";
}
leaf variable-bit-width-per-channel-supported {
when "/module-capability/ru-capabilities/format-of-iq-sample/realtime-variable-bit-width-supported = 'true'";
type boolean;
description
"Informs if variable bit width per channel is supported or not";
}
leaf syminc-supported {
type boolean;
description
"Informs if symbol number increment command in a C-Plane is
supported or not";
}
leaf regularization-factor-se-supported {
type boolean;
description
"Informs if regularizationFactor in section type 5 is
supported(true) or not(false)";
}
leaf little-endian-supported {
type boolean;
default false;
description
"All O-RUs support bigendian byte order. This node informs if module supports the
the optional capability for little endian byte order for C/U plane data flows.
Note - little endian support does not invalidate bigendian support.";
}
}
grouping scs-a-b {
description
"Grouping for scs-a and scs-b";
leaf scs-a{
type scs-config-type;
description
"Sub-carrier spacing configuration";
}
leaf scs-b{
type scs-config-type;
description
"Sub-carrier spacing configuration";
}
}
grouping ul-mixed-num-required-guard-rbs {
description
"Required number of guard resource blocks for the combination of
subcarrier spacing values for uplink";
uses scs-a-b;
leaf number-of-guard-rbs-ul{
type uint8;
description
"This value indicates the required number of guard resource blocks
between the mixed numerologies, the RB using scs-a and the RB
using scs-b. It's number is based on scs-a";
}
}
grouping dl-mixed-num-required-guard-rbs {
description
"Required number of guard resource blocks for the combination of
subcarrier spacing values for uplink";
uses scs-a-b;
leaf number-of-guard-rbs-dl{
type uint8;
description
"This value indicates the required number of guard resource blocks
between the mixed numerologies, the RB using scs-a and the RB
using scs-b. It's number is based on scs-a";
}
}
grouping ru-capabilities {
description
"Structure representing set of capabilities.";
leaf ru-supported-category {
type enumeration {
enum CAT_A {
description
"Informs that precoding is not supported in O-RU";
}
enum CAT_B {
description
"Informs that precoding is supported in O-RU";
}
}
description
"Informs about which category O-RU supports";
}
leaf number-of-ru-ports {
type uint8;
status deprecated;
description
"Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration)
- the number of O-RU ports is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports.
For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when PUSCH and PRACH are processed in the different endpoints.
In case there are specific endpoints that support non-time-managed traffic only
- the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic.";
}
leaf number-of-ru-ports-ul {
type uint8;
description
"Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration)
- the number of O-RU ports for uplink is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports.
For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when PUSCH and PRACH are processed in the different endpoints.
In case there are specific endpoints that support non-time-managed traffic only
- the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic.";
}
leaf number-of-ru-ports-dl {
type uint8;
description
"Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration)
- the number of O-RU ports for downlink is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports.
For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when SSB and non-SSB are processed in the different endpoints.
In case there are specific endpoints that support non-time-managed traffic only
- the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic.";
}
leaf number-of-spatial-streams {
type uint8;
description
"This value indicates the number of spatial streams supported at O-RU for DL and UL.
For DL, it is same as the number of antenna ports specified in 3GPP TS38.214, Section 5.2 and 3GPP TS36.213, Section 5.2.";
}
leaf max-power-per-pa-antenna {
type decimal64{
fraction-digits 4;
}
description
"This value indicates Maximum Power per PA per antenna. Value unit is dBm.";
}
leaf min-power-per-pa-antenna {
type decimal64{
fraction-digits 4;
}
description
"This value indicates Minimum Power per PA per antenna. Value unit is dBm.";
}
leaf fronthaul-split-option {
type uint8 {
range "7";
}
description
"This value indicates the Fronthaul Split Option, i.e., 2 or 7 in this release.";
}
container format-of-iq-sample {
description
"Indicates module capabilities about IQ samples";
uses format-of-iq-sample;
}
list ul-mixed-num-required-guard-rbs {
key "scs-a scs-b";
description
"List of required number of guard resource blocks
for the combination of subcarrier spacing values for downlink";
uses ul-mixed-num-required-guard-rbs;
}
list dl-mixed-num-required-guard-rbs {
key "scs-a scs-b";
description
"List of required number of guard resource blocks
for the combination of subcarrier spacing values for uplink";
uses dl-mixed-num-required-guard-rbs;
}
leaf energy-saving-by-transmission-blanks {
type boolean;
mandatory true;
description
"Parameter informs if unit supports energy saving by transmission blanking";
}
container eaxcid-grouping-capabilities {
if-feature o-ran-module-cap:EAXC-ID-GROUP-SUPPORTED;
description
"a container with parameters for eaxcid grouping";
leaf max-num-tx-eaxc-id-groups {
type uint8;
description
"Maximum number of configurable tx-eaxc-id-group supported by O-RU.";
}
leaf max-num-tx-eaxc-ids-per-group {
type uint8;
description
"Maximum number of member-tx-eaxc-id in single tx-eaxc-id-group supported by O-RU.";
}
leaf max-num-rx-eaxc-id-groups {
type uint8;
description
"the maximum number of groups with the eAxC IDs those are assigned to low-level-rx-links.";
}
leaf max-num-rx-eaxc-ids-per-group {
type uint8;
description
"the maximum number of eAxC IDs per rx-eaxc-id-group.";
}
}
leaf dynamic-transport-delay-management-supported {
type boolean;
mandatory true;
description
"Parameter informs if unit supports dynamic transport delay management through eCPRI Msg 5";
}
leaf support-only-unique-ecpri-seqid-per-eaxc {
type boolean;
default false;
description
"Parameter informs if O-RU expects unique ecpri sequence id for eAxC_IDs serving
for UL and DL for the same carrier component.
Note: If this is set to TRUE, the O-DU can decide to either use different eAxC_IDs for UL and
DL or can generate unique sequence ID per eAxC_ID.
TAKE NOTE: This leaf is backwards compatible from an O-RU persepctive BUT an O-RU that
sets this leaf to TRUE may result in incompatibilities when operating with an O-DU
designed according to the O-RAN CUS-Plane Specification v02.00, e.g., if the O-DU is
incapable of using different eAxC values between UL and DL";
}
container coupling-methods {
description
"O-RU's capabilities related to supported C-Plane and U-Plane coupling methods";
leaf coupling-via-frequency-and-time {
type boolean;
description
"Coupling via frequency and time; see methods of coupling of C-plane and U-plane in CUS-Plane specification";
}
leaf coupling-via-frequency-and-time-with-priorities {
type boolean;
description
"Coupling via Frequency and time with priorities; see methods of coupling of C-plane and U-plane in CUS-Plane specification.
Note: If coupling-via-frequency-and-time-with-priorities is 'true' then coupling-via-frequency-and-time shall also be 'true'.";
}
}
leaf ud-comp-len-supported {
type boolean;
description
"This property informs if O-RU supports optional field udCompLen in U-Plane messages.
Only in case this leaf is present and its value is TRUE, O-RU supports U-Plane messages
containing udCompLen field in section header.";
}
}
grouping sub-band-info {
description "container for collection of leafs for LAA subband 46";
list sub-band-frequency-ranges {
key sub-band;
description "frequency information on a per sub-band basis";
leaf sub-band {
type sub-band-string;
description "Sub band when band 46";
}
uses sub-band-max-min-ul-dl-frequency;
}
leaf number-of-laa-scarriers {
type uint8;
description
"This value indicates the number of LAA secondary carriers supported at O-RU.";
}
leaf maximum-laa-buffer-size {
type uint16;
description
"Maximum O-RU buffer size in Kilobytes (KB) per CC. This parameter is
needed at the O-DU to know how much data can be sent in advance
and stored at the O-RU to address the LBT uncertainity.";
}
leaf maximum-processing-time {
type uint16;
units microseconds;
description
"Maximum O-RU Processing time in microseconds at the O-RU to handle the
received/transmitted packets from/to the O-DU. This parameter is
needed at the O-DU to determine the time where it needs to send
the data to the O-RU.";
}
leaf self-configure {
type boolean;
description "This value indicates that the O-RU can manage the contention window locally. ";
}
}
grouping support-for-dl {
description
"Grouping for DL specific parameters";
leaf max-supported-frequency-dl {
type uint64;
description
"This value indicates Maximum supported downlink frequency. Value unit is Hz.";
}
leaf min-supported-frequency-dl {
type uint64;
description
"This value indicates Minimum supported downlink frequency. Value unit is Hz.";
}
leaf max-supported-bandwidth-dl {
type uint64;
description
"This value indicates Maximum total downlink bandwidth in module. Value unit is Hz.";
}
leaf max-num-carriers-dl {
type uint32;
description
"This value indicates Maximum number of downlink carriers in module.";
}
leaf max-carrier-bandwidth-dl {
type uint64;
description
"This value indicates Maximum bandwidth per downlink carrier. Value unit is Hz.";
}
leaf min-carrier-bandwidth-dl {
type uint64;
description
"This value indicates Minimum bandwidth per downlink carrier. Value unit is Hz.";
}
leaf-list supported-technology-dl {
type enumeration{
enum LTE {
description "LTE is supported in DL path.";
}
enum NR {
description "NR is supported in DL path.";
}
enum DSS_LTE_NR {
if-feature DSS_LTE_NR;
description
"DSS is supported in the DL, which implicitly means LTE and NR are also
BOTH supported in the DL.";
}
}
min-elements 1;
description
"This list provides information regarding technologies supported in DL path";
}
}
grouping support-for-ul {
description
"Grouping for UL specific parameters";
leaf max-supported-frequency-ul {
type uint64;
description
"This value indicates Maximum supported uplink frequency. Value unit is Hz.";
}
leaf min-supported-frequency-ul {
type uint64;
description
"This value indicates Minimum supported uplink frequency. Value unit is Hz.";
}
leaf max-supported-bandwidth-ul {
type uint64;
description
"This value indicates Maximum total uplink bandwidth in module. Value unit is Hz.";
}
leaf max-num-carriers-ul {
type uint32;
description
"This value indicates Maximum number of uplink carriers in module.";
}
leaf max-carrier-bandwidth-ul {
type uint64;
description
"This value indicates Maximum bandwidth per uplink carrier. Value unit is Hz.";
}
leaf min-carrier-bandwidth-ul {
type uint64;
description
"This value indicates Minimum bandwidth per uplink carrier. Value unit is Hz.";
}
leaf-list supported-technology-ul {
type enumeration{
enum LTE {
description "LTE is supported in UL path.";
}
enum NR {
description "NR is supported in UL path.";
}
enum DSS_LTE_NR {
if-feature DSS_LTE_NR;
description
"DSS is supported in the UL, which implicitly means LTE and NR are also
BOTH supported in the UL.";
}
}
min-elements 1;
description
"This list provides information regarding technologies supported in UL path";
}
}
grouping band-capabilities {
description
"Capabilities that are needed to be defined per each band";
leaf band-number {
type uint16;
description
"Band number";
}
container sub-band-info {
when "../band-number = '46'";
if-feature "o-ran-module-cap:LAA";
description "container for collection of leafs for LAA subband 46";
uses sub-band-info;
}
uses support-for-dl;
uses support-for-ul;
leaf max-num-component-carriers {
type uint8;
description "maximum number of component carriers supported by the O-RU";
}
leaf max-num-bands {
type uint16;
description "maximum number of bands supported by the O-RU";
}
leaf max-num-sectors {
type uint8;
description "maximum number of sectors supported by the O-RU";
}
leaf max-power-per-antenna {
type decimal64{
fraction-digits 4;
}
description
"This value indicates Maximum Power per band per antenna. Value unit is dBm.";
}
leaf min-power-per-antenna {
type decimal64{
fraction-digits 4;
}
description
"This value indicates Minimum Power per band per antenna. Value unit is dBm.";
}
leaf codebook-configuration_ng {
type uint8;
description
"This parameter informs the precoder codebook_ng that are used for precoding";
}
leaf codebook-configuration_n1 {
type uint8;
description
"This parameter informs the precoder codebook_n1 that are used for precoding";
}
leaf codebook-configuration_n2 {
type uint8;
description
"This parameter informs the precoder codebook_n2 that are used for precoding";
}
}
container module-capability {
description
"module capability object responsible for providing module capability.";
container ru-capabilities {
config false;
description
"Structure representing set of capabilities.";
uses ru-capabilities;
}
list band-capabilities {
key band-number;
config false;
description
"Capabilities that are needed to be defined per each band";
uses band-capabilities;
}
container rw-sub-band-info {
if-feature "o-ran-module-cap:LAA";
description "config true leafrefs for use as constraints for config true leafs";
leaf rw-number-of-laa-scarriers {
type leafref {
path "/module-capability/band-capabilities/sub-band-info/number-of-laa-scarriers";
require-instance false;
}
description
"This value indicates the number of LAA secondary carriers supported at O-RU.";
}
leaf rw-self-configure {
type leafref {
path "/module-capability/band-capabilities/sub-band-info/self-configure";
require-instance false;
}
description
"This value indicates that the O-RU can manage the contention window locally.";
}
}
}
}
@@ -0,0 +1,362 @@
module o-ran-processing-element {
yang-version 1.1;
namespace "urn:o-ran:processing-element:1.0";
prefix "o-ran-elements";
import ietf-yang-types {
prefix yang;
}
import ietf-inet-types {
prefix "inet";
}
import ietf-interfaces {
prefix "if";
}
import ietf-ip {
prefix "ip";
}
import o-ran-interfaces {
prefix "o-ran-int";
}
organization "O-RAN Alliance";
contact
"www.o-ran.org";
description
"This module defines the YANG definitions for mapping of transport flows to
processing elements. Three options are supported:
i) virtual MAC based mapping
ii) MAC addrress + VLAN-ID based mapping
iii) UDP/IP based mapping
Copyright 2020 the O-RAN Alliance.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the above disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the above disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the Members of the O-RAN Alliance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.";
revision "2020-04-17" {
description
"version 3.0.0
1) added new enum SHARED-CELL-ETH-INTERFACE in
transport-session-type and new containers north-eth-flow and
south-eth-flow to enable Shared cell scenario.";
reference "ORAN-WG4.M.0-v03.00";
}
revision "2019-07-03" {
description
"version 1.1.0
1) added new leaf to enable O-RU to report the maximum number of
transport flows it can support, e.g., due to restrictions on number
of VLAN-IDs when ethernet type transport is used.";
reference "ORAN-WG4.M.0-v01.00";
}
revision "2019-02-04" {
description
"version 1.0.0
1) imported model from xRAN
2) changed namespace and reference from xran to o-ran";
reference "ORAN-WG4.M.0-v01.00";
}
feature SHARED_CELL {
description
"Presence of feature indicates that this O-RU is capable to support
shared cell.";
}
// groupings
grouping pe-group {
leaf maximum-number-of-transport-flows {
type uint16 {
range "1..4094";
}
config false;
default 4094;
description
"The maximum number of transport flows that can be supported by an O-RU";
}
leaf transport-session-type {
type enumeration {
enum ETH-INTERFACE {
description "VLAN based CUS Transport ";
}
enum UDPIP-INTERFACE {
description "UDP/IP based CUS Transport ";
}
enum ALIASMAC-INTERFACE{
description "Alias MAC address based CUS Transport ";
}
enum SHARED-CELL-ETH-INTERFACE {
if-feature "SHARED_CELL";
description "VLAN based CUS Transport used for Shared Cell scenario";
}
}
default ETH-INTERFACE;
description
"the type of transport session used for identifying different processing
elements";
}
container enhanced-uplane-mapping {
presence "indicates that enhanced uplane mapping is used";
description "a mapping table for enhanced user plane marking";
list uplane-mapping {
key "up-marking-name";
description
"a mapping between up-link name and o-ran-interfaces:up-marking-name";
leaf up-marking-name {
type string;
description "a unique up marking name that is used for enhanced up marking";
}
choice up-markings {
description
"U-Plane markings";
case ethernet {
when "(../../transport-session-type = 'ALIASMAC-INTERFACE') or
(../../transport-session-type = 'ETH-INTERFACE') or
(../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE')";
leaf up-cos-name {
type leafref {
path "/if:interfaces/if:interface/o-ran-int:class-of-service/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name";
}
description "the Ethernet U-plane transport marking as defined in o-ran-interfaces";
}
}
case ipv4 {
when "(../../transport-session-type = 'UDPIP-INTERFACE')";
leaf upv4-dscp-name {
if-feature o-ran-int:UDPIP-BASED-CU-PLANE;
type leafref {
path "/if:interfaces/if:interface/ip:ipv4/o-ran-int:diffserv-markings/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name";
}
description "the IPv4 U-plane transport marking as defined in o-ran-interfaces";
}
}
case ipv6 {
when "(../../transport-session-type = 'UDPIP-INTERFACE')";
leaf upv6-dscp-name {
if-feature o-ran-int:UDPIP-BASED-CU-PLANE;
type leafref {
path "/if:interfaces/if:interface/ip:ipv6/o-ran-int:diffserv-markings/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name";
}
description "the IPv6 U-plane transport marking as defined in o-ran-interfaces";
}
}
}
}
}
list ru-elements {
key "name";
description
"the list of transport definitions for each processing element";
leaf name {
type string {
length "1..255";
}
description
"A name that is unique across the O-RU that identifies a processing
element instance.
This name may be used in fault management to refer to a fault source
or affected object";
}
container transport-flow {
description
"container for the transport-flow used for CU plane";
leaf interface-name {
type leafref {
path "/if:interfaces/if:interface/if:name";
}
description "the interface name ";
}
container aliasmac-flow {
when "../../../transport-session-type = 'ALIASMAC-INTERFACE'";
if-feature o-ran-int:ALIASMAC-BASED-CU-PLANE;
description "leafs for virtual mac type data flows";
leaf ru-aliasmac-address {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:alias-macs";
}
mandatory true;
description
"O-RU's alias MAC address used for alias MAC based flow";
}
leaf vlan-id {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
}
description
"O-RU's VLAN-ID used for alias MAC based flow";
}
leaf o-du-mac-address {
type yang:mac-address;
mandatory true;
description
"O-DU's MAC address used for alias MAC based flow";
}
}
container eth-flow {
when "../../../transport-session-type = 'ETH-INTERFACE'";
description "leafs for mac + vlan-id type data flows";
leaf ru-mac-address {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address";
}
mandatory true;
description
"O-RU's MAC address used for Ethernet based flow";
}
leaf vlan-id {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
}
mandatory true;
description
"O-RU's VLAN-ID used for Ethernet based flow";
}
leaf o-du-mac-address {
type yang:mac-address;
mandatory true;
description
"O-DU's MAC address used for Ethernet based flow";
}
}
container udpip-flow {
when "../../../transport-session-type = 'UDPIP-INTERFACE'";
description "leafs for UDP/IP type data flows";
choice address {
leaf ru-ipv4-address {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/ip:ipv4/ip:address/ip:ip";
}
description "O-RU's IPv4 address";
}
leaf ru-ipv6-address {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/ip:ipv6/ip:address/ip:ip";
}
description "O-RU's IPv6 address";
}
mandatory true;
description "choice of O-RU IPv4 or IPv6 address";
}
leaf o-du-ip-address {
type inet:ip-address;
mandatory true;
description "O-DU's IPv address";
}
leaf ru-ephemeral-udp-port {
type inet:port-number;
mandatory true;
description
"ephemeral port used by O-RU";
}
leaf o-du-ephemeral-udp-port {
type inet:port-number;
mandatory true;
description
"ephemeral port used by O-DU";
}
leaf ecpri-destination-udp {
type inet:port-number;
mandatory true;
description "the well known UDP port number used by eCPRI";
// fixme - add in a default when allocated by IANA
}
}
container north-eth-flow {
when "../../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE'";
if-feature "SHARED_CELL";
description "leafs for mac + vlan-id type data flows";
leaf ru-mac-address {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address";
}
description
"O-RU's MAC address used for Ethernet based flow";
}
leaf vlan-id {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
}
description
"O-RU's VLAN-ID used for Ethernet based flow";
}
leaf north-node-mac-address {
type yang:mac-address;
description
"North-node's MAC address used for Ethernet based flow";
}
}
container south-eth-flow {
when "../../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE'";
if-feature "SHARED_CELL";
description "leafs for mac + vlan-id type data flows";
leaf ru-mac-address {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address";
}
description
"O-RU's MAC address used for Ethernet based flow";
}
leaf vlan-id {
type leafref {
path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id";
}
description
"O-RU's VLAN-ID used for Ethernet based flow";
}
leaf south-node-mac-address {
type yang:mac-address;
description
"south-node's MAC address used for Ethernet based flow";
}
}
}
}
}
// top level container
container processing-elements {
description
"a model defining the mapping between transport flows and arbitrary
O-RAN processing elements. A processing element may be then defined for
handling connectivity or delay procedures, or defined with a corresponding
eaxcid for CU plane operations";
uses pe-group;
}
}
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -90,7 +90,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
rx_sym = callback_tag->symbol & 0xFF; rx_sym = callback_tag->symbol & 0xFF;
uint32_t ru_id = callback_tag->oXuId; uint32_t ru_id = callback_tag->oXuId;
LOG_D(NR_PHY, LOG_D(HW,
"rx_callback frame %d, subframe %d, slot %d, second %lld, rx_sym %d ru_id %d\n", "rx_callback frame %d, subframe %d, slot %d, second %lld, rx_sym %d ru_id %d\n",
frame, frame,
subframe, subframe,
@@ -127,7 +127,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
rx_RU[ru_id][slot2] = 1; rx_RU[ru_id][slot2] = 1;
if (last_frame > 0 && frame > 0 if (last_frame > 0 && frame > 0
&& ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023))))
LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); LOG_E(HW, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2);
for (int i = 0; i < num_ports; i++) { for (int i = 0; i < num_ports; i++) {
if (rx_RU[i][slot2] == 0) if (rx_RU[i][slot2] == 0)
return; return;
@@ -142,16 +142,16 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
info->tti = tti; info->tti = tti;
info->sl = slot2; info->sl = slot2;
info->f = frame; info->f = frame;
LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
pushNotifiedFIFO(&oran_sync_fifo, req); pushNotifiedFIFO(&oran_sync_fifo, req);
#else #else
LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); LOG_D(HW, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
oran_sync_info.tti = tti; oran_sync_info.tti = tti;
oran_sync_info.sl = slot2; oran_sync_info.sl = slot2;
oran_sync_info.f = frame; oran_sync_info.f = frame;
#endif #endif
} else } else
LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); LOG_E(HW, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
last_slot = slot2; last_slot = slot2;
last_frame = frame; last_frame = frame;
} // rx_sym == 7 } // rx_sym == 7
@@ -289,7 +289,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
while ((f = pollNotifiedFIFO(&oran_sync_fifo)) != NULL) { while ((f = pollNotifiedFIFO(&oran_sync_fifo)) != NULL) {
oran_sync_info_t *old_info = NotifiedFifoData(res); oran_sync_info_t *old_info = NotifiedFifoData(res);
oran_sync_info_t *new_info = NotifiedFifoData(f); oran_sync_info_t *new_info = NotifiedFifoData(f);
LOG_E(PHY, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl); LOG_E(HW, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl);
delNotifiedFIFO_elt(res); delNotifiedFIFO_elt(res);
res = f; res = f;
} }
@@ -305,14 +305,14 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
uint32_t tti_in = oran_sync_info.tti; uint32_t tti_in = oran_sync_info.tti;
static int last_slot = -1; static int last_slot = -1;
LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot); LOG_D(HW, "oran slot %d, last_slot %d\n", *slot, last_slot);
int cnt = 0; int cnt = 0;
// while (*slot == last_slot) { // while (*slot == last_slot) {
while (tti_in == oran_sync_info.tti) { while (tti_in == oran_sync_info.tti) {
//*slot = oran_sync_info.sl; //*slot = oran_sync_info.sl;
cnt++; cnt++;
} }
LOG_D(PHY, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); LOG_D(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot);
last_slot = *slot; last_slot = *slot;
#endif #endif
// return(0); // return(0);
@@ -380,9 +380,9 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
int16_t payload_len = 0; int16_t payload_len = 0;
LOG_D(PHY, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm); LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
LOG_D(PHY, LOG_D(HW,
"prbMap[%d] : PRBstart %d nPRBs %d\n", "prbMap[%d] : PRBstart %d nPRBs %d\n",
idxElm, idxElm,
pRbMap->prbMap[idxElm].nRBStart, pRbMap->prbMap[idxElm].nRBStart,
@@ -436,7 +436,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
} // vv_inf } // vv_inf
if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) { if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) {
for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
LOG_I(NR_PHY, LOG_I(HW,
"[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n", "[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n",
"o-du ", "o-du ",
o_xu_id, o_xu_id,
@@ -448,7 +448,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L, x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L,
x_counters[o_xu_id].Total_msgs_rcvd); x_counters[o_xu_id].Total_msgs_rcvd);
for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++) for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++)
LOG_I(NR_PHY, LOG_I(HW,
"[%s%d][pusch%d %7ld prach%d %7ld]\n", "[%s%d][pusch%d %7ld prach%d %7ld]\n",
"o_du", "o_du",
o_xu_id, o_xu_id,
+110 -26
View File
@@ -32,6 +32,10 @@
#include "stdio.h" #include "stdio.h"
#include "string.h" #include "string.h"
#ifdef OAI_MPLANE
#include "mplane/ru-mplane-api.h"
#endif
static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn) static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn)
{ {
printf("\ printf("\
@@ -522,6 +526,38 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
return true; return true;
} }
#ifdef OAI_MPLANE
static bool set_fh_eaxcid_conf_mplane(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat, const ru_session_list_t *ru_session_list)
{
xran_mplane_t *xran_mplane = &ru_session_list->ru_session[0].xran_mplane;
switch (cat) {
case XRAN_CATEGORY_A:
eaxcid_conf->mask_cuPortId = xran_mplane->du_port_bitmask;
eaxcid_conf->mask_bandSectorId = xran_mplane->band_sector_bitmask;
eaxcid_conf->mask_ccId = xran_mplane->ccid_bitmask;
eaxcid_conf->mask_ruPortId = xran_mplane->ru_port_bitmask;
eaxcid_conf->bit_cuPortId = xran_mplane->du_port;
eaxcid_conf->bit_bandSectorId = xran_mplane->band_sector; // total number of band sectors supported by O-RU should be retrieved by M-plane - <max-num-bands> && <max-num-sectors>
eaxcid_conf->bit_ccId = xran_mplane->ccid; // total number of CC supported by O-RU should be retrieved by M-plane - <max-num-component-carriers>
eaxcid_conf->bit_ruPortId = xran_mplane->ru_port;
break;
case XRAN_CATEGORY_B:
eaxcid_conf->mask_cuPortId = 0xf000;
eaxcid_conf->mask_bandSectorId = 0x0c00;
eaxcid_conf->mask_ccId = 0x0300;
eaxcid_conf->mask_ruPortId = 0x000f;
eaxcid_conf->bit_cuPortId = 12;
eaxcid_conf->bit_bandSectorId = 10;
eaxcid_conf->bit_ccId = 8;
eaxcid_conf->bit_ruPortId = 0;
break;
default:
return false;
}
return true;
}
#else
static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat) static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat)
{ {
/* CUS specification, section 3.1.3.1.6 /* CUS specification, section 3.1.3.1.6
@@ -540,8 +576,8 @@ static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran
eaxcid_conf->mask_ccId = 0x00f0; eaxcid_conf->mask_ccId = 0x00f0;
eaxcid_conf->mask_ruPortId = 0x000f; eaxcid_conf->mask_ruPortId = 0x000f;
eaxcid_conf->bit_cuPortId = 0; eaxcid_conf->bit_cuPortId = 0;
eaxcid_conf->bit_bandSectorId = 0; // total number of band sectors supported by O-RU should be retreived by M-plane - <max-num-bands> && <max-num-sectors> eaxcid_conf->bit_bandSectorId = 0; // total number of band sectors supported by O-RU should be retrieved by M-plane - <max-num-bands> && <max-num-sectors>
eaxcid_conf->bit_ccId = 0; // total number of CC supported by O-RU should be retreived by M-plane - <max-num-component-carriers> eaxcid_conf->bit_ccId = 0; // total number of CC supported by O-RU should be retrieved by M-plane - <max-num-component-carriers>
eaxcid_conf->bit_ruPortId = 0; eaxcid_conf->bit_ruPortId = 0;
break; break;
case XRAN_CATEGORY_B: case XRAN_CATEGORY_B:
@@ -560,6 +596,7 @@ static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran
return true; return true;
} }
#endif
uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr) uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr)
{ {
@@ -573,7 +610,7 @@ uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr)
return NULL; return NULL;
} }
static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_cat) static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xran_category xran_cat)
{ {
memset(fh_init, 0, sizeof(*fh_init)); memset(fh_init, 0, sizeof(*fh_init));
@@ -606,30 +643,46 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca
const int nfh = sizeofArray(FHconfigs); const int nfh = sizeofArray(FHconfigs);
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix); config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs #ifdef OAI_MPLANE
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
int num_rus = ru_session_list->num_rus;
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
return false;
if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf, xran_cat, ru_session_list))
return false;
/* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
fh_init->mtu = ru_session_list->ru_session[0].xran_mplane.mtu; // we suppose that each RU supports the same MTU size
int num_ru_addr = (fh_init->io_cfg.one_vf_cu_plane) ? num_rus : 2*num_rus;
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
for (int i = 0; i < num_rus; i++) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
for (int j = 0; j < num_ru_addr/num_rus; j++) {
if (get_ether_addr(ru_session_list->ru_session[i].xran_mplane.ru_mac_addr, &ea[i+j]) == NULL) {
printf("could not read ethernet address '%s' for RU!\n", ru_session_list->ru_session[i].xran_mplane.ru_mac_addr);
return false;
}
}
}
#else
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
return false; return false;
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat)) if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat))
return false; return false;
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
fh_init->dpdkBasebandFecMode = 0; // DPDK Baseband FEC device mode (0-SW, 1-HW); not used in xran
fh_init->dpdkBasebandDevice = NULL; // DPDK Baseband device address; not used in xran
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
it is necessary */
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
/* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be /* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame); communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */ xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr; fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt; int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr)); fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n"); AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
for (int i = 0; i < num_ru_addr; ++i) { for (int i = 0; i < num_ru_addr; ++i) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr; struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) { if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) {
@@ -637,7 +690,14 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca
return false; return false;
} }
} }
#endif
fh_init->dpdkBasebandFecMode = 0; // DPDK Baseband FEC device mode (0-SW, 1-HW); not used in xran
fh_init->dpdkBasebandDevice = NULL; // DPDK Baseband device address; not used in xran
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
it is necessary */
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec
#ifdef F_RELEASE #ifdef F_RELEASE
@@ -656,7 +716,8 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca
// this is a hack // this is a hack
int g_kbar; int g_kbar;
static bool set_fh_prach_config(const openair0_config_t *oai0, static bool set_fh_prach_config(void *mplane_api,
const openair0_config_t *oai0,
const uint32_t max_num_ant, const uint32_t max_num_ant,
const paramdef_t *prachp, const paramdef_t *prachp,
int nprach, int nprach,
@@ -692,8 +753,13 @@ static bool set_fh_prach_config(const openair0_config_t *oai0,
xran assumes PRACH offset >= max(Ntx, Nrx). However, we made a workaround that xran supports PRACH eAxC IDs same as PUSCH eAxC IDs. xran assumes PRACH offset >= max(Ntx, Nrx). However, we made a workaround that xran supports PRACH eAxC IDs same as PUSCH eAxC IDs.
This is achieved with is_prach and filter_id parameters in the patch. This is achieved with is_prach and filter_id parameters in the patch.
Please note that this approach only applies to the RUs that support this functionality, e.g. LITEON RU. */ Please note that this approach only applies to the RUs that support this functionality, e.g. LITEON RU. */
#ifdef OAI_MPLANE
xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api;
prach_config->eAxC_offset = xran_mplane->prach_offset;
#else
uint8_t offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr; uint8_t offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr;
prach_config->eAxC_offset = (offset != 0) ? offset : max_num_ant; prach_config->eAxC_offset = (offset != 0) ? offset : max_num_ant;
#endif
g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr; g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr;
@@ -722,17 +788,24 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame
return true; return true;
} }
static bool set_fh_ru_config(const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config) static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config)
{ {
ru_config->xranTech = XRAN_RAN_5GNR; // 5GNR or LTE ru_config->xranTech = XRAN_RAN_5GNR; // 5GNR or LTE
ru_config->xranCat = xran_cat; // mode: Catergory A or Category B ru_config->xranCat = xran_cat; // mode: Catergory A or Category B
ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC; // dynamic or static udCompHdr handling ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC; // dynamic or static udCompHdr handling
#ifdef OAI_MPLANE
xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api;
ru_config->iqWidth = xran_mplane->iq_width;
ru_config->iqWidth_PRACH = xran_mplane->iq_width;
#else
ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr; // IQ bit width ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr; // IQ bit width
AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n"); AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n");
ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method
ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr; // IQ bit width for PRACH ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr; // IQ bit width for PRACH
AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n"); AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n");
#endif
ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method
ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method for PRACH ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method for PRACH
AssertFatal(fftSize > 0, "FFT size cannot be 0\n"); AssertFatal(fftSize > 0, "FFT size cannot be 0\n");
ru_config->fftSize = fftSize; // FFT Size ru_config->fftSize = fftSize; // FFT Size
ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; // order of bytes in int16_t in buffer; big or little endian ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; // order of bytes in int16_t in buffer; big or little endian
@@ -757,7 +830,7 @@ static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint1
return true; return true;
} }
static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config) static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
{ {
AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n"); AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n");
AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus); AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus);
@@ -839,22 +912,22 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat,
#endif #endif
fh_config->puschMaskEnable = 0; // enable PUSCH mask; only used if id = O_RU fh_config->puschMaskEnable = 0; // enable PUSCH mask; only used if id = O_RU
fh_config->puschMaskSlot = 0; // specific which slot PUSCH channel masked; only used if id = O_RU fh_config->puschMaskSlot = 0; // specific which slot PUSCH channel masked; only used if id = O_RU
fh_config->cp_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_CP_VLAN_TAG)->uptr; // C-plane VLAN tag; not used in xran; needed for M-plane fh_config->cp_vlan_tag = 0; // C-plane VLAN tag; not used in xran; needed for M-plane
fh_config->up_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_UP_VLAN_TAG)->uptr; // U-plane VLAN tag; not used in xran; needed for M-plane fh_config->up_vlan_tag = 0; // U-plane VLAN tag; not used in xran; needed for M-plane
fh_config->debugStop = 0; // enable auto stop; only used if id = O_RU fh_config->debugStop = 0; // enable auto stop; only used if id = O_RU
fh_config->debugStopCount = 0; // enable auto stop after number of Tx packets; not used in xran fh_config->debugStopCount = 0; // enable auto stop after number of Tx packets; not used in xran
fh_config->DynamicSectionEna = 0; // enable dynamic C-Plane section allocation fh_config->DynamicSectionEna = 0; // enable dynamic C-Plane section allocation
fh_config->GPS_Alpha = 0; // refers to alpha as defined in section 9.7.2 of ORAN spec. this value should be alpha*(1/1.2288ns), range 0 - 1e7 (ns); offset_nsec = (pConf->GPS_Beta - offset_sec * 100) * 1e7 + pConf->GPS_Alpha fh_config->GPS_Alpha = 0; // refers to alpha as defined in section 9.7.2 of ORAN spec. this value should be alpha*(1/1.2288ns), range 0 - 1e7 (ns); offset_nsec = (pConf->GPS_Beta - offset_sec * 100) * 1e7 + pConf->GPS_Alpha
fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100 fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100
if (!set_fh_prach_config(oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf)) if (!set_fh_prach_config(mplane_api, oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf))
return false; return false;
/* SRS only used if XRAN_CATEGORY_B /* SRS only used if XRAN_CATEGORY_B
Note: srs_config->eAxC_offset >= prach_config->eAxC_offset + PRACH */ Note: srs_config->eAxC_offset >= prach_config->eAxC_offset + PRACH */
// fh_config->srs_conf = {0}; // fh_config->srs_conf = {0};
if (!set_fh_frame_config(oai0, &fh_config->frame_conf)) if (!set_fh_frame_config(oai0, &fh_config->frame_conf))
return false; return false;
if (!set_fh_ru_config(rup, oai0->split7.fftSize, nru, xran_cat, &fh_config->ru_conf)) if (!set_fh_ru_config(mplane_api, rup, oai0->split7.fftSize, nru, xran_cat, &fh_config->ru_conf))
return false; return false;
fh_config->bbdev_enc = NULL; // call back to poll BBDev encoder fh_config->bbdev_enc = NULL; // call back to poll BBDev encoder
@@ -889,24 +962,35 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat,
return true; return true;
} }
bool get_xran_config(const openair0_config_t *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config) bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config)
{ {
/* This xran integration release is only valid for O-RU CAT A. /* This xran integration release is only valid for O-RU CAT A.
Therefore, each FH parameter is hardcoded to CAT A. Therefore, each FH parameter is hardcoded to CAT A.
If you are interested in CAT B, please be aware that parameters of fh_init and fh_config structs must be modified accordingly. */ If you are interested in CAT B, please be aware that parameters of fh_init and fh_config structs must be modified accordingly. */
enum xran_category xran_cat = XRAN_CATEGORY_A; enum xran_category xran_cat = XRAN_CATEGORY_A;
if (!set_fh_init(fh_init, xran_cat)) { if (!set_fh_init(mplane_api, fh_init, xran_cat)) {
printf("could not read FHI 7.2/ORAN config\n"); printf("could not read FHI 7.2/ORAN config\n");
return false; return false;
} }
#ifdef OAI_MPLANE
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
if (!set_fh_config(o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) { xran_mplane_t *xran_mplane = &ru_session_list->ru_session[o_xu_id].xran_mplane;
if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
MP_LOG_I("could not read FHI 7.2/RU-specific config\n");
return false;
}
}
#else
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
printf("could not read FHI 7.2/RU-specific config\n"); printf("could not read FHI 7.2/RU-specific config\n");
return false; return false;
} }
} }
#endif
return true; return true;
} }
+1 -1
View File
@@ -29,7 +29,7 @@ struct xran_fh_init;
struct xran_fh_config; struct xran_fh_config;
struct openair0_config; struct openair0_config;
bool get_xran_config(const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config); bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config);
void print_fh_init(const struct xran_fh_init *fh_init); void print_fh_init(const struct xran_fh_init *fh_init);
void print_fh_config(const struct xran_fh_config *fh_config); void print_fh_config(const struct xran_fh_config *fh_config);
+1 -1
View File
@@ -443,7 +443,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
pi->prach_tag = tag; pi->prach_tag = tag;
pi->pusch_tag = tag; pi->pusch_tag = tag;
#ifdef E_RELEASE #ifdef E_RELEASE
LOG_W(PHY, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n"); LOG_W(HW, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n");
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]); oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
#elif defined F_RELEASE #elif defined F_RELEASE
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]); oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
+17 -9
View File
@@ -31,8 +31,12 @@
#define ORAN_CONFIG_SYSTEM_CORE "system_core" #define ORAN_CONFIG_SYSTEM_CORE "system_core"
#define ORAN_CONFIG_IO_CORE "io_core" #define ORAN_CONFIG_IO_CORE "io_core"
#define ORAN_CONFIG_WORKER_CORES "worker_cores" #define ORAN_CONFIG_WORKER_CORES "worker_cores"
#define ORAN_CONFIG_RU_ADDR "ru_addr" #define ORAN_CONFIG_DU_KEYPAIR "du_key_pair" // only needed for M-plane
#define ORAN_CONFIG_MTU "mtu" #define ORAN_CONFIG_DU_ADDR "du_addr" // only needed for M-plane
#define ORAN_CONFIG_VLAN_TAG "vlan_tag" // only needed for M-plane
#define ORAN_CONFIG_RU_ADDR "ru_addr" // not needed if M-plane used
#define ORAN_CONFIG_RU_IP_ADDR "ru_ip_addr" // only needed for M-plane
#define ORAN_CONFIG_MTU "mtu" // not needed if M-plane used
#define ORAN_CONFIG_FILE_PREFIX "file_prefix" #define ORAN_CONFIG_FILE_PREFIX "file_prefix"
#define ORAN_CONFIG_NETHPERPORT "eth_lines" #define ORAN_CONFIG_NETHPERPORT "eth_lines"
#define ORAN_CONFIG_NETHSPEED "eth_speed" #define ORAN_CONFIG_NETHSPEED "eth_speed"
@@ -48,7 +52,11 @@
{ORAN_CONFIG_SYSTEM_CORE, "DPDK control threads core\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {ORAN_CONFIG_SYSTEM_CORE, "DPDK control threads core\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \ {ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \
{ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \ {ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \
{ORAN_CONFIG_DU_KEYPAIR, "DU keypair for RU authentication\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_VLAN_TAG, "VLAN tag\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ {ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_RU_IP_ADDR, "IP addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \ {ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \
{ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \ {ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \
{ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \ {ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \
@@ -70,6 +78,10 @@
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \ { .s3a = { config_checkstr_assign_integer, \
{"PA", "VA"}, {0, 1}, 2} }, \ {"PA", "VA"}, {0, 1}, 2} }, \
{ .s5 = { NULL } }, \ { .s5 = { NULL } }, \
@@ -84,8 +96,6 @@
#define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul" #define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul"
#define ORAN_FH_CONFIG_T1A_UP "T1a_up" #define ORAN_FH_CONFIG_T1A_UP "T1a_up"
#define ORAN_FH_CONFIG_TA4 "Ta4" #define ORAN_FH_CONFIG_TA4 "Ta4"
#define ORAN_FH_CONFIG_CP_VLAN_TAG "cp_vlan_tag"
#define ORAN_FH_CONFIG_UP_VLAN_TAG "up_vlan_tag"
#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n" #define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n"
@@ -95,15 +105,13 @@
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ {ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ {ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ {ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_CP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{ORAN_FH_CONFIG_UP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
} }
// clang-format on // clang-format on
#define CONFIG_STRING_ORAN_RU "ru_config" #define CONFIG_STRING_ORAN_RU "ru_config"
#define ORAN_RU_CONFIG_IQWIDTH "iq_width" #define ORAN_RU_CONFIG_IQWIDTH "iq_width" // not needed if M-plane used
#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" #define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" // not needed if M-plane used
// clang-format off // clang-format off
#define ORAN_RU_DESC {\ #define ORAN_RU_DESC {\
@@ -114,7 +122,7 @@
#define CONFIG_STRING_ORAN_PRACH "prach_config" #define CONFIG_STRING_ORAN_PRACH "prach_config"
#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset" #define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset" // not needed if M-plane used
#define ORAN_PRACH_CONFIG_KBAR "kbar" #define ORAN_PRACH_CONFIG_KBAR "kbar"
// clang-format off // clang-format off
+90 -37
View File
@@ -39,11 +39,17 @@
// line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api // line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api
#include "../../app/src/common.h" #include "../../app/src/common.h"
#ifdef OAI_MPLANE
#include "mplane/init-mplane.h"
#include "mplane/connect-mplane.h"
#endif
typedef struct { typedef struct {
eth_state_t e; eth_state_t e;
rru_config_msg_type_t last_msg; rru_config_msg_type_t last_msg;
int capabilities_sent; int capabilities_sent;
void *oran_priv; void *oran_priv;
void *mplane_priv;
} oran_eth_state_t; } oran_eth_state_t;
notifiedFIFO_t oran_sync_fifo; notifiedFIFO_t oran_sync_fifo;
@@ -76,6 +82,10 @@ int trx_oran_stop(openair0_device *device)
printf("ORAN: %s\n", __FUNCTION__); printf("ORAN: %s\n", __FUNCTION__);
oran_eth_state_t *s = device->priv; oran_eth_state_t *s = device->priv;
xran_stop(s->oran_priv); xran_stop(s->oran_priv);
#ifdef OAI_MPLANE
printf("[MPLANE] Stopping M-plane.\n");
disconnect_mplane(s->mplane_priv);
#endif
return (0); return (0);
} }
@@ -204,11 +214,11 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
RU_proc_t *proc = &ru->proc; RU_proc_t *proc = &ru->proc;
int f, sl; int f, sl;
LOG_D(PHY, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]); LOG_D(HW, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]);
start_meas(&ru->rx_fhaul); start_meas(&ru->rx_fhaul);
int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl); int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl);
stop_meas(&ru->rx_fhaul); stop_meas(&ru->rx_fhaul);
LOG_D(PHY, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]); LOG_D(HW, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]);
if (ret != 0) { if (ret != 0) {
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl); printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl);
} }
@@ -221,7 +231,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
if (proc->first_rx == 0) { if (proc->first_rx == 0) {
if (proc->tti_rx != *slot) { if (proc->tti_rx != *slot) {
LOG_E(PHY, LOG_E(HW,
"Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n", "Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n",
proc->frame_rx, proc->frame_rx,
proc->tti_rx, proc->tti_rx,
@@ -231,7 +241,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
} }
if (proc->frame_rx != *frame) { if (proc->frame_rx != *frame) {
LOG_E(PHY, LOG_E(HW,
"Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n", "Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n",
proc->frame_rx, proc->frame_rx,
proc->tti_rx, proc->tti_rx,
@@ -241,10 +251,10 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
} }
} else { } else {
proc->first_rx = 0; proc->first_rx = 0;
LOG_I(PHY, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); LOG_I(HW, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
*frame = proc->frame_rx; *frame = proc->frame_rx;
*slot = proc->tti_rx; *slot = proc->tti_rx;
LOG_I(PHY, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); LOG_I(HW, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
} }
} }
@@ -279,7 +289,80 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
openair0_config_t *openair0_cfg, openair0_config_t *openair0_cfg,
eth_params_t *eth_params) eth_params_t *eth_params)
{ {
oran_eth_state_t *eth; oran_eth_state_t *eth = calloc_or_fail(1, sizeof(*eth));
struct xran_fh_init fh_init = {0};
struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0};
bool success = false;
#ifdef OAI_MPLANE
ru_session_list_t ru_session_list = {0};
success = init_mplane(&ru_session_list);
AssertFatal(success, "[MPLANE] Cannot initialize M-plane.\n");
bool ru_configured[ru_session_list.num_rus];
for (size_t i = 0; i < ru_session_list.num_rus; i++) {
ru_session_t *ru_session = &ru_session_list.ru_session[i];
ru_configured[i] = connect_mplane(ru_session);
if (!ru_configured[i]) {
continue;
}
ru_configured[i] = manage_ru(ru_session, openair0_cfg, ru_session_list.num_rus);
}
bool all_ok = true;
bool ru_ready[ru_session_list.num_rus];
for (size_t i = 0; i < ru_session_list.num_rus; i++) {
if (!ru_configured[i]) {
MP_LOG_I("RU with IP %s couldn't be configured.\n", ru_session_list.ru_session[i].ru_ip_add);
all_ok = false;
}
ru_ready[i] = false;
}
if (!all_ok) {
disconnect_mplane((void *)&ru_session_list);
AssertFatal(false, "[MPLANE] Stopping M-plane.\n");
}
while (true) {
sleep(1);
bool all_rus_ready = true;
for (int i = 0; i < ru_session_list.num_rus; i++) {
ru_session_t *ru_session = &ru_session_list.ru_session[i];
if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) {
MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add);
ru_ready[i] = true;
} else {
all_rus_ready = false;
break;
}
}
if (all_rus_ready) {
break;
}
}
eth->mplane_priv = (void *)&ru_session_list;
success = get_xran_config((void *)&ru_session_list, openair0_cfg, &fh_init, fh_config);
AssertFatal(success, "[MPLANE] Cannot configure xran with M-plane info.\n");
#else
success = get_xran_config(NULL, openair0_cfg, &fh_init, fh_config);
AssertFatal(success, "cannot get configuration for xran\n");
#endif
LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX);
eth->oran_priv = oai_oran_initialize(&fh_init, fh_config);
AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul");
// create message queues for ORAN sync
initNotifiedFIFO(&oran_sync_fifo);
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
eth->last_msg = (rru_config_msg_type_t)-1;
device->Mod_id = 0; device->Mod_id = 0;
device->transp_type = ETHERNET_TP; device->transp_type = ETHERNET_TP;
@@ -290,43 +373,13 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
device->trx_stop_func = trx_oran_stop; device->trx_stop_func = trx_oran_stop;
device->trx_set_freq_func = trx_oran_set_freq; device->trx_set_freq_func = trx_oran_set_freq;
device->trx_set_gains_func = trx_oran_set_gains; device->trx_set_gains_func = trx_oran_set_gains;
device->trx_write_func = trx_oran_write_raw; device->trx_write_func = trx_oran_write_raw;
device->trx_read_func = trx_oran_read_raw; device->trx_read_func = trx_oran_read_raw;
device->trx_ctlsend_func = trx_oran_ctlsend; device->trx_ctlsend_func = trx_oran_ctlsend;
device->trx_ctlrecv_func = trx_oran_ctlrecv; device->trx_ctlrecv_func = trx_oran_ctlrecv;
device->get_internal_parameter = get_internal_parameter; device->get_internal_parameter = get_internal_parameter;
eth = (oran_eth_state_t *)calloc(1, sizeof(oran_eth_state_t));
if (eth == NULL) {
AssertFatal(0 == 1, "out of memory\n");
}
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;
eth->e.if_name = eth_params->local_if_name;
eth->oran_priv = NULL; // define_oran_pointer();
device->priv = eth; device->priv = eth;
device->openair0_cfg = &openair0_cfg[0]; device->openair0_cfg = &openair0_cfg[0];
eth->last_msg = (rru_config_msg_type_t)-1;
LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX);
initNotifiedFIFO(&oran_sync_fifo);
struct xran_fh_init fh_init = {0};
struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0};
#ifndef OAI_MPLANE_SUPPORT
bool success = get_xran_config(openair0_cfg, &fh_init, fh_config);
AssertFatal(success, "cannot get configuration for xran\n");
#else
/* TODO: M-plane integration */
#endif
eth->oran_priv = oai_oran_initialize(&fh_init, fh_config);
AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul");
// create message queues for ORAN sync
return 0; return 0;
} }
@@ -0,0 +1,265 @@
Active_gNBs = ( "gNB-OAI-DU");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_DU_ID = 0xe00;
gNB_name = "gNB-OAI-DU";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
pusch_AntennaPorts = 8;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
force_UL256qam_off = 1;
maxMIMO_layers = 2;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 3950.4 MHz
# selected SSB frequency = 3950.4 MHz
absoluteFrequencySSB = 663360;
dl_frequencyBand = 77;
# frequency point A = 3901.26 MHz
dl_absoluteFrequencyPointA = 660084;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 273;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 77;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 273;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 1099;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 152;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 8;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 3;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -96;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 10;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "f1";
local_n_if_name = "enp193s0f0";
local_n_address = "172.21.16.51";
remote_n_address = "172.21.6.90";
local_n_portc = 500;
local_n_portd = 2153;
remote_n_portc = 501;
remote_n_portd = 2153;
pusch_TargetSNRx10 = 120;
pucch_TargetSNRx10 = 200;
dl_bler_target_upper = .35;
dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 100;
ul_max_mcs = 28;
min_grant_prb = 1;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 100;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = 10;
max_ldpc_iterations = 10;
tx_amp_backoff_dB = 12; # needs to match O-RU configuration
L1_rx_thread_core = 8;
L1_tx_thread_core = 10; # relevant after merge of l1_tx_thread
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 8;
nb_rx = 8;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 9;
sl_ahead = 10;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:01:01.0", "0000:01:01.1", "0000:01:01.2", "0000:01:01.3"); # two VFs can be used as well
system_core = 0;
io_core = 1;
worker_cores = (2);
du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69");
vlan_tag = (5, 5, 6, 6);
ru_ip_addr = ("192.168.80.5", "192.168.80.6");
fh_config = (
# RAN650 #1
{
T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336);
T1a_up = (294, 345);
Ta4 = (0, 200);
},
# RAN650 #2
{
T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336);
T1a_up = (294, 345);
Ta4 = (0, 200);
});
};
@@ -0,0 +1,273 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
maxMIMO_layers = 2;
pusch_AntennaPorts = 4;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
# force_UL256qam_off = 1;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 3350.01 MHz
# selected SSB frequency = 3349.92 MHz
absoluteFrequencySSB = 623328;
dl_frequencyBand = 78;
# frequency point A = 3300.87 MHz
dl_absoluteFrequencyPointA = 620058;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 273;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 78;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 273;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 1099;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 152;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 8;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 3;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -96;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 6;
nrofDownlinkSlots = 7;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 2;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 180;
pucch_TargetSNRx10 = 220;
dl_bler_target_upper = .35;
dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 1000;
ul_max_mcs = 28;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 100;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = 10;
max_ldpc_iterations = 15;
tx_amp_backoff_dB = 12; # needs to match O-RU configuration
L1_rx_thread_core = 8;
L1_tx_thread_core = 10;
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 9;
sl_ahead = 10;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well
system_core = 0;
io_core = 1;
worker_cores = (2);
du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:68","00:11:22:33:44:69");
vlan_tag = (11, 11);
ru_ip_addr = ("192.168.80.10");
fh_config = ({
T1a_cp_dl = (419, 470);
T1a_cp_ul = (285, 336);
T1a_up = (294, 345);
Ta4 = (0, 200);
});
};