Introduce separate gNB-CU-UP ID in configuration
3GPP has the concept of a gNB-CU-UP ID and a (separate) gNB ID (for gNB, CU-CP). This commit introduces the gNB-CU-UP as a separate ID that has to be set in the configuration file when running as a CU-UP. For the CU/monolithic gNB, it is optional (but needs to be the same as the gNB-ID if specified). The CU-UP ID is necessary, as some entities, e.g., the e2 agent, need to signal both IDs, e.g., to reconcile a CU-CP and (multiple) CU-UP(s) belonging together.
This commit is contained in:
@@ -8,6 +8,7 @@ gNBs =
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_CU_UP_ID = 0xe00;
|
||||
|
||||
# cell_type = "CELL_MACRO_GNB";
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ gNBs =
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_CU_UP_ID = 0xe00;
|
||||
|
||||
# cell_type = "CELL_MACRO_GNB";
|
||||
|
||||
|
||||
@@ -130,7 +130,8 @@ int main(int argc, char **argv)
|
||||
AssertFatal(rc >= 0, "Create task for CUUP E1 failed\n");
|
||||
nr_pdcp_layer_init(true);
|
||||
cu_init_f1_ue_data(); // for CU-UP/CP mapping: we use the same
|
||||
MessageDef *msg = RCconfig_NR_CU_E1(true);
|
||||
E1_t e1type = UPtype;
|
||||
MessageDef *msg = RCconfig_NR_CU_E1(&e1type);
|
||||
AssertFatal(msg != NULL, "Send init to task for E1AP UP failed\n");
|
||||
itti_send_msg_to_task(TASK_CUUP_E1, 0, msg);
|
||||
|
||||
|
||||
@@ -402,9 +402,9 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf
|
||||
|
||||
// If CU
|
||||
if (node_type == ngran_gNB_CU || node_type == ngran_gNB) {
|
||||
MessageDef *msg = RCconfig_NR_CU_E1(false);
|
||||
MessageDef *msg = RCconfig_NR_CU_E1(NULL);
|
||||
instance_t inst = 0;
|
||||
createE1inst(UPtype, inst, &E1AP_REGISTER_REQ(msg).net_config, NULL);
|
||||
createE1inst(UPtype, inst, E1AP_REGISTER_REQ(msg).gnb_id, &E1AP_REGISTER_REQ(msg).net_config, NULL);
|
||||
cuup_init_n3(inst);
|
||||
RC.nrrrc[gnb_id_start]->e1_inst = inst; // stupid instance !!!*/
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ typedef struct e1ap_setup_req_s {
|
||||
typedef struct e1ap_register_req_t {
|
||||
e1ap_setup_req_t setup_req;
|
||||
e1ap_net_config_t net_config;
|
||||
uint32_t gnb_id; // unused in CU-UP, but might be necessary for some functionality, e.g., E2 agent
|
||||
} e1ap_register_req_t;
|
||||
|
||||
typedef struct e1ap_setup_resp_s {
|
||||
|
||||
@@ -1801,7 +1801,7 @@ void cucp_task_send_sctp_init_req(instance_t instance, char *my_addr) {
|
||||
void e1_task_handle_sctp_association_ind(E1_t type, instance_t instance, sctp_new_association_ind_t *sctp_new_ind)
|
||||
{
|
||||
if (!getCxtE1(instance))
|
||||
createE1inst(type, instance, NULL, NULL);
|
||||
createE1inst(type, instance, 0, NULL, NULL);
|
||||
e1ap_upcp_inst_t *inst = getCxtE1(instance);
|
||||
inst->sockState = SCTP_STATE_ESTABLISHED;
|
||||
if (type == UPtype)
|
||||
@@ -1897,7 +1897,7 @@ void *E1AP_CUUP_task(void *arg) {
|
||||
switch (msgType) {
|
||||
case E1AP_REGISTER_REQ: {
|
||||
e1ap_register_req_t *reg_req = &E1AP_REGISTER_REQ(msg);
|
||||
createE1inst(UPtype, myInstance, ®_req->net_config, ®_req->setup_req);
|
||||
createE1inst(UPtype, myInstance, reg_req->gnb_id, ®_req->net_config, ®_req->setup_req);
|
||||
e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, ®_req->net_config);
|
||||
} break;
|
||||
|
||||
|
||||
@@ -37,12 +37,13 @@ e1ap_upcp_inst_t *getCxtE1(instance_t instance)
|
||||
return e1ap_inst[instance];
|
||||
}
|
||||
|
||||
void createE1inst(E1_t type, instance_t instance, e1ap_net_config_t *nc, e1ap_setup_req_t *req)
|
||||
void createE1inst(E1_t type, instance_t instance, uint64_t gnb_id, e1ap_net_config_t *nc, e1ap_setup_req_t *req)
|
||||
{
|
||||
AssertFatal(e1ap_inst[instance] == NULL, "Double call to E1 instance %d\n", (int)instance);
|
||||
e1ap_inst[instance] = calloc(1, sizeof(e1ap_upcp_inst_t));
|
||||
e1ap_inst[instance]->type = type;
|
||||
e1ap_inst[instance]->instance = instance;
|
||||
e1ap_inst[instance]->gnb_id = gnb_id;
|
||||
e1ap_inst[instance]->cuup.assoc_id = -1;
|
||||
if (nc)
|
||||
memcpy(&e1ap_inst[instance]->net_config, nc, sizeof(*nc));
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
typedef struct e1ap_upcp_inst_s {
|
||||
instance_t instance;
|
||||
uint32_t gnb_id; // associated gNB's ID, unused in E1 but necessary for e.g. E2 agent
|
||||
E1_t type;
|
||||
enum sctp_state_e sockState;
|
||||
struct {
|
||||
@@ -52,7 +53,7 @@ e1ap_upcp_inst_t *getCxtE1(instance_t instance);
|
||||
long E1AP_get_next_transaction_identifier();
|
||||
void E1AP_free_transaction_identifier(long id);
|
||||
|
||||
void createE1inst(E1_t type, instance_t instance, e1ap_net_config_t *nc, e1ap_setup_req_t *req);
|
||||
void createE1inst(E1_t type, instance_t instance, uint64_t gnb_id, e1ap_net_config_t *nc, e1ap_setup_req_t *req);
|
||||
|
||||
int e1ap_encode_send(E1_t type, sctp_assoc_t assoc_id, struct E1AP_E1AP_PDU *pdu, uint16_t stream, const char *func);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ static void get_NGU_S1U_addr(char **addr, uint16_t *port)
|
||||
return;
|
||||
}
|
||||
|
||||
MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
|
||||
MessageDef *RCconfig_NR_CU_E1(const E1_t *entity)
|
||||
{
|
||||
MessageDef *msgConfig = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_REGISTER_REQ);
|
||||
if (!msgConfig)
|
||||
@@ -82,14 +82,12 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
|
||||
sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0);
|
||||
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
|
||||
AssertFatal(num_gnbs == 1, "Support only one gNB per process\n");
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
paramdef_t *gnbParms = GNBParamList.paramarray[0];
|
||||
e1ap_setup_req_t *e1Setup = &E1AP_REGISTER_REQ(msgConfig).setup_req;
|
||||
|
||||
if (num_gnbs > 0) {
|
||||
config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
|
||||
paramdef_t *gnbParms = GNBParamList.paramarray[0];
|
||||
AssertFatal(gnbParms[GNB_GNB_ID_IDX].uptr != NULL, "gNB id %d is not defined in configuration file\n", 0);
|
||||
e1ap_setup_req_t *e1Setup = &E1AP_REGISTER_REQ(msgConfig).setup_req;
|
||||
msgConfig->ittiMsgHeader.destinationInstance = 0;
|
||||
e1Setup->gNB_cu_up_id = *(gnbParms[GNB_GNB_ID_IDX].uptr);
|
||||
if (*gnbParms[GNB_GNB_NAME_IDX].strptr)
|
||||
e1Setup->gNB_cu_up_name = *(gnbParms[GNB_GNB_NAME_IDX].strptr);
|
||||
|
||||
@@ -132,7 +130,11 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
|
||||
get_NGU_S1U_addr(&e1ap_nc->localAddressN3, &e1ap_nc->localPortN3);
|
||||
e1ap_nc->remotePortN3 = e1ap_nc->localPortN3 ;
|
||||
|
||||
if (separate_CUUP_process) {
|
||||
AssertFatal(config_isparamset(gnbParms, GNB_GNB_ID_IDX), "%s is not defined in configuration file\n", GNB_CONFIG_STRING_GNB_ID);
|
||||
uint32_t gnb_id = *gnbParms[GNB_GNB_ID_IDX].uptr;
|
||||
E1AP_REGISTER_REQ(msgConfig).gnb_id = gnb_id;
|
||||
|
||||
if (entity != NULL) {
|
||||
paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0};
|
||||
paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC;
|
||||
config_getlist(config_get_if(), &GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix);
|
||||
@@ -141,6 +143,24 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
|
||||
e1ap_nc->CUCP_e1_ip_address.ipv4 = 1;
|
||||
strcpy(e1ap_nc->CUUP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUUP].strptr));
|
||||
e1ap_nc->CUUP_e1_ip_address.ipv4 = 1;
|
||||
if (*entity == CPtype) {
|
||||
// CP needs gNB_ID (although not used, but other parts check it as
|
||||
// well), and gNB-CU-UP ID should NOT be present as it comes through E1!
|
||||
AssertFatal(!config_isparamset(gnbParms, GNB_GNB_CU_UP_ID_IDX), "%s must not be defined in configuration file\n", GNB_CONFIG_STRING_GNB_CU_UP_ID);
|
||||
} else { // UPtype
|
||||
AssertFatal(config_isparamset(gnbParms, GNB_GNB_CU_UP_ID_IDX), "%s is not be defined in configuration file\n", GNB_CONFIG_STRING_GNB_CU_UP_ID);
|
||||
e1Setup->gNB_cu_up_id = *gnbParms[GNB_GNB_CU_UP_ID_IDX].u64ptr;
|
||||
}
|
||||
} else {
|
||||
// integrated CU-CP/UP. We don't care about the gNB-CU-UP ID that much,
|
||||
// but if it's there, check it's the same as gNB ID
|
||||
uint64_t *gnb_cu_up_id = gnbParms[GNB_GNB_CU_UP_ID_IDX].u64ptr;
|
||||
AssertFatal(!config_isparamset(gnbParms, GNB_GNB_CU_UP_ID_IDX) || *gnb_cu_up_id == gnb_id,
|
||||
"%s is different of %s: they need to match or remove %s from config\n",
|
||||
GNB_CONFIG_STRING_GNB_CU_UP_ID,
|
||||
GNB_CONFIG_STRING_GNB_ID,
|
||||
GNB_CONFIG_STRING_GNB_CU_UP_ID);
|
||||
e1Setup->gNB_cu_up_id = gnb_id;
|
||||
}
|
||||
}
|
||||
return msgConfig;
|
||||
|
||||
@@ -146,7 +146,8 @@ void *gNB_app_task(void *args_p)
|
||||
if (node_type == ngran_gNB_CUCP) {
|
||||
if (itti_create_task(TASK_CUCP_E1, E1AP_CUCP_task, NULL) < 0)
|
||||
AssertFatal(false, "Create task for E1AP CP failed\n");
|
||||
MessageDef *msg = RCconfig_NR_CU_E1(true);
|
||||
E1_t e1type = CPtype;
|
||||
MessageDef *msg = RCconfig_NR_CU_E1(&e1type);
|
||||
AssertFatal(msg != NULL, "Send inti to task for E1AP CP failed\n");
|
||||
// this sends the E1AP_REGISTER_REQ to CU-CP so it sets up the socket
|
||||
// it does NOT use the E1AP part
|
||||
|
||||
@@ -107,7 +107,7 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i);
|
||||
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
|
||||
void wait_f1_setup_response(void);
|
||||
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update);
|
||||
MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process);
|
||||
MessageDef *RCconfig_NR_CU_E1(const E1_t *entity);
|
||||
ngran_node_t get_node_type(void);
|
||||
|
||||
#ifdef E2_AGENT
|
||||
|
||||
@@ -129,11 +129,13 @@ typedef enum {
|
||||
#define GNB_CONFIG_STRING_ENABLE_SDAP "enable_sdap"
|
||||
#define GNB_CONFIG_STRING_DRBS "drbs"
|
||||
#define GNB_CONFIG_STRING_GNB_DU_ID "gNB_DU_ID"
|
||||
#define GNB_CONFIG_STRING_GNB_CU_UP_ID "gNB_CU_UP_ID"
|
||||
|
||||
#define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n"
|
||||
#define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support"
|
||||
#define GNB_CONFIG_HLP_STRING_DRBS "Number of total DRBs to establish, including the mandatory for PDU SEssion (default=1)\n"
|
||||
#define GNB_CONFIG_HLP_GNB_DU_ID "defines the gNB-DU ID (only applicable for DU)"
|
||||
#define GNB_CONFIG_HLP_GNB_CU_UP_ID "defines the gNB-CU-UP ID (only applicable for CU-UP)"
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* cell configuration parameters */
|
||||
@@ -170,6 +172,7 @@ typedef enum {
|
||||
{GNB_CONFIG_STRING_ENABLE_SDAP, GNB_CONFIG_HLP_STRING_ENABLE_SDAP, PARAMFLAG_BOOL,.iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
{GNB_CONFIG_STRING_DRBS, GNB_CONFIG_HLP_STRING_DRBS, 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
|
||||
{GNB_CONFIG_STRING_GNB_DU_ID, GNB_CONFIG_HLP_GNB_DU_ID, 0, .u64ptr=NULL, .defint64val=1, TYPE_UINT64, 0}, \
|
||||
{GNB_CONFIG_STRING_GNB_CU_UP_ID, GNB_CONFIG_HLP_GNB_CU_UP_ID, 0, .u64ptr=NULL, .defint64val=1, TYPE_UINT64, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -203,6 +206,7 @@ typedef enum {
|
||||
#define GNB_ENABLE_SDAP_IDX 26
|
||||
#define GNB_DRBS 27
|
||||
#define GNB_GNB_DU_ID_IDX 28
|
||||
#define GNB_GNB_CU_UP_ID_IDX 29
|
||||
|
||||
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
|
||||
#define GNBPARAMS_CHECK { \
|
||||
|
||||
Reference in New Issue
Block a user