Add undocumented Aerial ERROR.indication vendor specific error codes
This MR adds the remaining vendor-specific ERROR.indication error codes
that are undocumented in the Aerial online documentation, but are
present in the cuPHY-CP/scfl2adapter/lib/scf_5g_fapi/scf_5g_fapi.h
header file.
This change stems from the appearance of an undocumented error code
during testing (SCF_ERROR_CODE_L1_MISSING_UL_IQ = 0x44) It aims to ease
the comprehension of the errors thrown by Aerial L1.
Extract common code from `fill_drb_to_be_setup_from_e1_resp` and
`rrc_fill_f1_drb_to_setup` into reusable helper functions to reduce
duplication and improve maintainability. This refactoring enables
multi-QoS flow handling per DRB and prepares helpers for upcoming
PDU Session Modify changes.
Impact:
- Enables multi-QoS flow support: `rrc_fill_f1_drb_to_setup` now
collects all QFIs mapped to a DRB instead of only the first one
- Reduces code duplication between E1 response and direct DRB setup
code paths
- Improves maintainability by centralizing F1 DRB setup logic
Major changes:
- Add `fill_f1_drb_info_nr`: fills DRB information IE including QoS
flows from QFI list
- Add `fill_f1_drb_to_be_setup`: creates F1 DRB to setup structure
from RRC DRB, PDU session, and QFI list
- Add `fill_f1_drbs_from_e1`: processes DRBs from E1 response and
extracts QFIs from drb_config->qosFlows
- Refactor `fill_drb_to_be_setup_from_e1_resp` to use
`fill_f1_drbs_from_e1`
- Refactor `rrc_fill_f1_drb_to_setup` to collect all QFIs mapped to
each DRB and use `fill_f1_drb_to_be_setup`
TS 38.413 8.2.3 PDU Session Modify:
> For each PDU session which failed to be modified, the PDU Session Resource Modify
> Unsuccessful Transfer IE shall be included containing the failure cause
> If the NG-RAN node receives a PDU SESSION RESOURCE MODIFY REQUEST message containing
> some PDU Session ID IEs (in the PDU Session Resource Modify Request List IE) that the
> NG-RAN node does not recognize, the NG-RAN node shall report the corresponding invalid
> PDU sessions as failed in the PDU SESSION RESOURCE MODIFY RESPONSE message
> with an appropriate cause value
Changes in the commit:
* add rrc_gNB_ngap_pdusession_mod_failure helper function to handle
abnormal conditions and send NGAP response with (all) failed PDU sessions
* improve error handling: send NGAP response instead of silently returning -1
when UE context lookup fails (unknown RAN UE NGAP ID)
* add AMF UE NGAP ID validation: check stored AMF UE NGAP ID matches request
and send failure response if mismatch (per 3GPP TS 38.413)
* handle unrecognized PDU Session IDs per 3GPP TS 38.413 8.2.3.4: add to
failed list to be sent in the reponse message
* simplify failure path: reuse rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP
instead of manually constructing response message
* remove failed PDU sessions from RRC list in rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP
* remove redundant code and improve code organization
* add bounds checking
* improve function signature
This commit refactors the rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP function
to improve code clarity, fix bugs, and ensure compliance with 3GPP TS 38.413
section 9.2.1.6.
The main improvement is ensuring the PDU Session Resource Modify Response message
is always sent with mandatory IEs, even when there are no PDU sessions to report
in the optional lists.
Key changes:
- Initialize message structure parameters to 0 by leveraging structure
initialization, ensuring clean state
- Replace local counter variables (pdu_sessions_done, pdu_sessions_failed)
with direct access to resp->nb_of_pdusessions and resp->nb_of_pdusessions_failed,
eliminating redundant state tracking and improving code clarity
- Remove conditional message sending: always send the response message
(per 3GPP TS 38.413 9.2.1.6, PDUSessionResourceModifyResponse must always
be sent with mandatory IEs: AMF-UE-NGAP-ID and RAN-UE-NGAP-ID, even when
optional lists are empty)
- Fix duplicate assignment: remove redundant p->pdusession_id assignment
(was assigned twice in the PDU_SESSION_STATUS_DONE case)
- Improve failed PDU session handling: use direct structure assignment
(failed->cause = session->cause) instead of field-by-field copying,
making the code more maintainable
- Remove failed PDU session upon response
- Enhance logging: improve log messages for better debugging and clarity
- Add function documentation comment
Introduce fill_e1_qos_flow_to_setup to translate pdusession_level_qos_parameter_t (NGAP)
into qos_flow_to_setup_t (E1), including ARP and QoS characteristics (dynamic/non-dynamic).
Refactor fill_e1_drb_to_setup to use the new helper for building QoS flows.
* Only include QoS flows whose drb_id matches the target DRB.
* Add DevAssert(drb_ngran.numQosFlow2Setup > 0) to ensure at least one QoS flow is added.
This change centralizes and simplifies QoS mapping logic between NGAP inputs
and E1 DRB configuration. It ensures correctness by associating QoS flows
to the appropriate DRB.
Major changes:
- Extract QoS flow mapping logic into fill_e1_qos_flow_to_setup helper function
- Filter QoS flows by matching drb_id before adding to DRB setup list
- Replace inline mapping code with helper function call
- Add assertion to verify at least one QoS flow is added per DRB
This commit fixes two related issues:
1. SDAP Header Mapping Bug (cucp_cuup_handler.c):
The original code incorrectly mapped SDAP header configuration from
internal E1AP representation to ASN.1 enum values. The internal
representation (`bearer_context_sdap_config_t`) uses true=present/false=absent,
while ASN.1 enum (`E1AP_SDAP_Configuration_t`) uses
0=present/1=absent. The fix correctly inverts the mapping:
- Internal true (1) → ASN.1 0 (present)
- Internal false (0) → ASN.1 1 (absent)
The commit also clarifies internal representation in the stack.
2. Test Overhead Adjustment (nr-cuup-load-test.c):
The change in (1) led to a failure in nr_cuup_functional_test
with assertion: "size % 4 == 0" in recv_ng()
- Changed UL packet overhead from 3 bytes to 2 bytes in sender_thread()
- Before the SDAP fix, the test incorrectly accounted for 3 bytes:
* 2 bytes PDCP header (correct)
* 1 byte SDAP header (incorrectly included)
- After the SDAP fix, SDAP headers are correctly set to absent, so
only 2 bytes (PDCP header) are needed
This ensures the test sends packets with the correct header size,
matching what CU-UP expects after the SDAP configuration fix.
The load test does not enable SDAP headers, therefore the original 3-byte
overhead was possibly a workaround for the SDAP header bug.
With the bug fixed, the test correctly uses 2-byte overhead (PDCP header).
This commit refactors the PDU Session Resource Modify Response message
structures to improve naming, documentation, and compliance with 3GPP TS 38.413 9.2.1.6.
Changes in NGAP:
- Rename qos_flow_tobe_modified_t to qos_flow_addmod_response_item_t to better
reflect its purpose as a QoS Flow Add or Modify Response Item IE (as per specs)
- Add mandatory AMF UE NGAP ID field to ngap_pdusession_modify_resp_t structure
- Optimize field types: change nb_of_pdusessions and nb_of_pdusessions_failed
from uint16_t to uint8_t (NGAP_MAX_PDU_SESSION limit) (ref 3GPP TS 38.413, 9.2.1.6)
- Update PDU Session Modify Response encoder to use amf_ue_ngap_id from the
message structure (pdusession_modify_resp_p->amf_ue_ngap_id) instead of
retrieving it from UE context (ue_context_p->amf_ue_ngap_id)
- Add comprehensive comments with 3GPP TS 38.413 section references throughout
Changes in RRC/NGAP:
- Populate amf_ue_ngap_id field in PDU Session Modify Response message from
UE context
- Update type reference to qos_flow_addmod_response_item_t
A DRB To Modify Item contains a Flow Mapping Information,
which overrides previous mapping information. For consistency,
rename the count member to reflect a QoS Flow modification,
since it is not limited to setup only.
- Rename DRB flow mapping counters to `numQosFlowsMod`
for a DRB To Modify List
- Adjust encode/decode/equality + E1AP tests
Add DRB To Remove List IE to PDU Session To Modify list, which is sent
in the Bearer Context Modification request. This allows the CUCP to
inform the CUUP about DRBs to be released in a specific PDU session
during a MODIFY procedure.
Changes:
* Add struct definition
* Add enc/dec/eq/cp func
* Add test
- Delete drbs field from gNB_RrcConfigurationReq and its use in RCconfig_NRRRC()
- Remove GNB_CONFIG_STRING_DRBS, help text, index, and GNBPARAMS_CHECK entry from gnb_paramdef.h
- Drop DU-side verification and DRB count logging in gnb_config.c
This commit introduces a new, configurable benchmark,
`test_channel_scalability`, designed to measure the performance and
scalability of the CUDA channel simulation pipeline under various
conditions.
This benchmark provides several key features:
- It supports multiple GPU execution models, including a high-throughput
"batch" mode, an asynchronous "stream" mode, and a "serial" mode for
baseline measurements.
- It includes an optional interference simulation mode, activated by the
`--sum-outputs` flag, which sums the outputs of multiple parallel
channels.
- Simulation parameters (MIMO configuration, signal length,
channel length, and batch size) are configurable via command-line
arguments.
- It runs the full simulation pipeline on both the CPU and the GPU,
reporting the average execution time for each and calculating the
overall speedup.
This commit extends the CUDA API with new functions designed for
high-throughput scalability testing and advanced concurrency.
Key additions include:
- Batched versions of the kernels (`..._batched`) that use the
`blockIdx.z` grid dimension to process many independent channel
simulations in parallel.
- A C-callable wrapper, `run_channel_pipeline_cuda_batched`, to
orchestrate the execution of these new kernels.
- A "streamed" version of the pipeline,
`run_channel_pipeline_cuda_streamed`, which accepts a
`cudaStream_t` as an argument. This allows the calling
application to manage the execution stream, enabling overlap
with other GPU or CPU tasks.
This commit adds a performance benchmark for the end-to-end channel simulation pipeline, named `test_channel_simulation`. Its methodology is as follows:
- It systematically iterates through a matrix of test cases, varying
MIMO configuration (Tx/Rx antennas), signal length, and channel
length.
- For each case, it runs both the full CPU pipeline (`multipath_channel_float`
followed by `add_noise_float`) and the single `run_channel_pipeline_cuda`
function.
- It measures the average execution time for both implementations over
many trials and calculates the resulting speedup.
This provides a performance characterization of the GPU pipeline across different workloads and directly compares it to the CPU baseline.
This commit introduces the main C-callable pipeline function,
`run_channel_pipeline_cuda`, located in a new `channel_pipeline.cu`
file.
This function serves as the primary entry point for the GPU channel
simulation. It orchestrates the entire sequence of operations:
- Manages Host-to-Device data transfers for the input signal and
channel coefficients.
- Launches the `multipath_channel_kernel` and the
`add_noise_and_phase_noise_kernel` in the correct order.
- Manages the Device-to-Host data transfer for the final output signal.
- Synchronizes to ensure completion before returning.
This commit adds a new standalone benchmark, `test_noise`, to measure
and compare the performance of the CPU and CUDA implementations of noise
generation.
The benchmark's methodology is as follows:
- It iterates through various configurations, including different
numbers of receive antennas and signal lengths.
- For each configuration, it runs both the CPU (`add_noise_float`)
and CUDA (`add_noise_cuda`) functions multiple times to get a stable
average execution time.
- It prints a formatted table comparing the CPU and GPU latencies and
calculates the resulting speedup.
This commit adds the CUDA implementation for adding Additive White
Gaussian Noise (AWGN) and phase noise to the signal. The code is
located in phase_noise.cu.
- The `add_noise_and_phase_noise_kernel` uses the NVIDIA cuRAND
library for efficient parallel random number generation.
- Helper functions are included to create, initialize, and destroy
the cuRAND states required by the kernel.
- Placeholder for a C-callable wrapper, `add_noise_cuda`, is also
provided.
This commit adds a new standalone unit test, `test_multipath`, to
validate the CUDA implementation of the multipath channel.
The test performs the following steps:
- Generates a random input signal and channel model.
- Runs the CPU version (`multipath_channel_float`) to get a baseline result.
- Runs the CUDA version (`multipath_channel_cuda`) with the same inputs.
- Compares the two outputs by calculating the Mean Squared Error (MSE)
and ensures it is below a small tolerance.
This commit introduces the CUDA implementation of the multipath channel
model in `multipath_channel.cu`.
- Implements `multipath_channel_kernel` using shared memory for
efficient, high-performance convolution.
- Provides a C-callable wrapper, `multipath_channel_cuda`, to
orchestrate the full pipeline of data transfers and kernel
launches.
- The wrapper includes support for multiple memory models (Explicit
Copy, Unified Memory, ATS) via preprocessor directives to adapt to
different build configurations.
- Adds a `interleave_channel_output_cuda` utility to convert signal
data from the CPU's planar format to the GPU's interleaved format.
This commit refactors the CPU-based channel model for improved reusability and extends it with single-precision floating-point support.
This serves as a performance and correctness baseline for the new CUDA implementation.
Key changes include:
- The original double-based multipath_channel function is refactored to remove hardcoded antenna dimensions from its signature. It now accepts dynamically sized arrays, making it more flexible for use in simulators like dlsim and ulsim.
- A new multipath_channel_float function is introduced to operate on float data types, matching the GPU's native format.
- A corresponding add_noise_float function is also added to complete the floating-point CPU pipeline.
- The new float-based functions are designed to work with an interleaved IQ sample format ([I, Q, I, Q]), which is more suitable for vectorized (SSE) and GPU processing.
This commit adds the initial infrastructure for building accelerated simulation components.
- Adds the CUDA_ENABLE option and logic to find the CUDA toolkit.
- Adds the CHANNEL_SSE option to enable SSE-specific code paths.
- Sets required properties on the SIMU target to allow linking with CUDA-compiled objects.
- Creates the initial oai_cuda.h header for the public API.
Integration `2026.w06`
* !3690 [FHI72] Support large DU delay profiles in the xran F, and include ProtO-RU emulator designed to run 7.2 with an USRP
* !3887 Update RHEL UBI image source to `registry.redhat.io`
* !3882 Change Aerial to pack directly in nvIPC message buffer
* !3895 CI: Ensure OAI-FLEXRIC-RAN-Integration-Test pipeline always uses latest commit for non-MR builds
* !3873 Ensure noise power is non-zero
* !3889 Enable imscope for split7.2
* !3801 Resolve "7.2 split ru_thread slot miss
* !3898 Fix config_libconfig_get for string
* !3876 Removing the duplicate loop in ULSCH power computation
Closes#972
See merge request oai/openairinterface5g!3888
Removing the duplicate loop in ULSCH power computation
- Removing the duplicate loop in ULSCH power computation.
- The logs obtained are as follows:
[NR_MAC] UE dc65: 134.11 Generating RA-Msg2 DCI, RA RNTI 0x113, state 1, preamble_index(RAPID) 42, timing_offset = 5 (estimated distance 195.3 [m])
[PHY] PUSCH not detected in 134.17 (307,302,50)
[PHY] PUSCH not detected in 134.17 (311,309,50)
[NR_MAC] 135 4: RA RNTI 41c5 CC_id 0 Scheduling retransmission of Msg3 in (135,8)
[NR_MAC] 135 4: RA RNTI a3cc CC_id 0 Scheduling retransmission of Msg3 in (135,8)
[PHY] PUSCH not detected in 134.18 (310,312,50)
[NR_MAC] 135 5: RA RNTI dc65 CC_id 0 Scheduling retransmission of Msg3 in (135,9)
[PHY] PUSCH not detected in 135.8 (309,309,50)
[PHY] PUSCH not detected in 135.8 (313,308,50)
[NR_MAC] 13515: RA RNTI 41c5 CC_id 0 Scheduling retransmission of Msg3 in (135,19)
[NR_MAC] 13515: RA RNTI a3cc CC_id 0 Scheduling retransmission of Msg3 in (135,19)
[PHY] PUSCH not detected in 135.9 (308,300,50)
[NR_MAC] 136 4: RA RNTI dc65 CC_id 0 Scheduling retransmission of Msg3 in (136,8)
[NR_PHY] [RAPROC] 135.19 Initiating RA procedure with preamble 6, energy 19.1 dB (I0 63, thres 120), delay 4 start symbol 0 freq index 0
[PHY] PUSCH not detected in 135.19 (310,310,50)
[PHY] PUSCH not detected in 135.19 (312,310,50)
[NR_MAC] 135.19 UE RA-RNTI 010b TC-RNTI 0888: initiating RA procedure
[NR_MAC] UE 0888: Sync beam index 0
[NR_MAC] UE 0888: Msg3 scheduled at 136.17 (136.10 TDA 2) start 0 RBs 8
[NR_MAC] UE 0888: 136.10 Generating RA-Msg2 DCI, RA RNTI 0x10b, state 1, preamble_index(RAPID) 6, timing_offset = 4 (estimated distance 156.3 [m])
- For the same scenario, develop branch gives exactly the same result. When
there is no PUSCH, the power measured for ULSCH and noise are practically
the same. Furthermore, the value in develop branch is also approximately
310 for the same noise level.
Expand RRC developer and usage documentation to match the current
multi-cell design with separate DU and cell management.
- rrc-dev.md: Document DU and cell data structures and key functions
(get_du_by_assoc_id, get_cell_by_cell_id, rrc_add_cell_to_du, etc.);
add DU and cell lifecycle (F1 Setup, config update, disconnection)
and UE cell association (serving cells, PCell/SCells) with sequence
diagrams; add handover and cell association update flow; update UE
context description.
- rrc-usage.md: Update DU/cell list output format and description
(e.g. integrated DU-CU) and multi-cell per DU wording.
This commit adds documentation comments and logging to improve
code readability and debugging capabilities for the multi-cell
architecture.
Changes:
- gnb_config.c: Add logging when configuring DU with cell ID and PCI
- rrc_gNB_du.c: Add documentation comment for ssb_arfcn_mtc()
- rrc_gNB_du.c: Add documentation comment for dump_du_info()
After introduction of new cell management design, these helper functions
are now only used internally within their respective modules and do not
need to be part of the public API. They are made static and their
declarations are removed from public headers.
Changes:
- f1ap_interface_management.c: Make free_f1ap_cell() and
copy_f1ap_served_cell_info() static
- f1ap_interface_management.h: Remove declarations for the above functions
- rrc_gNB_du.c: Make get_dl_band() and get_ssb_scs() static
- rrc_gNB_du.h: Remove declarations for get_dl_band() and get_ssb_scs()
Remove the single-cell limit in F1 Setup Request processing and
refactor to loop-based cell handling. Move cell validation (PLMN
check, neighbor configuration validation, system info extraction),
cell creation, SIB encoding, and neighbor labeling inside a loop
over all available cells.
Update F1 Setup Response to include all cells instead of hardcoding to 1.
Add warning log when more than one cell is received. Add proper
cleanup with free_f1ap_setup_response() on error paths.
Impact:
- F1 Setup now accepts and processes multiple cells from a single
DU, enabling multi-cell deployments
- All cells are validated, created, and included in the setup
response
Add xran_queue_length atomic variable to count the number of messages in
oran_sync_fifo (as notifiedFIFO_t does not do this). Use this to
tolerate some double messages (e.g. excessive processing delay), but
start to skip if messages accumulate.
Prior to this change, "Detected double sync message" was printed each
time there was more than one message, which reflected the previous
behavior when using polling, but the gNB might catch up if it is only
once. The new logic ensure that we don't skip individual slots but do so
once messages start to accumulate.
Finalize the migration from single-cell-per-DU to the multi-cell
architecture: remove legacy DU/cell fields and refactor RRC procedures
to use cell containers and UE serving cells instead of DU-based lookups.
Data structure changes:
- Remove nr_cellid from gNB_RRC_UE_t; cell identity comes from the UE's
serving_cells (PCell entry via ue_get_pcell_entry(ue)). UE_LOG_ARGS
and LOG_UE_* macros take a PCell entry pointer for null-safe cell_id
in logs; all call sites pass ue_get_pcell_entry(ue).
- Remove setup_req, mib, sib1, mtc from nr_rrc_du_container_t (held in
cell containers); remove nr_cellid from gNB_RRC_INST and its
assignment in gnb_config.c.
Function and signature updates:
- get_ssb_arfcn(): take cell container instead of DU.
- label_intra_frequency_neighbours(): drop du parameter, use cell only.
- Handover: Handover context (source and target) now stores cell
pointers (source->cell, target->cell) instead of DU pointers. When
the context is created (N2: on Handover Request; F1: in
nr_rrc_trigger_f1_ho), the target cell is set in ho_context->target->cell
and, for F1, the source cell in ho_context->source->cell.
nr_initiate_handover() takes only source_cell and reads the target
from ho_ctx->target->cell, so it no longer takes a target parameter.
The target is known at handover creation time, while the UE’s
serving_cells are only updated after F1 UE Context Setup Response.
- nr_rrc_trigger_f1_ho() and the N2 handover path pass cell pointers
and set ho_context->target->cell (and for F1, source->cell) when
the handover is triggered.
Procedure refactoring:
- Lookups: replace get_du_by_cell_id() with get_cell_by_cell_id()/
get_cell_by_pci(); remove get_du_by_cell_id() and
get_cell_information_by_phycellId().
Rationale: cell-specific data (MIB, SIB1, mtc, info) now lives in
cell containers, and a DU can host multiple cells. Callers need the
cell (to use cell->info, cell->mtc, etc.), not the DU. Looking up
by cell_id therefore returns the cell container
(get_cell_by_cell_id()); when the DU is needed, use
cell->assoc_id and get_du_by_assoc_id(). Looking up by PCI is
scoped (e.g. get_cell_by_pci_for_du() for a given DU, or via the
UE’s serving cells) because PCI is not globally unique.
- Setup/Reestablishment: resolve cell, register as PCell via
rrc_add_ue_serving_cell(); reestablishment resolves cell by PCI
(rrc_get_cell_by_pci_for_du), then rrc_remove_ue_scells_from_du +
rrc_add_ue_serving_cell; validate_ue_cell_association() after update.
- Measurement config: use cell->info (SCS/band) and cell->mtc.
- Handover: use cell containers end-to-end; after UE context
modification response call nr_rrc_update_cell_assoc_after_ho().
- NGAP: cell_id and TAC from UE PCell via rrc_get_pcell_for_ue();
Handover Notify: get cell for message content, use get_du_for_ue() for
DU existence check; paging resolves UE by 5G-S-TMSI-Part1 and uses that
UE's PCell (rrc_get_pcell_for_ue) for F1AP_PAGING_IND nr_cellid.
Performance and robustness:
- Use rrc_get_pcell_for_ue() when cell data is needed; use
get_du_for_ue() when only the DU is needed (F1/N2 HO trigger,
Handover Notify DU check) for efficiency.
- Reestablishment: remove old PCell before adding new; error handling
for PCell add and validation.
Code cleanup:
- F1 setup: stop copying/storing setup request in DU container; F1
disconnect only frees cell containers via rrc_free_cell_container().
- dump_du_info(): iterate du->cells and show all cells per DU.
- telnetsrv_ci.c: use du->gNB_DU_id directly and fix format (%ld).
- UeContextSetupRequest servCellIndex set to RRC_PCELL_INDEX; remove
servCellIndex from F1AP UE context modification request.
In rrc_gNB_NGAP.c, rrc_gNB_process_Handover_Request() is updated to
resolve the target by cell instead of by DU, then resolve the DU from
the cell's assoc_id. This aligns Handover Request with the new
cell-centric model and cell management APIs.
- Resolve target with get_cell_by_cell_id(&rrc->cells, msg->nr_cell_id)
instead of get_du_by_cell_id(); on failure, log "no cell found" and
send NGAP handover failure.
- Resolve DU with get_du_by_assoc_id(rrc, cell->assoc_id); add a
failure path (log, NGAP handover failure, return -1) when no DU
exists for the cell's assoc_id.
- Use cell->info (nr_rrc_cell_info_t) for logging and for key
derivation (nr_derive_key_ng_ran_star); use du->assoc_id
for UE context creation instead of du->setup_req->cell[0].info.
get_ssb_arfcn(du) is unchanged and still takes the DU; other DU-based
lookups are kept where still required.
Migrate F1 DU configuration update procedures in openair2/RRC/NR/rrc_gNB_du.c
to use the cell management API instead of accessing cell data through
setup_req, completing the transition to the new multi-cell architecture.
1. update_cell_info:
- Refactored to use cell management API: takes RRC instance, old cell_id,
and new cell info; finds cell via get_cell_by_cell_id() internally.
- Returns cell container pointer (or NULL on failure) instead of void.
- When cell_id changes: removes cell from RB tree (old key), updates via
cp_f1_served_cell_info_to_cell(), re-inserts (new key); validates no
duplicate cell_id/PCI before allowing change.
- Frees old MTC when new measurement timing config is present.
- Encapsulates cell lookup and update logic.
2. rrc_gNB_process_f1_du_configuration_update:
- Uses update_cell_info() for cell modify; validates cell belongs to DU
(assoc_id) after update.
- Duplicate checking via get_cell_by_cell_id() and
rrc_get_cell_by_pci_for_du()
- For cells to add: validates duplicate cell_id globally and duplicate
PCI within DU; rejects with logging.
- MIB/SIB1 updated in cell container (cell->mib, cell->sib1); uses
du->gNB_DU_id; passes cell to label_intra_frequency_neighbours();
removes direct setup_req->cell[0] access.
Backward compatibility: setup_req remains until migration is completed;
cell-specific data is managed in the cell container and accessed via
the cell management API. Improves separation of concerns and enables
proper multi-cell support.
Refactor F1 setup processing to create and manage cell containers during DU
initialization, establishing the foundation for multi-cell architecture where
cells are managed independently from DUs.
Why: Cell information is currently tied to F1AP structures (f1ap_served_cell_info_t),
which complicates multi-cell support. Introducing cell containers at F1 setup
decouples RRC cell management from F1AP and allows cells to be managed
independently while keeping existing code paths working.
Key changes:
1. Cell container creation (cp_f1_served_cell_info_to_cell):
New helper copying F1AP served cell info into nr_rrc_cell_container_t (cell_id,
pci, plmn, tac, TDD/FDD frequency info). Extracts and stores MTC in the cell.
2. Function signature updates:
get_cell_neighbour_list() and label_intra_frequency_neighbours() now take
nr_rrc_cell_container_t* and use cell->info; improved logging (cell_id, PCI,
SSB ARFCN).
3. valid_du_in_neighbour_configs:
Removed ssb_arfcn parameter; MTC is extracted and freed inside the function.
4. F1 Setup (rrc_gNB_process_f1_setup_req):
Initialize DU cell tree (RB_INIT(&du->cells)). Populate DU-only fields
(gNB_DU_id, gNB_DU_name, rrc_ver).
Flow:
- create cell with cp_f1_served_cell_info_to_cell
- add to global tree via rrc_add_cell()
- add DU via rrc_add_du()
- attach cell to DU with rrc_add_cell_to_du().
Store MIB/SIB1/MTC in cell.
Use cell container for neighbour labeling and SIB encoding.
5. Duplicate cell detection:
Use rrc_add_cell() for global cell tree insert; collision return indicates
duplicate cell_id. Clearer error messages for Cell ID vs PCI conflicts.
Use F1AP_CauseRadioNetwork_cell_not_available for cell conflicts.
6. DU configuration update:
Use get_cell_by_cell_id() to find cell, check assoc_id, pass cell container
to label_intra_frequency_neighbours().
7. DU disconnection:
Use rrc_cleanup_du() to remove cells from global tree and free resources;
logging uses DU fields (gNB_DU_id, gNB_DU_name).
8. Global cell tree:
Initialize rrc->cells in openair_rrc_gNB_configuration().
Backward compatibility: setup_req still built via cp_f1ap_setup_request();
du->mib, du->sib1, du->mtc remain set (shared with cell container).
Add integration tests for RRC cell and DU management and UE serving-cell
logic so that multi-cell behaviour and regressions can be validated
without running the full stack.
* test_du_lookup() – DU container lookup by assoc_id:
- Multiple DU creation and insertion into RRC DU tree
- Lookup of existing DUs by assoc_id
- Non-existing and invalid assoc_ids
- Cleanup of DU containers and cells
* test_cell_lookup() – Cell management and UE association:
- Cell lookup by cell_id and PCI (global and per-DU)
- DU-specific lookup: rrc_get_cell_for_du(), rrc_get_cell_by_pci_for_du()
- Duplicate cell and PCI collision handling (including PCI reuse across
DUs and rejection of duplicate PCI within same DU)
- Cell–DU association (add/remove cells from DU containers)
- UE serving cell: add PCell/SCells, get by ID, get PCell, max serving
cells limit, single PCell enforcement
- validate_ue_cell_association(), rrc_remove_ue_scells_from_du()
- Edge cases and error handling
Add openair2/RRC/NR/tests/rrc_cell_management_test.c and extend
openair2/RRC/NR/tests/CMakeLists.txt to build and register the test.
Add functions to manage UE serving cells so the RRC can track which cells
a UE is using (PCell and SCells) for multi-cell UE context and future
SCell management.
- rrc_cell_management.c / rrc_cell_management.h:
* rrc_get_ue_serving_cell_by_id(): return serving cell by servCellIndex
(O(k) linear search, k ≤ 32).
* rrc_add_ue_serving_cell(ue, cell, serving_cell_id): add entry to UE
serving_cells with validation: reject duplicate servCellIndex with
different nci, enforce max 32 serving cells (TS 38.331), keep PCell
at index 0 for O(1) access; return existing entry if same
servCellIndex and nci.
* rrc_remove_ue_scells_from_du(ue, assoc_id): remove all serving cells
for the given DU (handover/DU disconnect); use stored assoc_id for
O(k) comparison.
* ue_get_pcell_entry(): return PCell entry (first element, O(1)).
* rrc_get_pcell_for_ue(): return PCell container from cell tree using
UE's PCell entry.
* Header: RRC_PCELL_INDEX (0), RRC_MAX_NUM_SERVING_CELLS (32), and
declarations for the above.
- UE context lifecycle:
* rrc_gNB_create_ue_context(): seq_arr_init(serving_cells).
* rrc_delete_ue_data(): seq_arr_free(serving_cells).
Move DU tree management from rrc_gNB_du.c into rrc_cell_management so that
DU and cell lookup logic live in one place, improving maintainability and
testability (there is no DU lib).
- rrc_cell_management: add du_compare(), RB_GENERATE(rrc_du_tree),
get_du_by_assoc_id(), rrc_add_du(), rrc_rm_du(), rrc_cleanup_du(),
rrc_free_du_container(); declare them in rrc_cell_management.h.
- rrc_gNB_du: move du_compare(), RB_GENERATE, get_du_by_assoc_id()
to rrc_cell_management