ran_func_kpm.c 29.5 KB
Newer Older
1
#include "ran_func_kpm.h"
2 3 4 5 6 7 8 9 10
#include "openair2/E2AP/flexric/test/rnd/fill_rnd_data_kpm.h"
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
#include "openair3/NGAP/ngap_gNB_ue_context.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_entity.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
11
#include "openair2/F1AP/f1ap_ids.h"
12 13 14
#include <assert.h>
#include <stdio.h>

15 16 17 18 19 20 21

typedef struct {
    NR_UE_info_t *ue_list;
    size_t num_ues;
} matched_ues_mac_t;


22
static
23
matched_ues_mac_t filter_ues_by_s_nssai_in_du_or_monolithic(test_cond_e const condition, int64_t const value)
24
{
25 26 27 28 29
  matched_ues_mac_t matched_ues = {.num_ues = 0, .ue_list = calloc(MAX_MOBILES_PER_GNB, sizeof(NR_UE_info_t)) };
  assert(matched_ues.ue_list != NULL && "Memory exhausted");

  /* IMPORTANT: in the case of gNB-DU, it is not possible to filter UEs by S-NSSAI as the ngap context is stored in gNB-CU
                instead, we take all connected UEs*/
30

31 32 33 34
  // Take MAC info
  UE_iterator(RC.nrmac[0]->UE_info.list, ue)
  {
    if (ue)
35
    {
36 37 38 39
      ngap_gNB_ue_context_t *ngap_ue_context_list = NULL;

      // Filter connected UEs by S-NSSAI test condition to get list of matched UEs 
      // note: not possible to filter 
40
      switch (condition)
41 42 43 44 45
      {
      case EQUAL_TEST_COND:
      {
        if (NODE_IS_MONOLITHIC(RC.nrrrc[0]->node_type))
        {
46
          rrc_gNB_ue_context_t *rrc_ue_context_list = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], ue->rnti);
47 48 49 50 51 52 53 54 55 56 57 58 59
          ngap_ue_context_list = ngap_get_ue_context(rrc_ue_context_list->ue_context.rrc_ue_id);
          assert(ngap_ue_context_list->gNB_instance[0].s_nssai[0][0].sST == value && "Please, check the condition for S-NSSAI. At the moment, OAI supports eMBB");
        }
          matched_ues.ue_list[matched_ues.num_ues] = *ue;
          matched_ues.num_ues++;
          break;
        }
      
    
      default:
        assert(false && "Condition not yet implemented");
      }
      
60 61 62
    }    
  }

63 64 65
  assert(matched_ues.num_ues >= 1 && "The number of filtered UEs must be at least equal to 1");

  return matched_ues;
66 67
}

68 69 70 71 72 73 74

typedef struct {
  f1_ue_data_t * rrc_ue_id_list;  // list of matched UEs on RRC level containing only rrc_ue_id (gNB CU UE ID)
  size_t num_ues;

} matched_ues_rrc_t;

75
static
76
matched_ues_rrc_t filter_ues_by_s_nssai_in_cu(test_cond_e const condition, int64_t const value)
77
{
78 79
  matched_ues_rrc_t matched_ues = {.num_ues = 0, .rrc_ue_id_list = calloc(MAX_MOBILES_PER_GNB, sizeof(f1_ue_data_t)) };
  assert(matched_ues.rrc_ue_id_list != NULL && "Memory exhausted");
80 81


82 83 84 85 86 87
  struct rrc_gNB_ue_context_s *ue_context_p1 = NULL;
  RB_FOREACH(ue_context_p1, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
    
    ngap_gNB_ue_context_t *ngap_ue_context_list = ngap_get_ue_context(ue_context_p1->ue_context.rrc_ue_id);
    
    // Filter connected UEs by S-NSSAI test condition to get list of matched UEs 
88
    switch (condition)
89
    {
90 91 92 93 94 95 96 97 98
    case EQUAL_TEST_COND:
      assert(ngap_ue_context_list->gNB_instance[0].s_nssai[0][0].sST == value && "Please, check the condition for S-NSSAI. At the moment, OAI supports eMBB");
      matched_ues.rrc_ue_id_list[matched_ues.num_ues].secondary_ue = ue_context_p1->ue_context.rrc_ue_id;
      matched_ues.num_ues++;
      break;
    
    default:
      assert(false && "Condition not yet implemented");
    }
99
  }
100 101 102 103
  
  assert(matched_ues.num_ues >= 1 && "The number of filtered UEs must be at least equal to 1");
  
  return matched_ues;
104 105 106
}

static
107
nr_rlc_statistics_t get_rlc_stats_per_drb(NR_UE_info_t const * UE)
108 109 110 111 112
{
  assert(UE != NULL);

  nr_rlc_statistics_t rlc = {0};
  const int srb_flag = 0;
113
  const int rb_id = 1;  // at the moment, only 1 DRB is supported
114 115 116 117 118 119 120 121 122 123 124 125

  // Get RLC stats for specific DRB
  const bool rc = nr_rlc_get_statistics(UE->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(UE->rnti, rb_id+3, 1);
  
  return rlc;  
}

static
126
nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id)
127 128 129
{
  nr_pdcp_statistics_t pdcp = {0};
  const int srb_flag = 0;
130
  const int rb_id = 1;  // at the moment, only 1 DRB is supported
131 132

  // Get PDCP stats for specific DRB
133
  const bool rc = nr_pdcp_get_statistics(rrc_ue_id, srb_flag, rb_id, &pdcp);
134 135 136 137 138
  assert(rc == true && "Cannot get PDCP stats\n");

  return pdcp;
}

139
static 
140
gnb_e2sm_t fill_gnb_data(rrc_gNB_ue_context_t * ue_context_p)
141 142 143 144 145 146
{
  gnb_e2sm_t gnb = {0};

  // 6.2.3.16
  // Mandatory
  // AMF UE NGAP ID
147
  gnb.amf_ue_ngap_id = ue_context_p->ue_context.rrc_ue_id;
148 149 150

  // Mandatory
  //GUAMI 6.2.3.17 
151 152 153 154 155
  gnb.guami.plmn_id = (e2sm_plmn_t) {
                                    .mcc = ue_context_p->ue_context.ue_guami.mcc,
                                    .mnc = ue_context_p->ue_context.ue_guami.mnc,
                                    .mnc_digit_len = ue_context_p->ue_context.ue_guami.mnc_len
                                    };
156
  
157 158 159
  gnb.guami.amf_region_id = ue_context_p->ue_context.ue_guami.amf_region_id;
  gnb.guami.amf_set_id = ue_context_p->ue_context.ue_guami.amf_set_id;
  gnb.guami.amf_ptr = ue_context_p->ue_context.ue_guami.amf_pointer;
160

Teodora's avatar
Teodora committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
  // gNB-CU UE F1AP ID List
  // C-ifCUDUseparated 
  if (NODE_IS_CU(RC.nrrrc[0]->node_type))
  {
    gnb.gnb_cu_ue_f1ap_lst_len = 1;
    gnb.gnb_cu_ue_f1ap_lst = calloc(gnb.gnb_cu_ue_f1ap_lst_len, sizeof(uint32_t));
    assert(gnb.gnb_cu_ue_f1ap_lst != NULL);

    for (size_t i = 0; i < gnb.gnb_cu_ue_f1ap_lst_len; i++)
    {
      gnb.gnb_cu_ue_f1ap_lst[i] = ue_context_p->ue_context.rrc_ue_id;
    }
  }


176 177 178
  return gnb;
}

179 180
static
gnb_du_e2sm_t fill_gnb_du_data(const f1_ue_data_t * rrc_ue_id)
181
{
182
  gnb_du_e2sm_t gnb_du = {0};
183

184 185 186 187 188 189 190 191 192 193
  // 6.2.3.21
  // gNB CU UE F1AP
  // Mandatory
  gnb_du.gnb_cu_ue_f1ap = rrc_ue_id->secondary_ue;


  // 6.2.3.25
  // RAN UE ID
  // Optional
  gnb_du.ran_ue_id = NULL;
194

195
  return gnb_du;
196 197
}

