Commit e8661f5a authored by Robert Schmidt's avatar Robert Schmidt

Reset CU-CP E1 UE context after E1 Setup Response

As in deba3ae0 ("Reset CU-UP E1 UE contexts after E1 Setup
Response"), the CU-CP should reset the E1 UE contexts after E1 Setup
Response. 38.463 sec. 8.2.3 says

> This procedure also re-initialises the E1AP UE-related contexts (if
> any) and erases all related signalling connections in the two nodes like
> a Reset procedure would do.

In the case of CU-CP, this is a bit more complicated. More precisely, we
need to wait for the CU-UP to be available again before informing the DU
about the loss (implemented via an F1 Reset message), because otherwise,
the UE might reconnect immediately, before the CU-UP is online again.

Hence, on connection loss, we mark affected UEs (by setting their E1
association ID to 0); as long as the CU-UP does not connect, nothing
will happen (but UEs don't have user plane). Upon CU-UP connecting
again, we request release of the UEs via NGAP (similarly to what is done
if the DU goes offline, see invalidate_du_connections()), free the UE
contexts locally, and send an F1 Reset message to the DU, because
38.473 sec 8.2.1.2.1 says

> a failure at the gNB-CU [...] has resulted in the loss of some or
> all transaction reference information [...] a RESET message shall be
> sent to the gNB-DU.

The core should accept and send an NGAP release command message; since
no UE contexts are to be found (already deleted), the CU-CP will just
send a release complete (together with some warnings).

It might be possible to more gracefully handle the situation (e.g., as
described in 38.401 section 8.9.5 "Change of gNB-CU-UP"), but

- we lack the PDCP SN exchange
- the current procedure has the advantage of being equivalent to
  "restart of the entire gNB", with less downtown.
parent d2bb779e
......@@ -24,13 +24,17 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "PHY/defs_common.h"
#include "common/utils/alg/find.h"
#include "common/utils/alg/foreach.h"
#include "RRC/NR/nr_rrc_proto.h"
#include "T.h"
#include "as_message.h"
#include "assertions.h"
#include "common/ran_context.h"
#include "common/utils/T/T.h"
#include "rrc_gNB_UE_context.h"
#include "rrc_gNB_du.h"
#include "e1ap_messages_types.h"
#include "intertask_interface.h"
#include "nr_rrc_defs.h"
......@@ -38,6 +42,7 @@
#include "rrc_messages_types.h"
#include "tree.h"
#include "e1ap_interface_management.h"
#include "rrc_gNB_NGAP.h"
static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_container_t *b)
{
......@@ -168,6 +173,69 @@ static void e1ap_setup_failure(sctp_assoc_t assoc_id, uint64_t transac_id, e1ap_
itti_send_msg_to_task(TASK_CUCP_E1, 0 /*unused by callee*/, msg_p);
}
static bool has_assoc_id(const void *vval, const void *vit)
{
sctp_assoc_t val = *(sctp_assoc_t *)vval;
sctp_assoc_t it = *(sctp_assoc_t *)vit;
return val == it;
}
/* @brief Remove RRC UE contexts of UE without E1 connection.
*
* 38.463 sec 8.2.3. says that "[E1 Setup] procedure also re-initialises the
* E1AP UE-related contexts (if any) and erases all related signalling
* connections in the two nodes like a Reset procedure would do.". If the CU-UP
* reconnects, it's previous UE contexts are here, but not associated. To
* fulfil the above, we simply free all UE contexts that don't have a CU-UP,
* and send a F1 Reset message to the corresponding DU(s), following the fact
* that (38.473 sec 8.2.1.2.1) "a failure at the gNB-CU [...] has resulted in
* the loss of some or all transaction reference information[...] a RESET
* message shall be sent to the gNB-DU.". This might be overarching in that UEs
* that are in the process of connecting or that are on another DU might be
* affected by that reset procedure as well; we suppose they will connect later
* again. */
static void remove_unassociated_e1_connections(gNB_RRC_INST *rrc, sctp_assoc_t e1_assoc_id)
{
seq_arr_t affected_du;
seq_arr_init(&affected_du, sizeof(sctp_assoc_t));
seq_arr_t ue_context_to_remove;
seq_arr_init(&ue_context_to_remove, sizeof(rrc_gNB_ue_context_t *));
rrc_gNB_ue_context_t *ue_context_p = NULL;
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) {
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
uint32_t ue_id = UE->rrc_ue_id;
if (ue_associated_to_cuup(rrc, UE))
continue;
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
elm_arr_t ret = find_if(&affected_du, &ue_data.du_assoc_id, has_assoc_id);
if (!ret.found)
seq_arr_push_back(&affected_du, &ue_data.du_assoc_id, sizeof(ue_data.du_assoc_id));
/* remove UE context: we store the pointer, so pass pointer to ue_context_p */
seq_arr_push_back(&ue_context_to_remove, &ue_context_p, sizeof(ue_context_p));
LOG_I(NR_RRC, "remove E1-unassociated UE context ID %d\n", ue_id);
}
for (int i = 0; i < seq_arr_size(&ue_context_to_remove); ++i) {
/* we retrieve a pointer (=iterator) to the UE context pointer
* (ue_context_p), so dereference once */
rrc_gNB_ue_context_t *p = *(rrc_gNB_ue_context_t **)seq_arr_at(&ue_context_to_remove, i);
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RADIO_CONNECTION_WITH_UE_LOST};
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, p, cause);
rrc_remove_ue(rrc, p);
}
seq_arr_free(&ue_context_to_remove, NULL);
for (int i = 0; i < seq_arr_size(&affected_du); ++i) {
void *it = seq_arr_at(&affected_du, i);
sctp_assoc_t du_assoc_id = *(sctp_assoc_t *)it;
LOG_W(NR_RRC, "trigger F1 reset on DU %d due to E1 connection loss\n", du_assoc_id);
trigger_f1_reset(rrc, du_assoc_id);
}
seq_arr_free(&affected_du, NULL);
}
/**
* @brief E1AP Setup Request processing on CU-CP
*/
......@@ -216,6 +284,8 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t *
RB_INSERT(rrc_cuup_tree, &rrc->cuups, cuup);
rrc->num_cuups++;
remove_unassociated_e1_connections(rrc, assoc_id);
MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, E1AP_SETUP_RESP);
msg_p->ittiMsgHeader.originInstance = assoc_id;
e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(msg_p);
......@@ -225,6 +295,24 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t *
return 0;
}
/* @brief invalidate (remove) all E1 assoc ID from UE contexts belonging to this CU-UP */
static void invalidate_cuup_connections(gNB_RRC_INST *rrc, sctp_assoc_t e1_assoc_id)
{
rrc_gNB_ue_context_t *ue_context_p = NULL;
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) {
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
uint32_t ue_id = UE->rrc_ue_id;
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
if (ue_data.e1_assoc_id != e1_assoc_id)
continue; /* UE is on another CU-UP */
ue_data.e1_assoc_id = 0;
bool success = cu_update_f1_ue_data(ue_id, &ue_data);
DevAssert(success);
LOG_W(NR_RRC, "CU-UP %d of UE %d is gone\n", e1_assoc_id, ue_id);
}
}
/**
* @brief RRC Processing of the indication of E1 connection loss on CU-CP
*/
......@@ -232,6 +320,7 @@ void rrc_gNB_process_e1_lost_connection(gNB_RRC_INST *rrc, e1ap_lost_connection_
{
LOG_I(NR_RRC, "Received E1 connection loss indication on RRC\n");
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
invalidate_cuup_connections(rrc, assoc_id);
nr_rrc_cuup_container_t e = {.assoc_id = assoc_id};
nr_rrc_cuup_container_t *cuup = RB_FIND(rrc_cuup_tree, &rrc->cuups, &e);
if (cuup == NULL) {
......
......@@ -644,3 +644,14 @@ nr_rrc_du_container_t *find_target_du(gNB_RRC_INST *rrc, sctp_assoc_t source_ass
}
return target_du;
}
void trigger_f1_reset(gNB_RRC_INST *rrc, sctp_assoc_t du_assoc_id)
{
f1ap_reset_t reset = {
.transaction_id = F1AP_get_next_transaction_identifier(0, 0),
.cause = F1AP_CAUSE_TRANSPORT,
.cause_value = 1, // F1AP_CauseTransport_transport_resource_unavailable
.reset_type = F1AP_RESET_ALL, // DU does not support partial reset yet
};
rrc->mac_rrc.f1_reset(du_assoc_id, &reset);
}
......@@ -60,4 +60,6 @@ struct nr_rrc_du_container_t *find_target_du(struct gNB_RRC_INST_s *rrc, sctp_as
} \
}
void trigger_f1_reset(struct gNB_RRC_INST_s *rrc, sctp_assoc_t du_assoc_id);
#endif /* RRC_GNB_DU_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment