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.
This commit is contained in:
Robert Schmidt
2025-01-27 11:42:29 +01:00
10 changed files with 91 additions and 37 deletions
+35 -20
View File
@@ -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;
}
+1
View File
@@ -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);
+33 -1
View File
@@ -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;
}