Commit f6243e90 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/f1-ue-data-no-assert' into integration_2025_w04 (!3212)

F1AP IDs: Add update, fix concurrency bug

I suspect a concurrency bug: For instance, during reestablishment, the
CU needs to update the DU UE ID under which the UE is identified in the
DU. Previously, the CU would remove, then add the DU UE ID info. At the
same time, the PDCP thread might look up the information. This can lead
to asserts. Modify the code to do the update under (one) lock.

Also, refactor some code.
parents 2cecffb0 febeaa71
......@@ -29,6 +29,23 @@
#include "common/utils/assertions.h"
static f1_ue_data_t *get_hashtable_data(hash_table_t *ht, uint64_t ue_id)
{
void *data = NULL;
hashtable_rc_t ret = hashtable_get(ht, ue_id, &data);
AssertFatal(ret == HASH_TABLE_OK && data != NULL, "element for ue_id %ld not found\n", ue_id);
return data;
}
static bool add_hashtable_data(hash_table_t *ht, uint64_t ue_id, const f1_ue_data_t *data)
{
f1_ue_data_t *idata = malloc(sizeof(*idata));
AssertFatal(idata, "cannot allocate memory\n");
*idata = *data;
hashtable_rc_t ret = hashtable_insert(ht, ue_id, idata);
return ret == HASH_TABLE_OK;
}
/* we have separate versions for CU and DU, as both CU&DU might coexist in the
* same process */
static hash_table_t *cu2du_ue_mapping;
......@@ -52,12 +69,9 @@ bool cu_add_f1_ue_data(uint32_t ue_id, const f1_ue_data_t *data)
pthread_mutex_unlock(&cu2du_mutex);
return false;
}
f1_ue_data_t *idata = malloc(sizeof(*idata));
AssertFatal(idata, "cannot allocate memory\n");
*idata = *data;
hashtable_rc_t ret = hashtable_insert(cu2du_ue_mapping, key, idata);
bool ret = add_hashtable_data(cu2du_ue_mapping, key, data);
pthread_mutex_unlock(&cu2du_mutex);
return ret == HASH_TABLE_OK;
return ret;
}
bool cu_exists_f1_ue_data(uint32_t ue_id)
......@@ -70,15 +84,23 @@ bool cu_exists_f1_ue_data(uint32_t ue_id)
return ret == HASH_TABLE_OK;
}
f1_ue_data_t cu_get_f1_ue_data(uint32_t ue_id)
bool cu_update_f1_ue_data(uint32_t ue_id, const f1_ue_data_t *data)
{
pthread_mutex_lock(&cu2du_mutex);
DevAssert(cu2du_ue_mapping != NULL);
uint64_t key = ue_id;
void *data = NULL;
hashtable_rc_t ret = hashtable_get(cu2du_ue_mapping, key, &data);
AssertFatal(ret == HASH_TABLE_OK && data != NULL, "element for ue_id %d not found\n", ue_id);
f1_ue_data_t ued = *(f1_ue_data_t *)data;
hashtable_rc_t retrm = hashtable_remove(cu2du_ue_mapping, key);
AssertFatal(retrm == HASH_TABLE_OK, "could not remove UE %d, ret %d\n", ue_id, retrm);
bool ret = add_hashtable_data(cu2du_ue_mapping, key, data);
pthread_mutex_unlock(&cu2du_mutex);
return ret;
}
f1_ue_data_t cu_get_f1_ue_data(uint32_t ue_id)
{
pthread_mutex_lock(&cu2du_mutex);
DevAssert(cu2du_ue_mapping != NULL);
f1_ue_data_t ued = *get_hashtable_data(cu2du_ue_mapping, ue_id);
pthread_mutex_unlock(&cu2du_mutex);
return ued;
}
......@@ -115,12 +137,9 @@ bool du_add_f1_ue_data(uint32_t ue_id, const f1_ue_data_t *data)
pthread_mutex_unlock(&du2cu_mutex);
return false;
}
f1_ue_data_t *idata = malloc(sizeof(*idata));
AssertFatal(idata, "cannot allocate memory\n");
*idata = *data;
hashtable_rc_t ret = hashtable_insert(du2cu_ue_mapping, key, idata);
bool ret = add_hashtable_data(du2cu_ue_mapping, key, data);
pthread_mutex_unlock(&du2cu_mutex);
return ret == HASH_TABLE_OK;
return ret;
}
bool du_exists_f1_ue_data(uint32_t ue_id)
......@@ -137,11 +156,7 @@ f1_ue_data_t du_get_f1_ue_data(uint32_t ue_id)
{
pthread_mutex_lock(&du2cu_mutex);
DevAssert(du2cu_ue_mapping != NULL);
uint64_t key = ue_id;
void *data = NULL;
hashtable_rc_t ret = hashtable_get(du2cu_ue_mapping, key, &data);
AssertFatal(ret == HASH_TABLE_OK && data != NULL, "element for ue_id %d not found\n", ue_id);
f1_ue_data_t ued = *(f1_ue_data_t *)data;
f1_ue_data_t ued = *get_hashtable_data(du2cu_ue_mapping, ue_id);
pthread_mutex_unlock(&du2cu_mutex);
return ued;
}
......
......@@ -40,6 +40,7 @@ typedef struct f1_ue_data_t {
void cu_init_f1_ue_data(void);
bool cu_add_f1_ue_data(uint32_t ue_id, const f1_ue_data_t *data);
bool cu_exists_f1_ue_data(uint32_t ue_id);
bool cu_update_f1_ue_data(uint32_t ue_id, const f1_ue_data_t *data);
f1_ue_data_t cu_get_f1_ue_data(uint32_t ue_id);
bool cu_remove_f1_ue_data(uint32_t ue_id);
......
......@@ -25,7 +25,7 @@
#include "common/utils/assertions.h"
#include "f1ap_ids.h"
int main()
void du_data_test()
{
du_init_f1_ue_data();
int rnti = 13;
......@@ -38,5 +38,37 @@ int main()
DevAssert(exists);
f1_ue_data_t rdata = du_get_f1_ue_data(rnti);
DevAssert(rdata.secondary_ue == data.secondary_ue);
}
void cu_data_test()
{
cu_init_f1_ue_data();
int ue_id = 13;
f1_ue_data_t data = {.secondary_ue = 1};
bool ret = cu_add_f1_ue_data(ue_id, &data);
DevAssert(ret);
ret = cu_add_f1_ue_data(ue_id, &data);
DevAssert(!ret);
data.secondary_ue = 2;
ret = cu_update_f1_ue_data(ue_id, &data);
bool exists = cu_exists_f1_ue_data(ue_id);
DevAssert(exists);
f1_ue_data_t rdata = cu_get_f1_ue_data(ue_id);
DevAssert(rdata.secondary_ue == data.secondary_ue);
rdata.secondary_ue = 3;
// overwrite once more
ret = cu_update_f1_ue_data(ue_id, &rdata);
DevAssert(ret);
exists = cu_exists_f1_ue_data(ue_id);
DevAssert(exists);
f1_ue_data_t r2data = cu_get_f1_ue_data(ue_id);
DevAssert(r2data.secondary_ue == rdata.secondary_ue);
}
int main()
{
du_data_test();
cu_data_test();
return 0;
}
......@@ -482,7 +482,8 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id)
return NULL;
f1_ue_data_t new_ue_data = {.secondary_ue = cu_id};
du_add_f1_ue_data(rnti, &new_ue_data);
bool success = du_add_f1_ue_data(rnti, &new_ue_data);
DevAssert(success);
const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon;
const NR_ServingCellConfig_t *sccd = mac->common_channels[CC_id].pre_ServingCellConfig;
......@@ -826,7 +827,8 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
if (!du_exists_f1_ue_data(dl_rrc->gNB_DU_ue_id)) {
LOG_D(NR_MAC, "No CU UE ID stored for UE RNTI %04x, adding CU UE ID %d\n", dl_rrc->gNB_DU_ue_id, dl_rrc->gNB_CU_ue_id);
f1_ue_data_t new_ue_data = {.secondary_ue = dl_rrc->gNB_CU_ue_id};
du_add_f1_ue_data(dl_rrc->gNB_DU_ue_id, &new_ue_data);
bool success = du_add_f1_ue_data(dl_rrc->gNB_DU_ue_id, &new_ue_data);
DevAssert(success);
}
if (UE->expect_reconfiguration && dl_rrc->srb_id == 1) {
......
......@@ -150,7 +150,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
uint32_t cu_up_ue_id = req->gNB_cu_cp_ue_id;
f1_ue_data_t ued = {.secondary_ue = req->gNB_cu_cp_ue_id};
if (need_ue_id_mgmt) {
cu_add_f1_ue_data(cu_up_ue_id, &ued);
bool success = cu_add_f1_ue_data(cu_up_ue_id, &ued);
DevAssert(success);
LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, cu_up_ue_id);
}
......
......@@ -1185,8 +1185,8 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
/* update to old DU assoc id -- RNTI + secondary DU UE ID further below */
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
ue_data.du_assoc_id = source_ctx->du->assoc_id;
cu_remove_f1_ue_data(UE->rrc_ue_id);
cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data);
bool success = cu_update_f1_ue_data(UE->rrc_ue_id, &ue_data);
DevAssert(success);
nr_rrc_finalize_ho(UE);
} else if (physCellId != cell_info->nr_pci) {
/* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */
......@@ -1216,8 +1216,8 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
UE->nr_cellid = msg->nr_cellid;
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
ue_data.secondary_ue = msg->gNB_DU_ue_id;
cu_remove_f1_ue_data(UE->rrc_ue_id);
cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data);
bool success = cu_update_f1_ue_data(UE->rrc_ue_id, &ue_data);
DevAssert(success);
rrc_gNB_generate_RRCReestablishment(ue_context_p, msg->du2cu_rrc_container, old_rnti, du);
return;
......@@ -2150,8 +2150,8 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
ue_data.secondary_ue = target_ctx->du_ue_id;
ue_data.du_assoc_id = target_ctx->du->assoc_id;
cu_remove_f1_ue_data(UE->rrc_ue_id);
cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data);
bool success = cu_update_f1_ue_data(UE->rrc_ue_id, &ue_data);
DevAssert(success);
LOG_I(NR_RRC, "UE %d handover: update RNTI from %04x to %04x\n", UE->rrc_ue_id, UE->rnti, target_ctx->new_rnti);
nr_ho_source_cu_t *source_ctx = UE->ho_context->source;
DevAssert(source_ctx->old_rnti == UE->rnti);
......
......@@ -204,7 +204,8 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id,
AssertFatal(!cu_exists_f1_ue_data(ue->rrc_ue_id),
"UE F1 Context for ID %d already exists, logic bug\n",
ue->rrc_ue_id);
cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
bool success = cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
DevAssert(success);
RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p);
LOG_UE_EVENT(ue,
......
......@@ -142,8 +142,8 @@ sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue
/* update the association for the UE so it will be picked up later */
ue_data.e1_assoc_id = selected->assoc_id;
cu_remove_f1_ue_data(ue->rrc_ue_id);
cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
bool success = cu_update_f1_ue_data(ue->rrc_ue_id, &ue_data);
DevAssert(success);
LOG_I(RRC, "UE %d associating to CU-UP assoc_id %d out of %ld CU-UPs\n", ue->rrc_ue_id, ue_data.e1_assoc_id, rrc->num_cuups);
return ue_data.e1_assoc_id;
......
......@@ -426,9 +426,9 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
if (ue_data.du_assoc_id == assoc_id) {
/* this UE belongs to the DU that disconnected, set du_assoc_id to 0,
* meaning DU is offline, then trigger release request */
cu_remove_f1_ue_data(ue_id);
ue_data.du_assoc_id = 0;
cu_add_f1_ue_data(ue_id, &ue_data);
bool success = cu_update_f1_ue_data(ue_id, &ue_data);
DevAssert(success);
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, ue_context_p, cause);
count++;
......
......@@ -355,9 +355,11 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a
uint32_t du_ue_id = ue_context_p->ue_context.rnti;
uint32_t rrc_ue_id = ue_context_p->ue_context.rrc_ue_id;
f1_ue_data_t du_ue_data = {.secondary_ue = rrc_ue_id};
du_add_f1_ue_data(du_ue_id, &du_ue_data);
bool success = du_add_f1_ue_data(du_ue_id, &du_ue_data);
DevAssert(success);
f1_ue_data_t cu_ue_data = {.secondary_ue = du_ue_id};
cu_add_f1_ue_data(rrc_ue_id, &cu_ue_data);
success = cu_add_f1_ue_data(rrc_ue_id, &cu_ue_data);
DevAssert(success);
LOG_I(RRC, "Assign CU UE ID %d and DU UE ID %d to UE RNTI %04x\n", rrc_ue_id, du_ue_id, ue_context_p->ue_context.rnti);
// configure MAC and RLC
......
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