198 199 200 201 202 203 204 205
// Bad bad bad. Create a proper exponential moving average filter or at least, only read statistics
// Avoid coupling among sublayers
static uint32_t last_dl_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_ul_rlc_pdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_dl_total_prbs[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_ul_total_prbs[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_dl_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
static uint32_t last_ul_pdcp_sdu_total_bytes[MAX_MOBILES_PER_GNB] = {0};
206

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348

static
meas_record_lst_t fill_ue_mac_rlc_data(const NR_UE_info_t* UE, const size_t ue_idx, const char * meas_info_name_str, const uint32_t gran_period_ms)
{
  assert(UE != NULL);

  meas_record_lst_t meas_record = {0};

  // Get RLC stats per DRB
  nr_rlc_statistics_t rlc = get_rlc_stats_per_drb(UE);

  // Measurement Type as requested in Action Definition
  if (strcmp(meas_info_name_str, "DRB.UEThpDl") == 0)  //  3GPP TS 28.522 - section 5.1.1.3.1
  {
    meas_record.value = REAL_MEAS_VALUE;

    // Calculate DL Thp
    meas_record.real_val = (double)(rlc.txpdu_bytes - last_dl_rlc_pdu_total_bytes[ue_idx])*8/gran_period_ms;  // [kbps]
    last_dl_rlc_pdu_total_bytes[ue_idx] = rlc.txpdu_bytes;
    /*  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 */
  }
  else if (strcmp(meas_info_name_str, "DRB.UEThpUl") == 0)   //  3GPP TS 28.522 - section 5.1.1.3.3
  {
    meas_record.value = REAL_MEAS_VALUE;

    // Calculate UL Thp
    meas_record.real_val = (double)(rlc.rxpdu_bytes - last_ul_rlc_pdu_total_bytes[ue_idx])*8/gran_period_ms;  // [kbps]
    last_ul_rlc_pdu_total_bytes[ue_idx] = rlc.rxpdu_bytes;
    /*  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 */
  }
  else if (strcmp(meas_info_name_str, "DRB.RlcSduDelayDl") == 0)   //  3GPP TS 28.522 - section 5.1.3.3.3
  {
    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]
    /* 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 */
  }
  else if (strcmp(meas_info_name_str, "RRU.PrbTotDl") == 0)   //  3GPP TS 28.522 - section 5.1.1.2.1
  {
    meas_record.value = INTEGER_MEAS_VALUE;

    // Get the number of DL PRBs
    meas_record.int_val = UE->mac_stats.dl.total_rbs - last_dl_total_prbs[ue_idx];   // [PRBs]
    last_dl_total_prbs[ue_idx] = UE->mac_stats.dl.total_rbs;
    /*  note: per spec, DL PRB usage [%] = (total used PRBs for DL traffic / total available PRBs for DL traffic) * 100   
        here calculated as: aggregated DL PRBs (t) - aggregated DL PRBs (t-gran_period) */
  }
  else if (strcmp(meas_info_name_str, "RRU.PrbTotUl") == 0)   //  3GPP TS 28.522 - section 5.1.1.2.2
  {
    meas_record.value = INTEGER_MEAS_VALUE;

    // Get the number of UL PRBs
    meas_record.int_val = UE->mac_stats.ul.total_rbs - last_ul_total_prbs[ue_idx];   // [PRBs]
    last_ul_total_prbs[ue_idx] = UE->mac_stats.ul.total_rbs;
    /*  note: per spec, UL PRB usage [%] = (total used PRBs for UL traffic / total available PRBs for UL traffic) * 100   
        here calculated as: aggregated UL PRBs (t) - aggregated UL PRBs (t-gran_period) */
  }
  else
  {
    assert(false && "Measurement Name not yet implemented");
  }
  

  return meas_record;
}

static
meas_record_lst_t fill_ue_pdcp_data(const uint32_t rrc_ue_id, const size_t ue_idx, const char * meas_info_name_str)
{
  meas_record_lst_t meas_record = {0};

  // Get PDCP stats per DRB
  nr_pdcp_statistics_t pdcp = get_pdcp_stats_per_drb(rrc_ue_id);

  // Measurement Type as requested in Action Definition
  if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0)   //  3GPP TS 28.522 - section 5.1.2.1.1.1
  {
    meas_record.value = INTEGER_MEAS_VALUE;

    // Get DL data volume delivered to PDCP layer
    meas_record.int_val = (pdcp.rxsdu_bytes - last_dl_pdcp_sdu_total_bytes[ue_idx])*8/1000;   // [kb]
    last_dl_pdcp_sdu_total_bytes[ue_idx] = pdcp.rxsdu_bytes;
    /* note: this measurement is calculated as per spec */
  }
  else if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0)   //  3GPP TS 28.522 - section 5.1.2.1.2.1
  {
    meas_record.value = INTEGER_MEAS_VALUE;

    // Get UL data volume delivered from PDCP layer
    meas_record.int_val = (pdcp.txsdu_bytes - last_ul_pdcp_sdu_total_bytes[ue_idx])*8/1000;   // [kb]
    last_ul_pdcp_sdu_total_bytes[ue_idx] = pdcp.txsdu_bytes;
    /* note: this measurement is calculated as per spec */
  }
  else
  {
    assert(false && "Measurement Name not yet implemented");
  }
  

  return meas_record;
}

