From c36a6bcb477a8276dbe48ef3bd4eebf7996a6583 Mon Sep 17 00:00:00 2001 From: Mario Joa-Ng Date: Thu, 17 Jul 2025 23:04:14 +0200 Subject: [PATCH 01/61] Fix the bug in calculating fh_config->neAxc where num_beams_period is multiplified twice. --- radio/fhi_72/oran-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 89c1838fa3..684d44e7cf 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -918,7 +918,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->dpdk_port = ru_idx; // DPDK port number used for FH fh_config->sector_id = 0; // Band sector ID for FH; not used in xran fh_config->nCC = 1; // number of Component carriers supported on FH; M-plane info - fh_config->neAxc = RTE_MAX(oai0->num_distributed_ru * oai0->tx_num_channels / num_rus, oai0->num_distributed_ru * oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) + fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B fh_config->nDLFftSize = 0; // DL FFT size; not used in xran From 4eb9dd3d3829b9baf40d89fee15b0ec74c500da3 Mon Sep 17 00:00:00 2001 From: Mario Joa-Ng Date: Wed, 13 Aug 2025 15:50:38 +0200 Subject: [PATCH 02/61] set beam_id to -1 instead of 0. --- openair1/PHY/INIT/nr_init.c | 6 ++++-- openair1/PHY/INIT/nr_init_ru.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 60bc63dac4..778903be91 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -175,8 +175,10 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) if (cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) { common_vars->beam_id = (int **)malloc16(common_vars->num_beams_period * sizeof(int*)); - for (int i = 0; i < common_vars->num_beams_period; i++) - common_vars->beam_id[i] = (int*)malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + for (int i = 0; i < common_vars->num_beams_period; i++) { + common_vars->beam_id[i] = (int*)malloc16(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + memset(common_vars->beam_id[i], -1, fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + } } common_vars->txdataF = (c16_t ***)malloc16(common_vars->num_beams_period * sizeof(c16_t**)); for (int i = 0; i < common_vars->num_beams_period; i++) { diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index a0766c348f..ca753938a6 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -53,8 +53,10 @@ void nr_phy_init_RU(RU_t *ru) int nb_rx_streams = ru->nb_rx * ru->num_beams_period; LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period); ru->common.beam_id = malloc16_clear(ru->num_beams_period * sizeof(int*)); - for(int i = 0; i < ru->num_beams_period; i++) - ru->common.beam_id[i] = malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + for(int i = 0; i < ru->num_beams_period; i++) { + ru->common.beam_id[i] = malloc16(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + memset(ru->common.beam_id[i], -1, fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); + } if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals // Time-domain signals From e4f7443552fa6da3d04acb7df4ef7b215f832997 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 16 Oct 2025 16:11:55 +0200 Subject: [PATCH 03/61] =?UTF-8?q?Initialize=20NCC=3D0=20on=20NGAP=20Initia?= =?UTF-8?q?l=20Context=20Setup=20per=203GPP=20TS=2033.501=20=C2=A76.9.2.1.?= =?UTF-8?q?1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused kgnb_ncc: nh_ncc is already there Closes #1008 --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 3 +-- openair2/RRC/NR/rrc_gNB_NGAP.c | 4 +++- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6b65ecd263..2d92cb9630 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1025,7 +1025,7 @@ int do_RRCReestablishment(int8_t nh_ncc, uint8_t *const buffer, size_t buffer_si rrcReestablishment->criticalExtensions.choice.rrcReestablishment = CALLOC(1, sizeof(NR_RRCReestablishment_IEs_t)); // 3GPP TS 33.501 Section 6.11 Security handling for RRC connection re-establishment procedure - rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nextHopChainingCount = nh_ncc >= 0 ? nh_ncc : 0; + rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nextHopChainingCount = nh_ncc; rrcReestablishment->criticalExtensions.choice.rrcReestablishment->lateNonCriticalExtension = NULL; rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nonCriticalExtension = NULL; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index e76802338c..a52d5537c0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -188,7 +188,6 @@ typedef struct gNB_RRC_UE_s { /* KgNB as derived from KASME received from EPC */ uint8_t kgnb[32]; - int8_t kgnb_ncc; uint8_t nh[32]; int8_t nh_ncc; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c2734c755a..97d0feda67 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -998,8 +998,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; uint32_t ssb_arfcn = get_ssb_arfcn(du); LOG_I(NR_RRC, "Reestablishment update key pci=%d, earfcn_dl=%u\n", cell_info->nr_pci, ssb_arfcn); - nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, ue_p->nh_ncc >= 0 ? ue_p->nh : ue_p->kgnb, ue_p->kgnb); - ue_p->kgnb_ncc = 0; + nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, ue_p->nh_ncc > 0 ? ue_p->nh : ue_p->kgnb, ue_p->kgnb); int size = do_RRCReestablishment(ue_context_pP->ue_context.nh_ncc, buffer, NR_RRC_BUF_SIZE, xid); LOG_A(NR_RRC, "Send RRCReestablishment [%d bytes] to RNTI %04x\n", size, ue_p->rnti); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7d75384a9b..59cc242e28 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -122,7 +122,9 @@ static void set_UE_security_key(gNB_RRC_UE_t *UE, uint8_t *security_key_pP) /* Saves the security key */ memcpy(UE->kgnb, security_key_pP, SECURITY_KEY_LENGTH); memset(UE->nh, 0, SECURITY_KEY_LENGTH); - UE->nh_ncc = -1; + /* 3GPP TS 33.501 ยง6.9.2.1.1: On Initial Context Setup, AMF does not send NH; + * gNB shall initialize NCC to 0. */ + UE->nh_ncc = 0; char ascii_buffer[65]; for (i = 0; i < 32; i++) { From b0ab5e8795a53c39cba72c1ed68a59fc953b9756 Mon Sep 17 00:00:00 2001 From: Shubhika Garg Date: Fri, 17 Oct 2025 09:53:29 +0200 Subject: [PATCH 04/61] ci: Ensure DockerHub push failure doesn't halt pipeline - catchError will prevent from abruptly aborting the entire pipeline upon failure. - Removed redundant `currentBuild.result` in post-failure block --- ci-scripts/Jenkinsfile-GitLab-Container | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index 3301c133ec..a2bb8112fc 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -271,14 +271,15 @@ pipeline { when { expression {doBuild && "PUSH".equals(env.gitlabActionType)} } steps { script { - triggerSlaveJob ('RAN-DockerHub-Push', 'DockerHub-Push') + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + triggerSlaveJob ('RAN-DockerHub-Push', 'DockerHub-Push') + } } } post { failure { script { echo "Push to Docker-Hub KO" - currentBuild.result = 'FAILURE' failingStages += '\n * RAN-DockerHub-Push' } } From d0089369d3c0fc1d7b1976a277f27fa0f8af4e1a Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Fri, 17 Oct 2025 10:59:49 +0200 Subject: [PATCH 05/61] CI: adjust TDD pattern in SA-B200 40 MHz TDD test --- .../conf_files/gnb-du.sa.band78.106prb.usrpb200.conf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf index e4d9127284..23475e3838 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf @@ -135,11 +135,11 @@ gNBs = # 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; + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 3; + nrofDownlinkSymbols = 10; + nrofUplinkSlots = 1; + nrofUplinkSymbols = 2; ssPBCH_BlockPower = -25; } From 8424c8ecb6a44c9692ca8d0622bfb37381a8172f Mon Sep 17 00:00:00 2001 From: alexjiao Date: Fri, 17 Oct 2025 16:21:09 +0800 Subject: [PATCH 06/61] Fix crashes for T-Tracer to work with NR-UE 1. Fix UE_PHY_PDSCH_IQ event 2. Fix UE_PHY_PDCCH_ENERGY event 3. Fix UE_PHY_PDSCH_ENERGY event 4. Fix UE_PHY_MEAS event All fixes align NR UE events with their definitions in T_messages.txt and match the expected format in the tracer GUI parser. --- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 9 ++++++++- .../PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 16 +++++++++++----- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 4 ++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 43b27e3932..10cfa121a7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -372,7 +372,14 @@ void nr_rx_pdcch(PHY_VARS_NR_UE *ue, LOG_D(NR_PHY_DCI, "slot %d: pdcch log2_maxh = %d (%d,%d)\n", proc->nr_slot_rx, log2_maxh, avgP[0], avgs); #endif #if T_TRACER - T(T_UE_PHY_PDCCH_ENERGY, T_INT(0), T_INT(0), T_INT(proc->frame_rx % 1024), T_INT(proc->nr_slot_rx), T_INT(avgs)); + T(T_UE_PHY_PDCCH_ENERGY, + T_INT(0), + T_INT(proc->frame_rx % 1024), + T_INT(proc->nr_slot_rx), + T_INT(avg[0]), + T_INT(antRx > 1 ? avg[1] : 0), + T_INT(antRx > 2 ? avg[2] : 0), + T_INT(antRx > 3 ? avg[3] : 0)); #endif LOG_D(NR_PHY_DCI, "we enter nr_pdcch_channel_compensation(log2_maxh=%d)\n", log2_maxh); LOG_D(NR_PHY_DCI, "in nr_pdcch_channel_compensation(rxdataF_ext x dl_ch_estimates_ext -> rxdataF_comp)\n"); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 5e677b542b..ab73bedb4f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -540,6 +540,16 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } *log2_maxh = (log2_approx(avgs) / 2) + 1; LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, *log2_maxh, avgs); +#if T_TRACER + T(T_UE_PHY_PDSCH_ENERGY, + T_INT(gNB_id), + T_INT(frame % 1024), + T_INT(nr_slot_rx), + T_INT(avg[0]), // layer 0, antenna 0 + T_INT(n_rx > 1 ? avg[1] : 0), // layer 0, antenna 1 + T_INT(nl > 1 ? avg[n_rx] : 0), // layer 1, antenna 0 + T_INT(nl > 1 && n_rx > 1 ? avg[n_rx + 1] : 0)); // layer 1, antenna 1 +#endif } stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS); if (meas_enabled) { @@ -552,9 +562,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, first_symbol_flag, ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_LEVEL_STATS].p_time / (cpuf * 1000.0)); } -#if T_TRACER - T(T_UE_PHY_PDSCH_ENERGY, T_INT(gNB_id), T_INT(0), T_INT(frame % 1024), T_INT(nr_slot_rx)); -#endif //---------------------------------------------------------- //--------------------- channel compensation --------------- @@ -746,13 +753,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, #if T_TRACER T(T_UE_PHY_PDSCH_IQ, T_INT(gNB_id), - T_INT(ue->Mod_id), T_INT(frame % 1024), T_INT(nr_slot_rx), T_INT(nb_rb_pdsch), T_INT(fp->N_RB_UL), T_INT(fp->symbols_per_slot), - T_BUFFER(&rxdataF_comp[gNB_id][0], 2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ fp->N_RB_UL * 12 * 2)); + T_BUFFER(&rxdataF_comp[gNB_id][0], 2 * fp->N_RB_UL * 12 * fp->symbols_per_slot * 2)); #endif if (ue->phy_sim_pdsch_rxdataF_comp) diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index f22d13c5fc..69dd29c460 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -440,7 +440,6 @@ static void nr_ue_measurement_procedures(uint16_t l, if(nr_slot_rx == 0) T(T_UE_PHY_MEAS, T_INT(gNB_id), - T_INT(ue->Mod_id), T_INT(proc->frame_rx % 1024), T_INT(nr_slot_rx), T_INT((int)(10 * log10(ue->measurements.rsrp[0]) - ue->rx_total_gain_dB)), @@ -448,7 +447,8 @@ static void nr_ue_measurement_procedures(uint16_t l, T_INT((int)(ue->measurements.rx_power_avg_dB[0] - ue->measurements.n0_power_avg_dB)), T_INT((int)ue->measurements.rx_power_avg_dB[0]), T_INT((int)ue->measurements.n0_power_avg_dB), - T_INT((int)ue->measurements.wideband_cqi_avg[0])); + T_INT((int)ue->measurements.wideband_cqi_avg[0]), + T_INT((int)ue->common_vars.freq_offset)); #endif } From 5df7d000f9a04beb41ab98c77333e830666a9d15 Mon Sep 17 00:00:00 2001 From: alexjiao Date: Fri, 17 Oct 2025 16:34:24 +0800 Subject: [PATCH 07/61] Fix for DL SNR to work in T-Tracer with NR-UE Add missing T_UE_PHY_DL_TICK and T_UE_PHY_UL_TICK events Calculate missing n0_power_avg_dB for noise measurements --- openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 3 ++- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 36b8d8a673..7d6ab8e6f2 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -125,8 +125,9 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++) { ue->measurements.rx_power_avg_dB[gNB_id] = dB_fixed( ue->measurements.rx_power_avg[gNB_id]); + ue->measurements.n0_power_avg_dB = dB_fixed(ue->measurements.n0_power_avg); ue->measurements.wideband_cqi_tot[gNB_id] = ue->measurements.rx_power_tot_dB[gNB_id] - ue->measurements.n0_power_tot_dB; - ue->measurements.wideband_cqi_avg[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] - dB_fixed(ue->measurements.n0_power_avg); + ue->measurements.wideband_cqi_avg[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] - ue->measurements.n0_power_avg_dB; ue->measurements.rx_rssi_dBm[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] + 30 - SQ15_SQUARED_NORM_FACTOR_DB - ((int)ue->openair0_cfg[0].rx_gain[0] - (int)ue->openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 69dd29c460..a91ae75d32 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -372,6 +372,9 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n AssertFatal(ue->CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX,VCD_FUNCTION_IN); +#if T_TRACER + T(T_UE_PHY_UL_TICK, T_INT(ue->Mod_id), T_INT(frame_tx % 1024), T_INT(slot_tx)); +#endif const int samplesF_per_slot = NR_SYMBOLS_PER_SLOT * ue->frame_parms.ofdm_symbol_size; c16_t txdataF_buf[ue->frame_parms.nb_antennas_tx * samplesF_per_slot] __attribute__((aligned(32))); @@ -1039,6 +1042,9 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_ nr_ue_dlsch_init(phy_data->dlsch, NR_MAX_NB_LAYERS>4 ? 2:1, ue->max_ldpc_iterations); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_IN); +#if T_TRACER + T(T_UE_PHY_DL_TICK, T_INT(ue->Mod_id), T_INT(frame_rx % 1024), T_INT(nr_slot_rx)); +#endif LOG_D(PHY," ****** start RX-Chain for Frame.Slot %d.%d ****** \n", frame_rx%1024, nr_slot_rx); From 867d476397eddee945b38f1f60ba0fa3f86b92c9 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Fri, 17 Oct 2025 11:36:39 +0200 Subject: [PATCH 08/61] CI: L2-Sim-Test-4G replace node name by localhost By configuring the Jenkins pythonExecutor to match the test machine, we can use localhost as the node for running individual test cases. This change makes it easy to move tests across machines, as the only adjustment needed is updating the pythonExecutor in Jenkins. --- .../xml_files/container_4g_l2sim_tdd.xml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ci-scripts/xml_files/container_4g_l2sim_tdd.xml b/ci-scripts/xml_files/container_4g_l2sim_tdd.xml index eabece50cd..d9ac14038b 100644 --- a/ci-scripts/xml_files/container_4g_l2sim_tdd.xml +++ b/ci-scripts/xml_files/container_4g_l2sim_tdd.xml @@ -44,7 +44,7 @@ Pull_Local_Registry Pull Images from Local Registry - obelix + localhost oai-enb oai-lte-ue @@ -88,16 +88,16 @@ Attach_UE Attach OAI UE l2sim4g_ue - obelix + localhost Ping Ping trf-gen from LTE-UE 1 l2sim4g_ue - obelix + localhost l2sim4g_ext_dn - obelix + localhost -c 20 0 @@ -106,9 +106,9 @@ Ping Ping LTE-UE 1 from trf-gen l2sim4g_ext_dn - obelix + localhost l2sim4g_ue - obelix + localhost -c 20 0 @@ -117,9 +117,9 @@ Iperf Iperf UDP Downlink l2sim4g_ue - obelix + localhost l2sim4g_ext_dn - obelix + localhost -u -t 30 -b 1M -R 25 80 @@ -129,9 +129,9 @@ Iperf Iperf UDP Uplink l2sim4g_ue - obelix + localhost l2sim4g_ext_dn - obelix + localhost -u -t 30 -b 3M 25 80 @@ -149,7 +149,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - obelix + localhost oai-enb oai-lte-ue From 149c4dbf6ea8b6192849d4cbe3177d1227321c26 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Fri, 17 Oct 2025 12:17:15 +0200 Subject: [PATCH 09/61] CI: RFSim-5G update XML files Use node for Create/Deploy/Undeploy() (as done in !3579) --- .../xml_files/container_5g_rfsim_multiue.xml | 19 +++++++------------ .../xml_files/container_5g_rfsim_n2_ho.xml | 19 +++++++------------ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_rfsim_multiue.xml b/ci-scripts/xml_files/container_5g_rfsim_multiue.xml index 79d85e154c..4e8c582099 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_multiue.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_multiue.xml @@ -48,40 +48,36 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_multiue mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_multiue oai-gnb - 0 - 0 Deploy_Object Deploy OAI 5G NR-UE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_multiue oai-nr-ue - 0 - 0 @@ -195,15 +191,14 @@ ci-scripts/yaml_files/5g_rfsimulator_multiue 1,0,0,0 1,0,0,0 - 0 - 0 + localhost Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue diff --git a/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml b/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml index feffaedf05..404e46434c 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml @@ -55,33 +55,30 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_n2_ho mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G CU-CP/CU-UP/DU 0 + UE RFsim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_n2_ho oai-cucp-0 oai-cuup-0 oai-du-0 oai-nr-ue - 0 - 0 @@ -94,10 +91,9 @@ Deploy_Object Deploy OAI 5G CU-CP/CU-UP/DU 1 RFsim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_n2_ho oai-cucp-1 oai-cuup-1 oai-du-1 - 0 - 0 @@ -186,9 +182,8 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_n2_ho - 0 - 0 10,100,100,100 10,100,100,100 @@ -197,7 +192,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan From 2bacf7ba54da1e41c0efab8a6019aa2e852d8b73 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Fri, 17 Oct 2025 16:20:01 +0200 Subject: [PATCH 10/61] CI: RF-Sim-Test-4G replace node name by localhost By configuring the Jenkins pythonExecutor to match the test machine, we can use localhost as the node for running individual test cases. This change makes it easy to move tests across machines, as the only adjustment needed is updating the pythonExecutor in Jenkins. --- .../xml_files/container_4g_rfsim_fdd_05MHz.xml | 18 +++++++++--------- .../container_4g_rfsim_fdd_05MHz_noS1.xml | 16 ++++++++-------- .../xml_files/container_4g_rfsim_fdd_10MHz.xml | 18 +++++++++--------- .../xml_files/container_4g_rfsim_fdd_20MHz.xml | 18 +++++++++--------- .../xml_files/container_4g_rfsim_fembms.xml | 4 ++-- .../xml_files/container_4g_rfsim_mbms.xml | 4 ++-- .../xml_files/container_4g_rfsim_tdd_05MHz.xml | 16 ++++++++-------- 7 files changed, 47 insertions(+), 47 deletions(-) diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml index 4b93c10fcd..562856b00c 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml @@ -103,16 +103,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - acamas + localhost Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -c 20 5 @@ -121,9 +121,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - acamas + localhost rfsim4g_ue - acamas + localhost -c 20 5 @@ -136,8 +136,8 @@ -u -t 30 -b 2M -R 25 80 - acamas - acamas + localhost + localhost @@ -148,8 +148,8 @@ -u -t 30 -b 1M 25 80 - acamas - acamas + localhost + localhost diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml index 968e30071a..1773d5d439 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml @@ -83,9 +83,9 @@ Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - acamas + localhost rfsim4g_enb_nos1 - acamas + localhost -c 20 5 @@ -94,9 +94,9 @@ Ping Ping LTE-UE from eNB rfsim4g_enb_nos1 - acamas + localhost rfsim4g_ue - acamas + localhost -c 20 5 @@ -105,9 +105,9 @@ Iperf Iperf UDP DL rfsim4g_ue - acamas + localhost rfsim4g_enb_nos1 - acamas + localhost -u -t 30 -b 2M -R 25 80 @@ -117,9 +117,9 @@ Iperf Iperf UDP UL rfsim4g_ue - acamas + localhost rfsim4g_enb_nos1 - acamas + localhost -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml index 076ee6995b..7861d8f332 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml @@ -103,16 +103,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - acamas + localhost Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -c 20 5 @@ -121,9 +121,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - acamas + localhost rfsim4g_ue - acamas + localhost -c 20 5 @@ -132,9 +132,9 @@ Iperf Iperf UDP DL rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -u -t 30 -b 2M -R 25 80 @@ -144,9 +144,9 @@ Iperf Iperf UDP UL rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml index 2e049e4efe..9199f276e7 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml @@ -103,16 +103,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - acamas + localhost Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -c 20 5 @@ -121,9 +121,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - acamas + localhost rfsim4g_ue - acamas + localhost -c 20 5 @@ -132,9 +132,9 @@ Iperf Iperf UDP DL rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -u -t 30 -b 2M -R 25 80 @@ -144,9 +144,9 @@ Iperf Iperf UDP UL rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_fembms.xml b/ci-scripts/xml_files/container_4g_rfsim_fembms.xml index 7ab434c804..73c01f2b32 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fembms.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fembms.xml @@ -80,9 +80,9 @@ Iperf2_Unidir Iperf2 UDP DL rfsim4g_ue_fembms - acamas + localhost rfsim4g_enb_fembms - acamas + localhost -u -t 30 -b 2M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_mbms.xml b/ci-scripts/xml_files/container_4g_rfsim_mbms.xml index e6a4cde19a..ea00caa09e 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_mbms.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_mbms.xml @@ -80,9 +80,9 @@ Iperf Iperf UDP DL rfsim4g_ue - acamas + localhost rfsim4g_enb_nos1 - acamas + localhost -u -t 30 -b 2M -R 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml index 2e22577879..d3129e0c68 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml @@ -103,9 +103,9 @@ Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -c 20 5 @@ -114,9 +114,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - acamas + localhost rfsim4g_ue - acamas + localhost -c 20 5 @@ -125,9 +125,9 @@ Iperf Iperf UDP DL rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -u -t 30 -b 2M -R 25 80 @@ -137,9 +137,9 @@ Iperf Iperf UDP UL rfsim4g_ue - acamas + localhost rfsim4g_ext_dn - acamas + localhost -u -t 30 -b 1M 25 80 From c8b09f570f744bd02aad963e7a1291acbff15467 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Fri, 17 Oct 2025 16:21:12 +0200 Subject: [PATCH 11/61] CI: RF-Sim-Test-5G replace node name by localhost By configuring the Jenkins pythonExecutor to match the test machine, we can use localhost as the node for running individual test cases. This change makes it easy to move tests across machines, as the only adjustment needed is updating the pythonExecutor in Jenkins. --- .../xml_files/container_5g_e1_rfsim.xml | 6 +-- .../xml_files/container_5g_f1_rfsim.xml | 38 +++++++++--------- .../xml_files/container_5g_fdd_rfsim.xml | 18 ++++----- ci-scripts/xml_files/container_5g_rfsim.xml | 40 +++++++++---------- .../xml_files/container_5g_rfsim_24prb.xml | 22 +++++----- .../xml_files/container_5g_rfsim_2x2.xml | 18 ++++----- .../container_5g_rfsim_fdd_phytest.xml | 18 ++++----- .../container_5g_rfsim_fr2_32prb.xml | 10 ++--- .../xml_files/container_5g_rfsim_multiue.xml | 36 ++++++++--------- .../xml_files/container_5g_rfsim_n2_ho.xml | 26 ++++++------ .../xml_files/container_5g_rfsim_ntn_geo.xml | 18 ++++----- .../xml_files/container_5g_rfsim_ntn_leo.xml | 10 ++--- .../xml_files/container_5g_rfsim_sidelink.xml | 2 +- .../xml_files/container_5g_rfsim_tdd_dora.xml | 10 ++--- .../xml_files/container_5g_rfsim_u0_25prb.xml | 24 +++++------ 15 files changed, 148 insertions(+), 148 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_e1_rfsim.xml b/ci-scripts/xml_files/container_5g_e1_rfsim.xml index d27091ac63..54b34e0cff 100644 --- a/ci-scripts/xml_files/container_5g_e1_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_e1_rfsim.xml @@ -76,16 +76,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 - acamas acamas acamas + localhost localhost localhost Ping Ping ext-dn from all NR-UEs rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 - acamas acamas acamas + localhost localhost localhost rfsim5g_5gc_fixed_ip - acamas + localhost -c 20 -i0.25 5 diff --git a/ci-scripts/xml_files/container_5g_f1_rfsim.xml b/ci-scripts/xml_files/container_5g_f1_rfsim.xml index 50e794e4cb..d8dc580a04 100644 --- a/ci-scripts/xml_files/container_5g_f1_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_f1_rfsim.xml @@ -107,7 +107,7 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost @@ -122,9 +122,9 @@ Ping Ping ext-dn from all NR-UEs rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i0.25 5 @@ -132,7 +132,7 @@ Custom_Command Simulate a DL radio channel with noise (3 dB) - acamas + localhost echo channelmod modify 0 noise_power_dB 3 | ncat --send-only 192.168.71.181 8091 @@ -141,9 +141,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -153,9 +153,9 @@ Iperf (UL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -163,7 +163,7 @@ Custom_Command Trigger Reestablishment - acamas + localhost echo ci force_reestab | ncat 192.168.71.171 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' @@ -171,9 +171,9 @@ Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i0.5 -w25 80 @@ -181,56 +181,56 @@ Custom_Command Verify Reestablishment - acamas + localhost echo ci get_reestab_count | ncat 192.168.71.150 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' Custom_Command Simulate a disruption of DL radio channel (ploss 55) - acamas + localhost echo channelmod modify 0 ploss 55 | ncat 192.168.71.181 8091 Custom_Command Get UE sync state (UE ID 0) - acamas + localhost echo ciUE sync_state 0 | ncat 192.168.71.181 8091 | grep -E UE_NOT_SYNC Custom_Command Restoration of the original DL channel conditions (ploss 20) - acamas + localhost echo channelmod modify 0 ploss 20 | ncat 192.168.71.181 8091 Custom_Command Get UE sync state (UE ID 0) - acamas + localhost echo ciUE sync_state 0 | ncat 192.168.71.181 8091 | grep -E UE_CONNECTED Custom_Command Trigger Handover - acamas + localhost echo ci trigger_f1_ho | ncat 192.168.71.150 9090 Custom_Command UE (1) connected to DU-PCI 0? - acamas + localhost echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3584" Custom_Command UE (1) connected to DU-PCI 1? - acamas + localhost echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3585" diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml index 6ce1e37b90..3c4e30c97b 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml @@ -70,16 +70,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -88,9 +88,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i 0.25 5 @@ -100,9 +100,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 30 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -112,9 +112,9 @@ Iperf (UL/3Mbps/UDP)(30 sec) -u -b 3M -t 30 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 diff --git a/ci-scripts/xml_files/container_5g_rfsim.xml b/ci-scripts/xml_files/container_5g_rfsim.xml index d7fb38ef8f..e2566bfd25 100644 --- a/ci-scripts/xml_files/container_5g_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_rfsim.xml @@ -125,16 +125,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 rfsim5g_ue4 rfsim5g_ue5 rfsim5g_ue6 rfsim5g_ue7 rfsim5g_ue8 rfsim5g_ue9 rfsim5g_ue10 - acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas + localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -143,9 +143,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i 0.25 5 @@ -154,9 +154,9 @@ Ping Ping ext-dn from Second NR-UE rfsim5g_ue2 - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -165,9 +165,9 @@ Ping Ping Second NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue2 - acamas + localhost -c 20 -i 0.25 5 @@ -176,9 +176,9 @@ Ping Ping ext-dn from both UEs rfsim5g_ue rfsim5g_ue2 - acamas acamas + localhost localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -187,9 +187,9 @@ Ping Ping ext-dn from all UEs rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 rfsim5g_ue4 rfsim5g_ue5 rfsim5g_ue6 rfsim5g_ue7 rfsim5g_ue8 rfsim5g_ue9 rfsim5g_ue10 - acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas + localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 -s 1016 5 @@ -199,9 +199,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -211,9 +211,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -222,21 +222,21 @@ Attach_UE Attach OAI UE 1 and 2 rfsim5g_ue rfsim5g_ue2 - acamas acamas + localhost localhost Detach_UE Detach OAI UE 1 and 2 rfsim5g_ue rfsim5g_ue2 - acamas acamas + localhost localhost Detach_UE Detach OAI UE 3 to 10 rfsim5g_ue3 rfsim5g_ue4 rfsim5g_ue5 rfsim5g_ue6 rfsim5g_ue7 rfsim5g_ue8 rfsim5g_ue9 rfsim5g_ue10 - acamas acamas acamas acamas acamas acamas acamas acamas + localhost localhost localhost localhost localhost localhost localhost localhost diff --git a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml index 7db37d8e63..849c91a7b0 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml @@ -88,7 +88,7 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost @@ -101,9 +101,9 @@ Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i0.5 80 @@ -112,9 +112,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i0.2 5 @@ -124,9 +124,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -136,9 +136,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -146,14 +146,14 @@ Custom_Command Force Msg3 C-RNTI RA - acamas + localhost echo ciUE force_crnti_ra | ncat 192.168.71.150 8091 Custom_Command Force RRC_IDLE (UE ID 0) - acamas + localhost echo ciUE force_RRC_IDLE | ncat 192.168.71.150 8091 diff --git a/ci-scripts/xml_files/container_5g_rfsim_2x2.xml b/ci-scripts/xml_files/container_5g_rfsim_2x2.xml index 75924e1ca2..ed0e11807c 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_2x2.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_2x2.xml @@ -70,16 +70,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -88,9 +88,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i 0.25 5 @@ -100,9 +100,9 @@ Iperf (DL/10Mbps/UDP)(30 sec) -u -b 10M -t 20 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -112,9 +112,9 @@ Iperf (UL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 diff --git a/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml b/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml index b376df99f4..4ff5dbedc8 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml @@ -49,7 +49,7 @@ Custom_Command Clean-Up any residual volume - acamas + localhost docker volume rm 5g_rfsimulator_fdd_phytest_rrc.config -f @@ -77,9 +77,9 @@ Ping Ping gNB from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_gnb_nos1 - acamas + localhost -c20 -i0.2 0 @@ -88,9 +88,9 @@ Ping Ping NR-UE from gNB rfsim5g_gnb_nos1 - acamas + localhost rfsim5g_ue - acamas + localhost -c20 -i0.2 0 @@ -100,9 +100,9 @@ Iperf (DL/30kbps/UDP)(30 sec) -u -b 0.03M -t 20 -R -c 10.0.1.1 rfsim5g_ue - acamas + localhost rfsim5g_gnb_nos1 - acamas + localhost 5 90 @@ -112,9 +112,9 @@ Iperf (UL/30kbps/UDP)(30 sec) -u -b 0.03M -t 20 -c 10.0.1.1 rfsim5g_ue - acamas + localhost rfsim5g_gnb_nos1 - acamas + localhost 5 90 diff --git a/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml b/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml index 6a47da0ff9..37b90f2385 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml @@ -70,16 +70,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i0.2 0 @@ -88,9 +88,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i0.2 0 diff --git a/ci-scripts/xml_files/container_5g_rfsim_multiue.xml b/ci-scripts/xml_files/container_5g_rfsim_multiue.xml index 4e8c582099..215f58c2a7 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_multiue.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_multiue.xml @@ -84,16 +84,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_multiue1 rfsim5g_multiue2 rfsim5g_multiue3 rfsim5g_multiue4 rfsim5g_multiue5 rfsim5g_multiue6 rfsim5g_multiue7 rfsim5g_multiue8 rfsim5g_multiue9 rfsim5g_multiue10 - acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas + localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost Ping Ping ext-dn from NR-UE rfsim5g_multiue1 - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -102,9 +102,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_multiue1 - acamas + localhost -c 20 -i 0.25 5 @@ -113,9 +113,9 @@ Ping Ping ext-dn from Second NR-UE rfsim5g_multiue2 - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -124,9 +124,9 @@ Ping Ping Second NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_multiue2 - acamas + localhost -c 20 -i 0.25 5 @@ -135,9 +135,9 @@ Ping Ping ext-dn from both UEs rfsim5g_multiue1 rfsim5g_multiue2 - acamas acamas + localhost localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -146,9 +146,9 @@ Ping Ping ext-dn from all UEs rfsim5g_multiue1 rfsim5g_multiue2 rfsim5g_multiue3 rfsim5g_multiue4 rfsim5g_multiue5 rfsim5g_multiue6 rfsim5g_multiue7 rfsim5g_multiue8 rfsim5g_multiue9 rfsim5g_multiue10 - acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas + localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 -s 1016 5 @@ -158,9 +158,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_multiue1 - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -170,9 +170,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_multiue1 - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -181,7 +181,7 @@ Detach_UE Detach OAI UEs rfsim5g_multiue1 - acamas + localhost diff --git a/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml b/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml index 404e46434c..5da417c284 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml @@ -85,7 +85,7 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost @@ -100,9 +100,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 50 -i 0.25 5 @@ -111,9 +111,9 @@ Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 50 -i 0.25 10 @@ -123,9 +123,9 @@ Iperf (DL/10Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -135,9 +135,9 @@ Iperf (UL/4Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -151,7 +151,7 @@ Custom_Command Trigger N2 Handover - acamas + localhost echo ci trigger_n2_ho 1,1 | ncat 192.168.71.150 9090 yes @@ -159,14 +159,14 @@ Custom_Command UE (1) connected to DU-PCI 1? - acamas + localhost echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.180 9090 | grep "1234" Custom_Command Trigger N2 Handover - acamas + localhost echo ci trigger_n2_ho 0,1 | ncat 192.168.71.180 9090 yes @@ -174,7 +174,7 @@ Custom_Command UE (1) connected to DU-PCI 0? - acamas + localhost echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3584" diff --git a/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml b/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml index 7107b7971b..32bbbc683d 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml @@ -74,16 +74,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -92,9 +92,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i 0.25 5 @@ -102,7 +102,7 @@ Custom_Command Trigger Reestablishment - acamas + localhost echo ci force_reestab | ncat 192.168.71.140 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' yes @@ -111,9 +111,9 @@ Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i0.5 -w25 80 @@ -121,7 +121,7 @@ Custom_Command Verify Reestablishment - acamas + localhost echo ci get_reestab_count | ncat 192.168.71.140 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' yes diff --git a/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml b/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml index 63897cfb8b..dd9fb56067 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml @@ -69,16 +69,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -87,9 +87,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i 0.25 5 diff --git a/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml b/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml index 58bff964d4..6ddd6d13b7 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml @@ -74,7 +74,7 @@ Custom_Command Check that UE synched - acamas + localhost docker logs rfsim5g-oai-nr-ue-2 | grep -m 1 "PSBCH RX:OK" diff --git a/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml b/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml index 97730bd233..a9f7f2c3aa 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml @@ -49,7 +49,7 @@ Custom_Command Clean-Up any residual volume - acamas + localhost docker volume rm 5g_rfsimulator_tdd_dora_rrc.config -f @@ -83,9 +83,9 @@ Ping Ping gNB from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_gnb_nos1 - acamas + localhost -c20 -i0.2 0 @@ -94,9 +94,9 @@ Ping Ping NR-UE from gNB rfsim5g_gnb_nos1 - acamas + localhost rfsim5g_ue - acamas + localhost -c20 -i0.2 0 diff --git a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml index c5c76124d3..f70c81732e 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml @@ -72,16 +72,16 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - acamas + localhost Ping Ping ext-dn from NR-UE rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -90,9 +90,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - acamas + localhost rfsim5g_ue - acamas + localhost -c 20 -i 0.25 5 @@ -101,16 +101,16 @@ Attach_UE Verify 2nd PDU session is up rfsim5g_ue_pdu_2 - acamas + localhost Ping Ping ext-dn from NR-UE on PDU session ID 2 rfsim5g_ue_pdu_2 - acamas + localhost rfsim5g_ext_dn - acamas + localhost -c 20 -i 0.25 5 @@ -120,9 +120,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 @@ -132,9 +132,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - acamas + localhost rfsim5g_ext_dn - acamas + localhost 5 90 From 4d372c5f58b9fbf9b3dfb37661b2ddb53b36f626 Mon Sep 17 00:00:00 2001 From: alexjiao Date: Fri, 17 Oct 2025 18:07:50 +0800 Subject: [PATCH 12/61] Improve T-Tracer GUI for UE Make PHY measurements diagrams larger for a better view, reduce PHY/MAC/RLC/PDCP/RRC textlog height --- common/utils/T/tracer/ue.c | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/common/utils/T/tracer/ue.c b/common/utils/T/tracer/ue.c index f4ea38f980..6d7d9ce4c5 100644 --- a/common/utils/T/tracer/ue.c +++ b/common/utils/T/tracer/ue.c @@ -196,7 +196,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, view *v; logger *l; - main_window = new_toplevel_window(g, 1200, 900, "eNB tracer"); + main_window = new_toplevel_window(g, 1200, 900, "UE tracer"); top_container = new_container(g, VERTICAL); widget_add_child(g, main_window, top_container, -1); @@ -207,7 +207,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, /* logo */ widget_add_child(g, line, logo, -1); - input_signal_plot = new_xy_plot(g, 256, 55, "input signal", 20); + input_signal_plot = new_xy_plot(g, 512, 110, "input signal", 20); widget_add_child(g, line, input_signal_plot, -1); xy_plot_set_range(g, input_signal_plot, 0, 7680*10, 20, 70); input_signal_log = new_framelog(h, database, @@ -221,7 +221,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, logger_add_view(input_signal_log, input_signal_view); /* UE x PDSCH IQ data */ - w = new_xy_plot(g, 55, 55, "", 50); + w = new_xy_plot(g, 110, 110, "", 50); e->pdsch_iq_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, -500, 500, -500, 500); @@ -232,7 +232,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, e->pdsch_iq_ue_logger = l; /* UE x estimated DL channel */ - w = new_xy_plot(g, 280, 55, "", 50); + w = new_xy_plot(g, 560, 110, "", 50); e->dl_estimate_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 512*10, -10, 80); @@ -245,7 +245,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, e->dl_estimate_ue_logger = l; /* PHY Meas */ - w = new_xy_plot(g, 128, 55, "", 50); + w = new_xy_plot(g, 256, 110, "", 50); e->phy_meas_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -130, 35); @@ -271,7 +271,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, /* UE x DL mcs */ line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); - w = new_xy_plot(g, 128, 55, "", 20); + w = new_xy_plot(g, 192, 110, "", 20); xy_plot_set_range(g, w, 0, 1024*10, -2, 30); e->dl_mcs_xy_plot = w; widget_add_child(g, line, w, -1); @@ -282,7 +282,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, e->dl_mcs_logger = l; /* UE x UL mcs */ - w = new_xy_plot(g, 128, 55, "", 20); + w = new_xy_plot(g, 192, 110, "", 20); xy_plot_set_range(g, w, 0, 1024*10, -2, 30); e->ul_mcs_xy_plot = w; widget_add_child(g, line, w, -1); @@ -295,7 +295,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, /* UE x PUSCH TX Power */ // line = new_container(g, HORIZONTAL); // widget_add_child(g, top_container, line, -1); - w = new_xy_plot(g, 128, 55, "", 20); + w = new_xy_plot(g, 192, 110, "", 20); e->pusch_power_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -30, 50); @@ -313,7 +313,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, /* UE x PUCCH TX Power */ // line = new_container(g, HORIZONTAL); // widget_add_child(g, top_container, line, -1); - w = new_xy_plot(g, 128, 55, "", 20); + w = new_xy_plot(g, 192, 110, "", 20); e->pucch_power_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -30, 50); @@ -329,7 +329,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, e->pucch_ampl_logger = l; /* UE x PDSCH energy */ - w = new_xy_plot(g, 128, 55, "", 50); + w = new_xy_plot(g, 192, 110, "", 50); e->pdsch_energy_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -10, 80); @@ -355,7 +355,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, e->pdsch_energy_logger = l; /* UE x PDCCH energy */ - w = new_xy_plot(g, 128, 55, "", 50); + w = new_xy_plot(g, 192, 110, "", 50); e->pdcch_energy_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -10, 80); @@ -381,7 +381,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, e->pdcch_energy_logger = l; /* UE x PDCCH IQ data */ - w = new_xy_plot(g, 55, 55, "", 50); + w = new_xy_plot(g, 110, 110, "", 50); e->pdcch_iq_ue_xy_plot = w; widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, -100, 100, -100, 100); @@ -544,16 +544,16 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, /* phy/mac/rlc/pdcp/rrc textlog */ line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); - container_set_child_growable(g, top_container, line, 1); + container_set_child_growable(g, top_container, line, 0); /* phy */ col = new_container(g, VERTICAL); widget_add_child(g, line, col, -1); container_set_child_growable(g, line, col, 1); widget_add_child(g, col, new_label(g, "PHY"), -1); - text = new_textlist(g, 100, 10, new_color(g, "#afa")); + text = new_textlist(g, 100, 5, new_color(g, "#afa")); widget_add_child(g, col, text, -1); - container_set_child_growable(g, col, text, 1); + container_set_child_growable(g, col, text, 0); textview = new_view_textlist(10000, 10, g, text); e->phyview = textview; @@ -562,24 +562,24 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, col, -1); container_set_child_growable(g, line, col, 1); widget_add_child(g, col, new_label(g, "MAC"), -1); - text = new_textlist(g, 100, 10, new_color(g, "#adf")); + text = new_textlist(g, 100, 5, new_color(g, "#adf")); widget_add_child(g, col, text, -1); - container_set_child_growable(g, col, text, 1); + container_set_child_growable(g, col, text, 0); textview = new_view_textlist(10000, 10, g, text); e->macview = textview; line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); - container_set_child_growable(g, top_container, line, 1); + container_set_child_growable(g, top_container, line, 0); /* rlc */ col = new_container(g, VERTICAL); widget_add_child(g, line, col, -1); container_set_child_growable(g, line, col, 1); widget_add_child(g, col, new_label(g, "RLC"), -1); - text = new_textlist(g, 100, 10, new_color(g, "#aff")); + text = new_textlist(g, 100, 5, new_color(g, "#aff")); widget_add_child(g, col, text, -1); - container_set_child_growable(g, col, text, 1); + container_set_child_growable(g, col, text, 0); textview = new_view_textlist(10000, 10, g, text); e->rlcview = textview; @@ -588,24 +588,24 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, col, -1); container_set_child_growable(g, line, col, 1); widget_add_child(g, col, new_label(g, "PDCP"), -1); - text = new_textlist(g, 100, 10, new_color(g, "#ed9")); + text = new_textlist(g, 100, 5, new_color(g, "#ed9")); widget_add_child(g, col, text, -1); - container_set_child_growable(g, col, text, 1); + container_set_child_growable(g, col, text, 0); textview = new_view_textlist(10000, 10, g, text); e->pdcpview = textview; line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); - container_set_child_growable(g, top_container, line, 1); + container_set_child_growable(g, top_container, line, 0); /* rrc */ col = new_container(g, VERTICAL); widget_add_child(g, line, col, -1); container_set_child_growable(g, line, col, 1); widget_add_child(g, col, new_label(g, "RRC"), -1); - text = new_textlist(g, 100, 10, new_color(g, "#fdb")); + text = new_textlist(g, 100, 5, new_color(g, "#fdb")); widget_add_child(g, col, text, -1); - container_set_child_growable(g, col, text, 1); + container_set_child_growable(g, col, text, 0); textview = new_view_textlist(10000, 10, g, text); e->rrcview = textview; From f231655b31d4e36c98e602120094c2085b60ee96 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Mon, 20 Oct 2025 15:04:26 +0100 Subject: [PATCH 13/61] Restore UE Capability IE after RRCReestablishment --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index debc0d5530..064857a8e3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -967,6 +967,8 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = oldUE->CellGroup; oldUE->CellGroup = NULL; + UE->capability = oldUE->capability; + oldUE->capability = NULL; UE->mac_stats = oldUE->mac_stats; UE->measgap_config = oldUE->measgap_config; /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it From c645e8b0962eaf78b93b867341ff32bfb454acb3 Mon Sep 17 00:00:00 2001 From: Mario Joa-Ng Date: Wed, 13 Aug 2025 18:36:08 +0200 Subject: [PATCH 14/61] Fix xran: Correctly read PRACH beam index Upgrade xran patch, bump version number. --- .../F/oaioran_F.patch | 154 ++++++++++-------- radio/fhi_72/CMakeLists.txt | 2 +- 2 files changed, 89 insertions(+), 67 deletions(-) diff --git a/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch b/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch index bec423b95e..3f953b36d9 100644 --- a/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch +++ b/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch @@ -1,5 +1,5 @@ diff --git a/fhi_lib/app/src/common.h b/fhi_lib/app/src/common.h -index ac5f471..5efcce3 100644 +index ac5f471..b0f7ed1 100644 --- a/fhi_lib/app/src/common.h +++ b/fhi_lib/app/src/common.h @@ -28,7 +28,7 @@ @@ -7,7 +7,7 @@ index ac5f471..5efcce3 100644 #include -#define VERSIONX "oran_f_release_v1.0" -+#define VERSIONX "oran_f_release_v1.4" ++#define VERSIONX "oran_f_release_v1.5" #define APP_O_DU 0 #define APP_O_RU 1 @@ -919,7 +919,7 @@ index 4acade1..c939edc 100644 for(i = 0; i < xran_ports_num; i++){ g_xran_dev_ctx[i] = pCtx; diff --git a/fhi_lib/lib/src/xran_main.c b/fhi_lib/lib/src/xran_main.c -index 7c472d7..216c7f5 100644 +index 7c472d7..9da3621 100644 --- a/fhi_lib/lib/src/xran_main.c +++ b/fhi_lib/lib/src/xran_main.c @@ -35,7 +35,11 @@ @@ -969,7 +969,29 @@ index 7c472d7..216c7f5 100644 print_dbg("PRACH eAxC_offset %d\n", pPrachCPConfig->eAxC_offset); /* Save some configs for app */ -@@ -1570,6 +1593,7 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru +@@ -1169,6 +1192,10 @@ xran_prepare_cp_ul_slot(uint16_t xran_port_id, uint32_t nSlotIdx, uint32_t nCcS + uint8_t seqid = xran_get_cp_seqid(pHandle, XRAN_DIR_UL, cc_id, port_id); + + beam_id = xran_get_beamid(pHandle, XRAN_DIR_UL, cc_id, port_id, slot_id); ++ pBufList = &(p_xran_dev_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[buf_id][cc_id][ant_id].sBufferList); ++ struct xran_prb_map *prbMap = pBufList->pBuffers->pData; ++ struct xran_prb_elm *pPrbElm = &prbMap->prbMap[0]; //mjoang ++ beam_id = pPrbElm->nBeamIndex; + ret = generate_cpmsg_prach(pHandle, ¶ms, sect_geninfo, mbuf, p_xran_dev_ctx, + frame_id, subframe_id, slot_id, tti, + beam_id, cc_id, port_id, occasionid, seqid); +@@ -1338,6 +1365,10 @@ tx_cp_ul_cb(struct rte_timer *tim, void *arg) + uint8_t seqid = xran_get_cp_seqid(pHandle, XRAN_DIR_UL, cc_id, port_id); + + beam_id = xran_get_beamid(pHandle, XRAN_DIR_UL, cc_id, port_id, slot_id); ++ pBufList = &(p_xran_dev_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[buf_id][cc_id][ant_id].sBufferList); ++ struct xran_prb_map *prbMap = pBufList->pBuffers->pData; ++ struct xran_prb_elm *pPrbElm = &prbMap->prbMap[0]; //mjoang ++ beam_id = pPrbElm->nBeamIndex; + ret = generate_cpmsg_prach(pHandle, ¶ms, sect_geninfo, mbuf, p_xran_dev_ctx, + frame_id, subframe_id, slot_id, tti, + beam_id, cc_id, port_id, occasionid, seqid); +@@ -1570,6 +1601,7 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru { case ECPRI_IQ_DATA: pkt_data[num_data++] = pkt; @@ -977,7 +999,7 @@ index 7c472d7..216c7f5 100644 break; // For RU emulation case ECPRI_RT_CONTROL_DATA: -@@ -1587,7 +1611,7 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru +@@ -1587,7 +1619,7 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru break; default: if (p_dev_ctx->fh_init.io_cfg.id == O_DU) { @@ -986,7 +1008,7 @@ index 7c472d7..216c7f5 100644 } break; } -@@ -1876,7 +1900,7 @@ xran_sector_get_instances (uint32_t xran_port, void * pDevHandle, uint16_t nNumI +@@ -1876,7 +1908,7 @@ xran_sector_get_instances (uint32_t xran_port, void * pDevHandle, uint16_t nNumI for (i = 0; i < nNumInstances; i++) { /* Allocate Memory for CC handles */ @@ -995,7 +1017,7 @@ index 7c472d7..216c7f5 100644 if(pCcHandle == NULL) return XRAN_STATUS_RESOURCE; -@@ -2347,8 +2371,7 @@ ring_processing_func_per_port(void* args) +@@ -2347,8 +2379,7 @@ ring_processing_func_per_port(void* args) for (i = 0; i < ctx->io_cfg.num_vfs && i < XRAN_VF_MAX; i = i+1) { if (ctx->vf2xran_port[i] == port_id) { for(qi = 0; qi < ctx->rxq_per_port[port_id]; qi++){ @@ -1005,7 +1027,7 @@ index 7c472d7..216c7f5 100644 } } } -@@ -2414,9 +2437,6 @@ xran_spawn_workers(void) +@@ -2414,9 +2445,6 @@ xran_spawn_workers(void) nWorkerCore = nWorkerCore << 1; } @@ -1015,7 +1037,7 @@ index 7c472d7..216c7f5 100644 printf("O-XU %d\n", eth_ctx->io_cfg.id); printf("HW %d\n", icx_cpu); printf("Num cores %d\n", total_num_cores); -@@ -2453,7 +2473,7 @@ xran_spawn_workers(void) +@@ -2453,7 +2481,7 @@ xran_spawn_workers(void) eth_ctx->time_wrk_cfg.arg = NULL; eth_ctx->time_wrk_cfg.state = 1; @@ -1024,7 +1046,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2475,7 +2495,7 @@ xran_spawn_workers(void) +@@ -2475,7 +2503,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1033,7 +1055,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2502,7 +2522,7 @@ xran_spawn_workers(void) +@@ -2502,7 +2530,7 @@ xran_spawn_workers(void) } /** 1 - CP GEN **/ @@ -1042,7 +1064,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2536,7 +2556,7 @@ xran_spawn_workers(void) +@@ -2536,7 +2564,7 @@ xran_spawn_workers(void) else p_dev->tx_sym_gen_func = xran_process_tx_sym_cp_on_opt; @@ -1051,7 +1073,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2559,7 +2579,7 @@ xran_spawn_workers(void) +@@ -2559,7 +2587,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1060,7 +1082,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2586,7 +2606,7 @@ xran_spawn_workers(void) +@@ -2586,7 +2614,7 @@ xran_spawn_workers(void) } /** 1 - CP GEN **/ @@ -1069,7 +1091,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2613,7 +2633,7 @@ xran_spawn_workers(void) +@@ -2613,7 +2641,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1078,7 +1100,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2628,7 +2648,7 @@ xran_spawn_workers(void) +@@ -2628,7 +2656,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 - CP GEN **/ @@ -1087,7 +1109,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2643,7 +2663,7 @@ xran_spawn_workers(void) +@@ -2643,7 +2671,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 UP GEN **/ @@ -1096,7 +1118,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2682,7 +2702,7 @@ xran_spawn_workers(void) +@@ -2682,7 +2710,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1105,7 +1127,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2697,7 +2717,7 @@ xran_spawn_workers(void) +@@ -2697,7 +2725,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 - CP GEN **/ @@ -1114,7 +1136,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2712,7 +2732,7 @@ xran_spawn_workers(void) +@@ -2712,7 +2740,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 UP GEN **/ @@ -1123,7 +1145,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2727,7 +2747,7 @@ xran_spawn_workers(void) +@@ -2727,7 +2755,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 UP GEN **/ @@ -1132,7 +1154,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2766,7 +2786,7 @@ xran_spawn_workers(void) +@@ -2766,7 +2794,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1141,7 +1163,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2781,7 +2801,7 @@ xran_spawn_workers(void) +@@ -2781,7 +2809,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 Eth Tx **/ @@ -1150,7 +1172,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); -@@ -2797,7 +2817,7 @@ xran_spawn_workers(void) +@@ -2797,7 +2825,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 - CP GEN **/ @@ -1159,7 +1181,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2812,7 +2832,7 @@ xran_spawn_workers(void) +@@ -2812,7 +2840,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 UP GEN **/ @@ -1168,7 +1190,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2827,7 +2847,7 @@ xran_spawn_workers(void) +@@ -2827,7 +2855,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 4 UP GEN **/ @@ -1177,7 +1199,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2861,7 +2881,7 @@ xran_spawn_workers(void) +@@ -2861,7 +2889,7 @@ xran_spawn_workers(void) /* workers */ /** 0 Eth RX */ @@ -1186,7 +1208,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2876,7 +2896,7 @@ xran_spawn_workers(void) +@@ -2876,7 +2904,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 FH RX and BBDEV */ @@ -1195,7 +1217,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2891,7 +2911,7 @@ xran_spawn_workers(void) +@@ -2891,7 +2919,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 FH RX and BBDEV */ @@ -1204,7 +1226,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2906,7 +2926,7 @@ xran_spawn_workers(void) +@@ -2906,7 +2934,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 FH RX and BBDEV */ @@ -1213,7 +1235,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2921,7 +2941,7 @@ xran_spawn_workers(void) +@@ -2921,7 +2949,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** FH TX and BBDEV */ @@ -1222,7 +1244,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -2969,7 +2989,7 @@ xran_spawn_workers(void) +@@ -2969,7 +2997,7 @@ xran_spawn_workers(void) /* p_dev->tx_sym_gen_func = xran_process_tx_sym_cp_on_opt; */ @@ -1231,7 +1253,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3004,7 +3024,7 @@ xran_spawn_workers(void) +@@ -3004,7 +3032,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1240,7 +1262,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3031,7 +3051,7 @@ xran_spawn_workers(void) +@@ -3031,7 +3059,7 @@ xran_spawn_workers(void) } /** 1 - CP GEN **/ @@ -1249,7 +1271,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3062,7 +3082,7 @@ xran_spawn_workers(void) +@@ -3062,7 +3090,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1258,7 +1280,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3089,7 +3109,7 @@ xran_spawn_workers(void) +@@ -3089,7 +3117,7 @@ xran_spawn_workers(void) } /** 1 - CP GEN **/ @@ -1267,7 +1289,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3115,7 +3135,7 @@ xran_spawn_workers(void) +@@ -3115,7 +3143,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1276,7 +1298,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3130,7 +3150,7 @@ xran_spawn_workers(void) +@@ -3130,7 +3158,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 - CP GEN **/ @@ -1285,7 +1307,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3145,7 +3165,7 @@ xran_spawn_workers(void) +@@ -3145,7 +3173,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 UP GEN **/ @@ -1294,7 +1316,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3184,7 +3204,7 @@ xran_spawn_workers(void) +@@ -3184,7 +3212,7 @@ xran_spawn_workers(void) /* workers */ /** 0 FH RX and BBDEV */ @@ -1303,7 +1325,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3199,7 +3219,7 @@ xran_spawn_workers(void) +@@ -3199,7 +3227,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 - CP GEN **/ @@ -1312,7 +1334,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3214,7 +3234,7 @@ xran_spawn_workers(void) +@@ -3214,7 +3242,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 UP GEN **/ @@ -1321,7 +1343,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3229,7 +3249,7 @@ xran_spawn_workers(void) +@@ -3229,7 +3257,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 UP GEN **/ @@ -1330,7 +1352,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3266,7 +3286,7 @@ xran_spawn_workers(void) +@@ -3266,7 +3294,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1339,7 +1361,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3281,7 +3301,7 @@ xran_spawn_workers(void) +@@ -3281,7 +3309,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 - CP GEN **/ @@ -1348,7 +1370,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3296,7 +3316,7 @@ xran_spawn_workers(void) +@@ -3296,7 +3324,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 UP GEN **/ @@ -1357,7 +1379,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3311,7 +3331,7 @@ xran_spawn_workers(void) +@@ -3311,7 +3339,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 UP GEN **/ @@ -1366,7 +1388,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3326,7 +3346,7 @@ xran_spawn_workers(void) +@@ -3326,7 +3354,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 4 UP GEN **/ @@ -1375,7 +1397,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3348,7 +3368,7 @@ xran_spawn_workers(void) +@@ -3348,7 +3376,7 @@ xran_spawn_workers(void) /* workers */ /** 0 Eth RX */ @@ -1384,7 +1406,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3363,7 +3383,7 @@ xran_spawn_workers(void) +@@ -3363,7 +3391,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 FH RX and BBDEV */ @@ -1393,7 +1415,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3378,7 +3398,7 @@ xran_spawn_workers(void) +@@ -3378,7 +3406,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 FH RX and BBDEV */ @@ -1402,7 +1424,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3393,7 +3413,7 @@ xran_spawn_workers(void) +@@ -3393,7 +3421,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 FH RX and BBDEV */ @@ -1411,7 +1433,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3408,7 +3428,7 @@ xran_spawn_workers(void) +@@ -3408,7 +3436,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** FH TX and BBDEV */ @@ -1420,7 +1442,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3435,7 +3455,7 @@ xran_spawn_workers(void) +@@ -3435,7 +3463,7 @@ xran_spawn_workers(void) /* workers */ /** 0 Eth RX */ @@ -1429,7 +1451,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3450,7 +3470,7 @@ xran_spawn_workers(void) +@@ -3450,7 +3478,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 1 FH RX and BBDEV */ @@ -1438,7 +1460,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3465,7 +3485,7 @@ xran_spawn_workers(void) +@@ -3465,7 +3493,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 FH RX and BBDEV */ @@ -1447,7 +1469,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3480,7 +3500,7 @@ xran_spawn_workers(void) +@@ -3480,7 +3508,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 3 FH RX and BBDEV */ @@ -1456,7 +1478,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3495,7 +3515,7 @@ xran_spawn_workers(void) +@@ -3495,7 +3523,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 4 FH RX and BBDEV */ @@ -1465,7 +1487,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3510,7 +3530,7 @@ xran_spawn_workers(void) +@@ -3510,7 +3538,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** FH TX and BBDEV */ @@ -1474,7 +1496,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3537,7 +3557,7 @@ xran_spawn_workers(void) +@@ -3537,7 +3565,7 @@ xran_spawn_workers(void) /* workers */ /** 0 **/ @@ -1483,7 +1505,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3562,7 +3582,7 @@ xran_spawn_workers(void) +@@ -3562,7 +3590,7 @@ xran_spawn_workers(void) } /** 1 - CP GEN **/ @@ -1492,7 +1514,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3577,7 +3597,7 @@ xran_spawn_workers(void) +@@ -3577,7 +3605,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 2 UP GEN **/ @@ -1501,7 +1523,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3602,7 +3622,7 @@ xran_spawn_workers(void) +@@ -3602,7 +3630,7 @@ xran_spawn_workers(void) } /** 3 UP GEN **/ @@ -1510,7 +1532,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3627,7 +3647,7 @@ xran_spawn_workers(void) +@@ -3627,7 +3655,7 @@ xran_spawn_workers(void) } /** 4 UP GEN **/ @@ -1519,7 +1541,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -3642,7 +3662,7 @@ xran_spawn_workers(void) +@@ -3642,7 +3670,7 @@ xran_spawn_workers(void) eth_ctx->pkt_wrk_cfg[pThCtx->worker_id].arg = pThCtx; /** 5 UP GEN **/ @@ -1528,7 +1550,7 @@ index 7c472d7..216c7f5 100644 if(pThCtx == NULL){ print_err("pThCtx allocation error\n"); return XRAN_STATUS_FAIL; -@@ -4034,6 +4054,24 @@ xran_get_slot_idx (uint32_t PortId, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, +@@ -4034,6 +4062,24 @@ xran_get_slot_idx (uint32_t PortId, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, return tti; } diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index f2161d06a8..fb40852ebb 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -17,7 +17,7 @@ add_library(oran_fhlib_5g MODULE ) set(E_VERSION 5.1.6) -set(F_VERSION 6.1.4) +set(F_VERSION 6.1.5) find_package(xran REQUIRED) if(xran_VERSION VERSION_EQUAL E_VERSION) From 2d27e0fc0aed35bd5dd0651bab7533b901d8180e Mon Sep 17 00:00:00 2001 From: Mario Joa-Ng Date: Fri, 18 Jul 2025 20:00:09 -0400 Subject: [PATCH 15/61] Set TX nBeamIndex according to beam allocation Initialize ru_info structure with beam information, and set beams on TX direction. Initialize the number of antennas for both RX/TX in both cases for completeness. --- radio/fhi_72/oaioran.c | 8 ++++++++ radio/fhi_72/oran_isolate.c | 7 +++++++ radio/fhi_72/oran_isolate.h | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index fc9f58a492..d6a31f3bc1 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -512,6 +512,14 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { struct xran_section_desc *p_sec_desc = NULL; p_prbMapElm = &pRbMap->prbMap[idxElm]; + if (sym_idx == 0) { + // ant_id / no of antenna per beam gives the beam_nb + p_prbMapElm->nBeamIndex = ru->beam_id[ant_id / (ru->nb_tx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT]; + // In phy-f-1.0/fhi_lib/lib/api/xran_pkt_cp.h, beamId:15 is of 15bit. -1 set extension bit ef:1 to 1 mistakenly. + if (p_prbMapElm->nBeamIndex == -1) + p_prbMapElm->nBeamIndex = 0; + } + // assumes one fragment per symbol #ifdef E_RELEASE p_sec_desc = p_prbMapElm->p_sec_desc[sym_id][0]; diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 3bdbe1df12..48e95e7344 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -214,7 +214,10 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) { ru_info_t ru_info; ru_info.nb_rx = ru->nb_rx * ru->num_beams_period; + ru_info.nb_tx = ru->nb_tx * ru->num_beams_period; ru_info.rxdataF = ru->common.rxdataF; + ru_info.beam_id = ru->common.beam_id; + ru_info.num_beams_period = ru->num_beams_period; ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id] RU_proc_t *proc = &ru->proc; @@ -267,8 +270,12 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { start_meas(&ru->tx_fhaul); ru_info_t ru_info; + ru_info.nb_rx = ru->nb_rx * ru->num_beams_period; ru_info.nb_tx = ru->nb_tx * ru->num_beams_period; ru_info.txdataF_BF = ru->common.txdataF_BF; + ru_info.beam_id = ru->common.beam_id; + ru_info.num_beams_period = ru->num_beams_period; + // printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp); int ret = xran_fh_tx_send_slot(&ru_info, frame, slot, timestamp); diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h index 174c1399a6..7dd61ad739 100644 --- a/radio/fhi_72/oran_isolate.h +++ b/radio/fhi_72/oran_isolate.h @@ -41,6 +41,14 @@ typedef struct ru_info_s { int nb_tx; int32_t **txdataF_BF; + /// \brief Anaglogue beam ID for each OFDM symbol (used when beamforming not done in RU) + /// - first index: concurrent beam + /// - second index: beam_id [0.. symbols_per_frame] + int32_t **beam_id; + + /// number of concurrent analog beams in period + int num_beams_period; + // Needed for Prach int16_t **prach_buf; } ru_info_t; From 65ef3cfa7471db0ecf80d9f534532a14a9e9499d Mon Sep 17 00:00:00 2001 From: Mario Joa-Ng Date: Wed, 13 Aug 2025 16:23:41 +0200 Subject: [PATCH 16/61] Set RX nBeamIndex according to beam allocation Handle CP UL packet at xran_fx_tx_send_slot() instead of xran_fh_rx_read_slot(), as the latter would set this information too late (on reception on samples, but it needs to be filled in the CP packet prior to reception). --- radio/fhi_72/oaioran.c | 69 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index d6a31f3bc1..37661d7ad1 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -259,7 +259,14 @@ static bool is_tdd_ul_symbol(const struct xran_frame_config *frame_conf, int slo * slot is not UL). */ static bool is_tdd_dl_guard_slot(const struct xran_frame_config *frame_conf, int slot) { - return !is_tdd_ul_symbol(frame_conf, slot, XRAN_NUM_OF_SYMBOL_PER_SLOT - 1); + return !is_tdd_ul_symbol(frame_conf, slot, 0); +} + +/** @brief Check if current slot is UL or guard/mixed without UL (i.e., current + * slot is not UL). */ +static bool is_tdd_ul_guard_slot(const struct xran_frame_config *frame_conf, int slot) +{ + return is_tdd_ul_symbol(frame_conf, slot, XRAN_NUM_OF_SYMBOL_PER_SLOT - 1); } /** @details Read PRACH and PUSCH data from xran buffers. If @@ -337,7 +344,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) start_ptr = rx_data + (slot_size * slot_offset_rxdata); const struct xran_frame_config *frame_conf = &get_xran_fh_config(ant_id / nb_rx_per_ru)->frame_conf; // skip processing this slot is TX (no RX in this slot) - if (is_tdd_dl_guard_slot(frame_conf, *slot)) + if (!is_tdd_ul_guard_slot(frame_conf, *slot)) continue; // This loop would better be more inner to avoid confusion and maybe also errors. for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { @@ -484,12 +491,70 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) int nPRBs = fh_cfg->nDLRBs; int fftsize = 1 << fh_cfg->ru_conf.fftSize; int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports; + int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; + + // Handle CP UL packet here instead of at xran_fh_rx_read_slot() as oran_fh_if4p5_south_in() lags behind + // oran_fh_if4p5_south_out() (which is invoked at the right time slot) by 4 slots. + // Need to use --continuous-tx so that this routine will be triggered in RX slot. + for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. + for (uint8_t ant_id = 0; ant_id < ru->nb_rx; ant_id++) { + int first = 1; // The first UL symbol + const struct xran_frame_config *frame_conf = &get_xran_fh_config(ant_id / nb_rx_per_ru)->frame_conf; + // skip processing this slot is TX (no RX in this slot) + if (!is_tdd_ul_guard_slot(frame_conf, slot)) { + continue; + } + // This loop would better be more inner to avoid confusion and maybe also errors. + for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { + /* the callback is for mixed and UL slots. In mixed, we have to + * skip DL and guard symbols. */ + if (!is_tdd_ul_symbol(frame_conf, slot, sym_idx)) { + continue; + } + oran_buf_list_t *bufs = get_xran_buffers(ant_id / nb_rx_per_ru); + uint8_t *pPrbMapData = bufs->dstcp[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; + struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData; + + struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0]; + + struct xran_prb_map *pRbMap = pPrbMap; + uint32_t idxElm = 0; + + LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm); + for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { + LOG_D(HW, "prbMap[%d] : PRBstart %d nPRBs %d\n", idxElm, pRbMap->prbMap[idxElm].nRBStart, pRbMap->prbMap[idxElm].nRBSize); + pRbElm = &pRbMap->prbMap[idxElm]; + if (first) { + // ant_id / no of antenna per beam gives the beam_nb + pRbElm->nBeamIndex = + ru->beam_id[ant_id / (ru->nb_rx / ru->num_beams_period)][slot * XRAN_NUM_OF_SYMBOL_PER_SLOT + sym_idx]; + // In phy-f-1.0/fhi_lib/lib/api/xran_pkt_cp.h, beamId:15 is of 15bit. -1 set extension bit ef:1 to 1 mistakenly. + if (pRbElm->nBeamIndex == -1) { + pRbElm->nBeamIndex = 0; + } else { + first = 0; + } + } + } + } + } + } for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. for (uint8_t ant_id = 0; ant_id < ru->nb_tx; ant_id++) { oran_buf_list_t *bufs = get_xran_buffers(ant_id / nb_tx_per_ru); + const struct xran_frame_config *frame_conf = &get_xran_fh_config(ant_id / nb_tx_per_ru)->frame_conf; + // skip processing this slot is TX (no TX in this slot) + if (!is_tdd_dl_guard_slot(frame_conf, slot)) { + continue; + } // This loop would better be more inner to avoid confusion and maybe also errors. for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { + /* the callback is for mixed and UL slots. In mixed, we have to + * skip UL and guard symbols. */ + if (is_tdd_ul_symbol(frame_conf, slot, sym_idx)) { + continue; + } uint8_t *pData = bufs->src[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT].pData; uint8_t *pPrbMapData = bufs->srccp[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; From ad1b05cd016647d92a48d35590e49886474f759b Mon Sep 17 00:00:00 2001 From: Mario Joa-Ng Date: Wed, 13 Aug 2025 15:56:02 +0200 Subject: [PATCH 17/61] need to set beam_id for UPLINK_SLOT when using analog BF --- executables/nr-gnb.c | 5 ++++- openair1/SCHED_NR/nr_ru_procedures.c | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 1021aba1ce..4fb74c1a08 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -114,7 +114,10 @@ static void tx_func(processingData_L1tx_t *info) pushNotifiedFIFO(&gNB->resp_L1, res); int tx_slot_type = nr_slot_select(cfg, frame_tx, slot_tx); - if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM) { + // TODO check for analog_beam_list is a workaround while no beam API for beam + // selection is implemented + if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM + || cfg->analog_beamforming_ve.analog_beam_list) { start_meas(&info->gNB->phy_proc_tx); phy_procedures_gNB_TX(info, frame_tx, slot_tx, 1); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 0546455e36..f121914f11 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -185,9 +185,6 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) int txdataF_offset = slot_tx * fp->samples_per_slot_wCP; start_meas(&ru->precoding_stats); - if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT) - return; - if (gNB->common_vars.analog_bf) { for (int i = 0; i < ru->num_beams_period; i++) { memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot], @@ -196,6 +193,9 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) } } + if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT) + return; + // If there is no digital beamforming we just need to copy the data to RU if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) { for (int b = 0; b < ru->num_beams_period; b++) { From ae690217dd51a37b76fc0ee9e2433a0324c6b211 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Wed, 9 Apr 2025 11:05:54 -0400 Subject: [PATCH 18/61] Clean-up nr_slot_fep 1.Create new funtion nr_symbol_fep() to do OFDM demod of one symbol on all antennas. This is called by nr_slot_fep() for now. In the upcoming MR, this function will be called directly after reading each OFDM symbol from the radio. 2.Removed redundant memory alignment. DFT function performs memory alignment if the input memory is not aligned. --- executables/nr-gnb.c | 16 +- openair1/PHY/MODULATION/nr_modulation.h | 14 +- openair1/PHY/MODULATION/slot_fep_nr.c | 193 +++++++++++++----------- openair1/SIMULATION/NR_PHY/ulsim.c | 16 +- 4 files changed, 123 insertions(+), 116 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 505adf825c..a63c7984fb 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -193,14 +193,14 @@ static void rx_func(processingData_L1_t *info) int soffset = (slot_rx & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; for (int bb = 0; bb < gNB->common_vars.num_beams_period; bb++) { for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) { - apply_nr_rotation_RX(&gNB->frame_parms, - gNB->common_vars.rxdataF[bb][aa], - gNB->frame_parms.symbol_rotation[1], - slot_rx, - gNB->frame_parms.N_RB_UL, - soffset, - 0, - gNB->frame_parms.Ncp == EXTENDED ? 12 : 14); + const uint max_symb = (gNB->frame_parms.Ncp == EXTENDED) ? 12 : 14; + for (int sym = 0; sym < max_symb; sym++) + apply_nr_rotation_symbol_RX(&gNB->frame_parms, + gNB->common_vars.rxdataF[bb][aa] + soffset + sym * gNB->frame_parms.ofdm_symbol_size, + gNB->frame_parms.symbol_rotation[1], + gNB->frame_parms.N_RB_UL, + slot_rx, + sym); } } } diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h index 64886a2809..996a66b343 100644 --- a/openair1/PHY/MODULATION/nr_modulation.h +++ b/openair1/PHY/MODULATION/nr_modulation.h @@ -117,14 +117,12 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp); void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp); -void apply_nr_rotation_RX(const NR_DL_FRAME_PARMS *frame_parms, - c16_t *rxdataF, - const c16_t *rot, - int slot, - int nb_rb, - int soffset, - int first_symbol, - int nsymb); +void apply_nr_rotation_symbol_RX(const NR_DL_FRAME_PARMS *frame_parms, + c16_t *rxdataF, + const c16_t *rot, + int nb_rb, + int slot, + int symbol); /*! \brief Perform NR precoding. TS 38.211 V15.4.0 subclause 6.3.1.5 @param[in] datatx_F_precoding, Pointer to n_layers*re data array diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index cad3f92c33..50e19d8563 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -28,6 +28,36 @@ #include "PHY/nr_phy_common/inc/nr_phy_common.h" #include +/* rxdataF should be 16 bytes aligned */ +void nr_symbol_fep(const NR_DL_FRAME_PARMS *frame_parms, + const int slot, + const unsigned char symbol, + const int link_type, + c16_t *rxdata[frame_parms->nb_antennas_rx], + c16_t *rxdataF[frame_parms->nb_antennas_rx], + time_stats_t* dft_stats) +{ + AssertFatal(symbol < frame_parms->symbols_per_slot, + "slot_fep: symbol must be between 0 and %d\n", + frame_parms->symbols_per_slot - 1); + AssertFatal(slot < frame_parms->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_parms->slots_per_frame - 1); + + dft_size_idx_t dftsize = get_dft(frame_parms->ofdm_symbol_size); + for (unsigned char aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + if (dft_stats) start_meas(dft_stats); + dft(dftsize, (int16_t *)rxdata[aa], (int16_t *)rxdataF[aa], 1); + if (dft_stats) stop_meas(dft_stats); + + const bool is_sl = (link_type == link_type_sl); + apply_nr_rotation_symbol_RX(frame_parms, + rxdataF[aa], + frame_parms->symbol_rotation[link_type], + is_sl ? frame_parms->N_RB_SL : frame_parms->N_RB_DL, + slot, + symbol); + } +} + int nr_slot_fep(PHY_VARS_NR_UE *ue, const NR_DL_FRAME_PARMS *frame_parms, unsigned int slot, @@ -37,35 +67,23 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, uint32_t sample_offset, c16_t **rxdata) { - AssertFatal(symbol < frame_parms->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_parms->symbols_per_slot-1); + AssertFatal(symbol < frame_parms->symbols_per_slot, + "slot_fep: symbol must be between 0 and %d\n", + frame_parms->symbols_per_slot - 1); AssertFatal(slot < frame_parms->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_parms->slots_per_frame - 1); - bool is_sl = (linktype == link_type_sl) ? true : false; + bool is_sl = (linktype == link_type_sl); bool is_synchronized = (ue) ? ue->is_synchronized : false; - unsigned int nb_prefix_samples; - unsigned int nb_prefix_samples0; + unsigned int nb_prefix_samples = frame_parms->nb_prefix_samples; + unsigned int nb_prefix_samples0 = (is_synchronized || is_sl) ? frame_parms->nb_prefix_samples0 : nb_prefix_samples; + // For Sidelink 16 frames worth of samples is processed to find SSB, for 5G-NR 2. - unsigned int total_samples = (is_sl) ? 16 * frame_parms->samples_per_frame : 2 * frame_parms->samples_per_frame; - - int N_RB = (is_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_DL; - - if (is_synchronized || is_sl) { - nb_prefix_samples = frame_parms->nb_prefix_samples; - nb_prefix_samples0 = frame_parms->nb_prefix_samples0; - } else { - nb_prefix_samples = frame_parms->nb_prefix_samples; - nb_prefix_samples0 = frame_parms->nb_prefix_samples; - AssertFatal(slot == 0, "Slot should be 0\n"); - } - - dft_size_idx_t dftsize = get_dft(frame_parms->ofdm_symbol_size); - // This is for misalignment issues - c16_t tmp_dft_in[frame_parms->ofdm_symbol_size] __attribute__ ((aligned (32))); + const unsigned int total_samples = (is_sl) ? 16 * frame_parms->samples_per_frame : 2 * frame_parms->samples_per_frame; unsigned int rx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0); - unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol; + const unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol; for (int idx_symb = slot * frame_parms->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++) - rx_offset += (idx_symb%(0x7<numerology_index)) ? nb_prefix_samples : nb_prefix_samples0; + rx_offset += (idx_symb % (0x7 << frame_parms->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0; rx_offset += frame_parms->ofdm_symbol_size * symbol; rx_offset += sample_offset; @@ -73,48 +91,47 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, // use OFDM symbol from within 1/8th of the CP to avoid ISI rx_offset -= (nb_prefix_samples / frame_parms->ofdm_offset_divisor); - rx_offset %= total_samples; - - for (unsigned char aa=0; aanb_antennas_rx; aa++) { - c16_t *rxdata_ptr = &rxdata[aa][rx_offset]; + LOG_D(PHY, + "slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u energy %d\n", + slot, + symbol, + nb_prefix_samples, + nb_prefix_samples0, + rx_offset, + dB_fixed(signal_energy((int32_t *)&rxdata[0][rx_offset], frame_parms->ofdm_symbol_size))); + c16_t tmp_dft_in[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); + c16_t *rxdata_symb_ptr[frame_parms->nb_antennas_rx]; + c16_t *rxdataF_symb_ptr[frame_parms->nb_antennas_rx]; + for (unsigned char aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + rxdataF_symb_ptr[aa] = &rxdataF[aa][frame_parms->ofdm_symbol_size * symbol]; // This happens only during initial sync if (rx_offset + frame_parms->ofdm_symbol_size > total_samples) { - // rxdata is 2 frames len // we have to wrap on the end - - memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], (total_samples - rx_offset) * sizeof(int32_t)); - memcpy((void *)&tmp_dft_in[total_samples - rx_offset], - (void *)&rxdata[aa][0], + memcpy(&tmp_dft_in[aa][0], &rxdata[aa][rx_offset], (total_samples - rx_offset) * sizeof(int32_t)); + memcpy(&tmp_dft_in[aa][total_samples - rx_offset], + &rxdata[aa][0], (frame_parms->ofdm_symbol_size - (total_samples - rx_offset)) * sizeof(int32_t)); - rxdata_ptr = tmp_dft_in; - - } else if ((rx_offset & 7) != 0) { // if input to dft is not 256-bit aligned - memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], frame_parms->ofdm_symbol_size * sizeof(int32_t)); - rxdata_ptr = tmp_dft_in; + rxdata_symb_ptr[aa] = tmp_dft_in[aa]; + } else { + rxdata_symb_ptr[aa] = &rxdata[aa][rx_offset]; } if (ue && ue->cont_fo_comp) { start_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS); - nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, rxdata_ptr, tmp_dft_in, frame_parms->ofdm_symbol_size); - rxdata_ptr = tmp_dft_in; + nr_fo_compensation(ue->freq_offset, + frame_parms->samples_per_subframe, + rx_offset, + rxdata_symb_ptr[aa], + tmp_dft_in[aa], + frame_parms->ofdm_symbol_size); stop_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS); + rxdata_symb_ptr[aa] = tmp_dft_in[aa]; } - - if (ue) - start_meas_nr_ue_phy(ue, RX_DFT_STATS); - - dft(dftsize, - (int16_t *)rxdata_ptr, - (int16_t *)&rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], - 1); - - if (ue) - stop_meas_nr_ue_phy(ue, RX_DFT_STATS); - - apply_nr_rotation_RX(frame_parms, rxdataF[aa], frame_parms->symbol_rotation[linktype], slot, N_RB, 0, symbol, 1); } - + time_stats_t* dft_stats = NULL; + if (ue) dft_stats = &ue->phy_cpu_stats.cpu_time_stats[RX_DFT_STATS]; + nr_symbol_fep(frame_parms, slot, symbol, linktype, rxdata_symb_ptr, rxdataF_symb_ptr, dft_stats); return 0; } @@ -177,54 +194,46 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms, return 0; } -void apply_nr_rotation_RX(const NR_DL_FRAME_PARMS *frame_parms, - c16_t *rxdataF, - const c16_t *rot, - int slot, - int nb_rb, - int soffset, - int first_symbol, - int nsymb) +void apply_nr_rotation_symbol_RX(const NR_DL_FRAME_PARMS *frame_parms, + c16_t *rxdataF, + const c16_t *rot, + int nb_rb, + int slot, + int symbol) { - AssertFatal(first_symbol + nsymb <= NR_NUMBER_OF_SYMBOLS_PER_SLOT, - "First symbol %d and number of symbol %d not compatible with number of symbols in a slot %d\n", - first_symbol, nsymb, NR_NUMBER_OF_SYMBOLS_PER_SLOT); - int symb_offset = (slot % frame_parms->slots_per_subframe) * frame_parms->symbols_per_slot; + const int symb_offset = (slot % frame_parms->slots_per_subframe) * frame_parms->symbols_per_slot; - for (int symbol = first_symbol; symbol < first_symbol + nsymb; symbol++) { - - c16_t rot2 = rot[symbol + symb_offset]; - rot2.i = -rot2.i; - LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n", slot, symb_offset, rot2.r, rot2.i); - const c16_t *shift_rot = frame_parms->timeshift_symbol_rotation; - c16_t *this_symbol = &rxdataF[soffset + (frame_parms->ofdm_symbol_size * symbol)]; + c16_t rot2 = rot[symbol + symb_offset]; + rot2.i = -rot2.i; + LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n", slot, symb_offset, rot2.r, rot2.i); + const c16_t *shift_rot = frame_parms->timeshift_symbol_rotation; + c16_t *this_symbol = rxdataF; - if (nb_rb & 1) { - rotate_cpx_vector(this_symbol, &rot2, this_symbol, - (nb_rb + 1) * 6, 15); - rotate_cpx_vector(this_symbol + frame_parms->first_carrier_offset - 6, - &rot2, - this_symbol + frame_parms->first_carrier_offset - 6, - (nb_rb + 1) * 6, 15); - mult_cpx_vector(this_symbol, shift_rot, this_symbol, (nb_rb + 1) * 6, 15); - mult_cpx_vector(this_symbol + frame_parms->first_carrier_offset - 6, - shift_rot + frame_parms->first_carrier_offset - 6, + if (nb_rb & 1) { + rotate_cpx_vector(this_symbol, &rot2, this_symbol, (nb_rb + 1) * 6, 15); + rotate_cpx_vector(this_symbol + frame_parms->first_carrier_offset - 6, + &rot2, this_symbol + frame_parms->first_carrier_offset - 6, (nb_rb + 1) * 6, 15); - } else { - rotate_cpx_vector(this_symbol, &rot2, this_symbol, - nb_rb * 6, 15); - rotate_cpx_vector(this_symbol + frame_parms->first_carrier_offset, - &rot2, - this_symbol + frame_parms->first_carrier_offset, - nb_rb * 6, 15); - mult_cpx_vector(this_symbol, shift_rot, this_symbol, nb_rb * 6, 15); - mult_cpx_vector(this_symbol + frame_parms->first_carrier_offset, - shift_rot + frame_parms->first_carrier_offset, + mult_cpx_vector(this_symbol, shift_rot, this_symbol, (nb_rb + 1) * 6, 15); + mult_cpx_vector(this_symbol + frame_parms->first_carrier_offset - 6, + shift_rot + frame_parms->first_carrier_offset - 6, + this_symbol + frame_parms->first_carrier_offset - 6, + (nb_rb + 1) * 6, + 15); + } else { + rotate_cpx_vector(this_symbol, &rot2, this_symbol, nb_rb * 6, 15); + rotate_cpx_vector(this_symbol + frame_parms->first_carrier_offset, + &rot2, this_symbol + frame_parms->first_carrier_offset, nb_rb * 6, 15); - } + mult_cpx_vector(this_symbol, shift_rot, this_symbol, nb_rb * 6, 15); + mult_cpx_vector(this_symbol + frame_parms->first_carrier_offset, + shift_rot + frame_parms->first_carrier_offset, + this_symbol + frame_parms->first_carrier_offset, + nb_rb * 6, + 15); } } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index c4b2f854c2..b7f93cdf3a 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1468,14 +1468,14 @@ int main(int argc, char *argv[]) } int offset = (slot & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) { - apply_nr_rotation_RX(&gNB->frame_parms, - gNB->common_vars.rxdataF[0][aa], - gNB->frame_parms.symbol_rotation[1], - slot, - gNB->frame_parms.N_RB_UL, - offset, - 0, - gNB->frame_parms.Ncp == EXTENDED ? 12 : 14); + const unsigned int max_symb = (gNB->frame_parms.Ncp == EXTENDED) ? 12 : 14; + for (int sym = 0; sym < max_symb; sym++) + apply_nr_rotation_symbol_RX(&gNB->frame_parms, + gNB->common_vars.rxdataF[0][aa] + offset + sym * gNB->frame_parms.ofdm_symbol_size, + gNB->frame_parms.symbol_rotation[1], + gNB->frame_parms.N_RB_UL, + slot, + sym); } ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot, &UL_INFO); From e1b06d177e2082046355f58d534dba71e881eb2a Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 20 Aug 2025 16:25:05 +0200 Subject: [PATCH 19/61] Remove unused parameters from nr_pdcch_dmrs_rx --- openair1/PHY/NR_REFSIG/nr_dmrs_rx.c | 4 +--- openair1/PHY/NR_REFSIG/refsig_defs_ue.h | 4 +--- openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 7fd703ea30..e25d9700da 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -150,9 +150,7 @@ int nr_pdsch_dmrs_rx(const PHY_VARS_NR_UE *ue, return(0); } -int nr_pdcch_dmrs_rx(const PHY_VARS_NR_UE *ue, - unsigned int Ns, - const unsigned int *nr_gold_pdcch, +int nr_pdcch_dmrs_rx(const unsigned int *nr_gold_pdcch, c16_t *output, unsigned short p, unsigned short nb_rb_coreset) diff --git a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h index 1d2d4b87ae..414dae9976 100644 --- a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h +++ b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h @@ -35,9 +35,7 @@ void nr_pbch_dmrs_rx(int dmrss, const unsigned int *nr_gold_pbch, c16_t *output, /*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PDCCH DMRS. @param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables */ -int nr_pdcch_dmrs_rx(const PHY_VARS_NR_UE *ue, - unsigned int Ns, - const unsigned int *nr_gold_pdcch, +int nr_pdcch_dmrs_rx(const unsigned int *nr_gold_pdcch, c16_t *output, unsigned short p, unsigned short nb_rb_corset); diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 296606a426..e77fe87069 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -852,7 +852,7 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, c16_t pilot[(nb_rb_coreset + dmrs_ref) * 3] __attribute__((aligned(16))); // Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS const uint32_t *gold = nr_gold_pdcch(ue->frame_parms.N_RB_DL, ue->frame_parms.symbols_per_slot, scrambling_id, slot, symbol); - nr_pdcch_dmrs_rx(ue, slot, gold, pilot, 2000, (nb_rb_coreset + dmrs_ref)); + nr_pdcch_dmrs_rx(gold, pilot, 2000, (nb_rb_coreset + dmrs_ref)); for (aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { From 34052bf0ce93ced000fdd5648785916bc3569fd2 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 20 Aug 2025 17:49:00 +0200 Subject: [PATCH 20/61] Split PBCH and PDCCH processing in NR UE --- executables/nr-ue.c | 3 +- openair1/SCHED_NR_UE/defs.h | 3 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 81 +++++++++++---------- openair1/SIMULATION/NR_PHY/dlsim.c | 5 +- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index f789484465..e7132e15cf 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -564,7 +564,8 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, UE->if_inst->dl_indication(&dl_indication); } - sampleShift = pbch_pdcch_processing(UE, proc, phy_data); + sampleShift = pbch_processing(UE, proc, phy_data); + pdcch_processing(UE, proc, phy_data); if (phy_data->dlsch[0].active && (phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_ || phy_data->dlsch[0].rnti_type == TYPE_RA_RNTI_)) { // indicate to tx thread to wait for DLSCH decoding diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index c7f0deb118..e3c92ba5d4 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -92,7 +92,8 @@ */ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txp); -int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data); +int pbch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data); +void pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data); void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index f22d13c5fc..7e4ddd1067 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1027,14 +1027,55 @@ static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index) return ue->frame_parms.ssb_index == index; } -int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data) +void pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data) +{ + TracyCZone(ctx); + NR_DL_FRAME_PARMS *fp = &ue->frame_parms; + NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; + const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP; + __attribute__ ((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz]; + + uint8_t nb_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.duration : 0; + int first_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.StartSymbolIndex : 0; + int last_symb_pdcch = first_symb_pdcch + nb_symb_pdcch; + for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) { + nr_slot_fep(ue, fp, proc->nr_slot_rx, l, rxdataF, link_type_dl, 0, ue->common_vars.rxdata); + } + + // Hold the channel estimates in frequency domain. + int32_t pdcch_est_size = ((((fp->symbols_per_slot*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH))+15)/16)*16); + __attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[4 * fp->nb_antennas_rx][pdcch_est_size]; + + uint8_t dci_cnt = 0; + for(int n_ss = 0; n_ssnb_search_space; n_ss++) { + for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) { + // note: this only works if RBs for PDCCH are contigous! + nr_pdcch_channel_estimation(ue, + proc, + l, + &phy_pdcch_config->pdcch_config[n_ss].coreset, + fp->first_carrier_offset, + phy_pdcch_config->pdcch_config[n_ss].BWPStart, + pdcch_est_size, + pdcch_dl_ch_estimates, + rxdataF); + } + dci_cnt = dci_cnt + nr_ue_pdcch_procedures(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, phy_data, n_ss, rxdataF); + } + LOG_D(PHY, "[UE %d] Frame %d, nr_slot_rx %d: found %d DCIs\n", ue->Mod_id, proc->frame_rx, proc->nr_slot_rx, dci_cnt); + phy_pdcch_config->nb_search_space = 0; + TracyCZoneEnd(ctx); + if (ue->phy_sim_rxdataF) + memcpy(ue->phy_sim_rxdataF, rxdataF[0], sizeof(int32_t) * nb_symb_pdcch * ue->frame_parms.ofdm_symbol_size); +} + +int pbch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data) { TracyCZone(ctx, true); int frame_rx = proc->frame_rx; int nr_slot_rx = proc->nr_slot_rx; int gNB_id = proc->gNB_id; NR_DL_FRAME_PARMS *fp = &ue->frame_parms; - NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; int sampleShift = INT_MAX; nr_ue_dlsch_init(phy_data->dlsch, NR_MAX_NB_LAYERS>4 ? 2:1, ue->max_ldpc_iterations); @@ -1163,43 +1204,7 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_ } // for i } // for rsc_id } // for gNB_id - - LOG_D(PHY," ------ --> PDCCH ChannelComp/LLR Frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDCCH, VCD_FUNCTION_IN); - - uint8_t nb_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.duration : 0; - int first_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.StartSymbolIndex : 0; - int last_symb_pdcch = first_symb_pdcch + nb_symb_pdcch; - for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) { - nr_slot_fep(ue, fp, proc->nr_slot_rx, l, rxdataF, link_type_dl, 0, ue->common_vars.rxdata); - } - - // Hold the channel estimates in frequency domain. - int32_t pdcch_est_size = ((((fp->symbols_per_slot*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH))+15)/16)*16); - __attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[4 * fp->nb_antennas_rx][pdcch_est_size]; - - uint8_t dci_cnt = 0; - for(int n_ss = 0; n_ssnb_search_space; n_ss++) { - for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) { - // note: this only works if RBs for PDCCH are contigous! - nr_pdcch_channel_estimation(ue, - proc, - l, - &phy_pdcch_config->pdcch_config[n_ss].coreset, - fp->first_carrier_offset, - phy_pdcch_config->pdcch_config[n_ss].BWPStart, - pdcch_est_size, - pdcch_dl_ch_estimates, - rxdataF); - } - dci_cnt = dci_cnt + nr_ue_pdcch_procedures(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, phy_data, n_ss, rxdataF); - } - LOG_D(PHY, "[UE %d] Frame %d, nr_slot_rx %d: found %d DCIs\n", ue->Mod_id, frame_rx, nr_slot_rx, dci_cnt); - phy_pdcch_config->nb_search_space = 0; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDCCH, VCD_FUNCTION_OUT); TracyCZoneEnd(ctx); - if (ue->phy_sim_rxdataF) - memcpy(ue->phy_sim_rxdataF, rxdataF[0], sizeof(int32_t) * nb_symb_pdcch * ue->frame_parms.ofdm_symbol_size); return sampleShift; } diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 6329d5849f..752211fa10 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1216,9 +1216,8 @@ int main(int argc, char **argv) ue_dci_configuration(UE_mac, &dl_config, frame, slot); nr_ue_scheduled_response(&scheduled_response); - pbch_pdcch_processing(UE, - &UE_proc, - &phy_data); + pbch_processing(UE, &UE_proc, &phy_data); + pdcch_processing(UE, &UE_proc, &phy_data); pdsch_processing(UE, &UE_proc, &phy_data); From 22a335b1a8f22866330db4f9469f3aedb875850e Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 10 Sep 2025 07:54:30 +0200 Subject: [PATCH 21/61] Fix too large array in UE PDCCH RX --- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 7e4ddd1067..f18862e0aa 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1044,7 +1044,7 @@ void pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ // Hold the channel estimates in frequency domain. int32_t pdcch_est_size = ((((fp->symbols_per_slot*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH))+15)/16)*16); - __attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[4 * fp->nb_antennas_rx][pdcch_est_size]; + __attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[fp->nb_antennas_rx][pdcch_est_size]; uint8_t dci_cnt = 0; for(int n_ss = 0; n_ssnb_search_space; n_ss++) { From dcb69986ebddde7a0dbf5ef62eca1f5aba6d6a81 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 8 Sep 2025 17:07:22 +0200 Subject: [PATCH 22/61] Fix segfault in nr_pdcch_extract_rbs_single Fixed an issue where skipping unused PDCCH RBGs would cause the function to write/read from outside the symbol boundary --- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 71 +++++++++++++-------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 43b27e3932..47ebae8891 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -249,44 +249,43 @@ static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, * the position 0+c_rb-N_RB_DL/2 in rxdataF and we have to point the pointer at (1+c_rb-N_RB_DL/2) in rxdataF */ - int c_rb = 0; - for (int rb = 0; rb < coreset_nbr_rb; rb++, c_rb++) { - int c_rb_by6 = c_rb / 6; + for (int rb_group = 0; rb_group < coreset_nbr_rb / 6; rb_group++) { + if ((coreset_freq_dom[rb_group / 8] & (1 << (7 - (rb_group & 7)))) == 0) { + continue; + } + for (int rb = 0; rb < 6; rb++) { + int c_rb = rb_group * 6 + rb; + c16_t *rxF = NULL; + if ((frame_parms->N_RB_DL & 1) == 0) { + if ((c_rb + n_BWP_start) < frame_parms->N_RB_DL / 2) + // if RB to be treated is lower than middle system bandwidth then rxdataF pointed + // at (offset + c_br + symbol * ofdm_symbol_size): even case + rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); + else + // number of RBs is even and c_rb is higher than half system bandwidth (we don't skip DC) + // if these conditions are true the pointer has to be situated at the 1st part of the rxdataF + // we point at the 1st part of the rxdataF in symbol + rxF = rxFbase + RE_PER_RB * (c_rb + n_BWP_start - frame_parms->N_RB_DL / 2); + } else { + if ((c_rb + n_BWP_start) <= frame_parms->N_RB_DL / 2) + // if RB to be treated is lower than middle system bandwidth then rxdataF pointed + // at (offset + c_br + symbol * ofdm_symbol_size): odd case + rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); + else + // number of RBs is odd and c_rb is higher than half system bandwidth + 1 + // if these conditions are true the pointer has to be situated at the 1st part of + // the rxdataF just after the first IQ symbols of the RB containing DC + // we point at the 1st part of the rxdataF in symbol + rxF = rxFbase + RE_PER_RB * (c_rb + n_BWP_start - frame_parms->N_RB_DL / 2) - 6; + } - // skip zeros in frequency domain bitmap - while ((coreset_freq_dom[c_rb_by6 / 8] & (1 << (7 - (c_rb_by6 & 7)))) == 0) { - c_rb += 6; - c_rb_by6 = c_rb / 6; + const int valid_re[RE_PER_RB_OUT_DMRS] = {0, 2, 3, 4, 6, 7, 8, 10, 11}; + for (int i = 0; i < sizeofArray(valid_re); i++) { + *rxF_ext++ = rxF[valid_re[i]]; + *dl_ch0_ext++ = dl_ch0[valid_re[i]]; + } + dl_ch0 += RE_PER_RB; } - c16_t *rxF = NULL; - if ((frame_parms->N_RB_DL & 1) == 0) { - if ((c_rb + n_BWP_start) < frame_parms->N_RB_DL / 2) - // if RB to be treated is lower than middle system bandwidth then rxdataF pointed - // at (offset + c_br + symbol * ofdm_symbol_size): even case - rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); - else - // number of RBs is even and c_rb is higher than half system bandwidth (we don't skip DC) - // if these conditions are true the pointer has to be situated at the 1st part of the rxdataF - // we point at the 1st part of the rxdataF in symbol - rxF = rxFbase + RE_PER_RB * (c_rb + n_BWP_start - frame_parms->N_RB_DL / 2); - } else { - if ((c_rb + n_BWP_start) <= frame_parms->N_RB_DL / 2) - // if RB to be treated is lower than middle system bandwidth then rxdataF pointed - // at (offset + c_br + symbol * ofdm_symbol_size): odd case - rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); - else - // number of RBs is odd and c_rb is higher than half system bandwidth + 1 - // if these conditions are true the pointer has to be situated at the 1st part of - // the rxdataF just after the first IQ symbols of the RB containing DC - // we point at the 1st part of the rxdataF in symbol - rxF = rxFbase + RE_PER_RB * (c_rb + n_BWP_start - frame_parms->N_RB_DL / 2) - 6; - } - const int valid_re[RE_PER_RB_OUT_DMRS] = {0, 2, 3, 4, 6, 7, 8, 10, 11}; - for (int i = 0; i < sizeofArray(valid_re); i++) { - *rxF_ext++ = rxF[valid_re[i]]; - *dl_ch0_ext++ = dl_ch0[valid_re[i]]; - } - dl_ch0 += RE_PER_RB; } } } From 07ce1ed145e4742ba1b923634ab5183e5077383d Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 9 Sep 2025 16:32:29 +0200 Subject: [PATCH 23/61] Fix reading reading out of bounds in nr_pdcch_extract_rbs_single Fix reading out of bounds of rxdataF in the middle PRB in case of odd cell bandwidth. --- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 47ebae8891..44c560f6c7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -249,6 +249,7 @@ static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, * the position 0+c_rb-N_RB_DL/2 in rxdataF and we have to point the pointer at (1+c_rb-N_RB_DL/2) in rxdataF */ + c16_t middle_prb_buffer[RE_PER_RB]; for (int rb_group = 0; rb_group < coreset_nbr_rb / 6; rb_group++) { if ((coreset_freq_dom[rb_group / 8] & (1 << (7 - (rb_group & 7)))) == 0) { continue; @@ -270,7 +271,15 @@ static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, if ((c_rb + n_BWP_start) <= frame_parms->N_RB_DL / 2) // if RB to be treated is lower than middle system bandwidth then rxdataF pointed // at (offset + c_br + symbol * ofdm_symbol_size): odd case - rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); + // Reassemble the middle PRB + if (c_rb + n_BWP_start == frame_parms->N_RB_DL / 2) { + memcpy(middle_prb_buffer, rxFbase + frame_parms->ofdm_symbol_size - RE_PER_RB / 2, sizeof(c16_t) * RE_PER_RB / 2); + memcpy(middle_prb_buffer + RE_PER_RB / 2, rxFbase, sizeof(c16_t) * RE_PER_RB / 2); + rxF = middle_prb_buffer; + } else { + rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); + } + else // number of RBs is odd and c_rb is higher than half system bandwidth + 1 // if these conditions are true the pointer has to be situated at the 1st part of From ece9d51db30323a2aae568ec274ed103b5ecc370 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 21 Aug 2025 08:49:31 +0200 Subject: [PATCH 24/61] Symbol based PDCCH processing 1. Refactor PDCCH PHY functions to take rxdataF of one OFDM symbol and produce LLR for each search space. The modified functions take rxdataF in a different format than that produced by nr_slot_fep(). So for now a memcpy is used to change the array structure. Once nr_slot_fep() is modified, this memcpy will no longer be needed and will be removed. 2. Modify DCI functions to decode DCI in the last PDCCH symbol and inidcate to MAC once. 3. Fix PDCCH monitoring for start symbol > 0. 4. Fix multiple PDCCH monitoring within slot. Co-authored-by: Sakthivel Velumani --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 1 + .../nr_dl_channel_estimation.c | 28 +- openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 2 +- openair1/PHY/NR_UE_TRANSPORT/dci_nr.c | 321 ++++++++++++------ .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 20 +- openair1/SCHED_NR_UE/defs.h | 19 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 127 +++---- openair1/SIMULATION/NR_PHY/pbchsim.c | 11 - .../NR_MAC_UE/nr_ue_dci_configuration.c | 7 +- 9 files changed, 307 insertions(+), 229 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index dc52f1de2a..faebaffc6f 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -73,6 +73,7 @@ typedef struct { /// frequency_domain_resource; uint8_t frequency_domain_resource[6]; uint8_t StartSymbolIndex; + uint16_t StartSymbolBitmap; uint8_t duration; uint8_t CceRegMappingType; // interleaved or noninterleaved uint8_t RegBundleSize; // valid if CCE to REG mapping type is interleaved type diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index e77fe87069..6a49a17608 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -805,17 +805,12 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, uint16_t BWPStart, int32_t pdcch_est_size, c16_t pdcch_dl_ch_estimates[][pdcch_est_size], - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) + c16_t rxdataF[ue->frame_parms.nb_antennas_rx][ue->frame_parms.ofdm_symbol_size]) { int slot = proc->nr_slot_rx; unsigned char aarx; unsigned short k; unsigned int pilot_cnt; - int ch_offset,symbol_offset; - - ch_offset = ue->frame_parms.ofdm_symbol_size*symbol; - - symbol_offset = ue->frame_parms.ofdm_symbol_size*symbol; int nb_rb_coreset=0; int coreset_start_rb=0; @@ -830,8 +825,7 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, unsigned short coreset_start_subcarrier = first_carrier_offset+(BWPStart + coreset_start_rb)*12; #ifdef DEBUG_PDCCH - printf("PDCCH Channel Estimation : ch_offset %d, OFDM size %d, Ncp=%d, slot=%d, symbol %d\n", - ch_offset, + printf("PDCCH Channel Estimation : OFDM size %d, Ncp=%d, slot=%d, symbol %d\n", ue->frame_parms.ofdm_symbol_size, ue->frame_parms.Ncp, slot, @@ -858,8 +852,8 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, k = coreset_start_subcarrier; c16_t *pil = &pilot[dmrs_ref * 3]; - c16_t *rxF = &rxdataF[aarx][symbol_offset + k + 1]; - c16_t *dl_ch = &pdcch_dl_ch_estimates[aarx][ch_offset]; + c16_t *rxF = &rxdataF[aarx][k + 1]; + c16_t *dl_ch = &pdcch_dl_ch_estimates[aarx][0]; memset(dl_ch, 0, sizeof(c16_t) * ue->frame_parms.ofdm_symbol_size); @@ -879,29 +873,29 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, if (k >= ue->frame_parms.ofdm_symbol_size) { k -= ue->frame_parms.ofdm_symbol_size; - rxF = &rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = &rxdataF[aarx][k + 1]; } multadd_real_vector_complex_scalar(fm, c16mulShift(*pil++, *rxF, 15), dl_ch, 16); k = (k + 4) % ue->frame_parms.ofdm_symbol_size; - rxF = (c16_t *)&rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = (c16_t *)&rxdataF[aarx][k + 1)]; multadd_real_vector_complex_scalar(fr, c16mulShift(*pil++, *rxF, 15), dl_ch, 16); dl_ch += 12; k = (k + 4) % ue->frame_parms.ofdm_symbol_size; - rxF = (c16_t *)&rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = (c16_t *)&rxdataF[aarx][k + 1]; for (pilot_cnt=3; pilot_cnt<(3*nb_rb_coreset); pilot_cnt += 3) { multadd_real_vector_complex_scalar(fl, c16mulShift(*pil++, *rxF, 15), dl_ch, 16); k = (k + 4) % ue->frame_parms.ofdm_symbol_size; - rxF = (c16_t *)&rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = (c16_t *)&rxdataF[aarx][k + 1]; multadd_real_vector_complex_scalar(fm, c16mulShift(*pil++, *rxF, 15), dl_ch, 16); k = (k + 4) % ue->frame_parms.ofdm_symbol_size; - rxF = (c16_t *)&rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = (c16_t *)&rxdataF[aarx][k + 1]; multadd_real_vector_complex_scalar(fr, c16mulShift(*pil++, *rxF, 15), dl_ch, 16); dl_ch += 12; k = (k + 4) % ue->frame_parms.ofdm_symbol_size; - rxF = (c16_t *)&rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = (c16_t *)&rxdataF[aarx][k + 1]; } #else //ELSE CH_INTERP c32_t ch_sum = {0, 0}; @@ -915,7 +909,7 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, ch_sum.r += ch.r; ch_sum.i += ch.i; k = (k + 4) % ue->frame_parms.ofdm_symbol_size; - rxF = (c16_t *)&rxdataF[aarx][(symbol_offset + k + 1)]; + rxF = (c16_t *)&rxdataF[aarx][k + 1]; if (pilot_cnt % 3 == 2) { ch.r = ch_sum.r / 3; diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 66339e25a2..85b8999118 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -52,7 +52,7 @@ void nr_pdcch_channel_estimation(PHY_VARS_NR_UE *ue, uint16_t BWPStart, int32_t pdcch_est_size, c16_t pdcch_dl_ch_estimates[][pdcch_est_size], - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]); + c16_t rxdataF[ue->frame_parms.nb_antennas_rx][ue->frame_parms.ofdm_symbol_size]); c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp, const UE_nr_rxtx_proc_t *proc, diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index 44c560f6c7..9e48f52a03 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -41,6 +41,7 @@ #include "common/utils/nr/nr_common.h" #include #include "openair1/PHY/NR_REFSIG/nr_refsig_common.h" +#include "PHY/NR_UE_ESTIMATION/nr_estimation.h" #include "assertions.h" #include "T.h" @@ -72,10 +73,10 @@ #define RE_PER_RB_OUT_DMRS 9 static void nr_pdcch_demapping_deinterleaving(uint32_t coreset_nbr_rb, - c16_t llr[][coreset_nbr_rb * RE_PER_RB_OUT_DMRS], + c16_t *llr, c16_t *e_rx, uint8_t coreset_time_dur, - uint8_t reg_bundle_size_L, + uint8_t reg_bundle_size_L_in, uint8_t coreset_interleaver_size_R, uint8_t n_shift, uint8_t number_of_candidates, @@ -118,17 +119,11 @@ static void nr_pdcch_demapping_deinterleaving(uint32_t coreset_nbr_rb, | REG 0 (bundle 0) bundle 0 bundle 0 */ - - uint32_t coreset_C = 0; - int coreset_interleaved = 0; const int N_regs = coreset_nbr_rb * coreset_time_dur; - - if (reg_bundle_size_L != 0) { // interleaving will be done only if reg_bundle_size_L != 0 - coreset_interleaved = 1; - coreset_C = (uint32_t)(N_regs / (coreset_interleaver_size_R * reg_bundle_size_L)); - } else { - reg_bundle_size_L = 6; - } + /* interleaving will be done only if reg_bundle_size_L != 0 */ + const int coreset_C = (reg_bundle_size_L_in != 0) ? (uint32_t)(N_regs / (coreset_interleaver_size_R * reg_bundle_size_L_in)) : 0; + const int coreset_interleaved = (reg_bundle_size_L_in != 0) ? 1 : 0; + const int reg_bundle_size_L = (reg_bundle_size_L_in != 0) ? reg_bundle_size_L_in : 6; int B_rb = reg_bundle_size_L / coreset_time_dur; // nb of RBs occupied by each REG bundle int num_bundles_per_cce = 6 / reg_bundle_size_L; @@ -173,7 +168,7 @@ static void nr_pdcch_demapping_deinterleaving(uint32_t coreset_nbr_rb, for (int cce_count = 0; cce_count < L[c_id]; cce_count++) { for (int k = 0; k < NR_NB_REG_PER_CCE / reg_bundle_size_L; k++) { // loop over REG bundles int f = f_bundle_j_list_ord[c_id][k + NR_NB_REG_PER_CCE * cce_count / reg_bundle_size_L]; - c16_t *in = llr[symbol_idx] + f * B_rb * RE_PER_RB_OUT_DMRS; + c16_t *in = llr + (f * B_rb + symbol_idx * coreset_nbr_rb) * RE_PER_RB_OUT_DMRS; // loop over the RBs of the bundle memcpy(e_rx + RE_PER_RB_OUT_DMRS * rb_count, in, B_rb * RE_PER_RB_OUT_DMRS * sizeof(*e_rx)); rb_count += B_rb; @@ -200,16 +195,15 @@ static void nr_pdcch_llr(uint32_t sz, c16_t *rxF, c16_t *llr) // This function will extract the mapped DM-RS PDCCH REs as per 38.211 Section 7.4.1.3.2 (Mapping to physical resources) static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, - uint32_t coreset_nbr_rb, c16_t rxdataF[][rxdataF_sz], int32_t est_size, c16_t dl_ch_estimates[][est_size], int arraySz, c16_t rxdataF_ext[][arraySz], c16_t dl_ch_estimates_ext[][arraySz], - int symbol, NR_DL_FRAME_PARMS *frame_parms, uint8_t *coreset_freq_dom, + uint32_t coreset_nbr_rb, uint32_t n_BWP_start) { /* @@ -224,8 +218,8 @@ static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, */ for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - const c16_t *dl_ch0 = dl_ch_estimates[aarx] + frame_parms->ofdm_symbol_size * symbol; - c16_t *rxFbase = rxdataF[aarx] + frame_parms->ofdm_symbol_size * symbol; + c16_t *dl_ch0 = dl_ch_estimates[aarx]; + c16_t *rxFbase = rxdataF[aarx]; LOG_DDD("dl_ch0 = &dl_ch_estimates[aarx = (%d)][0]\n", aarx); c16_t *dl_ch0_ext = dl_ch_estimates_ext[aarx]; @@ -326,92 +320,222 @@ static void nr_pdcch_detection_mrc(int sz, c16_t rxdataF_comp[][sz]) } } -void nr_rx_pdcch(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - int32_t pdcch_est_size, - c16_t pdcch_dl_ch_estimates[][pdcch_est_size], - c16_t *pdcch_e_rx, - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) +/* Produce LLRs from received PDCCH signal */ +static void nr_rx_pdcch_symbol(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + int symbol, + int rel_symb_monOcc, + int ss_idx, + nr_phy_data_t *phy_data, + int llr_size_symbol, + c16_t rxdataF[ue->frame_parms.nb_antennas_rx][ue->frame_parms.ofdm_symbol_size], + c16_t llr[llr_size_symbol]) { - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + NR_DL_FRAME_PARMS *fp = &ue->frame_parms; + NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; + fapi_nr_coreset_t *coreset = &phy_pdcch_config->pdcch_config[ss_idx].coreset; + int32_t pdcch_est_size = ((((fp->ofdm_symbol_size + LTE_CE_FILTER_LENGTH) + 15) / 16) * 16); + __attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[fp->nb_antennas_rx][pdcch_est_size]; - int n_rb,rb_offset; - get_coreset_rballoc(rel15->coreset.frequency_domain_resource,&n_rb,&rb_offset); - const int antRx = frame_parms->nb_antennas_rx; + nr_pdcch_channel_estimation(ue, + proc, + symbol, + coreset, + fp->first_carrier_offset, + phy_pdcch_config->pdcch_config[ss_idx].BWPStart, + pdcch_est_size, + pdcch_dl_ch_estimates, + rxdataF); - // Pointer to llrs - const int symb_size = n_rb * RE_PER_RB_OUT_DMRS; - c16_t llr[rel15->coreset.duration][symb_size]; + const int32_t rx_size = ((4 * fp->N_RB_DL * 12 + 31) >> 5) << 5; + __attribute__((aligned(32))) c16_t rxdataF_ext[fp->nb_antennas_rx][rx_size]; + __attribute__((aligned(32))) c16_t rxdataF_comp[fp->nb_antennas_rx][rx_size]; + __attribute__((aligned(32))) c16_t pdcch_dl_ch_estimates_ext[fp->nb_antennas_rx][rx_size]; + memset(rxdataF_comp, 0, sizeof(rxdataF_comp)); - LOG_D(NR_PHY_DCI, - "pdcch coreset: freq %x, n_rb %d, rb_offset %d\n", - rel15->coreset.frequency_domain_resource[0], - n_rb, - rb_offset); - for (int s = 0; s < rel15->coreset.duration; s++) { - LOG_D(NR_PHY_DCI, "in nr_pdcch_extract_rbs_single(rxdataF -> rxdataF_ext || dl_ch_estimates -> dl_ch_estimates_ext)\n"); - const int arraySz = ceil_mod(symb_size, 32); - __attribute__((aligned(32))) c16_t rxdataF_ext[antRx][arraySz]; - __attribute__((aligned(32))) c16_t pdcch_dl_ch_estimates_ext[antRx][arraySz]; - nr_pdcch_extract_rbs_single(ue->frame_parms.samples_per_slot_wCP, - n_rb, - rxdataF, - pdcch_est_size, - pdcch_dl_ch_estimates, - arraySz, + int n_rb; + int rb_offset; + get_coreset_rballoc(coreset->frequency_domain_resource, &n_rb, &rb_offset); + + nr_pdcch_extract_rbs_single(ue->frame_parms.ofdm_symbol_size, + rxdataF, + pdcch_est_size, + pdcch_dl_ch_estimates, + rx_size, + rxdataF_ext, + pdcch_dl_ch_estimates_ext, + fp, + coreset->frequency_domain_resource, + n_rb, + phy_pdcch_config->pdcch_config[ss_idx].BWPStart); + + LOG_D(NR_PHY_DCI, "in channel level function (dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); + int avg[fp->nb_antennas_rx]; + nr_channel_level(0, rx_size, pdcch_dl_ch_estimates_ext, fp->nb_antennas_rx, 1, avg, n_rb * RE_PER_RB_OUT_DMRS); + int avgs = avg[0]; + for (int i = 1; i < fp->nb_antennas_rx; i++) + avgs = cmax(avgs, avg[i]); + const int log2_maxh = (log2_approx(avgs) / 2) + 5; //+frame_parms->nb_antennas_rx; + + nr_pdcch_channel_compensation(rx_size, rxdataF_ext, pdcch_dl_ch_estimates_ext, - rel15->coreset.StartSymbolIndex + s, - frame_parms, - rel15->coreset.frequency_domain_resource, - rel15->BWPStart); + rxdataF_comp, + fp->nb_antennas_rx, + log2_maxh); // log2_maxh+I0_shift - LOG_D(NR_PHY_DCI, "in channel level function (dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); - // compute channel level based on ofdm symbol 0 - int avg[antRx]; - nr_channel_level(0, arraySz, pdcch_dl_ch_estimates_ext, antRx, 1, avg, n_rb); - int avgs = avg[0]; - for (int i = 1; i < antRx; i++) - avgs = cmax(avgs, avg[i]); - uint8_t log2_maxh = (log2_approx(avgs) / 2) + 5; //+antRx; + UEscopeCopy(ue, pdcchRxdataF_comp, rxdataF_comp, sizeof(struct complex16), fp->nb_antennas_rx, rx_size, 0); -#ifdef UE_DEBUG_TRACE - LOG_D(NR_PHY_DCI, "slot %d: pdcch log2_maxh = %d (%d,%d)\n", proc->nr_slot_rx, log2_maxh, avgP[0], avgs); -#endif -#if T_TRACER - T(T_UE_PHY_PDCCH_ENERGY, T_INT(0), T_INT(0), T_INT(proc->frame_rx % 1024), T_INT(proc->nr_slot_rx), T_INT(avgs)); -#endif - LOG_D(NR_PHY_DCI, "we enter nr_pdcch_channel_compensation(log2_maxh=%d)\n", log2_maxh); - LOG_D(NR_PHY_DCI, "in nr_pdcch_channel_compensation(rxdataF_ext x dl_ch_estimates_ext -> rxdataF_comp)\n"); - // compute LLRs for ofdm symbol 0 only - __attribute__((aligned(32))) c16_t rxdataF_comp[antRx][arraySz]; - nr_pdcch_channel_compensation(arraySz, - rxdataF_ext, - pdcch_dl_ch_estimates_ext, - rxdataF_comp, - antRx, - log2_maxh); // log2_maxh+I0_shift - - UEscopeCopy(ue, pdcchRxdataF_comp, rxdataF_comp, sizeof(struct complex16), antRx, symb_size, 0); - - if (antRx > 1) - nr_pdcch_detection_mrc(arraySz, rxdataF_comp); - - nr_pdcch_llr(symb_size, rxdataF_comp[0], llr[s]); + if (fp->nb_antennas_rx > 1) { + nr_pdcch_detection_mrc(rx_size, rxdataF_comp); } - UEscopeCopy(ue, pdcchLlr, llr, sizeof(c16_t), 1, rel15->coreset.duration * symb_size, 0); - nr_pdcch_demapping_deinterleaving(n_rb, - llr, - pdcch_e_rx, - rel15->coreset.duration, - rel15->coreset.RegBundleSize, - rel15->coreset.InterleaverSize, - rel15->coreset.ShiftIndex, - rel15->number_of_candidates, - rel15->CCE, - rel15->L); + nr_pdcch_llr(llr_size_symbol, rxdataF_comp[0], llr); +} + +bool is_start_symbol_in_ss(const fapi_nr_dl_config_dci_dl_pdu_rel15_t *ss, const int symbol) +{ + return ((ss->coreset.StartSymbolBitmap >> (NR_SYMBOLS_PER_SLOT - 1 - symbol)) & 1); +} + +int get_pdcch_mon_occasions_slot(const fapi_nr_dl_config_dci_dl_pdu_rel15_t *ss, uint8_t start_symb[NR_SYMBOLS_PER_SLOT]) +{ + int sum = 0; + for (int s = 0; s < NR_SYMBOLS_PER_SLOT; s++) { + if (is_start_symbol_in_ss(ss, s)) { + if (start_symb != NULL) + start_symb[sum] = s; + sum++; + } + } + + return sum; +} + +int get_max_pdcch_monOcc(const NR_UE_PDCCH_CONFIG *phy_pdcch_config) +{ + int monOcc = 0; + for (int ss = 0; ss < phy_pdcch_config->nb_search_space; ss++) { + monOcc = max(monOcc, get_pdcch_mon_occasions_slot(&phy_pdcch_config->pdcch_config[ss], NULL)); + } + return monOcc; +} + +static void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + c16_t *pdcch_e_rx, + fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, + fapi_nr_dci_indication_t *dci_ind); + +void set_first_last_pdcch_symb(const NR_UE_PDCCH_CONFIG *phy_pdcch_config, int *first_symb, int *last_symb) +{ + *first_symb = NR_SYMBOLS_PER_SLOT; // max first pdcch symbol + *last_symb = 0; // min last pdcch symbol + for (int ss = 0; ss < phy_pdcch_config->nb_search_space; ss++) { + for (int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) { + if (is_start_symbol_in_ss(&phy_pdcch_config->pdcch_config[ss], symb)) { + const int duration = phy_pdcch_config->pdcch_config[ss].coreset.duration; + *first_symb = min(*first_symb, symb); + *last_symb = max(*last_symb, symb + duration - 1); + } + } + } +} + +/* Generates PDCCH LLRs from received symbol for each Search-Space */ +void nr_pdcch_generate_llr(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + int symbol, + nr_phy_data_t *phy_data, + int llr_size_symbol, + int num_monitoring_occ, + int max_symb, + c16_t rxdataF[ue->frame_parms.nb_antennas_rx][ue->frame_parms.ofdm_symbol_size], + c16_t pdcch_llr[phy_data->phy_pdcch_config.nb_search_space][num_monitoring_occ][max_symb * llr_size_symbol]) +{ + const NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; + + // Loop over search spaces + for (int ss_idx = 0; ss_idx < phy_pdcch_config->nb_search_space; ss_idx++) { + uint8_t start_symb[NR_SYMBOLS_PER_SLOT] = {0}; + const int num_monOcc = get_pdcch_mon_occasions_slot(&phy_pdcch_config->pdcch_config[ss_idx], start_symb); + // Loop over monitoring occations within the slot in this ss + for (int occ = 0; occ < num_monOcc; occ++) { + const int first_symb = start_symb[occ]; + const int last_symb = first_symb + phy_pdcch_config->pdcch_config[ss_idx].coreset.duration; + // Decode PDCCH and generate LLR for each ss in this OFDM symbol + if ((symbol >= first_symb) && (symbol < last_symb)) { + const int rel_symb_monOcc = symbol - first_symb; + nr_rx_pdcch_symbol(ue, + proc, + symbol, + rel_symb_monOcc, + ss_idx, + phy_data, + llr_size_symbol, + rxdataF, + &pdcch_llr[ss_idx][occ][rel_symb_monOcc * llr_size_symbol]); + } + } + } +} + +/* Decode DCI from LLRs for each Search-Space and send to MAC */ +void nr_pdcch_dci_indication(const UE_nr_rxtx_proc_t *proc, + int llr_size, + int max_monOcc, + PHY_VARS_NR_UE *ue, + nr_phy_data_t *phy_data, + c16_t llr[phy_data->phy_pdcch_config.nb_search_space][max_monOcc][llr_size]) +{ + NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; + + nr_downlink_indication_t dl_indication; + fapi_nr_dci_indication_t dci_ind = {.SFN = proc->frame_rx, .slot = proc->nr_slot_rx}; + + for (int ss_idx = 0; ss_idx < phy_pdcch_config->nb_search_space; ss_idx++) { + fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &phy_pdcch_config->pdcch_config[ss_idx]; + uint8_t unused_start_symb[NR_SYMBOLS_PER_SLOT] = {0}; + const int num_monitoring_occ = get_pdcch_mon_occasions_slot(rel15, unused_start_symb); + + int n_rb; + int rb_offset; + get_coreset_rballoc(rel15->coreset.frequency_domain_resource, &n_rb, &rb_offset); + + for (int m = 0; m < num_monitoring_occ; m++) { + /// PDCCH/DCI e-sequence (input to rate matching). + c16_t pdcch_e_rx[NR_MAX_PDCCH_SIZE]; + + nr_pdcch_demapping_deinterleaving(n_rb, + llr[ss_idx][m], + pdcch_e_rx, + rel15->coreset.duration, + rel15->coreset.RegBundleSize, + rel15->coreset.InterleaverSize, + rel15->coreset.ShiftIndex, + rel15->number_of_candidates, + rel15->CCE, + rel15->L); + + nr_dci_decoding_procedure(ue, proc, pdcch_e_rx, rel15, &dci_ind); + } + } + + for (int i = 0; i < dci_ind.number_of_dcis; i++) { + LOG_D(PHY, + "Frame.slot: %d.%d: DCI %i of %d total DCIs found --> rnti %x : format %d\n", + proc->frame_rx, + proc->nr_slot_rx, + i + 1, + dci_ind.number_of_dcis, + dci_ind.dci_list[i].rnti, + dci_ind.dci_list[i].dci_format); + } + + /* Send to MAC */ + nr_fill_dl_indication(&dl_indication, &dci_ind, NULL, proc, ue, phy_data); + ue->if_inst->dl_indication(&dl_indication); + phy_pdcch_config->nb_search_space = 0; } static void nr_pdcch_unscrambling(c16_t *e_rx, @@ -433,14 +557,13 @@ static void nr_pdcch_unscrambling(c16_t *e_rx, } } -void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - c16_t *pdcch_e_rx, - fapi_nr_dci_indication_t *dci_ind, - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15) +static void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + c16_t *pdcch_e_rx, + fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, + fapi_nr_dci_indication_t *dci_ind) { int e_rx_cand_idx = 0; - *dci_ind = (fapi_nr_dci_indication_t){.SFN = proc->frame_rx, .slot = proc->nr_slot_rx}; // if DCI for SIB we don't break after finding 1st DCI with that RNTI // there might be SIB1 and otherSIB in the same slot with the same length bool is_SI = rel15->rnti == SI_RNTI; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 41747a9ef1..ed348986e8 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -69,6 +69,12 @@ typedef struct pdsch_scope_req_s { void nr_ue_dlsch_init(NR_UE_DLSCH_t *dlsch_list, int num_dlsch, uint8_t max_ldpc_iterations); void nr_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned short nb_rb, unsigned char output_shift0); +void set_first_last_pdcch_symb(const NR_UE_PDCCH_CONFIG *phy_pdcch_config, int *first_symb, int *last_symb); + +int get_pdcch_mon_occasions_slot(const fapi_nr_dl_config_dci_dl_pdu_rel15_t *ss, uint8_t start_symb[NR_SYMBOLS_PER_SLOT]); + +int get_max_pdcch_monOcc(const NR_UE_PDCCH_CONFIG *phy_pdcch_config); + /** \brief This is the alternative top-level entry point for DLSCH decoding in UE. It handles all the HARQ processes in only one call. The routine first computes the segmentation information and then call LDPC decoder on the @@ -180,14 +186,6 @@ void nr_dlsch_unscrambling(int16_t* llr, uint32_t Nid, uint32_t n_RNTI); -void nr_rx_pdcch(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - int32_t pdcch_est_size, - c16_t pdcch_dl_ch_estimates[][pdcch_est_size], - c16_t *pdcch_e_rx, - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]); - /*! \brief Performs detection of SSS to find cell ID and other framing parameters (FDD/TDD, normal/extended prefix) @param phy_vars_ue Pointer to UE variables @param tot_metric Pointer to variable containing maximum metric under framing hypothesis (to be compared to other hypotheses @@ -279,12 +277,6 @@ void nr_sl_rf_card_config_freq(PHY_VARS_NR_UE *ue, openair0_config_t *openair0_cfg, int freq_offset); -void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - c16_t *pdcch_e_rx, - fapi_nr_dci_indication_t *dci_ind, - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15); - /** \brief This function is the top-level entry point to PDSCH demodulation, after frequency-domain transformation and channel estimation. It performs - RB extraction (signal and channel estimates) diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index e3c92ba5d4..3ba5226542 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -138,13 +138,22 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, void *typeSpecific, uint8_t *b); -int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue, +void nr_pdcch_generate_llr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, - int32_t pdcch_est_size, - c16_t pdcch_dl_ch_estimates[][pdcch_est_size], + int symbol, nr_phy_data_t *phy_data, - int n_ss, - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]); + int llr_size_symbol, + int num_monitoring_occ, + int max_symb, + c16_t rxdataF[ue->frame_parms.nb_antennas_rx][ue->frame_parms.ofdm_symbol_size], + c16_t pdcch_llr[phy_data->phy_pdcch_config.nb_search_space][num_monitoring_occ][max_symb * llr_size_symbol]); + +void nr_pdcch_dci_indication(const UE_nr_rxtx_proc_t *proc, + int llr_size, + int max_monOcc, + PHY_VARS_NR_UE *ue, + nr_phy_data_t *phy_data, + c16_t llr[phy_data->phy_pdcch_config.nb_search_space][max_monOcc][llr_size]); void nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index f18862e0aa..490b06c83c 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -527,53 +527,6 @@ static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue, return ret; } -int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - int32_t pdcch_est_size, - c16_t pdcch_dl_ch_estimates[][pdcch_est_size], - nr_phy_data_t *phy_data, - int n_ss, - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) -{ - int frame_rx = proc->frame_rx; - int nr_slot_rx = proc->nr_slot_rx; - NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; - - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15 = &phy_pdcch_config->pdcch_config[n_ss]; - - start_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS); - - /// PDCCH/DCI e-sequence (input to rate matching). - int32_t pdcch_e_rx_size = NR_MAX_PDCCH_SIZE; - c16_t pdcch_e_rx[pdcch_e_rx_size]; - - nr_rx_pdcch(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, pdcch_e_rx, rel15, rxdataF); - - fapi_nr_dci_indication_t dci_ind; - nr_dci_decoding_procedure(ue, proc, pdcch_e_rx, &dci_ind, rel15); - - for (int i = 0; i < dci_ind.number_of_dcis; i++) { - LOG_D(PHY, - "[UE %d] AbsSubFrame %d.%d: DCI %i of %d total DCIs found --> rnti %x : format %d\n", - ue->Mod_id, - frame_rx % 1024, - nr_slot_rx, - i + 1, - dci_ind.number_of_dcis, - dci_ind.dci_list[i].rnti, - dci_ind.dci_list[i].dci_format); - } - - nr_downlink_indication_t dl_indication; - // fill dl_indication message - nr_fill_dl_indication(&dl_indication, &dci_ind, NULL, proc, ue, phy_data); - // send to mac - ue->if_inst->dl_indication(&dl_indication); - stop_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PDCCH_PROCEDURES, VCD_FUNCTION_OUT); - return (dci_ind.number_of_dcis); -} - static freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]) { freq_alloc_bitmap_t alloc = { @@ -1027,46 +980,68 @@ static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index) return ue->frame_parms.ssb_index == index; } +static int get_pdcch_max_rbs(NR_UE_PDCCH_CONFIG *phy_pdcch_config) +{ + int nb_rb = 0; + int rb_offset = 0; + for (int i = 0; i < phy_pdcch_config->nb_search_space; i++) { + int tmp = 0; + get_coreset_rballoc(phy_pdcch_config->pdcch_config[i].coreset.frequency_domain_resource, &tmp, &rb_offset); + if (tmp > nb_rb) + nb_rb = tmp; + } + return nb_rb; +} + +static int get_max_pdcch_symb(const NR_UE_PDCCH_CONFIG *phy_pdcch_config) +{ + int max_pdcch_symb = 0; + for (int i = 0; i < phy_pdcch_config->nb_search_space; i++) + if (phy_pdcch_config->pdcch_config[i].coreset.duration > max_pdcch_symb) + max_pdcch_symb = phy_pdcch_config->pdcch_config[i].coreset.duration; + + return max_pdcch_symb; +} + void pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data) { - TracyCZone(ctx); - NR_DL_FRAME_PARMS *fp = &ue->frame_parms; + TracyCZone(ctx, true); + /* process PDCCH */ + LOG_D(PHY, " ------ --> PDCCH ChannelComp/LLR Frame.slot %d.%d ------ \n", proc->frame_rx % 1024, proc->nr_slot_rx); + start_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS); NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; + int num_monitoring_occ = get_max_pdcch_monOcc(phy_pdcch_config); + int max_nb_symb_pdcch = get_max_pdcch_symb(phy_pdcch_config); + int llr_size_symbol = get_pdcch_max_rbs(phy_pdcch_config) * 9; + c16_t pdcch_llr[phy_pdcch_config->nb_search_space][num_monitoring_occ][max_nb_symb_pdcch * llr_size_symbol]; + + int start_symb_pdcch, last_symb_pdcch; + set_first_last_pdcch_symb(phy_pdcch_config, &start_symb_pdcch, &last_symb_pdcch); + + /* Temporarily loop over symbols in the slot, perform OFDM demod and process PDCCH. + When symbol based proc design is fully merged, this function will be called to process only one symbol + and OFDM demod will be removed from here. */ const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP; - __attribute__ ((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz]; + __attribute__((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz]; - uint8_t nb_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.duration : 0; - int first_symb_pdcch = phy_pdcch_config->nb_search_space > 0 ? phy_pdcch_config->pdcch_config[0].coreset.StartSymbolIndex : 0; - int last_symb_pdcch = first_symb_pdcch + nb_symb_pdcch; - for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) { - nr_slot_fep(ue, fp, proc->nr_slot_rx, l, rxdataF, link_type_dl, 0, ue->common_vars.rxdata); - } + for (int symbol = start_symb_pdcch; symbol <= last_symb_pdcch; symbol++) { + NR_DL_FRAME_PARMS *fp = &ue->frame_parms; + nr_slot_fep(ue, fp, proc->nr_slot_rx, symbol, rxdataF, link_type_dl, 0, ue->common_vars.rxdata); + __attribute__((aligned(32))) c16_t rxdataF_symb[fp->nb_antennas_rx][((fp->ofdm_symbol_size + 7) / 8) * 8]; - // Hold the channel estimates in frequency domain. - int32_t pdcch_est_size = ((((fp->symbols_per_slot*(fp->ofdm_symbol_size+LTE_CE_FILTER_LENGTH))+15)/16)*16); - __attribute__((aligned(16))) c16_t pdcch_dl_ch_estimates[fp->nb_antennas_rx][pdcch_est_size]; + for (int ant = 0; ant < fp->nb_antennas_rx; ant++) + memcpy(rxdataF_symb[ant], &rxdataF[ant][symbol * fp->ofdm_symbol_size], sizeof(c16_t) * fp->ofdm_symbol_size); - uint8_t dci_cnt = 0; - for(int n_ss = 0; n_ssnb_search_space; n_ss++) { - for (int l = first_symb_pdcch; l < last_symb_pdcch; l++) { - // note: this only works if RBs for PDCCH are contigous! - nr_pdcch_channel_estimation(ue, - proc, - l, - &phy_pdcch_config->pdcch_config[n_ss].coreset, - fp->first_carrier_offset, - phy_pdcch_config->pdcch_config[n_ss].BWPStart, - pdcch_est_size, - pdcch_dl_ch_estimates, - rxdataF); + nr_pdcch_generate_llr(ue, proc, symbol, phy_data, llr_size_symbol, num_monitoring_occ, max_nb_symb_pdcch, rxdataF_symb, pdcch_llr); + if (symbol == last_symb_pdcch) { + nr_pdcch_dci_indication(proc, llr_size_symbol * max_nb_symb_pdcch, num_monitoring_occ, ue, phy_data, pdcch_llr); + UEscopeCopy(ue, pdcchLlr, pdcch_llr, sizeof(c16_t), 1, sizeof(pdcch_llr), 0); } - dci_cnt = dci_cnt + nr_ue_pdcch_procedures(ue, proc, pdcch_est_size, pdcch_dl_ch_estimates, phy_data, n_ss, rxdataF); } - LOG_D(PHY, "[UE %d] Frame %d, nr_slot_rx %d: found %d DCIs\n", ue->Mod_id, proc->frame_rx, proc->nr_slot_rx, dci_cnt); - phy_pdcch_config->nb_search_space = 0; + stop_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS); TracyCZoneEnd(ctx); if (ue->phy_sim_rxdataF) - memcpy(ue->phy_sim_rxdataF, rxdataF[0], sizeof(int32_t) * nb_symb_pdcch * ue->frame_parms.ofdm_symbol_size); + memcpy(ue->phy_sim_rxdataF, rxdataF[0], sizeof(int32_t) * max_nb_symb_pdcch * ue->frame_parms.ofdm_symbol_size); } int pbch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data) diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 6279663e74..4b44b34091 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -110,17 +110,6 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, { } -int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - int32_t pdcch_est_size, - c16_t pdcch_dl_ch_estimates[][pdcch_est_size], - nr_phy_data_t *phy_data, - int n_ss, - c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]) -{ - return 0; -} - configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index 218a513ec7..8a2074422e 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -307,12 +307,7 @@ static void config_dci_pdu(NR_UE_MAC_INST_t *mac, break; } - for (int i = 0; i < sps; i++) { - if ((monitoringSymbolsWithinSlot >> (sps - 1 - i)) & 1) { - rel15->coreset.StartSymbolIndex = i; - break; - } - } + rel15->coreset.StartSymbolBitmap = monitoringSymbolsWithinSlot; uint32_t Y = 0; if (ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) Y = get_Y(ss, slot, rel15->rnti); From 7807016ae62ba5a078a99dabfaf0c9133ddfb815 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Fri, 12 Sep 2025 18:51:54 -0400 Subject: [PATCH 25/61] pdcch: return pdcch processing is no ss configured --- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 490b06c83c..3f476ec7db 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -1005,11 +1005,14 @@ static int get_max_pdcch_symb(const NR_UE_PDCCH_CONFIG *phy_pdcch_config) void pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data) { + NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; + if (phy_pdcch_config->nb_search_space == 0) + return; + TracyCZone(ctx, true); /* process PDCCH */ LOG_D(PHY, " ------ --> PDCCH ChannelComp/LLR Frame.slot %d.%d ------ \n", proc->frame_rx % 1024, proc->nr_slot_rx); start_meas_nr_ue_phy(ue, DLSCH_RX_PDCCH_STATS); - NR_UE_PDCCH_CONFIG *phy_pdcch_config = &phy_data->phy_pdcch_config; int num_monitoring_occ = get_max_pdcch_monOcc(phy_pdcch_config); int max_nb_symb_pdcch = get_max_pdcch_symb(phy_pdcch_config); int llr_size_symbol = get_pdcch_max_rbs(phy_pdcch_config) * 9; From 48773b8517cf4795a73ec08a61fea0b5cc4544f2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 6 Oct 2025 17:51:17 +0200 Subject: [PATCH 26/61] fix handling of CSI measurement reports at L2 UE --- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 12 +++++-- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 33 +++++++++++--------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index b7ebd5a651..f8b9f18c11 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -431,6 +431,14 @@ typedef struct { float_t ssb_sinr_dB; } NR_SSB_meas_t; +typedef struct { + int rsrp_dBm; + uint8_t ri; + uint16_t i1; + uint8_t i2; + uint8_t cqi; +} NR_CSIRS_meas_t; + typedef enum ta_type { no_ta = 0, adjustment_ta, @@ -601,9 +609,6 @@ typedef struct NR_UE_MAC_INST_s { nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; - /// measurements from SS or CSI-RS - fapi_nr_l1_measurements_t l1_measurements; - //// FAPI-like interface message fapi_nr_ul_config_request_t *ul_config_request; fapi_nr_dl_config_request_t *dl_config_request; @@ -633,6 +638,7 @@ typedef struct NR_UE_MAC_INST_s { int ssb_start_subcarrier; NR_SSB_meas_t ssb_measurements[MAX_NB_SSB]; + NR_CSIRS_meas_t csirs_measurements; dci_pdu_rel15_t def_dci_pdu_rel15[NR_MAX_SLOTS_PER_FRAME][8]; diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 1f35df5c4b..c78d2217b4 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -307,7 +307,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca release_ul_BWP(mac, i); memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); - memset(&mac->l1_measurements, 0, sizeof(mac->l1_measurements)); + memset(&mac->csirs_measurements, 0, sizeof(mac->csirs_measurements)); memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); for (int i = mac->TAG_list.count; i > 0 ; i--) asn_sequence_del(&mac->TAG_list, i - 1, 1); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 7818b08362..28e7b7d42b 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1508,13 +1508,18 @@ nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements) { - LOG_D(NR_MAC, "(%d.%d) Received CSI-RS measurements\n", frame, slot); - memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements)); + LOG_D(NR_MAC, "(%d.%d) Received measurements from L1\n", frame, slot); bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS; if (!csi_meas && !l1_measurements->is_neighboring_cell) { int ssb_index = l1_measurements->ssb_index; mac->ssb_measurements[ssb_index].ssb_rsrp_dBm = l1_measurements->rsrp_dBm; mac->ssb_measurements[ssb_index].ssb_sinr_dB = l1_measurements->sinr_dB; + } else if (csi_meas) { + mac->csirs_measurements.rsrp_dBm = l1_measurements->rsrp_dBm; + mac->csirs_measurements.i1 = l1_measurements->i1; + mac->csirs_measurements.i2 = l1_measurements->i2; + mac->csirs_measurements.cqi = l1_measurements->cqi; + mac->csirs_measurements.ri = l1_measurements->rank_indicator; } nr_mac_rrc_meas_ind_ue(mac->ue_id, l1_measurements->gNB_index, @@ -3026,28 +3031,28 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, AssertFatal(csi_report, "Couldn't find CSI report with ID %ld\n", csi_reportconfig->reportConfigId); int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->l1_measurements.rank_indicator]; - int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->l1_measurements.rank_indicator]; - int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->l1_measurements.rank_indicator]; + int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->csirs_measurements.ri]; + int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->csirs_measurements.ri]; + int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->csirs_measurements.ri]; int padding_bitlen = 0; // TODO: Improvements will be needed to cri_bitlen>0 and pmi_x1_bitlen>0 if (mapping_type == ON_PUSCH) { p1_bits = cri_bitlen + ri_bitlen + cqi_bitlen; p2_bits = pmi_x1_bitlen + pmi_x2_bitlen; temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + ri_bitlen)) | - (mac->l1_measurements.rank_indicator << cqi_bitlen) | - (mac->l1_measurements.cqi); - temp_payload_2 = (mac->l1_measurements.i1 << pmi_x2_bitlen) | - mac->l1_measurements.i2; + (mac->csirs_measurements.ri << cqi_bitlen) | + (mac->csirs_measurements.cqi); + temp_payload_2 = (mac->csirs_measurements.i1 << pmi_x2_bitlen) | + mac->csirs_measurements.i2; } else { p1_bits = nr_get_csi_bitlen(csi_report); padding_bitlen = p1_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen); temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen + ri_bitlen)) | - (mac->l1_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) | - (mac->l1_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) | - (mac->l1_measurements.i2 << (cqi_bitlen)) | - (mac->l1_measurements.cqi); + (mac->csirs_measurements.ri << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) | + (mac->csirs_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) | + (mac->csirs_measurements.i2 << (cqi_bitlen)) | + (mac->csirs_measurements.cqi); } temp_payload_1 = reverse_bits(temp_payload_1, p1_bits); @@ -3106,7 +3111,7 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, } // TODO: Improvements will be needed to cri_ssbri_bitlen>0 - temp_payload = get_rsrp_index(mac->l1_measurements.rsrp_dBm); + temp_payload = get_rsrp_index(mac->csirs_measurements.rsrp_dBm); temp_payload = reverse_bits(temp_payload, n_bits); LOG_D(NR_MAC, "cri_ssbri_bitlen = %d\n", cri_ssbri_bitlen); From df3a768811a4d340b8cf3491330e9d140077179c Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 7 Oct 2025 15:36:28 +0200 Subject: [PATCH 27/61] fix updating nrofReportedRS after reconfiguration --- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index a2b7c26678..da436142ec 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -3867,8 +3867,15 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, NR_CSI_MeasConfig_t *csi_MeasConfig = spCellConfigDedicated->csi_MeasConfig->choice.setup; for (int report = 0; report < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; report++) { NR_CSI_ReportConfig_t *csirep = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[report]; - if(csirep->codebookConfig) + if (csirep->codebookConfig) config_csi_codebook(&configuration->pdsch_AntennaPorts, *pdsch_servingcellconfig->ext1->maxMIMO_Layers, csirep->codebookConfig); + if (csirep->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled + && csirep->groupBasedBeamReporting.choice.disabled + && csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + *csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = config_nrofReportedRS(uecap, + get_ssb_bitmap(scc), + scc, + configuration->max_num_rsrp); } NR_UplinkConfig_t *uplinkConfig = spCellConfigDedicated->uplinkConfig; From 5b5b9b3a300ba56848ebd531cab965320057796f Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Tue, 21 Oct 2025 15:02:01 +0200 Subject: [PATCH 28/61] CI: remove nssai_sd UE config when default value is used The SD value defaults to 0xffffff (16777215 in decimal) when not explicitly set on the UE. --- ci-scripts/conf_files/nrue.band78.106prb.l2sim.conf | 1 - ci-scripts/conf_files/ue.sa.conf | 1 - ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ci-scripts/conf_files/nrue.band78.106prb.l2sim.conf b/ci-scripts/conf_files/nrue.band78.106prb.l2sim.conf index 45d192dc04..0dfd31a789 100644 --- a/ci-scripts/conf_files/nrue.band78.106prb.l2sim.conf +++ b/ci-scripts/conf_files/nrue.band78.106prb.l2sim.conf @@ -14,7 +14,6 @@ key = "fec86ba6eb707ed08905757b1bb44b8f"; opc= "C42449363BBAD02B66D16BC975D77CC1"; dnn= "oai"; nssai_sst=1; -nssai_sd=16777215; } MACRLCs = ( diff --git a/ci-scripts/conf_files/ue.sa.conf b/ci-scripts/conf_files/ue.sa.conf index 9101c7e8e9..dc744fb732 100644 --- a/ci-scripts/conf_files/ue.sa.conf +++ b/ci-scripts/conf_files/ue.sa.conf @@ -4,7 +4,6 @@ uicc0 = { opc= "c42449363bbad02b66d16bc975d77cc1"; dnn= "oai"; nssai_sst=1; - nssai_sd=66051; } thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" diff --git a/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml index aac787a916..9fb80ad065 100644 --- a/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml @@ -17,7 +17,7 @@ services: #entrypoint: /bin/bash -c "sleep infinity" environment: TZ: Europe/Paris - USE_ADDITIONAL_OPTIONS: --usrp-args type=n3xx,name=ni-n3xx-31641B9,addr=192.168.10.2 -r 106 --numerology 1 --band 78 -C 3425010000 --ssb 509 --ue-fo-compensation --ue-rxgain 65 --tune-offset 20000000 -A 90 --log_config.global_log_options level,nocolor,time --uicc0.imsi 001020000000111 --uicc0.nssai_sd 16777215 + USE_ADDITIONAL_OPTIONS: --usrp-args type=n3xx,name=ni-n3xx-31641B9,addr=192.168.10.2 -r 106 --numerology 1 --band 78 -C 3425010000 --ssb 509 --ue-fo-compensation --ue-rxgain 65 --tune-offset 20000000 -A 90 --log_config.global_log_options level,nocolor,time --uicc0.imsi 001020000000111 volumes: - ../../conf_files/ue.sa.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: From a0f58d7104614ca8d6c5e97fdee50292706a5b44 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Tue, 21 Oct 2025 15:22:10 +0200 Subject: [PATCH 29/61] CI: Update CI conf files Update based on !3645 Note: For some test configurations we still need to provide ra_ResponseWindow, for more details, check commit message of 41d14b571c80c43a77078e83d8c115547b8748c5 --- .../conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf | 3 +-- ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf index 4be45f6e19..41e9974caf 100644 --- a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf +++ b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf @@ -106,8 +106,7 @@ gNBs = pucchGroupHopping = 0; hoppingId = 40; p0_nominal = -90; -# ssb_PositionsInBurs_BitmapPR -# 1=short, 2=medium, 3=long + ssb_PositionsInBurst_Bitmap = 1; # ssb_periodicityServingCell # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml index 6c03a02443..f3b75c1471 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml @@ -150,7 +150,6 @@ services: --telnetsrv --telnetsrv.listenaddr 192.168.71.171 --telnetsrv.shrmod ci --rfsimulator.serveraddr 192.168.71.190 - --gNBs.[0].servingCellConfigCommon.[0].ra_ResponseWindow 5 ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 depends_on: - oai-cucp-0 From 70d23e43df436768b5e8d98a83713a063a67c89c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 20:24:05 +0200 Subject: [PATCH 30/61] Fetch sdap configuration from sdap-config and store in new struct sdap_config_t This function is processing the NR_SDAP_Config_t received (from RRC) and is storing the SDAP configuration in a structure of type sdap_config_t. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 34 ++++++++++++++++++++++++++ openair2/SDAP/nr_sdap/nr_sdap_entity.h | 14 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 6860fba6e6..4c02318e57 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -653,6 +653,40 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id) return ret; } +/** @brief This function gets the relevant SDAP config from the received SDAP-Config */ +sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_Config, const int drb_id) +{ + DevAssert(sdap_Config); + sdap_config_t sdapConfig = {0}; + sdapConfig.drb_id = drb_id; + sdapConfig.sdap_rx = is_sdap_rx(is_gnb, sdap_Config); + sdapConfig.sdap_tx = is_sdap_tx(is_gnb, sdap_Config); + sdapConfig.defaultDRB = sdap_Config->defaultDRB; + // 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true + if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present)) + LOG_D(SDAP, "Received SDAP-Config with defaultDRB but sdap-HeaderUL is not present\n"); + if (sdap_Config->mappedQoS_FlowsToAdd) { + sdapConfig.mappedQFIs2AddCount = sdap_Config->mappedQoS_FlowsToAdd->list.count; + DevAssert(sdapConfig.mappedQFIs2AddCount <= SDAP_MAX_QFI); + LOG_D(SDAP, "DRB %d: mapped QFIs = %d \n", sdapConfig.drb_id, sdapConfig.mappedQFIs2AddCount); + for (int i = 0; i < sdapConfig.mappedQFIs2AddCount; i++){ + DevAssert(i < SDAP_MAX_QFI); + sdapConfig.mappedQFIs2Add[i] = *sdap_Config->mappedQoS_FlowsToAdd->list.array[i]; + LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd[%d] from RRC: %ld\n", i, sdapConfig.mappedQFIs2Add[i]); + } + } + sdapConfig.pdusession_id = sdap_Config->pdu_Session; + if (sdap_Config->mappedQoS_FlowsToRelease) { + sdapConfig.mappedQFIs2ReleaseCount = sdap_Config->mappedQoS_FlowsToRelease->list.count; + DevAssert(sdapConfig.mappedQFIs2ReleaseCount <= SDAP_MAX_QFI); + for (int i = 0; i < sdapConfig.mappedQFIs2ReleaseCount; i++) { + DevAssert(i < SDAP_MAX_QFI); + sdapConfig.mappedQFIs2Release[i] = *sdap_Config->mappedQoS_FlowsToRelease->list.array[i]; + } + } + return sdapConfig; +} + /** * @brief SDAP Entity reconfiguration at UE according to TS 37.324 * and triggered by RRC reconfiguration events according to clause 5.3.5.6.5 of TS 38.331. diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 3a42c6c076..3e3d95c3db 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -77,6 +77,18 @@ typedef struct qfi2drb_s { void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); +typedef struct { + int pdusession_id; + int drb_id; + bool sdap_rx; + bool sdap_tx; + bool defaultDRB; + NR_QFI_t mappedQFIs2Add[SDAP_MAX_QFI]; + uint8_t mappedQFIs2AddCount; + NR_QFI_t mappedQFIs2Release[SDAP_MAX_QFI]; + uint8_t mappedQFIs2ReleaseCount; +} sdap_config_t; + typedef struct nr_sdap_entity_s { ue_id_t ue_id; rb_id_t default_drb; @@ -180,6 +192,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, /* Entity Handling Related Functions */ nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id); +sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_Config, const int drb_id); + void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id); /** From e3aa91dec8acdc92c1111b5e442684ec8a91a660 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 22 Oct 2025 09:24:54 +0200 Subject: [PATCH 31/61] remove unused ulsch measurements at gNB --- .../PHY/NR_ESTIMATION/nr_measurements_gNB.c | 71 ------------------- openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h | 6 -- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 7 +- openair1/PHY/defs_gNB.h | 8 --- 4 files changed, 1 insertion(+), 91 deletions(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 2e6e4a54a6..fc6f81500a 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -188,74 +188,3 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy } } } - -// Scope: This function computes the UL SNR from the UL channel estimates -// -// Todo: -// - averaging IIR filter for RX power and noise -void nr_gnb_measurements(PHY_VARS_gNB *gNB, - NR_gNB_ULSCH_t *ulsch, - NR_gNB_PUSCH *pusch_vars, - unsigned char symbol, - uint8_t nrOfLayers) -{ - uint32_t rx_power_tot = 0; - unsigned short rx_power_avg_dB; - unsigned short rx_power_tot_dB; - RU_t *ru = gNB->RU_list[0]; - double rx_gain, rx_gain_offset; - if (ru && ru->rfdevice.openair0_cfg) { - rx_gain = ru->rfdevice.openair0_cfg->rx_gain[0]; - rx_gain_offset = ru->rfdevice.openair0_cfg->rx_gain_offset[0]; - } else if (ru && ru->ifdevice.openair0_cfg) { - rx_gain = ru->ifdevice.openair0_cfg->rx_gain[0]; - rx_gain_offset = ru->ifdevice.openair0_cfg->rx_gain_offset[0]; - } else { - LOG_W(NR_PHY, "no device for rx gain, take arbitrary gain = 1)\n"); - rx_gain = 1; - rx_gain_offset = 0; - } - PHY_MEASUREMENTS_gNB *meas = &gNB->measurements; - NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - int ch_offset = fp->ofdm_symbol_size * symbol; - int N_RB_UL = ulsch->harq_process->ulsch_pdu.rb_size; - ulsch_measurements_gNB *ulsch_measurements = &ulsch->ulsch_measurements; - - int rx_power[fp->nb_antennas_rx]; - int rx_spatial_power[nrOfLayers][fp->nb_antennas_rx]; - for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++){ - rx_power[aarx] = 0; - - for (int aatx = 0; aatx < nrOfLayers; aatx++){ - rx_spatial_power[aatx][aarx] = - (signal_energy_nodc((c16_t*)&pusch_vars->ul_ch_estimates[aatx * fp->nb_antennas_rx + aarx][ch_offset], - N_RB_UL * NR_NB_SC_PER_RB)); - - if (rx_spatial_power[aatx][aarx] < 0) { - rx_spatial_power[aatx][aarx] = 0; - } - - rx_power[aarx] += rx_spatial_power[aatx][aarx]; - } - LOG_D(PHY, "[RNTI %04x] RX power in antenna %d = %d\n", ulsch->rnti, aarx, rx_power[aarx]); - - rx_power_tot += rx_power[aarx]; - } - - rx_power_tot_dB = (unsigned short)dB_fixed(rx_power_tot); - rx_power_avg_dB = rx_power_tot_dB; - - ulsch_measurements->wideband_cqi_tot = dB_fixed2(rx_power_tot, meas->n0_power_tot); - ulsch_measurements->rx_rssi_dBm = - rx_power_avg_dB + 30 - SQ15_SQUARED_NORM_FACTOR_DB - (rx_gain - rx_gain_offset) - dB_fixed(fp->ofdm_symbol_size); - - LOG_D(PHY, - "[RNTI %04x] RSSI %d dBm/RE, RSSI (digital) %d dB (N_RB_UL %d), WBand CQI tot %d dB, N0 Power tot %d, RX Power tot %d\n", - ulsch->rnti, - ulsch_measurements->rx_rssi_dBm, - rx_power_avg_dB, - N_RB_UL, - ulsch_measurements->wideband_cqi_tot, - meas->n0_power_tot, - rx_power_tot); -} diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 04377db1b8..7e0a2a97bd 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -59,12 +59,6 @@ void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB); void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][9]); -void nr_gnb_measurements(PHY_VARS_gNB *gNB, - NR_gNB_ULSCH_t *ulsch, - NR_gNB_PUSCH *pusch_vars, - unsigned char symbol, - uint8_t nrOfLayers); - int nr_est_timing_advance_srs(const NR_DL_FRAME_PARMS *frame_parms, const c16_t srs_estimated_channel_time[][frame_parms->ofdm_symbol_size]); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 28f3e2cc67..3a32deab88 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -1188,12 +1188,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, pusch_ch_est_dmrs_pos_slot_mem); nvar += nvar_tmp; } - // measure the SNR from the channel estimation - nr_gnb_measurements(gNB, - &gNB->ulsch[ulsch_id], - pusch_vars, - symbol, - rel15_ul->nrOfLayers); + allocCast2D(n0_subband_power, unsigned int, gNB->measurements.n0_subband_power, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index fb549d4734..ebf459402e 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -215,13 +215,6 @@ static inline int crcType(int nbSeg, int len) return len > NR_MAX_PDSCH_TBS ? CRC24_A : CRC16; } -typedef struct { - //! estimated rssi (dBm) - int rx_rssi_dBm; - /// Wideband CQI (sum of all RX antennas, in dB) - char wideband_cqi_tot; -} ulsch_measurements_gNB; - typedef struct { uint32_t frame; uint32_t slot; @@ -243,7 +236,6 @@ typedef struct { /// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around uint8_t handled; delay_t delay; - ulsch_measurements_gNB ulsch_measurements; } NR_gNB_ULSCH_t; typedef struct { From c3eaef704f37d04eee5fe344d160db1045a2c186 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 25 Sep 2025 18:46:25 +0200 Subject: [PATCH 32/61] Add monolithic N2 handover test pipeline with B210 and Quectel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add XML pipeline for N2 handover testing - Add Docker compose for two monolithic gNBs - Features: * Two monolithic gNBs (gNB1, gNB2) with proper CU+DU parameters * Gradual attenuation control using RC4DAT attenuator (5s duration) * N2 handover sequence: gNB1 โ†’ gNB2 โ†’ gNB1 * Proper channel mapping: ch1-2 for gNB1, ch3-4 for gNB2 * Telnet server configuration for CI commands * Handover-specific neighbor configuration * Clean test state management with attenuator reset --- .../gnb.sa.band77.51prb.usrpb200.n2-ho.conf | 237 ++++++++++++++++++ .../container_sa_n2_ho_b210_quectel.xml | 230 +++++++++++++++++ .../5g_sa_n2_ho_b210/docker-compose.yml | 61 +++++ 3 files changed, 528 insertions(+) create mode 100644 ci-scripts/conf_files/gnb.sa.band77.51prb.usrpb200.n2-ho.conf create mode 100644 ci-scripts/xml_files/container_sa_n2_ho_b210_quectel.xml create mode 100644 ci-scripts/yaml_files/5g_sa_n2_ho_b210/docker-compose.yml diff --git a/ci-scripts/conf_files/gnb.sa.band77.51prb.usrpb200.n2-ho.conf b/ci-scripts/conf_files/gnb.sa.band77.51prb.usrpb200.n2-ho.conf new file mode 100644 index 0000000000..dc24284c18 --- /dev/null +++ b/ci-scripts/conf_files/gnb.sa.band77.51prb.usrpb200.n2-ho.conf @@ -0,0 +1,237 @@ +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 = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); + + // Include neighbour configuration for N2 handover + @include "neighbour-config-ho.conf" + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3610.56 MHz + absoluteFrequencySSB = 679104; + dl_frequencyBand = 77; + # this is 3599.94 MHz + dl_absoluteFrequencyPointA = 678388; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 51; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 13750; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + 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 = 51; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 13750; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#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 = 14; +#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, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# 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 = -25; + } + + ); + + # ------- 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.109"; }); + + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.19.98"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.19.98"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + ul_prbblack_SNR_threshold = 10; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 100; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0; + att_rx = 0; + bands = [77]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "external"; + time_src = "external"; +} +); + + +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 ="debug"; + f1ap_log_level ="debug"; +}; + diff --git a/ci-scripts/xml_files/container_sa_n2_ho_b210_quectel.xml b/ci-scripts/xml_files/container_sa_n2_ho_b210_quectel.xml new file mode 100644 index 0000000000..b67522b220 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_n2_ho_b210_quectel.xml @@ -0,0 +1,230 @@ + + + TEST-MONO-N2-HO-B210 + Monolithic N2 Handover 20 MHz TDD SA + tasks + + 000001 + 000002 + 000023 + 000003 + 000004 + 000005 + 000006 + 000007 + 000008 + 000009 + 000010 + 000011 + 000012 + 000013 + 000014 + 000015 + 000017 + 000018 + 000019 + 000016 + 000020 + 000021 + 000022 + + + + + DeployCoreNetwork + Initialize 5G Core + oc-cn5g-00103-ho + + + + Pull_Local_Registry + Pull Images from Local Registry + oai-gnb + groot + + + + Pull_Local_Registry + Pull Images from Local Registry + oai-gnb + rocket + + + + Create_Workspace + Create new Workspace for groot + groot + + + + Create_Workspace + Create new Workspace on rocket + rocket + + + + Custom_Command + Set initial attenuation on target gNB + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -s 1,2 0 -s 3,4 15 + + + + Deploy_Object + Deploy Monolithic gNB-PCI0 (TDD/Band77/20MHz/B210) in a container + ci-scripts/yaml_files/5g_sa_n2_ho_b210 + groot + oai-gnb-pci0 + + + + Deploy_Object + Deploy Monolithic gNB-PCI1 (TDD/Band77/20MHz/B210) in a container + ci-scripts/yaml_files/5g_sa_n2_ho_b210 + rocket + oai-gnb-pci1 + + + + Attach_UE + Attach Quectel + raspix + + + + Ping + Ping: 100pings in 20sec + raspix + oc-cn5g-00103-ho + -c 100 -i 0.2 + 5 + + + + IdleSleep + Sleep + 5 + + + + Custom_Command + Gradually attenuate gNB-PCI0 (ch1-2=15dB) and gNB-PCI1 (ch3-4=0dB) over 5s to trigger N2 Handover to gNB-PCI1 + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -r 1,2 15 -r 3,4 0 -d 5 + + + + Ping + Ping: 50pings in 10sec + raspix + oc-cn5g-00103-ho + -c 50 -i 0.2 + 5 + + + + Custom_Command + UE connected to gNB-PCI1? + rocket + echo ci fetch_du_by_ue_id 1 | ncat 127.0.0.1 9090 | grep "3585" + + + + Custom_Command + Gradually attenuate gNB-PCI0 (ch1-2=0dB) and gNB-PCI1 (ch3-4=15dB) over 5s to trigger N2 Handover back to gNB-PCI0 + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -r 1,2 0 -r 3,4 15 -d 5 + + + + Ping + Ping: 50pings in 10sec + raspix + oc-cn5g-00103-ho + -c 50 -i 0.2 + 5 + + + + Custom_Command + UE connected to gNB-PCI0? + groot + echo ci fetch_du_by_ue_id 1 | ncat 127.0.0.1 9090 | grep "3584" + + + + Custom_Command + true + Reset all attenuators to 0dB + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -s 1-4 0 + + + + Detach_UE + true + Detach Quectel + raspix + + + + Undeploy_Object + true + Undeploy Monolithic gNB-PCI0 + groot + ci-scripts/yaml_files/5g_sa_n2_ho_b210 + + + + Undeploy_Object + true + Undeploy Monolithic gNB-PCI1 + rocket + ci-scripts/yaml_files/5g_sa_n2_ho_b210 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + groot + oai-gnb + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + rocket + oai-gnb + + + + UndeployCoreNetwork + true + Terminate 5G Core + oc-cn5g-00103-ho + + + diff --git a/ci-scripts/yaml_files/5g_sa_n2_ho_b210/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n2_ho_b210/docker-compose.yml new file mode 100644 index 0000000000..6704b434db --- /dev/null +++ b/ci-scripts/yaml_files/5g_sa_n2_ho_b210/docker-compose.yml @@ -0,0 +1,61 @@ +services: + oai-gnb-pci0: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: oai-gnb-pci0 + cap_drop: + - ALL + cap_add: + - SYS_NICE + - IPC_LOCK + ulimits: + core: -1 # for core dumps + environment: + USE_B2XX: 'yes' + USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=30AD30F + --telnetsrv --telnetsrv.shrmod ci + --log_config.global_log_options level,nocolor,utc_time,line_num,function + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 + devices: + - /dev/bus/usb/:/dev/bus/usb/ + volumes: + - ../../conf_files/neighbour-config-ho.conf:/opt/oai-gnb/etc/neighbour-config-ho.conf + - ../../conf_files/gnb.sa.band77.51prb.usrpb200.n2-ho.conf:/opt/oai-gnb/etc/gnb.conf + network_mode: "host" + healthcheck: + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 + + oai-gnb-pci1: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: oai-gnb-pci1 + cap_drop: + - ALL + cap_add: + - SYS_NICE + - IPC_LOCK + ulimits: + core: -1 # for core dumps + environment: + USE_B2XX: 'yes' + USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=31F8010 + --gNBs.[0].nr_cellid 11111111 + --gNBs.[0].gNB_ID 0xe01 + --gNBs.[0].servingCellConfigCommon.[0].physCellId 1 + --gNBs.[0].servingCellConfigCommon.[0].ssb_PositionsInBurst_Bitmap 2 + --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 172.21.19.99 + --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 172.21.19.99 + --telnetsrv --telnetsrv.shrmod ci + --log_config.global_log_options level,nocolor,utc_time,line_num,function + devices: + - /dev/bus/usb/:/dev/bus/usb/ + volumes: + - ../../conf_files/neighbour-config-ho.conf:/opt/oai-gnb/etc/neighbour-config-ho.conf + - ../../conf_files/gnb.sa.band77.51prb.usrpb200.n2-ho.conf:/opt/oai-gnb/etc/gnb.conf + network_mode: "host" + healthcheck: + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 From 7ec646a8d266eef995d835b85d1d59fa0b9beace Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 20 Oct 2025 10:19:51 +0200 Subject: [PATCH 33/61] NGAP: fix PLMN/cell location for InitialUE and UplinkNAS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit is removing the storage of selected PLMN in NGAP UE context. We store the Serving PLMN in the RRC UE context instead. The Selected PLMN is the PLMN that the UE chose (or was directed to) for registration and it is sent in the RRCSetupComplete. This is different from the selected PLMN mentioned in the NG INITIAL UE MESSAGE for network sharing. Selected PLMN: determines which core network and AMF the UE is registered with GUAMI = Identifies the serving AMF and includes the PLMN of that AMF Serving PLMN: the PLMN that is currently serving the UE (e.g. contained in GUAMI) The AMFโ€™s PLMN may match the selected PLMN, or not (especially in network sharing or roaming). Regardless, the UE always have a Serving PLMN. Initial UE message does not have a TAI IE per se, but TAI is a mandatory member of the mandatory UserLocationInformation CHOICE. NR CGI is also mandatory and carried inside UserLocationInformation: in network sharing, the PLMN ID in TAI takes on additional significance: RAN is shared but CN are different, so in this case PLMN in TAI is needed for the AMF route the message to the correct operatorโ€™s core. If network sharing applies (e.g., shared RAN between PLMN-A and PLMN-B): the UE or network may select PLMN-B instead, and that PLMN identity is included in the Initial UE Messageโ€™s TAI IE. Conclusion: 1) UE always sends the selected PLMN during the registration, regardless of whether it is shared or not. 2) Selected PLMN Identity is an actual IE sent in the RRCSetupComplete while in NGAP there's no Selected PLMN Identity IE, only PLMN Identity IEs in both TAI and NR CGI. It is a subtle difference. 3) The serving PLMN of the UE needs to be stored in RRC UE Context for later use in NAS procedures. e.g. at initial registration it matches the Selected PLMN 4) No need to store PLMN in NGAP UE Context, params are passed by RRC 5) TAI and NR CGI, which contain the PLMN identity, are mandatory in UserLocationInformation IE CHOICE, and should reflect current status Changes - Initial UE Message: pass UE-selected PLMN and NR cell id from RRC to NGAP - Uplink NAS Transport: use PLMN, TAC, and cell id provided by the message; - Build NR CGI from gNB ID + cell id - Store UE-selected PLMN only in RRC UE context at NAS_FIRST_REQ for later Uplink NAS, stop storing PLMN in NGAP UE context --- openair2/COMMON/ngap_messages_types.h | 6 ++++++ openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB_NGAP.c | 23 +++++++++++++++------- openair3/NGAP/ngap_gNB_nas_procedures.c | 26 ++++++++++++------------- openair3/NGAP/ngap_gNB_ue_context.h | 5 ----- 5 files changed, 37 insertions(+), 25 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 2c4b0f8a0a..5be5e316ef 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -421,6 +421,8 @@ typedef struct ngap_nas_first_req_s { /* PLMN: Selected PLMN Identity (optional) * User Location Information (mandatory) */ plmn_id_t plmn; + // NR Cell ID for NR CGI (mandatory) + uint32_t nr_cell_id; // RRC Establishment Cause (mandatory) ngap_rrc_establishment_cause_t establishment_cause; // NAS-PDU (mandatory) @@ -434,6 +436,10 @@ typedef struct ngap_uplink_nas_s { uint32_t gNB_ue_ngap_id; /* NAS pdu */ byte_array_t nas_pdu; + /* UserLocationInformation (mandatory) */ + plmn_id_t plmn; // CGI and TAI + uint32_t nr_cell_id; // CGI + uint32_t tac; // TAI } ngap_uplink_nas_t; typedef struct target_cell_id_s { diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index e76802338c..eaeacae5ab 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -209,6 +209,8 @@ typedef struct gNB_RRC_UE_s { uint64_t amf_ue_ngap_id; // Globally Unique AMF Identifier nr_guami_t ue_guami; + // Serving PLMN of the UE + plmn_id_t serving_plmn; ngap_security_capabilities_t security_capabilities; //NSA block diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7d75384a9b..90b51ba118 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -223,17 +223,22 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC req->nas_pdu = create_byte_array(rrcSetupComplete->dedicatedNAS_Message.size, rrcSetupComplete->dedicatedNAS_Message.buf); /* Selected PLMN Identity (Optional) - * selectedPLMN-Identity in RRCSetupComplete: Index of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1) - * Selected PLMN Identity in INITIAL UE MESSAGE: Indicates the selected PLMN id for the non-3GPP access.*/ - if (rrcSetupComplete->selectedPLMN_Identity > rrc->configuration.num_plmn) { + * selectedPLMN-Identity in RRCSetupComplete: Index of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1) */ + int idx = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index + if (idx < 0 || idx >= rrc->configuration.num_plmn) { LOG_E(NGAP, - "Failed to send Initial UE Message: selected PLMN (%ld) identity is out of bounds (%d)\n", - rrcSetupComplete->selectedPLMN_Identity, + "Failed to send Initial UE Message: selected PLMN index (%d) is out of bounds [0..%d)\n", + idx, rrc->configuration.num_plmn); return; } - int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index - req->plmn = rrc->configuration.plmn[selected_plmn_identity]; // Select from the stored list + req->plmn = rrc->configuration.plmn[idx]; // Select from the stored list + /* UE is connected to only one PLMN at a time: store this as the serving PLMN */ + UE->serving_plmn = req->plmn; + + // Cell ID (NR CGI) + req->nr_cell_id = UE->nr_cellid; + // PLMN (NR CGI and TAI) plmn_id_t *p = &req->plmn; LOG_I(NGAP, "Selected PLMN in the NG Initial UE Message: MCC=%03d MNC=%0*d\n", p->mcc, p->mnc_digit_length, p->mnc); @@ -721,6 +726,10 @@ void rrc_gNB_send_NGAP_UPLINK_NAS(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_ NGAP_UPLINK_NAS(msg_p).gNB_ue_ngap_id = UE->rrc_ue_id; NGAP_UPLINK_NAS(msg_p).nas_pdu.len = nas->size; NGAP_UPLINK_NAS(msg_p).nas_pdu.buf = buf; + /* Fill PLMN and location info: use serving PLMN of the UE */ + NGAP_UPLINK_NAS(msg_p).plmn = UE->serving_plmn; + NGAP_UPLINK_NAS(msg_p).nr_cell_id = rrc->nr_cellid; + NGAP_UPLINK_NAS(msg_p).tac = rrc->configuration.tac; itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); } diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index cff9cd0b72..55cd7d61f4 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -181,7 +181,6 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf .amf_ref = amf, .gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id, .gNB_instance = instance_p, - .selected_plmn_identity = UEfirstReq->plmn, }; // RAN UE NGAP ID (M) @@ -211,16 +210,14 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR; asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p); - /* Set nRCellIdentity. default userLocationInformationNR */ - MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id, - 0, // Cell ID - &userinfo_nr_p->nR_CGI.nRCellIdentity); + /* NR CGI: use gNB ID and Cell ID passed from RRC */ + MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id, UEfirstReq->nr_cell_id, &userinfo_nr_p->nR_CGI.nRCellIdentity); - plmn_id_t *plmn = &ue_desc_p.selected_plmn_identity; + /* Use UE's selected PLMN for nR-CGI (from Initial UE Message) */ + plmn_id_t *plmn = &UEfirstReq->plmn; MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); - /* In case of network sharing, - the selected PLMN is indicated by the PLMN Identity IE within the TAI IE */ + /* Set TAI - use UE's selected PLMN */ INT24_TO_OCTET_STRING(instance_p->tac, &userinfo_nr_p->tAI.tAC); MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } @@ -444,17 +441,20 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR; asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p); - /* Set nRCellIdentity. default userLocationInformationNR */ + /* Set nRCellIdentity: use gNB ID and Cell ID */ MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id, - 0, // Cell ID + ngap_uplink_nas_p->nr_cell_id, &userinfo_nr_p->nR_CGI.nRCellIdentity); - plmn_id_t *plmn = &ue_context_p->selected_plmn_identity; + + /* NR CGI */ + plmn_id_t *plmn = &ngap_uplink_nas_p->plmn; MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); - /* Set TAI */ - INT24_TO_OCTET_STRING(ngap_gNB_instance_p->tac, &userinfo_nr_p->tAI.tAC); + /* TAI */ + INT24_TO_OCTET_STRING(ngap_uplink_nas_p->tac, &userinfo_nr_p->tAI.tAC); MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } + if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode uplink NAS transport\n"); /* Encode procedure has failed... */ diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index 1022f2f4c3..8053e8f8c6 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -69,11 +69,6 @@ typedef struct ngap_gNB_ue_context_s { /* Reference to AMF data this UE is attached to */ struct ngap_gNB_amf_data_s *amf_ref; - /* Signaled by the UE in RRC Connection Setup Complete and used in NAS Uplink - * to route NAS messages correctly. 0-based, not 1-based as in TS 36.331 - * 6.2.2 RRC Connection Setup Complete! */ - plmn_id_t selected_plmn_identity; - /* Reference to gNB data this UE is attached to */ ngap_gNB_instance_t *gNB_instance; } ngap_gNB_ue_context_t; From 32eae0a0a8014e746abce7d24e3acb25f9fd006a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 21 Oct 2025 10:37:56 +0200 Subject: [PATCH 34/61] Adopt plmn_id_t in nr_guami_t --- common/5g_platform_types.h | 4 +--- openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c | 12 +++++------- openair2/RRC/NR/rrc_gNB_NGAP.c | 4 +--- openair3/NGAP/ngap_common.c | 2 +- openair3/NGAP/ngap_gNB_nas_procedures.c | 12 ++++++------ openair3/NGAP/ngap_gNB_nnsf.c | 12 +++++------- 6 files changed, 19 insertions(+), 27 deletions(-) diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index 4ed7f33e47..7cae0afde7 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -37,9 +37,7 @@ typedef struct nssai_s { // Globally Unique AMF Identifier typedef struct nr_guami_s { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_len; + plmn_id_t plmn; uint8_t amf_region_id; uint16_t amf_set_id; uint8_t amf_pointer; diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c index a81a01d394..5d725f1df6 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c @@ -38,13 +38,11 @@ ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, __attr ue_id.gnb.amf_ue_ngap_id = auni < (1LL << 40) ? auni : 0; // Mandatory - //GUAMI 6.2.3.17 - ue_id.gnb.guami.plmn_id = (e2sm_plmn_t) { - .mcc = rrc_ue_context->ue_guami.mcc, - .mnc = rrc_ue_context->ue_guami.mnc, - .mnc_digit_len = rrc_ue_context->ue_guami.mnc_len - }; - + //GUAMI 6.2.3.17 + ue_id.gnb.guami.plmn_id = (e2sm_plmn_t){.mcc = rrc_ue_context->ue_guami.plmn.mcc, + .mnc = rrc_ue_context->ue_guami.plmn.mnc, + .mnc_digit_len = rrc_ue_context->ue_guami.plmn.mnc_digit_length}; + ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id; ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id; ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 90b51ba118..15c5aa19e9 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -165,9 +165,7 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) guami.amf_region_id = (amf_Id >> 16) & 0xff; guami.amf_set_id = (amf_Id >> 6) & 0x3ff; guami.amf_pointer = amf_Id & 0x3f; - guami.mcc = plmn.mcc; - guami.mnc = plmn.mnc; - guami.mnc_len = plmn.mnc_digit_length; + guami.plmn = plmn; return guami; } diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c index c3865cff10..8be57349ec 100644 --- a/openair3/NGAP/ngap_common.c +++ b/openair3/NGAP/ngap_common.c @@ -106,7 +106,7 @@ ngap_cause_t decode_ngap_cause(const NGAP_Cause_t *in) nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in) { nr_guami_t out = {0}; - TBCD_TO_MCC_MNC(&in->pLMNIdentity, out.mcc, out.mnc, out.mnc_len); + TBCD_TO_MCC_MNC(&in->pLMNIdentity, out.plmn.mcc, out.plmn.mnc, out.plmn.mnc_digit_length); OCTET_STRING_TO_INT8(&in->aMFRegionID, out.amf_region_id); OCTET_STRING_TO_INT16(&in->aMFSetID, out.amf_set_id); OCTET_STRING_TO_INT8(&in->aMFPointer, out.amf_pointer); diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 55cd7d61f4..7dd6359b7a 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -76,9 +76,9 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng const nr_guami_t *guami = &msg->ue_identity.guami; LOG_D(NGAP, "GUAMI is present: MCC=%03d MNC=%0*d RegionID=%d SetID=%d Pointer=%d\n", - guami->mcc, - guami->mnc_len, - guami->mnc, + guami->plmn.mcc, + guami->plmn.mnc_digit_length, + guami->plmn.mnc, guami->amf_region_id, guami->amf_set_id, guami->amf_pointer); @@ -89,9 +89,9 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id, - guami->mcc, - guami->mnc_len, - guami->mnc, + guami->plmn.mcc, + guami->plmn.mnc_digit_length, + guami->plmn.mnc, guami->amf_region_id, guami->amf_set_id, guami->amf_pointer); diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index f895737a0d..5fbc3e4d11 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -286,8 +286,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *inst struct plmn_identity_s *served_plmn_p = NULL; STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == guami.mcc) && - (served_plmn_p->mnc == guami.mnc)) { + if ((served_plmn_p->mcc == guami.plmn.mcc) && (served_plmn_p->mnc == guami.plmn.mnc)) { break; } } @@ -322,9 +321,9 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *inst } NGAP_WARN("No matching AMF found for GUAMI (MCC=%03d MNC=%0*d RegionID=%d SetID=%d Pointer=%d)\n", - guami.mcc, - guami.mnc_len, - guami.mnc, + guami.plmn.mcc, + guami.plmn.mnc_digit_length, + guami.plmn.mnc, guami.amf_region_id, guami.amf_set_id, guami.amf_pointer); @@ -373,8 +372,7 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami_no_cause(ngap_gNB_instanc struct plmn_identity_s *served_plmn_p = NULL; STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == guami.mcc) && - (served_plmn_p->mnc == guami.mnc)) { + if ((served_plmn_p->mcc == guami.plmn.mcc) && (served_plmn_p->mnc == guami.plmn.mnc)) { break; } } From 5f261d4f4c74e9cad2d390e42e6fbef11429b7eb Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 21 Oct 2025 11:12:13 +0200 Subject: [PATCH 35/61] Add PLMN validation for handover requests and store serving PLMN Prevent assertion in ngap_gNB_nas_uplink() due to uninitialized selected_plmn_identity: the selected_plmn_identity field was not being set during N2 handover, causing the assertion ((plmn->mnc_digit_length == 3) || (plmn->mnc_digit_length == 2)) to fail when processing subsequent NAS messages. The issue is that the Serving PLMN is not stored by RRC. During N2 mobility, RRC can get this info from GUAMI. When receiving the Handover Request the target gNB knows from GUAMI which serving PLMN is the AMF belonging to. In current design, allowed PLMNs are stored in rrc.configuration. The incoming PLMN needs to be validate against the PLMNs in the list, then stored in the UE context as Serving PLMN. This change adds PLMN validation when processing handover requests from the source gNB. The validation is needed because: - Target gNB must verify that the PLMN from the GUAMI in the handover request is allowed by its configuration before accepting the handover to prevent handover to unsupported PLMNs. - When PLMN validation fails, the target gNB now properly sends NGAP_HANDOVER_FAILURE - UE Context must store serving PLMN for later use --- openair2/RRC/NR/rrc_gNB_NGAP.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 15c5aa19e9..62fb68d92b 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -110,6 +110,24 @@ static const uint16_t NGAP_INTEGRITY_NIA3_MASK = 0x2000; static void set_UE_security_algos(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_security_capabilities_t *cap); +/** @brief Validates PLMN against allowed PLMN list and returns pointer to matching PLMN + * @param rrc RRC instance + * @param plmn PLMN to validate + * @return pointer to matching PLMN in configuration, or NULL if not found */ +static const plmn_id_t *get_serving_plmn(gNB_RRC_INST *rrc, const plmn_id_t *plmn) +{ + // Find matching PLMN in configuration + for (int idx = 0; idx < rrc->configuration.num_plmn; idx++) { + const plmn_id_t *allowed = &rrc->configuration.plmn[idx]; + if (allowed->mcc == plmn->mcc && allowed->mnc == plmn->mnc && allowed->mnc_digit_length == plmn->mnc_digit_length) { + LOG_D(NR_RRC, "PLMN (MCC:%d, MNC:%*d) matched with allowed PLMN[%d]\n", plmn->mcc, plmn->mnc_digit_length, plmn->mnc, idx); + return allowed; + } + } + LOG_W(NR_RRC, "PLMN (MCC:%d, MNC:%*d) not found in allowed PLMN list\n", plmn->mcc, plmn->mnc_digit_length, plmn->mnc); + return NULL; +} + /*! *\brief save security key. *\param UE UE context. @@ -1161,6 +1179,20 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); return -1; } + + // Validate PLMN from GUAMI against allowed PLMN list + const plmn_id_t *serving_plmn = get_serving_plmn(rrc, &msg->guami.plmn); + if (!serving_plmn) { + LOG_E(NR_RRC, "PLMN from GUAMI not supported - rejecting handover\n"); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_TARGET_NOT_ALLOWED, + }; + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); + return -1; + } + uint16_t pci = du->setup_req->cell[0].info.nr_pci; LOG_I(NR_RRC, "Received Handover Request (on NR Cell ID=%lu, PCI=%u) \n", msg->nr_cell_id, pci); @@ -1176,6 +1208,9 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga // Store IDs in UE context UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; UE->ue_guami = msg->guami; + // Store the serving PLMN + UE->serving_plmn = *serving_plmn; + UE->ho_context->target->ue_ho_prep_info = copy_byte_array(msg->ue_ho_prep_info); // store the received UE Security Capabilities in the UE context FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer); From 8ecda65d55356d92ae3b1d9410890eba89a96d10 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 Oct 2025 10:00:05 +0200 Subject: [PATCH 36/61] Remove Benetel radio drivers These drivers are superseded by the O-RAN 7.2 FHI. --- cmake_targets/build_oai | 4 +- radio/ETHERNET/CMakeLists.txt | 2 - radio/ETHERNET/benetel/4g/CMakeLists.txt | 20 - radio/ETHERNET/benetel/4g/benetel.c | 392 ---------- radio/ETHERNET/benetel/4g/dpdk_driver.c | 774 ------------------- radio/ETHERNET/benetel/4g/low.c | 94 --- radio/ETHERNET/benetel/4g/low.h | 50 -- radio/ETHERNET/benetel/4g/low_dpdk.c | 119 --- radio/ETHERNET/benetel/4g/shared_buffers.c | 117 --- radio/ETHERNET/benetel/4g/shared_buffers.h | 61 -- radio/ETHERNET/benetel/5g/CMakeLists.txt | 19 - radio/ETHERNET/benetel/5g/benetel.c | 399 ---------- radio/ETHERNET/benetel/5g/dpdk_driver.c | 835 --------------------- radio/ETHERNET/benetel/5g/low.c | 128 ---- radio/ETHERNET/benetel/5g/low.h | 49 -- radio/ETHERNET/benetel/5g/low_dpdk.c | 119 --- radio/ETHERNET/benetel/5g/shared_buffers.c | 123 --- radio/ETHERNET/benetel/5g/shared_buffers.h | 61 -- radio/ETHERNET/benetel/CMakeLists.txt | 9 - 19 files changed, 2 insertions(+), 3373 deletions(-) delete mode 100644 radio/ETHERNET/benetel/4g/CMakeLists.txt delete mode 100644 radio/ETHERNET/benetel/4g/benetel.c delete mode 100644 radio/ETHERNET/benetel/4g/dpdk_driver.c delete mode 100644 radio/ETHERNET/benetel/4g/low.c delete mode 100644 radio/ETHERNET/benetel/4g/low.h delete mode 100644 radio/ETHERNET/benetel/4g/low_dpdk.c delete mode 100644 radio/ETHERNET/benetel/4g/shared_buffers.c delete mode 100644 radio/ETHERNET/benetel/4g/shared_buffers.h delete mode 100644 radio/ETHERNET/benetel/5g/CMakeLists.txt delete mode 100644 radio/ETHERNET/benetel/5g/benetel.c delete mode 100644 radio/ETHERNET/benetel/5g/dpdk_driver.c delete mode 100644 radio/ETHERNET/benetel/5g/low.c delete mode 100644 radio/ETHERNET/benetel/5g/low.h delete mode 100644 radio/ETHERNET/benetel/5g/low_dpdk.c delete mode 100644 radio/ETHERNET/benetel/5g/shared_buffers.c delete mode 100644 radio/ETHERNET/benetel/5g/shared_buffers.h delete mode 100644 radio/ETHERNET/benetel/CMakeLists.txt diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 658b0b858a..56c5e9b66c 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -92,7 +92,7 @@ Options: USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default) Adds this RF board support (in external packages installation and in compilation) -t | --transport - Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS + Selects the transport protocol type, options: None, Ethernet, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS -P | --phy_simulators Makes the unitary tests Layer 1 simulators -V | --vcd @@ -278,7 +278,7 @@ function main() { TARGET_LIST="$TARGET_LIST oai_eth_transpro" CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase ;; - "benetel4g" | "benetel5g" | "oran_fhlib_4g") + "oran_fhlib_4g") TARGET_LIST="$TARGET_LIST $2" CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase ;; diff --git a/radio/ETHERNET/CMakeLists.txt b/radio/ETHERNET/CMakeLists.txt index 3a9b9dc5cb..dd0f603eda 100644 --- a/radio/ETHERNET/CMakeLists.txt +++ b/radio/ETHERNET/CMakeLists.txt @@ -9,5 +9,3 @@ set_target_properties(oai_eth_transpro PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMA add_custom_command(TARGET oai_eth_transpro POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboai_eth_transpro.so liboai_transpro.so WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - -add_subdirectory(benetel) diff --git a/radio/ETHERNET/benetel/4g/CMakeLists.txt b/radio/ETHERNET/benetel/4g/CMakeLists.txt deleted file mode 100644 index 164e33eb28..0000000000 --- a/radio/ETHERNET/benetel/4g/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -pkg_check_modules(libdpdk REQUIRED libdpdk=20.05.0) - -add_library(benetel_4g MODULE - benetel.c - shared_buffers.c - low.c - low_dpdk.c - dpdk_driver.c -) - -target_compile_definitions(benetel_4g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include") - -SET(DPDK_LIBS "-Wl,-rpath,$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -Wl,--whole-archive -L$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -ldpdk -Wl,--no-whole-archive") -target_include_directories(benetel_4g PRIVATE ${libdpdk_INCLUDE_DIRS}) -target_link_libraries(benetel_4g PRIVATE ${libdpdk_LIBRARIES}) -target_link_libraries(benetel_4g PRIVATE pthread dl rt m numa) -set_target_properties(benetel_4g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -add_custom_command(TARGET benetel_4g POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink libbenetel_4g.so liboai_transpro.so - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/radio/ETHERNET/benetel/4g/benetel.c b/radio/ETHERNET/benetel/4g/benetel.c deleted file mode 100644 index 8e221fe929..0000000000 --- a/radio/ETHERNET/benetel/4g/benetel.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * 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 - -#include "common_lib.h" -#include "ethernet_lib.h" -#include "shared_buffers.h" -#include "low.h" -#include "common/utils/LOG/log.h" -#include "common/utils/LOG/vcd_signal_dumper.h" - -typedef struct { - eth_state_t e; - shared_buffers buffers; - rru_config_msg_type_t last_msg; - int capabilities_sent; - void *benetel_priv; - char *dpdk_main_command_line; -} benetel_eth_state_t; - -int trx_benetel_start(openair0_device *device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return 0; -} - - -void trx_benetel_end(openair0_device *device) -{ - printf("BENETEL: %s\n", __FUNCTION__); -} - - -int trx_benetel_stop(openair0_device *device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_set_freq(openair0_device* device, openair0_config_t *openair0_cfg) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_set_gains(openair0_device* device, - openair0_config_t *openair0_cfg) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_get_stats(openair0_device* device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_reset_stats(openair0_device* device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int ethernet_tune(openair0_device *device, - unsigned int option, - int value) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return 0; -} - -int trx_benetel_write_raw(openair0_device *device, - openair0_timestamp timestamp, - void **buff, int nsamps, int cc, int flags) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return nsamps*4; -} - -int trx_benetel_read_raw(openair0_device *device, - openair0_timestamp *timestamp, - void **buff, int nsamps, int cc) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return nsamps*4; -} - -char *msg_type(int t) -{ - static char *s[12] = { - "RAU_tick", - "RRU_capabilities", - "RRU_config", - "RRU_config_ok", - "RRU_start", - "RRU_stop", - "RRU_sync_ok", - "RRU_frame_resynch", - "RRU_MSG_max_num", - "RRU_check_sync", - "RRU_config_update", - "RRU_config_update_ok", - }; - - if (t < 0 || t > 11) return "UNKNOWN"; - return s[t]; -} - -int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len) -{ - RRU_CONFIG_msg_t *rru_config_msg = msg; - benetel_eth_state_t *s = device->priv; - - printf("BENETEL: %s\n", __FUNCTION__); - - printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type, - msg_type(rru_config_msg->type)); - - s->last_msg = rru_config_msg->type; - - return msg_len; -} - -int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len) -{ - RRU_CONFIG_msg_t *rru_config_msg = msg; - benetel_eth_state_t *s = device->priv; - - printf("BENETEL: %s\n", __FUNCTION__); - - if (s->last_msg == RAU_tick && s->capabilities_sent == 0) { - RRU_capabilities_t *cap; - rru_config_msg->type = RRU_capabilities; - rru_config_msg->len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); - cap = (RRU_capabilities_t*)&rru_config_msg->msg[0]; - cap->FH_fmt = OAI_IF4p5_only; - cap->num_bands = 1; - cap->band_list[0] = 7; - cap->nb_rx[0] = device->openair0_cfg->rx_num_channels; - cap->nb_tx[0] = device->openair0_cfg->tx_num_channels; - cap->max_pdschReferenceSignalPower[0] = -27; - cap->max_rxgain[0] = 90; - - s->capabilities_sent = 1; - - return rru_config_msg->len; - } - if (s->last_msg == RRU_config) { - rru_config_msg->type = RRU_config_ok; - return 0; - } - if (s->last_msg == RRU_start) { - s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line); - } - /* correct? */ - while (1) pause(); - - return 0; -} - -void benetel_fh_if4p5_south_in(RU_t *ru, - int *frame, - int *subframe) -{ - benetel_eth_state_t *s = ru->ifdevice.priv; - PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB; - LTE_DL_FRAME_PARMS *fp; - int symbol; - int32_t *rxdata; - int antenna; - - lock_ul_buffer(&s->buffers, *subframe); -next: - while (!((s->buffers.ul_busy[0][*subframe] == 0x3fff && - s->buffers.ul_busy[1][*subframe] == 0x3fff) || - s->buffers.prach_busy[*subframe] == 1)) - wait_ul_buffer(&s->buffers, *subframe); - if (s->buffers.prach_busy[*subframe] == 1) { - int i; - int antenna = 0; - uint16_t *in; - uint16_t *out; - in = (uint16_t *)s->buffers.prach[*subframe]; - out = (uint16_t *)ru->prach_rxsigF[0][antenna]; - for (i = 0; i < 840*2; i++) - out[i] = ntohs(in[i]); - s->buffers.prach_busy[*subframe] = 0; - ru->wakeup_prach_eNB(ru->eNB_list[0], ru, *frame, *subframe); - goto next; - } - - eNB = eNB_list[0]; - fp = &eNB->frame_parms; - for (antenna = 0; antenna < ru->nb_rx; antenna++) { - for (symbol = 0; symbol < 14; symbol++) { - int i; - uint16_t *p = (uint16_t *)(&s->buffers.ul[antenna][*subframe][symbol*1200*4]); - for (i = 0; i < 1200*2; i++) { - p[i] = htons(p[i]); - } - rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size]; -#if 1 - memcpy(rxdata + 2048 - 600, - &s->buffers.ul[antenna][*subframe][symbol*1200*4], - 600 * 4); - memcpy(rxdata, - &s->buffers.ul[antenna][*subframe][symbol*1200*4] + 600*4, - 600 * 4); -#endif - } - } - - s->buffers.ul_busy[0][*subframe] = 0; - s->buffers.ul_busy[1][*subframe] = 0; - signal_ul_buffer(&s->buffers, *subframe); - unlock_ul_buffer(&s->buffers, *subframe); - - //printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *subframe); - - RU_proc_t *proc = &ru->proc; - extern int sf_ahead; - int f = *frame; - int sf = *subframe; - - //calculate timestamp_rx, timestamp_tx based on frame and subframe - proc->tti_rx = sf; - proc->frame_rx = f; - proc->timestamp_rx = ((proc->frame_rx * 10) + proc->tti_rx ) * fp->samples_per_tti ; - - if (get_nprocs()<=4) { - proc->tti_tx = (sf+sf_ahead)%10; - proc->frame_tx = (sf>(9-sf_ahead)) ? (f+1)&1023 : f; - } - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,f); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_IN_RU+ru->idx,sf); - proc->symbol_mask[sf] = 0; - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff); - -} - -void benetel_fh_if4p5_south_out(RU_t *ru, - int frame, - int subframe, - uint64_t timestamp) -{ - benetel_eth_state_t *s = ru->ifdevice.priv; - PHY_VARS_eNB **eNB_list = ru->eNB_list, *eNB; - LTE_DL_FRAME_PARMS *fp; - int symbol; - int32_t *txdata; - int aa; - - //printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, subframe, timestamp); - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); - - lock_dl_buffer(&s->buffers, subframe); - if (s->buffers.dl_busy[0][subframe] || - s->buffers.dl_busy[1][subframe]) { - printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, subframe); - unlock_dl_buffer(&s->buffers, subframe); - return; - } - eNB = eNB_list[0]; - fp = &eNB->frame_parms; - if (ru->num_eNB != 1 || fp->ofdm_symbol_size != 2048 || - fp->Ncp != NORMAL || fp->symbols_per_tti != 14) { - printf("%s:%d:%s: unsupported configuration\n", - __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - for (aa = 0; aa < ru->nb_tx; aa++) { - for (symbol = 0; symbol < 14; symbol++) { - txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size]; -#if 1 - memcpy(&s->buffers.dl[aa][subframe][symbol*1200*4], - txdata + 2048 - 600, - 600 * 4); - memcpy(&s->buffers.dl[aa][subframe][symbol*1200*4] + 600*4, - txdata + 1, - 600 * 4); -#endif - int i; - uint16_t *p = (uint16_t *)(&s->buffers.dl[aa][subframe][symbol*1200*4]); - for (i = 0; i < 1200*2; i++) { - p[i] = htons(p[i]); - } - } - } - - s->buffers.dl_busy[0][subframe] = 0x3fff; - s->buffers.dl_busy[1][subframe] = 0x3fff; - unlock_dl_buffer(&s->buffers, subframe); - - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.frame_tx); - VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_IF4P5_SOUTH_OUT_RU+ru->idx, ru->proc.tti_tx); - -} - -void *get_internal_parameter(char *name) -{ - printf("BENETEL: %s\n", __FUNCTION__); - - if (!strcmp(name, "fh_if4p5_south_in")) - return benetel_fh_if4p5_south_in; - if (!strcmp(name, "fh_if4p5_south_out")) - return benetel_fh_if4p5_south_out; - - return NULL; -} - -__attribute__((__visibility__("default"))) -int transport_init(openair0_device *device, - openair0_config_t *openair0_cfg, - eth_params_t * eth_params ) -{ - benetel_eth_state_t *eth; - - printf("BENETEL: %s\n", __FUNCTION__); - - device->Mod_id = 0; - device->transp_type = ETHERNET_TP; - device->trx_start_func = trx_benetel_start; - device->trx_get_stats_func = trx_benetel_get_stats; - device->trx_reset_stats_func = trx_benetel_reset_stats; - device->trx_end_func = trx_benetel_end; - device->trx_stop_func = trx_benetel_stop; - device->trx_set_freq_func = trx_benetel_set_freq; - device->trx_set_gains_func = trx_benetel_set_gains; - - device->trx_write_func = trx_benetel_write_raw; - device->trx_read_func = trx_benetel_read_raw; - - device->trx_ctlsend_func = trx_benetel_ctlsend; - device->trx_ctlrecv_func = trx_benetel_ctlrecv; - - device->get_internal_parameter = get_internal_parameter; - - eth = calloc(1, sizeof(benetel_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; - device->priv = eth; - device->openair0_cfg=&openair0_cfg[0]; - - if (openair0_cfg->sdr_addrs == NULL) { - printf("benetel: fatal: sdr_addrs not set in configuration file\n"); - exit(1); - } - - eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs); - if (eth->dpdk_main_command_line == NULL) { - AssertFatal(0==1, "out of memory\n"); - } - - eth->last_msg = -1; - - init_buffers(ð->buffers); - - return 0; -} diff --git a/radio/ETHERNET/benetel/4g/dpdk_driver.c b/radio/ETHERNET/benetel/4g/dpdk_driver.c deleted file mode 100644 index 2b6ef37e6f..0000000000 --- a/radio/ETHERNET/benetel/4g/dpdk_driver.c +++ /dev/null @@ -1,774 +0,0 @@ -/* license: to be defined */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "low.h" - -// HEADER DEFINITION -#define ANT_NUM buf[23] -#define PAYLOAD_1 buf[20] -#define PAYLOAD_2 buf[21] -#define ETH_TYPE buf[17] -#define SYMBOL buf[29] -#define SUBFRAME buf[28] -#define FRAME buf[27] - -static volatile bool force_quit; - -unsigned short iq[33600]; -unsigned char iq_swap[67200]; - -unsigned short *iq_ptr[14]; -unsigned int dl_start = 0; - -/* MAC updating enabled by default */ -static int mac_updating = 1; -#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 -#define MAX_PKT_BURST 32 -#define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */ -#define MEMPOOL_CACHE_SIZE 256 -/* - * Configurable number of RX/TX ring descriptors - */ -#define RTE_TEST_RX_DESC_DEFAULT 1024 -#define RTE_TEST_TX_DESC_DEFAULT 1024 -static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; -static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; -/* ethernet addresses of ports */ -static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; -/* mask of enabled ports */ -static uint32_t l2fwd_enabled_port_mask = 0; -/* list of enabled ports */ -static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; -static unsigned int l2fwd_rx_queue_per_lcore = 1; -#define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 16 -struct lcore_queue_conf { - unsigned n_rx_port; - unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; -} __rte_cache_aligned; -struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; -static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; -static struct rte_eth_conf port_conf = { - .rxmode = { - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_JUMBO_FRAME, - .split_hdr_size = 0, - .max_rx_pkt_len = 9500, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; -struct rte_mempool * l2fwd_pktmbuf_pool = NULL; -/* Per-port statistics struct */ -struct l2fwd_port_statistics { - uint64_t tx; - uint64_t rx; - uint64_t dropped; -} __rte_cache_aligned; -struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; -#define MAX_TIMER_PERIOD 86400 /* 1 day max */ -/* A tsc-based timer responsible for triggering statistics printout */ -static uint64_t timer_period = 10; /* default period is 10 seconds */ -/* Print out statistics on packets dropped */ -static void -print_stats(void) -{ - uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; - unsigned portid; - total_packets_dropped = 0; - total_packets_tx = 0; - total_packets_rx = 0; - const char clr[] = { 27, '[', '2', 'J', '\0' }; - const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; - /* Clear screen and move to top left */ - printf("%s%s", clr, topLeft); - printf("\nPort statistics ===================================="); - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { - /* skip disabled ports */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - printf("\nStatistics for port %u ------------------------------" - "\nPackets sent: %24"PRIu64 - "\nPackets received: %20"PRIu64 - "\nPackets dropped: %21"PRIu64, - portid, - port_statistics[portid].tx, - port_statistics[portid].rx, - port_statistics[portid].dropped); - total_packets_dropped += port_statistics[portid].dropped; - total_packets_tx += port_statistics[portid].tx; - total_packets_rx += port_statistics[portid].rx; - } - printf("\nAggregate statistics ===============================" - "\nTotal packets sent: %18"PRIu64 - "\nTotal packets received: %14"PRIu64 - "\nTotal packets dropped: %15"PRIu64, - total_packets_tx, - total_packets_rx, - total_packets_dropped); - printf("\n====================================================\n"); -} -static void -l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs) -{ - unsigned char *buf, *buf_tx; - unsigned int len; - struct ether_hdr *eth; - - unsigned dst_port; - int sent, prach_ctrl = 0; - struct rte_eth_dev_tx_buffer *buffer; - - unsigned char * IQ_ptr; - - ul_packet_t p; - - buf = rte_pktmbuf_mtod(m, unsigned char *); - //rte_memdump(stdout, "Rx Packet",buf ,34); - eth = rte_pktmbuf_mtod(m, struct ether_hdr *); - len = rte_pktmbuf_data_len(m); - - IQ_ptr = &buf[34]; - - //destination mac address (RRU MAC) - eth->d_addr.addr_bytes[0] = 0x02; - eth->d_addr.addr_bytes[1] = 0x00; - eth->d_addr.addr_bytes[2] = 0x5e; - eth->d_addr.addr_bytes[3] = 0x01; - eth->d_addr.addr_bytes[4] = 0x01; - eth->d_addr.addr_bytes[5] = 0x01; - - //source mac address (DU MAC) - eth->s_addr.addr_bytes[0] = 0xdd; - eth->s_addr.addr_bytes[1] = 0xdd; - eth->s_addr.addr_bytes[2] = 0xdd; - eth->s_addr.addr_bytes[3] = 0xdd; - eth->s_addr.addr_bytes[4] = 0xdd; - eth->s_addr.addr_bytes[5] = 0xdd; - - dst_port = l2fwd_dst_ports[portid]; - #if 1 - - if (buf[18] == 0xAA) //msg1 check - { - printf("\nHandshake MSG 1 Received\n"); - printf("\n====================================================\n"); - - buf[18] = 0xBB;//change to msg2 after receive msg1 - - printf("Handshake MSG 2 Sent\n"); - printf("\n====================================================\n"); - } - - #else - // Handshake Condition - if (buf[18] == 0x01 || buf[18] == 0x03) // ORAN handshake msgs. - { - if (buf[18] == 0x01) //msg1 check - { - printf("\nHandshake MSG 1 Received\n"); - printf("\n====================================================\n"); - - buf[18] = 0x02;//change to msg2 after receive msg1 - - printf("Handshake MSG 2 Sent\n"); - printf("\n====================================================\n"); - } - - else if(buf[18] == 0x03) //msg3 check - { - printf("Handshake MSG 3 Sent\n"); - printf("\n====================================================\n"); - - buf[18] = 0x04; - - printf("Handshake MSG 4 Sent\n"); - printf("\n====================================================\n"); - } - } - #endif - // Trigger start send DL packets - if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && SYMBOL == 0x09 && ANT_NUM == 0x00 && dl_start == 0){ - - printf("\nU-Plane Started\n"); - printf("\n====================================================\n"); - - dl_start = 1; - } - - - if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce) { - p.frame = FRAME; - p.subframe = SUBFRAME >> 4; - p.slot = 0; /* unused */ - p.symbol = SYMBOL; - p.antenna = ANT_NUM; - memcpy(p.iq, IQ_ptr, 4800); - store_ul(bs, &p); - } - - // U-PLANE UL PROCESSING - if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && dl_start == 1) - { - int a = ANT_NUM; - int tx_frame = FRAME; - int tx_subframe = SUBFRAME >> 4; - int tx_symbol = SYMBOL + 5; - if (tx_symbol > 13) { - tx_symbol -= 14; - tx_subframe++; - if (tx_subframe == 10) { - tx_subframe = 0; - tx_frame = (tx_frame + 1) & 255; - } - } - -// ANT_NUM = 0x00; -// SYMBOL = (SYMBOL + 5) % 14; - PAYLOAD_2 = 0xc8; - - FRAME = tx_frame; - SUBFRAME = tx_subframe << 4; - SYMBOL = tx_symbol; - - /* send actual DL data (if available) */ - lock_dl_buffer(bs->buffers, tx_subframe); - if (!(bs->buffers->dl_busy[a][tx_subframe] & (1 << tx_symbol))) { - printf("%s: warning, DL underflow (antenna %d sf.symbol %d.%d)\n", - __FUNCTION__, - a, - tx_subframe, tx_symbol); - memset(IQ_ptr, 0, 1200 * 4); - } else { - memcpy(IQ_ptr, bs->buffers->dl[a][tx_subframe] + tx_symbol * 1200*4, - 1200*4); - } - bs->buffers->dl_busy[a][tx_subframe] &= ~(1 << tx_symbol); - unlock_dl_buffer(bs->buffers, tx_subframe); - } - - // U-PLANE PRACH PROCESSING - else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){ - if (ANT_NUM == 0) { - store_prach(bs, FRAME, SUBFRAME>>4, IQ_ptr); - } - - rte_pktmbuf_free(m); - return; - } - - // Send Packets - buffer = tx_buffer[dst_port]; - - sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); - - if (sent) - port_statistics[dst_port].tx += sent; - -} -/* main processing loop */ -static void -l2fwd_main_loop(benetel_t *bs) -{ - struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; - struct rte_mbuf *m; - int sent; - unsigned lcore_id; - uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; - unsigned i, j, portid, nb_rx; - struct lcore_queue_conf *qconf; - const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * - BURST_TX_DRAIN_US; - struct rte_eth_dev_tx_buffer *buffer; - prev_tsc = 0; - timer_tsc = 0; - lcore_id = rte_lcore_id(); - qconf = &lcore_queue_conf[lcore_id]; - if (qconf->n_rx_port == 0) { - RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); - return; - } - RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); - for (i = 0; i < qconf->n_rx_port; i++) { - portid = qconf->rx_port_list[i]; - RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, - portid); - } - while (!force_quit) { - cur_tsc = rte_rdtsc(); - /* - * TX burst queue drain - */ - diff_tsc = cur_tsc - prev_tsc; - if (unlikely(diff_tsc > drain_tsc)) { - for (i = 0; i < qconf->n_rx_port; i++) { - portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; - buffer = tx_buffer[portid]; - sent = rte_eth_tx_buffer_flush(portid, 0, buffer); - if (sent) - port_statistics[portid].tx += sent; - } - /* if timer is enabled */ - if (timer_period > 0) { - /* advance the timer */ - timer_tsc += diff_tsc; - /* if timer has reached its timeout */ - if (unlikely(timer_tsc >= timer_period)) { - /* do this only on master core */ - if (lcore_id == rte_get_master_lcore()) { - //print_stats(); - /* reset the timer */ - timer_tsc = 0; - } - } - } - prev_tsc = cur_tsc; - } - /* - * Read packet from RX queues - */ - for (i = 0; i < qconf->n_rx_port; i++) { - portid = qconf->rx_port_list[i]; - nb_rx = rte_eth_rx_burst(portid, 0, - pkts_burst, MAX_PKT_BURST); - port_statistics[portid].rx += nb_rx; - for (j = 0; j < nb_rx; j++) { - m = pkts_burst[j]; - rte_prefetch0(rte_pktmbuf_mtod(m, void *)); - l2fwd_simple_forward(m, portid, bs); - } - } - } -} -static int -l2fwd_launch_one_lcore(void *bs) -{ - l2fwd_main_loop(bs); - return 0; -} -/* display usage */ -static void -l2fwd_usage(const char *prgname) -{ - printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" - " -p PORTMASK: hexadecimal bitmask of ports to configure\n" - " -q NQ: number of queue (=ports) per lcore (default is 1)\n" - " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" - " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" - " When enabled:\n" - " - The source MAC address is replaced by the TX port MAC address\n" - " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", - prgname); -} -static int -l2fwd_parse_portmask(const char *portmask) -{ - char *end = NULL; - unsigned long pm; - /* parse hexadecimal string */ - pm = strtoul(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - if (pm == 0) - return -1; - return pm; -} -static unsigned int -l2fwd_parse_nqueue(const char *q_arg) -{ - char *end = NULL; - unsigned long n; - /* parse hexadecimal string */ - n = strtoul(q_arg, &end, 10); - if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) - return 0; - if (n == 0) - return 0; - if (n >= MAX_RX_QUEUE_PER_LCORE) - return 0; - return n; -} -static int -l2fwd_parse_timer_period(const char *q_arg) -{ - char *end = NULL; - int n; - /* parse number string */ - n = strtol(q_arg, &end, 10); - if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - if (n >= MAX_TIMER_PERIOD) - return -1; - return n; -} -static const char short_options[] = - "p:" /* portmask */ - "q:" /* number of queues */ - "T:" /* timer period */ - ; -#define CMD_LINE_OPT_MAC_UPDATING "mac-updating" -#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" -enum { - /* long options mapped to a short option */ - /* first long only option value must be >= 256, so that we won't - * conflict with short options */ - CMD_LINE_OPT_MIN_NUM = 256, -}; -static const struct option lgopts[] = { - { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, - { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, - {NULL, 0, 0, 0} -}; -/* Parse the argument given in the command line of the application */ -static int -l2fwd_parse_args(int argc, char **argv) -{ - int opt, ret, timer_secs; - char **argvopt; - int option_index; - char *prgname = argv[0]; - argvopt = argv; - while ((opt = getopt_long(argc, argvopt, short_options, - lgopts, &option_index)) != EOF) { - switch (opt) { - /* portmask */ - case 'p': - l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); - if (l2fwd_enabled_port_mask == 0) { - printf("invalid portmask\n"); - l2fwd_usage(prgname); - return -1; - } - break; - /* nqueue */ - case 'q': - l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); - if (l2fwd_rx_queue_per_lcore == 0) { - printf("invalid queue number\n"); - l2fwd_usage(prgname); - return -1; - } - break; - /* timer period */ - case 'T': - timer_secs = l2fwd_parse_timer_period(optarg); - if (timer_secs < 0) { - printf("invalid timer period\n"); - l2fwd_usage(prgname); - return -1; - } - timer_period = timer_secs; - break; - /* long options */ - case 0: - break; - default: - l2fwd_usage(prgname); - return -1; - } - } - if (optind >= 0) - argv[optind-1] = prgname; - ret = optind-1; - optind = 1; /* reset getopt lib */ - return ret; -} -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - if (force_quit) - return; - all_ports_up = 1; - RTE_ETH_FOREACH_DEV(portid) { - if (force_quit) - return; - if ((port_mask & (1 << portid)) == 0) - continue; - memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up. Speed %u Mbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} -static void -signal_handler(int signum) -{ - if (signum == SIGINT || signum == SIGTERM) { - printf("\n\nSignal %d received, preparing to exit...\n", - signum); - force_quit = true; - } -} -int -dpdk_main(int argc, char **argv, benetel_t *bs) -{ - struct lcore_queue_conf *qconf; - int ret; - uint16_t nb_ports; - uint16_t nb_ports_available = 0; - uint16_t portid, last_port; - unsigned lcore_id, rx_lcore_id; - unsigned nb_ports_in_mask = 0; - unsigned int nb_lcores = 0; - unsigned int nb_mbufs; - /* init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); - argc -= ret; - argv += ret; - force_quit = false; - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - /* parse application arguments (after the EAL ones) */ - ret = l2fwd_parse_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); - printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); - /* convert to number of cycles */ - timer_period *= rte_get_timer_hz(); - nb_ports = rte_eth_dev_count_avail(); - if (nb_ports == 0) - rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); - /* check port mask to possible port mask */ - if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) - rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", - (1 << nb_ports) - 1); - /* reset l2fwd_dst_ports */ - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) - l2fwd_dst_ports[portid] = 0; - last_port = 0; - /* - * Each logical core is assigned a dedicated TX queue on each port. - */ - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - if (nb_ports_in_mask % 2) { - l2fwd_dst_ports[portid] = last_port; - l2fwd_dst_ports[last_port] = portid; - } - else - last_port = portid; - nb_ports_in_mask++; - } - if (nb_ports_in_mask % 2) { - printf("Notice: odd number of ports in portmask.\n"); - l2fwd_dst_ports[last_port] = last_port; - } - rx_lcore_id = 0; - qconf = NULL; - /* Initialize the port/queue configuration of each logical core */ - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - /* get the lcore_id for this port */ - while (rte_lcore_is_enabled(rx_lcore_id) == 0 || - lcore_queue_conf[rx_lcore_id].n_rx_port == - l2fwd_rx_queue_per_lcore) { - rx_lcore_id++; - if (rx_lcore_id >= RTE_MAX_LCORE) - rte_exit(EXIT_FAILURE, "Not enough cores\n"); - } - if (qconf != &lcore_queue_conf[rx_lcore_id]) { - /* Assigned a new logical core in the loop above. */ - qconf = &lcore_queue_conf[rx_lcore_id]; - nb_lcores++; - } - qconf->rx_port_list[qconf->n_rx_port] = portid; - qconf->n_rx_port++; - printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); - } - nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + - nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); - /* create the mbuf pool */ - l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, - MEMPOOL_CACHE_SIZE, 0, 9680, - rte_socket_id()); - if (l2fwd_pktmbuf_pool == NULL) - rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); - /* Initialise each port */ - RTE_ETH_FOREACH_DEV(portid) { - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_conf local_port_conf = port_conf; - struct rte_eth_dev_info dev_info; - /* skip ports that are not enabled */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { - printf("Skipping disabled port %u\n", portid); - continue; - } - nb_ports_available++; - /* init port */ - printf("Initializing port %u... ", portid); - fflush(stdout); - rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", - ret, portid); - ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, - &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors: err=%d, port=%u\n", - ret, portid); - rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); - /* init one RX queue */ - fflush(stdout); - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, - rte_eth_dev_socket_id(portid), - &rxq_conf, - l2fwd_pktmbuf_pool); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", - ret, portid); - /* init one TX queue on each port */ - fflush(stdout); - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, - rte_eth_dev_socket_id(portid), - &txq_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", - ret, portid); - /* Initialize TX buffers */ - tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", - RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, - rte_eth_dev_socket_id(portid)); - if (tx_buffer[portid] == NULL) - rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", - portid); - rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); - ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], - rte_eth_tx_buffer_count_callback, - &port_statistics[portid].dropped); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot set error callback for tx buffer on port %u\n", - portid); - /* Start device */ - ret = rte_eth_dev_start(portid); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", - ret, portid); - printf("done: \n"); - rte_eth_promiscuous_enable(portid); - printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", - portid, - l2fwd_ports_eth_addr[portid].addr_bytes[0], - l2fwd_ports_eth_addr[portid].addr_bytes[1], - l2fwd_ports_eth_addr[portid].addr_bytes[2], - l2fwd_ports_eth_addr[portid].addr_bytes[3], - l2fwd_ports_eth_addr[portid].addr_bytes[4], - l2fwd_ports_eth_addr[portid].addr_bytes[5]); - /* initialize port stats */ - memset(&port_statistics, 0, sizeof(port_statistics)); - } - if (!nb_ports_available) { - rte_exit(EXIT_FAILURE, - "All available ports are disabled. Please set portmask.\n"); - } - check_all_ports_link_status(l2fwd_enabled_port_mask); - ret = 0; - /* launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) { - ret = -1; - break; - } - } - RTE_ETH_FOREACH_DEV(portid) { - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - printf("Closing port %d...", portid); - rte_eth_dev_stop(portid); - rte_eth_dev_close(portid); - printf(" Done\n"); - } - printf("Bye...\n"); - return ret; -} diff --git a/radio/ETHERNET/benetel/4g/low.c b/radio/ETHERNET/benetel/4g/low.c deleted file mode 100644 index 14783a700b..0000000000 --- a/radio/ETHERNET/benetel/4g/low.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 "low.h" - -#include -#include -#include - -void store_ul(benetel_t *bs, ul_packet_t *ul) -{ - int a = ul->antenna; - - if (ul->subframe != bs->next_subframe[a] || - ul->symbol != bs->next_symbol[a]) { - printf("%s: fatal, antenna %d expected frame.sf.symbol %d.%d.%d, got %d.%d.%d\n", - __FUNCTION__, - a, - bs->expected_benetel_frame[a], bs->next_subframe[a], bs->next_symbol[a], - ul->frame, ul->subframe, ul->symbol); - exit(1); - } - - lock_ul_buffer(bs->buffers, bs->next_subframe[a]); - if (bs->buffers->ul_busy[a][bs->next_subframe[a]] & (1 << bs->next_symbol[a])) { - printf("%s: warning, UL overflow (sf.symbol %d.%d)\n", __FUNCTION__, - bs->next_subframe[a], bs->next_symbol[a]); - } - memcpy(bs->buffers->ul[a][bs->next_subframe[a]] + bs->next_symbol[a] * 1200*4, - ul->iq, 1200*4); - bs->buffers->ul_busy[a][bs->next_subframe[a]] |= (1 << bs->next_symbol[a]); - signal_ul_buffer(bs->buffers, bs->next_subframe[a]); - unlock_ul_buffer(bs->buffers, bs->next_subframe[a]); - - bs->next_symbol[a]++; - if (bs->next_symbol[a] == 14) { - bs->next_symbol[a] = 0; - bs->next_subframe[a] = (bs->next_subframe[a] + 1) % 10; - if (bs->next_subframe[a] == 0) { - bs->expected_benetel_frame[a]++; - bs->expected_benetel_frame[a] &= 255; - } - } -} - -void store_prach(benetel_t *bs, int frame, int subframe, void *data) -{ - static int last_frame = -1; - static int last_subframe = -1; - /* hack: antenna number is always 0, discard second packet with same f/sf */ - if (frame == last_frame && subframe == last_subframe) return; - last_frame = frame; - last_subframe = subframe; - - lock_ul_buffer(bs->buffers, subframe); - if (bs->buffers->prach_busy[subframe]) { - printf("store_prach: fatal: previous prach buffer not processed\n"); - unlock_ul_buffer(bs->buffers, subframe); - return; - } - bs->buffers->prach_busy[subframe] = 1; - memcpy(bs->buffers->prach[subframe], data, 849*4); - signal_ul_buffer(bs->buffers, subframe); - unlock_ul_buffer(bs->buffers, subframe); - -} - -void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line); - -void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line) -{ - if (!strcmp(ifname, "dpdk")) - return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line); - printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname); - exit(1); -} diff --git a/radio/ETHERNET/benetel/4g/low.h b/radio/ETHERNET/benetel/4g/low.h deleted file mode 100644 index e74bf89163..0000000000 --- a/radio/ETHERNET/benetel/4g/low.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 _BENETEL_4G_LOW_H_ -#define _BENETEL_4G_LOW_H_ - -#include "shared_buffers.h" - -typedef struct { - shared_buffers *buffers; - /* [2] is for two antennas */ - int next_subframe[2]; - int next_symbol[2]; - int expected_benetel_frame[2]; - char *dpdk_main_command_line; -} benetel_t; - -typedef struct { - int frame; - int subframe; - int slot; - int symbol; - int antenna; - unsigned char iq[4800]; -} ul_packet_t; - -void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line); - -void store_ul(benetel_t *bs, ul_packet_t *ul); -void store_prach(benetel_t *bs, int frame, int subframe, void *data); - -#endif /* _BENETEL_4G_LOW_H_ */ diff --git a/radio/ETHERNET/benetel/4g/low_dpdk.c b/radio/ETHERNET/benetel/4g/low_dpdk.c deleted file mode 100644 index edf62a67e0..0000000000 --- a/radio/ETHERNET/benetel/4g/low_dpdk.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 - */ - -/* those 2 lines for CPU_SET */ -#define _GNU_SOURCE -#include - -#include -#include -#include -#include - -#include "low.h" - -int dpdk_main(int argc, char **argv, benetel_t *); - -void *dpdk_thread(void *_bs) -{ - benetel_t *bs = _bs; - int n = 0; - char **v = NULL; // { "softmodem", "-n", "2", "-l", "8", "--", "-p", "0x2" }; - char *s = bs->dpdk_main_command_line; - char *tok; - - while ((tok = strtok(s, " ")) != NULL) { - n++; - v = realloc(v, n * sizeof(char *)); - if (v == NULL) { - printf("%s: out of memory\n", __FUNCTION__); - exit(1); - } - v[n-1] = tok; - s = NULL; - } - - dpdk_main(n, v, bs); - exit(1); - return 0; -} - -void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line) -{ - benetel_t *bs; - - bs = calloc(1, sizeof(benetel_t)); - if (bs == NULL) { - printf("%s: out of memory\n", __FUNCTION__); - exit(1); - } - - bs->buffers = buffers; - - bs->expected_benetel_frame[0] = 255; - bs->expected_benetel_frame[1] = 255; - - bs->dpdk_main_command_line = dpdk_main_command_line; - - pthread_attr_t attr; - - if (pthread_attr_init(&attr) != 0) { - printf("pthread_attr_init failed\n"); - exit(1); - } - - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(12,&cpuset); - if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) { - printf("pthread_attr_setaffinity_np failed\n"); - exit(1); - } - - if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) { - printf("pthread_attr_setschedpolicy failed\n"); - exit(1); - } - - struct sched_param params; - params.sched_priority = sched_get_priority_max(SCHED_FIFO); - if (sched_get_priority_max(SCHED_FIFO) == -1) { - printf("sched_get_priority_max failed\n"); - exit(1); - } - if (pthread_attr_setschedparam(&attr, ¶ms) != 0) { - printf("pthread_setschedparam failed\n"); - exit(1); - } - - pthread_t t; - if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) { - printf("%s: thread creation failed\n", __FUNCTION__); - exit(1); - } - - if (pthread_attr_destroy(&attr) != 0) { - printf("pthread_attr_init failed\n"); - exit(1); - } - - return bs; -} diff --git a/radio/ETHERNET/benetel/4g/shared_buffers.c b/radio/ETHERNET/benetel/4g/shared_buffers.c deleted file mode 100644 index 380cbabc73..0000000000 --- a/radio/ETHERNET/benetel/4g/shared_buffers.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 "shared_buffers.h" - -#include -#include -#include - -void init_buffers(shared_buffers *s) -{ - int subframe; - - memset(s, 0, sizeof(*s)); - - for (subframe = 0; subframe < 10; subframe++) { - if (pthread_mutex_init(&s->m_dl[subframe], NULL) != 0 || - pthread_cond_init(&s->c_dl[subframe], NULL) != 0 || - pthread_mutex_init(&s->m_ul[subframe], NULL) != 0 || - pthread_cond_init(&s->c_ul[subframe], NULL) != 0) { - printf("%s: error initializing mutex/cond\n", __FUNCTION__); - exit(1); - } - } - - /* in FDD the eNB's first transmitted DL subframe is 4 but the device - * needs to have subframes 1, 2 and 3 ready. Let's pretend there are ready. - */ - s->dl_busy[0][1] = 0x3fff; - s->dl_busy[0][2] = 0x3fff; - s->dl_busy[0][3] = 0x3fff; - s->dl_busy[1][1] = 0x3fff; - s->dl_busy[1][2] = 0x3fff; - s->dl_busy[1][3] = 0x3fff; -} - -void lock_dl_buffer(shared_buffers *s, int subframe) -{ - if (pthread_mutex_lock(&s->m_dl[subframe]) != 0) { - printf("%s: fatal: lock fails\n", __FUNCTION__); - exit(1); - } -} - -void unlock_dl_buffer(shared_buffers *s, int subframe) -{ - if (pthread_mutex_unlock(&s->m_dl[subframe]) != 0) { - printf("%s: fatal: unlock fails\n", __FUNCTION__); - exit(1); - } -} - -void wait_dl_buffer(shared_buffers *s, int subframe) -{ - if (pthread_cond_wait(&s->c_dl[subframe], &s->m_dl[subframe]) != 0) { - printf("%s: fatal: cond_wait fails\n", __FUNCTION__); - exit(1); - } -} - -void signal_dl_buffer(shared_buffers *s, int subframe) -{ - if (pthread_cond_broadcast(&s->c_dl[subframe]) != 0) { - printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__); - exit(1); - } -} - -void lock_ul_buffer(shared_buffers *s, int subframe) -{ - if (pthread_mutex_lock(&s->m_ul[subframe]) != 0) { - printf("%s: fatal: lock fails\n", __FUNCTION__); - exit(1); - } -} - -void unlock_ul_buffer(shared_buffers *s, int subframe) -{ - if (pthread_mutex_unlock(&s->m_ul[subframe]) != 0) { - printf("%s: fatal: unlock fails\n", __FUNCTION__); - exit(1); - } -} - -void wait_ul_buffer(shared_buffers *s, int subframe) -{ - if (pthread_cond_wait(&s->c_ul[subframe], &s->m_ul[subframe]) != 0) { - printf("%s: fatal: cond_wait fails\n", __FUNCTION__); - exit(1); - } -} - -void signal_ul_buffer(shared_buffers *s, int subframe) -{ - if (pthread_cond_broadcast(&s->c_ul[subframe]) != 0) { - printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__); - exit(1); - } -} diff --git a/radio/ETHERNET/benetel/4g/shared_buffers.h b/radio/ETHERNET/benetel/4g/shared_buffers.h deleted file mode 100644 index ed174265c5..0000000000 --- a/radio/ETHERNET/benetel/4g/shared_buffers.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 _BENETEL_4G_SHARED_BUFFERS_H_ -#define _BENETEL_4G_SHARED_BUFFERS_H_ - -#include -#include - -typedef struct { - /* [2] is for two antennas */ - unsigned char dl[2][10][14*1200*4]; - unsigned char ul[2][10][14*1200*4]; - uint16_t dl_busy[2][10]; - uint16_t ul_busy[2][10]; - - pthread_mutex_t m_ul[10]; - pthread_cond_t c_ul[10]; - - pthread_mutex_t m_dl[10]; - pthread_cond_t c_dl[10]; - - unsigned char prach[10][849*4]; - unsigned char prach_busy[10]; - - /* statistics/error counting */ - int ul_overflow; - int dl_underflow; -} shared_buffers; - -void init_buffers(shared_buffers *s); - -void lock_dl_buffer(shared_buffers *s, int subframe); -void unlock_dl_buffer(shared_buffers *s, int subframe); -void wait_dl_buffer(shared_buffers *s, int subframe); -void signal_dl_buffer(shared_buffers *s, int subframe); - -void lock_ul_buffer(shared_buffers *s, int subframe); -void unlock_ul_buffer(shared_buffers *s, int subframe); -void wait_ul_buffer(shared_buffers *s, int subframe); -void signal_ul_buffer(shared_buffers *s, int subframe); - -#endif /* _BENETEL_4G_SHARED_BUFFERS_H_ */ diff --git a/radio/ETHERNET/benetel/5g/CMakeLists.txt b/radio/ETHERNET/benetel/5g/CMakeLists.txt deleted file mode 100644 index cdad594ce3..0000000000 --- a/radio/ETHERNET/benetel/5g/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -pkg_check_modules(libdpdk REQUIRED libdpdk=20.05.0) - -add_library(benetel_5g MODULE - benetel.c - shared_buffers.c - low.c - low_dpdk.c - dpdk_driver.c -) - -SET(DPDK_LIBS "-Wl,-rpath,$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -Wl,--whole-archive -L$ENV{RTE_SDK}/$ENV{RTE_TARGET}/lib -ldpdk -Wl,--no-whole-archive") -target_include_directories(benetel_5g PRIVATE ${libdpdk_INCLUDE_DIRS}) -target_link_libraries(benetel_5g PRIVATE ${libdpdk_LIBRARIES}) -target_link_libraries(benetel_5g PRIVATE pthread dl rt m numa) -set_target_properties(benetel_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -I$ENV{RTE_SDK}/$ENV{RTE_TARGET}/include") -set_target_properties(benetel_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -add_custom_command(TARGET benetel_5g POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink libbenetel_5g.so liboai_transpro.so - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/radio/ETHERNET/benetel/5g/benetel.c b/radio/ETHERNET/benetel/5g/benetel.c deleted file mode 100644 index 996d568767..0000000000 --- a/radio/ETHERNET/benetel/5g/benetel.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * 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 - -#include "common_lib.h" -#include "ethernet_lib.h" -#include "shared_buffers.h" -#include "low.h" -#include "openair1/PHY/defs_gNB.h" - -typedef struct { - eth_state_t e; - shared_buffers buffers; - rru_config_msg_type_t last_msg; - int capabilities_sent; - void *benetel_priv; - char *dpdk_main_command_line; -} benetel_eth_state_t; - -int trx_benetel_start(openair0_device *device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return 0; -} - - -void trx_benetel_end(openair0_device *device) -{ - printf("BENETEL: %s\n", __FUNCTION__); -} - - -int trx_benetel_stop(openair0_device *device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_set_freq(openair0_device* device, openair0_config_t *openair0_cfg) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_set_gains(openair0_device* device, - openair0_config_t *openair0_cfg) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_get_stats(openair0_device* device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int trx_benetel_reset_stats(openair0_device* device) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return(0); -} - - -int ethernet_tune(openair0_device *device, - unsigned int option, - int value) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return 0; -} - -int trx_benetel_write_raw(openair0_device *device, - openair0_timestamp timestamp, - void **buff, int nsamps, int cc, int flags) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return nsamps*4; -} - -int trx_benetel_read_raw(openair0_device *device, - openair0_timestamp *timestamp, - void **buff, int nsamps, int cc) -{ - printf("BENETEL: %s\n", __FUNCTION__); - return nsamps*4; -} - -char *msg_type(int t) -{ - static char *s[12] = { - "RAU_tick", - "RRU_capabilities", - "RRU_config", - "RRU_config_ok", - "RRU_start", - "RRU_stop", - "RRU_sync_ok", - "RRU_frame_resynch", - "RRU_MSG_max_num", - "RRU_check_sync", - "RRU_config_update", - "RRU_config_update_ok", - }; - - if (t < 0 || t > 11) return "UNKNOWN"; - return s[t]; -} - -int trx_benetel_ctlsend(openair0_device *device, void *msg, ssize_t msg_len) -{ - RRU_CONFIG_msg_t *rru_config_msg = msg; - benetel_eth_state_t *s = device->priv; - - printf("BENETEL: %s\n", __FUNCTION__); - - printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type, - msg_type(rru_config_msg->type)); - - s->last_msg = rru_config_msg->type; - - return msg_len; -} - -int trx_benetel_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len) -{ - RRU_CONFIG_msg_t *rru_config_msg = msg; - benetel_eth_state_t *s = device->priv; - - printf("BENETEL: %s\n", __FUNCTION__); - - if (s->last_msg == RAU_tick && s->capabilities_sent == 0) { - RRU_capabilities_t *cap; - rru_config_msg->type = RRU_capabilities; - rru_config_msg->len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); - cap = (RRU_capabilities_t*)&rru_config_msg->msg[0]; - cap->FH_fmt = OAI_IF4p5_only; - cap->num_bands = 1; - cap->band_list[0] = 78; - /* TODO: hardcoded to 1 for the moment, get the real value somehow... */ - cap->nb_rx[0] = 1; //device->openair0_cfg->rx_num_channels; - cap->nb_tx[0] = 1; //device->openair0_cfg->tx_num_channels; - cap->max_pdschReferenceSignalPower[0] = -27; - cap->max_rxgain[0] = 90; - - s->capabilities_sent = 1; - - return rru_config_msg->len; - } -#if 0 - if (s->last_msg == RRU_config) { - rru_config_msg->type = RRU_config_ok; - return 0; - } - if (s->last_msg == RRU_start) { -printf("***************** benetel start\n"); - s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line); - } -#endif - if (s->last_msg == RRU_config) { - rru_config_msg->type = RRU_config_ok; - s->benetel_priv = benetel_start(s->e.if_name, &s->buffers, s->dpdk_main_command_line); - } - /* correct? */ -//printf("***************** benetel pause\n"); -// while (1) pause(); - - return 0; -} - -void benetel_fh_if4p5_south_in(RU_t *ru, - int *frame, - int *slot) -{ -//printf("XXX benetel_fh_if4p5_south_in %d %d\n", *frame, *slot); - benetel_eth_state_t *s = ru->ifdevice.priv; - NR_DL_FRAME_PARMS *fp; - int symbol; - int32_t *rxdata; - int antenna; - - lock_ul_buffer(&s->buffers, *slot); -#if 1 -next: - while (!((s->buffers.ul_busy[0][*slot] == 0x3fff && - s->buffers.ul_busy[1][*slot] == 0x3fff) || - s->buffers.prach_busy[*slot] == 1)) - wait_ul_buffer(&s->buffers, *slot); - if (s->buffers.prach_busy[*slot] == 1) { - int i; - int antenna = 0; - uint16_t *in; - uint16_t *out; - in = (uint16_t *)s->buffers.prach[*slot]; - out = (uint16_t *)ru->prach_rxsigF[0][antenna]; - for (i = 0; i < 839*2; i++) - out[i] = ntohs(in[i]); - s->buffers.prach_busy[*slot] = 0; - //printf("prach for f.sl %d.%d\n", *frame, *slot); - //ru->wakeup_prach_gNB(ru->gNB_list[0], ru, *frame, *slot); - goto next; - } -#endif - - fp = ru->nr_frame_parms; - for (antenna = 0; antenna < ru->nb_rx; antenna++) { - for (symbol = 0; symbol < 14; symbol++) { - int i; - int16_t *p = (int16_t *)(&s->buffers.ul[antenna][*slot][symbol*1272*4]); - for (i = 0; i < 1272*2; i++) { - p[i] = (int16_t)(ntohs(p[i])) / 16; - } - rxdata = &ru->common.rxdataF[antenna][symbol * fp->ofdm_symbol_size]; -#if 0 -if (*slot == 0 && symbol == 0) -printf("rxdata in benetel_fh_if4p5_south_in %p\n", &ru->common.rxdataF[antenna][0]); -#endif -#if 1 - memcpy(rxdata + 2048 - 1272/2, - &s->buffers.ul[antenna][*slot][symbol*1272*4], - (1272/2) * 4); - memcpy(rxdata, - &s->buffers.ul[antenna][*slot][symbol*1272*4] + (1272/2)*4, - (1272/2) * 4); -#endif - } - } - - s->buffers.ul_busy[0][*slot] = 0; - s->buffers.ul_busy[1][*slot] = 0; - signal_ul_buffer(&s->buffers, *slot); - unlock_ul_buffer(&s->buffers, *slot); - - //printf("BENETEL: %s (f.sf %d.%d)\n", __FUNCTION__, *frame, *slot); - - RU_proc_t *proc = &ru->proc; - int f = *frame; - int sl = *slot; - - //calculate timestamp_rx, timestamp_tx based on frame and slot - proc->tti_rx = sl; - proc->frame_rx = f; - /* TODO: be sure of samples_per_slot0 - FK: should use get_samples_per_slot(slot) - but for mu=1 its ok - */ - proc->timestamp_rx = ((proc->frame_rx * 20) + proc->tti_rx ) * fp->samples_per_slot0; - - if (get_nprocs()<=4) { - // why? what if there are more? - proc->tti_tx = (sl+ru->sl_ahead)%20; - proc->frame_tx = (sl>(19-ru->sl_ahead)) ? (f+1)&1023 : f; - } -} - -void benetel_fh_if4p5_south_out(RU_t *ru, - int frame, - int slot, - uint64_t timestamp) -{ - -//printf("XXX benetel_fh_if4p5_south_out %d %d %ld\n", frame, slot, timestamp); - benetel_eth_state_t *s = ru->ifdevice.priv; - NR_DL_FRAME_PARMS *fp; - int symbol; - int32_t *txdata; - int aa; - - //printf("BENETEL: %s (f.sf %d.%d ts %ld)\n", __FUNCTION__, frame, slot, timestamp); - - lock_dl_buffer(&s->buffers, slot); - if (s->buffers.dl_busy[0][slot] || - s->buffers.dl_busy[1][slot]) { - printf("%s: fatal: DL buffer busy for subframe %d\n", __FUNCTION__, slot); - unlock_dl_buffer(&s->buffers, slot); - return; - } - - fp = ru->nr_frame_parms; - if (ru->num_gNB != 1 || fp->ofdm_symbol_size != 2048 || - fp->Ncp != NORMAL || fp->symbols_per_slot != 14) { - printf("%s:%d:%s: unsupported configuration\n", - __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - for (aa = 0; aa < ru->nb_tx; aa++) { - for (symbol = 0; symbol < 14; symbol++) { - txdata = &ru->common.txdataF_BF[aa][symbol * fp->ofdm_symbol_size]; -#if 1 - memcpy(&s->buffers.dl[aa][slot][symbol*1272*4], - txdata + 2048 - (1272/2), - (1272/2) * 4); - memcpy(&s->buffers.dl[aa][slot][symbol*1272*4] + (1272/2)*4, - txdata, - (1272/2) * 4); -#endif - int i; - uint16_t *p = (uint16_t *)(&s->buffers.dl[aa][slot][symbol*1272*4]); - for (i = 0; i < 1272*2; i++) { - p[i] = htons(p[i]); - } - } - } - - s->buffers.dl_busy[0][slot] = 0x3fff; - s->buffers.dl_busy[1][slot] = 0x3fff; - unlock_dl_buffer(&s->buffers, slot); -} - -void *get_internal_parameter(char *name) -{ - printf("BENETEL: %s\n", __FUNCTION__); - - if (!strcmp(name, "fh_if4p5_south_in")) - return benetel_fh_if4p5_south_in; - if (!strcmp(name, "fh_if4p5_south_out")) - return benetel_fh_if4p5_south_out; - - return NULL; -} - -__attribute__((__visibility__("default"))) -int transport_init(openair0_device *device, - openair0_config_t *openair0_cfg, - eth_params_t * eth_params ) -{ - benetel_eth_state_t *eth; - - printf("BENETEL: %s\n", __FUNCTION__); - - device->Mod_id = 0; - device->transp_type = ETHERNET_TP; - device->trx_start_func = trx_benetel_start; - device->trx_get_stats_func = trx_benetel_get_stats; - device->trx_reset_stats_func = trx_benetel_reset_stats; - device->trx_end_func = trx_benetel_end; - device->trx_stop_func = trx_benetel_stop; - device->trx_set_freq_func = trx_benetel_set_freq; - device->trx_set_gains_func = trx_benetel_set_gains; - - device->trx_write_func = trx_benetel_write_raw; - device->trx_read_func = trx_benetel_read_raw; - - device->trx_ctlsend_func = trx_benetel_ctlsend; - device->trx_ctlrecv_func = trx_benetel_ctlrecv; - - device->get_internal_parameter = get_internal_parameter; - - eth = calloc(1, sizeof(benetel_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; - device->priv = eth; - device->openair0_cfg=&openair0_cfg[0]; - - if (openair0_cfg->sdr_addrs == NULL) { - printf("benetel: fatal: sdr_addrs not set in configuration file\n"); - exit(1); - } - - eth->dpdk_main_command_line = strdup(openair0_cfg->sdr_addrs); - if (eth->dpdk_main_command_line == NULL) { - AssertFatal(0==1, "out of memory\n"); - } - - eth->last_msg = -1; - - init_buffers(ð->buffers); - - return 0; -} diff --git a/radio/ETHERNET/benetel/5g/dpdk_driver.c b/radio/ETHERNET/benetel/5g/dpdk_driver.c deleted file mode 100644 index 9b398e9bd9..0000000000 --- a/radio/ETHERNET/benetel/5g/dpdk_driver.c +++ /dev/null @@ -1,835 +0,0 @@ -/* license: to be defined */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "low.h" - -// HEADER DEFINITION -#define ANT_NUM buf[23] -#define PAYLOAD_1 buf[20] -#define PAYLOAD_2 buf[21] -#define ETH_TYPE buf[17] -#define SYMBOL buf[29] -#define SUBFRAME buf[28] -#define FRAME buf[27] - -static volatile bool force_quit; - -unsigned short iq[712320]; -unsigned char iq_swap[1424640]; - -unsigned short *iq_ptr[14]; -unsigned int dl_start = 0, slot_id_ctrl = 0, count_symbol = 0, sf = 0x10; - -/* MAC updating enabled by default */ -static int mac_updating = 1; -#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 -#define MAX_PKT_BURST 32 -#define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */ -#define MEMPOOL_CACHE_SIZE 256 -/* - * Configurable number of RX/TX ring descriptors - */ -#define RTE_TEST_RX_DESC_DEFAULT 1024 -#define RTE_TEST_TX_DESC_DEFAULT 1024 -static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; -static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; -/* ethernet addresses of ports */ -static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; -/* mask of enabled ports */ -static uint32_t l2fwd_enabled_port_mask = 0; -/* list of enabled ports */ -static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; -static unsigned int l2fwd_rx_queue_per_lcore = 1; -#define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 16 -struct lcore_queue_conf { - unsigned n_rx_port; - unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; -} __rte_cache_aligned; -struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; -static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; -static struct rte_eth_conf port_conf = { - .rxmode = { - .split_hdr_size = 0, - .offloads = DEV_RX_OFFLOAD_JUMBO_FRAME, - .split_hdr_size = 0, - .max_rx_pkt_len = 9500, - }, - .txmode = { - .mq_mode = ETH_MQ_TX_NONE, - }, -}; -struct rte_mempool * l2fwd_pktmbuf_pool = NULL; -/* Per-port statistics struct */ -struct l2fwd_port_statistics { - uint64_t tx; - uint64_t rx; - uint64_t dropped; -} __rte_cache_aligned; -struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; -#define MAX_TIMER_PERIOD 86400 /* 1 day max */ -/* A tsc-based timer responsible for triggering statistics printout */ -static uint64_t timer_period = 10; /* default period is 10 seconds */ -/* Print out statistics on packets dropped */ -static void -print_stats(void) -{ - uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; - unsigned portid; - total_packets_dropped = 0; - total_packets_tx = 0; - total_packets_rx = 0; - const char clr[] = { 27, '[', '2', 'J', '\0' }; - const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; - /* Clear screen and move to top left */ - printf("%s%s", clr, topLeft); - printf("\nPort statistics ===================================="); - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { - /* skip disabled ports */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - printf("\nStatistics for port %u ------------------------------" - "\nPackets sent: %24"PRIu64 - "\nPackets received: %20"PRIu64 - "\nPackets dropped: %21"PRIu64, - portid, - port_statistics[portid].tx, - port_statistics[portid].rx, - port_statistics[portid].dropped); - total_packets_dropped += port_statistics[portid].dropped; - total_packets_tx += port_statistics[portid].tx; - total_packets_rx += port_statistics[portid].rx; - } - printf("\nAggregate statistics ===============================" - "\nTotal packets sent: %18"PRIu64 - "\nTotal packets received: %14"PRIu64 - "\nTotal packets dropped: %15"PRIu64, - total_packets_tx, - total_packets_rx, - total_packets_dropped); - printf("\n====================================================\n"); -} -static void -l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs) -{ - unsigned char *buf, *buf_tx; - unsigned int len; - struct ether_hdr *eth; - - unsigned dst_port; - int sent, prach_ctrl = 0; - struct rte_eth_dev_tx_buffer *buffer; - - unsigned char * IQ_ptr; - - ul_packet_t p; - - buf = rte_pktmbuf_mtod(m, unsigned char *); - //DD Debug - //rte_memdump(stdout, "Rx Packet",buf ,34); - eth = rte_pktmbuf_mtod(m, struct ether_hdr *); - len = rte_pktmbuf_data_len(m); - - IQ_ptr = &buf[34]; - if (portid == 0) - { - //destination mac address (RRU MAC) - /*eth->d_addr.addr_bytes[0] = 0x02; - eth->d_addr.addr_bytes[1] = 0x00; - eth->d_addr.addr_bytes[2] = 0x5e; - eth->d_addr.addr_bytes[3] = 0x01; - eth->d_addr.addr_bytes[4] = 0x01; - eth->d_addr.addr_bytes[5] = 0x01;*/ - - eth->d_addr.addr_bytes[0] = buf[6]; - eth->d_addr.addr_bytes[1] = buf[7]; - eth->d_addr.addr_bytes[2] = buf[8]; - eth->d_addr.addr_bytes[3] = buf[9]; - eth->d_addr.addr_bytes[4] = buf[10]; - eth->d_addr.addr_bytes[5] = buf[11]; - - //source mac address (DU MAC) - eth->s_addr.addr_bytes[0] = 0xdd; - eth->s_addr.addr_bytes[1] = 0xdd; - eth->s_addr.addr_bytes[2] = 0xdd; - eth->s_addr.addr_bytes[3] = 0xdd; - eth->s_addr.addr_bytes[4] = 0xdd; - eth->s_addr.addr_bytes[5] = 0xdd; - } - else - { - //destination mac address (RRU MAC) - /*eth->d_addr.addr_bytes[0] = 0x02; - eth->d_addr.addr_bytes[1] = 0x00; - eth->d_addr.addr_bytes[2] = 0x5e; - eth->d_addr.addr_bytes[3] = 0x01; - eth->d_addr.addr_bytes[4] = 0x01; - eth->d_addr.addr_bytes[5] = 0x01;*/ - - eth->d_addr.addr_bytes[0] = buf[6]; - eth->d_addr.addr_bytes[1] = buf[7]; - eth->d_addr.addr_bytes[2] = buf[8]; - eth->d_addr.addr_bytes[3] = buf[9]; - eth->d_addr.addr_bytes[4] = buf[10]; - eth->d_addr.addr_bytes[5] = buf[11]; - //source mac address (DU MAC) - eth->s_addr.addr_bytes[0] = 0xdd; - eth->s_addr.addr_bytes[1] = 0xdd; - eth->s_addr.addr_bytes[2] = 0xdd; - eth->s_addr.addr_bytes[3] = 0xdd; - eth->s_addr.addr_bytes[4] = 0xdd; - eth->s_addr.addr_bytes[5] = 0xde; - - } - dst_port = l2fwd_dst_ports[portid]; - //DD Debug - //printf("dstPort =%d\n", dst_port); - // Handshake Condition - if (buf[18] == 0xAA ) // ORAN handshake msgs. - { - printf("\n Start UP Request Received\n"); - printf("\n====================================================\n"); - - buf[18] = 0xBB;//change to msg2 after receive msg1 - - printf(" Start Up Response Sent\n"); - printf("\n====================================================\n"); - - } - - // Trigger start send DL packets - if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && SYMBOL == 0x44 && ANT_NUM == 0x00 && SUBFRAME == 0x00 && dl_start == 0){ - - printf("\nU-Plane Started\n"); - printf("\n====================================================\n"); - - dl_start = 1; - count_symbol = 28; - } - - - if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4) { - int subframe = SUBFRAME >> 4; - int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03); - p.frame = FRAME; - p.slot = subframe * 2 + slot; - p.symbol = SYMBOL & 0x3f; - p.antenna = ANT_NUM; - memcpy(p.iq, IQ_ptr, 5088); - store_ul(bs, &p); - // if (p.symbol==0) printf("store ul f.sl.sy %d.%d.%d\n", p.frame, p.slot, p.symbol); - } - - // U-PLANE UL PROCESSING - if(PAYLOAD_1 == 0x13 && PAYLOAD_2 == 0xe4 && dl_start == 1) - { - int a = ANT_NUM & 0x01; - int frame = FRAME; - int subframe = SUBFRAME >> 4; - int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03); - int symbol = SYMBOL & 0x3f; - int oai_slot; - - int tx_frame = frame; - int tx_subframe = subframe; - int tx_slot = slot; - int tx_symbol = symbol + 10; - - if (tx_symbol > 13) { - tx_symbol -= 14; - tx_slot++; - if (tx_slot == 2) { - tx_slot = 0; - tx_subframe++; - if (tx_subframe == 10) { - tx_subframe = 0; - tx_frame = (tx_frame + 1) & 255; - } - } - } - - // Mask the symbol bits from UL packet received and apply the shift. - SYMBOL = ((SYMBOL & 0b00111111) + 10) % 14; - - ANT_NUM = a; - SUBFRAME = sf; - - if (a == 1) - slot_id_ctrl++; - - // Slot id control for DL - if (slot_id_ctrl > 13) { - SYMBOL = SYMBOL | 0b01000000; - - if (a == 1) { - if (slot_id_ctrl > 27) { - slot_id_ctrl = 0; - sf = sf + 0x10; - - if (sf > 0x90){ - sf = 0; - } - } - } - } - - /* send actual DL data (if available) */ - oai_slot = tx_subframe * 2 + tx_slot; - lock_dl_buffer(bs->buffers, oai_slot); - if (!(bs->buffers->dl_busy[a][oai_slot] & (1 << tx_symbol))) { - //printf("%s: warning, DL underflow (antenna %d sl.symbol %d.%d)\n", __FUNCTION__,a, oai_slot, tx_symbol); - memset(IQ_ptr, 0, 1272 * 4); - } else { - memcpy(IQ_ptr, bs->buffers->dl[a][oai_slot] + tx_symbol * 1272*4, - 1272*4); - } - //printf("DL buffer f sf slot symbol %d %d %d %d (sf %d)\n", tx_frame, tx_subframe, tx_slot, tx_symbol, (int)sf); - bs->buffers->dl_busy[a][oai_slot] &= ~(1 << tx_symbol); - unlock_dl_buffer(bs->buffers, oai_slot); - } - - // U-PLANE PRACH PROCESSING - else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){ - if (ANT_NUM == 0) { - int subframe = SUBFRAME >> 4; - //int slot = ((SUBFRAME & 0x0f) << 2) | ((SYMBOL >> 6) & 0x03); - if (subframe==9) { - //printf("store prach f.sf.sl %d.%d.%d %d\n", FRAME, subframe, slot, subframe * 2 + slot); - store_prach(bs, FRAME, subframe * 2 + 1, IQ_ptr); - } - } - rte_pktmbuf_free(m); - return; - } - - // Send Packets - buffer = tx_buffer[dst_port]; - - sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); - - if (sent) - port_statistics[dst_port].tx += sent; - -} -/* main processing loop */ -static void -l2fwd_main_loop(benetel_t *bs) -{ - struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; - struct rte_mbuf *m; - int sent; - unsigned lcore_id; - uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; - unsigned i, j, portid, nb_rx; - struct lcore_queue_conf *qconf; - const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * - BURST_TX_DRAIN_US; - struct rte_eth_dev_tx_buffer *buffer; - prev_tsc = 0; - timer_tsc = 0; - lcore_id = rte_lcore_id(); - qconf = &lcore_queue_conf[lcore_id]; - if (qconf->n_rx_port == 0) { - RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); - return; - } - RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); - for (i = 0; i < qconf->n_rx_port; i++) { - portid = qconf->rx_port_list[i]; - RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, - portid); - } - while (!force_quit) { - cur_tsc = rte_rdtsc(); - /* - * TX burst queue drain - */ - diff_tsc = cur_tsc - prev_tsc; - if (unlikely(diff_tsc > drain_tsc)) { - for (i = 0; i < qconf->n_rx_port; i++) { - portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; - buffer = tx_buffer[portid]; - sent = rte_eth_tx_buffer_flush(portid, 0, buffer); - if (sent) - port_statistics[portid].tx += sent; - } - /* if timer is enabled */ - if (timer_period > 0) { - /* advance the timer */ - timer_tsc += diff_tsc; - /* if timer has reached its timeout */ - if (unlikely(timer_tsc >= timer_period)) { - /* do this only on master core */ - if (lcore_id == rte_get_master_lcore()) { - print_stats(); - /* reset the timer */ - timer_tsc = 0; - } - } - } - prev_tsc = cur_tsc; - } - /* - * Read packet from RX queues - */ - for (i = 0; i < qconf->n_rx_port; i++) { - portid = qconf->rx_port_list[i]; - nb_rx = rte_eth_rx_burst(portid, 0, - pkts_burst, MAX_PKT_BURST); - port_statistics[portid].rx += nb_rx; - for (j = 0; j < nb_rx; j++) { - m = pkts_burst[j]; - rte_prefetch0(rte_pktmbuf_mtod(m, void *)); - l2fwd_simple_forward(m, portid, bs); - } - } - } -} -static int -l2fwd_launch_one_lcore(void *bs) -{ - l2fwd_main_loop(bs); - return 0; -} -/* display usage */ -static void -l2fwd_usage(const char *prgname) -{ - printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" - " -p PORTMASK: hexadecimal bitmask of ports to configure\n" - " -q NQ: number of queue (=ports) per lcore (default is 1)\n" - " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" - " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" - " When enabled:\n" - " - The source MAC address is replaced by the TX port MAC address\n" - " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", - prgname); -} -static int -l2fwd_parse_portmask(const char *portmask) -{ - char *end = NULL; - unsigned long pm; - /* parse hexadecimal string */ - pm = strtoul(portmask, &end, 16); - if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - if (pm == 0) - return -1; - return pm; -} -static unsigned int -l2fwd_parse_nqueue(const char *q_arg) -{ - char *end = NULL; - unsigned long n; - /* parse hexadecimal string */ - n = strtoul(q_arg, &end, 10); - if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) - return 0; - if (n == 0) - return 0; - if (n >= MAX_RX_QUEUE_PER_LCORE) - return 0; - return n; -} -static int -l2fwd_parse_timer_period(const char *q_arg) -{ - char *end = NULL; - int n; - /* parse number string */ - n = strtol(q_arg, &end, 10); - if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) - return -1; - if (n >= MAX_TIMER_PERIOD) - return -1; - return n; -} -static const char short_options[] = - "p:" /* portmask */ - "q:" /* number of queues */ - "T:" /* timer period */ - ; -#define CMD_LINE_OPT_MAC_UPDATING "mac-updating" -#define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" -enum { - /* long options mapped to a short option */ - /* first long only option value must be >= 256, so that we won't - * conflict with short options */ - CMD_LINE_OPT_MIN_NUM = 256, -}; -static const struct option lgopts[] = { - { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, - { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, - {NULL, 0, 0, 0} -}; -/* Parse the argument given in the command line of the application */ -static int -l2fwd_parse_args(int argc, char **argv) -{ - int opt, ret, timer_secs; - char **argvopt; - int option_index; - char *prgname = argv[0]; - argvopt = argv; - while ((opt = getopt_long(argc, argvopt, short_options, - lgopts, &option_index)) != EOF) { - switch (opt) { - /* portmask */ - case 'p': - l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); - if (l2fwd_enabled_port_mask == 0) { - printf("invalid portmask\n"); - l2fwd_usage(prgname); - return -1; - } - break; - /* nqueue */ - case 'q': - l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); - if (l2fwd_rx_queue_per_lcore == 0) { - printf("invalid queue number\n"); - l2fwd_usage(prgname); - return -1; - } - break; - /* timer period */ - case 'T': - timer_secs = l2fwd_parse_timer_period(optarg); - if (timer_secs < 0) { - printf("invalid timer period\n"); - l2fwd_usage(prgname); - return -1; - } - timer_period = timer_secs; - break; - /* long options */ - case 0: - break; - case 'proc-type': - break; - case 'socket-mem': - break; - case 'file-prefix': - l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); - if (l2fwd_rx_queue_per_lcore == 0) { - printf("invalid queue number\n"); - l2fwd_usage(prgname); - return -1; - } - break; - /* timer period */ - /* timer period */ - /* timer period */ - default: - l2fwd_usage(prgname); - return -1; - } - } - if (optind >= 0) - argv[optind-1] = prgname; - ret = optind-1; - optind = 1; /* reset getopt lib */ - return ret; -} -/* Check the link status of all ports in up to 9s, and print them finally */ -static void -check_all_ports_link_status(uint32_t port_mask) -{ -#define CHECK_INTERVAL 100 /* 100ms */ -#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ - uint16_t portid; - uint8_t count, all_ports_up, print_flag = 0; - struct rte_eth_link link; - printf("\nChecking link status"); - fflush(stdout); - for (count = 0; count <= MAX_CHECK_TIME; count++) { - if (force_quit) - return; - all_ports_up = 1; - RTE_ETH_FOREACH_DEV(portid) { - if (force_quit) - return; - if ((port_mask & (1 << portid)) == 0) - continue; - memset(&link, 0, sizeof(link)); - rte_eth_link_get_nowait(portid, &link); - /* print link status if flag set */ - if (print_flag == 1) { - if (link.link_status) - printf( - "Port%d Link Up. Speed %u Mbps - %s\n", - portid, link.link_speed, - (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? - ("full-duplex") : ("half-duplex\n")); - else - printf("Port %d Link Down\n", portid); - continue; - } - /* clear all_ports_up flag if any link down */ - if (link.link_status == ETH_LINK_DOWN) { - all_ports_up = 0; - break; - } - } - /* after finally printing all link status, get out */ - if (print_flag == 1) - break; - if (all_ports_up == 0) { - printf("."); - fflush(stdout); - rte_delay_ms(CHECK_INTERVAL); - } - /* set the print_flag if all ports up or timeout */ - if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { - print_flag = 1; - printf("done\n"); - } - } -} -static void -signal_handler(int signum) -{ - if (signum == SIGINT || signum == SIGTERM) { - printf("\n\nSignal %d received, preparing to exit...\n", - signum); - force_quit = true; - } -} -int -dpdk_main(int argc, char **argv, benetel_t *bs) -{ - struct lcore_queue_conf *qconf; - int ret; - uint16_t nb_ports; - uint16_t nb_ports_available = 0; - uint16_t portid, last_port; - unsigned lcore_id, rx_lcore_id; - unsigned nb_ports_in_mask = 0; - unsigned int nb_lcores = 0; - unsigned int nb_mbufs; - /* init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); - argc -= ret; - argv += ret; - force_quit = false; - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - /* parse application arguments (after the EAL ones) */ - ret = l2fwd_parse_args(argc, argv); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); - printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); - /* convert to number of cycles */ - timer_period *= rte_get_timer_hz(); - nb_ports = rte_eth_dev_count_avail(); - if (nb_ports == 0) - rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); - /* check port mask to possible port mask */ - if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) - rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", - (1 << nb_ports) - 1); - /* reset l2fwd_dst_ports */ - for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) - l2fwd_dst_ports[portid] = 0; - last_port = 0; - /* - * Each logical core is assigned a dedicated TX queue on each port. - */ - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - if (nb_ports_in_mask % 2) { - l2fwd_dst_ports[portid] = last_port; - l2fwd_dst_ports[last_port] = portid; - } - else - last_port = portid; - nb_ports_in_mask++; - } - if (nb_ports_in_mask % 2) { - printf("Notice: odd number of ports in portmask.\n"); - l2fwd_dst_ports[last_port] = last_port; - } - rx_lcore_id = 0; - qconf = NULL; - /* Initialize the port/queue configuration of each logical core */ - RTE_ETH_FOREACH_DEV(portid) { - /* skip ports that are not enabled */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - /* get the lcore_id for this port */ - while (rte_lcore_is_enabled(rx_lcore_id) == 0 || - lcore_queue_conf[rx_lcore_id].n_rx_port == - l2fwd_rx_queue_per_lcore) { - rx_lcore_id++; - if (rx_lcore_id >= RTE_MAX_LCORE) - rte_exit(EXIT_FAILURE, "Not enough cores\n"); - } - if (qconf != &lcore_queue_conf[rx_lcore_id]) { - /* Assigned a new logical core in the loop above. */ - qconf = &lcore_queue_conf[rx_lcore_id]; - nb_lcores++; - } - qconf->rx_port_list[qconf->n_rx_port] = portid; - qconf->n_rx_port++; - printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); - } - nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + - nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); - /* create the mbuf pool */ - //DD Debug - //printf ("Proc Type %d \n", rte_eal_process_type()); - l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, - MEMPOOL_CACHE_SIZE, 0, 9680, - rte_socket_id()); - if (l2fwd_pktmbuf_pool == NULL) - rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); - /* Initialise each port */ - RTE_ETH_FOREACH_DEV(portid) { - struct rte_eth_rxconf rxq_conf; - struct rte_eth_txconf txq_conf; - struct rte_eth_conf local_port_conf = port_conf; - struct rte_eth_dev_info dev_info; - /* skip ports that are not enabled */ - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { - printf("Skipping disabled port %u\n", portid); - continue; - } - nb_ports_available++; - /* init port */ - printf("Initializing port %u... ", portid); - fflush(stdout); - rte_eth_dev_info_get(portid, &dev_info); - if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) - local_port_conf.txmode.offloads |= - DEV_TX_OFFLOAD_MBUF_FAST_FREE; - ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", - ret, portid); - ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, - &nb_txd); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot adjust number of descriptors: err=%d, port=%u\n", - ret, portid); - rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); - /* init one RX queue */ - fflush(stdout); - rxq_conf = dev_info.default_rxconf; - rxq_conf.offloads = local_port_conf.rxmode.offloads; - ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, - rte_eth_dev_socket_id(portid), - &rxq_conf, - l2fwd_pktmbuf_pool); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", - ret, portid); - /* init one TX queue on each port */ - fflush(stdout); - txq_conf = dev_info.default_txconf; - txq_conf.offloads = local_port_conf.txmode.offloads; - ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, - rte_eth_dev_socket_id(portid), - &txq_conf); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", - ret, portid); - /* Initialize TX buffers */ - tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", - RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, - rte_eth_dev_socket_id(portid)); - if (tx_buffer[portid] == NULL) - rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", - portid); - rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); - ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], - rte_eth_tx_buffer_count_callback, - &port_statistics[portid].dropped); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Cannot set error callback for tx buffer on port %u\n", - portid); - /* Start device */ - ret = rte_eth_dev_start(portid); - if (ret < 0) - rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", - ret, portid); - printf("done: \n"); - rte_eth_promiscuous_enable(portid); - printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", - portid, - l2fwd_ports_eth_addr[portid].addr_bytes[0], - l2fwd_ports_eth_addr[portid].addr_bytes[1], - l2fwd_ports_eth_addr[portid].addr_bytes[2], - l2fwd_ports_eth_addr[portid].addr_bytes[3], - l2fwd_ports_eth_addr[portid].addr_bytes[4], - l2fwd_ports_eth_addr[portid].addr_bytes[5]); - /* initialize port stats */ - memset(&port_statistics, 0, sizeof(port_statistics)); - } - if (!nb_ports_available) { - rte_exit(EXIT_FAILURE, - "All available ports are disabled. Please set portmask.\n"); - } - check_all_ports_link_status(l2fwd_enabled_port_mask); - ret = 0; - /* launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER); - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) { - ret = -1; - break; - } - } - RTE_ETH_FOREACH_DEV(portid) { - if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) - continue; - printf("Closing port %d...", portid); - rte_eth_dev_stop(portid); - rte_eth_dev_close(portid); - printf(" Done\n"); - } - printf("Bye...\n"); - return ret; -} diff --git a/radio/ETHERNET/benetel/5g/low.c b/radio/ETHERNET/benetel/5g/low.c deleted file mode 100644 index b34d69784f..0000000000 --- a/radio/ETHERNET/benetel/5g/low.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 "low.h" - -#include -#include -#include - -void store_ul(benetel_t *bs, ul_packet_t *ul) -{ -#if 0 -struct timespec t; -static struct timespec old; -clock_gettime(CLOCK_REALTIME, &t); -printf("store_ul %d.%ld (%ld)\n", (int)(t.tv_sec % 60), t.tv_nsec, t.tv_nsec - old.tv_nsec); -old = t; -#endif - - int a = ul->antenna; - - if (ul->slot != bs->next_slot[a] || - ul->symbol != bs->next_symbol[a]) { - printf("%s: error, antenna %d expected frame.sl.symbol %d.%d.%d, got %d.%d.%d\n", - __FUNCTION__, - a, bs->expected_benetel_frame[a], bs->next_slot[a], bs->next_symbol[a], - ul->frame, ul->slot, ul->symbol); - } - - /* fill missing data with 0s */ - while (ul->slot != bs->next_slot[a] || - ul->symbol != bs->next_symbol[a]) { - lock_ul_buffer(bs->buffers, bs->next_slot[a]); - if (bs->buffers->ul_busy[a][bs->next_slot[a]] & (1 << bs->next_symbol[a])) { - printf("%s: warning, antenna %d UL overflow (sl.symbol %d.%d)\n", __FUNCTION__, - a, bs->next_slot[a], bs->next_symbol[a]); - } - - memset(bs->buffers->ul[a][bs->next_slot[a]] + bs->next_symbol[a] * 1272*4, - 0, 1272*4); - bs->buffers->ul_busy[a][bs->next_slot[a]] |= (1 << bs->next_symbol[a]); - signal_ul_buffer(bs->buffers, bs->next_slot[a]); - unlock_ul_buffer(bs->buffers, bs->next_slot[a]); - - bs->next_symbol[a]++; - if (bs->next_symbol[a] == 14) { - bs->next_symbol[a] = 0; - bs->next_slot[a] = (bs->next_slot[a] + 1) % 20; - if (bs->next_slot[a] == 0) { - bs->expected_benetel_frame[a]++; - bs->expected_benetel_frame[a] &= 255; - } - } - } - - lock_ul_buffer(bs->buffers, bs->next_slot[a]); - if (bs->buffers->ul_busy[a][bs->next_slot[a]] & (1 << bs->next_symbol[a])) { - printf("%s: warning, antenna %d UL overflow (sl.symbol %d.%d)\n", __FUNCTION__, - a, bs->next_slot[a], bs->next_symbol[a]); - } - - memcpy(bs->buffers->ul[a][bs->next_slot[a]] + bs->next_symbol[a] * 1272*4, - ul->iq, 1272*4); - bs->buffers->ul_busy[a][bs->next_slot[a]] |= (1 << bs->next_symbol[a]); - signal_ul_buffer(bs->buffers, bs->next_slot[a]); - unlock_ul_buffer(bs->buffers, bs->next_slot[a]); - - bs->next_symbol[a]++; - if (bs->next_symbol[a] == 14) { - bs->next_symbol[a] = 0; - bs->next_slot[a] = (bs->next_slot[a] + 1) % 20; - if (bs->next_slot[a] == 0) { - bs->expected_benetel_frame[a]++; - bs->expected_benetel_frame[a] &= 255; - } - } -} - -void store_prach(benetel_t *bs, int frame, int slot, void *data) -{ - static int last_frame = -1; - static int last_slot = -1; - /* hack: antenna number is always 0, discard second packet with same f/sf */ - //if (frame == last_frame && slot == last_slot) return; - if (frame == last_frame && slot == last_slot) { printf("got f.sl %d.%d twice\n", frame, slot); return; } - last_frame = frame; - last_slot = slot; - - lock_ul_buffer(bs->buffers, slot); - if (bs->buffers->prach_busy[slot]) { - printf("store_prach: fatal: previous prach buffer not processed\n"); - unlock_ul_buffer(bs->buffers, slot); - return; - } - bs->buffers->prach_busy[slot] = 1; - memcpy(bs->buffers->prach[slot], data, 839*4); - signal_ul_buffer(bs->buffers, slot); - unlock_ul_buffer(bs->buffers, slot); - -} - -void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line); - -void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line) -{ - if (!strcmp(ifname, "dpdk")) - return benetel_start_dpdk(ifname, buffers, dpdk_main_command_line); - printf("benetel: fatal: interface %s not supported, only dpdpk is supported\n", ifname); - exit(1); -} diff --git a/radio/ETHERNET/benetel/5g/low.h b/radio/ETHERNET/benetel/5g/low.h deleted file mode 100644 index 659819296a..0000000000 --- a/radio/ETHERNET/benetel/5g/low.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 _BENETEL_5G_LOW_H_ -#define _BENETEL_5G_LOW_H_ - -#include "shared_buffers.h" - -typedef struct { - shared_buffers *buffers; - /* [2] is for two antennas */ - int next_slot[2]; - int next_symbol[2]; - int expected_benetel_frame[2]; - char *dpdk_main_command_line; -} benetel_t; - -typedef struct { - int frame; - int slot; - int symbol; - int antenna; - unsigned char iq[5088]; -} ul_packet_t; - -void *benetel_start(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line); - -void store_ul(benetel_t *bs, ul_packet_t *ul); -void store_prach(benetel_t *bs, int frame, int slot, void *data); - -#endif /* _BENETEL_5G_LOW_H_ */ diff --git a/radio/ETHERNET/benetel/5g/low_dpdk.c b/radio/ETHERNET/benetel/5g/low_dpdk.c deleted file mode 100644 index b26df07723..0000000000 --- a/radio/ETHERNET/benetel/5g/low_dpdk.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 - */ - -/* those 2 lines for CPU_SET */ -#define _GNU_SOURCE -#include - -#include -#include -#include -#include - -#include "low.h" - -int dpdk_main(int argc, char **argv, benetel_t *); - -void *dpdk_thread(void *_bs) -{ - benetel_t *bs = _bs; - int n = 0; - char **v = NULL; // = { "softmodem", "-n", "2", "--file-prefix", "pg2", "-l", "6", "--", "-p", "0x1" }; - char *s = bs->dpdk_main_command_line; - char *tok; - - while ((tok = strtok(s, " ")) != NULL) { - n++; - v = realloc(v, n * sizeof(char *)); - if (v == NULL) { - printf("%s: out of memory\n", __FUNCTION__); - exit(1); - } - v[n-1] = tok; - s = NULL; - } - - dpdk_main(n, v, bs); - exit(1); - return 0; -} - -void *benetel_start_dpdk(char *ifname, shared_buffers *buffers, char *dpdk_main_command_line) -{ - benetel_t *bs; - - bs = calloc(1, sizeof(benetel_t)); - if (bs == NULL) { - printf("%s: out of memory\n", __FUNCTION__); - exit(1); - } - - bs->buffers = buffers; - - bs->expected_benetel_frame[0] = 255; - bs->expected_benetel_frame[1] = 255; - - bs->dpdk_main_command_line = dpdk_main_command_line; - - pthread_attr_t attr; - - if (pthread_attr_init(&attr) != 0) { - printf("pthread_attr_init failed\n"); - exit(1); - } - - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(10,&cpuset); - if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset) != 0) { - printf("pthread_attr_setaffinity_np failed\n"); - exit(1); - } - - if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) { - printf("pthread_attr_setschedpolicy failed\n"); - exit(1); - } - - struct sched_param params; - params.sched_priority = sched_get_priority_max(SCHED_FIFO); - if (sched_get_priority_max(SCHED_FIFO) == -1) { - printf("sched_get_priority_max failed\n"); - exit(1); - } - if (pthread_attr_setschedparam(&attr, ¶ms) != 0) { - printf("pthread_setschedparam failed\n"); - exit(1); - } - - pthread_t t; - if (pthread_create(&t, &attr, dpdk_thread, bs) != 0) { - printf("%s: thread creation failed\n", __FUNCTION__); - exit(1); - } - - if (pthread_attr_destroy(&attr) != 0) { - printf("pthread_attr_init failed\n"); - exit(1); - } - - return bs; -} diff --git a/radio/ETHERNET/benetel/5g/shared_buffers.c b/radio/ETHERNET/benetel/5g/shared_buffers.c deleted file mode 100644 index a302400eb4..0000000000 --- a/radio/ETHERNET/benetel/5g/shared_buffers.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 "shared_buffers.h" - -#include -#include -#include - -void init_buffers(shared_buffers *s) -{ - int slot; - - memset(s, 0, sizeof(*s)); - - for (slot = 0; slot < 20; slot++) { - if (pthread_mutex_init(&s->m_dl[slot], NULL) != 0 || - pthread_cond_init(&s->c_dl[slot], NULL) != 0 || - pthread_mutex_init(&s->m_ul[slot], NULL) != 0 || - pthread_cond_init(&s->c_ul[slot], NULL) != 0) { - printf("%s: error initializing mutex/cond\n", __FUNCTION__); - exit(1); - } - } - - /* the gNB's first transmitted DL slot is 6 but the device - * needs to have slots 1, 2 and 3, 4 and 5 ready. Let's pretend - * they are ready. - */ - s->dl_busy[0][1] = 0x3fff; - s->dl_busy[0][2] = 0x3fff; - s->dl_busy[0][3] = 0x3fff; - s->dl_busy[0][4] = 0x3fff; - s->dl_busy[0][5] = 0x3fff; - s->dl_busy[1][1] = 0x3fff; - s->dl_busy[1][2] = 0x3fff; - s->dl_busy[1][3] = 0x3fff; - s->dl_busy[1][4] = 0x3fff; - s->dl_busy[1][5] = 0x3fff; -} - -void lock_dl_buffer(shared_buffers *s, int slot) -{ - if (pthread_mutex_lock(&s->m_dl[slot]) != 0) { - printf("%s: fatal: lock fails\n", __FUNCTION__); - exit(1); - } -} - -void unlock_dl_buffer(shared_buffers *s, int slot) -{ - if (pthread_mutex_unlock(&s->m_dl[slot]) != 0) { - printf("%s: fatal: unlock fails\n", __FUNCTION__); - exit(1); - } -} - -void wait_dl_buffer(shared_buffers *s, int slot) -{ - if (pthread_cond_wait(&s->c_dl[slot], &s->m_dl[slot]) != 0) { - printf("%s: fatal: cond_wait fails\n", __FUNCTION__); - exit(1); - } -} - -void signal_dl_buffer(shared_buffers *s, int slot) -{ - if (pthread_cond_broadcast(&s->c_dl[slot]) != 0) { - printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__); - exit(1); - } -} - -void lock_ul_buffer(shared_buffers *s, int slot) -{ - if (pthread_mutex_lock(&s->m_ul[slot]) != 0) { - printf("%s: fatal: lock fails\n", __FUNCTION__); - printf("%s: fatal: lock fails slot %d\n", __FUNCTION__, slot); - exit(1); - } -} - -void unlock_ul_buffer(shared_buffers *s, int slot) -{ - if (pthread_mutex_unlock(&s->m_ul[slot]) != 0) { - printf("%s: fatal: unlock fails\n", __FUNCTION__); - exit(1); - } -} - -void wait_ul_buffer(shared_buffers *s, int slot) -{ - if (pthread_cond_wait(&s->c_ul[slot], &s->m_ul[slot]) != 0) { - printf("%s: fatal: cond_wait fails\n", __FUNCTION__); - exit(1); - } -} - -void signal_ul_buffer(shared_buffers *s, int slot) -{ - if (pthread_cond_broadcast(&s->c_ul[slot]) != 0) { - printf("%s: fatal: cond_broadcast fails\n", __FUNCTION__); - exit(1); - } -} diff --git a/radio/ETHERNET/benetel/5g/shared_buffers.h b/radio/ETHERNET/benetel/5g/shared_buffers.h deleted file mode 100644 index 9d51b8138d..0000000000 --- a/radio/ETHERNET/benetel/5g/shared_buffers.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 _BENETEL_5G_SHARED_BUFFERS_H_ -#define _BENETEL_5G_SHARED_BUFFERS_H_ - -#include -#include - -typedef struct { - /* [2] is for two antennas */ - unsigned char dl[2][20][14*1272*4]; - unsigned char ul[2][20][14*1272*4]; - uint16_t dl_busy[2][20]; - uint16_t ul_busy[2][20]; - - pthread_mutex_t m_ul[20]; - pthread_cond_t c_ul[20]; - - pthread_mutex_t m_dl[20]; - pthread_cond_t c_dl[20]; - - unsigned char prach[20][849*4]; - unsigned char prach_busy[20]; - - /* statistics/error counting */ - int ul_overflow; - int dl_underflow; -} shared_buffers; - -void init_buffers(shared_buffers *s); - -void lock_dl_buffer(shared_buffers *s, int slot); -void unlock_dl_buffer(shared_buffers *s, int slot); -void wait_dl_buffer(shared_buffers *s, int slot); -void signal_dl_buffer(shared_buffers *s, int slot); - -void lock_ul_buffer(shared_buffers *s, int slot); -void unlock_ul_buffer(shared_buffers *s, int slot); -void wait_ul_buffer(shared_buffers *s, int slot); -void signal_ul_buffer(shared_buffers *s, int slot); - -#endif /* _BENETEL_5G_SHARED_BUFFERS_H_ */ diff --git a/radio/ETHERNET/benetel/CMakeLists.txt b/radio/ETHERNET/benetel/CMakeLists.txt deleted file mode 100644 index 1a95d1ec2c..0000000000 --- a/radio/ETHERNET/benetel/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_boolean_option(OAI_BENETEL4G OFF "Activate OAI's Benetel 4G radio driver" OFF) -if(OAI_BENETEL4G) - add_subdirectory(4g) -endif() - -add_boolean_option(OAI_BENETEL5G OFF "Activate OAI's Benetel 5G radio driver" OFF) -if(OAI_BENETEL5G) - add_subdirectory(5g) -endif() From ece138134bdf04b5d899609f2364a541687f452b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 Oct 2025 10:03:28 +0200 Subject: [PATCH 37/61] build_oai: remove non-existing oran_fhlib_4g option --- cmake_targets/build_oai | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 56c5e9b66c..6f61196e7e 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -278,10 +278,6 @@ function main() { TARGET_LIST="$TARGET_LIST oai_eth_transpro" CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase ;; - "oran_fhlib_4g") - TARGET_LIST="$TARGET_LIST $2" - CMAKE_CMD="$CMAKE_CMD -DOAI_${2^^}=ON" # ^^ makes uppercase - ;; "oran_fhlib_5g") TARGET_LIST="$TARGET_LIST $2" CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON" From e06d0c71990ddddb5e7e0c801f3dc2c7a8cf2533 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 21 Oct 2025 14:48:51 +0200 Subject: [PATCH 38/61] improve handling of selection of RSRP/SINR report via configuration file --- .../gnb.sa.band254.u0.25prb.rfsim.ntn.conf | 2 +- doc/MAC/mac-usage.md | 19 +++++++++++-------- openair2/GNB_APP/gnb_config.c | 15 +++++++++++---- openair2/GNB_APP/gnb_paramdef.h | 8 ++++---- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 8 +++++++- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 19 +++++++++---------- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf index a7663ae811..b3884a3d31 100644 --- a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf +++ b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf @@ -16,7 +16,7 @@ gNBs = ////////// Physical parameters: - do_SINR = 1; + CSI_report_type = "ssb_sinr"; min_rxtxtime = 6; disable_harq = 1; cu_sibs = [2]; diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index f4583b7a23..54a30cdd5f 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -257,7 +257,7 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration. * `do_CSIRS` (default 0): flag whether to use channel-state information reference signal (CSI-RS) * `do_SRS` (default 0): flag whether to use sounding reference signal (SRS) -* `do_SINR` (default 0): flag whether to enable CSI reporting of SSB-SINR (introduced in rel16) +* `CSI_report_type` (default `ssb_rsrp`): parameter to enable different CSI reporting (options: `ssb_rsrp`, `ssb_sinr` and `cri_rsrp`) Default setting of CSI reporting quantity is SSB-RSRP. * `min_rxtxtime` (default 2): minimum feedback time for UE to respond to transmissions (k1 and k2 in 3GPP spec) @@ -281,14 +281,17 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration. - `du_sibs` (default `[]`): list of SIBs to transmit in the cell. Currently, SIB19 (for NTN) is supported. -| DL MIMO |`do_CSIRS`|`do_SINR`| CSI report Quantity | -| ---------------------------- | -------- | ------- | --------------------------------------------------| -| OFF (pdsch_AntennaPorts = 1) | 0 | 0 | SSB-RSRP | -| OFF (pdsch_AntennaPorts = 1) | 0 | 1 | SSB-SINR | -| OFF (pdsch_AntennaPorts = 1) | 1 | 0 | CSI-Reference signal RSRP | -| OFF (pdsch_AntennaPorts = 1) | 1 | 1 | CSI-Reference signal SINR (not supported yet) | -| ON (pdsch_AntennaPorts > 1) | 1 | 0 | cri-RI-PMI-CQI | +| DL MIMO |`do_CSIRS`|`CSI_report_type`| CSI report Quantity | +| ------------------------------ | -------- | --------------- | --------------------------------------------------| +| any | any | `ssb_rsrp` | SSB-RSRP | +| any | 0 | `cri_rsrp` | SSB-RSRP (no CSI-RS configured) | +| any | 1 | `cri_rsrp` | CRI-RSRP | +| any | any | `ssb_sinr` | SSB-SINR | +| ON (`pdsch_AntennaPorts` > 1) | 1 | any | cri-RI-PMI-CQI | + +Note that activating `cri-RI-PMI-CQI` will result in that report to be produced +in addition to either `SSB-SINR`, `SSB-RSRP` or `CRI-RSRP`. DL-MIMO is configured using following parameters: `pdsch_AntennaPorts_XP` , `pdsch_AntennaPorts_N1` , `pdsch_AntennaPorts_N2`, `maxMIMO_layers` (see also [`RUNMODEM.md`](../RUNMODEM.md)) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 45532572cd..075bbd53fe 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -707,7 +707,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_gnb_param_notset(gnbp, GNB_DISABLE_HARQ_IDX, GNB_CONFIG_STRING_DISABLE_HARQ); verify_gnb_param_notset(gnbp, GNB_NUM_DL_HARQ_IDX, GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES); verify_gnb_param_notset(gnbp, GNB_NUM_UL_HARQ_IDX, GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES); - verify_gnb_param_notset(gnbp, GNB_DO_SINR_IDX, GNB_CONFIG_STRING_DOSINR); + verify_gnb_param_notset(gnbp, GNB_CONFIG_REP_IDX, GNB_CONFIG_STRING_CONFIG_REP); // check for some general sections verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST); @@ -1432,7 +1432,14 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr; config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr; config.max_num_rsrp = *GNBParamList.paramarray[0][GNB_LIMIT_RSRP_REPORT_IDX].iptr; - config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr; + if (strcmp(*(GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr), "ssb_rsrp") == 0) + config.report_type = SSB_RSRP; + else if (strcmp(*(GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr), "ssb_sinr") == 0) + config.report_type = SSB_SINR; + else if (strcmp(*(GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr), "cri_rsrp") == 0) + config.report_type = CRI_RSRP; + else + AssertFatal(false, "Invalid report type\n"); config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr; config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr; config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0; @@ -1443,10 +1450,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) if (config.disable_harq) LOG_W(GNB_APP, "\"disable_harq\" is a REL17 feature and is incompatible with REL15 and REL16 UEs!\n"); LOG_I(GNB_APP, - "CSI-RS %d, SRS %d, SINR:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", + "CSI-RS %d, SRS %d, reprt type:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", config.do_CSIRS, config.do_SRS, - config.do_SINR, + config.report_type, config.force_256qam_off ? "force off" : "may be on", config.use_deltaMCS ? "on" : "off", config.maxMIMO_layers, diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index e4e4bc3d2a..8efc4f999f 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -137,7 +137,7 @@ typedef enum { #define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels" #define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs" #define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs" -#define GNB_CONFIG_STRING_DOSINR "do_SINR" +#define GNB_CONFIG_STRING_CONFIG_REP "CSI_report_type" #define GNB_CONFIG_STRING_1ST_ACTIVE_BWP "first_active_bwp" #define GNB_CONFIG_STRING_LIMIT_RSRP_REPORT "max_num_RSRP_reported" @@ -153,7 +153,7 @@ typedef enum { #define GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST "List of aggregation levels with number of candidates per level. Element 0 - aggregation level 1" #define GNB_CONFIG_HLP_CU_SIBS "List of CU generated SIBs to be transmitted" #define GNB_CONFIG_HLP_DU_SIBS "List of DU generated SIBs to be transmitted" -#define GNB_CONFIG_HLP_DOSINR "Enable CSI feedback using SINR measurements on SSB" +#define GNB_CONFIG_HLP_CONFIG_REP "Define quantity for CSI report (options: ssb_rsrp, ssb_sinr and cri_rsrp)" /*-----------------------------------------------------------------------------------------------------------------------------------------*/ @@ -201,7 +201,7 @@ typedef enum { GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ -{GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_CONFIG_REP, GNB_CONFIG_HLP_CONFIG_REP, 0, .strptr=NULL, .defstrval="ssb_rsrp", TYPE_STRING, 0}, \ {GNB_CONFIG_STRING_1ST_ACTIVE_BWP, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_LIMIT_RSRP_REPORT, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ } @@ -246,7 +246,7 @@ typedef enum { #define GNB_UESS_AGG_LEVEL_LIST_IDX 35 #define GNB_CU_SIBS_IDX 36 #define GNB_DU_SIBS_IDX 37 -#define GNB_DO_SINR_IDX 38 +#define GNB_CONFIG_REP_IDX 38 #define GNB_1ST_ACTIVE_BWP_IDX 39 #define GNB_LIMIT_RSRP_REPORT_IDX 40 diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 026d8d563e..dfad999e76 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -179,6 +179,12 @@ typedef struct { int location_and_bw; } nr_bwp_config_t; +typedef enum { + SSB_RSRP, + CRI_RSRP, + SSB_SINR, +} nr_config_report_type_t; + typedef struct nr_mac_config_t { int sib1_tda; nr_pdsch_AntennaPorts_t pdsch_AntennaPorts; @@ -207,7 +213,7 @@ typedef struct nr_mac_config_t { int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; nr_redcap_config_t *redcap; nr_ptrs_config_t *ptrs; - bool do_SINR; + nr_config_report_type_t report_type; } nr_mac_config_t; typedef struct NR_preamble_ue { diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index a2b7c26678..02026d34d1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -2144,7 +2144,7 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { NR_CSI_ResourceConfig_t *csires = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_list]; if (csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) { - if (configuration->do_CSIRS && num_antenna_ports < 4) { + if (configuration->report_type == CRI_RSRP && configuration->do_CSIRS && num_antenna_ports < 4) { if (csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) resource_id = csires->csi_ResourceConfigId; } else { @@ -2166,20 +2166,19 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, csirep->reportConfigType.choice.periodic = calloc(1, sizeof(*csirep->reportConfigType.choice.periodic)); set_csi_meas_periodicity(servingcellconfigcommon, csirep, uid, curr_bwp, true); asn1cSeqAdd(&csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list, pucchcsires); - if (configuration->do_CSIRS && num_antenna_ports < 4) { + if (configuration->report_type == SSB_SINR) { + csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none; + csirep->reportQuantity.choice.none = (NULL_t)0; + csirep->ext2 = calloc(1, sizeof(*csirep->ext2)); + csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16)); + csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16; + csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0; + } else if (configuration->report_type == CRI_RSRP && configuration->do_CSIRS && num_antenna_ports < 4) { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; csirep->reportQuantity.choice.cri_RSRP = (NULL_t)0; } else { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP; csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0; - if (configuration->do_SINR) { - csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none; - csirep->reportQuantity.choice.none = (NULL_t)0; - csirep->ext2 = calloc(1, sizeof(*csirep->ext2)); - csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16)); - csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16; - csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0; - } } csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled)); From 78f36b64c2acc4f55c2ae7ae366b4bcf22a1a1be Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 22 Oct 2025 12:35:25 +0200 Subject: [PATCH 39/61] use of config module handling for CSI report type input --- openair2/GNB_APP/gnb_config.c | 13 ++++--------- openair2/GNB_APP/gnb_paramdef.h | 5 ++++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 075bbd53fe..056387de92 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1432,14 +1432,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr; config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr; config.max_num_rsrp = *GNBParamList.paramarray[0][GNB_LIMIT_RSRP_REPORT_IDX].iptr; - if (strcmp(*(GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr), "ssb_rsrp") == 0) - config.report_type = SSB_RSRP; - else if (strcmp(*(GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr), "ssb_sinr") == 0) - config.report_type = SSB_SINR; - else if (strcmp(*(GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr), "cri_rsrp") == 0) - config.report_type = CRI_RSRP; - else - AssertFatal(false, "Invalid report type\n"); + const char *report_type_s = *GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr; + config.report_type = config_get_processedint(cfg, &GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX]); config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr; config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr; config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0; @@ -1450,10 +1444,11 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) if (config.disable_harq) LOG_W(GNB_APP, "\"disable_harq\" is a REL17 feature and is incompatible with REL15 and REL16 UEs!\n"); LOG_I(GNB_APP, - "CSI-RS %d, SRS %d, reprt type:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", + "CSI-RS %d, SRS %d, report type %d (%s), 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", config.do_CSIRS, config.do_SRS, config.report_type, + report_type_s, config.force_256qam_off ? "force off" : "may be on", config.use_deltaMCS ? "on" : "off", config.maxMIMO_layers, diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 8efc4f999f..4ec09d06f0 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -293,7 +293,10 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ + { .s3a = { config_checkstr_assign_integer, \ + {"ssb_rsrp", "ssb_sinr", "cri_rsrp"}, \ + {SSB_RSRP, SSB_SINR, CRI_RSRP}, \ + 3 } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ } From 61b54178179f65f7fa2be95a974a89585db92ed3 Mon Sep 17 00:00:00 2001 From: Shubhika Garg Date: Fri, 17 Oct 2025 11:00:08 +0200 Subject: [PATCH 40/61] ci: Update and implement conditional DockerHub push - Push both AMD64 & ARMv8 Jetson images together for images built on both using `docker buildx imagetools` - Use standard 'docker pull and push' for images built only on AMD64. --- ci-scripts/Jenkinsfile-push-registry | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry index ccd91e28ff..60b8777ba9 100644 --- a/ci-scripts/Jenkinsfile-push-registry +++ b/ci-scripts/Jenkinsfile-push-registry @@ -84,9 +84,20 @@ pipeline { sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" sh "docker login -u oaicicd -p oaicicd ${OAI_Registry} > /dev/null 2>&1" listOfImages.eachWithIndex { item, iindex -> - sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop || true" - sh "docker buildx imagetools create --tag ${DH_Account}/${item}:${WEEK_TAG} ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" - sh "docker buildx imagetools create --tag ${DH_Account}/${item}:develop ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" + if (["oai-gnb", "oai-nr-ue", "oai-nr-cuup"].contains(item)) { + // For images built on AMD64 and ARMv8 Jetson + echo "Pushing image '${item}' for both AMD64 and ARM64 architectures with tags: ${WEEK_TAG} and develop" + sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop || true" + sh "docker buildx imagetools create --tag ${DH_Account}/${item}:${WEEK_TAG} ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" + sh "docker buildx imagetools create --tag ${DH_Account}/${item}:develop ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" + } else { + sh "docker pull --quiet ${OAI_Registry}/${item}:develop-${WEEK_SHA}" + sh "docker image tag ${OAI_Registry}/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:develop" + sh "docker image tag ${OAI_Registry}/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:${WEEK_TAG}" + sh "docker push --quiet ${DH_Account}/${item}:develop" + sh "docker push --quiet ${DH_Account}/${item}:${WEEK_TAG}" + } + sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop ${OAI_Registry}/${item}:develop-${WEEK_SHA} || true" } // Proxy is not following the same pattern. sh "docker image tag proxy:develop ${DH_Account}/proxy:develop" From 83fed82bcf2537ad4002336016350c081356e27a Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 23 Oct 2025 17:27:18 +0200 Subject: [PATCH 41/61] fix direct bugs of not used RU_RX_SLOT_DEPTH defined constant with this commit, the gNB can work if we change RU_RX_SLOT_DEPTH to another value than 4 but it remain not well designed --- executables/nr-gnb.c | 2 +- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 2 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 505adf825c..30f14bde24 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -190,7 +190,7 @@ static void rx_func(processingData_L1_t *info) //WA: comment rotation in tx/rx if (gNB->phase_comp) { //apply the rx signal rotation here - int soffset = (slot_rx & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; + int soffset = (slot_rx % RU_RX_SLOT_DEPTH) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size; for (int bb = 0; bb < gNB->common_vars.num_beams_period; bb++) { for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) { apply_nr_rotation_RX(&gNB->frame_parms, diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 2e6e4a54a6..94a417501c 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -136,7 +136,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy // TODO modify the measurements to take into account concurrent beams for (int s = first_symb; s < first_symb + num_symb; s++) { - int offset0 = ((slot&3)*frame_parms->symbols_per_slot + s) * frame_parms->ofdm_symbol_size; + int offset0 = ((slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot + s) * frame_parms->ofdm_symbol_size; for (int rb = 0; rb < frame_parms->N_RB_UL; rb++) { if ((rb_mask_ul[s][rb >> 5] & (1U << (rb & 31))) == 0 && // check that rb was not used in this subframe !(I0_SKIP_DC && rb == frame_parms->N_RB_UL >> 1)) { // skip middle PRB because of artificial noise possibly created by FFT diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 93d7feebe0..d73a315354 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -111,7 +111,7 @@ static void nr_pusch_antenna_processing(void *arg) c16_t **ul_ch_estimates = (c16_t **)pusch_vars->ul_ch_estimates; NR_DL_FRAME_PARMS *frame_parms = rdata->frame_parms; const int symbolSize = frame_parms->ofdm_symbol_size; - const int slot_offset = (Ns & 3) * frame_parms->symbols_per_slot * symbolSize; + const int slot_offset = (Ns % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * symbolSize; const int delta = get_delta(p, pusch_pdu->dmrs_config_type); const int symbol_offset = symbolSize * symbol; const int k0 = bwp_start_subcarrier; diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 28f3e2cc67..527063d29d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -1212,7 +1212,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, int end_sc = (start_sc + rel15_ul->rb_size * NR_NB_SC_PER_RB - 1) % frame_parms->ofdm_symbol_size; for (int s = rel15_ul->start_symbol_index; s < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); s++) { - int offset0 = ((slot & 3) * frame_parms->symbols_per_slot + s) * frame_parms->ofdm_symbol_size; + int offset0 = ((slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot + s) * frame_parms->ofdm_symbol_size; int offset = offset0 + (frame_parms->first_carrier_offset + start_sc) % frame_parms->ofdm_symbol_size; c16_t *ul_ch = &gNB->common_vars.rxdataF[beam_nb][aarx][offset]; if (end_sc < start_sc) { diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index ddf16a0541..2a3987e755 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -161,7 +161,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, nfapi_nr_pucch_pdu_t *pucch_pdu) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - int soffset = (slot & 3) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; + int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; AssertFatal(pucch_pdu->bit_len_harq > 0 || pucch_pdu->sr_flag > 0, "Either bit_len_harq (%d) or sr_flag (%d) must be > 0\n", From 2d7999cb28930912ebf6fa4e579682c96b9c9f89 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 8 Oct 2025 10:44:27 +0200 Subject: [PATCH 42/61] fix order of information when encoding/decoding RSRP meaas report with more than 1 resource --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 26 ++++++++----------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 14 +++++----- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 28e7b7d42b..363ce5d098 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2936,13 +2936,13 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, } else nb_meas = 2; - struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource; + struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL; for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ - SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList; + SSB_resource = &csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList; ///only one SSB resource set from spec 38.331 IE CSI-ResourceConfig - nb_ssb = SSB_resource.list.count; + nb_ssb = SSB_resource->list.count; break; } } @@ -2957,7 +2957,7 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) { // searching for the SSB index in the SSB resource table for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) { - if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) { + if (*SSB_resource->list.array[ssb_resource] == measured_ssb_idx) { sorted_rsrp_measurements[sorted_idx].ssb_index = ssb_resource; sorted_rsrp_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm; sorted_rsrp_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB; @@ -2968,12 +2968,12 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, } qsort(sorted_rsrp_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_rsrp); - uint32_t ssbi; - - if (ssbri_bits > 0) { - ssbi = sorted_rsrp_measurements[0].ssb_index; - temp_payload = reverse_bits(ssbi, ssbri_bits); - bits += ssbri_bits; + for (int i = 0; i < nb_meas; i++) { + if (ssbri_bits > 0) { + uint32_t ssbi = sorted_rsrp_measurements[i].ssb_index; + temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits); + bits += ssbri_bits; + } } uint8_t rsrp_idx = get_rsrp_index(sorted_rsrp_measurements[0].ssb_rsrp_dBm); @@ -2982,15 +2982,11 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, // from the second SSB, differential report for (int i = 1; i < nb_meas; i++) { - ssbi = sorted_rsrp_measurements[i].ssb_index; - temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits); - bits += ssbri_bits; - rsrp_idx = get_rsrp_diff_index(sorted_rsrp_measurements[0].ssb_rsrp_dBm,sorted_rsrp_measurements[i].ssb_rsrp_dBm); temp_payload |= (reverse_bits(rsrp_idx, 4) << bits); bits += 4; // 4 bits for subsequent RSRP } - break; // resorce found + break; // resource found } } int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index f3de970683..e689a8a978 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -589,11 +589,13 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, rsrp_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri; int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; - uint8_t curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); - rsrp_report->resource_id[0] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); - *cumul_bits += bitlen; + for (int i = 0; i < rsrp_report->nr_reports; i++) { + uint8_t idx_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((idx_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + *cumul_bits += bitlen; + } - curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); + uint8_t curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); int rsrp = curr_payload & 0x7f; *cumul_bits += 7; csi_report->nb_of_csi_ssb_report++; @@ -605,10 +607,6 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, } for (int i = 1; i < rsrp_report->nr_reports; i++) { - curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); - rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); - *cumul_bits += bitlen; - curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); csi_report->nb_of_csi_ssb_report++; rsrp_report->RSRP[i] = get_diff_rsrp(curr_payload & 0x0f, rsrp_report->RSRP[0]); From 747689596aa4e9c137c7a3bac02f9ae981bd2aad Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 21 Oct 2025 16:16:36 +0200 Subject: [PATCH 43/61] fix SINR report order at UE --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 25 ++++++++------------ 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 363ce5d098..aeb15fe864 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2795,13 +2795,13 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, } else nb_meas = 2; - struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource; + struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL; for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) { - SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList; + SSB_resource = &csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList; /// only one SSB resource set from spec 38.331 IE CSI-ResourceConfig - nb_ssb = SSB_resource.list.count; + nb_ssb = SSB_resource->list.count; break; } } @@ -2816,7 +2816,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) { // searching for the SSB index in the SSB resource table for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) { - if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) { + if (*SSB_resource->list.array[ssb_resource] == measured_ssb_idx) { sorted_sinr_measurements[sorted_idx].ssb_index = ssb_resource; sorted_sinr_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm; sorted_sinr_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB; @@ -2827,25 +2827,20 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, } qsort(sorted_sinr_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_sinr); - uint8_t ssbi; - // TS38.212 v16.5.0: Table 6.3.1.1.2-8A - if (ssbri_bits > 0) { - ssbi = sorted_sinr_measurements[0].ssb_index; - temp_payload = reverse_bits(ssbi, ssbri_bits); - bits += ssbri_bits; + for (int i = 0; i < nb_meas; i++) { + if (ssbri_bits > 0) { + uint8_t ssbi = sorted_sinr_measurements[i].ssb_index; + temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits); + bits += ssbri_bits; + } } uint8_t sinr_idx = get_sinr_index(sorted_sinr_measurements[0].ssb_sinr_dB); temp_payload |= (reverse_bits(sinr_idx, 7) << bits); bits += 7; // 7 bits for highest SINR - // from the second SSB, differential report for (int i = 1; i < nb_meas; i++) { - ssbi = sorted_sinr_measurements[i].ssb_index; - temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits); - bits += ssbri_bits; - sinr_idx = get_sinr_diff_index(sorted_sinr_measurements[0].ssb_sinr_dB, sorted_sinr_measurements[i].ssb_sinr_dB); temp_payload |= (reverse_bits(sinr_idx, 4) << bits); bits += 4; // 4 bits for differential SINR From 350263460b6a9bd47acc6a75beb83b6b112a595d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 10:09:56 +0200 Subject: [PATCH 44/61] Refactor processing of sdap_Config in add_drb (PDCP) * use get_sdap_Config to process sdap_Config * move SDAP config logic to the scope where it is relevant * add SDAP entity direcly in RRC, not from PDCP * replaced nr_pdcp_add_drbs with single add_drb call: it was no longer efficient to keep it in the new logic. The addMod list can be looped directly in RRC. * add specific function to add bearers from addMod list in E1, NSA, and UE --- doc/SW_archi.md | 2 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 25 +++- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 125 ++++++-------------- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 11 +- openair2/RRC/NR/rrc_gNB_nsa.c | 27 ++++- openair2/RRC/NR_UE/rrc_UE.c | 30 ++++- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 2 +- 7 files changed, 111 insertions(+), 111 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 9c3736ac2a..5b902a6675 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -325,7 +325,7 @@ The PDCP implementation is secured by a general mutex, akin to the design of the Initialization of the PDCP layer follows a structure similar to that of the RLC layer. The function `nr_pdcp_layer_init()` initializes PDCP, while a second initialization function, `pdcp_module_init()`, must also be invoked. -To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in PDCP, while `nr_pdcp_remove_UE()` is used for their removal. Similarly, `nr_pdcp_add_drbs()` adds UE DRBs in PDCP, with `nr_pdcp_remove_UE()` handling their removal. +To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in PDCP, while `nr_pdcp_remove_UE()` is used for their removal. Similarly, `add_drb()` adds UE DRB in PDCP, with `nr_pdcp_remove_UE()` handling their removal. ## PDCP Tx flow diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index b19ccceb22..f29c26842b 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -141,6 +141,24 @@ static instance_t get_f1_gtp_instance(void) return inst->gtpInst; } +/** @brief Add bearer in PDCP/SDAP for 5GC association (SA) */ +static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, const nr_pdcp_entity_security_keys_and_algos_t *sp) +{ + for (int i = 0; i < addMod->list.count; i++) { + NR_DRB_ToAddMod_t *drb = addMod->list.array[i]; + DevAssert(drb->cnAssociation); + DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING); + DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config); + DevAssert(drb->cnAssociation->choice.sdap_Config); + // get SDAP config + sdap_config_t sdap = nr_sdap_get_config(GNB_FLAG_YES, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity); + // add SDAP entity + new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + // add PDCP entity + add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); + } +} + void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { bool need_ue_id_mgmt = e1_used(); @@ -208,11 +226,10 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm; memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE); memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE); - nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE - cu_up_ue_id, - &DRB_configList, - &security_parameters); + + e1_add_bearers(cu_up_ue_id, &DRB_configList, &security_parameters); ASN_STRUCT_RESET(asn_DEF_NR_DRB_ToAddModList, &DRB_configList.list); + if (f1inst >= 0) { /* we have F1(-U) */ teid_t dummy_teid = 0xffff; // we will update later with answer from DU in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index ce885b6b33..6bd2d9354f 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -576,74 +576,31 @@ void add_srb(int is_gnb, } void add_drb(int is_gnb, - ue_id_t UEid, - struct NR_DRB_ToAddMod *s, + const ue_id_t UEid, + const NR_PDCP_Config_t *pdcp, + sdap_config_t *sdap, const nr_pdcp_entity_security_keys_and_algos_t *security_parameters) { - nr_pdcp_entity_t *pdcp_drb; nr_pdcp_ue_t *ue; - int drb_id = s->drb_Identity; - if (!s->pdcp_Config || !s->pdcp_Config->drb) { - LOG_E(PDCP, "DRB field mandatory present at setup. DRB %d not configured.\n", drb_id); + if (!pdcp->drb) { + LOG_E(PDCP, "Missing PDCP config. DRB %d not configured.\n", sdap->drb_id); return; } - struct NR_PDCP_Config__drb *drb = s->pdcp_Config->drb; + struct NR_PDCP_Config__drb *drb = pdcp->drb; int sn_size_ul = decode_sn_size_ul(*drb->pdcp_SN_SizeUL); int sn_size_dl = decode_sn_size_dl(*drb->pdcp_SN_SizeDL); int discard_timer = decode_discard_timer(*drb->discardTimer); - int has_integrity; - int has_ciphering; - /* if pdcp_Config->t_Reordering is not present, it means infinity (-1) */ int t_reordering = -1; - if (s->pdcp_Config->t_Reordering != NULL) { - t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering); + if (pdcp->t_Reordering != NULL) { + t_reordering = decode_t_reordering(*pdcp->t_Reordering); } - if (drb->integrityProtection != NULL) - has_integrity = 1; - else - has_integrity = 0; - - if (s->pdcp_Config->ext1 != NULL && s->pdcp_Config->ext1->cipheringDisabled != NULL) - has_ciphering = 0; - else - has_ciphering = 1; - - if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) { - LOG_E(PDCP, "fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n"); - exit(-1); - } - - int pdusession_id; - bool has_sdap_rx = false; - bool has_sdap_tx = false; - bool is_sdap_DefaultDRB = false; - NR_QFI_t *mappedQFIs2Add = NULL; - uint8_t mappedQFIs2AddCount=0; - if (s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity) - pdusession_id = s->cnAssociation->choice.eps_BearerIdentity; - else { - if (!s->cnAssociation->choice.sdap_Config) { - LOG_E(PDCP,"fatal, sdap_Config is null"); - exit(-1); - } - pdusession_id = s->cnAssociation->choice.sdap_Config->pdu_Session; - has_sdap_rx = is_sdap_rx(is_gnb, s->cnAssociation->choice.sdap_Config); - has_sdap_tx = is_sdap_tx(is_gnb, s->cnAssociation->choice.sdap_Config); - is_sdap_DefaultDRB = s->cnAssociation->choice.sdap_Config->defaultDRB == true ? 1 : 0; - mappedQFIs2Add = (NR_QFI_t*)s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.array[0]; - mappedQFIs2AddCount = s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.count; - LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd from RRC: %ld \n", *mappedQFIs2Add); - } - /* TODO(?): accept different UL and DL SN sizes? */ - if (sn_size_ul != sn_size_dl) { - LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl); - exit(1); - } + int has_integrity = (drb->integrityProtection != NULL) ? 1 : 0; + int has_ciphering = (pdcp->ext1 != NULL && pdcp->ext1->cipheringDisabled != NULL) ? 0 : 1; /* get actual ciphering and integrity algorithm based on pdcp_Config */ nr_pdcp_entity_security_keys_and_algos_t actual_security_parameters = *security_parameters; @@ -652,29 +609,33 @@ void add_drb(int is_gnb, nr_pdcp_manager_lock(nr_pdcp_ue_manager); ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, UEid); - if (nr_pdcp_get_rb(ue, drb_id, false) != NULL) { - LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", drb_id, UEid); + if (nr_pdcp_get_rb(ue, sdap->drb_id, false) != NULL) { + LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", sdap->drb_id, UEid); } else { - pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id, pdusession_id, - has_sdap_rx, has_sdap_tx, deliver_sdu_drb, ue, - is_gnb ? - deliver_pdu_drb_gnb : deliver_pdu_drb_ue, - ue, - sn_size_dl, t_reordering, discard_timer, - &actual_security_parameters); - nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb); + // code assumption: same SN size for both DL and UL + if (sn_size_ul != sn_size_dl) { + LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl); + exit(1); + } - LOG_I(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid); - /* add new SDAP entity for the PDU session the DRB belongs to */ - new_nr_sdap_entity(is_gnb, - has_sdap_rx, - has_sdap_tx, - UEid, - pdusession_id, - is_sdap_DefaultDRB, - drb_id, - mappedQFIs2Add, - mappedQFIs2AddCount); + // add PDCP entity + nr_pdcp_entity_t *pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, + is_gnb, + sdap->drb_id, + sdap->pdusession_id, + sdap->sdap_rx, + sdap->sdap_tx, + deliver_sdu_drb, + ue, + is_gnb ? deliver_pdu_drb_gnb : deliver_pdu_drb_ue, + ue, + sn_size_dl, + t_reordering, + discard_timer, + &actual_security_parameters); + nr_pdcp_ue_add_drb_pdcp_entity(ue, sdap->drb_id, pdcp_drb); + + LOG_I(PDCP, "Added DRB %d to UE ID %ld\n", sdap->drb_id, UEid); } nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } @@ -692,22 +653,6 @@ void nr_pdcp_add_srbs(eNB_flag_t enb_flag, LOG_W(PDCP, "nr_pdcp_add_srbs() with void list\n"); } -void nr_pdcp_add_drbs(eNB_flag_t enb_flag, - ue_id_t UEid, - NR_DRB_ToAddModList_t *const drb2add_list, - const nr_pdcp_entity_security_keys_and_algos_t *security_parameters) -{ - if (drb2add_list != NULL) { - for (int i = 0; i < drb2add_list->list.count; i++) { - add_drb(enb_flag, - UEid, - drb2add_list->list.array[i], - security_parameters); - } - } else - LOG_W(PDCP, "nr_pdcp_add_drbs() with void list\n"); -} - uint64_t get_pdcp_optmask(void) { return pdcp_optmask; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 375bd27458..75f41e2190 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -33,6 +33,7 @@ #include "nr_pdcp_ue_manager.h" struct NR_DRB_ToAddMod; struct NR_SRB_ToAddMod; +struct sdap_configuration_s; void nr_pdcp_layer_init(void); @@ -42,19 +43,15 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, const sdu_size_t sdu_buffer_size, uint8_t *const sdu_buffer); -void nr_pdcp_add_drbs(eNB_flag_t enb_flag, - ue_id_t UEid, - NR_DRB_ToAddModList_t *const drb2add_list, - const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); - void nr_pdcp_add_srbs(eNB_flag_t enb_flag, ue_id_t UEid, NR_SRB_ToAddModList_t *const srb2add_list, const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); void add_drb(int is_gnb, - ue_id_t UEid, - struct NR_DRB_ToAddMod *s, + const ue_id_t UEid, + const NR_PDCP_Config_t *pdcp, + struct sdap_configuration_s *sdap, const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); void nr_pdcp_remove_UE(ue_id_t ue_id); diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index f0f7201517..b6bf34729c 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -161,6 +161,28 @@ static NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, return rbconfig; } +static void rrc_nsa_add_drb(const int ue_id, + const NR_DRB_ToAddModList_t *addMod, + const nr_pdcp_entity_security_keys_and_algos_t *sp) +{ + for (int i = 0; i < addMod->list.count; i++) { + NR_DRB_ToAddMod_t *drb = addMod->list.array[i]; + DevAssert(drb->cnAssociation); + DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING); + DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity); + // get SDAP config + sdap_config_t sdap = {0}; + // EPC association + sdap.pdusession_id = drb->cnAssociation->choice.eps_BearerIdentity; + sdap.drb_id = drb->drb_Identity; + sdap.defaultDRB = true; + // add SDAP entity (terminated at gNB, since it's EPC) + new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + // add PDCP entity + add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); + } +} + /* generate prototypes for the tree management functions (RB_INSERT used in rrc_add_nsa_user) */ RB_PROTOTYPE(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s, entries, rrc_gNB_compare_ue_rnti_id); @@ -304,10 +326,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_ } DevAssert(UE->rb_config != NULL); - nr_pdcp_add_drbs(GNB_FLAG_YES, - UE->rrc_ue_id, - UE->rb_config->drb_ToAddModList, - &security_parameters); + rrc_nsa_add_drb(UE->rrc_ue_id, UE->rb_config->drb_ToAddModList, &security_parameters); /* assumption: only a single bearer, see above */ NR_DRB_ToAddModList_t *rb_list = UE->rb_config->drb_ToAddModList; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index d23dd14c58..81bd3b65bb 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -599,6 +599,31 @@ static void nr_rrc_process_dedicatedNAS_MessageList(NR_UE_RRC_INST_t *rrc, NR_RR } } +/** @brief Add bearer in PDCP/SDAP for 5GC association (SA) */ +static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, const nr_pdcp_entity_security_keys_and_algos_t *sp) +{ + DevAssert(drb->cnAssociation); + DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING); + // get SDAP config + sdap_config_t sdap = {0}; + if (drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity) { + DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity); + + // EPC association + sdap.pdusession_id = drb->cnAssociation->choice.eps_BearerIdentity; + sdap.drb_id = drb->drb_Identity; + sdap.defaultDRB = true; + } else { + DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config); + DevAssert(drb->cnAssociation->choice.sdap_Config); + sdap = nr_sdap_get_config(GNB_FLAG_NO, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity); + } + // add SDAP entity + new_nr_sdap_entity(GNB_FLAG_NO, ue_id, sdap); + // add PDCP entity + add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp); +} + /** * @brief add, modify and release SRBs and/or DRBs * @ref 3GPP TS 38.331 @@ -706,10 +731,7 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, NR_Rad nr_reconfigure_sdap_entity(sdap_Config, ue_rrc->ue_id, sdap_Config->pdu_Session, DRB_id); } else { set_DRB_status(ue_rrc ,DRB_id, RB_ESTABLISHED); - add_drb(false, - ue_rrc->ue_id, - radioBearerConfig->drb_ToAddModList->list.array[cnt], - &security_up_parameters); + rrc_ue_add_bearer(ue_rrc->ue_id, radioBearerConfig->drb_ToAddModList->list.array[cnt], &security_up_parameters); } } } // drb_ToAddModList // diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 3e3d95c3db..6ba76422fd 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -77,7 +77,7 @@ typedef struct qfi2drb_s { void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); -typedef struct { +typedef struct sdap_configuration_s { int pdusession_id; int drb_id; bool sdap_rx; From 68a3a849bca890b94a5d010f8bbfa7d398e3fefe Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 23:47:48 +0200 Subject: [PATCH 45/61] refactor: Use centralized get_sdap_Config in nr_reconfigure_sdap_entity Replace inline parameter extraction with get_sdap_Config() function call to: - Eliminate code duplication in SDAP configuration handling - Streamline QFI release processing with structured config object - Ensure consistent SDAP configuration extraction across all SDAP operations --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 4c02318e57..b5bb31933e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -704,26 +704,19 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in ue_id, pdusession_id); /* QFI to DRB mapping */ - NR_QFI_t *mappedQFIs2Add = (NR_QFI_t *)sdap_config->mappedQoS_FlowsToAdd->list.array[0]; - uint8_t mappedQFIs2AddCount = sdap_config->mappedQoS_FlowsToAdd->list.count; - bool has_sdap_rx = is_sdap_rx(is_gnb, sdap_config); - bool has_sdap_tx = is_sdap_tx(is_gnb, sdap_config); + sdap_config_t sdap = get_sdap_Config(is_gnb, sdap_config, drb_id); nr_sdap_ue_qfi2drb_config(sdap_entity, sdap_entity->default_drb, ue_id, - mappedQFIs2Add, - mappedQFIs2AddCount, + sdap.mappedQFIs2Add, + sdap.mappedQFIs2AddCount, drb_id, - has_sdap_rx, - has_sdap_tx); + sdap.sdap_rx, + sdap.sdap_tx); /* handle QFIs to DRB mapping rule to release */ - if (sdap_config->mappedQoS_FlowsToRelease) { - NR_QFI_t *mappedQFIs2release = (NR_QFI_t *)sdap_config->mappedQoS_FlowsToRelease->list.array[0]; - uint8_t mappedQFIs2RemoveCount = sdap_config->mappedQoS_FlowsToRelease->list.count; - for(int i = 0; i < mappedQFIs2RemoveCount; i++){ - uint8_t qfi = mappedQFIs2release[i]; - sdap_entity->qfi2drb_map_delete(sdap_entity, qfi); - } + for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { + uint8_t qfi = sdap.mappedQFIs2Release[i]; + sdap_entity->qfi2drb_map_delete(sdap_entity, qfi); } } From 7b42a65ac7c5f29711f3bc29a2856cc53dcc0a20 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 10:25:49 +0200 Subject: [PATCH 46/61] Refactor new_nr_sdap_entity to use sdap_config_t and always update mapping rules * change function signature: pass the sdap_config_t * update qfi2drb mapping when receiving a configuration for an already existing SDAP entity * always update mapping rules, not only for default DRB --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 72 +++++++++++++------------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 10 +--- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index b5bb31933e..9dcc309539 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -464,67 +464,65 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, * @param mapped_qfi_2_add, list of QoS flows to add/update * @param mappedQFIs2AddCount, number of QoS flows to add/update */ -nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, - bool has_sdap_rx, - bool has_sdap_tx, - ue_id_t ue_id, - int pdusession_id, - bool is_defaultDRB, - uint8_t drb_identity, - NR_QFI_t *mapped_qfi_2_add, - uint8_t mappedQFIs2AddCount) +nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap) { /* check whether the SDAP entity already exists and update QFI to DRB mapping rules in that case */ - if (nr_sdap_get_entity(ue_id, pdusession_id)) { - LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, pdusession_id); - nr_sdap_entity_t *existing_sdap_entity = nr_sdap_get_entity(ue_id, pdusession_id); - rb_id_t pdcp_entity = existing_sdap_entity->default_drb; - if(!is_gnb) - nr_sdap_ue_qfi2drb_config(existing_sdap_entity, - pdcp_entity, + nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap.pdusession_id); + if (sdap_entity) { + LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, sdap.pdusession_id); + if (!is_gnb) { + nr_sdap_ue_qfi2drb_config(sdap_entity, + sdap_entity->default_drb, ue_id, - mapped_qfi_2_add, - mappedQFIs2AddCount, - drb_identity, - has_sdap_rx, - has_sdap_tx); - return existing_sdap_entity; + sdap.mappedQFIs2Add, + sdap.mappedQFIs2AddCount, + sdap.drb_id, + sdap.sdap_rx, + sdap.sdap_tx); + } else { + // store QFI to DRB mapping rules + for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { + sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); + } + } + return sdap_entity; } - nr_sdap_entity_t *sdap_entity; - sdap_entity = calloc(1, sizeof(nr_sdap_entity_t)); - - if(sdap_entity == NULL) { - LOG_E(SDAP, "SDAP Entity creation failed, out of memory\n"); - exit(1); - } + sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity)); + // SDAP entity ids sdap_entity->ue_id = ue_id; - sdap_entity->pdusession_id = pdusession_id; + sdap_entity->pdusession_id = sdap.pdusession_id; sdap_entity->is_gnb = is_gnb; + // rx/tx entities sdap_entity->tx_entity = nr_sdap_tx_entity; sdap_entity->rx_entity = nr_sdap_rx_entity; + // control pdu function pointers sdap_entity->sdap_construct_ctrl_pdu = nr_sdap_construct_ctrl_pdu; sdap_entity->sdap_map_ctrl_pdu = nr_sdap_map_ctrl_pdu; sdap_entity->sdap_submit_ctrl_pdu = nr_sdap_submit_ctrl_pdu; + // QFI to DRB mapping functions pointers sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update; sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del; sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map; - sdap_entity->pdusession_sock = -1; - if(is_defaultDRB) { - sdap_entity->default_drb = drb_identity; - LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb); - LOG_D(SDAP, "RRC updating mapping rules: %d\n", mappedQFIs2AddCount); - for (int i = 0; i < mappedQFIs2AddCount; i++) - sdap_entity->qfi2drb_map_update(sdap_entity, mapped_qfi_2_add[i], sdap_entity->default_drb, has_sdap_rx, has_sdap_tx); + // set default DRB + if (sdap.defaultDRB) { + sdap_entity->default_drb = sdap.drb_id; + LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %ld \n", sdap_entity->default_drb); } + for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { + // store QFI to DRB mapping rules + sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); + } + + // update SDAP entity list pointers sdap_entity->next_entity = sdap_info.sdap_entity_llist; sdap_info.sdap_entity_llist = sdap_entity; diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 6ba76422fd..7670d4b03b 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -179,15 +179,7 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_u * TS 37.324 4.4 5.1.1 SDAP entity establishment * Establish an SDAP entity. */ -nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, - bool has_sdap_rx, - bool has_sdap_tx, - ue_id_t ue_id, - int pdusession_id, - bool is_defaultDRB, - uint8_t default_DRB, - NR_QFI_t *mapped_qfi_2_add, - uint8_t mappedQFIs2AddCount); +nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap); /* Entity Handling Related Functions */ nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id); From 7376c9545c08dbfeb776a3675f780a348d0ff2a3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 23:32:44 +0200 Subject: [PATCH 47/61] Refactor nr_sdap_qfi2drb_map The goal of this function is to return the DRB ID mapped to the input QFI, for both DL and UL. The function looks up the DRB that is mapped to the QFI, if no mapping rule exists returns the default DRB. Returns 0 If no mapping and no default DRB exists for that QFI The function should not update the stored mapping rules, that is done when receiving a new SDAP configuration. In this function it was removed. See TS 37.324, 5.2.1 Uplink > If there is no stored QoS flow to DRB mapping rule for the QoS flow as specified in the subclause 5.3, > map the SDAP SDU to the default DRB else, map the SDAP SDU to the DRB according to the stored QoS flow to DRB mapping rule. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 42 +++++++++++++++----------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 13 +------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 9dcc309539..be00f9dab8 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -357,27 +357,33 @@ void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){ } /** - * @brief maps the QFIs to the default DRB if not mapping rule exists - * @return DRB that is mapped to the QFI, 0 if no mapping and no default DRB exists for that QFI -*/ -rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi){ - rb_id_t pdcp_entity; - - pdcp_entity = entity->qfi2drb_table[qfi].drb_id; - - if(pdcp_entity){ - LOG_D(SDAP, "Mapping rule exists for QFI: %u\n", qfi); - return pdcp_entity; - } else if(entity->default_drb) { - LOG_D(SDAP, "Mapping QFI: %u to Default DRB: %ld\n", qfi, entity->default_drb); - entity->qfi2drb_map_update(entity, qfi, entity->default_drb, entity->qfi2drb_table[qfi].has_sdap_rx, entity->qfi2drb_table[qfi].has_sdap_tx); + * @brief get the DRB ID mapped to the QFI, for both DL and UL + * @return DRB that is mapped to the QFI + * or the default DRB if no mapping rule exists + * or 0 if no mapping and no default DRB exists for that QFI + * @ref TS 37.324, 5.2.1 Uplink + * If there is no stored QoS flow to DRB mapping rule for the + * QoS flow as specified in the subclause 5.3, and a default DRB is configured, + * map the SDAP SDU to the default DRB else, map the SDAP SDU to the DRB according + * to the stored QoS flow to DRB mapping rule. */ +static int nr_sdap_qfi2drb(nr_sdap_entity_t *entity, uint8_t qfi) +{ + /* Fetch DRB ID mapped to QFI */ + int drb_id = entity->qfi2drb_table[qfi].drb_id; + if (drb_id) { + /* QoS flow to DRB mapping rule exists, return corresponding DRB ID */ + LOG_D(SDAP, "Existing QoS flow to DRB mapping rule: QFI %u to DRB %d\n", qfi, drb_id); + return drb_id; + } else if (entity->default_drb) { + /* QoS flow to DRB mapping rule does not exist, map SDAP SDU to default DRB, e.g. return default DRB of the SDAP entity */ + LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %ld\n", entity->default_drb); return entity->default_drb; } else { - LOG_D(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi); + /* Note: UE undefined behaviour when neither a default DRB + nor a stored QoS flow to DRB mapping rule exists */ + LOG_E(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi); return SDAP_MAP_RULE_EMPTY; } - - return pdcp_entity; } nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){ @@ -508,7 +514,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // QFI to DRB mapping functions pointers sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update; sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del; - sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map; + sdap_entity->qfi2drb_map = nr_sdap_qfi2drb; sdap_entity->pdusession_sock = -1; // set default DRB diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 7670d4b03b..e8315ca846 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -105,7 +105,7 @@ typedef struct nr_sdap_entity_s { void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx); void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi); - rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); + int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi); @@ -144,17 +144,6 @@ void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t d /* QFI to DRB Mapping Related Function */ void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi); -/* - * TS 37.324 - * 4.4 Functions - * Mapping between a QoS flow and a DRB for both DL and UL. - * - * 5.2.1 Uplink - * If there is no stored QoS flow to DRB mapping rule for the QoS flow as specified in the subclause 5.3, map the SDAP SDU to the default DRB - * else, map the SDAP SDU to the DRB according to the stored QoS flow to DRB mapping rule. - */ -rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi); - /* * TS 37.324 5.3 QoS flow to DRB Mapping * construct an end-marker control PDU, as specified in the subclause 6.2.3, for the QoS flow; From bae1de16d6a4019c7f8e79db52c01c7397eca9a1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 23 Apr 2025 23:38:19 +0200 Subject: [PATCH 48/61] Refactor SDAP UL: QoS flow to DRB Mapping configuration and end-marker control PDU mapping The function nr_sdap_ue_qfi2drb_config should do UL QoS flow to DRB mapping configuration for a SDAP entity has already been established according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1 Configuration Procedures. It should handle both mapping rules to add and to remove. To this purpose: * Simplify function signature by passing the sdap config. * Improve readability of the function. * Move handling of sdap.mappedQFIs2ReleaseCount (in nr_reconfigure_sdap_entity) inside the function. * Simplify end-marker control PDU mapping function by removing unused DRB ID input parameter (the function is fetching the DRB ID based on the input map type) * use int instead of legacy rb_id_t * limit scope of functions whenever necessary --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 97 +++++++++++--------------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 4 +- 2 files changed, 42 insertions(+), 59 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index be00f9dab8..71805bc750 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -281,7 +281,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, */ if(!entity->qfi2drb_table[sdap_hdr->QFI].drb_id && entity->default_drb){ nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI); - rb_id_t sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI); + int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI); entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } @@ -296,7 +296,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, */ if (pdcp_entity != entity->qfi2drb_table[sdap_hdr->QFI].drb_id) { nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI); - rb_id_t sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI); + int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI); entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } @@ -397,15 +397,16 @@ nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){ return sdap_end_marker_hdr; } -rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi){ - rb_id_t drb_of_endmarker = 0; +int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi) +{ + int drb_of_endmarker = 0; if(map_type == SDAP_CTRL_PDU_MAP_DEF_DRB){ drb_of_endmarker = entity->default_drb; - LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %ld\n", dl_qfi, drb_of_endmarker); + LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %d\n", dl_qfi, drb_of_endmarker); } if(map_type == SDAP_CTRL_PDU_MAP_RULE_DRB){ drb_of_endmarker = entity->qfi2drb_map(entity, dl_qfi); - LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %ld\n", dl_qfi, drb_of_endmarker); + LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %d\n", dl_qfi, drb_of_endmarker); } return drb_of_endmarker; } @@ -421,39 +422,40 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_u } } -/** - * @brief UL QoS flow to DRB mapping configuration for an existing SDAP entity - * according to TS 37.324, 5.3 QoS flow to DRB Mapping, clause 5.3.1 Configuration Procedures - */ -static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity, - rb_id_t pdcp_entity, - ue_id_t ue_id, - NR_QFI_t *mapped_qfi_2_add, - uint8_t mappedQFIs2AddCount, - uint8_t drb_identity, - bool has_sdap_rx, - bool has_sdap_tx) +/** @brief UL QoS flow to DRB mapping configuration for a SDAP entity has already been established + * according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1 Configuration Procedures. + * The function handles both UL QoS Flows mapping rules to add and to remove. */ +static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue_id, const sdap_config_t sdap) { - LOG_D(SDAP, "RRC Configuring SDAP Entity\n"); - for(int i = 0; i < mappedQFIs2AddCount; i++){ - uint8_t qfi = mapped_qfi_2_add[i]; - /* a default DRB exists and there is no QFI to DRB mapping rule for the QFI */ - if (existing_sdap_entity->default_drb && existing_sdap_entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) { - nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi); - rb_id_t sdap_ctrl_pdu_drb = - existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi); - existing_sdap_entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); + // handle QFIs to DRB mapping rule to add + for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { + uint8_t qfi = sdap.mappedQFIs2Add[i]; + /* a default DRB exists and there is no stored QFI to DRB mapping rule for the QFI */ + if (entity->default_drb && entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) { + // construct an end-marker control PDU (6.2.3 TS 37.324) + nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi); + // map the end-marker control PDU to the default DRB + int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi); + // submit the end-marker control PDU to the lower layers + entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } - /* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header*/ - if (existing_sdap_entity->qfi2drb_table[qfi].drb_id != drb_identity && existing_sdap_entity->qfi2drb_table[qfi].has_sdap_tx) { - nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi); - rb_id_t sdap_ctrl_pdu_drb = - existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi); - existing_sdap_entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); + /* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header */ + if (entity->qfi2drb_table[qfi].drb_id != sdap.drb_id && entity->qfi2drb_table[qfi].has_sdap_tx) { + // construct an end-marker control PDU (6.2.3 TS 37.324) + nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi); + // map the end-marker control PDU to the DRB according to the stored QoS flow to DRB mapping rule + int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi); + // submit the end-marker control PDU to the lower layers + entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } - /* update QFI to DRB mapping rules */ + // store QFI to DRB mapping rules LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); - existing_sdap_entity->qfi2drb_map_update(existing_sdap_entity, qfi, drb_identity, has_sdap_rx, has_sdap_tx); + entity->qfi2drb_map_update(entity, qfi, sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); + } + + // handle QFIs to DRB mapping rule to release + for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { + entity->qfi2drb_map_delete(entity, sdap.mappedQFIs2Release[i]); } } @@ -478,14 +480,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons if (sdap_entity) { LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, sdap.pdusession_id); if (!is_gnb) { - nr_sdap_ue_qfi2drb_config(sdap_entity, - sdap_entity->default_drb, - ue_id, - sdap.mappedQFIs2Add, - sdap.mappedQFIs2AddCount, - sdap.drb_id, - sdap.sdap_rx, - sdap.sdap_tx); + nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); } else { // store QFI to DRB mapping rules for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { @@ -708,20 +703,8 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in ue_id, pdusession_id); /* QFI to DRB mapping */ - sdap_config_t sdap = get_sdap_Config(is_gnb, sdap_config, drb_id); - nr_sdap_ue_qfi2drb_config(sdap_entity, - sdap_entity->default_drb, - ue_id, - sdap.mappedQFIs2Add, - sdap.mappedQFIs2AddCount, - drb_id, - sdap.sdap_rx, - sdap.sdap_tx); - /* handle QFIs to DRB mapping rule to release */ - for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { - uint8_t qfi = sdap.mappedQFIs2Release[i]; - sdap_entity->qfi2drb_map_delete(sdap_entity, qfi); - } + sdap_config_t sdap = nr_sdap_get_config(is_gnb, sdap_config, drb_id); + nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); } void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index e8315ca846..ada9cfb26c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -108,7 +108,7 @@ typedef struct nr_sdap_entity_s { int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); - rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi); + int (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, int map_type, uint8_t dl_qfi); void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); bool (*tx_entity)(struct nr_sdap_entity_s *entity, @@ -156,7 +156,7 @@ nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi); * 1.) default DRB or * 2.) DRB according to the stored QoS flow to DRB mapping rule */ -rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi); +int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi); /* * TS 37.324 5.3 QoS flow to DRB Mapping From 3efaafa63390ab4db7c96fc61a5b9c87d762c23d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 12:55:09 +0200 Subject: [PATCH 49/61] Refactor QFI to DRB mapping logic nr_sdap_qfi2drb_map_update function pointer should process QFIs to add and release from the entity mapping, therefore a new function pointer for QFIs to add was introduced and the function pointer to release the QFIs was called in the same function. Now the nr_sdap_qfi2drb_map_update is: (1) looping through the QFIs to add/update and store in the qfi2drb_table (2) looping through the QFIs to release and delete from qfi2drb_table Also: * Update the function signature to use sdap_config_t and nr_sdap_entity_t * log error when the update fails * limit the scope of the function * clang-formatted * removed limit on table entries set by AVLBL_DRB, replaced with MAX_DRBS_PER_UE --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 70 ++++++++++++++++---------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 16 +++--- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 71805bc750..ec6386a62c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -333,27 +333,45 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, } } -/** - * @brief update QFI to DRB mapping rules -*/ -void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx) +/** @brief Update QFI to DRB mapping rules + * @param qfi the QoS Flow index, used as unique index of the qfi2drb mapping table + * @param drb the DRB ID to be mapped */ +static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap) { - if(qfi < SDAP_MAX_QFI && - qfi > SDAP_MAP_RULE_EMPTY && - drb > 0 && - drb <= AVLBL_DRB){ - entity->qfi2drb_table[qfi].drb_id = drb; - entity->qfi2drb_table[qfi].has_sdap_rx = has_sdap_rx; - entity->qfi2drb_table[qfi].has_sdap_tx = has_sdap_tx; - LOG_D(SDAP, "Updated mapping: QFI %u -> DRB %ld \n", qfi, entity->qfi2drb_table[qfi].drb_id); - } else { - LOG_D(SDAP, "Map updated failed, QFI: %u, DRB: %ld\n", qfi, drb); + for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Add[i]; + LOG_D(SDAP, "Updating QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id); + if (qfi < SDAP_MAX_QFI && qfi > SDAP_MAP_RULE_EMPTY && sdap->drb_id > 0 && sdap->drb_id <= MAX_DRBS_PER_UE) { + entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->sdap_rx, sdap->sdap_tx); + } else { + LOG_E(SDAP, "Failed to update qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); + } + } + for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Release[i]; + LOG_D(SDAP, "Deelting QFI to DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id); + entity->qfi2drb_map_delete(entity, qfi); } } -void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){ - entity->qfi2drb_table[qfi].drb_id = SDAP_NO_MAPPING_RULE; - LOG_D(SDAP, "Deleted mapping for QFI: %u \n", qfi); +static void nr_sdap_qfi2drb_map_add(nr_sdap_entity_t *entity, + const uint8_t qfi, + const uint8_t drb_id, + const uint8_t role_rx, + const uint8_t role_tx) +{ + qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi]; + LOG_D(SDAP, "%s mapping: QFI %u -> DRB %d \n", qfi2drb->drb_id == SDAP_NO_MAPPING_RULE ? "Add" : "Update", qfi, drb_id); + qfi2drb->drb_id = drb_id; + qfi2drb->has_sdap_rx = role_rx; + qfi2drb->has_sdap_tx = role_tx; +} + +static void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, const uint8_t qfi) +{ + qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi]; + qfi2drb->drb_id = SDAP_NO_MAPPING_RULE; + LOG_D(SDAP, "Deleted mapping for QFI=%d, DRB=%d\n", qfi, qfi2drb->drb_id); } /** @@ -448,15 +466,16 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue // submit the end-marker control PDU to the lower layers entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } - // store QFI to DRB mapping rules - LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); - entity->qfi2drb_map_update(entity, qfi, sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); } // handle QFIs to DRB mapping rule to release for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { entity->qfi2drb_map_delete(entity, sdap.mappedQFIs2Release[i]); } + + // store QFI to DRB mapping rules + LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); + entity->qfi2drb_map_update(entity, &sdap); } /** @@ -483,9 +502,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); } else { // store QFI to DRB mapping rules - for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { - sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); - } + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); } return sdap_entity; } @@ -508,6 +525,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // QFI to DRB mapping functions pointers sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update; + sdap_entity->qfi2drb_map_add = nr_sdap_qfi2drb_map_add; sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del; sdap_entity->qfi2drb_map = nr_sdap_qfi2drb; sdap_entity->pdusession_sock = -1; @@ -518,10 +536,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %ld \n", sdap_entity->default_drb); } - for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { - // store QFI to DRB mapping rules - sdap_entity->qfi2drb_map_update(sdap_entity, sdap.mappedQFIs2Add[i], sdap.drb_id, sdap.sdap_rx, sdap.sdap_tx); - } + // store QFI to DRB mapping rules + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); // update SDAP entity list pointers sdap_entity->next_entity = sdap_info.sdap_entity_llist; diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index ada9cfb26c..2d87961a62 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -38,7 +38,6 @@ #define SDAP_HDR_LENGTH (1) #define SDAP_MAX_QFI (64) #define SDAP_MAP_RULE_EMPTY (0) -#define AVLBL_DRB (5) #define SDAP_NO_MAPPING_RULE (0) #define SDAP_REFLECTIVE_MAPPING (1) #define SDAP_RQI_HANDLING (1) @@ -103,8 +102,13 @@ typedef struct nr_sdap_entity_s { qfi2drb_t qfi2drb_table[SDAP_MAX_QFI]; - void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx); - void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi); + void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, const sdap_config_t *sdap); + void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, const uint8_t qfi); + void (*qfi2drb_map_add)(struct nr_sdap_entity_s *entity, + const uint8_t qfi, + const uint8_t drb_id, + const uint8_t role_rx, + const uint8_t role_tx); int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); @@ -138,12 +142,6 @@ typedef struct nr_sdap_entity_s { struct nr_sdap_entity_s *next_entity; } nr_sdap_entity_t; -/* QFI to DRB Mapping Related Function */ -void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx); - -/* QFI to DRB Mapping Related Function */ -void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi); - /* * TS 37.324 5.3 QoS flow to DRB Mapping * construct an end-marker control PDU, as specified in the subclause 6.2.3, for the QoS flow; From 823340a2e23c5439c564de5417670b8fd9923e64 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 24 Apr 2025 16:33:37 +0200 Subject: [PATCH 50/61] Refactor handling of DL/UL SDAP header in the SDAP entity The TX/RX entity should have different behavior according to 5.2.1, 5.2.2, 3GPP TS 37.324, depending on whether it is UL and DL. The gNB can play a role both as UL RX entity and DL TX entity, while the UE can play a role both as UL TX entity and DL RX entity. The goal of this commit is to extend the information stored in the SDAP entity as the current code is just marking the entity as TX/RX. The commit introduces a bitmap to store the role of the entity, which can be DL RX, DL TX, UL RX and UL TX. Based on this the TX SDAP entity knows whether a DL/UL PDU should be build, and the RX SDAP entity knows whether a DL/UL PDU should be processed. See also Figure 4.2.2-1. SDAP headers are present only if enable_sdap option is used. --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 4 +- openair2/SDAP/nr_sdap/nr_sdap.c | 1 - openair2/SDAP/nr_sdap/nr_sdap_entity.c | 80 +++++++++++------------ openair2/SDAP/nr_sdap/nr_sdap_entity.h | 31 +++------ 4 files changed, 50 insertions(+), 66 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 6bd2d9354f..8f2bf0a043 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -623,8 +623,8 @@ void add_drb(int is_gnb, is_gnb, sdap->drb_id, sdap->pdusession_id, - sdap->sdap_rx, - sdap->sdap_tx, + (sdap->role & (SDAP_UL_RX | SDAP_DL_RX)) != 0, + (sdap->role & (SDAP_UL_TX | SDAP_DL_TX)) != 0, deliver_sdu_drb, ue, is_gnb ? deliver_pdu_drb_gnb : deliver_pdu_drb_ue, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index f6602c7597..58dc495c14 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -100,7 +100,6 @@ void sdap_data_ind(rb_id_t pdcp_entity, sdap_entity->rx_entity(sdap_entity, pdcp_entity, is_gnb, - has_sdap_rx, pdusession_id, ue_id, buf, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index ec6386a62c..89c9748a8e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -42,32 +42,20 @@ static nr_sdap_entity_info sdap_info; instance_t *N3GTPUInst = NULL; -/** - * @brief indicates whether it is a receiving SDAP entity - * i.e. for UE, header for DL data is present - * for gNB, header for UL data is present - */ -bool is_sdap_rx(bool is_gnb, NR_SDAP_Config_t *sdap_config) +/** @brief Returns a bitmap indicating the SDAP entity role, + * i.e. for UL transmission, header for UL data is present in RX/TX + * for DL transmission, header for DL data is present in RX/TX */ +static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config) { - if (is_gnb) { - return sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present; - } else { - return sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present; - } -} - -/** - * @brief indicates whether it is a transmitting SDAP entity - * i.e. for UE, header for UL data is present - * for gNB, header for DL data is present - */ -bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config) -{ - if (is_gnb) { - return sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present; - } else { - return sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present; - } + sdap_role_t role_ul = is_gnb ? SDAP_UL_RX : SDAP_UL_TX; + sdap_role_t role_dl = is_gnb ? SDAP_DL_TX : SDAP_DL_RX; + int role = 0; + if (sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present) + role |= role_ul; + if (sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present) + role |= role_dl; + DevAssert(role != 0); + return role; } void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu) @@ -107,7 +95,8 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, bool ret = false; /*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/ rb_id_t sdap_drb_id = rb_id; - int pdcp_ent_has_sdap = 0; + bool sdap_ul_tx = false; + bool sdap_dl_tx = false; if(sdu_buffer == NULL) { LOG_E(SDAP, "%s:%d:%s: NULL sdu_buffer \n", __FILE__, __LINE__, __FUNCTION__); @@ -119,12 +108,13 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, if(pdcp_entity){ sdap_drb_id = pdcp_entity; - pdcp_ent_has_sdap = entity->qfi2drb_table[qfi].has_sdap_tx; + sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity + sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %ld\n", qfi, entity->qfi2drb_table[qfi].drb_id); } - if(!pdcp_ent_has_sdap){ - LOG_D(SDAP, "TX - DRB ID: %ld does not have SDAP\n", entity->qfi2drb_table[qfi].drb_id); + if (!sdap_ul_tx && !sdap_dl_tx) { + LOG_D(SDAP, "TX - DRB ID: %ld does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id); ret = nr_pdcp_data_req_drb(ctxt_p, srb_flag, sdap_drb_id, @@ -147,7 +137,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, return 0; } - if(ctxt_p->enb_flag) { // gNB + if (sdap_dl_tx) { // create DL Data PDU with SDAP header offset = SDAP_HDR_LENGTH; /* * TS 37.324 4.4 Functions @@ -165,7 +155,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, LOG_D(SDAP, "TX Entity QFI: %u \n", sdap_hdr.QFI); LOG_D(SDAP, "TX Entity RQI: %u \n", sdap_hdr.RQI); LOG_D(SDAP, "TX Entity RDI: %u \n", sdap_hdr.RDI); - } else { // nrUE + } else if (sdap_ul_tx) { // create UL Data PDU with SDAP header offset = SDAP_HDR_LENGTH; /* * TS 37.324 4.4 Functions @@ -213,7 +203,6 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int is_gnb, - bool has_sdap_rx, int pdusession_id, ue_id_t ue_id, char *buf, @@ -221,9 +210,18 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, { /* The offset of the SDAP header, it might be 0 if has_sdap_rx is not true in the pdcp entity. */ int offset=0; + int qfi = buf[0] & 0x3F; // QFI is always the first 6 bits in the first octet + if (qfi <= 0 || qfi >= SDAP_MAX_QFI) { + LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi); + return; + } + + // Fetch entity role from the qfi2drb_table + bool sdap_ul_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_RX; // gNB RX entity + bool sdap_dl_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_RX; // UE RX entity if (is_gnb) { // gNB - if (has_sdap_rx) { // Handling the SDAP Header + if (sdap_ul_rx) { // UL Data/Control PDU with SDAP header offset = SDAP_HDR_LENGTH; nr_sdap_ul_hdr_t *sdap_hdr = (nr_sdap_ul_hdr_t *)buf; LOG_D(SDAP, "RX Entity Received QFI: %u\n", sdap_hdr->QFI); @@ -255,7 +253,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, * 5.2.2 Downlink * if the DRB from which this SDAP data PDU is received is configured by RRC with the presence of SDAP header. */ - if (has_sdap_rx) { // Handling the SDAP Header + if (sdap_dl_rx) { // DL Data/Control PDU with SDAP header offset = SDAP_HDR_LENGTH; /* * TS 37.324 5.2 Data transfer @@ -342,7 +340,7 @@ static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_conf uint8_t qfi = sdap->mappedQFIs2Add[i]; LOG_D(SDAP, "Updating QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id); if (qfi < SDAP_MAX_QFI && qfi > SDAP_MAP_RULE_EMPTY && sdap->drb_id > 0 && sdap->drb_id <= MAX_DRBS_PER_UE) { - entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->sdap_rx, sdap->sdap_tx); + entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role); } else { LOG_E(SDAP, "Failed to update qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); } @@ -357,14 +355,12 @@ static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_conf static void nr_sdap_qfi2drb_map_add(nr_sdap_entity_t *entity, const uint8_t qfi, const uint8_t drb_id, - const uint8_t role_rx, - const uint8_t role_tx) + const uint8_t role) { qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi]; LOG_D(SDAP, "%s mapping: QFI %u -> DRB %d \n", qfi2drb->drb_id == SDAP_NO_MAPPING_RULE ? "Add" : "Update", qfi, drb_id); qfi2drb->drb_id = drb_id; - qfi2drb->has_sdap_rx = role_rx; - qfi2drb->has_sdap_tx = role_tx; + qfi2drb->entity_role = role; } static void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, const uint8_t qfi) @@ -458,7 +454,8 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } /* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header */ - if (entity->qfi2drb_table[qfi].drb_id != sdap.drb_id && entity->qfi2drb_table[qfi].has_sdap_tx) { + bool ul_sdap_header = (entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX) != 0; + if (entity->qfi2drb_table[qfi].drb_id != sdap.drb_id && ul_sdap_header) { // construct an end-marker control PDU (6.2.3 TS 37.324) nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi); // map the end-marker control PDU to the DRB according to the stored QoS flow to DRB mapping rule @@ -674,8 +671,7 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_ DevAssert(sdap_Config); sdap_config_t sdapConfig = {0}; sdapConfig.drb_id = drb_id; - sdapConfig.sdap_rx = is_sdap_rx(is_gnb, sdap_Config); - sdapConfig.sdap_tx = is_sdap_tx(is_gnb, sdap_Config); + sdapConfig.role = get_sdap_role(is_gnb, sdap_Config); sdapConfig.defaultDRB = sdap_Config->defaultDRB; // 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present)) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 2d87961a62..874b58b828 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -68,10 +68,16 @@ typedef struct nr_sdap_ul_hdr_s { uint8_t DC:1; } __attribute__((packed)) nr_sdap_ul_hdr_t; +typedef enum { + SDAP_UL_TX = (1 << 0), + SDAP_UL_RX = (1 << 1), + SDAP_DL_TX = (1 << 2), + SDAP_DL_RX = (1 << 3) +} sdap_role_t; + typedef struct qfi2drb_s { rb_id_t drb_id; - bool has_sdap_rx; - bool has_sdap_tx; + int entity_role; } qfi2drb_t; void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); @@ -79,8 +85,7 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s typedef struct sdap_configuration_s { int pdusession_id; int drb_id; - bool sdap_rx; - bool sdap_tx; + int role; bool defaultDRB; NR_QFI_t mappedQFIs2Add[SDAP_MAX_QFI]; uint8_t mappedQFIs2AddCount; @@ -107,8 +112,7 @@ typedef struct nr_sdap_entity_s { void (*qfi2drb_map_add)(struct nr_sdap_entity_s *entity, const uint8_t qfi, const uint8_t drb_id, - const uint8_t role_rx, - const uint8_t role_tx); + const uint8_t role); int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi); nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); @@ -132,7 +136,6 @@ typedef struct nr_sdap_entity_s { void (*rx_entity)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int is_gnb, - bool has_sdap_rx, int pdusession_id, ue_id_t ue_id, char *buf, @@ -193,20 +196,6 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id); */ bool nr_sdap_delete_ue_entities(ue_id_t ue_id); -/** - * @brief indicates whether it is a receiving SDAP entity - * i.e. for UE, header for DL data is present - * for gNB, header for UL data is present - */ -bool is_sdap_rx(bool is_gnb, NR_SDAP_Config_t *sdap_config); - -/** - * @brief indicates whether it is a transmitting SDAP entity - * i.e. for UE, header for UL data is present - * for gNB, header for DL data is present - */ -bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config); - /** * @brief Run the SDAP reconfiguration for the DRB * @param[in] ue_id Unique identifier for the User Equipment. ID Range [0, 65536]. From 8207a4c352bb41af60d32f29067fa9a00738292c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 8 Jul 2025 15:33:28 +0200 Subject: [PATCH 51/61] SDAP refactoring: replace legacy (LTE) type rb_id_t with int --- openair2/SDAP/nr_sdap/nr_sdap.c | 4 ++-- openair2/SDAP/nr_sdap/nr_sdap.h | 4 ++-- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 22 +++++++++++----------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 14 +++++++------- openair3/ocp-gtpu/gtp_itf.h | 2 +- tests/nr-cuup/nr-cuup-load-test.c | 2 +- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index 58dc495c14..a32ce7152c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -47,7 +47,7 @@ static void reblock_tun_socket(int fd) bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, const srb_flag_t srb_flag, - const rb_id_t rb_id, + const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -82,7 +82,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p, return ret; } -void sdap_data_ind(rb_id_t pdcp_entity, +void sdap_data_ind(int pdcp_entity, int is_gnb, bool has_sdap_rx, int pdusession_id, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index 3877e58603..54a26e2a5b 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -35,7 +35,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, const srb_flag_t srb_flag, - const rb_id_t rb_id, + const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -53,7 +53,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p, * Uplink - gNB * Downlink - nrUE */ -void sdap_data_ind(rb_id_t pdcp_entity, +void sdap_data_ind(int pdcp_entity, int is_gnb, bool has_sdap_rx, int pdusession_id, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 89c9748a8e..198b8792fe 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -58,7 +58,7 @@ static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config) return role; } -void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu) +void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu) { protocol_ctxt_t ctxt = { .rntiMaybeUEid = ue_id }; @@ -72,7 +72,7 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s PDCP_TRANSMISSION_MODE_UNKNOWN, NULL, NULL); - LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %ld\n", sdap_ctrl_pdu_drb); + LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %d\n", sdap_ctrl_pdu_drb); LOG_D(SDAP, "QFI: %u\n R: %u\n D/C: %u\n", ctrl_pdu.QFI, ctrl_pdu.R, ctrl_pdu.DC); return; } @@ -80,7 +80,7 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, - const rb_id_t rb_id, + const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -94,7 +94,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, int offset=0; bool ret = false; /*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/ - rb_id_t sdap_drb_id = rb_id; + int sdap_drb_id = rb_id; bool sdap_ul_tx = false; bool sdap_dl_tx = false; @@ -104,17 +104,17 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, } uint8_t sdap_buf[SDAP_MAX_PDU]; - rb_id_t pdcp_entity = entity->qfi2drb_map(entity, qfi); + int pdcp_entity = entity->qfi2drb_map(entity, qfi); if(pdcp_entity){ sdap_drb_id = pdcp_entity; sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity - LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %ld\n", qfi, entity->qfi2drb_table[qfi].drb_id); + LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id); } if (!sdap_ul_tx && !sdap_dl_tx) { - LOG_D(SDAP, "TX - DRB ID: %ld does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id); + LOG_D(SDAP, "TX - DRB ID: %d does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id); ret = nr_pdcp_data_req_drb(ctxt_p, srb_flag, sdap_drb_id, @@ -201,7 +201,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, } static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, - rb_id_t pdcp_entity, + int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id, @@ -390,7 +390,7 @@ static int nr_sdap_qfi2drb(nr_sdap_entity_t *entity, uint8_t qfi) return drb_id; } else if (entity->default_drb) { /* QoS flow to DRB mapping rule does not exist, map SDAP SDU to default DRB, e.g. return default DRB of the SDAP entity */ - LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %ld\n", entity->default_drb); + LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %d\n", entity->default_drb); return entity->default_drb; } else { /* Note: UE undefined behaviour when neither a default DRB @@ -428,7 +428,7 @@ int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi) /** * @brief Submit the end-marker control PDU to PDCP according to TS 37.324, clause 5.3 */ -void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu) +void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu) { if(sdap_ctrl_pdu_drb){ nr_pdcp_submit_sdap_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, ctrl_pdu); @@ -530,7 +530,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // set default DRB if (sdap.defaultDRB) { sdap_entity->default_drb = sdap.drb_id; - LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %ld \n", sdap_entity->default_drb); + LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb); } // store QFI to DRB mapping rules diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index 874b58b828..b529dc0b4a 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -76,11 +76,11 @@ typedef enum { } sdap_role_t; typedef struct qfi2drb_s { - rb_id_t drb_id; + int drb_id; int entity_role; } qfi2drb_t; -void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); +void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); typedef struct sdap_configuration_s { int pdusession_id; @@ -95,7 +95,7 @@ typedef struct sdap_configuration_s { typedef struct nr_sdap_entity_s { ue_id_t ue_id; - rb_id_t default_drb; + int default_drb; /// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode, /// store which one we are bool is_gnb; @@ -117,12 +117,12 @@ typedef struct nr_sdap_entity_s { nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi); int (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, int map_type, uint8_t dl_qfi); - void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); + void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); bool (*tx_entity)(struct nr_sdap_entity_s *entity, protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, - const rb_id_t rb_id, + const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -134,7 +134,7 @@ typedef struct nr_sdap_entity_s { const bool rqi); void (*rx_entity)(struct nr_sdap_entity_s *entity, - rb_id_t pdcp_entity, + int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id, @@ -163,7 +163,7 @@ int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi) * TS 37.324 5.3 QoS flow to DRB Mapping * Submit the end-marker control PDU to the lower layer. */ -void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); +void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); /* * TS 37.324 4.4 5.1.1 SDAP entity establishment diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index 4fcb8190e4..a0d1580cf9 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -49,7 +49,7 @@ typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t; typedef bool (*gtpCallbackSDAP)(protocol_ctxt_t *ctxt_pP, const ue_id_t ue_id, const srb_flag_t srb_flagP, - const rb_id_t rb_idP, + const int rb_idP, const mui_t muiP, const confirm_t confirmP, const sdu_size_t sdu_buffer_sizeP, diff --git a/tests/nr-cuup/nr-cuup-load-test.c b/tests/nr-cuup/nr-cuup-load-test.c index 0c417ca5aa..1af262e146 100644 --- a/tests/nr-cuup/nr-cuup-load-test.c +++ b/tests/nr-cuup/nr-cuup-load-test.c @@ -165,7 +165,7 @@ static struct ue_stat { static bool recv_ng(protocol_ctxt_t *ctxt, const ue_id_t ue_id, const srb_flag_t flag, - const rb_id_t rb, + const int rb, const mui_t mui, const confirm_t confirm, const sdu_size_t size, From d760a16827d3786e89887177daad7b9167d8eebc Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 8 Sep 2025 16:14:05 +0200 Subject: [PATCH 52/61] SDAP TX: explicit check on qfi2drb_map output Each QFI should always be mapped to a DRB. If that is not the case, we have an undefined behavior. This should not occur. This commit prints an error in tx_entity and returns. --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 198b8792fe..83b6896b0e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -34,6 +34,8 @@ #include "tun_if.h" #include "nr_sdap.h" +#define NO_SDAP_HEADER 0 + typedef struct { nr_sdap_entity_t *sdap_entity_llist; } nr_sdap_entity_info; @@ -49,12 +51,11 @@ static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config) { sdap_role_t role_ul = is_gnb ? SDAP_UL_RX : SDAP_UL_TX; sdap_role_t role_dl = is_gnb ? SDAP_DL_TX : SDAP_DL_RX; - int role = 0; + int role = NO_SDAP_HEADER; if (sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present) role |= role_ul; if (sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present) role |= role_dl; - DevAssert(role != 0); return role; } @@ -106,11 +107,14 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, uint8_t sdap_buf[SDAP_MAX_PDU]; int pdcp_entity = entity->qfi2drb_map(entity, qfi); - if(pdcp_entity){ + if (pdcp_entity != SDAP_MAP_RULE_EMPTY) { sdap_drb_id = pdcp_entity; sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id); + } else { + LOG_E(SDAP, "QFI %u not mapped to any DRB - dropping SDU of size %d\n", qfi, sdu_buffer_size); + return false; } if (!sdap_ul_tx && !sdap_dl_tx) { @@ -672,6 +676,7 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_ sdap_config_t sdapConfig = {0}; sdapConfig.drb_id = drb_id; sdapConfig.role = get_sdap_role(is_gnb, sdap_Config); + LOG_D(SDAP, "SDAP headers %s\n", sdapConfig.role == NO_SDAP_HEADER ? "absent" : "present"); sdapConfig.defaultDRB = sdap_Config->defaultDRB; // 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present)) From 0348aa08b91ead59171cbb8ea45f4aa95765c298 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 14 Oct 2025 19:10:02 +0200 Subject: [PATCH 53/61] Remove rb_id parameter from SDAP TX entity - QFI determines DRB mapping - Remove rb_id parameter from nr_sdap_tx_entity() function signature - Update tx_entity function pointer - Remove rb_id parameter from sdap_data_req() function signature - Remove unused rb_id variable from sdap_tun_read_thread The rb_id parameter was redundant since SDAP determines DRB ID from QFI mapping via entity->qfi2drb_map(entity, qfi). This simplifies the interface. --- executables/lte-softmodem.c | 1 - openair2/SDAP/nr_sdap/nr_sdap.c | 5 ----- openair2/SDAP/nr_sdap/nr_sdap.h | 1 - openair2/SDAP/nr_sdap/nr_sdap_entity.c | 12 ++++-------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 1 - openair3/ocp-gtpu/gtp_itf.cpp | 1 - openair3/ocp-gtpu/gtp_itf.h | 1 - tests/nr-cuup/nr-cuup-load-test.c | 1 - 8 files changed, 4 insertions(+), 19 deletions(-) diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c index 77fdb21eb4..80b532607e 100644 --- a/executables/lte-softmodem.c +++ b/executables/lte-softmodem.c @@ -151,7 +151,6 @@ double cpuf; bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, const srb_flag_t srb_flag, - const rb_id_t rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index a32ce7152c..1aec02814e 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -47,7 +47,6 @@ static void reblock_tun_socket(int fd) bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, const srb_flag_t srb_flag, - const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -69,7 +68,6 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p, bool ret = sdap_entity->tx_entity(sdap_entity, ctxt_p, srb_flag, - rb_id, mui, confirm, sdu_buffer_size, @@ -115,8 +113,6 @@ static void *sdap_tun_read_thread(void *arg) int len; reblock_tun_socket(entity->pdusession_sock); - int rb_id = 1; - while (!entity->stop_thread) { len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD); if (len == -1) { @@ -147,7 +143,6 @@ static void *sdap_tun_read_thread(void *arg) entity->tx_entity(entity, &ctxt, SRB_FLAG_NO, - rb_id, RLC_MUI_UNDEFINED, RLC_SDU_CONFIRM_NO, len, diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index 54a26e2a5b..1164641970 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -35,7 +35,6 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, const srb_flag_t srb_flag, - const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 83b6896b0e..438e05dd60 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -81,7 +81,6 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, - const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, @@ -94,8 +93,6 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, /* The offset of the SDAP header, it might be 0 if has_sdap_tx is not true in the pdcp entity. */ int offset=0; bool ret = false; - /*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/ - int sdap_drb_id = rb_id; bool sdap_ul_tx = false; bool sdap_dl_tx = false; @@ -105,10 +102,9 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, } uint8_t sdap_buf[SDAP_MAX_PDU]; - int pdcp_entity = entity->qfi2drb_map(entity, qfi); + int drb_id = entity->qfi2drb_map(entity, qfi); - if (pdcp_entity != SDAP_MAP_RULE_EMPTY) { - sdap_drb_id = pdcp_entity; + if (drb_id != SDAP_MAP_RULE_EMPTY) { sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id); @@ -121,7 +117,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, LOG_D(SDAP, "TX - DRB ID: %d does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id); ret = nr_pdcp_data_req_drb(ctxt_p, srb_flag, - sdap_drb_id, + drb_id, mui, confirm, sdu_buffer_size, @@ -189,7 +185,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, */ ret = nr_pdcp_data_req_drb(ctxt_p, srb_flag, - sdap_drb_id, + drb_id, mui, confirm, sdu_buffer_size + offset, diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index b529dc0b4a..a5ac2953cf 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -122,7 +122,6 @@ typedef struct nr_sdap_entity_s { bool (*tx_entity)(struct nr_sdap_entity_s *entity, protocol_ctxt_t *ctxt_p, const srb_flag_t srb_flag, - const int rb_id, const mui_t mui, const confirm_t confirm, const sdu_size_t sdu_buffer_size, diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 9be1873612..aca2fcbb32 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -1244,7 +1244,6 @@ static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const st if (!uedata.callBackSDAP(&ctxt, uedata.ue_id, srb_flag, - rb_id, mui, confirm, sdu_buffer_size, diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index a0d1580cf9..c31f8c935e 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -49,7 +49,6 @@ typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t; typedef bool (*gtpCallbackSDAP)(protocol_ctxt_t *ctxt_pP, const ue_id_t ue_id, const srb_flag_t srb_flagP, - const int rb_idP, const mui_t muiP, const confirm_t confirmP, const sdu_size_t sdu_buffer_sizeP, diff --git a/tests/nr-cuup/nr-cuup-load-test.c b/tests/nr-cuup/nr-cuup-load-test.c index 1af262e146..533b119c9e 100644 --- a/tests/nr-cuup/nr-cuup-load-test.c +++ b/tests/nr-cuup/nr-cuup-load-test.c @@ -165,7 +165,6 @@ static struct ue_stat { static bool recv_ng(protocol_ctxt_t *ctxt, const ue_id_t ue_id, const srb_flag_t flag, - const int rb, const mui_t mui, const confirm_t confirm, const sdu_size_t size, From 04a1acf3767ff4bce0b0cad176a3bf927fca279e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 21 Oct 2025 16:56:22 +0200 Subject: [PATCH 54/61] PDCP: rename add_drb to nr_pdcp_add_drb --- doc/SW_archi.md | 2 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 10 +++++----- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 10 +++++----- openair2/RRC/NR/rrc_gNB_nsa.c | 2 +- openair2/RRC/NR_UE/rrc_UE.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 5b902a6675..c47a3cbc91 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -325,7 +325,7 @@ The PDCP implementation is secured by a general mutex, akin to the design of the Initialization of the PDCP layer follows a structure similar to that of the RLC layer. The function `nr_pdcp_layer_init()` initializes PDCP, while a second initialization function, `pdcp_module_init()`, must also be invoked. -To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in PDCP, while `nr_pdcp_remove_UE()` is used for their removal. Similarly, `add_drb()` adds UE DRB in PDCP, with `nr_pdcp_remove_UE()` handling their removal. +To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in PDCP, while `nr_pdcp_remove_UE()` is used for their removal. Similarly, `nr_pdcp_add_drb()` adds UE DRB in PDCP, with `nr_pdcp_remove_UE()` handling their removal. ## PDCP Tx flow diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index f29c26842b..4d81733380 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -155,7 +155,7 @@ static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, // add SDAP entity new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); // add PDCP entity - add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); + nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); } } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 8f2bf0a043..94d44fe8ce 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -575,11 +575,11 @@ void add_srb(int is_gnb, nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } -void add_drb(int is_gnb, - const ue_id_t UEid, - const NR_PDCP_Config_t *pdcp, - sdap_config_t *sdap, - const nr_pdcp_entity_security_keys_and_algos_t *security_parameters) +void nr_pdcp_add_drb(int is_gnb, + const ue_id_t UEid, + const NR_PDCP_Config_t *pdcp, + const sdap_config_t *sdap, + const nr_pdcp_entity_security_keys_and_algos_t *security_parameters) { nr_pdcp_ue_t *ue; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 75f41e2190..884ea11f60 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -48,11 +48,11 @@ void nr_pdcp_add_srbs(eNB_flag_t enb_flag, NR_SRB_ToAddModList_t *const srb2add_list, const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); -void add_drb(int is_gnb, - const ue_id_t UEid, - const NR_PDCP_Config_t *pdcp, - struct sdap_configuration_s *sdap, - const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); +void nr_pdcp_add_drb(int is_gnb, + const ue_id_t UEid, + const NR_PDCP_Config_t *pdcp, + const struct sdap_configuration_s *sdap, + const nr_pdcp_entity_security_keys_and_algos_t *security_parameters); void nr_pdcp_remove_UE(ue_id_t ue_id); void nr_pdcp_reestablishment(ue_id_t ue_id, diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index b6bf34729c..0c32a446ce 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -179,7 +179,7 @@ static void rrc_nsa_add_drb(const int ue_id, // add SDAP entity (terminated at gNB, since it's EPC) new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); // add PDCP entity - add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); + nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); } } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 81bd3b65bb..b852fad206 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -621,7 +621,7 @@ static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, con // add SDAP entity new_nr_sdap_entity(GNB_FLAG_NO, ue_id, sdap); // add PDCP entity - add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp); + nr_pdcp_add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp); } /** From 27be4e26a910bb6e4998b2229a8f29434fa33be8 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 21 Oct 2025 18:02:41 +0200 Subject: [PATCH 55/61] refactor: improve SDAP entity add/update flow management This commit refactors the SDAP entity QoS flow to DRB mapping functionality to improve code organization and enhance maintainability. Key changes: - Split nr_sdap_qfi2drb_map_update into focused functions: * nr_sdap_add_qos_flows_to_drb: handles QFI addition to DRB * nr_sdap_rm_qos_flows_from_drb: handles QFI removal from DRB * nr_sdap_ue_control_pdu_config: handles UE control PDU generation - Consolidate add/modify logic into reusable nr_sdap_addmod_entity function - Remove entity existence checking and updating from new_nr_sdap_entity: this function should only add SDAP entities - Improve function separation of concerns: do SDAP entity add or update separately and improve modularity by splitting operations in self contained functions - At SDAP creation, do only add of QFI to DRB mapping - rename new_nr_sdap_entity to nr_sdap_add_entity for function naming consinstency --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 2 +- openair2/RRC/NR/rrc_gNB_nsa.c | 2 +- openair2/RRC/NR_UE/rrc_UE.c | 2 +- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 115 ++++++++++---------- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 9 +- 5 files changed, 61 insertions(+), 69 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 4d81733380..ed9cc37c18 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -153,7 +153,7 @@ static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, // get SDAP config sdap_config_t sdap = nr_sdap_get_config(GNB_FLAG_YES, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity); // add SDAP entity - new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + nr_sdap_addmod_entity(GNB_FLAG_YES, ue_id, sdap); // add PDCP entity nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); } diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 0c32a446ce..996dc3528e 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -177,7 +177,7 @@ static void rrc_nsa_add_drb(const int ue_id, sdap.drb_id = drb->drb_Identity; sdap.defaultDRB = true; // add SDAP entity (terminated at gNB, since it's EPC) - new_nr_sdap_entity(GNB_FLAG_YES, ue_id, sdap); + nr_sdap_addmod_entity(GNB_FLAG_YES, ue_id, sdap); // add PDCP entity nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp); } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index b852fad206..6681eed855 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -619,7 +619,7 @@ static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, con sdap = nr_sdap_get_config(GNB_FLAG_NO, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity); } // add SDAP entity - new_nr_sdap_entity(GNB_FLAG_NO, ue_id, sdap); + nr_sdap_addmod_entity(GNB_FLAG_NO, ue_id, sdap); // add PDCP entity nr_pdcp_add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 438e05dd60..f0e791c683 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -331,27 +331,6 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, } } -/** @brief Update QFI to DRB mapping rules - * @param qfi the QoS Flow index, used as unique index of the qfi2drb mapping table - * @param drb the DRB ID to be mapped */ -static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap) -{ - for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) { - uint8_t qfi = sdap->mappedQFIs2Add[i]; - LOG_D(SDAP, "Updating QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id); - if (qfi < SDAP_MAX_QFI && qfi > SDAP_MAP_RULE_EMPTY && sdap->drb_id > 0 && sdap->drb_id <= MAX_DRBS_PER_UE) { - entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role); - } else { - LOG_E(SDAP, "Failed to update qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); - } - } - for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) { - uint8_t qfi = sdap->mappedQFIs2Release[i]; - LOG_D(SDAP, "Deelting QFI to DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id); - entity->qfi2drb_map_delete(entity, qfi); - } -} - static void nr_sdap_qfi2drb_map_add(nr_sdap_entity_t *entity, const uint8_t qfi, const uint8_t drb_id, @@ -437,13 +416,12 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hd } /** @brief UL QoS flow to DRB mapping configuration for a SDAP entity has already been established - * according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1 Configuration Procedures. - * The function handles both UL QoS Flows mapping rules to add and to remove. */ -static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue_id, const sdap_config_t sdap) + * according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1 Configuration Procedures. */ +static void nr_sdap_ue_control_pdu_config(nr_sdap_entity_t *entity, const ue_id_t ue_id, const sdap_config_t *sdap) { // handle QFIs to DRB mapping rule to add - for (int i = 0; i < sdap.mappedQFIs2AddCount; i++) { - uint8_t qfi = sdap.mappedQFIs2Add[i]; + for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Add[i]; /* a default DRB exists and there is no stored QFI to DRB mapping rule for the QFI */ if (entity->default_drb && entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) { // construct an end-marker control PDU (6.2.3 TS 37.324) @@ -455,7 +433,7 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue } /* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header */ bool ul_sdap_header = (entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX) != 0; - if (entity->qfi2drb_table[qfi].drb_id != sdap.drb_id && ul_sdap_header) { + if (entity->qfi2drb_table[qfi].drb_id != sdap->drb_id && ul_sdap_header) { // construct an end-marker control PDU (6.2.3 TS 37.324) nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi); // map the end-marker control PDU to the DRB according to the stored QoS flow to DRB mapping rule @@ -464,15 +442,42 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu); } } +} - // handle QFIs to DRB mapping rule to release - for (int i = 0; i < sdap.mappedQFIs2ReleaseCount; i++) { - entity->qfi2drb_map_delete(entity, sdap.mappedQFIs2Release[i]); +/** @brief Add QoS flows to a DRB */ +static void nr_sdap_add_qos_flows_to_drb(nr_sdap_entity_t *entity, const sdap_config_t *sdap) +{ + for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Add[i]; + LOG_D(SDAP, "Adding QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id); + if (qfi < SDAP_MAX_QFI && qfi > SDAP_MAP_RULE_EMPTY && sdap->drb_id > 0 && sdap->drb_id <= MAX_DRBS_PER_UE) { + entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role); + } else { + LOG_E(SDAP, "Failed to add qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id); + } } +} - // store QFI to DRB mapping rules - LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n"); - entity->qfi2drb_map_update(entity, &sdap); +/** @brief Remove QoS flows from a DRB */ +static void nr_sdap_rm_qos_flows_from_drb(nr_sdap_entity_t *entity, const sdap_config_t *sdap) +{ + for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) { + uint8_t qfi = sdap->mappedQFIs2Release[i]; + LOG_D(SDAP, "Removing QFI from DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id); + entity->qfi2drb_map_delete(entity, qfi); + } +} + +/** @brief Update QFI to DRB mapping rules + * @param qfi the QoS Flow index, used as unique index of the qfi2drb mapping table + * @param drb the DRB ID to be mapped */ +static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap) +{ + if (!entity->is_gnb) { // UE control PDU configuration + nr_sdap_ue_control_pdu_config(entity, entity->ue_id, sdap); + } + nr_sdap_add_qos_flows_to_drb(entity, sdap); + nr_sdap_rm_qos_flows_from_drb(entity, sdap); } /** @@ -480,31 +485,11 @@ static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *entity, const ue_id_t ue * @note there is one SDAP entity per PDU session * * @param is_gnb, indicates whether it is for gNB or UE - * @param has_sdap_rx, indicates whether it is a receiving SDAP entity - * @param has_sdap_tx, indicates whether it is a transmitting SDAP entity * @param ue_id, UE ID - * @param pdusession_id, PDU session ID - * @param is_defaultDRB, indicates whether the entity has a default DRB - * @param mapped_qfi_2_add, list of QoS flows to add/update - * @param mappedQFIs2AddCount, number of QoS flows to add/update - */ -nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap) + * @param sdap, SDAP configuration */ +static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap) { - /* check whether the SDAP entity already exists and - update QFI to DRB mapping rules in that case */ - nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap.pdusession_id); - if (sdap_entity) { - LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, sdap.pdusession_id); - if (!is_gnb) { - nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); - } else { - // store QFI to DRB mapping rules - sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); - } - return sdap_entity; - } - - sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity)); + nr_sdap_entity_t *sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity)); // SDAP entity ids sdap_entity->ue_id = ue_id; @@ -533,8 +518,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb); } - // store QFI to DRB mapping rules - sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); + // Add QoS flows to the DRB (initial configuration) + nr_sdap_add_qos_flows_to_drb(sdap_entity, &sdap); // update SDAP entity list pointers sdap_entity->next_entity = sdap_info.sdap_entity_llist; @@ -545,7 +530,17 @@ nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, cons // PDCP SDUs to/from the TUN interface. start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id); } - return sdap_entity; +} + +/** @brief Add or modify an SDAP entity if it already exists */ +void nr_sdap_addmod_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap) +{ + nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap.pdusession_id); + if (sdap_entity) { + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); + } else { + nr_sdap_add_entity(is_gnb, ue_id, sdap); + } } /** @@ -717,7 +712,7 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in pdusession_id); /* QFI to DRB mapping */ sdap_config_t sdap = nr_sdap_get_config(is_gnb, sdap_config, drb_id); - nr_sdap_ue_qfi2drb_config(sdap_entity, ue_id, sdap); + sdap_entity->qfi2drb_map_update(sdap_entity, &sdap); } void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index a5ac2953cf..a206189035 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -164,12 +164,6 @@ int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi) */ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu); -/* - * TS 37.324 4.4 5.1.1 SDAP entity establishment - * Establish an SDAP entity. - */ -nr_sdap_entity_t *new_nr_sdap_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap); - /* Entity Handling Related Functions */ nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id); @@ -177,6 +171,9 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_ void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id); +/** @brief Add or modify an SDAP entity based on whether it already exists */ +void nr_sdap_addmod_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t sdap); + /** * @brief Function to delete a single SDAP Entity based on the ue_id and pdusession_id. * @note 1. SDAP entities may have the same ue_id. From 110f5c73049641b9175185b8e301c406d3fd8de0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 13 Oct 2025 09:32:42 +0200 Subject: [PATCH 56/61] Updates for Feature Set --- doc/FEATURE_SET.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 4429cad56b..b0f85405be 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -31,7 +31,7 @@ The following features are valid for the gNB and the 5G-NR UE. * Subcarrier spacings: 15 and 30kHz (FR1), 120kHz (FR2) * Bandwidths: 10, 20, 40, 60, 80, 100MHz * Intermediate downlink and uplink frequencies to interface with IF equipment -* Procedures for 2-layer DL and UL MIMO +* Procedures for 4-layer DL and 2-layer UL SU-MIMO * Slot format: 14 OFDM symbols in UL or DL * Highly efficient 3GPP compliant LDPC encoder and decoder (BG1 and BG2 supported) * Highly efficient 3GPP compliant polar encoder and decoder @@ -47,7 +47,7 @@ These modes of operation are supported: * "noS1" mode (DL and UL, gNB, nrUE): - Connection setup stops after RA; RRC configuration is exchanged through files - - Creates TUN interface to PDCP to inject and receive user-place traffic + - Creates TUN interface to SDAP to inject and receive user-place traffic - No connection to the core network * Standalone (SA) mode (gNB, nrUE): - UE can register with the 5G Core Network through the gNB, establish a PDU @@ -73,7 +73,7 @@ These modes of operation are supported: - Single and multiple DMRS symbols - PTRS support - Support for up to 4 TX antennas - - Support for up to 2 layers + - Support for up to 4 layers - Support for 256 QAM * NR-CSIRS Generation of sequence at PHY * NR-PUSCH (including Segmentation, LDPC encoding, rate matching, scrambling, modulation, RB mapping, etc). @@ -104,7 +104,9 @@ These modes of operation are supported: ## gNB MAC - MAC -> PHY configuration using NR FAPI P5 interface -- MAC <-> PHY data interface using FAPI P7 interface for BCH PDU, DCI PDU, PDSCH PDU +- MAC <-> PHY data interface using FAPI P7 interface for DL_TTI.request, + UL_TTI.request, UL_DCI.request, TX_data.request, RX_Data.indication, + CRC.indication, UCI.indication, SRS.indication - Generation of and scheduler procedures for MIB/SIB1 - Scheduler procedures for RA - 4-Step RA @@ -125,7 +127,7 @@ These modes of operation are supported: - regular scheduler with dynamic proportionally-fair allocation - MCS adaptation from HARQ BLER - MAC header generation (including timing advance) -- ACK / NACK handling and HARQ procedures for downlink +- ACK/NACK handling and HARQ procedures for downlink - MAC uplink scheduler - phy-test scheduler (fixed allocation) - regular scheduler with dynamic proportionally-fair allocation @@ -144,6 +146,9 @@ These modes of operation are supported: neighbors include cells operating on different frequencies - DUs must be synchronized with each other for the measurements to be properly performed - Initial support for RedCap + - RedCap SIB1 v17 IEs supported + - Coexistence of RedCap and Normal UEs + - Handling of RedCap capability for small PDCP/RLC SN size - Scheduling of SIBs (2, 19) ## gNB RLC @@ -180,7 +185,7 @@ These modes of operation are supported: - NR RRC (38.331) Rel 17 messages using new [asn1c](https://github.com/mouse07410/asn1c) - LTE RRC (36.331) also updated to Rel 15 - Generation of system information (SIB2) -- RRC can configure PDCP, RLC, MAC +- RRC can configure PDCP and SDAP (through E1), and RLC and MAC (through F1) - Interface with GTP-U (tunnel creation/handling for S1-U (NSA), N3 (SA), F1 interfaces) - Integration of RRC messages and procedures supporting UE 5G SA connection - RRCSetupRequest/RRCSetup/RRCSetupComplete @@ -190,8 +195,10 @@ These modes of operation are supported: - Support for MasterCellGroup configuration (from DU) - Interface with NGAP for the interactions with the AMF - Interface with F1AP for CU/DU split deployment option - - Periodic RRC measurements of serving cell (no A/B events) -- Initial support for RedCap + - Interface with E1AP for CU-CP/CU-CP split deployment option + - Periodic RRC measurements of serving/neighbour cells and A2/A3 event + handling +- Initial support for RedCap (see MAC) ## gNB X2AP @@ -226,6 +233,7 @@ These modes of operation are supported: * F1 UE Context modification required * F1 UE Context release req/cmd/complete - F1 gNB CU configuration update + - F1 gNB DU configuration update - F1 Reset (handled at DU only, full reset only) - Interface with RRC - Interface with GTP-u (tunnel creation/handling for F1-U interface) @@ -245,7 +253,8 @@ These modes of operation are supported: - Bearer Context Modification (gNB-CU-CP initiated) - E1 Bearer Context Modification Request - E1 Bearer Context Modification Response -- Interface with RRC and PDCP + - E1 Reset +- Interface with RRC and PDCP/SDAP - One CU-CP can handle multiple CU-UPs ## gNB GTP-U From 66d8ada9827f729e0fa775dc19494b07be14949d Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 13 Oct 2025 10:54:54 +0200 Subject: [PATCH 57/61] Update UE feature set --- doc/FEATURE_SET.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index b0f85405be..1b095931e2 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -307,6 +307,7 @@ These modes of operation are supported: - Support for 256 QAM - Support for up to 2 TX antenna - Support for up to 2 layers + - Support for UCI on PUSCH * NR-PUCCH - Format 0 (2 bits for ACK/NACK and SR) - Format 2 (mainly for CSI feedback) @@ -339,6 +340,8 @@ These modes of operation are supported: * Minimum system information (MSI) - MIB processing - Scheduling of system information block 1 (SIB1) reception +* Other system information + - Scheduling of other system information blocks reception * Random access procedure (needs improvement, there is still not a clear separation between MAC and PHY) - Mapping SSBs to multiple ROs - Scheduling of PRACH @@ -407,8 +410,11 @@ These modes of operation are supported: * Integration of RRC messages and procedures supporting UE 5G SA connection according to 38.331 Rel.16 - RRCSetupRequest/RRCSetup/RRCSetupComplete + - RRCReject + - RRCRelease/ RRC going to IDLE - RRC Uplink/Downlink Information transfer carrying NAS messages transparently - RRC Reconfiguration/Reconfiguration complete + - RRCSetup fallback (after reestablishment) - RRCReestablishmentRequest/RRC Reestablishment/Reestablishment complete - Support for master cell group configuration - Reception of UECapabilityEnquiry, encoding and transmission of UECapability From 57e382ccd1a87d09424895bd4c434b023e120ffa Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 Oct 2025 10:37:49 +0200 Subject: [PATCH 58/61] Retroactively add release notes for v2.3.0 I forgot to add this when making the release. Put it retroactively to have things "in order". See also: https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.3.0 https://gitlab.eurecom.fr/oai/openairinterface5g/-/releases/v2.3.0 --- CHANGELOG.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5df218b36d..a9b355d079 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # RELEASE NOTES: # +## [v2.3.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.3.0) -> July 2025. ## + +General new features and improvements (both RAN and UE): +- Preliminary support for RedCap UEs +- Support for NTN LEO scenarios including SIB19 and channel emulation (see + doc/RUNMODEM.md) +- VRTSIM: new shared memory realtime radio (see develop/radio/vrtsim/README.md) +- Support for TDD pattern 2 +- Support for long PRACH +- Support for SIB2 +- Add unit tests using ctest (see doc/UnitTests.md) + +Stability and bug fixes: +- Improve various procedures (e.g., RRC reestablishment, RRC Reject, ...) +- Add improvements for ImScope +- Bugfixes in the entire stack (e.g., #803, #805, #810, #812, #818, #852, #878, + #884, #890, #895, #901, #907, #932, #939 ...) +- Documentation updates +- And many other small fixes, like memory leaks, crashes, ... + +RAN changes (gNB/CU/CU-CP/CU-UP/DU/DU-high/DU-low): +- Stability and performance improvements when running with 4-layer DL MIMO +- Stability and performance improvements when running with 2-layer UL MIMO +- Interoperability testing with Metanoia Jura and Foxconn RUs +- Support of O-RAN 7.2 M-plane (Start-up procedure including configuration + management, see also doc/ORAN_FHI7.2_Tutorial.md) +- Upgrade OSC FHI (xran) from E to F release +- Refactoring of LDPC interface and performance improvements +- Support for nFAPI in all scenarios for FR1 (see doc/nfapi.md) +- Support at least 32 UEs concurrently +- Improve robustness when running in split modes (F1, E1) +- Add basic support for beam management in FR2 +- Add support for O1 on DU (see also https://gitlab.eurecom.fr/oai/o1-adapter) +- E2 agent: Support for multiple E2SM-RC report service styles + +nrUE changes: +- Refactoring of threading towards better code and performance +- Add or rework various procedures (e.g., RA with C-RNTI, Going to Idle, RA, ...) +- Refactor and extend NAS implementation (e.g., Service Request, Registration + Request, Service Acept, Service Reject, ...) +- Support for continuous frequency offset compensation +- Reduce minimum RX-to-TX time to 3 + +Regression: +- Multiple BWPs do not work reliably on gNB; use tag 2025.w17 + ## [v2.2.0](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tags/v2.2.0) -> November 2024. ## General 5G improvements (both gNB and UE): From 23c115dc74bfaba3ced8b771897137d0bc6b5742 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 23 Oct 2025 15:54:23 +0200 Subject: [PATCH 59/61] Update NAS and mobility in Feature Set --- doc/FEATURE_SET.md | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 1b095931e2..4551bc1ff2 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -198,6 +198,13 @@ These modes of operation are supported: - Interface with E1AP for CU-CP/CU-CP split deployment option - Periodic RRC measurements of serving/neighbour cells and A2/A3 event handling +- RRC Mobility Management Procedures: + - Inter-DU Handover (F1-based handover within same CU) + - Inter-gNB Handover (N2-based handover between different gNBs) + - Handover Preparation Information generation and processing + - Handover Command generation and processing + - PDCP Status transfer procedures + - Support for handover decision triggers (A3 events, manual triggers) - Initial support for RedCap (see MAC) ## gNB X2AP @@ -216,6 +223,16 @@ These modes of operation are supported: - NGAP UE context release request/complete - NGAP UE radio capability info indication - NGAP PDU session resource setup request/response + - NGAP Mobility Management Procedures: + * NGAP Handover Required + * NGAP Handover Request + * NGAP Handover Request Acknowledge + * NGAP Handover Command + * NGAP Handover Notify + * NGAP Handover Cancel + * NGAP Handover Cancel Acknowledge + * NGAP Uplink RAN Status Transfer + * NGAP Downlink RAN Status Transfer - Interface with RRC ## gNB F1AP @@ -235,6 +252,8 @@ These modes of operation are supported: - F1 gNB CU configuration update - F1 gNB DU configuration update - F1 Reset (handled at DU only, full reset only) + - F1 Mobility Management Procedures: + * F1 Intra-CU Handover (Inter-DU mobility) - Interface with RRC - Interface with GTP-u (tunnel creation/handling for F1-U interface) - One CU(-CP) can handle multiple DUs @@ -421,17 +440,27 @@ These modes of operation are supported: * Interface with PDCP: configuration, DCCH and CCCH message handling * Interface with RLC and MAC for configuration -## UE NAS +## UE 5G NAS -* Transfer of NAS messages between the AMF and the UE supporting the UE registration with the core network and the PDU session establishment according to 24.501 Rel.16 +* Transfer of NAS messages between the AMF and the UE supporting the UE registration with the core network and the PDU session establishment according to 24.501 Rel.16 +* 5GMM (5G Mobility Management) messages: + - Service Request/Accept/Reject (enc/dec library only) - Identity Request/Response - Authentication Request/Response - Security Mode Command/Complete - Registration Request/Accept/Complete + - Deregistration Request (UE originating) + - Uplink NAS Transport +* 5GSM (5G Session Management) messages: - PDU Session Establishment Request/Accept - - NAS configuration and basic interfacing with RRC - +* Security Features: + - NAS message integrity protection and ciphering + - Security context establishment and management +* Integration: + - NAS configuration and interfacing with RRC + - Integration with SDAP for user plane data transfer +For detailed implementation status, encoding/decoding support, and unit test coverage, see [5G NAS Implementation Documentation](5Gnas.md). # OpenAirInterface 4G LTE eNB Feature Set # From a898c18ddcbdae4a3ad6026dc6bc31e5741fdc95 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 24 Oct 2025 10:43:25 +0200 Subject: [PATCH 60/61] Update NTN in Feature Set --- doc/FEATURE_SET.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 4551bc1ff2..df1cb60af4 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -125,13 +125,14 @@ These modes of operation are supported: - MAC downlink scheduler - phy-test scheduler (fixed allocation and usable also without UE) - regular scheduler with dynamic proportionally-fair allocation - - MCS adaptation from HARQ BLER + - MCS adaptation from HARQ BLER or SSB-SINR report - MAC header generation (including timing advance) - ACK/NACK handling and HARQ procedures for downlink - MAC uplink scheduler - phy-test scheduler (fixed allocation) - regular scheduler with dynamic proportionally-fair allocation - HARQ procedures for uplink + - MCS adaption from HARQ BLER or PUSCH SINR - Scheduler procedures for SRS reception - Periodic SRS reception - Channel rank computation up to 2x2 scenario @@ -149,7 +150,12 @@ These modes of operation are supported: - RedCap SIB1 v17 IEs supported - Coexistence of RedCap and Normal UEs - Handling of RedCap capability for small PDCP/RLC SN size -- Scheduling of SIBs (2, 19) +- Scheduling of other SIBs (2, 19) +- NTN + - Support downlinkHARQ-FeedbackDisabled-r17 + - Support for 32 PDSCH and PUSCH HARQ processes per UE + - Consider ntn-Config-r17.cellSpecificKoffset-r17 in scheduling + - Function-based interface for ntn-Config-r17 updates (used by NTN-LEO RFsimulator) ## gNB RLC @@ -296,7 +302,8 @@ These modes of operation are supported: - non-blind synchronization (information required: carrier frequency, bandwidth, numerology) - option to search SSB inside the bandwidth available * Time tracking based on PBCH DMRS -* Frequency offset estimation based on PSS and SSS +* Initial Frequency offset estimation based on PSS and SSS +* Continuous Frequency offset estimation and compensation based on PBCH DMRS * 15kHz and 30kHz SCS for FR1 and 120 kHz SCS for FR2 * Reception of NR-PSS/NR-SSS * NR-PBCH supports multiple SSBs and flexible periodicity @@ -342,6 +349,10 @@ These modes of operation are supported: - Support for multiple gNB reception with gNBs synced via GPSDO * NR-PRACH - Formats 0,1,2,3, A1-A3, B1-B3 +* NTN + - TA adjustemt based on ntn-Config-r17 information + - Autonomous TA adjustemt between SIB19 receptions based on DL time tracking + - UL Doppler pre-compensation based on continuous DL FO estimation * Highly efficient 3GPP compliant LDPC encoder and decoder (BG1 and BG2 are supported) * Highly efficient 3GPP compliant polar encoder and decoder * Encoder and decoder for short block @@ -397,6 +408,10 @@ These modes of operation are supported: - Periodic and aperiodic SRS transmission * Bandwidth part (BWP) operation - Operation in configured dedicated BWP through RRCSetup or RRCReconfiguration +* NTN + - Support downlinkHARQ-FeedbackDisabled-r17 + - Support for 32 PDSCH and PUSCH HARQ processes + - Consider ntn-Config-r17.cellSpecificKoffset-r17 in scheduling ## UE RLC @@ -437,6 +452,9 @@ These modes of operation are supported: - RRCReestablishmentRequest/RRC Reestablishment/Reestablishment complete - Support for master cell group configuration - Reception of UECapabilityEnquiry, encoding and transmission of UECapability +* NTN according to 38.331 Rel.17 + - Reception of ntn-Config-r17 from SIB19 or reconfigurationWithSync + - Handling of ntn-UlSyncValidityDuration-r17 in SIB19 * Interface with PDCP: configuration, DCCH and CCCH message handling * Interface with RLC and MAC for configuration From 41ce5954612245e4e1e25066beb3195d1dacca83 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 24 Oct 2025 15:11:25 +0200 Subject: [PATCH 61/61] Update supported bandwiths --- doc/FEATURE_SET.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index df1cb60af4..e3876457e6 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -29,7 +29,7 @@ The following features are valid for the gNB and the 5G-NR UE. * Static FDD * Normal CP * Subcarrier spacings: 15 and 30kHz (FR1), 120kHz (FR2) -* Bandwidths: 10, 20, 40, 60, 80, 100MHz +* Bandwidths: 5-100MHz (FR1), 100 and 200MHz (FR2) * Intermediate downlink and uplink frequencies to interface with IF equipment * Procedures for 4-layer DL and 2-layer UL SU-MIMO * Slot format: 14 OFDM symbols in UL or DL