Select CU-UP based on slice
This commit is contained in:
@@ -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);
|
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_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);
|
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,
|
void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req,
|
||||||
|
|||||||
@@ -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;
|
UE->amf_ue_ngap_id = msg->amf_ue_ngap_id;
|
||||||
e1ap_bearer_setup_req_t bearer_req = {0};
|
e1ap_bearer_setup_req_t bearer_req = {0};
|
||||||
|
|
||||||
|
|
||||||
|
e1ap_nssai_t cuup_nssai = {0};
|
||||||
for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) {
|
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);
|
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true);
|
||||||
pdusession_t *session = &pduSession->param;
|
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;
|
pdu->nssai.sd = 0xffffff;
|
||||||
if (nssai->sD_flag)
|
if (nssai->sD_flag)
|
||||||
pdu->nssai.sd = nssai->sD[0] << 16 | nssai->sD[1] << 8 | nssai->sD[0];
|
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->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;
|
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);
|
int xid = rrc_gNB_get_next_transaction_identifier(instance);
|
||||||
UE->xids[xid] = RRC_PDUSESSION_ESTABLISH;
|
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);
|
rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,29 @@ static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_cont
|
|||||||
/* Tree management functions */
|
/* Tree management functions */
|
||||||
RB_GENERATE/*_STATIC*/(rrc_cuup_tree, nr_rrc_cuup_container_t, entries, cuup_compare);
|
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)
|
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
|
/* 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;
|
int m = (ue->rrc_ue_id - 1) % n_t;
|
||||||
nr_rrc_cuup_container_t *cuup = NULL;
|
nr_rrc_cuup_container_t *cuup = NULL;
|
||||||
RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) {
|
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;
|
return cuup;
|
||||||
|
}
|
||||||
m--;
|
m--;
|
||||||
}
|
}
|
||||||
/* this should not happen: no CU-UP available? */
|
/* 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);
|
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
|
||||||
if (ue_data.e1_assoc_id == 0) {
|
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);
|
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);
|
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;
|
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 */
|
/* check if there is already a UE associated */
|
||||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
|
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
|
||||||
if (ue_data.e1_assoc_id != 0) {
|
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;
|
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 */
|
return 0; /* no CUUP connected */
|
||||||
}
|
}
|
||||||
|
|
||||||
const nr_rrc_cuup_container_t *selected = select_cuup_round_robin(rrc->num_cuups, &rrc->cuups, ue);
|
const nr_rrc_cuup_container_t *selected = NULL;
|
||||||
if (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);
|
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 */
|
/* update the association for the UE so it will be picked up later */
|
||||||
ue_data.e1_assoc_id = selected->assoc_id;
|
ue_data.e1_assoc_id = selected->assoc_id;
|
||||||
|
|||||||
Reference in New Issue
Block a user