mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
501 lines
20 KiB
C
501 lines
20 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
#include "ran_func_kpm_subs.h"
|
|
|
|
#include <search.h>
|
|
|
|
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
|
|
|
e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src)
|
|
{
|
|
e2_node_level_stats_t dst = {
|
|
.mac_stats.dl.total_prb_aggregate = src->mac_stats.dl.total_prb_aggregate,
|
|
.mac_stats.dl.used_prb_aggregate = src->mac_stats.dl.used_prb_aggregate,
|
|
.mac_stats.ul.total_prb_aggregate = src->mac_stats.ul.total_prb_aggregate,
|
|
.mac_stats.ul.used_prb_aggregate = src->mac_stats.ul.used_prb_aggregate,
|
|
};
|
|
|
|
return dst;
|
|
}
|
|
|
|
/* measurements that need to store values from previous reporting period have a limitation
|
|
when it comes to multiple subscriptions to the same UEs; ric_req_id is unique per subscription */
|
|
typedef struct uldlcounter {
|
|
uint32_t dl;
|
|
uint32_t ul;
|
|
} uldlcounter_t;
|
|
|
|
static uldlcounter_t last_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
|
|
|
|
static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id, const int rb_id)
|
|
{
|
|
nr_pdcp_statistics_t pdcp = {0};
|
|
const int srb_flag = 0;
|
|
|
|
// Get PDCP stats for specific DRB
|
|
const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp);
|
|
assert(rc == true && "Cannot get PDCP stats\n");
|
|
|
|
return pdcp;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.2.1.1.1
|
|
note: this measurement is calculated as per spec */
|
|
static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
const size_t ue_idx,
|
|
__attribute__((unused))e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
// Get PDCP stats per DRB
|
|
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
|
nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(ue_info.rrc_ue_id, rb_id);
|
|
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
// Get DL data volume delivered to PDCP layer
|
|
meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000000; // [Mb]
|
|
last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.2.1.2.1
|
|
note: this measurement is calculated as per spec */
|
|
static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
const size_t ue_idx,
|
|
__attribute__((unused))e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
// Get PDCP stats per DRB
|
|
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
|
nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(ue_info.rrc_ue_id, rb_id);
|
|
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
// Get UL data volume delivered from PDCP layer
|
|
meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000000; // [Mb]
|
|
last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
static long last_known_ss_rsrp_encoded = 0;
|
|
|
|
static meas_record_lst_t fill_L1M_SS_RSRP(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
__attribute__((unused)) cudu_ue_info_pair_t ue_info,
|
|
__attribute__((unused)) const size_t ue_idx,
|
|
__attribute__((unused)) e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
if (RC.nrrrc == NULL || RC.nrrrc[0] == NULL) {
|
|
LOG_W(NR_RRC, "[KPM] L1M.SS-RSRP: RRC not initialised, returning last-known\n");
|
|
goto emit;
|
|
}
|
|
if (RC.nrrrc[0]->rrc_ue_head.rbh_root == NULL) {
|
|
LOG_D(NR_RRC, "[KPM] L1M.SS-RSRP: no RRC-connected UEs, returning last-known\n");
|
|
goto emit;
|
|
}
|
|
|
|
uint64_t sum_encoded = 0;
|
|
uint32_t reporting_ues = 0;
|
|
struct rrc_gNB_ue_context_s *ue_ctx = NULL;
|
|
RB_FOREACH(ue_ctx, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
|
|
if (ue_ctx == NULL)
|
|
continue;
|
|
const NR_MeasResults_t *mr = ue_ctx->ue_context.measResults;
|
|
if (mr == NULL)
|
|
continue;
|
|
if (mr->measResultServingMOList.list.count == 0)
|
|
continue;
|
|
if (mr->measResultServingMOList.list.array == NULL)
|
|
continue;
|
|
const NR_MeasResultServMO_t *serv_mo = mr->measResultServingMOList.list.array[0];
|
|
if (serv_mo == NULL)
|
|
continue;
|
|
const struct NR_MeasResultNR__measResult__cellResults *cr =
|
|
&serv_mo->measResultServingCell.measResult.cellResults;
|
|
if (cr == NULL)
|
|
continue;
|
|
long encoded = 0;
|
|
if (cr->resultsSSB_Cell != NULL && cr->resultsSSB_Cell->rsrp != NULL) {
|
|
encoded = *(cr->resultsSSB_Cell->rsrp);
|
|
} else if (cr->resultsCSI_RS_Cell != NULL && cr->resultsCSI_RS_Cell->rsrp != NULL) {
|
|
encoded = *(cr->resultsCSI_RS_Cell->rsrp);
|
|
} else {
|
|
continue;
|
|
}
|
|
sum_encoded += (uint64_t)encoded;
|
|
reporting_ues++;
|
|
}
|
|
|
|
if (reporting_ues > 0) {
|
|
last_known_ss_rsrp_encoded = (long)((sum_encoded + reporting_ues / 2) / reporting_ues);
|
|
LOG_D(NR_RRC, "[KPM] L1M.SS-RSRP: cell-level mean over %u UE(s), encoded=%ld\n",
|
|
reporting_ues, last_known_ss_rsrp_encoded);
|
|
}
|
|
|
|
emit:;
|
|
|
|
if (last_known_ss_rsrp_encoded == 0) {
|
|
LOG_W(NR_RRC, "[KPM] L1M.SS-RSRP: no MeasurementReport received yet, returning 0\n");
|
|
meas_record.int_val = 0;
|
|
} else {
|
|
meas_record.int_val = last_known_ss_rsrp_encoded - 157;
|
|
}
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
static bool last_known_ss_sinr_valid = false;
|
|
static long last_known_ss_sinr_encoded = 0;
|
|
|
|
static meas_record_lst_t fill_MR_NRScSSSINR(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
__attribute__((unused)) cudu_ue_info_pair_t ue_info,
|
|
__attribute__((unused)) const size_t ue_idx,
|
|
__attribute__((unused)) e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
if (RC.nrrrc == NULL || RC.nrrrc[0] == NULL)
|
|
goto emit_sinr;
|
|
if (RC.nrrrc[0]->rrc_ue_head.rbh_root == NULL)
|
|
goto emit_sinr;
|
|
|
|
uint64_t sum_encoded = 0;
|
|
uint32_t reporting_ues = 0;
|
|
struct rrc_gNB_ue_context_s *ue_ctx = NULL;
|
|
RB_FOREACH(ue_ctx, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
|
|
if (ue_ctx == NULL)
|
|
continue;
|
|
const NR_MeasResults_t *mr = ue_ctx->ue_context.measResults;
|
|
if (mr == NULL)
|
|
continue;
|
|
if (mr->measResultServingMOList.list.count == 0)
|
|
continue;
|
|
if (mr->measResultServingMOList.list.array == NULL)
|
|
continue;
|
|
const NR_MeasResultServMO_t *serv_mo = mr->measResultServingMOList.list.array[0];
|
|
if (serv_mo == NULL)
|
|
continue;
|
|
const struct NR_MeasResultNR__measResult__cellResults *cr =
|
|
&serv_mo->measResultServingCell.measResult.cellResults;
|
|
if (cr == NULL)
|
|
continue;
|
|
long encoded = 0;
|
|
if (cr->resultsSSB_Cell != NULL && cr->resultsSSB_Cell->sinr != NULL) {
|
|
encoded = *(cr->resultsSSB_Cell->sinr);
|
|
} else if (cr->resultsCSI_RS_Cell != NULL && cr->resultsCSI_RS_Cell->sinr != NULL) {
|
|
encoded = *(cr->resultsCSI_RS_Cell->sinr);
|
|
} else {
|
|
continue;
|
|
}
|
|
sum_encoded += (uint64_t)encoded;
|
|
reporting_ues++;
|
|
}
|
|
|
|
if (reporting_ues > 0) {
|
|
last_known_ss_sinr_encoded = (long)((sum_encoded + reporting_ues / 2) / reporting_ues);
|
|
last_known_ss_sinr_valid = true;
|
|
LOG_D(NR_RRC, "[KPM] MR.NRScSSSINR: cell-level mean over %u UE(s), encoded=%ld\n",
|
|
reporting_ues, last_known_ss_sinr_encoded);
|
|
}
|
|
|
|
emit_sinr:;
|
|
|
|
if (!last_known_ss_sinr_valid) {
|
|
LOG_W(NR_RRC, "[KPM] MR.NRScSSSINR: no MeasurementReport received yet, returning -127\n");
|
|
meas_record.int_val = -127;
|
|
} else {
|
|
meas_record.int_val = (last_known_ss_sinr_encoded - 46) / 2;
|
|
}
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
static meas_record_lst_t fill_RRC_ConnMean(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
__attribute__((unused)) cudu_ue_info_pair_t ue_info,
|
|
__attribute__((unused)) const size_t ue_idx,
|
|
__attribute__((unused)) e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
int count = 0;
|
|
struct rrc_gNB_ue_context_s *ue_context_p = NULL;
|
|
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
|
|
count++;
|
|
}
|
|
meas_record.int_val = count;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
#if defined (NGRAN_GNB_DU)
|
|
static uldlcounter_t last_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
|
|
static uldlcounter_t last_total_prbs[MAX_MOBILES_PER_GNB] = {0};
|
|
|
|
static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb_id)
|
|
{
|
|
nr_rlc_statistics_t rlc = {0};
|
|
const int srb_flag = 0;
|
|
|
|
// Get RLC stats for specific DRB
|
|
const bool rc = nr_rlc_get_statistics(rnti, srb_flag, rb_id, &rlc);
|
|
assert(rc == true && "Cannot get RLC stats\n");
|
|
|
|
// Activate average sojourn time at the RLC buffer for specific DRB
|
|
nr_rlc_activate_avg_time_to_tx(rnti, rb_id+3, 1);
|
|
|
|
return rlc;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.3.3.3
|
|
note: by default this measurement is calculated for previous 100ms (openair2/LAYER2/nr_rlc/nr_rlc_entity.c:118, 173, 213); please, update according to your needs */
|
|
static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
__attribute__((unused))const size_t ue_idx,
|
|
__attribute__((unused))e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
// Get RLC stats per DRB
|
|
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
|
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id);
|
|
|
|
meas_record.value = REAL_MEAS_VALUE;
|
|
|
|
// Get the value of sojourn time at the RLC buffer
|
|
meas_record.real_val = rlc.txsdu_avg_time_to_tx; // [μs]
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.1.3.1
|
|
note: per spec, average UE throughput in DL (taken into consideration values from all UEs, and averaged)
|
|
here calculated as: UE specific throughput in DL */
|
|
static meas_record_lst_t fill_DRB_UEThpDl(__attribute__((unused)) const label_info_lst_t label,
|
|
uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
const size_t ue_idx,
|
|
__attribute__((unused))e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
|
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id);
|
|
meas_record.value = REAL_MEAS_VALUE;
|
|
|
|
// Calculate DL Thp
|
|
meas_record.real_val = (double)(rlc.txpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].dl)*8/gran_period_ms; // [kbps]
|
|
last_rlc_pdu_total_bytes[ue_idx].dl = rlc.txpdu_bytes;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.1.3.3
|
|
note: per spec, average UE throughput in UL (taken into consideration values from all UEs, and averaged)
|
|
here calculated as: UE specific throughput in UL */
|
|
static meas_record_lst_t fill_DRB_UEThpUl(__attribute__((unused)) const label_info_lst_t label,
|
|
uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
const size_t ue_idx,
|
|
__attribute__((unused))e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
// Get RLC stats per DRB
|
|
const int rb_id = 1; // at the moment, only 1 DRB is supported
|
|
nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(ue_info.ue->rnti, rb_id);
|
|
|
|
meas_record.value = REAL_MEAS_VALUE;
|
|
|
|
// Calculate UL Thp
|
|
meas_record.real_val = (double)(rlc.rxpdu_bytes - last_rlc_pdu_total_bytes[ue_idx].ul)*8/gran_period_ms; // [kbps]
|
|
last_rlc_pdu_total_bytes[ue_idx].ul = rlc.rxpdu_bytes;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.1.2.1
|
|
note: this measurement is calculated as per spec */
|
|
static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
const size_t ue_idx,
|
|
e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
// Get the number of DL PRBs
|
|
const uint64_t tot_prb_dl_aggr = node_stats[1].mac_stats.dl.total_prb_aggregate - node_stats[0].mac_stats.dl.total_prb_aggregate;
|
|
meas_record.int_val = (tot_prb_dl_aggr == 0) ? 0 : (ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl) * 100 / tot_prb_dl_aggr; // [%]
|
|
last_total_prbs[ue_idx].dl = ue_info.ue->mac_stats.dl.total_rbs;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
/* 3GPP TS 28.522 - section 5.1.1.2.2
|
|
note: this measurement is calculated as per spec */
|
|
static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused)) const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
cudu_ue_info_pair_t ue_info,
|
|
const size_t ue_idx,
|
|
e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {0};
|
|
|
|
meas_record.value = INTEGER_MEAS_VALUE;
|
|
|
|
// Get the number of UL PRBs
|
|
const uint64_t tot_prb_ul_aggr = node_stats[1].mac_stats.ul.total_prb_aggregate - node_stats[0].mac_stats.ul.total_prb_aggregate;
|
|
meas_record.int_val = (tot_prb_ul_aggr == 0) ? 0 : (ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul) * 100 / tot_prb_ul_aggr; // [%]
|
|
last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs;
|
|
|
|
return meas_record;
|
|
}
|
|
|
|
/* 3GPP TS 28.552 - section 5.1.1.12.1*/
|
|
static meas_record_lst_t fill_CARR_PDSCHMCSDist(const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
__attribute__((unused)) cudu_ue_info_pair_t ue_info,
|
|
__attribute__((unused)) const size_t ue_idx,
|
|
__attribute__((unused))e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {.value = INTEGER_MEAS_VALUE};
|
|
|
|
if (RC.nrmac == NULL || RC.nrmac[0] == NULL) {
|
|
meas_record.int_val = 0;
|
|
return meas_record;
|
|
}
|
|
NR_du_stats_t* du_stats = &RC.nrmac[0]->du_stats;
|
|
|
|
if (label.distBinX != NULL && label.distBinY != NULL && label.distBinZ != NULL) {
|
|
uint32_t bin_x = *label.distBinX, bin_y = *label.distBinY, bin_z = *label.distBinZ;
|
|
if (bin_x >= 1 && bin_x <= 8 && bin_y >= 1 && bin_y <= 3 && bin_z <= 31) {
|
|
meas_record.int_val = du_stats->pdsch_mcs_dist[bin_x - 1][bin_y - 1][bin_z];
|
|
} else {
|
|
printf("[E2 AGENT] Unknown binX %d, binY %d, binZ %d for \"CARR.PDSCHMCSDist\" measurement\n", bin_x, bin_y, bin_z);
|
|
meas_record.int_val = 0;
|
|
}
|
|
return meas_record;
|
|
}
|
|
|
|
uint64_t weighted_sum = 0;
|
|
uint64_t total_count = 0;
|
|
for (int x = 0; x < 8; x++) {
|
|
for (int y = 0; y < 3; y++) {
|
|
for (int z = 0; z < 28; z++) {
|
|
uint64_t c = du_stats->pdsch_mcs_dist[x][y][z];
|
|
weighted_sum += (uint64_t)z * c;
|
|
total_count += c;
|
|
}
|
|
}
|
|
}
|
|
meas_record.int_val = (total_count > 0) ? (long)(weighted_sum / total_count) : 0;
|
|
return meas_record;
|
|
}
|
|
|
|
static meas_record_lst_t fill_CARR_PUSCHMCSDist(const label_info_lst_t label,
|
|
__attribute__((unused)) uint32_t gran_period_ms,
|
|
__attribute__((unused)) cudu_ue_info_pair_t ue_info,
|
|
__attribute__((unused)) const size_t ue_idx,
|
|
__attribute__((unused)) e2_node_level_stats_t* node_stats)
|
|
{
|
|
meas_record_lst_t meas_record = {.value = INTEGER_MEAS_VALUE};
|
|
|
|
if (RC.nrmac == NULL || RC.nrmac[0] == NULL) {
|
|
meas_record.int_val = 0;
|
|
return meas_record;
|
|
}
|
|
NR_du_stats_t* du_stats = &RC.nrmac[0]->du_stats;
|
|
|
|
if (label.distBinX != NULL && label.distBinY != NULL && label.distBinZ != NULL) {
|
|
uint32_t bin_x = *label.distBinX, bin_y = *label.distBinY, bin_z = *label.distBinZ;
|
|
|
|
if (bin_x >= 1 && bin_x <= 8 && bin_y >= 1 && bin_y <= 2 && bin_z <= 31) {
|
|
meas_record.int_val = du_stats->pusch_mcs_dist[bin_x - 1][bin_y - 1][bin_z];
|
|
} else {
|
|
printf("[E2 AGENT] Unknown binX %d, binY %d, binZ %d for \"CARR.PUSCHMCSDist\" measurement\n", bin_x, bin_y, bin_z);
|
|
meas_record.int_val = 0;
|
|
}
|
|
return meas_record;
|
|
}
|
|
|
|
uint64_t weighted_sum = 0;
|
|
uint64_t total_count = 0;
|
|
for (int x = 0; x < 8; x++) {
|
|
for (int y = 0; y < 2; y++) {
|
|
for (int z = 0; z < 28; z++) { /* exclude MCS 28..31 (retx) */
|
|
uint64_t c = du_stats->pusch_mcs_dist[x][y][z];
|
|
weighted_sum += (uint64_t)z * c;
|
|
total_count += c;
|
|
}
|
|
}
|
|
}
|
|
meas_record.int_val = (total_count > 0) ? (long)(weighted_sum / total_count) : 0;
|
|
return meas_record;
|
|
}
|
|
#endif
|
|
|
|
static kv_measure_t lst_measure[] = {
|
|
{.key = "DRB.PdcpSduVolumeDL", .value = fill_DRB_PdcpSduVolumeDL },
|
|
{.key = "DRB.PdcpSduVolumeUL", .value = fill_DRB_PdcpSduVolumeUL },
|
|
{.key = "L1M.SS-RSRP", .value = fill_L1M_SS_RSRP },
|
|
{.key = "MR.NRScSSSINR", .value = fill_MR_NRScSSSINR },
|
|
{.key = "RRC.ConnMean", .value = fill_RRC_ConnMean },
|
|
#if defined (NGRAN_GNB_DU)
|
|
{.key = "DRB.RlcSduDelayDl", .value = fill_DRB_RlcSduDelayDl },
|
|
{.key = "DRB.UEThpDl", .value = fill_DRB_UEThpDl },
|
|
{.key = "DRB.UEThpUl", .value = fill_DRB_UEThpUl },
|
|
{.key = "RRU.PrbTotDl", .value = fill_RRU_PrbTotDl },
|
|
{.key = "RRU.PrbTotUl", .value = fill_RRU_PrbTotUl },
|
|
{.key = "CARR.PDSCHMCSDist", .value = fill_CARR_PDSCHMCSDist },
|
|
{.key = "CARR.PUSCHMCSDist", .value = fill_CARR_PUSCHMCSDist },
|
|
#endif
|
|
};
|
|
|
|
void init_kpm_subs_data(void)
|
|
{
|
|
const size_t ht_len = sizeof(lst_measure) / sizeof(lst_measure[0]);
|
|
hcreate(ht_len);
|
|
|
|
ENTRY kv_pair;
|
|
|
|
for (size_t i = 0; i < ht_len; i++) {
|
|
kv_pair.key = lst_measure[i].key;
|
|
kv_pair.data = &lst_measure[i];
|
|
hsearch(kv_pair, ENTER);
|
|
}
|
|
}
|
|
|
|
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, const label_info_lst_t label, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats)
|
|
{
|
|
assert(kpm_meas_name != NULL);
|
|
|
|
ENTRY search_entry = {.key = kpm_meas_name};
|
|
ENTRY *found_entry = hsearch(search_entry, FIND);
|
|
assert(found_entry != NULL && "Unsupported KPM measurement name");
|
|
|
|
kv_measure_t *kv_found = (kv_measure_t *)found_entry->data;
|
|
meas_record_lst_t meas_record = kv_found->value(label, gran_period_ms, ue_info, ue_idx, node_stats);
|
|
|
|
return meas_record;
|
|
}
|