From 0a6998db4b6639a22c67e6048a2b8a02d8fe9b00 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 28 Sep 2023 20:53:21 +0200 Subject: [PATCH] Select CU-UP based on slice --- openair2/RRC/NR/nr_rrc_proto.h | 2 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 11 ++++++++- openair2/RRC/NR/rrc_gNB_cuup.c | 45 ++++++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index c85aada0b9..96f5b0e28b 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -133,7 +133,7 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP); sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); -sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); +sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd); int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req); void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req, diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 553cf9ecf1..0e7f01fd8e 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -757,6 +757,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; e1ap_bearer_setup_req_t bearer_req = {0}; + + e1ap_nssai_t cuup_nssai = {0}; for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) { rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true); pdusession_t *session = &pduSession->param; @@ -780,6 +782,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins pdu->nssai.sd = 0xffffff; if (nssai->sD_flag) pdu->nssai.sd = nssai->sD[0] << 16 | nssai->sD[1] << 8 | nssai->sD[0]; + if (cuup_nssai.sst == 0) + cuup_nssai = pdu->nssai; /* for CU-UP selection below */ pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; @@ -827,7 +831,12 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } int xid = rrc_gNB_get_next_transaction_identifier(instance); UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; - sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE); + /* Limitation: we assume one fixed CU-UP per UE. We base the selection on + * NSSAI, but the UE might have multiple PDU sessions with differing slices, + * in which we might need to select different CU-UPs. In this case, we would + * actually need to group the E1 bearer context setup for the different + * CU-UPs, and send them to the different CU-UPs. */ + sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); return; } diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c index 29761491ed..3ab6dfe7bb 100644 --- a/openair2/RRC/NR/rrc_gNB_cuup.c +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -35,6 +35,29 @@ static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_cont /* Tree management functions */ RB_GENERATE/*_STATIC*/(rrc_cuup_tree, nr_rrc_cuup_container_t, entries, cuup_compare); +static const nr_rrc_cuup_container_t *select_cuup_slice(const struct rrc_cuup_tree *t, const gNB_RRC_UE_t *ue, int sst, int sd) +{ + nr_rrc_cuup_container_t *second_best_match = NULL; /* if no NSSAI matches exactly */ + nr_rrc_cuup_container_t *cuup = NULL; + RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) { + e1ap_setup_req_t *sr = cuup->setup_req; + for (int p = 0; p < sr->supported_plmns; ++p) { + /* actually we should also check that the PLMN selected by the UE matches */ + for (int s = 0; s < sr->plmn[p].supported_slices; ++s) { + e1ap_nssai_t *nssai = &sr->plmn[p].slice[s]; + if (nssai->sst == sst && nssai->sd == sd) { + LOG_I(RRC, "selecting CU-UP ID %ld based on exact NSSAI match (%d:0x%06x)\n", sr->gNB_cu_up_id, sst, sd); + return cuup; /* exact match */ + } else if (nssai->sst == sst && second_best_match == NULL) { + LOG_I(RRC, "second best match: CU-UP ID %ld matches SST %d\n", sr->gNB_cu_up_id, sst); + second_best_match = cuup; /* only the SST matches -> "good enough" */ + } + } + } + } + return second_best_match; +} + static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const struct rrc_cuup_tree *t, const gNB_RRC_UE_t *ue) { /* pick the CU-UP following a "round-robin" fashion: select CU-UP M = RRC UE @@ -42,8 +65,10 @@ static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const int m = (ue->rrc_ue_id - 1) % n_t; nr_rrc_cuup_container_t *cuup = NULL; RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) { - if (m == 0) + if (m == 0) { + LOG_I(RRC, "round-robin match: select CU-UP ID %ld (no NSSAI match)\n", cuup->setup_req->gNB_cu_up_id); return cuup; + } m--; } /* this should not happen: no CU-UP available? */ @@ -55,18 +80,19 @@ sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); if (ue_data.e1_assoc_id == 0) { LOG_W(RRC, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id); - return get_new_cuup_for_ue(rrc, ue); + /* we could possibly check the SST/SD from the PDU session */ + return get_new_cuup_for_ue(rrc, ue, 0, 0); } LOG_D(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); return ue_data.e1_assoc_id; } -sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue) +sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd) { /* check if there is already a UE associated */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); if (ue_data.e1_assoc_id != 0) { - LOG_D(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); + LOG_I(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id); return ue_data.e1_assoc_id; } @@ -77,10 +103,15 @@ sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue return 0; /* no CUUP connected */ } - const nr_rrc_cuup_container_t *selected = select_cuup_round_robin(rrc->num_cuups, &rrc->cuups, ue); - if (selected == NULL) + const nr_rrc_cuup_container_t *selected = NULL; + if (sst != 0) /* only do if there is slice information */ + selected = select_cuup_slice(&rrc->cuups, ue, sst, sd); + if (selected == NULL) /* nothing found yet */ + selected = select_cuup_round_robin(rrc->num_cuups, &rrc->cuups, ue); + if (selected == NULL) { selected = RB_ROOT(&rrc->cuups); - AssertFatal(selected != NULL, "logic error: could not select CU-UP\n"); + } + AssertFatal(selected != NULL, "logic error: could not select CU-UP, is one connected?\n"); /* update the association for the UE so it will be picked up later */ ue_data.e1_assoc_id = selected->assoc_id;