This commit introduces the uplink MU-MIMO joint processing framework.
It models a scenario where a single gNB serves multiple spatially
multiplexed UEs sharing the exact same time and frequency resources.
Note that we dont handle SRS and PTRS for multiple UEs here.
Also, the cuda is restricted to single UE scenario.
Signed-off-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
This commit introduces a dedicated simulation environment to validate
the uplink MU-MIMO joint processing framework. It models a scenario
where a single gNB serves multiple spatially multiplexed UEs sharing
the exact same time and frequency resources.
The simulator executes the complete physical layer baseband pipeline:
- PUSCH data generation and LDPC encoding per UE
- OFDM modulation (TX)
- Signal propagation through a multi-path channel model
- OFDM demodulation (RX) at the gNB
- Joint PUSCH decoding, equalization, and spatial demultiplexing
Performance metrics such as scrambling errors and BLER per UE is
evaluated at the end of the simulation.
Note: The current simulation evaluates performance based on a single
HARQ round (retransmissions are not supported).
Signed-off-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
- The nr_rx_pusch_tp() function, which handles single UE PUSCH RX
processing, is extended to nr_rx_pusch_group_tp() for group based
processing, where all UEs belonging to the same group are processed
together.
- A joint PDU is created that accumulates all the layers of the UEs in
a group to process them jointly. This creates a virtual single UE
MIMO configuration that can be processed using existing OAI functions.
The resulting output consists of the LLRs from all the UEs. The LLRs
are further separated per UE, and unscrambling is performed
individually.
- Note that the unscrambling step is removed from
nr_pusch_symbol_processing(). Because the resulting output from joint
processing consists of LLRs from multiple UEs, these LLRs need to be
separated before they can be unscrambled individually.
Signed-off-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
Refactor ULSCH_id based processing of the PUSCH PDUs to group based
processing using FAPI groups. This is required to process multiple
PUSCH PDUs jointly for MU-MIMO. This is an initial commit that
supports group size = 1 and will be extended to > 1 in the following
commits.
The flow of group information from MAC to PHY using FAPI is as follows:
- In MAC, nr_schedule_pusch_fapi_groups() is introduced to group UEs
that have PUSCH PDUs with the same frequency, time, and QAM order
along with orthogonal DMRS ports into a single group. The FAPI
groups consist of UE lists filled with a PDU index. Based on the
parameter UL_tti_req->n_group, the number of unique groups is
identified. In each group, the parameter group->n_ue defines the
number of UEs present in the group along with their PDU indices.
- After receiving the FAPI message in the PHY from MAC, in
nr_save_ul_tti_req(), a group number and group size for each
PUSCH PDU is allocated in nr_fill_ulsch(), and a PUSCH job is created.
- Further, after a job is created, in phy_procedures_gNB_uespec_RX(),
the PUSCH PDUs of the ULSCH_ids for each group are segregated based
on the group index. They are processed jointly using
handle_pusch_rx_group_trigger(), and the PUSCH DTX per UE in the
group is calculated using handle_pusch_DTX().
Signed-off-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
The function handle_pusch_decode_trigger() consists of PUSCH RX processing and PUSCH DTX detection
per UE. This is now split into two functions: handle_pusch_rx_trigger() and handle_pusch_DTX(). This
is needed for group based processing where each group consists of multiple UEs and
handle_pusch_rx_trigger() processes PUSCH RX for multiple UEs jointly while handle_pusch_DTX() need to
detect PUSCH DTX per UE.
Signed-off-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
Integration `2026.w19`
* ci: post MR validation comments only on warnings or errors in pre-ci-check
* ci: skip merge-commit validation for integration branches
* !4088 fixing wrong logic for SIMO and MISO AWGN channels
* !4052 Add OAI - WNC gNB config file
* !4091 Fix build with unit tests, build all in CI
* !4089 Fixing broken nr-cu-nrppa-test simulator and nr-ue-nas-simualtor
* !4099 Allow control signal level at input of OFDM modulator
* !4092 Remove more unused parameters
* !4102 nr-cuup-load-test: avoid unaligned memory access
* !4077 Update microamp FR2 doc for firmware 0.1.174
* !3960 fix: issue 1054 - Config: Creating New Array members via command line arguments
* !3810 UE symbol based PBCH, PSBCH receiver
* !4103 Update CN5G images to stable release `v2.2.1`
* !3814 Multi-QoS Handling and PDU Session Modify
* !4064 FAPI: fix UCI payload byte length for bit_len multiples of 8
* !4078 [M-plane] Improvements, fixes + Add CI M-plane pipeline
Closes#1054, #1075, and #541
See merge request oai/openairinterface5g!4095
FAPI: fix UCI payload byte length for bit_len multiples of 8
Problem
When testing with cuBB as the FAPI PNF (L1) and ruSIM, the VNF (OAI L2)
was consistently failing to unpack UCI.indication messages containing
PUCCH format 2/3/4 PDUs with CSI-1 reports:
vnf_handle_nr_uci_indication: Failed to unpack message
pullarray8: pullarray8 no space in buffer
Root cause
All variable-length payload fields in the UCI pack/unpack functions
(HARQ, SR, CSI-1, CSI-2) computed their byte length as:
const uint16_t csi_len = bit_len / 8 + 1;
This formula seems wrong for any bit_len that is an exact multiple of 8.
For example, bit_len=8 gives csi_len=2, but 8 bits fit in exactly 1
byte. The correct ceiling division is (bit_len + 7) / 8.
cuBB packs CSI-1 payload bytes using the correct formula, so for an
8-bit CSI codebook it sends 1 byte. OAI's unpacker computed csi_len=2
and called pullarray8 requesting 2 bytes from a buffer with only 1
remaining, triggering the error.
The failure was also specific to PUCCH 2/3/4 (and would affect PUSCH
UCI) because PUCCH 0/1 carries no variable-length byte arrays — its HARQ
payload is packed as individual uint8 values per ACK bit, so pullarray8
is never called.
Diagnosis
Added NFAPI_TRACE_NOTE logging throughout the unpack chain (enabled via
NFAPI_TRACE_LEVEL=note) to trace PDU type, bitmap, computed lengths, and
buffer remaining bytes at each branch. The following sequence confirmed
the exact failure site:
[N] unpack_nr_uci_indication: sfn=592 slot=9 num_ucis=1 buf_remaining=21
[N] unpack_nr_uci_indication: unpacking UCI[0/1] buf_remaining=21
[N] unpack_nr_uci_indication_body: pdu_type=2 pdu_size=21 buf_remaining=17
[N] unpack_nr_uci_pucch_2_3_4: PUCCH-2/3/4 rnti=0x5c2d pucch_format=0 pduBitmap=0x04 buf_remaining=4
[N] unpack_nr_uci_pucch_2_3_4: PUCCH-2/3/4 CSI-1 csi_part1_bit_len=8 csi_len=2 buf_remaining=1
[N] unpack_nr_uci_pucch_2_3_4: PUCCH-2/3/4 CSI-1 about to pullarray8 csi_len=2 buf_remaining=1
[E] pullarray8: pullarray8 no space in buffer
This was also cross-checked against a pcap capture of the nvipc
interface, which confirmed cuBB sends PDUSize=21 with 1 byte for the
8-bit CSI-1 payload — consistent with (8+7)/8 = 1.
Tentative Fix
Replace bit_len / 8 + 1 with (bit_len + 7) / 8 at all 14 affected sites
across both pack and unpack functions for PUSCH, PUCCH 0/1 (SR/HARQ),
and PUCCH 2/3/4 (SR, HARQ, CSI-1, CSI-2) in nr_fapi_p7.c.
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Reviewed-by: Rúben Soares Silva <rsilva@allbesmart.pt>
Multi-QoS Handling and PDU Session Modify
This MR implements comprehensive QoS flows handling and PDU Session
Modify procedures in the RRC layer, enabling full support for multiple
QoS flows per DRB and dynamic QoS management per 3GPP specs. Key
changes:
1. Multi-QoS Flows Support
- Multiple QoS flows per DRB: Support for multiple QoS flows mapped to a
single DRB
- Intelligent QoS-to-DRB mapping: Implements resource-type-aware
multiplexing based on 3GPP TS 23.501 Table 5.7.4-1
- DC-GBR flows (5QI 82-90): Dedicated DRB, max 1 flow per DRB
- GBR flows (5QI 1-4, 65-67, 71-76): Max 2 flows per DRB
- Non-GBR flows (5QI 5-11, 69-70, 79-80): Max 5 flows per DRB
- Aggregate cap: Maximum 5 flows per DRB
- 5QI validation: Early validation of standardized 5QI values (1-9,
65-90) during QoS flow setup/modify
2. PDU Session Modify Procedures
- Complete E1AP/RRC integration: Full Bearer Context Modification
support with DRB lifecycle management
- DRB To Setup/Modify/Remove lists: Complete support for all DRB
operations in Bearer Context Modification
- QoS flow operations: Support for QoS flow add, modify, and release
operations
- QoS flow mapping: Proper handling of QoS flow modifications in
DRB To Modify List
- Automatic DRB management: DRB setup, modification, and removal
based on QoS flow changes. Reuse existing DRBs if the incoming QoS
flow is compatible.
- Delayed transactions: PDU Session Modify added to delayed
transactions list for proper sequencing
3. GTP-U Tunnel Refactoring
- Architecture alignment:
- N3 tunnels: 1 per PDU session with QFI marking, container for
multiple bearers, supporting multiple QoS flows
- F1-U tunnels: 1 per DRB without QFI marking
- SDAP ownership of QoS: move QoS management to be fully owned by
SDAP
4. QoS Enhancements
- Dynamic5QI support: Full support for Dynamic5QI with packet delay
budget and packet error rate
- GBR QoS flows: Support for Guaranteed Bit Rate QoS flows with
GFBR/MFBR parameters
- DRB QoS aggregation: DRB-level QoS computed from all mapped QoS
flows using ARP priority (not 5QI priority)
- QoS priority level refactoring: Proper type definitions per 3GPP
TS 23.501 (QoS Priority Level: 1-127, ARP Priority Level: 1-15)
Technical Changes
RRC Layer
- Refactored `nr_rrc_add_bearers()` to support intelligent QoS-to-DRB
mapping
- Added `nr_rrc_update_qos()` for QoS flow add/modify with automatic DRB
assignment
- Implemented `nr_rrc_update_pdusession()` for QoS flow release and DRB
cleanup
- Consolidated F1 UE Context Modification Request handling
- Simplified PDU status tracking by removing intermediate states
- Added QoS flow and DRB removal utilities
- Updated RRC bearers tests with comprehensive multi-QoS testing
- Adapted `nr-cuup-load-test.c` to new GTP design
NGAP Layer
- Extended PDU Session Resource Modify Request Transfer with QoS
add/modify/release lists
- Added proper type definitions (`pdusession_mod_req_transfer_t`,
`qos_flow_to_release_t`)
- Fixed NGAP PDU Session Modify transfer encoding
GTP-U Layer
- Refactored tunnel creation API: scalar fields instead of arrays
- Split tunnel creation into `n3_gtpu_create()` and
`f1_drb_gtpu_create()`
- Added bearer-to-QFI mapping structure (`gtpv1u_rb_t`)
- Implemented QFI de-duplication and one-to-one QFI-to-bearer mapping
- Reduced inter-dependencies between LTE and NR
SDAP Layer
- Fixed default DRB tracking: Only one default DRB per SDAP entity per
PDU session (TS 37.324)
- Set default DRB to first DRB added when creating bearers
F1AP Layer
- Added GBR QoS Flow Information IE handling in CU
- Implemented DRB QoS aggregation from multiple QoS flows
- Extended F1AP test cases to support multiple QoS flows
Code Quality Improvements
- Improved error handling throughout the stack
- Enhanced logging and debugging capabilities
- Added comprehensive unit tests for multi-QoS scenarios
- Improved type safety and validation
Testing
The code was validated with Open5gs v2.7.6, OAI CN5G and COTS UE.
How to reproduce with Open5gs:
1. Start Open5gs
2. From the Open5gs web UI: add multiple QFIs to the same DNN.
3. Restart Open5gs
4. Run gNB and UE
The user will see the following:
1. QoS flows arrive via NGAP PDU Session Setup/Modify requests, each
with a QFI and 5QI.
2. The gNB assigns each flow to a DRB, creating a new DRB or reusing an
existing one based on 5QI compatibility (compatible flows, i.e. same
5QI characteristics, share a DRB)
3. At the SDAP layer, packets are tagged with QFI headers; at the GTP-U
layer, uplink packets include QFI in the PDU Session Container for
core network mapping.
Documentation
- Added comprehensive QoS flows handling documentation with 3GPP
standards references
- Updated PDU Session Modify sequence diagrams
Note
* This implementation aligns with:
- 3GPP TS 23.501 (QoS framework)
- 3GPP TS 38.413 (NGAP)
- 3GPP TS 37.324 (SDAP)
- 3GPP TS 38.463 (F1AP)
- 3GPP TS 29.281 (GTP-U)
- 3GPP TS 38.331 (RRC)
* Multi-QoS and PDU Session Modify are both added to this MR since QoS
flows update is triggered by PDU Session Modify in some scenarios
(e.g. with Open5gs, used for validation).
* Core functional changes introduced by commits with prefix "QoS
Handling" or "PDU Session Modify"
* This MR replaces the old !2703.
* This MR adopts relevant CU changes from !2836, namely:
* Adds new shared QoS types
* Add standardized 5QI table and helper
* Dynamic5QI support + validation
* Computation of DRB QoS (aggregate QoS) and priority/GBR
* F1AP DRB-level QoS
* Closes#541 (5QI validation)
* Closes#1075 (Optional NAS-PDU in PDU Session Setup Request)
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Reviewed-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
- new configuration for PLMN 00105, 40MHz and 100 MHz added on AmariUE
- helm charts for OC CN with PLMN 00105 added to cacofonix, new CN added
to ci_infra.yaml, IP address range of the new CN: 172.21.6.116-118
- test with 1 AmariUE (to be extended in future MR), with SISO
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Running container in privileged mode and host network mode is needed
for running fhi72 gNB with M-plane
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Running container in privileged mode and host network mode is needed
for running fhi72 gNB with M-plane
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
- Build and install libyang (v2.1.111) and libnetconf2 (v2.1.37) from source.
- Build ran-build-fhi72 image with M-plane enabled
- Copy YANG models required for M-plane operation into the container.
- Update gNB Dockerfile to work without M-plane
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
After attach, run UL ping so N3 UL traffic hits the UPF
before the first DL ping. That triggers UL PDR classification
in the UPF and avoids DL GTP-U using the default QFI.
Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
Expand the 25PRB RFSim CI scenario to validate two PDU sessions with
PCF-driven QoS rules and deterministic per-flow traffic ports. Update
iperf execution to use `-B`/`-p` from test args.
Changes:
- Update `container_5g_rfsim_u0_25prb.xml` to add dual-session
validation steps, routing setup, and multi-flow UDP iperf
for UL/DL with explicit bind/port arguments.
- Change `cls_oaicitest.py` to parse bind/port from
`iperf_args`, and return a clear error when the iperf client exits non-zero.
- Update `nrue.uicc.2pdu.conf` to configure
session 2 on `openairinterface` with distinct `nssai_sd` values.
- Extend `5g_rfsimulator/mini_nonrf_config.yaml`
with PCF endpoints, dual slices, dual DNN entries, and PCF policy paths,
and disable local PCC rules in SMF.
- Update `5g_rfsimulator_u0_25prb/docker-compose.yaml`
to add the `oai-pcf` service, mount policy directories, and add ext-dn
route for the second UE subnet.
- Add PCF policy data files for this scenario, in :
`policies/policy_decisions/policy_decision.yaml`
`policies/pcc_rules/pcc_rules.yaml`
`policies/qos_data/qos_data.yaml`
About the ci-scripts:
Co-authored-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
fix: issue 1054 - Config: Creating New Array members via command line arguments
Before this change, if you wanted to use --rfsimulator.[0].serveraddr
server on the command line but if you had no rfsimulator block in your
config file, it would just ignore it and print:
[CONFIG] unknown option: --rfsimulator.[0].serveraddr
[CONFIG] unknown option: server
This is because the config module only processes array members that
already exist in the config file. If the array is empty, the command
args are never checked.
What I changed is, in config_getlist() in config_userapi.c, after it
finishes processing existing array parameters, it checks whether a new
parameter is needed. If so, it matches with the list of parameters
first, then the highest index is found for that parameter using the
strtol,
"--rfsimulator.[0].serveraddr",
"--rfsimulator.[2].serveraddr",
What I changed is, in config_getlist() in config_userapi.c, after it
finishes processing existing array parameters, it checks whether a new
parameter is needed. If so, it matches with the list of parameters
first, then the highest index is found for that parameter using the
strtol,
"--rfsimulator.[0].serveraddr",
"--rfsimulator.[2].serveraddr",
"--rfsimulator.[4].serverport",
"--rfsimulator.[1].serveraddr",
It sets the index as 4, allocates 4 slots, memory is managed via
standard functions then it fills the gap of all the indices.
this closes#1054
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Reviewed-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
bit_len / 8 + 1 overcounts by 1 when bit_len is an exact multiple of 8.
Replace with (bit_len + 7) / 8 across all pack/unpack sites for PUSCH
and PUCCH 2/3/4 SR/HARQ/CSI payloads, and in the utility functions
(eq, copy, size calculator, dump) and unit test fill functions.
Fixes UCI.indication unpack failure against cuBB when CSI-1 report
is 8 bits.
Signed-off-by: Gabriele Gemmi <g.gemmi@northeastern.edu>
nr-cuup-load-test: avoid unaligned memory access
Use memcpy() instead of unaligned pointer access
tests/nr-cuup/nr-cuup-load-test.c:431:16: runtime error: store to misaligned address 0x756d02eca1a2 for type 'uint32_t', which requires 4 byte alignment
tests/nr-cuup/nr-cuup-load-test.c:267:14: runtime error: load of misaligned address 0x756d095edcf6 for type 'uint32_t', which requires 4 byte alignment
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Reviewed-by: Rakesh Mundlamuri <rakesh.mundlamuri@openairinterface.org>
Use memcpy() instead of unaligned pointer access
tests/nr-cuup/nr-cuup-load-test.c:431:16: runtime error: store to misaligned address 0x756d02eca1a2 for type 'uint32_t', which requires 4 byte alignment
tests/nr-cuup/nr-cuup-load-test.c:267:14: runtime error: load of misaligned address 0x756d095edcf6 for type 'uint32_t', which requires 4 byte alignment
Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
A RU can have multiple interfaces but for the M-plane purposes,
we need the ethernet interface.
Signed-off-by: Teodora Vladić <teodora.vladic@openairinterface.org>
Fix broken nr-cu-nrppa-test simulator and nr-ue-nas-simualtor
This MR fixes the simulators broken due to the changes from !3993 and
!4010. The changes were related to storing service network name in nas
and routing indicator in uicc
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Reviewed-by: Robert Schmidt <robert.schmidt@openairinterface.org>
Allow control signal level at input of OFDM modulator
This simple fix removes an error floor in nr_dlsim tests with 256QAM. It
adds -Q to nr_dlsim to control gNB TX amplitude (like tx_backoff_dB in
gNB RU section). With
./nr_dlsim -R273 -b273 -s30 -e27 -I10 -q1 -n100 -Q30
has 0 errors. The default in nr_dlsim remains -36 dBFs.
Signed-off-by: Jaroslava Fiedlerova <jaroslava.fiedlerova@openairinterface.org>
Reviewed-by: Robert Schmidt <robert.schmidt@openairinterface.org>