Commit 9e2c889d authored by Teodora's avatar Teodora

Multi RC REPORT service styles support

Issue: unforeseen capability of having the same RAN Parameter ID across different
REPORT service styles.

Solution: keep only RAN Parameter IDs from REPORT styles that are supported by OAI.
Implement sequence array where each element is combination of RIC request ID (unique per RIC SUBSCRIPTION)
and Event Trigger Definition. This way we can properly check further conditions for a certain RAN Parameter ID.
(e.g. if xApp is subscribed to RRC Connected and/or other modes, for "RRC State Changed To" RAN Parameter ID)

Next steps: for new RAN Parameter ID, add new sequence array.
Co-authored-by: default avatarBischoff <tano.bischoff@hhi.fraunhofer.de>
Co-authored-by: default avatarShrinish Donde <shrinish.donde@hhi.fraunhofer.de>
Co-authored-by: default avatarKhanh Toan Pham <khanh.toan.pham@hhi.fraunhofer.de>
parent 0053a3d0
...@@ -169,7 +169,7 @@ static void fill_rc_report(ran_func_def_report_t* report) ...@@ -169,7 +169,7 @@ static void fill_rc_report(ran_func_def_report_t* report)
// Mandatory // Mandatory
// 9.3.8 // 9.3.8
// [1- 4294967295] // [1- 4294967295]
report_style->ran_param[0].id = RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID; report_style->ran_param[0].id = E2SM_RC_RS4_RRC_STATE_CHANGED_TO;
// RAN Parameter Name // RAN Parameter Name
// Mandatory // Mandatory
...@@ -476,14 +476,11 @@ void read_rc_setup_sm(void* data) ...@@ -476,14 +476,11 @@ void read_rc_setup_sm(void* data)
DevAssert(ret == 0); DevAssert(ret == 0);
} }
RB_PROTOTYPE(ric_id_2_param_id_trees, ric_req_id_s, entries, cmp_ric_req_id);
static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc_state) static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc_state)
{ {
seq_ran_param_t seq_ran_param = {0}; seq_ran_param_t seq_ran_param = {0};
seq_ran_param.ran_param_id = RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID; seq_ran_param.ran_param_id = E2SM_RC_RS4_RRC_STATE_CHANGED_TO;
seq_ran_param.ran_param_val.type = ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE; seq_ran_param.ran_param_val.type = ELEMENT_KEY_FLAG_FALSE_RAN_PARAMETER_VAL_TYPE;
seq_ran_param.ran_param_val.flag_false = calloc(1, sizeof(ran_parameter_value_t)); seq_ran_param.ran_param_val.flag_false = calloc(1, sizeof(ran_parameter_value_t));
assert(seq_ran_param.ran_param_val.flag_false != NULL && "Memory exhausted"); assert(seq_ran_param.ran_param_val.flag_false != NULL && "Memory exhausted");
...@@ -528,23 +525,40 @@ static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_contex ...@@ -528,23 +525,40 @@ static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_contex
return rc_ind; return rc_ind;
} }
static void send_aper_ric_ind(const uint32_t ric_req_id, rc_ind_data_t* rc_ind_data)
{
async_event_agent_api(ric_req_id, rc_ind_data);
printf("[E2 AGENT] Event for RIC request ID %d generated\n", ric_req_id);
}
static void check_rrc_state(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state, const uint32_t ric_req_id, const e2sm_rc_ev_trg_frmt_4_t *frmt_4)
{
for (size_t i = 0; i < frmt_4->sz_ue_info_chng; i++) {
const rrc_state_lst_t *rrc_elem = &frmt_4->ue_info_chng[i].rrc_state;
for (size_t j = 0; j < rrc_elem->sz_rrc_state; j++) {
const rrc_state_e2sm_rc_e ev_tr_rrc_state = rrc_elem->state_chng_to[j].state_chngd_to;
if (ev_tr_rrc_state == (rrc_state_e2sm_rc_e)rrc_state || ev_tr_rrc_state == ANY_RRC_STATE_E2SM_RC) {
rc_ind_data_t* rc_ind_data = fill_ue_rrc_state_change(rrc_ue_context, rrc_state);
send_aper_ric_ind(ric_req_id, rc_ind_data);
}
}
}
}
void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state) void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state)
{ {
pthread_mutex_lock(&rc_mutex); pthread_mutex_lock(&rc_mutex);
if (rc_subs_data.rb[RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID].rbh_root == NULL) { if (rc_subs_data.rs4_param202.data == NULL) {
pthread_mutex_unlock(&rc_mutex); pthread_mutex_unlock(&rc_mutex);
return; return;
} }
struct ric_req_id_s *node;
RB_FOREACH(node, ric_id_2_param_id_trees, &rc_subs_data.rb[RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID]) {
rc_ind_data_t* rc_ind_data = fill_ue_rrc_state_change(rrc_ue_context, rrc_state);
// Needs review: memory ownership of the type rc_ind_data_t is transferred to the E2 Agent. Bad const size_t num_subs = seq_arr_size(&rc_subs_data.rs4_param202);
async_event_agent_api(node->ric_req_id, rc_ind_data); for (size_t sub_idx = 0; sub_idx < num_subs; sub_idx++) {
printf( "Event for RIC Req ID %u generated\n", node->ric_req_id); const ran_param_data_t data = *(const ran_param_data_t *)seq_arr_at(&rc_subs_data.rs4_param202, sub_idx);
check_rrc_state(rrc_ue_context, rrc_state, data.ric_req_id, &data.ev_tr.frmt_4);
} }
pthread_mutex_unlock(&rc_mutex); pthread_mutex_unlock(&rc_mutex);
} }
...@@ -553,38 +567,65 @@ static void free_aperiodic_subscription(uint32_t ric_req_id) ...@@ -553,38 +567,65 @@ static void free_aperiodic_subscription(uint32_t ric_req_id)
remove_rc_subs_data(&rc_subs_data, ric_req_id); remove_rc_subs_data(&rc_subs_data, ric_req_id);
} }
static seq_arr_t *get_sa(const e2sm_rc_event_trigger_t *ev_tr, const uint32_t ran_param_id)
{
seq_arr_t *sa = NULL;
switch (ev_tr->format) {
case FORMAT_4_E2SM_RC_EV_TRIGGER_FORMAT:
if (ran_param_id == E2SM_RC_RS4_RRC_STATE_CHANGED_TO) {
sa = &rc_subs_data.rs4_param202;
}
break;
default:
printf("[E2 AGENT] RC REPORT Style %d not yet implemented.\n", ev_tr->format + 1);
break;
}
return sa;
}
static void get_list_for_report_style(const uint32_t ric_req_id, const e2sm_rc_event_trigger_t *ev_tr, const size_t sz, const param_report_def_t *param_def)
{
for (size_t i = 0; i < sz; i++) {
seq_arr_t *sa = get_sa(ev_tr, param_def[i].ran_param_id);
if (!sa) {
printf("[E2 AGENT] Requested RAN Parameter ID %d not yet implemented", param_def[i].ran_param_id);
} else {
struct ran_param_data data = { .ric_req_id = ric_req_id, .ev_tr = cp_e2sm_rc_event_trigger(ev_tr) };
insert_rc_subs_data(sa, &data);
}
}
}
sm_ag_if_ans_t write_subs_rc_sm(void const* src) sm_ag_if_ans_t write_subs_rc_sm(void const* src)
{ {
assert(src != NULL); // && src->type == RAN_CTRL_SUBS_V1_03); assert(src != NULL); // && src->type == RAN_CTRL_SUBS_V1_03);
wr_rc_sub_data_t* wr_rc = (wr_rc_sub_data_t*)src; wr_rc_sub_data_t* wr_rc = (wr_rc_sub_data_t*)src;
assert(wr_rc->rc.ad != NULL && "Cannot be NULL"); assert(wr_rc->rc.ad != NULL && "Cannot be NULL");
sm_ag_if_ans_t ans = {0};
const uint32_t ric_req_id = wr_rc->ric_req_id;
const uint32_t report_style = wr_rc->rc.ad->ric_style_type;
// 9.2.1.2 RIC ACTION DEFINITION IE // 9.2.1.2 RIC ACTION DEFINITION IE
switch (wr_rc->rc.ad->format) { switch (wr_rc->rc.ad->format) {
case FORMAT_1_E2SM_RC_ACT_DEF: { case FORMAT_1_E2SM_RC_ACT_DEF: { // for all REPORT styles
// Parameters to be Reported List // Parameters to be Reported List
// [1-65535] // [1-65535]
const uint32_t ric_req_id = wr_rc->ric_req_id; if (wr_rc->rc.et.format + 1 != report_style) { // wr_rc->rc.et.format is an enum -> initialization starts from 0
arr_ran_param_id_t* arr_ran_param_id = calloc(1, sizeof(arr_ran_param_id_t)); AssertError(false, return ans, "[E2 AGENT] Event Trigger Definition Format %d doesn't correspond to REPORT style %d.\n", wr_rc->rc.et.format + 1, report_style);
assert(arr_ran_param_id != NULL && "Memory exhausted");
arr_ran_param_id->len = wr_rc->rc.ad->frmt_1.sz_param_report_def;
arr_ran_param_id->ran_param_id = calloc(arr_ran_param_id->len, sizeof(ran_param_id_e));
const size_t sz = arr_ran_param_id->len;
for(size_t i = 0; i < sz; i++) {
arr_ran_param_id->ran_param_id[i] = wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id;
} }
insert_rc_subs_data(&rc_subs_data, ric_req_id, arr_ran_param_id); get_list_for_report_style(ric_req_id, &wr_rc->rc.et, wr_rc->rc.ad->frmt_1.sz_param_report_def, wr_rc->rc.ad->frmt_1.param_report_def);
break; break;
} }
default: default:
AssertFatal(wr_rc->rc.ad->format == FORMAT_1_E2SM_RC_ACT_DEF, "Action Definition Format %d not yet implemented", wr_rc->rc.ad->format); AssertError(wr_rc->rc.ad->format == FORMAT_1_E2SM_RC_ACT_DEF, return ans, "[E2 AGENT] Action Definition Format %d not yet implemented", wr_rc->rc.ad->format + 1);
} }
sm_ag_if_ans_t ans = {.type = SUBS_OUTCOME_SM_AG_IF_ANS_V0}; ans.type = SUBS_OUTCOME_SM_AG_IF_ANS_V0;
ans.subs_out.type = APERIODIC_SUBSCRIPTION_FLRC; ans.subs_out.type = APERIODIC_SUBSCRIPTION_FLRC;
ans.subs_out.aper.free_aper_subs = free_aperiodic_subscription; ans.subs_out.aper.free_aper_subs = free_aperiodic_subscription;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "ran_func_rc_subs.h" #include "ran_func_rc_subs.h"
#include "common/utils/assertions.h" #include "common/utils/assertions.h"
#include "common/utils/alg/find.h"
#include <assert.h> #include <assert.h>
#include <pthread.h> #include <pthread.h>
...@@ -29,86 +30,36 @@ ...@@ -29,86 +30,36 @@
static pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER;
int cmp_ric_req_id(struct ric_req_id_s *c1, struct ric_req_id_s *c2) static bool eq_int(const void* value, const void* it)
{ {
if (c1->ric_req_id < c2->ric_req_id) const uint32_t ric_req_id = *(uint32_t *)value;
return -1; const ran_param_data_t *dit = (const ran_param_data_t *)it;
return ric_req_id == dit->ric_req_id;
if (c1->ric_req_id > c2->ric_req_id)
return 1;
return 0;
} }
RB_GENERATE(ric_id_2_param_id_trees, ric_req_id_s, entries, cmp_ric_req_id); void init_rc_subs_data(rc_subs_data_t *rc_subs_data)
void init_rc_subs_data(rc_subs_data_t* rc_subs_data)
{ {
pthread_mutex_lock(&rc_mutex); pthread_mutex_lock(&rc_mutex);
// Initialize sequence array
// Initialize hash table seq_arr_init(&rc_subs_data->rs4_param202, sizeof(ran_param_data_t));
DevAssert(rc_subs_data->htable == NULL);
// Initialize RB trees
// 1 RB tree = 1 ran_param_id => many ric_req_id(s)
for (size_t i = 0; i < END_E2SM_RC_RAN_PARAM_ID; i++) {
RB_INIT(&rc_subs_data->rb[i]);
}
rc_subs_data->htable = hashtable_create(MAX_NUM_RIC_REQ_ID, NULL, free);
assert(rc_subs_data->htable != NULL && "Memory exhausted");
pthread_mutex_unlock(&rc_mutex); pthread_mutex_unlock(&rc_mutex);
} }
void insert_rc_subs_data(rc_subs_data_t* rc_subs_data, uint32_t ric_req_id, arr_ran_param_id_t* arr_ran_param_id) void insert_rc_subs_data(seq_arr_t *seq_arr, ran_param_data_t *data)
{ {
pthread_mutex_lock(&rc_mutex); pthread_mutex_lock(&rc_mutex);
// Insert (RIC request ID + Event Trigger Definition) in specific RAN Parameter ID sequence
// Insert in hash table seq_arr_push_back(seq_arr, data, sizeof(*data));
DevAssert(rc_subs_data->htable != NULL);
uint64_t key = ric_req_id;
// Check if the subscription already exists
AssertFatal(hashtable_is_key_exists(rc_subs_data->htable, key) == HASH_TABLE_KEY_NOT_EXISTS, "RIC req ID %d already subscribed", ric_req_id);
arr_ran_param_id_t* data = malloc(sizeof(*data));
assert(data != NULL);
*data = *arr_ran_param_id;
hashtable_rc_t ret = hashtable_insert(rc_subs_data->htable, key, data);
assert(ret == HASH_TABLE_OK && "Hash table not ok");
// Insert in RB trees
// 1 RB tree = 1 ran_param_id => many ric_req_id(s)
const size_t sz = arr_ran_param_id->len;
rb_ric_req_id_t *node = calloc(1, sizeof(*node));
assert(node != NULL);
node->ric_req_id = ric_req_id;
for (size_t i = 0; i < sz; i++) {
RB_INSERT(ric_id_2_param_id_trees, &rc_subs_data->rb[arr_ran_param_id->ran_param_id[i]], node);
}
pthread_mutex_unlock(&rc_mutex); pthread_mutex_unlock(&rc_mutex);
} }
void remove_rc_subs_data(rc_subs_data_t* rc_subs_data, uint32_t ric_req_id) void remove_rc_subs_data(rc_subs_data_t *rc_subs_data, uint32_t ric_req_id)
{ {
pthread_mutex_lock(&rc_mutex); pthread_mutex_lock(&rc_mutex);
DevAssert(rc_subs_data->htable != NULL); /* find the sequence element that matches RIC request ID */
elm_arr_t elm = find_if(&rc_subs_data->rs4_param202, (void *)&ric_req_id, eq_int);
uint64_t key = ric_req_id; ran_param_data_t *data = elm.it;
// Get the array of ran_param_id(s) free_e2sm_rc_event_trigger(&data->ev_tr);
void *data = NULL; seq_arr_erase(&rc_subs_data->rs4_param202, elm.it);
hashtable_rc_t ret = hashtable_get(rc_subs_data->htable, key, &data);
AssertFatal(ret == HASH_TABLE_OK && data != NULL, "element for ue_id %d not found\n", ric_req_id);
arr_ran_param_id_t arr_ran_param_id = *(arr_ran_param_id_t *)data;
// Remove ric_req_id with its ran_param_id(s) from hash table
ret = hashtable_remove(rc_subs_data->htable, key);
// Remove ric_req_id from each ran_param_id tree where subscribed
rb_ric_req_id_t *node = calloc(1, sizeof(*node));
assert(node != NULL);
node->ric_req_id = ric_req_id;
for (size_t i = 0; i < arr_ran_param_id.len; i++) {
RB_REMOVE(ric_id_2_param_id_trees, &rc_subs_data->rb[arr_ran_param_id.ran_param_id[i]], node);
}
pthread_mutex_unlock(&rc_mutex); pthread_mutex_unlock(&rc_mutex);
} }
...@@ -22,35 +22,74 @@ ...@@ -22,35 +22,74 @@
#ifndef RAN_FUNC_SM_RAN_CTRL_SUBSCRIPTION_AGENT_H #ifndef RAN_FUNC_SM_RAN_CTRL_SUBSCRIPTION_AGENT_H
#define RAN_FUNC_SM_RAN_CTRL_SUBSCRIPTION_AGENT_H #define RAN_FUNC_SM_RAN_CTRL_SUBSCRIPTION_AGENT_H
#include "common/utils/hashtable/hashtable.h" #include "openair2/E2AP/flexric/src/sm/rc_sm/ie/rc_data_ie.h"
#include "common/utils/collection/tree.h" #include "common/utils/ds/seq_arr.h"
typedef enum { typedef enum { // 8.2.1 RAN Parameters for Report Service Style 1
RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID = 202, // 8.2.4 RAN Parameters for Report Service Style 4 E2SM_RC_RS1_UE_EVENT_ID = 1,
E2SM_RC_RS1_NI_MESSAGE = 2,
E2SM_RC_RS1_RRC_MESSAGE = 3,
E2SM_RC_RS1_UE_ID = 4,
E2SM_RC_RS1_OLD_AMF_UE_NGAP_ID = 5,
E2SM_RC_RS1_CELL_GLOBAL_ID = 6,
END_E2SM_RC_RAN_PARAM_ID END_E2SM_RC_RS1_RAN_PARAM_ID
} ran_param_id_e; } report_style_1_ran_param_id_e;
typedef struct{ typedef enum { // 8.2.2 RAN Parameters for Report Service Style 2
size_t len; E2SM_RC_RS2_CURRENT_UE_ID = 1,
ran_param_id_e* ran_param_id; E2SM_RC_RS2_OLD_UE_ID = 2,
} arr_ran_param_id_t; E2SM_RC_RS2_CURRENT_RRC_STATE = 3,
E2SM_RC_RS2_OLD_RRC_STATE = 4,
E2SM_RC_RS2_UE_CONTEXT_INFORMATION_CONTAINER = 5,
E2SM_RC_RS2_CELL_GLOBAL_ID = 6,
E2SM_RC_RS2_UE_INFORMATION = 7,
typedef struct ric_req_id_s { END_E2SM_RC_RS2_RAN_PARAM_ID
RB_ENTRY(ric_req_id_s) entries; } report_style_2_ran_param_id_e;
typedef enum { // 8.2.3 RAN Parameters for Report Service Style 3
E2SM_RC_RS3_CELL_CONTEXT_INFORMATION = 1,
E2SM_RC_RS3_CELL_DELETED = 2,
E2SM_RC_RS3_NEIGHBOUR_RELATION_TABLE = 3,
END_E2SM_RC_RS3_RAN_PARAM_ID
} report_style_3_ran_param_id_e;
typedef enum { // 8.2.4 RAN Parameters for Report Service Style 4
E2SM_RC_RS4_UL_MAC_CE = 100,
E2SM_RC_RS4_DL_MAC_CE = 101,
E2SM_RC_RS4_DL_BUFFER_OCCUPANCY = 102,
E2SM_RC_RS4_CURRENT_RRC_STATE = 201,
E2SM_RC_RS4_RRC_STATE_CHANGED_TO = 202,
E2SM_RC_RS4_RRC_MESSAGE = 203,
E2SM_RC_RS4_OLD_UE_ID = 300,
E2SM_RC_RS4_CURRENT_UE_ID = 301,
E2SM_RC_RS4_NI_MESSAGE = 302,
E2SM_RC_RS4_CELL_GLOBAL_ID = 400,
END_E2SM_RC_RS4_RAN_PARAM_ID
} report_style_4_ran_param_id_e;
typedef enum { // 8.2.5 RAN Parameters for Report Service Style 5
E2SM_RC_RS5_UE_CONTEXT_INFORMATION = 1,
E2SM_RC_RS5_CELL_CONTEXT_INFORMATION = 2,
E2SM_RC_RS5_NEIGHBOUR_RELATION_TABLE = 3,
END_E2SM_RC_RS5_RAN_PARAM_ID
} report_style_5_ran_param_id_e;
typedef struct ran_param_data {
uint32_t ric_req_id; uint32_t ric_req_id;
} rb_ric_req_id_t; e2sm_rc_event_trigger_t ev_tr;
} ran_param_data_t;
typedef struct { typedef struct {
RB_HEAD(ric_id_2_param_id_trees, ric_req_id_s) rb[END_E2SM_RC_RAN_PARAM_ID]; // 1 RB tree = (1 RAN Parameter ID) : (n RIC Request ID) => m RB tree = (m RAN Parameter ID) : (n RIC Request ID) seq_arr_t rs4_param202; // E2SM_RC_RS4_RRC_STATE_CHANGED_TO
hash_table_t* htable; // 1 Hash table = (n RIC Request ID) : (m RAN Parameter ID)
} rc_subs_data_t; } rc_subs_data_t;
void init_rc_subs_data(rc_subs_data_t *rc_subs_data);
int cmp_ric_req_id(struct ric_req_id_s *c1, struct ric_req_id_s *c2); void insert_rc_subs_data(seq_arr_t *seq_arr, ran_param_data_t *data);
void remove_rc_subs_data(rc_subs_data_t *rc_subs_data, uint32_t ric_req_id);
void init_rc_subs_data(rc_subs_data_t* rc_subs_data);
void insert_rc_subs_data(rc_subs_data_t* rc_subs_data, uint32_t ric_req_id, arr_ran_param_id_t* arr_ran_param_id);
void remove_rc_subs_data(rc_subs_data_t* rc_subs_data, uint32_t ric_req_id);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment