From f184293ec0ec428471da6c8b38f6024b2e8aceba Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 3 Mar 2025 16:55:05 +0100 Subject: [PATCH 01/55] all CSI measurement report handling is disabled in phytest mode gNB, this commit allows RSRP measurements handling --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index e541fdfc68..32eb82d0c7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -655,6 +655,11 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, // verify if report with current id has been scheduled for this frame and slot if ((n_slots_frame*frame + slot - offset)%period == 0) { reportQuantity_type = csi_report->reportQuantity_type; + // phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP + if (get_softmodem_params()->phy_test + && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP + && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) + continue; LOG_D(MAC,"SFN/SF:%d/%d reportQuantity type = %d\n",frame,slot,reportQuantity_type); switch(reportQuantity_type) { case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: @@ -880,8 +885,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, } free(uci_234->harq.harq_payload); } - /* phy-test has hardcoded allocation, so no use to handle CSI reports */ - if ((uci_234->pduBitmap >> 2) & 0x01 && !get_softmodem_params()->phy_test) { + if ((uci_234->pduBitmap >> 2) & 0x01) { LOG_D(NR_MAC, "CSI CRC %d\n", uci_234->csi_part1.csi_part1_crc); if (uci_234->csi_part1.csi_part1_crc != 1) { // API to parse the csi report and store it into sched_ctrl From 9502e7537ca3d53a77fb9ffbe21d8414448e02cc Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 19 Mar 2025 10:00:38 +0100 Subject: [PATCH 02/55] avoiding segfault in LOGs in case of harq disabled --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 0092c388b6..39aae6db49 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1032,9 +1032,9 @@ void nr_schedule_ue_spec(module_id_t module_id, harq->round, nr_get_rv(harq->round % 4), harq->ndi, - pucch->timing_indicator, - pucch->frame, - pucch->ul_slot, + pucch ? pucch->timing_indicator : 0, + pucch ? pucch->frame : 0, + pucch ? pucch->ul_slot : 0, sched_pdsch->pucch_allocation, sched_ctrl->tpc1); @@ -1222,7 +1222,7 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_payload.ndi, dci_payload.rv, dci_payload.tpc, - pucch->timing_indicator); + pucch ? pucch->timing_indicator : 0); const int rnti_type = TYPE_C_RNTI_; fill_dci_pdu_rel15(&UE->sc_info, From 159f06cbf594b45a90d818f893b5d927b1568924 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Mar 2025 10:39:32 +0100 Subject: [PATCH 03/55] remove unnecessary gNB include in config_ue --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 1f0e552ba0..efe6a536e9 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -34,7 +34,6 @@ #define SPEED_OF_LIGHT 299792458 #include "mac_defs.h" -#include #include "NR_MAC_UE/mac_proto.h" #include "NR_MAC-CellGroupConfig.h" #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h" From 2269f1e49324ee21c5af9606a0fc93aaee175da0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Mar 2025 10:45:15 +0100 Subject: [PATCH 04/55] remove unnecessary gNB include in nr_mac_common --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 31 +++++++++---------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 -- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index d30c51ecc1..4332d18b90 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -30,7 +30,8 @@ */ -#include "LAYER2/NR_MAC_gNB/mac_proto.h" +#include "nr_mac.h" +#include "nr_mac_common.h" #include "common/utils/nr/nr_common.h" #include #include @@ -2431,6 +2432,19 @@ uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config, return n_antenna_port; } +static int binomial(int n, int k) +{ + if (k > n - k) + k = n - k; + int c = 1; + for (int i = 1; i <= k; i++, n--) { + if (c / i > UINT_MAX/n) // return 0 on overflow + return 0; + c = c / i * n + c % i * n / i; + } + return c; +} + // #define DEBUG_SRS_RESOURCE_IND uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, NR_PUSCH_Config_t *pusch_Config, @@ -3422,21 +3436,6 @@ uint8_t get_pusch_mcs_table(long *mcs_Table, } -int binomial(int n, int k) { - int c = 1, i; - - if (k > n-k) - k = n-k; - - for (i = 1; i <= k; i++, n--) { - if (c/i > UINT_MAX/n) // return 0 on overflow - return 0; - - c = c / i * n + c % i * n / i; - } - return c; -} - /* extract PTRS values from RC and validate it based upon 38.214 5.1.6.3 */ bool set_dl_ptrs_values(NR_PTRS_DownlinkConfig_t *ptrs_config, uint16_t rbSize,uint8_t mcsIndex, uint8_t mcsTable, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 4ce1f1126c..65c5aba9f1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -337,8 +337,6 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP, unsigned char drx_cmd, unsigned char *ue_cont_res_id); -int binomial(int n, int k); - /* \brief Function to indicate a received SDU on ULSCH. @param Mod_id Instance ID of gNB @param CC_id Component carrier index From 38fe30baabe18aa6f453b74be7ed0f053d79335e Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Mar 2025 11:30:53 +0100 Subject: [PATCH 05/55] improvements for NFAPI compilation for the UE --- CMakeLists.txt | 4 ++-- nfapi/oai_integration/nfapi_pnf.c | 1 - nfapi/open-nFAPI/pnf/src/pnf.c | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cdc796a5b..842f94b7d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1885,14 +1885,14 @@ add_executable(nr-uesoftmodem ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c ${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c + ${NFAPI_USER_DIR}/nfapi.c ${PHY_INTERFACE_DIR}/queue_t.c ) target_link_libraries(nr-uesoftmodem PRIVATE -Wl,--start-group nr_rrc SECURITY UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB - PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB NFAPI_PNF_LIB - NFAPI_USER_LIB MISC_NFAPI_NR_LIB + PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB ITTI SIMU shlib_loader -Wl,--end-group z dl) diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index 10d635562f..21b3e1e90e 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -54,7 +54,6 @@ #include "PHY/INIT/phy_init.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/LTE_TRANSPORT/transport_proto.h" -#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair1/SCHED_NR/fapi_nr_l1.h" #include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" #include "openair1/PHY/defs_gNB.h" diff --git a/nfapi/open-nFAPI/pnf/src/pnf.c b/nfapi/open-nFAPI/pnf/src/pnf.c index 3880e53c6c..4cef8e6412 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf.c +++ b/nfapi/open-nFAPI/pnf/src/pnf.c @@ -41,7 +41,6 @@ #include "NR_BCCH-BCH-Message.h" #include "NR_ServingCellConfigCommon.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "SCHED_NR/phy_frame_config_nr.h" #include "NR_MIB.h" From 45fffcff7126f8b8de44c811f057edcec14c8b61 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Mar 2025 11:49:03 +0100 Subject: [PATCH 06/55] remove include mac_proto in f1ap file --- openair2/F1AP/f1ap_du_rrc_message_transfer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c index 7fd83ecd78..4b9b9e1947 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c @@ -49,7 +49,6 @@ #include "openair2/RRC/NR/rrc_gNB_UE_context.h" #include "asn1_msg.h" #include "intertask_interface.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" From c4ef8931d81b8afa16480ab6133d79dfbf04c452 Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 13 Mar 2025 19:29:04 +0100 Subject: [PATCH 07/55] prevent possible segfault in compute_csi_bitlen --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index d30c51ecc1..9910bca878 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4779,12 +4779,16 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report uint8_t nb_resources = 0; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; NR_CSI_ResourceConfigId_t csi_ResourceConfigId; - struct NR_CSI_ResourceConfig *csi_resourceconfig; + NR_CSI_ResourceConfig_t *csi_resourceconfig; + if (!csi_MeasConfig->csi_ReportConfigToAddModList) { + LOG_E(NR_MAC, "csi_ReportConfigToAddModList is NULL, not expected\n"); + return; + } // for each CSI measurement report configuration (list of CSI-ReportConfig) LOG_D(NR_MAC,"Searching %d csi_reports\n",csi_MeasConfig->csi_ReportConfigToAddModList->list.count); for (csi_report_id = 0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) { - struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; + NR_CSI_ReportConfig_t *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; // MAC structure for CSI measurement reports (per UE and per report) nr_csi_report_t *csi_report = &csi_report_template[csi_report_id]; // csi-ResourceConfigId of a CSI-ResourceConfig included in the configuration From ec4232814a811243ac7c3e85352bacc46a625a9e Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 14 Mar 2025 08:54:57 +0100 Subject: [PATCH 08/55] prevent possible segfault in functions to compute csi report type bitlen also improving formatting of the same functions --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 237 +++++++++--------- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 27 -- 2 files changed, 123 insertions(+), 141 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 9910bca878..eb5a8fd26d 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4357,127 +4357,132 @@ bool set_ul_ptrs_values(NR_PTRS_UplinkConfig_t *ul_ptrs_config, } //! Calculating number of bits set -uint8_t number_of_bits_set(uint8_t buf) { +static uint8_t number_of_bits_set(uint8_t buf) +{ uint8_t nb_of_bits_set = 0; uint8_t mask = 0xff; - uint8_t index = 0; - - for (index=7; (buf & mask) && (index>=0) ; index--){ - if (buf & (1<= 0); index--) { + if (buf & (1 << index)) nb_of_bits_set++; - - mask>>=1; + mask >>= 1; } return nb_of_bits_set; } -void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t nb_resources, - nr_csi_report_t *csi_report) { - +static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t nb_resources, nr_csi_report_t *csi_report) +{ if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) { - if (NULL != csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) - csi_report->CSI_report_bitlen.nb_ssbri_cri = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; + if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + csi_report->CSI_report_bitlen.nb_ssbri_cri = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1; else /*! From Spec 38.331 * nrofReportedRS - * The number (N) of measured RS resources to be reported per report setting in a non-group-based report. N <= N_max, where N_max is either 2 or 4 depending on UE + * The number (N) of measured RS resources to be reported per report setting in a non-group-based report. + * N <= N_max, where N_max is either 2 or 4 depending on UE * capability. FFS: The signaling mechanism for the gNB to select a subset of N beams for the UE to measure and report. * When the field is absent the UE applies the value 1 */ - csi_report->CSI_report_bitlen.nb_ssbri_cri= 1; + csi_report->CSI_report_bitlen.nb_ssbri_cri = 1; } else - csi_report->CSI_report_bitlen.nb_ssbri_cri= 2; + csi_report->CSI_report_bitlen.nb_ssbri_cri = 2; if (nb_resources) { csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources)); - csi_report->CSI_report_bitlen.rsrp_bitlen = 7; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - csi_report->CSI_report_bitlen.diff_rsrp_bitlen =4; //From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP } else { - csi_report->CSI_report_bitlen.cri_ssbri_bitlen =0; + csi_report->CSI_report_bitlen.cri_ssbri_bitlen = 0; csi_report->CSI_report_bitlen.rsrp_bitlen = 0; - csi_report->CSI_report_bitlen.diff_rsrp_bitlen =0; + csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 0; } } -uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - nr_csi_report_t *csi_report) +static uint8_t compute_ri_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, nr_csi_report_t *csi_report) { - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; uint8_t nb_allowed_ri, ri_bitlen; - uint8_t ri_restriction = 0; if (codebookConfig == NULL) { csi_report->csi_meas_bitlen.ri_bitlen = 0; - return ri_restriction; + return 0; } + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL; + struct NR_CodebookConfig__codebookType__type1 *type1 = NULL; + if (codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1) + type1 = codebookConfig->codebookType.choice.type1; + else + LOG_E(NR_MAC, "Only type1 codebook configuration is supported\n"); + if (type1 && type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) + type1single = type1->subType.choice.typeI_SinglePanel; + else + LOG_E(NR_MAC, "Only type1 single panel codebook configuration is supported\n"); + + if (!type1single) + return -1; + + uint8_t ri_restriction = type1single->typeI_SinglePanel_ri_Restriction.buf[0]; + // codebook type1 single panel - if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel == codebookConfig->codebookType.choice.type1->subType.present) { - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel; - if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) { - - ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; - + if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_two) { + nb_allowed_ri = number_of_bits_set(ri_restriction); + ri_bitlen = ceil(log2(nb_allowed_ri)); + // from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel + ri_bitlen = ri_bitlen < 1 ? ri_bitlen : 1; + csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen; + } + if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) { + if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present == + NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { + // 4 ports nb_allowed_ri = number_of_bits_set(ri_restriction); ri_bitlen = ceil(log2(nb_allowed_ri)); - - ri_bitlen = ri_bitlen < 1 ? ri_bitlen : 1; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel + // from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel + ri_bitlen = ri_bitlen < 2 ? ri_bitlen : 2; csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen; } - if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo){ - if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present == - NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { - // 4 ports - - ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; - - nb_allowed_ri = number_of_bits_set(ri_restriction); - ri_bitlen = ceil(log2(nb_allowed_ri)); - - ri_bitlen = ri_bitlen < 2 ? ri_bitlen : 2; //from the spec 38.212 and table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel - csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen; - } - else { - // more than 4 ports - - ri_restriction = csi_reportconfig->codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel->typeI_SinglePanel_ri_Restriction.buf[0]; - - nb_allowed_ri = number_of_bits_set(ri_restriction); - ri_bitlen = ceil(log2(nb_allowed_ri)); - - csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen; - } - } - return ri_restriction; - } - else - AssertFatal(1==0,"Other configurations not yet implemented\n"); - return -1; -} - -void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report) { - - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; - for(int i=0; i<8; i++) { - if (codebookConfig == NULL || ((ri_restriction>>i)&0x01) == 0) - csi_report->csi_meas_bitlen.li_bitlen[i]=0; else { - // codebook type1 single panel - if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel==codebookConfig->codebookType.choice.type1->subType.present) - csi_report->csi_meas_bitlen.li_bitlen[i]=ceil(log2(i+1))<2?ceil(log2(i+1)):2; + // more than 4 ports + nb_allowed_ri = number_of_bits_set(ri_restriction); + ri_bitlen = ceil(log2(nb_allowed_ri)); + csi_report->csi_meas_bitlen.ri_bitlen = ri_bitlen; + } + } + return ri_restriction; +} + +static void compute_li_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t ri_restriction, nr_csi_report_t *csi_report) +{ + struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; + for(int i = 0; i < 8; i++) { + if (codebookConfig == NULL || ((ri_restriction >> i) & 0x01) == 0) + csi_report->csi_meas_bitlen.li_bitlen[i] = 0; + else { + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL; + struct NR_CodebookConfig__codebookType__type1 *type1 = NULL; + if (codebookConfig && codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1) + type1 = codebookConfig->codebookType.choice.type1; else - AssertFatal(1==0,"Other configurations not yet implemented\n"); + LOG_E(NR_MAC, "Only type1 codebook configuration is supported\n"); + if (type1 && type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) + type1single = type1->subType.choice.typeI_SinglePanel; + else + LOG_E(NR_MAC, "Only type1 single panel codebook configuration is supported\n"); + // codebook type1 single panel + if (type1single) + csi_report->csi_meas_bitlen.li_bitlen[i] = ceil(log2(i + 1)) < 2 ? ceil(log2(i + 1)) : 2; + else + csi_report->csi_meas_bitlen.li_bitlen[i] = 0; } } } -void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2, - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo) { - +static void get_n1n2_o1o2_singlepanel(int *n1, + int *n2, + int *o1, + int *o2, + const struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo) +{ // Table 5.2.2.2.1-2 in 38.214 for supported configurations switch(morethantwo->n1_n2.present){ case (NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction): @@ -4559,7 +4564,7 @@ void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2, *o2 = 1; break; default: - AssertFatal(1==0,"Not supported configuration for n1_n2 in codebook configuration"); + AssertFatal(false, "Not supported configuration for n1_n2 in codebook configuration"); } } @@ -4691,15 +4696,13 @@ static void set_bitlen_size_singlepanel(CSI_Meas_bitlen_t *csi_bitlen, int n1, i } break; default: - AssertFatal(1==0,"Invalid rank in x1 x2 bit length computation\n"); + AssertFatal(false, "Invalid rank in x1 x2 bit length computation\n"); } csi_bitlen->pmi_x1_bitlen[i] = csi_bitlen->pmi_i11_bitlen[i] + csi_bitlen->pmi_i12_bitlen[i] + csi_bitlen->pmi_i13_bitlen[i]; } -void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report) +static void compute_pmi_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t ri_restriction, nr_csi_report_t *csi_report) { NR_CodebookConfig_t *codebookConfig = csi_reportconfig->codebookConfig; for(int i = 0; i < 8; i++) { @@ -4731,45 +4734,51 @@ void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, } } else - AssertFatal(1==0,"Type1 Multi-panel Codebook Config not yet implemented\n"); + AssertFatal(false, "Type1 Multi-panel Codebook Config not yet implemented\n"); } else - AssertFatal(1==0,"Type2 Codebook Config not yet implemented\n"); + AssertFatal(false, "Type2 Codebook Config not yet implemented\n"); } } } -void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report) { +static void compute_cqi_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t ri_restriction, nr_csi_report_t *csi_report) +{ + NR_CodebookConfig_t *codebookConfig = csi_reportconfig->codebookConfig; + struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL; + struct NR_CodebookConfig__codebookType__type1 *type1 = NULL; + if (codebookConfig && codebookConfig->codebookType.present == NR_CodebookConfig__codebookType_PR_type1) + type1 = codebookConfig->codebookType.choice.type1; + else + LOG_E(NR_MAC, "Only type1 codebook configuration is supported\n"); + if (type1 && type1->subType.present == NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel) + type1single = type1->subType.choice.typeI_SinglePanel; + else + LOG_E(NR_MAC, "Only type1 single panel codebook configuration is supported\n"); - struct NR_CodebookConfig *codebookConfig = csi_reportconfig->codebookConfig; struct NR_CSI_ReportConfig__reportFreqConfiguration *freq_config = csi_reportconfig->reportFreqConfiguration; + if (!freq_config + || *freq_config->cqi_FormatIndicator != NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI) { + LOG_E(NR_MAC, "Only wide-band CQI reporting is supported\n"); + return; + } - if (*freq_config->cqi_FormatIndicator == NR_CSI_ReportConfig__reportFreqConfiguration__cqi_FormatIndicator_widebandCQI) { - for(int i=0; i<8; i++) { - if ((ri_restriction>>i)&0x01) { - csi_report->csi_meas_bitlen.cqi_bitlen[i] = 4; - if(codebookConfig != NULL) { - if (NR_CodebookConfig__codebookType__type1__subType_PR_typeI_SinglePanel == codebookConfig->codebookType.choice.type1->subType.present){ - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = codebookConfig->codebookType.choice.type1->subType.choice.typeI_SinglePanel; - if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) { - if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present > - NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { - // more than 4 antenna ports - if (i > 4) - csi_report->csi_meas_bitlen.cqi_bitlen[i] += 4; // CQI for second TB - } - } - } + for(int i = 0; i < 8; i++) { + if ((ri_restriction >> i) & 0x01) { + csi_report->csi_meas_bitlen.cqi_bitlen[i] = 4; + if (!type1single) + continue; + if (type1single->nrOfAntennaPorts.present == NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts_PR_moreThanTwo) { + if (type1single->nrOfAntennaPorts.choice.moreThanTwo->n1_n2.present > + NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo__n1_n2_PR_two_one_TypeI_SinglePanel_Restriction) { + // more than 4 antenna ports + if (i > 4) + csi_report->csi_meas_bitlen.cqi_bitlen[i] += 4; // CQI for second TB } } - else - csi_report->csi_meas_bitlen.cqi_bitlen[i] = 0; - } + } else + csi_report->csi_meas_bitlen.cqi_bitlen[i] = 0; } - else - AssertFatal(1==0,"Sub-band CQI reporting not yet supported"); } //!TODO : same function can be written to handle csi_resources @@ -4852,18 +4861,18 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); break; case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); break; case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); break; case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen=ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index b8d1fae38c..487e81ac40 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -290,33 +290,6 @@ bool set_ul_ptrs_values(NR_PTRS_UplinkConfig_t *ul_ptrs_config, @returns transformPrecoding value */ long get_transformPrecoding(const NR_UE_UL_BWP_t *current_UL_BWP, nr_dci_format_t dci_format, uint8_t configuredGrant); -uint8_t number_of_bits_set(uint8_t buf); - -void compute_rsrp_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t nb_resources, - nr_csi_report_t *csi_report); - -uint8_t compute_ri_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - nr_csi_report_t *csi_report); - -void compute_li_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report); - -void get_n1n2_o1o2_singlepanel(int *n1, int *n2, int *o1, int *o2, - struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel__nrOfAntennaPorts__moreThanTwo *morethantwo); - -void get_x1x2_bitlen_singlepanel(int n1, int n2, int o1, int o2, - int *x1, int *x2, int rank, int codebook_mode); - -void compute_pmi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report); - -void compute_cqi_bitlen(struct NR_CSI_ReportConfig *csi_reportconfig, - uint8_t ri_restriction, - nr_csi_report_t *csi_report); - void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report_t *csi_report_template); uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report); From 7af5e9f59e1aedb9025a5d42e1303c5408566bd5 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 14 Mar 2025 10:14:01 +0100 Subject: [PATCH 09/55] prevent possible segfault in is_ss_monitor_occasion function --- openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c | 2 ++ 1 file changed, 2 insertions(+) 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 3817e06759..9ebf2dbeb4 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -415,6 +415,8 @@ void get_monitoring_period_offset(const NR_SearchSpace_t *ss, int *period, int * bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per_frame, const NR_SearchSpace_t *ss) { + if (!ss) + return false; const int duration = ss->duration ? *ss->duration : 1; bool monitor = false; int period, offset; From 1d1814f8b34a5271ceba37ef5c4c1120bc75d340 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 14 Jan 2025 14:27:05 +0100 Subject: [PATCH 10/55] Shared memory time domain bidirectional IQ channel This implements a server-client bidirectional time domain IQ channel via shared memory. The server creates the channel and should be aware of the client receiver configuration (num rx/tx antennas). Server shall be the time source and should call shm_iq_channel_produce_samples at regular intervals --- common/utils/CMakeLists.txt | 1 + common/utils/shm_iq_channel/CMakeLists.txt | 6 + .../utils/shm_iq_channel/shm_td_iq_channel.c | 286 ++++++++++++++++++ .../utils/shm_iq_channel/shm_td_iq_channel.h | 148 +++++++++ .../utils/shm_iq_channel/tests/CMakeLists.txt | 5 + .../tests/test_shm_td_iq_channel.c | 169 +++++++++++ 6 files changed, 615 insertions(+) create mode 100644 common/utils/shm_iq_channel/CMakeLists.txt create mode 100644 common/utils/shm_iq_channel/shm_td_iq_channel.c create mode 100644 common/utils/shm_iq_channel/shm_td_iq_channel.h create mode 100644 common/utils/shm_iq_channel/tests/CMakeLists.txt create mode 100644 common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c diff --git a/common/utils/CMakeLists.txt b/common/utils/CMakeLists.txt index ccb15bfd47..b311d0542f 100644 --- a/common/utils/CMakeLists.txt +++ b/common/utils/CMakeLists.txt @@ -21,3 +21,4 @@ if (ENABLE_TESTS) endif() add_subdirectory(barrier) add_subdirectory(actor) +add_subdirectory(shm_iq_channel) diff --git a/common/utils/shm_iq_channel/CMakeLists.txt b/common/utils/shm_iq_channel/CMakeLists.txt new file mode 100644 index 0000000000..57c7d343ef --- /dev/null +++ b/common/utils/shm_iq_channel/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(shm_td_iq_channel shm_td_iq_channel.c) +target_include_directories(shm_td_iq_channel PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +if (ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.c b/common/utils/shm_iq_channel/shm_td_iq_channel.c new file mode 100644 index 0000000000..89e09ddb1f --- /dev/null +++ b/common/utils/shm_iq_channel/shm_td_iq_channel.c @@ -0,0 +1,286 @@ +/* + * 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 "shm_td_iq_channel.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "assertions.h" +#include "utils.h" +#include "common/utils/threadPool/pthread_utils.h" + +#define CIRCULAR_BUFFER_SIZE (30720 * 14 * 20) + +typedef struct { + int magic; + int num_antennas_tx; + int num_antennas_rx; + uint64_t timestamp; + bool is_connected; + pthread_mutex_t mutex; + pthread_cond_t cond; +} ShmTDIQChannelData; + +typedef struct ShmTDIQChannel_s { + IQChannelType type; + ShmTDIQChannelData *data; + uint64_t last_timestamp; + char name[256]; + sample_t *tx_iq_data; + sample_t *rx_iq_data; +} ShmTDIQChannel; + +ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant) +{ + // Create shared memory segment + int fd = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + AssertFatal(fd != -1, "shm_open failed: %s\n", strerror(errno)); + size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * num_tx_ant; + size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * num_rx_ant; + size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size; + + // Set the size of the shared memory segment + int res = ftruncate(fd, total_size); + AssertFatal(res != -1, "ftruncate failed: %s\n", strerror(errno)); + + // Map shared memory segment to address space + ShmTDIQChannelData *shm_ptr = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + AssertFatal(shm_ptr != MAP_FAILED, "mmap failed: %s\n", strerror(errno)); + + // Initialize shared memory + memset(shm_ptr, 0, total_size); + shm_ptr->num_antennas_tx = num_tx_ant; + shm_ptr->num_antennas_rx = num_rx_ant; + shm_ptr->is_connected = false; + ShmTDIQChannel *channel = calloc_or_fail(1, sizeof(ShmTDIQChannel)); + strncpy(channel->name, name, sizeof(channel->name) - 1); + channel->tx_iq_data = (sample_t *)(shm_ptr + 1); + channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t); + channel->data = shm_ptr; + channel->type = IQ_CHANNEL_TYPE_SERVER; + channel->last_timestamp = 0; + pthread_mutexattr_t mutex_attr; + pthread_condattr_t cond_attr; + int ret = pthread_mutexattr_init(&mutex_attr); + AssertFatal(ret == 0, "pthread_mutexattr_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_condattr_init(&cond_attr); + AssertFatal(ret == 0, "pthread_condattr_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); + AssertFatal(ret == 0, "pthread_mutexattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); + AssertFatal(ret == 0, "pthread_condattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_mutex_init(&shm_ptr->mutex, &mutex_attr); + AssertFatal(ret == 0, "pthread_mutex_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_cond_init(&shm_ptr->cond, &cond_attr); + AssertFatal(ret == 0, "pthread_cond_init() failed: errno %d, %s\n", errno, strerror(errno)); + + shm_ptr->magic = SHM_MAGIC_NUMBER; + close(fd); + return channel; +} + +ShmTDIQChannel *shm_td_iq_channel_connect(const char *name, int timeout_in_seconds) +{ + // Create shared memory segment + int fd = -1; + while (timeout_in_seconds > 0 && fd == -1) { + fd = shm_open(name, O_RDWR, S_IRUSR | S_IWUSR); + timeout_in_seconds--; + printf("Waiting for server to create shared memory segment\n"); + sleep(1); + } + AssertFatal(fd != -1, "shm_open() failed: errno %d, %s", errno, strerror(errno)); + + struct stat buf; + fstat(fd, &buf); + size_t total_size = buf.st_size; + + // Map shared memory segment to address space + ShmTDIQChannelData *shm_ptr = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (shm_ptr == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + ShmTDIQChannel *channel = calloc_or_fail(1, sizeof(ShmTDIQChannel)); + channel->data = shm_ptr; + channel->tx_iq_data = (sample_t *)(shm_ptr + 1); + size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * channel->data->num_antennas_tx; + channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t); + channel->type = IQ_CHANNEL_TYPE_CLIENT; + channel->last_timestamp = 0; + while (shm_ptr->magic != SHM_MAGIC_NUMBER) { + printf("Waiting for server to initialize shared memory\n"); + sleep(1); + } + shm_ptr->is_connected = true; + close(fd); + return channel; +} + +IQChannelErrorType shm_td_iq_channel_tx(ShmTDIQChannel *channel, + uint64_t timestamp, + uint64_t num_samples, + int antenna, + const sample_t *tx_iq_data) +{ + ShmTDIQChannelData *data = channel->data; + if (data->is_connected == false) { + return CHANNEL_ERROR_NOT_CONNECTED; + } + // timestamp in the past + uint64_t current_time = data->timestamp; + if (timestamp < current_time) { + return CHANNEL_ERROR_TOO_LATE; + } + // timestamp is too far in the future + if (timestamp - current_time + num_samples >= CIRCULAR_BUFFER_SIZE) { + return CHANNEL_ERROR_TOO_EARLY; + } + + sample_t *base_ptr; + if (channel->type == IQ_CHANNEL_TYPE_CLIENT) { + base_ptr = channel->rx_iq_data + antenna * CIRCULAR_BUFFER_SIZE; + } else { + base_ptr = channel->tx_iq_data + antenna * CIRCULAR_BUFFER_SIZE; + } + + uint64_t first_sample = timestamp % CIRCULAR_BUFFER_SIZE; + uint64_t last_sample = first_sample + num_samples - 1; + if (last_sample >= CIRCULAR_BUFFER_SIZE) { + size_t num_samples_first_copy = CIRCULAR_BUFFER_SIZE - first_sample; + memcpy(base_ptr + first_sample, tx_iq_data, num_samples_first_copy * sizeof(sample_t)); + memcpy(base_ptr, tx_iq_data + num_samples_first_copy, (num_samples - num_samples_first_copy) * sizeof(sample_t)); + } else { + memcpy(base_ptr + first_sample, tx_iq_data, num_samples * sizeof(sample_t)); + } + return CHANNEL_NO_ERROR; +} + +IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel, + uint64_t timestamp, + uint64_t num_samples, + int antenna, + sample_t *tx_iq_data) +{ + ShmTDIQChannelData *data = channel->data; + if (data->is_connected == false) { + return CHANNEL_ERROR_NOT_CONNECTED; + } + // timestamp in the future + uint64_t current_time = data->timestamp; + if (timestamp > current_time) { + return CHANNEL_ERROR_TOO_EARLY; + } + // timestamp is too far in the past + if (current_time - timestamp >= CIRCULAR_BUFFER_SIZE) { + return CHANNEL_ERROR_TOO_LATE; + } + + sample_t *base_ptr; + if (channel->type == IQ_CHANNEL_TYPE_CLIENT) { + base_ptr = channel->tx_iq_data + antenna * CIRCULAR_BUFFER_SIZE; + } else { + base_ptr = channel->rx_iq_data + antenna * CIRCULAR_BUFFER_SIZE; + } + + uint64_t first_sample = timestamp % CIRCULAR_BUFFER_SIZE; + uint64_t last_sample = first_sample + num_samples - 1; + if (last_sample >= CIRCULAR_BUFFER_SIZE) { + size_t num_samples_first_copy = CIRCULAR_BUFFER_SIZE - first_sample; + memcpy(tx_iq_data, base_ptr + first_sample, num_samples_first_copy * sizeof(sample_t)); + memcpy(tx_iq_data + num_samples_first_copy, base_ptr, (num_samples - num_samples_first_copy) * sizeof(sample_t)); + } else { + memcpy(tx_iq_data, base_ptr + first_sample, num_samples * sizeof(sample_t)); + } + return CHANNEL_NO_ERROR; +} + +void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples) +{ + ShmTDIQChannelData *data = channel->data; + if (channel->type != IQ_CHANNEL_TYPE_SERVER) { + return; + } + if (data->is_connected == false) { + return; + } + mutexlock(data->mutex); + data->timestamp += num_samples; + condbroadcast(data->cond); + mutexunlock(data->mutex); +} + +void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp) +{ + ShmTDIQChannelData *data = channel->data; + if (data->is_connected == false) { + abort(); + return; + } + + size_t current_timestamp = data->timestamp; + if (current_timestamp >= timestamp) { + return; + } + mutexlock(data->mutex); + while (current_timestamp < timestamp) { + condwait(data->cond, data->mutex); + current_timestamp = data->timestamp; + } + mutexunlock(data->mutex); + return; +} + +uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel) +{ + ShmTDIQChannelData *data = channel->data; + return data->timestamp; +} + +bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel) +{ + return channel->data->is_connected; +} + +void shm_td_iq_channel_destroy(ShmTDIQChannel *channel) +{ + ShmTDIQChannelData *data = channel->data; + size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_tx; + size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_rx; + size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size; + munmap(data, total_size); + if (channel->type == IQ_CHANNEL_TYPE_SERVER) { + shm_unlink(channel->name); + } + free(channel); +} diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.h b/common/utils/shm_iq_channel/shm_td_iq_channel.h new file mode 100644 index 0000000000..7c5a730914 --- /dev/null +++ b/common/utils/shm_iq_channel/shm_td_iq_channel.h @@ -0,0 +1,148 @@ +/* + * 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 SHM_IQ_CHANNEL_H +#define SHM_IQ_CHANNEL_H + +#include "../threadPool/pthread_utils.h" +#include +#include +#include + +#define SHM_MAGIC_NUMBER 0x12345678 + +/** + * ShmTdIqChannel is a shared memory bidirectional time domain IQ channel with a single clock + * source. The server (clock source) shall create the channel while the client should connect to + * it. + * + * To write samples, send them via a pointer passed to shm_td_iq_channel_tx. + * To read samples, receive them via a pointer passed to shm_td_iq_channel_rx. You can either wait until + * the sample are available using shm_td_iq_channel_wait or poll using shm_td_iq_channel_rx until the return + * value is not CHANNEL_ERROR_TOO_EARLY. + * To indicate that samples are ready to be read by the client, call shm_td_iq_channel_produce_samples + * (server only). + * + * The timestamps used in the API are in absolute samples from the time the client/server connection started. + */ + +typedef enum IQChannelType { IQ_CHANNEL_TYPE_SERVER, IQ_CHANNEL_TYPE_CLIENT } IQChannelType; +typedef uint32_t sample_t; +typedef enum IQChannelErrorType { + CHANNEL_NO_ERROR, + CHANNEL_ERROR_TOO_LATE, + CHANNEL_ERROR_TOO_EARLY, + CHANNEL_ERROR_NOT_CONNECTED +} IQChannelErrorType; + +typedef struct ShmTDIQChannel_s ShmTDIQChannel; + +/** + * @brief Creates a shared memory IQ channel. + * + * @param name The name of the shared memory segment. + * @param num_tx_ant The number of TX antennas. + * @param num_rx_ant The number of RX antennas. + * @return A pointer to the created ShmTDIQChannel structure. + */ +ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant); + +/** + * @brief Connects to an existing shared memory IQ channel. + * + * @param name The name of the shared memory segment. + * @param timeout_in_seconds The timeout in seconds for the connection attempt. + * @return A pointer to the connected ShmTDIQChannel structure. + */ +ShmTDIQChannel *shm_td_iq_channel_connect(const char *name, int timeout_in_seconds); + +/** + * @brief Transmit data in the channel + * + * @param channel The ShmTDIQChannel structure. + * @param timestamp The timestamp for which to get the TX IQ data slot. + * @param num_samples The number of samples to write. + * @param antenna The antenna index. + * @param tx_iq_data The TX IQ data to write. + * + * @return CHANNEL_NO_ERROR if successful, error type otherwise + */ +IQChannelErrorType shm_td_iq_channel_tx(ShmTDIQChannel *channel, + uint64_t timestamp, + uint64_t num_samples, + int antenna, + const sample_t *tx_iq_data); + +/** + * @brief Receive iq data from the channel + * + * @param channel The ShmTDIQChannel structure. + * @param timestamp The timestamp for which to get the RX IQ data slot. + * @param num_samples The number of samples to read. + * @param antenna The antenna index. + * @param tx_iq_data pointer to the RX IQ data slot. + * @return CHANNEL_NO_ERROR if successful, error type otherwise + */ +IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel, + uint64_t timestamp, + uint64_t num_samples, + int antenna, + sample_t *tx_iq_data); + +/** + * @brief Advances the time in the channel by specified number of samples + * + * @param channel The ShmTDIQChannel structure. + * @param num_symbols The number of samples to produce. + */ +void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, uint64_t num_samples); + +/** + * @brief Wait until sample at the specified timestamp is available + * + * @param channel The ShmTDIQChannel structure. + */ +void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp); + +/** + * @brief Checks if the IQ channel is connected. + * + * @param channel The ShmTDIQChannel structure. + * @return True if the channel is connected, false otherwise. + */ +bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel); + +/** + * @brief Destroys the shared memory IQ channel. + * + * @param channel The ShmTDIQChannel structure. + */ +void shm_td_iq_channel_destroy(ShmTDIQChannel *channel); + +/** + * @brief Returns current sample + * + * @param channel The ShmTDIQChannel structure. + * + * @return Current time as sample count since beginning of transmission + */ +uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel); + +#endif diff --git a/common/utils/shm_iq_channel/tests/CMakeLists.txt b/common/utils/shm_iq_channel/tests/CMakeLists.txt new file mode 100644 index 0000000000..f80f9cffbc --- /dev/null +++ b/common/utils/shm_iq_channel/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_shm_td_iq_channel test_shm_td_iq_channel.c) +target_link_libraries(test_shm_td_iq_channel shm_td_iq_channel minimal_lib pthread) +add_dependencies(tests test_shm_td_iq_channel) +# Commented out due to issues with ASAN in the unit test docker container +#add_test(test_shm_td_iq_channel ./test_shm_td_iq_channel) diff --git a/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c b/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c new file mode 100644 index 0000000000..f5170b8144 --- /dev/null +++ b/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c @@ -0,0 +1,169 @@ +/* + * 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 +#include +#include +#include +#include +#include "assertions.h" + +#define SHM_CHANNEL_NAME "shm_iq_channel_test_file" +#include "shm_td_iq_channel.h" + +void server(void); +int client(void); + +enum { MODE_SERVER, MODE_CLIENT, MODE_FORK }; +int main(int argc, char *argv[]) +{ + int mode = MODE_FORK; + if (argc == 2) { + if (strcmp(argv[1], "server") == 0) { + mode = MODE_SERVER; + } else if (strcmp(argv[1], "client") == 0) { + mode = MODE_CLIENT; + } + } else if (argc > 2) { + printf("Usage: %s [server|client]\n", argv[0]); + return 1; + } + switch (mode) { + case MODE_SERVER: + server(); + break; + case MODE_CLIENT: + return client(); + break; + case MODE_FORK: { + char file[256]; + snprintf(file, sizeof(file), "/dev/shm/%s", SHM_CHANNEL_NAME); + remove(file); + int pid = fork(); + if (pid == 0) { + server(); + } else { + return client(); + } + } break; + } + + return 0; +} + +const int num_updates = 50; +const int num_samples_per_update = 30720; +void *produce_symbols(void *arg) +{ + ShmTDIQChannel *channel = (ShmTDIQChannel *)arg; + for (int i = 0; i < num_updates; i++) { + shm_td_iq_channel_produce_samples(channel, num_samples_per_update); + usleep(20000); + } + return 0; +} + +void server(void) +{ + int num_ant_tx = 1; + int num_ant_rx = 1; + ShmTDIQChannel *channel = shm_td_iq_channel_create(SHM_CHANNEL_NAME, num_ant_tx, num_ant_rx); + for (int i = 0; i < 10; i++) { + if (shm_td_iq_channel_is_connected(channel)) { + printf("Server connected\n"); + break; + } + printf("Waiting for client\n"); + sleep(1); + } + AssertFatal(shm_td_iq_channel_is_connected(channel), "Server failed to connect\n"); + + pthread_t producer_thread; + int ret = pthread_create(&producer_thread, NULL, produce_symbols, channel); + AssertFatal(ret == 0, "pthread_create() failed: errno %d, %s\n", errno, strerror(errno)); + + uint64_t timestamp = 0; + int iq_contents = 0; + while (timestamp < num_samples_per_update * num_updates) { + shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update); + uint64_t target_timestamp = timestamp + num_samples_per_update; + timestamp += num_samples_per_update; + uint32_t iq_data[num_samples_per_update]; + for (int i = 0; i < num_samples_per_update; i++) { + iq_data[i] = iq_contents; + } + int result = shm_td_iq_channel_tx(channel, target_timestamp, num_samples_per_update, 0, iq_data); + AssertFatal(result == CHANNEL_NO_ERROR, "Failed to write data\n"); + iq_contents++; + } + + printf("Finished writing data\n"); + + ret = pthread_join(producer_thread, NULL); + AssertFatal(ret == 0, "pthread_join() failed: errno %d, %s\n", errno, strerror(errno)); + shm_td_iq_channel_destroy(channel); +} + +int client(void) +{ + int total_errors = 0; + ShmTDIQChannel *channel = shm_td_iq_channel_connect(SHM_CHANNEL_NAME, 10); + for (int i = 0; i < 10; i++) { + if (shm_td_iq_channel_is_connected(channel)) { + printf("Client connected\n"); + break; + } + printf("Waiting for server\n"); + sleep(1); + } + AssertFatal(shm_td_iq_channel_is_connected(channel), "Client failed to connect\n"); + + uint64_t timestamp = 0; + int iq_contents = 0; + + while (timestamp < num_samples_per_update * num_updates) { + shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update); + // Server starts producing from second slot + if (timestamp > num_samples_per_update) { + uint64_t target_timestamp = timestamp - num_samples_per_update; + uint32_t iq_data[num_samples_per_update]; + int result = shm_td_iq_channel_rx(channel, target_timestamp, num_samples_per_update, 0, iq_data); + AssertFatal(result == CHANNEL_NO_ERROR, "Failed to read data\n"); + int num_errors = 0; + for (int i = 0; i < num_samples_per_update; i++) { + if (iq_data[i] != iq_contents) { + num_errors++; + } + } + if (num_errors) { + printf("Found %d errors, value = %d, reference = %d\n", num_errors, iq_data[0], iq_contents); + total_errors += num_errors; + } + iq_contents++; + } + timestamp += num_samples_per_update; + } + + printf("Finished reading data\n"); + shm_td_iq_channel_destroy(channel); + return total_errors; +} From 1a69a4efe1d00bde29eb30018d5e03d93a47bbf8 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 11 Feb 2025 12:14:34 +0100 Subject: [PATCH 11/55] Shared memory realtime radio simulation Realtime and near-realtime RFSimulator alternative without channel modelling. The purpose of this library is to allow realtime simulation of gNB and nrUE. The library is loaded using --device.name shm_radio. The server side (gNB) should also configure --shm_radio.role server and --shm_radio.timescale according to requirements. Limitations: - Only 1UE-to-1gNB connection supported Future work: - Channel modelling - Telnet API - Histogram of the TX time budget --- doc/README.md | 1 + radio/CMakeLists.txt | 5 + radio/shm_radio/CMakeLists.txt | 4 + radio/shm_radio/README.md | 19 +++ radio/shm_radio/shm_radio.c | 240 +++++++++++++++++++++++++++++++++ 5 files changed, 269 insertions(+) create mode 100644 radio/shm_radio/CMakeLists.txt create mode 100644 radio/shm_radio/README.md create mode 100644 radio/shm_radio/shm_radio.c diff --git a/doc/README.md b/doc/README.md index 4786458a66..30e0116abf 100644 --- a/doc/README.md +++ b/doc/README.md @@ -118,6 +118,7 @@ Some directories under `radio` contain READMEs: - [BladeRF](../radio/BLADERF/README) - [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md) - [fhi_72](../radio/fhi_72/README.md) +- [shm_radio](../radio/shm_radio/README.md) The other SDRs (AW2S, LimeSDR, ...) have no READMEs. diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt index fb9086e2eb..a2da0ac616 100644 --- a/radio/CMakeLists.txt +++ b/radio/CMakeLists.txt @@ -37,3 +37,8 @@ add_boolean_option(OAI_USRP OFF "Activate OAI's USRP driver" OFF) if(OAI_USRP) add_subdirectory(USRP) endif() + +add_boolean_option(OAI_SHM_RADIO ON "Activate OAI's shared memory radio driver" OFF) +if(OAI_SHM_RADIO) + add_subdirectory(shm_radio) +endif() diff --git a/radio/shm_radio/CMakeLists.txt b/radio/shm_radio/CMakeLists.txt new file mode 100644 index 0000000000..dcaf3b6e1d --- /dev/null +++ b/radio/shm_radio/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(shm_radio MODULE shm_radio.c) +set_target_properties(shm_radio PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(shm_radio PRIVATE shm_td_iq_channel) +add_dependencies(shm_radio generate_T) diff --git a/radio/shm_radio/README.md b/radio/shm_radio/README.md new file mode 100644 index 0000000000..6d66878110 --- /dev/null +++ b/radio/shm_radio/README.md @@ -0,0 +1,19 @@ +# Overview + +This implements a shared memory realtime and near-realtime radio interface. +This is performed using `shm_td_iq_channel` which handles the shared memory +interface. + +# Limitations + + - Only 1gNB to 1nrUE + - Only 1rx and 1tx antennas + - No channel modelling + +# Usage + +On the UE and gNB: use `device.name shm_radio` command line argument. + +Additionally on gNB use `shm_radio.role server` and optionally +`shm_radio.timescale ` to set the timescale. Timescale 1.0 +is the default and means realtime. diff --git a/radio/shm_radio/shm_radio.c b/radio/shm_radio/shm_radio.c new file mode 100644 index 0000000000..9962a996f7 --- /dev/null +++ b/radio/shm_radio/shm_radio.c @@ -0,0 +1,240 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "common_lib.h" +#include "shm_td_iq_channel.h" + +// Simulator role +typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; + +#define ROLE_CLIENT_STRING "client" +#define ROLE_SERVER_STRING "server" + +#define SHM_RADIO_SECTION "shm_radio" +#define TIME_SCALE_HLP \ + "sample time scale. 1.0 means realtime. Values > 1 mean faster than realtime. Values < 1 mean slower than realtime\n" + +// clang-format off +#define SHM_RADIO_PARAMS_DESC \ + { \ + {"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "shm_radio_channel", TYPE_STRING, 0}, \ + {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \ + {"timescale", TIME_SCALE_HLP, 0, .dblptr = &shm_radio_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \ + }; +// clang-format on + +typedef struct { + int role; + char channel_name[40]; + ShmTDIQChannel *channel; + uint64_t last_received_sample; + pthread_t timing_thread; + bool run_timing_thread; + double timescale; + double sample_rate; + uint64_t tx_samples_late; + uint64_t tx_early; + uint64_t tx_samples_total; + uint64_t rx_samples_late; + uint64_t rx_early; + uint64_t rx_samples_total; + double average_tx_budget; +} shm_radio_state_t; + +static void shm_radio_readconfig(shm_radio_state_t *shm_radio_state) +{ + char *channel_name = NULL; + char *role = NULL; + paramdef_t shm_radio_params[] = SHM_RADIO_PARAMS_DESC; + int ret = config_get(config_get_if(), shm_radio_params, sizeofArray(shm_radio_params), SHM_RADIO_SECTION); + AssertFatal(ret >= 0, "configuration couldn't be performed\n"); + strncpy(shm_radio_state->channel_name, channel_name, sizeof(shm_radio_state->channel_name) - 1); + if (strncmp(role, ROLE_CLIENT_STRING, strlen(ROLE_CLIENT_STRING)) == 0) { + shm_radio_state->role = ROLE_CLIENT; + } else if (strncmp(role, ROLE_SERVER_STRING, strlen(ROLE_SERVER_STRING)) == 0) { + shm_radio_state->role = ROLE_SERVER; + } else { + AssertFatal(false, "Invalid role configuration\n"); + } +} + +static void *shm_radio_timing_job(void *arg) +{ + shm_radio_state_t *shm_radio_state = arg; + struct timespec timestamp; + if (clock_gettime(CLOCK_REALTIME, ×tamp)) { + LOG_E(UTIL, "clock_gettime failed\n"); + exit(1); + } + double leftover_samples = 0; + while (shm_radio_state->run_timing_thread) { + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(UTIL, "clock_gettime failed\n"); + exit(1); + } + uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec); + timestamp = current_time; + double samples_to_produce = shm_radio_state->sample_rate * shm_radio_state->timescale * diff / 1e9; + + // Attempt to correct compounding rounding error + leftover_samples += samples_to_produce - (uint64_t)samples_to_produce; + if (leftover_samples > 1.0f) { + samples_to_produce += 1; + leftover_samples -= 1; + } + shm_td_iq_channel_produce_samples(shm_radio_state->channel, samples_to_produce); + usleep(1); + } + return 0; +} + +static int shm_radio_connect(openair0_device *device) +{ + shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + if (shm_radio_state->role == ROLE_SERVER) { + shm_radio_state->channel = shm_td_iq_channel_create(shm_radio_state->channel_name, 1, 1); + shm_radio_state->run_timing_thread = true; + while (!shm_td_iq_channel_is_connected(shm_radio_state->channel)) { + LOG_I(HW, "Waiting for client\n"); + sleep(1); + } + int ret = pthread_create(&shm_radio_state->timing_thread, NULL, shm_radio_timing_job, shm_radio_state); + AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); + } else { + shm_radio_state->channel = shm_td_iq_channel_connect(shm_radio_state->channel_name, 10); + } + return 0; +} + +static int shm_radio_write(openair0_device *device, + openair0_timestamp timestamp, + void **samplesVoid, + int nsamps, + int nbAnt, + int flags) +{ + timestamp -= device->openair0_cfg->command_line_sample_advance; + shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + uint64_t sample = shm_td_iq_channel_get_current_sample(shm_radio_state->channel); + int64_t diff = timestamp - sample; + double budget = diff / (shm_radio_state->sample_rate / 1e6); + shm_radio_state->average_tx_budget = .05 * budget + .95 * shm_radio_state->average_tx_budget; + + int ret = shm_td_iq_channel_tx(shm_radio_state->channel, timestamp, nsamps, 0, samplesVoid[0]); + if (ret == CHANNEL_ERROR_TOO_LATE) { + shm_radio_state->tx_samples_late += nsamps; + } else if (ret == CHANNEL_ERROR_TOO_EARLY) { + shm_radio_state->tx_early += 1; + } + shm_radio_state->tx_samples_total += nsamps; + return nsamps; +} + +static int shm_radio_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) +{ + shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + shm_td_iq_channel_wait(shm_radio_state->channel, shm_radio_state->last_received_sample + nsamps); + int ret = shm_td_iq_channel_rx(shm_radio_state->channel, shm_radio_state->last_received_sample, nsamps, 0, samplesVoid[0]); + if (ret == CHANNEL_ERROR_TOO_LATE) { + shm_radio_state->rx_samples_late += nsamps; + } else if (ret == CHANNEL_ERROR_TOO_EARLY) { + shm_radio_state->rx_early += 1; + } + shm_radio_state->rx_samples_total += nsamps; + *ptimestamp = shm_radio_state->last_received_sample; + shm_radio_state->last_received_sample += nsamps; + return nsamps; +} + +static void shm_radio_end(openair0_device *device) +{ + shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + if (shm_radio_state->role == ROLE_SERVER) { + shm_radio_state->run_timing_thread = false; + int ret = pthread_join(shm_radio_state->timing_thread, NULL); + AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno)); + } + LOG_I(HW, + "SHM_RADIO: Realtime issues: TX %.2f%%, RX %.2f%%\n", + shm_radio_state->tx_samples_late / (float)shm_radio_state->tx_samples_total * 100, + shm_radio_state->rx_samples_late / (float)shm_radio_state->rx_samples_total * 100); + LOG_I(HW, + "SHM_RADIO: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n", + shm_radio_state->tx_early, + shm_radio_state->rx_early); + LOG_I(HW, "SHM_RADIO: Average TX budget %.3lf uS\n", shm_radio_state->average_tx_budget); + shm_td_iq_channel_destroy(shm_radio_state->channel); +} + +static int shm_radio_stub(openair0_device *device) +{ + return 0; +} +static int shm_radio_stub2(openair0_device *device, openair0_config_t *openair0_cfg) +{ + return 0; +} + +__attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) +{ + shm_radio_state_t *shm_radio_state = calloc(1, sizeof(shm_radio_state_t)); + shm_radio_readconfig(shm_radio_state); + LOG_I(HW, + "Running as %s\n", + shm_radio_state->role == ROLE_SERVER ? "server: waiting for client to connect" + : "client: will connect to a shm_radio server"); + device->trx_start_func = shm_radio_connect; + device->trx_reset_stats_func = shm_radio_stub; + device->trx_end_func = shm_radio_end; + device->trx_stop_func = shm_radio_stub; + device->trx_set_freq_func = shm_radio_stub2; + device->trx_set_gains_func = shm_radio_stub2; + device->trx_write_func = shm_radio_write; + device->trx_read_func = shm_radio_read; + + device->type = RFSIMULATOR; + device->openair0_cfg = &openair0_cfg[0]; + device->priv = shm_radio_state; + device->trx_write_init = shm_radio_stub; + shm_radio_state->last_received_sample = 0; + shm_radio_state->sample_rate = openair0_cfg->sample_rate; + return 0; +} From 551279119000c7b0b17459aa1cc7649e731bcf0e Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 27 Feb 2025 08:38:13 +0100 Subject: [PATCH 12/55] Add histogram for time budget printed at the exit of shm_radio --- radio/shm_radio/shm_radio.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/radio/shm_radio/shm_radio.c b/radio/shm_radio/shm_radio.c index 9962a996f7..6bb2c9b364 100644 --- a/radio/shm_radio/shm_radio.c +++ b/radio/shm_radio/shm_radio.c @@ -60,6 +60,13 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; }; // clang-format on +typedef struct histogram_s { + uint64_t diff[30]; + int num_samples; + int min_samples; + double range; +} histogram_t; + typedef struct { int role; char channel_name[40]; @@ -76,8 +83,29 @@ typedef struct { uint64_t rx_early; uint64_t rx_samples_total; double average_tx_budget; + histogram_t tx_histogram; } shm_radio_state_t; +static void histogram_add(histogram_t *histogram, double diff) +{ + histogram->num_samples++; + if (histogram->num_samples >= histogram->min_samples) { + int bin = min(sizeofArray(histogram->diff) - 1, max(0, (int)(diff / histogram->range * sizeofArray(histogram->diff)))); + histogram->diff[bin]++; + } +} + +static void histogram_print(histogram_t *histogram) +{ + LOG_I(HW, "SHM_RADIO: TX budget histogram: %d samples\n", histogram->num_samples); + float bin_size = histogram->range / sizeofArray(histogram->diff); + float bin_start = 0; + for (int i = 0; i < sizeofArray(histogram->diff); i++) { + LOG_I(HW, "Bin %d\t[%.1f - %.1fuS]:\t\t%lu\n", i, bin_start, bin_start + bin_size, histogram->diff[i]); + bin_start += bin_size; + } +} + static void shm_radio_readconfig(shm_radio_state_t *shm_radio_state) { char *channel_name = NULL; @@ -157,6 +185,7 @@ static int shm_radio_write(openair0_device *device, int64_t diff = timestamp - sample; double budget = diff / (shm_radio_state->sample_rate / 1e6); shm_radio_state->average_tx_budget = .05 * budget + .95 * shm_radio_state->average_tx_budget; + histogram_add(&shm_radio_state->tx_histogram, budget); int ret = shm_td_iq_channel_tx(shm_radio_state->channel, timestamp, nsamps, 0, samplesVoid[0]); if (ret == CHANNEL_ERROR_TOO_LATE) { @@ -201,6 +230,7 @@ static void shm_radio_end(openair0_device *device) shm_radio_state->tx_early, shm_radio_state->rx_early); LOG_I(HW, "SHM_RADIO: Average TX budget %.3lf uS\n", shm_radio_state->average_tx_budget); + histogram_print(&shm_radio_state->tx_histogram); shm_td_iq_channel_destroy(shm_radio_state->channel); } @@ -236,5 +266,8 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi device->trx_write_init = shm_radio_stub; shm_radio_state->last_received_sample = 0; shm_radio_state->sample_rate = openair0_cfg->sample_rate; + shm_radio_state->tx_histogram.min_samples = 100; + // Set the histogram range to 3000uS. Anything above that is not interesting + shm_radio_state->tx_histogram.range = 3000.0; return 0; } From 4b61f14064bd8fbd1191b3281e839b045ed74dde Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 5 Mar 2025 13:36:35 +0100 Subject: [PATCH 13/55] shm_radio: Exchange information between peers This allows to exchange the number of antennas between client and server. This is necessary for channel modelling later. --- radio/shm_radio/shm_radio.c | 116 +++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/radio/shm_radio/shm_radio.c b/radio/shm_radio/shm_radio.c index 6bb2c9b364..c8779fc8a3 100644 --- a/radio/shm_radio/shm_radio.c +++ b/radio/shm_radio/shm_radio.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -67,6 +69,11 @@ typedef struct histogram_s { double range; } histogram_t; +// Information about the peer +typedef struct peer_info_s { + int num_rx_antennas; +} peer_info_t; + typedef struct { int role; char channel_name[40]; @@ -84,6 +91,7 @@ typedef struct { uint64_t rx_samples_total; double average_tx_budget; histogram_t tx_histogram; + peer_info_t peer_info; } shm_radio_state_t; static void histogram_add(histogram_t *histogram, double diff) @@ -154,11 +162,116 @@ static void *shm_radio_timing_job(void *arg) return 0; } +/** + * @brief Exchanges peer information between the server and the client. + * + * This function sets up a Unix domain socket server, waits for a client to connect, + * and exchanges peer information (number of RX antennas) with the client. + * + * @param peer_info The peer information to send to the client. + * @return The peer information received from the client. + * + * @note This function will block until a client connects and the information is exchanged. + */ +static peer_info_t server_exchange_peer_info(peer_info_t peer_info) +{ + int server_fd, client_fd; + struct sockaddr_un addr; + socklen_t addr_len = sizeof(addr); + + // Create a Unix domain socket + server_fd = socket(AF_UNIX, SOCK_STREAM, 0); + AssertFatal(server_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Bind the socket to a file path + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/tmp/shm_radio_socket", sizeof(addr.sun_path) - 1); + unlink(addr.sun_path); // Ensure the path does not already exist + int ret = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)); + AssertFatal(ret == 0, "bind() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Listen for incoming connections + ret = listen(server_fd, 1); + AssertFatal(ret == 0, "listen() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Accept a connection from a client + client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + AssertFatal(client_fd >= 0, "accept() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Send the antenna info to the server + ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0); + AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno)); + + ssize_t bytes_received = recv(client_fd, &peer_info, sizeof(peer_info), 0); + AssertFatal(bytes_received == sizeof(peer_info), "recv() failed: errno: %d, %s\n", errno, strerror(errno)); + + LOG_I(HW, "Received client info: RX %d\n", peer_info.num_rx_antennas); + + // Close the client and server sockets + close(client_fd); + close(server_fd); + return peer_info; +} + +/** + * @brief Exchanges peer information between the client and the server. + * + * This function connects to a Unix domain socket server, exchanges peer information + * (number of RX antennas) with the server, and returns the peer information received + * from the server. + * + * @param peer_info The peer information to send to the server. + * @return The peer information received from the server. + * + * @note This function will block until the information is exchanged. + */ +static peer_info_t client_exchange_peer_info(peer_info_t peer_info) +{ + int client_fd; + struct sockaddr_un addr; + + // Create a Unix domain socket + client_fd = socket(AF_UNIX, SOCK_STREAM, 0); + AssertFatal(client_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Connect to the server + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, "/tmp/shm_radio_socket", sizeof(addr.sun_path) - 1); + int ret = -1; + int tries = 0; + while (ret != 0 && tries < 10) { + ret = connect(client_fd, (struct sockaddr *)&addr, sizeof(addr)); + tries++; + sleep(1); + } + AssertFatal(ret == 0, "connect() failed: errno: %d, %s\n", errno, strerror(errno)); + + peer_info_t peer_info_received; + ssize_t bytes_received = recv(client_fd, &peer_info_received, sizeof(peer_info_received), 0); + AssertFatal(bytes_received == sizeof(peer_info_received), "recv() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Send the antenna info to the server + ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0); + AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno)); + + LOG_I(HW, "Received peer info: RX %d\n", peer_info_received.num_rx_antennas); + + // Close the client socket + close(client_fd); + return peer_info_received; +} + static int shm_radio_connect(openair0_device *device) { shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + peer_info_t peer_info = {.num_rx_antennas = device->openair0_cfg[0].rx_num_channels}; if (shm_radio_state->role == ROLE_SERVER) { - shm_radio_state->channel = shm_td_iq_channel_create(shm_radio_state->channel_name, 1, 1); + shm_radio_state->peer_info = server_exchange_peer_info(peer_info); + shm_radio_state->channel = shm_td_iq_channel_create(shm_radio_state->channel_name, + shm_radio_state->peer_info.num_rx_antennas, + device->openair0_cfg[0].rx_num_channels); shm_radio_state->run_timing_thread = true; while (!shm_td_iq_channel_is_connected(shm_radio_state->channel)) { LOG_I(HW, "Waiting for client\n"); @@ -167,6 +280,7 @@ static int shm_radio_connect(openair0_device *device) int ret = pthread_create(&shm_radio_state->timing_thread, NULL, shm_radio_timing_job, shm_radio_state); AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); } else { + shm_radio_state->peer_info = client_exchange_peer_info(peer_info); shm_radio_state->channel = shm_td_iq_channel_connect(shm_radio_state->channel_name, 10); } return 0; From c1d02c13b732767bb33dd35731e29c7a4246e720 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Mar 2025 15:44:24 +0100 Subject: [PATCH 14/55] remove f1ap from NR_L2_UE --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 842f94b7d3..defe4c6c3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1351,7 +1351,7 @@ target_link_libraries(L2_UE PRIVATE GTPV1U) target_link_libraries(L2_UE PRIVATE asn1_lte_rrc_hdrs) add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} ) -target_link_libraries(NR_L2_UE PRIVATE f1ap nr_rlc) +target_link_libraries(NR_L2_UE PRIVATE nr_rlc) target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common nr_ue_power_procedures nr_ue_ra_procedures) target_link_libraries(NR_L2_UE PRIVATE nr_nas) From 5d3708ac3ee7dec979204b3ae19f56a3d3fb9722 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 5 Mar 2025 14:48:05 +0100 Subject: [PATCH 15/55] Realtime channel emulation for shm_radio --- common/utils/actor/CMakeLists.txt | 4 +- openair1/SIMULATION/TOOLS/sim.h | 1 + radio/shm_radio/CMakeLists.txt | 4 +- radio/shm_radio/README.md | 14 +- radio/shm_radio/noise_device.c | 90 +++++++++ radio/shm_radio/noise_device.h | 31 ++++ radio/shm_radio/shm_radio.c | 292 ++++++++++++++++++++++++++---- 7 files changed, 391 insertions(+), 45 deletions(-) create mode 100644 radio/shm_radio/noise_device.c create mode 100644 radio/shm_radio/noise_device.h diff --git a/common/utils/actor/CMakeLists.txt b/common/utils/actor/CMakeLists.txt index 40057d347e..182f54651d 100644 --- a/common/utils/actor/CMakeLists.txt +++ b/common/utils/actor/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(actor actor.c) -target_include_directories(actor PUBLIC ./) -target_link_libraries(actor PUBLIC thread-pool) +# Only include header files due to issues with ODR in threadPool binaries +target_include_directories(actor PUBLIC ./ ../threadPool/) if (ENABLE_TESTS) add_subdirectory(tests) endif() diff --git a/openair1/SIMULATION/TOOLS/sim.h b/openair1/SIMULATION/TOOLS/sim.h index d6b20a9eb9..34cae4ba55 100644 --- a/openair1/SIMULATION/TOOLS/sim.h +++ b/openair1/SIMULATION/TOOLS/sim.h @@ -50,6 +50,7 @@ typedef enum { #define CHANMODEL_FREE_RSQRT_6 1<<1 #define CHANMODEL_FREE_RSQRT_NTAPS 1<<2 #define CHANMODEL_FREE_AMPS 1<<3 +#define SHR3 (jz = jsr, jsr ^= (jsr << 13), jsr ^= (jsr >> 17), jsr ^= (jsr << 5), jz + jsr) typedef enum { CORR_LEVEL_LOW, diff --git a/radio/shm_radio/CMakeLists.txt b/radio/shm_radio/CMakeLists.txt index dcaf3b6e1d..24f61cbd01 100644 --- a/radio/shm_radio/CMakeLists.txt +++ b/radio/shm_radio/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(shm_radio MODULE shm_radio.c) +add_library(shm_radio MODULE shm_radio.c noise_device.c) set_target_properties(shm_radio PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(shm_radio PRIVATE shm_td_iq_channel) +target_link_libraries(shm_radio PRIVATE SIMU shm_td_iq_channel actor) add_dependencies(shm_radio generate_T) diff --git a/radio/shm_radio/README.md b/radio/shm_radio/README.md index 6d66878110..fbe44c97bf 100644 --- a/radio/shm_radio/README.md +++ b/radio/shm_radio/README.md @@ -2,13 +2,14 @@ This implements a shared memory realtime and near-realtime radio interface. This is performed using `shm_td_iq_channel` which handles the shared memory -interface. +interface. # Limitations - - Only 1gNB to 1nrUE - - Only 1rx and 1tx antennas - - No channel modelling + - Only 1gNB to 1nrUE: gNB as a server, UE as a client. + - Server only accepts connections during device bringup. This means that + restarting the client will not make it reconnect, the server has to be + restarted as well. # Usage @@ -17,3 +18,8 @@ On the UE and gNB: use `device.name shm_radio` command line argument. Additionally on gNB use `shm_radio.role server` and optionally `shm_radio.timescale ` to set the timescale. Timescale 1.0 is the default and means realtime. + +Channel modelling can be enabled by adding `shm_radio.chanmod 1` to the +command line and should work the same as channel modelling in rfsimulator, +see rfsimulator [documentation](../rfsimulator/README.md), provided that your +CPU is fast enough. diff --git a/radio/shm_radio/noise_device.c b/radio/shm_radio/noise_device.c new file mode 100644 index 0000000000..2e15944d4a --- /dev/null +++ b/radio/shm_radio/noise_device.c @@ -0,0 +1,90 @@ +/* + * 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 +#include "noise_device.h" + +// Use block size equal to cache size +#define BLOCK_SIZE (64 / sizeof(float)) // 4 bytes per float +// Use a power of 2 for block size length +#define NUM_BLOCKS (8192) +#define NOISE_VECTOR_LENGTH (BLOCK_SIZE * NUM_BLOCKS) + +static struct { + pthread_t noise_device_thread; + float noise[NOISE_VECTOR_LENGTH] __attribute__((aligned(64))); + float noise_power; + bool running; +} state; + +static uint32_t jz, jsr = 123456789; +static uint32_t random_uint(void) +{ + return SHR3; +} + +static void generate_one_block_noise(int write_block_index, float noise_power) +{ + // Generate noise vector + float block[BLOCK_SIZE]; + for (int i = 0; i < BLOCK_SIZE; i++) { + block[i] = noise_power * gaussZiggurat(0, 1); + } + // Write block to noise vector + memcpy(state.noise + write_block_index * BLOCK_SIZE, block, sizeof(block)); +} + +void *noise_device_thread_function(void *arg) +{ + while (state.running) { + // Generate noise vector + generate_one_block_noise(random_uint() % NUM_BLOCKS, state.noise_power); + usleep(10000); + } + return NULL; +} + +void init_noise_device(float noise_power) +{ + for (int i = 0; i < NUM_BLOCKS; i++) { + generate_one_block_noise(i, noise_power); + } + int ret = pthread_create(&state.noise_device_thread, NULL, noise_device_thread_function, NULL); + AssertFatal(ret == 0, "pthread_create failed: %d, errno %d (%s)\n", ret, errno, strerror(errno)); +} + +void free_noise_device(void) +{ + state.running = false; + pthread_join(state.noise_device_thread, NULL); +} + +void get_noise_vector(float *noise_vector, int length) +{ + int start_block = random_uint() % NUM_BLOCKS; + while (length > 0) { + int copy_size = min(length, (NUM_BLOCKS - start_block) * BLOCK_SIZE); + memcpy(noise_vector, &state.noise[start_block * BLOCK_SIZE], copy_size * sizeof(float)); + start_block = 0; + length -= copy_size; + noise_vector += copy_size; + } +} diff --git a/radio/shm_radio/noise_device.h b/radio/shm_radio/noise_device.h new file mode 100644 index 0000000000..421723891a --- /dev/null +++ b/radio/shm_radio/noise_device.h @@ -0,0 +1,31 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef NOISE_DEVICE_H +#define NOISE_DEVICE_H + +#include "SIMULATION/TOOLS/sim.h" + +void init_noise_device(float noise_power); +void free_noise_device(void); +void get_noise_vector(float *noise_vector, int length); + +#endif diff --git a/radio/shm_radio/shm_radio.c b/radio/shm_radio/shm_radio.c index c8779fc8a3..6dfa1179ee 100644 --- a/radio/shm_radio/shm_radio.c +++ b/radio/shm_radio/shm_radio.c @@ -42,10 +42,16 @@ #include #include "common_lib.h" #include "shm_td_iq_channel.h" +#include "SIMULATION/TOOLS/sim.h" +#include "actor.h" +#include "noise_device.h" +#include "simde/x86/avx512.h" // Simulator role typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; +#define NUM_CHANMOD_THREADS 1 + #define ROLE_CLIENT_STRING "client" #define ROLE_SERVER_STRING "server" @@ -59,6 +65,7 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; {"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "shm_radio_channel", TYPE_STRING, 0}, \ {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \ {"timescale", TIME_SCALE_HLP, 0, .dblptr = &shm_radio_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \ + {"chanmod", "Enable channel modelling", 0, .iptr = &shm_radio_state->chanmod, .defintval = 0, TYPE_INT, 0}, \ }; // clang-format on @@ -74,6 +81,14 @@ typedef struct peer_info_s { int num_rx_antennas; } peer_info_t; +typedef struct tx_timing_s { + uint64_t tx_samples_late; + uint64_t tx_early; + uint64_t tx_samples_total; + double average_tx_budget; + histogram_t tx_histogram; +} tx_timing_t; + typedef struct { int role; char channel_name[40]; @@ -83,15 +98,18 @@ typedef struct { bool run_timing_thread; double timescale; double sample_rate; - uint64_t tx_samples_late; - uint64_t tx_early; - uint64_t tx_samples_total; uint64_t rx_samples_late; uint64_t rx_early; uint64_t rx_samples_total; - double average_tx_budget; - histogram_t tx_histogram; + tx_timing_t *tx_timing; peer_info_t peer_info; + int chanmod; + double rx_freq; + double tx_bw; + int tx_num_channels; + int rx_num_channels; + channel_desc_t *channel_desc; + Actor_t *channel_modelling_actors; } shm_radio_state_t; static void histogram_add(histogram_t *histogram, double diff) @@ -114,6 +132,27 @@ static void histogram_print(histogram_t *histogram) } } +static void histogram_merge(histogram_t *dest, histogram_t *src) +{ + for (int i = 0; i < sizeofArray(dest->diff); i++) { + dest->diff[i] += src->diff[i]; + } + dest->num_samples += src->num_samples; +} + +static void load_channel_model(shm_radio_state_t *shm_radio_state) +{ + load_channellist(shm_radio_state->tx_num_channels, + shm_radio_state->peer_info.num_rx_antennas, + shm_radio_state->sample_rate, + shm_radio_state->rx_freq, + shm_radio_state->tx_bw); + char *model_name = shm_radio_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model"; + shm_radio_state->channel_desc = find_channel_desc_fromname(model_name); + random_channel(shm_radio_state->channel_desc, 0); + AssertFatal(shm_radio_state->channel_desc != NULL, "Could not find channel model %s\n", model_name); +} + static void shm_radio_readconfig(shm_radio_state_t *shm_radio_state) { char *channel_name = NULL; @@ -176,16 +215,13 @@ static void *shm_radio_timing_job(void *arg) static peer_info_t server_exchange_peer_info(peer_info_t peer_info) { int server_fd, client_fd; - struct sockaddr_un addr; - socklen_t addr_len = sizeof(addr); // Create a Unix domain socket server_fd = socket(AF_UNIX, SOCK_STREAM, 0); AssertFatal(server_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno)); // Bind the socket to a file path - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; + struct sockaddr_un addr = {.sun_family = AF_UNIX}; strncpy(addr.sun_path, "/tmp/shm_radio_socket", sizeof(addr.sun_path) - 1); unlink(addr.sun_path); // Ensure the path does not already exist int ret = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)); @@ -196,6 +232,7 @@ static peer_info_t server_exchange_peer_info(peer_info_t peer_info) AssertFatal(ret == 0, "listen() failed: errno: %d, %s\n", errno, strerror(errno)); // Accept a connection from a client + socklen_t addr_len = sizeof(addr); client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); AssertFatal(client_fd >= 0, "accept() failed: errno: %d, %s\n", errno, strerror(errno)); @@ -229,15 +266,13 @@ static peer_info_t server_exchange_peer_info(peer_info_t peer_info) static peer_info_t client_exchange_peer_info(peer_info_t peer_info) { int client_fd; - struct sockaddr_un addr; // Create a Unix domain socket client_fd = socket(AF_UNIX, SOCK_STREAM, 0); AssertFatal(client_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno)); // Connect to the server - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; + struct sockaddr_un addr = {.sun_family = AF_UNIX}; strncpy(addr.sun_path, "/tmp/shm_radio_socket", sizeof(addr.sun_path) - 1); int ret = -1; int tries = 0; @@ -266,9 +301,33 @@ static peer_info_t client_exchange_peer_info(peer_info_t peer_info) static int shm_radio_connect(openair0_device *device) { shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + // Exchange peer info peer_info_t peer_info = {.num_rx_antennas = device->openair0_cfg[0].rx_num_channels}; if (shm_radio_state->role == ROLE_SERVER) { shm_radio_state->peer_info = server_exchange_peer_info(peer_info); + } else { + shm_radio_state->peer_info = client_exchange_peer_info(peer_info); + } + + // Handle channel modelling after number of RX antennas are known + int num_tx_stats = 1; + if (shm_radio_state->chanmod) { + shm_radio_state->channel_modelling_actors = calloc_or_fail(shm_radio_state->peer_info.num_rx_antennas, sizeof(Actor_t)); + for (int i = 0; i < shm_radio_state->peer_info.num_rx_antennas; i++) { + init_actor(&shm_radio_state->channel_modelling_actors[i], "chanmod", -1); + } + load_channel_model(shm_radio_state); + num_tx_stats = shm_radio_state->peer_info.num_rx_antennas; + } + shm_radio_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t)); + for (int i = 0; i < num_tx_stats; i++) { + shm_radio_state->tx_timing[i].tx_histogram.min_samples = 100; + // Set the histogram range to 3000uS. Anything above that is not interesting + shm_radio_state->tx_timing[i].tx_histogram.range = 3000.0; + } + + // Setup a shared memory channel + if (shm_radio_state->role == ROLE_SERVER) { shm_radio_state->channel = shm_td_iq_channel_create(shm_radio_state->channel_name, shm_radio_state->peer_info.num_rx_antennas, device->openair0_cfg[0].rx_num_channels); @@ -280,12 +339,146 @@ static int shm_radio_connect(openair0_device *device) int ret = pthread_create(&shm_radio_state->timing_thread, NULL, shm_radio_timing_job, shm_radio_state); AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); } else { - shm_radio_state->peer_info = client_exchange_peer_info(peer_info); shm_radio_state->channel = shm_td_iq_channel_connect(shm_radio_state->channel_name, 10); } + return 0; } +static int shm_radio_write_internal(shm_radio_state_t *shm_radio_state, + openair0_timestamp timestamp, + c16_t *samples, + int nsamps, + int aarx, + int flags, + int stats_index) +{ + tx_timing_t *tx_timing = &shm_radio_state->tx_timing[stats_index]; + + uint64_t sample = shm_td_iq_channel_get_current_sample(shm_radio_state->channel); + int64_t diff = timestamp - sample; + double budget = diff / (shm_radio_state->sample_rate / 1e6); + tx_timing->average_tx_budget = .05 * budget + .95 * tx_timing->average_tx_budget; + histogram_add(&tx_timing->tx_histogram, budget); + + int ret = shm_td_iq_channel_tx(shm_radio_state->channel, timestamp, nsamps, aarx, (sample_t *)samples); + + if (ret == CHANNEL_ERROR_TOO_LATE) { + tx_timing->tx_samples_late += nsamps; + } else if (ret == CHANNEL_ERROR_TOO_EARLY) { + tx_timing->tx_early += 1; + } + tx_timing->tx_samples_total += nsamps; + + return nsamps; +} + +typedef struct { + shm_radio_state_t *shm_radio_state; + openair0_timestamp timestamp; + c16_t *samples[4]; + int nsamps; + int nbAnt; + int flags; + int aarx; +} channel_modelling_args_t; + +static void perform_channel_modelling(void *arg) +{ + channel_modelling_args_t *channel_modelling_args = arg; + int nsamps = channel_modelling_args->nsamps; + int aarx = channel_modelling_args->aarx; + int nb_tx_ant = channel_modelling_args->nbAnt; + c16_t **input_samples = (c16_t **)channel_modelling_args->samples; + + int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t)); + cf_t samples[aligned_nsamps] __attribute__((aligned(64))); + // Apply noise from global settings + get_noise_vector((float *)samples, nsamps * 2); + + channel_desc_t *channel_desc = channel_modelling_args->shm_radio_state->channel_desc; + const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0); + + // Convert channel impulse response to float + apply pathloss + cf_t channel_impulse_response[nb_tx_ant][channel_desc->channel_length]; + for (int aatx = 0; aatx < nb_tx_ant; aatx++) { + const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)]; + for (int i = 0; i < channel_desc->channel_length; i++) { + channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear; + channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear; + } + } + + for (int aatx = 0; aatx < nb_tx_ant; aatx++) { + for (int i = 0; i < nsamps; i++) { + cf_t *impulse_response = channel_impulse_response[aatx]; + for (int l = 0; l < channel_desc->channel_length; l++) { + int idx = i - l; + // TODO: Use AVX512 for this + // TODO: What are the previously sent samples (for impulse response) + if (idx >= 0) { + c16_t tx_input = input_samples[aatx][idx]; + samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i; + samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i; + } + } + } + } + + // Convert to c16_t + c16_t samples_out[aligned_nsamps] __attribute__((aligned(64))); +#if defined(__AVX512F__) + for (int i = 0; i < aligned_nsamps / 8; i++) { + simde__m512 *in = (simde__m512 *)&samples[i * 8]; + simde__m256i *out = (simde__m256i *)&samples_out[i * 8]; + *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in)); + } +#elif defined(__AVX2__) + for (int i = 0; i < aligned_nsamps / 4; i++) { + simde__m256 *in = (simde__m256 *)&samples[i * 4]; + simde__m128i *out = (simde__m128i *)&samples_out[i * 4]; + *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in)); + } +#else + for (int i = 0; i < nsamps; i++) { + samples_out[i].r = lroundf(samples[i].r); + samples_out[i].i = lroundf(samples[i].i); + } +#endif + + shm_radio_write_internal(channel_modelling_args->shm_radio_state, + channel_modelling_args->timestamp, + samples_out, + channel_modelling_args->nsamps, + aarx, + channel_modelling_args->flags, + aarx); +} + +static int shm_radio_write_with_chanmod(shm_radio_state_t *shm_radio_state, + openair0_timestamp timestamp, + void **samplesVoid, + int nsamps, + int nbAnt, + int flags) +{ + for (int aarx = 0; aarx < shm_radio_state->peer_info.num_rx_antennas; aarx++) { + notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling); + channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task); + args->shm_radio_state = shm_radio_state; + args->timestamp = timestamp; + args->nsamps = nsamps; + args->nbAnt = nbAnt; + args->flags = flags; + args->aarx = aarx; + for (int i = 0; i < nbAnt; i++) { + args->samples[i] = samplesVoid[i]; + } + pushNotifiedFIFO(&shm_radio_state->channel_modelling_actors[aarx].fifo, task); + } + return nsamps; +} + static int shm_radio_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, @@ -295,20 +488,9 @@ static int shm_radio_write(openair0_device *device, { timestamp -= device->openair0_cfg->command_line_sample_advance; shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; - uint64_t sample = shm_td_iq_channel_get_current_sample(shm_radio_state->channel); - int64_t diff = timestamp - sample; - double budget = diff / (shm_radio_state->sample_rate / 1e6); - shm_radio_state->average_tx_budget = .05 * budget + .95 * shm_radio_state->average_tx_budget; - histogram_add(&shm_radio_state->tx_histogram, budget); - - int ret = shm_td_iq_channel_tx(shm_radio_state->channel, timestamp, nsamps, 0, samplesVoid[0]); - if (ret == CHANNEL_ERROR_TOO_LATE) { - shm_radio_state->tx_samples_late += nsamps; - } else if (ret == CHANNEL_ERROR_TOO_EARLY) { - shm_radio_state->tx_early += 1; - } - shm_radio_state->tx_samples_total += nsamps; - return nsamps; + return shm_radio_state->chanmod + ? shm_radio_write_with_chanmod(shm_radio_state, timestamp, samplesVoid, nsamps, nbAnt, flags) + : shm_radio_write_internal(shm_radio_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0); } static int shm_radio_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) @@ -335,17 +517,38 @@ static void shm_radio_end(openair0_device *device) int ret = pthread_join(shm_radio_state->timing_thread, NULL); AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno)); } + + tx_timing_t *tx_timing = shm_radio_state->tx_timing; + if (shm_radio_state->chanmod) { + for (int i = 0; i < shm_radio_state->peer_info.num_rx_antennas; i++) { + shutdown_actor(&shm_radio_state->channel_modelling_actors[i]); + } + free(shm_radio_state->channel_modelling_actors); + for (int i = 1; i < shm_radio_state->peer_info.num_rx_antennas; i++) { + histogram_merge(&tx_timing->tx_histogram, &tx_timing[i].tx_histogram); + tx_timing->tx_early += tx_timing[i].tx_early; + tx_timing->tx_samples_late += tx_timing[i].tx_samples_late; + tx_timing->average_tx_budget += tx_timing[i].average_tx_budget; + tx_timing->tx_samples_total += tx_timing[i].tx_samples_total; + } + tx_timing->average_tx_budget /= shm_radio_state->peer_info.num_rx_antennas; + } + // produce 1 second of extra samples so threads can finish + shm_td_iq_channel_produce_samples(shm_radio_state->channel, shm_radio_state->sample_rate); + sleep(1); + shm_td_iq_channel_destroy(shm_radio_state->channel); + LOG_I(HW, "SHM_RADIO: Realtime issues: TX %.2f%%, RX %.2f%%\n", - shm_radio_state->tx_samples_late / (float)shm_radio_state->tx_samples_total * 100, + tx_timing->tx_samples_late / (float)tx_timing->tx_samples_total * 100, shm_radio_state->rx_samples_late / (float)shm_radio_state->rx_samples_total * 100); LOG_I(HW, "SHM_RADIO: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n", - shm_radio_state->tx_early, + tx_timing->tx_early, shm_radio_state->rx_early); - LOG_I(HW, "SHM_RADIO: Average TX budget %.3lf uS\n", shm_radio_state->average_tx_budget); - histogram_print(&shm_radio_state->tx_histogram); - shm_td_iq_channel_destroy(shm_radio_state->channel); + LOG_I(HW, "SHM_RADIO: Average TX budget %.3lf uS\n", tx_timing->average_tx_budget); + histogram_print(&tx_timing->tx_histogram); + free(shm_radio_state->tx_timing); } static int shm_radio_stub(openair0_device *device) @@ -357,9 +560,16 @@ static int shm_radio_stub2(openair0_device *device, openair0_config_t *openair0_ return 0; } +static int shm_radio_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) +{ + shm_radio_state_t *s = device->priv; + s->rx_freq = openair0_cfg->rx_freq[0]; + return 0; +} + __attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { - shm_radio_state_t *shm_radio_state = calloc(1, sizeof(shm_radio_state_t)); + shm_radio_state_t *shm_radio_state = calloc_or_fail(1, sizeof(shm_radio_state_t)); shm_radio_readconfig(shm_radio_state); LOG_I(HW, "Running as %s\n", @@ -369,7 +579,7 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi device->trx_reset_stats_func = shm_radio_stub; device->trx_end_func = shm_radio_end; device->trx_stop_func = shm_radio_stub; - device->trx_set_freq_func = shm_radio_stub2; + device->trx_set_freq_func = shm_radio_set_freq; device->trx_set_gains_func = shm_radio_stub2; device->trx_write_func = shm_radio_write; device->trx_read_func = shm_radio_read; @@ -380,8 +590,16 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi device->trx_write_init = shm_radio_stub; shm_radio_state->last_received_sample = 0; shm_radio_state->sample_rate = openair0_cfg->sample_rate; - shm_radio_state->tx_histogram.min_samples = 100; - // Set the histogram range to 3000uS. Anything above that is not interesting - shm_radio_state->tx_histogram.range = 3000.0; + shm_radio_state->rx_freq = openair0_cfg->rx_freq[0]; + shm_radio_state->tx_bw = openair0_cfg->tx_bw; + shm_radio_state->tx_num_channels = openair0_cfg->tx_num_channels; + shm_radio_state->rx_num_channels = openair0_cfg->rx_num_channels; + + if (shm_radio_state->chanmod) { + init_channelmod(); + int noise_power_dBFS = get_noise_power_dBFS(); + int16_t noise_power = noise_power_dBFS == INVALID_DBFS_VALUE ? 0 : (int16_t)(32767.0 / powf(10.0, .05 * -noise_power_dBFS)); + init_noise_device(noise_power); + } return 0; } From c5c2e8781091d3e7f832e8f785a87c949433b701 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 26 Mar 2025 15:32:59 +0100 Subject: [PATCH 16/55] Rename shm_radio to vrtsim --- doc/README.md | 2 +- radio/CMakeLists.txt | 6 +- radio/shm_radio/CMakeLists.txt | 4 - radio/vrtsim/CMakeLists.txt | 4 + radio/{shm_radio => vrtsim}/README.md | 8 +- radio/{shm_radio => vrtsim}/noise_device.c | 0 radio/{shm_radio => vrtsim}/noise_device.h | 0 .../shm_radio.c => vrtsim/vrtsim.c} | 283 +++++++++--------- 8 files changed, 150 insertions(+), 157 deletions(-) delete mode 100644 radio/shm_radio/CMakeLists.txt create mode 100644 radio/vrtsim/CMakeLists.txt rename radio/{shm_radio => vrtsim}/README.md (69%) rename radio/{shm_radio => vrtsim}/noise_device.c (100%) rename radio/{shm_radio => vrtsim}/noise_device.h (100%) rename radio/{shm_radio/shm_radio.c => vrtsim/vrtsim.c} (61%) diff --git a/doc/README.md b/doc/README.md index 30e0116abf..cee2620f95 100644 --- a/doc/README.md +++ b/doc/README.md @@ -118,7 +118,7 @@ Some directories under `radio` contain READMEs: - [BladeRF](../radio/BLADERF/README) - [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md) - [fhi_72](../radio/fhi_72/README.md) -- [shm_radio](../radio/shm_radio/README.md) +- [vrtsim](../radio/vrtsim/README.md) The other SDRs (AW2S, LimeSDR, ...) have no READMEs. diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt index a2da0ac616..654fb037f0 100644 --- a/radio/CMakeLists.txt +++ b/radio/CMakeLists.txt @@ -38,7 +38,7 @@ if(OAI_USRP) add_subdirectory(USRP) endif() -add_boolean_option(OAI_SHM_RADIO ON "Activate OAI's shared memory radio driver" OFF) -if(OAI_SHM_RADIO) - add_subdirectory(shm_radio) +add_boolean_option(VRTSIM_RADIO ON "Activate OAI's shared memory radio driver" OFF) +if(VRTSIM_RADIO) + add_subdirectory(vrtsim) endif() diff --git a/radio/shm_radio/CMakeLists.txt b/radio/shm_radio/CMakeLists.txt deleted file mode 100644 index 24f61cbd01..0000000000 --- a/radio/shm_radio/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_library(shm_radio MODULE shm_radio.c noise_device.c) -set_target_properties(shm_radio PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(shm_radio PRIVATE SIMU shm_td_iq_channel actor) -add_dependencies(shm_radio generate_T) diff --git a/radio/vrtsim/CMakeLists.txt b/radio/vrtsim/CMakeLists.txt new file mode 100644 index 0000000000..79eb4d88da --- /dev/null +++ b/radio/vrtsim/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(vrtsim MODULE vrtsim.c noise_device.c) +set_target_properties(vrtsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor) +add_dependencies(vrtsim generate_T) diff --git a/radio/shm_radio/README.md b/radio/vrtsim/README.md similarity index 69% rename from radio/shm_radio/README.md rename to radio/vrtsim/README.md index fbe44c97bf..71455175c3 100644 --- a/radio/shm_radio/README.md +++ b/radio/vrtsim/README.md @@ -13,13 +13,13 @@ interface. # Usage -On the UE and gNB: use `device.name shm_radio` command line argument. +On the UE and gNB: use `device.name vrtsim` command line argument. -Additionally on gNB use `shm_radio.role server` and optionally -`shm_radio.timescale ` to set the timescale. Timescale 1.0 +Additionally on gNB use `vrtsim.role server` and optionally +`vrtsim.timescale ` to set the timescale. Timescale 1.0 is the default and means realtime. -Channel modelling can be enabled by adding `shm_radio.chanmod 1` to the +Channel modelling can be enabled by adding `vrtsim.chanmod 1` to the command line and should work the same as channel modelling in rfsimulator, see rfsimulator [documentation](../rfsimulator/README.md), provided that your CPU is fast enough. diff --git a/radio/shm_radio/noise_device.c b/radio/vrtsim/noise_device.c similarity index 100% rename from radio/shm_radio/noise_device.c rename to radio/vrtsim/noise_device.c diff --git a/radio/shm_radio/noise_device.h b/radio/vrtsim/noise_device.h similarity index 100% rename from radio/shm_radio/noise_device.h rename to radio/vrtsim/noise_device.h diff --git a/radio/shm_radio/shm_radio.c b/radio/vrtsim/vrtsim.c similarity index 61% rename from radio/shm_radio/shm_radio.c rename to radio/vrtsim/vrtsim.c index 6dfa1179ee..f0e0151aa6 100644 --- a/radio/shm_radio/shm_radio.c +++ b/radio/vrtsim/vrtsim.c @@ -55,17 +55,17 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; #define ROLE_CLIENT_STRING "client" #define ROLE_SERVER_STRING "server" -#define SHM_RADIO_SECTION "shm_radio" +#define VRTSIM_SECTION "vrtsim" #define TIME_SCALE_HLP \ "sample time scale. 1.0 means realtime. Values > 1 mean faster than realtime. Values < 1 mean slower than realtime\n" // clang-format off -#define SHM_RADIO_PARAMS_DESC \ +#define VRTSIM_PARAMS_DESC \ { \ - {"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "shm_radio_channel", TYPE_STRING, 0}, \ + {"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "vrtsim_channel", TYPE_STRING, 0}, \ {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \ - {"timescale", TIME_SCALE_HLP, 0, .dblptr = &shm_radio_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \ - {"chanmod", "Enable channel modelling", 0, .iptr = &shm_radio_state->chanmod, .defintval = 0, TYPE_INT, 0}, \ + {"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \ + {"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \ }; // clang-format on @@ -110,7 +110,7 @@ typedef struct { int rx_num_channels; channel_desc_t *channel_desc; Actor_t *channel_modelling_actors; -} shm_radio_state_t; +} vrtsim_state_t; static void histogram_add(histogram_t *histogram, double diff) { @@ -123,7 +123,7 @@ static void histogram_add(histogram_t *histogram, double diff) static void histogram_print(histogram_t *histogram) { - LOG_I(HW, "SHM_RADIO: TX budget histogram: %d samples\n", histogram->num_samples); + LOG_I(HW, "VRTSIM: TX budget histogram: %d samples\n", histogram->num_samples); float bin_size = histogram->range / sizeofArray(histogram->diff); float bin_start = 0; for (int i = 0; i < sizeofArray(histogram->diff); i++) { @@ -140,46 +140,46 @@ static void histogram_merge(histogram_t *dest, histogram_t *src) dest->num_samples += src->num_samples; } -static void load_channel_model(shm_radio_state_t *shm_radio_state) +static void load_channel_model(vrtsim_state_t *vrtsim_state) { - load_channellist(shm_radio_state->tx_num_channels, - shm_radio_state->peer_info.num_rx_antennas, - shm_radio_state->sample_rate, - shm_radio_state->rx_freq, - shm_radio_state->tx_bw); - char *model_name = shm_radio_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model"; - shm_radio_state->channel_desc = find_channel_desc_fromname(model_name); - random_channel(shm_radio_state->channel_desc, 0); - AssertFatal(shm_radio_state->channel_desc != NULL, "Could not find channel model %s\n", model_name); + load_channellist(vrtsim_state->tx_num_channels, + vrtsim_state->peer_info.num_rx_antennas, + vrtsim_state->sample_rate, + vrtsim_state->rx_freq, + vrtsim_state->tx_bw); + char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model"; + vrtsim_state->channel_desc = find_channel_desc_fromname(model_name); + random_channel(vrtsim_state->channel_desc, 0); + AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name); } -static void shm_radio_readconfig(shm_radio_state_t *shm_radio_state) +static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state) { char *channel_name = NULL; char *role = NULL; - paramdef_t shm_radio_params[] = SHM_RADIO_PARAMS_DESC; - int ret = config_get(config_get_if(), shm_radio_params, sizeofArray(shm_radio_params), SHM_RADIO_SECTION); + paramdef_t vrtsim_params[] = VRTSIM_PARAMS_DESC; + int ret = config_get(config_get_if(), vrtsim_params, sizeofArray(vrtsim_params), VRTSIM_SECTION); AssertFatal(ret >= 0, "configuration couldn't be performed\n"); - strncpy(shm_radio_state->channel_name, channel_name, sizeof(shm_radio_state->channel_name) - 1); + strncpy(vrtsim_state->channel_name, channel_name, sizeof(vrtsim_state->channel_name) - 1); if (strncmp(role, ROLE_CLIENT_STRING, strlen(ROLE_CLIENT_STRING)) == 0) { - shm_radio_state->role = ROLE_CLIENT; + vrtsim_state->role = ROLE_CLIENT; } else if (strncmp(role, ROLE_SERVER_STRING, strlen(ROLE_SERVER_STRING)) == 0) { - shm_radio_state->role = ROLE_SERVER; + vrtsim_state->role = ROLE_SERVER; } else { AssertFatal(false, "Invalid role configuration\n"); } } -static void *shm_radio_timing_job(void *arg) +static void *vrtsim_timing_job(void *arg) { - shm_radio_state_t *shm_radio_state = arg; + vrtsim_state_t *vrtsim_state = arg; struct timespec timestamp; if (clock_gettime(CLOCK_REALTIME, ×tamp)) { LOG_E(UTIL, "clock_gettime failed\n"); exit(1); } double leftover_samples = 0; - while (shm_radio_state->run_timing_thread) { + while (vrtsim_state->run_timing_thread) { struct timespec current_time; if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { LOG_E(UTIL, "clock_gettime failed\n"); @@ -187,7 +187,7 @@ static void *shm_radio_timing_job(void *arg) } uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec); timestamp = current_time; - double samples_to_produce = shm_radio_state->sample_rate * shm_radio_state->timescale * diff / 1e9; + double samples_to_produce = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9; // Attempt to correct compounding rounding error leftover_samples += samples_to_produce - (uint64_t)samples_to_produce; @@ -195,7 +195,7 @@ static void *shm_radio_timing_job(void *arg) samples_to_produce += 1; leftover_samples -= 1; } - shm_td_iq_channel_produce_samples(shm_radio_state->channel, samples_to_produce); + shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce); usleep(1); } return 0; @@ -222,7 +222,7 @@ static peer_info_t server_exchange_peer_info(peer_info_t peer_info) // Bind the socket to a file path struct sockaddr_un addr = {.sun_family = AF_UNIX}; - strncpy(addr.sun_path, "/tmp/shm_radio_socket", sizeof(addr.sun_path) - 1); + strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1); unlink(addr.sun_path); // Ensure the path does not already exist int ret = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)); AssertFatal(ret == 0, "bind() failed: errno: %d, %s\n", errno, strerror(errno)); @@ -273,7 +273,7 @@ static peer_info_t client_exchange_peer_info(peer_info_t peer_info) // Connect to the server struct sockaddr_un addr = {.sun_family = AF_UNIX}; - strncpy(addr.sun_path, "/tmp/shm_radio_socket", sizeof(addr.sun_path) - 1); + strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1); int ret = -1; int tries = 0; while (ret != 0 && tries < 10) { @@ -298,70 +298,70 @@ static peer_info_t client_exchange_peer_info(peer_info_t peer_info) return peer_info_received; } -static int shm_radio_connect(openair0_device *device) +static int vrtsim_connect(openair0_device *device) { - shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; + vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; // Exchange peer info peer_info_t peer_info = {.num_rx_antennas = device->openair0_cfg[0].rx_num_channels}; - if (shm_radio_state->role == ROLE_SERVER) { - shm_radio_state->peer_info = server_exchange_peer_info(peer_info); + if (vrtsim_state->role == ROLE_SERVER) { + vrtsim_state->peer_info = server_exchange_peer_info(peer_info); } else { - shm_radio_state->peer_info = client_exchange_peer_info(peer_info); + vrtsim_state->peer_info = client_exchange_peer_info(peer_info); } // Handle channel modelling after number of RX antennas are known int num_tx_stats = 1; - if (shm_radio_state->chanmod) { - shm_radio_state->channel_modelling_actors = calloc_or_fail(shm_radio_state->peer_info.num_rx_antennas, sizeof(Actor_t)); - for (int i = 0; i < shm_radio_state->peer_info.num_rx_antennas; i++) { - init_actor(&shm_radio_state->channel_modelling_actors[i], "chanmod", -1); + if (vrtsim_state->chanmod) { + vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->peer_info.num_rx_antennas, sizeof(Actor_t)); + for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) { + init_actor(&vrtsim_state->channel_modelling_actors[i], "chanmod", -1); } - load_channel_model(shm_radio_state); - num_tx_stats = shm_radio_state->peer_info.num_rx_antennas; + load_channel_model(vrtsim_state); + num_tx_stats = vrtsim_state->peer_info.num_rx_antennas; } - shm_radio_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t)); + vrtsim_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t)); for (int i = 0; i < num_tx_stats; i++) { - shm_radio_state->tx_timing[i].tx_histogram.min_samples = 100; + vrtsim_state->tx_timing[i].tx_histogram.min_samples = 100; // Set the histogram range to 3000uS. Anything above that is not interesting - shm_radio_state->tx_timing[i].tx_histogram.range = 3000.0; + vrtsim_state->tx_timing[i].tx_histogram.range = 3000.0; } // Setup a shared memory channel - if (shm_radio_state->role == ROLE_SERVER) { - shm_radio_state->channel = shm_td_iq_channel_create(shm_radio_state->channel_name, - shm_radio_state->peer_info.num_rx_antennas, - device->openair0_cfg[0].rx_num_channels); - shm_radio_state->run_timing_thread = true; - while (!shm_td_iq_channel_is_connected(shm_radio_state->channel)) { + if (vrtsim_state->role == ROLE_SERVER) { + vrtsim_state->channel = shm_td_iq_channel_create(vrtsim_state->channel_name, + vrtsim_state->peer_info.num_rx_antennas, + device->openair0_cfg[0].rx_num_channels); + vrtsim_state->run_timing_thread = true; + while (!shm_td_iq_channel_is_connected(vrtsim_state->channel)) { LOG_I(HW, "Waiting for client\n"); sleep(1); } - int ret = pthread_create(&shm_radio_state->timing_thread, NULL, shm_radio_timing_job, shm_radio_state); + int ret = pthread_create(&vrtsim_state->timing_thread, NULL, vrtsim_timing_job, vrtsim_state); AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); } else { - shm_radio_state->channel = shm_td_iq_channel_connect(shm_radio_state->channel_name, 10); + vrtsim_state->channel = shm_td_iq_channel_connect(vrtsim_state->channel_name, 10); } return 0; } -static int shm_radio_write_internal(shm_radio_state_t *shm_radio_state, - openair0_timestamp timestamp, - c16_t *samples, - int nsamps, - int aarx, - int flags, - int stats_index) +static int vrtsim_write_internal(vrtsim_state_t *vrtsim_state, + openair0_timestamp timestamp, + c16_t *samples, + int nsamps, + int aarx, + int flags, + int stats_index) { - tx_timing_t *tx_timing = &shm_radio_state->tx_timing[stats_index]; + tx_timing_t *tx_timing = &vrtsim_state->tx_timing[stats_index]; - uint64_t sample = shm_td_iq_channel_get_current_sample(shm_radio_state->channel); + uint64_t sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel); int64_t diff = timestamp - sample; - double budget = diff / (shm_radio_state->sample_rate / 1e6); + double budget = diff / (vrtsim_state->sample_rate / 1e6); tx_timing->average_tx_budget = .05 * budget + .95 * tx_timing->average_tx_budget; histogram_add(&tx_timing->tx_histogram, budget); - int ret = shm_td_iq_channel_tx(shm_radio_state->channel, timestamp, nsamps, aarx, (sample_t *)samples); + int ret = shm_td_iq_channel_tx(vrtsim_state->channel, timestamp, nsamps, aarx, (sample_t *)samples); if (ret == CHANNEL_ERROR_TOO_LATE) { tx_timing->tx_samples_late += nsamps; @@ -374,7 +374,7 @@ static int shm_radio_write_internal(shm_radio_state_t *shm_radio_state, } typedef struct { - shm_radio_state_t *shm_radio_state; + vrtsim_state_t *vrtsim_state; openair0_timestamp timestamp; c16_t *samples[4]; int nsamps; @@ -396,7 +396,7 @@ static void perform_channel_modelling(void *arg) // Apply noise from global settings get_noise_vector((float *)samples, nsamps * 2); - channel_desc_t *channel_desc = channel_modelling_args->shm_radio_state->channel_desc; + channel_desc_t *channel_desc = channel_modelling_args->vrtsim_state->channel_desc; const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0); // Convert channel impulse response to float + apply pathloss @@ -446,26 +446,26 @@ static void perform_channel_modelling(void *arg) } #endif - shm_radio_write_internal(channel_modelling_args->shm_radio_state, - channel_modelling_args->timestamp, - samples_out, - channel_modelling_args->nsamps, - aarx, - channel_modelling_args->flags, - aarx); + vrtsim_write_internal(channel_modelling_args->vrtsim_state, + channel_modelling_args->timestamp, + samples_out, + channel_modelling_args->nsamps, + aarx, + channel_modelling_args->flags, + aarx); } -static int shm_radio_write_with_chanmod(shm_radio_state_t *shm_radio_state, - openair0_timestamp timestamp, - void **samplesVoid, - int nsamps, - int nbAnt, - int flags) +static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, + openair0_timestamp timestamp, + void **samplesVoid, + int nsamps, + int nbAnt, + int flags) { - for (int aarx = 0; aarx < shm_radio_state->peer_info.num_rx_antennas; aarx++) { + for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) { notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling); channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task); - args->shm_radio_state = shm_radio_state; + args->vrtsim_state = vrtsim_state; args->timestamp = timestamp; args->nsamps = nsamps; args->nbAnt = nbAnt; @@ -474,128 +474,121 @@ static int shm_radio_write_with_chanmod(shm_radio_state_t *shm_radio_state, for (int i = 0; i < nbAnt; i++) { args->samples[i] = samplesVoid[i]; } - pushNotifiedFIFO(&shm_radio_state->channel_modelling_actors[aarx].fifo, task); + pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task); } return nsamps; } -static int shm_radio_write(openair0_device *device, - openair0_timestamp timestamp, - void **samplesVoid, - int nsamps, - int nbAnt, - int flags) +static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { timestamp -= device->openair0_cfg->command_line_sample_advance; - shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; - return shm_radio_state->chanmod - ? shm_radio_write_with_chanmod(shm_radio_state, timestamp, samplesVoid, nsamps, nbAnt, flags) - : shm_radio_write_internal(shm_radio_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0); + vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; + return vrtsim_state->chanmod ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags) + : vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0); } -static int shm_radio_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) +static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) { - shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; - shm_td_iq_channel_wait(shm_radio_state->channel, shm_radio_state->last_received_sample + nsamps); - int ret = shm_td_iq_channel_rx(shm_radio_state->channel, shm_radio_state->last_received_sample, nsamps, 0, samplesVoid[0]); + vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; + shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps); + int ret = shm_td_iq_channel_rx(vrtsim_state->channel, vrtsim_state->last_received_sample, nsamps, 0, samplesVoid[0]); if (ret == CHANNEL_ERROR_TOO_LATE) { - shm_radio_state->rx_samples_late += nsamps; + vrtsim_state->rx_samples_late += nsamps; } else if (ret == CHANNEL_ERROR_TOO_EARLY) { - shm_radio_state->rx_early += 1; + vrtsim_state->rx_early += 1; } - shm_radio_state->rx_samples_total += nsamps; - *ptimestamp = shm_radio_state->last_received_sample; - shm_radio_state->last_received_sample += nsamps; + vrtsim_state->rx_samples_total += nsamps; + *ptimestamp = vrtsim_state->last_received_sample; + vrtsim_state->last_received_sample += nsamps; return nsamps; } -static void shm_radio_end(openair0_device *device) +static void vrtsim_end(openair0_device *device) { - shm_radio_state_t *shm_radio_state = (shm_radio_state_t *)device->priv; - if (shm_radio_state->role == ROLE_SERVER) { - shm_radio_state->run_timing_thread = false; - int ret = pthread_join(shm_radio_state->timing_thread, NULL); + vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; + if (vrtsim_state->role == ROLE_SERVER) { + vrtsim_state->run_timing_thread = false; + int ret = pthread_join(vrtsim_state->timing_thread, NULL); AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno)); } - tx_timing_t *tx_timing = shm_radio_state->tx_timing; - if (shm_radio_state->chanmod) { - for (int i = 0; i < shm_radio_state->peer_info.num_rx_antennas; i++) { - shutdown_actor(&shm_radio_state->channel_modelling_actors[i]); + tx_timing_t *tx_timing = vrtsim_state->tx_timing; + if (vrtsim_state->chanmod) { + for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) { + shutdown_actor(&vrtsim_state->channel_modelling_actors[i]); } - free(shm_radio_state->channel_modelling_actors); - for (int i = 1; i < shm_radio_state->peer_info.num_rx_antennas; i++) { + free(vrtsim_state->channel_modelling_actors); + for (int i = 1; i < vrtsim_state->peer_info.num_rx_antennas; i++) { histogram_merge(&tx_timing->tx_histogram, &tx_timing[i].tx_histogram); tx_timing->tx_early += tx_timing[i].tx_early; tx_timing->tx_samples_late += tx_timing[i].tx_samples_late; tx_timing->average_tx_budget += tx_timing[i].average_tx_budget; tx_timing->tx_samples_total += tx_timing[i].tx_samples_total; } - tx_timing->average_tx_budget /= shm_radio_state->peer_info.num_rx_antennas; + tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas; } // produce 1 second of extra samples so threads can finish - shm_td_iq_channel_produce_samples(shm_radio_state->channel, shm_radio_state->sample_rate); + shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate); sleep(1); - shm_td_iq_channel_destroy(shm_radio_state->channel); + shm_td_iq_channel_destroy(vrtsim_state->channel); LOG_I(HW, - "SHM_RADIO: Realtime issues: TX %.2f%%, RX %.2f%%\n", + "VRTSIM: Realtime issues: TX %.2f%%, RX %.2f%%\n", tx_timing->tx_samples_late / (float)tx_timing->tx_samples_total * 100, - shm_radio_state->rx_samples_late / (float)shm_radio_state->rx_samples_total * 100); + vrtsim_state->rx_samples_late / (float)vrtsim_state->rx_samples_total * 100); LOG_I(HW, - "SHM_RADIO: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n", + "VRTSIM: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n", tx_timing->tx_early, - shm_radio_state->rx_early); - LOG_I(HW, "SHM_RADIO: Average TX budget %.3lf uS\n", tx_timing->average_tx_budget); + vrtsim_state->rx_early); + LOG_I(HW, "VRTSIM: Average TX budget %.3lf uS\n", tx_timing->average_tx_budget); histogram_print(&tx_timing->tx_histogram); - free(shm_radio_state->tx_timing); + free(vrtsim_state->tx_timing); } -static int shm_radio_stub(openair0_device *device) +static int vrtsim_stub(openair0_device *device) { return 0; } -static int shm_radio_stub2(openair0_device *device, openair0_config_t *openair0_cfg) +static int vrtsim_stub2(openair0_device *device, openair0_config_t *openair0_cfg) { return 0; } -static int shm_radio_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) +static int vrtsim_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) { - shm_radio_state_t *s = device->priv; + vrtsim_state_t *s = device->priv; s->rx_freq = openair0_cfg->rx_freq[0]; return 0; } __attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { - shm_radio_state_t *shm_radio_state = calloc_or_fail(1, sizeof(shm_radio_state_t)); - shm_radio_readconfig(shm_radio_state); + vrtsim_state_t *vrtsim_state = calloc_or_fail(1, sizeof(vrtsim_state_t)); + vrtsim_readconfig(vrtsim_state); LOG_I(HW, "Running as %s\n", - shm_radio_state->role == ROLE_SERVER ? "server: waiting for client to connect" - : "client: will connect to a shm_radio server"); - device->trx_start_func = shm_radio_connect; - device->trx_reset_stats_func = shm_radio_stub; - device->trx_end_func = shm_radio_end; - device->trx_stop_func = shm_radio_stub; - device->trx_set_freq_func = shm_radio_set_freq; - device->trx_set_gains_func = shm_radio_stub2; - device->trx_write_func = shm_radio_write; - device->trx_read_func = shm_radio_read; + vrtsim_state->role == ROLE_SERVER ? "server: waiting for client to connect" : "client: will connect to a vrtsim server"); + device->trx_start_func = vrtsim_connect; + device->trx_reset_stats_func = vrtsim_stub; + device->trx_end_func = vrtsim_end; + device->trx_stop_func = vrtsim_stub; + device->trx_set_freq_func = vrtsim_set_freq; + device->trx_set_gains_func = vrtsim_stub2; + device->trx_write_func = vrtsim_write; + device->trx_read_func = vrtsim_read; device->type = RFSIMULATOR; device->openair0_cfg = &openair0_cfg[0]; - device->priv = shm_radio_state; - device->trx_write_init = shm_radio_stub; - shm_radio_state->last_received_sample = 0; - shm_radio_state->sample_rate = openair0_cfg->sample_rate; - shm_radio_state->rx_freq = openair0_cfg->rx_freq[0]; - shm_radio_state->tx_bw = openair0_cfg->tx_bw; - shm_radio_state->tx_num_channels = openair0_cfg->tx_num_channels; - shm_radio_state->rx_num_channels = openair0_cfg->rx_num_channels; + device->priv = vrtsim_state; + device->trx_write_init = vrtsim_stub; + vrtsim_state->last_received_sample = 0; + vrtsim_state->sample_rate = openair0_cfg->sample_rate; + vrtsim_state->rx_freq = openair0_cfg->rx_freq[0]; + vrtsim_state->tx_bw = openair0_cfg->tx_bw; + vrtsim_state->tx_num_channels = openair0_cfg->tx_num_channels; + vrtsim_state->rx_num_channels = openair0_cfg->rx_num_channels; - if (shm_radio_state->chanmod) { + if (vrtsim_state->chanmod) { init_channelmod(); int noise_power_dBFS = get_noise_power_dBFS(); int16_t noise_power = noise_power_dBFS == INVALID_DBFS_VALUE ? 0 : (int16_t)(32767.0 / powf(10.0, .05 * -noise_power_dBFS)); From 347eb5a50daaf6b54dfb584f023697898fde1627 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 14 Feb 2025 11:53:10 +0100 Subject: [PATCH 17/55] Add vrtsim to build_oai and some oai images --- cmake_targets/build_oai | 2 +- docker/Dockerfile.gNB.rhel9 | 1 + docker/Dockerfile.gNB.rocky | 1 + docker/Dockerfile.gNB.ubuntu22 | 1 + docker/Dockerfile.nrUE.rhel9 | 1 + docker/Dockerfile.nrUE.rocky | 1 + docker/Dockerfile.nrUE.ubuntu22 | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 27bb63ff89..f0d08328cf 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -485,7 +485,7 @@ function main() { # add some default libraries that should always be built # for eNB, gNB, UEs, simulators if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then - TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml" + TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim" fi mkdir -p $DIR/$BUILD_DIR/build diff --git a/docker/Dockerfile.gNB.rhel9 b/docker/Dockerfile.gNB.rhel9 index 894d1f6aa7..824e3b3833 100644 --- a/docker/Dockerfile.gNB.rhel9 +++ b/docker/Dockerfile.gNB.rhel9 @@ -72,6 +72,7 @@ COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \ /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ + /oai-ran/cmake_targets/ran_build/build/libvrtsim.so \ /usr/local/lib/ COPY --from=gnb-base \ diff --git a/docker/Dockerfile.gNB.rocky b/docker/Dockerfile.gNB.rocky index 5c17c78e57..225432fdab 100644 --- a/docker/Dockerfile.gNB.rocky +++ b/docker/Dockerfile.gNB.rocky @@ -69,6 +69,7 @@ COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \ /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ + /oai-ran/cmake_targets/ran_build/build/libvrtsim.so \ /usr/local/lib/ COPY --from=gnb-base \ diff --git a/docker/Dockerfile.gNB.ubuntu22 b/docker/Dockerfile.gNB.ubuntu22 index da2074c64b..68c903450a 100644 --- a/docker/Dockerfile.gNB.ubuntu22 +++ b/docker/Dockerfile.gNB.ubuntu22 @@ -110,6 +110,7 @@ COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_rrc.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_o1.so \ + /oai-ran/cmake_targets/ran_build/build/libvrtsim.so \ /usr/local/lib/ # Now we are copying from builder-image the UHD files. diff --git a/docker/Dockerfile.nrUE.rhel9 b/docker/Dockerfile.nrUE.rhel9 index 8ab486bd85..3a2900da27 100644 --- a/docker/Dockerfile.nrUE.rhel9 +++ b/docker/Dockerfile.nrUE.rhel9 @@ -75,6 +75,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ + /oai-ran/cmake_targets/ran_build/build/libvrtsim.so \ /usr/local/lib/ COPY --from=nr-ue-base \ diff --git a/docker/Dockerfile.nrUE.rocky b/docker/Dockerfile.nrUE.rocky index d0455527fa..7f112af53a 100644 --- a/docker/Dockerfile.nrUE.rocky +++ b/docker/Dockerfile.nrUE.rocky @@ -72,6 +72,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ + /oai-ran/cmake_targets/ran_build/build/libvrtsim.so \ /usr/local/lib/ COPY --from=nr-ue-base \ diff --git a/docker/Dockerfile.nrUE.ubuntu22 b/docker/Dockerfile.nrUE.ubuntu22 index 45ad4bbe03..c3b6592753 100644 --- a/docker/Dockerfile.nrUE.ubuntu22 +++ b/docker/Dockerfile.nrUE.ubuntu22 @@ -110,6 +110,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ciUE.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ + /oai-ran/cmake_targets/ran_build/build/libvrtsim.so \ /usr/local/lib/ # Now we are copying from builder-image the UHD files. From 391998667774546a4e51e041444e4e620623bc0e Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 26 Mar 2025 16:10:08 +0100 Subject: [PATCH 18/55] replace L2_NR dependency in f1ap with GTPV1U The above is necessary to not compile as many gNB dependencies into the UE. RLC only uses GTP, which was satisfied by L2_NR, but that's not necessary. However, only that change results in /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/libe2_ran_func_cuup.a(ran_func_rc.c.o): in function `get_list_for_report_style': openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c:596:(.text+0xbe7): undefined reference to `cp_e2sm_rc_event_trigger' /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c:596:(.text+0xc5b): undefined reference to `cp_e2sm_rc_event_trigger' /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c:596:(.text+0xd3b): undefined reference to `cp_e2sm_rc_event_trigger' /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c:596:(.text+0xd9d): undefined reference to `cp_e2sm_rc_event_trigger' /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c:596:(.text+0xded): undefined reference to `cp_e2sm_rc_event_trigger' /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/libe2_ran_func_cuup.a(ran_func_rc.c.o):openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c:596: more undefined references to `cp_e2sm_rc_event_trigger' follow /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/libe2_ran_func_cuup.a(ran_func_rc_subs.c.o): in function `remove_rc_subs_data': openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.c:60:(.text+0xbe): undefined reference to `find_if' /usr/bin/ld: openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.c:62:(.text+0xca): undefined reference to `free_e2sm_rc_event_trigger' nr-cuup previously satisfied these dependencies by depending on L2_NR which links in e2_ran_func_du_cucp_cuup. However, the nr-cuup E2 RAN functions are in e2_ran_func_cuup. In the latter, the file rc_data_ie.c was missing (for cp_e2sm_rc_event_trigger), which in turn needs e2sm_rc_ir_obj. Finally, find_if comes through alg. Co-authored-by: Robert Schmidt --- CMakeLists.txt | 2 +- openair2/E2AP/RAN_FUNCTION/CMakeLists.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index defe4c6c3b..5d37670c34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -450,7 +450,7 @@ add_library(f1ap ${F1AP_DIR}/f1ap_handlers.c ${F1AP_DIR}/f1ap_itti_messaging.c) target_include_directories(f1ap PUBLIC F1AP_DIR) -target_link_libraries(f1ap PUBLIC asn1_f1ap L2_NR) +target_link_libraries(f1ap PUBLIC asn1_f1ap GTPV1U) target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE f1ap_lib) target_include_directories(f1ap PRIVATE ${F1AP_DIR}/lib) diff --git a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt index 578bf489df..27497ae873 100644 --- a/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt +++ b/openair2/E2AP/RAN_FUNCTION/CMakeLists.txt @@ -6,13 +6,14 @@ add_library(e2_ran_func_cuup STATIC O-RAN/ran_func_kpm_subs.c O-RAN/ran_func_rc.c O-RAN/ran_func_rc_subs.c + ../flexric/src/sm/rc_sm/ie/rc_data_ie.c CUSTOMIZED/ran_func_gtp.c # GTP SM not yet implemented in CU-UP CUSTOMIZED/ran_func_pdcp.c CUSTOMIZED/ran_func_tc.c # currently, not implemented; therefore, filling rnd data ../flexric/test/rnd/fill_rnd_data_tc.c ) -target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj sm_common_ie_obj ds) +target_link_libraries(e2_ran_func_cuup PUBLIC asn1_nr_rrc nr_rrc asn1_nr_rrc_hdrs e2_time_obj kpm_ric_info_common_obj 3gpp_derived_ie_obj e2sm_rc_ir_obj sm_common_ie_obj ds alg) target_compile_definitions(e2_ran_func_cuup PUBLIC ${E2AP_VERSION} ${KPM_VERSION} NGRAN_GNB_CUUP) From c826a20583014c3c8862e338abaa2c97e4ac0ddf Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 27 Mar 2025 09:24:50 +0100 Subject: [PATCH 19/55] prevent NSA init in SA for a wrong condition --- executables/nr-ue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d1b9ba648f..24322bf8e6 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -1214,7 +1214,7 @@ void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconf NR_UE_MAC_INST_t *mac = get_mac_inst(i); mac->if_module = nr_ue_if_module_init(i); AssertFatal(mac->if_module, "can not initialize IF module\n"); - if (!IS_SA_MODE(get_softmodem_params()) || !get_softmodem_params()->sl_mode) { + if (!IS_SA_MODE(get_softmodem_params()) && !get_softmodem_params()->sl_mode) { init_nsa_message(&rrc_inst[i], reconfig_file, rbconfig_file); nr_rlc_activate_srb0(mac_inst[i].crnti, NULL, send_srb0_rrc); } From 66485aeb1d3418cea3c0ceddc0d1a9002f24bb21 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 27 Mar 2025 09:17:28 +0000 Subject: [PATCH 20/55] correctly set cellBarredNTN_r17 for NTN band again fixes e73e04543ab3279438995176d054ffae5b811b30 --- openair2/RRC/NR/nr_rrc_config.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 796ef4a3e1..e39dd3581f 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -2460,17 +2460,6 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, asn1cSeqAdd(&sib1->si_SchedulingInfo->schedulingInfoList.list,schedulingInfo);*/ - const NR_FreqBandIndicatorNR_t band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; - if (is_ntn_band(band)) { - sib1->nonCriticalExtension = CALLOC(1, sizeof(struct NR_SIB1_v1610_IEs)); - sib1->nonCriticalExtension->nonCriticalExtension = CALLOC(1, sizeof(struct NR_SIB1_v1630_IEs)); - sib1->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension = CALLOC(1, sizeof(struct NR_SIB1_v1700_IEs)); - // If cell provides NTN access, set cellBarredNTN to notBarred. - struct NR_SIB1_v1700_IEs *sib1_v1700 = sib1->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension; - sib1_v1700->cellBarredNTN_r17 = CALLOC(1, sizeof(long)); - *sib1_v1700->cellBarredNTN_r17 = NR_SIB1_v1700_IEs__cellBarredNTN_r17_notBarred; - } - // servingCellConfigCommon asn1cCalloc(sib1->servingCellConfigCommon, ServCellCom); NR_BWP_DownlinkCommon_t *initialDownlinkBWP = &ServCellCom->downlinkConfigCommon.initialDownlinkBWP; @@ -2485,6 +2474,7 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, frequencyInfoDL->frequencyBandList.list.array[i]; } + const NR_FreqBandIndicatorNR_t band = *frequencyInfoDL->frequencyBandList.list.array[0]; frequency_range_t frequency_range = get_freq_range_from_band(band); sib1->servingCellConfigCommon->downlinkConfigCommon.frequencyInfoDL.offsetToPointA = get_ssb_offset_to_pointA(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB, scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, @@ -2712,6 +2702,12 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, asn1cSeqAdd(&si_schedulinginfo2_r17->sib_MappingInfo_r17.list, sib_type_info); asn1cSeqAdd(&sib_v17_scheduling_info->schedulingInfoList2_r17.list, si_schedulinginfo2_r17); sib1_1700->si_SchedulingInfo_v1700 = sib_v17_scheduling_info; + + if (is_ntn_band(band)) { + // If cell provides NTN access, set cellBarredNTN to notBarred. + sib1_1700->cellBarredNTN_r17 = CALLOC(1, sizeof(long)); + *sib1_1700->cellBarredNTN_r17 = NR_SIB1_v1700_IEs__cellBarredNTN_r17_notBarred; + } } } From 981ecb5dde5b0e250d008284d95710352336d5b3 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 19 Feb 2025 15:41:12 +0000 Subject: [PATCH 21/55] NR UE: fix nr_pbch_channel_estimation() --- .../PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 e585c28d04..b6161e0e27 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -575,8 +575,8 @@ c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp, DEBUG_PBCH("PBCH DMRS Correlation : gNB_id %d , OFDM size %d, Ncp=%d, k=%u symbol %d\n", proc->gNB_id, - ue->frame_parms.ofdm_symbol_size, - ue->frame_parms.Ncp, + fp->ofdm_symbol_size, + fp->Ncp, k, symbol); @@ -590,8 +590,8 @@ c32_t nr_pbch_dmrs_correlation(const NR_DL_FRAME_PARMS *fp, c16_t *pil = pilot; const c16_t *rxF = &rxdataF[aarx][symbol_offset + k]; - DEBUG_PBCH("pbch ch est pilot RB_DL %d\n", ue->frame_parms.N_RB_DL); - DEBUG_PBCH("k %u, first_carrier %d\n", k, ue->frame_parms.first_carrier_offset); + DEBUG_PBCH("pbch ch est pilot RB_DL %d\n", fp->N_RB_DL); + DEBUG_PBCH("k %u, first_carrier %d\n", k, fp->first_carrier_offset); // Treat first 2 pilots specially (left edge) computed_val = c32x16maddShift(*pil, rxF[re_offset], computed_val, 15); @@ -769,7 +769,7 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp, multaddRealVectorComplexScalar(fr, ch, dl_ch, 16); pil++; re_offset = (re_offset + 4) % fp->ofdm_symbol_size; - dl_ch += 24; + dl_ch += 12; for (int pilot_cnt = 3; pilot_cnt < (3 * num_rbs); pilot_cnt += 3) { // if (pilot_cnt == 30) @@ -779,7 +779,7 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp, if (dmrss == 1 && pilot_cnt == 12) { pilot_cnt=48; re_offset = (re_offset + 144) % fp->ofdm_symbol_size; - dl_ch += 288; + dl_ch += 144; } ch = c16mulShift(*pil, rxF[re_offset], 15); DEBUG_PBCH("pilot %u: rxF= (%d,%d), ch= (%d,%d), pil=(%d,%d)\n", From cfde90dc85793924588cf5926ed87b93821ec906 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 21 Feb 2025 19:32:10 +0000 Subject: [PATCH 22/55] rfsimulator: apply deadlock detection only if more than one client is connected --- radio/rfsimulator/simulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index b11f4034ca..ca01a1768c 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -1004,7 +1004,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest t->nextRxTstamp + nsamps); flushInput(t, 3, nsamps); } - if (t->hanging_workaround && loops++ > 10 && t->role == SIMU_ROLE_SERVER) { + if (t->hanging_workaround && loops++ > 10 && t->role == SIMU_ROLE_SERVER && nb_ue > 1) { // Just start producing samples. The clients will catch up. have_to_wait = false; LOG_W(HW, From a164623fa3be3cc4617f6c122b9b1a4838dbeb4d Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 27 Mar 2025 09:52:55 +0100 Subject: [PATCH 23/55] prevent access to NULL pointer in RELEASE_IE_FROMLIST --- common/utils/oai_asn1.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/utils/oai_asn1.h b/common/utils/oai_asn1.h index 0f202bf699..4d7ea6c73f 100644 --- a/common/utils/oai_asn1.h +++ b/common/utils/oai_asn1.h @@ -78,6 +78,10 @@ // Prints an error if ID not found in list. #define RELEASE_IE_FROMLIST(SOURCE, TARGET, FIELD) \ do { \ + if (!TARGET) { \ + LOG_E(NR_MAC, "Target list not present, impossible to release element\n"); \ + break; \ + } \ for (int iI = 0; iI < SOURCE->list.count; iI++) { \ long eL = *SOURCE->list.array[iI]; \ int iJ; \ From 01877f0c9de93863a3e86723787704e21ce6e601 Mon Sep 17 00:00:00 2001 From: Reem Bahsoun Date: Tue, 25 Mar 2025 15:15:26 +0100 Subject: [PATCH 24/55] Add gNB configuration for Foxconn RU in targets. - Tested with OAI tag `2024.w30`. --- ...nb.sa.band78.273prb.fhi72.4x4-foxconn.conf | 271 ++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf new file mode 100644 index 0000000000..97fd75bda8 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf @@ -0,0 +1,271 @@ +Active_gNBs = ( "oai-du"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "oai-du"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pdsch_AntennaPorts_N1 = 2; + maxMIMO_layers = 2; + pusch_AntennaPorts = 4; + do_CSIRS = 1; + do_SRS = 0; + + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; +# downlinkConfigCommon + #frequencyInfoDL + # selected SSB frequency = 3748.80 MHz + absoluteFrequencySSB = 649920; + dl_frequencyBand = 78; + # frequency point A = 3700.86 MHz + dl_absoluteFrequencyPointA = 646724; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + #this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart)) + initialDLBWPlocationAndBandwidth = 1099; + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 151;# testMAC 158; OAI gNB 98 +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + 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; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 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 = 5; #6; + nrofDownlinkSlots = 3; #7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 1; #2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 0; + } + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "172.21.6.5"; }); + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 120; + pucch_TargetSNRx10 = 260; + ul_bler_target_upper = .35; + ul_bler_target_lower = .15; + pusch_FailureThres = 100; + ul_max_mcs = 28; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 130; + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 15; + tx_amp_backoff_dB = 24; # needs to match O-RU configuration + L1_rx_thread_core = 8; + L1_tx_thread_core = 10; + phase_compensation = 0; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 4; + nb_rx = 4; + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 9; + sl_ahead = 5; + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration +} +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level = "info"; + hw_log_level = "info"; + phy_log_level = "info"; + mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + ngap_log_level = "info"; + f1ap_log_level = "info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); + system_core = 0; + io_core = 1; + worker_cores = (2); + ru_addr = ("6c:ad:ad:00:04:dc", "6c:ad:ad:00:04:dc"); + mtu = 8000; + fh_config = ({ + T1a_cp_dl = (285, 470); + T1a_cp_ul = (285, 429); + T1a_up = (96, 196); + Ta4 = (0, 75); + ru_config = { + iq_width = 9; + iq_width_prach = 9; + }; + }); +}; From 1b8a6d001bcb67341093c8fc9b4f0a6a786efe18 Mon Sep 17 00:00:00 2001 From: Reem Bahsoun Date: Tue, 25 Mar 2025 15:29:42 +0100 Subject: [PATCH 25/55] Add documentation for Foxconn RU in ORAN_FHI7.2_Tutorial.md - This addition is based on past tests, iperf3 UDP throughput was 520Mbps DL and 40Mbps UL. - Throughput degrades when using OAI L1 with tags beyond `2024.w30`. - This RU is being CI tested only in the Aerial pipeline, not with OAI L1. - The document will be updated once the issue is identified and fixed. --- doc/ORAN_FHI7.2_Tutorial.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index c28f75a2cf..560733881f 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -72,6 +72,7 @@ tested any RU without S-plane. Radio units we are testing/integrating: |LiteON RU |01.00.08/02.00.03 | |Benetel 650 |RAN650-1v1.0.4-dda1bf5| |Benetel 550 CAT-A|RAN550-1v1.0.4-605a25a| +|Foxconn RPQN |v3.1.15q.551_rc10 | Tested libxran releases: @@ -671,6 +672,40 @@ The RU configuration is stored in `/etc/rumanager.conf`. The required modificati At this stage, RU must be rebooted so the changes apply. +### Foxconn RPQN RU + +**Version v3.1.15q.551_rc10** + +The OAI configuration file [`gnb.sa.band78.273prb.fhi72.4X4-foxconn.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4X4-foxconn.conf) corresponds to: +- TDD pattern `DDDSU`, 2.5ms +- Bandwidth 100MHz +- MTU 8000 + +#### RU configuration + +After switching on or rebooting the RU, the `/home/root/test/init_rrh_config_enable_cuplane` script should be run. + +The RU configuration file is located in `/home/root/test/RRHconfig_xran.xml`. The required modifications: +1. `RRH_DST_MAC_ADDR` +2. `RRH_SRC_MAC_ADDR` +3. `RRH_EAXC_ID_TYPE1` +4. `RRH_EAXC_ID_TYPE3` +5. `RRH_CMPR_HDR_PRESENT` -> `0` +6. `RRH_C_PLANE_VLAN_TAG` +7. `RRH_U_PLANE_VLAN_TAG` +8. `RRH_LO_FREQUENCY_KHZ` -> `3750000, 0` +9. `RRH_DISABLE_USING_CAL_TABLES` -> `YES` +10. `RRH_TX_ATTENUATION` -> must be larger than 10dB +11. `RRH_RX_ATTENUATION` -> must be lower than 30dB + +RU must be rebooted so the changes apply. + +**Note** + +- The RU was tested with the `2024.w30` tag of OAI. +- The measured throughput was **520 Mbps DL** and **40 Mbps UL**. +- With newer OAI versions, throughput degrades. This issue is currently under investigation. + ## Configure Network Interfaces and DPDK VFs The 7.2 fronthaul uses the xran library, which requires DPDK. In this step, we From cea02a16b14ca63fe2746657513bea9f3941e630 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 20 Feb 2025 16:23:58 +0100 Subject: [PATCH 26/55] Modify 5g_fdd_rfsimulator testcase to use shm_radio Use timescale 0.5 to make sure the iperf UL test passes. Also, disable asan as this adds computational complexity that makes the test fail. --- ci-scripts/xml_files/container_5g_fdd_rfsim.xml | 4 ++-- .../5g_fdd_rfsimulator/docker-compose.yaml | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml index 276bb5b9a3..1c43120131 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml @@ -43,7 +43,7 @@ Pull_Local_Registry Pull Images from Local Registry 0 - oai-gnb-asan oai-nr-ue-asan + oai-gnb oai-nr-ue Create_Workspace @@ -134,7 +134,7 @@ true Clean Test Images on Test Server 0 - oai-gnb-asan oai-nr-ue-asan + oai-gnb oai-nr-ue diff --git a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml index a6103a3815..8c4688262b 100644 --- a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml @@ -86,8 +86,7 @@ services: cap_drop: - ALL environment: - USE_ADDITIONAL_OPTIONS: -E --rfsim --log_config.global_log_options level,nocolor,time - ASAN_OPTIONS: detect_leaks=0 + USE_ADDITIONAL_OPTIONS: -E --log_config.global_log_options level,nocolor,time --device.name vrtsim --vrtsim.role server --vrtsim.timescale 0.5 depends_on: - oai-ext-dn networks: @@ -95,11 +94,13 @@ services: ipv4_address: 192.168.71.140 volumes: - ../../conf_files/gnb.sa.band66.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf + - tmp_data:/tmp/ healthcheck: test: /bin/bash -c "pgrep nr-softmodem" interval: 10s timeout: 5s retries: 5 + ipc: host oai-nr-ue: image: ${REGISTRY:-oaisoftwarealliance}/${NRUE_IMG:-oai-nr-ue}:${TAG:-develop} container_name: rfsim5g-oai-nr-ue @@ -109,7 +110,7 @@ services: - NET_ADMIN # for interface bringup - NET_RAW # for ping environment: - USE_ADDITIONAL_OPTIONS: -E --rfsim -r 106 --numerology 1 --uicc0.imsi 208990100001100 --band 66 -C 2169090000 --CO -400000000 --ssb 378 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time + USE_ADDITIONAL_OPTIONS: -E -r 106 --numerology 1 --uicc0.imsi 208990100001100 --band 66 -C 2169090000 --CO -400000000 --ssb 378 --log_config.global_log_options level,nocolor,time --device.name vrtsim depends_on: - oai-gnb networks: @@ -119,11 +120,13 @@ services: - /dev/net/tun:/dev/net/tun volumes: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf + - tmp_data:/tmp/ healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" interval: 10s timeout: 5s retries: 5 + ipc: host networks: public_net: @@ -142,3 +145,6 @@ networks: - subnet: 192.168.72.128/26 driver_opts: com.docker.network.bridge.name: "rfsim5g-traffic" + +volumes: + tmp_data: From b141faaf30246f0099b7d86bbe19a89963a81b98 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Wed, 26 Mar 2025 15:57:18 +0100 Subject: [PATCH 27/55] K-offset updated with configured sub carrier spacing According to 38.331 , cell specific K-OFFSET provided in SIB19 is provided in number of slots as per 15Khz SCS Koffset before being applied, needs to be updated to the slots according to the configured subcarrier spacing. --- executables/nr-ue.c | 24 ++++++++------- openair2/LAYER2/NR_MAC_UE/config_ue.c | 7 +++++ openair2/LAYER2/NR_MAC_UE/mac_defs.h | 4 +-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 8 ++--- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 31 +++++++++++--------- 5 files changed, 44 insertions(+), 30 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d1b9ba648f..7ae02d1ea6 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -872,18 +872,22 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE, if (*update_ntn_system_information) { *update_ntn_system_information = false; - *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; - UE->timing_advance = fp->samples_per_subframe * UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; - *timing_advance += - fp->get_samples_slot_timestamp(slot_nr, - fp, - UE->ntn_config_message->ntn_config_params.cell_specific_k_offset - *ntn_koffset); - *ntn_koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; + double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; + UE->timing_advance = fp->samples_per_subframe * total_ta_ms; + + int mu = fp->numerology_index; + int koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; + if (*ntn_koffset != koffset) { + *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); + *timing_advance += fp->get_samples_slot_timestamp(slot_nr, fp, (koffset - *ntn_koffset) << mu); + *ntn_koffset = koffset; + } LOG_I(PHY, - "cell_specific_k_offset = %d ms, ntn_total_time_advance_ms = %f ms (%d samples)\n", + "k_offset = %d ms (%d slots), ntn_total_time_advance_ms = %f ms (%d samples)\n", *ntn_koffset, - UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms, + *ntn_koffset << mu, + total_ta_ms, UE->timing_advance); } } @@ -1080,7 +1084,7 @@ void *UE_thread(void *arg) if (UE->ntn_config_message->update) { UE->ntn_config_message->update = false; update_ntn_system_information = true; - nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; + nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset << fp->numerology_index; } int slot_nr = absolute_slot % nb_slot_frame; diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 1f0e552ba0..cf53a800a4 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -306,6 +306,13 @@ void configure_ntn_ta(module_id_t module_id, ntn_timing_advance_componets_t *ntn ntn_ta->ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; } ntn_ta->ntn_params_changed = true; + + LOG_D(NR_MAC, + "SIB19 Rxd. k_offset:%ld, N_Common_Ta:%f,drift:%f,N_UE_TA:%f \n", + ntn_ta->cell_specific_k_offset, + ntn_ta->N_common_ta_adj, + ntn_ta->ntn_ta_commondrift, + ntn_ta->N_UE_TA_adj); } static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP) diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index cfa3952759..838d1989f0 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -649,9 +649,9 @@ static inline double GET_COMPLETE_TIME_ADVANCE_MS(const ntn_timing_advance_compo return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj; } -static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta) +static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta, int scs) { - return NR_UE_CAPABILITY_SLOT_RX_TO_TX + ntn_ta->cell_specific_k_offset; + return NR_UE_CAPABILITY_SLOT_RX_TO_TX + (ntn_ta->cell_specific_k_offset << scs); } /*@}*/ diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 83bbcadbe5..c0cda918d1 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -927,10 +927,10 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, const uint16_t feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta), + AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld).\n", feedback_ti, - GET_DURATION_RX_TO_TX(&mac->ntn_ta)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing)); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; set_harq_status(mac, @@ -1220,11 +1220,11 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing); const uint16_t feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset; - AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta), + AssertFatal(feedback_ti > GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing), "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%ld). Min feedback time set in config " "file (min_rxtxtime).\n", feedback_ti, - GET_DURATION_RX_TO_TX(&mac->ntn_ta)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing)); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index edd3bc1db7..3c18360d21 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1037,9 +1037,11 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger return; } - AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(&mac->ntn_ta), + int scs = mac->current_UL_BWP->scs; + AssertFatal(slot_offset > GET_DURATION_RX_TO_TX(&mac->ntn_ta, scs), "Slot offset between DCI and aperiodic SRS (%d) needs to be higher than DURATION_RX_TO_TX (%ld)\n", - slot_offset, GET_DURATION_RX_TO_TX(&mac->ntn_ta)); + slot_offset, + GET_DURATION_RX_TO_TX(&mac->ntn_ta, scs)); int n_slots_frame = mac->frame_structure.numb_slots_frame; int sched_slot = (slot + slot_offset) % n_slots_frame; if (!is_ul_slot(sched_slot, &mac->frame_structure)) { @@ -1563,23 +1565,24 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, AssertFatal(1 == 0, "Invalid numerology %i\n", mu); } - AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta), - "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", + AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to " + "%ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, - GET_DURATION_RX_TO_TX(&mac->ntn_ta), - GET_DURATION_RX_TO_TX(&mac->ntn_ta), - GET_DURATION_RX_TO_TX(&mac->ntn_ta)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu)); *slot_tx = (current_slot + k2 + delta) % slots_per_frame; *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; } else { - - AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta), - "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", + AssertFatal(k2 > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in " + "gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", k2, - GET_DURATION_RX_TO_TX(&mac->ntn_ta), - GET_DURATION_RX_TO_TX(&mac->ntn_ta), - GET_DURATION_RX_TO_TX(&mac->ntn_ta)); + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu), + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu)); if (k2 < 0) { // This can happen when a false DCI is received LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2); @@ -2203,7 +2206,7 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t add_slots++; } nr_timer_setup(&ra->response_window_timer, - ra->response_window_setup_time + add_slots + GET_DURATION_RX_TO_TX(&mac->ntn_ta), + ra->response_window_setup_time + add_slots + GET_DURATION_RX_TO_TX(&mac->ntn_ta, mac->current_DL_BWP->scs), 1); nr_timer_start(&ra->response_window_timer); } else if (ra->ra_type == RA_2_STEP) { From 3a095ac57edd930818cbca109d783b9eb0a99748 Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 11 Dec 2024 14:14:34 +0100 Subject: [PATCH 28/55] M-plane support - explanation on needed parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RU IP address - to connect to RUs via netconf - DU MAC address - for setting up the CU-planes on RU; not used in xran - VLAN tag (*) - for setting up the CU-planes on RU; not used in xran - DU keypair - for authentication when connecting to RU(s) The parameters that RU-controller shall retreive from RU list of capabilities: - MTU - compression - RU MAC address - PRACH offset (**) (*) VLAN tag is not used in xran but an option is given in fh_config struct. In my opinion, it is not a very suitable place, as it is needed for VFs. Therefore, I moved it in the initialization part for M-plane purposes. (**) PRACH offset shall be >= max(Ntx,Nrx), as per O-RAN CUS specification: "The O-DU may decide to use same eAxC ID value to address endpoints on different O-RUs, but eAxC ID values assigned to one O-RU must be unique within the O-RU’s endpoints of same direction." => however, LITEON supports flexible assignment of PRACH eAxC IDs, so we made a workaround in the xran library to support PRACH eAxC IDs same as PUSCH eAxC IDs. --- radio/fhi_72/oran-config.c | 4 ++-- radio/fhi_72/oran-params.h | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 2f2032c30a..ba8fb2fcea 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -839,8 +839,8 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat, #endif fh_config->puschMaskEnable = 0; // enable PUSCH mask; only used if id = O_RU fh_config->puschMaskSlot = 0; // specific which slot PUSCH channel masked; only used if id = O_RU - fh_config->cp_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_CP_VLAN_TAG)->uptr; // C-plane VLAN tag; not used in xran; needed for M-plane - fh_config->up_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_UP_VLAN_TAG)->uptr; // U-plane VLAN tag; not used in xran; needed for M-plane + fh_config->cp_vlan_tag = 0; // C-plane VLAN tag; not used in xran; needed for M-plane + fh_config->up_vlan_tag = 0; // U-plane VLAN tag; not used in xran; needed for M-plane fh_config->debugStop = 0; // enable auto stop; only used if id = O_RU fh_config->debugStopCount = 0; // enable auto stop after number of Tx packets; not used in xran fh_config->DynamicSectionEna = 0; // enable dynamic C-Plane section allocation diff --git a/radio/fhi_72/oran-params.h b/radio/fhi_72/oran-params.h index 20c3d71634..42aabd99bb 100644 --- a/radio/fhi_72/oran-params.h +++ b/radio/fhi_72/oran-params.h @@ -31,8 +31,12 @@ #define ORAN_CONFIG_SYSTEM_CORE "system_core" #define ORAN_CONFIG_IO_CORE "io_core" #define ORAN_CONFIG_WORKER_CORES "worker_cores" -#define ORAN_CONFIG_RU_ADDR "ru_addr" -#define ORAN_CONFIG_MTU "mtu" +#define ORAN_CONFIG_DU_KEYPAIR "du_key_pair" // only needed for M-plane +#define ORAN_CONFIG_DU_ADDR "du_addr" // only needed for M-plane +#define ORAN_CONFIG_VLAN_TAG "vlan_tag" // only needed for M-plane +#define ORAN_CONFIG_RU_ADDR "ru_addr" // not needed if M-plane used +#define ORAN_CONFIG_RU_IP_ADDR "ru_ip_addr" // only needed for M-plane +#define ORAN_CONFIG_MTU "mtu" // not needed if M-plane used #define ORAN_CONFIG_FILE_PREFIX "file_prefix" #define ORAN_CONFIG_NETHPERPORT "eth_lines" #define ORAN_CONFIG_NETHSPEED "eth_speed" @@ -48,7 +52,11 @@ {ORAN_CONFIG_SYSTEM_CORE, "DPDK control threads core\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \ {ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \ + {ORAN_CONFIG_DU_KEYPAIR, "DU keypair for RU authentication\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_VLAN_TAG, "VLAN tag\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_RU_IP_ADDR, "IP addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ {ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \ {ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \ {ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \ @@ -70,6 +78,10 @@ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ { .s3a = { config_checkstr_assign_integer, \ {"PA", "VA"}, {0, 1}, 2} }, \ { .s5 = { NULL } }, \ @@ -84,8 +96,6 @@ #define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul" #define ORAN_FH_CONFIG_T1A_UP "T1a_up" #define ORAN_FH_CONFIG_TA4 "Ta4" -#define ORAN_FH_CONFIG_CP_VLAN_TAG "cp_vlan_tag" -#define ORAN_FH_CONFIG_UP_VLAN_TAG "up_vlan_tag" #define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n" @@ -95,15 +105,13 @@ {ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ {ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ {ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \ - {ORAN_FH_CONFIG_CP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ - {ORAN_FH_CONFIG_UP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ } // clang-format on #define CONFIG_STRING_ORAN_RU "ru_config" -#define ORAN_RU_CONFIG_IQWIDTH "iq_width" -#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" +#define ORAN_RU_CONFIG_IQWIDTH "iq_width" // not needed if M-plane used +#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" // not needed if M-plane used // clang-format off #define ORAN_RU_DESC {\ @@ -114,7 +122,7 @@ #define CONFIG_STRING_ORAN_PRACH "prach_config" -#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset" +#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset" // not needed if M-plane used #define ORAN_PRACH_CONFIG_KBAR "kbar" // clang-format off From 3219d0a5a1215de986eac283e43c41ab47b5f0eb Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 11 Dec 2024 23:19:46 +0100 Subject: [PATCH 29/55] Delete duplicated FindLibXml2.cmake file - cmake version 3.12 defines libxml2 module; the default path is /usr/share/cmake-3./Modules/FindLibXml2.cmake - OAI requires minimum cmake version 3.16 --- cmake_targets/tools/MODULES/FindLibXml2.cmake | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100755 cmake_targets/tools/MODULES/FindLibXml2.cmake diff --git a/cmake_targets/tools/MODULES/FindLibXml2.cmake b/cmake_targets/tools/MODULES/FindLibXml2.cmake deleted file mode 100755 index e18dc2e921..0000000000 --- a/cmake_targets/tools/MODULES/FindLibXml2.cmake +++ /dev/null @@ -1,53 +0,0 @@ -# - Try to find the LibXml2 xml processing library -# Once done this will define -# -# LIBXML2_FOUND - System has LibXml2 -# LIBXML2_INCLUDE_DIR - The LibXml2 include directory -# LIBXML2_LIBRARIES - The libraries needed to use LibXml2 -# LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2 -# LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2 - -#============================================================================= -# Copyright 2006-2009 Kitware, Inc. -# Copyright 2006 Alexander Neundorf -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -# use pkg-config to get the directories and then use these values -# in the FIND_PATH() and FIND_LIBRARY() calls -FIND_PACKAGE(PkgConfig) -PKG_CHECK_MODULES(PC_LIBXML libxml-2.0) -SET(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER}) - -FIND_PATH(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h - HINTS - ${PC_LIBXML_INCLUDEDIR} - ${PC_LIBXML_INCLUDE_DIRS} - PATH_SUFFIXES libxml2 - ) - -FIND_LIBRARY(LIBXML2_LIBRARIES NAMES xml2 libxml2 - HINTS - ${PC_LIBXML_LIBDIR} - ${PC_LIBXML_LIBRARY_DIRS} - ) - -FIND_PROGRAM(LIBXML2_XMLLINT_EXECUTABLE xmllint) -# for backwards compat. with KDE 4.0.x: -SET(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}") - -# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR) - -MARK_AS_ADVANCED(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE) - From 978fa2ed053d7353932a7e3e56f5ccc282f7c399 Mon Sep 17 00:00:00 2001 From: Teodora Date: Sat, 15 Feb 2025 17:04:43 +0100 Subject: [PATCH 30/55] These commands are unnecessary - the FHI72 CMakeLists.txt exists and POST_BUILD properly links oran_fhlib_5g library --- cmake_targets/build_oai | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 27bb63ff89..d92e488e90 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -504,12 +504,6 @@ function main() { echo_info "Built Doxygen based documentation. The documentation file is located here: $DIR/$BUILD_DIR/build/doc/html/index.html" fi - # TODO: once we got the CMakeLists.txt file done for the ORAN files, remove the following lines - if [[ $TARGET_LIST =~ "oran_fhlib_5g" ]]; then - rm -f liboai_transpro.so - ln -s liboran_fhlib_5g.so liboai_transpro.so - fi - if [ "$UE" = 1 ] ; then echo_info "Compiling UE specific part" From efcc9fc9d4f66e19f4e1da1667acfcca905350c2 Mon Sep 17 00:00:00 2001 From: Teodora Date: Sat, 15 Feb 2025 17:13:30 +0100 Subject: [PATCH 31/55] Properly include xran_common.h in ${xran_INCLUDE_DIRS} - ${xran_LOCATION}/src/xran_common.h - delete unnecessary target_include_directories() from FHI72 --- cmake_targets/tools/MODULES/Findxran.cmake | 10 ++++++---- radio/fhi_72/CMakeLists.txt | 3 --- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake index 290a782350..1ade3ac522 100644 --- a/cmake_targets/tools/MODULES/Findxran.cmake +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -75,7 +75,6 @@ endif() find_path(xran_INCLUDE_DIR NAMES - xran_common.h xran_compression.h xran_cp_api.h xran_ecpri_owd_measurements.h @@ -84,7 +83,7 @@ find_path(xran_INCLUDE_DIR xran_pkt_up.h xran_sync_api.h HINTS ${xran_LOCATION} - PATH_SUFFIXES api include + PATH_SUFFIXES api NO_DEFAULT_PATH ) find_library(xran_LIBRARY @@ -127,16 +126,19 @@ find_package_handle_standard_args(xran VERSION_VAR xran_VERSION ) +# in proper usage of cmake, include directory should only contain "api", but not header files under "src" directory; +# however, we use xran_dev_get_ctx() and xran_dev_get_ctx_by_id() functions which are defined in xran_common.h; +# since xran_common.h is under "src" directory, we have to include it in ${xran_INCLUDE_DIRS} if(xran_FOUND) set(xran_LIBRARIES ${xran_LIBRARY}) - set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR}) + set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR} ${xran_INCLUDE_DIR}/../src) endif() if(xran_FOUND AND NOT TARGET xran::xran) add_library(xran::xran UNKNOWN IMPORTED) set_target_properties(xran::xran PROPERTIES IMPORTED_LOCATION "${xran_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIR}" + INTERFACE_INCLUDE_DIRECTORIES "${xran_INCLUDE_DIRS}" ) endif() diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 3fab4f5d47..dd31db27f2 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -36,9 +36,6 @@ target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) target_link_libraries(oran_fhlib_5g PRIVATE pthread dl rt m numa) target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB}) -# TODO: can be removed? -target_include_directories(oran_fhlib_5g PRIVATE ${xran_INCLUDE_DIRS}/../src/) - add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON) set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) From 0be72c1917a148752a13fc2f58998701122daeca Mon Sep 17 00:00:00 2001 From: Teodora Date: Tue, 18 Feb 2025 11:16:22 +0100 Subject: [PATCH 32/55] Install dependencies for M-plane support --- cmake_targets/tools/build_helper | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 3fc1db7b56..057c4860d6 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -546,7 +546,10 @@ check_install_additional_tools (){ libforms-bin \ libforms-dev \ libxft-dev \ - xmlstarlet" + xmlstarlet \ + libpcre3-dev \ + libssh-dev \ + libxml2-dev" elif [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]] || [[ "$OS_DISTRO" == "rocky" ]] || [[ "$OS_DISTRO" == "fedora" ]]; then PACKAGE_LIST="\ doxygen \ @@ -556,7 +559,10 @@ check_install_additional_tools (){ libXft-devel \ xforms \ xforms-devel \ - xmlstarlet" + xmlstarlet \ + pcre-devel \ + libssh-devel \ + libxml2-devel" fi $SUDO $INSTALLER install -y $PACKAGE_LIST $optional_packages } From da63bf9f9ff83f2e1a4b88292e086475519e1c2a Mon Sep 17 00:00:00 2001 From: Teodora Date: Sat, 15 Feb 2025 17:23:42 +0100 Subject: [PATCH 33/55] M-plane integration - initial commit --- cmake_targets/build_oai | 6 +- radio/fhi_72/CMakeLists.txt | 12 ++- radio/fhi_72/mplane/CMakeLists.txt | 64 ++++++++++++++ radio/fhi_72/mplane/init-mplane.c | 131 ++++++++++++++++++++++++++++ radio/fhi_72/mplane/init-mplane.h | 30 +++++++ radio/fhi_72/mplane/ru-mplane-api.h | 95 ++++++++++++++++++++ radio/fhi_72/oran_isolate.c | 61 +++++++------ 7 files changed, 363 insertions(+), 36 deletions(-) create mode 100644 radio/fhi_72/mplane/CMakeLists.txt create mode 100644 radio/fhi_72/mplane/init-mplane.c create mode 100644 radio/fhi_72/mplane/init-mplane.h create mode 100644 radio/fhi_72/mplane/ru-mplane-api.h diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index d92e488e90..003527056f 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -99,7 +99,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 + Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g, oran_fhlib_5g_mplane -P | --phy_simulators Makes the unitary tests Layer 1 simulators -s | --check @@ -304,6 +304,10 @@ function main() { TARGET_LIST="$TARGET_LIST $2" CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON" ;; + "oran_fhlib_5g_mplane") + TARGET_LIST="$TARGET_LIST $2" + CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON" + ;; "None") ;; *) diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index dd31db27f2..8b047a9316 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -30,15 +30,19 @@ endif() add_compile_options(-Wno-packed-not-aligned) set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") -target_link_libraries(oran_fhlib_5g PRIVATE xran::xran) -target_link_libraries(oran_fhlib_5g PRIVATE ${dpdk_LINK_LIBRARIES}) +target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) -target_link_libraries(oran_fhlib_5g PRIVATE pthread dl rt m numa) -target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB}) add_boolean_option(OAI_FHI72_USE_POLLING OFF "Enable polling in FHI72 driver" ON) +message(STATUS "Building FHI72 CUS library") + set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oran_fhlib_5g POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_boolean_option(OAI_FHI72_MPLANE OFF "Activate OAI's FHI 7.2 M-plane support" OFF) +if(OAI_FHI72_MPLANE) + add_subdirectory(mplane) +endif() diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt new file mode 100644 index 0000000000..7cc53dd40f --- /dev/null +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -0,0 +1,64 @@ +add_library(oran_fhlib_5g_mplane MODULE + ../oran_isolate.c + ../oaioran.c + ../oran-config.c + ../oran-init.c +) +add_dependencies(oran_fhlib_5g_mplane oran_fhlib_5g) + +if(xran_VERSION VERSION_EQUAL 5.1.4) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE E_RELEASE) +elseif(xran_VERSION VERSION_EQUAL 6.1.1) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE F_RELEASE) +endif() + +# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress +# alignment 1 of 'struct XYZ' is less than 2 +add_compile_options(-Wno-packed-not-aligned) + +set_target_properties(oran_fhlib_5g_mplane PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") +target_link_libraries(oran_fhlib_5g_mplane PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) +target_include_directories(oran_fhlib_5g_mplane PRIVATE ${dpdk_INCLUDE_DIRS}) + +target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE) + +################################################### + +target_sources(oran_fhlib_5g_mplane PRIVATE + init-mplane.c +) + +pkg_check_modules(libyang REQUIRED libyang) +pkg_check_modules(libnetconf2 REQUIRED libnetconf2) + +if(libyang_VERSION VERSION_LESS_EQUAL 1.0.240 AND libnetconf2_VERSION VERSION_LESS_EQUAL 1.1.46) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE MPLANE_V1) +elseif((libyang_VERSION VERSION_GREATER 1.0.240 AND libyang_VERSION VERSION_LESS 2.1.4)) + message(FATAL_ERROR "Minimum libyang v2 subversion required is v2.1.4, but found ${libyang_VERSION}") +elseif((libnetconf2_VERSION VERSION_GREATER 1.1.46 AND libnetconf2_VERSION VERSION_LESS 2.1.25)) + message(FATAL_ERROR "Minimum libnetconf2 v2 subversion required is v2.1.25, but found ${libnetconf2_VERSION}") +elseif((libyang_VERSION VERSION_GREATER_EQUAL 2.1.4 AND libyang_VERSION VERSION_LESS_EQUAL 2.1.111) AND (libnetconf2_VERSION VERSION_GREATER_EQUAL 2.1.25 AND libnetconf2_VERSION VERSION_LESS_EQUAL 2.1.37)) + target_compile_definitions(oran_fhlib_5g_mplane PRIVATE MPLANE_V2) +else() + message(FATAL_ERROR "Unknown libyang version ${libyang_VERSION} and libnetconf2 version ${libnetconf2_VERSION}") +endif() + +target_include_directories(oran_fhlib_5g_mplane PRIVATE ${libyang_INCLUDE_DIRS} ${libnetconf2_INCLUDE_DIRS}) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE ${libyang_LDFLAGS} ${libyang_LINK_LIBRARIES} ${libnetconf2_LINK_LIBRARIES}) + +pkg_check_modules(libssh REQUIRED libssh) +target_include_directories(oran_fhlib_5g_mplane PRIVATE ${libssh_INCLUDE_DIRS}) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE ${libssh_LINK_LIBRARIES}) + +find_package(LibXml2 REQUIRED) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE LibXml2::LibXml2) + +set(YANG_MODELS "${CMAKE_SOURCE_DIR}/radio/fhi_72/mplane/yang/models") +target_compile_definitions(oran_fhlib_5g_mplane PRIVATE YANG_MODELS="${YANG_MODELS}") + +message(STATUS "Building FHI72 CUSM library") + +set_target_properties(oran_fhlib_5g_mplane PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +add_custom_command(TARGET oran_fhlib_5g_mplane POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g_mplane.so liboai_transpro.so + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c new file mode 100644 index 0000000000..31988f3dba --- /dev/null +++ b/radio/fhi_72/mplane/init-mplane.c @@ -0,0 +1,131 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "init-mplane.h" +#include "radio/fhi_72/oran-params.h" + +#include +#include + +static void lnc2_print_clb(NC_VERB_LEVEL level, const char *msg) +{ + switch (level) { + case NC_VERB_ERROR: + MP_LOG_I("[LIBNETCONF2] ERROR: %s.\n", msg); + break; + case NC_VERB_WARNING: + MP_LOG_I("[LIBNETCONF2] WARNING: %s.\n", msg); + break; + case NC_VERB_VERBOSE: + MP_LOG_I("[LIBNETCONF2] VERBOSE: %s.\n", msg); + break; + case NC_VERB_DEBUG: + case NC_VERB_DEBUG_LOWLVL: + MP_LOG_I("[LIBNETCONF2] DEBUG: %s.\n", msg); + break; + default: + assert(false && "[LIBNETCONF2] Unknown log level."); + } +} + +static void ly_print_clb(LY_LOG_LEVEL level, const char *msg, const char *path) +{ + switch (level) { + case LY_LLERR: + MP_LOG_I("[LIBYANG] ERROR: %s (path: %s).\n", msg, path); + break; + case LY_LLWRN: + MP_LOG_I("[LIBYANG] WARNING: %s (path: %s).\n", msg, path); + break; + case LY_LLVRB: + MP_LOG_I("[LIBYANG] VERBOSE: %s (path: %s).\n", msg, path); + break; + case LY_LLDBG: + MP_LOG_I("[LIBYANG] DEBUG: %s (path: %s).\n", msg, path); + break; + default: + assert(false && "[LIBYANG] Unknown log level."); + } +} + +static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name) +{ + /* the config module does not know const-correctness... */ + int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name); + DevAssert(idx >= 0); + return &pd[idx]; +} + +bool init_mplane(ru_session_list_t *ru_session_list) +{ + paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC; + int nump = sizeofArray(fhip); + int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN); + if (ret <= 0) { + MP_LOG_I("Problem reading section \"%s\".\n", CONFIG_STRING_ORAN); + return false; + } + + ru_session_list->du_key_pair = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->strlistptr; + int num_keys = gpd(fhip, nump, ORAN_CONFIG_DU_KEYPAIR)->numelt; + AssertError(num_keys == 2, return false, "[MPLANE] Expected {pub-key-path, priv-key-path}. Loaded {%s, %s}.\n", ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]); + + char **ru_ip_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->strlistptr; + int num_rus = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->numelt; + char **du_mac_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr; + int num_dus = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt; + int32_t *vlan_tag = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->iptr; + int num_vlan_tags = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->numelt; + + AssertError(num_dus == num_vlan_tags, return false, "[MPLANE] Number of DU MAC addresses should be equal to the number of VLAN tags.\n"); + + int num_cu_planes = num_dus / num_rus; + + ru_session_list->num_rus = num_rus; + ru_session_list->ru_session = calloc(num_rus, sizeof(ru_session_t)); + for (size_t i = 0; i < num_rus; i++) { + ru_session_t *ru_session = &ru_session_list->ru_session[i]; + ru_session->session = NULL; + ru_session->ru_ip_add = calloc(strlen(ru_ip_addrs[i]) + 1, sizeof(char)); + memcpy(ru_session->ru_ip_add, ru_ip_addrs[i], strlen(ru_ip_addrs[i]) + 1); + + // store DU MAC addresses and VLAN tags + ru_session->ru_mplane_config.num_cu_planes = num_cu_planes; + ru_session->ru_mplane_config.du_mac_addr = calloc_or_fail(num_cu_planes, sizeof(char*)); + ru_session->ru_mplane_config.vlan_tag = calloc_or_fail(num_cu_planes, sizeof(int32_t)); + for (int j = 0; j < num_cu_planes; j++) { + const int idx = i*num_cu_planes+j; + ru_session->ru_mplane_config.du_mac_addr[j] = calloc(1, strlen(du_mac_addr[idx]) + 1); + memcpy(ru_session->ru_mplane_config.du_mac_addr[j], du_mac_addr[idx], strlen(du_mac_addr[idx]) + 1); + ru_session->ru_mplane_config.vlan_tag[j] = vlan_tag[idx]; + } + } + + nc_client_init(); + int keypair_ret = nc_client_ssh_add_keypair(ru_session_list->du_key_pair[0], ru_session_list->du_key_pair[1]); + AssertError(keypair_ret == 0, return false, "[MPLANE] Unable to add DU ssh key pair.\n"); + + // logs for netconf2 and yang libraries + nc_set_print_clb(lnc2_print_clb); + ly_set_log_clb(ly_print_clb, 1); + + return true; +} diff --git a/radio/fhi_72/mplane/init-mplane.h b/radio/fhi_72/mplane/init-mplane.h new file mode 100644 index 0000000000..ee558fd77d --- /dev/null +++ b/radio/fhi_72/mplane/init-mplane.h @@ -0,0 +1,30 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef OAI_MPLANE_H +#define OAI_MPLANE_H + +#include "ru-mplane-api.h" +#include "radio/COMMON/common_lib.h" + +bool init_mplane(ru_session_list_t *ru_session_list); + +#endif /* OAI_MPLANE_H */ diff --git a/radio/fhi_72/mplane/ru-mplane-api.h b/radio/fhi_72/mplane/ru-mplane-api.h new file mode 100644 index 0000000000..4b3b1719c1 --- /dev/null +++ b/radio/fhi_72/mplane/ru-mplane-api.h @@ -0,0 +1,95 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef RU_MPLANE_API_H +#define RU_MPLANE_API_H + +#include +#include +#include + +#include "common/utils/LOG/log.h" + +#define MP_LOG_I(x, args...) LOG_I(HW, "[MPLANE] " x, ##args) +#define MP_LOG_W(x, args...) LOG_W(HW, "[MPLANE] " x, ##args) + +typedef struct { + bool ptp_state; + bool rx_carrier_state; + bool tx_carrier_state; + // to be extended with any notification callback + +} ru_notif_t; + +typedef struct { + char *ru_mac_addr; + uint32_t mtu; + int16_t iq_width; + uint8_t prach_offset; + + // DU sends to RU and xran + uint16_t du_port_bitmask; + uint16_t band_sector_bitmask; + uint16_t ccid_bitmask; + uint16_t ru_port_bitmask; + + // DU retrieves from RU, and sends to xran + uint8_t du_port; + uint8_t band_sector; + uint8_t ccid; + uint8_t ru_port; + +} xran_mplane_t; + +typedef struct { + size_t num; + char **name; +} uplane_info_t; + +typedef struct { + size_t num_cu_planes; + char **du_mac_addr; // one or two VF(s) for CU-planes + int32_t *vlan_tag; // one or two VF(s) for CU-planes + char *interface_name; + uplane_info_t tx_endpoints; + uplane_info_t rx_endpoints; + uplane_info_t tx_carriers; + uplane_info_t rx_carriers; + +} ru_mplane_config_t; + +typedef struct { + char *ru_ip_add; + ru_mplane_config_t ru_mplane_config; + void *session; + xran_mplane_t xran_mplane; + ru_notif_t ru_notif; + +} ru_session_t; + +typedef struct { + size_t num_rus; + ru_session_t *ru_session; + char **du_key_pair; + +} ru_session_list_t; + +#endif /* RU_MPLANE_API_H */ diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index d3f4fa1796..0221892c37 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -39,6 +39,10 @@ // line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api #include "../../app/src/common.h" +#ifdef OAI_MPLANE +#include "mplane/init-mplane.h" +#endif + typedef struct { eth_state_t e; rru_config_msg_type_t last_msg; @@ -279,7 +283,32 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d openair0_config_t *openair0_cfg, eth_params_t *eth_params) { - oran_eth_state_t *eth; + oran_eth_state_t *eth = calloc_or_fail(1, sizeof(*eth)); + + struct xran_fh_init fh_init = {0}; + struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0}; + + bool success = false; +#ifdef OAI_MPLANE + ru_session_list_t ru_session_list = {0}; + success = init_mplane(&ru_session_list); + AssertFatal(success, "[MPLANE] Cannot initialize M-plane.\n"); +#else + success = get_xran_config(openair0_cfg, &fh_init, fh_config); + AssertFatal(success, "cannot get configuration for xran\n"); +#endif + + LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX); + eth->oran_priv = oai_oran_initialize(&fh_init, fh_config); + AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul"); + // create message queues for ORAN sync + + initNotifiedFIFO(&oran_sync_fifo); + + eth->e.flags = ETH_RAW_IF4p5_MODE; + eth->e.compression = NO_COMPRESS; + eth->e.if_name = eth_params->local_if_name; + eth->last_msg = (rru_config_msg_type_t)-1; device->Mod_id = 0; device->transp_type = ETHERNET_TP; @@ -290,43 +319,13 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d device->trx_stop_func = trx_oran_stop; device->trx_set_freq_func = trx_oran_set_freq; device->trx_set_gains_func = trx_oran_set_gains; - device->trx_write_func = trx_oran_write_raw; device->trx_read_func = trx_oran_read_raw; - device->trx_ctlsend_func = trx_oran_ctlsend; device->trx_ctlrecv_func = trx_oran_ctlrecv; - device->get_internal_parameter = get_internal_parameter; - - eth = (oran_eth_state_t *)calloc(1, sizeof(oran_eth_state_t)); - if (eth == NULL) { - AssertFatal(0 == 1, "out of memory\n"); - } - - eth->e.flags = ETH_RAW_IF4p5_MODE; - eth->e.compression = NO_COMPRESS; - eth->e.if_name = eth_params->local_if_name; - eth->oran_priv = NULL; // define_oran_pointer(); device->priv = eth; device->openair0_cfg = &openair0_cfg[0]; - eth->last_msg = (rru_config_msg_type_t)-1; - - LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX); - - initNotifiedFIFO(&oran_sync_fifo); - - struct xran_fh_init fh_init = {0}; - struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0}; -#ifndef OAI_MPLANE_SUPPORT - bool success = get_xran_config(openair0_cfg, &fh_init, fh_config); - AssertFatal(success, "cannot get configuration for xran\n"); -#else - /* TODO: M-plane integration */ -#endif - eth->oran_priv = oai_oran_initialize(&fh_init, fh_config); - AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul"); - // create message queues for ORAN sync return 0; } From 3f98ec50ef5cab9e2813dbb74c0b4cfd2745c024 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 12:15:42 +0100 Subject: [PATCH 34/55] Add ssh connect function for M-plane --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/connect-mplane.c | 57 ++++++++++++++++++++++++++++ radio/fhi_72/mplane/connect-mplane.h | 29 ++++++++++++++ radio/fhi_72/oran_isolate.c | 10 +++++ 4 files changed, 97 insertions(+) create mode 100644 radio/fhi_72/mplane/connect-mplane.c create mode 100644 radio/fhi_72/mplane/connect-mplane.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 7cc53dd40f..b699c35094 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -26,6 +26,7 @@ target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE) target_sources(oran_fhlib_5g_mplane PRIVATE init-mplane.c + connect-mplane.c ) pkg_check_modules(libyang REQUIRED libyang) diff --git a/radio/fhi_72/mplane/connect-mplane.c b/radio/fhi_72/mplane/connect-mplane.c new file mode 100644 index 0000000000..7f4e5e40e6 --- /dev/null +++ b/radio/fhi_72/mplane/connect-mplane.c @@ -0,0 +1,57 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "connect-mplane.h" +#include "common/utils/assertions.h" + +#include +#include + +static int my_auth_hostkey_check(const char *hostname, ssh_session session, void *priv) +{ + (void)hostname; + (void)session; + (void)priv; + + return 0; +} + +bool connect_mplane(ru_session_t *ru_session) +{ + int port = NC_PORT_SSH; + char *user = "oranbenetel"; + + nc_client_ssh_set_username(user); + + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); // ssh-key identification + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); + nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1); + + nc_client_ssh_set_auth_hostkey_check_clb(my_auth_hostkey_check, "DATA"); // host-key identification + + MP_LOG_I("RPC request to RU \"%s\" = with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port); + ru_session->session = nc_connect_ssh(ru_session->ru_ip_add, port, NULL); + AssertError(ru_session->session != NULL, return false, "[MPLANE] RU IP address %s unreachable. Maybe M-plane is disabled on the RU?\n", ru_session->ru_ip_add); + + MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port); + + return true; +} diff --git a/radio/fhi_72/mplane/connect-mplane.h b/radio/fhi_72/mplane/connect-mplane.h new file mode 100644 index 0000000000..5283e6ef75 --- /dev/null +++ b/radio/fhi_72/mplane/connect-mplane.h @@ -0,0 +1,29 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef CONNECT_MPLANE_H +#define CONNECT_MPLANE_H + +#include "ru-mplane-api.h" + +bool connect_mplane(ru_session_t *ru_session); + +#endif /* CONNECT_MPLANE_H */ diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 0221892c37..a249924731 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -41,6 +41,7 @@ #ifdef OAI_MPLANE #include "mplane/init-mplane.h" +#include "mplane/connect-mplane.h" #endif typedef struct { @@ -293,6 +294,15 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d ru_session_list_t ru_session_list = {0}; success = init_mplane(&ru_session_list); AssertFatal(success, "[MPLANE] Cannot initialize M-plane.\n"); + + bool ru_configured[ru_session_list.num_rus]; + for (size_t i = 0; i < ru_session_list.num_rus; i++) { + ru_session_t *ru_session = &ru_session_list.ru_session[i]; + ru_configured[i] = connect_mplane(ru_session); + if (!ru_configured[i]) { + continue; + } + } #else success = get_xran_config(openair0_cfg, &fh_init, fh_config); AssertFatal(success, "cannot get configuration for xran\n"); From 93aaaef50e1e23b2d275777fc515fc567f703e88 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 13:06:59 +0100 Subject: [PATCH 35/55] Add RPC send and receive functionalities --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/rpc-send-recv.c | 296 ++++++++++++++++++++++++++++ radio/fhi_72/mplane/rpc-send-recv.h | 34 ++++ 3 files changed, 331 insertions(+) create mode 100644 radio/fhi_72/mplane/rpc-send-recv.c create mode 100644 radio/fhi_72/mplane/rpc-send-recv.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index b699c35094..f58238024e 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -27,6 +27,7 @@ target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE) target_sources(oran_fhlib_5g_mplane PRIVATE init-mplane.c connect-mplane.c + rpc-send-recv.c ) pkg_check_modules(libyang REQUIRED libyang) diff --git a/radio/fhi_72/mplane/rpc-send-recv.c b/radio/fhi_72/mplane/rpc-send-recv.c new file mode 100644 index 0000000000..4b218fc164 --- /dev/null +++ b/radio/fhi_72/mplane/rpc-send-recv.c @@ -0,0 +1,296 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "rpc-send-recv.h" + +#include "common/utils/assertions.h" + + +#ifdef MPLANE_V1 +static bool recv_v1(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer) +{ + struct nc_reply *reply; + struct nc_reply_data *data_rpl; + struct nc_reply_error *error; + LYD_FORMAT output_format = LYD_XML; + uint32_t ly_wd; + + while (1) { + msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, 0, &reply); + if (msgtype == NC_MSG_ERROR) { + AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n"); + } else if (msgtype == NC_MSG_WOULDBLOCK) { + AssertError(false, return false, "[MPLANE] Timeout for receiving a reply expired.\n"); + } else if (msgtype == NC_MSG_NOTIF) { + /* read again */ + continue; + } else if (msgtype == NC_MSG_REPLY_ERR_MSGID) { + /* unexpected message, try reading again to get the correct reply */ + MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n"); + nc_reply_free(reply); + continue; + } + break; + } + + switch (reply->type) { + case NC_RPL_OK: + MP_LOG_I("RPC reply = OK.\n"); + break; + case NC_RPL_DATA: + data_rpl = (struct nc_reply_data *)reply; + + switch (wd_mode) { + case NC_WD_ALL: + ly_wd = LYP_WD_ALL; + break; + case NC_WD_ALL_TAG: + ly_wd = LYP_WD_ALL_TAG; + break; + case NC_WD_TRIM: + ly_wd = LYP_WD_TRIM; + break; + case NC_WD_EXPLICIT: + ly_wd = LYP_WD_EXPLICIT; + break; + default: + ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN + break; + } + + if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) { + AssertError((!data_rpl->data || (data_rpl->data->schema->nodetype != LYS_RPC) || (data_rpl->data->child == NULL) + || (data_rpl->data->child->schema->nodetype != LYS_ANYXML)), return false, "[MPLANE] Cannot get schema.\n"); + + struct lyd_node_anydata *any = (struct lyd_node_anydata *)data_rpl->data->child; + switch (any->value_type) { + case LYD_ANYDATA_CONSTSTRING: + case LYD_ANYDATA_STRING: + *answer = strdup(any->value.str); + break; + case LYD_ANYDATA_DATATREE: + lyd_print_mem(answer, any->value.tree, output_format, LYP_WITHSIBLINGS); + break; + case LYD_ANYDATA_XML: + lyxml_print_mem(answer, any->value.xml, LYXML_PRINT_SIBLINGS); + break; + default: + AssertError(false, return false, "[MPLANE] Unknown yang type.\n"); + } + break; + } else if (nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG || nc_rpc_get_type(rpc) == NC_RPC_GET) { + const char *tag = nc_rpc_get_type(rpc) == NC_RPC_GETCONFIG ? "config" : "data"; + char *buffer = NULL; + lyd_print_mem(&buffer, data_rpl->data, output_format, LYP_WITHSIBLINGS | LYP_NETCONF | ly_wd); + *answer = calloc(strlen(buffer)+128, sizeof(char)); + sprintf(*answer, "<%s xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n%s", tag, buffer, tag); + } else { + AssertError(false, return false, "[MPLANE] Unknown RPC type.\n"); + } + + break; + case NC_RPL_ERROR: + error = (struct nc_reply_error *)reply; + for (int i = 0; i < error->count; ++i) { + const struct nc_err *err = &error->err[i]; + MP_LOG_I("RPC reply = ERROR\n\ + \ttype: %s\n\ + \ttag: %s\n\ + \tseverity: %s\n\ + \tapp-tag: %s\n\ + \tpath: %s\n\ + \tmessage: %s\n\ + \tSID: %s\n", + err->type, + err->tag, + err->severity, + err->apptag, + err->path, + err->message, + err->sid); + + for (int j = 0; j < err->attr_count; ++j) { + MP_LOG_I("\tbad-attr #%d: %s\n", j + 1, err->attr[j]); + } + for (int j = 0; j < err->elem_count; ++j) { + MP_LOG_I("\tbad-elem #%d: %s\n", j + 1, err->elem[j]); + } + for (int j = 0; j < err->ns_count; ++j) { + MP_LOG_I("\tbad-ns #%d: %s\n", j + 1, err->ns[j]); + } + for (int j = 0; j < err->other_count; ++j) { + char *str = NULL; + lyxml_print_mem(&str, err->other[j], 0); + MP_LOG_I("\tother #%d:\n%s\n", j + 1, str); + free(str); + } + } + AssertError(false, return false, "[MPLANE] Unable to continue.\n"); + break; + default: + AssertError(false, return false, "[MPLANE] Internal error.\n"); + nc_reply_free(reply); + } + nc_reply_free(reply); + + return true; +} +#elif defined MPLANE_V2 +static bool recv_v2(struct nc_session *session, struct nc_rpc *rpc, NC_MSG_TYPE msgtype, const uint64_t msgid, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer) +{ + struct lyd_node *envp, *op, *err; + LYD_FORMAT output_format = LYD_XML; + uint32_t ly_wd; + + while (1) { + msgtype = nc_recv_reply(session, rpc, msgid, timeout_ms, &envp, &op); + if (msgtype == NC_MSG_ERROR) { + AssertError(false, return false, "[MPLANE] Failed to receive a reply.\n"); + } else if (msgtype == NC_MSG_WOULDBLOCK) { + AssertError(false, return false, "[MPLANE] Timeout for receiving a reply for RPC expired.\n"); + } else if (msgtype == NC_MSG_NOTIF) { // for SUBSCRIBE + /* read again */ + continue; + } else if (msgtype == NC_MSG_REPLY_ERR_MSGID) { + /* unexpected message, try reading again to get the correct reply */ + MP_LOG_I("Unexpected reply received - ignoring and waiting for the correct reply.\n"); + lyd_free_tree(envp); + lyd_free_tree(op); + continue; + } + break; + } + + /* get functionality */ + if (op) { + /* data reply */ + if (nc_rpc_get_type(rpc) == NC_RPC_GETSCHEMA) { + /* special case */ + if (!lyd_child(op) || (lyd_child(op)->schema->nodetype != LYS_ANYXML)) { + AssertError(false, return false, "[MPLANE] Cannot get schema."); + } + struct lyd_node_any *any = (struct lyd_node_any *)lyd_child(op); + switch (any->value_type) { + case LYD_ANYDATA_STRING: + case LYD_ANYDATA_XML: + *answer = strdup(any->value.str); + break; + case LYD_ANYDATA_DATATREE: + lyd_print_mem(answer, any->value.tree, output_format, LYD_PRINT_WITHSIBLINGS); + break; + default: + AssertError(false, return false, "[MPLANE] Unexpected yang type."); + } + } else { + switch (wd_mode) { + case NC_WD_ALL: + ly_wd = LYD_PRINT_WD_ALL; + break; + case NC_WD_ALL_TAG: + ly_wd = LYD_PRINT_WD_ALL_TAG; + break; + case NC_WD_TRIM: + ly_wd = LYD_PRINT_WD_TRIM; + break; + case NC_WD_EXPLICIT: + ly_wd = LYD_PRINT_WD_EXPLICIT; + break; + default: + ly_wd = 0; // when wd_mode = NC_WD_UNKNOWN + break; + } + lyd_print_mem(answer, lyd_child(op), output_format, LYD_PRINT_WITHSIBLINGS | ly_wd); + } + /* edit/validate/commit functionalities */ + } else if (!strcmp(LYD_NAME(lyd_child(envp)), "ok")) { + MP_LOG_I("RPC reply = OK.\n"); + } else { + LY_LIST_FOR(lyd_child(envp), err) { + struct lyd_node *type, *tag, *severity, *app_tag, *path, *er_msg, *info = NULL; + lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &type); + lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &tag); + lyd_find_sibling_opaq_next(lyd_child(err), "error-severity", &severity); + lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &app_tag); + lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &path); + lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &er_msg); + + MP_LOG_I("RPC reply = ERROR\n\ + \ttype: %s\n\ + \ttag: %s\n\ + \tseverity: %s\n\ + \tapp-tag: %s\n\ + \tpath: %s\n\ + \tmessage: %s\n", + (type ? ((struct lyd_node_opaq *)type)->value : NULL), + (tag ? ((struct lyd_node_opaq *)tag)->value : NULL), + (severity ? ((struct lyd_node_opaq *)severity)->value : NULL), + (app_tag ? ((struct lyd_node_opaq *)app_tag)->value : NULL), + (path ? ((struct lyd_node_opaq *)path)->value : NULL), + (er_msg ? ((struct lyd_node_opaq *)er_msg)->value : NULL)); + + info = lyd_child(err); + while (!lyd_find_sibling_opaq_next(info, "error-info", &info)) { + char *str = NULL; + lyd_print_mem(&str, lyd_child(info), output_format, LYD_PRINT_WITHSIBLINGS); + MP_LOG_I("\tinfo: %s\n", str); + info = info->next; + free(str); + } + lyd_free_tree(type); + lyd_free_tree(tag); + lyd_free_tree(severity); + lyd_free_tree(app_tag); + lyd_free_tree(path); + lyd_free_tree(er_msg); + lyd_free_tree(info); + } + lyd_free_tree(envp); + lyd_free_tree(op); + AssertError(false, return false, "[MPLANE] Unable to continue.\n"); + } + + lyd_free_tree(envp); + lyd_free_tree(op); + + return true; +} +#endif + +bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer) +{ + uint64_t msgid; + NC_MSG_TYPE msgtype; + + msgtype = nc_send_rpc(session, rpc, 1000, &msgid); + if (msgtype == NC_MSG_ERROR) { + AssertError(false, return false, "[MPLANE] Failed to send the RPC.\n"); + } else if (msgtype == NC_MSG_WOULDBLOCK) { + AssertError(false, return false, "[MPLANE] Timeout for sending the RPC expired.\n"); + } + +#ifdef MPLANE_V1 + return recv_v1(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer); +#elif defined MPLANE_V2 + return recv_v2(session, rpc, msgtype, msgid, wd_mode, timeout_ms, answer); +#else + AssertError(false, return false, "[MPLANE] Unknown M-plane version found. Tried \"MPLANE_V1\" and \"MPLANE_V2\".\n"); +#endif +} diff --git a/radio/fhi_72/mplane/rpc-send-recv.h b/radio/fhi_72/mplane/rpc-send-recv.h new file mode 100644 index 0000000000..4cf2095713 --- /dev/null +++ b/radio/fhi_72/mplane/rpc-send-recv.h @@ -0,0 +1,34 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef RPC_SEND_RECEIVE_MPLANE_H +#define RPC_SEND_RECEIVE_MPLANE_H + +#include "ru-mplane-api.h" + +#include +#include + +#define CLI_RPC_REPLY_TIMEOUT 60000 // time [ms] to wait for server reply + +bool rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc, const NC_WD_MODE wd_mode, const int timeout_ms, char **answer); + +#endif /* RPC_SEND_RECEIVE_MPLANE_H */ From d9e3725a21d992405a12cfcff68953279f68c36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Soares=20Silva?= Date: Thu, 6 Mar 2025 11:37:17 +0000 Subject: [PATCH 36/55] Unpack SRS report TLV not expecting padding to be present Add a function pullx32 to pull x amount of bytes into uint32_t Change the unpacking to pull only the needed bytes, and skip over the padding, when not Aerial Change SRS.indication dumping function to also print the report TLV contents Change SRS.indication unitary test to fill the last 4 byte block of the report TLV according to the length, with padding --- nfapi/oai_integration/aerial/fapi_vnf_p7.c | 7 ++--- nfapi/open-nFAPI/common/public_inc/nfapi.h | 12 +++++++++ nfapi/open-nFAPI/common/src/nfapi.c | 25 +++++++++++++++++ nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h | 1 + nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c | 28 +++++++++++++++++--- nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c | 14 +++++++++- nfapi/tests/p7/nr_fapi_srs_indication_test.c | 9 ++++--- 7 files changed, 83 insertions(+), 13 deletions(-) diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p7.c b/nfapi/oai_integration/aerial/fapi_vnf_p7.c index 263df7bd8a..cb8fa4550f 100644 --- a/nfapi/oai_integration/aerial/fapi_vnf_p7.c +++ b/nfapi/oai_integration/aerial/fapi_vnf_p7.c @@ -309,11 +309,8 @@ uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, nfapi_nr_srs_indication_t *srs_ind = (nfapi_nr_srs_indication_t *)msg; for (uint8_t pdu_idx = 0; pdu_idx < srs_ind->number_of_pdus; pdu_idx++) { nfapi_nr_srs_indication_pdu_t *pdu = &srs_ind->pdu_list[pdu_idx]; - nfapi_srs_report_tlv_t *report_tlv = &pdu->report_tlv; - for (int i = 0; i < (report_tlv->length + 3) / 4; i++) { - if (!pull32(pDataMsg, &report_tlv->value[i], data_end)) { - return 0; - } + if (!unpack_nr_srs_report_tlv_value(&pdu->report_tlv, pDataMsg, data_end)) { + return 0; } } return retval; diff --git a/nfapi/open-nFAPI/common/public_inc/nfapi.h b/nfapi/open-nFAPI/common/public_inc/nfapi.h index 99c7d7ec7e..2cb9cee996 100644 --- a/nfapi/open-nFAPI/common/public_inc/nfapi.h +++ b/nfapi/open-nFAPI/common/public_inc/nfapi.h @@ -36,6 +36,18 @@ uint8_t pull8(uint8_t **in, uint8_t *out, uint8_t *end); uint8_t pulls8(uint8_t **in, int8_t *out, uint8_t *end); uint8_t pull16(uint8_t **in, uint16_t *out, uint8_t *end); uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end); + + /*! \brief Pull an arbitrary amount of bytes ( 0 to 4 ) into an uint32_t + * \param length the amount of bytes to pull + * \param in the buffer from where to pull the bytes + * \param out a pointer to the destination uint32_t + * \param end a pointer to the end of the buffer in + * + * This function is used to pull `length` amount of bytes from `in` into `out`. + * Used where pulling the full 32 bits would cause the `in` pointer to go over `end`. + * It's currently used to pull the last bytes of a payload where the buffer does not contain padding at the end. + */ +uint8_t pullx32(uint8_t length, uint8_t **in, uint32_t *out, uint8_t *end); uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end); uint8_t pulls32(uint8_t **in, int32_t *out, uint8_t *end); diff --git a/nfapi/open-nFAPI/common/src/nfapi.c b/nfapi/open-nFAPI/common/src/nfapi.c index 97352b98f7..716387ae7d 100644 --- a/nfapi/open-nFAPI/common/src/nfapi.c +++ b/nfapi/open-nFAPI/common/src/nfapi.c @@ -259,6 +259,31 @@ uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end) } } +uint8_t pullx32(uint8_t length, uint8_t **in, uint32_t *out, uint8_t *end) +{ + uint8_t *pIn = *in; + if (length > 4) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s Can't pull more than 4 bytes (%d) into a uint32_t\n", __FUNCTION__, length); + on_error(); + return 0; + } + if ((end - pIn) >= length) { + for (int i = 0; i < length; i++) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + *out |= ((uint32_t)pIn[i] << (8 * i)); +#else + *out = ((uint32_t)pIn[i] << (8 * (length - 1 - i))); +#endif + } + (*in) += length; + return length; + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s no space in buffer\n", __FUNCTION__); + on_error(); + return 0; + } +} + uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end) { uint8_t *pIn = *in; diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h index 76e2043f2d..c2701acb5f 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h @@ -50,6 +50,7 @@ uint8_t pack_nr_uci_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e uint8_t unpack_nr_uci_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config); uint8_t pack_nr_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *config); uint8_t unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config); +uint8_t unpack_nr_srs_report_tlv_value(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end); uint8_t pack_nr_rach_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *config); uint8_t unpack_nr_rach_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config); #endif // OPENAIRINTERFACE_NR_FAPI_P7_H diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c index a247541315..7b840fc126 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c @@ -2300,6 +2300,28 @@ uint8_t pack_nr_srs_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e return 1; } +uint8_t unpack_nr_srs_report_tlv_value(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ +#ifndef ENABLE_AERIAL + for (int i = 0; i < (report_tlv->length + 3) / 4; i++) { + if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) { + return 0; + } + } +#else + const uint16_t last_idx = ((report_tlv->length + 3) / 4) - 1; + for (int i = 0; i < last_idx; i++) { + if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) { + return 0; + } + } + // Pull last bytes according to how much padding it would need to be 32-bit aligned + const uint8_t padding = get_tlv_padding(report_tlv->length); + pullx32(4 - padding, ppReadPackedMsg, &report_tlv->value[last_idx], end); +#endif + return 1; +} + static uint8_t unpack_nr_srs_report_tlv(nfapi_srs_report_tlv_t *report_tlv, uint8_t **ppReadPackedMsg, uint8_t *end) { if(!(pull16(ppReadPackedMsg, &report_tlv->tag, end) && @@ -2307,10 +2329,8 @@ static uint8_t unpack_nr_srs_report_tlv(nfapi_srs_report_tlv_t *report_tlv, uint return 0; } #ifndef ENABLE_AERIAL - for (int i = 0; i < (report_tlv->length + 3) / 4; i++) { - if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) { - return 0; - } + if (!unpack_nr_srs_report_tlv_value(report_tlv, ppReadPackedMsg, end)) { + return 0; } #endif return 1; diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c index c753cbcb1c..9939a6f535 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c @@ -2684,6 +2684,18 @@ void dump_uci_indication(const nfapi_nr_uci_indication_t *msg) } } +static void dump_srs_report_tlv(const nfapi_srs_report_tlv_t* tlv, int depth) +{ + depth++; + INDENTED_PRINTF("TAG = 0x%02x\n", tlv->tag); + INDENTED_PRINTF("LENGTH = 0x%02x\n", tlv->length); + INDENTED_PRINTF("VALUE = "); + for (int i = 0; i < ((tlv->length + 3) / 4); ++i) { + printf("0x%04x ", tlv->value[i]); + } + printf("\n"); +} + void dump_srs_indication(const nfapi_nr_srs_indication_t *msg) { int depth = 0; @@ -2704,7 +2716,7 @@ void dump_srs_indication(const nfapi_nr_srs_indication_t *msg) INDENTED_PRINTF("Timing advance offset in nanoseconds = 0x%02x\n", pdu->timing_advance_offset_nsec); INDENTED_PRINTF("SRS usage = 0x%02x\n", pdu->srs_usage); INDENTED_PRINTF("Report Type = 0x%02x\n", pdu->report_type); - /* call to dump_srs_report_tlv */ + dump_srs_report_tlv(&pdu->report_tlv, depth); depth--; } } diff --git a/nfapi/tests/p7/nr_fapi_srs_indication_test.c b/nfapi/tests/p7/nr_fapi_srs_indication_test.c index 49b73fd8f5..1271606b77 100644 --- a/nfapi/tests/p7/nr_fapi_srs_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_srs_indication_test.c @@ -24,11 +24,14 @@ static void fil_srs_indication_report_tlv(nfapi_srs_report_tlv_t *tlv) { - tlv->tag = rand16_range(0,3); - tlv->length = rand32_range(0,sizeof(tlv->value)); - for (int i = 0; i < (tlv->length + 3) / 4; ++i) { + tlv->tag = rand16_range(0, 3); + tlv->length = rand32_range(1, sizeof(tlv->value)); + const uint16_t last_idx = ((tlv->length + 3) / 4) - 1; + for (int i = 0; i < last_idx; ++i) { tlv->value[i] = rand32(); } + const uint8_t num_bytes = 4 - get_tlv_padding(tlv->length); + tlv->value[last_idx] = rand32_range(0, 1 << (8 * num_bytes)); } static void fill_srs_indication_PDU(nfapi_nr_srs_indication_pdu_t *pdu) From 064866459c71513d347e6a68095b4aac8bf47a0c Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 14:40:00 +0100 Subject: [PATCH 37/55] Add RPC for M-plane --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/get-mplane.c | 47 ++++++++++++++++++++++++++++++ radio/fhi_72/mplane/get-mplane.h | 29 ++++++++++++++++++ radio/fhi_72/mplane/init-mplane.c | 14 +++++++++ radio/fhi_72/mplane/init-mplane.h | 2 ++ radio/fhi_72/oran_isolate.c | 1 + 6 files changed, 94 insertions(+) create mode 100644 radio/fhi_72/mplane/get-mplane.c create mode 100644 radio/fhi_72/mplane/get-mplane.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index f58238024e..2699beb6d9 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -28,6 +28,7 @@ target_sources(oran_fhlib_5g_mplane PRIVATE init-mplane.c connect-mplane.c rpc-send-recv.c + get-mplane.c ) pkg_check_modules(libyang REQUIRED libyang) diff --git a/radio/fhi_72/mplane/get-mplane.c b/radio/fhi_72/mplane/get-mplane.c new file mode 100644 index 0000000000..06aa6d0317 --- /dev/null +++ b/radio/fhi_72/mplane/get-mplane.c @@ -0,0 +1,47 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "get-mplane.h" +#include "rpc-send-recv.h" + +#include "common/utils/assertions.h" + +bool get_mplane(ru_session_t *ru_session, char **answer) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + char *filter = NULL; // e.g. "/o-ran-delay-management:delay-management"; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + + MP_LOG_I("RPC request to RU \"%s\" = operational datastore.\n", ru_session->ru_ip_add); + rpc = nc_rpc_get(filter, wd, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, answer); + AssertError(success, return false, "[MPLANE] Unable to retrieve operational datastore.\n"); + + MP_LOG_I("Successfully retrieved operational datastore from RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + + return true; +} diff --git a/radio/fhi_72/mplane/get-mplane.h b/radio/fhi_72/mplane/get-mplane.h new file mode 100644 index 0000000000..a47abdc8f5 --- /dev/null +++ b/radio/fhi_72/mplane/get-mplane.h @@ -0,0 +1,29 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef GET_MPLANE_H +#define GET_MPLANE_H + +#include "ru-mplane-api.h" + +bool get_mplane(ru_session_t *ru_session, char **answer); + +#endif /* GET_MPLANE_H */ diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 31988f3dba..cd83ccc4f6 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -21,6 +21,7 @@ #include "init-mplane.h" #include "radio/fhi_72/oran-params.h" +#include "get-mplane.h" #include #include @@ -129,3 +130,16 @@ bool init_mplane(ru_session_list_t *ru_session_list) return true; } + +bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus) +{ + bool success = false; + + char *operational_ds = NULL; + success = get_mplane(ru_session, &operational_ds); + AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via get_mplane().\n"); + + free(operational_ds); + + return true; +} diff --git a/radio/fhi_72/mplane/init-mplane.h b/radio/fhi_72/mplane/init-mplane.h index ee558fd77d..5077908d64 100644 --- a/radio/fhi_72/mplane/init-mplane.h +++ b/radio/fhi_72/mplane/init-mplane.h @@ -27,4 +27,6 @@ bool init_mplane(ru_session_list_t *ru_session_list); +bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus); + #endif /* OAI_MPLANE_H */ diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index a249924731..8104b1a2c2 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -302,6 +302,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d if (!ru_configured[i]) { continue; } + ru_configured[i] = manage_ru(ru_session, openair0_cfg, ru_session_list.num_rus); } #else success = get_xran_config(openair0_cfg, &fh_init, fh_config); From fb670db91e7143bf054352997c3edf3b421de28c Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 14:51:42 +0100 Subject: [PATCH 38/55] Get info from xml operational datastore - obtain one or multiple node values --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/xml/get-xml.c | 95 ++++++++++++++++++++++++++++++ radio/fhi_72/mplane/xml/get-xml.h | 48 +++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 radio/fhi_72/mplane/xml/get-xml.c create mode 100644 radio/fhi_72/mplane/xml/get-xml.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 2699beb6d9..1d00c26ab2 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -29,6 +29,7 @@ target_sources(oran_fhlib_5g_mplane PRIVATE connect-mplane.c rpc-send-recv.c get-mplane.c + xml/get-xml.c ) pkg_check_modules(libyang REQUIRED libyang) diff --git a/radio/fhi_72/mplane/xml/get-xml.c b/radio/fhi_72/mplane/xml/get-xml.c new file mode 100644 index 0000000000..616d2e480f --- /dev/null +++ b/radio/fhi_72/mplane/xml/get-xml.c @@ -0,0 +1,95 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "get-xml.h" + +#include +#include + +static char *find_ru_xml_node(xmlNode *node, const char *filter) +{ + for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) { + if (cur_node->type != XML_ELEMENT_NODE) + continue; + + if (strcmp((const char *)cur_node->name, filter) == 0) { + xmlNode *target_node = cur_node; + + for(xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) { + if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) { + target_node = cur_node2; + break; + } + } + return (char *)xmlNodeGetContent(target_node); + } + char *answer = find_ru_xml_node(cur_node->children, filter); + if (answer != NULL) { + return answer; + } + } + return NULL; +} + +char *get_ru_xml_node(const char *buffer, const char *filter) +{ + // Initialize the xml file + size_t len = strlen(buffer) + 1; + xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0); + xmlNode *root_element = xmlDocGetRootElement(doc); + + return find_ru_xml_node(root_element->children, filter); +} + +static void find_ru_xml_list(xmlNode *node, const char *filter, char ***match_list, size_t *count) +{ + for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) { + if (cur_node->type != XML_ELEMENT_NODE) + continue; + if (strcmp((const char *)cur_node->name, filter) == 0) { + xmlNode *name_node = NULL; + + for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) { + if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) { + name_node = cur_node2; + break; + } + } + const char *content = (const char *)xmlNodeGetContent(name_node ? name_node : cur_node); + if (content) { + *match_list = realloc(*match_list, (*count + 1) * sizeof(char *)); + (*match_list)[*count] = strdup(content); + (*count)++; + } + } + find_ru_xml_list(cur_node->children, filter, match_list, count); + } +} + +void get_ru_xml_list(const char *buffer, const char *filter, char ***match_list, size_t *count) +{ + // Initialize the xml file + size_t len = strlen(buffer) + 1; + xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0); + xmlNode *root_element = xmlDocGetRootElement(doc); + + find_ru_xml_list(root_element->children, filter, match_list, count); +} diff --git a/radio/fhi_72/mplane/xml/get-xml.h b/radio/fhi_72/mplane/xml/get-xml.h new file mode 100644 index 0000000000..5241e64af6 --- /dev/null +++ b/radio/fhi_72/mplane/xml/get-xml.h @@ -0,0 +1,48 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef GET_MPLANE_INFO_XML_H +#define GET_MPLANE_INFO_XML_H + +#include +#include + +/** + * @brief retrieves the node value that matches filter. + * + * @param[in] buffer Buffer in xml format. + * @param[in] filter The node name (matching criteria). + * @return Expected one string that matches the node name. + */ +char *get_ru_xml_node(const char *buffer, const char *filter); + +/** + * @brief retrieves the node values that matches filter. + * + * @param[in] buffer Buffer in xml format. + * @param[in] filter The node name (matching criteria). + * @param[out] match_list Resulting list containing node values. + * @param[out] count The number of nodes that match criteria. + * @return Void. + */ +void get_ru_xml_list(const char *buffer, const char *filter, char ***match_list, size_t *count); + +#endif /* GET_MPLANE_INFO_XML_H */ From 07bab2a707110855d963e9844d0fb34617e7c028 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 15:01:30 +0100 Subject: [PATCH 39/55] Get the current sync status from operational datastore --- radio/fhi_72/mplane/init-mplane.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index cd83ccc4f6..e9c91387db 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -22,6 +22,7 @@ #include "init-mplane.h" #include "radio/fhi_72/oran-params.h" #include "get-mplane.h" +#include "xml/get-xml.h" #include #include @@ -139,6 +140,13 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz success = get_mplane(ru_session, &operational_ds); AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via get_mplane().\n"); + bool ptp_state = false; + const char *sync_state = get_ru_xml_node(operational_ds, "sync-state"); + if (strcmp(sync_state, "LOCKED") == 0) { + MP_LOG_I("RU is already PTP synchronized.\n"); + ptp_state = true; + } + free(operational_ds); return true; From 6266239c34e2b440d0af697c3d36eaa31d4539f9 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 15:21:37 +0100 Subject: [PATCH 40/55] Add RPC for M-plane --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/init-mplane.c | 12 +++ radio/fhi_72/mplane/subscribe-mplane.c | 133 +++++++++++++++++++++++++ radio/fhi_72/mplane/subscribe-mplane.h | 31 ++++++ 4 files changed, 177 insertions(+) create mode 100644 radio/fhi_72/mplane/subscribe-mplane.c create mode 100644 radio/fhi_72/mplane/subscribe-mplane.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 1d00c26ab2..0092f96698 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -29,6 +29,7 @@ target_sources(oran_fhlib_5g_mplane PRIVATE connect-mplane.c rpc-send-recv.c get-mplane.c + subscribe-mplane.c xml/get-xml.c ) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index e9c91387db..72f6d46701 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -22,6 +22,7 @@ #include "init-mplane.h" #include "radio/fhi_72/oran-params.h" #include "get-mplane.h" +#include "subscribe-mplane.h" #include "xml/get-xml.h" #include @@ -147,6 +148,17 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz ptp_state = true; } + /* 1) as per M-plane spec, RU must be in supervised mode, + where stream = NULL && filter = "/o-ran-supervision:supervision-notification"; + 2) additionally, we want to subscribe to PTP state change, + where stream = NULL && filter = "/o-ran-sync:synchronization-state-change"; + => since more than one subscription at the time within one session is not possible, we will subscribe to all notifications */ + const char *stream = "NETCONF"; + const char *filter = NULL; + ru_session->ru_notif.ptp_state = ptp_state; + success = subscribe_mplane(ru_session, stream, filter, (void *)&ru_session->ru_notif); + AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via subscribe_mplane().\n"); + free(operational_ds); return true; diff --git a/radio/fhi_72/mplane/subscribe-mplane.c b/radio/fhi_72/mplane/subscribe-mplane.c new file mode 100644 index 0000000000..64215c0aba --- /dev/null +++ b/radio/fhi_72/mplane/subscribe-mplane.c @@ -0,0 +1,133 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "subscribe-mplane.h" +#include "rpc-send-recv.h" +#include "common/utils/assertions.h" + +#include +#include + +#ifdef MPLANE_V1 +static void recv_notif_v1(const struct nc_notif *notif, ru_notif_t *answer) +{ + const char *node_name = notif->tree->child->attr->name; + const char *value = notif->tree->child->attr->value_str; + if (strcmp(node_name, "sync-state")) { + if (strcmp(value, "LOCKED") == 0) { + answer->ptp_state = true; + } else { + answer->ptp_state = false; + } + } + + // carriers state - to be filled +} + +static void notif_clb_v1(struct nc_session *session, const struct nc_notif *notif) +{ + ru_notif_t *answer = nc_session_get_data(session); + LYD_FORMAT output_format = LYD_JSON; + + char *subs_reply = NULL; + lyd_print_mem(&subs_reply, notif->tree, output_format, LYP_WITHSIBLINGS); + MP_LOG_I("\nReceived notification at (%s)\n%s\n", notif->datetime, subs_reply); + + recv_notif_v1(notif, answer); +} +#elif MPLANE_V2 +static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer) +{ + const char *notif = op->schema->name; + + if (strcmp(notif, "synchronization-state-change") == 0) { + const char *value = lyd_get_value(op->child); + if (strcmp(value, "LOCKED") == 0) { + answer->ptp_state = true; + } else { // "FREERUN" or "HOLDOVER" + answer->ptp_state = false; + } + } else if (strcmp(notif, "rx-array-carriers-state-change") == 0) { + const char *value = lyd_get_value(lyd_child(op->child)->next); + if (strcmp(value, "READY") == 0) { + answer->rx_carrier_state = true; + } else { // "DISABLED" or "BUSY" + answer->rx_carrier_state = false; + } + } else if (strcmp(notif, "tx-array-carriers-state-change") == 0) { + const char *value = lyd_get_value(lyd_child(op->child)->next); + if (strcmp(value, "READY") == 0) { + answer->tx_carrier_state = true; + } else { // "DISABLED" or "BUSY" + answer->tx_carrier_state = false; + } + } +} + +static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp, const struct lyd_node *op, void *user_data) +{ + ru_notif_t *answer = (ru_notif_t *)user_data; + LYD_FORMAT output_format = LYD_JSON; + + char *subs_reply = NULL; + lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS); + const char *ru_ip_add = nc_session_get_host(session); + MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply); + + recv_notif_v2((struct lyd_node_inner *)op, answer); +} +#endif + +bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + char *start_time = NULL, *stop_time = NULL; + + MP_LOG_I("RPC request to RU \"%s\" = with stream \"%s\" and filter \"%s\".\n", ru_session->ru_ip_add, stream, filter); + rpc = nc_rpc_subscribe(stream, NULL, start_time, stop_time, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + /* create notification thread so that notifications can immediately be received */ +#ifdef MPLANE_V1 + if (!nc_session_ntf_thread_running(ru_session->session)) { + nc_session_set_data(ru_session->session, answer); + int ret = nc_recv_notif_dispatch(ru_session->session, notif_clb_v1); + AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n"); + } else { + MP_LOG_I("Notification thread is already running for RU %s.\n", ru_session->ru_ip_add); + } +#elif MPLANE_V2 + int ret = nc_recv_notif_dispatch_data(ru_session->session, notif_clb_v2, answer, NULL); + AssertError(ret == 0, return false, "[MPLANE] Failed to create notification thread.\n"); +#endif + + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); + AssertError(success, return false, "[MPLANE] Failed to subscribe to: stream \"%s\", filter \"%s\".\n", stream, filter); + + MP_LOG_I("Successfully subscribed to all notifications from RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + + return true; +} diff --git a/radio/fhi_72/mplane/subscribe-mplane.h b/radio/fhi_72/mplane/subscribe-mplane.h new file mode 100644 index 0000000000..c5a6762fe9 --- /dev/null +++ b/radio/fhi_72/mplane/subscribe-mplane.h @@ -0,0 +1,31 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef SUBSCRIBE_MPLANE_H +#define SUBSCRIBE_MPLANE_H + +#include "ru-mplane-api.h" + +#include + +bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer); + +#endif /* SUBSCRIBE_MPLANE_H */ From 2cd5c1faf76498d1be552db5601c2fbf7312e10e Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 15:34:15 +0100 Subject: [PATCH 41/55] Add RPC for M-plane --- radio/fhi_72/mplane/init-mplane.c | 7 +++++++ radio/fhi_72/mplane/subscribe-mplane.c | 25 +++++++++++++++++++++++++ radio/fhi_72/mplane/subscribe-mplane.h | 2 ++ 3 files changed, 34 insertions(+) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 72f6d46701..453a8b1390 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -159,7 +159,14 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz success = subscribe_mplane(ru_session, stream, filter, (void *)&ru_session->ru_notif); AssertError(success, return false, "[MPLANE] Unable to continue: could not get RU answer via subscribe_mplane().\n"); + // when subscribed to the supervision notification, the watchdog timer needs to be updated + char *watchdog_answer = NULL; + success = update_timer_mplane(ru_session, &watchdog_answer); + AssertError(success, return false, "[MPLANE] Unable to update the watchdog timer. RU will do a reset after default supervision timer of (60+10)[s] expires.\n"); + MP_LOG_I("Watchdog timer answer: \n\t%s\n", watchdog_answer); + free(operational_ds); + free(watchdog_answer); return true; } diff --git a/radio/fhi_72/mplane/subscribe-mplane.c b/radio/fhi_72/mplane/subscribe-mplane.c index 64215c0aba..d96d367d35 100644 --- a/radio/fhi_72/mplane/subscribe-mplane.c +++ b/radio/fhi_72/mplane/subscribe-mplane.c @@ -131,3 +131,28 @@ bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char * return true; } + +bool update_timer_mplane(ru_session_t *ru_session, char **answer) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + const char *content = "\n\ +65535\n\ +65535\n\ +"; + + MP_LOG_I("RPC request to RU \"%s\" = \"%s\".\n", ru_session->ru_ip_add, content); + rpc = nc_rpc_act_generic_xml(content, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, answer); + AssertError(success, return false, "[MPLANE] Failed to update the watchdog timer.\n"); + + MP_LOG_I("Successfully updated supervision timer to (65535+65535)[s] for RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + + return true; +} diff --git a/radio/fhi_72/mplane/subscribe-mplane.h b/radio/fhi_72/mplane/subscribe-mplane.h index c5a6762fe9..6cb7a10310 100644 --- a/radio/fhi_72/mplane/subscribe-mplane.h +++ b/radio/fhi_72/mplane/subscribe-mplane.h @@ -28,4 +28,6 @@ bool subscribe_mplane(ru_session_t *ru_session, const char *stream, const char *filter, void *answer); +bool update_timer_mplane(ru_session_t *ru_session, char **answer); + #endif /* SUBSCRIBE_MPLANE_H */ From 45d0eaf3c49ba8377cef62b8f20da0153321c070 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 15:46:08 +0100 Subject: [PATCH 42/55] Get and store M-plane related params for xran --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/init-mplane.c | 5 ++ radio/fhi_72/mplane/ru-mplane-api.c | 127 ++++++++++++++++++++++++++++ radio/fhi_72/mplane/ru-mplane-api.h | 2 + 4 files changed, 135 insertions(+) create mode 100644 radio/fhi_72/mplane/ru-mplane-api.c diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 0092f96698..f028be8102 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -30,6 +30,7 @@ target_sources(oran_fhlib_5g_mplane PRIVATE rpc-send-recv.c get-mplane.c subscribe-mplane.c + ru-mplane-api.c xml/get-xml.c ) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 453a8b1390..34d68a30d0 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -165,6 +165,11 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz AssertError(success, return false, "[MPLANE] Unable to update the watchdog timer. RU will do a reset after default supervision timer of (60+10)[s] expires.\n"); MP_LOG_I("Watchdog timer answer: \n\t%s\n", watchdog_answer); + // save RU info for xran + const int max_num_ant = max(oai->tx_num_channels/num_rus, oai->rx_num_channels/num_rus); + success = get_config_for_xran(operational_ds, max_num_ant, &ru_session->xran_mplane); + AssertError(success, return false, "[MPLANE] Unable to retrieve required info for xran from RU \"%s\".\n", ru_session->ru_ip_add); + free(operational_ds); free(watchdog_answer); diff --git a/radio/fhi_72/mplane/ru-mplane-api.c b/radio/fhi_72/mplane/ru-mplane-api.c new file mode 100644 index 0000000000..ada42fd841 --- /dev/null +++ b/radio/fhi_72/mplane/ru-mplane-api.c @@ -0,0 +1,127 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "ru-mplane-api.h" +#include "xml/get-xml.h" +#include "common/utils/assertions.h" + +#include + +static void free_match_list(char **match_list, size_t count) +{ + for (size_t i = 0; i < count; i++) { + free(match_list[i]); + } + free(match_list); +} + +static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant) +{ + if (interface_mtu == 1500) { + MP_LOG_I("Interface MTU %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.\n", interface_mtu); + xran_mplane->mtu = 9600; + } else { + xran_mplane->mtu = interface_mtu; + } + + if (first_iq_width != 9) { + MP_LOG_I("IQ bitwidth %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9.\n", first_iq_width); + xran_mplane->iq_width = 9; + } else { + xran_mplane->iq_width = first_iq_width; + } + + xran_mplane->prach_offset = max_num_ant; +} + +bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane) +{ + /* some O-RU vendors are not fully compliant as per M-plane specifications */ + const char *ru_vendor = get_ru_xml_node(buffer, "mfg-name"); + + // RU MAC + xran_mplane->ru_mac_addr = get_ru_xml_node(buffer, "mac-address"); // TODO: support for VVDN, as it defines multiple MAC addresses + + // MTU + const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "interface-mtu")); + + // IQ bitwidth + char **match_list = NULL; + size_t count = 0; + get_ru_xml_list(buffer, "iq-bitwidth", &match_list, &count); + const int16_t first_iq_width = (int16_t)atoi((char *)match_list[0]); + free_match_list(match_list, count); + + // PRACH offset + // xran_mplane->prach_offset + + // DU port ID bitmask + xran_mplane->du_port_bitmask = 0xf000; + // Band sector bitmask + xran_mplane->band_sector_bitmask = 0x0f00; + // CC ID bitmask + xran_mplane->ccid_bitmask = 0x00f0; + // RU port ID bitmask + xran_mplane->ru_port_bitmask = 0x000f; + + // DU port ID + xran_mplane->du_port = 0; + // Band sector + xran_mplane->band_sector = 0; + // CC ID + xran_mplane->ccid = 0; + // RU port ID + xran_mplane->ru_port = 0; + + if (strcasecmp(ru_vendor, "BENETEL") == 0 /* || strcmp(ru_vendor, "VVDN-LPRU") == 0 || strcmp(ru_vendor, "Metanoia") == 0 */) { + fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant); + } else { + AssertError(false, return false, "[MPLANE] %s RU currently not supported.\n", ru_vendor); + } + + MP_LOG_I("Storing the following information to forward to xran:\n\ + RU MAC address %s\n\ + MTU %d\n\ + IQ bitwidth %d\n\ + PRACH offset %d\n\ + DU port bitmask %d\n\ + Band sector bitmask %d\n\ + CC ID bitmask %d\n\ + RU port ID bitmask %d\n\ + DU port ID %d\n\ + Band sector ID %d\n\ + CC ID %d\n\ + RU port ID %d\n", + xran_mplane->ru_mac_addr, + xran_mplane->mtu, + xran_mplane->iq_width, + xran_mplane->prach_offset, + xran_mplane->du_port_bitmask, + xran_mplane->band_sector_bitmask, + xran_mplane->ccid_bitmask, + xran_mplane->ru_port_bitmask, + xran_mplane->du_port, + xran_mplane->band_sector, + xran_mplane->ccid, + xran_mplane->ru_port); + + return true; +} diff --git a/radio/fhi_72/mplane/ru-mplane-api.h b/radio/fhi_72/mplane/ru-mplane-api.h index 4b3b1719c1..5b49814efa 100644 --- a/radio/fhi_72/mplane/ru-mplane-api.h +++ b/radio/fhi_72/mplane/ru-mplane-api.h @@ -92,4 +92,6 @@ typedef struct { } ru_session_list_t; +bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane); + #endif /* RU_MPLANE_API_H */ From e0ffba49ae4593ea959b993c7949b6683f7d3b44 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 15:51:52 +0100 Subject: [PATCH 43/55] Store U-plane related info from xml - interface name, - TX/RX carrier names, and - TX/RX endpoint names --- radio/fhi_72/mplane/init-mplane.c | 4 ++++ radio/fhi_72/mplane/ru-mplane-api.c | 30 +++++++++++++++++++++++++++++ radio/fhi_72/mplane/ru-mplane-api.h | 2 ++ 3 files changed, 36 insertions(+) diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 34d68a30d0..add3916f4d 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -170,6 +170,10 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz success = get_config_for_xran(operational_ds, max_num_ant, &ru_session->xran_mplane); AssertError(success, return false, "[MPLANE] Unable to retrieve required info for xran from RU \"%s\".\n", ru_session->ru_ip_add); + // save the U-plane info + success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config); + AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n"); + free(operational_ds); free(watchdog_answer); diff --git a/radio/fhi_72/mplane/ru-mplane-api.c b/radio/fhi_72/mplane/ru-mplane-api.c index ada42fd841..d387a40864 100644 --- a/radio/fhi_72/mplane/ru-mplane-api.c +++ b/radio/fhi_72/mplane/ru-mplane-api.c @@ -125,3 +125,33 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_ return true; } + +bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config) +{ + // Interface name + ru_mplane_config->interface_name = get_ru_xml_node(buffer, "interface"); + + // PDSCH + uplane_info_t *tx_end = &ru_mplane_config->tx_endpoints; + get_ru_xml_list(buffer, "static-low-level-tx-endpoints", &tx_end->name, &tx_end->num); + AssertError(tx_end->name != NULL, return false, "[MPLANE] Cannot get TX endpoint names.\n"); + + // TX carriers + uplane_info_t *tx_carriers = &ru_mplane_config->tx_carriers; + get_ru_xml_list(buffer, "tx-arrays", &tx_carriers->name, &tx_carriers->num); + AssertError(tx_carriers->name != NULL, return false, "[MPLANE] Cannot get TX carrier names.\n"); + + // PUSCH and PRACH + uplane_info_t *rx_end = &ru_mplane_config->rx_endpoints; + get_ru_xml_list(buffer, "static-low-level-rx-endpoints", &rx_end->name, &rx_end->num); + AssertError(rx_end->name != NULL, return false, "[MPLANE] Cannot get RX endpoint names.\n"); + + // RX carriers + uplane_info_t *rx_carriers = &ru_mplane_config->rx_carriers; + get_ru_xml_list(buffer, "rx-arrays", &rx_carriers->name, &rx_carriers->num); + AssertError(rx_carriers->name != NULL, return false, "[MPLANE] Cannot get RX carrier names.\n"); + + MP_LOG_I("Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.\n"); + + return true; +} diff --git a/radio/fhi_72/mplane/ru-mplane-api.h b/radio/fhi_72/mplane/ru-mplane-api.h index 5b49814efa..1afabd4d23 100644 --- a/radio/fhi_72/mplane/ru-mplane-api.h +++ b/radio/fhi_72/mplane/ru-mplane-api.h @@ -94,4 +94,6 @@ typedef struct { bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane); +bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config); + #endif /* RU_MPLANE_API_H */ From dd8a6eaaf53a8210613714a9d53c697a17110f13 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 16:56:54 +0100 Subject: [PATCH 44/55] Load yang models Ideally, we should load the yang models from the RU operational datastore, but the issues are following: 1) the yang models order is not good - dependancy models have to be loaded first 2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) Added support in both cases, loading from RU with RPC, and loading statically from "radio/fhi_72/mplane/yang/models" folder. --- radio/fhi_72/mplane/CMakeLists.txt | 1 + radio/fhi_72/mplane/yang/get-yang.c | 141 + radio/fhi_72/mplane/yang/get-yang.h | 31 + .../mplane/yang/models/iana-hardware.yang | 180 ++ .../mplane/yang/models/iana-if-type.yang | 1611 ++++++++++ .../mplane/yang/models/ietf-hardware.yang | 1141 +++++++ .../mplane/yang/models/ietf-interfaces.yang | 1073 +++++++ radio/fhi_72/mplane/yang/models/ietf-ip.yang | 860 ++++++ .../models/o-ran-compression-factors.yang | 368 +++ .../mplane/yang/models/o-ran-interfaces.yang | 414 +++ .../mplane/yang/models/o-ran-module-cap.yang | 840 +++++ .../yang/models/o-ran-processing-element.yang | 362 +++ .../mplane/yang/models/o-ran-uplane-conf.yang | 2706 +++++++++++++++++ 13 files changed, 9728 insertions(+) create mode 100644 radio/fhi_72/mplane/yang/get-yang.c create mode 100644 radio/fhi_72/mplane/yang/get-yang.h create mode 100755 radio/fhi_72/mplane/yang/models/iana-hardware.yang create mode 100644 radio/fhi_72/mplane/yang/models/iana-if-type.yang create mode 100755 radio/fhi_72/mplane/yang/models/ietf-hardware.yang create mode 100644 radio/fhi_72/mplane/yang/models/ietf-interfaces.yang create mode 100644 radio/fhi_72/mplane/yang/models/ietf-ip.yang create mode 100644 radio/fhi_72/mplane/yang/models/o-ran-compression-factors.yang create mode 100644 radio/fhi_72/mplane/yang/models/o-ran-interfaces.yang create mode 100644 radio/fhi_72/mplane/yang/models/o-ran-module-cap.yang create mode 100644 radio/fhi_72/mplane/yang/models/o-ran-processing-element.yang create mode 100644 radio/fhi_72/mplane/yang/models/o-ran-uplane-conf.yang diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index f028be8102..183121e40a 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -32,6 +32,7 @@ target_sources(oran_fhlib_5g_mplane PRIVATE subscribe-mplane.c ru-mplane-api.c xml/get-xml.c + yang/get-yang.c ) pkg_check_modules(libyang REQUIRED libyang) diff --git a/radio/fhi_72/mplane/yang/get-yang.c b/radio/fhi_72/mplane/yang/get-yang.c new file mode 100644 index 0000000000..c27454136f --- /dev/null +++ b/radio/fhi_72/mplane/yang/get-yang.c @@ -0,0 +1,141 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "get-yang.h" +#include "../rpc-send-recv.h" +#include "common/utils/assertions.h" + +#include + +static bool store_schemas(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + LYS_INFORMAT ly_format = LYS_IN_YANG; + +#ifdef MPLANE_V1 + *ctx = ly_ctx_new(NULL, 0); +#elif defined MPLANE_V2 + ly_ctx_new(NULL, 0, ctx); +#endif + + for (xmlNode *cur_node = node; cur_node; cur_node = cur_node->next) { + if (strcmp((const char *)cur_node->name, "schema") == 0) { + + xmlNode *name_node = xmlFirstElementChild(cur_node); + char *module_name = (char *)xmlNodeGetContent(name_node); + xmlNode *revision_node = xmlNextElementSibling(name_node); + char *module_revision = (char *)xmlNodeGetContent(revision_node); + xmlNode *format_node = xmlNextElementSibling(revision_node); + char *module_format = (char *)xmlNodeGetContent(format_node); + + if (strcmp(module_format, "yang") != 0) + continue; + + MP_LOG_I("RPC request to RU \"%s\" = for module \"%s\".\n", ru_session->ru_ip_add, module_name); + struct nc_rpc *get_schema_rpc = nc_rpc_getschema(module_name, module_revision, "yang", param); + char *schema_data = NULL; + bool success = rpc_send_recv((struct nc_session *)ru_session->session, get_schema_rpc, wd, timeout, &schema_data); + AssertError(success, return false, "[MPLANE] Unable to get schema for module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add); + + if (schema_data) { +#ifdef MPLANE_V1 + const struct lys_module *mod = lys_parse_mem(*ctx, schema_data, ly_format); +#elif defined MPLANE_V2 + struct lys_module *mod = NULL; + lys_parse_mem(*ctx, schema_data, ly_format, &mod); +#endif + free(schema_data); + if (!mod) { + MP_LOG_W("Unable to load module \"%s\" from RU \"%s\".\n", module_name, ru_session->ru_ip_add); + nc_rpc_free(get_schema_rpc); + ly_ctx_destroy(*ctx); + return false; + } + } + nc_rpc_free(get_schema_rpc); + } + } + + return true; +} + +static bool load_from_operational_ds(xmlNode *node, ru_session_t *ru_session, struct ly_ctx **ctx) +{ + for (xmlNode *schemas_node = node; schemas_node; schemas_node = schemas_node->next) { + if(schemas_node->type != XML_ELEMENT_NODE) + continue; + if (strcmp((const char *)schemas_node->name, "schemas") == 0) { + return store_schemas(schemas_node->children, ru_session, ctx); + } else { + bool success = load_from_operational_ds(schemas_node->children, ru_session, ctx); + if (success) + return true; + } + } + return false; +} + +bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx) +{ + // Initialize the xml file + size_t len = strlen(buffer) + 1; + xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0); + xmlNode *root_element = xmlDocGetRootElement(doc); + + bool success = load_from_operational_ds(root_element->children, ru_session, ctx); + if (success) { + MP_LOG_I("Successfully loaded all yang modules from operational datastore for RU \"%s\".\n", ru_session->ru_ip_add); + return true; + } else { + MP_LOG_W("Unable to load all yang modules from operational datastore for RU \"%s\". Using yang models present in \"models\" subfolder.\n", ru_session->ru_ip_add); + } + + /* ideally, we should load the yang models from the operational datastore, but the issues are following: + 1) the yang models order is not good - the dependancy models have to be loaded first + 2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) */ + const char *yang_dir = YANG_MODELS; + const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf"}; + +#ifdef MPLANE_V1 + *ctx = ly_ctx_new(yang_dir, 0); + AssertError(*ctx != NULL, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx)); +#elif defined MPLANE_V2 + LY_ERR ret = ly_ctx_new(yang_dir, 0, ctx); + AssertError(ret == LY_SUCCESS, return false, "[MPLANE] Unable to create libyang context: %s.\n", ly_errmsg(*ctx)); +#endif + + const size_t num_models = sizeof(yang_models) / sizeof(yang_models[0]); + for (size_t i = 0; i < num_models; ++i) { +#ifdef MPLANE_V1 + const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL); + AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]); +#elif defined MPLANE_V2 + const struct lys_module *mod = ly_ctx_load_module(*ctx, yang_models[i], NULL, NULL); + AssertError(mod != NULL, return false, "[MPLANE] Failed to load yang model %s.\n", yang_models[i]); +#endif + } + + MP_LOG_I("Successfully loaded all yang modules for RU \"%s\".\n", ru_session->ru_ip_add); + + return true; +} diff --git a/radio/fhi_72/mplane/yang/get-yang.h b/radio/fhi_72/mplane/yang/get-yang.h new file mode 100644 index 0000000000..5956bde203 --- /dev/null +++ b/radio/fhi_72/mplane/yang/get-yang.h @@ -0,0 +1,31 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef GET_MPLANE_YANG_MODELS_H +#define GET_MPLANE_YANG_MODELS_H + +#include "../ru-mplane-api.h" + +#include + +bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx); + +#endif /* GET_MPLANE_YANG_MODELS_H */ diff --git a/radio/fhi_72/mplane/yang/models/iana-hardware.yang b/radio/fhi_72/mplane/yang/models/iana-hardware.yang new file mode 100755 index 0000000000..52bcaf3a03 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/iana-hardware.yang @@ -0,0 +1,180 @@ +module iana-hardware { +yang-version 1.1; +namespace "urn:ietf:params:xml:ns:yang:iana-hardware"; +prefix ianahw; + +organization "IANA"; +contact + " Internet Assigned Numbers Authority + Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States of America + Tel: +1 310 301 5800 + E-Mail: iana@iana.org>"; + +description + "IANA-defined identities for hardware class. + The latest revision of this YANG module can be obtained from + the IANA website. + Requests for new values should be made to IANA via + email (iana@iana.org). + Copyright (c) 2018 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + The initial version of this YANG module is part of RFC 8348; + see the RFC itself for full legal notices."; +reference + "https://www.iana.org/assignments/yang-parameters"; + +revision 2018-03-13 { + description + "Initial revision."; + reference + "RFC 8348: A YANG Data Model for Hardware Management"; +} + +/* + * Identities + */ + +identity hardware-class { + description + "This identity is the base for all hardware class + identifiers."; +} + +identity unknown { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is unknown + to the server."; +} + +identity chassis { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is an + overall container for networking equipment. Any class of + physical component, except a stack, may be contained within a + chassis; a chassis may only be contained within a stack."; +} + +identity backplane { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of device for aggregating and forwarding networking traffic, + such as a shared backplane in a modular ethernet switch. Note + that an implementation may model a backplane as a single + physical component, which is actually implemented as multiple + discrete physical components (within a chassis or stack)."; +} + +identity container { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is capable + of containing one or more removable physical entities, + possibly of different types. For example, each (empty or + full) slot in a chassis will be modeled as a container. Note + that all removable physical components should be modeled + within a container component, such as field-replaceable + modules, fans, or power supplies. Note that all known + containers should be modeled by the agent, including empty + containers."; +} + +identity power-supply { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is a + power-supplying component."; +} + +identity fan { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is a fan or + other heat-reduction component."; +} + +identity sensor { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of sensor, such as a temperature sensor within a router + chassis."; +} + +identity module { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of self-contained sub-system. If a module component is + removable, then it should be modeled within a container + component; otherwise, it should be modeled directly within + another physical component (e.g., a chassis or another + module)."; +} + +identity port { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of networking port capable of receiving and/or transmitting + networking traffic."; +} + +identity stack { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of super-container (possibly virtual) intended to group + together multiple chassis entities. A stack may be realized + by a virtual cable, a real interconnect cable attached to + multiple chassis, or multiple interconnect cables. A stack + should not be modeled within any other physical components, + but a stack may be contained within another stack. Only + chassis components should be contained within a stack."; +} + +identity cpu { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of central processing unit."; +} + +identity energy-object { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of energy object, i.e., it is a piece of equipment that is + part of or attached to a communications network that is + monitored, it is controlled, or it aids in the management of + another device for Energy Management."; +} + +identity battery { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of battery."; +} + +identity storage-drive { + base ianahw:hardware-class; + description + "This identity is applicable if the hardware class is some sort + of component with data storage capability as its main + functionality, e.g., hard disk drive (HDD), solid-state device + (SSD), solid-state hybrid drive (SSHD), object storage device + (OSD), or other."; +} +} diff --git a/radio/fhi_72/mplane/yang/models/iana-if-type.yang b/radio/fhi_72/mplane/yang/models/iana-if-type.yang new file mode 100644 index 0000000000..24d04e60fe --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/iana-if-type.yang @@ -0,0 +1,1611 @@ +module iana-if-type { + namespace "urn:ietf:params:xml:ns:yang:iana-if-type"; + prefix ianaift; + + import ietf-interfaces { + prefix if; + } + + organization "IANA"; + contact + " Internet Assigned Numbers Authority + Postal: ICANN + 12025 Waterfront Drive, Suite 300 + Los Angeles, CA 90094-2536 + United States + Tel: +1 310 301 5800 + "; + description + "This YANG module defines YANG identities for IANA-registered + interface types. + This YANG module is maintained by IANA and reflects the + 'ifType definitions' registry. + The latest revision of this YANG module can be obtained from + the IANA web site. + Requests for new values should be made to IANA via + email (iana&iana.org). + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + The initial version of this YANG module is part of RFC 7224; + see the RFC itself for full legal notices."; + reference + "IANA 'ifType definitions' registry. + "; + + revision 2017-01-19 { + description + "Registered ifType 289."; + } + + revision 2016-11-23 { + description + "Registered ifTypes 283-288."; + } + + revision 2016-06-09 { + description + "Registered ifType 282."; + } + revision 2016-05-03 { + description + "Registered ifType 281."; + } + revision 2015-06-12 { + description + "Corrected formatting issue."; + } + revision 2014-09-24 { + description + "Registered ifType 280."; + } + revision 2014-09-19 { + description + "Registered ifType 279."; + } + revision 2014-07-03 { + description + "Registered ifTypes 277-278."; + } + revision 2014-05-19 { + description + "Updated the contact address."; + } + revision 2014-05-08 { + description + "Initial revision."; + reference + "RFC 7224: IANA Interface Type YANG Module"; + } + + identity iana-interface-type { + base if:interface-type; + description + "This identity is used as a base for all interface types + defined in the 'ifType definitions' registry."; + } + + identity other { + base iana-interface-type; + } + identity regular1822 { + base iana-interface-type; + } + identity hdh1822 { + base iana-interface-type; + } + identity ddnX25 { + base iana-interface-type; + } + identity rfc877x25 { + base iana-interface-type; + reference + "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer"; + } + identity ethernetCsmacd { + base iana-interface-type; + description + "For all Ethernet-like interfaces, regardless of speed, + as per RFC 3635."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity iso88023Csmacd { + base iana-interface-type; + status deprecated; + description + "Deprecated via RFC 3635. + Use ethernetCsmacd(6) instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity iso88024TokenBus { + base iana-interface-type; + } + identity iso88025TokenRing { + base iana-interface-type; + } + identity iso88026Man { + base iana-interface-type; + } + identity starLan { + base iana-interface-type; + status deprecated; + description + "Deprecated via RFC 3635. + Use ethernetCsmacd(6) instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity proteon10Mbit { + base iana-interface-type; + } + identity proteon80Mbit { + base iana-interface-type; + } + identity hyperchannel { + base iana-interface-type; + } + identity fddi { + base iana-interface-type; + reference + "RFC 1512 - FDDI Management Information Base"; + } + identity lapb { + base iana-interface-type; + reference + "RFC 1381 - SNMP MIB Extension for X.25 LAPB"; + } + identity sdlc { + base iana-interface-type; + } + identity ds1 { + base iana-interface-type; + description + "DS1-MIB."; + reference + "RFC 4805 - Definitions of Managed Objects for the + DS1, J1, E1, DS2, and E2 Interface Types"; + } + identity e1 { + base iana-interface-type; + status obsolete; + description + "Obsolete; see DS1-MIB."; + reference + "RFC 4805 - Definitions of Managed Objects for the + DS1, J1, E1, DS2, and E2 Interface Types"; + } + identity basicISDN { + base iana-interface-type; + description + "No longer used. See also RFC 2127."; + } + identity primaryISDN { + base iana-interface-type; + description + "No longer used. See also RFC 2127."; + } + identity propPointToPointSerial { + base iana-interface-type; + description + "Proprietary serial."; + } + identity ppp { + base iana-interface-type; + } + identity softwareLoopback { + base iana-interface-type; + } + identity eon { + base iana-interface-type; + description + "CLNP over IP."; + } + identity ethernet3Mbit { + base iana-interface-type; + } + identity nsip { + base iana-interface-type; + description + "XNS over IP."; + } + identity slip { + base iana-interface-type; + description + "Generic SLIP."; + } + identity ultra { + base iana-interface-type; + description + "Ultra Technologies."; + } + identity ds3 { + base iana-interface-type; + description + "DS3-MIB."; + reference + "RFC 3896 - Definitions of Managed Objects for the + DS3/E3 Interface Type"; + } + identity sip { + base iana-interface-type; + description + "SMDS, coffee."; + reference + "RFC 1694 - Definitions of Managed Objects for SMDS + Interfaces using SMIv2"; + } + identity frameRelay { + base iana-interface-type; + description + "DTE only."; + reference + "RFC 2115 - Management Information Base for Frame Relay + DTEs Using SMIv2"; + } + identity rs232 { + base iana-interface-type; + reference + "RFC 1659 - Definitions of Managed Objects for RS-232-like + Hardware Devices using SMIv2"; + } + identity para { + base iana-interface-type; + description + "Parallel-port."; + reference + "RFC 1660 - Definitions of Managed Objects for + Parallel-printer-like Hardware Devices using + SMIv2"; + } + identity arcnet { + base iana-interface-type; + description + "ARCnet."; + } + identity arcnetPlus { + base iana-interface-type; + description + "ARCnet Plus."; + } + identity atm { + base iana-interface-type; + description + "ATM cells."; + } + identity miox25 { + base iana-interface-type; + reference + "RFC 1461 - SNMP MIB extension for Multiprotocol + Interconnect over X.25"; + } + identity sonet { + base iana-interface-type; + description + "SONET or SDH."; + } + identity x25ple { + base iana-interface-type; + reference + "RFC 2127 - ISDN Management Information Base using SMIv2"; + } + identity iso88022llc { + base iana-interface-type; + } + identity localTalk { + base iana-interface-type; + } + identity smdsDxi { + base iana-interface-type; + } + identity frameRelayService { + base iana-interface-type; + description + "FRNETSERV-MIB."; + reference + "RFC 2954 - Definitions of Managed Objects for Frame + Relay Service"; + } + identity v35 { + base iana-interface-type; + } + identity hssi { + base iana-interface-type; + } + identity hippi { + base iana-interface-type; + } + identity modem { + base iana-interface-type; + description + "Generic modem."; + } + identity aal5 { + base iana-interface-type; + description + "AAL5 over ATM."; + } + identity sonetPath { + base iana-interface-type; + } + identity sonetVT { + base iana-interface-type; + } + identity smdsIcip { + base iana-interface-type; + description + "SMDS InterCarrier Interface."; + } + identity propVirtual { + base iana-interface-type; + description + "Proprietary virtual/internal."; + reference + "RFC 2863 - The Interfaces Group MIB"; + } + identity propMultiplexor { + base iana-interface-type; + description + "Proprietary multiplexing."; + reference + "RFC 2863 - The Interfaces Group MIB"; + } + identity ieee80212 { + base iana-interface-type; + description + "100BaseVG."; + } + identity fibreChannel { + base iana-interface-type; + description + "Fibre Channel."; + } + identity hippiInterface { + base iana-interface-type; + description + "HIPPI interfaces."; + } + identity frameRelayInterconnect { + base iana-interface-type; + status obsolete; + description + "Obsolete; use either + frameRelay(32) or frameRelayService(44)."; + } + identity aflane8023 { + base iana-interface-type; + description + "ATM Emulated LAN for 802.3."; + } + identity aflane8025 { + base iana-interface-type; + description + "ATM Emulated LAN for 802.5."; + } + identity cctEmul { + base iana-interface-type; + description + "ATM Emulated circuit."; + } + identity fastEther { + base iana-interface-type; + status deprecated; + description + "Obsoleted via RFC 3635. + ethernetCsmacd(6) should be used instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity isdn { + base iana-interface-type; + description + "ISDN and X.25."; + reference + "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN + in the Packet Mode"; + } + identity v11 { + base iana-interface-type; + description + "CCITT V.11/X.21."; + } + identity v36 { + base iana-interface-type; + description + "CCITT V.36."; + } + identity g703at64k { + base iana-interface-type; + description + "CCITT G703 at 64Kbps."; + } + identity g703at2mb { + base iana-interface-type; + status obsolete; + description + "Obsolete; see DS1-MIB."; + } + identity qllc { + base iana-interface-type; + description + "SNA QLLC."; + } + identity fastEtherFX { + base iana-interface-type; + status deprecated; + description + "Obsoleted via RFC 3635. + ethernetCsmacd(6) should be used instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity channel { + base iana-interface-type; + description + "Channel."; + } + identity ieee80211 { + base iana-interface-type; + description + "Radio spread spectrum."; + } + identity ibm370parChan { + base iana-interface-type; + description + "IBM System 360/370 OEMI Channel."; + } + identity escon { + base iana-interface-type; + description + "IBM Enterprise Systems Connection."; + } + identity dlsw { + base iana-interface-type; + description + "Data Link Switching."; + } + identity isdns { + base iana-interface-type; + description + "ISDN S/T interface."; + } + identity isdnu { + base iana-interface-type; + description + "ISDN U interface."; + } + identity lapd { + base iana-interface-type; + description + "Link Access Protocol D."; + } + identity ipSwitch { + base iana-interface-type; + description + "IP Switching Objects."; + } + identity rsrb { + base iana-interface-type; + description + "Remote Source Route Bridging."; + } + identity atmLogical { + base iana-interface-type; + description + "ATM Logical Port."; + reference + "RFC 3606 - Definitions of Supplemental Managed Objects + for ATM Interface"; + } + identity ds0 { + base iana-interface-type; + description + "Digital Signal Level 0."; + reference + "RFC 2494 - Definitions of Managed Objects for the DS0 + and DS0 Bundle Interface Type"; + } + identity ds0Bundle { + base iana-interface-type; + description + "Group of ds0s on the same ds1."; + reference + "RFC 2494 - Definitions of Managed Objects for the DS0 + and DS0 Bundle Interface Type"; + } + identity bsc { + base iana-interface-type; + description + "Bisynchronous Protocol."; + } + identity async { + base iana-interface-type; + description + "Asynchronous Protocol."; + } + identity cnr { + base iana-interface-type; + description + "Combat Net Radio."; + } + identity iso88025Dtr { + base iana-interface-type; + description + "ISO 802.5r DTR."; + } + identity eplrs { + base iana-interface-type; + description + "Ext Pos Loc Report Sys."; + } + identity arap { + base iana-interface-type; + description + "Appletalk Remote Access Protocol."; + } + identity propCnls { + base iana-interface-type; + description + "Proprietary Connectionless Protocol."; + } + identity hostPad { + base iana-interface-type; + description + "CCITT-ITU X.29 PAD Protocol."; + } + identity termPad { + base iana-interface-type; + description + "CCITT-ITU X.3 PAD Facility."; + } + identity frameRelayMPI { + base iana-interface-type; + description + "Multiproto Interconnect over FR."; + } + identity x213 { + base iana-interface-type; + description + "CCITT-ITU X213."; + } + identity adsl { + base iana-interface-type; + description + "Asymmetric Digital Subscriber Loop."; + } + identity radsl { + base iana-interface-type; + description + "Rate-Adapt. Digital Subscriber Loop."; + } + identity sdsl { + base iana-interface-type; + description + "Symmetric Digital Subscriber Loop."; + } + identity vdsl { + base iana-interface-type; + description + "Very H-Speed Digital Subscrib. Loop."; + } + identity iso88025CRFPInt { + base iana-interface-type; + description + "ISO 802.5 CRFP."; + } + identity myrinet { + base iana-interface-type; + description + "Myricom Myrinet."; + } + identity voiceEM { + base iana-interface-type; + description + "Voice recEive and transMit."; + } + identity voiceFXO { + base iana-interface-type; + description + "Voice Foreign Exchange Office."; + } + identity voiceFXS { + base iana-interface-type; + description + "Voice Foreign Exchange Station."; + } + identity voiceEncap { + base iana-interface-type; + description + "Voice encapsulation."; + } + identity voiceOverIp { + base iana-interface-type; + description + "Voice over IP encapsulation."; + } + identity atmDxi { + base iana-interface-type; + description + "ATM DXI."; + } + identity atmFuni { + base iana-interface-type; + description + "ATM FUNI."; + } + identity atmIma { + base iana-interface-type; + description + "ATM IMA."; + } + identity pppMultilinkBundle { + base iana-interface-type; + description + "PPP Multilink Bundle."; + } + identity ipOverCdlc { + base iana-interface-type; + description + "IBM ipOverCdlc."; + } + identity ipOverClaw { + base iana-interface-type; + description + "IBM Common Link Access to Workstn."; + } + identity stackToStack { + base iana-interface-type; + description + "IBM stackToStack."; + } + identity virtualIpAddress { + base iana-interface-type; + description + "IBM VIPA."; + } + identity mpc { + base iana-interface-type; + description + "IBM multi-protocol channel support."; + } + identity ipOverAtm { + base iana-interface-type; + description + "IBM ipOverAtm."; + reference + "RFC 2320 - Definitions of Managed Objects for Classical IP + and ARP Over ATM Using SMIv2 (IPOA-MIB)"; + } + identity iso88025Fiber { + base iana-interface-type; + description + "ISO 802.5j Fiber Token Ring."; + } + identity tdlc { + base iana-interface-type; + description + "IBM twinaxial data link control."; + } + identity gigabitEthernet { + base iana-interface-type; + status deprecated; + description + "Obsoleted via RFC 3635. + ethernetCsmacd(6) should be used instead."; + reference + "RFC 3635 - Definitions of Managed Objects for the + Ethernet-like Interface Types"; + } + identity hdlc { + base iana-interface-type; + description + "HDLC."; + } + identity lapf { + base iana-interface-type; + description + "LAP F."; + } + identity v37 { + base iana-interface-type; + description + "V.37."; + } + identity x25mlp { + base iana-interface-type; + description + "Multi-Link Protocol."; + } + identity x25huntGroup { + base iana-interface-type; + description + "X25 Hunt Group."; + } + identity transpHdlc { + base iana-interface-type; + description + "Transp HDLC."; + } + identity interleave { + base iana-interface-type; + description + "Interleave channel."; + } + identity fast { + base iana-interface-type; + description + "Fast channel."; + } + identity ip { + base iana-interface-type; + description + "IP (for APPN HPR in IP networks)."; + } + identity docsCableMaclayer { + base iana-interface-type; + description + "CATV Mac Layer."; + } + identity docsCableDownstream { + base iana-interface-type; + description + "CATV Downstream interface."; + } + identity docsCableUpstream { + base iana-interface-type; + description + "CATV Upstream interface."; + } + identity a12MppSwitch { + base iana-interface-type; + description + "Avalon Parallel Processor."; + } + identity tunnel { + base iana-interface-type; + description + "Encapsulation interface."; + } + identity coffee { + base iana-interface-type; + description + "Coffee pot."; + reference + "RFC 2325 - Coffee MIB"; + } + identity ces { + base iana-interface-type; + description + "Circuit Emulation Service."; + } + identity atmSubInterface { + base iana-interface-type; + description + "ATM Sub Interface."; + } + identity l2vlan { + base iana-interface-type; + description + "Layer 2 Virtual LAN using 802.1Q."; + } + identity l3ipvlan { + base iana-interface-type; + description + "Layer 3 Virtual LAN using IP."; + } + identity l3ipxvlan { + base iana-interface-type; + description + "Layer 3 Virtual LAN using IPX."; + } + identity digitalPowerline { + base iana-interface-type; + description + "IP over Power Lines."; + } + identity mediaMailOverIp { + base iana-interface-type; + description + "Multimedia Mail over IP."; + } + identity dtm { + base iana-interface-type; + description + "Dynamic synchronous Transfer Mode."; + } + identity dcn { + base iana-interface-type; + description + "Data Communications Network."; + } + identity ipForward { + base iana-interface-type; + description + "IP Forwarding Interface."; + } + identity msdsl { + base iana-interface-type; + description + "Multi-rate Symmetric DSL."; + } + identity ieee1394 { + base iana-interface-type; + + description + "IEEE1394 High Performance Serial Bus."; + } + identity if-gsn { + base iana-interface-type; + description + "HIPPI-6400."; + } + identity dvbRccMacLayer { + base iana-interface-type; + description + "DVB-RCC MAC Layer."; + } + identity dvbRccDownstream { + base iana-interface-type; + description + "DVB-RCC Downstream Channel."; + } + identity dvbRccUpstream { + base iana-interface-type; + description + "DVB-RCC Upstream Channel."; + } + identity atmVirtual { + base iana-interface-type; + description + "ATM Virtual Interface."; + } + identity mplsTunnel { + base iana-interface-type; + description + "MPLS Tunnel Virtual Interface."; + } + identity srp { + base iana-interface-type; + description + "Spatial Reuse Protocol."; + } + identity voiceOverAtm { + base iana-interface-type; + description + "Voice over ATM."; + } + identity voiceOverFrameRelay { + base iana-interface-type; + description + "Voice Over Frame Relay."; + } + identity idsl { + base iana-interface-type; + description + "Digital Subscriber Loop over ISDN."; + } + identity compositeLink { + base iana-interface-type; + description + "Avici Composite Link Interface."; + } + identity ss7SigLink { + base iana-interface-type; + description + "SS7 Signaling Link."; + } + identity propWirelessP2P { + base iana-interface-type; + description + "Prop. P2P wireless interface."; + } + identity frForward { + base iana-interface-type; + description + "Frame Forward Interface."; + } + identity rfc1483 { + base iana-interface-type; + description + "Multiprotocol over ATM AAL5."; + reference + "RFC 1483 - Multiprotocol Encapsulation over ATM + Adaptation Layer 5"; + } + identity usb { + base iana-interface-type; + description + "USB Interface."; + } + identity ieee8023adLag { + base iana-interface-type; + description + "IEEE 802.3ad Link Aggregate."; + } + identity bgppolicyaccounting { + base iana-interface-type; + description + "BGP Policy Accounting."; + } + identity frf16MfrBundle { + base iana-interface-type; + description + "FRF.16 Multilink Frame Relay."; + } + identity h323Gatekeeper { + base iana-interface-type; + description + "H323 Gatekeeper."; + } + identity h323Proxy { + base iana-interface-type; + description + "H323 Voice and Video Proxy."; + } + identity mpls { + base iana-interface-type; + description + "MPLS."; + } + identity mfSigLink { + base iana-interface-type; + description + "Multi-frequency signaling link."; + } + identity hdsl2 { + base iana-interface-type; + description + "High Bit-Rate DSL - 2nd generation."; + } + identity shdsl { + base iana-interface-type; + description + "Multirate HDSL2."; + } + identity ds1FDL { + base iana-interface-type; + description + "Facility Data Link (4Kbps) on a DS1."; + } + identity pos { + base iana-interface-type; + description + "Packet over SONET/SDH Interface."; + } + identity dvbAsiIn { + base iana-interface-type; + description + "DVB-ASI Input."; + } + identity dvbAsiOut { + base iana-interface-type; + description + "DVB-ASI Output."; + } + identity plc { + base iana-interface-type; + description + "Power Line Communications."; + } + identity nfas { + base iana-interface-type; + description + "Non-Facility Associated Signaling."; + } + identity tr008 { + base iana-interface-type; + description + "TR008."; + } + identity gr303RDT { + base iana-interface-type; + description + "Remote Digital Terminal."; + } + identity gr303IDT { + base iana-interface-type; + description + "Integrated Digital Terminal."; + } + identity isup { + base iana-interface-type; + description + "ISUP."; + } + identity propDocsWirelessMaclayer { + base iana-interface-type; + description + "Cisco proprietary Maclayer."; + } + identity propDocsWirelessDownstream { + base iana-interface-type; + description + "Cisco proprietary Downstream."; + } + identity propDocsWirelessUpstream { + base iana-interface-type; + description + "Cisco proprietary Upstream."; + } + identity hiperlan2 { + base iana-interface-type; + description + "HIPERLAN Type 2 Radio Interface."; + } + identity propBWAp2Mp { + base iana-interface-type; + description + "PropBroadbandWirelessAccesspt2Multipt (use of this value + for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f + is deprecated, and ieee80216WMAN(237) should be used + instead)."; + } + identity sonetOverheadChannel { + base iana-interface-type; + description + "SONET Overhead Channel."; + } + identity digitalWrapperOverheadChannel { + base iana-interface-type; + description + "Digital Wrapper."; + } + identity aal2 { + base iana-interface-type; + description + "ATM adaptation layer 2."; + } + identity radioMAC { + base iana-interface-type; + description + "MAC layer over radio links."; + } + identity atmRadio { + base iana-interface-type; + description + "ATM over radio links."; + } + identity imt { + base iana-interface-type; + description + "Inter-Machine Trunks."; + } + identity mvl { + base iana-interface-type; + description + "Multiple Virtual Lines DSL."; + } + identity reachDSL { + base iana-interface-type; + description + "Long Reach DSL."; + } + identity frDlciEndPt { + base iana-interface-type; + description + "Frame Relay DLCI End Point."; + } + identity atmVciEndPt { + base iana-interface-type; + description + "ATM VCI End Point."; + } + identity opticalChannel { + base iana-interface-type; + description + "Optical Channel."; + } + identity opticalTransport { + base iana-interface-type; + description + "Optical Transport."; + } + identity propAtm { + base iana-interface-type; + description + "Proprietary ATM."; + } + identity voiceOverCable { + base iana-interface-type; + description + "Voice Over Cable Interface."; + } + identity infiniband { + base iana-interface-type; + description + "Infiniband."; + } + identity teLink { + base iana-interface-type; + description + "TE Link."; + } + identity q2931 { + base iana-interface-type; + description + "Q.2931."; + } + identity virtualTg { + base iana-interface-type; + description + "Virtual Trunk Group."; + } + identity sipTg { + base iana-interface-type; + description + "SIP Trunk Group."; + } + identity sipSig { + base iana-interface-type; + description + "SIP Signaling."; + } + identity docsCableUpstreamChannel { + base iana-interface-type; + description + "CATV Upstream Channel."; + } + identity econet { + base iana-interface-type; + description + "Acorn Econet."; + } + identity pon155 { + base iana-interface-type; + description + "FSAN 155Mb Symetrical PON interface."; + } + identity pon622 { + base iana-interface-type; + description + "FSAN 622Mb Symetrical PON interface."; + } + identity bridge { + base iana-interface-type; + description + "Transparent bridge interface."; + } + identity linegroup { + base iana-interface-type; + description + "Interface common to multiple lines."; + } + identity voiceEMFGD { + base iana-interface-type; + description + "Voice E&M Feature Group D."; + } + identity voiceFGDEANA { + base iana-interface-type; + description + "Voice FGD Exchange Access North American."; + } + identity voiceDID { + base iana-interface-type; + description + "Voice Direct Inward Dialing."; + } + identity mpegTransport { + base iana-interface-type; + description + "MPEG transport interface."; + } + identity sixToFour { + base iana-interface-type; + status deprecated; + description + "6to4 interface (DEPRECATED)."; + reference + "RFC 4087 - IP Tunnel MIB"; + } + identity gtp { + base iana-interface-type; + description + "GTP (GPRS Tunneling Protocol)."; + } + identity pdnEtherLoop1 { + base iana-interface-type; + description + "Paradyne EtherLoop 1."; + } + identity pdnEtherLoop2 { + base iana-interface-type; + description + "Paradyne EtherLoop 2."; + } + identity opticalChannelGroup { + base iana-interface-type; + description + "Optical Channel Group."; + } + identity homepna { + base iana-interface-type; + description + "HomePNA ITU-T G.989."; + } + identity gfp { + base iana-interface-type; + description + "Generic Framing Procedure (GFP)."; + } + identity ciscoISLvlan { + base iana-interface-type; + description + "Layer 2 Virtual LAN using Cisco ISL."; + } + identity actelisMetaLOOP { + base iana-interface-type; + description + "Acteleis proprietary MetaLOOP High Speed Link."; + } + identity fcipLink { + base iana-interface-type; + description + "FCIP Link."; + } + identity rpr { + base iana-interface-type; + description + "Resilient Packet Ring Interface Type."; + } + identity qam { + base iana-interface-type; + description + "RF Qam Interface."; + } + identity lmp { + base iana-interface-type; + description + "Link Management Protocol."; + reference + "RFC 4327 - Link Management Protocol (LMP) Management + Information Base (MIB)"; + } + identity cblVectaStar { + base iana-interface-type; + description + "Cambridge Broadband Networks Limited VectaStar."; + } + identity docsCableMCmtsDownstream { + base iana-interface-type; + description + "CATV Modular CMTS Downstream Interface."; + } + identity adsl2 { + base iana-interface-type; + status deprecated; + description + "Asymmetric Digital Subscriber Loop Version 2 + (DEPRECATED/OBSOLETED - please use adsl2plus(238) + instead)."; + reference + "RFC 4706 - Definitions of Managed Objects for Asymmetric + Digital Subscriber Line 2 (ADSL2)"; + } + identity macSecControlledIF { + base iana-interface-type; + description + "MACSecControlled."; + } + identity macSecUncontrolledIF { + base iana-interface-type; + description + "MACSecUncontrolled."; + } + identity aviciOpticalEther { + base iana-interface-type; + description + "Avici Optical Ethernet Aggregate."; + } + identity atmbond { + base iana-interface-type; + description + "atmbond."; + } + identity voiceFGDOS { + base iana-interface-type; + description + "Voice FGD Operator Services."; + } + identity mocaVersion1 { + base iana-interface-type; + description + "MultiMedia over Coax Alliance (MoCA) Interface + as documented in information provided privately to IANA."; + } + identity ieee80216WMAN { + base iana-interface-type; + description + "IEEE 802.16 WMAN interface."; + } + identity adsl2plus { + base iana-interface-type; + description + "Asymmetric Digital Subscriber Loop Version 2 - + Version 2 Plus and all variants."; + } + identity dvbRcsMacLayer { + base iana-interface-type; + description + "DVB-RCS MAC Layer."; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + identity dvbTdm { + base iana-interface-type; + description + "DVB Satellite TDM."; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + identity dvbRcsTdma { + base iana-interface-type; + description + "DVB-RCS TDMA."; + reference + "RFC 5728 - The SatLabs Group DVB-RCS MIB"; + } + identity x86Laps { + base iana-interface-type; + description + "LAPS based on ITU-T X.86/Y.1323."; + } + identity wwanPP { + base iana-interface-type; + description + "3GPP WWAN."; + } + identity wwanPP2 { + base iana-interface-type; + description + "3GPP2 WWAN."; + } + identity voiceEBS { + base iana-interface-type; + description + "Voice P-phone EBS physical interface."; + } + identity ifPwType { + base iana-interface-type; + description + "Pseudowire interface type."; + reference + "RFC 5601 - Pseudowire (PW) Management Information Base (MIB)"; + } + identity ilan { + base iana-interface-type; + description + "Internal LAN on a bridge per IEEE 802.1ap."; + } + identity pip { + base iana-interface-type; + description + "Provider Instance Port on a bridge per IEEE 802.1ah PBB."; + } + identity aluELP { + base iana-interface-type; + description + "Alcatel-Lucent Ethernet Link Protection."; + } + identity gpon { + base iana-interface-type; + description + "Gigabit-capable passive optical networks (G-PON) as per + ITU-T G.948."; + } + identity vdsl2 { + base iana-interface-type; + description + "Very high speed digital subscriber line Version 2 + (as per ITU-T Recommendation G.993.2)."; + reference + "RFC 5650 - Definitions of Managed Objects for Very High + Speed Digital Subscriber Line 2 (VDSL2)"; + } + identity capwapDot11Profile { + base iana-interface-type; + description + "WLAN Profile Interface."; + reference + "RFC 5834 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Binding MIB for + IEEE 802.11"; + } + identity capwapDot11Bss { + base iana-interface-type; + description + "WLAN BSS Interface."; + reference + "RFC 5834 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Binding MIB for + IEEE 802.11"; + } + identity capwapWtpVirtualRadio { + base iana-interface-type; + description + "WTP Virtual Radio Interface."; + reference + "RFC 5833 - Control and Provisioning of Wireless Access + Points (CAPWAP) Protocol Base MIB"; + } + identity bits { + base iana-interface-type; + description + "bitsport."; + } + identity docsCableUpstreamRfPort { + base iana-interface-type; + description + "DOCSIS CATV Upstream RF Port."; + } + identity cableDownstreamRfPort { + base iana-interface-type; + description + "CATV downstream RF Port."; + } + identity vmwareVirtualNic { + base iana-interface-type; + description + "VMware Virtual Network Interface."; + } + identity ieee802154 { + base iana-interface-type; + description + "IEEE 802.15.4 WPAN interface."; + reference + "IEEE 802.15.4-2006"; + } + identity otnOdu { + base iana-interface-type; + description + "OTN Optical Data Unit."; + } + identity otnOtu { + base iana-interface-type; + description + "OTN Optical channel Transport Unit."; + } + identity ifVfiType { + base iana-interface-type; + description + "VPLS Forwarding Instance Interface Type."; + } + identity g9981 { + base iana-interface-type; + description + "G.998.1 bonded interface."; + } + identity g9982 { + base iana-interface-type; + description + "G.998.2 bonded interface."; + } + identity g9983 { + base iana-interface-type; + description + "G.998.3 bonded interface."; + } + + identity aluEpon { + base iana-interface-type; + description + "Ethernet Passive Optical Networks (E-PON)."; + } + identity aluEponOnu { + base iana-interface-type; + description + "EPON Optical Network Unit."; + } + identity aluEponPhysicalUni { + base iana-interface-type; + description + "EPON physical User to Network interface."; + } + identity aluEponLogicalLink { + base iana-interface-type; + description + "The emulation of a point-to-point link over the EPON + layer."; + } + identity aluGponOnu { + base iana-interface-type; + description + "GPON Optical Network Unit."; + reference + "ITU-T G.984.2"; + } + identity aluGponPhysicalUni { + base iana-interface-type; + description + "GPON physical User to Network interface."; + reference + "ITU-T G.984.2"; + } + identity vmwareNicTeam { + base iana-interface-type; + description + "VMware NIC Team."; + } + identity docsOfdmDownstream { + base iana-interface-type; + description + "CATV Downstream OFDM interface."; + } + identity docsOfdmaUpstream { + base iana-interface-type; + description + "CATV Upstream OFDMA interface."; + } + identity gfast { + base iana-interface-type; + description + "G.fast port."; + reference + "ITU-T G.9701"; + } + identity sdci { + base iana-interface-type; + description + "SDCI (IO-Link)."; + reference + "IEC 61131-9 Edition 1.0 2013-09"; + } + identity xboxWireless { + base iana-interface-type; + description + "Xbox wireless."; + } + identity fastdsl { + base iana-interface-type; + description + "FastDSL."; + reference + "BBF TR-355"; + } + identity docsCableScte55d1FwdOob { + base iana-interface-type; + description + "Cable SCTE 55-1 OOB Forward Channel."; + } + identity docsCableScte55d1RetOob { + base iana-interface-type; + description + "Cable SCTE 55-1 OOB Return Channel."; + } + identity docsCableScte55d2DsOob { + base iana-interface-type; + description + "Cable SCTE 55-2 OOB Downstream Channel."; + } + identity docsCableScte55d2UsOob { + base iana-interface-type; + description + "Cable SCTE 55-2 OOB Upstream Channel."; + } + identity docsCableNdf { + base iana-interface-type; + description + "Cable Narrowband Digital Forward."; + } + identity docsCableNdr { + base iana-interface-type; + description + "Cable Narrowband Digital Return."; + } + identity ptm { + base iana-interface-type; + description + "Packet Transfer Mode."; + } +} diff --git a/radio/fhi_72/mplane/yang/models/ietf-hardware.yang b/radio/fhi_72/mplane/yang/models/ietf-hardware.yang new file mode 100755 index 0000000000..f444e26ee6 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/ietf-hardware.yang @@ -0,0 +1,1141 @@ +module ietf-hardware { +yang-version 1.1; +namespace "urn:ietf:params:xml:ns:yang:ietf-hardware"; +prefix hw; + +import ietf-inet-types { + prefix inet; +} +import ietf-yang-types { + prefix yang; +} +import iana-hardware { + prefix ianahw; +} + +organization + "IETF NETMOD (Network Modeling) Working Group"; + +contact + "WG Web: + WG List: + Editor: Andy Bierman + + Editor: Martin Bjorklund + + Editor: Jie Dong + + Editor: Dan Romascanu + "; + +description + "This module contains a collection of YANG definitions for + managing hardware. + This data model is designed for the Network Management Datastore + Architecture (NMDA) defined in RFC 8342. + Copyright (c) 2018 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + This version of this YANG module is part of RFC 8348; see + the RFC itself for full legal notices."; + +revision 2018-03-13 { + description + "Initial revision."; + reference + "RFC 8348: A YANG Data Model for Hardware Management"; +} + +/* + * Features + */ + +feature entity-mib { + description + "This feature indicates that the device implements + the ENTITY-MIB."; + reference + "RFC 6933: Entity MIB (Version 4)"; +} + +feature hardware-state { + description + "Indicates that ENTITY-STATE-MIB objects are supported"; + reference + "RFC 4268: Entity State MIB"; +} + +feature hardware-sensor { + description + "Indicates that ENTITY-SENSOR-MIB objects are supported"; + reference + "RFC 3433: Entity Sensor Management Information Base"; +} + +/* + * Typedefs + */ + +typedef admin-state { + type enumeration { + enum unknown { + value 1; + description + "The resource is unable to report administrative state."; + } + enum locked { + value 2; + description + "The resource is administratively prohibited from use."; + } + enum shutting-down { + value 3; + description + "The resource usage is administratively limited to current + instances of use."; + } + enum unlocked { + value 4; + description + "The resource is not administratively prohibited from + use."; + } + } + description + "Represents the various possible administrative states."; + reference + "RFC 4268: Entity State MIB - EntityAdminState"; +} + +typedef oper-state { + type enumeration { + enum unknown { + value 1; + description + "The resource is unable to report its operational state."; + } + enum disabled { + value 2; + description + "The resource is totally inoperable."; + } + enum enabled { + value 3; + + description + "The resource is partially or fully operable."; + } + enum testing { + value 4; + description + "The resource is currently being tested and cannot + therefore report whether or not it is operational."; + } + } + description + "Represents the possible values of operational states."; + reference + "RFC 4268: Entity State MIB - EntityOperState"; +} + +typedef usage-state { + type enumeration { + enum unknown { + value 1; + description + "The resource is unable to report usage state."; + } + enum idle { + value 2; + description + "The resource is servicing no users."; + } + enum active { + value 3; + description + "The resource is currently in use, and it has sufficient + spare capacity to provide for additional users."; + } + enum busy { + value 4; + description + "The resource is currently in use, but it currently has no + spare capacity to provide for additional users."; + } + } + description + "Represents the possible values of usage states."; + reference + "RFC 4268: Entity State MIB - EntityUsageState"; +} + +typedef alarm-state { + type bits { + bit unknown { + position 0; + description + "The resource is unable to report alarm state."; + } + bit under-repair { + position 1; + description + "The resource is currently being repaired, which, depending + on the implementation, may make the other values in this + bit string not meaningful."; + } + bit critical { + position 2; + description + "One or more critical alarms are active against the + resource."; + } + bit major { + position 3; + description + "One or more major alarms are active against the + resource."; + } + bit minor { + position 4; + description + "One or more minor alarms are active against the + resource."; + } + bit warning { + position 5; + description + "One or more warning alarms are active against the + resource."; + } + bit indeterminate { + position 6; + description + "One or more alarms of whose perceived severity cannot be + determined are active against this resource."; + } + } + description + "Represents the possible values of alarm states. An alarm is a + persistent indication of an error or warning condition. + When no bits of this attribute are set, then no active alarms + are known against this component and it is not under repair."; + reference + "RFC 4268: Entity State MIB - EntityAlarmStatus"; +} + +typedef standby-state { + type enumeration { + enum unknown { + value 1; + description + "The resource is unable to report standby state."; + } + enum hot-standby { + value 2; + description + "The resource is not providing service, but it will be + immediately able to take over the role of the resource to + be backed up, without the need for initialization + activity, and will contain the same information as the + resource to be backed up."; + } + enum cold-standby { + value 3; + description + "The resource is to back up another resource, but it will + not be immediately able to take over the role of a + resource to be backed up and will require some + initialization activity."; + } + enum providing-service { + value 4; + description + "The resource is providing service."; + } + } + description + "Represents the possible values of standby states."; + reference + "RFC 4268: Entity State MIB - EntityStandbyStatus"; +} + +typedef sensor-value-type { + type enumeration { + enum other { + value 1; + description + "A measure other than those listed below."; + } + enum unknown { + value 2; + description + "An unknown measurement or arbitrary, relative numbers"; + } + enum volts-AC { + value 3; + description + "A measure of electric potential (alternating current)."; + } + enum volts-DC { + value 4; + description + "A measure of electric potential (direct current)."; + } + enum amperes { + value 5; + description + "A measure of electric current."; + } + enum watts { + value 6; + description + "A measure of power."; + } + enum hertz { + value 7; + description + "A measure of frequency."; + } + enum celsius { + value 8; + description + "A measure of temperature."; + } + enum percent-RH { + value 9; + description + "A measure of percent relative humidity."; + } + enum rpm { + value 10; + description + "A measure of shaft revolutions per minute."; + } + enum cmm { + value 11; + description + "A measure of cubic meters per minute (airflow)."; + } + enum truth-value { + value 12; + description + "Value is one of 1 (true) or 2 (false)"; + } + } + description + "A node using this data type represents the sensor measurement + data type associated with a physical sensor value. The actual + data units are determined by examining a node of this type + together with the associated sensor-value-scale node. + A node of this type SHOULD be defined together with nodes of + type sensor-value-scale and type sensor-value-precision. + These three types are used to identify the semantics of a node + of type sensor-value."; + reference + "RFC 3433: Entity Sensor Management Information Base - + EntitySensorDataType"; +} + +typedef sensor-value-scale { + type enumeration { + enum yocto { + value 1; + description + "Data scaling factor of 10^-24."; + } + enum zepto { + value 2; + description + "Data scaling factor of 10^-21."; + } + enum atto { + value 3; + description + "Data scaling factor of 10^-18."; + } + enum femto { + value 4; + description + "Data scaling factor of 10^-15."; + } + enum pico { + value 5; + description + "Data scaling factor of 10^-12."; + } + enum nano { + value 6; + description + "Data scaling factor of 10^-9."; + } + enum micro { + value 7; + description + "Data scaling factor of 10^-6."; + } + enum milli { + value 8; + description + "Data scaling factor of 10^-3."; + } + enum units { + value 9; + description + "Data scaling factor of 10^0."; + } + enum kilo { + value 10; + description + "Data scaling factor of 10^3."; + } + enum mega { + value 11; + description + "Data scaling factor of 10^6."; + } + enum giga { + value 12; + description + "Data scaling factor of 10^9."; + } + enum tera { + value 13; + description + "Data scaling factor of 10^12."; + } + enum peta { + value 14; + description + "Data scaling factor of 10^15."; + } + enum exa { + value 15; + description + "Data scaling factor of 10^18."; + } + enum zetta { + value 16; + description + "Data scaling factor of 10^21."; + } + enum yotta { + value 17; + description + "Data scaling factor of 10^24."; + } + } + description + "A node using this data type represents a data scaling factor, + represented with an International System of Units (SI) prefix. + The actual data units are determined by examining a node of + this type together with the associated sensor-value-type. + A node of this type SHOULD be defined together with nodes of + type sensor-value-type and type sensor-value-precision. + Together, associated nodes of these three types are used to + identify the semantics of a node of type sensor-value."; + reference + "RFC 3433: Entity Sensor Management Information Base - + EntitySensorDataScale"; +} + +typedef sensor-value-precision { + type int8 { + range "-8 .. 9"; + } + description + "A node using this data type represents a sensor value + precision range. + A node of this type SHOULD be defined together with nodes of + type sensor-value-type and type sensor-value-scale. Together, + associated nodes of these three types are used to identify the + semantics of a node of type sensor-value. + If a node of this type contains a value in the range 1 to 9, + it represents the number of decimal places in the fractional + part of an associated sensor-value fixed-point number. + If a node of this type contains a value in the range -8 to -1, + it represents the number of accurate digits in the associated + sensor-value fixed-point number. + The value zero indicates the associated sensor-value node is + not a fixed-point number. + Server implementers must choose a value for the associated + sensor-value-precision node so that the precision and accuracy + of the associated sensor-value node is correctly indicated. + For example, a component representing a temperature sensor + that can measure 0 to 100 degrees C in 0.1 degree + increments, +/- 0.05 degrees, would have a + sensor-value-precision value of '1', a sensor-value-scale + value of 'units', and a sensor-value ranging from '0' to + '1000'. The sensor-value would be interpreted as + 'degrees C * 10'."; + reference + "RFC 3433: Entity Sensor Management Information Base - + EntitySensorPrecision"; +} + +typedef sensor-value { + type int32 { + range "-1000000000 .. 1000000000"; + } + description + "A node using this data type represents a sensor value. + A node of this type SHOULD be defined together with nodes of + type sensor-value-type, type sensor-value-scale, and + type sensor-value-precision. Together, associated nodes of + those three types are used to identify the semantics of a node + of this data type. + The semantics of a node using this data type are determined by + the value of the associated sensor-value-type node. + If the associated sensor-value-type node is equal to 'voltsAC', + 'voltsDC', 'amperes', 'watts', 'hertz', 'celsius', or 'cmm', + then a node of this type MUST contain a fixed-point number + ranging from -999,999,999 to +999,999,999. The value + -1000000000 indicates an underflow error. The value + +1000000000 indicates an overflow error. The + sensor-value-precision indicates how many fractional digits + are represented in the associated sensor-value node. + If the associated sensor-value-type node is equal to + 'percentRH', then a node of this type MUST contain a number + ranging from 0 to 100. + If the associated sensor-value-type node is equal to 'rpm', + then a node of this type MUST contain a number ranging from + -999,999,999 to +999,999,999. + If the associated sensor-value-type node is equal to + 'truth-value', then a node of this type MUST contain either the + value 1 (true) or the value 2 (false). + If the associated sensor-value-type node is equal to 'other' or + 'unknown', then a node of this type MUST contain a number + ranging from -1000000000 to 1000000000."; + reference + "RFC 3433: Entity Sensor Management Information Base - + EntitySensorValue"; +} + +typedef sensor-status { + type enumeration { + enum ok { + value 1; + description + "Indicates that the server can obtain the sensor value."; + } + enum unavailable { + value 2; + description + "Indicates that the server presently cannot obtain the + sensor value."; + } + enum nonoperational { + value 3; + description + "Indicates that the server believes the sensor is broken. + The sensor could have a hard failure (disconnected wire) + or a soft failure such as out-of-range, jittery, or wildly + fluctuating readings."; + } + } + description + "A node using this data type represents the operational status + of a physical sensor."; + reference + "RFC 3433: Entity Sensor Management Information Base - + EntitySensorStatus"; +} + +/* + * Data nodes + */ + +container hardware { + description + "Data nodes representing components. + If the server supports configuration of hardware components, + then this data model is instantiated in the configuration + datastores supported by the server. The leaf-list 'datastore' + for the module 'ietf-hardware' in the YANG library provides + this information."; + + leaf last-change { + type yang:date-and-time; + config false; + description + "The time the '/hardware/component' list changed in the + operational state."; + } + + list component { + key name; + description + "List of components. + When the server detects a new hardware component, it + initializes a list entry in the operational state. + If the server does not support configuration of hardware + components, list entries in the operational state are + initialized with values for all nodes as detected by the + implementation. + Otherwise, this procedure is followed: + 1. If there is an entry in the '/hardware/component' list + in the intended configuration with values for the nodes + 'class', 'parent', and 'parent-rel-pos' that are equal + to the detected values, then the list entry in the + operational state is initialized with the configured + values, including the 'name'. + 2. Otherwise (i.e., there is no matching configuration + entry), the list entry in the operational state is + initialized with values for all nodes as detected by + the implementation. + If the '/hardware/component' list in the intended + configuration is modified, then the system MUST behave as if + it re-initializes itself and follow the procedure in (1)."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalEntry"; + + leaf name { + type string; + description + "The name assigned to this component. + This name is not required to be the same as + entPhysicalName."; + } + + leaf class { + type identityref { + base ianahw:hardware-class; + } + mandatory true; + description + "An indication of the general hardware type of the + component."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalClass"; + } + + leaf physical-index { + if-feature entity-mib; + type int32 { + range "1..2147483647"; + } + config false; + description + "The entPhysicalIndex for the entPhysicalEntry represented + by this list entry."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalIndex"; + } + + leaf description { + type string; + config false; + description + "A textual description of the component. This node should + contain a string that identifies the manufacturer's name + for the component and should be set to a distinct value + for each version or model of the component."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalDescr"; + } + + leaf parent { + type leafref { + path "../../component/name"; + require-instance false; + } + description + "The name of the component that physically contains this + component. + If this leaf is not instantiated, it indicates that this + component is not contained in any other component. + In the event that a physical component is contained by + more than one physical component (e.g., double-wide + modules), this node contains the name of one of these + components. An implementation MUST use the same name + every time this node is instantiated."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalContainedIn"; + } + + leaf parent-rel-pos { + type int32 { + range "0 .. 2147483647"; + } + description + "An indication of the relative position of this child + component among all its sibling components. Sibling + components are defined as components that: + o share the same value of the 'parent' node and + o share a common base identity for the 'class' node. + Note that the last rule gives implementations flexibility + in how components are numbered. For example, some + implementations might have a single number series for all + components derived from 'ianahw:port', while some others + might have different number series for different + components with identities derived from 'ianahw:port' (for + example, one for registered jack 45 (RJ45) and one for + small form-factor pluggable (SFP))."; + + reference + "RFC 6933: Entity MIB (Version 4) - + entPhysicalParentRelPos"; + } + + leaf-list contains-child { + type leafref { + path "../../component/name"; + } + config false; + description + "The name of the contained component."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalChildIndex"; + } + + leaf hardware-rev { + type string; + config false; + description + "The vendor-specific hardware revision string for the + component. The preferred value is the hardware revision + identifier actually printed on the component itself (if + present)."; + reference + "RFC 6933: Entity MIB (Version 4) - + entPhysicalHardwareRev"; + } + + leaf firmware-rev { + type string; + config false; + description + "The vendor-specific firmware revision string for the + component."; + reference + "RFC 6933: Entity MIB (Version 4) - + entPhysicalFirmwareRev"; + } + + leaf software-rev { + type string; + config false; + + description + "The vendor-specific software revision string for the + component."; + reference + "RFC 6933: Entity MIB (Version 4) - + entPhysicalSoftwareRev"; + } + + leaf serial-num { + type string; + config false; + description + "The vendor-specific serial number string for the + component. The preferred value is the serial number + string actually printed on the component itself (if + present)."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalSerialNum"; + } + + leaf mfg-name { + type string; + config false; + description + "The name of the manufacturer of this physical component. + The preferred value is the manufacturer name string + actually printed on the component itself (if present). + Note that comparisons between instances of the + 'model-name', 'firmware-rev', 'software-rev', and + 'serial-num' nodes are only meaningful amongst components + with the same value of 'mfg-name'. + If the manufacturer name string associated with the + physical component is unknown to the server, then this + node is not instantiated."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalMfgName"; + } + + leaf model-name { + type string; + config false; + description + "The vendor-specific model name identifier string + associated with this physical component. The preferred + value is the customer-visible part number, which may be + printed on the component itself. + If the model name string associated with the physical + component is unknown to the server, then this node is not + instantiated."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalModelName"; + } + + leaf alias { + type string; + description + "An 'alias' name for the component, as specified by a + network manager, that provides a non-volatile 'handle' for + the component. + If no configured value exists, the server MAY set the + value of this node to a locally unique value in the + operational state. + A server implementation MAY map this leaf to the + entPhysicalAlias MIB object. Such an implementation needs + to use some mechanism to handle the differences in size + and characters allowed between this leaf and + entPhysicalAlias. The definition of such a mechanism is + outside the scope of this document."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalAlias"; + } + + leaf asset-id { + type string; + description + "This node is a user-assigned asset tracking identifier for + the component. + A server implementation MAY map this leaf to the + entPhysicalAssetID MIB object. Such an implementation + needs to use some mechanism to handle the differences in + size and characters allowed between this leaf and + entPhysicalAssetID. The definition of such a mechanism is + outside the scope of this document."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalAssetID"; + } + + leaf is-fru { + type boolean; + config false; + + description + "This node indicates whether or not this component is + considered a 'field-replaceable unit' by the vendor. If + this node contains the value 'true', then this component + identifies a field-replaceable unit. For all components + that are permanently contained within a field-replaceable + unit, the value 'false' should be returned for this + node."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalIsFRU"; + } + + leaf mfg-date { + type yang:date-and-time; + config false; + description + "The date of manufacturing of the managed component."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalMfgDate"; + } + + leaf-list uri { + type inet:uri; + description + "This node contains identification information about the + component."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalUris"; + } + + leaf uuid { + type yang:uuid; + config false; + description + "A Universally Unique Identifier of the component."; + reference + "RFC 6933: Entity MIB (Version 4) - entPhysicalUUID"; + } + + container state { + if-feature hardware-state; + description + "State-related nodes"; + reference + "RFC 4268: Entity State MIB"; + + leaf state-last-changed { + type yang:date-and-time; + config false; + description + "The date and time when the value of any of the + admin-state, oper-state, usage-state, alarm-state, or + standby-state changed for this component. + If there has been no change since the last + re-initialization of the local system, this node + contains the date and time of local system + initialization. If there has been no change since the + component was added to the local system, this node + contains the date and time of the insertion."; + reference + "RFC 4268: Entity State MIB - entStateLastChanged"; + } + + leaf admin-state { + type admin-state; + description + "The administrative state for this component. + This node refers to a component's administrative + permission to service both other components within its + containment hierarchy as well other users of its + services defined by means outside the scope of this + module. + Some components exhibit only a subset of the remaining + administrative state values. Some components cannot be + locked; hence, this node exhibits only the 'unlocked' + state. Other components cannot be shut down gracefully; + hence, this node does not exhibit the 'shutting-down' + state."; + reference + "RFC 4268: Entity State MIB - entStateAdmin"; + } + + leaf oper-state { + type oper-state; + config false; + description + "The operational state for this component. + Note that this node does not follow the administrative + state. An administrative state of 'down' does not + predict an operational state of 'disabled'. + Note that some implementations may not be able to + accurately report oper-state while the admin-state node + has a value other than 'unlocked'. In these cases, this + node MUST have a value of 'unknown'."; + reference + "RFC 4268: Entity State MIB - entStateOper"; + } + + leaf usage-state { + type usage-state; + config false; + description + "The usage state for this component. + This node refers to a component's ability to service + more components in a containment hierarchy. + Some components will exhibit only a subset of the usage + state values. Components that are unable to ever + service any components within a containment hierarchy + will always have a usage state of 'busy'. In some + cases, a component will be able to support only one + other component within its containment hierarchy and + will therefore only exhibit values of 'idle' and + 'busy'."; + reference + "RFC 4268: Entity State MIB - entStateUsage"; + } + + leaf alarm-state { + type alarm-state; + config false; + description + "The alarm state for this component. It does not + include the alarms raised on child components within its + containment hierarchy."; + reference + "RFC 4268: Entity State MIB - entStateAlarm"; + } + + leaf standby-state { + type standby-state; + config false; + description + "The standby state for this component. + Some components will exhibit only a subset of the + remaining standby state values. If this component + cannot operate in a standby role, the value of this node + will always be 'providing-service'."; + reference + "RFC 4268: Entity State MIB - entStateStandby"; + } + } + + container sensor-data { + when 'derived-from-or-self(../class, + "ianahw:sensor")' { + description + "Sensor data nodes present for any component of type + 'sensor'"; + } + if-feature hardware-sensor; + config false; + + description + "Sensor-related nodes."; + reference + "RFC 3433: Entity Sensor Management Information Base"; + + leaf value { + type sensor-value; + description + "The most recent measurement obtained by the server + for this sensor. + A client that periodically fetches this node should also + fetch the nodes 'value-type', 'value-scale', and + 'value-precision', since they may change when the value + is changed."; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorValue"; + } + + leaf value-type { + type sensor-value-type; + description + "The type of data units associated with the + sensor value"; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorType"; + } + leaf value-scale { + type sensor-value-scale; + description + "The (power of 10) scaling factor associated + with the sensor value"; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorScale"; + } + + leaf value-precision { + type sensor-value-precision; + description + "The number of decimal places of precision + associated with the sensor value"; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorPrecision"; + } + + leaf oper-status { + type sensor-status; + description + "The operational status of the sensor."; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorOperStatus"; + } + + leaf units-display { + type string; + description + "A textual description of the data units that should be + used in the display of the sensor value."; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorUnitsDisplay"; + } + + leaf value-timestamp { + type yang:date-and-time; + description + "The time the status and/or value of this sensor was last + obtained by the server."; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorValueTimeStamp"; + } + leaf value-update-rate { + type uint32; + units "milliseconds"; + description + "An indication of the frequency that the server updates + the associated 'value' node, represented in + milliseconds. The value zero indicates: + - the sensor value is updated on demand (e.g., + when polled by the server for a get-request), + - the sensor value is updated when the sensor + value changes (event-driven), or + - the server does not know the update rate."; + reference + "RFC 3433: Entity Sensor Management Information Base - + entPhySensorValueUpdateRate"; + } + } + } +} + +/* + * Notifications + */ + +notification hardware-state-change { + description + "A hardware-state-change notification is generated when the + value of /hardware/last-change changes in the operational + state."; + reference + "RFC 6933: Entity MIB (Version 4) - entConfigChange"; +} + +notification hardware-state-oper-enabled { + if-feature hardware-state; + description + "A hardware-state-oper-enabled notification signifies that a + component has transitioned into the 'enabled' state."; + + leaf name { + type leafref { + path "/hardware/component/name"; + } + + description + "The name of the component that has transitioned into the + 'enabled' state."; + } + leaf admin-state { + type leafref { + path "/hardware/component/state/admin-state"; + } + description + "The administrative state for the component."; + } + leaf alarm-state { + type leafref { + path "/hardware/component/state/alarm-state"; + } + description + "The alarm state for the component."; + } + reference + "RFC 4268: Entity State MIB - entStateOperEnabled"; +} + +notification hardware-state-oper-disabled { + if-feature hardware-state; + description + "A hardware-state-oper-disabled notification signifies that a + component has transitioned into the 'disabled' state."; + + leaf name { + type leafref { + path "/hardware/component/name"; + } + description + "The name of the component that has transitioned into the + 'disabled' state."; + } + leaf admin-state { + type leafref { + path "/hardware/component/state/admin-state"; + } + description + "The administrative state for the component."; + } + leaf alarm-state { + type leafref { + path "/hardware/component/state/alarm-state"; + } + + description + "The alarm state for the component."; + } + reference + "RFC 4268: Entity State MIB - entStateOperDisabled"; +} + +} diff --git a/radio/fhi_72/mplane/yang/models/ietf-interfaces.yang b/radio/fhi_72/mplane/yang/models/ietf-interfaces.yang new file mode 100644 index 0000000000..8dae9d3e21 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/ietf-interfaces.yang @@ -0,0 +1,1073 @@ +module ietf-interfaces { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces"; + prefix if; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (Network Modeling) Working Group"; + + contact + "WG Web: + WG List: + Editor: Martin Bjorklund + "; + + description + "This module contains a collection of YANG definitions for + managing network interfaces. + Copyright (c) 2018 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + This version of this YANG module is part of RFC 8343; see + the RFC itself for full legal notices."; + + revision 2018-02-20 { + description + "Updated to support NMDA."; + reference + "RFC 8343: A YANG Data Model for Interface Management"; + } + + revision 2014-05-08 { + description + "Initial revision."; + reference + "RFC 7223: A YANG Data Model for Interface Management"; + } + + /* + * Typedefs + */ + + typedef interface-ref { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description + "This type is used by data models that need to reference + interfaces."; + } + + /* + * Identities + */ + + identity interface-type { + description + "Base identity from which specific interface types are + derived."; + } + + /* + * Features + */ + + feature arbitrary-names { + description + "This feature indicates that the device allows user-controlled + interfaces to be named arbitrarily."; + } + feature pre-provisioning { + description + "This feature indicates that the device supports + pre-provisioning of interface configuration, i.e., it is + possible to configure an interface whose physical interface + hardware is not present on the device."; + } + feature if-mib { + description + "This feature indicates that the device implements + the IF-MIB."; + reference + "RFC 2863: The Interfaces Group MIB"; + } + + /* + * Data nodes + */ + + container interfaces { + description + "Interface parameters."; + + list interface { + key "name"; + + description + "The list of interfaces on the device. + The status of an interface is available in this list in the + operational state. If the configuration of a + system-controlled interface cannot be used by the system + (e.g., the interface hardware present does not match the + interface type), then the configuration is not applied to + the system-controlled interface shown in the operational + state. If the configuration of a user-controlled interface + cannot be used by the system, the configured interface is + not instantiated in the operational state. + System-controlled interfaces created by the system are + always present in this list in the operational state, + whether or not they are configured."; + + leaf name { + type string; + description + "The name of the interface. + A device MAY restrict the allowed values for this leaf, + possibly depending on the type of the interface. + For system-controlled interfaces, this leaf is the + device-specific name of the interface. + If a client tries to create configuration for a + system-controlled interface that is not present in the + operational state, the server MAY reject the request if + the implementation does not support pre-provisioning of + interfaces or if the name refers to an interface that can + never exist in the system. A Network Configuration + Protocol (NETCONF) server MUST reply with an rpc-error + with the error-tag 'invalid-value' in this case. + If the device supports pre-provisioning of interface + configuration, the 'pre-provisioning' feature is + advertised. + If the device allows arbitrarily named user-controlled + interfaces, the 'arbitrary-names' feature is advertised. + When a configured user-controlled interface is created by + the system, it is instantiated with the same name in the + operational state. + A server implementation MAY map this leaf to the ifName + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifName. The definition of + such a mechanism is outside the scope of this document."; + reference + "RFC 2863: The Interfaces Group MIB - ifName"; + } + + leaf description { + type string; + description + "A textual description of the interface. + A server implementation MAY map this leaf to the ifAlias + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifAlias. The definition of + such a mechanism is outside the scope of this document. + Since ifAlias is defined to be stored in non-volatile + storage, the MIB implementation MUST map ifAlias to the + value of 'description' in the persistently stored + configuration."; + reference + "RFC 2863: The Interfaces Group MIB - ifAlias"; + } + + leaf type { + type identityref { + base interface-type; + } + mandatory true; + description + "The type of the interface. + When an interface entry is created, a server MAY + initialize the type leaf with a valid value, e.g., if it + is possible to derive the type from the name of the + interface. + If a client tries to set the type of an interface to a + value that can never be used by the system, e.g., if the + type is not supported or if the type does not match the + name of the interface, the server MUST reject the request. + A NETCONF server MUST reply with an rpc-error with the + error-tag 'invalid-value' in this case."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf enabled { + type boolean; + default "true"; + description + "This leaf contains the configured, desired state of the + interface. + Systems that implement the IF-MIB use the value of this + leaf in the intended configuration to set + IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry + has been initialized, as described in RFC 2863. + Changes in this leaf in the intended configuration are + reflected in ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf link-up-down-trap-enable { + if-feature if-mib; + type enumeration { + enum enabled { + value 1; + description + "The device will generate linkUp/linkDown SNMP + notifications for this interface."; + } + enum disabled { + value 2; + description + "The device will not generate linkUp/linkDown SNMP + notifications for this interface."; + } + } + description + "Controls whether linkUp/linkDown SNMP notifications + should be generated for this interface. + If this node is not configured, the value 'enabled' is + operationally used by the server for interfaces that do + not operate on top of any other interface (i.e., there are + no 'lower-layer-if' entries), and 'disabled' otherwise."; + reference + "RFC 2863: The Interfaces Group MIB - + ifLinkUpDownTrapEnable"; + } + + leaf admin-status { + if-feature if-mib; + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "Not ready to pass packets and not in some test mode."; + } + enum testing { + value 3; + description + "In some test mode."; + } + } + config false; + mandatory true; + description + "The desired state of the interface. + This leaf has the same read semantics as ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf oper-status { + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + + description + "The interface does not pass any packets."; + } + enum testing { + value 3; + description + "In some test mode. No operational packets can + be passed."; + } + enum unknown { + value 4; + description + "Status cannot be determined for some reason."; + } + enum dormant { + value 5; + description + "Waiting for some external event."; + } + enum not-present { + value 6; + description + "Some component (typically hardware) is missing."; + } + enum lower-layer-down { + value 7; + description + "Down due to state of lower-layer interface(s)."; + } + } + config false; + mandatory true; + description + "The current operational state of the interface. + This leaf has the same semantics as ifOperStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifOperStatus"; + } + + leaf last-change { + type yang:date-and-time; + config false; + description + "The time the interface entered its current operational + state. If the current state was entered prior to the + last re-initialization of the local network management + subsystem, then this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifLastChange"; + } + + leaf if-index { + if-feature if-mib; + type int32 { + range "1..2147483647"; + } + config false; + mandatory true; + description + "The ifIndex value for the ifEntry represented by this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifIndex"; + } + + leaf phys-address { + type yang:phys-address; + config false; + description + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a Media Access Control (MAC) address. The + interface's media-specific modules must define the bit + and byte ordering and the format of the value of this + object. For interfaces that do not have such an address + (e.g., a serial line), this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; + } + + leaf-list higher-layer-if { + type interface-ref; + config false; + description + "A list of references to interfaces layered on top of this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf-list lower-layer-if { + type interface-ref; + config false; + + description + "A list of references to interfaces layered underneath this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf speed { + type yang:gauge64; + units "bits/second"; + config false; + description + "An estimate of the interface's current bandwidth in bits + per second. For interfaces that do not vary in + bandwidth or for those where no accurate estimation can + be made, this node should contain the nominal bandwidth. + For interfaces that have no concept of bandwidth, this + node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - + ifSpeed, ifHighSpeed"; + } + + container statistics { + config false; + description + "A collection of interface-related statistics objects."; + + leaf discontinuity-time { + type yang:date-and-time; + mandatory true; + description + "The time on the most recent occasion at which any one or + more of this interface's counters suffered a + discontinuity. If no such discontinuities have occurred + since the last re-initialization of the local management + subsystem, then this node contains the time the local + management subsystem re-initialized itself."; + } + + leaf in-octets { + type yang:counter64; + description + "The total number of octets received on the interface, + including framing characters. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; + } + + leaf in-unicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were not addressed to a + multicast or broadcast address at this sub-layer. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; + } + + leaf in-broadcast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a broadcast + address at this sub-layer. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInBroadcastPkts"; + } + + leaf in-multicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a multicast + address at this sub-layer. For a MAC-layer protocol, + this includes both Group and Functional addresses. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInMulticastPkts"; + } + + leaf in-discards { + type yang:counter32; + description + "The number of inbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being deliverable to a higher-layer + protocol. One possible reason for discarding such a + packet could be to free up buffer space. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInDiscards"; + } + + leaf in-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of + inbound transmission units that contained errors + preventing them from being deliverable to a higher-layer + protocol. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInErrors"; + } + + leaf in-unknown-protos { + type yang:counter32; + + description + "For packet-oriented interfaces, the number of packets + received via the interface that were discarded because + of an unknown or unsupported protocol. For + character-oriented or fixed-length interfaces that + support protocol multiplexing, the number of + transmission units received via the interface that were + discarded because of an unknown or unsupported protocol. + For any interface that does not support protocol + multiplexing, this counter is not present. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; + } + + leaf out-octets { + type yang:counter64; + description + "The total number of octets transmitted out of the + interface, including framing characters. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; + } + + leaf out-unicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were not addressed + to a multicast or broadcast address at this sub-layer, + including those that were discarded or not sent. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; + } + + leaf out-broadcast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + broadcast address at this sub-layer, including those + that were discarded or not sent. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutBroadcastPkts"; + } + + leaf out-multicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + multicast address at this sub-layer, including those + that were discarded or not sent. For a MAC-layer + protocol, this includes both Group and Functional + addresses. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutMulticastPkts"; + } + + leaf out-discards { + type yang:counter32; + description + "The number of outbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being transmitted. One possible reason + for discarding such a packet could be to free up buffer + space. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; + } + + leaf out-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutErrors"; + } + } + + } + } + + /* + * Legacy typedefs + */ + + typedef interface-state-ref { + type leafref { + path "/if:interfaces-state/if:interface/if:name"; + } + status deprecated; + description + "This type is used by data models that need to reference + the operationally present interfaces."; + } + + /* + * Legacy operational state data nodes + */ + + container interfaces-state { + config false; + status deprecated; + description + "Data nodes for the operational state of interfaces."; + + list interface { + key "name"; + status deprecated; + + description + "The list of interfaces on the device. + System-controlled interfaces created by the system are + always present in this list, whether or not they are + configured."; + + leaf name { + type string; + status deprecated; + description + "The name of the interface. + A server implementation MAY map this leaf to the ifName + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifName. The definition of + such a mechanism is outside the scope of this document."; + reference + "RFC 2863: The Interfaces Group MIB - ifName"; + } + + leaf type { + type identityref { + base interface-type; + } + mandatory true; + status deprecated; + description + "The type of the interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf admin-status { + if-feature if-mib; + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "Not ready to pass packets and not in some test mode."; + } + enum testing { + value 3; + description + "In some test mode."; + } + } + mandatory true; + status deprecated; + description + "The desired state of the interface. + This leaf has the same read semantics as ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf oper-status { + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "The interface does not pass any packets."; + } + enum testing { + value 3; + description + "In some test mode. No operational packets can + be passed."; + } + enum unknown { + value 4; + description + "Status cannot be determined for some reason."; + } + enum dormant { + value 5; + description + "Waiting for some external event."; + } + enum not-present { + value 6; + description + "Some component (typically hardware) is missing."; + } + enum lower-layer-down { + value 7; + description + "Down due to state of lower-layer interface(s)."; + } + } + mandatory true; + status deprecated; + description + "The current operational state of the interface. + This leaf has the same semantics as ifOperStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifOperStatus"; + } + + leaf last-change { + type yang:date-and-time; + status deprecated; + description + "The time the interface entered its current operational + state. If the current state was entered prior to the + last re-initialization of the local network management + subsystem, then this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifLastChange"; + } + + leaf if-index { + if-feature if-mib; + type int32 { + range "1..2147483647"; + } + mandatory true; + status deprecated; + description + "The ifIndex value for the ifEntry represented by this + interface."; + + reference + "RFC 2863: The Interfaces Group MIB - ifIndex"; + } + + leaf phys-address { + type yang:phys-address; + status deprecated; + description + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a Media Access Control (MAC) address. The + interface's media-specific modules must define the bit + and byte ordering and the format of the value of this + object. For interfaces that do not have such an address + (e.g., a serial line), this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; + } + + leaf-list higher-layer-if { + type interface-state-ref; + status deprecated; + description + "A list of references to interfaces layered on top of this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf-list lower-layer-if { + type interface-state-ref; + status deprecated; + description + "A list of references to interfaces layered underneath this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf speed { + type yang:gauge64; + units "bits/second"; + status deprecated; + description + "An estimate of the interface's current bandwidth in bits + per second. For interfaces that do not vary in + bandwidth or for those where no accurate estimation can + be made, this node should contain the nominal bandwidth. + For interfaces that have no concept of bandwidth, this + node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - + ifSpeed, ifHighSpeed"; + } + + container statistics { + status deprecated; + description + "A collection of interface-related statistics objects."; + + leaf discontinuity-time { + type yang:date-and-time; + mandatory true; + status deprecated; + description + "The time on the most recent occasion at which any one or + more of this interface's counters suffered a + discontinuity. If no such discontinuities have occurred + since the last re-initialization of the local management + subsystem, then this node contains the time the local + management subsystem re-initialized itself."; + } + + leaf in-octets { + type yang:counter64; + status deprecated; + description + "The total number of octets received on the interface, + including framing characters. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; + } + + leaf in-unicast-pkts { + type yang:counter64; + status deprecated; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were not addressed to a + multicast or broadcast address at this sub-layer. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; + } + + leaf in-broadcast-pkts { + type yang:counter64; + status deprecated; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a broadcast + address at this sub-layer. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInBroadcastPkts"; + } + + leaf in-multicast-pkts { + type yang:counter64; + status deprecated; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a multicast + address at this sub-layer. For a MAC-layer protocol, + this includes both Group and Functional addresses. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInMulticastPkts"; + } + + leaf in-discards { + type yang:counter32; + status deprecated; + + description + "The number of inbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being deliverable to a higher-layer + protocol. One possible reason for discarding such a + packet could be to free up buffer space. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInDiscards"; + } + + leaf in-errors { + type yang:counter32; + status deprecated; + description + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of + inbound transmission units that contained errors + preventing them from being deliverable to a higher-layer + protocol. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInErrors"; + } + + leaf in-unknown-protos { + type yang:counter32; + status deprecated; + description + "For packet-oriented interfaces, the number of packets + received via the interface that were discarded because + of an unknown or unsupported protocol. For + character-oriented or fixed-length interfaces that + support protocol multiplexing, the number of + transmission units received via the interface that were + discarded because of an unknown or unsupported protocol. + For any interface that does not support protocol + multiplexing, this counter is not present. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; + } + + leaf out-octets { + type yang:counter64; + status deprecated; + description + "The total number of octets transmitted out of the + interface, including framing characters. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; + } + + leaf out-unicast-pkts { + type yang:counter64; + status deprecated; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were not addressed + to a multicast or broadcast address at this sub-layer, + including those that were discarded or not sent. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; + } + + leaf out-broadcast-pkts { + type yang:counter64; + status deprecated; + + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + broadcast address at this sub-layer, including those + that were discarded or not sent. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutBroadcastPkts"; + } + + leaf out-multicast-pkts { + type yang:counter64; + status deprecated; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + multicast address at this sub-layer, including those + that were discarded or not sent. For a MAC-layer + protocol, this includes both Group and Functional + addresses. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutMulticastPkts"; + } + + leaf out-discards { + type yang:counter32; + status deprecated; + description + "The number of outbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being transmitted. One possible reason + for discarding such a packet could be to free up buffer + space. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; + } + + leaf out-errors { + type yang:counter32; + status deprecated; + description + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutErrors"; + } + } + } + } +} diff --git a/radio/fhi_72/mplane/yang/models/ietf-ip.yang b/radio/fhi_72/mplane/yang/models/ietf-ip.yang new file mode 100644 index 0000000000..449081b5c9 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/ietf-ip.yang @@ -0,0 +1,860 @@ +module ietf-ip { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-ip"; + prefix ip; + + import ietf-interfaces { + prefix if; + } + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (Network Modeling) Working Group"; + + contact + "WG Web: + WG List: + Editor: Martin Bjorklund + "; + description + "This module contains a collection of YANG definitions for + managing IP implementations. + Copyright (c) 2018 IETF Trust and the persons identified as + authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + This version of this YANG module is part of RFC 8344; see + the RFC itself for full legal notices."; + + revision 2018-02-22 { + description + "Updated to support NMDA."; + reference + "RFC 8344: A YANG Data Model for IP Management"; + } + + revision 2014-06-16 { + description + "Initial revision."; + reference + "RFC 7277: A YANG Data Model for IP Management"; + } + + /* + * Features + */ + + feature ipv4-non-contiguous-netmasks { + description + "Indicates support for configuring non-contiguous + subnet masks."; + } + + feature ipv6-privacy-autoconf { + description + "Indicates support for privacy extensions for stateless address + autoconfiguration in IPv6."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6"; + } + + /* + * Typedefs + */ + + typedef ip-address-origin { + type enumeration { + enum other { + description + "None of the following."; + } + + enum static { + description + "Indicates that the address has been statically + configured -- for example, using the Network Configuration + Protocol (NETCONF) or a command line interface."; + } + enum dhcp { + description + "Indicates an address that has been assigned to this + system by a DHCP server."; + } + enum link-layer { + description + "Indicates an address created by IPv6 stateless + autoconfiguration that embeds a link-layer address in its + interface identifier."; + } + enum random { + description + "Indicates an address chosen by the system at + random, e.g., an IPv4 address within 169.254/16, a + temporary address as described in RFC 4941, or a + semantically opaque address as described in RFC 7217."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + RFC 7217: A Method for Generating Semantically Opaque + Interface Identifiers with IPv6 Stateless + Address Autoconfiguration (SLAAC)"; + } + } + description + "The origin of an address."; + } + + typedef neighbor-origin { + type enumeration { + enum other { + description + "None of the following."; + } + enum static { + description + "Indicates that the mapping has been statically + configured -- for example, using NETCONF or a command line + interface."; + } + + enum dynamic { + description + "Indicates that the mapping has been dynamically resolved + using, for example, IPv4 ARP or the IPv6 Neighbor + Discovery protocol."; + } + } + description + "The origin of a neighbor entry."; + } + + /* + * Data nodes + */ + + augment "/if:interfaces/if:interface" { + description + "IP parameters on interfaces. + If an interface is not capable of running IP, the server + must not allow the client to configure these parameters."; + + container ipv4 { + presence + "Enables IPv4 unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Parameters for the IPv4 address family."; + + leaf enabled { + type boolean; + default true; + description + "Controls whether IPv4 is enabled or disabled on this + interface. When IPv4 is enabled, this interface is + connected to an IPv4 stack, and the interface can send + and receive IPv4 packets."; + } + leaf forwarding { + type boolean; + default false; + description + "Controls IPv4 packet forwarding of datagrams received by, + but not addressed to, this interface. IPv4 routers + forward datagrams. IPv4 hosts do not (except those + source-routed via the host)."; + } + + leaf mtu { + type uint16 { + range "68..max"; + } + units "octets"; + description + "The size, in octets, of the largest IPv4 packet that the + interface will send and receive. + The server may restrict the allowed values for this leaf, + depending on the interface's type. + If this leaf is not configured, the operationally used MTU + depends on the interface's type."; + reference + "RFC 791: Internet Protocol"; + } + list address { + key "ip"; + description + "The list of IPv4 addresses on the interface."; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address on the interface."; + } + choice subnet { + mandatory true; + description + "The subnet can be specified as a prefix length or, + if the server supports non-contiguous netmasks, as + a netmask."; + leaf prefix-length { + type uint8 { + range "0..32"; + } + description + "The length of the subnet prefix."; + } + leaf netmask { + if-feature ipv4-non-contiguous-netmasks; + type yang:dotted-quad; + description + "The subnet specified as a netmask."; + } + } + + leaf origin { + type ip-address-origin; + config false; + description + "The origin of this address."; + } + } + list neighbor { + key "ip"; + description + "A list of mappings from IPv4 addresses to + link-layer addresses. + Entries in this list in the intended configuration are + used as static entries in the ARP Cache. + In the operational state, this list represents the ARP + Cache."; + reference + "RFC 826: An Ethernet Address Resolution Protocol"; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + mandatory true; + description + "The link-layer address of the neighbor node."; + } + leaf origin { + type neighbor-origin; + config false; + description + "The origin of this neighbor entry."; + } + } + } + + container ipv6 { + presence + "Enables IPv6 unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Parameters for the IPv6 address family."; + + leaf enabled { + type boolean; + default true; + description + "Controls whether IPv6 is enabled or disabled on this + interface. When IPv6 is enabled, this interface is + connected to an IPv6 stack, and the interface can send + and receive IPv6 packets."; + } + leaf forwarding { + type boolean; + default false; + description + "Controls IPv6 packet forwarding of datagrams received by, + but not addressed to, this interface. IPv6 routers + forward datagrams. IPv6 hosts do not (except those + source-routed via the host)."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 6.2.1, IsRouter"; + } + leaf mtu { + type uint32 { + range "1280..max"; + } + units "octets"; + description + "The size, in octets, of the largest IPv6 packet that the + interface will send and receive. + The server may restrict the allowed values for this leaf, + depending on the interface's type. + If this leaf is not configured, the operationally used MTU + depends on the interface's type."; + reference + "RFC 8200: Internet Protocol, Version 6 (IPv6) + Specification + Section 5"; + } + + list address { + key "ip"; + description + "The list of IPv6 addresses on the interface."; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address on the interface."; + } + leaf prefix-length { + type uint8 { + range "0..128"; + } + mandatory true; + description + "The length of the subnet prefix."; + } + leaf origin { + type ip-address-origin; + config false; + description + "The origin of this address."; + } + leaf status { + type enumeration { + enum preferred { + description + "This is a valid address that can appear as the + destination or source address of a packet."; + } + enum deprecated { + description + "This is a valid but deprecated address that should + no longer be used as a source address in new + communications, but packets addressed to such an + address are processed as expected."; + } + enum invalid { + description + "This isn't a valid address, and it shouldn't appear + as the destination or source address of a packet."; + } + + enum inaccessible { + description + "The address is not accessible because the interface + to which this address is assigned is not + operational."; + } + enum unknown { + description + "The status cannot be determined for some reason."; + } + enum tentative { + description + "The uniqueness of the address on the link is being + verified. Addresses in this state should not be + used for general communication and should only be + used to determine the uniqueness of the address."; + } + enum duplicate { + description + "The address has been determined to be non-unique on + the link and so must not be used."; + } + enum optimistic { + description + "The address is available for use, subject to + restrictions, while its uniqueness on a link is + being verified."; + } + } + config false; + description + "The status of an address. Most of the states correspond + to states from the IPv6 Stateless Address + Autoconfiguration protocol."; + reference + "RFC 4293: Management Information Base for the + Internet Protocol (IP) + - IpAddressStatusTC + RFC 4862: IPv6 Stateless Address Autoconfiguration"; + } + } + + list neighbor { + key "ip"; + description + "A list of mappings from IPv6 addresses to + link-layer addresses. + Entries in this list in the intended configuration are + used as static entries in the Neighbor Cache. + In the operational state, this list represents the + Neighbor Cache."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)"; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + mandatory true; + description + "The link-layer address of the neighbor node. + In the operational state, if the neighbor's 'state' leaf + is 'incomplete', this leaf is not instantiated."; + } + leaf origin { + type neighbor-origin; + config false; + description + "The origin of this neighbor entry."; + } + leaf is-router { + type empty; + config false; + description + "Indicates that the neighbor node acts as a router."; + } + + leaf state { + type enumeration { + enum incomplete { + description + "Address resolution is in progress, and the + link-layer address of the neighbor has not yet been + determined."; + } + enum reachable { + description + "Roughly speaking, the neighbor is known to have been + reachable recently (within tens of seconds ago)."; + } + enum stale { + description + "The neighbor is no longer known to be reachable, but + until traffic is sent to the neighbor no attempt + should be made to verify its reachability."; + } + enum delay { + description + "The neighbor is no longer known to be reachable, and + traffic has recently been sent to the neighbor. + Rather than probe the neighbor immediately, however, + delay sending probes for a short while in order to + give upper-layer protocols a chance to provide + reachability confirmation."; + } + enum probe { + description + "The neighbor is no longer known to be reachable, and + unicast Neighbor Solicitation probes are being sent + to verify reachability."; + } + } + config false; + description + "The Neighbor Unreachability Detection state of this + entry."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 7.3.2"; + } + } + + leaf dup-addr-detect-transmits { + type uint32; + default 1; + description + "The number of consecutive Neighbor Solicitation messages + sent while performing Duplicate Address Detection on a + tentative address. A value of zero indicates that + Duplicate Address Detection is not performed on + tentative addresses. A value of one indicates a single + transmission with no follow-up retransmissions."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration"; + } + container autoconf { + description + "Parameters to control the autoconfiguration of IPv6 + addresses, as described in RFC 4862."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration"; + + leaf create-global-addresses { + type boolean; + default true; + description + "If enabled, the host creates global addresses as + described in RFC 4862."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration + Section 5.5"; + } + leaf create-temporary-addresses { + if-feature ipv6-privacy-autoconf; + type boolean; + default false; + description + "If enabled, the host creates temporary addresses as + described in RFC 4941."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6"; + } + + leaf temporary-valid-lifetime { + if-feature ipv6-privacy-autoconf; + type uint32; + units "seconds"; + default 604800; + description + "The time period during which the temporary address + is valid."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + - TEMP_VALID_LIFETIME"; + } + leaf temporary-preferred-lifetime { + if-feature ipv6-privacy-autoconf; + type uint32; + units "seconds"; + default 86400; + description + "The time period during which the temporary address is + preferred."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + - TEMP_PREFERRED_LIFETIME"; + } + } + } + } + + /* + * Legacy operational state data nodes + */ + + augment "/if:interfaces-state/if:interface" { + status deprecated; + description + "Data nodes for the operational state of IP on interfaces."; + + container ipv4 { + presence + "Present if IPv4 is enabled on this interface"; + config false; + status deprecated; + description + "Interface-specific parameters for the IPv4 address family."; + + leaf forwarding { + type boolean; + status deprecated; + description + "Indicates whether IPv4 packet forwarding is enabled or + disabled on this interface."; + } + leaf mtu { + type uint16 { + range "68..max"; + } + units "octets"; + status deprecated; + description + "The size, in octets, of the largest IPv4 packet that the + interface will send and receive."; + reference + "RFC 791: Internet Protocol"; + } + list address { + key "ip"; + status deprecated; + description + "The list of IPv4 addresses on the interface."; + + leaf ip { + type inet:ipv4-address-no-zone; + status deprecated; + description + "The IPv4 address on the interface."; + } + choice subnet { + status deprecated; + description + "The subnet can be specified as a prefix length or, + if the server supports non-contiguous netmasks, as + a netmask."; + leaf prefix-length { + type uint8 { + range "0..32"; + } + status deprecated; + description + "The length of the subnet prefix."; + } + leaf netmask { + if-feature ipv4-non-contiguous-netmasks; + type yang:dotted-quad; + status deprecated; + description + "The subnet specified as a netmask."; + } + } + leaf origin { + type ip-address-origin; + status deprecated; + description + "The origin of this address."; + } + } + list neighbor { + key "ip"; + status deprecated; + description + "A list of mappings from IPv4 addresses to + link-layer addresses. + This list represents the ARP Cache."; + reference + "RFC 826: An Ethernet Address Resolution Protocol"; + + leaf ip { + type inet:ipv4-address-no-zone; + status deprecated; + description + "The IPv4 address of the neighbor node."; + } + + leaf link-layer-address { + type yang:phys-address; + status deprecated; + description + "The link-layer address of the neighbor node."; + } + leaf origin { + type neighbor-origin; + status deprecated; + description + "The origin of this neighbor entry."; + } + } + } + + container ipv6 { + presence + "Present if IPv6 is enabled on this interface"; + config false; + status deprecated; + description + "Parameters for the IPv6 address family."; + + leaf forwarding { + type boolean; + default false; + status deprecated; + description + "Indicates whether IPv6 packet forwarding is enabled or + disabled on this interface."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 6.2.1, IsRouter"; + } + leaf mtu { + type uint32 { + range "1280..max"; + } + units "octets"; + status deprecated; + description + "The size, in octets, of the largest IPv6 packet that the + interface will send and receive."; + reference + "RFC 8200: Internet Protocol, Version 6 (IPv6) + Specification + Section 5"; + } + list address { + key "ip"; + status deprecated; + description + "The list of IPv6 addresses on the interface."; + + leaf ip { + type inet:ipv6-address-no-zone; + status deprecated; + description + "The IPv6 address on the interface."; + } + leaf prefix-length { + type uint8 { + range "0..128"; + } + mandatory true; + status deprecated; + description + "The length of the subnet prefix."; + } + leaf origin { + type ip-address-origin; + status deprecated; + description + "The origin of this address."; + } + leaf status { + type enumeration { + enum preferred { + description + "This is a valid address that can appear as the + destination or source address of a packet."; + } + enum deprecated { + description + "This is a valid but deprecated address that should + no longer be used as a source address in new + communications, but packets addressed to such an + address are processed as expected."; + } + enum invalid { + description + "This isn't a valid address, and it shouldn't appear + as the destination or source address of a packet."; + } + + enum inaccessible { + description + "The address is not accessible because the interface + to which this address is assigned is not + operational."; + } + enum unknown { + description + "The status cannot be determined for some reason."; + } + enum tentative { + description + "The uniqueness of the address on the link is being + verified. Addresses in this state should not be + used for general communication and should only be + used to determine the uniqueness of the address."; + } + enum duplicate { + description + "The address has been determined to be non-unique on + the link and so must not be used."; + } + enum optimistic { + description + "The address is available for use, subject to + restrictions, while its uniqueness on a link is + being verified."; + } + } + status deprecated; + description + "The status of an address. Most of the states correspond + to states from the IPv6 Stateless Address + Autoconfiguration protocol."; + reference + "RFC 4293: Management Information Base for the + Internet Protocol (IP) + - IpAddressStatusTC + RFC 4862: IPv6 Stateless Address Autoconfiguration"; + } + } + + list neighbor { + key "ip"; + status deprecated; + description + "A list of mappings from IPv6 addresses to + link-layer addresses. + This list represents the Neighbor Cache."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)"; + + leaf ip { + type inet:ipv6-address-no-zone; + status deprecated; + description + "The IPv6 address of the neighbor node."; + } + leaf link-layer-address { + type yang:phys-address; + status deprecated; + description + "The link-layer address of the neighbor node."; + } + leaf origin { + type neighbor-origin; + status deprecated; + description + "The origin of this neighbor entry."; + } + leaf is-router { + type empty; + status deprecated; + description + "Indicates that the neighbor node acts as a router."; + } + leaf state { + type enumeration { + enum incomplete { + description + "Address resolution is in progress, and the + link-layer address of the neighbor has not yet been + determined."; + } + enum reachable { + description + "Roughly speaking, the neighbor is known to have been + reachable recently (within tens of seconds ago)."; + } + enum stale { + description + "The neighbor is no longer known to be reachable, but + until traffic is sent to the neighbor no attempt + should be made to verify its reachability."; + } + enum delay { + description + "The neighbor is no longer known to be reachable, and + traffic has recently been sent to the neighbor. + Rather than probe the neighbor immediately, however, + delay sending probes for a short while in order to + give upper-layer protocols a chance to provide + reachability confirmation."; + } + enum probe { + description + "The neighbor is no longer known to be reachable, and + unicast Neighbor Solicitation probes are being sent + to verify reachability."; + } + } + status deprecated; + description + "The Neighbor Unreachability Detection state of this + entry."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 7.3.2"; + } + } + } + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-compression-factors.yang b/radio/fhi_72/mplane/yang/models/o-ran-compression-factors.yang new file mode 100644 index 0000000000..5816b5ed63 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-compression-factors.yang @@ -0,0 +1,368 @@ +module o-ran-compression-factors { + yang-version 1.1; + namespace "urn:o-ran:compression-factors:1.0"; + prefix "o-ran-compression-factors"; + + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the module capabilities for + the O-RAN Radio Unit U-Plane configuration. + + Copyright 2020 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + revision "2020-08-10" { + description + "version 4.0.0 + + 1) supporting compression types per endpoint + 2) adding feature for configurable fs-offset for compression"; + + reference "ORAN-WG4.M.0-v04.00"; + } + + revision "2020-04-17" { + description + "version 3.0.0 + + 1) adding selective RE sending compression types"; + + reference "ORAN-WG4.M.0-v03.00"; + } + + revision "2019-07-03" { + description + "version 1.1.0 + + 1) changes related to compression bitwidth presentation"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + feature CONFIGURABLE-FS-OFFSET { + description + "Presence of this feature means that O-RU supports configurable fs-offset for compression."; + } + + grouping compression-method-grouping { + description + "Grouping for compression method."; + + leaf iq-bitwidth { + type uint8; + description + "Bitwidth to be used in compression"; + } + + leaf compression-method { + type enumeration { + enum NO_COMPRESSION { + description + "No compression will be used"; + } + enum BLOCK_FLOATING_POINT { + description + "Block floating point compression and decompression will be used"; + } + + enum BLOCK_SCALING { + description + "Block scaling compression and decompresion will be used"; + } + + enum U_LAW { + description + "u-Law compression and decompresion method will be used"; + } + + enum BEAMSPACE { + description + "Beamspace compression and decompression will be used"; + } + + enum MODULATION { + description + "Modulation compression and decompression will be used"; + } + enum BLOCK-FLOATING-POINT-SELECTIVE-RE-SENDING { + description + "block floating point with selective re sending + compression and decompression will be used"; + } + enum MODULATION-COMPRESSION-SELECTIVE-RE-SENDING { + description + "modulation compression with selective re sending + compression and decompression will be used"; + } + } + description + "Compresion method which can be supported by the O-RU"; + } + } + + grouping compression-formats { + description + "Grouping deicated to list compression formats as choice"; + + choice compression-format { + description + "Choice of compression format for particular element"; + + case no-compresison { + description "Compression for beam weights is not supported."; + } + case block-floating-point { + description "Block floating point compression and decompression is supported."; + + leaf exponent { + type uint8 { + range "4"; + } + description "Exponent bit width size in number of bits used when encoding in udCompParam."; + } + } + + case block-floating-point-selective-re-sending { + description + "Block floating point with selective re sending compression and decompression is supported."; + + leaf sres-exponent { + type uint8 { + range "4"; + } + description "Exponent bit width size in number of bits used when encoding in udCompParam."; + } + } + + case block-scaling { + description "Block scaling compression and decompresion is supported."; + leaf block-scalar { + type uint8; + description + "Common scaler for compressed PRB"; + } + } + + case u-law { + description "u-Law compression and decompresion method is supported."; + leaf comp-bit-width { + type uint8 { + range "0..15"; + } + description "Bit with for u-law compression"; + } + leaf comp-shift { + type uint8 { + range "0..15"; + } + description + "the shift applied to the entire PRB"; + } + } + + case beam-space-compression { + description "Beamspace compression and decompression is supported. Applies to beamforming weights only."; + leaf-list active-beam-space-coeficient-mask { + type uint8; + description + "active beamspace coefficient indices associated with the compressed beamforming vector"; + } + leaf block-scaler { + type uint8; + description + "Common scaler for compressed beamforming coefficients"; + } + } + + case modulation-compression { + description "Modulation compression and decompression is supported."; + leaf csf { + type uint8 { + range "0..1"; + } + description "Constallation shift flag"; + } + + leaf mod-comp-scaler { + type uint16 { + range "0..32767"; + } + description "Modulation compression scaler value."; + } + } + + case modulation-compression-selective-re-sending { + description "Modulation compression with selective re sending and decompression is supported."; + leaf sres-csf { + type uint8 { + range "0..1"; + } + description "Constallation shift flag"; + } + + leaf sres-mod-comp-scaler { + type uint16 { + range "0..32767"; + } + description "Modulation compression scaler value."; + } + } + + } + } + + grouping compression-params { + description + "Parameters to define compression"; + + leaf compression-type { + type enumeration { + enum STATIC { + description + "Indicates that static compression method will be used (both compression and IQ bitwidth)"; + } + enum DYNAMIC { + description + "Indicates that dynamic compression method will be used"; + } + } + mandatory true; + description + "Compression type that O-DU wants to be supported"; + } + +// *********** TO BE REMOVED *********** + leaf bitwidth { + when "../compression-type = 'STATIC'"; + type uint8; + status deprecated; + description + "Bitwidth to be used in compression. + This has since been replaced in M-Plane version + 2.0.0 with the iq-bitwidth schema node"; + } +// ************************************* + + uses compression-formats; + } + + grouping compression-parameters { + description + "Parameters used to define description type"; + + leaf iq-bitwidth { + type uint8; + description + "Bitwidth to be used in compression"; + } + + uses compression-formats; + } + + grouping format-of-iq-sample { + description + "Indicates module capabilities about IQ samples"; + + leaf dynamic-compression-supported { + type boolean; + + description + "Informs if radio supports dynamic compression method"; + } + + leaf realtime-variable-bit-width-supported { + type boolean; + + description + "Informs if O-RU supports realtime variable bit with"; + } + + list compression-method-supported { + uses compression-parameters; + + description + "List of supported compression methods by O-RU + Note: if O-RU supports different compression methods per endpoint + then please refer do endpoints to have information what + exactly is supported on a paticular endpoint"; + } + + leaf syminc-supported { + type boolean; + + description + "Informs if symbol number increment command in a C-Plane is + supported or not"; + } + + leaf regularization-factor-se-supported { + type boolean; + + description + "Informs if regularizationFactor in section type 5 is + supported(true) or not(false)"; + } + + leaf little-endian-supported { + type boolean; + default false; + + description + "All O-RUs support bigendian byte order. This node informs if module supports the + the optional capability for little endian byte order for C/U plane data flows. + + Note - little endian support does not invalidate bigendian support."; + } + } + + + grouping compression-details { + description ""; + + leaf iq-bitwidth { + type uint8; + description + "Bitwidth to be used in compression"; + } + + uses compression-params; + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-interfaces.yang b/radio/fhi_72/mplane/yang/models/o-ran-interfaces.yang new file mode 100644 index 0000000000..92587ce40c --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-interfaces.yang @@ -0,0 +1,414 @@ +module o-ran-interfaces { + yang-version 1.1; + namespace "urn:o-ran:interfaces:1.0"; + prefix "o-ran-int"; + + + import ietf-inet-types { + prefix "inet"; + } + + import iana-if-type { + prefix "ianaift"; + } + + import ietf-interfaces { + prefix "if"; + } + + import ietf-ip { + prefix "ip"; + } + + import ietf-hardware { + prefix "hw"; + } + + import ietf-yang-types { + prefix "yang"; + } + + import iana-hardware { + prefix "ianahw"; + } + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the YANG definitions for managng the O-RAN + interfaces. + + Copyright 2020 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + revision "2020-04-17" { + description + "version 1.2.0 + + 1) updated descriptions to clarify operation when vlan-tagging is false"; + + reference "ORAN-WG4.M.0-v03.00"; + } + revision "2019-07-03" { + description + "version 1.1.0 + + 1) increasing max elements for user plane DSCP markings to 64 + 2) re-organizing layout to facilitate cross-WG adoption, whilst ensuring + nodes are syntactically and semantically equivalent"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + feature UDPIP-BASED-CU-PLANE { + description + "This feature indicates that the RU supports the UDP/IP based transport + for the CU plane."; + } + + feature ALIASMAC-BASED-CU-PLANE { + description + "This feature indicates that the RU supports the alias MAC address + based transport for the CU plane."; + } + + + typedef pcp { + type uint8 { + range "0..7"; + } + description + "Priority Code Point. PCP is a 3-bit field that refers to the + class of service applied to a VLAN tagged frame. The + field specifies a priority value between 0 and 7, these values + can be used by quality of service (QoS) to prioritize + different classes of traffic."; + reference + "IEEE 802.1Q-2014: Virtual Bridged Local Area Networks"; + } + + grouping cos-marking { + description + "Configuration data for CU Plane ethernet CoS marking. + This grouping is only applicable to an interface when vlan-tagging is + set to TRUE for that interface. In other cases, it may be ignored."; + container class-of-service { + description + "CoS Configuration"; + leaf u-plane-marking { + type pcp; + default 7; + description + "Marking used for default u-plane flows. + 7 represents highest priority for u-plane marking"; + } + leaf c-plane-marking { + type pcp; + default 7; + description "7 represents highest priority for c-plane marking"; + } + leaf m-plane-marking { + type pcp; + default 2; + description "2 represents highest excellent effort for m-plane marking"; + } + leaf s-plane-marking { + type pcp; + default 7; + description "7 represents highest priority for s-plane marking"; + } + leaf other-marking { + type pcp; + default 1; + description "1 represents best effort for other marking"; + } + list enhanced-uplane-markings{ + key "up-marking-name"; + max-elements 4; + description + "list of mappings for enhanced (non-default) u-plane markings"; + leaf up-marking-name { + type string; + description "The name of the marking"; + } + leaf enhanced-marking { + type pcp; + description "the enhanced u-plane marking"; + } + } + } + } + + grouping dscp-marking { + description + "Configuration data for CU Plane DSCP marking"; + container diffserv-markings { + description + "DSCP Configuration"; + leaf u-plane-marking { + type inet:dscp; + default 46; + description + "Marking used for default u-plane flows. + 46 represents expedited forwarding"; + } + leaf c-plane-marking { + type inet:dscp; + default 46; + description "46 represents expedited forwarding"; + } + leaf s-plane-marking { + type inet:dscp; + default 46; + description "46 represents expedited forwarding"; + } + leaf other-marking { + type inet:dscp; + default 0; + description "0 represents best effort forwarding"; + } + list enhanced-uplane-markings{ + key up-marking-name; + max-elements 64; + description + "list of mappings for enhanced (non-default) u-plane markings"; + leaf up-marking-name { + type string; + description "The name of the marking"; + } + leaf enhanced-marking { + type inet:dscp; + description "the enhanced u-plane marking"; + } + } + } + } + +// Cross Working Group Augmentations Follow + +// Cross Working Group augmentations for basic Ethernet leafs + + augment "/if:interfaces/if:interface" { + when "if:type = 'ianaift:ethernetCsmacd'" { + description "Applies to Ethernet interfaces"; + } + description + "Augment the interface model with parameters for + base Ethernet interface"; + + leaf l2-mtu { + type uint16 { + range "64 .. 65535"; + } + units bytes; + default 1500; + description + "The maximum size of layer 2 frames that may be transmitted + or received on the interface (excluding any FCS overhead). + For Ethernet interfaces it also excludes the + 4-8 byte overhead of any known (i.e. explicitly matched by + a child sub-interface) 801.1Q VLAN tags."; + } + leaf vlan-tagging { + type boolean; + default true; + description + "Indicates if VLAN tagging is used. + Default true is used to enable equipment to autonomously discover that + it is connected to a trunk port. + + This may be set to false, for example, when the O-RU is directly + connected to the O-DU. In such cases, native Ethernet frames may be + used across the O-RAN interface, i.e., any PCP markings defined + in the cos-markings grouping are NOT used by the O-RU and any default + value or configured value using those leafs may be ignored by the O-RAN + equipment."; + } + uses cos-marking; + } + +// Cross Working Group augmentation for l2vlan interfaces for VLAN definition + + augment "/if:interfaces/if:interface" { + when "if:type = 'ianaift:l2vlan'"; + description "augments for VLAN definition"; + leaf base-interface { + type if:interface-ref; + must "/if:interfaces/if:interface[if:name = current()]" + + "/o-ran-int:vlan-tagging = 'true'" { + description + "The base interface must have VLAN tagging enabled."; + } + description + "The base interface for the VLAN sub-interafce."; + } + leaf vlan-id { + type uint16 { + range "1..4094"; + } + description + "The VLAN-ID."; + } + } + +// Cross Working Group augmention for both ethernetCsmacd and l2vlan interfaces + + augment "/if:interfaces/if:interface" { + when "(if:type = 'ianaift:ethernetCsmacd') or + (if:type = 'ianaift:l2vlan')" { + description "Applies to ethernetCsmacd and l2vlan interfaces"; + } + description + "Augment the interface model with parameters for all + both ethernetCsmacd and l2vlan interfaces."; + leaf last-cleared { + type yang:date-and-time; + config false; + description + "Timestamp of the last time the interface counters were + cleared."; + } + } + +// Cross Working Group augmention to ietf-ip covering DSCP for M-Plane + +augment "/if:interfaces/if:interface/ip:ipv4" { + description "augments for IPv4 based M-Plane transport"; + leaf m-plane-marking { + type inet:dscp; + default 18; + description "18 represents AF21 or 'immediate traffic'"; + } +} +augment "/if:interfaces/if:interface/ip:ipv6" { + description "augments for IPv6 based M-Plane transport"; + leaf m-plane-marking { + type inet:dscp; + default 18; + description "18 represents AF21 or 'immediate traffic'"; + } +} + +// WG4 Specific Augmentations Follow + +// WG4 Augmentation for basic Ethernet leafs + + augment "/if:interfaces/if:interface" { + if-feature ALIASMAC-BASED-CU-PLANE; + when "if:type = 'ianaift:ethernetCsmacd'" { + description + "Applies to WG4 Ethernet interfaces for alias MAC based CU-Plane"; + } + description + "Augment the interface model with parameters for + base Ethernet interface"; + + leaf-list alias-macs { + type yang:mac-address; + description + "Augments interfaces with range of alias MAC addresses."; + } + } + +// WG4 Augmention for both ethernetCsmacd and l2vlan interfaces + + augment "/if:interfaces/if:interface" { + when "(if:type = 'ianaift:ethernetCsmacd') or + (if:type = 'ianaift:l2vlan')" { + description "Applies to ethernetCsmacd and l2vlan interfaces"; + } + description + "Augment the interface model with parameters for all + both ethernetCsmacd and l2vlan interfaces."; + leaf mac-address { + type yang:mac-address; + description + "The MAC address of the interface."; + } + container port-reference { + description + "a port reference used by other O-RAN modules"; + leaf port-name { + type leafref { + path '/hw:hardware/hw:component/hw:name'; + } + must "derived-from-or-self(deref(current())/../hw:class, 'ianahw:port')"; +// TAKE NOTE - depending on version of pyang, this may generate various +// warnings, e.g., warning: XPath for "port-name" does not exist + description + "O-RAN interfaces use a reference to a physical port component. + + In this case, the component name referenced must be of class type + port, i.e., when /hw:hardware/hw:component/hw:class is derived from + ianahw:port"; + } + leaf port-number { + type uint8; + description + "A number allocated by the server which identifies a port. + Port number value is 0 to N-1 where N is number of ports + in the device. + + This value is fixed for the lifetime of the equipment, i.e., cannot be + changed during equipment reboots."; + } + } + } + +// WG4 specific augmention to ietf-ip covering DSCP for CUS Plane + + augment "/if:interfaces/if:interface/ip:ipv4" { + if-feature UDPIP-BASED-CU-PLANE; + description "augments for IPv4 based CUS transport"; + uses dscp-marking; + } + augment "/if:interfaces/if:interface/ip:ipv6" { + if-feature UDPIP-BASED-CU-PLANE; + description "augments for IPv6 based CUS transport"; + uses dscp-marking; + } + +// Other Working Group Specific Augmentations Follow Here + + + rpc reset-interface-counters { + description + "Management plane triggered restart of the interface counters."; + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-module-cap.yang b/radio/fhi_72/mplane/yang/models/o-ran-module-cap.yang new file mode 100644 index 0000000000..e726d57e72 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-module-cap.yang @@ -0,0 +1,840 @@ +module o-ran-module-cap { + yang-version 1.1; + namespace "urn:o-ran:module-cap:1.0"; + prefix "o-ran-module-cap"; + + import o-ran-compression-factors { + prefix "cf"; + revision-date 2020-08-10; + } + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the module capabilities for + the O-RAN Radio Unit. + + Copyright 2020 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + revision "2020-08-10" { + description + "version 4.0.0 + + 1) added RO capability to expose O-RU's ability to support udCompLen record in U-Plane section header fields + 2) feature indicating support for static PRACH configuration introduced + 3) feature indicating support for static SRS configuration introduced + 4) feature indicating support for TDD pattern configuration introduced + 5) backward compatible change to introduce new O-RU's features related + to Section Description Priority to serve for CUS-Plane C"; + + reference "ORAN-WG4.M.0-v04.00"; + } + + revision "2020-04-17" { + description + "version 3.0.0 + + 1) Adding optional little endian support + 2) Added support for Dynamic Spectrum Sharing feature + 3) Enable number-of-ru-ports to be different between dl and ul + 4) Enable regularizationFactor to be signalled outside of section type 6 + 5) Enable PRACH preamble formats supported to be signalled by O-RU + 6) adding support for selective RE sending + 7) supporting new section extension for grouping multiple ports + 8) signalling to enable O-RU to ndicate is requires unique ecpri sequence id + for eAxC_IDs serving for UL and DL for the same carrier component"; + + reference "ORAN-WG4.M.0-v03.00"; + } + + revision "2019-07-03" { + description + "version 1.1.0 + + 1) backward compatible change to introduce new RW leafs for use in + constraints in uplane-config and laa models. + 2) removing unnecessary relations to band 46 in uplink"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + feature LAA { + description + "Indicates that the Radio Unit supports LAA."; + } + + feature EAXC-ID-GROUP-SUPPORTED { + description + "indicates that the Radio Unit supports EAXC-ID-GROUP-SUPPORTED."; + } + + feature TRANSPORT-FRAGMENTATION { + description + "This leaf is used to indicate whether the O-RU supports O-RAN Radio Transport Fragmentation"; + } + + feature DSS_LTE_NR { + description + "Indicates that the Radio Unit supports Dynamic Spectrum Sharing between LTE and NR."; + } + + feature PRACH-STATIC-CONFIGURATION-SUPPORTED { + description + "This leaf is used to indicate O-RU's support for configuration of PRACH (Physical Random Access Channel) pattern in the static manner, so that PRACH U-Plane traffic can be processed by RU without receiving C-Plane messages conveying the PRACH configuration."; + } + + feature SRS-STATIC-CONFIGURATION-SUPPORTED { + description + "This leaf is used to indicate O-RU's support for configuration of SRS (Sounding Reference Signal Channel) pattern in the static manner, so that SRS U-Plane traffic can be processed by RU without receiving C-Plane messages conveying the SRS configuration."; + } + + feature CONFIGURABLE-TDD-PATTERN-SUPPORTED { + description + "This leaf is used to indicate O-RU's support for configurable TDD pattern."; + } + + typedef sub-band-string { + type string { + pattern [ABCD]; + } + description "Sub bands definition"; + } + + typedef scs-config-type { + type enumeration { + enum KHZ_15 { + value 0; + description + "15kHz sub carrier spacing"; + } + enum KHZ_30 { + value 1; + description + "30kHz sub carrier spacing"; + } + enum KHZ_60 { + value 2; + description + "60kHz sub carrier spacing"; + } + enum KHZ_120 { + value 3; + description + "120kHz sub carrier spacing"; + } + enum KHZ_240 { + value 4; + description + "240kHz sub carrier spacing"; + } + enum KHZ_1_25 { + value 12; + description + "1,25kHz sub carrier spacing"; + } + enum KHZ_3_75 { + value 13; + description + "3.75kHz sub carrier spacing"; + } + enum KHZ_5 { + value 14; + description + "5kHz sub carrier spacing"; + } + enum KHZ_7_5 { + value 15; + description + "7.5kHz sub carrier spacing"; + } + } + + description + "Scs configuration type definition"; + } + + grouping compression-method-grouping { + description + "Grouping for compression method."; + + leaf compression-method { + type enumeration { + enum BLOCK_FLOATING_POINT { + description + "Block floating point compression and decompression will be used"; + } + + enum BLOCK_SCALING { + description + "Block scaling compression and decompresion will be used"; + } + + enum U_LAW { + description + "u-Law compression and decompresion method will be used"; + } + + enum BEAMSPACE { + description + "Beamspace compression and decompression will be used"; + } + + enum MODULATION { + description + "Modulation compression and decompression will be used"; + } + + enum BLOCK-FLOATING-POINT-SELECTIVE-RE-SENDING { + description + "block floating point with selective re sending + compression and decompression will be used"; + } + enum MODULATION-COMPRESSION-SELECTIVE-RE-SENDING { + description + "modulation compression with selective re sending + compression and decompression will be used"; + } + } + description + "Compresion method which can be supported by the O-RU. + An O-RU may further refine the applicability of compression + methods per endpoint using o-ran-uplane-conf.yang model"; + } + } + + grouping sub-band-max-min-ul-dl-frequency { + description + "Grouping for defining max and min supported frequency - dl and ul."; + + leaf max-supported-frequency-dl { + type uint64; + description + "This value indicates Maximum supported downlink frequency in the + LAA subband. Value unit is Hz."; + } + + leaf min-supported-frequency-dl { + type uint64; + description + "This value indicates Minimum supported downlink frequency in the + LAA subband. Value unit is Hz."; + } + } + + grouping format-of-iq-sample { + description + "Indicates module capabilities about IQ samples"; + + leaf dynamic-compression-supported { + type boolean; + + description + "Informs if radio supports dynamic compression method"; + } + + leaf realtime-variable-bit-width-supported { + type boolean; + + description + "Informs if O-RU supports realtime variable bit with"; + } + + list compression-method-supported { + uses cf:compression-details; + + leaf-list fs-offset { + if-feature cf:CONFIGURABLE-FS-OFFSET; + type uint8; + default 0; + description + "List of fs offset values supported with this IQ format / compression method; + fs-offset adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format. + Please refer to CU-Plane specification for details"; + } + + description + "List of supported compression methods by O-RU + Note: if O-RU supports different compression methods per endpoint + then please refer to endpoints to have information what + exactly is supported on paticular endpoint"; + } + + leaf variable-bit-width-per-channel-supported { + when "/module-capability/ru-capabilities/format-of-iq-sample/realtime-variable-bit-width-supported = 'true'"; + type boolean; + + description + "Informs if variable bit width per channel is supported or not"; + } + + leaf syminc-supported { + type boolean; + + description + "Informs if symbol number increment command in a C-Plane is + supported or not"; + } + + leaf regularization-factor-se-supported { + type boolean; + + description + "Informs if regularizationFactor in section type 5 is + supported(true) or not(false)"; + } + + leaf little-endian-supported { + type boolean; + default false; + + description + "All O-RUs support bigendian byte order. This node informs if module supports the + the optional capability for little endian byte order for C/U plane data flows. + + Note - little endian support does not invalidate bigendian support."; + } + + } + + grouping scs-a-b { + description + "Grouping for scs-a and scs-b"; + leaf scs-a{ + type scs-config-type; + description + "Sub-carrier spacing configuration"; + } + leaf scs-b{ + type scs-config-type; + description + "Sub-carrier spacing configuration"; + } + } + + grouping ul-mixed-num-required-guard-rbs { + description + "Required number of guard resource blocks for the combination of + subcarrier spacing values for uplink"; + uses scs-a-b; + leaf number-of-guard-rbs-ul{ + type uint8; + description + "This value indicates the required number of guard resource blocks + between the mixed numerologies, the RB using scs-a and the RB + using scs-b. It's number is based on scs-a"; + } + } + + grouping dl-mixed-num-required-guard-rbs { + description + "Required number of guard resource blocks for the combination of + subcarrier spacing values for uplink"; + uses scs-a-b; + leaf number-of-guard-rbs-dl{ + type uint8; + description + "This value indicates the required number of guard resource blocks + between the mixed numerologies, the RB using scs-a and the RB + using scs-b. It's number is based on scs-a"; + } + } + + grouping ru-capabilities { + description + "Structure representing set of capabilities."; + + leaf ru-supported-category { + type enumeration { + enum CAT_A { + description + "Informs that precoding is not supported in O-RU"; + } + enum CAT_B { + description + "Informs that precoding is supported in O-RU"; + } + } + + description + "Informs about which category O-RU supports"; + } + + leaf number-of-ru-ports { + type uint8; + status deprecated; + description + "Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration) + - the number of O-RU ports is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports. + For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when PUSCH and PRACH are processed in the different endpoints. + In case there are specific endpoints that support non-time-managed traffic only + - the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic."; + } + leaf number-of-ru-ports-ul { + type uint8; + description + "Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration) + - the number of O-RU ports for uplink is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports. + For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when PUSCH and PRACH are processed in the different endpoints. + In case there are specific endpoints that support non-time-managed traffic only + - the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic."; + } + leaf number-of-ru-ports-dl { + type uint8; + description + "Assuming all endpoints support time-managed traffic AND non-time-managed traffic (choice is as per configuration) + - the number of O-RU ports for downlink is the product of number of spatial streams (leaf number-of-spatial-streams) and number of numerologies O-RU supports. + For example, if the number of spatial streams is 4 then the number of O-RU ports is 8 when SSB and non-SSB are processed in the different endpoints. + In case there are specific endpoints that support non-time-managed traffic only + - the number of O-RU ports calculated with above mentioned equation is extended by number of endpoints supporting only non-time-managed traffic."; + } + + leaf number-of-spatial-streams { + type uint8; + description + "This value indicates the number of spatial streams supported at O-RU for DL and UL. + For DL, it is same as the number of antenna ports specified in 3GPP TS38.214, Section 5.2 and 3GPP TS36.213, Section 5.2."; + } + + leaf max-power-per-pa-antenna { + type decimal64{ + fraction-digits 4; + } + description + "This value indicates Maximum Power per PA per antenna. Value unit is dBm."; + } + + leaf min-power-per-pa-antenna { + type decimal64{ + fraction-digits 4; + } + description + "This value indicates Minimum Power per PA per antenna. Value unit is dBm."; + } + + leaf fronthaul-split-option { + type uint8 { + range "7"; + } + description + "This value indicates the Fronthaul Split Option, i.e., 2 or 7 in this release."; + } + + container format-of-iq-sample { + description + "Indicates module capabilities about IQ samples"; + + uses format-of-iq-sample; + } + + list ul-mixed-num-required-guard-rbs { + key "scs-a scs-b"; + description + "List of required number of guard resource blocks + for the combination of subcarrier spacing values for downlink"; + + uses ul-mixed-num-required-guard-rbs; + } + list dl-mixed-num-required-guard-rbs { + key "scs-a scs-b"; + description + "List of required number of guard resource blocks + for the combination of subcarrier spacing values for uplink"; + + uses dl-mixed-num-required-guard-rbs; + } + + leaf energy-saving-by-transmission-blanks { + type boolean; + mandatory true; + description + "Parameter informs if unit supports energy saving by transmission blanking"; + } + container eaxcid-grouping-capabilities { + if-feature o-ran-module-cap:EAXC-ID-GROUP-SUPPORTED; + description + "a container with parameters for eaxcid grouping"; + leaf max-num-tx-eaxc-id-groups { + type uint8; + description + "Maximum number of configurable tx-eaxc-id-group supported by O-RU."; + } + leaf max-num-tx-eaxc-ids-per-group { + type uint8; + description + "Maximum number of member-tx-eaxc-id in single tx-eaxc-id-group supported by O-RU."; + } + leaf max-num-rx-eaxc-id-groups { + type uint8; + description + "the maximum number of groups with the eAxC IDs those are assigned to low-level-rx-links."; + } + leaf max-num-rx-eaxc-ids-per-group { + type uint8; + description + "the maximum number of eAxC IDs per rx-eaxc-id-group."; + } + } + + leaf dynamic-transport-delay-management-supported { + type boolean; + mandatory true; + description + "Parameter informs if unit supports dynamic transport delay management through eCPRI Msg 5"; + } + + leaf support-only-unique-ecpri-seqid-per-eaxc { + type boolean; + default false; + description + "Parameter informs if O-RU expects unique ecpri sequence id for eAxC_IDs serving + for UL and DL for the same carrier component. + + Note: If this is set to TRUE, the O-DU can decide to either use different eAxC_IDs for UL and + DL or can generate unique sequence ID per eAxC_ID. + + TAKE NOTE: This leaf is backwards compatible from an O-RU persepctive BUT an O-RU that + sets this leaf to TRUE may result in incompatibilities when operating with an O-DU + designed according to the O-RAN CUS-Plane Specification v02.00, e.g., if the O-DU is + incapable of using different eAxC values between UL and DL"; + } + + container coupling-methods { + description + "O-RU's capabilities related to supported C-Plane and U-Plane coupling methods"; + + leaf coupling-via-frequency-and-time { + type boolean; + description + "Coupling via frequency and time; see methods of coupling of C-plane and U-plane in CUS-Plane specification"; + } + + leaf coupling-via-frequency-and-time-with-priorities { + type boolean; + description + "Coupling via Frequency and time with priorities; see methods of coupling of C-plane and U-plane in CUS-Plane specification. + Note: If coupling-via-frequency-and-time-with-priorities is 'true' then coupling-via-frequency-and-time shall also be 'true'."; + } + } + + leaf ud-comp-len-supported { + type boolean; + description + "This property informs if O-RU supports optional field udCompLen in U-Plane messages. + Only in case this leaf is present and its value is TRUE, O-RU supports U-Plane messages + containing udCompLen field in section header."; + } + } + + grouping sub-band-info { + description "container for collection of leafs for LAA subband 46"; + list sub-band-frequency-ranges { + key sub-band; + description "frequency information on a per sub-band basis"; + leaf sub-band { + type sub-band-string; + description "Sub band when band 46"; + } + uses sub-band-max-min-ul-dl-frequency; + } + leaf number-of-laa-scarriers { + type uint8; + description + "This value indicates the number of LAA secondary carriers supported at O-RU."; + } + + leaf maximum-laa-buffer-size { + type uint16; + description + "Maximum O-RU buffer size in Kilobytes (KB) per CC. This parameter is + needed at the O-DU to know how much data can be sent in advance + and stored at the O-RU to address the LBT uncertainity."; + } + + leaf maximum-processing-time { + type uint16; + units microseconds; + description + "Maximum O-RU Processing time in microseconds at the O-RU to handle the + received/transmitted packets from/to the O-DU. This parameter is + needed at the O-DU to determine the time where it needs to send + the data to the O-RU."; + } + + leaf self-configure { + type boolean; + description "This value indicates that the O-RU can manage the contention window locally. "; + } + } + + grouping support-for-dl { + description + "Grouping for DL specific parameters"; + + leaf max-supported-frequency-dl { + type uint64; + description + "This value indicates Maximum supported downlink frequency. Value unit is Hz."; + } + + leaf min-supported-frequency-dl { + type uint64; + description + "This value indicates Minimum supported downlink frequency. Value unit is Hz."; + } + + leaf max-supported-bandwidth-dl { + type uint64; + description + "This value indicates Maximum total downlink bandwidth in module. Value unit is Hz."; + } + + leaf max-num-carriers-dl { + type uint32; + description + "This value indicates Maximum number of downlink carriers in module."; + } + + leaf max-carrier-bandwidth-dl { + type uint64; + description + "This value indicates Maximum bandwidth per downlink carrier. Value unit is Hz."; + } + + leaf min-carrier-bandwidth-dl { + type uint64; + description + "This value indicates Minimum bandwidth per downlink carrier. Value unit is Hz."; + } + + leaf-list supported-technology-dl { + type enumeration{ + enum LTE { + description "LTE is supported in DL path."; + } + enum NR { + description "NR is supported in DL path."; + } + enum DSS_LTE_NR { + if-feature DSS_LTE_NR; + description + "DSS is supported in the DL, which implicitly means LTE and NR are also + BOTH supported in the DL."; + } + } + min-elements 1; + description + "This list provides information regarding technologies supported in DL path"; + } + } + + grouping support-for-ul { + description + "Grouping for UL specific parameters"; + + leaf max-supported-frequency-ul { + type uint64; + description + "This value indicates Maximum supported uplink frequency. Value unit is Hz."; + } + + leaf min-supported-frequency-ul { + type uint64; + description + "This value indicates Minimum supported uplink frequency. Value unit is Hz."; + } + + leaf max-supported-bandwidth-ul { + type uint64; + description + "This value indicates Maximum total uplink bandwidth in module. Value unit is Hz."; + } + + leaf max-num-carriers-ul { + type uint32; + description + "This value indicates Maximum number of uplink carriers in module."; + } + + leaf max-carrier-bandwidth-ul { + type uint64; + description + "This value indicates Maximum bandwidth per uplink carrier. Value unit is Hz."; + } + + leaf min-carrier-bandwidth-ul { + type uint64; + description + "This value indicates Minimum bandwidth per uplink carrier. Value unit is Hz."; + } + + leaf-list supported-technology-ul { + type enumeration{ + enum LTE { + description "LTE is supported in UL path."; + } + enum NR { + description "NR is supported in UL path."; + } + enum DSS_LTE_NR { + if-feature DSS_LTE_NR; + description + "DSS is supported in the UL, which implicitly means LTE and NR are also + BOTH supported in the UL."; + } + } + min-elements 1; + description + "This list provides information regarding technologies supported in UL path"; + } + } + + grouping band-capabilities { + description + "Capabilities that are needed to be defined per each band"; + + leaf band-number { + type uint16; + description + "Band number"; + } + + container sub-band-info { + when "../band-number = '46'"; + if-feature "o-ran-module-cap:LAA"; + description "container for collection of leafs for LAA subband 46"; + uses sub-band-info; + } + + uses support-for-dl; + uses support-for-ul; + + leaf max-num-component-carriers { + type uint8; + description "maximum number of component carriers supported by the O-RU"; + } + + leaf max-num-bands { + type uint16; + description "maximum number of bands supported by the O-RU"; + } + + leaf max-num-sectors { + type uint8; + description "maximum number of sectors supported by the O-RU"; + } + + leaf max-power-per-antenna { + type decimal64{ + fraction-digits 4; + } + description + "This value indicates Maximum Power per band per antenna. Value unit is dBm."; + } + + leaf min-power-per-antenna { + type decimal64{ + fraction-digits 4; + } + description + "This value indicates Minimum Power per band per antenna. Value unit is dBm."; + } + + leaf codebook-configuration_ng { + type uint8; + description + "This parameter informs the precoder codebook_ng that are used for precoding"; + } + + leaf codebook-configuration_n1 { + type uint8; + description + "This parameter informs the precoder codebook_n1 that are used for precoding"; + } + + leaf codebook-configuration_n2 { + type uint8; + description + "This parameter informs the precoder codebook_n2 that are used for precoding"; + } + } + + container module-capability { + + description + "module capability object responsible for providing module capability."; + + container ru-capabilities { + config false; + description + "Structure representing set of capabilities."; + + uses ru-capabilities; + } + + list band-capabilities { + key band-number; + config false; + description + "Capabilities that are needed to be defined per each band"; + + uses band-capabilities; + } + container rw-sub-band-info { + if-feature "o-ran-module-cap:LAA"; + description "config true leafrefs for use as constraints for config true leafs"; + leaf rw-number-of-laa-scarriers { + type leafref { + path "/module-capability/band-capabilities/sub-band-info/number-of-laa-scarriers"; + require-instance false; + } + description + "This value indicates the number of LAA secondary carriers supported at O-RU."; + } + leaf rw-self-configure { + type leafref { + path "/module-capability/band-capabilities/sub-band-info/self-configure"; + require-instance false; + } + description + "This value indicates that the O-RU can manage the contention window locally."; + } + } + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-processing-element.yang b/radio/fhi_72/mplane/yang/models/o-ran-processing-element.yang new file mode 100644 index 0000000000..fc930a0a81 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-processing-element.yang @@ -0,0 +1,362 @@ +module o-ran-processing-element { + yang-version 1.1; + namespace "urn:o-ran:processing-element:1.0"; + prefix "o-ran-elements"; + + import ietf-yang-types { + prefix yang; + } + + import ietf-inet-types { + prefix "inet"; + } + + import ietf-interfaces { + prefix "if"; + } + + import ietf-ip { + prefix "ip"; + } + + import o-ran-interfaces { + prefix "o-ran-int"; + } + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the YANG definitions for mapping of transport flows to + processing elements. Three options are supported: + i) virtual MAC based mapping + ii) MAC addrress + VLAN-ID based mapping + iii) UDP/IP based mapping + + Copyright 2020 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + revision "2020-04-17" { + description + "version 3.0.0 + + 1) added new enum SHARED-CELL-ETH-INTERFACE in + transport-session-type and new containers north-eth-flow and + south-eth-flow to enable Shared cell scenario."; + + reference "ORAN-WG4.M.0-v03.00"; + } + + revision "2019-07-03" { + description + "version 1.1.0 + + 1) added new leaf to enable O-RU to report the maximum number of + transport flows it can support, e.g., due to restrictions on number + of VLAN-IDs when ethernet type transport is used."; + + reference "ORAN-WG4.M.0-v01.00"; + } + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + feature SHARED_CELL { + description + "Presence of feature indicates that this O-RU is capable to support + shared cell."; + } +// groupings + + grouping pe-group { + leaf maximum-number-of-transport-flows { + type uint16 { + range "1..4094"; + } + config false; + default 4094; + description + "The maximum number of transport flows that can be supported by an O-RU"; + } + leaf transport-session-type { + type enumeration { + enum ETH-INTERFACE { + description "VLAN based CUS Transport "; + } + enum UDPIP-INTERFACE { + description "UDP/IP based CUS Transport "; + } + enum ALIASMAC-INTERFACE{ + description "Alias MAC address based CUS Transport "; + } + enum SHARED-CELL-ETH-INTERFACE { + if-feature "SHARED_CELL"; + description "VLAN based CUS Transport used for Shared Cell scenario"; + } + } + default ETH-INTERFACE; + description + "the type of transport session used for identifying different processing + elements"; + } + container enhanced-uplane-mapping { + presence "indicates that enhanced uplane mapping is used"; + description "a mapping table for enhanced user plane marking"; + list uplane-mapping { + key "up-marking-name"; + description + "a mapping between up-link name and o-ran-interfaces:up-marking-name"; + leaf up-marking-name { + type string; + description "a unique up marking name that is used for enhanced up marking"; + } + choice up-markings { + description + "U-Plane markings"; + case ethernet { + when "(../../transport-session-type = 'ALIASMAC-INTERFACE') or + (../../transport-session-type = 'ETH-INTERFACE') or + (../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE')"; + leaf up-cos-name { + type leafref { + path "/if:interfaces/if:interface/o-ran-int:class-of-service/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name"; + } + description "the Ethernet U-plane transport marking as defined in o-ran-interfaces"; + } + } + case ipv4 { + when "(../../transport-session-type = 'UDPIP-INTERFACE')"; + leaf upv4-dscp-name { + if-feature o-ran-int:UDPIP-BASED-CU-PLANE; + type leafref { + path "/if:interfaces/if:interface/ip:ipv4/o-ran-int:diffserv-markings/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name"; + } + description "the IPv4 U-plane transport marking as defined in o-ran-interfaces"; + } + } + case ipv6 { + when "(../../transport-session-type = 'UDPIP-INTERFACE')"; + leaf upv6-dscp-name { + if-feature o-ran-int:UDPIP-BASED-CU-PLANE; + type leafref { + path "/if:interfaces/if:interface/ip:ipv6/o-ran-int:diffserv-markings/o-ran-int:enhanced-uplane-markings/o-ran-int:up-marking-name"; + } + description "the IPv6 U-plane transport marking as defined in o-ran-interfaces"; + } + } + } + } + } + list ru-elements { + key "name"; + description + "the list of transport definitions for each processing element"; + leaf name { + type string { + length "1..255"; + } + description + "A name that is unique across the O-RU that identifies a processing + element instance. + + This name may be used in fault management to refer to a fault source + or affected object"; + } + container transport-flow { + description + "container for the transport-flow used for CU plane"; + leaf interface-name { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description "the interface name "; + } + container aliasmac-flow { + when "../../../transport-session-type = 'ALIASMAC-INTERFACE'"; + if-feature o-ran-int:ALIASMAC-BASED-CU-PLANE; + description "leafs for virtual mac type data flows"; + leaf ru-aliasmac-address { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:alias-macs"; + } + mandatory true; + description + "O-RU's alias MAC address used for alias MAC based flow"; + } + leaf vlan-id { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id"; + } + description + "O-RU's VLAN-ID used for alias MAC based flow"; + } + leaf o-du-mac-address { + type yang:mac-address; + mandatory true; + description + "O-DU's MAC address used for alias MAC based flow"; + } + } + container eth-flow { + when "../../../transport-session-type = 'ETH-INTERFACE'"; + description "leafs for mac + vlan-id type data flows"; + leaf ru-mac-address { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address"; + } + mandatory true; + description + "O-RU's MAC address used for Ethernet based flow"; + } + leaf vlan-id { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id"; + } + mandatory true; + description + "O-RU's VLAN-ID used for Ethernet based flow"; + } + leaf o-du-mac-address { + type yang:mac-address; + mandatory true; + description + "O-DU's MAC address used for Ethernet based flow"; + } + } + container udpip-flow { + when "../../../transport-session-type = 'UDPIP-INTERFACE'"; + description "leafs for UDP/IP type data flows"; + choice address { + leaf ru-ipv4-address { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/ip:ipv4/ip:address/ip:ip"; + } + description "O-RU's IPv4 address"; + } + leaf ru-ipv6-address { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/ip:ipv6/ip:address/ip:ip"; + } + description "O-RU's IPv6 address"; + } + mandatory true; + description "choice of O-RU IPv4 or IPv6 address"; + } + leaf o-du-ip-address { + type inet:ip-address; + mandatory true; + description "O-DU's IPv address"; + } + leaf ru-ephemeral-udp-port { + type inet:port-number; + mandatory true; + description + "ephemeral port used by O-RU"; + } + leaf o-du-ephemeral-udp-port { + type inet:port-number; + mandatory true; + description + "ephemeral port used by O-DU"; + } + leaf ecpri-destination-udp { + type inet:port-number; + mandatory true; + description "the well known UDP port number used by eCPRI"; + // fixme - add in a default when allocated by IANA + } + } + container north-eth-flow { + when "../../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE'"; + if-feature "SHARED_CELL"; + description "leafs for mac + vlan-id type data flows"; + leaf ru-mac-address { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address"; + } + description + "O-RU's MAC address used for Ethernet based flow"; + } + leaf vlan-id { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id"; + } + description + "O-RU's VLAN-ID used for Ethernet based flow"; + } + leaf north-node-mac-address { + type yang:mac-address; + description + "North-node's MAC address used for Ethernet based flow"; + } + } + container south-eth-flow { + when "../../../transport-session-type = 'SHARED-CELL-ETH-INTERFACE'"; + if-feature "SHARED_CELL"; + description "leafs for mac + vlan-id type data flows"; + leaf ru-mac-address { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:mac-address"; + } + description + "O-RU's MAC address used for Ethernet based flow"; + } + leaf vlan-id { + type leafref { + path "/if:interfaces/if:interface[if:name = current()/../../interface-name]/o-ran-int:vlan-id"; + } + description + "O-RU's VLAN-ID used for Ethernet based flow"; + } + leaf south-node-mac-address { + type yang:mac-address; + description + "south-node's MAC address used for Ethernet based flow"; + } + } + } + } + } + +// top level container + + container processing-elements { + description + "a model defining the mapping between transport flows and arbitrary + O-RAN processing elements. A processing element may be then defined for + handling connectivity or delay procedures, or defined with a corresponding + eaxcid for CU plane operations"; + uses pe-group; + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-uplane-conf.yang b/radio/fhi_72/mplane/yang/models/o-ran-uplane-conf.yang new file mode 100644 index 0000000000..16fbaf3335 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-uplane-conf.yang @@ -0,0 +1,2706 @@ +module o-ran-uplane-conf { + yang-version 1.1; + namespace "urn:o-ran:uplane-conf:1.0"; + prefix "o-ran-uplane-conf"; + + import o-ran-processing-element { + prefix "o-ran-pe"; + } + + import ietf-interfaces { + prefix "if"; + } + + import o-ran-module-cap { + prefix "mcap"; + revision-date 2020-08-10; + } + + import o-ran-compression-factors { + prefix "cf"; + revision-date 2020-08-10; + } + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the module capabilities for + the O-RAN Radio Unit U-Plane configuration. + + Copyright 2020 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + + revision "2020-08-10" { + description + "version 4.0.0 + + 1) parameters allowing for static PRACH configuration introduced + 2) parameters allowing for static SRS configuration introduced + 3) parameters allowing for configuration of TDD pattern introduced + 4) Backward compatible change to introduce new parameter 'coupling-method' related + to Section Description Priority to serve for CUS-Plane CR"; + + reference "ORAN-WG4.M.0-v04.00"; + } + + revision "2020-04-17" { + description + "version 3.0.0 + + 1) Adding optional little endian support + 2) Adding a new capability parameter to indicate that the O-RU + supports regularizationFactor in section type 5 + 3) Added support for Dynamic Spectrum Sharing feature + 4) Clarify the supported number of reMasks in RU side + 5) Section extension for grouping multiple ports + 6) adding PRACH formats to endpoint capabilities"; + + reference "ORAN-WG4.M.0-v03.00"; + } + + revision "2019-07-03" { + description + "version 1.1.0 + + 1) added new leaf multiple-numerology-supported to enable O-RU to report + whether it supports multiple numerologies. + + 2) fixing broken constraints (configuration cannot be dependent on + operational state). This is a backwards incompatible revision. + + As these constraints only apply when the LAA feature is used, and also + when considering the limited number of implementation that need to be + taken into consideration for backwards compatibility, it has been + agreed to NOT increment the namespace integer. + + 3) added frequency related capabilities for tx-arrays and rx-array + + 4) removed redundant LAA import"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + feature EAXC-GAIN-CORRECTION { + description + "Presence of feature indicates that O-RU supports eAxC specific gain correction."; + } + + feature TX-REFERENCE-LEVEL { + description + "Presence of feature indicates that O-RU supports TX gain reference level control"; + } + + typedef prach-preamble-format { + type enumeration { + enum LTE-0 { + description + "LTE PRACH Preamble format 0"; + } + enum LTE-1 { + description + "LTE PRACH Preamble format 1"; + } + enum LTE-2 { + description + "LTE PRACH Preamble format 2"; + } + enum LTE-3 { + description + "LTE PRACH Preamble format 3"; + } + enum LTE-4 { + description + "LTE PRACH Preamble format 4"; + } + enum LTE-NB0 { + description + "LTE Narrowband PRACH format 0"; + } + enum LTE-NB1 { + description + "LTE Narrowband PRACH format 1"; + } + enum NR-0 { + description + "5GNR PRACH Preamble format 0"; + } + enum NR-1 { + description + "5GNR PRACH Preamble format 1"; + } + enum NR-2 { + description + "5GNR PRACH Preamble format 2"; + } + enum NR-3 { + description + "5GNR PRACH Preamble format 3"; + } + enum NR-A1 { + description + "5GNR PRACH Preamble format A1"; + } + enum NR-A2 { + description + "5GNR PRACH Preamble format A2"; + } + enum NR-A3 { + description + "5GNR PRACH Preamble format A3"; + } + enum NR-B1 { + description + "5GNR PRACH Preamble format B1"; + } + enum NR-B2 { + description + "5GNR PRACH Preamble format B2"; + } + enum NR-B3 { + description + "5GNR PRACH Preamble format B3"; + } + enum NR-B4 { + description + "5GNR PRACH Preamble format B4"; + } + enum NR-C0 { + description + "5GNR PRACH Preamble format C0"; + } + enum NR-C2 { + description + "5GNR PRACH Preamble format C2"; + } + } + + description + "PRACH preamble format definition"; + } + + typedef polarisation_type { + type enumeration { + enum MINUS_45 { + description "MINUS_45"; + } + enum ZERO { + description "ZERO"; + } + enum PLUS_45 { + description "PLUS_45"; + } + enum PLUS_90 { + description "PLUS_90"; + } + } + description "Type definition for polarisations"; + } + + grouping general-config { + description "a group for general configuration"; + + container general-config { + description "a container for general configuration"; + + leaf regularization-factor-se-configured { + type boolean; + default false; + description + "Informs if regularizationfactor in section extension is configured(true) or not(false), this + leaf indicates whether the O-DU will send the regularizationfactor in section extension. + + If the O-RU does not support regularization-factor-se-supported in o-ran-module-cap.yang, + this leaf is ignored."; + } + + leaf little-endian-byte-order { + type boolean; + default false; + + description + "If little endian byte order for C/U plane data flows is supported by + the O-RU, indicates if the O-RU should use little endian byte order + for all UL and DL C/U plane data flows. + + If little endian byte order is NOT supported, this node is ignored + (and the default bigendian byte order used)"; + } + } + } + + grouping laa-carrier-config { + description "Carrier Configuration for support of LAA. "; + leaf ed-threshold-pdsch { + type int8; + units dBm; + description + "This value indicates Energy Detection(ED) threshold for LBT for PDSCH and for measurements in dBm."; + } + + leaf ed-threshold-drs { + type int8; + units dBm; + description + "This value indicates Energy Detection(ED) threshold for LBT for DRS in dBm."; + } + + leaf tx-antenna-ports { + type uint8; + description + "This value indicates Tx antenna ports for DRS (1, 2, 4)"; + } + + leaf transmission-power-for-drs { + type int8; + units decibels; + description + "This value indicates offset of Cell specific reference Signal(CRS) power to reference signal power (dB). + DRS signal consists of CRS, PSS, SSS, and optionally CSI-RS."; + } + + leaf dmtc-period { + type enumeration { + enum FORTY { + description + "40 ms"; + } + enum EIGHTY { + description + "80 ms"; + } + enum ONE-HUNDRED-SIXTY { + description + "160 ms"; + } + } + units milliseconds; + description + "This value indicates DRS measurement timing configuration (DMTC) period in ms"; + } + + leaf dmtc-offset { + type uint8; + units subframes; + description + "This value indicates dmtc offset in Subframes."; + } + + leaf lbt-timer { + type uint16; + units milliseconds; + description + "This value indicates LBT Timer in milliseconds."; + } + + list max-cw-usage-counter { + when "/mcap:module-capability/mcap:rw-sub-band-info/mcap:rw-self-configure = 'true'"; + key "priority"; + description ""; + leaf priority { + type enumeration { + enum P1 { + description "priority 1"; + } + enum P2 { + description "priority 2"; + } + enum P3 { + description "priority 3"; + } + enum P4 { + description "priority 4"; + } + } + description "This value provides the priority class traffic for which the counter is calculated."; + } + + leaf counter-value { + type uint8 { + range "1..8"; + } + description "This value indicates the maximum value of counter + which shows how many max congestion window value is used for backoff + number of priority class traffic. This value is defined at 3GPP 36.213 + section 15.1.3 as K."; + } + } + } + + grouping coupling-methods { + description + "Grouping for configuration of desired C-Plane / U-Plane coupling methods (if supported)"; + leaf coupling-to { + type leafref { + path "/mcap:module-capability/mcap:ru-capabilities/mcap:coupling-methods/mcap:coupling-via-frequency-and-time"; + require-instance false; + } + + description + "RW instance of RO parameter."; + } + leaf coupling-method { + when "../coupling-to = 'true'"; + type enumeration{ + enum NORMAL { + description "Coupling via sectionId value. This value can be used always."; + } + enum FREQUENCY_AND_TIME { + description "Coupling via frequency and time. Can be used when coupling-via-frequency-and-time = true + or coupling-via-frequency-and-time-with-priorities = true in o-ran-module-cap.yang"; + } + enum FREQUENCY_AND_TIME_WITH_PRIORITIES { + description "Coupling via frequency and time with priorities. Can be used when + coupling-via-frequency-and-time-with-priorities = true in o-ran-module-cap.yang"; + } + } + default NORMAL; + description + "Method of coupling between C-Plane and U-Plane messages; see methods of coupling + of C-Plane and U-Plane in CUS-Plane specification"; + } + } + + grouping eaxc { + description + "One eAxC identifier (eAxC ID) comprises a band and sector + identifier (BandSector_ID), a component-carrier identifier (CC_ID) and a + spatial stream identifier (RU_Port_ID). + + In this version of the specification, one eAxC contains only one spatial + stream (i.e. one beam per subcarrier) at a time. + + Bit allocation is subdivided as follows: + * O_DU_Port_ID: Used to differentiate processing units at O-DU + * BandSector_ID: Aggregated cell identifier + * CC_ID: distinguishes Carrier Components + * RU_Port_ID: Used to differentiate spatial streams or beams on the O-RU + + The bitwidth of each of the above fields is variable this model is supposed to check + if we are occpying bits continuously but we do not have to occupy all 16 bits"; + + + leaf o-du-port-bitmask { + type uint16; + mandatory true; + description + "mask for eaxc-id bits used to encode O-DU Port ID"; + } + + leaf band-sector-bitmask { + type uint16; + mandatory true; + description + "mask for eaxc-id bits used to encode the band sector ID"; + } + + leaf ccid-bitmask { + type uint16; + mandatory true; + description + "mask for eaxc-id bits used to encode the component carrier id"; + } + + leaf ru-port-bitmask { + type uint16; + mandatory true; + description + "mask for eaxc-id bits used to encode the O-RU Port ID"; + } + + leaf eaxc-id { + type uint16; + mandatory true; + description + "encoded value of eaxcid to be read by CU-Plane"; + } + } + + grouping parameters { + description + "Grouping of all parameters common between UL and DL"; + + leaf name { + type string; + mandatory true; + description "Unique name of array antenna"; + } + + leaf number-of-rows { + type uint16; + mandatory true; + description "Number of rows array elements are shaped into - M"; + } + + leaf number-of-columns { + type uint16; + mandatory true; + description "Number of columns array elements are shaped into - N"; + } + + leaf number-of-array-layers { + type uint8; + mandatory true; + description "Number of array layers array elements are shaped into - Q"; + } + + leaf horizontal-spacing { + type decimal64 { + fraction-digits 5; + } + units Meter; + + description "Average distance between centers of nearby AE in horizontal direction (in array coordinates system)"; + } + + leaf vertical-spacing{ + type decimal64 { + fraction-digits 5; + } + units Meter; + + description "Average distance between centers of nearby AE in vertical direction (in array coordinates system)"; + } + + container normal-vector-direction { + description + "Counter-clockwise rotation around z and y axis."; + + leaf azimuth-angle{ + type decimal64 { + fraction-digits 4; + } + units Degrees; + + description "Azimuth angle, counter-clockwise rotation around z-axis. Value 'zero' points to broad-side, value '90' points to y-axis"; + } + leaf zenith-angle{ + type decimal64 { + fraction-digits 4; + } + units Degrees; + + description "Zenith angle, counter-clockwise rotation around y-axis. Value 'zero' points to zenith, value '90' points to horizon"; + } + } + + container leftmost-bottom-array-element-position { + description "Structure describing position of leftmost, bottom array element."; + leaf x { + type decimal64 { + fraction-digits 4; + } + units Meter; + + description "X dimension of position of leftmost, bottom array element"; + } + + leaf y { + type decimal64 { + fraction-digits 4; + } + units Meter; + + description "Y dimension of position of leftmost, bottom array element"; + } + + leaf z { + type decimal64 { + fraction-digits 4; + } + units Meter; + + description "Z dimension of position of leftmost, bottom array element"; + } + } + list polarisations { + key "p"; + min-elements 1; + max-elements 2; + + description + "List of supported polarisations."; + + leaf p { + type uint8; + mandatory true; + description + "Polarisation index. See CUS-plane"; + } + + leaf polarisation { + type polarisation_type; + mandatory true; + description "Type of polarisation supported by array."; + } + } + leaf band-number { + type leafref { + path "/mcap:module-capability/mcap:band-capabilities/mcap:band-number"; + } + mandatory true; + description + "This parameter informing which frequency band particular antenna + array is serving for. + Intended use is to deal with multiband solutions."; + } + } + + grouping array-choice { + choice antenna-type { + case tx { + leaf tx-array-name { + type leafref { + path "/o-ran-uplane-conf:user-plane-configuration/o-ran-uplane-conf:tx-arrays/o-ran-uplane-conf:name"; + } + + description + "Leafref to tx array if such is choosen"; + } + } + case rx { + leaf rx-array-name { + type leafref { + path "/o-ran-uplane-conf:user-plane-configuration/o-ran-uplane-conf:rx-arrays/o-ran-uplane-conf:name"; + } + + description + "Leafref to rx array if such is choosen"; + } + } + description + "Choice for antenna type"; + } + description + "Elements which groups choice for antenna type"; + } + + grouping scs-config { + description + "It groups all parameters related to SCS configuration"; + + leaf frame-structure { + type uint8; + + description + "This parameter defines the frame structure. The first 4 bits define the FFT/iFFT size + being used for all IQ data processing related to this message. + The second 4 bits define the sub carrier spacing as well as the number of slots per 1ms sub-frame + according to 3GPP TS 38.211, taking for completeness also 3GPP TS 36.211 into account"; + } + + leaf cp-type { + type enumeration { + enum NORMAL { + description + "Normal cyclic prefix"; + } + + enum EXTENDED { + description + "Extended cyclic prefix"; + } + } + + description + "Provides type of CP (cyclic prefix) if section type 3 is not used or type of CP cannot be determined from cpLength."; + } + + leaf cp-length { + type uint16; + units Ts; + mandatory true; + description + "Used for symbol 0 for NR & LTE, and symbol 7*2u for NR. + See CUS-plane"; + } + + leaf cp-length-other { + type uint16; + units Ts; + mandatory true; + description + "Used for other symbols than by cp-length above"; + } + + leaf offset-to-absolute-frequency-center { + type int32; + mandatory true; + description + "This provides value of freqOffset to be used if section type 3 is not used. See freqOffset in CUS-plane."; + } + + list number-of-prb-per-scs { + key scs; + description + "List of configured for each SCS that will be used."; + + leaf scs { + type mcap:scs-config-type; + description + "Value corresponds to SCS values defined for frameStructure in C-plane. + Note: set of allowed values is restricted by SCS derived from values in supported-frame-structures."; + } + + leaf number-of-prb { + type uint16; + mandatory true; + description + "Determines max number of PRBs that will be used in all sections per one symbol. + This is affecting allocation of resources to endpoint. Value shall not exceed constrains + defined by max-prb-per-symbol of endpoint type. In addition sum (over all used epoints + within a group of endpoints sharing resources) of number-of-prb rounded up to + nearest value from prb-capacity-allocation-granularity shall not exceed max-prb-per-symbol of the group."; + } + } + } + + grouping tx-common-array-carrier-elements { + description + "This grouping containes all common parameters for tx-array-carriers and rx-array-carriers"; + + leaf absolute-frequency-center { + type uint32; + mandatory true; + description + "Absolute Radio Frequency Channel Number - indirectly indicates RF center carrier frequency of signal. + Reflected in arfcn."; + } + + leaf center-of-channel-bandwidth { + type uint64; + units Hz; + mandatory true; + description + "Center frequency of channel bandwidth in Hz. Common for all numerologies."; + } + + leaf channel-bandwidth { + type uint64; + units Hz; + mandatory true; + + description + "Width of carrier given in Hertz"; + } + + leaf active { + type enumeration { + enum INACTIVE { + description + "carrier does not provide signal - transmission is disabled"; + } + enum SLEEP{ + description + "carrier is fully configured and was active but is energy saving mode"; + } + enum ACTIVE{ + description + "carrier is fully configured and properly providing the signal"; + } + } + default INACTIVE; + + description + "Indicates if transmission is enabled for this array carriers. Note that Netconf server uses state parameter + to indicate actual state of array carriers operation. When array carriers is in sleep status, + Netconf server rejects all other operation request to tx-array-carriers object except either request to change from sleep + to active status or delete MO operation (see 4.8) to the object."; + } + + leaf state { + type enumeration { + enum DISABLED { + description + "array carrier is not active - transmission of signal is disabled."; + } + enum BUSY { + description + "array carrier is processing an operation requested by change of active parameter. + When array carriers is BUSY the transmission of signal is not guaranteed."; + } + enum READY { + description + "array carrier had completed activation operation - is active and transmission of signal is ongoing."; + } + } + config false; + mandatory true; + description + "Indicates state of array carriers activation operation"; + } + + leaf type { + type enumeration { + enum NR { + description + "5G technology"; + } + enum LTE { + description + "LTE technology"; + } + enum DSS_LTE_NR { + if-feature mcap:DSS_LTE_NR; + description + "NR and LTE technologies in Dynamic Spectrum Sharing mode"; + } + } + description + "Type of carrier. Indicates array-carrier technology."; + } + + leaf duplex-scheme { + type enumeration { + enum TDD { + description + "TDD scheme"; + } + enum FDD { + description + "FDD scheme"; + } + } + config false; + + description + "Type of duplex scheme O-RU supports."; + } + leaf rw-duplex-scheme { + type leafref { + path "/user-plane-configuration/tx-array-carriers[name=current()/../name]" + "/duplex-scheme"; + require-instance false; + } + description + "Config true type of duplex scheme."; + } + leaf rw-type { + type leafref { + path "/user-plane-configuration/tx-array-carriers[name=current()/../name]" + "/type"; + require-instance false; + } + description + "Config true type of carrier."; + } + } + + grouping rx-common-array-carrier-elements { + description + "This grouping containes all common parameters for tx-array-carriers and rx-array-carriers"; + + leaf absolute-frequency-center { + type uint32; + mandatory true; + description + "Absolute Radio Frequency Channel Number - indirectly indicates RF center carrier frequency of signal. + Reflected in arfcn."; + } + + leaf center-of-channel-bandwidth { + type uint64; + units Hz; + mandatory true; + description + "Center frequency of channel bandwidth in Hz. Common for all numerologies."; + } + + leaf channel-bandwidth { + type uint64; + units Hz; + mandatory true; + + description + "Width of carrier given in Hertz"; + } + + leaf active { + type enumeration { + enum INACTIVE { + description + "carrier does not provide signal - transmission is disabled"; + } + enum SLEEP{ + description + "carrier is fully configured and was active but is energy saving mode"; + } + enum ACTIVE{ + description + "carrier is fully configured and properly providing the signal"; + } + } + default INACTIVE; + + description + "Indicates if transmission is enabled for this array carriers. Note that Netconf server uses state parameter + to indicate actual state of array carriers operation. When array carriers is in sleep status, + Netconf server rejects all other operation request to tx-array-carriers object except either request to change from sleep + to active status or delete MO operation (see 4.8) to the object."; + } + + leaf state { + type enumeration { + enum DISABLED { + description + "array carrier is not active - transmission of signal is disabled."; + } + enum BUSY { + description + "array carrier is processing an operation requested by change of active parameter. + When array carriers is BUSY the transmission of signal is not guaranteed."; + } + enum READY { + description + "array carrier had completed activation operation - is active and transmission of signal is ongoing."; + } + } + config false; + mandatory true; + description + "Indicates state of array carriers activation operation"; + } + + leaf type { + type enumeration { + enum NR { + description + "5G technology"; + } + enum LTE { + description + "LTE technology"; + } + enum DSS_LTE_NR { + if-feature mcap:DSS_LTE_NR; + description + "NR and LTE technologies in Dynamic Spectrum Sharing mode"; + } + } + description + "Type of carrier. Indicates array-carrier technology."; + } + + leaf duplex-scheme { + type enumeration { + enum TDD { + description + "TDD scheme"; + } + enum FDD { + description + "FDD scheme"; + } + } + config false; + + description + "Type of duplex scheme O-RU supports."; + } + } + + grouping endpoint-section-capacity { + leaf max-control-sections-per-data-section { + type uint8 { + range "1..12"; + } + description + "Max number of C-plane sections (C-plane section is part of C-plane message that carries 'section fields') + referring to same U-plane section (U-plane section is part of U-plane message that carries + 'section header fields' and 'PRB fields') that is supported by endpoint. + Note that additional limitations specific for each section type apply on top of this number."; + } + leaf max-sections-per-symbol { + type uint16; + description + "Max number of sections within one symbol that can be processed by endpoint + or processed collectively by group of endpoints sharing capacity"; + } + leaf max-sections-per-slot { + type uint16; + description + "Max number of sections within one slot that can be processed by endpoint + or processed collectively by group of endpoints sharing capacity."; + } + + leaf max-remasks-per-section-id { + type uint8 { + range "1..12"; + } + default 12; + description + "maximum number of different reMask values that is applied to a PRB + within one section id. This value can be processed by endpoint + or processed collectively by group of endpoints sharing capacity"; + } + + description + "Parameters describing section capacity where section is undestood as number of different sectionId values"; + } + + grouping endpoint-beam-capacity { + leaf max-beams-per-symbol { + type uint16; + description + "Max number of beams within one symbol that can be processed by endpoint + or processed collectively by group of endpoints sharing capacity"; + } + leaf max-beams-per-slot { + type uint16; + description + "Max number of beams within one slot that can be processed by endpoint + or processed collectively by group of endpoints sharing capacity"; + } + + description + "Parameters describing beam capacity where number of beams is understood as number of different beamId values"; + } + + grouping endpoint-prb-capacity { + leaf max-prb-per-symbol { + type uint16; + description + "Max number of prbs within one symbol that can be processed by endpoint + or processed collectively by group of endpoints sharing capacity"; + } + + description + "Attributes presenting processing capacity related to PRB."; + } + + grouping endpoint-numerology-capacity { + leaf max-numerologies-per-symbol { + type uint16; + description + "Max number of numerologies within one symbol that can be processed by endpoint + or processed collectively by group of endpoints sharing capacity"; + } + + description + "Attributes presenting processing capacity related to numerology. + + This leaf contains valid data only when multiple-numerology-supported + is set to true."; + } + + grouping endpoint-static-config-support { + leaf static-config-supported { + type enumeration { + enum NONE { + description + "The endpoint does not support static PRACH / SRS configuration. + Reception of PRACH / SRS is possible through real time C-Plane messages + if other endpoint capabilities allow for that."; + } + enum PRACH { + if-feature mcap:PRACH-STATIC-CONFIGURATION-SUPPORTED; + description + "The endpoint supports statically configured PRACH reception"; + } + enum SRS { + if-feature mcap:SRS-STATIC-CONFIGURATION-SUPPORTED; + description + "The endpoint supports statically configured SRS reception"; + } + } + default NONE; + + description + "The parameter informs if endpoint can be statically configured to process PRACH or SRS reception"; + } + + leaf max-prach-patterns { + when "(/user-plane-configuration/static-low-level-rx-endpoints[name=current()/../name]/static-config-supported = 'PRACH')"; + type uint8; + description + "Maximum number of PRACH patterns the endpoint can handle in PRACH configuration"; + } + + leaf max-srs-patterns { + when "(/user-plane-configuration/static-low-level-rx-endpoints[name=current()/../name]/static-config-supported = 'SRS')"; + type uint8; + description + "Maximum number of SRS patterns the endpoint can handle in SRS configuration"; + } + + description + "Endpoint's capabilities related to static PRACH / SRS configuration."; + } + + grouping endpoint-tdd-pattern-support { + leaf configurable-tdd-pattern-supported { + type boolean; + default false; + + description + "The parameter informs if endpoint supports configuration for TDD pattern"; + } + + leaf tdd-group { + type uint8; + description + "Parameter is used to group static-low-level-[tr]x-endpoints. + Note: [tr]x-array-carriers using static-low-level-[tr]x-endpoints + having the same value of tdd-group, must have the same TDD switching + points and the same directions to the air interface granted - regardless TDD switching + is controlled by M-Plane or by C-Plane"; + } + + description + "This grouping exposes static-low-level-[tr]x-endpoint's capabilities related to its support for configurable + TDD patterns and limitations regarding common TDD switching per groups of endpoints."; + } + + grouping uplane-conf-group { + description + "Grouping for uplane configuration related parameters"; + + list low-level-tx-links { + key name; + description + "Object model for low-level-tx-link configuration"; + + leaf name { + type string; + description + "Unique name of low-level-tx-link object."; + } + + leaf processing-element { + type leafref { + path "/o-ran-pe:processing-elements/o-ran-pe:ru-elements/o-ran-pe:name"; + } + mandatory true; + description + "Contains name of processing-element to be used as transport by low-level-tx-link"; + } + + leaf tx-array-carrier { + type leafref { + path "/user-plane-configuration/tx-array-carriers/name"; + } + mandatory true; + description + "Contains name of tx-array-carriers MO to be used as transport by low-level-tx-link"; + } + + leaf low-level-tx-endpoint { + type leafref { + path "/user-plane-configuration/low-level-tx-endpoints/name"; + } + mandatory true; + description + "Contains name of low-level-tx-endpoints MO to be used as transport by low-level-tx-link"; + } + } + + list low-level-rx-links { + key name; + description + "Object model for low-level-rx-links configuration"; + + leaf name { + type string; + + description + "Unique name of low-level-rx-links object."; + } + + leaf processing-element { + type leafref { + path "/o-ran-pe:processing-elements/o-ran-pe:ru-elements/o-ran-pe:name"; + } + mandatory true; + description + "Contains name of processing-element to be used as transport by LowLevelTxLink"; + } + + leaf rx-array-carrier { + type leafref { + path "/user-plane-configuration/rx-array-carriers/name"; + } + mandatory true; + + description + "Contains name of rx-array-carriers MO to be used as transport by low-level-rx-links"; + } + + leaf low-level-rx-endpoint { + type leafref { + path "/user-plane-configuration/low-level-rx-endpoints/name"; + } + mandatory true; + + description + "Contains name of low-level-rx-endpoints MO to be used as transport by low-level-rx-links"; + } + + leaf user-plane-uplink-marking { + type leafref { + path "/o-ran-pe:processing-elements/o-ran-pe:enhanced-uplane-mapping/o-ran-pe:uplane-mapping/o-ran-pe:up-marking-name"; + } + description + "Parameter to set the non-default marking for user-plane"; + } + } + + list endpoint-types { + key "id"; + config false; + description + "Properties of endpoint that are common to multiple endpoints if such are identified"; + + leaf id { + type uint16; + description + "Identifies type of endpoints sharing same properties. Values shall start with 0 and shall be allocated without gaps."; + } + + list supported-section-types { + key "section-type"; + description + "Indicates section types and extensions endpoints of this type support"; + + leaf section-type { + type uint8; + + description + "This parameter determines the characteristics of U-plane data to be transferred or received from a beam with one pattern id."; + } + + leaf-list supported-section-extensions { + type uint8; + + description + "This parameter provides the extension types supported by the O-RU + which provides additional parameters specific to the subject data extension"; + } + } + + leaf-list supported-frame-structures { + type uint8; + + description + "List of supported values of frame structure"; + } + + leaf managed-delay-support { + type enumeration { + enum MANAGED { + description + "Time managed delays are supported"; + } + + enum NON_MANAGED { + description + "Non time managed delays are supported"; + } + + enum BOTH { + description + "Both time managed and non time managed delays are supported"; + } + } + + description + "Type of delay supported by the endpoint"; + } + + leaf multiple-numerology-supported { + type boolean; + default true; + description + "Indicates whether the endpoint type supports multiple numerologies"; + } + + leaf max-numerology-change-duration { + type uint16 { + range "0..10000"; + } + + units Ts; + description + "Maximum gap of endpoint operation that will be caused by changing of + numerology. + + This time is required for reconfiguration and flushing of pipes. + + This leaf contains valid data only when multiple-numerology-supported + is set to true."; + } + + uses endpoint-section-capacity; + uses endpoint-beam-capacity; + uses endpoint-prb-capacity; + + leaf-list prb-capacity-allocation-granularity { + type uint16; + + description + "List of capacity allocation steps. O-RU allocates PRB capacity rounding it up to nearest value N + from prb-capacity-allocation-granularity such that M >= number-of-prb-per-scs. + See also number-of-prb-per-scs/number-of-prb."; + } + + uses endpoint-numerology-capacity; + } + + list endpoint-capacity-sharing-groups { + key "id"; + config false; + description + "Represents groups of endpoints that share capacity. Depending on O-RU implementation, + processing resources that handle CU-plane (e.g. memory to keep sections and beams) + could be allocated per endpoint or shared between several endpoints. + To address this O-RU shall reports own capability per endpoint (see endpoint-types) + and per group of endpoints sharing capacity. + If endpoint is in multiple groups then resulting constraint is minimum over all groups. + Note: values of parameters representing capacity that is not shared between endpoints in a group + shall be set to max value of specific parameter; this effectively removes related constraint."; + + leaf id { + type uint16; + description + "Identifies group of endpoints sharing resources. + Values shall start with 0 and shall be allocated without gaps."; + } + uses endpoint-section-capacity; + uses endpoint-beam-capacity; + uses endpoint-prb-capacity; + uses endpoint-numerology-capacity; + + leaf max-endpoints { + type uint16; + description + "Indicates how many endpoints in the group can be used4 simultaneously"; + } + leaf max-managed-delay-endpoints { + type uint16; + description + "Number of endpoints supporting managed delay that can be used (configured for use) at a time"; + } + leaf max-non-managed-delay-endpoints { + type uint16; + description + "Number of endpoints supporting non-managed delay that can be used (configured for use) at a time"; + } + } + + list endpoint-prach-group { + key "id"; + config false; + description + "Represents group of a series of PRACH preamble formats"; + + leaf id { + type uint16; + description + "Identifies group of PRACH preamble formats."; + } + + leaf-list supported-prach-preamble-formats { + type prach-preamble-format; + min-elements 1; + description + "the list of PRACH preamble formats supported by the endpoint-type that is + applicable to static-low-level-rx-endpoints in the O-RU"; + } + + } + + list supported-compression-method-sets { + key "id"; + config false; + description + "List of available compression methods supported by device"; + + leaf id { + type uint16; + description + "Identification number for compression method set"; + } + + list compression-method-supported { + uses cf:compression-parameters; + + leaf-list fs-offset { + if-feature cf:CONFIGURABLE-FS-OFFSET; + type uint8; + default 0; + description + "Adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format. + Please refer to CU-Plane specification for details"; + + } + description + "List of supported compression methods by O-RU + Note: if O-RU supports different compression methods per endpoint + then please refer to endpoints to have information what + exactly is supported on paticular endpoint"; + } + } + + list static-low-level-tx-endpoints { + key name; + config false; + description + "Object model for static-low-level-tx-endpoints configuration"; + + leaf name { + type string; + + description + "Unique name of static-low-level-tx-endpoints object."; + } + + leaf-list restricted-interfaces { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description + "Optionally used to indicate that a low-level link is constrained to operate only via a subset of the available interfaces."; + } + + leaf array { + type leafref { + path "/user-plane-configuration/tx-arrays/name"; + } + mandatory true; + description + "Contains distname of tx-arrays, particular low-level-tx-endpoints is in hardware dependency with. + Note: single instance of tx-arrays can be referenced by many instances of low-level-tx-endpoints + (e.g. to allow DU to handle multiple fronthauls and multiple component carriers)."; + } + + leaf endpoint-type { + type leafref { + path "../../endpoint-types/id"; + } + + description + "Reference to endpoint type capabilities list element supported by this endpoint"; + } + + leaf-list capacity-sharing-groups { + type leafref { + path "../../endpoint-capacity-sharing-groups/id"; + } + + description + "Reference to capacities of sharing-groups supported by this endpoint"; + } + + list supported-reference-level { + if-feature TX-REFERENCE-LEVEL; + key "id"; + description + "Informs about supported ranges for gain reference level."; + + leaf id { + type uint16; + description + "Identification number for particular range"; + } + + leaf min { + type decimal64 { + fraction-digits 4; + } + units dB; + mandatory true; + description + "Minimum of supported gain reference level"; + } + + leaf max { + type decimal64 { + fraction-digits 4; + } + units dB; + mandatory true; + description + "Maximum of supported gain reference level"; + } + } + + container compression { + description + "Container collecting compression related parameters."; + + leaf dynamic-compression-supported { + type boolean; + + description + "Informs if endpoint supports dynamic compression method"; + } + + leaf realtime-variable-bit-width-supported { + type boolean; + + description + "Informs if endpoint supports realtime variable bit with"; + } + + leaf supported-compression-set-id { + type leafref { + path "../../../supported-compression-method-sets/id"; + } + + description + "Id of supported compression set for this endpoint"; + } + } + + uses endpoint-tdd-pattern-support; + + } + + list static-low-level-rx-endpoints { + key name; + config false; + description + "Object model for static-low-level-rx-endpoints configuration"; + + leaf name { + type string; + + description + "Unique name of static-low-level-rx-endpoints object."; + } + + leaf-list restricted-interfaces { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description + "Optionally used to indicate that a low-level link is constrained to operate only via a subset of the available interfaces."; + } + + leaf array { + type leafref { + path "/user-plane-configuration/rx-arrays/name"; + } + mandatory true; + description + "Contains distname of rx-arrays, particular low-level-rx-endpoints is in hardware dependency with. + Note: single instance of rx-arrays can be referenced by many instances of low-level-rx-endpoints + (e.g. to allow DU to handle multiple fronthauls and multiple component carriers)."; + } + + leaf endpoint-type { + type leafref { + path "../../endpoint-types/id"; + } + + description + "Reference to endpoint type capabilities list element supported by this endpoint"; + } + + leaf-list capacity-sharing-groups { + type leafref { + path "../../endpoint-capacity-sharing-groups/id"; + } + + description + "Reference to capacities of sharing-groups supported by this endpoint"; + } + + leaf prach-group { + type leafref { + path "../../endpoint-prach-group/id"; + require-instance false; + } + description + "An optional leaf used for those rx endpoints that support PRACH, indicating + the group id describing the set of of PRACH preambles supported"; + } + + container compression { + description + "Container collecting compression related parameters."; + + leaf dynamic-compression-supported { + type boolean; + + description + "Informs if endpoint supports dynamic compression method"; + } + + leaf realtime-variable-bit-width-supported { + type boolean; + + description + "Informs if endpoint supports realtime variable bit with"; + } + + leaf supported-compression-set-id { + type leafref { + path "../../../supported-compression-method-sets/id"; + } + + description + "Id of supported compression set for this endpoint"; + } + } + + uses endpoint-static-config-support; + + uses endpoint-tdd-pattern-support; + + } + + list low-level-tx-endpoints { + key "name"; + + description + "Object model for low-level-tx-endpoints configuration - augmented static-low-level-tx-endpoints by local-address + which cannot be added to static low-level-tx-endpoints as we cannot have modificable element in static object"; + + leaf name { + type leafref { + path "/user-plane-configuration/static-low-level-tx-endpoints/name"; + require-instance false; + } + mandatory true; + + description + "Unique name of low-level-tx-endpoint object. Reference to static object"; + } + + container compression { + presence + "This container shall exists to avoid missaligned compression + methods between devices"; + + description + "Container which consists of global configurable parameters for compression"; + + uses cf:compression-details; + + leaf fs-offset { + if-feature cf:CONFIGURABLE-FS-OFFSET; + type uint8; + default 0; + description + "Adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format. + Please refer to CU-Plane specification for details"; + } + + list dynamic-compression-configuration { + when "../compression-type = 'DYNAMIC'"; + key "id"; + unique "compression-method iq-bitwidth fs-offset"; + description + "List of possible configuration in case dynamic configuration is used + Note: In case of empty list all available compressions can be choosen dynamically + and default fs-offset is taken (0)."; + + leaf id { + type uint16; + description + "Identification number for particular compression"; + } + + uses cf:compression-method-grouping; + + leaf fs-offset { + if-feature cf:CONFIGURABLE-FS-OFFSET; + type uint8; + default 0; + description + "Adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format. + Please refer to CU-Plane specification for details"; + } + } + } + + uses scs-config; + + container e-axcid { + uses eaxc; + + description + "Contains local address of low level TX endpoint offered by Netconf server."; + } + + uses coupling-methods; + + leaf configurable-tdd-pattern-supported { + type leafref { + path "/user-plane-configuration/static-low-level-rx-endpoints[name=current()/../name]/configurable-tdd-pattern-supported"; + require-instance false; + } + description "RO to RW parameter mapping - needed for conditional under tx-array-carrier"; + } + } + + list low-level-rx-endpoints { + key name; + + description + "Object model for low-level-rx-endpoint configuration - augmented static-low-level-rx-endpoints by local-address + which cannot be added to static low-level-rx-endpoints as we cannot have modificable element in static object"; + + leaf name { + type leafref { + path "/user-plane-configuration/static-low-level-rx-endpoints/name"; + require-instance false; + } + mandatory true; + + description + "Unique name of low-level-rx-endpoint object. Reference to static object"; + } + + container compression { + description + "Container which consists of global configurable parameters for compression"; + + uses cf:compression-details; + + leaf fs-offset { + if-feature cf:CONFIGURABLE-FS-OFFSET; + type uint8; + default 0; + description + "Adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format. + Please refer to CU-Plane specification for details"; + } + + list dynamic-compression-configuration { + when "../compression-type = 'DYNAMIC'"; + key "id"; + unique "compression-method iq-bitwidth fs-offset"; + description + "List of possible configuration in case dynamic configuration is used + Note: In case of empty list all available compressions can be choosen dynamically + and default fs-offset is taken (0)."; + + leaf id { + type uint16; + description + "Identification number for particular compression"; + } + + uses cf:compression-method-grouping; + + leaf fs-offset { + if-feature cf:CONFIGURABLE-FS-OFFSET; + type uint8; + default 0; + description + "Adjusts FS (full scale) value of IQ format relative to FS derived from unmodified IQ format. + Please refer to CU-Plane specification for details"; + } + } + } + + uses scs-config; + + list ul-fft-sampling-offsets { + key scs; + description + "List of FFT sampling offsets configured for each SCS that will be used. + Client shall configure one element for each SCS that will be used."; + + leaf scs { + type mcap:scs-config-type; + description + "Value corresponds to SCS values defined for frameStructure in C-plane + Note: set of allowed values is restricted by SCS derived from values in supported-frame-structures."; + } + + leaf ul-fft-sampling-offset { + type uint16; + + units Ts; + description + "Determines time advance of capture window for FFT. + Value represents time advance of capture window start in relation to the end of CP. Unit is Ts. + Note: value of this parameter is usually set to '0' (zero) for PRACH channels. + Any phase offset resulting from the non-zero value of this parameter is handled in O-DU."; + } + } + + container e-axcid { + uses eaxc; + + description + "Contains local address of low level RX endpoint offered by Netconf server."; + } + + leaf eaxc-gain-correction { + if-feature EAXC-GAIN-CORRECTION; + type decimal64 { + fraction-digits 4; + } + units dB; + default 0; + description + "eAxC specifc part of overall gain_correction. + gain_correction = common array-carrier gain-correction + eAxC-gain-correction."; + } + + leaf non-time-managed-delay-enabled { + type boolean; + default false; + description + "Tells if non time managed delay shall be enabled"; + } + + uses coupling-methods; + + leaf static-config-supported { + type leafref { + path "/user-plane-configuration/static-low-level-rx-endpoints[name=current()/../name]/static-config-supported"; + require-instance false; + } + description "RO to RW parameter mapping - for further conditionals"; + } + + leaf static-prach-configuration { + when "(/user-plane-configuration/low-level-rx-endpoints[name=current()/../name]/static-config-supported = 'PRACH')"; + if-feature mcap:PRACH-STATIC-CONFIGURATION-SUPPORTED; + type leafref { + path "/user-plane-configuration/static-prach-configurations/static-prach-config-id"; + } + description + "This parameter creates reference to static PRACH configuration applicable for particular endpoint"; + } + + leaf static-srs-configuration { + when "(/user-plane-configuration/low-level-rx-endpoints[name=current()/../name]/static-config-supported = 'SRS')"; + if-feature mcap:SRS-STATIC-CONFIGURATION-SUPPORTED; + type leafref { + path "/user-plane-configuration/static-srs-configurations/static-srs-config-id"; + } + description + "This parameter creates reference to static SRS configuration applicable for particular endpoint"; + } + + leaf configurable-tdd-pattern-supported { + if-feature mcap:CONFIGURABLE-TDD-PATTERN-SUPPORTED; + type leafref { + path "/user-plane-configuration/static-low-level-rx-endpoints[name=current()/../name]/configurable-tdd-pattern-supported"; + require-instance false; + } + description "RO to RW parameter mapping - needed for conditional under rx-array-carrier"; + } + } + + list tx-array-carriers { + key name; + description + "Object model for tx-array-carriers configuration"; + + leaf name { + type string; + + description + "Unique name of tx-array-carriers object."; + } + + uses tx-common-array-carrier-elements; + + leaf band-number { + if-feature mcap:LAA; + type leafref { + path "/mcap:module-capability/mcap:band-capabilities/mcap:band-number"; + require-instance false; + } + description + "This parameter informing which frequency band particular antenna + array is serving for. + Intended use is to deal with multiband solutions."; + } + + container lte-tdd-frame { + when "(/user-plane-configuration/tx-array-carriers/rw-type = 'LTE') and (/user-plane-configuration/tx-array-carriers/rw-duplex-scheme = 'TDD')"; + status deprecated; + description + "Container which consists of global configurable parameters for tdd Frame. + This contained is deprecated due to introduction of TDD pattern configuration + applicable in a common way for LTE and NR."; + + leaf subframe-assignment { + type enumeration { + enum SAO { + description "subframe assignment configuration 0"; + } + enum SA1 { + description "subframe assignment configuration 1"; + } + enum SA2 { + description "subframe assignment configuration 2"; + } + enum SA3 { + description "subframe assignment configuration 3"; + } + enum SA4 { + description "subframe assignment configuration 4"; + } + enum SA5 { + description "subframe assignment configuration 5"; + } + enum SA6 { + description "subframe assignment configuration 6"; + } + } + mandatory true; + description + "Indicates DL/UL subframe configuration as specified in + 3GPP TS 36.211 [v15.3.0, table 4.2-2]"; + } + leaf special-subframe-pattern { + type enumeration { + enum SPP0 { + description "special subframe pattern configuration 0"; + } + enum SPP1 { + description "special subframe pattern configuration 1"; + } + enum SPP2 { + description "special subframe pattern configuration 2"; + } + enum SPP3 { + description "special subframe pattern configuration 3"; + } + enum SPP4 { + description "special subframe pattern configuration 4"; + } + enum SPP5 { + description "special subframe pattern configuration 5"; + } + enum SPP6 { + description "special subframe pattern configuration 6"; + } + enum SPP7 { + description "special subframe pattern configuration 7"; + } + enum SPP8 { + description "special subframe pattern configuration 8"; + } + enum SPP9 { + description "special subframe pattern configuration 9"; + } + enum SPP10 { + description "special subframe pattern configuration 10"; + } + } + mandatory true; + description + "Indicates TDD special subframe configuration as in TS 36.211 + [v15.3.0, table 4.2-1] "; + } + } + + container laa-carrier-configuration { + when "../band-number = 46"; + if-feature mcap:LAA; + description "Container to specify LAA feature related carrier configuration."; + uses laa-carrier-config; + } + + leaf gain { + type decimal64 { + fraction-digits 4; + } + units dB; + mandatory true; + + description + "Transmission gain in dB. Value applicable to each array element carrier belonging to array carrier."; + } + + leaf downlink-radio-frame-offset { + type uint32 { + range 0..12288000; + } + mandatory true; + + description + "This parameter is used for offsetting the starting position of 10ms radio frame. + Note: The value should have same value within DU to all tx-array-carrierss that have same frequency and bandwidth. + Note2: Unit is 1/1.2288e9 Hz and accuracy is 1/4 Tc. Then, its range is calculated 0..12288000."; + } + + leaf downlink-sfn-offset { + type int16 { + range -32768..32767; + } + mandatory true; + + description + "This parameter is used for offsetting SFN value. + Unit is in 10ms. + Note: The value should have same value within DU to all tx-array-carrierss that have same frequency and bandwidth."; + } + + leaf reference-level { + if-feature TX-REFERENCE-LEVEL; + type decimal64 { + fraction-digits 4; + } + units dB; + default 0; + description + "Allows to adjust reference level for sum of IQ signal power over eAxCs in this array-carrier."; + } + + leaf configurable-tdd-pattern { + when "not(/user-plane-configuration/low-level-tx-endpoints[name = string(/user-plane-configuration/low-level-tx-links[tx-array-carrier = current()/../name]/tx-array-carrier)]/configurable-tdd-pattern-supported = 'false')"; + if-feature mcap:CONFIGURABLE-TDD-PATTERN-SUPPORTED; + type leafref { + path "/user-plane-configuration/configurable-tdd-patterns/tdd-pattern-id"; + } + description + "This parameter creates reference to configuration for TDD pattern applicable for particular tx-array-carrier. + The leaf may exist under tx-array-carrier only in case O-RU supports feature 'CONFIGURABLE-TDD-PATTERN-SUPPORTED' + AND all low-level-tx-endpoints linked to this tx-array-carrier have configurable-tdd-pattern-supported = 'true'"; + } + } + + list rx-array-carriers { + key name; + description + "Object model for rx-array-carriers configuration"; + + leaf name { + type string; + description + "Unique name of rx-array-carriers object."; + } + + uses rx-common-array-carrier-elements; + + leaf downlink-radio-frame-offset { + type uint32 { + range 0..12288000; + } + mandatory true; + + description + "This parameter is used for offsetting the starting position of 10ms radio frame. + Note: The value should have same value within DU to all tx-array-carrierss that have same frequency and bandwidth. + Note2: Unit is 1/1.2288e9 Hz and accuracy is 1/4 Tc. Then, its range is calculated 0..12288000."; + } + + leaf downlink-sfn-offset { + type int16 { + range -32768..32767; + } + mandatory true; + + description + "This parameter is used for offsetting SFN value. + Unit is in 10ms. + Note: The value should have same value within DU to all tx-array-carrierss that have same frequency and bandwidth."; + } + + leaf gain-correction { + type decimal64 { + fraction-digits 4; + + } + units dB; + mandatory true; + description + "Gain correction of RF path linked with array element or array layers. + Common part of overall gain_correction. + gain_correction = common array-carrier gain-correction + eAxC gain correction."; + } + + leaf n-ta-offset { + type uint32; + units Tc; + mandatory true; + description + "Value of configurable N-TA offset + units are Tc=~0.5ns=1/1.96608GHz"; + } + + leaf configurable-tdd-pattern { + when "not(/user-plane-configuration/low-level-rx-endpoints[name = string(/user-plane-configuration/low-level-rx-links[rx-array-carrier = current()/../name]/rx-array-carrier)]/configurable-tdd-pattern-supported = 'false')"; + if-feature mcap:CONFIGURABLE-TDD-PATTERN-SUPPORTED; + type leafref { + path "/user-plane-configuration/configurable-tdd-patterns/tdd-pattern-id"; + } + description + "This parameter creates reference to configuration for TDD pattern applicable for particular rx-array-carrier. + The leaf may exist under rx-array-carrier only in case O-RU supports feature 'CONFIGURABLE-TDD-PATTERN-SUPPORTED' + AND all low-level-rx-endpoints linked to this rx-array-carrier have configurable-tdd-pattern-supported = 'true'"; + } + } + + list tx-arrays { + key "name"; + config false; + description + "Structure describing TX array parameters"; + + uses parameters; + + leaf max-gain { + type decimal64 { + fraction-digits 4; + + } + units dB; + mandatory true; + description + "Max gain of RF path linked with array element (minimum over elements of array) or array layers"; + } + + leaf independent-power-budget { + type boolean; + mandatory true; + description + "If true then every element of array has own, power budget independent from power budget of other elements. + Else all elements of array that are at same row and column and have same polarization share power budget"; + } + + list capabilities { + description + "List of capabilities related to this tx-array"; + uses mcap:support-for-dl; + } + } + + list rx-arrays { + key "name"; + config false; + description "Structure describing RX array parameters"; + + uses parameters; + container gain-correction-range { + leaf max { + type decimal64 { + fraction-digits 4; + } + units dB; + mandatory true; + description "Array gain correction factor - maximum allowed value"; + } + leaf min { + type decimal64 { + fraction-digits 4; + } + units dB; + mandatory true; + description "Array gain correction factor - minimum allowed value"; + } + + description + "Array gain correction factor"; + } + + list capabilities { + description + "List of capabilities related to this rx-array"; + uses mcap:support-for-ul; + } + } + + list relations { + key "entity"; + config false; + description "Structure describing relations between array elements"; + + leaf entity { + type uint16; + + description + "Relation entity. Used as a key for list of relations."; + } + + container array1 { + uses array-choice; + + description + "Defnes name for first array"; + } + container array2 { + uses array-choice; + + description + "Defnes name for second array"; + } + list types { + key "relation-type"; + description + "Defines relation type and pairs for array elements for given arrays"; + + leaf relation-type { + type enumeration { + enum SHARED { + description "SHARED"; + } + enum COALOCATED { + description "COALOCATED"; + } + } + description "Type of relation between array elements"; + } + list pairs { + key "element-array1"; + description + "defines related array elements"; + + leaf element-array1 { + type uint16; + + description + "Tells about id of element from array1"; + } + leaf element-array2 { + type uint16; + + description + "Tells about id of element from array2"; + } + } + } + } + + container eaxc-id-group-configuration { + if-feature mcap:EAXC-ID-GROUP-SUPPORTED; + description + "This is the container for eAxC ID group configuration."; + leaf max-num-tx-eaxc-id-groups { + type leafref { + path "/mcap:module-capability/mcap:ru-capabilities/mcap:eaxcid-grouping-capabilities/mcap:max-num-tx-eaxc-id-groups"; + require-instance false; + } + description "eaxc-id-group-configuration"; + } + leaf max-num-tx-eaxc-ids-per-group { + type leafref { + path "/mcap:module-capability/mcap:ru-capabilities/mcap:eaxcid-grouping-capabilities/mcap:max-num-tx-eaxc-ids-per-group"; + require-instance false; + } + description "max-num-tx-eaxc-ids-per-group"; + } + leaf max-num-rx-eaxc-id-groups { + type leafref { + path "/mcap:module-capability/mcap:ru-capabilities/mcap:eaxcid-grouping-capabilities/mcap:max-num-rx-eaxc-id-groups"; + require-instance false; + } + description "max-num-rx-eaxc-id-groups"; + } + leaf max-num-rx-eaxc-ids-per-group { + type leafref { + path "/mcap:module-capability/mcap:ru-capabilities/mcap:eaxcid-grouping-capabilities/mcap:max-num-rx-eaxc-ids-per-group"; + require-instance false; + } + description "max-num-rx-eaxc-ids-per-group"; + } + + list tx-eaxc-id-group { + must "count(../tx-eaxc-id-group) <= ../max-num-tx-eaxc-id-groups" { + error-message "too many tx-eaxcid-id groups"; + } + key "representative-tx-eaxc-id"; + description + "This is a list of the groups of the eAxC IDs assigned to low-level-tx-endpoints. + Each group is a union of the 'member-tx-eaxc-id's and a 'representative-tx-eaxc-id'. + The low-level-tx-endpoint associated to 'representative-tx-eaxc-id' is able to + process the DL C-plane information for all the low-level-tx-endpoints associated + to 'member-tx-eaxc-id's. + + Take Note: This list should only contain eAxC IDs assigned to a tx-endpoint."; + + + leaf representative-tx-eaxc-id { + type uint16; + description + "This parameter contains eAxC_ID that populates content of C-Plane section + extension 11 to eAxC_IDs configured in the group as 'member-tx-eaxc-id'(s)."; + } + leaf-list member-tx-eaxc-id { + type uint16; + must "count(../member-tx-eaxc-id) <= ../../max-num-tx-eaxc-ids-per-group" { + error-message "too many tx-eaxcid-id members"; + } + must "current()!=../representative-tx-eaxc-id" { + error-message "the representative eaxcid does not need to be a list member"; + } + description + "This is a list of member eAxC IDs, which together with the representative-tx-eaxc-id, + are assigned to low-level-tx-endpoints in the group."; + } + } + + list rx-eaxc-id-group { + must "count(../rx-eaxc-id-group) <= ../max-num-rx-eaxc-id-groups" { + error-message "too many rx-eaxcid-id groups"; + } + key "representative-rx-eaxc-id"; + description + "This is a list of the groups of the eAxC IDs assigned to low-level-rx-endpoints. + Each group is a union of 'member-rx-eaxc-id's and a 'representative-rx-eaxc-id'. + The low-level-rx-endpoint associated to 'representative-rx-eaxc-id' is able to + process the UL C-plane information for all the low-level-rx-endpoints associated + to 'member-rx-eaxc-id's. + + Take Note: This list should only contain eAxC IDs assigned to a rx-endpoint."; + + leaf representative-rx-eaxc-id { + type uint16; + description + "This parameter contains eAxC_ID that populates content of C-Plane section + extension 11 to eAxC_IDs configured in the group as 'member-rx-eaxc-id'(s)."; + } + + leaf-list member-rx-eaxc-id { + type uint16; + must "count(../member-rx-eaxc-id) <= ../../max-num-rx-eaxc-ids-per-group" { + error-message "too many rx-eaxcid-id members"; + } + must "current()!=../representative-rx-eaxc-id" { + error-message "the representative eaxcid does not need to be a list member"; + } + description + "This is a list of member eAxC IDs assigned to low-level-rx-endpoints in the group."; + } + } + } + + list static-prach-configurations { + if-feature mcap:PRACH-STATIC-CONFIGURATION-SUPPORTED; + key static-prach-config-id; + description + "List of static PRACH configurations. An O-RU shall reject any configuration + modification which exceed the maximum permitted configurations supported by + the O-RU"; + + leaf static-prach-config-id { + type uint8; + description + "Supplementary parameter acting as key in list of static PRACH configurations."; + } + + uses static-prach-configuration; + } + + grouping static-prach-configuration { + description + "Set of parameters related to static PRACH configuration"; + + leaf pattern-period { + type uint16 { + range 1..1024; + } + mandatory true; + description + "Period after which static PRACH patterns are repeated. Unit: number of frames."; + } + + leaf guard-tone-low-re { + type uint32; + mandatory true; + description + "Number of REs occupied by the low guard tones."; + } + + leaf num-prach-re { + type uint32; + mandatory true; + description + "Number of contiguous PRBs per data section description"; + } + + leaf guard-tone-high-re { + type uint32; + mandatory true; + description + "Number of REs occupied by the high guard tones."; + } + + leaf sequence-duration { + type uint32 { + range 256..24576; + } + units Ts; + mandatory true; + description + "Duration of single sequence of the PRACH. Sequence may be considered as 'single PRACH symbol'"; + } + + list prach-patterns { + key prach-pattern-id; + min-elements 1; + description + "Provides a PRACH pattern. Each record in the list represents a single PRACH occasion. Number of list entries cannot exceed max-prach-patterns"; + + leaf prach-pattern-id { + type uint16; + mandatory true; + description + "Supplementary parameter acting as key for prach-pattern list."; + } + + leaf number-of-repetitions { + type uint8{ + range 1..14; + } + mandatory true; + description + "This parameter defines number of PRACH repetitions in PRACH occasion, + to which the section control is applicable."; + } + + leaf number-of-occasions { + type uint8; + mandatory true; + description + "This parameter informs how many consecutive PRACH occasions is described by the PRACH pattern."; + } + + leaf re-offset { + type uint32; + mandatory true; + description + "Offset between the start of lowest-frequency RE of lowest-frequency PRB + and the start of lowest-frequency RE belonging to the PRACH occasion. + The re-offset is configured as number of PRACH REs."; + } + + list occasion-parameters { + key occasion-id; + min-elements 1; + description + "This is list of cp-lengths, gp-lengths and beam-ids applicable + per each PRACH occasion in PRACH pattern. + Note: the number of records in this list MUST be equal + to value of parameter number-of-occasions."; + + leaf occasion-id { + type uint8; + mandatory true; + description + "Supplementary parameter acting as key in 'occasion-parameters' list"; + } + + leaf cp-length { + type uint16; + units Ts; + mandatory true; + description + "Cyclic prefix length. See CUS-plane specification for detailed description."; + } + + leaf gp-length { + type uint16; + units Ts; + description + "Guard period length."; + } + + leaf beam-id { + type uint16; + mandatory true; + description + "This parameter defines the beam pattern to be applied to the U-Plane data. + beamId = 0 means no beamforming operation will be performed."; + } + } + + leaf frame-number { + type uint16{ + range 0..1023; + } + mandatory true; + description + "This parameter is an index inside the pattern-length, such that + PRACH occasion is happening for SFN which fulfills following equation: + [SFN mod pattern-length = frame-id]"; + } + + leaf sub-frame-id { + type uint16; + mandatory true; + description + "Identifier of sub-frame of the PRACH occasion. Value is interpreted in the same way + as subframeId field in a section description of a C-Plane message."; + } + + leaf time-offset { + type uint16; + units Ts; + mandatory true; + description + "This parameter defines the time-offset from the start of the sub-frame + to the start of the first Cyclic Prefix of PRACH pattern"; + } + } + } + + grouping static-srs-configuration { + description + "Set of parameters related to static PRACH configuration"; + + leaf pattern-period { + type uint16 { + range 1..1024; + } + mandatory true; + description + "Period after which static SRS patterns are repeated. Unit: number of frames."; + } + + list srs-patterns { + key srs-pattern-id; + min-elements 1; + description + "Provides a SRS pattern. Each record in the list represents a single PRACH occasion. Number of list entries cannot exceed max-srs-patterns."; + + leaf srs-pattern-id { + type uint16; + mandatory true; + description + "Supplementary parameter acting as key for srs-pattern list."; + } + + leaf sub-frame-id { + type uint16; + mandatory true; + description + "Identifier of sub-frame of the Raw SRS occasion. Value is interpreted in the same way + as subframeId field in a section description of a C-Plane message."; + } + + leaf slot-id { + type uint16; + mandatory true; + description + "Identifier of slot of the Raw SRS occasion. Value is interpreted in the same way + as slotId field in a section description of a C-Plane message."; + } + + leaf start-symbol-id { + type uint16; + mandatory true; + description + "Identifier of first symbol of the Raw SRS occasion. Value is interpreted in the same way + as startSymbolId field in a section description of a C-Plane message."; + } + + leaf beam-id { + type uint16; + mandatory true; + description + "This parameter defines the beam pattern to be applied to the U-Plane data. + beamId = 0 means no beamforming operation will be performed."; + } + + leaf num-symbol { + type uint16; + mandatory true; + description + "This parameter defines number of consecutive symbols covered by specific srs-pattern. + Single srs-pattern may address at least one symbol. However, possible optimizations + could allow for several (up to 14) symbols."; + } + + leaf start-prbc { + type uint16 { + range 0..1023; + } + mandatory true; + description + "Identifier of first PRB of the Raw SRS occasion. Value is interpreted in the same way + as startPrbc field in a section description of a C-Plane message."; + } + + leaf num-prbc { + type uint16; + mandatory true; + description + "Number of PRBs of the Raw SRS occasion. Value is interpreted in the same way + as numPrbc field in a section description of a C-Plane message."; + } + } + } + + grouping configurable-tdd-pattern { + description + "Set of parameters related to configurable TDD pattern. + Note: configurable-tdd-pattern shall not be used in case the usage would collide with + deprecated 'lte-tdd-pattern'."; + + list switching-points { + key switching-point-id; + description + "List of switching points within frame, related to configurable TDD pattern. + An O-RU shall reject any configuration modification which exceeds the maximum + number of switching-points supported by the O-RU"; + + leaf switching-point-id { + type uint16; + description + "Supplementary parameter acting as key for switching-points list."; + } + + leaf direction { + type enumeration { + enum UL { + description "Uplink"; + } + enum DL { + description "Downlink"; + } + enum GP { + description "Guard period"; + } + } + mandatory true; + description + "Parameter provides information regarding desired signal direction at the moment switching point occurs."; + } + + leaf frame-offset { + type uint32; + mandatory true; + description + "Offset from DL air frame boundary transmitted at RF connector to the point in time that is characteristic to the operation on RF switches. Unit is 1/1.2288e9 Hz and accuracy is 1/4 Tc."; + } + } + } + + list static-srs-configurations { + if-feature mcap:SRS-STATIC-CONFIGURATION-SUPPORTED; + key static-srs-config-id; + description + "List of static SRS configurations"; + + leaf static-srs-config-id { + type uint8; + description + "Supplementary parameter acting as key in the list of static SRS configurations."; + } + + uses static-srs-configuration; + } + + list configurable-tdd-patterns { + if-feature mcap:CONFIGURABLE-TDD-PATTERN-SUPPORTED; + key tdd-pattern-id; + description + "List of configured TDD patterns"; + + leaf tdd-pattern-id { + type uint8; + description + "Supplementary parameter acting as key in the list of configured TDD patterns."; + } + + uses configurable-tdd-pattern; + } + } + + grouping tx-array-notification-group { + description + "Grouping for tx-array for notification"; + + list tx-array-carriers{ + key name; + description "notification of state change for tx-array-carriers"; + + leaf name{ + type leafref{ + path "/user-plane-configuration/tx-array-carriers/name"; + } + description + "name of tx-array-carriers is notified at state change"; + } + leaf state{ + type leafref{ + path "/user-plane-configuration/tx-array-carriers/state"; + } + description + "state of tx-array-carriers is notified at state change"; + } + } + } + + grouping rx-array-notification-group { + description + "Grouping for rx-array for notification"; + + list rx-array-carriers{ + key name; + description + "Notification used to inform about state change of rx-array-carriers"; + leaf name{ + type leafref{ + path "/user-plane-configuration/rx-array-carriers/name"; + } + description + "name of rx-array-carriers is notified at state change"; + } + leaf state{ + type leafref{ + path "/user-plane-configuration/rx-array-carriers/state"; + } + description + "state of rx-array-carriers is notified at state change"; + } + } + } + +// top level container + + container user-plane-configuration { + description "top level container for user plane configuration"; + + uses uplane-conf-group; + uses general-config; + } + + //notification statement + notification tx-array-carriers-state-change { + description + "Notification used to inform about state change of tx-array-carriers"; + uses tx-array-notification-group; + } + notification rx-array-carriers-state-change { + description + "Notification used to inform about state change of tx-array-carriers"; + + uses rx-array-notification-group; + } +} From e79c79b82eb31e028710e4d8e745d98e04c46d34 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 17:16:55 +0100 Subject: [PATCH 45/55] Add RPC for M-plane - generate CU-planes RU configuration based on the loaded yang models and DU config file - not yet implemented for libyang and libnetconf2 v1 --- radio/fhi_72/mplane/CMakeLists.txt | 2 + radio/fhi_72/mplane/config-mplane.c | 70 ++++ radio/fhi_72/mplane/config-mplane.h | 30 ++ radio/fhi_72/mplane/init-mplane.c | 6 + radio/fhi_72/mplane/yang/create-yang-config.c | 392 ++++++++++++++++++ radio/fhi_72/mplane/yang/create-yang-config.h | 32 ++ 6 files changed, 532 insertions(+) create mode 100644 radio/fhi_72/mplane/config-mplane.c create mode 100644 radio/fhi_72/mplane/config-mplane.h create mode 100644 radio/fhi_72/mplane/yang/create-yang-config.c create mode 100644 radio/fhi_72/mplane/yang/create-yang-config.h diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 183121e40a..a6bd7e62d7 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -30,9 +30,11 @@ target_sources(oran_fhlib_5g_mplane PRIVATE rpc-send-recv.c get-mplane.c subscribe-mplane.c + config-mplane.c ru-mplane-api.c xml/get-xml.c yang/get-yang.c + yang/create-yang-config.c ) pkg_check_modules(libyang REQUIRED libyang) diff --git a/radio/fhi_72/mplane/config-mplane.c b/radio/fhi_72/mplane/config-mplane.c new file mode 100644 index 0000000000..7a66c6ec7a --- /dev/null +++ b/radio/fhi_72/mplane/config-mplane.c @@ -0,0 +1,70 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "config-mplane.h" +#include "rpc-send-recv.h" +#include "yang/get-yang.h" +#include "yang/create-yang-config.h" +#include "common/utils/assertions.h" + +#include +#include + +bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + NC_DATASTORE target = NC_DATASTORE_CANDIDATE; + NC_RPC_EDIT_DFLTOP op = NC_RPC_EDIT_DFLTOP_MERGE; + NC_RPC_EDIT_TESTOPT test = NC_RPC_EDIT_TESTOPT_UNKNOWN; + NC_RPC_EDIT_ERROPT err = NC_RPC_EDIT_ERROPT_UNKNOWN; + + bool success = false; + + struct ly_ctx *ctx = NULL; + success = load_yang_models(ru_session, buffer, &ctx); + AssertError(success, return false, "[MPLANE] Unable to continue.\n"); + + char *content = NULL; + success = configure_ru_from_yang(&ctx, ru_session, oai, num_rus, &content); + AssertError(success, return false, "[MPLANE] Unable to create content for RPC.\n"); + + MP_LOG_I("RPC request to RU \"%s\" = :\n%s\n", ru_session->ru_ip_add, content); + rpc = nc_rpc_edit(target, op, test, err, content, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); + AssertError(success, return false, "[MPLANE] Failed to edit configuration for the candidate datastore.\n"); + + MP_LOG_I("Successfully edited the candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + free(content); +#ifdef MPLANE_V1 + ly_ctx_destroy(ctx, NULL); +#elif defined MPLANE_V2 + ly_ctx_destroy(ctx); +#endif + + return true; +} diff --git a/radio/fhi_72/mplane/config-mplane.h b/radio/fhi_72/mplane/config-mplane.h new file mode 100644 index 0000000000..aecf8dc348 --- /dev/null +++ b/radio/fhi_72/mplane/config-mplane.h @@ -0,0 +1,30 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef CONFIGURE_MPLANE_H +#define CONFIGURE_MPLANE_H + +#include "ru-mplane-api.h" +#include "radio/COMMON/common_lib.h" + +bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus); + +#endif /* CONFIGURE_MPLANE_H */ diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index add3916f4d..5966012945 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -23,6 +23,7 @@ #include "radio/fhi_72/oran-params.h" #include "get-mplane.h" #include "subscribe-mplane.h" +#include "config-mplane.h" #include "xml/get-xml.h" #include @@ -174,6 +175,11 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config); AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n"); + if (ru_session->ru_notif.ptp_state) { + success = edit_config_mplane(ru_session, operational_ds, oai, num_rus); + AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n"); + } + free(operational_ds); free(watchdog_answer); diff --git a/radio/fhi_72/mplane/yang/create-yang-config.c b/radio/fhi_72/mplane/yang/create-yang-config.c new file mode 100644 index 0000000000..7276b9fae0 --- /dev/null +++ b/radio/fhi_72/mplane/yang/create-yang-config.c @@ -0,0 +1,392 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "create-yang-config.h" +#include "common/utils/nr/nr_common.h" + +#define VERIFY_SUCCESS(var, message, args...) AssertError(var, return false, message, ##args) + +#ifdef MPLANE_V2 +static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + + ret = lyd_new_path(NULL, *ctx, "/ietf-interfaces:interfaces", NULL, 0, root); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"interfaces\" node.\n"); + + struct lyd_node *interface_node = NULL; + ret = lyd_new_list(*root, NULL, "interface", 0, &interface_node, int_name); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"interface\" node.\n"); + + struct lyd_node *type_node = NULL; + ret = lyd_new_term(interface_node, NULL, "type", "iana-if-type:l2vlan", 0, &type_node); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"type\" node.\n"); + + ret = lyd_new_term(interface_node, NULL, "enabled", "true", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"enabled\" node.\n"); + + const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented(*ctx, "o-ran-interfaces"); + VERIFY_SUCCESS(oran_int_mod != NULL, "[MPLANE] Failed to get \"o-ran-interfaces\" module.\n"); + + struct lyd_node *base_int = NULL; + ret = lyd_new_term(interface_node, oran_int_mod, "base-interface", ru_session->ru_mplane_config.interface_name, 0, &base_int); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"base-interface\" node with name \"%s\".\n", ru_session->ru_mplane_config.interface_name); + + struct lyd_node *vlan_id = NULL; + char vlan_tag_str[8]; + snprintf(vlan_tag_str, sizeof(vlan_tag_str), "%d", ru_session->ru_mplane_config.vlan_tag[idx]); + ret = lyd_new_term(interface_node, oran_int_mod, "vlan-id", vlan_tag_str, 0, &vlan_id); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"vlan-id\" node with \"%d\".\n", ru_session->ru_mplane_config.vlan_tag[idx]); + + struct lyd_node *ru_mac_addr = NULL; + ret = lyd_new_term(interface_node, oran_int_mod, "mac-address", ru_session->xran_mplane.ru_mac_addr, 0, &ru_mac_addr); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"mac-address\" node with \"%s\".\n", ru_session->xran_mplane.ru_mac_addr); + + return true; +} + +static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + + ret = lyd_new_path(NULL, *ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"processing-elements\" node.\n"); + + ret = lyd_new_term(*root, NULL, "transport-session-type", "ETH-INTERFACE", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"transport-session-type\" node.\n"); + + struct lyd_node *ru_elem_node = NULL; + char plane_name[8]; + snprintf(plane_name, sizeof(plane_name), "PLANE_%ld", idx); + ret = lyd_new_list(*root, NULL, "ru-elements", 0, &ru_elem_node, plane_name); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-elements\" node.\n"); + + struct lyd_node *transp_flow = NULL; + ret = lyd_new_inner(ru_elem_node, NULL, "transport-flow", 0, &transp_flow); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"transport-flow\" node.\n"); + + ret = lyd_new_term(transp_flow, NULL, "interface-name", int_name, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"interface-name\" node.\n"); + + struct lyd_node *eth_flow = NULL; + ret = lyd_new_inner(transp_flow, NULL, "eth-flow", 0, ð_flow); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eth-flow\" node.\n"); + + char vlan_tag_str[8]; + snprintf(vlan_tag_str, sizeof(vlan_tag_str), "%d", ru_session->ru_mplane_config.vlan_tag[idx]); + ret = lyd_new_term(eth_flow, NULL, "vlan-id", vlan_tag_str, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"vlan-id\" node.\n"); + + ret = lyd_new_term(eth_flow, NULL, "ru-mac-address", ru_session->xran_mplane.ru_mac_addr, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-mac-address\" node.\n"); + + ret = lyd_new_term(eth_flow, NULL, "o-du-mac-address", ru_session->ru_mplane_config.du_mac_addr[idx], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-mac-address\" node.\n"); + + return true; +} + +static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + + ret = lyd_new_term(*root, NULL, "cp-length", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length\" node.\n"); + + ret = lyd_new_term(*root, NULL, "cp-length-other", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length-other\" node.\n"); + + // to we actually store this from DU config file? + ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"offset-to-absolute-frequency-center\" node.\n"); + + struct lyd_node *compression_node = NULL; + ret = lyd_new_inner(*root, NULL, "compression", 0, &compression_node); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression\" node.\n"); + + char iq_width_str[8]; + snprintf(iq_width_str, sizeof(iq_width_str), "%d", xran_mplane->iq_width); + ret = lyd_new_term(compression_node, NULL, "iq-bitwidth", iq_width_str, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"iq-bitwidth\" node.\n"); + + if (xran_mplane->iq_width < 16) { + ret = lyd_new_term(compression_node, NULL, "compression-type", "STATIC", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-type\" node.\n"); + + // ret = lyd_new_term(compression_node, NULL, "compression-method", "BLOCK_FLOATING_POINT", 0, NULL); + // VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-method\" node.\n"); + } + + struct lyd_node *eaxc_conf = NULL; + ret = lyd_new_inner(*root, NULL, "e-axcid", 0, &eaxc_conf); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"e-axcid\" node.\n"); + + char eaxc_id[8]; + snprintf(eaxc_id, sizeof(eaxc_id), "%ld", idx); + ret = lyd_new_term(eaxc_conf, NULL, "eaxc-id", eaxc_id, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eaxc-id\" node.\n"); + + char du_port_bitmask[16]; + snprintf(du_port_bitmask, sizeof(du_port_bitmask), "%d", xran_mplane->du_port_bitmask); + ret = lyd_new_term(eaxc_conf, NULL, "o-du-port-bitmask", du_port_bitmask, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-port-bitmask\" node.\n"); + + char band_sector_bitmask[8]; + snprintf(band_sector_bitmask, sizeof(band_sector_bitmask), "%d", xran_mplane->band_sector_bitmask); + ret = lyd_new_term(eaxc_conf, NULL, "band-sector-bitmask", band_sector_bitmask, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"band-sector-bitmask\" node.\n"); + + char ccid_bitmask[8]; + snprintf(ccid_bitmask, sizeof(ccid_bitmask), "%d", xran_mplane->ccid_bitmask); + ret = lyd_new_term(eaxc_conf, NULL, "ccid-bitmask", ccid_bitmask, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ccid-bitmask\" node.\n"); + + char ru_port_bitmask[8]; + snprintf(ru_port_bitmask, sizeof(ru_port_bitmask), "%d", xran_mplane->ru_port_bitmask); + ret = lyd_new_term(eaxc_conf, NULL, "ru-port-bitmask", ru_port_bitmask, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-port-bitmask\" node.\n"); + + return true; +} + +static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + bool success = true; + + ret = lyd_new_path(NULL, *ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"user-plane-configuration\" node.\n"); + + if (ru_session->ru_mplane_config.rx_carriers.num != 1 || ru_session->ru_mplane_config.tx_carriers.num !=1) + MP_LOG_I("Only one carrier supported at the moment.\n"); + + // RX carriers + struct lyd_node *rx_carrier_node = NULL; + ret = lyd_new_list(*root, NULL, "rx-array-carriers", 0, &rx_carrier_node, ru_session->ru_mplane_config.rx_carriers.name[0]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carriers\" node.\n"); + + char rx_freq[16]; + snprintf(rx_freq, sizeof(rx_freq), "%.0f", oai->rx_freq[0]); + ret = lyd_new_term(rx_carrier_node, NULL, "center-of-channel-bandwidth", rx_freq, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"center-of-channel-bandwidth\" node.\n"); + + char rx_arfcn[16]; + snprintf(rx_arfcn, sizeof(rx_arfcn), "%d", to_nrarfcn(oai->nr_band, oai->rx_freq[0], oai->nr_scs_for_raster, oai->rx_bw)); + ret = lyd_new_term(rx_carrier_node, NULL, "absolute-frequency-center", rx_arfcn, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"absolute-frequency-center\" node.\n"); + + char rx_bw[16]; + snprintf(rx_bw, sizeof(rx_bw), "%.0f", oai->rx_bw); + ret = lyd_new_term(rx_carrier_node, NULL, "channel-bandwidth", rx_bw, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n"); + + ret = lyd_new_term(rx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-radio-frame-offset\" node.\n"); + + ret = lyd_new_term(rx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n"); + + // oai->rx_gain_offset is this the correction? if yes, test it later + ret = lyd_new_term(rx_carrier_node, NULL, "gain-correction", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain-correction\" node.\n"); + + ret = lyd_new_term(rx_carrier_node, NULL, "n-ta-offset", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"n-ta-offset\" node.\n"); + + ret = lyd_new_term(rx_carrier_node, NULL, "active", "ACTIVE", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n"); + + // TX carriers + struct lyd_node *tx_carrier_node = NULL; + ret = lyd_new_list(*root, NULL, "tx-array-carriers", 0, &tx_carrier_node, ru_session->ru_mplane_config.tx_carriers.name[0]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-array-carriers\" node.\n"); + + char tx_freq[16]; + snprintf(tx_freq, sizeof(tx_freq), "%.0f", oai->tx_freq[0]); + ret = lyd_new_term(tx_carrier_node, NULL, "center-of-channel-bandwidth", tx_freq, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"center-of-channel-bandwidth\" node.\n"); + + char tx_arfcn[16]; + snprintf(tx_arfcn, sizeof(tx_arfcn), "%d", to_nrarfcn(oai->nr_band, oai->tx_freq[0], oai->nr_scs_for_raster, oai->tx_bw)); + ret = lyd_new_term(tx_carrier_node, NULL, "absolute-frequency-center", tx_arfcn, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"absolute-frequency-center\" node.\n"); + + char tx_bw[16]; + snprintf(tx_bw, sizeof(tx_bw), "%.0f", oai->tx_bw); + ret = lyd_new_term(tx_carrier_node, NULL, "channel-bandwidth", tx_bw, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n"); + + // oai->tx_gain to be tested + ret = lyd_new_term(tx_carrier_node, NULL, "gain", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain\" node.\n"); + + ret = lyd_new_term(tx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-radio-frame-offset\" node.\n"); + + ret = lyd_new_term(tx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n"); + + ret = lyd_new_term(tx_carrier_node, NULL, "active", "ACTIVE", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n"); + + // PUSCH & PRACH endpoints + const size_t num_rx_ch = oai->rx_num_channels / num_rus; + for (size_t i = 0; i < num_rx_ch; i++) { + struct lyd_node *pusch_node = NULL; + ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &pusch_node, ru_session->ru_mplane_config.rx_endpoints.name[i]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n"); + + success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pusch_node); + VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[i]); + + const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2); + struct lyd_node *prach_node = NULL; + ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &prach_node, ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n"); + + success = fill_uplane_ch_v2(&ru_session->xran_mplane, i + ru_session->xran_mplane.prach_offset, &prach_node); + VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]); + } + + // PDSCH endpoints + const size_t num_tx_ch = oai->tx_num_channels / num_rus; + for (size_t i = 0; i < num_tx_ch; i++) { + struct lyd_node *pdsch_node = NULL; + ret = lyd_new_list(*root, NULL, "low-level-tx-endpoints", 0, &pdsch_node, ru_session->ru_mplane_config.tx_endpoints.name[i]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoints\" node.\n"); + + success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pdsch_node); + VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-tx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.tx_endpoints.name[i]); + } + + // PUSCH and PRACH links + for (size_t i = 0; i < num_rx_ch; i++) { + // PUSCH + struct lyd_node *pusch_link_node = NULL; + char pusch_link[16]; + snprintf(pusch_link, sizeof(pusch_link), "%s%ld", "PuschLink", i); + ret = lyd_new_list(*root, NULL, "low-level-rx-links", 0, &pusch_link_node, pusch_link); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-links\" node.\n"); + + ret = lyd_new_term(pusch_link_node, NULL, "processing-element", u_proc_elem, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n"); + + ret = lyd_new_term(pusch_link_node, NULL, "rx-array-carrier", ru_session->ru_mplane_config.rx_carriers.name[0], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carrier\" node.\n"); + + ret = lyd_new_term(pusch_link_node, NULL, "low-level-rx-endpoint", ru_session->ru_mplane_config.rx_endpoints.name[i], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoint\" node.\n"); + + // PRACH + struct lyd_node *prach_link_node = NULL; + char prach_link[16]; + snprintf(prach_link, sizeof(prach_link), "%s%ld", "PrachLink", i); + ret = lyd_new_list(*root, NULL, "low-level-rx-links", 0, &prach_link_node, prach_link); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-links\" node.\n"); + + ret = lyd_new_term(prach_link_node, NULL, "processing-element", u_proc_elem, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n"); + + ret = lyd_new_term(prach_link_node, NULL, "rx-array-carrier", ru_session->ru_mplane_config.rx_carriers.name[0], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-array-carrier\" node.\n"); + + const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2); + ret = lyd_new_term(prach_link_node, NULL, "low-level-rx-endpoint", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoint\" node.\n"); + } + + // PDSCH links + for (size_t i = 0; i < num_tx_ch; i++) { + struct lyd_node *pdsch_link_node = NULL; + char pdsch_link[16]; + snprintf(pdsch_link, sizeof(pdsch_link), "%s%ld", "PdschLink", i); + ret = lyd_new_list(*root, NULL, "low-level-tx-links", 0, &pdsch_link_node, pdsch_link); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-links\" node.\n"); + + ret = lyd_new_term(pdsch_link_node, NULL, "processing-element", u_proc_elem, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"processing-element\" node.\n"); + + ret = lyd_new_term(pdsch_link_node, NULL, "tx-array-carrier", ru_session->ru_mplane_config.tx_carriers.name[0], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-array-carrier\" node.\n"); + + ret = lyd_new_term(pdsch_link_node, NULL, "low-level-tx-endpoint", ru_session->ru_mplane_config.tx_endpoints.name[i], 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoint\" node.\n"); + } + + return true; +} +#endif + +bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result) +{ + bool success = false; + +#ifdef MPLANE_V1 + VERIFY_SUCCESS(success, "[MPLANE] To be implemented and tested.\n"); +#elif defined MPLANE_V2 + const ru_mplane_config_t *ru_config = &ru_session->ru_mplane_config; + size_t num_cu_planes = ru_config->num_cu_planes; + if (num_cu_planes == 2 && ru_config->vlan_tag[0] == ru_config->vlan_tag[1]) { + MP_LOG_I("The VLAN tags for C and U plane for the RU \"%s\" are the same. Therefore, configuring one common interface and one processing element.\n", ru_session->ru_ip_add); + num_cu_planes = 1; + } + + struct lyd_node *all_merge = NULL; + LY_ERR ret = LY_SUCCESS; + + for (size_t i = 0; i < num_cu_planes; i++) { + // + struct lyd_node *cu_interface = NULL; + char int_name[12]; + snprintf(int_name, sizeof(int_name), "INTERFACE_%ld", i); + success = create_cu_interface_v2(ctx, ru_session, i, int_name, &cu_interface); + VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane interface.\n"); + + // + struct lyd_node *proc_elem = NULL; + success = create_proc_elem_v2(ctx, ru_session, i, int_name, &proc_elem); + VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane processing element.\n"); + + ret = lyd_merge_siblings(&all_merge, cu_interface, 0); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface.\n"); + ret = lyd_merge_siblings(&all_merge, proc_elem, 0); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge processing element.\n"); + + lyd_free_tree(cu_interface); + lyd_free_tree(proc_elem); + } + + // + struct lyd_node *uplane_conf = NULL; + success = create_uplane_conf_v2(ctx, ru_session, oai, num_rus, "PLANE_0", &uplane_conf); + VERIFY_SUCCESS(success, "[MPLANE] Cannot create U-plane configuration.\n"); + + ret = lyd_merge_siblings(&uplane_conf, all_merge, 0); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n"); + + lyd_print_mem(result, uplane_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS); + + lyd_free_siblings(all_merge); + lyd_free_siblings(uplane_conf); +#endif + + return true; +} diff --git a/radio/fhi_72/mplane/yang/create-yang-config.h b/radio/fhi_72/mplane/yang/create-yang-config.h new file mode 100644 index 0000000000..9e06bdc923 --- /dev/null +++ b/radio/fhi_72/mplane/yang/create-yang-config.h @@ -0,0 +1,32 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef CREATE_MPLANE_YANG_CONFIG_H +#define CREATE_MPLANE_YANG_CONFIG_H + +#include "../ru-mplane-api.h" +#include "radio/COMMON/common_lib.h" + +#include + +bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result); + +#endif /* CREATE_MPLANE_YANG_CONFIG_H */ From b478930a047f86def402ff5a732f314fba5f2bbf Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 17:22:41 +0100 Subject: [PATCH 46/55] Add RPC for M-plane --- radio/fhi_72/mplane/config-mplane.c | 23 +++++++++++++++++++++++ radio/fhi_72/mplane/config-mplane.h | 2 ++ radio/fhi_72/mplane/init-mplane.c | 3 +++ 3 files changed, 28 insertions(+) diff --git a/radio/fhi_72/mplane/config-mplane.c b/radio/fhi_72/mplane/config-mplane.c index 7a66c6ec7a..94d3bbe49e 100644 --- a/radio/fhi_72/mplane/config-mplane.c +++ b/radio/fhi_72/mplane/config-mplane.c @@ -68,3 +68,26 @@ bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const open return true; } + +bool validate_config_mplane(ru_session_t *ru_session) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + char *src_start = NULL; + NC_DATASTORE source = NC_DATASTORE_CANDIDATE; + + MP_LOG_I("RPC request to RU \"%s\" = candidate datastore.\n", ru_session->ru_ip_add); + rpc = nc_rpc_validate(source, src_start, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); + AssertError(success, return false, "[MPLANE] Failed to validate candidate datastore.\n"); + + MP_LOG_I("Successfully validated candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + + return true; +} diff --git a/radio/fhi_72/mplane/config-mplane.h b/radio/fhi_72/mplane/config-mplane.h index aecf8dc348..ba3c926954 100644 --- a/radio/fhi_72/mplane/config-mplane.h +++ b/radio/fhi_72/mplane/config-mplane.h @@ -27,4 +27,6 @@ bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus); +bool validate_config_mplane(ru_session_t *ru_session); + #endif /* CONFIGURE_MPLANE_H */ diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 5966012945..f3560850fe 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -178,6 +178,9 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz if (ru_session->ru_notif.ptp_state) { success = edit_config_mplane(ru_session, operational_ds, oai, num_rus); AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n"); + + success = validate_config_mplane(ru_session); + AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n"); } free(operational_ds); From f22bc5acc74e6b63f02cd0c3512f561ab0fe6bdd Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 17:25:39 +0100 Subject: [PATCH 47/55] Add RPC for M-plane --- radio/fhi_72/mplane/config-mplane.c | 24 ++++++++++++++++++++++++ radio/fhi_72/mplane/config-mplane.h | 2 ++ radio/fhi_72/mplane/init-mplane.c | 3 +++ 3 files changed, 29 insertions(+) diff --git a/radio/fhi_72/mplane/config-mplane.c b/radio/fhi_72/mplane/config-mplane.c index 94d3bbe49e..69ff1fd2b3 100644 --- a/radio/fhi_72/mplane/config-mplane.c +++ b/radio/fhi_72/mplane/config-mplane.c @@ -91,3 +91,27 @@ bool validate_config_mplane(ru_session_t *ru_session) return true; } + +bool commit_config_mplane(ru_session_t *ru_session) +{ + int timeout = CLI_RPC_REPLY_TIMEOUT; + struct nc_rpc *rpc; + NC_WD_MODE wd = NC_WD_ALL; + NC_PARAMTYPE param = NC_PARAMTYPE_CONST; + int confirmed = 0; + int32_t confirm_timeout = 0; + char *persist = NULL, *persist_id = NULL; + + MP_LOG_I("RPC request to RU \"%s\" = candidate datastore.\n", ru_session->ru_ip_add); + rpc = nc_rpc_commit(confirmed, confirm_timeout, persist, persist_id, param); + AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); + + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); + AssertError(success, return false, "[MPLANE] Failed to commit candidate datastore.\n"); + + MP_LOG_I("Successfully commited CU-planes configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add); + + nc_rpc_free(rpc); + + return true; +} diff --git a/radio/fhi_72/mplane/config-mplane.h b/radio/fhi_72/mplane/config-mplane.h index ba3c926954..c8451ca8a0 100644 --- a/radio/fhi_72/mplane/config-mplane.h +++ b/radio/fhi_72/mplane/config-mplane.h @@ -29,4 +29,6 @@ bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const open bool validate_config_mplane(ru_session_t *ru_session); +bool commit_config_mplane(ru_session_t *ru_session); + #endif /* CONFIGURE_MPLANE_H */ diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index f3560850fe..352a564cec 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -181,6 +181,9 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz success = validate_config_mplane(ru_session); AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n"); + + success = commit_config_mplane(ru_session); + AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n"); } free(operational_ds); From 430026f1ecc2f14061cf3e0dceec7b20bcd5f7e8 Mon Sep 17 00:00:00 2001 From: Teodora Date: Tue, 11 Feb 2025 12:35:52 +0100 Subject: [PATCH 48/55] Wait until RUs are ready and add RPC for M-plane - if RU(s) are not well configured, disconnect immediately and stop the DU - if all RUs are well configured, proceed with waiting until ready. The RU is ready when the carriers are activated. Either the RU already has preconfigured carriers (previous M-plane client configured), or the DU has to wait until receives the notifications. --- radio/fhi_72/mplane/connect-mplane.c | 16 +++++++++++ radio/fhi_72/mplane/connect-mplane.h | 2 ++ radio/fhi_72/mplane/init-mplane.c | 12 ++++++++ radio/fhi_72/mplane/ru-mplane-api.h | 1 + radio/fhi_72/mplane/subscribe-mplane.c | 2 ++ radio/fhi_72/oran_isolate.c | 40 ++++++++++++++++++++++++++ 6 files changed, 73 insertions(+) diff --git a/radio/fhi_72/mplane/connect-mplane.c b/radio/fhi_72/mplane/connect-mplane.c index 7f4e5e40e6..08b758bef1 100644 --- a/radio/fhi_72/mplane/connect-mplane.c +++ b/radio/fhi_72/mplane/connect-mplane.c @@ -55,3 +55,19 @@ bool connect_mplane(ru_session_t *ru_session) return true; } + +void disconnect_mplane(void *rus_disconnect) +{ + ru_session_list_t *ru_session_list = (ru_session_list_t *)rus_disconnect; + + for (size_t i = 0; i num_rus; i++) { + ru_session_t *ru_session = &ru_session_list->ru_session[i]; + if (ru_session->session == NULL) + continue; + MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add); + nc_session_free(ru_session->session, NULL); + ru_session->session = NULL; + } + + nc_client_destroy(); +} diff --git a/radio/fhi_72/mplane/connect-mplane.h b/radio/fhi_72/mplane/connect-mplane.h index 5283e6ef75..e46aa60f19 100644 --- a/radio/fhi_72/mplane/connect-mplane.h +++ b/radio/fhi_72/mplane/connect-mplane.h @@ -26,4 +26,6 @@ bool connect_mplane(ru_session_t *ru_session); +void disconnect_mplane(void *rus_disconnect); + #endif /* CONNECT_MPLANE_H */ diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 352a564cec..39e8cfb995 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -186,6 +186,18 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n"); } + const char *usage_state = get_ru_xml_node(operational_ds, "usage-state"); + MP_LOG_I("Usage state = \"%s\" for RU \"%s\".\n", usage_state, ru_session->ru_ip_add); + if (strcmp(usage_state, "busy") == 0) { // carriers are already activated + ru_session->ru_notif.rx_carrier_state = true; + ru_session->ru_notif.tx_carrier_state = true; + ru_session->ru_notif.config_change = true; + } else { + ru_session->ru_notif.rx_carrier_state = false; + ru_session->ru_notif.tx_carrier_state = false; + ru_session->ru_notif.config_change = false; + } + free(operational_ds); free(watchdog_answer); diff --git a/radio/fhi_72/mplane/ru-mplane-api.h b/radio/fhi_72/mplane/ru-mplane-api.h index 1afabd4d23..70857adea6 100644 --- a/radio/fhi_72/mplane/ru-mplane-api.h +++ b/radio/fhi_72/mplane/ru-mplane-api.h @@ -35,6 +35,7 @@ typedef struct { bool ptp_state; bool rx_carrier_state; bool tx_carrier_state; + bool config_change; // to be extended with any notification callback } ru_notif_t; diff --git a/radio/fhi_72/mplane/subscribe-mplane.c b/radio/fhi_72/mplane/subscribe-mplane.c index d96d367d35..9a8e28c4c1 100644 --- a/radio/fhi_72/mplane/subscribe-mplane.c +++ b/radio/fhi_72/mplane/subscribe-mplane.c @@ -79,6 +79,8 @@ static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer) } else { // "DISABLED" or "BUSY" answer->tx_carrier_state = false; } + } else if (strcmp(notif, "netconf-config-change") == 0) { + answer->config_change = true; } } diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 8104b1a2c2..a5e2d5baf7 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -49,6 +49,7 @@ typedef struct { rru_config_msg_type_t last_msg; int capabilities_sent; void *oran_priv; + void *mplane_priv; } oran_eth_state_t; notifiedFIFO_t oran_sync_fifo; @@ -81,6 +82,10 @@ int trx_oran_stop(openair0_device *device) printf("ORAN: %s\n", __FUNCTION__); oran_eth_state_t *s = device->priv; xran_stop(s->oran_priv); +#ifdef OAI_MPLANE + printf("[MPLANE] Stopping M-plane.\n"); + disconnect_mplane(s->mplane_priv); +#endif return (0); } @@ -304,6 +309,41 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d } ru_configured[i] = manage_ru(ru_session, openair0_cfg, ru_session_list.num_rus); } + + bool all_ok = true; + bool ru_ready[ru_session_list.num_rus]; + for (size_t i = 0; i < ru_session_list.num_rus; i++) { + if (!ru_configured[i]) { + MP_LOG_I("RU with IP %s couldn't be configured.\n", ru_session_list.ru_session[i].ru_ip_add); + all_ok = false; + } + ru_ready[i] = false; + } + + if (!all_ok) { + disconnect_mplane((void *)&ru_session_list); + AssertFatal(false, "[MPLANE] Stopping M-plane.\n"); + } + + while (true) { + sleep(1); + bool all_rus_ready = true; + for (int i = 0; i < ru_session_list.num_rus; i++) { + ru_session_t *ru_session = &ru_session_list.ru_session[i]; + if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) { + MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add); + ru_ready[i] = true; + } else { + all_rus_ready = false; + break; + } + } + if (all_rus_ready) { + break; + } + } + + eth->mplane_priv = (void *)&ru_session_list; #else success = get_xran_config(openair0_cfg, &fh_init, fh_config); AssertFatal(success, "cannot get configuration for xran\n"); From d5fceb8e1fd3d6599d938531caa7799b656376f1 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 17:46:08 +0100 Subject: [PATCH 49/55] Parsing RU M-plane info to xran --- radio/fhi_72/oran-config.c | 132 +++++++++++++++++++++++++++++------- radio/fhi_72/oran-config.h | 2 +- radio/fhi_72/oran_isolate.c | 5 +- 3 files changed, 113 insertions(+), 26 deletions(-) diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index ba8fb2fcea..71804c5298 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -32,6 +32,10 @@ #include "stdio.h" #include "string.h" +#ifdef OAI_MPLANE +#include "mplane/ru-mplane-api.h" +#endif + static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn) { printf("\ @@ -522,6 +526,38 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in return true; } +#ifdef OAI_MPLANE +static bool set_fh_eaxcid_conf_mplane(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat, const ru_session_list_t *ru_session_list) +{ + xran_mplane_t *xran_mplane = &ru_session_list->ru_session[0].xran_mplane; + switch (cat) { + case XRAN_CATEGORY_A: + eaxcid_conf->mask_cuPortId = xran_mplane->du_port_bitmask; + eaxcid_conf->mask_bandSectorId = xran_mplane->band_sector_bitmask; + eaxcid_conf->mask_ccId = xran_mplane->ccid_bitmask; + eaxcid_conf->mask_ruPortId = xran_mplane->ru_port_bitmask; + eaxcid_conf->bit_cuPortId = xran_mplane->du_port; + eaxcid_conf->bit_bandSectorId = xran_mplane->band_sector; // total number of band sectors supported by O-RU should be retrieved by M-plane - && + eaxcid_conf->bit_ccId = xran_mplane->ccid; // total number of CC supported by O-RU should be retrieved by M-plane - + eaxcid_conf->bit_ruPortId = xran_mplane->ru_port; + break; + case XRAN_CATEGORY_B: + eaxcid_conf->mask_cuPortId = 0xf000; + eaxcid_conf->mask_bandSectorId = 0x0c00; + eaxcid_conf->mask_ccId = 0x0300; + eaxcid_conf->mask_ruPortId = 0x000f; + eaxcid_conf->bit_cuPortId = 12; + eaxcid_conf->bit_bandSectorId = 10; + eaxcid_conf->bit_ccId = 8; + eaxcid_conf->bit_ruPortId = 0; + break; + default: + return false; + } + + return true; +} +#else static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat) { /* CUS specification, section 3.1.3.1.6 @@ -540,8 +576,8 @@ static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran eaxcid_conf->mask_ccId = 0x00f0; eaxcid_conf->mask_ruPortId = 0x000f; eaxcid_conf->bit_cuPortId = 0; - eaxcid_conf->bit_bandSectorId = 0; // total number of band sectors supported by O-RU should be retreived by M-plane - && - eaxcid_conf->bit_ccId = 0; // total number of CC supported by O-RU should be retreived by M-plane - + eaxcid_conf->bit_bandSectorId = 0; // total number of band sectors supported by O-RU should be retrieved by M-plane - && + eaxcid_conf->bit_ccId = 0; // total number of CC supported by O-RU should be retrieved by M-plane - eaxcid_conf->bit_ruPortId = 0; break; case XRAN_CATEGORY_B: @@ -560,6 +596,7 @@ static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran return true; } +#endif uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr) { @@ -573,7 +610,7 @@ uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr) return NULL; } -static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_cat) +static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xran_category xran_cat) { memset(fh_init, 0, sizeof(*fh_init)); @@ -606,30 +643,46 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca const int nfh = sizeofArray(FHconfigs); config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix); - int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs +#ifdef OAI_MPLANE + ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api; + int num_rus = ru_session_list->num_rus; + fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs + if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) + return false; + if (!set_fh_eaxcid_conf_mplane(&fh_init->eAxCId_conf, xran_cat, ru_session_list)) + return false; + /* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be + communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame); + xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */ + fh_init->mtu = ru_session_list->ru_session[0].xran_mplane.mtu; // we suppose that each RU supports the same MTU size + int num_ru_addr = (fh_init->io_cfg.one_vf_cu_plane) ? num_rus : 2*num_rus; + fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr)); + AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n"); + for (int i = 0; i < num_rus; i++) { + struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr; + for (int j = 0; j < num_ru_addr/num_rus; j++) { + if (get_ether_addr(ru_session_list->ru_session[i].xran_mplane.ru_mac_addr, &ea[i+j]) == NULL) { + printf("could not read ethernet address '%s' for RU!\n", ru_session_list->ru_session[i].xran_mplane.ru_mac_addr); + return false; + } + } + } +#else + int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs + fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus)) return false; if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat)) return false; - - fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs - fh_init->dpdkBasebandFecMode = 0; // DPDK Baseband FEC device mode (0-SW, 1-HW); not used in xran - fh_init->dpdkBasebandDevice = NULL; // DPDK Baseband device address; not used in xran - /* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes; - it is necessary */ - fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr); /* maximum transmission unit (MTU) is the size of the largest protocol data unit (PDU) that can be communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame); xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */ fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr; - - fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function - int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt; fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr)); - char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr; AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n"); + char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr; for (int i = 0; i < num_ru_addr; ++i) { struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr; if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) { @@ -637,7 +690,14 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca return false; } } +#endif + fh_init->dpdkBasebandFecMode = 0; // DPDK Baseband FEC device mode (0-SW, 1-HW); not used in xran + fh_init->dpdkBasebandDevice = NULL; // DPDK Baseband device address; not used in xran + /* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes; + it is necessary */ + fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr); + fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec #ifdef F_RELEASE @@ -656,7 +716,8 @@ static bool set_fh_init(struct xran_fh_init *fh_init, enum xran_category xran_ca // this is a hack int g_kbar; -static bool set_fh_prach_config(const openair0_config_t *oai0, +static bool set_fh_prach_config(void *mplane_api, + const openair0_config_t *oai0, const uint32_t max_num_ant, const paramdef_t *prachp, int nprach, @@ -692,8 +753,13 @@ static bool set_fh_prach_config(const openair0_config_t *oai0, xran assumes PRACH offset >= max(Ntx, Nrx). However, we made a workaround that xran supports PRACH eAxC IDs same as PUSCH eAxC IDs. This is achieved with is_prach and filter_id parameters in the patch. Please note that this approach only applies to the RUs that support this functionality, e.g. LITEON RU. */ +#ifdef OAI_MPLANE + xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api; + prach_config->eAxC_offset = xran_mplane->prach_offset; +#else uint8_t offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr; prach_config->eAxC_offset = (offset != 0) ? offset : max_num_ant; +#endif g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr; @@ -722,17 +788,24 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame return true; } -static bool set_fh_ru_config(const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config) +static bool set_fh_ru_config(void *mplane_api, const paramdef_t *rup, uint16_t fftSize, int nru, enum xran_category xran_cat, struct xran_ru_config *ru_config) { ru_config->xranTech = XRAN_RAN_5GNR; // 5GNR or LTE ru_config->xranCat = xran_cat; // mode: Catergory A or Category B ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC; // dynamic or static udCompHdr handling +#ifdef OAI_MPLANE + xran_mplane_t *xran_mplane = (xran_mplane_t *)mplane_api; + ru_config->iqWidth = xran_mplane->iq_width; + ru_config->iqWidth_PRACH = xran_mplane->iq_width; +#else ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr; // IQ bit width AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n"); - ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr; // IQ bit width for PRACH AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n"); +#endif + ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; // compression method for PRACH + AssertFatal(fftSize > 0, "FFT size cannot be 0\n"); ru_config->fftSize = fftSize; // FFT Size ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; // order of bytes in int16_t in buffer; big or little endian @@ -757,7 +830,7 @@ static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint1 return true; } -static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config) +static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config) { AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n"); AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus); @@ -847,14 +920,14 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat, fh_config->GPS_Alpha = 0; // refers to alpha as defined in section 9.7.2 of ORAN spec. this value should be alpha*(1/1.2288ns), range 0 - 1e7 (ns); offset_nsec = (pConf->GPS_Beta - offset_sec * 100) * 1e7 + pConf->GPS_Alpha fh_config->GPS_Beta = 0; // beta value as defined in section 9.7.2 of ORAN spec. range -32767 ~ +32767; offset_sec = pConf->GPS_Beta / 100 - if (!set_fh_prach_config(oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf)) + if (!set_fh_prach_config(mplane_api, oai0, fh_config->neAxc, prachp, nprach, &fh_config->prach_conf)) return false; /* SRS only used if XRAN_CATEGORY_B Note: srs_config->eAxC_offset >= prach_config->eAxC_offset + PRACH */ // fh_config->srs_conf = {0}; if (!set_fh_frame_config(oai0, &fh_config->frame_conf)) return false; - if (!set_fh_ru_config(rup, oai0->split7.fftSize, nru, xran_cat, &fh_config->ru_conf)) + if (!set_fh_ru_config(mplane_api, rup, oai0->split7.fftSize, nru, xran_cat, &fh_config->ru_conf)) return false; fh_config->bbdev_enc = NULL; // call back to poll BBDev encoder @@ -889,24 +962,35 @@ static bool set_fh_config(int ru_idx, int num_rus, enum xran_category xran_cat, return true; } -bool get_xran_config(const openair0_config_t *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config) +bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config) { /* This xran integration release is only valid for O-RU CAT A. Therefore, each FH parameter is hardcoded to CAT A. If you are interested in CAT B, please be aware that parameters of fh_init and fh_config structs must be modified accordingly. */ enum xran_category xran_cat = XRAN_CATEGORY_A; - if (!set_fh_init(fh_init, xran_cat)) { + if (!set_fh_init(mplane_api, fh_init, xran_cat)) { printf("could not read FHI 7.2/ORAN config\n"); return false; } +#ifdef OAI_MPLANE + ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api; for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { - if (!set_fh_config(o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) { + xran_mplane_t *xran_mplane = &ru_session_list->ru_session[o_xu_id].xran_mplane; + if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) { + MP_LOG_I("could not read FHI 7.2/RU-specific config\n"); + return false; + } + } +#else + for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { + if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) { printf("could not read FHI 7.2/RU-specific config\n"); return false; } } +#endif return true; } diff --git a/radio/fhi_72/oran-config.h b/radio/fhi_72/oran-config.h index c5a086638f..bbe934e757 100644 --- a/radio/fhi_72/oran-config.h +++ b/radio/fhi_72/oran-config.h @@ -29,7 +29,7 @@ struct xran_fh_init; struct xran_fh_config; struct openair0_config; -bool get_xran_config(const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config); +bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cfg, struct xran_fh_init *fh_init, struct xran_fh_config *fh_config); void print_fh_init(const struct xran_fh_init *fh_init); void print_fh_config(const struct xran_fh_config *fh_config); diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index a5e2d5baf7..3a63045817 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -344,8 +344,11 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d } eth->mplane_priv = (void *)&ru_session_list; + + success = get_xran_config((void *)&ru_session_list, openair0_cfg, &fh_init, fh_config); + AssertFatal(success, "[MPLANE] Cannot configure xran with M-plane info.\n"); #else - success = get_xran_config(openair0_cfg, &fh_init, fh_config); + success = get_xran_config(NULL, openair0_cfg, &fh_init, fh_config); AssertFatal(success, "cannot get configuration for xran\n"); #endif From c7dffd416a46450a47b88ad8b6d9119e2bbc77cd Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 18:01:41 +0100 Subject: [PATCH 50/55] Add Benetel550 4x4 reference gNB config file for M-plane --- ...78.273prb.fhi72.4x4-benetel550-mplane.conf | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf new file mode 100644 index 0000000000..6fa4c200dc --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf @@ -0,0 +1,273 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pdsch_AntennaPorts_N1 = 2; + maxMIMO_layers = 2; + pusch_AntennaPorts = 4; + do_CSIRS = 1; + do_SRS = 0; + sib1_tda = 15; + # force_UL256qam_off = 1; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + # n_TimingAdvanceOffset = 0; +# downlinkConfigCommon + #frequencyInfoDL + # center frequency = 3350.01 MHz + # selected SSB frequency = 3349.92 MHz + absoluteFrequencySSB = 623328; + dl_frequencyBand = 78; + # frequency point A = 3300.87 MHz + dl_absoluteFrequencyPointA = 620058; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1 + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 23; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 152; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 0; + preambleReceivedTargetPower = -100; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 8; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 3; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 2; + p0_NominalWithGrant = -96; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 0; + p0_nominal = -96; + + ssb_PositionsInBurst_Bitmap = 0x1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 0; + } + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "172.21.6.5"; }); + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 180; + pucch_TargetSNRx10 = 220; + dl_bler_target_upper = .35; + dl_bler_target_lower = .15; + ul_bler_target_upper = .35; + ul_bler_target_lower = .15; + pusch_FailureThres = 1000; + ul_max_mcs = 28; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 100; + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 15; + tx_amp_backoff_dB = 12; # needs to match O-RU configuration + L1_rx_thread_core = 8; + L1_tx_thread_core = 10; + phase_compensation = 0; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 4; + nb_rx = 4; + att_tx = 0; + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 9; + sl_ahead = 10; + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration +} +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level = "info"; + hw_log_level = "info"; + phy_log_level = "info"; + mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + ngap_log_level = "info"; + f1ap_log_level = "info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well + system_core = 0; + io_core = 1; + worker_cores = (2); + du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa"); + du_addr = ("00:11:22:33:44:68","00:11:22:33:44:69"); + vlan_tag = (11, 11); + ru_ip_addr = ("192.168.80.10"); + fh_config = ({ + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 200); + }); +}; From 75d5b31f4ae18b6f77a111766d8f39e26deaa7e8 Mon Sep 17 00:00:00 2001 From: Teodora Date: Sat, 29 Mar 2025 17:28:14 +0100 Subject: [PATCH 51/55] Add Benetel650 8x8 reference DU config file for M-plane --- ...73prb.fhi72.8x8-benetel650_650-mplane.conf | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf new file mode 100644 index 0000000000..28f9baf6f8 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf @@ -0,0 +1,265 @@ +Active_gNBs = ( "gNB-OAI-DU"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_DU_ID = 0xe00; + gNB_name = "gNB-OAI-DU"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pdsch_AntennaPorts_N1 = 2; + pusch_AntennaPorts = 8; + do_CSIRS = 1; + do_SRS = 0; + sib1_tda = 15; + force_UL256qam_off = 1; + maxMIMO_layers = 2; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + # n_TimingAdvanceOffset = 0; +# downlinkConfigCommon + #frequencyInfoDL + # center frequency = 3950.4 MHz + # selected SSB frequency = 3950.4 MHz + absoluteFrequencySSB = 663360; + dl_frequencyBand = 77; + # frequency point A = 3901.26 MHz + dl_absoluteFrequencyPointA = 660084; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1 + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 77; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 23; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 152; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 0; + preambleReceivedTargetPower = -100; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 8; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 3; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 2; + p0_NominalWithGrant = -96; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 0; + p0_nominal = -96; + + ssb_PositionsInBurst_Bitmap = 0x1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 3; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 1; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = 10; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + } +); + + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_if_name = "enp193s0f0"; + local_n_address = "172.21.16.51"; + remote_n_address = "172.21.6.90"; + local_n_portc = 500; + local_n_portd = 2153; + remote_n_portc = 501; + remote_n_portd = 2153; + pusch_TargetSNRx10 = 120; + pucch_TargetSNRx10 = 200; + dl_bler_target_upper = .35; + dl_bler_target_lower = .15; + ul_bler_target_upper = .35; + ul_bler_target_lower = .15; + pusch_FailureThres = 100; + ul_max_mcs = 28; + min_grant_prb = 1; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 100; + pucch0_dtx_threshold = 80; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 10; + tx_amp_backoff_dB = 12; # needs to match O-RU configuration + L1_rx_thread_core = 8; + L1_tx_thread_core = 10; # relevant after merge of l1_tx_thread + phase_compensation = 0; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 8; + nb_rx = 8; + att_tx = 0; + att_rx = 0; + bands = [77]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 9; + sl_ahead = 10; + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration +} +); + +log_config : +{ + global_log_level = "info"; + hw_log_level = "info"; + phy_log_level = "info"; + mac_log_level = "info"; + rlc_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + ngap_log_level = "info"; + f1ap_log_level = "info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:01:01.0", "0000:01:01.1", "0000:01:01.2", "0000:01:01.3"); # two VFs can be used as well + system_core = 0; + io_core = 1; + worker_cores = (2); + du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa"); + du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); + vlan_tag = (5, 5, 6, 6); + ru_ip_addr = ("192.168.80.5", "192.168.80.6"); + fh_config = ( +# RAN650 #1 + { + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 200); + }, +# RAN650 #2 + { + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 200); + }); +}; From bf0a0aa06b19b133be5a0c323535e0c33b2fe5ea Mon Sep 17 00:00:00 2001 From: Teodora Date: Sat, 29 Mar 2025 12:18:50 +0100 Subject: [PATCH 52/55] Clarification on delay profile --- doc/ORAN_FHI7.2_Tutorial.md | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index c28f75a2cf..8da06fe15e 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -942,10 +942,8 @@ Edit the sample OAI gNB configuration file and check following parameters: including the advantages and disadvantages of each mode, refer to [Memory in DPDK](https://www.dpdk.org/memory-in-dpdk-part-2-deep-dive-into-iova/) * `owdm_enable`: used for eCPRI One-Way Delay Measurements; it depends if the RU supports it; if not set to 1 (enabled), default value is 0 (disabled) - * `fh_config`: parameters that need to match RU parameters - * timing parameters (starting with `T`) depend on the RU: `Tadv_cp_dl` is a - single number, the rest pairs of numbers `(x, y)` specifying minimum and - maximum delays + * `fh_config` + * DU delay profile (`T1a` and `Ta4`): pairs of numbers `(x, y)` specifying minimum and maximum delays * `ru_config`: RU-specific configuration: * `iq_width`: Width of DL/UL IQ samples: if 16, no compression, if <16, applies compression @@ -1094,10 +1092,10 @@ fhi_72 = { // mtu fh_config = ( { - // timing, ru_config, prach_config of RU1 + // DU delay profile, ru_config, prach_config of RU1 }, { - // timing, ru_config, prach_config of RU2 + // DU delay profile, ru_config, prach_config of RU2 } ); }; @@ -1121,11 +1119,6 @@ fhi_72 = { fh_config = ( # RAN650 #1 { - Tadv_cp_dl = 125; - T2a_cp_dl = (259, 500); - T2a_cp_ul = (25, 500); - T2a_up = (134, 375); - Ta3 = (152, 160); T1a_cp_dl = (419, 470); T1a_cp_ul = (285, 336); T1a_up = (294, 345); @@ -1137,11 +1130,6 @@ fhi_72 = { }, # RAN650 #2 { - Tadv_cp_dl = 125; - T2a_cp_dl = (259, 500); - T2a_cp_ul = (25, 500); - T2a_up = (134, 375); - Ta3 = (152, 160); T1a_cp_dl = (419, 470); T1a_cp_ul = (285, 336); T1a_up = (294, 345); From a4479a2e65a372452faa44c401c588df5c78c285 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 18:02:27 +0100 Subject: [PATCH 53/55] Add M-plane tutorial --- doc/ORAN_FHI7.2_Tutorial.md | 811 +++++++++++++++++++++++++++++++++++- 1 file changed, 810 insertions(+), 1 deletion(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 8da06fe15e..da82f69734 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -964,7 +964,7 @@ Layer mapping (eAxC offsets) happens as follows: **Note** - At the moment, OAI is compatible with CAT A O-RU only. Therefore, SRS is not supported. -- XRAN retreives DU MAC address with `rte_eth_macaddr_get()` function. Hence, `fhi_72.du_addr` parameter is not taken into account. +- XRAN retrieves DU MAC address with `rte_eth_macaddr_get()` function. Hence, `fhi_72.du_addr` parameter is not taken into account. # Start and Operation of OAI gNB @@ -1173,6 +1173,815 @@ Note the eight entries after `avg_IO`. You should be able to connect a UE now. + +# OAI Management Plane +We support Configuration Management in OAI gNB, where gNB configures CU-planes, interfaces, TX/RX antennas, and TX/RX carriers for the RU. +The reference specifications: +* `O-RAN.WG4.MP.0-v05.00` +* `O-RAN.WG4.MP-YANGs-v04.00` + +## M-plane prerequisites +Before proceeding, please make sure you have a support for 7.2 interface, as described in [Prerequisites](#prerequisites). + +### DHCP server +The M-plane requires a DHCP server, where the M-plane connection can be established over untagged or tagged VLAN. We tested with untagged (the default VLAN is 1). +Please modify `/etc/dhcp/dhcpd.conf` configuration based on your testbed. + +
+Example DHCP server configuration + +``` +class "vendor-class" { + match option vendor-class-identifier; +} +subclass "vendor-class" "o-ran-ru2/Benetel" { + vendor-option-space VC; +} +option space VC; +option VC.server-address code 129 = array of ip-address; +option VC.server-fqdn code 130 = string; +# Netconf client IP address - DHCP option 43 +option VC.server-address 192.168.80.1; +option VC.server-fqdn "o_du_1.operator.com"; +set vendor-string = option vendor-class-identifier; +# option 143 - DHCPv4 SZTP Redirect Option (RFC8572) +# 2 bytes of URI's length + URI +option sztp code 143 = { unsigned integer 16, string }; +option sztp 15 "https://192.168.80.1"; +# port is optional in URI, e.g. "https://192.168.80.1:222" +#option sztp 20 "https://192.168.80.1:2222"; +subnet 192.168.80.0 netmask 255.255.255.0 { + option routers 192.168.80.1; + option subnet-mask 255.255.255.0; + option domain-name "oai.com"; + option domain-name-servers 172.21.3.100; + host benetel_ru { + # RU MAC address + hardware ethernet ; + # RU IP address + fixed-address ; + } +} +``` +
+ +Please, configure the interface as: +```bash +sudo ip address add 192.168.80.1/24 dev +``` + +### Mandatory packages +* On Fedora (we haven't yet tested RHEL): +```bash +sudo dnf install pcre-devel libssh-devel libxml2-devel libyang2-devel libnetconf2-devel +``` + +* On Ubuntu: +```bash +sudo apt-get install libpcre3-dev libssh-dev libxml2-dev +``` + +On Ubuntu, please note: `sudo apt-get install libyang2-dev libnetconf2-dev` will install unsupported versions (i.e. v2.0.112/v2.0.24 for `libyang2-dev`/`libnetconf2-dev`, but minimum required are v2.1.4/v2.1.25). +Therefore, please compile these libraries from source, as following: + +
+Installing latest v2 libyang2 and libnetconf2 libraries + +``` +rm -rf /tmp/build_mplane_v2 +mkdir /tmp/build_mplane_v2 + +# libyang +cd /tmp/build_mplane_v2 +git clone https://github.com/CESNET/libyang.git +cd libyang +git checkout v2.1.111 +mkdir build && cd build +cmake -DENABLE_TESTS=OFF \ + -DENABLE_VALGRIND_TESTS=OFF \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DCMAKE_INSTALL_RPATH=/usr/local/lib \ + -DPLUGINS_DIR=/usr/local/lib/libyang \ + -DPLUGINS_DIR_EXTENSIONS=/usr/local/lib/libyang/extensions \ + -DPLUGINS_DIR_TYPES=/usr/local/lib/libyang/types \ + -DYANG_MODULE_DIR=/usr/local/share/yang/modules/libyang .. +make -j8 +sudo make install +sudo ldconfig + +#libnetconf +cd /tmp/build_mplane_v2 +git clone https://github.com/CESNET/libnetconf2.git +cd libnetconf2 +git checkout v2.1.37 +mkdir build && cd build +cmake -DENABLE_TESTS=OFF \ + -DENABLE_EXAMPLES=OFF \ + -DENABLE_VALGRIND_TESTS=OFF \ + -DCLIENT_SEARCH_DIR=/usr/local/share/yang/modules \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DCMAKE_INSTALL_RPATH=/usr/local/lib \ + -DLIBYANG_INCLUDE_DIR=/usr/local/include \ + -DLIBYANG_LIBRARY=/usr/local/lib/libyang.so \ + -DLY_VERSION_PATH=/usr/local/include \ + -DYANG_MODULE_DIR=/usr/local/share/yang/modules/libnetconf2 .. +make -j8 +sudo make install +sudo ldconfig + +# to uninstall libraries +# cd /tmp/build_mplane_v2/libyang/build && sudo make uninstall +# cd /tmp/build_mplane_v2/libnetconf2/build && sudo make uninstall +# cd +# rm -rf /tmp/build_mplane_v2 +``` +
+ +If you would like to install these libraries in the custom path, please replace `/usr/local` default path to e.g. `/opt/mplane-v2`. + +## Benetel O-RU +Note: Only v1.2.2 RAN550 and RAN650 have been successfully tested. + +### One time steps +Connect to the RU as user `root`, enable the mplane service, and reboot: +```bash +ssh root@ +systemctl enable mplane +reboot +``` +Once the mplane service is successfully enabled on the RU, two new users are being added in `/etc/passwd`: +```bash +... +oranbenetel:x:1000:1000::/home/oranbenetel:/bin/sh +oranext:x:1001:1001::/home/oranext:/bin/sh +``` +Create `oranbenetel` home directory: +```bash +mkdir /home/oranbenetel && chown oranbenetel:oranbenetel /home/oranbenetel +``` +Connect to the RU as user `oranbenetel`, generate ssh keys, and copy DU public key into RU for NETCONF authentication: +```bash +ssh oranbenetel@ +ssh-keygen +echo "" >> ~/.ssh/authorized_keys +``` + + +## gNB configuration +The reference gNB configuration file for one Benetel RAN550: +[`gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf) +The reference DU configuration file for two Benetel RAN650: +[gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf) + +In order to run gNB/DU with M-plane, we need to modify the `fhi_72` section in the configuration file. +Example for one RU: +```bash +fhi_72 = { + dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1"); # one VF can be used as well + system_core = 0; + io_core = 1; + worker_cores = (2); + du_key_pair = ("/.ssh/id_rsa.pub", "/.ssh/id_rsa"); + du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67"); # only one needed if one VF configured + vlan_tag = (9, 9); # only one needed if one VF configured + ru_ip_addr = ("192.168.80.9"); + fh_config = ({ + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 200); + }); +}; +``` +Example for two RUs: +```bash +fhi_72 = { + dpdk_devices = ("0000:c3:11.0", "0000:c3:11.1", "0000:c3:11.2", "0000:c3:11.3"); # two VFs can be used as well + system_core = 0; + io_core = 1; + worker_cores = (2); + du_key_pair = ("/home/oaicicd/.ssh/id_rsa.pub", "/home/oaicicd/.ssh/id_rsa"); + du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); # only two needed if two VFs configured + vlan_tag = (9, 9, 11, 11); # only two needed if two VFs configured + ru_ip_addr = ("192.168.80.9", "192.168.80.10"); + fh_config = ( +# RAN550 #1 + { + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 200); + }, +# RAN550 #2 + { + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 200); + }); +}; +``` + +* `fhi_72` : + * `dpdk_devices`: [*] + * `system_core`: [*] + * `io_core`: [*] + * `worker_cores`: [*] + * `file_prefix`: [*] + * `du_key_pair`: ssh public and private keys to authenticate RU with NETCONF + * `du_addr`: DU MAC address(es) to create CU-plane interface(s) in the RU + * `vlan_tag`: VLAN U and C plane tags to create CU-plane interface(s) in the RU + * `ru_ip_addr`: RU IP address to connect to the RU via M-plane + * `dpdk_mem_size`: [*] + * `dpdk_iova_mode`: [*] + * `owdm_enable`: [*] + * `fh_config`: only DU delay profile (`T1a` and `Ta4`) + +[*] see [Configure OAI gNB](#configure-oai-gnb) for more details + +The following parameters are retrieved from the RU and forwarded to the xran: +* `MTU` +* `RU MAC address` +* `IQ compression`: if RU supports multiple, the first value in the list is taken; please note that the same value is used for PxSCH/PRACH +* `PRACH offset`: hardcoded based on the RU vendor (i.e. for Benetel `max(Nrx,Ntx)`) + +## Build and compile gNB +The following cmake options are available: +* `OAI_FHI72` = CUS support +* `OAI_FHI72_MPLANE` = M support + +Compiled libraries: +* `OAI_FHI72` <=> `oran_fhlib_5g` +* `OAI_FHI72` && `OAI_FHI72_MPLANE` <=> `oran_fhlib_5g` (CUS) && `oran_fhlib_5g_mplane` (CUSM) + +### Using build_oai script +```bash +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g +cd ~/openairinterface5g/cmake_targets/ +./build_oai -I # if you never installed OAI, use this command once before the next line +./build_oai --install-optional-packages # for pcre/libpcre3, libssh, and libxml2 library installation +./build_oai --gNB --ninja -t oran_fhlib_5g_mplane --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib +# if libyang2 and libnetconf2 are installed in `/opt/mplane-v2`, please use the following command: +PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig ./build_oai --gNB --ninja -t oran_fhlib_5g_mplane --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib +``` + +### Using cmake directly +```bash +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g +cd ~/openairinterface5g/ +mkdir build && cd build +cmake .. -GNinja -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib +# if libyang2 and libnetconf2 are installed in `/opt/mplane-v2`, please use the following command: +PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig cmake .. -GNinja -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib +ninja nr-softmodem oran_fhlib_5g_mplane params_libconfig +``` + +## Start the gNB +Run the `nr-softmodem` from the build directory: +```bash +cd ~/openairinterface5g/cmake_targets/ran_build/build +sudo ./nr-softmodem -O --thread-pool +``` + +**Warning**: Make sure that the configuration file you add after the `-O` option is adapted to your machine, especially to its isolated cores. + +M-plane sequence diagram: + +```mermaid +sequenceDiagram + participant dhcp as DHCP server + participant du as O-DU + participant ru as O-RU + + dhcp->ru: 1. Transport Layer Initialization + note over dhcp,ru: (a) perform VLAN scan (untagged or tagged VLAN)
(b) DHCP assigns IP address to RU
(c) DHCP sends DU IP address to RU + + du->ru: 2. NETCONF/SSH connect + + du->>ru: 3. DU retrieves RU info + note left of du: + + note over du: Check if RU is PTP synced + + du->>ru: 4. DU subscribes to all RU notifications + note left of du: + + du->>ru: 5. DU updates the supervision timer + note left of du: + + note over du: Store RU MAC, MTU, IQ bitwidth, and PRACH offset info for xran + + note over du: Store all the RU U-plane info - interface name, TX/RX carrier, and TX/RX endpoint names + + du->>ru: 6. DU loads yang models + note left of du: + note right of ru: ietf-netconf-monitoring.yang + + du->>ru: 7. DU performs CU-plane configuration + note left of du: + + note over ru: (1) o-ran-interface.yang - create new interface with VLAN tag, DU and RU MAC addresses
(2)(opt.) o-ran-transceiver.yang - for file upload
(3) o-ran-processing-elements.yang - element with which RU ports should be assigned
(4) o-ran-uplane-conf.yang
#8193;(4a) low-level-tx/rx-endpoints - PxSCH, PRACH
#8193;(4b) tx/rx-array-carriers - center frequency, BW, gain, ACTIVE,...
#8193;(4c) low-level-tx/rx-links - mapping endpoints, carriers and processing element
#8193;(4d)(opt.) if CAT B, SRS configuration
#8193;(4e)(opt.) TDD configuration + + du->>ru: 8. DU checks if CU-plane configuration is valid + note left of du: + + du->>ru: 9. If valid, DU commits the changes + note left of du: + + du->>ru: 10. DU retrieves RU states + note right of ru: ietf-hardware.yang + note left of du: + note over ru: admin-state, power-state, oper-state,
availability-state, usage-state + + ru->>du: 11. RU notifies DU about the configuration change + + note over du: DU configures xran + + du->ru: 12. DU and RU exchange packets +``` + + +
+4x4 MIMO and 100MHz BW with Benetel 550 RU example run + +``` +[HW] [MPLANE] RPC request to RU "192.168.80.9" = with username "oranbenetel" and port ID "830". +[HW] [MPLANE] Successfuly connected to RU "192.168.80.9" with username "oranbenetel" and port ID "830". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = operational datastore. +[HW] [MPLANE] Successfully retrieved operational datastore from RU "192.168.80.9". +[HW] [MPLANE] RU is already PTP synchronized. +[HW] [MPLANE] RPC request to RU "192.168.80.9" = with stream "NETCONF" and filter "(null)". +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully subscribed to all notifications from RU "192.168.80.9". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = " +65535 +65535 +". +[HW] [MPLANE] Successfully updated supervision timer to (65535+65535)[s] for RU "192.168.80.9". +[HW] [MPLANE] Watchdog timer answer: + 2025-03-30T08:52:31+02:00 + +[HW] [MPLANE] Interface MTU 1500 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600. +[HW] [MPLANE] IQ bitwidth 16 unreliable/not correctly reported by Benetel O-RU, hardcoding to 9. +[HW] [MPLANE] Storing the following information to forward to xran: + RU MAC address 8c:1f:64:d1:11:c0 + MTU 9600 + IQ bitwidth 9 + PRACH offset 4 + DU port bitmask 61440 + Band sector bitmask 3840 + CC ID bitmask 240 + RU port ID bitmask 15 + DU port ID 0 + Band sector ID 0 + CC ID 0 + RU port ID 0 +[HW] [MPLANE] Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names. +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-yang-metadata". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "yang". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-inet-types". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-yang-types". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-yang-schema-mount". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-yang-structure-ext". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-datastores". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "sysrepo". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-netconf-acm". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-factory-default". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "sysrepo-factory-default". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-yang-library". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "sysrepo-monitoring". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "sysrepo-plugind". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-netconf". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-netconf-with-defaults". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-netconf-notifications". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-origin". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-netconf-monitoring". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-netconf-nmda". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "nc-notifications". +[HW] [MPLANE] [LIBYANG] ERROR: Data model "notifications" not found in local searchdirs. (path: (null)). +[HW] [MPLANE] [LIBYANG] ERROR: Loading "notifications" module failed. (path: (null)). +[HW] [MPLANE] [LIBYANG] ERROR: Parsing module "nc-notifications" failed. (path: (null)). +[HW] [MPLANE] Unable to load module "nc-notifications" from RU "192.168.80.9". +[HW] [MPLANE] Unable to load all yang modules from operational datastore for RU "192.168.80.9". Using yang models present in "models" subfolder. +[HW] [MPLANE] Successfully loaded all yang modules for RU "192.168.80.9". +[HW] [MPLANE] The VLAN tags for C and U plane for the RU "192.168.80.9" are the same. Therefore, configuring one common interface and one processing element. +[HW] [MPLANE] RPC request to RU "192.168.80.9" = : + + + INTERFACE_0 + ianaift:l2vlan + true + 8c:1f:64:d1:11:c0 + eth0 + 9 + + + + ETH-INTERFACE + + PLANE_0 + + INTERFACE_0 + + 8c:1f:64:d1:11:c0 + 9 + 00:11:22:33:44:66 + + + + + + + PdschLink0 + PLANE_0 + TxArray0 + LowLevelTxEndpoint0 + + + PdschLink1 + PLANE_0 + TxArray0 + LowLevelTxEndpoint1 + + + PdschLink2 + PLANE_0 + TxArray0 + LowLevelTxEndpoint2 + + + PdschLink3 + PLANE_0 + TxArray0 + LowLevelTxEndpoint3 + + + PuschLink0 + PLANE_0 + RxArray0 + LowLevelRxEndpoint0 + + + PrachLink0 + PLANE_0 + RxArray0 + LowLevelRxPrachEndpoint0 + + + PuschLink1 + PLANE_0 + RxArray0 + LowLevelRxEndpoint1 + + + PrachLink1 + PLANE_0 + RxArray0 + LowLevelRxPrachEndpoint1 + + + PuschLink2 + PLANE_0 + RxArray0 + LowLevelRxEndpoint2 + + + PrachLink2 + PLANE_0 + RxArray0 + LowLevelRxPrachEndpoint2 + + + PuschLink3 + PLANE_0 + RxArray0 + LowLevelRxEndpoint3 + + + PrachLink3 + PLANE_0 + RxArray0 + LowLevelRxPrachEndpoint3 + + + LowLevelTxEndpoint0 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 0 + + + + LowLevelTxEndpoint1 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 1 + + + + LowLevelTxEndpoint2 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 2 + + + + LowLevelTxEndpoint3 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 3 + + + + LowLevelRxEndpoint0 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 0 + + + + LowLevelRxPrachEndpoint0 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 4 + + + + LowLevelRxEndpoint1 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 1 + + + + LowLevelRxPrachEndpoint1 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 5 + + + + LowLevelRxEndpoint2 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 2 + + + + LowLevelRxPrachEndpoint2 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 6 + + + + LowLevelRxEndpoint3 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 3 + + + + LowLevelRxPrachEndpoint3 + + 9 + STATIC + + 0 + 0 + 0 + + 61440 + 3840 + 240 + 15 + 7 + + + + TxArray0 + 663360 + 3950400000 + 100000000 + ACTIVE + 0.0 + 0 + 0 + + + RxArray0 + 663360 + 3950400000 + 100000000 + ACTIVE + 0 + 0 + 0.0 + 0 + + + +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.80.9". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = candidate datastore. +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = candidate datastore. +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully commited CU-planes configuration into running datastore for RU "192.168.80.9". +[HW] [MPLANE] Usage state = "idle" for RU "192.168.80.9". +[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.049085102+00:00) +{ + "o-ran-uplane-conf:rx-array-carriers-state-change": { + "rx-array-carriers": [ + { + "name": "RxArray0", + "state": "BUSY" + } + ] + } +} + +[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.058136880+00:00) +{ + "o-ran-uplane-conf:tx-array-carriers-state-change": { + "tx-array-carriers": [ + { + "name": "TxArray0", + "state": "BUSY" + } + ] + } +} + +[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.078776163+00:00) +{ + "o-ran-uplane-conf:rx-array-carriers-state-change": { + "rx-array-carriers": [ + { + "name": "RxArray0", + "state": "READY" + } + ] + } +} + +[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.093039138+00:00) +{ + "o-ran-uplane-conf:tx-array-carriers-state-change": { + "tx-array-carriers": [ + { + "name": "TxArray0", + "state": "READY" + } + ] + } +} + +[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.452751936+00:00) +{ + "ietf-netconf-notifications:netconf-config-change": { + "changed-by": { + "username": "root", + "session-id": 0 + }, + "datastore": "running", + "edit": [ + { + "target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']", + "operation": "create" + }, + { + "target": "/ietf-interfaces:interfaces/interface[name='INTERFACE_0']/name", + "operation": "create" + }, +... +} + +[HW] [MPLANE] RU "192.168.80.9" is now ready. +``` +
+ + +Note: If you wish to run the fronthaul without M-plane, no need for recompilation, as the library `oran_fhlib_5g` already exists. +The only mandatory step is to link `oran_fhlib_5g` to `oai_transpro` library. +```bash +cd ~/openairinterface5g/cmake_targets/ran_build/build +rm liboai_transpro.so +ln -s liboran_fhlib_5g.so liboai_transpro.so +sudo ./nr-softmodem -O --thread-pool +``` + + # Contact in case of questions You can ask your question on the [mailing lists](https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/MailingList). From 7beb88425fc9b0dc200cb285c5b2649ad81ff258 Mon Sep 17 00:00:00 2001 From: Teodora Date: Mon, 3 Feb 2025 18:18:26 +0100 Subject: [PATCH 54/55] Use [HW] logging instead of [PHY] or [NR_PHY] --- radio/fhi_72/oaioran.c | 24 ++++++++++++------------ radio/fhi_72/oran-init.c | 2 +- radio/fhi_72/oran_isolate.c | 12 ++++++------ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 16dd2d85de..cbc530a785 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -90,7 +90,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) rx_sym = callback_tag->symbol & 0xFF; uint32_t ru_id = callback_tag->oXuId; - LOG_D(NR_PHY, + LOG_D(HW, "rx_callback frame %d, subframe %d, slot %d, second %lld, rx_sym %d ru_id %d\n", frame, subframe, @@ -127,7 +127,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) rx_RU[ru_id][slot2] = 1; if (last_frame > 0 && frame > 0 && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) - LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); + LOG_E(HW, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2); for (int i = 0; i < num_ports; i++) { if (rx_RU[i][slot2] == 0) return; @@ -142,16 +142,16 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) info->tti = tti; info->sl = slot2; info->f = frame; - LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); + LOG_D(HW, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot); pushNotifiedFIFO(&oran_sync_fifo, req); #else - LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + LOG_D(HW, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); oran_sync_info.tti = tti; oran_sync_info.sl = slot2; oran_sync_info.f = frame; #endif } else - LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); + LOG_E(HW, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot); last_slot = slot2; last_frame = frame; } // rx_sym == 7 @@ -289,7 +289,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) while ((f = pollNotifiedFIFO(&oran_sync_fifo)) != NULL) { oran_sync_info_t *old_info = NotifiedFifoData(res); oran_sync_info_t *new_info = NotifiedFifoData(f); - LOG_E(PHY, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl); + LOG_E(HW, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl); delNotifiedFIFO_elt(res); res = f; } @@ -305,14 +305,14 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) uint32_t tti_in = oran_sync_info.tti; static int last_slot = -1; - LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot); + LOG_D(HW, "oran slot %d, last_slot %d\n", *slot, last_slot); int cnt = 0; // while (*slot == last_slot) { while (tti_in == oran_sync_info.tti) { //*slot = oran_sync_info.sl; cnt++; } - LOG_D(PHY, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); + LOG_D(HW, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot); last_slot = *slot; #endif // return(0); @@ -380,9 +380,9 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) int16_t payload_len = 0; - LOG_D(PHY, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm); + LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm); for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) { - LOG_D(PHY, + LOG_D(HW, "prbMap[%d] : PRBstart %d nPRBs %d\n", idxElm, pRbMap->prbMap[idxElm].nRBStart, @@ -436,7 +436,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) } // vv_inf if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) { for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) { - LOG_I(NR_PHY, + LOG_I(HW, "[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n", "o-du ", o_xu_id, @@ -448,7 +448,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L, x_counters[o_xu_id].Total_msgs_rcvd); for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++) - LOG_I(NR_PHY, + LOG_I(HW, "[%s%d][pusch%d %7ld prach%d %7ld]\n", "o_du", o_xu_id, diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index 97930a172b..fd3fdaa5bf 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -443,7 +443,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi pi->prach_tag = tag; pi->pusch_tag = tag; #ifdef E_RELEASE - LOG_W(PHY, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n"); + LOG_W(HW, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n"); oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]); #elif defined F_RELEASE oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]); diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 3a63045817..0a200a39a0 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -214,11 +214,11 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) RU_proc_t *proc = &ru->proc; int f, sl; - LOG_D(PHY, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]); + LOG_D(HW, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]); start_meas(&ru->rx_fhaul); int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl); stop_meas(&ru->rx_fhaul); - LOG_D(PHY, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]); + LOG_D(HW, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]); if (ret != 0) { printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl); } @@ -231,7 +231,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { - LOG_E(PHY, + LOG_E(HW, "Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n", proc->frame_rx, proc->tti_rx, @@ -241,7 +241,7 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) } if (proc->frame_rx != *frame) { - LOG_E(PHY, + LOG_E(HW, "Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n", proc->frame_rx, proc->tti_rx, @@ -251,10 +251,10 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) } } else { proc->first_rx = 0; - LOG_I(PHY, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); + LOG_I(HW, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); *frame = proc->frame_rx; *slot = proc->tti_rx; - LOG_I(PHY, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); + LOG_I(HW, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx); } } From 321b1c4ce1ce6c606f259dfac4221013ac46e1be Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 18 Feb 2025 18:21:03 +0100 Subject: [PATCH 55/55] Increase maximum logging line length for in-memory log - Increase the maximum logging line for print done through log_output_memory(). The reason is that we hit this line length when printing some machine generated configuration (XML) through the M-plane. Increase to make more of it visible. - To limit the impact, only increase this locally in function log_output_memory(), and statically assert that it will never be larger than 64 kB. In other places, we use the old limit. - Move the definition MAX_LOG_TOTAL to log.c, because it's only used there. --- common/utils/LOG/log.c | 30 +++++++++++++++++++----------- common/utils/LOG/log.h | 6 ------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index 148da232ae..61003857ab 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -52,6 +52,13 @@ // main log variables +/** @defgroup _max_length Maximum Length of LOG + * @ingroup _macro + * @brief the macros that describe the maximum length of LOG + * @{*/ + +#define MAX_LOG_TOTAL 16384 /*!< \brief the maximum length of a log */ + // Fixme: a better place to be shure it is called void read_cpu_hardware (void) __attribute__ ((constructor)); #if !defined(__arm__) && !defined(__aarch64__) @@ -877,31 +884,32 @@ static void log_output_memory(log_component_t *c, const char *file, const char * * correctly. It was not a big problem because in practice MAX_LOG_TOTAL is * big enough so that the buffer is never full. */ - char log_buffer[MAX_LOG_TOTAL]; + static_assert(4 * MAX_LOG_TOTAL <= 65536, "log buffer limited to 64kB, please reduce MAX_LOG_TOTAL\n"); + char log_buffer[4 * MAX_LOG_TOTAL]; // make sure that for log trace the extra info is only printed once, reset when the level changes if (level < OAILOG_TRACE) { - int n = log_header(c, log_buffer+len, MAX_LOG_TOTAL, file, func, line, level); + int n = log_header(c, log_buffer+len, sizeof(log_buffer), file, func, line, level); if (n > 0) { len += n; - if (len > MAX_LOG_TOTAL) { - len = MAX_LOG_TOTAL; + if (len > sizeof(log_buffer)) { + len = sizeof(log_buffer); } } } - int n = vsnprintf(log_buffer+len, MAX_LOG_TOTAL-len, format, args); + int n = vsnprintf(log_buffer+len, sizeof(log_buffer)-len, format, args); if (n > 0) { len += n; - if (len > MAX_LOG_TOTAL) { - len = MAX_LOG_TOTAL; + if (len > sizeof(log_buffer)) { + len = sizeof(log_buffer); } } if (!((g_log->flag) & FLAG_NOCOLOR)) { - int n = snprintf(log_buffer+len, MAX_LOG_TOTAL-len, "%s", log_level_highlight_end[level]); + int n = snprintf(log_buffer+len, sizeof(log_buffer)-len, "%s", log_level_highlight_end[level]); if (n > 0) { len += n; - if (len > MAX_LOG_TOTAL) { - len = MAX_LOG_TOTAL; + if (len > sizeof(log_buffer)) { + len = sizeof(log_buffer); } } } @@ -941,7 +949,7 @@ static void log_output_memory(log_component_t *c, const char *file, const char * } } }else{ - AssertFatal(len >= 0 && len <= MAX_LOG_TOTAL, "Bad len %d\n", len); + AssertFatal(len >= 0 && len <= sizeof(log_buffer), "Bad len %d\n", len); if (write(fileno(c->stream), log_buffer, len)) {}; } } diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index d153a4aeaf..7b9b570a06 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -65,12 +65,6 @@ extern "C" { #endif -/** @defgroup _max_length Maximum Length of LOG - * @ingroup _macro - * @brief the macros that describe the maximum length of LOG - * @{*/ - -#define MAX_LOG_TOTAL 16384 /*!< \brief the maximum length of a log */ /** @}*/ /** @defgroup _log_level Message levels defined by LOG