static
meas_info_format_1_lst_t * fill_kpm_meas_info_frm_1(const size_t len, const kpm_act_def_format_1_t * act_def_fr_1)
{
  meas_info_format_1_lst_t * meas_info_lst = calloc(len, sizeof(meas_info_format_1_lst_t));
  assert(meas_info_lst != NULL && "Memory exhausted" );

  // Get measInfo from action definition
  for (size_t i = 0; i < len; i++)
  {
    // Measurement Type
    meas_info_lst[i].meas_type.type = act_def_fr_1->meas_info_lst[i].meas_type.type;
    // Measurement Name
    if (act_def_fr_1->meas_info_lst[i].meas_type.type == NAME_MEAS_TYPE) {
      meas_info_lst[i].meas_type.name.buf = calloc(act_def_fr_1->meas_info_lst[i].meas_type.name.len, sizeof(uint8_t));
      memcpy(meas_info_lst[i].meas_type.name.buf, act_def_fr_1->meas_info_lst[i].meas_type.name.buf, act_def_fr_1->meas_info_lst[i].meas_type.name.len);
      meas_info_lst[i].meas_type.name.len = act_def_fr_1->meas_info_lst[i].meas_type.name.len;
    } else {
      meas_info_lst[i].meas_type.id = act_def_fr_1->meas_info_lst[i].meas_type.id;
    }


    // Label Information
    meas_info_lst[i].label_info_lst_len = 1;
    meas_info_lst[i].label_info_lst = calloc(meas_info_lst[i].label_info_lst_len, sizeof(label_info_lst_t));
    assert(meas_info_lst[i].label_info_lst != NULL && "Memory exhausted" );

    for (size_t j = 0; j < meas_info_lst[i].label_info_lst_len; j++) {
      meas_info_lst[i].label_info_lst[j].noLabel = malloc(sizeof(enum_value_e));
      *meas_info_lst[i].label_info_lst[j].noLabel = TRUE_ENUM_VALUE;
    }
  }

  return meas_info_lst;
}

static
kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_du(const NR_UE_info_t* UE, const size_t ue_idx,  const kpm_act_def_format_1_t * act_def_fr_1)
349 350
{
  kpm_ind_msg_format_1_t msg_frm_1 = {0};
351 352 353 354 355
  
  // Measurement Data contains a set of Meas Records, each collected at each granularity period
  msg_frm_1.meas_data_lst_len = 1;  /*  this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms)
                                        please, check their values in xApp */
  
356 357 358
  msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
  assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );

359 360
  for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++)
  {
361
    // Measurement Record
362
    msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len;  // record data list length corresponds to info list length from action definition
363

364 365
    msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
    assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");
366

367
    for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++)  // each meas record corresponds to one meas type
368 369
    {
      // Measurement Type as requested in Action Definition
370
      switch (act_def_fr_1->meas_info_lst[j].meas_type.type)
371 372 373
      {
      case NAME_MEAS_TYPE:
      {
374 375 376
        char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
        memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
        meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';
377

378
        msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms);
379 380 381 382 383 384 385 386 387 388 389
        break;
      }
      
      case ID_MEAS_TYPE:
        assert(false && "ID Measurement Type not yet implemented");
        break;

      default:
        assert(false && "Measurement Type not recognized");
        break;
      }
390 391 392 393 394

    }
  }

  // Measurement Information - OPTIONAL
395
  msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
