From 5354ad8a26f694c55b27b867ffd054004db720f0 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 10 Apr 2025 21:12:44 +0200 Subject: [PATCH 01/51] Add support for TYPE_IPV4ADDR in yaml config module --- common/config/yaml/config_yaml.cpp | 15 ++++++++++ common/config/yaml/tests/CMakeLists.txt | 1 + common/config/yaml/tests/test_ipv4.yaml | 4 +++ common/config/yaml/tests/test_yaml_config.cpp | 30 +++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 common/config/yaml/tests/test_ipv4.yaml diff --git a/common/config/yaml/config_yaml.cpp b/common/config/yaml/config_yaml.cpp index 108dee1ac2..138163ce0e 100644 --- a/common/config/yaml/config_yaml.cpp +++ b/common/config/yaml/config_yaml.cpp @@ -25,6 +25,8 @@ extern "C" { #include "common/config/config_userapi.h" void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree); void config_check_valptr(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int elt_sz, int nb_elt); +#include "../config_userapi.h" +#include "../config_common.h" } #include #include @@ -98,6 +100,9 @@ void SetDefault(configmodule_interface_t *cfg, paramdef_t *param) param->uptr = (uint32_t *)param->defintarrayval; } break; + case TYPE_IPV4ADDR: + config_setdefault_ipv4addr(cfg, param, param->defstrval); + break; default: AssertFatal(false, "Unhandled type %d", param->type); } @@ -186,6 +191,16 @@ void SetNonDefault(configmodule_interface_t *cfg, const YAML::Node &node, paramd } break; } + case TYPE_IPV4ADDR: { + std::string ipv4addr = node[optname].as(); + char* ipv4addr_ptr = strdup(ipv4addr.c_str()); + int rst = config_assign_ipv4addr(cfg, param, ipv4addr_ptr); + free(ipv4addr_ptr); + if (rst < 0) { + fprintf(stderr,"[LIBCONFIG] %s not valid for %s \n", ipv4addr.c_str(), optname.c_str()); + } + break; + } default: AssertFatal(false, "Unhandled type %d", param->type); } diff --git a/common/config/yaml/tests/CMakeLists.txt b/common/config/yaml/tests/CMakeLists.txt index 6290f2fc15..d33fa57658 100644 --- a/common/config/yaml/tests/CMakeLists.txt +++ b/common/config/yaml/tests/CMakeLists.txt @@ -10,3 +10,4 @@ configure_file(test_string.yaml test_string.yaml COPYONLY) configure_file(test_list_of_mappings.yml test_list_of_mappings.yml COPYONLY) configure_file(test_int_array.yaml test_int_array.yaml COPYONLY) configure_file(test_read_mapping_as_list.yaml test_read_mapping_as_list.yaml COPYONLY) +configure_file(test_ipv4.yaml test_ipv4.yaml COPYONLY) diff --git a/common/config/yaml/tests/test_ipv4.yaml b/common/config/yaml/tests/test_ipv4.yaml new file mode 100644 index 0000000000..c7d1b4866f --- /dev/null +++ b/common/config/yaml/tests/test_ipv4.yaml @@ -0,0 +1,4 @@ +test: + ipv4_1: 0.0.0.0 + ipv4_2: 192.168.0.1 + #ipv4_3: check default diff --git a/common/config/yaml/tests/test_yaml_config.cpp b/common/config/yaml/tests/test_yaml_config.cpp index deaa52cd1a..384a1f406c 100644 --- a/common/config/yaml/tests/test_yaml_config.cpp +++ b/common/config/yaml/tests/test_yaml_config.cpp @@ -391,6 +391,36 @@ TEST(yaml_config, test_read_mapping_as_list) { end_configmodule(cfg); } +TEST(yaml_config, test_read_ipv4) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_ipv4.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t p = {}; + p.type = TYPE_IPV4ADDR; + strncpy(p.optname, "ipv4_1", sizeof(p.optname) - 1); + uint32_t addr = 0; + p.uptr = &addr; + p.defstrval = nullptr; + char prefix[] = "test"; + config_yaml_get(cfg, &p, 1, prefix); + printf("%x\n", addr); + + strncpy(p.optname, "ipv4_2", sizeof(p.optname) - 1); + config_yaml_get(cfg, &p, 1, prefix); + printf("%x\n", addr); + + p.defstrval = strdup("10.0.0.1"); + strncpy(p.optname, "ipv4_3", sizeof(p.optname) - 1); + config_yaml_get(cfg, &p, 1, prefix); + printf("%x\n", addr); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); + free(p.defstrval); +} + int main(int argc, char** argv) { logInit(); From 729b0eb34814596e2d3bce5c28e0717cdafaa681 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 28 Apr 2025 10:14:38 +0200 Subject: [PATCH 02/51] Print errno in nr_sdap_rx_entity --- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index d93a508c33..7f2f3dd07c 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -329,7 +329,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, LOG_D(SDAP, "RX Entity offset : %d\n", offset); if (len != size-offset) - LOG_E(SDAP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + LOG_E(SDAP, "write failed to fd %d! errno = %s\n", entity->pdusession_sock, strerror(errno)); } } From ce1766301711f0eb0369a8d3168605ed17a46163 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 28 Apr 2025 15:38:06 +0200 Subject: [PATCH 03/51] Release all user plane resources when going to IDLE Release all SDAP entities for a UE in nr_rrc_going_to_IDLE(). With this change the SDAP entities of the UE are cleaned up when going into RRC_IDLE, including tun sockets, threads etc. A new SDAP entity is created when re-attaching to the network. --- openair2/RRC/NR_UE/rrc_UE.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index b36c2d676d..4abc712507 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2562,6 +2562,9 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, nr_pdcp_release_drb(rrc->ue_id, i); } } + // stop TUN threads and clean up SDAP entities + nr_sdap_delete_ue_entities(rrc->ue_id); + for (int i = 1; i < NR_NUM_SRB; i++) { if (rrc->Srb[i] != RB_NOT_PRESENT) { rrc->Srb[i] = RB_NOT_PRESENT; From 084bbb0363da9e1db6435c1fd33a834f6faf0875 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 07:48:50 +0000 Subject: [PATCH 04/51] nrLDPC_coding_t2: also support newer DPDK versions --- .../PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt index 5b89d36f38..f64384568a 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt @@ -7,7 +7,7 @@ add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 libr if (ENABLE_LDPC_T2) - pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk=20.11.9) + pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk>=20.11.9) find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS}) if (NOT PMD_T2) From d8b3bfd17b57a70abd68c21eaa970157be9dd83f Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 08:11:32 +0000 Subject: [PATCH 05/51] nrLDPC_coding_t2: use nb_segments_decoding() and nb_segments_encoding() to calculate num_segments --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 6eb8f0dacc..2e9756ead4 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -1036,16 +1036,14 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec pthread_mutex_lock(&decode_mutex); - uint16_t num_blocks = 0; - for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ - num_blocks += nrLDPC_slot_decoding_parameters->TBs[h].C; - } + const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters); + uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); /* It is not unlikely that l_ol becomes big enough to overflow the stack * If you observe this behavior then move it to the heap * Then you would better do a persistent allocation to limit the overhead */ - uint8_t l_ol[num_blocks * LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); + uint8_t l_ol[num_segments * LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); // hardcoded we use first device struct active_device *ad = active_devs; @@ -1082,7 +1080,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec } for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { - ret = allocate_buffers_on_socket(queue_ops[type], num_blocks * sizeof(struct rte_bbdev_op_data), socket_id); + ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); ret = init_op_data_objs_dec(*queue_ops[type], l_ol, @@ -1107,6 +1105,9 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc pthread_mutex_lock(&encode_mutex); if (nrLDPC_slot_encoding_parameters->tprep != NULL) start_meas(nrLDPC_slot_encoding_parameters->tprep); + + const uint16_t num_segments = nb_segments_encoding(nrLDPC_slot_encoding_parameters); + // hardcoded to use the first found board struct active_device *ad = active_devs; int ret; @@ -1126,12 +1127,8 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc &op_params->q_bufs[socket_id][queue_id].hard_outputs, &op_params->q_bufs[socket_id][queue_id].harq_inputs, &op_params->q_bufs[socket_id][queue_id].harq_outputs}; - uint16_t num_blocks = 0; - for(uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ - num_blocks += nrLDPC_slot_encoding_parameters->TBs[h].C; - } for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { - ret = allocate_buffers_on_socket(queue_ops[type], num_blocks * sizeof(struct rte_bbdev_op_data), socket_id); + ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); ret = init_op_data_objs_enc(*queue_ops[type], nrLDPC_slot_encoding_parameters, From 1612ba33a8a9be870df0ad36981385b242b05dd0 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 08:48:12 +0000 Subject: [PATCH 06/51] nrLDPC_coding_t2: remove unused soft_outputs, harq_inputs and harq_outputs elements --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 65 +++++-------------- .../nrLDPC_coding_t2/nrLDPC_coding_t2.h | 3 - 2 files changed, 15 insertions(+), 53 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 2e9756ead4..5a7cc75c3f 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -76,9 +76,6 @@ struct active_device { struct rte_mempool *bbdev_enc_op_pool; struct rte_mempool *in_mbuf_pool; struct rte_mempool *hard_out_mbuf_pool; - struct rte_mempool *soft_out_mbuf_pool; - struct rte_mempool *harq_in_mbuf_pool; - struct rte_mempool *harq_out_mbuf_pool; } active_devs[RTE_BBDEV_MAX_DEVS]; static int nb_active_devs; @@ -86,9 +83,6 @@ static int nb_active_devs; struct data_buffers { struct rte_bbdev_op_data *inputs; struct rte_bbdev_op_data *hard_outputs; - struct rte_bbdev_op_data *soft_outputs; - struct rte_bbdev_op_data *harq_inputs; - struct rte_bbdev_op_data *harq_outputs; }; /* Operation parameters specific for given test case */ @@ -395,9 +389,9 @@ static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs, bufs[j].data = m_head; bufs[j].offset = 0; bufs[j].length = 0; - - if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) { - if ((op_type == DATA_INPUT) && large_input) { + + if (op_type == DATA_INPUT) { + if (large_input) { /* Allocate a fake overused mbuf */ data = rte_malloc(NULL, data_len, 0); AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len); @@ -452,9 +446,9 @@ static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, bufs[j].data = m_head; bufs[j].offset = 0; bufs[j].length = 0; - - if ((op_type == DATA_INPUT) || (op_type == DATA_HARQ_INPUT)) { - if ((op_type == DATA_INPUT) && large_input) { + + if (op_type == DATA_INPUT) { + if (large_input) { /* Allocate a fake overused mbuf */ data = rte_malloc(NULL, data_len, 0); AssertFatal(data != NULL, "rte malloc failed with %u bytes", data_len); @@ -509,17 +503,11 @@ free_buffers(struct active_device *ad, struct test_op_params *op_params) rte_mempool_free(ad->bbdev_enc_op_pool); rte_mempool_free(ad->in_mbuf_pool); rte_mempool_free(ad->hard_out_mbuf_pool); - rte_mempool_free(ad->soft_out_mbuf_pool); - rte_mempool_free(ad->harq_in_mbuf_pool); - rte_mempool_free(ad->harq_out_mbuf_pool); for (int i = 2; i < rte_lcore_count(); ++i) { for (int j = 0; j < RTE_MAX_NUMA_NODES; ++j) { rte_free(op_params->q_bufs[j][i].inputs); rte_free(op_params->q_bufs[j][i].hard_outputs); - rte_free(op_params->q_bufs[j][i].soft_outputs); - rte_free(op_params->q_bufs[j][i].harq_inputs); - rte_free(op_params->q_bufs[j][i].harq_outputs); } } } @@ -571,16 +559,8 @@ set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, ops[j]->ldpc_dec.harq_combined_input.offset = harq_combined_offset; ops[j]->ldpc_dec.harq_combined_output.offset = harq_combined_offset; - if (bufs->hard_outputs != NULL) - ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + j]; - if (bufs->inputs != NULL) - ops[j]->ldpc_dec.input = bufs->inputs[start_idx + j]; - if (bufs->soft_outputs != NULL) - ops[j]->ldpc_dec.soft_output = bufs->soft_outputs[start_idx + j]; - if (bufs->harq_inputs != NULL) - ops[j]->ldpc_dec.harq_combined_input = bufs->harq_inputs[start_idx + j]; - if (bufs->harq_outputs != NULL) - ops[j]->ldpc_dec.harq_combined_output = bufs->harq_outputs[start_idx + j]; + ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + j]; + ops[j]->ldpc_dec.input = bufs->inputs[start_idx + j]; ++j; } } @@ -1052,18 +1032,10 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec rte_bbdev_info_get(ad->dev_id, &info); int socket_id = GET_SOCKET(info.socket_id); // fill_queue_buffers -> init_op_data_objs - struct rte_mempool *in_mp = ad->in_mbuf_pool; - struct rte_mempool *hard_out_mp = ad->hard_out_mbuf_pool; - struct rte_mempool *soft_out_mp = ad->soft_out_mbuf_pool; - struct rte_mempool *harq_in_mp = ad->harq_in_mbuf_pool; - struct rte_mempool *harq_out_mp = ad->harq_out_mbuf_pool; - struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {in_mp, soft_out_mp, hard_out_mp, harq_in_mp, harq_out_mp}; + struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {ad->in_mbuf_pool, ad->hard_out_mbuf_pool}; uint8_t queue_id = ad->dec_queue; struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, - &op_params->q_bufs[socket_id][queue_id].soft_outputs, - &op_params->q_bufs[socket_id][queue_id].hard_outputs, - &op_params->q_bufs[socket_id][queue_id].harq_inputs, - &op_params->q_bufs[socket_id][queue_id].harq_outputs}; + &op_params->q_bufs[socket_id][queue_id].hard_outputs}; int offset = 0; for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ @@ -1079,7 +1051,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec } } - for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { + for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); ret = init_op_data_objs_dec(*queue_ops[type], @@ -1115,19 +1087,12 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc rte_bbdev_info_get(ad->dev_id, &info); int socket_id = GET_SOCKET(info.socket_id); // fill_queue_buffers -> init_op_data_objs - struct rte_mempool *in_mp = ad->in_mbuf_pool; - struct rte_mempool *hard_out_mp = ad->hard_out_mbuf_pool; - struct rte_mempool *soft_out_mp = ad->soft_out_mbuf_pool; - struct rte_mempool *harq_in_mp = ad->harq_in_mbuf_pool; - struct rte_mempool *harq_out_mp = ad->harq_out_mbuf_pool; - struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {in_mp, soft_out_mp, hard_out_mp, harq_in_mp, harq_out_mp}; + struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {ad->in_mbuf_pool, ad->hard_out_mbuf_pool}; uint8_t queue_id = ad->enc_queue; struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, - &op_params->q_bufs[socket_id][queue_id].soft_outputs, - &op_params->q_bufs[socket_id][queue_id].hard_outputs, - &op_params->q_bufs[socket_id][queue_id].harq_inputs, - &op_params->q_bufs[socket_id][queue_id].harq_outputs}; - for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) { + &op_params->q_bufs[socket_id][queue_id].hard_outputs}; + + for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); ret = init_op_data_objs_enc(*queue_ops[type], diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h index 9da33f4671..642ac8f55a 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h @@ -16,10 +16,7 @@ enum op_data_type { DATA_INPUT = 0, - DATA_SOFT_OUTPUT, DATA_HARD_OUTPUT, - DATA_HARQ_INPUT, - DATA_HARQ_OUTPUT, DATA_NUM_TYPES, }; From ac9a8f017b23b8a0b2b9389985caa9d5cac5f988 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 08:58:15 +0000 Subject: [PATCH 07/51] nrLDPC_coding_t2 fix: make sure to free allocated mbufs The DPDK driver may directly provide the internal HW mbuf in the dequeued structure. So don't try to free the mbufs from that dequeued structure, but the ones we allocated. --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 5a7cc75c3f..6a26316f1c 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -618,8 +618,6 @@ retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, data_len = rte_pktmbuf_data_len(m) - hard_output->offset; data = m->buf_addr; memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data + m->data_off, data_len); - rte_pktmbuf_free(ops[j]->ldpc_dec.hard_output.data); - rte_pktmbuf_free(ops[j]->ldpc_dec.input.data); ++j; } } @@ -668,8 +666,6 @@ retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, E_sum += nrLDPC_slot_encoding_parameters->TBs[h].segments[r].E; byte_offset = (E_sum + 7) / 8; bit_offset = E_sum % 8; - rte_pktmbuf_free(m); - rte_pktmbuf_free(ops[j]->ldpc_enc.input.data); ++j; } } @@ -1068,6 +1064,11 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec LOG_E(PHY, "Couldn't start pmd dec\n"); } + for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { + for (int segment = 0; segment < num_segments; ++segment) + rte_pktmbuf_free((*queue_ops[type])[segment].data); + } + pthread_mutex_unlock(&decode_mutex); return 0; } @@ -1104,6 +1105,12 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); } ret = start_pmd_enc(ad, op_params, nrLDPC_slot_encoding_parameters); + + for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { + for (int segment = 0; segment < num_segments; ++segment) + rte_pktmbuf_free((*queue_ops[type])[segment].data); + } + pthread_mutex_unlock(&encode_mutex); return ret; } From 48e78ff4b000d9538be1006de0069b1315c32996 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 09:09:31 +0000 Subject: [PATCH 08/51] nrLDPC_coding_t2: fix q_bufs memory leak --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 6a26316f1c..17f1dac69c 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -496,20 +496,12 @@ static int allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const } // DPDK BBDEV copy -static void -free_buffers(struct active_device *ad, struct test_op_params *op_params) +static void free_mempools(struct active_device *ad) { rte_mempool_free(ad->bbdev_dec_op_pool); rte_mempool_free(ad->bbdev_enc_op_pool); rte_mempool_free(ad->in_mbuf_pool); rte_mempool_free(ad->hard_out_mbuf_pool); - - for (int i = 2; i < rte_lcore_count(); ++i) { - for (int j = 0; j < RTE_MAX_NUMA_NODES; ++j) { - rte_free(op_params->q_bufs[j][i].inputs); - rte_free(op_params->q_bufs[j][i].hard_outputs); - } - } } // based on DPDK BBDEV copy_reference_ldpc_dec_op @@ -998,7 +990,7 @@ int32_t nrLDPC_coding_shutdown() struct active_device *ad = active_devs; int dev_id = 0; struct rte_bbdev_stats stats; - free_buffers(ad, op_params); + free_mempools(ad); rte_free(op_params); rte_bbdev_stats_get(dev_id, &stats); rte_bbdev_stop(dev_id); @@ -1067,6 +1059,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { for (int segment = 0; segment < num_segments; ++segment) rte_pktmbuf_free((*queue_ops[type])[segment].data); + rte_free(*queue_ops[type]); } pthread_mutex_unlock(&decode_mutex); @@ -1109,6 +1102,7 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { for (int segment = 0; segment < num_segments; ++segment) rte_pktmbuf_free((*queue_ops[type])[segment].data); + rte_free(*queue_ops[type]); } pthread_mutex_unlock(&encode_mutex); From 300346c43afffa413b21c24308acdeff6366f596 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 09:30:39 +0000 Subject: [PATCH 09/51] nrLDPC_coding_t2: replace global q_bufs by struct data_buffers on stack --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 17f1dac69c..04e41268f8 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -96,7 +96,6 @@ struct test_op_params { uint16_t num_lcores; int vector_mask; rte_atomic16_t sync; - struct data_buffers q_bufs[RTE_MAX_NUMA_NODES][MAX_QUEUES]; }; /* Contains per lcore params */ @@ -113,6 +112,7 @@ struct thread_params { struct test_op_params *op_params; struct rte_bbdev_dec_op *dec_ops[MAX_BURST]; struct rte_bbdev_enc_op *enc_ops[MAX_BURST]; + struct data_buffers *data_buffers; }; static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { @@ -703,7 +703,7 @@ pmd_lcore_ldpc_dec(void *arg) struct rte_bbdev_dec_op **ops_deq; ops_enq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); ops_deq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); - struct data_buffers *bufs = NULL; + struct data_buffers *bufs = tp->data_buffers; uint16_t h, i, j; int ret; struct rte_bbdev_info info; @@ -712,7 +712,6 @@ pmd_lcore_ldpc_dec(void *arg) AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); rte_bbdev_info_get(tp->dev_id, &info); - bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) rte_pause(); @@ -793,13 +792,13 @@ static int pmd_lcore_ldpc_enc(void *arg) ops_deq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); struct rte_bbdev_info info; int ret; - struct data_buffers *bufs = NULL; + struct data_buffers *bufs = tp->data_buffers; uint16_t num_to_enq; AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); rte_bbdev_info_get(tp->dev_id, &info); - bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; + while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) rte_pause(); ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp_enc, ops_enq, num_segments); @@ -840,6 +839,7 @@ static int pmd_lcore_ldpc_enc(void *arg) // based on DPDK BBDEV throughput_pmd_lcore_dec int start_pmd_dec(struct active_device *ad, struct test_op_params *op_params, + struct data_buffers *data_buffers, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { int ret; @@ -857,6 +857,7 @@ int start_pmd_dec(struct active_device *ad, t_params[0].dev_id = ad->dev_id; t_params[0].lcore_id = rte_lcore_id(); t_params[0].op_params = op_params; + t_params[0].data_buffers = data_buffers; t_params[0].queue_id = ad->dec_queue; t_params[0].iter_count = 0; t_params[0].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; @@ -868,6 +869,7 @@ int start_pmd_dec(struct active_device *ad, t_params[used_cores].dev_id = ad->dev_id; t_params[used_cores].lcore_id = lcore_id; t_params[used_cores].op_params = op_params; + t_params[used_cores].data_buffers = data_buffers; t_params[used_cores].queue_id = ad->queue_ids[used_cores]; t_params[used_cores].iter_count = 0; t_params[used_cores].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; @@ -885,6 +887,7 @@ int start_pmd_dec(struct active_device *ad, // based on DPDK BBDEV throughput_pmd_lcore_enc int32_t start_pmd_enc(struct active_device *ad, struct test_op_params *op_params, + struct data_buffers *data_buffers, nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { unsigned int lcore_id, used_cores = 0; @@ -896,6 +899,7 @@ int32_t start_pmd_enc(struct active_device *ad, t_params[0].dev_id = ad->dev_id; t_params[0].lcore_id = rte_lcore_id() + 1; t_params[0].op_params = op_params; + t_params[0].data_buffers = data_buffers; t_params[0].queue_id = ad->enc_queue; t_params[0].iter_count = 0; t_params[0].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; @@ -907,6 +911,7 @@ int32_t start_pmd_enc(struct active_device *ad, t_params[used_cores].dev_id = ad->dev_id; t_params[used_cores].lcore_id = lcore_id; t_params[used_cores].op_params = op_params; + t_params[used_cores].data_buffers = data_buffers; t_params[used_cores].queue_id = ad->queue_ids[1]; t_params[used_cores].iter_count = 0; t_params[used_cores].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; @@ -1021,9 +1026,8 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec int socket_id = GET_SOCKET(info.socket_id); // fill_queue_buffers -> init_op_data_objs struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {ad->in_mbuf_pool, ad->hard_out_mbuf_pool}; - uint8_t queue_id = ad->dec_queue; - struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, - &op_params->q_bufs[socket_id][queue_id].hard_outputs}; + struct data_buffers data_buffers; + struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&data_buffers.inputs, &data_buffers.hard_outputs}; int offset = 0; for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ @@ -1051,7 +1055,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); } - ret = start_pmd_dec(ad, op_params, nrLDPC_slot_decoding_parameters); + ret = start_pmd_dec(ad, op_params, &data_buffers, nrLDPC_slot_decoding_parameters); if (ret < 0) { LOG_E(PHY, "Couldn't start pmd dec\n"); } @@ -1082,9 +1086,8 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc int socket_id = GET_SOCKET(info.socket_id); // fill_queue_buffers -> init_op_data_objs struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {ad->in_mbuf_pool, ad->hard_out_mbuf_pool}; - uint8_t queue_id = ad->enc_queue; - struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&op_params->q_bufs[socket_id][queue_id].inputs, - &op_params->q_bufs[socket_id][queue_id].hard_outputs}; + struct data_buffers data_buffers; + struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&data_buffers.inputs, &data_buffers.hard_outputs}; for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); @@ -1097,7 +1100,8 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc info.drv.min_alignment); AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); } - ret = start_pmd_enc(ad, op_params, nrLDPC_slot_encoding_parameters); + + ret = start_pmd_enc(ad, op_params, &data_buffers, nrLDPC_slot_encoding_parameters); for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { for (int segment = 0; segment < num_segments; ++segment) From e45aff7763058332c2078c4899ce593ac1066872 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 09:43:51 +0000 Subject: [PATCH 10/51] nrLDPC_coding_t2: replace global mp_dec and mp_enc by bbdev_op_pool in thread_params --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 04e41268f8..644eb38d62 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -87,8 +87,6 @@ struct data_buffers { /* Operation parameters specific for given test case */ struct test_op_params { - struct rte_mempool *mp_dec; - struct rte_mempool *mp_enc; struct rte_bbdev_dec_op *ref_dec_op; struct rte_bbdev_enc_op *ref_enc_op; uint16_t burst_sz; @@ -113,6 +111,7 @@ struct thread_params { struct rte_bbdev_dec_op *dec_ops[MAX_BURST]; struct rte_bbdev_enc_op *enc_ops[MAX_BURST]; struct data_buffers *data_buffers; + struct rte_mempool *bbdev_op_pool; }; static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { @@ -675,10 +674,8 @@ static int init_test_op_params(struct test_op_params *op_params, int ret = 0; if (op_type == RTE_BBDEV_OP_LDPC_DEC) { ret = rte_bbdev_dec_op_alloc_bulk(ops_mp, &op_params->ref_dec_op, num_to_process); - op_params->mp_dec = ops_mp; } else { ret = rte_bbdev_enc_op_alloc_bulk(ops_mp, &op_params->ref_enc_op, 1); - op_params->mp_enc = ops_mp; } AssertFatal(ret == 0, "rte_bbdev_op_alloc_bulk() failed"); @@ -705,7 +702,6 @@ pmd_lcore_ldpc_dec(void *arg) ops_deq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); struct data_buffers *bufs = tp->data_buffers; uint16_t h, i, j; - int ret; struct rte_bbdev_info info; uint16_t num_to_enq; @@ -715,7 +711,7 @@ pmd_lcore_ldpc_dec(void *arg) while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) rte_pause(); - ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp_dec, ops_enq, num_segments); + int ret = rte_bbdev_dec_op_alloc_bulk(tp->bbdev_op_pool, ops_enq, num_segments); AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); set_ldpc_dec_op(ops_enq, 0, bufs, nrLDPC_slot_decoding_parameters); @@ -791,7 +787,6 @@ static int pmd_lcore_ldpc_enc(void *arg) ops_enq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); ops_deq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); struct rte_bbdev_info info; - int ret; struct data_buffers *bufs = tp->data_buffers; uint16_t num_to_enq; @@ -801,7 +796,8 @@ static int pmd_lcore_ldpc_enc(void *arg) while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) rte_pause(); - ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp_enc, ops_enq, num_segments); + + int ret = rte_bbdev_enc_op_alloc_bulk(tp->bbdev_op_pool, ops_enq, num_segments); AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); set_ldpc_enc_op(ops_enq, 0, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_encoding_parameters); @@ -858,6 +854,7 @@ int start_pmd_dec(struct active_device *ad, t_params[0].lcore_id = rte_lcore_id(); t_params[0].op_params = op_params; t_params[0].data_buffers = data_buffers; + t_params[0].bbdev_op_pool = ad->bbdev_dec_op_pool; t_params[0].queue_id = ad->dec_queue; t_params[0].iter_count = 0; t_params[0].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; @@ -870,6 +867,7 @@ int start_pmd_dec(struct active_device *ad, t_params[used_cores].lcore_id = lcore_id; t_params[used_cores].op_params = op_params; t_params[used_cores].data_buffers = data_buffers; + t_params[used_cores].bbdev_op_pool = ad->bbdev_dec_op_pool; t_params[used_cores].queue_id = ad->queue_ids[used_cores]; t_params[used_cores].iter_count = 0; t_params[used_cores].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; @@ -900,6 +898,7 @@ int32_t start_pmd_enc(struct active_device *ad, t_params[0].lcore_id = rte_lcore_id() + 1; t_params[0].op_params = op_params; t_params[0].data_buffers = data_buffers; + t_params[0].bbdev_op_pool = ad->bbdev_enc_op_pool; t_params[0].queue_id = ad->enc_queue; t_params[0].iter_count = 0; t_params[0].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; @@ -912,6 +911,7 @@ int32_t start_pmd_enc(struct active_device *ad, t_params[used_cores].lcore_id = lcore_id; t_params[used_cores].op_params = op_params; t_params[used_cores].data_buffers = data_buffers; + t_params[used_cores].bbdev_op_pool = ad->bbdev_enc_op_pool; t_params[used_cores].queue_id = ad->queue_ids[1]; t_params[used_cores].iter_count = 0; t_params[used_cores].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; From f47b549f416696762b800de21ac2ddaa73445483 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 09:57:44 +0000 Subject: [PATCH 11/51] nrLDPC_coding_t2: remove unused rte_bbdev_dec_op from test_op_params and thread_params --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 644eb38d62..a215adb210 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -87,8 +87,6 @@ struct data_buffers { /* Operation parameters specific for given test case */ struct test_op_params { - struct rte_bbdev_dec_op *ref_dec_op; - struct rte_bbdev_enc_op *ref_enc_op; uint16_t burst_sz; uint16_t num_to_process; uint16_t num_lcores; @@ -108,8 +106,6 @@ struct thread_params { rte_atomic16_t processing_status; rte_atomic16_t burst_sz; struct test_op_params *op_params; - struct rte_bbdev_dec_op *dec_ops[MAX_BURST]; - struct rte_bbdev_enc_op *enc_ops[MAX_BURST]; struct data_buffers *data_buffers; struct rte_mempool *bbdev_op_pool; }; @@ -671,15 +667,6 @@ static int init_test_op_params(struct test_op_params *op_params, uint16_t num_to_process, uint16_t num_lcores) { - int ret = 0; - if (op_type == RTE_BBDEV_OP_LDPC_DEC) { - ret = rte_bbdev_dec_op_alloc_bulk(ops_mp, &op_params->ref_dec_op, num_to_process); - } else { - ret = rte_bbdev_enc_op_alloc_bulk(ops_mp, &op_params->ref_enc_op, 1); - } - - AssertFatal(ret == 0, "rte_bbdev_op_alloc_bulk() failed"); - op_params->burst_sz = burst_sz; op_params->num_to_process = num_to_process; op_params->num_lcores = num_lcores; From 73c6d1fb621c6e9fcb2a41f01ee83fdf1387bee6 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:02:42 +0000 Subject: [PATCH 12/51] nrLDPC_coding_t2: remove unused burst_sz --- .../CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index a215adb210..821b23f61f 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -87,7 +87,6 @@ struct data_buffers { /* Operation parameters specific for given test case */ struct test_op_params { - uint16_t burst_sz; uint16_t num_to_process; uint16_t num_lcores; int vector_mask; @@ -104,7 +103,6 @@ struct thread_params { uint8_t iter_count; rte_atomic16_t nb_dequeued; rte_atomic16_t processing_status; - rte_atomic16_t burst_sz; struct test_op_params *op_params; struct data_buffers *data_buffers; struct rte_mempool *bbdev_op_pool; @@ -667,7 +665,6 @@ static int init_test_op_params(struct test_op_params *op_params, uint16_t num_to_process, uint16_t num_lcores) { - op_params->burst_sz = burst_sz; op_params->num_to_process = num_to_process; op_params->num_lcores = num_lcores; return 0; From ea7e6ffb0b7251184875dc7d1cadf9b079b2761d Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:04:56 +0000 Subject: [PATCH 13/51] nrLDPC_coding_t2: remove unused num_to_process --- .../CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 821b23f61f..ae741992ff 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -87,7 +87,6 @@ struct data_buffers { /* Operation parameters specific for given test case */ struct test_op_params { - uint16_t num_to_process; uint16_t num_lcores; int vector_mask; rte_atomic16_t sync; @@ -665,7 +664,6 @@ static int init_test_op_params(struct test_op_params *op_params, uint16_t num_to_process, uint16_t num_lcores) { - op_params->num_to_process = num_to_process; op_params->num_lcores = num_lcores; return 0; } From b02e6e8ddd51c6c91ea3938b1fd5d60ae38591c8 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:06:48 +0000 Subject: [PATCH 14/51] nrLDPC_coding_t2: inline and remove now nearly empty init_test_op_params() --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index ae741992ff..acece39884 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -656,18 +656,6 @@ retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, return 0; } -// based on DPDK BBDEV init_test_op_params -static int init_test_op_params(struct test_op_params *op_params, - enum rte_bbdev_op_type op_type, - struct rte_mempool *ops_mp, - uint16_t burst_sz, - uint16_t num_to_process, - uint16_t num_lcores) -{ - op_params->num_lcores = num_lcores; - return 0; -} - // based on DPDK BBDEV throughput_pmd_lcore_ldpc_dec static int pmd_lcore_ldpc_dec(void *arg) @@ -963,12 +951,7 @@ int32_t nrLDPC_coding_init() printf("Couldn't create mempools"); return -1; } - f_ret = init_test_op_params(op_params, RTE_BBDEV_OP_LDPC_DEC, ad->bbdev_dec_op_pool, num_queues, num_queues, 1); - f_ret = init_test_op_params(op_params, RTE_BBDEV_OP_LDPC_ENC, ad->bbdev_enc_op_pool, num_queues, num_queues, 1); - if (f_ret != 0) { - printf("Couldn't init test op params"); - return -1; - } + op_params->num_lcores = 1; return 0; } From 4dde956e8428a402314aeede1755ca8bc6eba9f0 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:11:32 +0000 Subject: [PATCH 15/51] nrLDPC_coding_t2: remove unused vector_mask --- .../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index acece39884..3cd364cf49 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -88,7 +88,6 @@ struct data_buffers { /* Operation parameters specific for given test case */ struct test_op_params { uint16_t num_lcores; - int vector_mask; rte_atomic16_t sync; }; @@ -583,10 +582,7 @@ set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, } } -static int -retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, - const int vector_mask, - nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { struct rte_bbdev_op_data *hard_output; uint16_t data_len = 0; @@ -701,7 +697,7 @@ pmd_lcore_ldpc_dec(void *arg) DevAssert(time_out <= TIME_OUT_POLL); } if (deq == enq) { - ret = retrieve_ldpc_dec_op(ops_deq, tp->op_params->vector_mask, nrLDPC_slot_decoding_parameters); + ret = retrieve_ldpc_dec_op(ops_deq, nrLDPC_slot_decoding_parameters); AssertFatal(ret == 0, "LDPC offload decoder failed!"); tp->iter_count = 0; /* get the max of iter_count for all dequeued ops */ From adbf056abb946a50f67e74149da5a381a1b12caa Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:14:30 +0000 Subject: [PATCH 16/51] nrLDPC_coding_t2: remove unused global variable m_head --- .../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 3cd364cf49..cab1b6b442 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -412,7 +412,6 @@ static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs, // based on DPDK BBDEV init_op_data_objs static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters, - struct rte_mbuf *m_head, struct rte_mempool *mbuf_pool, enum op_data_type op_type, uint16_t min_alignment) @@ -891,8 +890,6 @@ int32_t start_pmd_enc(struct active_device *ad, struct test_op_params *op_params = NULL; -struct rte_mbuf *m_head[DATA_NUM_TYPES]; - // OAI CODE int32_t nrLDPC_coding_init() { @@ -1053,12 +1050,7 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); - ret = init_op_data_objs_enc(*queue_ops[type], - nrLDPC_slot_encoding_parameters, - m_head[type], - mbuf_pools[type], - type, - info.drv.min_alignment); + ret = init_op_data_objs_enc(*queue_ops[type], nrLDPC_slot_encoding_parameters, mbuf_pools[type], type, info.drv.min_alignment); AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); } From c1e057bc8b239f7b9bdb221bb1fadb113158a035 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:22:38 +0000 Subject: [PATCH 17/51] nrLDPC_coding_t2: remove unused atomic variables nb_dequeued and processing_status --- .../CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index cab1b6b442..691e06b684 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -99,8 +99,6 @@ struct thread_params { nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters; nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters; uint8_t iter_count; - rte_atomic16_t nb_dequeued; - rte_atomic16_t processing_status; struct test_op_params *op_params; struct data_buffers *data_buffers; struct rte_mempool *bbdev_op_pool; From 07ff8a27c4eb95fdff1a7b2e86568d519794dc51 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:27:05 +0000 Subject: [PATCH 18/51] nrLDPC_coding_t2: remove unused functions mbuf_reset() and check_bit() --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 691e06b684..68bfa5ef2d 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -122,26 +122,6 @@ static uint16_t nb_segments_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_s return nb_segments; } -// DPDK BBDEV copy -static inline void -mbuf_reset(struct rte_mbuf *m) -{ - m->pkt_len = 0; - - do { - m->data_len = 0; - m = m->next; - } while (m != NULL); -} - -/* Read flag value 0/1 from bitmap */ -// DPDK BBDEV copy -static inline bool -check_bit(uint32_t bitmap, uint32_t bitmask) -{ - return bitmap & bitmask; -} - /* calculates optimal mempool size not smaller than the val */ // DPDK BBDEV copy static unsigned int From b5c9e13df35fca124780ac0ed8f846d9159c4fcd Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:32:12 +0000 Subject: [PATCH 19/51] nrLDPC_coding_t2: remove unused #define HARQ_INCR --- .../CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 68bfa5ef2d..ac1308ecd0 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -45,8 +45,6 @@ #define SYNC_WAIT 0 #define SYNC_START 1 #define TIME_OUT_POLL 1e8 -/* Increment for next code block in external HARQ memory */ -#define HARQ_INCR 32768 /* Headroom for filler LLRs insertion in HARQ buffer */ #define FILLER_HEADROOM 1024 /* Number of segments that could be stored in HARQ combined buffers */ From d442461bd13e0ca7075932b1a648169afb2f3507 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:49:10 +0000 Subject: [PATCH 20/51] nrLDPC_coding_t2: remove unused start_idx from set_ldpc_enc_op() and set_ldpc_dec_op() --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index ac1308ecd0..6f047e8a31 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -473,7 +473,6 @@ static void free_mempools(struct active_device *ad) // based on DPDK BBDEV copy_reference_ldpc_dec_op static void set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, - unsigned int start_idx, struct data_buffers *bufs, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { @@ -517,8 +516,8 @@ set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, ops[j]->ldpc_dec.harq_combined_input.offset = harq_combined_offset; ops[j]->ldpc_dec.harq_combined_output.offset = harq_combined_offset; - ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[start_idx + j]; - ops[j]->ldpc_dec.input = bufs->inputs[start_idx + j]; + ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[j]; + ops[j]->ldpc_dec.input = bufs->inputs[j]; ++j; } } @@ -527,7 +526,6 @@ set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, // based on DPDK BBDEV copy_reference_ldpc_enc_op static void set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, - unsigned int start_idx, struct rte_bbdev_op_data *inputs, struct rte_bbdev_op_data *outputs, nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) @@ -550,8 +548,8 @@ set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, ops[j]->ldpc_enc.rv_index = nrLDPC_slot_encoding_parameters->TBs[h].rv_index; ops[j]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH; ops[j]->ldpc_enc.code_block_mode = 1; - ops[j]->ldpc_enc.output = outputs[start_idx + j]; - ops[j]->ldpc_enc.input = inputs[start_idx + j]; + ops[j]->ldpc_enc.output = outputs[j]; + ops[j]->ldpc_enc.input = inputs[j]; ++j; } } @@ -654,7 +652,7 @@ pmd_lcore_ldpc_dec(void *arg) int ret = rte_bbdev_dec_op_alloc_bulk(tp->bbdev_op_pool, ops_enq, num_segments); AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); - set_ldpc_dec_op(ops_enq, 0, bufs, nrLDPC_slot_decoding_parameters); + set_ldpc_dec_op(ops_enq, bufs, nrLDPC_slot_decoding_parameters); for (enq = 0, deq = 0; enq < num_segments;) { num_to_enq = num_segments; @@ -740,8 +738,8 @@ static int pmd_lcore_ldpc_enc(void *arg) int ret = rte_bbdev_enc_op_alloc_bulk(tp->bbdev_op_pool, ops_enq, num_segments); AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); + set_ldpc_enc_op(ops_enq, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_encoding_parameters); - set_ldpc_enc_op(ops_enq, 0, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_encoding_parameters); if (nrLDPC_slot_encoding_parameters->tprep != NULL) stop_meas(nrLDPC_slot_encoding_parameters->tprep); if (nrLDPC_slot_encoding_parameters->tparity != NULL) From af7054554ba4d98abb8fc9c05b8ee96bc678901a Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 10:52:32 +0000 Subject: [PATCH 21/51] nrLDPC_coding_t2: make parameters for set_ldpc_dec_op() more smilar to set_ldpc_enc_op() --- .../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 6f047e8a31..7729bec58c 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -473,7 +473,8 @@ static void free_mempools(struct active_device *ad) // based on DPDK BBDEV copy_reference_ldpc_dec_op static void set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, - struct data_buffers *bufs, + struct rte_bbdev_op_data *inputs, + struct rte_bbdev_op_data *outputs, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { unsigned int h; @@ -516,8 +517,8 @@ set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, ops[j]->ldpc_dec.harq_combined_input.offset = harq_combined_offset; ops[j]->ldpc_dec.harq_combined_output.offset = harq_combined_offset; - ops[j]->ldpc_dec.hard_output = bufs->hard_outputs[j]; - ops[j]->ldpc_dec.input = bufs->inputs[j]; + ops[j]->ldpc_dec.hard_output = outputs[j]; + ops[j]->ldpc_dec.input = inputs[j]; ++j; } } @@ -652,7 +653,7 @@ pmd_lcore_ldpc_dec(void *arg) int ret = rte_bbdev_dec_op_alloc_bulk(tp->bbdev_op_pool, ops_enq, num_segments); AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); - set_ldpc_dec_op(ops_enq, bufs, nrLDPC_slot_decoding_parameters); + set_ldpc_dec_op(ops_enq, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_decoding_parameters); for (enq = 0, deq = 0; enq < num_segments;) { num_to_enq = num_segments; From 2df487fc8b78362ee397fadca94a2082288641fc Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 11:02:58 +0000 Subject: [PATCH 22/51] nrLDPC_coding_t2: use rte_bbdev_op_type_str() instead of hardcoded array of strings --- .../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 7729bec58c..9a18342e56 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -53,15 +53,6 @@ pthread_mutex_t encode_mutex; pthread_mutex_t decode_mutex; -const char *typeStr[] = { - "RTE_BBDEV_OP_NONE", /**< Dummy operation that does nothing */ - "RTE_BBDEV_OP_TURBO_DEC", /**< Turbo decode */ - "RTE_BBDEV_OP_TURBO_ENC", /**< Turbo encode */ - "RTE_BBDEV_OP_LDPC_DEC", /**< LDPC decode */ - "RTE_BBDEV_OP_LDPC_ENC", /**< LDPC encode */ - "RTE_BBDEV_OP_TYPE_COUNT", /**< Count of different op types */ -}; - /* Represents tested active devices */ struct active_device { const char *driver_name; @@ -259,7 +250,7 @@ static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info) /* Display for debug the capabilities of the card */ for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { - printf("device: %d, capability[%d]=%s\n", dev_id, i, typeStr[info->drv.capabilities[i].type]); + printf("device: %d, capability[%d]=%s\n", dev_id, i, rte_bbdev_op_type_str(info->drv.capabilities[i].type)); if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_ENC) { const struct rte_bbdev_op_cap_ldpc_enc cap = info->drv.capabilities[i].cap.ldpc_enc; printf(" buffers: src = %d, dst = %d\n capabilites: ", cap.num_buffers_src, cap.num_buffers_dst); From 944ac15ab514aa639e40d854ef44806a2ab972ad Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 11:06:26 +0000 Subject: [PATCH 23/51] nrLDPC_coding_t2: allocate array of rte_bbdev_dec_op pointers on stack instead of heap --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 9a18342e56..87b9229541 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -627,10 +627,8 @@ pmd_lcore_ldpc_dec(void *arg) int time_out = 0; const uint16_t queue_id = tp->queue_id; const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters); - struct rte_bbdev_dec_op **ops_enq; - struct rte_bbdev_dec_op **ops_deq; - ops_enq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); - ops_deq = (struct rte_bbdev_dec_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_dec_op *), RTE_CACHE_LINE_SIZE); + struct rte_bbdev_dec_op *ops_enq[num_segments]; + struct rte_bbdev_dec_op *ops_deq[num_segments]; struct data_buffers *bufs = tp->data_buffers; uint16_t h, i, j; struct rte_bbdev_info info; @@ -698,8 +696,6 @@ pmd_lcore_ldpc_dec(void *arg) } rte_bbdev_dec_op_free_bulk(ops_enq, num_segments); - rte_free(ops_enq); - rte_free(ops_deq); // Return the worst decoding number of iterations for all segments return tp->iter_count; } @@ -713,10 +709,8 @@ static int pmd_lcore_ldpc_enc(void *arg) int time_out = 0; const uint16_t queue_id = tp->queue_id; const uint16_t num_segments = nb_segments_encoding(nrLDPC_slot_encoding_parameters); - struct rte_bbdev_enc_op **ops_enq; - struct rte_bbdev_enc_op **ops_deq; - ops_enq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_enq", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); - ops_deq = (struct rte_bbdev_enc_op **)rte_calloc("struct rte_bbdev_dec_op **ops_dec", num_segments, sizeof(struct rte_bbdev_enc_op *), RTE_CACHE_LINE_SIZE); + struct rte_bbdev_enc_op *ops_enq[num_segments]; + struct rte_bbdev_enc_op *ops_deq[num_segments]; struct rte_bbdev_info info; struct data_buffers *bufs = tp->data_buffers; uint16_t num_to_enq; @@ -758,8 +752,6 @@ static int pmd_lcore_ldpc_enc(void *arg) if (nrLDPC_slot_encoding_parameters->toutput != NULL) stop_meas(nrLDPC_slot_encoding_parameters->toutput); rte_bbdev_enc_op_free_bulk(ops_enq, num_segments); - rte_free(ops_enq); - rte_free(ops_deq); return ret; } From c3d0b2db5c6e8d4ed13e684a3d1fc97ac5b5af81 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 11:13:54 +0000 Subject: [PATCH 24/51] nrLDPC_coding_t2 fix: use rte_pktmbuf_mtod_offset() to consider offset when accessing output data --- .../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 87b9229541..e738e7cc5e 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -552,7 +552,7 @@ static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, nrLDPC_slot_decod struct rte_bbdev_op_data *hard_output; uint16_t data_len = 0; struct rte_mbuf *m; - char *data; + uint8_t *data; unsigned int h; unsigned int i; unsigned int j = 0; @@ -561,8 +561,8 @@ static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, nrLDPC_slot_decod hard_output = &ops[j]->ldpc_dec.hard_output; m = hard_output->data; data_len = rte_pktmbuf_data_len(m) - hard_output->offset; - data = m->buf_addr; - memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data + m->data_off, data_len); + data = rte_pktmbuf_mtod_offset(m, uint8_t *, hard_output->offset); + memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data, data_len); ++j; } } @@ -584,7 +584,7 @@ retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, struct rte_bbdev_op_data *output = &ops[j]->ldpc_enc.output; struct rte_mbuf *m = output->data; uint16_t data_len = rte_pktmbuf_data_len(m) - output->offset; - uint8_t *data = m->buf_addr + m->data_off; + uint8_t *data = rte_pktmbuf_mtod_offset(m, uint8_t *, output->offset); reverse_bits_u8(data, data_len, data); if (bit_offset == 0) { memcpy(&p_out[byte_offset], data, data_len); From ffb8e8ff37b48a8da840bce41f3d3b13a0bdebb9 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 11:26:17 +0000 Subject: [PATCH 25/51] nrLDPC_coding_t2: nb_TBs is of type int --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 55 ++++++++----------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index e738e7cc5e..0cbca9d5fb 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -95,8 +95,7 @@ struct thread_params { static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { uint16_t nb_segments = 0; - for (uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) - { + for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { nb_segments+=nrLDPC_slot_decoding_parameters->TBs[h].C; } return nb_segments; @@ -104,8 +103,7 @@ static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_s static uint16_t nb_segments_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { uint16_t nb_segments = 0; - for (uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) - { + for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { nb_segments+=nrLDPC_slot_encoding_parameters->TBs[h].C; } return nb_segments; @@ -328,9 +326,9 @@ static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs, uint16_t min_alignment) { bool large_input = false; - uint16_t j = 0; - for (uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { - for (uint16_t i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + int j = 0; + for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { + for (int i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { uint32_t data_len = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; char *data; struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool); @@ -384,8 +382,8 @@ static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, uint16_t min_alignment) { bool large_input = false; - uint16_t j = 0; - for (uint16_t h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { + int j = 0; + for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { for (int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { uint32_t data_len = (nrLDPC_slot_encoding_parameters->TBs[h].K - nrLDPC_slot_encoding_parameters->TBs[h].F + 7) / 8; char *data; @@ -468,11 +466,9 @@ set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, struct rte_bbdev_op_data *outputs, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { - unsigned int h; - unsigned int i; - unsigned int j = 0; - for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ - for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + int j = 0; + for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { + for (int i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { ops[j]->ldpc_dec.cb_params.e = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; ops[j]->ldpc_dec.basegraph = nrLDPC_slot_decoding_parameters->TBs[h].BG; ops[j]->ldpc_dec.z_c = nrLDPC_slot_decoding_parameters->TBs[h].Z; @@ -522,11 +518,9 @@ set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, struct rte_bbdev_op_data *outputs, nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { - unsigned int h; - unsigned int i; - unsigned int j = 0; - for (h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ - for (i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { + int j = 0; + for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { + for (int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { ops[j]->ldpc_enc.cb_params.e = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E; ops[j]->ldpc_enc.basegraph = nrLDPC_slot_encoding_parameters->TBs[h].BG; ops[j]->ldpc_enc.z_c = nrLDPC_slot_encoding_parameters->TBs[h].Z; @@ -553,11 +547,9 @@ static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, nrLDPC_slot_decod uint16_t data_len = 0; struct rte_mbuf *m; uint8_t *data; - unsigned int h; - unsigned int i; - unsigned int j = 0; - for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ - for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + int j = 0; + for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { + for (int i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { hard_output = &ops[j]->ldpc_dec.hard_output; m = hard_output->data; data_len = rte_pktmbuf_data_len(m) - hard_output->offset; @@ -574,13 +566,13 @@ retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { uint8_t *p_out = NULL; - unsigned int j = 0; - for (unsigned int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ + int j = 0; + for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ int E_sum = 0; int bit_offset = 0; int byte_offset = 0; p_out = nrLDPC_slot_encoding_parameters->TBs[h].output; - for (unsigned int r = 0; r < nrLDPC_slot_encoding_parameters->TBs[h].C; ++r) { + for (int r = 0; r < nrLDPC_slot_encoding_parameters->TBs[h].C; ++r) { struct rte_bbdev_op_data *output = &ops[j]->ldpc_enc.output; struct rte_mbuf *m = output->data; uint16_t data_len = rte_pktmbuf_data_len(m) - output->offset; @@ -630,7 +622,6 @@ pmd_lcore_ldpc_dec(void *arg) struct rte_bbdev_dec_op *ops_enq[num_segments]; struct rte_bbdev_dec_op *ops_deq[num_segments]; struct data_buffers *bufs = tp->data_buffers; - uint16_t h, i, j; struct rte_bbdev_info info; uint16_t num_to_enq; @@ -664,9 +655,9 @@ pmd_lcore_ldpc_dec(void *arg) AssertFatal(ret == 0, "LDPC offload decoder failed!"); tp->iter_count = 0; /* get the max of iter_count for all dequeued ops */ - j = 0; - for (h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ - for (i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { + int j = 0; + for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { + for (int i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { bool *status = &nrLDPC_slot_decoding_parameters->TBs[h].segments[i].decodeSuccess; tp->iter_count = RTE_MAX(ops_enq[j]->ldpc_dec.iter_count, tp->iter_count); @@ -946,7 +937,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&data_buffers.inputs, &data_buffers.hard_outputs}; int offset = 0; - for(uint16_t h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h){ + for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { for (int r = 0; r < nrLDPC_slot_decoding_parameters->TBs[h].C; r++) { memcpy(z_ol, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t)); simde__m128i *pv_ol128 = (simde__m128i *)z_ol; From 073a705720116a8889ca3918beba76a29b1a3c85 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 11:31:42 +0000 Subject: [PATCH 26/51] nrLDPC_coding_t2: minor cleanup --- .../nrLDPC_coding_t2/nrLDPC_coding_t2.c | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 0cbca9d5fb..6960959e50 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -543,17 +543,13 @@ set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { - struct rte_bbdev_op_data *hard_output; - uint16_t data_len = 0; - struct rte_mbuf *m; - uint8_t *data; int j = 0; for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { for (int i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { - hard_output = &ops[j]->ldpc_dec.hard_output; - m = hard_output->data; - data_len = rte_pktmbuf_data_len(m) - hard_output->offset; - data = rte_pktmbuf_mtod_offset(m, uint8_t *, hard_output->offset); + struct rte_bbdev_op_data *hard_output = &ops[j]->ldpc_dec.hard_output; + struct rte_mbuf *m = hard_output->data; + uint16_t data_len = rte_pktmbuf_data_len(m) - hard_output->offset; + uint8_t *data = rte_pktmbuf_mtod_offset(m, uint8_t *, hard_output->offset); memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data, data_len); ++j; } @@ -615,17 +611,16 @@ pmd_lcore_ldpc_dec(void *arg) { struct thread_params *tp = arg; nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters = tp->nrLDPC_slot_decoding_parameters; - uint16_t enq, deq; int time_out = 0; const uint16_t queue_id = tp->queue_id; const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters); struct rte_bbdev_dec_op *ops_enq[num_segments]; struct rte_bbdev_dec_op *ops_deq[num_segments]; struct data_buffers *bufs = tp->data_buffers; - struct rte_bbdev_info info; - uint16_t num_to_enq; AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); + + struct rte_bbdev_info info; rte_bbdev_info_get(tp->dev_id, &info); while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) @@ -635,21 +630,19 @@ pmd_lcore_ldpc_dec(void *arg) AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); set_ldpc_dec_op(ops_enq, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_decoding_parameters); - for (enq = 0, deq = 0; enq < num_segments;) { - num_to_enq = num_segments; - if (unlikely(num_segments - enq < num_to_enq)) - num_to_enq = num_segments - enq; - + uint16_t enq = 0, deq = 0; + while (enq < num_segments) { + uint16_t num_to_enq = num_segments - enq; enq += rte_bbdev_enqueue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_enq[enq], num_to_enq); deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); } - /* dequeue the remaining */ while (deq < enq) { deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); time_out++; DevAssert(time_out <= TIME_OUT_POLL); } + if (deq == enq) { ret = retrieve_ldpc_dec_op(ops_deq, nrLDPC_slot_decoding_parameters); AssertFatal(ret == 0, "LDPC offload decoder failed!"); @@ -696,18 +689,16 @@ static int pmd_lcore_ldpc_enc(void *arg) { struct thread_params *tp = arg; nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters = tp->nrLDPC_slot_encoding_parameters; - uint16_t enq, deq; int time_out = 0; const uint16_t queue_id = tp->queue_id; const uint16_t num_segments = nb_segments_encoding(nrLDPC_slot_encoding_parameters); struct rte_bbdev_enc_op *ops_enq[num_segments]; struct rte_bbdev_enc_op *ops_deq[num_segments]; - struct rte_bbdev_info info; struct data_buffers *bufs = tp->data_buffers; - uint16_t num_to_enq; AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); + struct rte_bbdev_info info; rte_bbdev_info_get(tp->dev_id, &info); while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) @@ -721,10 +712,10 @@ static int pmd_lcore_ldpc_enc(void *arg) stop_meas(nrLDPC_slot_encoding_parameters->tprep); if (nrLDPC_slot_encoding_parameters->tparity != NULL) start_meas(nrLDPC_slot_encoding_parameters->tparity); - for (enq = 0, deq = 0; enq < num_segments;) { - num_to_enq = num_segments; - if (unlikely(num_segments - enq < num_to_enq)) - num_to_enq = num_segments - enq; + + uint16_t enq = 0, deq = 0; + while (enq < num_segments) { + uint16_t num_to_enq = num_segments - enq; enq += rte_bbdev_enqueue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_enq[enq], num_to_enq); deq += rte_bbdev_dequeue_ldpc_enc_ops(tp->dev_id, queue_id, &ops_deq[deq], enq - deq); } @@ -752,11 +743,9 @@ int start_pmd_dec(struct active_device *ad, struct data_buffers *data_buffers, nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { - int ret; unsigned int lcore_id, used_cores = 0; - uint16_t num_lcores; /* Set number of lcores */ - num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores; + int num_lcores = (ad->nb_queues < (op_params->num_lcores)) ? ad->nb_queues : op_params->num_lcores; /* Allocate memory for thread parameters structure */ struct thread_params *t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), RTE_CACHE_LINE_SIZE); AssertFatal(t_params != 0, @@ -788,7 +777,7 @@ int start_pmd_dec(struct active_device *ad, rte_eal_remote_launch(pmd_lcore_ldpc_dec, &t_params[used_cores++], lcore_id); } rte_atomic16_set(&op_params->sync, SYNC_START); - ret = pmd_lcore_ldpc_dec(&t_params[0]); + int ret = pmd_lcore_ldpc_dec(&t_params[0]); /* Master core is always used */ // for (used_cores = 1; used_cores < num_lcores; used_cores++) // ret |= rte_eal_wait_lcore(t_params[used_cores].lcore_id); @@ -912,13 +901,12 @@ int32_t nrLDPC_coding_shutdown() return 0; } -int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters){ - +int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +{ pthread_mutex_lock(&decode_mutex); const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters); - uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); /* It is not unlikely that l_ol becomes big enough to overflow the stack * If you observe this behavior then move it to the heap * Then you would better do a persistent allocation to limit the overhead @@ -939,6 +927,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec int offset = 0; for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { for (int r = 0; r < nrLDPC_slot_decoding_parameters->TBs[h].C; r++) { + uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); memcpy(z_ol, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t)); simde__m128i *pv_ol128 = (simde__m128i *)z_ol; simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset]; From b264ddc1ec88664e2e6b0532507ec9642119dbb9 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Fri, 2 May 2025 12:01:16 +0000 Subject: [PATCH 27/51] nrLDPC_coding_t2 fix: convert the correct number of LLRs from 16 Bit to 8 Bit --- .../CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c index 6960959e50..04ad571de0 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c @@ -931,8 +931,7 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec memcpy(z_ol, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t)); simde__m128i *pv_ol128 = (simde__m128i *)z_ol; simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset]; - int kc = nrLDPC_slot_decoding_parameters->TBs[h].BG == 2 ? 52 : 68; - for (int i = 0, j = 0; j < ((kc * nrLDPC_slot_decoding_parameters->TBs[h].Z) >> 4) + 1; i += 2, j++) { + for (int i = 0, j = 0; j < ((nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E + 15) >> 4); i += 2, j++) { pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]); } offset += LDPC_MAX_CB_SIZE; From 6638839177f81257d044b628b7640ad8804a9459 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 May 2025 16:42:32 +0200 Subject: [PATCH 28/51] Update NAS documentation with information about NAS 5GS and OAI implementation status --- doc/5Gnas.md | 96 +++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/doc/5Gnas.md b/doc/5Gnas.md index db0c19f07e..f3e3b8beeb 100644 --- a/doc/5Gnas.md +++ b/doc/5Gnas.md @@ -1,39 +1,63 @@ - +# About 5GS NAS +The 5G System Non-Access Stratum (5GS NAS) is defined in 3GPP TS 24.501. It operates within the control plane, facilitating communication between the User Equipment (UE) and the Access and Mobility Management Function (AMF) over the N1 interface. -This tuto for 5G gNB NAS design -{: .text-center} +Key 5GS NAS messages: -# source files +* Mobility Management (5GMM): Handles UE registration, deregistration, authentication and tracking area updates. 5GMM also manages transitions between idle and connected states. +* Session Management (5GSM): Establishes, modifies, and releases PDU sessions. Coordinates with the Session Management Function (SMF) to manage user-plane resources. -openair2/RRC/NR/nr_ngap_gNB.c: skeleton for interface with NGAP -openair3/NAS/COMMON/milenage.h: a simple milenage implementation, depend only on crypto library -openair3/NAS/COMMON/NR_NAS_defs.h: messages defined for NAS implemented in C: C struct, C enums and automatic conversion to labels for debug messages -openair3/NAS/COMMON/nr_common.c: 5G NAS common code between gNB and UE -openair3/UICC/usim_interface.c: UICC simulation for USIM messages +# OAI Implementation Status -openair3/NAS/NR_UE/ue_process_nas.c: NAS code for UE +The following tables lists implemented NAS messages and whether there is an encoder or decoder function, and if a corresponding unit test exists. -openair3/NAS/gNB/network_process_nas.c: NAS code for gNB running without 5GC +| Type | Message | Encoding | Decoding | Unit test | +|-------|-------------------------------------------|----------|----------|------------| +| 5GMM | Service Request | yes | yes | yes | +| 5GMM | Service Accept | yes | yes | yes | +| 5GMM | Service Reject | yes | yes | yes | +| 5GMM | Authentication Response | yes | no | no | +| 5GMM | Identity Response | yes | no | no | +| 5GMM | Security Mode Complete | yes | no | no | +| 5GMM | Uplink NAS Transport | yes | no | no | +| 5GMM | Registration Request | yes | yes | no | +| 5GMM | Registration Accept | yes | yes | yes | +| 5GMM | Registration Complete | yes | yes | no | +| 5GMM | Deregistration Request (UE originating) | yes | no | no | +| 5GSM | PDU Session Establishment Request | yes | no | no | +| 5GSM | PDU Session Establishment Accept | no | yes | no | -openair3/TEST/test5Gnas.c: unitary testing of NAS messages: encodes+decode a standard network entry, mixing code from UE and 5GC (or gNB in noCore) +## Code Structure + +[openair3/NAS/NR_UE/nr_nas_msg.c](../openair3/NAS/NR_UE/nr_nas_msg.c): +* NAS procedures and message handlers/callbacks +* Integration with RRC (ITTI) and SDAP +* Invokes enc/dec libraries +* Handles 5GMM state and mode + +[openair3/NAS/NR_UE/5GS/fgs_nas_lib.c](../openair3/NAS/NR_UE/5GS/fgs_nas_lib.c): +[openair3/NAS/NR_UE/5GS/NR_NAS_defs.h](../openair3/NAS/NR_UE/5GS/NR_NAS_defs.h): +* encoding and decoding functions for 5G NAS message headers and payloads +* relies on 5GMM/5GSM messages libs for payload encoding + +[openair3/NAS/NR_UE/5GS/fgs_nas_utils.h](../openair3/NAS/NR_UE/5GS/fgs_nas_utils.h): +* NAS helpers, macros + +[openair3/NAS/NR_UE/5GS/5GMM](../openair3/NAS/NR_UE/5GS/5GMM): +* encoding/decoding functions and definitions for 5GMM NAS messages payloads + +[openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c](../openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c): +[openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h](../openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h): +* encoding/decoding functions and definitions for common 5GMM IEs + +[openair3/NAS/NR_UE/5GS/5GSM](../openair3/NAS/NR_UE/5GS/5GSM): +* encoding and decoding functions for 5GSM NAS messages payloads # USIM simulation A new USIM simulation, that parameters are in regular OAI config files @@ -44,10 +68,6 @@ In case we run several UEs in one process, the variable section name allows to m The NAS implementation uses this possibility. -# UE side -UEprocessNAS() is the entry for all messages. -It decodes the message type and call the specific function for each messgae - ## Identityrequest + IdentityResponse When the UE receives the request, it stores the 5GC request parameters in the UE context ( UE->uicc pointer) It calls "scheduleNAS", that would trigger a answer (seeing general archtecture, it will probly be a itti message to future RRC or NGAP thread). @@ -88,19 +108,3 @@ Here after, the gNB mode "noCore" processing in gNB: NGAP calls the entry functi When the gNB completes RRC attach, it sends a first message to NGAP thread. Normal processing sends NGAP initial UE message, in noCore mode, it should call: identityRequest() that encode the NAS identity request inside the gNB. The gNB NGAP thread then should call the piece of code that forward the message to the UE as when it receives a NAS message from 5GC. - -## All NAS coming from UE -When NGAP thread receives a NAS message from lower layers, it encapsulates it to forward it to the 5GC. In "noCore" mode it calls processNAS(). - -This function stores in the gNB the NAS data, then it should encode the next message (identity, authentication, security mode) or do nothing (registration complete). - - -
-**Note** -{: .panel-heading} -
- - -
-
- From 4eb55f83ab94e8d5852b04cec59fbf0a9c2b16e4 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 20 May 2025 15:18:07 +0200 Subject: [PATCH 29/51] Remove gNB NAS documentation section: noCore function is no longer supported --- doc/5Gnas.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/doc/5Gnas.md b/doc/5Gnas.md index f3e3b8beeb..d6ae26cb27 100644 --- a/doc/5Gnas.md +++ b/doc/5Gnas.md @@ -97,14 +97,3 @@ When the scheduler wants to encode the answer, it calls registrationComplete() ## registrationComplete To be defined in UE, this NAS message is done after RRC sequence completes - -# gNB side -gNB NGAP thread receives the NAS message from PHY layers -In normal mode, it send it to the core network with no decoding. - -Here after, the gNB mode "noCore" processing in gNB: NGAP calls the entry function: processNAS() instead of forwarding the packet to the 5GC - -## RRCModeComplete + Identityrequest -When the gNB completes RRC attach, it sends a first message to NGAP thread. -Normal processing sends NGAP initial UE message, in noCore mode, it should call: identityRequest() that encode the NAS identity request inside the gNB. -The gNB NGAP thread then should call the piece of code that forward the message to the UE as when it receives a NAS message from 5GC. From 278a0bcc67787402a28d006e595281d9c080e897 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 20 May 2025 15:46:08 +0200 Subject: [PATCH 30/51] Update USIM section in 5GS NAS documentation --- doc/5Gnas.md | 68 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/doc/5Gnas.md b/doc/5Gnas.md index d6ae26cb27..a120ed2173 100644 --- a/doc/5Gnas.md +++ b/doc/5Gnas.md @@ -59,41 +59,51 @@ The following tables lists implemented NAS messages and whether there is an enco [openair3/NAS/NR_UE/5GS/5GSM](../openair3/NAS/NR_UE/5GS/5GSM): * encoding and decoding functions for 5GSM NAS messages payloads -# USIM simulation -A new USIM simulation, that parameters are in regular OAI config files +# USIM Simulation -## To open the USIM -init_uicc() takes a parameter: the name of the block in the config file -In case we run several UEs in one process, the variable section name allows to make several UEs configurations in one config file. +OAI includes a simulated USIM implementation that reads its parameters from standard configuration files. This allows for rapid prototyping and testing without relying on a physical UICC card. The USIM-related configuration is handled via the `init_uicc()` function. -The NAS implementation uses this possibility. +## Configuration -## Identityrequest + IdentityResponse -When the UE receives the request, it stores the 5GC request parameters in the UE context ( UE->uicc pointer) -It calls "scheduleNAS", that would trigger a answer (seeing general archtecture, it will probly be a itti message to future RRC or NGAP thread). +The simulation reads values from a named section in the config file. -When the scheduler wants to encode the answer, it calls identityResponse() -The UE search for a section in the config file called "uicc" -it encodes the NAS answer with the IMSI, as a 4G compatible authentication. -A future release would encode 5G SUPI as native 5G UICC. +**Config options in the `uicc` section**: -## Authenticationrequest + authenticationResponse -When the UE receives the request, it stores the 5GC request parameters in the UE context ( UE->uicc pointer) -It calls "scheduleNAS", that would trigger a answer (seeing general archtecture, it will probly be a itti message to future RRC or NGAP thread). +| Parameter | Description | Default value | +|---------------|-----------------------------------|--------------------------------------------| +| `imsi` | User IMSI | `2089900007487` | +| `nmc_size` | Number of digits in NMC | `2` | +| `key` | Subscription key (Ki) | `fec86ba6eb707ed08905757b1bb44b8f` | +| `opc` | OPc value | `c42449363bbad02b66d16bc975d77cc1` | +| `amf` | AMF value | `8000` | +| `sqn` | Sequence number | `000000` | +| `dnn` | Default DNN (APN) | `oai` | +| `nssai_sst` | NSSAI slice/service type | `1` | +| `nssai_sd` | NSSAI slice differentiator | `0xffffff` | +| `imeisv` | IMEISV string | `6754567890123413` | -When the scheduler wants to encode the answer, it calls authenticationResponse() -The UE search for a section in the config file called "uicc" -It uses the Milenage parameters of this section to encode a milenage response -A future release would encode 5G new authentication cyphering functions. +These are parsed and stored in the `uicc_t` structure. -## SecurityModeCommand + securityModeComplete -When the UE receives the request it will: -Selected NAS security algorithms: store it for future encoding -Replayed UE security capabilities: check if it is equal to UE capabilities it sent to the 5GC -IMEISV request: to implement -ngKSI: Key set Indicator, similator to 4G to select a ciphering keys set +## Initialization -When the scheduler wants to encode the answer, it calls registrationComplete() +The UE calls `init_uicc` via `checkUicc` to allocate memory for the `uicc_t` structure member and load parameters using `config_get()` from the selected config section. Then the UICC structure is stored in the NAS context. `nr_ue_nas_t`, to be used to fill identity and security credentials when generating responses to 5GC messages such as `Identity Response`, `Authentication Response`, and `Security Mode Complete`. + +## Milenage Authentication and Key Derivation + +When the UE receives a **5GMM Authentication Request**, the function `generateAuthenticationResp` generates a valid `Authentication Response` with the necessary derived NAS and AS security keys. The function `derive_ue_keys` parses the Authentication Request and performs the entire 5G AKA key hierarchy: + +* Extracts the `RAND` and `SQN` +* Performs Milenage Algorithms f2-f5 using `f2345()` from the UICC input +* Computes the `RES` using `transferRES()` +* Derives the keys `KAUSF`, `KSEAF`, `KAMF`, `KNASenc`/`KNASint` via `derive_knas()` and `KGNB` for RRC ciphering (via `derive_kgnb()`) + +## Security Mode Complete + +When the UE receives a **Security Mode Command** from the 5GC, it responds with a `Security Mode Complete` message. This message is protected with the newly established NAS security context and may carry additional payloads, including the UE’s identity and a nested NAS message (e.g., `Registration Request`) in the `FGSNasMessageContainer`. The function responsible for building and securing this response is `generateSecurityModeComplete`. + +### IMEISV + +The **IMEISV**, is encoded using the `fill_imeisv()` helper. This function extracts each digit from the configured `imeisvStr` in the UICC context and populates the mobile identity structure. + +See TS 24.501 §4.4 for reference. -## registrationComplete -To be defined in UE, this NAS message is done after RRC sequence completes From ae650bc9ea4b7856d93a2b1e6944539b244c9f38 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 22 May 2025 17:07:16 +0200 Subject: [PATCH 31/51] T: macpdu2wireshark: dump to file instead of sending UDP packets In NR with several layers, we may have MAC PDU of size bigger than 64KB, which does not fit into a UDP buffer, destroying macpdu2wireshark. Let's add an option to dump to a pcap file instead of using UDP packets. The DLT 252 magic is used (check wireshark documentation to understand). Run macpdu2wireshark with -h to see how to configure wireshark to read the produced files. --- common/utils/T/DOC/T/wireshark.md | 11 +- common/utils/T/tracer/macpdu2wireshark.c | 202 ++++++++++++++++++----- 2 files changed, 173 insertions(+), 40 deletions(-) diff --git a/common/utils/T/DOC/T/wireshark.md b/common/utils/T/DOC/T/wireshark.md index af11535bdc..0119955621 100644 --- a/common/utils/T/DOC/T/wireshark.md +++ b/common/utils/T/DOC/T/wireshark.md @@ -3,7 +3,8 @@ First, read the [basic usage](./basic.md) to compile things. It is possible to use `wireshark` to analyse MAC PDUs for UEs, -MIBs, SIBs, and random accesses seen by the eNodeB. +MIBs, SIBs, and random accesses seen by the eNodeB. It also +works for the gNB, as well as for the nrUE. ## Live usage @@ -20,6 +21,14 @@ Then run: ./macpdu2wireshark -d ../T_messages.txt -live ``` +Note: in some cases a MAC PDU may be bigger than the size of an UDP payload +(slightly less than 64 KiB). This is particularily the case for large +bandwidths in NR and MIMO. In this case macpdu2wireshark, sending UDP packets +in its default mode of operations, will fail. By using the option `-to-file` +a pcap file may be directly generated. You need to configure wireshark to +process the generated files (run `macpdu2wireshark -h` to see how to +configure wireshark for this case). + For other options of `macpdu2wireshark`, run: ```shell diff --git a/common/utils/T/tracer/macpdu2wireshark.c b/common/utils/T/tracer/macpdu2wireshark.c index 607023db6a..6d0a564ab8 100644 --- a/common/utils/T/tracer/macpdu2wireshark.c +++ b/common/utils/T/tracer/macpdu2wireshark.c @@ -115,6 +115,11 @@ typedef struct { int max_sib; int live; int no_bind; + /* config to dump to file instead of UDP */ + /* output_filename != NULL means to output to file */ + char *output_filename; + FILE *output_file; + /* runtime vars */ int cur_mib; int cur_sib; @@ -129,19 +134,96 @@ typedef struct { int nr_next_ue_id; } ev_data; +/****************************************************************************/ +/* direct output to pcap file */ +/****************************************************************************/ + +void write_pcap_header(const char *filename, FILE *f) +{ + /* see 'man pcap-savefile' for format */ + uint32_t magic = 0xa1b23c4d; /* magic for second/nanosecond */ + uint16_t major = 2; + uint16_t minor = 4; + uint32_t reserved = 0; + uint32_t snapshot_length = 0x7fffffff; /* let's be generous */ + uint32_t link_layer_type = 252; /* DLT_WIRESHARK_UPPER_PDU */ + if (fwrite(&magic, 4, 1, f) != 1 + || fwrite(&major, 2, 1, f) != 1 + || fwrite(&minor, 2, 1, f) != 1 + || fwrite(&reserved, 4, 1, f) != 1 + || fwrite(&reserved, 4, 1, f) != 1 + || fwrite(&snapshot_length, 4, 1, f) != 1 + || fwrite(&link_layer_type, 4, 1, f) != 1) { + printf("fatal: error writing header to %s\n", filename); + exit(1); + } +} + +const char *pcap_trace_header(int is_lte) +{ + static char header_nr[] = { + 0x00, 12, /* type = EXP_PDU_TAG_DISSECTOR_NAME */ + 0x00, 16, /* length */ + 'm', 'a', 'c', '-', 'n', 'r', '-', 'f', 'r', 'a', 'm', 'e', 'd', 0, 0, 0, + 0x00, 0x00, 0x00, 0x00 /* EXP_PDU_TAG_END_OF_OPT with length 0 */ + }; + static char header_lte[] = { + 0x00, 12, /* type = EXP_PDU_TAG_DISSECTOR_NAME */ + 0x00, 16, /* length */ + 'm', 'a', 'c', '-', 'l', 't', 'e', '-', 'f', 'r', 'a', 'm', 'e', 'd', 0, 0, + 0x00, 0x00, 0x00, 0x00 /* EXP_PDU_TAG_END_OF_OPT with length 0 */ + }; + return is_lte ? header_lte : header_nr; +} + +void write_pcap_trace(const char *filename, FILE *f, + struct timespec sending_time, + const char *buf, int size, int is_lte) +{ + uint32_t second = sending_time.tv_sec; + uint32_t nanosecond = sending_time.tv_nsec; + uint32_t length = size + 24; + /* untruncated_length == length, we dump everything */ + uint32_t untruncated_length = length; + if (fwrite(&second, 4, 1, f) != 1 + || fwrite(&nanosecond, 4, 1, f) != 1 + || fwrite(&length, 4, 1, f) != 1 + || fwrite(&untruncated_length, 4, 1, f) != 1 + || fwrite(pcap_trace_header(is_lte), 24, 1, f) != 1 + || fwrite(buf, size, 1, f) != 1) { + printf("fatal: error writing to file %s\n", filename); + exit(1); + } +} +void write_pcap_trace_lte(const char *filename, FILE *f, + struct timespec sending_time, + const char *buf, int size) +{ + write_pcap_trace(filename, f, sending_time, buf, size, 1); +} + +void write_pcap_trace_nr(const char *filename, FILE *f, + struct timespec sending_time, + const char *buf, int size) +{ + write_pcap_trace(filename, f, sending_time, buf, size, 0); +} + /****************************************************************************/ /* LTE */ /****************************************************************************/ -void trace_lte(ev_data *d, int direction, int rnti_type, int rnti, - int frame, int subframe, void *buf, int bufsize, int preamble, - int sr_rnti) +void trace_lte(struct timespec sending_time, ev_data *d, int direction, + int rnti_type, int rnti, int frame, int subframe, void *buf, + int bufsize, int preamble, int sr_rnti) { ssize_t ret; int fsf; int i; d->buf.osize = 0; - PUTS(&d->buf, MAC_LTE_START_STRING); + + if (!d->output_filename) + PUTS(&d->buf, MAC_LTE_START_STRING); PUTC(&d->buf, FDD_RADIO); PUTC(&d->buf, direction); PUTC(&d->buf, rnti_type); @@ -202,16 +284,21 @@ void trace_lte(ev_data *d, int direction, int rnti_type, int rnti, for (i = 0; i < bufsize; i++) PUTC(&d->buf, ((char *)buf)[i]); - ret = sendto(d->socket, d->buf.obuf, d->buf.osize, 0, - (struct sockaddr *)&d->to, sizeof(struct sockaddr_in)); + if (d->output_filename) { + write_pcap_trace_lte(d->output_filename, d->output_file, sending_time, + d->buf.obuf, d->buf.osize); + } else { + ret = sendto(d->socket, d->buf.obuf, d->buf.osize, 0, + (struct sockaddr *)&d->to, sizeof(struct sockaddr_in)); - if (ret != d->buf.osize) abort(); + if (ret != d->buf.osize) abort(); + } } void ul(void *_d, event e) { ev_data *d = _d; - trace_lte(d, DIRECTION_UPLINK, C_RNTI, e.e[d->ul_rnti].i, + trace_lte(e.sending_time, d, DIRECTION_UPLINK, C_RNTI, e.e[d->ul_rnti].i, e.e[d->ul_frame].i, e.e[d->ul_subframe].i, e.e[d->ul_data].b, e.e[d->ul_data].bsize, NO_PREAMBLE, NO_SR_RNTI); @@ -229,7 +316,7 @@ void dl(void *_d, event e) d->cur_sib++; } - trace_lte(d, DIRECTION_DOWNLINK, + trace_lte(e.sending_time, d, DIRECTION_DOWNLINK, e.e[d->dl_rnti].i != 0xffff ? C_RNTI : SI_RNTI, e.e[d->dl_rnti].i, e.e[d->dl_frame].i, e.e[d->dl_subframe].i, e.e[d->dl_data].b, e.e[d->dl_data].bsize, @@ -245,7 +332,7 @@ void mib(void *_d, event e) if (d->max_mib && d->cur_mib == d->max_mib) return; d->cur_mib++; - trace_lte(d, DIRECTION_DOWNLINK, NO_RNTI, 0, + trace_lte(e.sending_time, d, DIRECTION_DOWNLINK, NO_RNTI, 0, e.e[d->mib_frame].i, e.e[d->mib_subframe].i, e.e[d->mib_data].b, e.e[d->mib_data].bsize, NO_PREAMBLE, NO_SR_RNTI); @@ -254,7 +341,7 @@ void mib(void *_d, event e) void preamble(void *_d, event e) { ev_data *d = _d; - trace_lte(d, DIRECTION_UPLINK, NO_RNTI, 0, + trace_lte(e.sending_time, d, DIRECTION_UPLINK, NO_RNTI, 0, e.e[d->preamble_frame].i, e.e[d->preamble_subframe].i, NULL, 0, e.e[d->preamble_preamble].i, NO_SR_RNTI); @@ -263,7 +350,7 @@ void preamble(void *_d, event e) void ue_preamble(void *_d, event e) { ev_data *d = _d; - trace_lte(d, DIRECTION_UPLINK, NO_RNTI, 0, + trace_lte(e.sending_time, d, DIRECTION_UPLINK, NO_RNTI, 0, e.e[d->ue_preamble_frame].i, e.e[d->ue_preamble_subframe].i, NULL, 0, e.e[d->ue_preamble_preamble].i, NO_SR_RNTI); @@ -272,7 +359,8 @@ void ue_preamble(void *_d, event e) void rar(void *_d, event e) { ev_data *d = _d; - trace_lte(d, DIRECTION_DOWNLINK, RA_RNTI, e.e[d->rar_rnti].i, + trace_lte(e.sending_time, d, DIRECTION_DOWNLINK, + RA_RNTI, e.e[d->rar_rnti].i, e.e[d->rar_frame].i, e.e[d->rar_subframe].i, e.e[d->rar_data].b, e.e[d->rar_data].bsize, NO_PREAMBLE, NO_SR_RNTI); @@ -281,7 +369,7 @@ void rar(void *_d, event e) void sr(void *_d, event e) { ev_data *d = _d; - trace_lte(d, DIRECTION_UPLINK, NO_RNTI, 0, + trace_lte(e.sending_time, d, DIRECTION_UPLINK, NO_RNTI, 0, e.e[d->sr_frame].i, e.e[d->sr_subframe].i, NULL, 0, NO_PREAMBLE, e.e[d->sr_rnti].i); @@ -310,14 +398,15 @@ void sr(void *_d, event e) #define NR_C_RNTI 3 #define NR_SI_RNTI 4 -void trace_nr(ev_data *d, int direction, int rnti_type, int rnti, - int frame, int slot, int harq_pid, void *buf, int bufsize, - int preamble) +void trace_nr(struct timespec sending_time, ev_data *d, int direction, + int rnti_type, int rnti, int frame, int slot, int harq_pid, void *buf, + int bufsize, int preamble) { ssize_t ret; int i; d->buf.osize = 0; - PUTS(&d->buf, MAC_NR_START_STRING); + if (!d->output_filename) + PUTS(&d->buf, MAC_NR_START_STRING); PUTC(&d->buf, NR_TDD_RADIO); PUTC(&d->buf, direction); PUTC(&d->buf, rnti_type); @@ -361,17 +450,23 @@ void trace_nr(ev_data *d, int direction, int rnti_type, int rnti, for (i = 0; i < bufsize; i++) PUTC(&d->buf, ((char *)buf)[i]); - ret = sendto(d->socket, d->buf.obuf, d->buf.osize, 0, - (struct sockaddr *)&d->to, sizeof(struct sockaddr_in)); + if (d->output_filename) { + write_pcap_trace_nr(d->output_filename, d->output_file, sending_time, + d->buf.obuf, d->buf.osize); + } else { + ret = sendto(d->socket, d->buf.obuf, d->buf.osize, 0, + (struct sockaddr *)&d->to, sizeof(struct sockaddr_in)); - if (ret != d->buf.osize) abort(); + if (ret != d->buf.osize) abort(); + } } void nr_ul(void *_d, event e) { ev_data *d = _d; - trace_nr(d, NR_DIRECTION_UPLINK, NR_C_RNTI, e.e[d->nr_ul_rnti].i, + trace_nr(e.sending_time, d, NR_DIRECTION_UPLINK, + NR_C_RNTI, e.e[d->nr_ul_rnti].i, e.e[d->nr_ul_frame].i, e.e[d->nr_ul_slot].i, e.e[d->nr_ul_harq_pid].i, e.e[d->nr_ul_data].b, e.e[d->nr_ul_data].bsize, NO_PREAMBLE); @@ -389,7 +484,7 @@ void nr_dl(void *_d, event e) d->cur_sib++; } - trace_nr(d, NR_DIRECTION_DOWNLINK, + trace_nr(e.sending_time, d, NR_DIRECTION_DOWNLINK, e.e[d->nr_dl_rnti].i != 0xffff ? NR_C_RNTI : NR_SI_RNTI, e.e[d->nr_dl_rnti].i, e.e[d->nr_dl_frame].i, e.e[d->nr_dl_slot].i, e.e[d->nr_dl_harq_pid].i, e.e[d->nr_dl_data].b, @@ -400,7 +495,8 @@ void nr_dl_retx(void *_d, event e) { ev_data *d = _d; - trace_nr(d, NR_DIRECTION_DOWNLINK, NR_C_RNTI, e.e[d->nr_dl_retx_rnti].i, + trace_nr(e.sending_time, d, NR_DIRECTION_DOWNLINK, + NR_C_RNTI, e.e[d->nr_dl_retx_rnti].i, e.e[d->nr_dl_retx_frame].i, e.e[d->nr_dl_retx_slot].i, e.e[d->nr_dl_retx_harq_pid].i, e.e[d->nr_dl_retx_data].b, e.e[d->nr_dl_retx_data].bsize, NO_PREAMBLE); @@ -416,7 +512,7 @@ void nr_mib(void *_d, event e) d->cur_mib++; - trace_nr(d, NR_DIRECTION_DOWNLINK, NR_NO_RNTI, 0, + trace_nr(e.sending_time, d, NR_DIRECTION_DOWNLINK, NR_NO_RNTI, 0, e.e[d->nr_mib_frame].i, e.e[d->nr_mib_slot].i, 0 /* harq pid */, e.e[d->nr_mib_data].b, e.e[d->nr_mib_data].bsize, NO_PREAMBLE); } @@ -431,7 +527,7 @@ void nr_ue_mib(void *_d, event e) d->cur_mib++; - trace_nr(d, NR_DIRECTION_DOWNLINK, NR_NO_RNTI, 0, + trace_nr(e.sending_time, d, NR_DIRECTION_DOWNLINK, NR_NO_RNTI, 0, e.e[d->nr_ue_mib_frame].i, e.e[d->nr_ue_mib_slot].i, 0 /* harq pid */, e.e[d->nr_ue_mib_data].b, e.e[d->nr_ue_mib_data].bsize, NO_PREAMBLE); } @@ -440,7 +536,8 @@ void nr_rar(void *_d, event e) { ev_data *d = _d; - trace_nr(d, NR_DIRECTION_DOWNLINK, NR_RA_RNTI, e.e[d->nr_rar_rnti].i, + trace_nr(e.sending_time, d, NR_DIRECTION_DOWNLINK, + NR_RA_RNTI, e.e[d->nr_rar_rnti].i, e.e[d->nr_rar_frame].i, e.e[d->nr_rar_slot].i, 0 /* harq pid */, e.e[d->nr_rar_data].b, e.e[d->nr_rar_data].bsize, NO_PREAMBLE); } @@ -449,7 +546,8 @@ void nr_ue_ul(void *_d, event e) { ev_data *d = _d; - trace_nr(d, NR_DIRECTION_UPLINK, NR_C_RNTI, e.e[d->nr_ue_ul_rnti].i, + trace_nr(e.sending_time, d, NR_DIRECTION_UPLINK, + NR_C_RNTI, e.e[d->nr_ue_ul_rnti].i, e.e[d->nr_ue_ul_frame].i, e.e[d->nr_ue_ul_slot].i, e.e[d->nr_ue_ul_harq_pid].i, e.e[d->nr_ue_ul_data].b, e.e[d->nr_ue_ul_data].bsize, NO_PREAMBLE); @@ -467,7 +565,7 @@ void nr_ue_dl(void *_d, event e) d->cur_sib++; } - trace_nr(d, NR_DIRECTION_DOWNLINK, + trace_nr(e.sending_time, d, NR_DIRECTION_DOWNLINK, e.e[d->nr_ue_dl_rnti].i != 0xffff ? NR_C_RNTI : NR_SI_RNTI, e.e[d->nr_ue_dl_rnti].i, e.e[d->nr_ue_dl_frame].i, e.e[d->nr_ue_dl_slot].i, e.e[d->nr_ue_dl_harq_pid].i, @@ -477,7 +575,8 @@ void nr_ue_dl(void *_d, event e) void nr_ue_rar(void *_d, event e) { ev_data *d = _d; - trace_nr(d, DIRECTION_DOWNLINK, RA_RNTI, e.e[d->nr_ue_rar_rnti].i, + trace_nr(e.sending_time, d, DIRECTION_DOWNLINK, + RA_RNTI, e.e[d->nr_ue_rar_rnti].i, e.e[d->nr_ue_rar_frame].i, e.e[d->nr_ue_rar_slot].i, 0, e.e[d->nr_ue_rar_data].b, e.e[d->nr_ue_rar_data].bsize, NO_PREAMBLE); @@ -833,7 +932,15 @@ void usage(void) " -live-port tracee's port (default %d)\n" " -no-bind don't bind to IP address (for remote logging)\n" "-i and -live are mutually exclusive options. One of them must be provided\n" - "but not both.\n", + "but not both.\n" + "\n" + "Use the following options to dump to a file instead of sending UDP packets:\n" + " -to-file dump to file using the mac framed format\n" + "\n" + "To use wireshark with files created using the option '-to-file',\n" + "you need to configure wireshark:\n" + " in Analyze->Enabled Protocols search for MAC-NR-FRAMED and\n" + " MAC-LTE-FRAMED and enable them.\n", DEFAULT_IP, DEFAULT_PORT, DEFAULT_LIVE_IP, @@ -881,11 +988,13 @@ int main(int n, char **v) if (!strcmp(v[i], "-live-ip")) { if(i>n-2)usage(); live_ip = v[++i]; continue; } if (!strcmp(v[i], "-live-port")) { if(i>n-2)usage(); live_port = atoi(v[++i]); continue; } if (!strcmp(v[i], "-no-bind")) { d.no_bind = 1; continue; } + if (!strcmp(v[i], "-to-file")) { if(i>n-2)usage(); d.output_filename = v[++i]; continue; } usage(); } if (database_filename == NULL) { printf("ERROR: provide a database file (-d)\n"); + printf("use -h for help on usage\n"); exit(1); } @@ -992,17 +1101,27 @@ int main(int n, char **v) register_handler_function(h, nr_ue_dl_id, nr_ue_dl, &d); register_handler_function(h, nr_ue_rar_id, nr_ue_rar, &d); - d.socket = socket(AF_INET, SOCK_DGRAM, 0); + if (d.output_filename) { + d.output_file = fopen(d.output_filename, "w"); + if (d.output_file == NULL) { + perror(d.output_filename); + exit(1); + } + write_pcap_header(d.output_filename, d.output_file); + } else { + d.socket = socket(AF_INET, SOCK_DGRAM, 0); - if (d.socket == -1) { - perror("socket"); - exit(1); + if (d.socket == -1) { + perror("socket"); + exit(1); + } + + d.to.sin_family = AF_INET; + d.to.sin_port = htons(port); + d.to.sin_addr.s_addr = inet_addr(ip); + new_thread(receiver, &d); } - d.to.sin_family = AF_INET; - d.to.sin_port = htons(port); - d.to.sin_addr.s_addr = inet_addr(ip); - new_thread(receiver, &d); OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL}; /* read messages */ @@ -1025,5 +1144,10 @@ int main(int n, char **v) handle_event(h, e); } + if (d.output_filename) { + if (fclose(d.output_file)) + perror(d.output_filename); + } + return 0; } From b815c8648c6173ac3b25133d2469f3253f67862b Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 23 May 2025 16:57:38 +0200 Subject: [PATCH 32/51] bugfix: pass correct buffer --- openair2/RRC/LTE/rrc_UE.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index f7b513d264..2216fb5a75 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -1818,8 +1818,8 @@ rrc_ue_process_ueCapabilityEnquiry( ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.rrc_TransactionIdentifier = UECapabilityEnquiry->rrc_TransactionIdentifier; ue_CapabilityRAT_Container.rat_Type = LTE_RAT_Type_eutra; OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container.ueCapabilityRAT_Container, - (const char *)UE_rrc_inst[ctxt_pP->module_id].UECapability, - UE_rrc_inst[ctxt_pP->module_id].UECapability_size); + (const char *)UE_rrc_inst[ctxt_pP->module_id].UECap->sdu, + UE_rrc_inst[ctxt_pP->module_id].UECap->sdu_size); // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf = UE_rrc_inst[ue_mod_idP].UECapability; // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size; AssertFatal(UECapabilityEnquiry->criticalExtensions.present == LTE_UECapabilityEnquiry__criticalExtensions_PR_c1, From 549c71c32c31698385493973be5cef362befda4c Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Mon, 26 May 2025 12:25:27 +0200 Subject: [PATCH 33/51] CI: revert modification of SSB per RACH occasion in SC-FDMA test Set ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR parameter back to 4, revert modification done in a4f9a7a6d4048a888fd39ccb49e249c8fc48322e. --- .../conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf index 92b0ad794c..ba06b69dd2 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf @@ -83,7 +83,7 @@ gNBs = ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 2; + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; #one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; #ra_ContentionResolutionTimer From f84ec1340c0f1876009eeb8ed6687220d8e2b06a Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 17 May 2025 15:15:52 +0200 Subject: [PATCH 34/51] limit the number of preambles per SSB at UE in case PRACH is configured with groupB --- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index b7dc9cf7a9..2f717a7466 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -336,17 +336,14 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac) nb_of_preambles = preamb_ga; } } - int rand_preamb = (rand_r(&seed) % ra->ssb_ro_config.preambles_per_ssb); + int pream_per_ssb = min(ra->ssb_ro_config.preambles_per_ssb, nb_of_preambles); + int rand_preamb = rand_r(&seed) % pream_per_ssb; if (ra->ssb_ro_config.ssb_per_ro < 1) ra->ra_PreambleIndex = groupOffset + rand_preamb; else { int ssb_pr_idx = mac->ssb_list.nb_ssb_per_index[mac->mib_ssb] % (int)ra->ssb_ro_config.ssb_per_ro; ra->ra_PreambleIndex = groupOffset + (ssb_pr_idx * ra->ssb_ro_config.preambles_per_ssb) + rand_preamb; } - AssertFatal(ra->ra_PreambleIndex < nb_of_preambles, - "Error! Selected preamble %d which exceeds number of prambles available %d\n", - ra->ra_PreambleIndex, - nb_of_preambles); } static void configure_ra_preamble(NR_UE_MAC_INST_t *mac) From ad2a8a89916fbdee695faadf6f2b2a5f6e340394 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 25 Apr 2025 11:45:25 +0200 Subject: [PATCH 35/51] Add 5 tests to force RRC_IDLE in a row in 5g_rfsimulator_24prb pipeline --- .../xml_files/container_5g_rfsim_24prb.xml | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml index f4ee341c94..5a59880b2f 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml @@ -34,9 +34,24 @@ 020002 030001 030002 + 040002 + 000004 + 020001 + 040002 + 000004 + 020001 + 040002 + 000004 + 020001 + 040002 + 000004 + 020001 + 040002 + 000004 + 020001 040001 000004 - 020002 + 020001 100001 222222 @@ -82,7 +97,7 @@ IdleSleep Sleep - 5 + 1 @@ -92,8 +107,8 @@ cacofonix rfsim5g_ext_dn cacofonix - -c 20 -i0.2 - 5 + -c 20 -i0.5 + 80 @@ -139,13 +154,19 @@ yes + + Custom_Command + Force RRC_IDLE (UE ID 0) + cacofonix + echo ciUE force_RRC_IDLE | nc 192.168.71.150 8091 + yes + + Undeploy_Object true Undeploy all OAI 5G stack ci-scripts/yaml_files/5g_rfsimulator_24prb - 1,0,0,0 - 1,0,0,0 0 0 From 844986ff92143db10e7fa6fc7eeac752b4c2efb2 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 15:32:53 +0200 Subject: [PATCH 36/51] SDAP: close TUN socket to unblock thread and clean interface shutdown * Close entity->pdusession_sock manually before pthread_join() to unblock sdap_tun_read_thread() * Update tun_destroy() to open a fresh socket for interface management, independent from the data socket * Fix check on success of change_interface_state() in tun_destroy(): is a boolean * Handle ENODEV error when bringing interface down: treat as success if the interface is already gone. * tun_destroy() is now handling INTERFACE_DOWN, so `INTERFACE_DOWN` in `tun_config()` is no longer needed --- common/utils/tun_if.c | 27 +++++++++++++++++++-------- common/utils/tun_if.h | 3 +-- openair2/SDAP/nr_sdap/nr_sdap.c | 6 +++++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/common/utils/tun_if.c b/common/utils/tun_if.c index 87bba5a513..4bb1f7ec58 100644 --- a/common/utils/tun_if.c +++ b/common/utils/tun_if.c @@ -168,10 +168,14 @@ static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_ struct ifreq ifr = {0}; strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); + /* get flags of this interface: see netdevice(7) */ bool success = ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t)&ifr) == 0; - if (!success) - goto fail_interface_state; + if (!success && if_action == INTERFACE_DOWN && errno == ENODEV) { + LOG_W(OIP, "trying to remove non-existant device %s\n", ifn); + return true; + } + LOG_D(OIP, "Got flags for %s: 0x%x (action: %s)\n", ifn, ifr.ifr_flags, action); if (if_action == INTERFACE_UP) { ifr.ifr_flags |= IFF_UP | IFF_NOARP | IFF_POINTOPOINT; @@ -183,6 +187,8 @@ static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_ success = ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t)&ifr) == 0; if (!success) goto fail_interface_state; + LOG_D(OIP, "Interface %s successfully set %s\n", ifn, action); + return true; fail_interface_state: @@ -201,10 +207,6 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6) return false; } - if (!change_interface_state(sock_fd, ifname, INTERFACE_DOWN)) { - close(sock_fd); - return false; - } bool success = true; if (ipv4 != NULL) success = setInterfaceParameter(sock_fd, ifname, AF_INET, ipv4, SIOCSIFADDR); @@ -272,8 +274,17 @@ int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id) return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string); } -void tun_destroy(const char *dev, int fd) { - if (change_interface_state(fd, dev, INTERFACE_DOWN) == 0) { +void tun_destroy(const char *dev) +{ + // Use a new socket for ioctl operations + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + LOG_E(UTIL, "Failed to create socket for interface teardown: %d, %s\n", errno, strerror(errno)); + return; + } + + bool success = change_interface_state(fd, dev, INTERFACE_DOWN); + if (success) { LOG_I(UTIL, "Interface %s is now down.\n", dev); } else { LOG_E(UTIL, "Could not bring interface %s down.\n", dev); diff --git a/common/utils/tun_if.h b/common/utils/tun_if.h index e73b4be94e..8e1463624f 100644 --- a/common/utils/tun_if.h +++ b/common/utils/tun_if.h @@ -84,8 +84,7 @@ int tun_alloc(const char *dev); /*! * \brief This function destroys the TUN interface * \param[in] dev name of the interface - * \param[in] fd file descriptor of the allocated interface */ -void tun_destroy(const char *dev, int fd); +void tun_destroy(const char *dev); #endif /*TUN_IF_H_*/ diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index 44b8fa2cb0..946cc22ced 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -194,6 +194,10 @@ void remove_ip_if(nr_sdap_entity_t *entity) DevAssert(entity != NULL); // Stop the read thread entity->stop_thread = true; + + // Close the socket: read() will get EBADF and exit + close(entity->pdusession_sock); + int ret = pthread_join(entity->pdusession_thread, NULL); AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno)); // Bring down the IP interface @@ -205,5 +209,5 @@ void remove_ip_if(nr_sdap_entity_t *entity) } else { tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1); } - tun_destroy(ifname, entity->pdusession_sock); + tun_destroy(ifname); } From bcab56afb48bae044c0a675538ce26fd7d275c98 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 15:36:54 +0200 Subject: [PATCH 37/51] sdap_tun_read_thread(): handle and log different errno --- openair2/SDAP/nr_sdap/nr_sdap.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index 946cc22ced..f6602c7597 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -121,8 +121,21 @@ static void *sdap_tun_read_thread(void *arg) while (!entity->stop_thread) { len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD); if (len == -1) { - LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno)); - return NULL; + if (errno == EINTR) + continue; // interrupted system call + + if (errno == EBADF || errno == EINVAL) { + LOG_I(SDAP, "Socket closed, exiting TUN read thread for UE %ld, PDU session %d\n", entity->ue_id, entity->pdusession_id); + break; + } + + LOG_E(PDCP, "read() failed: errno %d (%s)\n", errno, strerror(errno)); + break; + } + + if (len == 0) { + LOG_W(SDAP, "TUN socket returned EOF - exiting thread\n"); + break; } LOG_D(SDAP, "read data of size %d\n", len); From f7a04de762d751e5968b69622707f11a54a0479b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 15:50:32 +0200 Subject: [PATCH 38/51] Add ciUE telnet command to trigger UE initiated deregistration --- common/utils/telnetsrv/telnetsrv_ciUE.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common/utils/telnetsrv/telnetsrv_ciUE.c b/common/utils/telnetsrv/telnetsrv_ciUE.c index 721cb0e5cd..90e044ed86 100644 --- a/common/utils/telnetsrv/telnetsrv_ciUE.c +++ b/common/utils/telnetsrv/telnetsrv_ciUE.c @@ -102,12 +102,21 @@ int force_crnti_ra(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +static int force_deregistration(char *buf, int debug, telnet_printfunc_t prnt) +{ + MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_DEREGISTRATION_REQ); + NAS_DEREGISTRATION_REQ(msg).cause = AS_DETACH; + itti_send_msg_to_task(TASK_NAS_NRUE, 0, msg); + return 0; +} + /* Telnet shell command definitions */ static telnetshell_cmddef_t cicmds[] = { {"sync_state", "[UE_ID(int,opt)]", get_sync_state}, {"force_rlf", "", force_rlf}, {"force_RRC_IDLE", "", force_RRC_IDLE}, {"force_crnti_ra", "", force_crnti_ra}, + {"deregistration", "", force_deregistration}, {"", "", NULL}, }; From 4129619714371aecaf60723eaa243600dae5bad8 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 15:57:16 +0200 Subject: [PATCH 39/51] Bugfix in nas_security_rx_process: process first the security type and then the header length This commit restores the behaviour before the changes introduced in 611c0554. The NAS Deregistration Accept message is unprotected, therefore the function will return NAS_SECURITY_UNPROTECTED that would then be considered as NAS_SECURITY_INTEGRITY_PASSED Unprotected message have a plain header of 3 octets, however security protected messages have a 7 octets header. --- openair3/NAS/NR_UE/nr_nas_msg.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index b1378c3360..37ed60edaf 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -133,11 +133,15 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_b { if (nas->security_container == NULL) return NAS_SECURITY_NO_SECURITY_CONTEXT; - /* header is 7 bytes, require at least one byte of payload */ - if (pdu_length < 8) - return NAS_SECURITY_BAD_INPUT; - switch (pdu_buffer[1]) { + if (pdu_length < sizeof(fgmm_msg_header_t)) { + LOG_E(NAS, "Invalid buffer length = %d: must hold at least a plain 5GMM header\n", pdu_length); + return NAS_SECURITY_BAD_INPUT; + } + int security_type = pdu_buffer[1]; + LOG_D(NAS, "Security type is: %s\n", print_info(security_type, security_header_type_s, sizeofArray(security_header_type_s))); + + switch (security_type) { case PLAIN_5GS_MSG: return NAS_SECURITY_UNPROTECTED; break; @@ -154,6 +158,12 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_b break; } + /* header is 7 bytes, require at least one byte of payload */ + if (pdu_length < 8) { + LOG_E(NAS, "Invalid buffer length = %d\n", pdu_length); + return NAS_SECURITY_BAD_INPUT; + } + /* synchronize NAS SQN, based on 24.501 4.4.3.1 */ // Sequence number int nas_sqn = pdu_buffer[6]; From 737b2f44c42518f8c94470952e8a4ddda888d911 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 2 May 2025 18:30:42 +0200 Subject: [PATCH 40/51] Print NAS_DOWNLINK_DATA_IND message type content The information about the payload carried by NAS DOWNLINK is helpful in the logging and also for debugging purposes, therefore it was added in this commit by enabling the already existing relevant function. --- openair3/NAS/NR_UE/nr_nas_msg.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 37ed60edaf..a40edad79d 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1754,14 +1754,7 @@ void *nas_nrue(void *args_p) } break; case NAS_DOWNLINK_DATA_IND: { - LOG_I(NAS, - "[UE %ld] Received %s: length %u , buffer %p\n", - nas->UE_id, - ITTI_MSG_NAME(msg_p), - NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length, - NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data); as_nas_info_t initialNasMsg = {0}; - uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data; int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; int msg_type = get_msg_type(pdu_buffer, pdu_length); @@ -1779,6 +1772,13 @@ void *nas_nrue(void *args_p) break; } + LOG_I(NAS, + "[UE %ld] Received %s type %s with length %u\n", + nas->UE_id, + ITTI_MSG_NAME(msg_p), + print_info(msg_type, message_text_info, sizeofArray(message_text_info)), + NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length); + switch (msg_type) { case FGS_IDENTITY_REQUEST: generateIdentityResponse(&initialNasMsg, *(pdu_buffer + 3), nas->uicc); From 330b8dc8fa0ffdd89bfc316674406a8c3532e572 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sun, 4 May 2025 22:46:16 +0200 Subject: [PATCH 41/51] Add library for NAS Identity Request * Add Identity Request decoding function * Define type for Identity Type NAS IE * Target include directory in NAS IEs CMakeLists.txt (for NAS utils) --- .../NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt | 2 + .../NR_UE/5GS/5GMM/IES/FGSMobileIdentity.h | 23 ++++++++---- .../NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt | 1 + .../5GS/5GMM/MSG/fgmm_identity_request.c | 37 +++++++++++++++++++ .../5GS/5GMM/MSG/fgmm_identity_request.h | 36 ++++++++++++++++++ 5 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.c create mode 100644 openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.h diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt index 40bfcbabcd..a4bb516b89 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt @@ -11,3 +11,5 @@ target_link_libraries(fgs_5gmm_ies_lib PUBLIC nas_common_ies_lib PRIVATE log_headers ) + +target_include_directories(fgs_5gmm_ies_lib PRIVATE ../../) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSMobileIdentity.h b/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSMobileIdentity.h index b7e66019cc..4d6d4d7eed 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSMobileIdentity.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSMobileIdentity.h @@ -30,8 +30,8 @@ #include #include #include - #include "OctetString.h" +#include "fgs_nas_utils.h" #ifndef FGS_MOBILE_IDENTITY_H_ #define FGS_MOBILE_IDENTITY_H_ @@ -129,15 +129,22 @@ typedef struct { uint8_t macaddr; } Macaddr5GSMobileIdentity_t; +#define FOREACH_IDENTITY_TYPE(TYPE_DEF) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_NOIDENTITY, 0) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_SUCI, 1) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_5G_GUTI, 2) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_IMEI, 3) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_5GS_TMSI, 4) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_IMEISV, 5) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_MAC_ADDR, 6) \ + TYPE_DEF(FGS_MOBILE_IDENTITY_EUI64, 7) + +typedef enum { FOREACH_IDENTITY_TYPE(TO_ENUM) } fgs_identity_type_t; + +static const text_info_t fgs_identity_type_text[] = {FOREACH_IDENTITY_TYPE(TO_TEXT)}; + // clang-format off typedef union FGSMobileIdentity_tag { -#define FGS_MOBILE_IDENTITY_NOIDENTITY 0b000 -#define FGS_MOBILE_IDENTITY_SUCI 0b001 -#define FGS_MOBILE_IDENTITY_5G_GUTI 0b010 -#define FGS_MOBILE_IDENTITY_IMEI 0b011 -#define FGS_MOBILE_IDENTITY_5GS_TMSI 0b100 -#define FGS_MOBILE_IDENTITY_IMEISV 0b101 -#define FGS_MOBILE_IDENTITY_MAC_ADDR 0b110 NoIdentity5GSMobileIdentity_t noidentity; Suci5GSMobileIdentity_t suci; Guti5GSMobileIdentity_t guti; diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt index 3b51ec748c..bf47e478b9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(fgs_5gmm_lib OBJECT fgmm_service_reject.c RegistrationRequest.c RegistrationAccept.c + fgmm_identity_request.c FGSIdentityResponse.c FGSAuthenticationResponse.c FGSNASSecurityModeComplete.c diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.c new file mode 100644 index 0000000000..b41035f6ea --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.c @@ -0,0 +1,37 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "fgmm_identity_request.h" +#include +#include "FGSMobileIdentity.h" + +int decode_fgs_identity_request(fgs_identity_request_msg_t *msg, const byte_array_t *buffer) +{ + if (buffer->len < 1) { + PRINT_NAS_ERROR("Failed to decode NAS Identity Request: invalid buffer length %ld\n", buffer->len); + return -1; + } + + // Bits 3-1 (least significant 3 bits) + msg->fgsmobileidentity = buffer->buf[0] & 0x07; + + return 1; +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.h new file mode 100644 index 0000000000..104f133ed1 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_identity_request.h @@ -0,0 +1,36 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef FGS_IDENTITY_REQUEST_H +#define FGS_IDENTITY_REQUEST_H + +#include +#include +#include "common/utils/ds/byte_array.h" +#include "FGSMobileIdentity.h" + +typedef struct { + fgs_identity_type_t fgsmobileidentity; +} fgs_identity_request_msg_t; + +int decode_fgs_identity_request(fgs_identity_request_msg_t *msg, const byte_array_t *buffer); + +#endif /* FGS_IDENTITY_REQUEST_H */ From 7f96a04c1b3c48a3f5e9373eab2bf669cd4e5174 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sun, 4 May 2025 22:52:16 +0200 Subject: [PATCH 42/51] Add handler for NAS Identity Request * trigger Identity Response callback from the handler * process decoded message According to 4.4.4.2 3GPP TS 24.501, Identity Request with Identity Type SUCI is not expected to be integrity protected. --- openair3/NAS/NR_UE/nr_nas_msg.c | 44 ++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index a40edad79d..b539dc98ae 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -50,6 +50,7 @@ #include "SORTransparentContainer.h" #include "FGSIdentityResponse.h" #include "fgmm_authentication_request.h" +#include "fgmm_identity_request.h" #include "T.h" #include "aka_functions.h" #include "assertions.h" @@ -802,7 +803,7 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) } } -void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype, uicc_t *uicc) +static void generateIdentityResponse(as_nas_info_t *initialNasMsg, const uint8_t identitytype, uicc_t *uicc) { int size = sizeof(fgmm_msg_header_t); fgmm_nas_message_plain_t plain = {0}; @@ -823,6 +824,39 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size); } +static void handle_identity_request(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas, const byte_array_t buffer) +{ + fgmm_msg_header_t mm_header = {0}; + fgs_identity_request_msg_t msg = {0}; + + // Decode plain NAS header + int decoded = decode_5gmm_msg_header(&mm_header, buffer.buf, buffer.len); + if (decoded < 0) { + LOG_E(NAS, "Failed to decode NAS Identity Request header\n"); + return; + } + + byte_array_t payload = {.buf = &buffer.buf[decoded], .len = buffer.len - decoded}; + + // Decode identity request payload + if (decode_fgs_identity_request(&msg, &payload) < 0) { + LOG_E(NAS, "Failed to decode Identity Request message\n"); + return; + } + + LOG_I(NAS, + "Received IDENTITY REQUEST for identity type: %s\n", + print_info(msg.fgsmobileidentity, fgs_identity_type_text, sizeofArray(fgs_identity_type_text))); + + if (mm_header.message_type == NAS_SECURITY_UNPROTECTED && msg.fgsmobileidentity != FGS_MOBILE_IDENTITY_SUCI) { + // see 3GPP TS 24.501 4.4.4.2 + LOG_E(NAS, "Only SUCI mobile identity is expected in a security-unprotected request\n"); + return; + } + + generateIdentityResponse(initialNasMsg, msg.fgsmobileidentity, nas->uicc); +} + static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf) { derive_ue_keys(buf, nas); @@ -1757,6 +1791,7 @@ void *nas_nrue(void *args_p) as_nas_info_t initialNasMsg = {0}; uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data; int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; + byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length}; int msg_type = get_msg_type(pdu_buffer, pdu_length); security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length); @@ -1781,13 +1816,11 @@ void *nas_nrue(void *args_p) switch (msg_type) { case FGS_IDENTITY_REQUEST: - generateIdentityResponse(&initialNasMsg, *(pdu_buffer + 3), nas->uicc); + handle_identity_request(&initialNasMsg, nas, buffer); break; - case FGS_AUTHENTICATION_REQUEST: { - byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length}; + case FGS_AUTHENTICATION_REQUEST: handle_fgmm_authentication_request(nas, &initialNasMsg, &buffer); break; - } case FGS_SECURITY_MODE_COMMAND: handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length); break; @@ -1813,7 +1846,6 @@ void *nas_nrue(void *args_p) exit(1); break; case FGS_SERVICE_ACCEPT: { - byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length}; handle_service_accept(nas, &buffer); break; } From e651a29a2acd4508db3d5b97f5450e364b088a28 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 15 May 2025 12:05:33 +0200 Subject: [PATCH 43/51] Use byte_array_t in nas_security_rx_process --- openair3/NAS/NR_UE/nr_nas_msg.c | 49 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index b539dc98ae..58cb008af3 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -70,6 +70,7 @@ #include "fgs_nas_utils.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" +#include "ds/byte_array.h" #define MAX_NAS_UE 4 @@ -130,16 +131,16 @@ static const char *print_info(uint8_t id, const text_info_t *array, uint8_t arra return "N/A"; } -static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_buffer, int pdu_length) +static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer) { if (nas->security_container == NULL) return NAS_SECURITY_NO_SECURITY_CONTEXT; - if (pdu_length < sizeof(fgmm_msg_header_t)) { - LOG_E(NAS, "Invalid buffer length = %d: must hold at least a plain 5GMM header\n", pdu_length); + if (buffer.len < sizeof(fgmm_msg_header_t)) { + LOG_E(NAS, "Invalid buffer length = %ld: must hold at least a plain 5GMM header\n", buffer.len); return NAS_SECURITY_BAD_INPUT; } - int security_type = pdu_buffer[1]; + int security_type = buffer.buf[1]; LOG_D(NAS, "Security type is: %s\n", print_info(security_type, security_header_type_s, sizeofArray(security_header_type_s))); switch (security_type) { @@ -150,9 +151,9 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_b case INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX: case INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX: /* only accept "integrity protected and ciphered" messages */ - if (pdu_buffer[6] == 0) - LOG_E(NAS, "Received nas_count_dl = %d\n", pdu_buffer[6]); - LOG_E(NAS, "todo: unhandled security type %s (pdu_buffer[1] = %d)\n", security_header_type_s[pdu_buffer[1]].text, pdu_buffer[1]); + if (buffer.buf[6] == 0) + LOG_E(NAS, "Received nas_count_dl = %d\n", buffer.buf[6]); + LOG_E(NAS, "todo: unhandled security type %s (buffer.buf[1] = %d)\n", security_header_type_s[buffer.buf[1]].text, buffer.buf[1]); return NAS_SECURITY_BAD_INPUT; break; default: @@ -160,14 +161,14 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_b } /* header is 7 bytes, require at least one byte of payload */ - if (pdu_length < 8) { - LOG_E(NAS, "Invalid buffer length = %d\n", pdu_length); + if (buffer.len < 8) { + LOG_E(NAS, "Invalid buffer length = %ld\n", buffer.len); return NAS_SECURITY_BAD_INPUT; } /* synchronize NAS SQN, based on 24.501 4.4.3.1 */ // Sequence number - int nas_sqn = pdu_buffer[6]; + int nas_sqn = buffer.buf[6]; int target_sqn = nas->security.nas_count_dl & 0xff; if (nas_sqn != target_sqn) { if (nas_sqn < target_sqn) @@ -189,28 +190,28 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_b stream_cipher.count = nas->security.nas_count_dl; stream_cipher.bearer = 1; /* todo: don't hardcode */ stream_cipher.direction = 1; - stream_cipher.message = pdu_buffer + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH - 1; + stream_cipher.message = buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH - 1; /* length in bits */ - stream_cipher.blength = (pdu_length - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH + 1) << 3; + stream_cipher.blength = (buffer.len - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH + 1) << 3; stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, computed_mac); - uint8_t *received_mac = pdu_buffer + 2; + uint8_t *received_mac = buffer.buf + 2; if (memcmp(received_mac, computed_mac, NAS_INTEGRITY_SIZE) != 0) return NAS_SECURITY_INTEGRITY_FAILED; /* decipher */ - uint8_t payload_len = pdu_length - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; + uint8_t payload_len = buffer.len - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; uint8_t buf[payload_len]; stream_cipher.context = nas->security_container->ciphering_context; stream_cipher.count = nas->security.nas_count_dl; stream_cipher.bearer = 1; /* todo: don't hardcode */ stream_cipher.direction = 1; - stream_cipher.message = pdu_buffer + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; + stream_cipher.message = buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; /* length in bits */ stream_cipher.blength = (payload_len) << 3; stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); - memcpy(pdu_buffer + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH, buf, payload_len); + memcpy(buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH, buf, payload_len); nas->security.nas_count_dl++; @@ -1720,25 +1721,23 @@ void *nas_nrue(void *args_p) NAS_CONN_ESTABLI_CNF(msg_p).errCode, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); - uint8_t *pdu_buffer = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.nas_data; - int pdu_length = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length; - - security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length); + byte_array_t ba = {.buf = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.nas_data, .len = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length}; + security_state_t security_state = nas_security_rx_process(nas, ba); if (security_state != NAS_SECURITY_INTEGRITY_PASSED && security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) { LOG_E(NAS, "NAS integrity failed, discard incoming message: security state is %s\n", security_state_info[security_state].text); break; } - int msg_type = get_msg_type(pdu_buffer, pdu_length); + int msg_type = get_msg_type(ba.buf, ba.len); if (msg_type == FGS_REGISTRATION_ACCEPT) { - handle_registration_accept(nas, pdu_buffer, pdu_length); + handle_registration_accept(nas, ba.buf, ba.len); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { - handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id); + handle_pdu_session_accept(ba.buf, ba.len, nas->UE_id); } // Free NAS buffer memory after use (coming from RRC) - free(pdu_buffer); + free_byte_array(ba); break; } @@ -1794,7 +1793,7 @@ void *nas_nrue(void *args_p) byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length}; int msg_type = get_msg_type(pdu_buffer, pdu_length); - security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length); + security_state_t security_state = nas_security_rx_process(nas, buffer); /* special cases accepted without protection */ if (security_state == NAS_SECURITY_UNPROTECTED) { /* for the moment, only FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING is accepted */ From f672d9088ce23dffbd8881b8a5855429022ce3cf Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sun, 4 May 2025 23:05:54 +0200 Subject: [PATCH 44/51] Simplify handling of security check of received NAS messages NAS 3GPP TS 24.501 clause 4.4.4.2 specify which NAS messages are an exception to the integrity protection. All the other scenarios are expected to be integrity protected. The nas_security_rx_process function is returning: 1) NAS_SECURITY_NO_SECURITY_CONTEXT if no security context is established 2) NAS_SECURITY_UNPROTECTED for the messages listed in 4.4.4.2 3) NAS_SECURITY_INTEGRITY_PASSED if the integrity check is successful These 3 results can be all considered successful. The other not. Also, add a function to check whether a message is allowed to be integrity unprotected, as per clause 4.2.2.2. --- openair3/NAS/NR_UE/nr_nas_msg.c | 57 ++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 58cb008af3..3ea9bea9e7 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -78,10 +78,10 @@ static nr_ue_nas_t nr_ue_nas[MAX_NAS_UE] = {0}; #define FOREACH_STATE(TYPE_DEF) \ TYPE_DEF(NAS_SECURITY_NO_SECURITY_CONTEXT, 0) \ - TYPE_DEF(NAS_SECURITY_NEW_SECURITY_CONTEXT, 1) \ - TYPE_DEF(NAS_SECURITY_UNPROTECTED, 2) \ - TYPE_DEF(NAS_SECURITY_INTEGRITY_FAILED, 3) \ - TYPE_DEF(NAS_SECURITY_INTEGRITY_PASSED, 4) \ + TYPE_DEF(NAS_SECURITY_UNPROTECTED, 1) \ + TYPE_DEF(NAS_SECURITY_INTEGRITY_PASSED, 2) \ + TYPE_DEF(NAS_SECURITY_NEW_SECURITY_CONTEXT, 3) \ + TYPE_DEF(NAS_SECURITY_INTEGRITY_FAILED, 4) \ TYPE_DEF(NAS_SECURITY_BAD_INPUT, 5) const char *nr_release_cause_desc[] = {"RRC_CONNECTION_FAILURE", "RRC_RESUME_FAILURE", "OTHER"}; @@ -131,7 +131,27 @@ static const char *print_info(uint8_t id, const text_info_t *array, uint8_t arra return "N/A"; } -static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer) +/** @brief Check whether a message belongs to the list of messages that + * are allowed to be integrity unprotected (4.4.4.2 3GPP TS 24.501) */ +static bool unprotected_allowed(byte_array_t buffer, fgs_nas_msg_t msg_type) +{ + switch (msg_type) { + case FGS_IDENTITY_REQUEST: // check on SUCI done in the handler + case FGS_AUTHENTICATION_REQUEST: + case FGS_AUTHENTICATION_RESULT: + case FGS_AUTHENTICATION_REJECT: + case FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING: // for non switch off: deregistration type IE set to NORMAL_DEREGISTRATION + return true; + case FGS_REGISTRATION_REJECT: + case FGS_SERVICE_REJECT: + // unprotected if the 5GMM cause is not #76 + return buffer.buf[4] != Not_authorized_for_this_CAG_or_authorized_for_CAG_cells_only; + default: + return false; + } +} + +static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer, fgs_nas_msg_t msg_type) { if (nas->security_container == NULL) return NAS_SECURITY_NO_SECURITY_CONTEXT; @@ -145,7 +165,7 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t b switch (security_type) { case PLAIN_5GS_MSG: - return NAS_SECURITY_UNPROTECTED; + return unprotected_allowed(buffer, msg_type) ? NAS_SECURITY_UNPROTECTED : NAS_SECURITY_BAD_INPUT; break; case INTEGRITY_PROTECTED: case INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX: @@ -1272,7 +1292,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi // Plain 5GMM fgs_deregistration_request_ue_originating_msg *mm_msg = &sp_msg.plain.mm_msg.fgs_deregistration_request_ue_originating; - mm_msg->deregistrationtype.switchoff = NORMAL_DEREGISTRATION; + mm_msg->deregistrationtype.switchoff = NORMAL_DEREGISTRATION; // note: in case this is changed to SWITCH_OFF, handle in unprotected_allowed mm_msg->deregistrationtype.reregistration_required = REREGISTRATION_NOT_REQUIRED; mm_msg->deregistrationtype.access_type = TGPP_ACCESS; mm_msg->naskeysetidentifier.naskeysetidentifier = 1; @@ -1426,7 +1446,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * } } -static uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) +static fgs_nas_msg_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) { if (pdu_buffer == NULL) goto error; @@ -1722,14 +1742,13 @@ void *nas_nrue(void *args_p) NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); byte_array_t ba = {.buf = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.nas_data, .len = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length}; - security_state_t security_state = nas_security_rx_process(nas, ba); - if (security_state != NAS_SECURITY_INTEGRITY_PASSED && security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) { + fgs_nas_msg_t msg_type = get_msg_type(ba.buf, ba.len); + security_state_t security_state = nas_security_rx_process(nas, ba, msg_type); + if (security_state > NAS_SECURITY_INTEGRITY_PASSED) { LOG_E(NAS, "NAS integrity failed, discard incoming message: security state is %s\n", security_state_info[security_state].text); break; } - int msg_type = get_msg_type(ba.buf, ba.len); - if (msg_type == FGS_REGISTRATION_ACCEPT) { handle_registration_accept(nas, ba.buf, ba.len); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { @@ -1791,17 +1810,9 @@ void *nas_nrue(void *args_p) uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data; int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length}; - int msg_type = get_msg_type(pdu_buffer, pdu_length); - - security_state_t security_state = nas_security_rx_process(nas, buffer); - /* special cases accepted without protection */ - if (security_state == NAS_SECURITY_UNPROTECTED) { - /* for the moment, only FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING is accepted */ - if (msg_type == FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING) - security_state = NAS_SECURITY_INTEGRITY_PASSED; - } - - if (security_state != NAS_SECURITY_INTEGRITY_PASSED && security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) { + fgs_nas_msg_t msg_type = get_msg_type(pdu_buffer, pdu_length); + security_state_t security_state = nas_security_rx_process(nas, buffer, msg_type); + if (security_state > NAS_SECURITY_INTEGRITY_PASSED) { LOG_E(NAS, "NAS integrity failed, discard incoming message\n"); break; } From d405cbb77f180bba40195376f9c55fe4d71b4ef5 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sun, 4 May 2025 23:27:35 +0200 Subject: [PATCH 45/51] Handle security header type "integrity protected with new 5G NAS security context" The Security Mode Command is the only NAS message sending a security header type "integrity protected with new 5G NAS security context". Such header type is indicating that there is no valid security context and it is indicating the current one configured by the AMF. When receiving a Security Mode Command the "AMF shall reset the downlink NAS COUNT" and use it to integrity protect the initial Security Mode Command. "The AMF shall send the SECURITY MODE COMMAND message unciphered, but shall integrity protect [...] The AMF shall set the security header type of the message to "integrity protected with new 5G NAS security context". See 5.4.2.2 3GPP TS 24.501. This commit is ensuring the NAS DL count is reset when the relevant security header is received. Also, the security container is deleted since no more valid and NAS_SECURITY_NO_SECURITY_CONTEXT is returned. The setup of the new security context is done by "handle_security_mode_command", --- openair3/NAS/NR_UE/nr_nas_msg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 3ea9bea9e7..e5fea020c7 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -167,8 +167,13 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t b case PLAIN_5GS_MSG: return unprotected_allowed(buffer, msg_type) ? NAS_SECURITY_UNPROTECTED : NAS_SECURITY_BAD_INPUT; break; - case INTEGRITY_PROTECTED: case INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX: + stream_security_container_delete(nas->security_container); + nas->security_container = NULL; + nas->security.nas_count_dl = 0; + return NAS_SECURITY_NO_SECURITY_CONTEXT; + break; + case INTEGRITY_PROTECTED: case INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX: /* only accept "integrity protected and ciphered" messages */ if (buffer.buf[6] == 0) From 16740e5eb076d94fe66366ca2ca1f1e81361fa1a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 09:43:22 +0200 Subject: [PATCH 46/51] Use UL NAS Count to derive KgNB (6.8 of 3GPP TS 33.501) The UE shall use the currently stored UL NAS count to derive the KgNB. Hardcoding the UL count to 0 is wrong, if there is a reset to be done it should be explicitly done elsewhere. Closes #832 --- openair3/NAS/NR_UE/nr_nas_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index e5fea020c7..d152a5d4a3 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -510,7 +510,7 @@ static void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) derive_kausf(ck, ik, sqn, kausf, nas->uicc); derive_kseaf(kausf, kseaf, nas->uicc); derive_kamf(kseaf, kamf, 0x0000, nas->uicc); - derive_kgnb(kamf, 0, kgnb); + derive_kgnb(kamf, nas->security.nas_count_ul, kgnb); printf("kausf:"); for (int i = 0; i < 32; i++) { From 1b84bd8b6544f2172ac72bb33205e1f26c1a1f81 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 27 May 2025 08:46:41 +0200 Subject: [PATCH 47/51] Update README.md --- doc/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/README.md b/doc/README.md index f1b0ba8284..24050666a7 100644 --- a/doc/README.md +++ b/doc/README.md @@ -86,9 +86,7 @@ Legacy unmaintained files: - [Information on gNB MAC](./MAC/mac-usage.md) - [Information on gNB RRC](./RRC/rrc-usage.md) - [Information on analog beamforming implementation](./analog_beamforming.md) - -Legacy unmaintained files: -- [`5Gnas.md`](./5Gnas.md) +- [Information on the UE 5G NAS implementation](./5Gnas.md) # Building and running from images From 09543b3255b07a3b03a4e2418f49d94c5cf007d2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 27 May 2025 09:54:00 +0200 Subject: [PATCH 48/51] copy stats to new UE during re-establishment --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 0df7cf9943..9928c168c1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -973,6 +973,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = oldUE->CellGroup; oldUE->CellGroup = NULL; + UE->mac_stats = oldUE->mac_stats; mac_remove_nr_ue(mac, *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_unlock(&mac->sched_lock); nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id); From 8f9b89925e37520c070aa196a7685aab6b3cef94 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 16 May 2025 18:05:31 +0200 Subject: [PATCH 49/51] Replace hashtable with epoll_event_t in rfsimulator Replace the FD <-> buffer_t hashtable with epoll_event_t mapping. This simplifies the code, reduces the probability of memory leaks and removes a possible data race on the hashtable during rfsimulator shutdown. --- radio/rfsimulator/CMakeLists.txt | 2 +- radio/rfsimulator/simulator.c | 132 ++++++++----------------------- 2 files changed, 36 insertions(+), 98 deletions(-) diff --git a/radio/rfsimulator/CMakeLists.txt b/radio/rfsimulator/CMakeLists.txt index 61b053a1ce..efba710bad 100644 --- a/radio/rfsimulator/CMakeLists.txt +++ b/radio/rfsimulator/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(rfsimulator MODULE apply_channelmod.c ../../openair1/PHY/TOOLS/signal_energy.c ) -target_link_libraries(rfsimulator PRIVATE SIMU HASHTABLE) +target_link_libraries(rfsimulator PRIVATE SIMU) set_target_properties(rfsimulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_executable(replay_node stored_node.c) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 8070bf837e..32648758c8 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -50,7 +50,6 @@ #define CHANNELMOD_DYNAMICLOAD #include #include "rfsimulator.h" -#include "hashtable.h" #define PORT 4043 //default TCP port for this simulator // @@ -70,22 +69,6 @@ #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b))) #define GENERATE_CHANNEL 10 // each frame (or slot?) in DL - -// This needs to be re-architected in the future -// -// File Descriptors management in rfsimulator is not optimized -// Relying on FD_SETSIZE (actually 1024) is not appropriated -// Also the use of fd value as returned by Linux as an index for buf[] structure is not appropriated -// especially for client (UE) side since only 1 fd per connection to a gNB is needed. On the server -// side the value should be tuned to the maximum number of connections with UE's which corresponds -// to the maximum number of UEs hosted by a gNB which is unlikely to be in the order of thousands -// since all I/Q's would flow through the same TCP transport. -// Until a convenient management is implemented, the MAX_FD_RFSIMU is used everywhere (instead of -// FD_SETSIE) and reduced to 125. This should allow for around 20 simultaeous UEs. -// -// An indirection level via hashtable was added to allow the software to use FDs above MAX_FD_RFSIMU. -// -// #define MAX_FD_RFSIMU FD_SETSIZE #define MAX_FD_RFSIMU 250 #define SEND_BUFF_SIZE 100000000 // Socket buffer size @@ -169,8 +152,6 @@ typedef struct { int saveIQfile; buffer_t buf[MAX_FD_RFSIMU]; int next_buf; - // Hashtable used as an indirection level between file descriptor and the buf array - hash_table_t *fd_to_buf_map; int rx_num_channels; int tx_num_channels; double sample_rate; @@ -187,42 +168,14 @@ typedef struct { int hanging_workaround; } rfsimulator_state_t; - -static buffer_t *get_buff_from_socket(rfsimulator_state_t *simulator_state, int socket) +static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock) { - uint64_t buffer_index; - if (hashtable_get(simulator_state->fd_to_buf_map, socket, (void **)&buffer_index) == HASH_TABLE_OK) { - return &simulator_state->buf[buffer_index]; - } else { - return NULL; - } -} - -static void add_buff_to_socket_mapping(rfsimulator_state_t *simulator_state, int socket, uint64_t buff_index) -{ - hashtable_rc_t rc = hashtable_insert(simulator_state->fd_to_buf_map, socket, (void *)buff_index); - AssertFatal(rc == HASH_TABLE_OK, - "%s sock = %d\n", - rc == HASH_TABLE_INSERT_OVERWRITTEN_DATA ? "Duplicate entry in hashtable" : "Hashtable is not allocated", - socket); -} - -static void remove_buff_to_socket_mapping(rfsimulator_state_t *simulator_state, int socket) -{ - // Failure is fine here - hashtable_remove(simulator_state->fd_to_buf_map, socket); -} - -static int allocCirBuf(rfsimulator_state_t *bridge, int sock) -{ - /* TODO: cleanup code so that this AssertFatal becomes useless */ - AssertFatal(sock >= 0 && sock < sizeofArray(bridge->buf), "socket %d is not in range\n", sock); uint64_t buff_index = bridge->next_buf++ % MAX_FD_RFSIMU; buffer_t *ptr=&bridge->buf[buff_index]; ptr->circularBuf = calloc(1, sampleToByte(CirSize, 1)); if (ptr->circularBuf == NULL) { LOG_E(HW, "malloc(%lu) failed\n", sampleToByte(CirSize, 1)); - return -1; + return NULL; } ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; @@ -234,14 +187,14 @@ static int allocCirBuf(rfsimulator_state_t *bridge, int sock) int sendbuff = SEND_BUFF_SIZE; if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) != 0) { LOG_E(HW, "setsockopt(SO_SNDBUF) failed\n"); - return -1; + return NULL; } struct epoll_event ev= {0}; ev.events = EPOLLIN | EPOLLRDHUP; - ev.data.fd = sock; + ev.data.ptr = ptr; if (epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD, sock, &ev) != 0) { LOG_E(HW, "epoll_ctl(EPOLL_CTL_ADD) failed\n"); - return -1; + return NULL; } if ( bridge->channelmod > 0) { @@ -269,7 +222,7 @@ static int allocCirBuf(rfsimulator_state_t *bridge, int sock) ptr->channel_model = find_channel_desc_fromname(legacy_model_name); if (!ptr->channel_model) { LOG_E(HW, "Channel model %s/%s not found, check config file\n", modelname, legacy_model_name); - return -1; + return NULL; } } @@ -278,34 +231,29 @@ static int allocCirBuf(rfsimulator_state_t *bridge, int sock) random_channel(ptr->channel_model,false); LOG_I(HW, "Random channel %s in rfsimulator activated\n", modelname); } - add_buff_to_socket_mapping(bridge, sock, buff_index); - return 0; + return ptr; } -static void removeCirBuf(rfsimulator_state_t *bridge, int sock) { - if (epoll_ctl(bridge->epollfd, EPOLL_CTL_DEL, sock, NULL) != 0) { +static void removeCirBuf(rfsimulator_state_t *bridge, buffer_t *buf) +{ + if (epoll_ctl(bridge->epollfd, EPOLL_CTL_DEL, buf->conn_sock, NULL) != 0) { LOG_E(HW, "epoll_ctl(EPOLL_CTL_DEL) failed\n"); } - close(sock); - buffer_t* buf = get_buff_from_socket(bridge, sock); - if (buf) { - free(buf->circularBuf); - // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented - // a lot of mem leaks - //free(bridge->buf[sock].channel_model); - memset(buf, 0, sizeof(buffer_t)); - buf->conn_sock=-1; - remove_buff_to_socket_mapping(bridge, sock); - nb_ue--; - } + close(buf->conn_sock); + free(buf->circularBuf); + // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented + // a lot of mem leaks + // free(bridge->buf[sock].channel_model); + memset(buf, 0, sizeof(buffer_t)); + buf->conn_sock = -1; + nb_ue--; } -static void socketError(rfsimulator_state_t *bridge, int sock) { - buffer_t* buf = get_buff_from_socket(bridge, sock); - if (!buf) return; +static void socketError(rfsimulator_state_t *bridge, buffer_t *buf) +{ if (buf->conn_sock != -1) { LOG_W(HW, "Lost socket\n"); - removeCirBuf(bridge, sock); + removeCirBuf(bridge, buf); if (bridge->role == SIMU_ROLE_CLIENT) exit(1); @@ -661,7 +609,7 @@ static int startServer(openair0_device *device) } struct epoll_event ev = {0}; ev.events = EPOLLIN; - ev.data.fd = t->listen_sock; + ev.data.ptr = NULL; if (epoll_ctl(t->epollfd, EPOLL_CTL_ADD, t->listen_sock, &ev) != 0) { LOG_E(HW, "epoll_ctl(EPOLL_CTL_ADD) failed, errno(%d)\n", errno); return -1; @@ -730,7 +678,7 @@ static int startClient(openair0_device *device) if (setblocking(sock, notBlocking) == -1) { return -1; } - return allocCirBuf(t, sock); + return allocCirBuf(t, sock) == NULL ? -1 : 0; } static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags, bool alreadyLocked) { @@ -815,9 +763,9 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi } for (int nbEv = 0; nbEv < nfds; ++nbEv) { - int fd=events[nbEv].data.fd; + buffer_t *b = events[nbEv].data.ptr; - if (events[nbEv].events & EPOLLIN && fd == t->listen_sock) { + if (events[nbEv].events & EPOLLIN && b == NULL) { int conn_sock; conn_sock = accept(t->listen_sock, NULL, NULL); if (conn_sock == -1) { @@ -827,7 +775,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi if (setblocking(conn_sock, notBlocking)) { return false; } - if (allocCirBuf(t, conn_sock) == -1) { + buffer_t *new_buf = allocCirBuf(t, conn_sock); + if (new_buf == NULL) { return false; } LOG_I(HW, "A client connects, sending the current time\n"); @@ -840,17 +789,13 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false); - buffer_t *b = get_buff_from_socket(t, conn_sock); - if (b->channel_model) - b->channel_model->start_TS = t->lastWroteTS; + if (new_buf->channel_model) + new_buf->channel_model->start_TS = t->lastWroteTS; } else { if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) { - socketError(t,fd); + socketError(t, b); continue; } - - buffer_t *b = get_buff_from_socket(t, fd); - if (!b) continue; if ( b->circularBuf == NULL ) { LOG_E(HW, "Received data on not connected socket %d\n", events[nbEv].data.fd); continue; @@ -865,7 +810,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi b->remainToTransfer : b->circularBufEnd - b->transferPtr ; - ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT); + ssize_t sz = recv(b->conn_sock, b->transferPtr, blockSz, MSG_DONTWAIT); if ( sz < 0 ) { if ( errno != EAGAIN ) { @@ -925,7 +870,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi pthread_mutex_lock(&Sockmutex); if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) - LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS); + LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->conn_sock, t->lastWroteTS, b->lastReceivedTS); pthread_mutex_unlock(&Sockmutex); b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize]; @@ -935,11 +880,11 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi if ( b->headerMode==false ) { if ( ! b->trashingPacket ) { b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); - LOG_D(HW, "UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS); + LOG_D(HW, "UEsock: %d Set b->lastReceivedTS %ld\n", b->conn_sock, b->lastReceivedTS); } if ( b->remainToTransfer==0) { - LOG_D(HW, "UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS); + LOG_D(HW, "UEsock: %d Completed block reception: %ld\n", b->conn_sock, b->lastReceivedTS); b->headerMode=true; b->transferPtr=(char *)&b->th; b->remainToTransfer = sizeof(samplesBlockHeader_t); @@ -1142,10 +1087,9 @@ static void rfsimulator_end(openair0_device *device) { for (int i = 0; i < MAX_FD_RFSIMU; i++) { buffer_t *b = &s->buf[i]; if (b->conn_sock >= 0 ) - removeCirBuf(s, b->conn_sock); + removeCirBuf(s, b); } close(s->epollfd); - hashtable_destroy(&s->fd_to_buf_map); free(s); } static void stopServer(openair0_device *device) @@ -1171,11 +1115,6 @@ static int rfsimulator_write_init(openair0_device *device) { return 0; } -void do_not_free_integer(void *integer) -{ - (void)integer; -} - __attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { // to change the log level, use this on command line @@ -1222,7 +1161,6 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { for (int i = 0; i < MAX_FD_RFSIMU; i++) rfsimulator->buf[i].conn_sock=-1; rfsimulator->next_buf = 0; - rfsimulator->fd_to_buf_map = hashtable_create(MAX_FD_RFSIMU, NULL, do_not_free_integer); AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1, "epoll_create1() failed, errno(%d)", errno); // we need to call randominit() for telnet server (use gaussdouble=>uniformrand) From 56330fde7c689a74c13be032b9c26e86c6111543 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 26 May 2025 11:21:36 +0200 Subject: [PATCH 50/51] Make number of UL/DL actors in NR UE fully configurable Due to different processing requirements on different CPUs it might be beneficial to enable the users to set the number of UL/DL actors. Allow disabling UL/DL actor frameworks and processing inline or setting the number of DL/UL threads with --num-ul-actors/num-dl-actors This was tested to work with 0 UL/DL actors with rfsim. --- executables/nr-ue.c | 19 +++++++++++++------ executables/nr-uesoftmodem.c | 18 ++++++++++++------ executables/nr-uesoftmodem.h | 7 +++++-- openair1/PHY/defs_nr_UE.h | 6 ++---- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 5a30900c3d..1939c4175b 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -106,9 +106,12 @@ static void *NRUE_phy_stub_standalone_pnf_task(void *arg); static void start_process_slot_tx(void* arg) { notifiedFIFO_elt_t *newTx = arg; nr_rxtx_thread_data_t *curMsgTx = NotifiedFifoData(newTx); - int num_ul_actors_to_use = - get_nrUE_params()->num_ul_actors == 0 ? NUM_UL_ACTORS : min(get_nrUE_params()->num_ul_actors, NUM_UL_ACTORS); - pushNotifiedFIFO(&curMsgTx->UE->ul_actors[curMsgTx->proc.nr_slot_tx % num_ul_actors_to_use].fifo, newTx); + int num_ul_actors = get_nrUE_params()->num_ul_actors; + if (num_ul_actors > 0) { + pushNotifiedFIFO(&curMsgTx->UE->ul_actors[curMsgTx->proc.nr_slot_tx % num_ul_actors].fifo, newTx); + } else { + newTx->processingFunc(curMsgTx); + } } static size_t dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, size_t max_len) @@ -677,10 +680,10 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE) /* Clearing UE harq while DL actors are active causes race condition. So we let the current execution to complete here.*/ - for (int i = 0; i < NUM_DL_ACTORS; i++) { + for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) { flush_actor(UE->dl_actors + i); } - for (int i = 0; i < NUM_UL_ACTORS; i++) { + for (int i = 0; i < get_nrUE_params()->num_ul_actors; i++) { flush_actor(UE->ul_actors + i); } @@ -1183,7 +1186,11 @@ void *UE_thread(void *arg) int ret = UE_dl_preprocessing(UE, &curMsgRx->proc, tx_wait_for_dlsch, &curMsgRx->phy_data, &stats_printed); if (ret != INT_MAX) shiftForNextFrame = ret; - pushNotifiedFIFO(&UE->dl_actors[curMsg.proc.nr_slot_rx % NUM_DL_ACTORS].fifo, newRx); + if (get_nrUE_params()->num_dl_actors > 0) { + pushNotifiedFIFO(&UE->dl_actors[curMsg.proc.nr_slot_rx % get_nrUE_params()->num_dl_actors].fifo, newRx); + } else { + newRx->processingFunc(curMsgRx); + } // apply new NTN timing information apply_ntn_config(UE, fp, slot_nr, &duration_rx_to_tx, &timing_advance, &ntn_koffset); diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 980ab3bbd2..3106f823b3 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -506,11 +506,17 @@ int main(int argc, char **argv) UE[CC_id]->sl_mode = get_softmodem_params()->sl_mode; init_actor(&UE[CC_id]->sync_actor, "SYNC_", -1); - for (int i = 0; i < NUM_DL_ACTORS; i++) { - init_actor(&UE[CC_id]->dl_actors[i], "DL_", -1); + if (get_nrUE_params()->num_dl_actors > 0) { + UE[CC_id]->dl_actors = calloc_or_fail(get_nrUE_params()->num_dl_actors, sizeof(*UE[CC_id]->dl_actors)); + for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) { + init_actor(&UE[CC_id]->dl_actors[i], "DL_", -1); + } } - for (int i = 0; i < NUM_UL_ACTORS; i++) { - init_actor(&UE[CC_id]->ul_actors[i], "UL_", -1); + if (get_nrUE_params()->num_ul_actors > 0) { + UE[CC_id]->ul_actors = calloc_or_fail(get_nrUE_params()->num_ul_actors, sizeof(*UE[CC_id]->ul_actors)); + for (int i = 0; i < get_nrUE_params()->num_ul_actors; i++) { + init_actor(&UE[CC_id]->ul_actors[i], "UL_", -1); + } } init_nr_ue_vars(UE[CC_id], inst); @@ -576,10 +582,10 @@ int main(int argc, char **argv) for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { PHY_VARS_NR_UE *phy_vars = PHY_vars_UE_g[0][CC_id]; if (phy_vars) { - for (int i = 0; i < NUM_UL_ACTORS; i++) { + for (int i = 0; i < get_nrUE_params()->num_ul_actors; i++) { shutdown_actor(&phy_vars->ul_actors[i]); } - for (int i = 0; i < NUM_DL_ACTORS; i++) { + for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) { shutdown_actor(&phy_vars->dl_actors[i]); } int ret = pthread_join(phy_vars->main_thread, NULL); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 5af21a16e8..2eb9138e78 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -22,7 +22,8 @@ extern uint16_t ue_id_g; #define CONFIG_HLP_FREQ_SYNC_I "coefficient for Integrating part of continuous frequency offset compensation PI controller\n" #define CONFIG_HLP_CONT_FO_COMP "Enable continuous frequency offset (FO) estimation and compensation and specify main FO source (1 = local oscillator, 2 = Doppler shift)\n" #define CONFIG_HLP_AGC "Rx Gain control used for UE\n" -#define CONFIG_HLP_NUM_UL_ACTORS "Number of UL actors to use. Set to 0 to use the default value\n" +#define CONFIG_HLP_NUM_UL_ACTORS "Number of UL actors to use. Set to 0 to disable UL actor framework and do processing inline\n" +#define CONFIG_HLP_NUM_DL_ACTORS "Number of DL actors to use. Set to 0 to disable DL actor framework and do processing inline\n" /***************************************************************************************************************************************/ /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument @@ -78,7 +79,8 @@ extern uint16_t ue_id_g; {"freq-sync-I", CONFIG_HLP_FREQ_SYNC_I, 0, .dblptr=&(nrUE_params.freq_sync_I), .defdblval=0.001, TYPE_DOUBLE, 0}, \ {"cont-fo-comp", CONFIG_HLP_CONT_FO_COMP, 0, .iptr=&(nrUE_params.cont_fo_comp), .defintval=0, TYPE_INT, 0}, \ {"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \ - {"num-ul-actors", CONFIG_HLP_NUM_UL_ACTORS, 0, .iptr=&nrUE_params.num_ul_actors, .defintval=0, TYPE_INT, 0}, \ + {"num-ul-actors", CONFIG_HLP_NUM_UL_ACTORS, 0, .iptr=&nrUE_params.num_ul_actors, .defintval=2, TYPE_INT, 0}, \ + {"num-dl-actors", CONFIG_HLP_NUM_DL_ACTORS, 0, .iptr=&nrUE_params.num_dl_actors, .defintval=4, TYPE_INT, 0}, \ } // clang-format on @@ -119,6 +121,7 @@ typedef struct { int vcdflag; int tx_max_power; int num_ul_actors; + int num_dl_actors; } nrUE_params_t; extern uint64_t get_nrUE_optmask(void); extern uint64_t set_nrUE_optmask(uint64_t bitmask); diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index f22e3e212b..db8524eddd 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -81,8 +81,6 @@ #define bzero(s,n) (memset((s),0,(n))) /// suppress compiler warning for unused arguments #define UNUSED(x) (void)x; -#define NUM_DL_ACTORS 4 -#define NUM_UL_ACTORS 2 // Set the number of barriers for processSlotTX to 512. This value has to be at least 483 for NTN where // DL-to-UL offset is up to 483. The selected value is also half of the frame range so that @@ -519,8 +517,8 @@ typedef struct PHY_VARS_NR_UE_s { sl_nr_sidelink_mode_t sl_mode; sl_nr_ue_phy_params_t SL_UE_PHY_PARAMS; Actor_t sync_actor; - Actor_t dl_actors[NUM_DL_ACTORS]; - Actor_t ul_actors[NUM_UL_ACTORS]; + Actor_t *dl_actors; + Actor_t *ul_actors; ntn_config_message_t* ntn_config_message; pthread_t main_thread; pthread_t stat_thread; From 6574bc2c611ca8f029f64f256088db6998f65b2b Mon Sep 17 00:00:00 2001 From: arora Date: Wed, 28 May 2025 10:09:23 +0200 Subject: [PATCH 51/51] (doc): update README with build icons for dedicated arch and os Signed-off-by: arora --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 592ff13f66..17e275f240 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,9 @@

License - Supported OS Ubuntu 20 Supported OS Ubuntu 22 Supported OS Ubuntu 24 - Supported OS RELH9 + Supported OS RHEL9 Supported OS Fedora 41

@@ -16,7 +15,9 @@

- + + +