Enable multiple RC subscriptions
- create hash table to save ric_req_id (key) and array of ran_param_id(s) (values), per each subscription
- create RB tree to store list of ric_req_id(s) for each ran_param_id
=> when the async event occurs, it is easier and faster to search per ran_param_id and send the indication message to all xApps (ric_req_id(s)) subscribed to the same ran_param_id
- it is important to mention that both data structures need to be maintained, especially when unsubscription occurs (free_aperiodic_subscription)
This commit is contained in:
@@ -9,6 +9,7 @@ add_library(e2_ran_func_cuup STATIC
|
||||
O-RAN/ran_func_kpm.c # this file should only contain PDCP-U/GTP; to be done in the future
|
||||
../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
O-RAN/ran_func_rc.c # this file should only contain PDCP-U/GTP; to be done in the future
|
||||
O-RAN/ran_func_rc_subs.c
|
||||
../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
)
|
||||
|
||||
@@ -27,6 +28,7 @@ add_library(e2_ran_func_du_cucp_cuup STATIC
|
||||
../flexric/test/rnd/fill_rnd_data_kpm.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
O-RAN/ran_func_rc.c # this file should only contain RRC/PDCP-C; to be done in the future
|
||||
# when nr-softmodem is divided in separate executables
|
||||
O-RAN/ran_func_rc_subs.c
|
||||
../flexric/test/rnd/fill_rnd_data_rc.c # this dependancy will be taken out once RAN Function Definition is implemented
|
||||
../flexric/src/sm/rc_sm/ie/rc_data_ie.c
|
||||
CUSTOMIZED/ran_func_mac.c
|
||||
|
||||
@@ -20,22 +20,41 @@
|
||||
*/
|
||||
|
||||
#include "ran_func_rc.h"
|
||||
#include "ran_func_rc_subs.h"
|
||||
#include "ran_func_rc_extern.h"
|
||||
#include "../../flexric/test/rnd/fill_rnd_data_rc.h" // this dependancy will be taken out once RAN Function Definition is implemented
|
||||
#include "../../flexric/src/sm/rc_sm/ie/ir/lst_ran_param.h"
|
||||
#include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h"
|
||||
#include "../../flexric/src/agent/e2_agent_api.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/ran_context.h"
|
||||
|
||||
static const int rrc_state_changed_to = 202;
|
||||
static bool subs_rrc_state_change = false;
|
||||
static uint32_t ric_req_id = 0;
|
||||
static pthread_once_t once_rc_mutex = PTHREAD_ONCE_INIT;
|
||||
static rc_subs_data_t rc_subs_data = {0};
|
||||
static pthread_mutex_t rc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void init_once_rc(void)
|
||||
{
|
||||
init_rc_subs_data(&rc_subs_data);
|
||||
}
|
||||
|
||||
void read_rc_setup_sm(void* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
// assert(data->type == RAN_CTRL_V1_3_AGENT_IF_E2_SETUP_ANS_V0);
|
||||
rc_e2_setup_t* rc = (rc_e2_setup_t*)data;
|
||||
rc->ran_func_def = fill_rc_ran_func_def();
|
||||
|
||||
// E2 Setup Request is sent periodically until the connection is established
|
||||
// RC subscritpion data should be initialized only once
|
||||
const int ret = pthread_once(&once_rc_mutex, init_once_rc);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
|
||||
RB_PROTOTYPE(ric_id_2_param_id_trees, ric_req_id_s, entries, cmp_ric_req_id);
|
||||
|
||||
static ue_id_e2sm_t fill_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context)
|
||||
{
|
||||
@@ -65,11 +84,11 @@ static ue_id_e2sm_t fill_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context)
|
||||
ue_id.gnb.gnb_cu_cp_ue_e1ap_lst[i] = rrc_ue_context->rrc_ue_id;
|
||||
}
|
||||
} else if (RC.nrrrc[0]->node_type == ngran_gNB_DU) {
|
||||
assert(false && "Cannot access RRC layer in DU\n");
|
||||
assert(false && "RRC state change cannot be triggered from DU\n");
|
||||
}
|
||||
|
||||
#elif defined (NGRAN_GNB_CUUP)
|
||||
assert(false && "Cannot access RRC layer in CU-UP\n");
|
||||
assert(false && "RRC state change cannot be triggered from CU-UP\n");
|
||||
|
||||
#endif
|
||||
|
||||
@@ -88,7 +107,7 @@ static seq_ran_param_t fill_rrc_state_change_seq_ran(const rc_sm_rrc_state_e rrc
|
||||
{
|
||||
seq_ran_param_t seq_ran_param = {0};
|
||||
|
||||
seq_ran_param.ran_param_id = rrc_state_changed_to;
|
||||
seq_ran_param.ran_param_id = RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID;
|
||||
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");
|
||||
@@ -132,34 +151,70 @@ static rc_ind_data_t* fill_ue_rrc_state_change(const gNB_RRC_UE_t *rrc_ue_contex
|
||||
return rc_ind;
|
||||
}
|
||||
|
||||
|
||||
void signal_rrc_state_changed_to(const gNB_RRC_UE_t *rrc_ue_context, const rc_sm_rrc_state_e rrc_state)
|
||||
{
|
||||
AssertFatal(subs_rrc_state_change == true, "xApp should be subscribed to E2 node before sending the RIC INDICATION Message\n");
|
||||
{
|
||||
pthread_mutex_lock(&rc_mutex);
|
||||
if (rc_subs_data.rb[RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID].rbh_root == NULL) {
|
||||
pthread_mutex_unlock(&rc_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
rc_ind_data_t* rc_ind_data = fill_ue_rrc_state_change(rrc_ue_context, rrc_state);
|
||||
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);
|
||||
|
||||
async_event_agent_api(ric_req_id, rc_ind_data);
|
||||
printf("Event for RIC Req ID %u generated\n", ric_req_id);
|
||||
// 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);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&rc_mutex);
|
||||
}
|
||||
|
||||
bool read_rc_sm(void* data)
|
||||
static void free_aperiodic_subscription(uint32_t ric_req_id)
|
||||
{
|
||||
assert(data != NULL);
|
||||
// assert(data->type == RAN_CTRL_STATS_V1_03);
|
||||
assert(0!=0 && "Not implemented");
|
||||
|
||||
return true;
|
||||
remove_rc_subs_data(&rc_subs_data, ric_req_id);
|
||||
}
|
||||
|
||||
void read_rc_setup_sm(void* data)
|
||||
sm_ag_if_ans_t write_subs_rc_sm(void const* src)
|
||||
{
|
||||
assert(data != NULL);
|
||||
// assert(data->type == RAN_CTRL_V1_3_AGENT_IF_E2_SETUP_ANS_V0);
|
||||
rc_e2_setup_t* rc = (rc_e2_setup_t*)data;
|
||||
rc->ran_func_def = fill_rc_ran_func_def();
|
||||
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");
|
||||
|
||||
// 9.2.1.2 RIC ACTION DEFINITION IE
|
||||
switch (wr_rc->rc.ad->format) {
|
||||
case FORMAT_1_E2SM_RC_ACT_DEF: {
|
||||
// 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;
|
||||
}
|
||||
insert_rc_subs_data(&rc_subs_data, ric_req_id, arr_ran_param_id);
|
||||
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);
|
||||
}
|
||||
|
||||
sm_ag_if_ans_t 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;
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
@@ -205,36 +260,12 @@ sm_ag_if_ans_t write_ctrl_rc_sm(void const* data)
|
||||
return ans;
|
||||
}
|
||||
|
||||
sm_ag_if_ans_t write_subs_rc_sm(void const* src)
|
||||
|
||||
bool read_rc_sm(void* data)
|
||||
{
|
||||
assert(src != NULL); // && src->type == RAN_CTRL_SUBS_V1_03);
|
||||
assert(data != NULL);
|
||||
// assert(data->type == RAN_CTRL_STATS_V1_03);
|
||||
assert(0!=0 && "Not implemented");
|
||||
|
||||
wr_rc_sub_data_t* wr_rc = (wr_rc_sub_data_t*)src;
|
||||
|
||||
ric_req_id = wr_rc->ric_req_id; // store the ric_req_id to generate asynchronous event
|
||||
|
||||
assert(wr_rc->rc.ad != NULL && "Cannot be NULL");
|
||||
|
||||
// 9.2.1.2 RIC ACTION DEFINITION IE
|
||||
switch (wr_rc->rc.ad->format) {
|
||||
case FORMAT_1_E2SM_RC_ACT_DEF: {
|
||||
// Parameters to be Reported List
|
||||
// [1-65535]
|
||||
for(size_t i = 0; i < wr_rc->rc.ad->frmt_1.sz_param_report_def; i++) {
|
||||
if (wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id == rrc_state_changed_to) {
|
||||
subs_rrc_state_change = true;
|
||||
} else {
|
||||
AssertFatal(wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id == rrc_state_changed_to, "RAN Parameter ID %d not yet implemented\n", wr_rc->rc.ad->frmt_1.param_report_def[i].ran_param_id);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
sm_ag_if_ans_t ans = {0};
|
||||
|
||||
return ans;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
|
||||
#include "openair2/E2AP/flexric/src/agent/../sm/sm_io.h"
|
||||
|
||||
bool read_rc_sm(void *);
|
||||
|
||||
void read_rc_setup_sm(void* data);
|
||||
|
||||
sm_ag_if_ans_t write_ctrl_rc_sm(void const* data);
|
||||
|
||||
sm_ag_if_ans_t write_subs_rc_sm(void const* src);
|
||||
|
||||
#endif
|
||||
sm_ag_if_ans_t write_ctrl_rc_sm(void const* data);
|
||||
|
||||
bool read_rc_sm(void *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "ran_func_rc_subs.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define MAX_NUM_RIC_REQ_ID 64
|
||||
|
||||
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)
|
||||
{
|
||||
if (c1->ric_req_id < c2->ric_req_id)
|
||||
return -1;
|
||||
|
||||
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)
|
||||
{
|
||||
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");
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&rc_mutex);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&rc_mutex);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
typedef enum {
|
||||
RRC_STATE_CHANGED_TO_E2SM_RC_RAN_PARAM_ID = 202, // 8.2.4 RAN Parameters for Report Service Style 4
|
||||
|
||||
END_E2SM_RC_RAN_PARAM_ID
|
||||
} ran_param_id_e;
|
||||
|
||||
typedef struct{
|
||||
size_t len;
|
||||
ran_param_id_e* ran_param_id;
|
||||
} arr_ran_param_id_t;
|
||||
|
||||
typedef struct ric_req_id_s {
|
||||
RB_ENTRY(ric_req_id_s) entries;
|
||||
uint32_t ric_req_id;
|
||||
} rb_ric_req_id_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)
|
||||
} 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);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user