396
  msg_frm_1.meas_info_lst = fill_kpm_meas_info_frm_1(msg_frm_1.meas_info_lst_len, act_def_fr_1);
397

398 399
  return msg_frm_1;
}
400

401 402 403 404
static
kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_du(const matched_ues_mac_t matched_ues, const kpm_act_def_format_1_t * act_def_fr_1)
{
  assert(act_def_fr_1 != NULL);
405 406


407
  kpm_ind_msg_format_3_t msg_frm_3 = {0};
408

409 410 411 412 413
  // Fill UE Measurement Reports
  
  msg_frm_3.ue_meas_report_lst_len = matched_ues.num_ues;
  msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
  assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");
414

415 416 417 418 419 420 421 422 423 424
  for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++)
  {
    // Fill UE ID data
    f1_ue_data_t rrc_ue_id = du_get_f1_ue_data(matched_ues.ue_list[i].rnti);  // get gNB CU UE ID as rrc_ue_id
    msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_DU_UE_ID_E2SM;
    msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb_du = fill_gnb_du_data(&rrc_ue_id);
      
    // Fill UE related info
    msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_du(&matched_ues.ue_list[i], i, act_def_fr_1);
  }
425

426 427 428

  return msg_frm_3;
}
429 430

static
431
kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_cu(const uint32_t rrc_ue_id, const size_t ue_idx, const kpm_act_def_format_1_t * act_def_fr_1)
432
{
433
  kpm_ind_msg_format_1_t msg_frm_1 = {0};
434
  
435 436 437
  // Measurement Data contains a set of Meas Records, each collected at each granularity period
  msg_frm_1.meas_data_lst_len = 1;  /*  this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms)
                                        please, check their values in xApp */
438
  
439 440 441 442
  msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
  assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );

  for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++)
443
  {
444 445
    // Measurement Record
    msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len;  // record data list length corresponds to info list length from action definition
446

447 448 449 450
    msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
    assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");

    for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++)  // each meas record corresponds to one meas type
451
    {
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
      // Measurement Type as requested in Action Definition
      switch (act_def_fr_1->meas_info_lst[j].meas_type.type)
      {
      case NAME_MEAS_TYPE:
      {
        char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
        memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
        meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';

        msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str);
        break;
      }
      
      case ID_MEAS_TYPE:
        assert(false && "ID Measurement Type not yet implemented");
        break;

      default:
        assert(false && "Measurement Type not recognized");
        break;
      }

474 475 476
    }
  }

477 478 479 480 481
  // Measurement Information - OPTIONAL
  msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
  msg_frm_1.meas_info_lst = fill_kpm_meas_info_frm_1(msg_frm_1.meas_info_lst_len, act_def_fr_1);

  return msg_frm_1;
482 483 484
}

static
485
kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_cu(const matched_ues_rrc_t matched_ues, const kpm_act_def_format_1_t * act_def_fr_1)
486
{
487 488 489
  assert(act_def_fr_1 != NULL);


490
  kpm_ind_msg_format_3_t msg_frm_3 = {0};
491

492 493 494 495 496 497 498 499 500
  // Fill UE Measurement Reports
  
  msg_frm_3.ue_meas_report_lst_len = matched_ues.num_ues;
  msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
  assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");

  for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++)
  {
    // Fill UE ID data
Teodora's avatar
Teodora committed
501 502 503
    rrc_gNB_ue_context_t *rrc_ue_context_list = rrc_gNB_get_ue_context(RC.nrrrc[0], matched_ues.rrc_ue_id_list[i].secondary_ue);
    msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM;
    msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list);
504

505 506 507
    // Fill UE related info
    msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_cu(matched_ues.rrc_ue_id_list[i].secondary_ue, i, act_def_fr_1);
  }
508

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
  return msg_frm_3;
}

