From 79c920cd811ce992ab7d9e5ddf6b26228a24ba80 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 22 Nov 2023 17:33:31 +0100 Subject: [PATCH] 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. --- ci-scripts/conf_files/gnb-cuup.sa.f1.conf | 1 + .../conf_files/gnb-cuup.sa.f1.quectel.conf | 1 + executables/nr-cuup.c | 3 +- executables/nr-softmodem.c | 4 +-- openair2/COMMON/e1ap_messages_types.h | 1 + openair2/E1AP/e1ap.c | 4 +-- openair2/E1AP/e1ap_common.c | 3 +- openair2/E1AP/e1ap_common.h | 3 +- openair2/E1AP/e1ap_setup.c | 34 +++++++++++++++---- openair2/GNB_APP/gnb_app.c | 3 +- openair2/GNB_APP/gnb_config.h | 2 +- openair2/GNB_APP/gnb_paramdef.h | 4 +++ 12 files changed, 47 insertions(+), 16 deletions(-) diff --git a/ci-scripts/conf_files/gnb-cuup.sa.f1.conf b/ci-scripts/conf_files/gnb-cuup.sa.f1.conf index 357518bcf2..d6c54f0b9a 100644 --- a/ci-scripts/conf_files/gnb-cuup.sa.f1.conf +++ b/ci-scripts/conf_files/gnb-cuup.sa.f1.conf @@ -8,6 +8,7 @@ gNBs = { ////////// Identification parameters: gNB_ID = 0xe00; + gNB_CU_UP_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; diff --git a/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf b/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf index 4e65547db9..7a2fc7db21 100644 --- a/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf +++ b/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf @@ -8,6 +8,7 @@ gNBs = { ////////// Identification parameters: gNB_ID = 0xe00; + gNB_CU_UP_ID = 0xe00; # cell_type = "CELL_MACRO_GNB"; diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 1e6c22a337..5fb66bc73a 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -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); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index edead47430..d97ec3a10d 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -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 !!!*/ diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index c50efd337f..dba73dd8b9 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -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 { diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 077c67ca98..2aeb873c71 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -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; diff --git a/openair2/E1AP/e1ap_common.c b/openair2/E1AP/e1ap_common.c index cf8982339d..984c3de887 100644 --- a/openair2/E1AP/e1ap_common.c +++ b/openair2/E1AP/e1ap_common.c @@ -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)); diff --git a/openair2/E1AP/e1ap_common.h b/openair2/E1AP/e1ap_common.h index e0aea6990f..4acc606bec 100644 --- a/openair2/E1AP/e1ap_common.h +++ b/openair2/E1AP/e1ap_common.h @@ -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); diff --git a/openair2/E1AP/e1ap_setup.c b/openair2/E1AP/e1ap_setup.c index f80a3962a6..70f90b9a56 100644 --- a/openair2/E1AP/e1ap_setup.c +++ b/openair2/E1AP/e1ap_setup.c @@ -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; diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index 74a8a997bd..e2c0b48bd4 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -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 diff --git a/openair2/GNB_APP/gnb_config.h b/openair2/GNB_APP/gnb_config.h index 1238296045..d02b5eb4f5 100644 --- a/openair2/GNB_APP/gnb_config.h +++ b/openair2/GNB_APP/gnb_config.h @@ -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 diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index faac41fbee..e07a89d305 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -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 { \