Commit 1114ee3a authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/rc-report-service-fix' into integration_2025_w07 (!3252)

[E2 agent] 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.
parents 651ef3da 9e2c889d
......@@ -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;
......
......@@ -21,6 +21,7 @@
#include "ran_func_rc_subs.h"
#include "common/utils/assertions.h"
#include "common/utils/alg/find.h"
#include <assert.h>
#include <pthread.h>
......@@ -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);
}
......@@ -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
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