static
kpm_ind_msg_format_1_t fill_kpm_ind_msg_frm_1_in_monolithic(const NR_UE_info_t* UE, const size_t ue_idx, const uint32_t rrc_ue_id, const kpm_act_def_format_1_t * act_def_fr_1)
{
  kpm_ind_msg_format_1_t msg_frm_1 = {0};
  
  // Measurement Data contains a set of Meas Records, each collected at each granularity period
  msg_frm_1.meas_data_lst_len = 1;  /*  this value is equal to (kpm_ric_event_trigger_format_1.report_period_ms/act_def_fr_1->gran_period_ms)
                                        please, check their values in xApp */
  
  msg_frm_1.meas_data_lst = calloc(msg_frm_1.meas_data_lst_len, sizeof(*msg_frm_1.meas_data_lst));
  assert(msg_frm_1.meas_data_lst != NULL && "Memory exhausted" );

  for (size_t i = 0; i<msg_frm_1.meas_data_lst_len; i++)
  {
    // Measurement Record
    msg_frm_1.meas_data_lst[i].meas_record_len = act_def_fr_1->meas_info_lst_len;  // record data list length corresponds to info list length from action definition

    msg_frm_1.meas_data_lst[i].meas_record_lst = calloc(msg_frm_1.meas_data_lst[i].meas_record_len, sizeof(meas_record_lst_t));
    assert(msg_frm_1.meas_data_lst[i].meas_record_lst != NULL && "Memory exhausted");
531

532
    for (size_t j = 0; j < msg_frm_1.meas_data_lst[i].meas_record_len; j++)  // each meas record corresponds to one meas type
533
    {
534 535
      // Measurement Type as requested in Action Definition
      switch (act_def_fr_1->meas_info_lst[j].meas_type.type)
536
      {
537 538 539 540 541 542 543 544 545 546 547 548 549 550
      case NAME_MEAS_TYPE:
      {
        char meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len + 1];
        memcpy(meas_info_name_str, act_def_fr_1->meas_info_lst[j].meas_type.name.buf, act_def_fr_1->meas_info_lst[j].meas_type.name.len);
        meas_info_name_str[act_def_fr_1->meas_info_lst[j].meas_type.name.len] = '\0';

        if (strcmp(meas_info_name_str, "DRB.PdcpSduVolumeDL") == 0 || strcmp(meas_info_name_str, "DRB.PdcpSduVolumeUL") == 0)
        {
          msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_pdcp_data(rrc_ue_id, ue_idx, meas_info_name_str);
        }
        else
        {
          msg_frm_1.meas_data_lst[i].meas_record_lst[j] = fill_ue_mac_rlc_data(UE, ue_idx, meas_info_name_str, act_def_fr_1->gran_period_ms);
        }
551 552 553
        
        break;
      }
554 555 556 557
      
      case ID_MEAS_TYPE:
        assert(false && "ID Measurement Type not yet implemented");
        break;
558

559 560 561 562
      default:
        assert(false && "Measurement Type not recognized");
        break;
      } 
563
    }
564
  }
565

566 567 568
  // Measurement Information - OPTIONAL
  msg_frm_1.meas_info_lst_len = act_def_fr_1->meas_info_lst_len;
  msg_frm_1.meas_info_lst = fill_kpm_meas_info_frm_1(msg_frm_1.meas_info_lst_len, act_def_fr_1);
569

570

571 572 573 574 575 576 577 578 579 580 581 582
  return msg_frm_1;
}

static
kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3_in_monolithic(const matched_ues_mac_t matched_ues, const kpm_act_def_format_1_t * act_def_fr_1)
{
  assert(act_def_fr_1 != NULL);


  kpm_ind_msg_format_3_t msg_frm_3 = {0};

  // Fill UE Measurement Reports
583
  
584 585 586 587 588 589 590 591
  msg_frm_3.ue_meas_report_lst_len = matched_ues.num_ues;
  msg_frm_3.meas_report_per_ue = calloc(msg_frm_3.ue_meas_report_lst_len, sizeof(meas_report_per_ue_t));
  assert(msg_frm_3.meas_report_per_ue != NULL && "Memory exhausted");


  for (size_t i = 0; i<msg_frm_3.ue_meas_report_lst_len; i++)
  {
    // Fill UE ID data
592
    rrc_gNB_ue_context_t *rrc_ue_context_list = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], matched_ues.ue_list[i].rnti);
593 594 595 596 597 598 599
    msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.type = GNB_UE_ID_E2SM;
    msg_frm_3.meas_report_per_ue[i].ue_meas_report_lst.gnb = fill_gnb_data(rrc_ue_context_list);
      
    // Fill UE related info
    msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1_in_monolithic(&matched_ues.ue_list[i], i, rrc_ue_context_list->ue_context.rrc_ue_id, act_def_fr_1);
  }

