diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c index ef23bf2fd4..908107c891 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c @@ -169,7 +169,7 @@ static void fill_rc_report(ran_func_def_report_t* report) // Mandatory // 9.3.8 // [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 // Mandatory @@ -476,14 +476,11 @@ void read_rc_setup_sm(void* data) 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) { 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.flag_false = calloc(1, sizeof(ran_parameter_value_t)); 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 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) -{ +{ 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); 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 - async_event_agent_api(node->ric_req_id, rc_ind_data); - printf( "Event for RIC Req ID %u generated\n", node->ric_req_id); + const size_t num_subs = seq_arr_size(&rc_subs_data.rs4_param202); + for (size_t sub_idx = 0; sub_idx < num_subs; sub_idx++) { + 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); } @@ -553,38 +567,65 @@ static void free_aperiodic_subscription(uint32_t 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) { assert(src != NULL); // && src->type == RAN_CTRL_SUBS_V1_03); - wr_rc_sub_data_t* wr_rc = (wr_rc_sub_data_t*)src; - 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 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 // [1-65535] - const uint32_t ric_req_id = wr_rc->ric_req_id; - arr_ran_param_id_t* arr_ran_param_id = calloc(1, sizeof(arr_ran_param_id_t)); - 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; + if (wr_rc->rc.et.format + 1 != report_style) { // wr_rc->rc.et.format is an enum -> initialization starts from 0 + 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); } - 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; } - + 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.aper.free_aper_subs = free_aperiodic_subscription; diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.c index 6c7176eafb..9d37a89fd8 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.c @@ -21,6 +21,7 @@ #include "ran_func_rc_subs.h" #include "common/utils/assertions.h" +#include "common/utils/alg/find.h" #include #include @@ -29,86 +30,36 @@ 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) - return -1; - - if (c1->ric_req_id > c2->ric_req_id) - return 1; - - return 0; + const uint32_t ric_req_id = *(uint32_t *)value; + const ran_param_data_t *dit = (const ran_param_data_t *)it; + return ric_req_id == dit->ric_req_id; } -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); - - // Initialize hash table - 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"); + // Initialize sequence array + seq_arr_init(&rc_subs_data->rs4_param202, sizeof(ran_param_data_t)); 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); - - // Insert in hash table - 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); - } - + // Insert (RIC request ID + Event Trigger Definition) in specific RAN Parameter ID sequence + seq_arr_push_back(seq_arr, data, sizeof(*data)); 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); - DevAssert(rc_subs_data->htable != NULL); - - uint64_t key = ric_req_id; - // Get the array of ran_param_id(s) - void *data = NULL; - 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); - } - + /* 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); + ran_param_data_t *data = elm.it; + free_e2sm_rc_event_trigger(&data->ev_tr); + seq_arr_erase(&rc_subs_data->rs4_param202, elm.it); pthread_mutex_unlock(&rc_mutex); } diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.h b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.h index 1eb013c37c..80fc7e5706 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.h +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_subs.h @@ -22,35 +22,74 @@ #ifndef RAN_FUNC_SM_RAN_CTRL_SUBSCRIPTION_AGENT_H #define RAN_FUNC_SM_RAN_CTRL_SUBSCRIPTION_AGENT_H -#include "common/utils/hashtable/hashtable.h" -#include "common/utils/collection/tree.h" +#include "openair2/E2AP/flexric/src/sm/rc_sm/ie/rc_data_ie.h" +#include "common/utils/ds/seq_arr.h" -typedef enum { - RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID = 202, // 8.2.4 RAN Parameters for Report Service Style 4 +typedef enum { // 8.2.1 RAN Parameters for Report Service Style 1 + 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 -} ran_param_id_e; + END_E2SM_RC_RS1_RAN_PARAM_ID +} report_style_1_ran_param_id_e; -typedef struct{ - size_t len; - ran_param_id_e* ran_param_id; -} arr_ran_param_id_t; +typedef enum { // 8.2.2 RAN Parameters for Report Service Style 2 + E2SM_RC_RS2_CURRENT_UE_ID = 1, + E2SM_RC_RS2_OLD_UE_ID = 2, + 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 { - RB_ENTRY(ric_req_id_s) entries; + END_E2SM_RC_RS2_RAN_PARAM_ID +} 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; -} rb_ric_req_id_t; + e2sm_rc_event_trigger_t ev_tr; +} ran_param_data_t; 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) - hash_table_t* htable; // 1 Hash table = (n RIC Request ID) : (m RAN Parameter ID) + seq_arr_t rs4_param202; // E2SM_RC_RS4_RRC_STATE_CHANGED_TO } rc_subs_data_t; - -int cmp_ric_req_id(struct ric_req_id_s *c1, struct ric_req_id_s *c2); - -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); +void init_rc_subs_data(rc_subs_data_t *rc_subs_data); +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); #endif