Implement QoS flow multiplexing logic that optimizes DRB usage by classifying
5QI values per 3GPP TS 23.501 Table 5.7.4-1 and applying resource-type-aware
multiplexing limits. The changes are adopted in nr_rrc_add_bearers, which
is the RRC function responsible for adding PDU Sessions and DRBs in RRC.
Key features:
- Classify 5QI by resource type (DC-GBR, GBR, Non-GBR)
- Reuse existing DRBs when QoS characteristics are compatible
- Dedicated DRBs for DC-GBR (5QI 82-90) and high-priority services
- Per-type multiplexing limits: DC-GBR=1, GBR=2, Non-GBR=5
- Aggregate cap: max 5 flows per DRB
Implementation:
- nr_rrc_get_5qi_resource_type():
Maps 5QI values to resource types using lookup table.
DC-GBR: 5QI 82-90, GBR: 5QI 1-4,65-67,71-76, Non-GBR: 5QI 5-11,69-70,79-80.
Unknown 5QIs default to Non-GBR with warning.
- nr_rrc_qos_dedicated_drb():
Identifies 5QIs requiring isolated DRBs (high priority, low-PER).
Includes: DC-GBR: 5QI 82-90, 5QI 4,6-10 (video), 5QI 70 (mission-critical),
5QI 71-73 (live streaming), 5QI 80 (low-latency).
- nr_rrc_count_qos_flows_by_type():
Counts QoS flows mapped to a specific DRB, grouped by resource type.
Used to check capacity and enforce multiplexing limits.
- nr_rrc_find_suitable_drb_for_qos():
Searches existing DRBs in the same PDU session for available capacity.
Checks resource type compatibility, per-type limits, and aggregate cap.
Returns DRB ID if suitable, -1 if new DRB needed.
DC-GBR flows always return -1 (require dedicated DRB).
- nr_rrc_assign_drb_to_qos_flow(), which either reuses a DRB
selected by nr_rrc_find_suitable_drb_for_qos() or creates a new DRB via
nr_rrc_add_drb, assigns its ID to the QoS flow
Note: this commit is multi-QoS ready.
Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
QoS Priority Level range is 1-127, fits in uint8_t (3GPP TS 23.501 §5.7.3.3).
Refactor qos_priority field in pdusession_level_qos_parameter_t to use
qos_priority_level_t typedef (uint8_t) instead of uint64_t. Also,
improve documentation.
Changes:
- Add qos_priority_level_t typedef (uint8_t), more efficient than uint64_t
- Change pdusession_level_qos_parameter_t.qos_priority from uint64_t
to qos_priority_level_t
- Add MIN_QOS_PRIORITY_LEVEL (1) and MAX_QOS_PRIORITY_LEVEL (127)
defines for range checks
Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
Since qos_priority_t reprensents the ARP priority level, an integer
(1..15), this commit is renaming it to qos_arp_priority_level_t
typedef (uint8_t) for better clarity and cleaning up unnecessary enum definition.
Changes:
- Rename qos_priority_t to qos_arp_priority_level_t (uint8_t typedef)
for type safety and semantic meaning
- Remove enum with 15 explicit values (not needed, matches spec as integer)
- Add MIN_QOS_ARP_PRIORITY_LEVEL (1) and MAX_QOS_ARP_PRIORITY_LEVEL (15) defines
for bound checks, simpler and more efficient
- Update qos_arp_t struct to use new typedef
References:
- 3GPP TS 23.501 §5.7.2.2!
Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
Replace NGAP_MAX_PDU_SESSION and E1AP_MAX_NUM_PDU_SESSIONS with
shared NR_MAX_NB_PDU_SESSIONS constant. The value (256) is consistent
with both TS 38.331, TS 38.413 and TS 38.463
All protocol layers (NGAP, E1AP, RRC, SDAP) now use a single
shared constant for maximum PDU sessions per UE, ensuring
consistency across the codebase
E1AP_MAX_NUM_PDU_SESSIONS (was 4) is removed from e1ap_messages_types.h
Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
ZMQ radio
This is a zmq radio implementation that attempts to integrate NR UE with
the ocudu project.
OAI integration status:
This can currently be used to connect OAI gnb and OAI UE.
Compilation:
cmake --build . --target nr-softmodem nr-uesoftmodem ldpc params_libconfig zmq_radio
Running
- gNB command:
sudo ./nr-softmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --device.name zmq_radio --zmq.[0].tx_channels tcp://127.0.0.1:4556 --zmq.[0].rx_channels tcp://127.0.0.1:4557
- UE command:
sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --ssb 516 --device.name zmq_radio --zmq.[0].tx_channels tcp://127.0.0.1:4557 --zmq.[0].rx_channels tcp://127.0.0.1:4556
A new CI testcase for 2x2 configuration was added.
OCUDU integration status:
The OAI NR UE enters RRC Connected state.
For more details, please refer to the description of MR !3975.
T-Tracer & Data Recording v1.1: UL PHY trace modularization and recording
enhancements
Based on the plan with @schmidtr and @roux-cedric, we agreed to enhance
the data recording in two phases:
- Phase 1: Update Data Recording framework to get All internal Massive
Updates and enhancements through the whole framework public
- Phase2: Restructure T-Tracer Apps and remove all Mems in gNB and UE
Softmodems to Get data on T-tarcer Apps for all activated Messages
symbol-by-symbol, and related Meta-data, then do the aggregation on
the T-tracer App. So, there is No Memory Creation at all on the 5G NR
Stack.
This Merge Request is for Phase 1. We address the comments given in: !3632
Summary: Refactor T-Tracer instrumentation for UL PHY data capture and
improve the data recording application (v1.0 → v1.1). This MR extracts
inline T() macro calls into modular wrapper functions, adds Unix timestamp
fields to trace messages, implements a 4-state shared memory protocol for
gNB/UE tracers, and delivers an improved synchronized recording architecture
in Python.
Changes:
- T-Tracer: Modular UL PHY trace wrappers
- Add T_messages_creator.c/.h with 7 wrapper functions (log_ul_fd_dmrs,
log_ul_fd_chan_est_dmrs_pos, log_ul_fd_pusch_iq,
log_ul_fd_chan_est_dmrs_interpl, log_ul_payload_rx_bits,
log_ul_payload_tx_bits, log_ul_scrambled_tx_bits) and a static
log_ul_common() helper
- Register T_messages_creator.c in the T library CMake build
- Update T_messages.txt definitions: Remove string timestamps and get
time stamp directly from sending_time of T-macro.
- PHY: Replace inline T() calls with wrappers
- gNB (nr_ulsch_demodulation.c, nr_ul_channel_estimation.c,
phy_procedures_nr_gNB.c): replace inline T() calls with
T_messages_creator wrappers
- UE (nr_ulsch_coding.c, nr_ulsch_ue.c): replace inline T() calls with
log_ul_payload_tx_bits and log_ul_scrambled_tx_bits wrappers
- Remove deprecated log_tools.c/.h and its CMake reference
- T-Tracer gNB & UE apps: Enhancements
- Implement 4-state shared memory protocol (WAIT → CONFIG → RECORD → STOP)
for coordination with the data recording app
- Add event_trace_msg_ul_data struct with 27 UL metadata fields
- Refactor event loop to poll()-based with proper signal handling
- Separate project IDs (gNB=2335, UE=2336) and ftok paths for independent
shared memory segments
- Update shared memory sizing: Limit number of records to
NUM_MESSAGES_PER_SLOT=5, 100 slots
- Data Recording App v1.1
- Improved architecture with thread pool and barrier synchronization
- Frame/slot-based message grouping with per-slot validation
- atexit/signal-based cleanup for graceful shared memory detach
- Delete legacy data_recording_app_v1.0.py
- Library improvements
- config_interface.py: remove legacy YAML config reader, streamline to
JSON-only
- shared_memory_interface.py: new module for shared memory
attach/read/protocol
- wireless_parameters_mapper.py: new module for NR parameter mapping
- data_recording_messages_def.py: updated message definitions for
27-field struct
- sigmf_interface.py, sync_service.py, common_utils.py: remove unused
imports and dead code
- Documentation
- Update data_recording.md for v1.1 architecture and usage
- refactor timestamp handling
- Replace string-based SENDING_TIME with integer SEC/NSEC fields.
- Designed the shared memory protocol with a 4-state machine (STATE_WAIT=0, STATE_CONFIG=1, STATE_RECORD=2, STATE_STOP=3) for command/control between the recording app and the T-Tracer service
- Implemented two shared memory segments: one for reading commands (addr_rd) and one for writing captured data (addr_wr)
- Created event_trace_msg_ul_data struct mapping all 27 UL metadata fields (frame, slot, datetime, MCS, DMRS parameters, etc.) by name from the T-Tracer database
- Implemented setup_trace_msg_ul_data() using the G() macro to map field names to indices at startup
- Wrote the main event loop using poll() to avoid busy-waiting, with get_event() to receive T-Tracer events from the softmodem socket
ctest: fix tests when compiling with sanitizers, ignore build directories,
fix spsc_q build
- Fix the directory to the current build directory to enable running with
sanitizers with ctest
- add build* to .gitignore to close#1074
- fix spsc_q compilation on non-C++23 compilers to close#1073
stdatomic.h is a C++23 feature [1]. Thus, "older" compilers such as
gcc-11 (default in Ubuntu 22) do not know this, and can therefore not
correctly compile spsc_q. Fix this by alternatively including atomic for
C++.
Fixes errors such as
stdatomic.h:40:9: error: ‘_Atomic’ does not name a type
[1] https://en.cppreference.com/cpp/header/stdatomic.h
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
L1 gNB type0 PDSCH
PDSCH type0 allows frequency allocation via PRB bitmap (type1 is via
start and number of PRBs) allowing for non contiguous allocation in
frequency domain
This commit introduces ZMQ-based radio library. Each pair of RX/TX antennas is
represented by a ZMQ REQ/REP socket pair which streams continuous IQ samples
from radio start until stop.
Usage:
Simplest configuration is to connect OAI NR UE to OAI GNB with the same number
of antennas - by inverting the RX and TX channels in ZMQ radio configuration the
gNBs TX is mapped to UEs RX antennas and vice versa.
L1 RX: use queues instead of arrays and linear search for PUCCH, PUSCH, SRS, PRACH
This MR is an attempt to reduce the time L1 RX searches in array for the
next job to process, and instead use a queue. This queue is a FIFO,
because the various jobs (FAPI messages) to process come in order, and
need to be processed in order. The MR (hopefully, to be measured)
reduces the amount of time spent searching for the next UE (because the
next job is always at the beginning of the queue), and should scale
better for many UEs.
It does the following:
- introduce two helper libraries for (1) Frame.Slot calculation (sfn_t),
already introduced in !3521 (merged) commit 3102068e, and (2) a ring
buffer with fixed size
- use sfn_t and ring buffer (gNB->pucch_queue) to remove the linear
array for PUCCH (gNB->pucch)
- use sfn_t and ring buffer (gNB->pusch_queue) for some PUSCH lookups.
Because we need to still store PUSCH contexts, gNB->pusch is still
there
- use sfn_t and ring buffer (gNB->srs_queue) to remove the linear array
for SRS (gNB->srs)
- use sfn_t and ring buffers (gNB->prach_ru_queue and
gNB->prach_l1rx_queue) to remove the linear array for PRACH
(gNB->prach_list)
- some minor cleanups, e.g., additional loops over the PUSCH array,
using const, using pointers instead of indices, etc
Miscellaneous code improvements
- A fix in a yaml config file as reported by @Abdo-Gaber
- proper positioning of static functions in a couple of gNB scheduler
files
- some effort to split NR from LTE code in compilation
- harmonization of macros for unused variables
Add SIB 3,4 support, configurable SIB2 and refactor CU/DU SIB management
This MR makes neighbour and inter-frequency configuration drive how
SIB2/SIB3/SIB4 are built and sent from CU to DUs. It standardizes SIB
payloads as byte_array_t with typed SIB IDs across RRC, F1AP and MAC,
reducing ad‑hoc buffer handling. Neighbour parsing, validation and
lookup are tightened.
Changes
- Minor refactor to gNB neighbour parsing and storage (shared PLMN
extraction, safer allocation, etc).
- Represent SIB containers uniformly as byte_array_t plus nr_sib_type_t,
and adapt F1AP, MAC and RRC users to the new container API.
- Make SIB2 cell-reselection information fully config-driven with
explicit bounds checking and SIB2 ASN.1 building from that config.
- Generate SIB3 intra-frequency neighbours from the per-cell neighbour
list and propagate them from CU to DU over F1, with MAC
decoding/attaching them to SystemInformation.
- Generate SIB4 inter-frequency neighbours from a new frequency_list
plus neighbour SIB3/SIB4 offsets, and propagate them from CU to DU
over F1, with MAC decoding/attaching them.
- Add basic ASN.1 round-trip tests for SIB2/SIB3/SIB4 and SIB4 range
checks, and update RRC docs to describe the neighbour/inter-frequency
configuration model.
Testing:
1. in gNB conf file:
cu_sibs = (2, 3, 4);
2. Update neighbour config file with SIB3/SIB4 conf:
(see documentation)
3. run gNB and UE as usual
---
Logs & configs: see MR on Gitlab
Because it is SPSC, atomic variables are enough to synchronize the two
threads. Concretely put() is modified to ensure that read_idx is
"acquired" so that the read index has been written, including memory, by
the other thread. "Release" ensures that the write operation (including
the memory to the buffer) is written before it is visible to the other
thread in get() (which in turn "acquires" it). For more information, see
also [1].
The rest of the library has been simplified to work only with put() and
get(), reducing total code and the surface for possible bugs.
This (and the previous) version has been tested with the
threadSanitizer:
TSAN_OPTIONS=halt_on_error=1 ./common/utils/ds/tests/test_spsc_q_perf
On my machine, using Google Benchmark, I measure a considerable 5x speed
improvement:
$ /tmp/benchmark/tools/compare.py benchmarks pthread.json atomic.json
Comparing pthread.json to atomic.json
Benchmark Time CPU Time Old Time New CPU Old CPU New
--------------------------------------------------------------------------------------------------------------
BM_spsc_q/10 -0.8201 -0.0740 266779912 47989020 52387 48512
BM_spsc_q/16 -0.8301 -0.0520 249656592 42428540 51462 48784
BM_spsc_q/32 -0.8003 -0.0841 230248798 45972155 53841 49311
BM_spsc_q/64 -0.7995 -0.0506 210429791 42199674 50690 48124
BM_spsc_q/128 -0.7930 -0.1101 205212273 42483155 52745 46936
BM_spsc_q/160 -0.7880 -0.1663 216644738 45938247 53400 44518
OVERALL_GEOMEAN -0.8057 -0.0904 0 0 0 0
[1] https://en.cppreference.com/w/c/atomic/memory_order.html
Assisted-By: Claude:claude-sonnet-4-6
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
This data structure is designed to support the use cases of the L1,
i.e., provide a queue which can be quickly used to order L1 jobs in FIFO
order with simple iteration of jobs to treat. It is a Single-Consumer
Single-Producer queue library.
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Unify SIB container handling by introducing a typed SIB enum and storing
SIB payloads as byte_array_t across common NR types, F1AP helpers, MAC,
and RRC DU setup code.
Changes:
- Include byte_array support in nr_common.h, add nr_sib_type_t (NR_SIB_1–NR_SIB_21),
and change nr_SIBs_t to hold only nr_sib_type_t SIB_type.
- Switch f1ap_sib_msg_t in f1ap_messages_types.h to use a byte_array_t SI_container
instead of raw pointer and length fields.
- Update F1AP encode/decode, equality, copy, and free helpers in
f1ap_interface_management.c to work on SI_container.buf / SI_container.len and
use eq_byte_array, copy_byte_array, and free_byte_array.
- Adapt F1AP tests in f1ap_lib_test.c to build and inspect SIB containers via
SI_container.buf and SI_container.len.
- Replace magic SIB numbers with nr_sib_type_t values in gnb_config.c
(get_sys_info and fill_du_sibs) to validate and configure DU SIBs.
- Rework nr_mac_configure_other_sib in NR_MAC_gNB/config.c to decode SIB2
from a byte_array_t container, fix freeing by releasing the decoded sib2 on
failure, and use NR_SIB_2 / NR_SIB_19 for CU/DU SIB selection.
- Add an add_si_msg helper in rrc_gNB_du.c and refactor the SIB2 branch of
rrc_gNB_process_f1_setup_req to populate cell->SI_msg from encoded local
byte array while iterating SIBs with FOR_EACH_SEQ_ARR.
Change 1: config_check_intval() now uses the correct integer pointer for TYPE_INT
Problem: config_check_intval() previously dereferenced param->uptr regardless
of param->type. For parameters declared as signed (TYPE_INT / TYPE_INT32), the
active union member is param->iptr, and param->uptr may be NULL -> using uptr
makes validation unsafe and type-inconsistent.
What changed: Updated config_check_intval() behavior (signature unchanged).
Handle both param->type, param->iptr and param->uptr.
Change 1: new config_check_uintrange() for unsigned range constraints
Problem: there was a signed range checker (config_check_intrange()) that reads
param->iptr, but there was no dedicated unsigned range validator using param->uptr.
What changed: added config_check_uintrange() in config_userapi.h/.c
The new function reads param->uptr as uint32_t and validates against
param->chkPptr->s2.okintrange[] endpoints.
Change 3: constify input params for f2 function pointers
Problem: checkedparam_t.s2.f2 was typed with non-const input params, even though
range checks only read. A safer const-safe signature is required.
What changed: s2.f2 now takes const configmodule_interface_t *
and const paramdef_t *. config_check_intrange() and config_check_uintrange() use
the same const-qualified parameters.
Further unused arguments cleanup
More fixes for unused function arguments (see #1057),
add_compile_options(-Wunused-parameter) added in folders:
- nfapi
- openair2
- openair3
- USRP
- rfsimulator
Cleanup common_lib.h
This change reduces the number of dependecies of common_lib.h and simplifies
the task of implementing an external OAI radio library.
Remove a lot of unused code, defines, and config options
Remove unused header files and defines.
Slightly clean up gnb_config.c by removing all _IDX variables. Remove
these unused parameters:
- MACRLCs.[0].num_cc
- MACRLCs.[0].local_n_portc
- MACRLCs.[0].remove_n_portc
- MACRLCs.[0].remote_s_portc
- MACRLCs.[0].remote_s_portd
- L1s.[0].num_cc
- L1s.[0].local_n_portc
More compilation improvements
Mostly to decouple NR files from LTE headers.
At least in one instance, ulsch_input_buffer_array, using an LTE constant in
NR code was quite dangerous because the buffer in NR could easily be larger
than what the LTE constant foresee.
Extend UICC configuration parsing to provide: routing_indicator,
protection_scheme, home_network_public_key, and home_network_public_key_id.
Use the protection_scheme value to decide what SUCI Profile Scheme to
apply during SUCI generation. Add support for Profile Scheme A which
provides ECIES-based encryption using Curve25519 and X9.63 KDF as outlined
in TS 33.501 Section C.3.4.1 Profile A.
When a configuration file specifies an unsupported Profile Scheme,
the NAS layer triggers a fatal error. This occurs either because
Profile Scheme B is unimplemented or the build uses OpenSSL < 3.0,
which lacks Curve25519 and X9.63 KDF support, ensuring users are
informed of the incompatibility.
Integrate channel pipeline library with vrtsim with two acceleration
options chosen at compile time:
- threadpool if CUDA support is disabled
- CUDA otherwise
- all RAN code, CI code, configuration files, dockerfiles, in CSSL v1.0
- all deployment code (openshift, charts, ancillary files like shell
scripts), in MIT
- documentation in CC-BY-4.0
- exceptions might apply and are listed in NOTICE
- there is a new LICENSES folder with all licenses
- CONTRIBUTIONS.md has been updated accordingly
For automated changes based on OAI PL v1.1:
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.{c,h,cpp}
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.ts
perl -i~ -0pe 's/<!--.*Licensed to the OpenAirInterface.*openairinterface.org\n.*-->/<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->/s' **/*.xml
The rest (cmake, files with missing license, cmake) manually.