600 601 602
  return msg_frm_3;
}

603 604
static
kpm_ric_ind_hdr_format_1_t kpm_ind_hdr_frm_1(void)
605 606 607
{
  kpm_ric_ind_hdr_format_1_t hdr_frm_1 = {0};

608 609 610 611 612 613 614 615 616
  int64_t const t = time_now_us();
#if defined KPM_V2
  hdr_frm_1.collectStartTime = t/1000000; // seconds
#elif defined KPM_V3 
  hdr_frm_1.collectStartTime = t; // microseconds
#else
  static_assert(0!=0, "Undefined KPM SM Version");
#endif

617
  hdr_frm_1.fileformat_version = NULL;
618 619 620 621 622 623 624 625

  // Check E2 Node NG-RAN Type
  if (NODE_IS_DU(RC.nrrrc[0]->node_type))
  {
    hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
    hdr_frm_1.sender_name->buf = calloc(strlen("My OAI-DU") + 1, sizeof(char));
    memcpy(hdr_frm_1.sender_name->buf, "My OAI-DU", strlen("My OAI-DU"));
    hdr_frm_1.sender_name->len = strlen("My OAI-DU");
626

627 628 629 630 631 632 633 634 635 636 637
    hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
    hdr_frm_1.sender_type->buf = calloc(strlen("DU") + 1, sizeof(char));
    memcpy(hdr_frm_1.sender_type->buf, "DU", strlen("DU"));
    hdr_frm_1.sender_type->len = strlen("DU");
  }
  else if (NODE_IS_CU(RC.nrrrc[0]->node_type))
  {
    hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
    hdr_frm_1.sender_name->buf = calloc(strlen("My OAI-CU") + 1, sizeof(char));
    memcpy(hdr_frm_1.sender_name->buf, "My OAI-CU", strlen("My OAI-CU"));
    hdr_frm_1.sender_name->len = strlen("My OAI-CU");
638

639 640 641 642 643 644 645 646 647 648 649
    hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
    hdr_frm_1.sender_type->buf = calloc(strlen("CU") + 1, sizeof(char));
    memcpy(hdr_frm_1.sender_type->buf, "CU", strlen("CU"));
    hdr_frm_1.sender_type->len = strlen("CU");
  }
  else if (NODE_IS_MONOLITHIC(RC.nrrrc[0]->node_type))
  {
    hdr_frm_1.sender_name = calloc(1, sizeof(byte_array_t));
    hdr_frm_1.sender_name->buf = calloc(strlen("My OAI-MONO") + 1, sizeof(char));
    memcpy(hdr_frm_1.sender_name->buf, "My OAI-MONO", strlen("My OAI-MONO"));
    hdr_frm_1.sender_name->len = strlen("My OAI-MONO");
650

651 652 653 654
    hdr_frm_1.sender_type = calloc(1, sizeof(byte_array_t));
    hdr_frm_1.sender_type->buf = calloc(strlen("MONO") + 1, sizeof(char));
    memcpy(hdr_frm_1.sender_type->buf, "MONO", strlen("MONO"));
    hdr_frm_1.sender_type->len = strlen("MONO");
655 656
  } else {
    assert(0!=0 && "Unknown node type");
657
  }
658

659 660 661 662 663 664 665 666
  hdr_frm_1.vendor_name = calloc(1, sizeof(byte_array_t));
  hdr_frm_1.vendor_name->buf = calloc(strlen("OAI") + 1, sizeof(char));
  memcpy(hdr_frm_1.vendor_name->buf, "OAI", strlen("OAI"));
  hdr_frm_1.vendor_name->len = strlen("OAI");

  return hdr_frm_1;
}

667
kpm_ind_hdr_t kpm_ind_hdr(void)
668 669 670 671
{
  kpm_ind_hdr_t hdr = {0};

  hdr.type = FORMAT_1_INDICATION_HEADER;
672
  hdr.kpm_ric_ind_hdr_format_1 = kpm_ind_hdr_frm_1();
673 674 675 676 677 678 679

  return hdr;
}

void read_kpm_sm(void* data)
{
  assert(data != NULL);
680
  // assert(data->type == KPM_STATS_V3_0);
681

682
  kpm_rd_ind_data_t* const kpm = (kpm_rd_ind_data_t*)data;
683

684
  assert(kpm->act_def != NULL && "Cannot be NULL");
685

686 687
  // 7.8 Supported RIC Styles and E2SM IE Formats
  // Action Definition Format 4 corresponds to Indication Message Format 3
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
  switch (kpm->act_def->type) {
    case FORMAT_4_ACTION_DEFINITION: {
      kpm->ind.hdr = kpm_ind_hdr();

      kpm->ind.msg.type = FORMAT_3_INDICATION_MESSAGE;
      // Filter the UE by the test condition criteria
      kpm_act_def_format_4_t const* frm_4 = &kpm->act_def->frm_4; // 8.2.1.2.4
      for (size_t i = 0; i < frm_4->matching_cond_lst_len; i++) {
        switch (frm_4->matching_cond_lst[i].test_info_lst.test_cond_type) {
          case GBR_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }
          case AMBR_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }
          case IsStat_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }
          case IsCatM_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }

          case DL_RSRP_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }

          case DL_RSRQ_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }

          case UL_RSRP_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }

          case CQI_TEST_COND_TYPE: {
            // This is a bad idea. Done only to check FlexRIC xAPP
            printf("CQI not implemented!. Randomly filling the data \n");
            goto rnd_data_label;
            break;
          }

          case fiveQI_TEST_COND_TYPE: {
            assert(0 != 0 && "Not implemented");
            break;
          }

          case QCI_TEST_COND_TYPE: {
            ;
            assert(0 != 0 && "Not implemented");
            break;
          }
          case S_NSSAI_TEST_COND_TYPE: {
            assert(frm_4->matching_cond_lst[i].test_info_lst.S_NSSAI == TRUE_TEST_COND_TYPE && "Must be true");
            assert(frm_4->matching_cond_lst[i].test_info_lst.test_cond != NULL && "Even though is optional..");
            assert(frm_4->matching_cond_lst[i].test_info_lst.int_value != NULL && "Even though is optional..");

            test_cond_e const test_cond = *frm_4->matching_cond_lst[i].test_info_lst.test_cond;
            int64_t const value = *frm_4->matching_cond_lst[i].test_info_lst.int_value;
            // Check E2 Node NG-RAN Type
            if (NODE_IS_DU(RC.nrrrc[0]->node_type)) {
              matched_ues_mac_t matched_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, value);
              kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_du(matched_ues, &frm_4->action_def_format_1);
            } else if (NODE_IS_CU(RC.nrrrc[0]->node_type)) {
              matched_ues_rrc_t matched_ues = filter_ues_by_s_nssai_in_cu(test_cond, value);
              kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_cu(matched_ues, &frm_4->action_def_format_1);
            } else if (NODE_IS_MONOLITHIC(RC.nrrrc[0]->node_type)) {
              matched_ues_mac_t matched_ues = filter_ues_by_s_nssai_in_du_or_monolithic(test_cond, value);
              kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3_in_monolithic(matched_ues, &frm_4->action_def_format_1);
            } else {
              assert(false && "NG-RAN Type not implemented");
            }

            break;
          }

          default:
            assert(false && "Unknown Test condition");
772 773 774
        }
      }

775
      break;
776
    }
777

778 779 780 781
    default: {
    rnd_data_label:
      kpm->ind.hdr = fill_rnd_kpm_ind_hdr();
      kpm->ind.msg = fill_rnd_kpm_ind_msg();
782

783 784
      break;
    }
785
  }
786 787 788 789 790 791 792 793
}

void read_kpm_setup_sm(void* e2ap)
{
  assert(e2ap != NULL);
//  assert(e2ap->type == KPM_V3_0_AGENT_IF_E2_SETUP_ANS_V0);

  kpm_e2_setup_t* kpm = (kpm_e2_setup_t*)(e2ap);
794
  kpm->ran_func_def = fill_rnd_kpm_ran_func_def(); 
795 796 797 798 799 800 801 802 803 804
}

sm_ag_if_ans_t write_ctrl_kpm_sm(void const* src)
{
  assert(0 !=0 && "Not supported");
  (void)src;
  sm_ag_if_ans_t ans = {0};
  return ans;
}