diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 318856f7d4..426537b51d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,16 +25,16 @@ include: - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/setup/all.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/features/all.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/tools/python.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/tools/test_reporter.yml - local: .gitlab/ci/builders/version.yml - local: .gitlab/ci/build.yml @@ -65,6 +65,7 @@ variables: ################################################################################ job cleaner: extends: .job cleaner + timeout: 4h rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ @@ -111,6 +112,20 @@ trigger docker: variables: PY_DIR: docker/metrics_server +helm: + stage: ci + rules: + - if: $CI_DESCRIPTION =~ /Weekly/ + variables: + CI_DESCRIPTION: Synchronization with srsGNB + NOTIFY_SLACK: "true" + trigger: + project: softwareradiosystems/ci/srsgnb_k8s + branch: main + needs: + - job: trigger docker + artifacts: false + ################################################################################ ## Static ################################################################################ @@ -259,10 +274,10 @@ clangsa: stage: static needs: [] variables: - KUBERNETES_CPU_REQUEST: 7 - KUBERNETES_CPU_LIMIT: 7 - KUBERNETES_MEMORY_REQUEST: 13Gi - KUBERNETES_MEMORY_LIMIT: 13Gi + KUBERNETES_CPU_REQUEST: 6 + KUBERNETES_CPU_LIMIT: 6 + KUBERNETES_MEMORY_REQUEST: 12Gi + KUBERNETES_MEMORY_LIMIT: 12Gi tags: - ${AMD64_TAG} interruptible: false diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 63745b6fa7..d5160c0f3b 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -17,7 +17,7 @@ variables: AMD64_AVX2_TAG: amd64-avx2 AMD64_AVX512_TAG: amd64-avx2-avx512 ARM64_TAG: arm64 - + INFRASTRUCTURE_TAG: description: Computer architecture and supported instruction sets options: @@ -280,7 +280,7 @@ variables: bash -c "${CTEST_CMD} && echo 0 > ${status_file} || echo 1 > ${status_file}" \ && ret=$(cat ${status_file}) || ret=124 - if [[ $TEST_MODE = "coverage" ]]; then + if [[ $TEST_MODE = "coverage" ]]; then common_options="-j${KUBERNETES_CPU_REQUEST} \ --exclude-unreachable-branches \ --gcov-ignore-parse-errors=negative_hits.warn_once_per_file \ @@ -677,7 +677,7 @@ intermediate commits cached: - if: $CI_MERGE_REQUEST_LABELS =~ /no-cache/ when: never - if: $ON_MR - timeout: 1 hour + timeout: 2 hour variables: SAVE_ARTIFACTS: "True" script: @@ -1889,7 +1889,7 @@ check-affinity-manager-nocpu: echo $output echo "**********************************************************************************" echo "Error for number of CPU = $((i-2))" - echo -e "\n\n\n\n\n" + echo -e "\n\n\n\n\n" fi done diff --git a/.gitlab/ci/builders.yml b/.gitlab/ci/builders.yml index 6c5519e2f1..37532ee6a2 100644 --- a/.gitlab/ci/builders.yml +++ b/.gitlab/ci/builders.yml @@ -8,13 +8,13 @@ include: - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/setup/all.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/tools/docker.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/tools/python.yml - local: .gitlab/ci/builders/version.yml - local: .gitlab/ci/src_cache.yml @@ -468,7 +468,7 @@ manifest [ubuntu, 20.04]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] ################################################################################ # Ubuntu 22.04 @@ -555,7 +555,7 @@ manifest [ubuntu, 22.04]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] ################################################################################ # Ubuntu 23.10 @@ -642,7 +642,7 @@ manifest [ubuntu, 23.10]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] ################################################################################ # Ubuntu 24.04 @@ -719,7 +719,7 @@ manifest [ubuntu, 24.04]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] ################################################################################ # Debian @@ -781,7 +781,7 @@ manifest [debian, 11]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] alternative-tag [debian, 12, amd64]: extends: @@ -826,7 +826,7 @@ manifest [debian, 12]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] ################################################################################ # Rhel 8 @@ -890,7 +890,7 @@ manifest [rhel, 8]: optional: false parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] ################################################################################ # Archlinux @@ -926,11 +926,11 @@ manifest [archlinux, latest]: script: - | skopeo copy \ - docker://${REGISTRY}${CI_PROJECT_NAMESPACE#'softwareradiosystems'}/${CI_PROJECT_NAME}/builder-$OS_NAME-$OS_VERSION:${DOCKER_BUILDER_VERSION}-amd64 \ - docker://${REGISTRY}${CI_PROJECT_NAMESPACE#'softwareradiosystems'}/${CI_PROJECT_NAME}/builder-$OS_NAME-$OS_VERSION:${DOCKER_BUILDER_VERSION} + docker://${REGISTRY_URI}${CI_PROJECT_NAMESPACE#'softwareradiosystems'}/${CI_PROJECT_NAME}/builder-$OS_NAME-$OS_VERSION:${DOCKER_BUILDER_VERSION}-amd64 \ + docker://${REGISTRY_URI}${CI_PROJECT_NAMESPACE#'softwareradiosystems'}/${CI_PROJECT_NAME}/builder-$OS_NAME-$OS_VERSION:${DOCKER_BUILDER_VERSION} parallel: matrix: - - REGISTRY: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] + - REGISTRY_URI: ["${CR_REGISTRY_URI}", "${GITLAB_REGISTRY_URI}"] needs: - builder version - job: alternative-tag [archlinux, latest, amd64] diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index b8cd7c9881..f533fbd339 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -8,13 +8,13 @@ include: - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/setup/all.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/tools/python.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/tools/docker.yml ################################################################################ @@ -120,23 +120,21 @@ metrics version check in retina: ################################################################################ .docker compose: stage: compose - image: docker:24.0.7 + image: docker:24.0.7-dind tags: - - saas-linux-medium-amd64 + - amd64-avx2 timeout: 2h - variables: - DOCKER_HOST: tcp://docker:2375/ - DOCKER_DRIVER: overlay2 - DOCKER_TLS_CERTDIR: "" - services: - - name: docker:24.0.7-dind - alias: docker - entrypoint: ["env", "-u", "DOCKER_HOST"] - command: ["dockerd-entrypoint.sh"] + before_script: + - dockerd-entrypoint.sh & + - | + while ! ( nc -zv localhost 2376 2>&1 >/dev/null ) + do + sleep 1 + done gnb docker compose: extends: .docker compose - variables: + variables: &build_in_compose_variables KUBERNETES_CPU_REQUEST: 6 KUBERNETES_CPU_LIMIT: 6 KUBERNETES_MEMORY_REQUEST: 12Gi @@ -151,7 +149,7 @@ gnb docker compose: - docker/docker-compose.yml - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ script: - - docker compose -f docker/docker-compose.yml build --build-arg LIB=${LIB} --build-arg LIB_VERSION=${LIB_VERSION} gnb + - docker compose -f docker/docker-compose.yml build --build-arg NUM_CORES=${KUBERNETES_CPU_LIMIT} --build-arg LIB=${LIB} --build-arg LIB_VERSION=${LIB_VERSION} gnb - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb ${TEST_CMD}" parallel: matrix: @@ -162,6 +160,8 @@ gnb docker compose: 5gc docker compose: extends: .docker compose + variables: + <<: *build_in_compose_variables rules: - if: $ON_MR changes: @@ -170,6 +170,7 @@ gnb docker compose: - docker/docker-compose.yml - if: $CI_DESCRIPTION =~ /Weekly/ script: + - docker compose -f docker/docker-compose.yml build --build-arg NUM_CORES=${KUBERNETES_CPU_LIMIT} 5gc - docker compose -f docker/docker-compose.yml run 5gc 5gc -v grafana docker compose: diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 16ee7dba5a..4d992d58c1 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -8,7 +8,7 @@ include: - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/setup/all.yml variables: @@ -305,11 +305,12 @@ amari 32UE: "iperf and tcp and not band:3", ] -amari 32UE beta: +amari 8UE beta: extends: amari 32UE parallel: matrix: - KEYWORDS: ["reestablishment", "handover"] + allow_failure: true amari 32UE asan: extends: .zmq @@ -521,14 +522,13 @@ viavi: - *retina-needs parallel: matrix: - - KEYWORDS: - [ - "fading and 32UE", - "fading and 1UE", - "ideal and 32UE", + - KEYWORDS: [ "ideal and 1UE", - "birth-death and 32UE", + "ideal and 32UE", + "fading and 1UE", + # "fading and 32UE", "birth-death and 1UE", + # "birth-death and 32UE", ] viavi-debug: @@ -576,5 +576,5 @@ retina setup: retina post: stage: .post extends: .demolition - dependencies: + dependencies: - load retina variables diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 81109095af..22aaf718df 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.49.16 +RETINA_VERSION=0.49.18 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/.gitlab/ci/release.yml b/.gitlab/ci/release.yml index 1cb2609b53..225637325b 100644 --- a/.gitlab/ci/release.yml +++ b/.gitlab/ci/release.yml @@ -8,10 +8,10 @@ include: - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/setup/all.yml - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/features/all.yml stages: diff --git a/.gitlab/ci/trx.yml b/.gitlab/ci/trx.yml index 07660f6a40..0b0273bd2a 100644 --- a/.gitlab/ci/trx.yml +++ b/.gitlab/ci/trx.yml @@ -8,7 +8,7 @@ include: - project: softwareradiosystems/ci/tools - ref: "19" + ref: "20" file: .gitlab/ci-shared/setup/all.yml - local: .gitlab/ci/build.yml diff --git a/apps/services/metrics_hub.cpp b/apps/services/metrics_hub.cpp index 28daf10bba..e5bb79221f 100644 --- a/apps/services/metrics_hub.cpp +++ b/apps/services/metrics_hub.cpp @@ -56,21 +56,33 @@ rlc_metrics_source* metrics_hub::get_rlc_metrics_source(std::string source_name_ return nullptr; } -void scheduler_ue_metrics_source::report_metrics(span ue_metrics) +scheduler_ue_metrics_source::scheduler_ue_metrics_source(std::string source_name_) : + metrics_hub_source(source_name_), + logger(srslog::fetch_basic_logger("ALL")), + metrics_pool(metric_pool_initial_capacity) +{ +} + +void scheduler_ue_metrics_source::report_metrics(const scheduler_cell_metrics& metrics) { srsran_assert(executor != nullptr, "Task executor must not be nullptr"); - std::vector ue_metrics_copy(ue_metrics.begin(), ue_metrics.end()); - if (not executor->execute([this, ue_metrics_copy]() { + + // Fetch a metrics report object from the pool. + auto cached_metrics = metrics_pool.get(); + // Try to reuse the pre-existing memory in the cached_metrics object. + cached_metrics->ue_metrics.assign(metrics.ue_metrics.begin(), metrics.ue_metrics.end()); + cached_metrics->nof_error_indications = metrics.nof_error_indications; + + if (not executor->execute([this, cached_metrics = std::move(cached_metrics)]() { for (auto& subscriber : subscribers) { - span ue_metrics_span(ue_metrics_copy); - subscriber->report_metrics(ue_metrics_span); + subscriber->report_metrics(*cached_metrics); } })) { - srslog::fetch_basic_logger("ALL").warning("Failed to dispatch scheduler UE metrics"); + logger.warning("Failed to dispatch scheduler UE metrics"); } } -void scheduler_ue_metrics_source::add_subscriber(scheduler_ue_metrics_notifier& subscriber) +void scheduler_ue_metrics_source::add_subscriber(scheduler_metrics_notifier& subscriber) { subscribers.push_back(&subscriber); } diff --git a/apps/services/metrics_hub.h b/apps/services/metrics_hub.h index a7362b050d..de5dd2a554 100644 --- a/apps/services/metrics_hub.h +++ b/apps/services/metrics_hub.h @@ -26,6 +26,7 @@ #include "srsran/rlc/rlc_metrics.h" #include "srsran/scheduler/scheduler_metrics.h" #include "srsran/support/executors/task_executor.h" +#include "srsran/support/memory_pool/unbounded_object_pool.h" namespace srsran { @@ -42,22 +43,28 @@ class metrics_hub_source task_executor* executor; }; -class scheduler_ue_metrics_source : public metrics_hub_source, public scheduler_ue_metrics_notifier +class scheduler_ue_metrics_source : public metrics_hub_source, public scheduler_metrics_notifier { public: - scheduler_ue_metrics_source(std::string source_name_) : metrics_hub_source(source_name_){}; - ~scheduler_ue_metrics_source() = default; - void report_metrics(span ue_metrics) override; - void add_subscriber(scheduler_ue_metrics_notifier& subscriber); + scheduler_ue_metrics_source(std::string source_name_); + void report_metrics(const scheduler_cell_metrics& metrics) override; + void add_subscriber(scheduler_metrics_notifier& subscriber); private: - std::vector subscribers; + static constexpr size_t metric_pool_initial_capacity = 3; + + srslog::basic_logger& logger; + + std::vector subscribers; + + // We use the metrics pool to cache and avoid allocating memory for each report in a RT thread. + unbounded_object_pool metrics_pool; }; class rlc_metrics_source : public metrics_hub_source, public rlc_metrics_notifier { public: - rlc_metrics_source(std::string source_name_) : metrics_hub_source(source_name_){}; + rlc_metrics_source(std::string source_name_) : metrics_hub_source(source_name_) {} ~rlc_metrics_source() = default; void report_metrics(const rlc_metrics& metrics) override; void add_subscriber(rlc_metrics_notifier& subscriber); diff --git a/apps/services/metrics_log_helper.cpp b/apps/services/metrics_log_helper.cpp index 4cecf9e3d8..15187470fc 100644 --- a/apps/services/metrics_log_helper.cpp +++ b/apps/services/metrics_log_helper.cpp @@ -114,20 +114,24 @@ static std::string float_to_eng_string(float f, int digits) return float_to_string(scaled, digits, 5 - factor.length()) + factor; } -void metrics_log_helper::report_metrics(span ue_metrics) +void metrics_log_helper::report_metrics(const scheduler_cell_metrics& metrics) { fmt::memory_buffer buffer; - for (const auto& ue : ue_metrics) { + for (const auto& ue : metrics.ue_metrics) { fmt::format_to(buffer, "Scheduler UE Metrics:"); fmt::format_to(buffer, " pci={}", ue.pci); fmt::format_to(buffer, " rnti={:x}", to_value(ue.rnti)); - if (!iszero(ue.cqi)) { - fmt::format_to(buffer, " cqi={}", int(ue.cqi)); + if (ue.cqi_stats.get_nof_observations() > 0) { + fmt::format_to(buffer, " cqi={}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); } else { fmt::format_to(buffer, " cqi=n/a"); } - fmt::format_to(buffer, " ri={}", int(ue.ri)); + if (ue.ri_stats.get_nof_observations() > 0) { + fmt::format_to(buffer, " ri={:.1f}", ue.ri_stats.get_mean()); + } else { + fmt::format_to(buffer, " ri=n/a"); + } fmt::format_to(buffer, " dl_mcs={}", int(ue.dl_mcs.to_uint())); if (ue.dl_brate_kbps > 0) { diff --git a/apps/services/metrics_log_helper.h b/apps/services/metrics_log_helper.h index 735331e50f..2319b4c943 100644 --- a/apps/services/metrics_log_helper.h +++ b/apps/services/metrics_log_helper.h @@ -28,7 +28,7 @@ namespace srsran { /// Class used to receive metrics reports and write them into a log file. -class metrics_log_helper : public scheduler_ue_metrics_notifier, public rlc_metrics_notifier +class metrics_log_helper : public scheduler_metrics_notifier, public rlc_metrics_notifier { public: explicit metrics_log_helper(srslog::basic_logger& logger_) : logger(logger_) {} @@ -37,7 +37,7 @@ class metrics_log_helper : public scheduler_ue_metrics_notifier, public rlc_metr bool is_enabled() const { return (logger.info.enabled() or logger.debug.enabled()); }; /// Notifier for the scheduler metrics. - void report_metrics(span ue_metrics) override; + void report_metrics(const scheduler_cell_metrics& metrics) override; /// Notifier for the RLC metrics. void report_metrics(const rlc_metrics& metrics) override; diff --git a/apps/services/metrics_plotter_json.cpp b/apps/services/metrics_plotter_json.cpp index 5cc386b2ad..2fd9bbf4c1 100644 --- a/apps/services/metrics_plotter_json.cpp +++ b/apps/services/metrics_plotter_json.cpp @@ -31,7 +31,7 @@ namespace { DECLARE_METRIC("pci", metric_pci, pci_t, ""); DECLARE_METRIC("rnti", metric_rnti, uint16_t, ""); DECLARE_METRIC("cqi", metric_cqi, uint8_t, ""); -DECLARE_METRIC("ri", metric_ri, uint8_t, ""); +DECLARE_METRIC("ri", metric_ri, float, ""); DECLARE_METRIC("dl_mcs", metric_dl_mcs, uint8_t, ""); DECLARE_METRIC("dl_brate", metric_dl_brate, double, ""); DECLARE_METRIC("dl_nof_ok", metric_dl_nof_ok, unsigned, ""); @@ -61,12 +61,23 @@ DECLARE_METRIC_SET("ue_container", metric_ul_nof_nok, metric_bsr); +/// cell-wide metrics. +DECLARE_METRIC("error_indication_count", metric_error_indication_count, unsigned, ""); +DECLARE_METRIC("average_latency", metric_average_latency, unsigned, ""); +DECLARE_METRIC("latency_thres_count", metric_latency_thres_count, unsigned, ""); +DECLARE_METRIC_LIST("latency_thres_count", mlist_thres_count, std::vector); +DECLARE_METRIC_SET("cell_metrics", + cell_metrics, + metric_error_indication_count, + metric_average_latency, + mlist_thres_count); + /// Metrics root object. DECLARE_METRIC("timestamp", metric_timestamp_tag, double, ""); DECLARE_METRIC_LIST("ue_list", mlist_ues, std::vector); /// Metrics context. -using metric_context_t = srslog::build_context_type; +using metric_context_t = srslog::build_context_type; } // namespace @@ -77,20 +88,22 @@ static double get_time_stamp() return std::chrono::duration_cast(tp).count() * 1e-3; } -void metrics_plotter_json::report_metrics(span ue_metrics) +void metrics_plotter_json::report_metrics(const scheduler_cell_metrics& metrics) { metric_context_t ctx("JSON Metrics"); - for (const auto& ue : ue_metrics) { + for (const auto& ue : metrics.ue_metrics) { ctx.get().emplace_back(); auto& output = ctx.get().back(); output.write(ue.pci); output.write(to_value(ue.rnti)); - if (ue.cqi) { - output.write(ue.cqi); + if (ue.cqi_stats.get_nof_observations() > 0) { + output.write(static_cast(std::roundf(ue.cqi_stats.get_mean()))); + } + if (ue.ri_stats.get_nof_observations() > 0) { + output.write(ue.ri_stats.get_mean()); } - output.write(ue.ri); output.write(ue.dl_mcs.to_uint()); output.write(ue.dl_brate_kbps * 1e3); output.write(ue.dl_nof_ok); @@ -106,6 +119,15 @@ void metrics_plotter_json::report_metrics(span ue_me output.write(ue.bsr); } + auto& cell_output = ctx.get(); + cell_output.write(metrics.nof_error_indications); + cell_output.write(metrics.average_decision_latency.count()); + for (unsigned count : metrics.latency_histogram) { + cell_output.get().emplace_back(); + auto& elem = cell_output.get().back(); + elem.value = count; + } + // Log the context. ctx.write(get_time_stamp()); log_chan(ctx); diff --git a/apps/services/metrics_plotter_json.h b/apps/services/metrics_plotter_json.h index 23b58d92e3..56f4f773fe 100644 --- a/apps/services/metrics_plotter_json.h +++ b/apps/services/metrics_plotter_json.h @@ -27,13 +27,13 @@ namespace srsran { /// Class used to receive metrics reports from scheduler and format them into a JSON file. -class metrics_plotter_json : public scheduler_ue_metrics_notifier +class metrics_plotter_json : public scheduler_metrics_notifier { public: explicit metrics_plotter_json(srslog::log_channel& log_chan_) : log_chan(log_chan_) {} /// Notifier called from the scheduler. - void report_metrics(span ue_metrics) override; + void report_metrics(const scheduler_cell_metrics& metrics) override; private: srslog::log_channel& log_chan; diff --git a/apps/services/metrics_plotter_stdout.cpp b/apps/services/metrics_plotter_stdout.cpp index f610b4c17c..f86df2cdb3 100644 --- a/apps/services/metrics_plotter_stdout.cpp +++ b/apps/services/metrics_plotter_stdout.cpp @@ -124,29 +124,34 @@ static std::string float_to_eng_string(float f, int digits) return " " + float_to_string(scaled, digits, 5 - factor.length()) + factor; } -void metrics_plotter_stdout::report_metrics(span ue_metrics) +void metrics_plotter_stdout::report_metrics(const scheduler_cell_metrics& metrics) { if (!print_metrics) { return; } - if (ue_metrics.size() > 10) { + if (metrics.ue_metrics.size() > 10) { print_header(); - } else if (++nof_lines > 10 && !ue_metrics.empty()) { + } else if (++nof_lines > 10 && !metrics.ue_metrics.empty()) { nof_lines = 0; print_header(); } - for (const auto& ue : ue_metrics) { + for (const auto& ue : metrics.ue_metrics) { fmt::print("{:>4}", ue.pci); fmt::print("{:>5x}", to_value(ue.rnti)); - if (!iszero(ue.cqi)) { - fmt::print(" | {:>3}", int(ue.cqi)); + + if (ue.cqi_stats.get_nof_observations() > 0) { + fmt::print(" | {:>3}", static_cast(std::roundf(ue.cqi_stats.get_mean()))); } else { fmt::print(" | {:>3.3}", "n/a"); } - fmt::print(" {:>2}", int(ue.ri)); + if (ue.ri_stats.get_nof_observations() > 0) { + fmt::print(" {:>3.1f}", ue.ri_stats.get_mean()); + } else { + fmt::print(" {:>3.3}", "n/a"); + } fmt::print(" {:>2}", int(ue.dl_mcs.to_uint())); if (ue.dl_brate_kbps > 0) { diff --git a/apps/services/metrics_plotter_stdout.h b/apps/services/metrics_plotter_stdout.h index 9e829d0247..36797dbd05 100644 --- a/apps/services/metrics_plotter_stdout.h +++ b/apps/services/metrics_plotter_stdout.h @@ -27,13 +27,13 @@ namespace srsran { /// Class used to receive metrics reports from scheduler and pretty-print them to the console. -class metrics_plotter_stdout : public scheduler_ue_metrics_notifier +class metrics_plotter_stdout : public scheduler_metrics_notifier { public: explicit metrics_plotter_stdout(bool print_metrics_) : print_metrics(print_metrics_) {} /// Notifier called from the scheduler. - void report_metrics(span ue_metrics) override; + void report_metrics(const scheduler_cell_metrics& metrics) override; /// This can be called from another execution context to turn on/off the actual plotting. void toggle_print(); diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager.cpp index 86f30da8fa..9e3a58cf99 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager.cpp @@ -204,7 +204,7 @@ std::vector worker_manager::create_fapi_ } std::vector -worker_manager::create_du_hi_slot_workers(unsigned nof_cells) +worker_manager::create_du_hi_slot_workers(unsigned nof_cells, bool rt_mode) { using namespace execution_config_helper; std::vector workers; @@ -218,7 +218,7 @@ worker_manager::create_du_hi_slot_workers(unsigned nof_cells) std::chrono::microseconds{10}, // Left empty, is filled later. {}, - os_thread_realtime_priority::max() - 2, + rt_mode ? os_thread_realtime_priority::max() - 2 : os_thread_realtime_priority::no_realtime(), affinity_mng[cell_id].calcute_affinity_mask(sched_affinity_mask_types::l2_cell)}; workers.push_back(du_cell_worker); @@ -256,7 +256,7 @@ void worker_manager::create_du_executors(bool is_blocking_m } // Workers for handling cell slot indications of different cells. - auto slot_workers = create_du_hi_slot_workers(nof_cells); + auto slot_workers = create_du_hi_slot_workers(nof_cells, not is_blocking_mode_active); for (unsigned cell_id = 0; cell_id != nof_cells; ++cell_id) { const std::string cell_id_str = std::to_string(cell_id); diff --git a/apps/services/worker_manager.h b/apps/services/worker_manager.h index 1ccdc9ba43..1d80c6d89e 100644 --- a/apps/services/worker_manager.h +++ b/apps/services/worker_manager.h @@ -142,7 +142,8 @@ struct worker_manager : public worker_manager_executor_getter { std::vector create_fapi_workers(unsigned nof_cells); - std::vector create_du_hi_slot_workers(unsigned nof_cells); + std::vector create_du_hi_slot_workers(unsigned nof_cells, + bool rt_mode); /// Helper method that creates the Distributed Unit executors. void create_du_executors(bool is_blocking_mode_active, diff --git a/apps/units/cu_cp/cu_cp_config_translators.cpp b/apps/units/cu_cp/cu_cp_config_translators.cpp index 26656938bd..5a74f60003 100644 --- a/apps/units/cu_cp/cu_cp_config_translators.cpp +++ b/apps/units/cu_cp/cu_cp_config_translators.cpp @@ -24,6 +24,7 @@ #include "cu_cp_unit_config.h" #include "srsran/cu_cp/cu_cp_configuration_helpers.h" #include "srsran/ran/nr_cgi_helpers.h" +#include "srsran/rlc/rlc_config.h" #include using namespace srsran; diff --git a/apps/units/flexible_du/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/du_high/du_high_config_translators.cpp index 39e522bcfc..11f7738f62 100644 --- a/apps/units/flexible_du/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_translators.cpp @@ -844,8 +844,8 @@ e2ap_configuration srsran::generate_e2_config(const du_high_unit_config& du_high { e2ap_configuration out_cfg = srsran::config_helpers::make_default_e2ap_config(); out_cfg.gnb_id = du_high.gnb_id; - out_cfg.ran_node_name = "srsgnb01"; // TODO: Remove dependency from E2-DU. out_cfg.plmn = du_high.cells_cfg.front().cell.plmn; + out_cfg.gnb_du_id = du_high.gnb_du_id; out_cfg.e2sm_kpm_enabled = du_high.e2_cfg.e2sm_kpm_enabled; out_cfg.e2sm_rc_enabled = du_high.e2_cfg.e2sm_rc_enabled; diff --git a/docker/open5gs/Dockerfile b/docker/open5gs/Dockerfile index 5c314424de..eeef086e4d 100644 --- a/docker/open5gs/Dockerfile +++ b/docker/open5gs/Dockerfile @@ -68,10 +68,12 @@ RUN echo $OPEN5GS_VERSION > ./open5gsversion # RUN git ls-remote --tags https://github.com/open5gs/open5gs | sort -t '/' -k 3 -V | awk -F/ '{ print $3 }' | awk '!/\^\{\}/' | tail -n 1 > ./open5gsversion # open5gs -RUN git clone --depth 1 --branch $(cat ./open5gsversion) https://github.com/open5gs/open5gs open5gs\ +ARG NUM_CORES="" +RUN if [ -z "$NUM_CORES" ]; then NUM_CORES=$(nproc); fi && \ + git clone --depth 1 --branch $(cat ./open5gsversion) https://github.com/open5gs/open5gs open5gs\ && cd open5gs \ && meson build --prefix=`pwd`/install \ - && ninja -C build \ + && ninja -j ${NUM_CORES} -C build \ && cd build \ && ninja install diff --git a/include/srsran/adt/complex.h b/include/srsran/adt/complex.h index 4fa469b383..0f4eee49b7 100644 --- a/include/srsran/adt/complex.h +++ b/include/srsran/adt/complex.h @@ -55,6 +55,8 @@ struct cbf16_t { cbf16_t(cf_t value) : cbf16_t(value.real(), value.imag()) {} + cbf16_t(std::complex value) : real(to_bf16(value.real())), imag(to_bf16(value.imag())) {} + bool operator==(cbf16_t other) const { return (real == other.real) && (imag == other.imag); } bool operator!=(cbf16_t other) const { return !(*this == other); } diff --git a/include/srsran/adt/mpmc_queue.h b/include/srsran/adt/mpmc_queue.h index f2c9ea4456..6c06e46d81 100644 --- a/include/srsran/adt/mpmc_queue.h +++ b/include/srsran/adt/mpmc_queue.h @@ -31,53 +31,38 @@ namespace srsran { namespace detail { -// Specialization for lockfree MPMC using no blocking mechanism. +/// Specialization for lockfree MPMC without a blocking mechanism. template class queue_impl { - struct custom_deleter { - void operator()(::rigtorp::MPMCQueue* ptr) const - { - using mpmc_queue = ::rigtorp::MPMCQueue; - if (ptr != nullptr) { - ptr->~mpmc_queue(); - free(ptr); - } - } - }; - public: template - explicit queue_impl(size_t qsize) + explicit queue_impl(size_t qsize) : queue(qsize) { - // Note: Pre-c++17 does not support new with alignof > alignof(max_align_t). - void* ptr = nullptr; - int ret = posix_memalign(&ptr, alignof(::rigtorp::MPMCQueue), sizeof(::rigtorp::MPMCQueue)); - report_error_if_not(ret == 0, "Unable to allocate memory for MPMCQueue"); - queue.reset(new (ptr)::rigtorp::MPMCQueue(qsize)); } - bool try_push(const T& elem) { return queue->try_push(elem); } - bool try_push(T&& elem) { return queue->try_push(std::move(elem)); } + bool try_push(const T& elem) { return queue.try_push(elem); } + + bool try_push(T&& elem) { return queue.try_push(std::move(elem)); } - bool try_pop(T& elem) { return queue->try_pop(elem); } + bool try_pop(T& elem) { return queue.try_pop(elem); } size_t size() const { // Note: MPMCqueue size can be negative. - ptrdiff_t ret = queue->size(); + ptrdiff_t ret = queue.size(); return static_cast(std::max(ret, static_cast(0))); } - bool empty() const { return queue->empty(); } + bool empty() const { return queue.empty(); } - size_t capacity() const { return queue->capacity(); } + size_t capacity() const { return queue.capacity(); } protected: - std::unique_ptr<::rigtorp::MPMCQueue, custom_deleter> queue; + ::rigtorp::MPMCQueue queue; }; -// Specialization for lockfree MPMC using a sleep as blocking mechanism. +/// Specialization for lockfree MPMC using a sleep as the blocking mechanism. template class queue_impl : public queue_impl @@ -133,4 +118,4 @@ class queue_impl class queue_impl { @@ -64,7 +65,7 @@ class queue_impl queue; }; -// Specialization for lock-based MPMC, using a condition variable as blocking mechanism. +/// Specialization for lock-based MPMC, using a condition variable as the blocking mechanism. template class queue_impl : public queue_impl diff --git a/include/srsran/adt/mutexed_mpsc_queue.h b/include/srsran/adt/mutexed_mpsc_queue.h index 25332d3643..86b3110a75 100644 --- a/include/srsran/adt/mutexed_mpsc_queue.h +++ b/include/srsran/adt/mutexed_mpsc_queue.h @@ -30,8 +30,8 @@ namespace srsran { namespace detail { -// Specialization for lock-based MPSC, using a condition variable or sleep as blocking mechanism. The dequeues are -// done in a batch to minimize mutex contention. +/// Specialization for lock-based MPSC, using a condition variable or sleep as blocking mechanism. The dequeues are done +/// in a batch to minimize mutex contention. template class queue_impl { @@ -39,6 +39,13 @@ class queue_impl queue_cond_var_barrier, queue_sleep_barrier>; + const size_t cap; + std::atomic count_local_objs{0}; + std::array, 2> queues; + unsigned index_queue_for_pop = 0; + mutable std::mutex mutex; + queue_barrier barrier; + public: template explicit queue_impl(size_t qsize, Args&&... args) : @@ -166,18 +173,13 @@ class queue_impl count_local_objs.fetch_sub(1, std::memory_order_relaxed); } - ring_buffer& popping_queue() { return queues[index_queue_for_pop]; } - ring_buffer& pushing_queue() { return queues[1 - index_queue_for_pop]; } - const ring_buffer& pushing_queue() const { return queues[1 - index_queue_for_pop]; } + ring_buffer& popping_queue() { return queues[index_queue_for_pop]; } - const size_t cap; - std::atomic count_local_objs{0}; - std::array, 2> queues; - unsigned index_queue_for_pop = 0; - mutable std::mutex mutex; - queue_barrier barrier; + ring_buffer& pushing_queue() { return queues[1 - index_queue_for_pop]; } + + const ring_buffer& pushing_queue() const { return queues[1 - index_queue_for_pop]; } }; } // namespace detail -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/adt/spsc_queue.h b/include/srsran/adt/spsc_queue.h index c4ffdd49ae..92e0b42753 100644 --- a/include/srsran/adt/spsc_queue.h +++ b/include/srsran/adt/spsc_queue.h @@ -31,60 +31,44 @@ namespace srsran { namespace detail { -// Specialization for lockfree SPSC without blocking mechanism. +/// Specialization for lockfree SPSC without a blocking mechanism. template class queue_impl { - struct custom_deleter { - void operator()(::rigtorp::SPSCQueue* ptr) const - { - using namespace ::rigtorp; - if (ptr != nullptr) { - ptr->~SPSCQueue(); - free(ptr); - } - } - }; - public: template - explicit queue_impl(size_t qsize) + explicit queue_impl(size_t qsize) : queue(qsize) { - // Note: Pre-c++17 does not support new with alignof > alignof(max_align_t). - void* ptr = nullptr; - int ret = posix_memalign(&ptr, alignof(::rigtorp::SPSCQueue), sizeof(::rigtorp::SPSCQueue)); - report_error_if_not(ret == 0, "Unable to allocate memory for SPSCQueue"); - queue.reset(new (ptr)::rigtorp::SPSCQueue(qsize)); } template bool try_push(U&& elem) { - return queue->try_push(std::forward(elem)); + return queue.try_push(std::forward(elem)); } bool try_pop(T& elem) { - T* front = queue->front(); + T* front = queue.front(); if (front != nullptr) { elem = std::move(*front); - queue->pop(); + queue.pop(); return true; } return false; } - size_t size() const { return queue->size(); } + size_t size() const { return queue.size(); } - bool empty() const { return queue->empty(); } + bool empty() const { return queue.empty(); } - size_t capacity() const { return queue->capacity(); } + size_t capacity() const { return queue.capacity(); } protected: - std::unique_ptr<::rigtorp::SPSCQueue, custom_deleter> queue; + ::rigtorp::SPSCQueue queue; }; -// Specialization for lockfree SPSC using a spin sleep loop as blocking mechanism. +/// Specialization for lockfree SPSC using a spin sleep loop as the blocking mechanism. template class queue_impl : public queue_impl @@ -118,7 +102,7 @@ class queue_implqueue->pop(); + this->queue.pop(); return true; } return false; @@ -130,7 +114,7 @@ class queue_implqueue->pop(); + this->queue.pop(); return true; } return false; @@ -140,7 +124,7 @@ class queue_implqueue->front(); + T* front = this->queue.front(); if (front != nullptr) { return front; } @@ -154,4 +138,4 @@ class queue_impl bands; /// NR bands provided/supported by the cell. - du_sys_info sys_info; /// System information provided by DU -}; - -struct du_processor_context { - du_index_t du_index = du_index_t::invalid; /// Index assisgned by CU-CP - gnb_du_id_t id = gnb_du_id_t::invalid; /// the gNB-DU-ID - std::string name = "none"; /// gNB-DU-Name +struct du_cell_configuration { + /// CU-CP specific DU cell identifier. + du_cell_index_t cell_index = du_cell_index_t::invalid; + /// Global cell ID. + nr_cell_global_id_t cgi; + /// Tracking Area Code + uint32_t tac; + /// Physical cell ID + pci_t pci; + /// NR bands provided/supported by the cell. + std::vector bands; + /// System Information provided by the DU for this cell. + du_sys_info sys_info; }; } // namespace srs_cu_cp - } // namespace srsran diff --git a/include/srsran/cu_cp/security_manager_config.h b/include/srsran/cu_cp/security_manager_config.h new file mode 100644 index 0000000000..b05b4d2802 --- /dev/null +++ b/include/srsran/cu_cp/security_manager_config.h @@ -0,0 +1,36 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/security/security.h" + +namespace srsran { +namespace srs_cu_cp { + +struct security_manager_config { + security::preferred_integrity_algorithms int_algo_pref_list; ///< Integrity protection algorithms preference list + security::preferred_ciphering_algorithms enc_algo_pref_list; ///< Encryption algorithms preference list +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_factory.cpp b/include/srsran/cu_cp/ue_configuration.h similarity index 70% rename from lib/cu_cp/up_resource_manager/up_resource_manager_factory.cpp rename to include/srsran/cu_cp/ue_configuration.h index 81d473a248..7c2f2ff779 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_factory.cpp +++ b/include/srsran/cu_cp/ue_configuration.h @@ -20,13 +20,18 @@ * */ -#include "up_resource_manager_impl.h" -#include "srsran/cu_cp/up_resource_manager.h" +#pragma once -using namespace srsran; +#include "srsran/cu_cp/cu_cp_types.h" -std::unique_ptr -srsran::srs_cu_cp::create_up_resource_manager(const srs_cu_cp::up_resource_manager_cfg& cfg_) -{ - return std::make_unique(cfg_); -} \ No newline at end of file +namespace srsran { +namespace srs_cu_cp { + +/// UE configuration passed to CU-CP +struct ue_configuration { + std::chrono::seconds inactivity_timer; + unsigned max_nof_supported_ues = MAX_NOF_CU_UES; +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/include/srsran/cu_cp/ue_manager.h b/include/srsran/cu_cp/ue_manager.h deleted file mode 100644 index bfa1365973..0000000000 --- a/include/srsran/cu_cp/ue_manager.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * This file is part of srsRAN. - * - * srsRAN is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsRAN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#pragma once - -#include "ue_task_scheduler.h" -#include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/ngap/ngap.h" -#include "srsran/ngap/ngap_types.h" -#include "srsran/ran/gnb_du_id.h" -#include "srsran/rrc/rrc_ue.h" - -namespace srsran { -namespace srs_cu_cp { - -/// Forward declared classes. -class du_processor_rrc_ue_control_message_notifier; -class du_processor_rrc_ue_srb_control_notifier; - -/// \brief Context of a CU-CP UE. -struct cu_cp_ue_context { - du_index_t du_idx = du_index_t::invalid; - gnb_du_id_t du_id = gnb_du_id_t::invalid; - ue_index_t ue_index = ue_index_t::invalid; - rnti_t crnti = rnti_t::INVALID_RNTI; - /// \brief Flag to disable new UE reconfigurations. This can be used, for instance, to reconfigure UE contexts - /// that are in the process of handover. - bool reconfiguration_disabled = false; -}; - -/// Common UE interface. -class common_ue -{ -public: - virtual ~common_ue() = default; - - /// \brief Get the UE index of the UE. - virtual ue_index_t get_ue_index() = 0; - - /// \brief Get the UP resource manager of the UE. - virtual up_resource_manager& get_up_resource_manager() = 0; - - /// \brief Get the task scheduler of the UE. - virtual ue_task_scheduler& get_task_sched() = 0; - - /// \brief Get the security context of the UE. - virtual security::security_context& get_security_context() = 0; -}; - -/// Interface for DU UE. -class du_ue -{ -public: - virtual ~du_ue() = default; - - // common - /// \brief Get the UE index of the UE. - virtual ue_index_t get_ue_index() = 0; - - /// \brief Get the UP resource manager of the UE. - virtual up_resource_manager& get_up_resource_manager() = 0; - - /// \brief Get the task scheduler of the UE. - virtual ue_task_scheduler& get_task_sched() = 0; - - /// \brief Get the security context of the UE. - virtual security::security_context& get_security_context() = 0; - - /// \brief Get the RRC UE control message notifier of the UE. - virtual du_processor_rrc_ue_control_message_notifier& get_rrc_ue_notifier() = 0; - - /// \brief Get the RRC UE SRB control notifier of the UE. - virtual du_processor_rrc_ue_srb_control_notifier& get_rrc_ue_srb_notifier() = 0; - - /// \brief Get the RRC UE context update notifier of the UE. - virtual rrc_ue_context_update_notifier& get_rrc_ue_context_update_notifier() = 0; - - /// \brief Get the RRC UE measurement notifier of the UE. - virtual rrc_ue_measurement_notifier& get_rrc_ue_measurement_notifier() = 0; - - /// \brief Get the PCI of the UE. - [[nodiscard]] virtual pci_t get_pci() const = 0; - - /// \brief Get the C-RNTI of the UE. - [[nodiscard]] virtual rnti_t get_c_rnti() const = 0; - - /// \brief Get the DU index of the UE. - virtual du_index_t get_du_index() = 0; - - /// \brief Get the PCell index of the UE. - virtual du_cell_index_t get_pcell_index() = 0; - - /// \brief Update a UE with DU-Id, PCI and/or C-RNTI. - virtual void update_du_ue(gnb_du_id_t du_id_, pci_t pci_, rnti_t c_rnti_) = 0; - - /// \brief Set the PCell infox of the UE. - /// \param[in] pcell_index PCell index of the UE. - virtual void set_pcell_index(du_cell_index_t pcell_index) = 0; - - /// \brief Set the RRC UE control message notifier of the UE. - /// \param[in] rrc_ue_notifier_ RRC UE control message notifier of the UE. - virtual void set_rrc_ue_notifier(du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_) = 0; - - /// \brief Set the RRC UE SRB notifier of the UE. - /// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. - virtual void set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_) = 0; - - /// \brief Retrieves the UE context. - virtual cu_cp_ue_context& get_ue_context() = 0; - [[nodiscard]] virtual const cu_cp_ue_context& get_ue_context() const = 0; -}; - -/// UE configuration passed to CU-CP -struct ue_configuration { - std::chrono::seconds inactivity_timer; - unsigned max_nof_supported_ues = MAX_NOF_CU_UES; -}; - -/// Common UE manager interface. -class common_ue_manager -{ -public: - virtual ~common_ue_manager() = default; - - /// \brief Find the UE with the given UE index. - /// \param[in] ue_index Index of the UE to be found. - /// \return Pointer to the UE if found, nullptr otherwise. - virtual common_ue* find_ue(ue_index_t ue_index) = 0; -}; - -/// DU Processor UE manager interface. -class du_processor_ue_manager -{ -public: - virtual ~du_processor_ue_manager() = default; - - /// \brief Allocate and return the UE index of a new UE. - virtual ue_index_t add_ue(du_index_t du_index) = 0; - - /// \brief Add PCI and C-RNTI to a UE for the given UE index. If the UE can't be found or if a UE with the UE index - /// was already setup, nulltpr is returned. - /// \param[in] ue_index Index of the UE to add the notifiers to. - /// \param[in] du_id gNB-DU Id of the DU to which UE connected to. - /// \param[in] pci PCI of the cell that the UE is connected to. - /// \param[in] rnti RNTI of the UE to be added. - /// \return Pointer to the newly added DU UE if successful, nullptr otherwise. - virtual du_ue* set_ue_du_context(ue_index_t ue_index, gnb_du_id_t du_id, pci_t pci, rnti_t rnti) = 0; - - /// \brief Find the DU UE with the given UE index. - /// \param[in] ue_index Index of the UE to be found. - /// \return Pointer to the DU UE if found, nullptr otherwise. - virtual du_ue* find_du_ue(ue_index_t ue_index) = 0; - - /// \brief Find the UE task scheduler of the specified UE, even if the DU UE context is not created. - /// \param[in] ue_index Index of the UE. - /// \return Pointer to the UE task scheduler if found, nullptr otherwise. - virtual ue_task_scheduler* find_ue_task_scheduler(ue_index_t ue_index) = 0; - - /// \brief Get the number of UEs connected to a specific DU. - /// \return Number of UEs. - virtual size_t get_nof_du_ues(du_index_t du_index) = 0; -}; - -/// Interface for NGAP UE. -class ngap_ue -{ -public: - virtual ~ngap_ue() = default; - - /// \brief Get the UE index of the UE. - virtual ue_index_t get_ue_index() = 0; - - /// \brief Get the UP resource manager of the UE. - virtual up_resource_manager& get_up_resource_manager() = 0; - - /// \brief Get the task scheduler of the UE. - virtual ue_task_scheduler& get_task_sched() = 0; - - /// \brief Get the RRC UE PDU notifier of the UE. - virtual ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() = 0; - - /// \brief Get the RRC UE control notifier of the UE. - virtual ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() = 0; -}; - -/// NGAP UE manager interface. -class ngap_ue_manager -{ -public: - virtual ~ngap_ue_manager() = default; - - /// \brief Add notifier to a UE for the given UE index. A RAN UE ID is allocated internally. If a new UE can't be - /// found or if a UE with the UE index was already setup, nulltpr is returned. - /// \param[in] ue_index Index of the UE to add the notifiers to. - /// \param[in] rrc_ue_pdu_notifier RRC UE PDU notifier for the UE. - /// \param[in] rrc_ue_ctrl_notifier RRC UE control notifier for the UE. - /// \return Pointer to the NGAP UE if found, nullptr otherwise. - virtual ngap_ue* set_ue_ng_context(ue_index_t ue_index, - ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier, - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier) = 0; - - /// \brief Find the NGAP UE with the given UE index. - /// \param[in] ue_index Index of the UE to be found. - /// \return Pointer to the NGAP UE if found, nullptr otherwise. - virtual ngap_ue* find_ngap_ue(ue_index_t ue_index) = 0; - - /// \brief Find the UE task scheduler of the specified UE, even if the NGAP UE context is not created. - /// \param[in] ue_index Index of the UE. - /// \return Pointer to the UE task scheduler if found, nullptr otherwise. - virtual ue_task_scheduler* find_ue_task_scheduler(ue_index_t ue_index) = 0; - - /// \brief Get the number of UEs connected to the AMF. - /// \return Number of UEs. - virtual size_t get_nof_ngap_ues() = 0; -}; - -} // namespace srs_cu_cp -} // namespace srsran diff --git a/include/srsran/cu_cp/up_context.h b/include/srsran/cu_cp/up_context.h new file mode 100644 index 0000000000..228c7086d4 --- /dev/null +++ b/include/srsran/cu_cp/up_context.h @@ -0,0 +1,74 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "cu_cp_types.h" +#include "srsran/ran/lcid.h" +#include "srsran/rlc/rlc_config.h" + +namespace srsran { + +namespace srs_cu_cp { + +/// \brief List of all supported 5QIs and their corresponding PDCP/SDAP configs +struct up_resource_manager_cfg { + std::map five_qi_config; ///< Configuration for available 5QI. +}; + +struct up_qos_flow_context { + qos_flow_id_t qfi = qos_flow_id_t::invalid; + cu_cp_qos_flow_level_qos_params qos_params; +}; + +struct up_drb_context { + srsran::drb_id_t drb_id = drb_id_t::invalid; + pdu_session_id_t pdu_session_id = pdu_session_id_t::invalid; + s_nssai_t s_nssai = {}; + bool default_drb = false; + srsran::rlc_mode rlc_mod; + cu_cp_qos_flow_level_qos_params qos_params; // DRB QoS params. + std::map qos_flows; // QoS flow IDs of all QoS flows mapped to this DRB. + std::vector ul_up_tnl_info_to_be_setup_list; // Allocated by CU-UP. + + pdcp_config pdcp_cfg; + sdap_config_t sdap_cfg; +}; + +struct up_pdu_session_context { + up_pdu_session_context(pdu_session_id_t id_) : id(id_){}; + pdu_session_id_t id = pdu_session_id_t::invalid; + std::map drbs; +}; + +/// \brief This struct holds the UP configuration currently in place. +struct up_context { + std::map pdu_sessions; // Map of existing PDU sessions. + + /// Hash-maps for quick access. + std::map drb_map; // Maps DRB ID to corresponding PDU session. + std::map qos_flow_map; // Maps QoS flow to corresponding DRB. +}; + +} // namespace srs_cu_cp + +} // namespace srsran diff --git a/include/srsran/cu_cp/up_resource_manager.h b/include/srsran/cu_cp/up_resource_manager.h deleted file mode 100644 index b3ed7fe3e0..0000000000 --- a/include/srsran/cu_cp/up_resource_manager.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * - * Copyright 2021-2024 Software Radio Systems Limited - * - * This file is part of srsRAN. - * - * srsRAN is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * srsRAN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#pragma once - -#include "cu_cp_types.h" -#include "srsran/ran/lcid.h" -#include "srsran/rlc/rlc_config.h" - -namespace srsran { - -namespace srs_cu_cp { - -/// \brief List of all supported 5QIs and their corresponding PDCP/SDAP configs -struct up_resource_manager_cfg { - std::map five_qi_config; ///< Configuration for available 5QI. -}; - -struct up_qos_flow_context { - qos_flow_id_t qfi = qos_flow_id_t::invalid; - cu_cp_qos_flow_level_qos_params qos_params; -}; - -struct up_drb_context { - srsran::drb_id_t drb_id = drb_id_t::invalid; - pdu_session_id_t pdu_session_id = pdu_session_id_t::invalid; - s_nssai_t s_nssai = {}; - bool default_drb = false; - srsran::rlc_mode rlc_mod; - cu_cp_qos_flow_level_qos_params qos_params; // DRB QoS params. - std::map qos_flows; // QoS flow IDs of all QoS flows mapped to this DRB. - std::vector ul_up_tnl_info_to_be_setup_list; // Allocated by CU-UP. - - pdcp_config pdcp_cfg; - sdap_config_t sdap_cfg; -}; - -struct up_pdu_session_context { - up_pdu_session_context(pdu_session_id_t id_) : id(id_){}; - pdu_session_id_t id = pdu_session_id_t::invalid; - std::map drbs; -}; - -/// \brief This struct holds the UP configuration currently in place. -struct up_context { - std::map pdu_sessions; // Map of existing PDU sessions. - - /// Hash-maps for quick access. - std::map drb_map; // Maps DRB ID to corresponding PDU session. - std::map qos_flow_map; // Maps QoS flow to corresponding DRB. -}; - -/// \brief Update for a PDU session. -struct up_pdu_session_context_update { - up_pdu_session_context_update(pdu_session_id_t id_) : id(id_){}; - pdu_session_id_t id; - std::map drb_to_add; - std::vector drb_to_remove; -}; - -// Struct that contains all fields required to update the UP config based on an incoming -// PDU sessions resource setup request over NGAP. This config is then used to: -// * Initiate or modifiy the CU-UPs bearer context over E1AP -// * Modify the DU's UE context over F1AP -// * Modify the CU-UPs bearer context over E1AP (update TEIDs, etc) -// * Modify the UE's configuration over RRC signaling -// For PDU sessions to be setup the entire session context is included in the struct as this has been allocated by UP -// resource manager. For removal of PDU sessions or DRBs only the respective identifiers are included. -struct up_config_update { - bool initial_context_creation = true; // True if this is the first PDU session to be created. - std::map - pdu_sessions_to_setup_list; // List of PDU sessions to be added. - std::map - pdu_sessions_to_modify_list; // List of PDU sessions to be modified. - std::vector pdu_sessions_to_remove_list; // List of PDU sessions to be removed. - std::vector pdu_sessions_failed_to_modify_list; // List of PDU sessions that failed to be modified. - std::vector drb_to_remove_list; // List of DRBs to be removed. -}; - -// Response given back to the UP resource manager containing the full context -// that could be setup. -struct up_config_update_result { - std::vector pdu_sessions_added_list; // List of sessions that have been added. - std::vector pdu_sessions_modified_list; // List of sessions that have been modified. - std::vector pdu_sessions_removed_list; // List of sessions that have been removed. -}; - -/// \brief Free function to convert existing UP context into config update (useful to setup new UEs). -up_config_update to_config_update(const up_context& old_context); - -/// Object to manage user-plane (UP) resources including configs, PDU session, DRB and QoS flow -/// allocation/creation/deletion -class up_resource_manager -{ -public: - virtual ~up_resource_manager() = default; - - /// \brief Checks whether incoming PDU session resource setup items are valid. - virtual bool - validate_request(const slotted_id_vector& setup_items) = 0; - - /// \brief Checks whether an incoming PDU session resource modify request is valid. - virtual bool validate_request(const cu_cp_pdu_session_resource_modify_request& pdu) = 0; - - /// \brief Checks whether an incoming PDU session resource release command is valid. - virtual bool validate_request(const cu_cp_pdu_session_resource_release_command& pdu) = 0; - - /// \brief Returns updated UP config based on the PDU session resource setup items. - virtual up_config_update - calculate_update(const slotted_id_vector& setup_items) = 0; - - /// \brief Returns updated UP config based on the PDU session resource modification request. - virtual up_config_update calculate_update(const cu_cp_pdu_session_resource_modify_request& pdu) = 0; - - /// \brief Returns updated UP config based on the PDU session resource release command. - virtual up_config_update calculate_update(const cu_cp_pdu_session_resource_release_command& pdu) = 0; - - /// \brief Apply and merge the config with the currently stored one. - virtual bool apply_config_update(const up_config_update_result& config) = 0; - - /// \brief Return context for given PDU session ID. - virtual const up_pdu_session_context& get_pdu_session_context(pdu_session_id_t psi) = 0; - - /// \brief Return context for a given DRB ID. - virtual const up_drb_context& get_drb_context(drb_id_t drb_id) = 0; - - /// \brief Returns True if PDU session with given ID already exists. - virtual bool has_pdu_session(pdu_session_id_t pdu_session_id) = 0; - - /// \brief Return number of DRBs. - virtual size_t get_nof_drbs() = 0; - - /// \brief Returns the number of PDU sessions of the UE. - virtual size_t get_nof_pdu_sessions() = 0; - - /// \brief Returns the number of active QoS flows in a particular PDU sessions. - virtual size_t get_nof_qos_flows(pdu_session_id_t psi) = 0; - - /// \brief Returns the number of *all* active QoS flows across all PDU sessions. - virtual size_t get_total_nof_qos_flows() = 0; - - /// \brief Return a map of all PDU sessions as const reference. - virtual const std::map& get_pdu_sessions_map() = 0; - - /// \brief Return vector of ID of all active PDU sessions. - virtual std::vector get_pdu_sessions() = 0; - - /// \brief Return vector of active DRBs. - virtual std::vector get_drbs() = 0; - - /// \brief Return up context for transfer. - virtual up_context get_up_context() = 0; - - /// \brief Set up context from an already existing context. - virtual void set_up_context(const up_context& ctx) = 0; -}; - -/// Creates an instance of an UP resource manager. -std::unique_ptr create_up_resource_manager(const up_resource_manager_cfg& cfg_); - -} // namespace srs_cu_cp - -} // namespace srsran diff --git a/include/srsran/du_high/du_high_configuration.h b/include/srsran/du_high/du_high_configuration.h index d1fd6886bd..c74e15cb6f 100644 --- a/include/srsran/du_high/du_high_configuration.h +++ b/include/srsran/du_high/du_high_configuration.h @@ -36,7 +36,7 @@ struct du_high_configuration { f1u_du_gateway* f1u_gw = nullptr; mac_result_notifier* phy_adapter = nullptr; timer_manager* timers = nullptr; - scheduler_ue_metrics_notifier* sched_ue_metrics_notifier = nullptr; + scheduler_metrics_notifier* sched_ue_metrics_notifier = nullptr; rlc_metrics_notifier* rlc_metrics_notif = nullptr; e2_connection_client* e2_client = nullptr; e2_du_metrics_interface* e2_du_metric_iface = nullptr; diff --git a/include/srsran/e1ap/cu_cp/e1ap_cu_cp.h b/include/srsran/e1ap/cu_cp/e1ap_cu_cp.h index e08ffa3234..6d09629e85 100644 --- a/include/srsran/e1ap/cu_cp/e1ap_cu_cp.h +++ b/include/srsran/e1ap/cu_cp/e1ap_cu_cp.h @@ -134,6 +134,12 @@ class e1ap_cu_cp_notifier public: virtual ~e1ap_cu_cp_notifier() = default; + /// \brief Request scheduling a task for a UE. + /// \param[in] ue_index The index of the UE. + /// \param[in] task The task to schedule. + /// \returns True if the task was successfully scheduled, false otherwise. + virtual bool schedule_async_task(ue_index_t ue_index, async_task task) = 0; + /// \brief Notifies about the reception of a Bearer Context Inactivity Notification message. /// \param[in] msg The received Bearer Context Inactivity Notification message. virtual void on_bearer_context_inactivity_notification_received(const cu_cp_inactivity_notification& msg) = 0; diff --git a/include/srsran/e1ap/cu_cp/e1ap_cu_cp_factory.h b/include/srsran/e1ap/cu_cp/e1ap_cu_cp_factory.h index 45a64866b2..61d8ad161f 100644 --- a/include/srsran/e1ap/cu_cp/e1ap_cu_cp_factory.h +++ b/include/srsran/e1ap/cu_cp/e1ap_cu_cp_factory.h @@ -23,7 +23,6 @@ #pragma once #include "e1ap_cu_cp.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/support/executors/task_executor.h" #include "srsran/support/timers.h" #include @@ -35,7 +34,6 @@ namespace srs_cu_cp { std::unique_ptr create_e1ap(e1ap_message_notifier& e1ap_pdu_notifier_, e1ap_cu_up_processor_notifier& e1ap_cu_up_processor_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_, unsigned max_nof_supported_ues_); diff --git a/include/srsran/e2/e2.h b/include/srsran/e2/e2.h index bf45f742cc..11168a9ae3 100644 --- a/include/srsran/e2/e2.h +++ b/include/srsran/e2/e2.h @@ -84,13 +84,13 @@ class e2_connection_manager virtual async_task start_initial_e2_setup_routine() = 0; }; -class e2_du_metrics_notifier : public scheduler_ue_metrics_notifier, public rlc_metrics_notifier +class e2_du_metrics_notifier : public scheduler_metrics_notifier, public rlc_metrics_notifier { public: virtual ~e2_du_metrics_notifier() = default; using rlc_metrics_notifier::report_metrics; - using scheduler_ue_metrics_notifier::report_metrics; + using scheduler_metrics_notifier::report_metrics; }; class e2_du_metrics_interface diff --git a/include/srsran/e2/e2_du_metrics_connector.h b/include/srsran/e2/e2_du_metrics_connector.h index e442d1ec22..566946cd89 100644 --- a/include/srsran/e2/e2_du_metrics_connector.h +++ b/include/srsran/e2/e2_du_metrics_connector.h @@ -38,7 +38,7 @@ class e2_du_metrics_connector : public e2_du_metrics_notifier, public e2_du_metr e2_du_metrics_connector(); ~e2_du_metrics_connector() = default; - void report_metrics(span ue_metrics) override; + void report_metrics(const scheduler_cell_metrics& metrics) override; void report_metrics(const rlc_metrics& metrics) override; diff --git a/include/srsran/e2/e2ap_configuration.h b/include/srsran/e2/e2ap_configuration.h index cee9c875a2..9484a9c3a2 100644 --- a/include/srsran/e2/e2ap_configuration.h +++ b/include/srsran/e2/e2ap_configuration.h @@ -22,19 +22,21 @@ #pragma once +#include "srsran/ran/gnb_du_id.h" #include "srsran/ran/gnb_id.h" +#include #include namespace srsran { /// \brief E2AP configuration struct e2ap_configuration { - gnb_id_t gnb_id = {0, 22}; - std::string ran_node_name; - std::string plmn; /// Full PLMN as string (without possible filler digit) e.g. "00101" - unsigned max_setup_retries = 5; - bool e2sm_kpm_enabled = false; - bool e2sm_rc_enabled = false; + gnb_id_t gnb_id = {0, 22}; + std::string plmn; /// Full PLMN as string (without possible filler digit) e.g. "00101" + std::optional gnb_du_id; + unsigned max_setup_retries = 5; + bool e2sm_kpm_enabled = false; + bool e2sm_rc_enabled = false; }; } // namespace srsran diff --git a/include/srsran/e2/e2ap_configuration_helpers.h b/include/srsran/e2/e2ap_configuration_helpers.h index 05ff30a266..9f98749b2a 100644 --- a/include/srsran/e2/e2ap_configuration_helpers.h +++ b/include/srsran/e2/e2ap_configuration_helpers.h @@ -33,7 +33,6 @@ inline e2ap_configuration make_default_e2ap_config() { e2ap_configuration cfg{}; cfg.gnb_id = {411, 22}; - cfg.ran_node_name = "srsgnb01"; cfg.plmn = "00101"; cfg.max_setup_retries = 5; cfg.e2sm_kpm_enabled = false; @@ -44,11 +43,6 @@ inline e2ap_configuration make_default_e2ap_config() /// Returns true if the given E2 configuration is valid, otherwise false. inline bool is_valid_configuration(const e2ap_configuration& config) { - if (config.ran_node_name.empty()) { - fmt::print("RAN node name is empty\n"); - return false; - } - if (config.plmn.empty()) { fmt::print("PLMN id is empty\n"); return false; diff --git a/include/srsran/f1ap/cu_cp/du_setup_notifier.h b/include/srsran/f1ap/cu_cp/du_setup_notifier.h index 1bfe4328f0..8f429d7d9e 100644 --- a/include/srsran/f1ap/cu_cp/du_setup_notifier.h +++ b/include/srsran/f1ap/cu_cp/du_setup_notifier.h @@ -68,6 +68,12 @@ struct du_setup_result { bool is_accepted() const { return std::holds_alternative(result); } }; +struct du_config_update_request { + gnb_du_id_t gnb_du_id; + std::vector served_cells_to_add; + std::vector served_cells_to_rem; +}; + /// \brief Interface used to handle F1AP interface management procedures as defined in TS 38.473 section 8.2. class du_setup_notifier { diff --git a/include/srsran/mac/mac_config.h b/include/srsran/mac/mac_config.h index 0797b67f83..f68054deca 100644 --- a/include/srsran/mac/mac_config.h +++ b/include/srsran/mac/mac_config.h @@ -58,8 +58,8 @@ struct mac_config { mac_expert_config mac_cfg; mac_pcap& pcap; // Parameters passed to MAC scheduler. - scheduler_expert_config sched_cfg; - scheduler_ue_metrics_notifier& metric_notifier; + scheduler_expert_config sched_cfg; + scheduler_metrics_notifier& metric_notifier; }; } // namespace srsran diff --git a/include/srsran/ngap/ngap.h b/include/srsran/ngap/ngap.h index e037834019..f1dcbee5f8 100644 --- a/include/srsran/ngap/ngap.h +++ b/include/srsran/ngap/ngap.h @@ -27,12 +27,12 @@ #include "srsran/ngap/ngap_reset.h" #include "srsran/ngap/ngap_setup.h" #include "srsran/support/async/async_task.h" -#include "srsran/support/timers.h" namespace srsran { namespace srs_cu_cp { struct ngap_message; +struct up_pdu_session_context; /// This interface is used to push NGAP messages to the NGAP interface. class ngap_message_handler @@ -97,7 +97,58 @@ class ngap_ue_context_removal_handler virtual void remove_ue_context(ue_index_t ue_index) = 0; }; -/// Interface to notify the CU-CP about an NGAP UE creation. +/// Notifier to the RRC UE for NAS PDUs. +class ngap_rrc_ue_pdu_notifier +{ +public: + virtual ~ngap_rrc_ue_pdu_notifier() = default; + + /// \brief Notify about the a new nas pdu. + /// \param [in] nas_pdu The nas pdu. + virtual void on_new_pdu(byte_buffer nas_pdu) = 0; +}; + +/// Notifier to the RRC UE for control messages. +class ngap_rrc_ue_control_notifier +{ +public: + virtual ~ngap_rrc_ue_control_notifier() = default; + + /// \brief Notify about the reception of new security context. + virtual async_task on_new_security_context() = 0; + + /// \brief Get packed handover preparation message for inter-gNB handover. + virtual byte_buffer on_handover_preparation_message_required() = 0; +}; + +/// NGAP notifier to the CU-CP UE +class ngap_cu_cp_ue_notifier +{ +public: + virtual ~ngap_cu_cp_ue_notifier() = default; + + /// \brief Get the UE index of the UE. + virtual ue_index_t get_ue_index() = 0; + + /// \brief Schedule an async task for the UE. + virtual bool schedule_async_task(async_task task) = 0; + + /// \brief Get the RRC UE PDU notifier of the UE. + virtual ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() = 0; + + /// \brief Get the RRC UE control notifier of the UE. + virtual ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() = 0; + + /// \brief Notify the CU-CP about a security context + /// \param[in] sec_ctxt The received security context + /// \return True if the security context was successfully initialized, false otherwise + virtual bool init_security_context(security::security_context sec_ctxt) = 0; + + /// \brief Check if security is enabled + [[nodiscard]] virtual bool is_security_enabled() const = 0; +}; + +/// NGAP notifier to the CU-CP. class ngap_cu_cp_notifier { public: @@ -105,8 +156,20 @@ class ngap_cu_cp_notifier /// \brief Notifies the CU-CP about a new NGAP UE. /// \param[in] ue_index The index of the new NGAP UE. - /// \returns True if the UE was successfully created, false otherwise. - virtual bool on_new_ngap_ue(ue_index_t ue_index) = 0; + /// \returns Pointer to the NGAP UE notifier. + virtual ngap_cu_cp_ue_notifier* on_new_ngap_ue(ue_index_t ue_index) = 0; + + /// \brief Request scheduling a task for a UE. + /// \param[in] ue_index The index of the UE. + /// \param[in] task The task to schedule. + /// \returns True if the task was successfully scheduled, false otherwise. + virtual bool schedule_async_task(ue_index_t ue_index, async_task task) = 0; + + /// \brief Notify the CU-CP about a security context received in a handover request. + /// \param[in] ue_index Index of the UE. + /// \param[in] sec_ctxt The received security context. + /// \return True if the security context was successfully initialized, false otherwise. + virtual bool on_handover_request_received(ue_index_t ue_index, security::security_context sec_ctxt) = 0; /// \brief Notify about the reception of a new PDU Session Resource Setup Request. /// \param[in] request The received PDU Session Resource Setup Request. @@ -196,33 +259,6 @@ class ngap_control_message_handler const unsigned tac) = 0; }; -/// Interface to notify about NAS PDUs and messages. -class ngap_rrc_ue_pdu_notifier -{ -public: - virtual ~ngap_rrc_ue_pdu_notifier() = default; - - /// \brief Notify about the a new nas pdu. - /// \param [in] nas_pdu The nas pdu. - virtual void on_new_pdu(byte_buffer nas_pdu) = 0; -}; - -/// Interface to notify the RRC UE about control messages. -class ngap_rrc_ue_control_notifier -{ -public: - virtual ~ngap_rrc_ue_control_notifier() = default; - - /// \brief Notify about the reception of new security context. - virtual async_task on_new_security_context(const security::security_context& sec_context) = 0; - - /// \brief Get packed handover preparation message for inter-gNB handover. - virtual byte_buffer on_handover_preparation_message_required() = 0; - - /// \brief Get the status of the security context. - virtual bool on_security_enabled() = 0; -}; - /// Interface to control the NGAP. class ngap_ue_control_manager { @@ -232,8 +268,10 @@ class ngap_ue_control_manager /// \brief Updates the NGAP UE context with a new UE index. /// \param[in] new_ue_index The new index of the UE. /// \param[in] old_ue_index The old index of the UE. + /// \param[in] new_ue_notifier The notifier to the new UE. /// \returns True if the update was successful, false otherwise. - virtual bool update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index) = 0; + virtual bool + update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index, ngap_cu_cp_ue_notifier& new_ue_notifier) = 0; }; /// \brief Interface to query statistics from the NGAP interface. diff --git a/include/srsran/ngap/ngap_factory.h b/include/srsran/ngap/ngap_factory.h index e7c09bc768..32cc799742 100644 --- a/include/srsran/ngap/ngap_factory.h +++ b/include/srsran/ngap/ngap_factory.h @@ -24,7 +24,6 @@ #include "ngap.h" #include "ngap_configuration.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/support/executors/task_executor.h" #include @@ -38,7 +37,6 @@ class n2_connection_client; std::unique_ptr create_ngap(ngap_configuration& ngap_cfg_, ngap_cu_cp_notifier& cu_cp_ue_creation_notifier_, ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - ngap_ue_manager& ue_manager_, n2_connection_client& n2_gateway_handler_, timer_manager& timers_, task_executor& ctrl_exec_); diff --git a/include/srsran/ngap/ngap_handover.h b/include/srsran/ngap/ngap_handover.h index 8cd1adeafc..da65526ea9 100644 --- a/include/srsran/ngap/ngap_handover.h +++ b/include/srsran/ngap/ngap_handover.h @@ -36,9 +36,10 @@ struct ngap_ue_source_handover_context { }; struct ngap_handover_preparation_request { - ue_index_t ue_index = ue_index_t::invalid; - gnb_id_t gnb_id; - nr_cell_id_t nci; + ue_index_t ue_index = ue_index_t::invalid; + gnb_id_t gnb_id; + nr_cell_id_t nci; + std::map> pdu_sessions; }; struct ngap_handover_preparation_response { diff --git a/include/srsran/phy/support/resource_grid_reader.h b/include/srsran/phy/support/resource_grid_reader.h index 1effc2414e..0275f162b5 100644 --- a/include/srsran/phy/support/resource_grid_reader.h +++ b/include/srsran/phy/support/resource_grid_reader.h @@ -62,36 +62,67 @@ class resource_grid_reader : public resource_grid_base /// /// \param[out] symbols Destination symbol buffer. /// \param[in] port Port index. - /// \param[in] l Symbol index. + /// \param[in] l OFDM symbol index. /// \param[in] k_init Initial subcarrier index. - /// \param[in] mask Boolean mask denoting the subcarriers to be read (if \c true), starting from \c k_init. + /// \param[in] mask Boolean mask denoting the subcarriers to be read (if \c true), starting from \c k_init. /// \return A view to the unused entries of \c symbols. - /// \note The number of elements of \c mask shall be equal to or greater than the resource grid number of subcarriers. - /// \note The number of elements of \c symbol shall be equal to or greater than the number of true elements in - /// \c mask. + /// \note The initial subcarrier plus the number of elements of \c mask shall not exceed the number of resource grid + /// subcarriers. + /// \note The number of elements of \c symbols shall be equal to or greater than the number of true elements in + /// \c mask. virtual span get(span symbols, unsigned port, unsigned l, unsigned k_init, const bounded_bitset& mask) const = 0; + /// \brief Gets a number of resource elements in the resource grid at the given port and symbol using a bounded bitset + /// to indicate which subcarriers are allocated and which are not. + /// + /// \param[out] symbols Destination symbol buffer. + /// \param[in] port Port index. + /// \param[in] l OFDM symbol index. + /// \param[in] k_init Initial subcarrier index. + /// \param[in] mask Boolean mask denoting the subcarriers to be read (if \c true), starting from \c k_init. + /// \return A view to the unused entries of \c symbols. + /// \note The initial subcarrier plus the number of elements of \c mask shall not exceed the number of resource grid + /// subcarriers. + /// \note The number of elements of \c symbols shall be equal to or greater than the number of true elements in + /// \c mask. + virtual span get(span symbols, + unsigned port, + unsigned l, + unsigned k_init, + const bounded_bitset& mask) const = 0; + /// \brief Gets a number of resource elements for a given port and symbol \c l starting at \c k_init and picks the /// first element every \c stride. /// /// \param[out] symbols Destination symbol buffer. /// \param[in] port Port index. - /// \param[in] l Symbol index. + /// \param[in] l OFDM symbol index. /// \param[in] k_init Initial subcarrier index. /// \param[in] stride Distance between the elements to get. /// \note The sum of \c k_init and the number of elements in \c symbols shall not exceed the resource grid number of /// subcarriers. virtual void get(span symbols, unsigned port, unsigned l, unsigned k_init, unsigned stride = 1) const = 0; + /// \brief Gets a consecutive number of resource elements for a given port and OFDM symbol \c l starting at + /// subcarrier \c k_init. + /// + /// \param[out] symbols Destination symbol buffer. + /// \param[in] port Port index. + /// \param[in] l OFDM symbol index. + /// \param[in] k_init Initial subcarrier index. + /// \note The sum of \c k_init and the number of elements in \c symbols shall not exceed the resource grid number of + /// subcarriers. + virtual void get(span symbols, unsigned port, unsigned l, unsigned k_init) const = 0; + /// \brief Gets a view of all resource elements for a given port and symbol \c l. /// /// \param[in] port Port index. - /// \param[in] l Symbol index. - virtual span get_view(unsigned port, unsigned l) const = 0; + /// \param[in] l OFDM symbol index. + virtual span get_view(unsigned port, unsigned l) const = 0; }; } // namespace srsran diff --git a/include/srsran/phy/support/resource_grid_reader_empty.h b/include/srsran/phy/support/resource_grid_reader_empty.h index ecf0ee9171..76d026a431 100644 --- a/include/srsran/phy/support/resource_grid_reader_empty.h +++ b/include/srsran/phy/support/resource_grid_reader_empty.h @@ -62,6 +62,17 @@ class resource_grid_reader_empty : public resource_grid_reader return {}; } + // See interface for documentation. + span get(span symbols, + unsigned /**/, + unsigned /**/, + unsigned /**/, + const bounded_bitset& /**/) const override + { + srsvec::zero(symbols); + return {}; + } + // See interface for documentation. void get(span symbols, unsigned /**/, unsigned /**/, unsigned /**/, unsigned /**/) const override { @@ -69,7 +80,10 @@ class resource_grid_reader_empty : public resource_grid_reader } // See interface for documentation. - span get_view(unsigned /**/, unsigned /**/) const override { return {}; } + void get(span symbols, unsigned /**/, unsigned /**/, unsigned /**/) const override { srsvec::zero(symbols); } + + // See interface for documentation. + span get_view(unsigned /**/, unsigned /**/) const override { return {}; } private: unsigned nof_ports; diff --git a/include/srsran/phy/upper/channel_estimation.h b/include/srsran/phy/upper/channel_estimation.h index 45f0d89e4e..cac9e5c83c 100644 --- a/include/srsran/phy/upper/channel_estimation.h +++ b/include/srsran/phy/upper/channel_estimation.h @@ -27,7 +27,6 @@ #include "srsran/adt/bounded_bitset.h" #include "srsran/adt/span.h" -#include "srsran/adt/static_vector.h" #include "srsran/adt/tensor.h" #include "srsran/phy/constants.h" #include "srsran/phy/upper/channel_state_information.h" @@ -99,7 +98,7 @@ class channel_estimate ce.resize({dims.nof_prb * NRE, dims.nof_symbols, dims.nof_rx_ports, dims.nof_tx_layers}); // Set all reserved memory to one. - span data = ce.get_view<4>({}); + span data = ce.get_view<4>({}); std::fill(data.begin(), data.end(), 1.0F); // Reserve memory for the rest of channel statistics. @@ -200,23 +199,39 @@ class channel_estimate /// \brief Returns a read-write view to the RE channel estimates of the path between the given Rx port and Tx layer. /// /// The view is represented as a vector indexed by i) subcarriers and ii) OFDM symbols. - span get_path_ch_estimate(unsigned rx_port, unsigned tx_layer = 0) + span get_path_ch_estimate(unsigned rx_port, unsigned tx_layer = 0) { + srsran_assert(rx_port < nof_rx_ports, + "The receive port index (i.e., {}) exceeds the number of receive ports (i.e., {}).", + rx_port, + nof_rx_ports); + srsran_assert(tx_layer < nof_tx_layers, + "The transmit layer index (i.e., {}) exceeds the number of transmit layers (i.e., {}).", + tx_layer, + nof_tx_layers); return ce.get_view<2>({rx_port, tx_layer}); } /// \brief Returns a read-only view to the RE channel estimates of the path between the given Rx port and Tx layer. /// /// The view is represented as a vector indexed by i) subcarriers and ii) OFDM symbols. - span get_path_ch_estimate(unsigned rx_port, unsigned tx_layer = 0) const + span get_path_ch_estimate(unsigned rx_port, unsigned tx_layer = 0) const { + srsran_assert(rx_port < nof_rx_ports, + "The receive port index (i.e., {}) exceeds the number of receive ports (i.e., {}).", + rx_port, + nof_rx_ports); + srsran_assert(tx_layer < nof_tx_layers, + "The transmit layer index (i.e., {}) exceeds the number of transmit layers (i.e., {}).", + tx_layer, + nof_tx_layers); return ce.get_view<2>({rx_port, tx_layer}); } /// \brief Returns a read-write view to the RE channel estimates for a given OFDM symbol, Rx port and Tx layer. /// /// The view is represented as a vector indexed by subcarrier. - span get_symbol_ch_estimate(unsigned i_symbol, unsigned rx_port = 0, unsigned tx_layer = 0) + span get_symbol_ch_estimate(unsigned i_symbol, unsigned rx_port = 0, unsigned tx_layer = 0) { return ce.get_view<1>({i_symbol, rx_port, tx_layer}); } @@ -224,7 +239,7 @@ class channel_estimate /// \brief Returns a read-only view to the RE channel estimates for a given OFDM symbol, Rx port and Tx layer. /// /// The view is represented as a vector indexed by subcarrier. - span get_symbol_ch_estimate(unsigned i_symbol, unsigned rx_port = 0, unsigned tx_layer = 0) const + span get_symbol_ch_estimate(unsigned i_symbol, unsigned rx_port = 0, unsigned tx_layer = 0) const { return ce.get_view<1>({i_symbol, rx_port, tx_layer}); } @@ -405,7 +420,7 @@ class channel_estimate /// The channel estimate should be thought as four-dimensional tensor with dimensions representing, in order, /// subcarriers, OFDM symbols, receive ports and, finally, transmit layers. However, it is represented as a single /// vector, indexed in the same order: i) subcarriers, ii) OFDM symbols, iii) Rx ports, and iv) Tx layers. - dynamic_tensor<4, cf_t> ce; + dynamic_tensor<4, cbf16_t> ce; /// Transforms a port-layer pair into a linear index. unsigned path_to_index(unsigned rx_port, unsigned tx_layer = 0) const diff --git a/include/srsran/phy/upper/equalization/channel_equalizer.h b/include/srsran/phy/upper/equalization/channel_equalizer.h index 5de1520064..c4488c44fd 100644 --- a/include/srsran/phy/upper/equalization/channel_equalizer.h +++ b/include/srsran/phy/upper/equalization/channel_equalizer.h @@ -62,11 +62,11 @@ class channel_equalizer public: /// \brief Container for input and output Resource Elements. /// \remark Dimension indexing given by \ref channel_equalizer::re_dims. - using re_list = tensor(re_dims::nof_dims), cf_t, re_dims>; + using re_list = tensor(re_dims::nof_dims), cbf16_t, re_dims>; /// \brief Container for the channel estimates. /// \remark Dimension indexing given by \ref channel_equalizer::ch_dims. - using ch_est_list = tensor(ch_dims::nof_dims), cf_t, ch_dims>; + using ch_est_list = tensor(ch_dims::nof_dims), cbf16_t, ch_dims>; /// Default destructor. virtual ~channel_equalizer() = default; diff --git a/include/srsran/ran/gnb_du_id.h b/include/srsran/ran/gnb_du_id.h index 65f2171375..52b71eecec 100644 --- a/include/srsran/ran/gnb_du_id.h +++ b/include/srsran/ran/gnb_du_id.h @@ -34,4 +34,9 @@ inline gnb_du_id_t int_to_gnb_du_id(uint64_t id) return static_cast(id); } +inline int gnb_du_id_to_int(gnb_du_id_t gnb_du_id) +{ + return static_cast(gnb_du_id); +} + } // namespace srsran \ No newline at end of file diff --git a/include/srsran/rlc/rlc_config.h b/include/srsran/rlc/rlc_config.h index d8d90b69b3..9dcaf45569 100644 --- a/include/srsran/rlc/rlc_config.h +++ b/include/srsran/rlc/rlc_config.h @@ -22,12 +22,12 @@ #pragma once -#include "srsran/adt/optional.h" #include "srsran/pdcp/pdcp_sn_size.h" #include "srsran/support/srsran_assert.h" #include "srsran/support/timers.h" #include "fmt/format.h" #include +#include #include namespace srsran { diff --git a/include/srsran/rrc/rrc_config.h b/include/srsran/rrc/rrc_config.h index 911e3ac2e3..540b85bfe8 100644 --- a/include/srsran/rrc/rrc_config.h +++ b/include/srsran/rrc/rrc_config.h @@ -23,7 +23,8 @@ #pragma once #include "rrc_ue_config.h" -#include "srsran/adt/optional.h" +#include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/ran/gnb_id.h" #include "srsran/rrc/rrc_ue_config.h" #include #include diff --git a/include/srsran/rrc/rrc_du.h b/include/srsran/rrc/rrc_du.h index a11246ce24..f8e643d95a 100644 --- a/include/srsran/rrc/rrc_du.h +++ b/include/srsran/rrc/rrc_du.h @@ -25,8 +25,6 @@ #include "rrc_cell_context.h" #include "rrc_ue.h" #include "srsran/cu_cp/cell_meas_manager_config.h" -#include "srsran/cu_cp/ue_task_scheduler.h" -#include "srsran/ran/band_helper.h" namespace srsran { namespace srs_cu_cp { @@ -49,12 +47,11 @@ struct rrc_ue_creation_message { ue_index_t ue_index; rnti_t c_rnti; rrc_cell_context cell; - security::security_context* sec_context; rrc_pdu_f1ap_notifier* f1ap_pdu_notifier; rrc_ue_context_update_notifier* rrc_ue_cu_cp_notifier; rrc_ue_measurement_notifier* measurement_notifier; + rrc_ue_cu_cp_ue_notifier* cu_cp_ue_notifier; byte_buffer du_to_cu_container; - ue_task_scheduler* ue_task_sched; std::optional rrc_context; }; @@ -67,7 +64,7 @@ class rrc_du_ue_repository virtual ~rrc_du_ue_repository() = default; /// Creates a new RRC UE object and returns a handle to it. - virtual rrc_ue_interface* add_ue(up_resource_manager& resource_mng, const rrc_ue_creation_message& msg) = 0; + virtual rrc_ue_interface* add_ue(const rrc_ue_creation_message& msg) = 0; /// Send RRC Release to all UEs connected to this DU. virtual void release_ues() = 0; diff --git a/include/srsran/rrc/rrc_ue.h b/include/srsran/rrc/rrc_ue.h index e64895aacc..1252bd5a7b 100644 --- a/include/srsran/rrc/rrc_ue.h +++ b/include/srsran/rrc/rrc_ue.h @@ -28,13 +28,11 @@ #include "srsran/asn1/rrc_nr/ue_cap.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/cu_cp/cu_cp_ue_messages.h" -#include "srsran/cu_cp/up_resource_manager.h" #include "srsran/ran/rnti.h" #include "srsran/rrc/rrc.h" #include "srsran/rrc/rrc_ue_config.h" #include "srsran/security/security.h" #include "srsran/support/async/async_task.h" -#include "srsran/support/timers.h" namespace asn1 { namespace rrc_nr { @@ -244,10 +242,6 @@ class rrc_ue_control_message_handler /// \return The measurement config, if present. virtual std::optional generate_meas_config(std::optional current_meas_config) = 0; - /// \brief Handle the reception of a new security context. - /// \return True if the security context was applied successfully, false otherwise - virtual bool handle_new_security_context(const security::security_context& sec_context) = 0; - /// \brief Handle the handover command RRC PDU. /// \param[in] cmd The handover command RRC PDU. /// \returns The handover RRC Reconfiguration PDU. If the handover command is invalid, the PDU is empty. @@ -269,11 +263,7 @@ class rrc_ue_init_security_context_handler virtual ~rrc_ue_init_security_context_handler() = default; /// \brief Handle the received Init Security Context. - /// \param[in] sec_ctxt The Init Security Context. - virtual async_task handle_init_security_context(const security::security_context& sec_ctxt) = 0; - - /// \brief Get the status of the security context. - virtual bool get_security_enabled() = 0; + virtual async_task handle_init_security_context() = 0; }; /// Handler to get the handover preparation context to the NGAP. @@ -285,6 +275,43 @@ class rrc_ue_handover_preparation_handler virtual byte_buffer get_packed_handover_preparation_message() = 0; }; +class rrc_ue_cu_cp_ue_notifier +{ +public: + virtual ~rrc_ue_cu_cp_ue_notifier() = default; + + /// \brief Get the timer factory for the UE. + virtual timer_factory get_timer_factory() = 0; + + /// \brief Get the task executor for the UE. + virtual task_executor& get_executor() = 0; + + /// \brief Schedule an async task for the UE. + virtual bool schedule_async_task(async_task task) = 0; + + /// \brief Get the AS configuration for the RRC domain + virtual security::sec_as_config get_rrc_as_config() = 0; + + /// \brief Get the AS configuration for the RRC domain with 128-bit keys + virtual security::sec_128_as_config get_rrc_128_as_config() = 0; + + /// \brief Enable security + virtual void enable_security() = 0; + + /// \brief Get the current security context + virtual security::security_context get_security_context() = 0; + + /// \brief Get the selected security algorithms + virtual security::sec_selected_algos get_security_algos() = 0; + + /// \brief Update the security context + /// \param[in] sec_ctxt The new security context + virtual void update_security_context(security::security_context sec_ctxt) = 0; + + /// \brief Perform horizontal key derivation + virtual void perform_horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn) = 0; +}; + /// Struct containing all information needed from the old RRC UE for Reestablishment. struct rrc_ue_reestablishment_context_response { ue_index_t ue_index = ue_index_t::invalid; @@ -327,12 +354,20 @@ class rrc_ue_context_update_notifier /// \param[in] old_ue_index The old UE index of the UE that sent the Reestablishment Request. virtual async_task on_ue_transfer_required(ue_index_t old_ue_index) = 0; - /// \brief Notify the CU-CP to remove a UE from the CU-CP. - virtual async_task on_ue_removal_required() = 0; - /// \brief Notify the CU-CP to release a UE. /// \param[in] request The release request. virtual async_task on_ue_release_required(const cu_cp_ue_context_release_request& request) = 0; + + /// \brief Notify the CU-CP to setup an UP context. + /// \param[in] ctxt The UP context to setup. + virtual void on_up_context_setup_required(up_context ctxt) = 0; + + /// \brief Get the UP context of the UE. + /// \returns The UP context of the UE. + virtual up_context on_up_context_required() = 0; + + /// \brief Notify the CU-CP to remove a UE from the CU-CP. + virtual async_task on_ue_removal_required() = 0; }; /// Interface to notify about measurements diff --git a/include/srsran/rrc/rrc_ue_config.h b/include/srsran/rrc/rrc_ue_config.h index 29f1ad69a2..021acbb285 100644 --- a/include/srsran/rrc/rrc_ue_config.h +++ b/include/srsran/rrc/rrc_ue_config.h @@ -23,9 +23,7 @@ #pragma once #include "rrc_types.h" -#include "srsran/cu_cp/up_resource_manager.h" #include "srsran/pdcp/pdcp_t_reordering.h" -#include "srsran/srslog/srslog.h" namespace srsran { namespace srs_cu_cp { @@ -45,8 +43,6 @@ struct rrc_ue_cfg_t { unsigned rrc_procedure_timeout_ms; ///< Timeout used for RRC message exchange with UE. It needs to suit the expected ///< communication delay and account for potential retransmissions (HARQ and RLC), ///< UE processing delays (see Sec 12 in TS 38.331), SR delays, etc. - security::preferred_integrity_algorithms int_algo_pref_list; ///< Integrity protection algorithms preference list - security::preferred_ciphering_algorithms enc_algo_pref_list; ///< Encryption algorithms preference list }; } // namespace srs_cu_cp diff --git a/include/srsran/scheduler/config/scheduler_config.h b/include/srsran/scheduler/config/scheduler_config.h index 179bd27eee..05063a7844 100644 --- a/include/srsran/scheduler/config/scheduler_config.h +++ b/include/srsran/scheduler/config/scheduler_config.h @@ -32,7 +32,7 @@ namespace srsran { struct scheduler_config { const scheduler_expert_config& expert_params; sched_configuration_notifier& config_notifier; - scheduler_ue_metrics_notifier& metrics_notifier; + scheduler_metrics_notifier& metrics_notifier; }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/include/srsran/scheduler/scheduler_metrics.h b/include/srsran/scheduler/scheduler_metrics.h index 9c43a19692..d55c379de6 100644 --- a/include/srsran/scheduler/scheduler_metrics.h +++ b/include/srsran/scheduler/scheduler_metrics.h @@ -27,6 +27,7 @@ #include "srsran/ran/phy_time_unit.h" #include "srsran/ran/rnti.h" #include "srsran/ran/sch/sch_mcs.h" +#include "srsran/support/stats.h" #include namespace srsran { @@ -36,8 +37,6 @@ struct scheduler_ue_metrics { pci_t pci; unsigned nof_prbs; rnti_t rnti; - uint8_t cqi; - uint8_t ri; sch_mcs_index dl_mcs; double dl_prbs_used; double dl_brate_kbps; @@ -55,16 +54,33 @@ struct scheduler_ue_metrics { unsigned dl_bs; std::optional last_ta; std::optional last_phr; + /// CQI statistics over the metrics report interval. + sample_statistics cqi_stats; + /// RI statistics over the metrics report interval. + sample_statistics ri_stats; }; -/// \brief Notifier interface used by scheduler to report UE metrics. -class scheduler_ue_metrics_notifier +/// \brief Snapshot of the metrics for a cell and its UEs. +struct scheduler_cell_metrics { + /// Latency histogram number of bins. + constexpr static unsigned latency_hist_bins = 10; + /// Distance between histogram bins. + constexpr static unsigned nof_usec_per_bin = 50; + + unsigned nof_error_indications = 0; + std::chrono::microseconds average_decision_latency{0}; + std::array latency_histogram{0}; + std::vector ue_metrics; +}; + +/// \brief Notifier interface used by scheduler to report metrics. +class scheduler_metrics_notifier { public: - virtual ~scheduler_ue_metrics_notifier() = default; + virtual ~scheduler_metrics_notifier() = default; /// \brief This method will be called periodically by the scheduler to report the latest UE metrics statistics. - virtual void report_metrics(span ue_metrics) = 0; + virtual void report_metrics(const scheduler_cell_metrics& report) = 0; }; } // namespace srsran diff --git a/include/srsran/security/security.h b/include/srsran/security/security.h index aa9d12ced4..a89eacc278 100644 --- a/include/srsran/security/security.h +++ b/include/srsran/security/security.h @@ -220,9 +220,9 @@ struct security_context { bool select_algorithms(preferred_integrity_algorithms pref_inte_list, preferred_ciphering_algorithms pref_ciph_list); void generate_as_keys(); - sec_as_config get_as_config(sec_domain domain); - sec_128_as_config get_128_as_config(sec_domain domain); - void horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn); + [[nodiscard]] sec_as_config get_as_config(sec_domain domain) const; + [[nodiscard]] sec_128_as_config get_128_as_config(sec_domain domain) const; + void horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn); }; /****************************************************************************** diff --git a/include/srsran/support/memory_pool/unbounded_object_pool.h b/include/srsran/support/memory_pool/unbounded_object_pool.h new file mode 100644 index 0000000000..f9eba0c059 --- /dev/null +++ b/include/srsran/support/memory_pool/unbounded_object_pool.h @@ -0,0 +1,86 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#ifdef ENABLE_TSAN +#include "sanitizer/tsan_interface.h" +#endif + +#include "cameron314/concurrentqueue.h" +#include + +namespace srsran { + +/// Unbounded, thread-safe object pool. Ideal for large objects. Use with caution. +template +class unbounded_object_pool +{ + struct pool_deleter { + pool_deleter() = default; + pool_deleter(unbounded_object_pool& parent_) : parent(&parent_) {} + void operator()(T* ptr) + { + if (ptr != nullptr) { + std::unique_ptr obj{ptr}; +#ifdef ENABLE_TSAN + __tsan_release((void*)obj.get()); +#endif + parent->objects.enqueue(std::move(obj)); + } + } + + unbounded_object_pool* parent; + }; + +public: + using ptr = std::unique_ptr; + + unbounded_object_pool(unsigned initial_capacity) + { + for (unsigned i = 0; i != initial_capacity; ++i) { + objects.enqueue(std::make_unique()); + } + } + + ptr get() + { + std::unique_ptr popped; + if (objects.try_dequeue(popped)) { +#ifdef ENABLE_TSAN + __tsan_acquire((void*)popped.get()); +#endif + return ptr{popped.release(), pool_deleter{*this}}; + } + return ptr{new T(), pool_deleter{*this}}; + } + + unsigned current_capacity_approx() const + { + return objects.size_approx(); + } + +private: + moodycamel::ConcurrentQueue> objects; +}; + +} // namespace srsran diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index c79b364aa8..922f2cf488 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(cell_meas_manager) add_subdirectory(mobility_manager) add_subdirectory(up_resource_manager) +add_subdirectory(ue_security_manager) set(SOURCES cu_cp_factory.cpp @@ -31,9 +32,11 @@ set(SOURCES cu_up_processor/cu_up_processor_impl.cpp cu_up_processor/cu_up_processor_factory.cpp cu_up_processor/cu_up_processor_repository.cpp + du_processor/du_configuration_manager.cpp du_processor/du_processor_impl.cpp du_processor/du_processor_factory.cpp du_processor/du_processor_repository.cpp + metrics_handler/metrics_handler_impl.cpp routine_managers/cu_cp_routine_manager.cpp routines/amf_connection_setup_routine.cpp routines/pdu_session_routine_helpers.cpp @@ -49,11 +52,11 @@ set(SOURCES routines/mobility/inter_du_handover_routine.cpp routines/mobility/inter_cu_handover_target_routine.cpp routines/mobility/handover_reconfiguration_routine.cpp - metrics_handler/metrics_handler_impl.cpp - ue_manager/ue_task_scheduler_impl.cpp task_schedulers/cu_up_task_scheduler.cpp task_schedulers/du_task_scheduler.cpp - ue_manager/ue_manager_impl.cpp + ue_manager/cu_cp_ue_impl.cpp + ue_manager/ue_manager_impl.cpp + ue_manager/ue_task_scheduler_impl.cpp ) add_library(srsran_cu_cp STATIC ${SOURCES}) @@ -61,6 +64,7 @@ add_library(srsran_cu_cp STATIC ${SOURCES}) target_link_libraries(srsran_cu_cp srsran_cu_cp_cell_meas_manager srsran_cu_cp_mobility_manager + srsran_ue_security_manager srsran_e1ap_cu_cp srsran_f1ap_cu srsran_ngap diff --git a/lib/cu_cp/adapters/du_processor_adapters.h b/lib/cu_cp/adapters/du_processor_adapters.h index d57c875f5b..c91ecb3196 100644 --- a/lib/cu_cp/adapters/du_processor_adapters.h +++ b/lib/cu_cp/adapters/du_processor_adapters.h @@ -25,8 +25,6 @@ #include "../cu_cp_controller/cu_cp_controller.h" #include "../cu_cp_impl_interface.h" #include "../du_processor/du_processor.h" -#include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" -#include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" #include "srsran/rrc/rrc_du.h" #include "srsran/support/srsran_assert.h" #include @@ -171,11 +169,10 @@ class du_processor_rrc_du_adapter : public du_processor_rrc_du_ue_notifier return rrc_du_cell_handler->handle_served_cell_list(served_cell_list); } - rrc_ue_interface* on_ue_creation_request(up_resource_manager& resource_mng, - const rrc_ue_creation_message& msg) override + rrc_ue_interface* on_ue_creation_request(const rrc_ue_creation_message& msg) override { srsran_assert(rrc_du_handler != nullptr, "RRC DU UE handler must not be nullptr"); - return rrc_du_handler->add_ue(resource_mng, msg); + return rrc_du_handler->add_ue(msg); } void on_release_ues() override @@ -251,12 +248,6 @@ class du_processor_rrc_ue_adapter : public du_processor_rrc_ue_control_message_n return rrc_ue_handler->get_packed_handover_preparation_message(); } - bool on_new_security_context(const security::security_context& sec_context) override - { - srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); - return rrc_ue_handler->handle_new_security_context(sec_context); - } - byte_buffer on_new_rrc_handover_command(byte_buffer cmd) override { srsran_assert(rrc_ue_handler != nullptr, "RRC UE handler must not be nullptr"); diff --git a/lib/cu_cp/adapters/e1ap_adapters.h b/lib/cu_cp/adapters/e1ap_adapters.h index 4ef0fb7ee5..2366089984 100644 --- a/lib/cu_cp/adapters/e1ap_adapters.h +++ b/lib/cu_cp/adapters/e1ap_adapters.h @@ -54,6 +54,12 @@ class e1ap_cu_cp_adapter : public e1ap_cu_cp_notifier public: void connect_cu_cp(cu_cp_e1ap_event_handler& cu_cp_handler_) { cu_cp_handler = &cu_cp_handler_; } + bool schedule_async_task(ue_index_t ue_index, async_task task) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NGAP handler must not be nullptr"); + return cu_cp_handler->schedule_ue_task(ue_index, std::move(task)); + } + void on_bearer_context_inactivity_notification_received(const cu_cp_inactivity_notification& msg) override { srsran_assert(cu_cp_handler != nullptr, "E1AP handler must not be nullptr"); diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index c9621e21ba..bae479a98d 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -24,9 +24,10 @@ #include "../cu_cp_impl_interface.h" #include "../du_processor/du_processor.h" +#include "../ue_manager/cu_cp_ue_impl_interface.h" +#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/ngap/ngap.h" #include "srsran/rrc/rrc.h" -#include "srsran/srslog/srslog.h" namespace srsran { namespace srs_cu_cp { @@ -62,12 +63,24 @@ class ngap_cu_cp_adapter : public ngap_cu_cp_du_repository_notifier, public ngap return cu_cp_handler->handle_ngap_handover_request(request); } - bool on_new_ngap_ue(ue_index_t ue_index) override + ngap_cu_cp_ue_notifier* on_new_ngap_ue(ue_index_t ue_index) override { srsran_assert(cu_cp_handler != nullptr, "CU-CP NGAP handler must not be nullptr"); return cu_cp_handler->handle_new_ngap_ue(ue_index); } + bool schedule_async_task(ue_index_t ue_index, async_task task) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NGAP handler must not be nullptr"); + return cu_cp_handler->schedule_ue_task(ue_index, std::move(task)); + } + + bool on_handover_request_received(ue_index_t ue_index, security::security_context sec_ctxt) override + { + srsran_assert(cu_cp_handler != nullptr, "CU-CP NGAP handler must not be nullptr"); + return cu_cp_handler->handle_handover_request(ue_index, sec_ctxt); + } + async_task on_new_pdu_session_resource_setup_request(cu_cp_pdu_session_resource_setup_request& request) override { @@ -113,19 +126,71 @@ class ngap_cu_cp_adapter : public ngap_cu_cp_du_repository_notifier, public ngap cu_cp_ngap_handler* cu_cp_handler = nullptr; }; +/// Adapter between NGAP and CU-CP UE +class ngap_cu_cp_ue_adapter : public ngap_cu_cp_ue_notifier +{ +public: + ngap_cu_cp_ue_adapter() = default; + + void connect_ue(cu_cp_ue_impl_interface& ue_) { ue = &ue_; } + + /// \brief Get the UE index of the UE. + ue_index_t get_ue_index() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_ue_index(); + } + + /// \brief Schedule an async task for the UE. + bool schedule_async_task(async_task task) override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_task_sched().schedule_async_task(std::move(task)); + } + + /// \brief Get the RRC UE PDU notifier of the UE. + ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_rrc_ue_pdu_notifier(); + } + + /// \brief Get the RRC UE control notifier of the UE. + ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_rrc_ue_control_notifier(); + } + + bool init_security_context(security::security_context sec_ctxt) override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().init_security_context(sec_ctxt); + } + + [[nodiscard]] bool is_security_enabled() const override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().is_security_enabled(); + } + +private: + cu_cp_ue_impl_interface* ue = nullptr; +}; + /// Adapter between NGAP and RRC UE class ngap_rrc_ue_adapter : public ngap_rrc_ue_pdu_notifier, public ngap_rrc_ue_control_notifier { public: ngap_rrc_ue_adapter() = default; - void connect_rrc_ue(rrc_dl_nas_message_handler* rrc_ue_msg_handler_, - rrc_ue_init_security_context_handler* rrc_ue_security_handler_, - rrc_ue_handover_preparation_handler* rrc_ue_ho_prep_handler_) + void connect_rrc_ue(rrc_dl_nas_message_handler& rrc_ue_msg_handler_, + rrc_ue_init_security_context_handler& rrc_ue_security_handler_, + rrc_ue_handover_preparation_handler& rrc_ue_ho_prep_handler_) { - rrc_ue_msg_handler = rrc_ue_msg_handler_; - rrc_ue_security_handler = rrc_ue_security_handler_; - rrc_ue_ho_prep_handler = rrc_ue_ho_prep_handler_; + rrc_ue_msg_handler = &rrc_ue_msg_handler_; + rrc_ue_security_handler = &rrc_ue_security_handler_; + rrc_ue_ho_prep_handler = &rrc_ue_ho_prep_handler_; } void on_new_pdu(byte_buffer nas_pdu) override @@ -134,21 +199,15 @@ class ngap_rrc_ue_adapter : public ngap_rrc_ue_pdu_notifier, public ngap_rrc_ue_ rrc_ue_msg_handler->handle_dl_nas_transport_message(std::move(nas_pdu)); } - async_task on_new_security_context(const security::security_context& sec_context) override - { - srsran_assert(rrc_ue_security_handler != nullptr, "RRC UE security handler must not be nullptr"); - return rrc_ue_security_handler->handle_init_security_context(sec_context); - } - - bool on_security_enabled() override + async_task on_new_security_context() override { srsran_assert(rrc_ue_security_handler != nullptr, "RRC UE security handler must not be nullptr"); - return rrc_ue_security_handler->get_security_enabled(); + return rrc_ue_security_handler->handle_init_security_context(); } byte_buffer on_handover_preparation_message_required() override { - srsran_assert(rrc_ue_ho_prep_handler != nullptr, "RRC UE up manager must not be nullptr"); + srsran_assert(rrc_ue_ho_prep_handler != nullptr, "RRC UE UP manager must not be nullptr"); return rrc_ue_ho_prep_handler->get_packed_handover_preparation_message(); } diff --git a/lib/cu_cp/adapters/rrc_ue_adapters.h b/lib/cu_cp/adapters/rrc_ue_adapters.h index 48ad8bb123..aefe9e3f84 100644 --- a/lib/cu_cp/adapters/rrc_ue_adapters.h +++ b/lib/cu_cp/adapters/rrc_ue_adapters.h @@ -24,8 +24,10 @@ #include "../cu_cp_controller/cu_cp_controller.h" #include "../cu_cp_impl_interface.h" -#include "../du_processor/du_processor.h" +#include "../ue_manager/cu_cp_ue_impl_interface.h" +#include "../up_resource_manager/up_resource_manager_impl.h" #include "srsran/adt/byte_buffer.h" +#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/ngap/ngap.h" #include "srsran/rrc/rrc_ue.h" @@ -93,6 +95,87 @@ class rrc_ue_ngap_adapter : public rrc_ue_nas_notifier, public rrc_ue_control_no ngap_control_message_handler* ngap_ctrl_msg_handler = nullptr; }; +/// Adapter between RRC UE and CU-CP UE +class rrc_ue_cu_cp_ue_adapter : public rrc_ue_cu_cp_ue_notifier +{ +public: + rrc_ue_cu_cp_ue_adapter() = default; + + void connect_ue(cu_cp_ue_impl_interface& ue_) { ue = &ue_; } + + /// \brief Schedule an async task for the UE. + bool schedule_async_task(async_task task) override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_task_sched().schedule_async_task(std::move(task)); + } + + timer_factory get_timer_factory() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_task_sched().get_timer_factory(); + } + + task_executor& get_executor() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_task_sched().get_executor(); + } + + /// \brief Get the AS configuration for the RRC domain + security::sec_as_config get_rrc_as_config() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().get_rrc_as_config(); + } + + /// \brief Get the AS configuration for the RRC domain with 128-bit keys + security::sec_128_as_config get_rrc_128_as_config() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().get_rrc_128_as_config(); + } + + /// \brief Enable security + void enable_security() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().enable_security(); + } + + /// \brief Get the current security context + security::security_context get_security_context() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().get_security_context(); + } + + /// \brief Get the selected security algorithms + security::sec_selected_algos get_security_algos() override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().get_security_algos(); + } + + /// \brief Update the security context + /// \param[in] sec_ctxt The new security context + void update_security_context(security::security_context sec_ctxt) override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().update_security_context(sec_ctxt); + } + + /// \brief Perform horizontal key derivation + void perform_horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn) override + { + srsran_assert(ue != nullptr, "CU-CP UE must not be nullptr"); + return ue->get_security_manager().perform_horizontal_key_derivation(target_pci, target_ssb_arfcn); + } + +private: + cu_cp_ue_impl_interface* ue = nullptr; +}; + /// Adapter between RRC UE and CU-CP class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_ue_measurement_notifier { @@ -102,11 +185,13 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u void connect_cu_cp(cu_cp_rrc_ue_interface& cu_cp_rrc_ue_, cu_cp_ue_removal_handler& ue_removal_handler_, cu_cp_controller& ctrl_, + up_resource_manager& up_mng_, cu_cp_measurement_handler& meas_handler_) { cu_cp_rrc_ue_handler = &cu_cp_rrc_ue_; ue_removal_handler = &ue_removal_handler_; controller = &ctrl_; + up_mng = &up_mng_; meas_handler = &meas_handler_; } @@ -146,18 +231,30 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u return cu_cp_rrc_ue_handler->handle_ue_context_transfer(ue_index, old_ue_index); } - async_task on_ue_removal_required() override - { - srsran_assert(ue_removal_handler != nullptr, "CU-CP UE removal handler must not be nullptr"); - return ue_removal_handler->handle_ue_removal_request(ue_index); - } - async_task on_ue_release_required(const cu_cp_ue_context_release_request& request) override { srsran_assert(cu_cp_rrc_ue_handler != nullptr, "CU-CP handler must not be nullptr"); return cu_cp_rrc_ue_handler->handle_ue_context_release(request); } + void on_up_context_setup_required(up_context ctxt) override + { + srsran_assert(up_mng != nullptr, "UP resource manager must not be nullptr"); + up_mng->set_up_context(ctxt); + } + + up_context on_up_context_required() override + { + srsran_assert(up_mng != nullptr, "UP resource manager must not be nullptr"); + return up_mng->get_up_context(); + } + + async_task on_ue_removal_required() override + { + srsran_assert(ue_removal_handler != nullptr, "CU-CP UE removal handler must not be nullptr"); + return ue_removal_handler->handle_ue_removal_request(ue_index); + } + std::optional on_measurement_config_request(nr_cell_id_t nci, std::optional current_meas_config = {}) override { @@ -174,6 +271,7 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u private: cu_cp_rrc_ue_interface* cu_cp_rrc_ue_handler = nullptr; cu_cp_ue_removal_handler* ue_removal_handler = nullptr; + up_resource_manager* up_mng = nullptr; cu_cp_controller* controller = nullptr; cu_cp_measurement_handler* meas_handler = nullptr; ue_index_t ue_index; diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp index 83c15ac47e..add1d91ceb 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.cpp @@ -102,16 +102,7 @@ bool cu_cp_controller::handle_du_setup_request(du_index_t du_idx, const du_setup // If AMF is not connected, it either means that the CU-CP is not operational state or there is a CU-CP failure. return false; } - for (auto& cell : req.gnb_du_served_cells_list) { - if (not cfg.rrc_config.gnb_id.contains_nci(cell.served_cell_info.nr_cgi.nci)) { - logger.warning("du={}: Rejecting DU configuration update. Cause: NCI {:#x} does not match gNB-Id {:#x}", - du_idx, - cell.served_cell_info.nr_cgi.nci, - cfg.rrc_config.gnb_id.id); - return false; - } - } - return du_mng.handle_du_config_update(du_idx, req); + return true; } bool cu_cp_controller::request_ue_setup() const diff --git a/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp b/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp index c13bc0c5ac..416cb19a36 100644 --- a/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp +++ b/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp @@ -244,23 +244,3 @@ void du_connection_manager::stop() stop_cvar.wait(lock, [this] { return stop_completed; }); } } - -bool du_connection_manager::handle_du_config_update(du_index_t du_idx, const du_setup_request& req) -{ - for (unsigned i = 0, nof_dus = dus.get_nof_dus(); i != nof_dus; ++i) { - du_index_t other_du_idx = uint_to_du_index(i); - if (other_du_idx == du_idx) { - continue; - } - const f1ap_du_context& du_ctxt = - dus.get_du_processor(other_du_idx).get_f1ap_interface().get_f1ap_handler().get_context(); - - if (du_ctxt.gnb_du_id == req.gnb_du_id) { - logger.warning("du={}: Rejecting DU configuration update. Cause: DU with GNB-DU-ID already exists.", - req.gnb_du_id); - return false; - } - } - - return true; -} diff --git a/lib/cu_cp/cu_cp_controller/du_connection_manager.h b/lib/cu_cp/cu_cp_controller/du_connection_manager.h index c424efe634..68dc39d526 100644 --- a/lib/cu_cp/cu_cp_controller/du_connection_manager.h +++ b/lib/cu_cp/cu_cp_controller/du_connection_manager.h @@ -52,9 +52,6 @@ class du_connection_manager : public cu_cp_f1c_handler void stop(); - /// Validate new gNB-DU configuration update. - bool handle_du_config_update(du_index_t du_idx, const du_setup_request& req); - private: class shared_du_connection_context; class f1_gw_to_cu_cp_pdu_adapter; diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 37c4e3d47c..e0f03129ca 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -28,10 +28,10 @@ #include "routines/ue_removal_routine.h" #include "routines/ue_transaction_info_release_routine.h" #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/cu_cp/security_manager_config.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" #include "srsran/ngap/ngap_factory.h" #include "srsran/rrc/rrc_du.h" -#include "srsran/support/executors/sync_task_executor.h" #include #include #include @@ -51,7 +51,11 @@ static void assert_cu_cp_configuration_valid(const cu_cp_configuration& cfg) cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : cfg(config_), - ue_mng(config_.ue_config, up_resource_manager_cfg{config_.rrc_config.drb_config}, *cfg.timers, *cfg.cu_cp_executor), + ue_mng(config_.ue_config, + up_resource_manager_cfg{config_.rrc_config.drb_config}, + security_manager_config{cfg.rrc_config.int_algo_pref_list, cfg.rrc_config.enc_algo_pref_list}, + *cfg.timers, + *cfg.cu_cp_executor), cell_meas_mng(config_.mobility_config.meas_manager_config, cell_meas_ev_notifier, ue_mng), routine_mng(ue_mng, cfg.default_security_indication, logger), du_db(du_repository_config{cfg, @@ -65,7 +69,7 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : rrc_du_cu_cp_notifier, conn_notifier, srslog::fetch_basic_logger("CU-CP")}), - cu_up_db(cu_up_repository_config{cfg, e1ap_ev_notifier, ue_mng, srslog::fetch_basic_logger("CU-CP")}), + cu_up_db(cu_up_repository_config{cfg, e1ap_ev_notifier, srslog::fetch_basic_logger("CU-CP")}), metrics_hdlr(std::make_unique(*cfg.cu_cp_executor, *cfg.timers, ue_mng, du_db)) { assert_cu_cp_configuration_valid(cfg); @@ -77,13 +81,8 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : rrc_du_cu_cp_notifier.connect_cu_cp(get_cu_cp_measurement_config_handler()); // Create NGAP. - ngap_entity = create_ngap(cfg.ngap_config, - ngap_cu_cp_ev_notifier, - ngap_cu_cp_ev_notifier, - ue_mng, - *cfg.n2_gw, - *cfg.timers, - *cfg.cu_cp_executor); + ngap_entity = create_ngap( + cfg.ngap_config, ngap_cu_cp_ev_notifier, ngap_cu_cp_ev_notifier, *cfg.n2_gw, *cfg.timers, *cfg.cu_cp_executor); rrc_ue_ngap_notifier.connect_ngap(ngap_entity->get_ngap_nas_message_handler(), ngap_entity->get_ngap_control_message_handler()); @@ -167,7 +166,7 @@ ngap_event_handler& cu_cp_impl::get_ngap_event_handler() void cu_cp_impl::handle_bearer_context_inactivity_notification(const cu_cp_inactivity_notification& msg) { if (msg.ue_inactive) { - du_ue* ue = ue_mng.find_du_ue(msg.ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(msg.ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", msg.ue_index); cu_cp_ue_context_release_request req; @@ -225,18 +224,15 @@ cu_cp_impl::handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, async_task cu_cp_impl::handle_rrc_reestablishment_context_modification_required(ue_index_t ue_index) { - du_ue* ue = ue_mng.find_du_ue(ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", ue_index); srsran_assert(cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0)) != nullptr, "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); - security::security_context sec_ctx = ue->get_security_context(); - security::sec_as_config up_sec = sec_ctx.get_as_config(security::sec_domain::up); - return routine_mng.start_reestablishment_context_modification_routine( ue_index, - up_sec, + ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), du_db.get_du_processor(get_du_index_from_ue_index(ue_index)).get_f1ap_interface().get_f1ap_ue_context_manager(), ue->get_rrc_ue_notifier(), @@ -264,6 +260,7 @@ async_task cu_cp_impl::handle_ue_context_transfer(ue_index_t ue_index, ue_ srsran_assert(cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0)) != nullptr, "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); + srsran_assert(ue_mng.find_ue(ue_index) != nullptr, "ue={} not found", ue_index); // Task to run in old UE task scheduler. auto handle_ue_context_transfer_impl = [this, ue_index, old_ue_index]() { @@ -284,7 +281,8 @@ async_task cu_cp_impl::handle_ue_context_transfer(ue_index_t ue_index, ue_ } // Transfer NGAP UE Context to new UE and remove the old context - if (not ngap_entity->update_ue_index(ue_index, old_ue_index)) { + if (not ngap_entity->update_ue_index( + ue_index, old_ue_index, ue_mng.find_ue(ue_index)->get_ngap_cu_cp_ue_notifier())) { return false; } @@ -350,9 +348,13 @@ void cu_cp_impl::handle_handover_ue_context_push(ue_index_t source_ue_index, ue_ srsran_assert(cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0)) != nullptr, "cu_up_index={}: could not find CU-UP", uint_to_cu_up_index(0)); + srsran_assert(ue_mng.find_ue(target_ue_index) != nullptr, "ue={} not found", target_ue_index); // Transfer NGAP UE Context to new UE and remove the old context - ngap_entity->update_ue_index(target_ue_index, source_ue_index); + if (!ngap_entity->update_ue_index( + target_ue_index, source_ue_index, ue_mng.find_ue(target_ue_index)->get_ngap_cu_cp_ue_notifier())) { + return; + } // Transfer E1AP UE Context to new UE and remove old context cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->update_ue_index(target_ue_index, source_ue_index); } @@ -363,10 +365,20 @@ async_task cu_cp_impl::handle_ue_context_release(const cu_cp_ue_context_re request, ngap_entity->get_ngap_control_message_handler(), *this, logger); } +bool cu_cp_impl::handle_handover_request(ue_index_t ue_index, security::security_context sec_ctxt) +{ + cu_cp_ue* ue = ue_mng.find_ue(ue_index); + if (ue == nullptr) { + logger.warning("ue={}: Could not find UE", ue_index); + return false; + } + return ue->get_security_manager().init_security_context(sec_ctxt); +} + async_task cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_resource_setup_request& request) { - du_ue* ue = ue_mng.find_du_ue(request.ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(request.ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", request.ue_index); srsran_assert(cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0)) != nullptr, "cu_up_index={}: could not find CU-UP", @@ -374,7 +386,7 @@ cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_reso return routine_mng.start_pdu_session_resource_setup_routine( request, - ue->get_security_context().get_as_config(security::sec_domain::up), + ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), du_db.get_du_processor(get_du_index_from_ue_index(request.ue_index)) .get_f1ap_interface() @@ -386,7 +398,7 @@ cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_reso async_task cu_cp_impl::handle_new_pdu_session_resource_modify_request(const cu_cp_pdu_session_resource_modify_request& request) { - du_ue* ue = ue_mng.find_du_ue(request.ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(request.ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", request.ue_index); srsran_assert(cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0)) != nullptr, "cu_up_index={}: could not find CU-UP", @@ -405,7 +417,7 @@ cu_cp_impl::handle_new_pdu_session_resource_modify_request(const cu_cp_pdu_sessi async_task cu_cp_impl::handle_new_pdu_session_resource_release_command(const cu_cp_pdu_session_resource_release_command& command) { - du_ue* ue = ue_mng.find_du_ue(command.ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(command.ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", command.ue_index); srsran_assert(cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0)) != nullptr, "cu_up_index={}: could not find CU-UP", @@ -521,7 +533,7 @@ cu_cp_impl::handle_inter_du_handover_request(const cu_cp_inter_du_handover_reque du_index_t& source_du_index, du_index_t& target_du_index) { - du_ue* ue = ue_mng.find_du_ue(request.source_ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(request.source_ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", request.source_ue_index); byte_buffer sib1 = du_db.get_du_processor(target_du_index).get_mobility_handler().get_packed_sib1(request.cgi); @@ -591,14 +603,17 @@ void cu_cp_impl::handle_du_processor_removal(du_index_t du_index) void cu_cp_impl::handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& rrc_ue) { // Connect RRC UE to NGAP to RRC UE adapter - ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(&rrc_ue.get_rrc_dl_nas_message_handler(), - &rrc_ue.get_rrc_ue_init_security_context_handler(), - &rrc_ue.get_rrc_ue_handover_preparation_handler()); + ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue(rrc_ue.get_rrc_dl_nas_message_handler(), + rrc_ue.get_rrc_ue_init_security_context_handler(), + rrc_ue.get_rrc_ue_handover_preparation_handler()); // Connect cu-cp to rrc ue adapters ue_mng.get_cu_cp_rrc_ue_adapter(ue_index).connect_rrc_ue(rrc_ue.get_rrc_ue_context_handler()); - ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp( - get_cu_cp_rrc_ue_interface(), get_cu_cp_ue_removal_handler(), *controller, get_cu_cp_measurement_handler()); + ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp(get_cu_cp_rrc_ue_interface(), + get_cu_cp_ue_removal_handler(), + *controller, + ue_mng.find_ue(ue_index)->get_up_resource_manager(), + get_cu_cp_measurement_handler()); } byte_buffer cu_cp_impl::handle_target_cell_sib1_required(du_index_t du_index, nr_cell_global_id_t cgi) @@ -611,10 +626,23 @@ async_task cu_cp_impl::handle_transaction_info_loss(const f1_ue_transactio return launch_async(ev.ues_lost, ue_mng, *this); } -bool cu_cp_impl::handle_new_ngap_ue(ue_index_t ue_index) +ngap_cu_cp_ue_notifier* cu_cp_impl::handle_new_ngap_ue(ue_index_t ue_index) { - return ue_mng.set_ue_ng_context( - ue_index, ue_mng.get_ngap_rrc_ue_adapter(ue_index), ue_mng.get_ngap_rrc_ue_adapter(ue_index)); + auto* ue = ue_mng.find_ue(ue_index); + if (ue == nullptr) { + return nullptr; + } + return &ue->get_ngap_cu_cp_ue_notifier(); +} + +bool cu_cp_impl::schedule_ue_task(ue_index_t ue_index, async_task task) +{ + if (ue_mng.find_ue_task_scheduler(ue_index) == nullptr) { + logger.debug("UE task scheduler not found for UE index={}", ue_index); + return false; + } + + return ue_mng.find_ue_task_scheduler(ue_index)->schedule_async_task(std::move(task)); } void cu_cp_impl::on_statistics_report_timer_expired() diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index eb7491b221..c2e17433c8 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -81,6 +81,7 @@ class cu_cp_impl final : public cu_cp, void handle_handover_ue_context_push(ue_index_t source_ue_index, ue_index_t target_ue_index) override; // cu_cp_ngap_handler + bool handle_handover_request(ue_index_t ue_index, security::security_context sec_ctxt) override; async_task handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_resource_setup_request& request) override; async_task @@ -146,7 +147,10 @@ class cu_cp_impl final : public cu_cp, async_task handle_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) override; // NGAP UE creation handler - bool handle_new_ngap_ue(ue_index_t ue_index) override; + ngap_cu_cp_ue_notifier* handle_new_ngap_ue(ue_index_t ue_index) override; + + // cu_cp_task_scheduler_handler + bool schedule_ue_task(ue_index_t ue_index, async_task task) override; void on_statistics_report_timer_expired(); diff --git a/lib/cu_cp/cu_cp_impl_interface.h b/lib/cu_cp/cu_cp_impl_interface.h index 8fcac16f42..565ac066f4 100644 --- a/lib/cu_cp/cu_cp_impl_interface.h +++ b/lib/cu_cp/cu_cp_impl_interface.h @@ -46,16 +46,35 @@ class cu_cp_ue_context_release_handler handle_ue_context_release_command(const cu_cp_ue_context_release_command& command) = 0; }; +/// Interface for the CU-CP to schedule tasks for UEs. +class cu_cp_task_scheduler_handler +{ +public: + virtual ~cu_cp_task_scheduler_handler() = default; + + /// \brief Schedule a task for a UE. + /// \param[in] ue_index The index of the UE. + /// \param[in] task The task to schedule. + /// \returns True if the task was successfully scheduled, false otherwise. + virtual bool schedule_ue_task(ue_index_t ue_index, async_task task) = 0; +}; + /// Interface for the NGAP notifier to communicate with the CU-CP. -class cu_cp_ngap_handler : public cu_cp_ue_context_release_handler +class cu_cp_ngap_handler : public cu_cp_ue_context_release_handler, public cu_cp_task_scheduler_handler { public: virtual ~cu_cp_ngap_handler() = default; /// \brief Handle the creation of a new NGAP UE. This will add the NGAP adapters to the UE manager. /// \param[in] ue_index The index of the new NGAP UE. - /// \returns True if the UE was successfully created, false otherwise. - virtual bool handle_new_ngap_ue(ue_index_t ue_index) = 0; + /// \returns Pointer to the NGAP UE notifier. + virtual ngap_cu_cp_ue_notifier* handle_new_ngap_ue(ue_index_t ue_index) = 0; + + /// \brief Initialize security context by selecting security algorithms and generating K_rrc_enc and K_rrc_int + /// \param[in] ue_index Index of the UE. + /// \param[in] sec_ctxt The received security context. + /// \return True if the security context was successfully initialized, false otherwise. + virtual bool handle_handover_request(ue_index_t ue_index, security::security_context sec_ctxt) = 0; /// \brief Handle the reception of a new PDU Session Resource Setup Request. /// \param[in] request The received PDU Session Resource Setup Request. @@ -91,7 +110,7 @@ class cu_cp_ngap_handler : public cu_cp_ue_context_release_handler }; /// Handler of E1AP-CU-CP events. -class cu_cp_e1ap_event_handler +class cu_cp_e1ap_event_handler : public cu_cp_task_scheduler_handler { public: virtual ~cu_cp_e1ap_event_handler() = default; diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_factory.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_factory.cpp index 0f1dbef2c6..44b6feb6ed 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_factory.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_factory.cpp @@ -32,11 +32,10 @@ std::unique_ptr srsran::srs_cu_cp::create_cu_up_processor(const cu_up_processor_config_t cu_up_processor_config_, e1ap_message_notifier& e1ap_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, cu_up_task_scheduler& task_sched_, task_executor& ctrl_exec_) { auto cu_up_processor = std::make_unique( - cu_up_processor_config_, e1ap_notifier_, cu_cp_notifier_, ue_mng_, task_sched_, ctrl_exec_); + cu_up_processor_config_, e1ap_notifier_, cu_cp_notifier_, task_sched_, ctrl_exec_); return cu_up_processor; } diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_factory.h b/lib/cu_cp/cu_up_processor/cu_up_processor_factory.h index b4aa1d8851..ee67fa2394 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_factory.h +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_factory.h @@ -25,7 +25,6 @@ #include "../task_schedulers/cu_up_task_scheduler.h" #include "cu_up_processor_config.h" #include "cu_up_processor_impl_interface.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/e1ap/common/e1ap_common.h" #include "srsran/support/executors/task_executor.h" #include @@ -38,7 +37,6 @@ std::unique_ptr create_cu_up_processor(const cu_up_processor_config_t cu_up_processor_config_, e1ap_message_notifier& e1ap_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, cu_up_task_scheduler& task_sched_, task_executor& ctrl_exec_); diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp index fa78ac0a9f..61a9e9b0c4 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.cpp @@ -29,13 +29,11 @@ using namespace srs_cu_cp; cu_up_processor_impl::cu_up_processor_impl(const cu_up_processor_config_t cu_up_processor_config_, e1ap_message_notifier& e1ap_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, cu_up_task_scheduler& task_sched_, task_executor& ctrl_exec_) : cfg(cu_up_processor_config_), e1ap_notifier(e1ap_notifier_), cu_cp_notifier(cu_cp_notifier_), - ue_mng(ue_mng_), task_sched(task_sched_), ctrl_exec(ctrl_exec_) { @@ -46,7 +44,6 @@ cu_up_processor_impl::cu_up_processor_impl(const cu_up_processor_config_t cu_up_ e1ap = create_e1ap(e1ap_notifier, e1ap_ev_notifier, cu_cp_notifier, - ue_mng, task_sched.get_timer_manager(), ctrl_exec, cfg.max_nof_supported_ues); diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h index f215813d73..efb0a67978 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_impl.h @@ -23,12 +23,9 @@ #pragma once #include "../adapters/e1ap_adapters.h" -#include "../adapters/ngap_adapters.h" #include "../task_schedulers/cu_up_task_scheduler.h" #include "cu_up_processor_config.h" -#include "srsran/adt/slotted_array.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/support/async/fifo_async_task_scheduler.h" #include "srsran/support/executors/task_executor.h" @@ -43,7 +40,6 @@ class cu_up_processor_impl : public cu_up_processor_impl_interface cu_up_processor_impl(const cu_up_processor_config_t cu_up_processor_config_, e1ap_message_notifier& e1ap_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, cu_up_task_scheduler& task_sched_, task_executor& ctrl_exec_); @@ -78,7 +74,6 @@ class cu_up_processor_impl : public cu_up_processor_impl_interface e1ap_message_notifier& e1ap_notifier; e1ap_cu_cp_notifier& cu_cp_notifier; - common_ue_manager& ue_mng; cu_up_task_scheduler& task_sched; task_executor& ctrl_exec; diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp index 6c2e1fb223..d4518da3d3 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp @@ -111,7 +111,6 @@ cu_up_index_t cu_up_processor_repository::add_cu_up(std::unique_ptr cu_up = create_cu_up_processor(std::move(cu_up_cfg), *cu_up_ctxt.e1ap_tx_pdu_notifier, cfg.e1ap_ev_notifier, - cfg.ue_mng, cu_up_task_sched, *cfg.cu_cp.cu_cp_executor); diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h index dd32637e28..78a60a69d5 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h @@ -22,13 +22,10 @@ #pragma once -#include "../adapters/e1ap_adapters.h" -#include "../cu_cp_impl_interface.h" #include "../task_schedulers/cu_up_task_scheduler.h" +#include "cu_up_processor_impl_interface.h" #include "srsran/cu_cp/cu_cp_e1_handler.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/ue_manager.h" -#include "srsran/support/async/async_task.h" #include namespace srsran { @@ -39,7 +36,6 @@ struct cu_cp_configuration; struct cu_up_repository_config { const cu_cp_configuration& cu_cp; e1ap_cu_cp_notifier& e1ap_ev_notifier; - common_ue_manager& ue_mng; srslog::basic_logger& logger; }; diff --git a/lib/cu_cp/du_processor/du_configuration_handler.h b/lib/cu_cp/du_processor/du_configuration_handler.h new file mode 100644 index 0000000000..e36454f9e7 --- /dev/null +++ b/lib/cu_cp/du_processor/du_configuration_handler.h @@ -0,0 +1,81 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/cu_cp/du_processor_context.h" +#include "srsran/f1ap/cu_cp/du_setup_notifier.h" +#include "srsran/ran/gnb_du_id.h" +#include "srsran/support/srsran_assert.h" + +namespace srsran { +namespace srs_cu_cp { + +/// Current configuration of the DU being managed by the CU-CP. +struct du_configuration_context { + /// gNB-DU ID reported during F1 setup, as per TS 38.473. + gnb_du_id_t id; + /// gNB-DU name reported during F1 setup, as per TS 38.473. + std::string name; + uint8_t rrc_version = 2; + /// Served cells for this DU. + std::vector served_cells; + + const du_cell_configuration* find_cell(pci_t pci) const + { + auto it = std::find_if(served_cells.begin(), served_cells.end(), [&pci](const auto& c) { return c.pci == pci; }); + return it != served_cells.end() ? &(*it) : nullptr; + } + const du_cell_configuration* find_cell(nr_cell_global_id_t cgi) const + { + auto it = std::find_if(served_cells.begin(), served_cells.end(), [&cgi](const auto& c) { return c.cgi == cgi; }); + return it != served_cells.end() ? &(*it) : nullptr; + } +}; + +class du_configuration_handler +{ +public: + virtual ~du_configuration_handler() = default; + + /// \brief Whether the DU already shared its configuration with the CU-CP. + bool has_context() const { return ctxt != nullptr; } + + /// Getter for the current DU configuration. + const du_configuration_context& get_context() const + { + srsran_assert(ctxt != nullptr, "bad access to DU configuration context"); + return *ctxt; + } + + /// Add a new DU configuration the CU-CP. + virtual error_type handle_new_du_config(const du_setup_request& req) = 0; + + /// Update the configuration of an existing DU managed by the CU-CP. + virtual error_type handle_du_config_update(const du_config_update_request& req) = 0; + +protected: + const du_configuration_context* ctxt = nullptr; +}; + +} // namespace srs_cu_cp +} // namespace srsran \ No newline at end of file diff --git a/lib/cu_cp/du_processor/du_configuration_manager.cpp b/lib/cu_cp/du_processor/du_configuration_manager.cpp new file mode 100644 index 0000000000..08254224ec --- /dev/null +++ b/lib/cu_cp/du_processor/du_configuration_manager.cpp @@ -0,0 +1,270 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "du_configuration_manager.h" +#include "srsran/ran/nr_cgi_helpers.h" +#include "srsran/rrc/rrc_config.h" + +using namespace srsran; +using namespace srs_cu_cp; + +static error_type validate_cell_config(const cu_cp_du_served_cells_item& served_cell) +{ + const auto& cell_info = served_cell.served_cell_info; + + if (not config_helpers::is_valid(cell_info.nr_cgi)) { + return error_type{ + du_setup_result::rejected{cause_protocol_t::semantic_error, "Invalid NR CGI"}}; + } + + if (not served_cell.served_cell_info.five_gs_tac.has_value()) { + return error_type{du_setup_result::rejected{ + cause_protocol_t::msg_not_compatible_with_receiver_state, fmt::format("Missing TAC for cell")}}; + } + + if (not served_cell.gnb_du_sys_info.has_value()) { + return error_type{du_setup_result::rejected{ + cause_protocol_t::semantic_error, fmt::format("Missing system information for cell")}}; + } + + return {}; +} + +class du_configuration_manager::du_configuration_handler_impl : public du_configuration_handler +{ +public: + du_configuration_handler_impl(du_configuration_manager& parent_) : parent(parent_) {} + ~du_configuration_handler_impl() override + { + if (ctxt != nullptr) { + parent.rem_du(this->ctxt->id); + } + } + + validation_result handle_new_du_config(const du_setup_request& req) override + { + if (this->ctxt != nullptr) { + return error_type{ + du_setup_result::rejected{cause_protocol_t::msg_not_compatible_with_receiver_state, "DU already configured"}}; + } + auto ret = parent.add_du_config(req); + if (ret.has_value()) { + this->ctxt = ret.value(); + return {}; + } + return ret.error(); + } + + validation_result handle_du_config_update(const du_config_update_request& req) override + { + if (this->ctxt == nullptr) { + return error_type{du_setup_result::rejected{ + cause_protocol_t::msg_not_compatible_with_receiver_state, "DU with same gNB-DU-Id was not setup"}}; + } + + // Reconfiguration. + auto ret = parent.handle_du_config_update(*this->ctxt, req); + if (ret.is_error()) { + return ret.error(); + } + this->ctxt = ret.value(); + return {}; + } + +private: + du_configuration_manager& parent; +}; + +du_configuration_manager::du_configuration_manager(const rrc_cfg_t& rrc_cfg_) : + rrc_cfg(rrc_cfg_), logger(srslog::fetch_basic_logger("CU-CP")) +{ +} + +std::unique_ptr du_configuration_manager::create_du_handler() +{ + return std::make_unique(*this); +} + +static du_cell_configuration create_du_cell_config(du_cell_index_t cell_idx, + const cu_cp_du_served_cells_item& f1ap_cell_cfg) +{ + const auto& cell_req = f1ap_cell_cfg.served_cell_info; + du_cell_configuration cell; + cell.cell_index = cell_idx; + cell.cgi = cell_req.nr_cgi; + cell.tac = cell_req.five_gs_tac.value(); + cell.pci = cell_req.nr_pci; + // Add band information. + if (cell_req.nr_mode_info.fdd.has_value()) { + for (const auto& band : cell_req.nr_mode_info.fdd.value().dl_nr_freq_info.freq_band_list_nr) { + cell.bands.push_back(uint_to_nr_band(band.freq_band_ind_nr)); + } + } else if (cell_req.nr_mode_info.tdd.has_value()) { + for (const auto& band : cell_req.nr_mode_info.tdd.value().nr_freq_info.freq_band_list_nr) { + cell.bands.push_back(uint_to_nr_band(band.freq_band_ind_nr)); + } + } + // Add packed MIB and SIB1 + cell.sys_info.packed_mib = f1ap_cell_cfg.gnb_du_sys_info->mib_msg.copy(); + cell.sys_info.packed_sib1 = f1ap_cell_cfg.gnb_du_sys_info->sib1_msg.copy(); + return cell; +} + +expected +du_configuration_manager::add_du_config(const du_setup_request& req) +{ + // Validate config. + auto result = validate_new_du_config(req); + if (result.is_error()) { + return result.error(); + } + + // Create new DU config context. + auto ret = dus.emplace(req.gnb_du_id, du_configuration_context{}); + du_configuration_context& ctxt = ret.first->second; + ctxt.id = req.gnb_du_id; + ctxt.name = req.gnb_du_name; + ctxt.rrc_version = req.gnb_du_rrc_version; + ctxt.served_cells.resize(req.gnb_du_served_cells_list.size()); + for (unsigned i = 0; i != ctxt.served_cells.size(); ++i) { + ctxt.served_cells[i] = create_du_cell_config(uint_to_du_cell_index(i), req.gnb_du_served_cells_list[i]); + } + return &ctxt; +} + +expected +du_configuration_manager::handle_du_config_update(const du_configuration_context& current_ctxt, + const du_config_update_request& req) +{ + if (current_ctxt.id != req.gnb_du_id) { + logger.warning("du_id={}: Failed to update DU. Cause: DU ID mismatch", current_ctxt.id); + return nullptr; + } + auto it = dus.find(current_ctxt.id); + if (it == dus.end()) { + logger.error("du_id={}: DU config update called for non-existent DU", current_ctxt.id); + return nullptr; + } + + // Validate config. + if (not validate_du_config_update(req)) { + return nullptr; + } + + // Update DU config. + du_configuration_context& du_context = it->second; + // > Remove cells. + for (const nr_cell_global_id_t& cgi : req.served_cells_to_rem) { + auto cell_it = std::find_if(it->second.served_cells.begin(), + it->second.served_cells.end(), + [&cgi](const du_cell_configuration& item) { return item.cgi == cgi; }); + if (cell_it != it->second.served_cells.end()) { + du_context.served_cells.erase(cell_it); + } else { + logger.warning( + "du_id={}: Failed to remove cell nci={}. Cause: It was not previously set", current_ctxt.id, cgi.nci); + } + } + // > Add new cells. + for (const auto& cell_to_add : req.served_cells_to_add) { + // Allocate cell index. + du_cell_index_t cell_idx = du_cell_index_t::invalid; + for (unsigned i = 0; i != MAX_NOF_DU_CELLS; ++i) { + if (std::none_of( + du_context.served_cells.begin(), du_context.served_cells.end(), [i](const du_cell_configuration& item) { + return item.cell_index == uint_to_du_cell_index(i); + })) { + cell_idx = uint_to_du_cell_index(i); + break; + } + } + // Note: Existence of a free cell index should be guaranteed during validation. + srsran_assert(cell_idx != du_cell_index_t::invalid, "Failed to allocate cell index"); + + du_context.served_cells.push_back(create_du_cell_config(cell_idx, cell_to_add)); + } + return &it->second; +} + +void du_configuration_manager::rem_du(gnb_du_id_t du_id) +{ + auto it = dus.find(du_id); + if (it == dus.end()) { + logger.warning("du_id={}: Failed to remove DU. Cause: DU not found", du_id); + return; + } + dus.erase(it); +} + +error_type +du_configuration_manager::validate_new_du_config(const du_setup_request& req) const +{ + // Ensure the DU config does not collide with other DUs. + for (const auto& [du_id, du_cfg] : dus) { + if (du_cfg.id == req.gnb_du_id) { + return error_type{ + du_setup_result::rejected{cause_protocol_t::msg_not_compatible_with_receiver_state, "Duplicate DU ID"}}; + } + } + + if (req.gnb_du_served_cells_list.size() > MAX_NOF_DU_CELLS) { + return error_type{ + du_setup_result::rejected{cause_protocol_t::msg_not_compatible_with_receiver_state, "Too many served cells"}}; + } + + // Validate served cell configurations. + for (const auto& served_cell : req.gnb_du_served_cells_list) { + auto ret = validate_cell_config_request(served_cell); + if (not ret.has_value()) { + return ret; + } + } + + return {}; +} + +error_type +du_configuration_manager::validate_du_config_update(const du_config_update_request& req) const +{ + // TODO + return {}; +} + +error_type +du_configuration_manager::validate_cell_config_request(const cu_cp_du_served_cells_item& cell_req) const +{ + auto ret = validate_cell_config(cell_req); + if (ret.is_error()) { + return ret.error(); + } + + // Ensure NCIs match the gNB-Id. + if (not rrc_cfg.gnb_id.contains_nci(cell_req.served_cell_info.nr_cgi.nci)) { + return error_type{ + du_setup_result::rejected{cause_protocol_t::msg_not_compatible_with_receiver_state, + fmt::format("NCI {:#x} of the served Cell does not match gNB-Id {:#x}", + cell_req.served_cell_info.nr_cgi.nci, + rrc_cfg.gnb_id.id)}}; + } + + return {}; +} diff --git a/lib/cu_cp/du_processor/du_configuration_manager.h b/lib/cu_cp/du_processor/du_configuration_manager.h new file mode 100644 index 0000000000..e028057f2d --- /dev/null +++ b/lib/cu_cp/du_processor/du_configuration_manager.h @@ -0,0 +1,66 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "du_configuration_handler.h" +#include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/srslog/srslog.h" + +namespace srsran { +namespace srs_cu_cp { + +struct rrc_cfg_t; + +/// Validator and repository of configurations for DUs handled by the CU-CP. +class du_configuration_manager +{ +public: + du_configuration_manager(const rrc_cfg_t& rrc_cfg_); + + /// Create a new DU configuration handler. + std::unique_ptr create_du_handler(); + + size_t nof_dus() const { return dus.size(); } + +private: + class du_configuration_handler_impl; + + using validation_result = error_type; + + expected add_du_config(const du_setup_request& req); + expected + handle_du_config_update(const du_configuration_context& current_ctxt, const du_config_update_request& req); + void rem_du(gnb_du_id_t du_id); + + validation_result validate_new_du_config(const du_setup_request& req) const; + validation_result validate_du_config_update(const du_config_update_request& req) const; + validation_result validate_cell_config_request(const cu_cp_du_served_cells_item& served_cell) const; + + const rrc_cfg_t& rrc_cfg; + srslog::basic_logger& logger; + + std::unordered_map dus; +}; + +} // namespace srs_cu_cp +} // namespace srsran \ No newline at end of file diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 48c546e272..72ba458eff 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -22,13 +22,9 @@ #pragma once -#include "../cu_cp_controller/common_task_scheduler.h" #include "du_metrics_handler.h" -#include "srsran/adt/optional.h" #include "srsran/adt/static_vector.h" -#include "srsran/cu_cp/cu_cp_f1c_handler.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" -#include "srsran/ngap/ngap_handover.h" #include "srsran/ran/nr_cgi.h" #include "srsran/rrc/rrc_du.h" #include @@ -148,11 +144,9 @@ class du_processor_rrc_du_ue_notifier virtual bool on_new_served_cell_list(const std::vector& served_cell_list) = 0; /// \brief Notify RRC DU to create a UE. - /// \param[in] resource_mng The UP resource manager of this UE. /// \param[in] msg The UE creation message. /// \return Returns a handle to the created UE. - virtual rrc_ue_interface* on_ue_creation_request(up_resource_manager& resource_mng, - const rrc_ue_creation_message& msg) = 0; + virtual rrc_ue_interface* on_ue_creation_request(const rrc_ue_creation_message& msg) = 0; /// Send RRC Release to all UEs connected to this DU. virtual void on_release_ues() = 0; @@ -198,10 +192,6 @@ class du_processor_rrc_ue_control_message_notifier virtual byte_buffer get_packed_handover_preparation_message() = 0; - /// \brief Notify about the reception of a new security context. - /// \return True if the security context was applied successfully, false otherwise - virtual bool on_new_security_context(const security::security_context& sec_context) = 0; - /// \brief Notify about the reception of a new Handover Command PDU. /// \param[in] cmd The handover command RRC PDU. /// \returns The RRC Handover Reconfiguration PDU. If the Handover Command PDU is invalid, an empty buffer is diff --git a/lib/cu_cp/du_processor/du_processor_config.h b/lib/cu_cp/du_processor/du_processor_config.h index d1b6c6b398..4c7b50cefc 100644 --- a/lib/cu_cp/du_processor/du_processor_config.h +++ b/lib/cu_cp/du_processor/du_processor_config.h @@ -23,6 +23,7 @@ #pragma once #include "../cu_cp_controller/node_connection_notifier.h" +#include "du_configuration_handler.h" #include "srsran/f1ap/cu_cp/f1ap_configuration.h" #include "srsran/rrc/rrc_config.h" @@ -30,14 +31,15 @@ namespace srsran { namespace srs_cu_cp { struct du_processor_config_t { - std::string name = "srs_cu_cp"; - du_index_t du_index = du_index_t::invalid; - uint8_t rrc_version = 2; - srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP"); - du_connection_notifier* du_setup_notif = nullptr; - rrc_cfg_t rrc_cfg; // TODO: do we put subcomponent configs here? - security_indication_t default_security_indication; // default if not signaled via NGAP - f1ap_configuration f1ap_cfg; + std::string name = "srs_cu_cp"; + du_index_t du_index = du_index_t::invalid; + uint8_t rrc_version = 2; + srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-CP"); + du_connection_notifier* du_setup_notif = nullptr; + rrc_cfg_t rrc_cfg; // TODO: do we put subcomponent configs here? + security_indication_t default_security_indication; // default if not signaled via NGAP + f1ap_configuration f1ap_cfg; + std::unique_ptr du_cfg_hdlr; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/du_processor/du_processor_factory.cpp b/lib/cu_cp/du_processor/du_processor_factory.cpp index 8dd4d5653e..32fa811d1d 100644 --- a/lib/cu_cp/du_processor/du_processor_factory.cpp +++ b/lib/cu_cp/du_processor/du_processor_factory.cpp @@ -30,25 +30,25 @@ using namespace srsran; using namespace srs_cu_cp; std::unique_ptr -srsran::srs_cu_cp::create_du_processor(const du_processor_config_t& du_processor_config_, +srsran::srs_cu_cp::create_du_processor(du_processor_config_t du_processor_config, du_processor_cu_cp_notifier& cu_cp_notifier_, f1ap_message_notifier& f1ap_notifier_, rrc_ue_nas_notifier& rrc_ue_nas_pdu_notifier_, rrc_ue_control_notifier& rrc_ue_ngap_ctrl_notifier_, rrc_du_measurement_config_notifier& rrc_du_cu_cp_notifier, common_task_scheduler& common_task_sched_, - du_processor_ue_manager& ue_manager_, + ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_) { - auto du_processor = std::make_unique(du_processor_config_, + auto du_processor = std::make_unique(std::move(du_processor_config), cu_cp_notifier_, f1ap_notifier_, rrc_ue_nas_pdu_notifier_, rrc_ue_ngap_ctrl_notifier_, rrc_du_cu_cp_notifier, common_task_sched_, - ue_manager_, + ue_mng_, timers_, ctrl_exec_); return du_processor; diff --git a/lib/cu_cp/du_processor/du_processor_factory.h b/lib/cu_cp/du_processor/du_processor_factory.h index fe9d815c40..11f5afeca6 100644 --- a/lib/cu_cp/du_processor/du_processor_factory.h +++ b/lib/cu_cp/du_processor/du_processor_factory.h @@ -22,9 +22,9 @@ #pragma once +#include "../ue_manager/ue_manager_impl.h" #include "du_processor.h" #include "du_processor_config.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/f1ap/common/f1ap_common.h" #include "srsran/rrc/rrc_ue.h" #include "srsran/support/executors/task_executor.h" @@ -36,14 +36,14 @@ namespace srs_cu_cp { class common_task_scheduler; /// Creates an instance of an DU processor interface -std::unique_ptr create_du_processor(const du_processor_config_t& du_processor_config_, +std::unique_ptr create_du_processor(du_processor_config_t du_processor_config_, du_processor_cu_cp_notifier& cu_cp_notifier_, f1ap_message_notifier& f1ap_notifier_, rrc_ue_nas_notifier& rrc_ue_nas_pdu_notifier_, rrc_ue_control_notifier& rrc_ue_ngap_ctrl_notifier_, rrc_du_measurement_config_notifier& rrc_du_cu_cp_notifier, common_task_scheduler& common_task_sched_, - du_processor_ue_manager& ue_manager_, + ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_); diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index 160c6933ea..eee2a6c5f3 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -32,26 +32,24 @@ using namespace srsran; using namespace srs_cu_cp; -du_processor_impl::du_processor_impl(const du_processor_config_t& du_processor_config_, +du_processor_impl::du_processor_impl(du_processor_config_t du_processor_config_, du_processor_cu_cp_notifier& cu_cp_notifier_, f1ap_message_notifier& f1ap_pdu_notifier_, rrc_ue_nas_notifier& rrc_ue_nas_pdu_notifier_, rrc_ue_control_notifier& rrc_ue_ngap_ctrl_notifier_, rrc_du_measurement_config_notifier& rrc_du_cu_cp_notifier, common_task_scheduler& common_task_sched_, - du_processor_ue_manager& ue_manager_, + ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_) : - cfg(du_processor_config_), + cfg(std::move(du_processor_config_)), cu_cp_notifier(cu_cp_notifier_), f1ap_pdu_notifier(f1ap_pdu_notifier_), rrc_ue_nas_pdu_notifier(rrc_ue_nas_pdu_notifier_), rrc_ue_ngap_ctrl_notifier(rrc_ue_ngap_ctrl_notifier_), - ue_manager(ue_manager_), + ue_mng(ue_mng_), f1ap_ev_notifier(common_task_sched_, *this) { - context.du_index = cfg.du_index; - // create f1ap f1ap = create_f1ap(cfg.f1ap_cfg, f1ap_pdu_notifier, f1ap_ev_notifier, timers_, ctrl_exec_); @@ -64,7 +62,7 @@ du_processor_impl::du_processor_impl(const du_processor_config_t& du_proc rrc = create_rrc_du(rrc_creation_msg); rrc_du_adapter.connect_rrc_du(rrc->get_rrc_du_cell_manager(), rrc->get_rrc_du_ue_repository()); - cu_cp_notifier.on_du_processor_created(context.du_index, + cu_cp_notifier.on_du_processor_created(cfg.du_index, f1ap->get_f1ap_ue_context_removal_handler(), f1ap->get_f1ap_statistics_handler(), rrc->get_rrc_ue_handler(), @@ -75,14 +73,17 @@ du_setup_result du_processor_impl::handle_du_setup_request(const du_setup_reques { du_setup_result res; - // Set DU context - context.id = request.gnb_du_id; - context.name = request.gnb_du_name; - // Check if CU-CP is in a state to accept a new DU connection. - if (not cfg.du_setup_notif->on_du_setup_request(context.du_index, request)) { - res.result = - du_setup_result::rejected{cause_misc_t::unspecified, "CU-CP is not in a state to accept a new DU connection"}; + if (not cfg.du_setup_notif->on_du_setup_request(cfg.du_index, request)) { + res.result = du_setup_result::rejected{cause_protocol_t::msg_not_compatible_with_receiver_state, + "CU-CP is not in a state to accept a new DU connection"}; + return res; + } + + // Validate and update DU configuration. + auto cfg_res = cfg.du_cfg_hdlr->handle_new_du_config(request); + if (cfg_res.is_error()) { + res.result = cfg_res.error(); return res; } @@ -94,61 +95,9 @@ du_setup_result du_processor_impl::handle_du_setup_request(const du_setup_reques return res; } - for (const auto& served_cell : request.gnb_du_served_cells_list) { - du_cell_context du_cell; - du_cell.du_index = context.du_index; - du_cell.cell_index = get_next_du_cell_index(); - - if (du_cell.cell_index == du_cell_index_t::invalid) { - res.result = du_setup_result::rejected{cause_misc_t::ctrl_processing_overload, - "Maximum number of DU cells supported in the CU-CP reached"}; - return res; - } - - du_cell.cgi = served_cell.served_cell_info.nr_cgi; - if (not config_helpers::is_valid(du_cell.cgi)) { - res.result = du_setup_result::rejected{cause_protocol_t::semantic_error, - fmt::format("Invalid CGI for cell {}", du_cell.cell_index)}; - return res; - } - - du_cell.pci = served_cell.served_cell_info.nr_pci; - - if (not served_cell.served_cell_info.five_gs_tac.has_value()) { - res.result = du_setup_result::rejected{cause_protocol_t::msg_not_compatible_with_receiver_state, - fmt::format("Missing TAC for cell {}", du_cell.cell_index)}; - return res; - } - du_cell.tac = served_cell.served_cell_info.five_gs_tac.value(); - - if (not served_cell.gnb_du_sys_info.has_value()) { - res.result = du_setup_result::rejected{cause_protocol_t::semantic_error, - fmt::format("Missing system information for cell {}", du_cell.cell_index)}; - return res; - } - // Store and unpack system information - du_cell.sys_info.packed_mib = served_cell.gnb_du_sys_info.value().mib_msg.copy(); - du_cell.sys_info.packed_sib1 = served_cell.gnb_du_sys_info.value().sib1_msg.copy(); - - // Add band information. - if (served_cell.served_cell_info.nr_mode_info.fdd.has_value()) { - for (const auto& band : served_cell.served_cell_info.nr_mode_info.fdd.value().dl_nr_freq_info.freq_band_list_nr) { - du_cell.bands.push_back(uint_to_nr_band(band.freq_band_ind_nr)); - } - } else if (served_cell.served_cell_info.nr_mode_info.tdd.has_value()) { - for (const auto& band : served_cell.served_cell_info.nr_mode_info.tdd.value().nr_freq_info.freq_band_list_nr) { - du_cell.bands.push_back(uint_to_nr_band(band.freq_band_ind_nr)); - } - } - - // TODO: add unpacking of sys_info - - // add cell to DU context - du_cell_index_t cell_index = du_cell.cell_index; - cell_db.emplace(cell_index, std::move(du_cell)); - + const du_configuration_context& du_config = cfg.du_cfg_hdlr->get_context(); + for (const du_cell_configuration& cell : du_config.served_cells) { // Add cell to lookup - auto& cell = cell_db.at(cell_index); if (tac_to_nr_cgi.find(cell.tac) == tac_to_nr_cgi.end()) { tac_to_nr_cgi.emplace(cell.tac, std::vector{cell.cgi}); } else { @@ -176,34 +125,10 @@ du_setup_result du_processor_impl::handle_du_setup_request(const du_setup_reques ue_index_t du_processor_impl::allocate_new_ue_index() { - return ue_manager.add_ue(context.du_index); -} - -du_cell_index_t du_processor_impl::find_cell(uint64_t packed_nr_cell_id) -{ - for (auto& cell_pair : cell_db) { - auto& cell = cell_pair.second; - if (cell.cgi.nci == packed_nr_cell_id) { - return cell.cell_index; - } - } - return du_cell_index_t::invalid; + return ue_mng.add_ue(cfg.du_index); } -du_cell_index_t du_processor_impl::get_next_du_cell_index() -{ - for (int du_cell_idx_int = du_cell_index_to_uint(du_cell_index_t::min); du_cell_idx_int < MAX_NOF_DU_CELLS; - du_cell_idx_int++) { - du_cell_index_t cell_idx = uint_to_du_cell_index(du_cell_idx_int); - if (cell_db.find(cell_idx) == cell_db.end()) { - return cell_idx; - } - } - logger.warning("No DU cell index available"); - return du_cell_index_t::invalid; -} - -bool du_processor_impl::create_rrc_ue(du_ue& ue, +bool du_processor_impl::create_rrc_ue(cu_cp_ue& ue, rnti_t c_rnti, const nr_cell_global_id_t& cgi, byte_buffer du_to_cu_rrc_container, @@ -214,22 +139,23 @@ bool du_processor_impl::create_rrc_ue(du_ue& ue, std::forward_as_tuple(ue.get_ue_index()), std::forward_as_tuple(f1ap->get_f1ap_rrc_message_handler(), ue.get_ue_index())); + const du_cell_configuration& cell = *cfg.du_cfg_hdlr->get_context().find_cell(cgi); + // Create new RRC UE entity rrc_ue_creation_message rrc_ue_create_msg{}; rrc_ue_create_msg.ue_index = ue.get_ue_index(); rrc_ue_create_msg.c_rnti = c_rnti; rrc_ue_create_msg.cell.cgi = cgi; - rrc_ue_create_msg.cell.tac = cell_db.at(ue.get_pcell_index()).tac; - rrc_ue_create_msg.cell.pci = cell_db.at(ue.get_pcell_index()).pci; - rrc_ue_create_msg.cell.bands = cell_db.at(ue.get_pcell_index()).bands; - rrc_ue_create_msg.sec_context = &ue.get_security_context(); + rrc_ue_create_msg.cell.tac = cell.tac; + rrc_ue_create_msg.cell.pci = cell.pci; + rrc_ue_create_msg.cell.bands = cell.bands; rrc_ue_create_msg.f1ap_pdu_notifier = &rrc_ue_f1ap_adapters.at(ue.get_ue_index()); rrc_ue_create_msg.rrc_ue_cu_cp_notifier = &ue.get_rrc_ue_context_update_notifier(); rrc_ue_create_msg.measurement_notifier = &ue.get_rrc_ue_measurement_notifier(); + rrc_ue_create_msg.cu_cp_ue_notifier = &ue.get_rrc_ue_cu_cp_ue_notifier(); rrc_ue_create_msg.du_to_cu_container = std::move(du_to_cu_rrc_container); - rrc_ue_create_msg.ue_task_sched = &ue.get_task_sched(); rrc_ue_create_msg.rrc_context = std::move(rrc_context); - auto* rrc_ue = rrc_du_adapter.on_ue_creation_request(ue.get_up_resource_manager(), std::move(rrc_ue_create_msg)); + auto* rrc_ue = rrc_du_adapter.on_ue_creation_request(std::move(rrc_ue_create_msg)); if (rrc_ue == nullptr) { logger.warning("Could not create RRC UE"); return false; @@ -256,23 +182,23 @@ du_processor_impl::handle_ue_rrc_context_creation_request(const ue_rrc_context_c srsran_assert(config_helpers::is_valid(req.cgi), "ue={}: Invalid CGI", req.ue_index); // Check that creation message is valid - du_cell_index_t pcell_index = find_cell(req.cgi.nci); - if (pcell_index == du_cell_index_t::invalid) { - srsran_assert(ue_manager.find_ue_task_scheduler(req.ue_index) != nullptr, "ue={}: Could not find UE", req.ue_index); + const du_cell_configuration* pcell = cfg.du_cfg_hdlr->get_context().find_cell(req.cgi); + if (pcell == nullptr) { + srsran_assert(ue_mng.find_ue_task_scheduler(req.ue_index) != nullptr, "ue={}: Could not find UE", req.ue_index); logger.warning("ue={}: Could not find cell with NCI={}", req.ue_index, req.cgi.nci); - ue_manager.find_ue_task_scheduler(req.ue_index) + ue_mng.find_ue_task_scheduler(req.ue_index) ->schedule_async_task(cu_cp_notifier.on_ue_removal_required(req.ue_index)); return {}; } - const pci_t pci = cell_db.at(pcell_index).pci; + const pci_t pci = pcell->pci; // Create new UE RRC context - du_ue* ue = ue_manager.set_ue_du_context(req.ue_index, context.id, pci, req.c_rnti); + cu_cp_ue* ue = ue_mng.set_ue_du_context(req.ue_index, cfg.du_cfg_hdlr->get_context().id, pci, req.c_rnti); if (ue == nullptr) { logger.warning("ue={}: Could not create UE context", req.ue_index); return {}; } - ue->set_pcell_index(pcell_index); + ue->set_pcell_index(pcell->cell_index); // Create RRC UE. If the DU-to-CU-RRC-Container is empty, the UE will be rejected. if (not create_rrc_ue(*ue, req.c_rnti, req.cgi, req.du_to_cu_rrc_container.copy(), std::move(req.prev_context))) { @@ -297,7 +223,7 @@ void du_processor_impl::handle_du_initiated_ue_context_release_request(const f1a { srsran_assert(request.ue_index != ue_index_t::invalid, "Invalid UE index", request.ue_index); - du_ue* ue = ue_manager.find_du_ue(request.ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(request.ue_index); if (ue == nullptr) { logger.warning("ue={}: Dropping DU initiated UE context release request. UE does not exist", request.ue_index); return; @@ -396,7 +322,7 @@ void du_processor_impl::handle_paging_message(cu_cp_paging_message& msg) // If not nr cgi for a tac from the paging message is found paging message is not forwarded to DU if (!nr_cgi_for_tac_found) { - logger.info("du_index={}: No NR CGI for paging TACs available at this DU", context.du_index); + logger.info("du_index={}: No NR CGI for paging TACs available at this DU", cfg.du_index); return; } @@ -405,7 +331,7 @@ void du_processor_impl::handle_paging_message(cu_cp_paging_message& msg) void du_processor_impl::send_ngap_ue_context_release_request(ue_index_t ue_index, ngap_cause_t cause) { - du_ue* ue = ue_manager.find_du_ue(ue_index); + cu_cp_ue* ue = ue_mng.find_du_ue(ue_index); srsran_assert(ue != nullptr, "ue={}: Could not find DU UE", ue_index); cu_cp_ue_context_release_request req; @@ -429,30 +355,29 @@ void du_processor_impl::send_ngap_ue_context_release_request(ue_index_t ue_index bool du_processor_impl::has_cell(pci_t pci) { - return std::any_of(cell_db.begin(), cell_db.end(), [pci](const auto& cell) { return cell.second.pci == pci; }); + return cfg.du_cfg_hdlr->get_context().find_cell(pci) != nullptr; } bool du_processor_impl::has_cell(nr_cell_global_id_t cgi) { - return std::any_of(cell_db.begin(), cell_db.end(), [cgi](const auto& cell) { return cell.second.cgi == cgi; }); + return cfg.du_cfg_hdlr->get_context().find_cell(cgi) != nullptr; } std::optional du_processor_impl::get_cgi(pci_t pci) { - std::optional cgi; - for (const auto& cell : cell_db) { - if (cell.second.pci == pci) { - return cell.second.cgi; - } + const du_cell_configuration* cell = cfg.du_cfg_hdlr->get_context().find_cell(pci); + if (cell != nullptr) { + return cell->cgi; } - return cgi; + return std::nullopt; } byte_buffer du_processor_impl::get_packed_sib1(nr_cell_global_id_t cgi) { - for (const auto& cell : cell_db) { - if (cell.second.cgi == cgi) { - return cell.second.sys_info.packed_sib1.copy(); + const auto& cells = cfg.du_cfg_hdlr->get_context().served_cells; + for (const auto& cell : cells) { + if (cell.cgi == cgi) { + return cell.sys_info.packed_sib1.copy(); } } return byte_buffer{}; @@ -461,11 +386,15 @@ byte_buffer du_processor_impl::get_packed_sib1(nr_cell_global_id_t cgi) metrics_report::du_info du_processor_impl::handle_du_metrics_report_request() const { metrics_report::du_info report; - report.id = context.id; - for (const auto& cell : cell_db) { - report.cells.emplace_back(); - report.cells.back().cgi = cell.second.cgi; - report.cells.back().pci = cell.second.pci; + report.id = gnb_du_id_t::invalid; + if (cfg.du_cfg_hdlr->has_context()) { + report.id = cfg.du_cfg_hdlr->get_context().id; + const auto& cells = cfg.du_cfg_hdlr->get_context().served_cells; + for (const auto& cell : cells) { + report.cells.emplace_back(); + report.cells.back().cgi = cell.cgi; + report.cells.back().pci = cell.pci; + } } return report; } diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index 3e233b570e..000cdec66a 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -25,6 +25,8 @@ #include "../adapters/du_processor_adapters.h" #include "../adapters/f1ap_adapters.h" #include "../adapters/rrc_ue_adapters.h" +#include "../ue_manager/ue_manager_impl.h" +#include "du_configuration_handler.h" #include "du_processor.h" #include "du_processor_config.h" #include "srsran/cu_cp/cu_cp_types.h" @@ -33,7 +35,6 @@ #include "srsran/ran/nr_cgi.h" #include "srsran/support/executors/task_executor.h" #include -#include namespace srsran { namespace srs_cu_cp { @@ -48,27 +49,27 @@ class du_processor_impl : public du_processor, public du_processor_mobility_handler { public: - du_processor_impl(const du_processor_config_t& du_processor_config_, + du_processor_impl(du_processor_config_t du_processor_config_, du_processor_cu_cp_notifier& cu_cp_notifier_, f1ap_message_notifier& f1ap_notifier_, rrc_ue_nas_notifier& rrc_ue_nas_pdu_notifier_, rrc_ue_control_notifier& rrc_ue_ngap_ctrl_notifier_, rrc_du_measurement_config_notifier& rrc_du_cu_cp_notifier, common_task_scheduler& common_task_sched_, - du_processor_ue_manager& ue_manager_, + ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_); - ~du_processor_impl() = default; + ~du_processor_impl() override = default; // getter functions - du_index_t get_du_index() override { return context.du_index; } + du_index_t get_du_index() override { return cfg.du_index; } f1ap_cu& get_f1ap_handler() override { return *f1ap; }; f1ap_ue_context_manager& get_f1ap_ue_context_manager() override { return *f1ap; } f1ap_ue_context_removal_handler& get_f1ap_ue_context_removal_handler() override { return *f1ap; } f1ap_statistics_handler& get_f1ap_statistics_handler() override { return *f1ap; } - size_t get_nof_ues() const override { return ue_manager.get_nof_du_ues(context.du_index); }; + size_t get_nof_ues() const override { return ue_mng.get_nof_du_ues(cfg.du_index); }; // du_processor_f1ap_interface du_setup_result handle_du_setup_request(const du_setup_request& req) override; @@ -102,26 +103,12 @@ class du_processor_impl : public du_processor, private: /// \brief Create RRC UE object for given UE. /// \return True on success, falso otherwise. - bool create_rrc_ue(du_ue& ue, + bool create_rrc_ue(cu_cp_ue& ue, rnti_t c_rnti, const nr_cell_global_id_t& cgi, byte_buffer du_to_cu_rrc_container, std::optional rrc_context); - /// \brief Lookup the cell based on a given NR cell ID. - /// \param[in] packed_nr_cell_id The packed NR cell ID received over F1AP. - du_cell_index_t find_cell(uint64_t packed_nr_cell_id); - - /// \brief Get the next available DU cell index. - /// \return The next DU cell index. - du_cell_index_t get_next_du_cell_index(); - - /// \brief Get the DU processor cell database. - /// \return The DU processor cell database. - std::map& get_cell_db() { return cell_db; }; - - // F1AP senders - // NGAP senders /// \brief Request UE context release over NGAP. /// \param[in] ue_index The UE. @@ -135,21 +122,15 @@ class du_processor_impl : public du_processor, f1ap_message_notifier& f1ap_pdu_notifier; rrc_ue_nas_notifier& rrc_ue_nas_pdu_notifier; rrc_ue_control_notifier& rrc_ue_ngap_ctrl_notifier; - du_processor_ue_manager& ue_manager; + ue_manager& ue_mng; du_processor_f1ap_ue_context_adapter f1ap_ue_context_notifier; du_processor_f1ap_paging_adapter f1ap_paging_notifier; // F1AP to DU processor adapter f1ap_du_processor_adapter f1ap_ev_notifier; - du_processor_context context; - std::map cell_db; /// flattened version of served cells list provided by DU/F1AP - std::map> tac_to_nr_cgi; - // timers associated with a given DU. - timer_manager timer_db; - // F1AP to RRC UE adapters std::unordered_map f1ap_rrc_ue_adapters; diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index 6db2be7691..eeb708a56f 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -30,7 +30,10 @@ using namespace srsran; using namespace srs_cu_cp; -du_processor_repository::du_processor_repository(du_repository_config cfg_) : cfg(cfg_), logger(cfg.logger) {} +du_processor_repository::du_processor_repository(du_repository_config cfg_) : + cfg(cfg_), logger(cfg.logger), du_cfg_mng(cfg.cu_cp.rrc_config) +{ +} du_index_t du_processor_repository::add_du(std::unique_ptr f1ap_tx_pdu_notifier) { @@ -54,15 +57,16 @@ du_index_t du_processor_repository::add_du(std::unique_ptr du = create_du_processor(du_cfg, + std::unique_ptr du = create_du_processor(std::move(du_cfg), du_ctxt.du_to_cu_cp_notifier, *du_ctxt.f1ap_tx_pdu_notifier, cfg.ue_nas_pdu_notifier, cfg.ue_ngap_ctrl_notifier, cfg.meas_config_notifier, cfg.common_task_sched, - cfg.ue_manager, + cfg.ue_mng, *cfg.cu_cp.timers, *cfg.cu_cp.cu_cp_executor); diff --git a/lib/cu_cp/du_processor/du_processor_repository.h b/lib/cu_cp/du_processor/du_processor_repository.h index f403820cc8..1604c08e01 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.h +++ b/lib/cu_cp/du_processor/du_processor_repository.h @@ -28,9 +28,10 @@ #include "../cu_cp_controller/common_task_scheduler.h" #include "../cu_cp_impl_interface.h" #include "../task_schedulers/du_task_scheduler.h" +#include "../ue_manager/ue_manager_impl.h" +#include "du_configuration_manager.h" #include "du_metrics_handler.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/support/async/async_task.h" #include @@ -47,7 +48,7 @@ struct du_repository_config { rrc_ue_nas_notifier& ue_nas_pdu_notifier; rrc_ue_control_notifier& ue_ngap_ctrl_notifier; common_task_scheduler& common_task_sched; - du_processor_ue_manager& ue_manager; + ue_manager& ue_mng; rrc_du_measurement_config_notifier& meas_config_notifier; du_connection_notifier& du_conn_notif; srslog::basic_logger& logger; @@ -108,6 +109,8 @@ class du_processor_repository : public du_repository_ngap_handler, public du_rep srslog::basic_logger& logger; std::map du_db; + + du_configuration_manager du_cfg_mng; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/mobility_manager/mobility_manager_impl.cpp b/lib/cu_cp/mobility_manager/mobility_manager_impl.cpp index d483d88751..635d045660 100644 --- a/lib/cu_cp/mobility_manager/mobility_manager_impl.cpp +++ b/lib/cu_cp/mobility_manager/mobility_manager_impl.cpp @@ -69,7 +69,7 @@ void mobility_manager::handle_handover(ue_index_t ue_index, pci_t neighbor_pci) { // Find the UE context. - du_ue* u = ue_mng.find_du_ue(ue_index); + cu_cp_ue* u = ue_mng.find_du_ue(ue_index); if (u == nullptr) { logger.error("ue={}: Couldn't find UE", ue_index); return; @@ -126,7 +126,7 @@ void mobility_manager::handle_inter_du_handover(ue_index_t source_ue_index, request.cgi = cgi.value(); request.target_du_index = target_du_index; - du_ue* u = ue_mng.find_du_ue(source_ue_index); + cu_cp_ue* u = ue_mng.find_du_ue(source_ue_index); if (u == nullptr) { logger.error("ue={}: Couldn't find UE", source_ue_index); return; @@ -151,7 +151,7 @@ void mobility_manager::handle_inter_cu_handover(ue_index_t source_ue_index, gnb_id_t target_gnb_id, nr_cell_id_t target_nci) { - du_ue* u = ue_mng.find_du_ue(source_ue_index); + cu_cp_ue* u = ue_mng.find_du_ue(source_ue_index); if (u == nullptr) { logger.error("ue={}: Couldn't find UE", source_ue_index); return; @@ -162,6 +162,19 @@ void mobility_manager::handle_inter_cu_handover(ue_index_t source_ue_index, request.gnb_id = target_gnb_id; request.nci = target_nci; + // create a map of all PDU sessions and their associated QoS flows + const std::map& pdu_sessions = + ue_mng.find_ue(source_ue_index)->get_up_resource_manager().get_pdu_sessions_map(); + for (const auto& pdu_session : pdu_sessions) { + std::vector qos_flows; + for (const auto& drb : pdu_session.second.drbs) { + for (const auto& qos_flow : drb.second.qos_flows) { + qos_flows.push_back(qos_flow.first); + } + } + request.pdu_sessions.insert({pdu_session.first, qos_flows}); + } + // Send handover preparation request to the NGAP handler. auto ho_trigger = [this, request, response = ngap_handover_preparation_response{}](coro_context>& ctx) mutable { diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp b/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp index 3b9f255bc8..4147635f86 100644 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp +++ b/lib/cu_cp/routine_managers/cu_cp_routine_manager.cpp @@ -56,7 +56,7 @@ async_task cu_cp_routine_manager::sta e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, f1ap_ue_context_manager& f1ap_ue_ctxt_mng, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - up_resource_manager& rrc_ue_up_resource_manager) + up_resource_manager& up_resource_mng) { return launch_async(setup_msg, ue_mng.get_ue_config(), @@ -65,7 +65,7 @@ async_task cu_cp_routine_manager::sta e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, - rrc_ue_up_resource_manager, + up_resource_mng, logger); } @@ -75,10 +75,10 @@ cu_cp_routine_manager::start_pdu_session_resource_modification_routine( e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, f1ap_ue_context_manager& f1ap_ue_ctxt_mng, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - up_resource_manager& rrc_ue_up_resource_manager) + up_resource_manager& up_resource_mng) { return launch_async( - modify_msg, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, rrc_ue_up_resource_manager, logger); + modify_msg, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, up_resource_mng, logger); } async_task @@ -89,7 +89,7 @@ cu_cp_routine_manager::start_pdu_session_resource_release_routine( ngap_control_message_handler& ngap_handler, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, ue_task_scheduler& task_sched, - up_resource_manager& rrc_ue_up_resource_manager) + up_resource_manager& up_resource_mng) { return launch_async(release_cmd, e1ap_bearer_ctxt_mng, @@ -97,7 +97,7 @@ cu_cp_routine_manager::start_pdu_session_resource_release_routine( ngap_handler, rrc_ue_ctrl_notifier, task_sched, - rrc_ue_up_resource_manager, + up_resource_mng, logger); } diff --git a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h index 31518df8a3..cc718cab5d 100644 --- a/lib/cu_cp/routine_managers/cu_cp_routine_manager.h +++ b/lib/cu_cp/routine_managers/cu_cp_routine_manager.h @@ -48,7 +48,7 @@ class cu_cp_routine_manager : public common_task_scheduler e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, f1ap_ue_context_manager& f1ap_ue_ctxt_mng, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - up_resource_manager& rrc_ue_up_resource_manager); + up_resource_manager& up_resource_mng); async_task start_pdu_session_resource_release_routine(const cu_cp_pdu_session_resource_release_command& release_cmd, @@ -57,14 +57,14 @@ class cu_cp_routine_manager : public common_task_scheduler ngap_control_message_handler& ngap_handler, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, ue_task_scheduler& task_sched, - up_resource_manager& rrc_ue_up_resource_manager); + up_resource_manager& up_resource_mng); async_task start_pdu_session_resource_modification_routine(const cu_cp_pdu_session_resource_modify_request& modify_msg, e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng, f1ap_ue_context_manager& f1ap_ue_ctxt_mng, du_processor_rrc_ue_control_message_notifier& rrc_ue_ctrl_notifier, - up_resource_manager& rrc_ue_up_resource_manager); + up_resource_manager& up_resource_mng); async_task start_ue_context_release_routine(const cu_cp_ue_context_release_command& command, diff --git a/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.cpp b/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.cpp index be6faa1512..91b3b89f63 100644 --- a/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.cpp +++ b/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.cpp @@ -22,6 +22,7 @@ #include "handover_reconfiguration_routine.h" #include "../../du_processor/du_processor.h" +#include "../../up_resource_manager/up_resource_manager_impl.h" using namespace srsran; using namespace srsran::srs_cu_cp; @@ -30,7 +31,7 @@ using namespace asn1::rrc_nr; handover_reconfiguration_routine::handover_reconfiguration_routine( const rrc_reconfiguration_procedure_request& request_, const ue_index_t& target_ue_index_, - du_ue& source_ue_, + cu_cp_ue& source_ue_, f1ap_ue_context_manager& source_f1ap_ue_ctxt_mng_, cu_cp_ue_context_manipulation_handler& cu_cp_handler_, srslog::basic_logger& logger_) : diff --git a/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.h b/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.h index 496997a857..195e6ef5fa 100644 --- a/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.h +++ b/lib/cu_cp/routines/mobility/handover_reconfiguration_routine.h @@ -35,7 +35,7 @@ class handover_reconfiguration_routine public: handover_reconfiguration_routine(const rrc_reconfiguration_procedure_request& request_, const ue_index_t& target_ue_index_, - du_ue& source_ue_, + cu_cp_ue& source_ue_, f1ap_ue_context_manager& source_f1ap_ue_ctxt_mng_, cu_cp_ue_context_manipulation_handler& cu_cp_handler_, srslog::basic_logger& logger_); @@ -52,7 +52,7 @@ class handover_reconfiguration_routine f1ap_ue_context_modification_request ue_context_mod_request; const ue_index_t target_ue_index; // Index of the target UE - du_ue& source_ue; // UE in the source DU + cu_cp_ue& source_ue; // UE in the source DU f1ap_ue_context_manager& source_f1ap_ue_ctxt_mng; // to send UE context modification to source UE cu_cp_ue_context_manipulation_handler& cu_cp_handler; // To receive the reconfigurationComplete from target UE diff --git a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp index b955029400..036febe5e5 100644 --- a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.cpp @@ -87,14 +87,12 @@ void inter_cu_handover_target_routine::operator()( // Prepare E1AP Bearer Context Setup Request and call E1AP notifier { - // Generate security keys for Bearer Context Setup Request (RRC UE is not created yet) - security_cfg = generate_security_keys(rrc_context.sec_context); - if (!security_cfg.has_value()) { - logger.warning("ue={}: \"{}\" failed to generate security keys", request.ue_index, name()); + // Get security keys for Bearer Context Setup Request (RRC UE is not created yet) + if (!ue->get_security_manager().is_security_context_initialized()) { + logger.warning("ue={}: \"{}\" failed. Cause: Security context not initialized", request.ue_index, name()); CORO_EARLY_RETURN(generate_handover_resource_allocation_response(false)); } - - if (!fill_e1ap_bearer_context_setup_request(security_cfg.value())) { + if (!fill_e1ap_bearer_context_setup_request(ue->get_security_manager().get_up_as_config())) { logger.warning("ue={}: \"{}\" failed to fill context at CU-UP", request.ue_index, name()); CORO_EARLY_RETURN(generate_handover_resource_allocation_response(false)); } @@ -237,37 +235,6 @@ bool handle_procedure_response(e1ap_bearer_context_modification_request& bearer_ return ue_context_setup_resp.success; } -std::optional -inter_cu_handover_target_routine::generate_security_keys(security::security_context& sec_context) -{ - std::optional cfg; - - // Select preferred integrity algorithm. - security::preferred_integrity_algorithms inc_algo_pref_list = {security::integrity_algorithm::nia2, - security::integrity_algorithm::nia1, - security::integrity_algorithm::nia3, - security::integrity_algorithm::nia0}; - security::preferred_ciphering_algorithms ciph_algo_pref_list = {security::ciphering_algorithm::nea0, - security::ciphering_algorithm::nea2, - security::ciphering_algorithm::nea1, - security::ciphering_algorithm::nea3}; - if (not sec_context.select_algorithms(inc_algo_pref_list, ciph_algo_pref_list)) { - logger.warning("ue={}: Could not select security algorithm", request.ue_index); - return cfg; - } - logger.debug("ue={}: Selected security algorithms NIA=NIA{} NEA=NEA{}", - request.ue_index, - sec_context.sel_algos.integ_algo, - sec_context.sel_algos.cipher_algo); - - // Generate K_rrc_enc and K_rrc_int - sec_context.generate_as_keys(); - - cfg = sec_context.get_as_config(security::sec_domain::rrc); - - return cfg; -} - bool inter_cu_handover_target_routine::fill_e1ap_bearer_context_setup_request(const security::sec_as_config& sec_info) { bearer_context_setup_request.ue_index = request.ue_index; diff --git a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.h b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.h index 39a4cfaf06..793bb4088e 100644 --- a/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.h +++ b/lib/cu_cp/routines/mobility/inter_cu_handover_target_routine.h @@ -45,8 +45,7 @@ class inter_cu_handover_target_routine private: bool fill_e1ap_bearer_context_setup_request(const security::sec_as_config& sec_info); - std::optional generate_security_keys(security::security_context& sec_context); - void create_srb1(); + void create_srb1(); ngap_handover_resource_allocation_response generate_handover_resource_allocation_response(bool success); const ngap_handover_request request; @@ -58,11 +57,10 @@ class inter_cu_handover_target_routine srslog::basic_logger& logger; - du_ue* ue = nullptr; - rrc_ue_transfer_context rrc_context; //< Passed to new RRC UE upon creation. - up_config_update next_config; - std::optional security_cfg; - const security_indication_t& default_security_indication; // default if not signaled via NGAP + cu_cp_ue* ue = nullptr; + rrc_ue_transfer_context rrc_context; //< Passed to new RRC UE upon creation. + up_config_update next_config; + const security_indication_t& default_security_indication; // default if not signaled via NGAP // (sub-)routine requests e1ap_bearer_context_setup_request bearer_context_setup_request; diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp index 0174037bd5..439f3e87e3 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.cpp @@ -146,8 +146,13 @@ void inter_du_handover_routine::operator()(coro_contextget_security_context().get_as_config(security::sec_domain::up))) { + if (!target_ue->get_security_manager().is_security_context_initialized()) { + logger.warning( + "ue={}: \"{}\" failed. Cause: Security context not initialized", target_ue->get_ue_index(), name()); + CORO_EARLY_RETURN(response_msg); + } + + if (!add_security_context_to_bearer_context_modification(target_ue->get_security_manager().get_up_as_config())) { logger.warning("ue={}: \"{}\" failed to create UE context at target DU", request.source_ue_index, name()); CORO_AWAIT(ue_removal_handler.handle_ue_removal_request(target_ue_context_setup_request.ue_index)); // Note: From this point the UE is removed and only the stored context can be accessed. @@ -203,7 +208,6 @@ void inter_du_handover_routine::operator()(coro_context(rrc_reconfig_args, @@ -298,7 +302,7 @@ bool inter_du_handover_routine::generate_ue_context_setup_request(f1ap_ue_contex return true; } -void inter_du_handover_routine::create_srb(du_ue* ue, srb_id_t srb_id) +void inter_du_handover_routine::create_srb(cu_cp_ue* ue, srb_id_t srb_id) { srb_creation_message srb_msg{}; srb_msg.ue_index = ue->get_ue_index(); diff --git a/lib/cu_cp/routines/mobility/inter_du_handover_routine.h b/lib/cu_cp/routines/mobility/inter_du_handover_routine.h index de3d37b692..8682f7ec6a 100644 --- a/lib/cu_cp/routines/mobility/inter_du_handover_routine.h +++ b/lib/cu_cp/routines/mobility/inter_du_handover_routine.h @@ -54,15 +54,15 @@ class inter_du_handover_routine bool generate_ue_context_setup_request(f1ap_ue_context_setup_request& setup_request, const static_vector& srbs, const rrc_ue_transfer_context& transfer_context); - void create_srb(du_ue* ue, srb_id_t srb_id); + void create_srb(cu_cp_ue* ue, srb_id_t srb_id); bool add_security_context_to_bearer_context_modification(const srsran::security::sec_as_config& security_cfg); const cu_cp_inter_du_handover_request request; const byte_buffer target_cell_sib1; - du_ue* source_ue = nullptr; // Pointer to UE in the source DU - du_ue* target_ue = nullptr; // Pointer to UE in the target DU + cu_cp_ue* source_ue = nullptr; // Pointer to UE in the source DU + cu_cp_ue* target_ue = nullptr; // Pointer to UE in the target DU rrc_ue_transfer_context source_rrc_context; diff --git a/lib/cu_cp/routines/mobility/mobility_helpers.h b/lib/cu_cp/routines/mobility/mobility_helpers.h index e6d895e13b..cc9e1062ee 100644 --- a/lib/cu_cp/routines/mobility/mobility_helpers.h +++ b/lib/cu_cp/routines/mobility/mobility_helpers.h @@ -22,8 +22,8 @@ #pragma once +#include "../../up_resource_manager/up_resource_manager_impl.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/up_resource_manager.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" #include "srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h" diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp index 2556c608e2..acfbe3078b 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.cpp @@ -57,13 +57,13 @@ pdu_session_resource_modification_routine::pdu_session_resource_modification_rou e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_) : modify_request(modify_request_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), rrc_ue_notifier(rrc_ue_notifier_), - rrc_ue_up_resource_manager(rrc_ue_up_resource_manager_), + up_resource_mng(up_resource_mng_), logger(logger_) { } @@ -76,14 +76,14 @@ void pdu_session_resource_modification_routine::operator()( logger.debug("ue={}: \"{}\" initialized", modify_request.ue_index, name()); // Perform initial sanity checks on incoming message. - if (!rrc_ue_up_resource_manager.validate_request(modify_request)) { + if (!up_resource_mng.validate_request(modify_request)) { logger.warning("ue={}: \"{}\" Invalid PduSessionResourceModification", modify_request.ue_index, name()); CORO_EARLY_RETURN(generate_pdu_session_resource_modify_response(false)); } { // Calculate next user-plane configuration based on incoming modify message. - next_config = rrc_ue_up_resource_manager.calculate_update(modify_request); + next_config = up_resource_mng.calculate_update(modify_request); } { @@ -338,7 +338,7 @@ pdu_session_resource_modification_routine::generate_pdu_session_resource_modify_ for (const auto& pdu_session_to_mod : next_config.pdu_sessions_to_modify_list) { result.pdu_sessions_modified_list.push_back(pdu_session_to_mod.second); } - rrc_ue_up_resource_manager.apply_config_update(result); + up_resource_mng.apply_config_update(result); for (const auto& psi : next_config.pdu_sessions_failed_to_modify_list) { cu_cp_pdu_session_resource_failed_to_modify_item failed_item; diff --git a/lib/cu_cp/routines/pdu_session_resource_modification_routine.h b/lib/cu_cp/routines/pdu_session_resource_modification_routine.h index 0e93e5778f..c71b824b65 100644 --- a/lib/cu_cp/routines/pdu_session_resource_modification_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_modification_routine.h @@ -23,6 +23,7 @@ #pragma once #include "../du_processor/du_processor.h" +#include "../up_resource_manager/up_resource_manager_impl.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/support/async/async_task.h" @@ -38,8 +39,8 @@ class pdu_session_resource_modification_routine e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - up_resource_manager& rrc_ue_up_resource_manager_, - srslog::basic_logger& logger_); + up_resource_manager& up_resource_mng_, + srslog::basic_logger& logger_); void operator()(coro_context>& ctx); @@ -56,10 +57,10 @@ class pdu_session_resource_modification_routine up_config_update next_config; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - up_resource_manager& rrc_ue_up_resource_manager; // to get RRC DRB config + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + up_resource_manager& up_resource_mng; // to get RRC DRB config srslog::basic_logger& logger; // (sub-)routine requests diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp index 835edd1d21..e548d57d67 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.cpp @@ -34,7 +34,7 @@ pdu_session_resource_release_routine::pdu_session_resource_release_routine( ngap_control_message_handler& ngap_handler_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, ue_task_scheduler& task_sched_, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_) : release_cmd(release_cmd_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), @@ -42,7 +42,7 @@ pdu_session_resource_release_routine::pdu_session_resource_release_routine( ngap_handler(ngap_handler_), rrc_ue_notifier(rrc_ue_notifier_), task_sched(task_sched_), - rrc_ue_up_resource_manager(rrc_ue_up_resource_manager_), + up_resource_mng(up_resource_mng_), logger(logger_) { } @@ -69,14 +69,14 @@ void pdu_session_resource_release_routine::operator()( logger.debug("ue={}: \"{}\" initialized", release_cmd.ue_index, name()); // Perform initial sanity checks on incoming message. - if (!rrc_ue_up_resource_manager.validate_request(release_cmd)) { + if (!up_resource_mng.validate_request(release_cmd)) { logger.warning("ue={}: \"{}\" Invalid PduSessionResourceReleaseCommand", release_cmd.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_release_response(false)); } { // Calculate next user-plane configuration based on incoming release command. - next_config = rrc_ue_up_resource_manager.calculate_update(release_cmd); + next_config = up_resource_mng.calculate_update(release_cmd); } // Inform CU-UP about the release of a bearer @@ -172,7 +172,7 @@ pdu_session_resource_release_routine::handle_pdu_session_resource_release_respon for (const auto& pdu_session_to_remove : next_config.pdu_sessions_to_remove_list) { result.pdu_sessions_removed_list.push_back(pdu_session_to_remove); } - rrc_ue_up_resource_manager.apply_config_update(result); + up_resource_mng.apply_config_update(result); if (success) { logger.debug("ue={}: \"{}\" finalized", release_cmd.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_resource_release_routine.h b/lib/cu_cp/routines/pdu_session_resource_release_routine.h index 79090dd758..3f89240778 100644 --- a/lib/cu_cp/routines/pdu_session_resource_release_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_release_routine.h @@ -23,6 +23,8 @@ #pragma once #include "../du_processor/du_processor.h" +#include "../up_resource_manager/up_resource_manager_impl.h" +#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/ngap/ngap.h" #include "srsran/support/async/async_task.h" @@ -41,9 +43,8 @@ class pdu_session_resource_release_routine ngap_control_message_handler& ngap_handler_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, ue_task_scheduler& task_sched_, - - up_resource_manager& rrc_ue_up_resource_manager_, - srslog::basic_logger& logger_); + up_resource_manager& up_resource_mng_, + srslog::basic_logger& logger_); void operator()(coro_context>& ctx); @@ -64,7 +65,7 @@ class pdu_session_resource_release_routine ngap_control_message_handler& ngap_handler; // to request UE release du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE ue_task_scheduler& task_sched; // to schedule UE release request (over NGAP) - up_resource_manager& rrc_ue_up_resource_manager; // to get RRC DRB config + up_resource_manager& up_resource_mng; // to get RRC DRB config srslog::basic_logger& logger; // (sub-)routine requests diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp index 08c2163d76..b920cbd94e 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.cpp @@ -35,7 +35,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& const cu_cp_pdu_session_resource_setup_request setup_msg, const e1ap_bearer_context_modification_response& bearer_context_modification_response, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, const security_indication_t& default_security_indication, srslog::basic_logger& logger); @@ -45,7 +45,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r const cu_cp_pdu_session_resource_setup_request& setup_msg, const e1ap_bearer_context_setup_response& bearer_context_setup_response, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, const security_indication_t& default_security_indication, srslog::basic_logger& logger); @@ -72,7 +72,7 @@ pdu_session_resource_setup_routine::pdu_session_resource_setup_routine( e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_) : setup_msg(setup_msg_), ue_cfg(ue_cfg_), @@ -81,7 +81,7 @@ pdu_session_resource_setup_routine::pdu_session_resource_setup_routine( e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), rrc_ue_notifier(rrc_ue_notifier_), - rrc_ue_up_resource_manager(rrc_ue_up_resource_manager_), + up_resource_mng(up_resource_mng_), logger(logger_) { } @@ -94,7 +94,7 @@ void pdu_session_resource_setup_routine::operator()( logger.debug("ue={}: \"{}\" initialized", setup_msg.ue_index, name()); // Perform initial sanity checks on incoming message. - if (!rrc_ue_up_resource_manager.validate_request(setup_msg.pdu_session_res_setup_items)) { + if (!up_resource_mng.validate_request(setup_msg.pdu_session_res_setup_items)) { logger.info("ue={}: \"{}\" Invalid PduSessionResourceSetup", setup_msg.ue_index, name()); CORO_EARLY_RETURN(handle_pdu_session_resource_setup_result(false)); } @@ -112,7 +112,7 @@ void pdu_session_resource_setup_routine::operator()( { // Calculate next user-plane configuration based on incoming setup message. - next_config = rrc_ue_up_resource_manager.calculate_update(setup_msg.pdu_session_res_setup_items); + next_config = up_resource_mng.calculate_update(setup_msg.pdu_session_res_setup_items); } // sanity check passed, decide whether we have to create a Bearer Context at the CU-UP or modify an existing one. @@ -133,7 +133,7 @@ void pdu_session_resource_setup_routine::operator()( setup_msg, bearer_context_setup_response, next_config, - rrc_ue_up_resource_manager, + up_resource_mng, default_security_indication, logger)) { logger.warning("ue={}: \"{}\" failed to setup bearer at CU-UP", setup_msg.ue_index, name()); @@ -155,7 +155,7 @@ void pdu_session_resource_setup_routine::operator()( setup_msg, bearer_context_modification_response, next_config, - rrc_ue_up_resource_manager, + up_resource_mng, default_security_indication, logger)) { logger.warning("ue={}: \"{}\" failed to modify bearer at CU-UP", setup_msg.ue_index, name()); @@ -200,7 +200,7 @@ void pdu_session_resource_setup_routine::operator()( setup_msg, bearer_context_modification_response, next_config, - rrc_ue_up_resource_manager, + up_resource_mng, default_security_indication, logger)) { logger.warning("ue={}: \"{}\" failed to modify bearer at CU-UP", setup_msg.ue_index, name()); @@ -258,7 +258,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& const cu_cp_pdu_session_resource_setup_request setup_msg, const e1ap_bearer_context_modification_response& bearer_context_modification_response, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, const security_indication_t& default_security_indication, srslog::basic_logger& logger) { @@ -269,7 +269,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& setup_msg.pdu_session_res_setup_items, bearer_context_modification_response.pdu_session_resource_setup_list, next_config, - rrc_ue_up_resource_manager_, + up_resource_mng_, default_security_indication, logger)) { return false; @@ -298,7 +298,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r const cu_cp_pdu_session_resource_setup_request& setup_msg, const e1ap_bearer_context_setup_response& bearer_context_setup_response, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, const security_indication_t& default_security_indication, srslog::basic_logger& logger) { @@ -309,7 +309,7 @@ bool handle_procedure_response(cu_cp_pdu_session_resource_setup_response& r setup_msg.pdu_session_res_setup_items, bearer_context_setup_response.pdu_session_resource_setup_list, next_config, - rrc_ue_up_resource_manager_, + up_resource_mng_, default_security_indication, logger)) { return false; @@ -407,7 +407,7 @@ pdu_session_resource_setup_routine::handle_pdu_session_resource_setup_result(boo for (const auto& pdu_session_to_add : next_config.pdu_sessions_to_setup_list) { result.pdu_sessions_added_list.push_back(pdu_session_to_add.second); } - rrc_ue_up_resource_manager.apply_config_update(result); + up_resource_mng.apply_config_update(result); } else { logger.info("ue={}: \"{}\" failed", setup_msg.ue_index, name()); diff --git a/lib/cu_cp/routines/pdu_session_resource_setup_routine.h b/lib/cu_cp/routines/pdu_session_resource_setup_routine.h index efa22ce0bf..3355103b90 100644 --- a/lib/cu_cp/routines/pdu_session_resource_setup_routine.h +++ b/lib/cu_cp/routines/pdu_session_resource_setup_routine.h @@ -23,7 +23,8 @@ #pragma once #include "../du_processor/du_processor.h" -#include "srsran/cu_cp/ue_manager.h" +#include "../up_resource_manager/up_resource_manager_impl.h" +#include "srsran/cu_cp/ue_configuration.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/support/async/async_task.h" @@ -57,7 +58,7 @@ class pdu_session_resource_setup_routine e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_); void operator()(coro_context>& ctx); @@ -77,10 +78,10 @@ class pdu_session_resource_setup_routine up_config_update next_config; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - up_resource_manager& rrc_ue_up_resource_manager; // to get RRC DRB config + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + up_resource_manager& up_resource_mng; // to get RRC DRB config srslog::basic_logger& logger; // (sub-)routine requests diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp index 26575ddba0..6d10057e0c 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.cpp +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.cpp @@ -278,12 +278,12 @@ bool srsran::srs_cu_cp::update_setup_list( const slotted_id_vector& pdu_session_resource_setup_list, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager, + up_resource_manager& up_resource_mng, const security_indication_t& default_security_indication, const srslog::basic_logger& logger) { // Set up SRB2 if this is the first DRB to be setup - if (rrc_ue_up_resource_manager.get_nof_drbs() == 0) { + if (up_resource_mng.get_nof_drbs() == 0) { f1ap_srbs_to_be_setup_mod_item srb2; srb2.srb_id = srb_id_t::srb2; srb_setup_mod_list.emplace(srb2.srb_id, srb2); @@ -409,7 +409,7 @@ bool srsran::srs_cu_cp::update_setup_list( const slotted_id_vector& pdu_session_resource_setup_list, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager, + up_resource_manager& up_resource_mng, const srslog::basic_logger& logger) { // Set up SRB1 and SRB2 (this is for inter CU handover, so no SRBs are setup yet) diff --git a/lib/cu_cp/routines/pdu_session_routine_helpers.h b/lib/cu_cp/routines/pdu_session_routine_helpers.h index 0b9ca5df15..f69e614ae3 100644 --- a/lib/cu_cp/routines/pdu_session_routine_helpers.h +++ b/lib/cu_cp/routines/pdu_session_routine_helpers.h @@ -22,9 +22,9 @@ #pragma once +#include "../up_resource_manager/up_resource_manager_impl.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/ue_manager.h" -#include "srsran/cu_cp/up_resource_manager.h" +#include "srsran/cu_cp/ue_configuration.h" #include "srsran/e1ap/common/e1ap_types.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" #include "srsran/f1ap/cu_cp/f1ap_cu_ue_context_update.h" @@ -93,7 +93,7 @@ bool update_setup_list( const slotted_id_vector& pdu_session_resource_setup_list, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager, + up_resource_manager& up_resource_mng, const security_indication_t& default_security_indication, const srslog::basic_logger& logger); @@ -103,7 +103,7 @@ bool update_setup_list(slotted_id_vector& pdu_session_resource_setup_list, up_config_update& next_config, - up_resource_manager& rrc_ue_up_resource_manager, + up_resource_manager& up_resource_mng, const srslog::basic_logger& logger); bool update_setup_list(e1ap_bearer_context_modification_request& bearer_ctxt_mod_request, diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp index 4c59de9b05..87813cbeeb 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.cpp @@ -34,14 +34,14 @@ reestablishment_context_modification_routine::reestablishment_context_modificati e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - up_resource_manager& rrc_ue_up_resource_manager_, + up_resource_manager& up_resource_mng_, srslog::basic_logger& logger_) : ue_index(ue_index_), security_cfg(security_cfg_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), rrc_ue_notifier(rrc_ue_notifier_), - rrc_ue_up_resource_manager(rrc_ue_up_resource_manager_), + up_resource_mng(up_resource_mng_), logger(logger_) { } @@ -82,7 +82,7 @@ void reestablishment_context_modification_routine::operator()(coro_context pdu_sessions_to_setup_list; - for (const auto& pdu_session_id : rrc_ue_up_resource_manager.get_pdu_sessions()) { + for (const auto& pdu_session_id : up_resource_mng.get_pdu_sessions()) { up_pdu_session_context_update context_update{pdu_session_id}; - context_update.drb_to_add = rrc_ue_up_resource_manager.get_pdu_session_context(pdu_session_id).drbs; + context_update.drb_to_add = up_resource_mng.get_pdu_session_context(pdu_session_id).drbs; pdu_sessions_to_setup_list.emplace(pdu_session_id, context_update); } @@ -162,13 +162,13 @@ bool reestablishment_context_modification_routine::generate_bearer_context_modif bearer_context_modification_request.new_ul_tnl_info_required = true; // Request new UL TNL info for all DRBs - std::vector pdu_session_ids = rrc_ue_up_resource_manager.get_pdu_sessions(); + std::vector pdu_session_ids = up_resource_mng.get_pdu_sessions(); e1ap_ng_ran_bearer_context_mod_request ngran_bearer_context_mod_req = {}; for (const pdu_session_id_t& psi : pdu_session_ids) { e1ap_pdu_session_res_to_modify_item pdu_sess_mod_item; pdu_sess_mod_item.pdu_session_id = psi; - const std::map& drbs = rrc_ue_up_resource_manager.get_pdu_session_context(psi).drbs; + const std::map& drbs = up_resource_mng.get_pdu_session_context(psi).drbs; for (const std::pair& drb : drbs) { logger.debug("{}, {}: Requesting new UL TNL for DRB", psi, drb.first); e1ap_drb_to_modify_item_ng_ran drb_to_mod = {}; @@ -213,7 +213,7 @@ bool reestablishment_context_modification_routine::generate_ue_context_modificat item.transfer.qos_flow_add_or_modify_response_list.emplace(); // re-establish old flows - const up_drb_context& drb_up_context = rrc_ue_up_resource_manager.get_drb_context(e1ap_drb_item.drb_id); + const up_drb_context& drb_up_context = up_resource_mng.get_drb_context(e1ap_drb_item.drb_id); for (const auto& flow : drb_up_context.qos_flows) { qos_flow_add_or_mod_response_item qos_flow; diff --git a/lib/cu_cp/routines/reestablishment_context_modification_routine.h b/lib/cu_cp/routines/reestablishment_context_modification_routine.h index 6c3cbb9eaf..3de42f2e6e 100644 --- a/lib/cu_cp/routines/reestablishment_context_modification_routine.h +++ b/lib/cu_cp/routines/reestablishment_context_modification_routine.h @@ -23,7 +23,7 @@ #pragma once #include "../du_processor/du_processor.h" -#include "srsran/cu_cp/cu_cp_f1c_handler.h" +#include "../up_resource_manager/up_resource_manager_impl.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp_bearer_context_update.h" #include "srsran/support/async/async_task.h" @@ -41,8 +41,8 @@ class reestablishment_context_modification_routine e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_, - up_resource_manager& rrc_ue_up_resource_manager_, - srslog::basic_logger& logger_); + up_resource_manager& up_resource_mng_, + srslog::basic_logger& logger_); void operator()(coro_context>& ctx); @@ -63,10 +63,10 @@ class reestablishment_context_modification_routine ue_index_t ue_index = ue_index_t::invalid; security::sec_as_config security_cfg; - e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP - f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU - du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE - up_resource_manager& rrc_ue_up_resource_manager; // to get RRC DRB config + e1ap_bearer_context_manager& e1ap_bearer_ctxt_mng; // to trigger bearer context setup at CU-UP + f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU + du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier; // to trigger RRC Reconfiguration at UE + up_resource_manager& up_resource_mng; // to get RRC DRB config srslog::basic_logger& logger; // (sub-)routine requests diff --git a/lib/cu_cp/routines/ue_context_release_routine.cpp b/lib/cu_cp/routines/ue_context_release_routine.cpp index 34f5cdc067..11248b8f7e 100644 --- a/lib/cu_cp/routines/ue_context_release_routine.cpp +++ b/lib/cu_cp/routines/ue_context_release_routine.cpp @@ -31,13 +31,13 @@ ue_context_release_routine::ue_context_release_routine(const cu_cp_ue_context_re e1ap_bearer_context_manager* e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, cu_cp_ue_removal_handler& ue_removal_handler_, - du_processor_ue_manager& ue_manager_, + ue_manager& ue_mng_, srslog::basic_logger& logger_) : command(command_), e1ap_bearer_ctxt_mng(e1ap_bearer_ctxt_mng_), f1ap_ue_ctxt_mng(f1ap_ue_ctxt_mng_), ue_removal_handler(ue_removal_handler_), - ue_manager(ue_manager_), + ue_mng(ue_mng_), logger(logger_) { srsran_assert(!command.cause.valueless_by_exception(), "Release command needs to be set."); @@ -53,18 +53,18 @@ void ue_context_release_routine::operator()(coro_contextget_up_resource_manager().get_pdu_sessions(); + ue_mng.find_du_ue(command.ue_index)->get_up_resource_manager().get_pdu_sessions(); // Call RRC UE notifier to get the release context of the UE and add the location info to the UE context release // complete message - release_context = ue_manager.find_du_ue(command.ue_index) + release_context = ue_mng.find_du_ue(command.ue_index) ->get_rrc_ue_notifier() .get_rrc_ue_release_context(command.requires_rrc_release); release_complete.user_location_info = release_context.user_location_info; } if (e1ap_bearer_ctxt_mng != nullptr and - not ue_manager.find_du_ue(command.ue_index)->get_up_resource_manager().get_pdu_sessions().empty()) { + not ue_mng.find_du_ue(command.ue_index)->get_up_resource_manager().get_pdu_sessions().empty()) { // If there is an active E1AP context, // prepare Bearer Context Release Command and call E1AP notifier bearer_context_release_command.ue_index = command.ue_index; diff --git a/lib/cu_cp/routines/ue_context_release_routine.h b/lib/cu_cp/routines/ue_context_release_routine.h index 096d02b2e1..8760757ea5 100644 --- a/lib/cu_cp/routines/ue_context_release_routine.h +++ b/lib/cu_cp/routines/ue_context_release_routine.h @@ -37,7 +37,7 @@ class ue_context_release_routine e1ap_bearer_context_manager* e1ap_bearer_ctxt_mng_, f1ap_ue_context_manager& f1ap_ue_ctxt_mng_, cu_cp_ue_removal_handler& ue_removal_handler_, - du_processor_ue_manager& ue_manager_, + ue_manager& ue_mng_, srslog::basic_logger& logger_); void operator()(coro_context>& ctx); @@ -50,7 +50,7 @@ class ue_context_release_routine e1ap_bearer_context_manager* e1ap_bearer_ctxt_mng = nullptr; // to trigger bearer context setup at CU-UP f1ap_ue_context_manager& f1ap_ue_ctxt_mng; // to trigger UE context modification at DU cu_cp_ue_removal_handler& ue_removal_handler; // to remove UE - du_processor_ue_manager& ue_manager; + ue_manager& ue_mng; srslog::basic_logger& logger; // (sub-)routine requests diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp new file mode 100644 index 0000000000..6f0f1406ac --- /dev/null +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.cpp @@ -0,0 +1,121 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "cu_cp_ue_impl.h" + +using namespace srsran; +using namespace srs_cu_cp; + +cu_cp_ue::cu_cp_ue(const ue_index_t ue_index_, + const up_resource_manager_cfg& up_cfg, + const security_manager_config& sec_cfg, + ue_task_scheduler_impl task_sched_, + const pci_t pci_, + const rnti_t c_rnti_) : + ue_index(ue_index_), + task_sched(std::move(task_sched_)), + up_mng(up_cfg), + sec_mng(sec_cfg), + rrc_ue_cu_cp_ev_notifier(ue_index) +{ + if (pci_ != INVALID_PCI) { + pci = pci_; + } + + if (c_rnti_ != rnti_t::INVALID_RNTI) { + ue_ctxt.crnti = c_rnti_; + } + + ue_ctxt.du_idx = get_du_index_from_ue_index(ue_index); + + rrc_ue_cu_cp_ue_ev_notifier.connect_ue(*this); + ngap_cu_cp_ue_ev_notifier.connect_ue(*this); +} + +/// \brief Update a UE with PCI and/or C-RNTI. +void cu_cp_ue::update_du_ue(gnb_du_id_t du_id_, pci_t pci_, rnti_t c_rnti_) +{ + if (du_id_ != gnb_du_id_t::invalid) { + ue_ctxt.du_id = du_id_; + } + + if (pci_ != INVALID_PCI) { + pci = pci_; + } + + if (c_rnti_ != rnti_t::INVALID_RNTI) { + ue_ctxt.crnti = c_rnti_; + } +} + +/// \brief Set/update the measurement context of the UE. +void cu_cp_ue::update_meas_context(cell_meas_manager_ue_context meas_ctxt) +{ + meas_context = std::move(meas_ctxt); +} + +/// \brief Set the DU and PCell index of the UE. +/// \param[in] pcell_index PCell index of the UE. +void cu_cp_ue::set_pcell_index(du_cell_index_t pcell_index_) +{ + pcell_index = pcell_index_; +} + +/// \brief Set the RRC UE control message notifier of the UE. +/// \param[in] rrc_ue_notifier_ RRC UE control message notifier of the UE. +void cu_cp_ue::set_rrc_ue_notifier(du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_) +{ + rrc_ue_notifier = &rrc_ue_notifier_; +} + +/// \brief Set the RRC UE SRB notifier of the UE. +/// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. +void cu_cp_ue::set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_) +{ + rrc_ue_srb_notifier = &rrc_ue_srb_notifier_; +} + +/// \brief Get the RRC UE PDU notifier of the UE. +ngap_rrc_ue_pdu_notifier& cu_cp_ue::get_rrc_ue_pdu_notifier() +{ + return ngap_rrc_ue_ev_notifier; +} + +/// \brief Get the RRC UE control notifier of the UE. +ngap_rrc_ue_control_notifier& cu_cp_ue::get_rrc_ue_control_notifier() +{ + return ngap_rrc_ue_ev_notifier; +} + +/// \brief Get the RRC UE control message notifier of the UE. +du_processor_rrc_ue_control_message_notifier& cu_cp_ue::get_rrc_ue_notifier() +{ + srsran_assert(rrc_ue_notifier != nullptr, "ue={}: RRC UE notifier was not set", ue_index); + return *rrc_ue_notifier; +} + +/// \brief Get the RRC UE SRB control notifier of the UE. +du_processor_rrc_ue_srb_control_notifier& cu_cp_ue::get_rrc_ue_srb_notifier() +{ + srsran_assert(rrc_ue_srb_notifier != nullptr, "ue={}: RRC UE SRB notifier was not set", ue_index); + return *rrc_ue_srb_notifier; +} diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h new file mode 100644 index 0000000000..8b029fc924 --- /dev/null +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl.h @@ -0,0 +1,178 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "../adapters/cu_cp_adapters.h" +#include "../adapters/ngap_adapters.h" +#include "../adapters/rrc_ue_adapters.h" +#include "../cell_meas_manager/measurement_context.h" +#include "../ue_security_manager/ue_security_manager_impl.h" +#include "../up_resource_manager/up_resource_manager_impl.h" +#include "cu_cp_ue_impl_interface.h" +#include "ue_task_scheduler_impl.h" +#include + +namespace srsran { + +namespace srs_cu_cp { + +/// \brief Context of a CU-CP UE. +struct cu_cp_ue_context { + du_index_t du_idx = du_index_t::invalid; + gnb_du_id_t du_id = gnb_du_id_t::invalid; + ue_index_t ue_index = ue_index_t::invalid; + rnti_t crnti = rnti_t::INVALID_RNTI; + /// \brief Flag to disable new UE reconfigurations. This can be used, for instance, to reconfigure UE contexts + /// that are in the process of handover. + bool reconfiguration_disabled = false; +}; + +class cu_cp_ue : public cu_cp_ue_impl_interface +{ +public: + cu_cp_ue(const ue_index_t ue_index_, + const up_resource_manager_cfg& up_cfg, + const security_manager_config& sec_cfg, + ue_task_scheduler_impl task_sched_, + const pci_t pci_ = INVALID_PCI, + const rnti_t c_rnti_ = rnti_t::INVALID_RNTI); + + /// \brief Cancel all pending UE tasks. + void stop(); + + /// \brief Get the UE index of the UE. + ue_index_t get_ue_index() override { return ue_index; } + + /// \brief Get the PCI of the UE. + [[nodiscard]] pci_t get_pci() const { return pci; }; + + /// \brief Get the C-RNTI of the UE. + [[nodiscard]] rnti_t get_c_rnti() const { return ue_ctxt.crnti; } + + [[nodiscard]] gnb_du_id_t get_du_id() const { return ue_ctxt.du_id; } + + /// \brief Get the DU index of the UE. + du_index_t get_du_index() { return ue_ctxt.du_idx; } + + /// \brief Get the PCell index of the UE. + du_cell_index_t get_pcell_index() { return pcell_index; } + + /// \brief Get the UP resource manager of the UE. + up_resource_manager& get_up_resource_manager() override { return up_mng; } + + /// \brief Get the task scheduler of the UE. + ue_task_scheduler& get_task_sched() override { return task_sched; } + + /// \brief Get the security manager of the UE. + ue_security_manager& get_security_manager() override { return sec_mng; } + + cu_cp_ue_context& get_ue_context() { return ue_ctxt; } + [[nodiscard]] const cu_cp_ue_context& get_ue_context() const { return ue_ctxt; } + + /// \brief Get the measurement context of the UE. + cell_meas_manager_ue_context& get_meas_context() { return meas_context; } + + /// \brief Update a UE with PCI and/or C-RNTI. + void update_du_ue(gnb_du_id_t du_id_ = gnb_du_id_t::invalid, + pci_t pci_ = INVALID_PCI, + rnti_t c_rnti_ = rnti_t::INVALID_RNTI); + + /// \brief Set/update the measurement context of the UE. + void update_meas_context(cell_meas_manager_ue_context meas_ctxt); + + /// \brief Check if the DU UE context is created. + /// \return True if the DU UE context is created, false otherwise. + [[nodiscard]] bool du_ue_created() const { return ue_ctxt.du_idx != du_index_t::invalid; } + + /// \brief Set the DU and PCell index of the UE. + /// \param[in] pcell_index PCell index of the UE. + void set_pcell_index(du_cell_index_t pcell_index_); + + /// \brief Set the RRC UE control message notifier of the UE. + /// \param[in] rrc_ue_notifier_ RRC UE control message notifier of the UE. + void set_rrc_ue_notifier(du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_); + + /// \brief Set the RRC UE SRB notifier of the UE. + /// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. + void set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_); + + /// \brief Get the RRC UE PDU notifier of the UE. + ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() override; + + /// \brief Get the RRC UE control notifier of the UE. + ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() override; + + /// \brief Get the NGAP CU-CP UE notifier of the UE. + ngap_cu_cp_ue_notifier& get_ngap_cu_cp_ue_notifier() { return ngap_cu_cp_ue_ev_notifier; } + + /// \brief Get the RRC UE CU-CP UE notifier of the UE. + rrc_ue_cu_cp_ue_notifier& get_rrc_ue_cu_cp_ue_notifier() { return rrc_ue_cu_cp_ue_ev_notifier; } + + /// \brief Get the RRC UE control message notifier of the UE. + du_processor_rrc_ue_control_message_notifier& get_rrc_ue_notifier(); + + /// \brief Get the RRC UE SRB control notifier of the UE. + du_processor_rrc_ue_srb_control_notifier& get_rrc_ue_srb_notifier(); + + rrc_ue_context_update_notifier& get_rrc_ue_context_update_notifier() { return rrc_ue_cu_cp_ev_notifier; } + + /// \brief Get the RRC UE measurement notifier of the UE. + rrc_ue_measurement_notifier& get_rrc_ue_measurement_notifier() { return rrc_ue_cu_cp_ev_notifier; } + + /// \brief Get the NGAP to RRC UE adapter of the UE. + ngap_rrc_ue_adapter& get_ngap_rrc_ue_adapter() { return ngap_rrc_ue_ev_notifier; } + + /// \brief Get the CU-CP to RRC UE adapter of the UE. + cu_cp_rrc_ue_adapter& get_cu_cp_rrc_ue_adapter() { return cu_cp_rrc_ue_ev_notifier; } + + /// \brief Get the RRC to CU-CP adapter of the UE. + rrc_ue_cu_cp_adapter& get_rrc_ue_cu_cp_adapter() { return rrc_ue_cu_cp_ev_notifier; } + +private: + // common context + ue_index_t ue_index = ue_index_t::invalid; + ue_task_scheduler_impl task_sched; + up_resource_manager up_mng; + ue_security_manager sec_mng; + + // du ue context + cu_cp_ue_context ue_ctxt; + du_cell_index_t pcell_index = du_cell_index_t::invalid; + pci_t pci = INVALID_PCI; + + rrc_ue_cu_cp_ue_adapter rrc_ue_cu_cp_ue_ev_notifier; + du_processor_rrc_ue_control_message_notifier* rrc_ue_notifier = nullptr; + du_processor_rrc_ue_srb_control_notifier* rrc_ue_srb_notifier = nullptr; + + // ngap ue context + ngap_cu_cp_ue_adapter ngap_cu_cp_ue_ev_notifier; + ngap_rrc_ue_adapter ngap_rrc_ue_ev_notifier; + + // cu-cp ue context + cu_cp_rrc_ue_adapter cu_cp_rrc_ue_ev_notifier; + rrc_ue_cu_cp_adapter rrc_ue_cu_cp_ev_notifier; + cell_meas_manager_ue_context meas_context; +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h b/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h new file mode 100644 index 0000000000..0f33b79c43 --- /dev/null +++ b/lib/cu_cp/ue_manager/cu_cp_ue_impl_interface.h @@ -0,0 +1,65 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "../ue_security_manager/ue_security_manager_impl.h" +#include "srsran/cu_cp/cu_cp_types.h" + +namespace srsran { + +namespace srs_cu_cp { + +// Forward declarations. +class up_resource_manager; +class ue_task_scheduler; +class ue_security_manager; +class ngap_rrc_ue_pdu_notifier; +class ngap_rrc_ue_control_notifier; + +/// Common UE interface. +class cu_cp_ue_impl_interface +{ +public: + virtual ~cu_cp_ue_impl_interface() = default; + + /// \brief Get the UE index of the UE. + virtual ue_index_t get_ue_index() = 0; + + /// \brief Get the UP resource manager of the UE. + virtual up_resource_manager& get_up_resource_manager() = 0; + + /// \brief Get the task scheduler of the UE. + virtual ue_task_scheduler& get_task_sched() = 0; + + /// \brief Get the security manager of the UE. + virtual ue_security_manager& get_security_manager() = 0; + + /// \brief Get the RRC UE PDU notifier of the UE. + virtual ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() = 0; + + /// \brief Get the RRC UE control notifier of the UE. + virtual ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() = 0; +}; + +} // namespace srs_cu_cp +} // namespace srsran diff --git a/lib/cu_cp/ue_manager/ue_manager_impl.cpp b/lib/cu_cp/ue_manager/ue_manager_impl.cpp index b677f6cf70..ab6f6838b6 100644 --- a/lib/cu_cp/ue_manager/ue_manager_impl.cpp +++ b/lib/cu_cp/ue_manager/ue_manager_impl.cpp @@ -21,6 +21,7 @@ */ #include "ue_manager_impl.h" +#include "srsran/cu_cp/security_manager_config.h" using namespace srsran; using namespace srs_cu_cp; @@ -32,9 +33,10 @@ void cu_cp_ue::stop() ue_manager::ue_manager(const ue_configuration& ue_config_, const up_resource_manager_cfg& up_config_, + const security_manager_config& sec_config_, timer_manager& timers, task_executor& cu_cp_exec) : - ue_config(ue_config_), up_config(up_config_), ue_task_scheds(timers, cu_cp_exec, logger) + ue_config(ue_config_), up_config(up_config_), sec_config(sec_config_), ue_task_scheds(timers, cu_cp_exec, logger) { } @@ -63,7 +65,7 @@ ue_index_t ue_manager::add_ue(du_index_t du_index) // Create UE object ues.emplace(std::piecewise_construct, std::forward_as_tuple(new_ue_index), - std::forward_as_tuple(new_ue_index, up_config, std::move(ue_sched))); + std::forward_as_tuple(new_ue_index, up_config, sec_config, std::move(ue_sched))); logger.info("ue={}: Created new CU-CP UE", new_ue_index); @@ -110,9 +112,9 @@ ue_index_t ue_manager::get_ue_index(pci_t pci, rnti_t rnti) return ue_index_t::invalid; } -// common_ue_manager +// common -common_ue* ue_manager::find_ue(ue_index_t ue_index) +cu_cp_ue* ue_manager::find_ue(ue_index_t ue_index) { if (ues.find(ue_index) != ues.end()) { return &ues.at(ue_index); @@ -128,9 +130,9 @@ ue_task_scheduler* ue_manager::find_ue_task_scheduler(ue_index_t ue_index) return nullptr; } -// du_processor_ue_manager +// du processor -du_ue* ue_manager::set_ue_du_context(ue_index_t ue_index, gnb_du_id_t du_id, pci_t pci, rnti_t rnti) +cu_cp_ue* ue_manager::set_ue_du_context(ue_index_t ue_index, gnb_du_id_t du_id, pci_t pci, rnti_t rnti) { srsran_assert(ue_index != ue_index_t::invalid, "Invalid ue_index={}", ue_index); srsran_assert(pci != INVALID_PCI, "Invalid pci={}", pci); @@ -159,7 +161,7 @@ du_ue* ue_manager::set_ue_du_context(ue_index_t ue_index, gnb_du_id_t du_id, pci return &ue; } -du_ue* ue_manager::find_du_ue(ue_index_t ue_index) +cu_cp_ue* ue_manager::find_du_ue(ue_index_t ue_index) { if (ues.find(ue_index) != ues.end() && ues.at(ue_index).du_ue_created()) { return &ues.at(ue_index); @@ -167,43 +169,6 @@ du_ue* ue_manager::find_du_ue(ue_index_t ue_index) return nullptr; } -// ngap_ue_manager - -ngap_ue* ue_manager::set_ue_ng_context(ue_index_t ue_index, - ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier_, - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier_) -{ - srsran_assert(ue_index != ue_index_t::invalid, "Invalid ue_index={}", ue_index); - - // check if the UE is already present - if (ues.find(ue_index) != ues.end() && ues.at(ue_index).ngap_ue_created()) { - logger.warning("ue={}: UE already exists", ue_index); - return nullptr; - } - - // UE must be created by DU processor - if (ues.find(ue_index) == ues.end()) { - logger.warning("UE has not been created"); - return nullptr; - } - - auto& ue = ues.at(ue_index); - - ue.add_ngap_ue_context(rrc_ue_pdu_notifier_, rrc_ue_ctrl_notifier_); - - logger.debug("ue={}: Added NGAP UE", ue_index); - - return &ue; -} - -ngap_ue* ue_manager::find_ngap_ue(ue_index_t ue_index) -{ - if (ues.find(ue_index) != ues.end() && ues.at(ue_index).ngap_ue_created()) { - return &ues.at(ue_index); - } - return nullptr; -} - std::vector ue_manager::handle_ue_metrics_report_request() const { std::vector report; diff --git a/lib/cu_cp/ue_manager/ue_manager_impl.h b/lib/cu_cp/ue_manager/ue_manager_impl.h index fafa2dbbff..9f5261b167 100644 --- a/lib/cu_cp/ue_manager/ue_manager_impl.h +++ b/lib/cu_cp/ue_manager/ue_manager_impl.h @@ -26,218 +26,23 @@ #include "../adapters/ngap_adapters.h" #include "../adapters/rrc_ue_adapters.h" #include "../cell_meas_manager/measurement_context.h" +#include "../ue_security_manager/ue_security_manager_impl.h" +#include "cu_cp_ue_impl.h" #include "ue_metrics_handler.h" #include "ue_task_scheduler_impl.h" -#include "srsran/cu_cp/ue_manager.h" +#include "srsran/cu_cp/ue_configuration.h" #include namespace srsran { namespace srs_cu_cp { -struct ngap_ue_t { - ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier; - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier; - - ngap_ue_t(ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier_, ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier_) : - rrc_ue_pdu_notifier(rrc_ue_pdu_notifier_), rrc_ue_ctrl_notifier(rrc_ue_ctrl_notifier_) - { - } -}; - -class cu_cp_ue final : public common_ue, public du_ue, public ngap_ue -{ -public: - cu_cp_ue(const ue_index_t ue_index_, - const up_resource_manager_cfg& up_cfg, - ue_task_scheduler_impl task_sched_, - const pci_t pci_ = INVALID_PCI, - const rnti_t c_rnti_ = rnti_t::INVALID_RNTI) : - ue_index(ue_index_), - task_sched(std::move(task_sched_)), - up_mng(create_up_resource_manager(up_cfg)), - rrc_ue_cu_cp_ev_notifier(ue_index) - { - if (pci_ != INVALID_PCI) { - pci = pci_; - } - - if (c_rnti_ != rnti_t::INVALID_RNTI) { - ue_ctxt.crnti = c_rnti_; - } - - ue_ctxt.du_idx = get_du_index_from_ue_index(ue_index); - } - - /// \brief Cancel all pending UE tasks. - void stop(); - - // generic_ue - - /// \brief Get the UE index of the UE. - ue_index_t get_ue_index() override { return ue_index; } - - /// \brief Get the UP resource manager of the UE. - up_resource_manager& get_up_resource_manager() override { return *up_mng; } - - /// \brief Get the task scheduler of the UE. - ue_task_scheduler& get_task_sched() override { return task_sched; } - - /// \brief Get the security context of the UE. - security::security_context& get_security_context() override { return sec_context; } - - // du_ue - - /// \brief Get the RRC UE control message notifier of the UE. - du_processor_rrc_ue_control_message_notifier& get_rrc_ue_notifier() override - { - srsran_assert(rrc_ue_notifier != nullptr, "ue={}: RRC UE notifier was not set", ue_index); - return *rrc_ue_notifier; - } - - /// \brief Get the RRC UE SRB control notifier of the UE. - du_processor_rrc_ue_srb_control_notifier& get_rrc_ue_srb_notifier() override - { - srsran_assert(rrc_ue_srb_notifier != nullptr, "ue={}: RRC UE SRB notifier was not set", ue_index); - return *rrc_ue_srb_notifier; - } - - rrc_ue_context_update_notifier& get_rrc_ue_context_update_notifier() override { return rrc_ue_cu_cp_ev_notifier; } - - /// \brief Get the RRC UE measurement notifier of the UE. - rrc_ue_measurement_notifier& get_rrc_ue_measurement_notifier() override { return rrc_ue_cu_cp_ev_notifier; } - - /// \brief Get the PCI of the UE. - [[nodiscard]] pci_t get_pci() const override { return pci; }; - - /// \brief Get the C-RNTI of the UE. - [[nodiscard]] rnti_t get_c_rnti() const override { return ue_ctxt.crnti; } - - [[nodiscard]] gnb_du_id_t get_du_id() const { return ue_ctxt.du_id; } - - /// \brief Get the DU index of the UE. - du_index_t get_du_index() override { return ue_ctxt.du_idx; } - - /// \brief Get the PCell index of the UE. - du_cell_index_t get_pcell_index() override { return pcell_index; } - - cu_cp_ue_context& get_ue_context() override { return ue_ctxt; } - [[nodiscard]] const cu_cp_ue_context& get_ue_context() const override { return ue_ctxt; } - - /// \brief Update a UE with PCI and/or C-RNTI. - void update_du_ue(gnb_du_id_t du_id_ = gnb_du_id_t::invalid, - pci_t pci_ = INVALID_PCI, - rnti_t c_rnti_ = rnti_t::INVALID_RNTI) override - { - if (du_id_ != gnb_du_id_t::invalid) { - ue_ctxt.du_id = du_id_; - } - - if (pci_ != INVALID_PCI) { - pci = pci_; - } - - if (c_rnti_ != rnti_t::INVALID_RNTI) { - ue_ctxt.crnti = c_rnti_; - } - } - - /// \brief Set the DU and PCell index of the UE. - /// \param[in] pcell_index PCell index of the UE. - void set_pcell_index(du_cell_index_t pcell_index_) override { pcell_index = pcell_index_; } - - /// \brief Set the RRC UE control message notifier of the UE. - /// \param[in] rrc_ue_notifier_ RRC UE control message notifier of the UE. - void set_rrc_ue_notifier(du_processor_rrc_ue_control_message_notifier& rrc_ue_notifier_) override - { - rrc_ue_notifier = &rrc_ue_notifier_; - } - - /// \brief Set the RRC UE SRB notifier of the UE. - /// \param[in] rrc_ue_srb_notifier_ RRC UE SRB control notifier of the UE. - void set_rrc_ue_srb_notifier(du_processor_rrc_ue_srb_control_notifier& rrc_ue_srb_notifier_) override - { - rrc_ue_srb_notifier = &rrc_ue_srb_notifier_; - } - - [[nodiscard]] bool du_ue_created() const { return ue_ctxt.du_idx != du_index_t::invalid; } - - // ngap_ue - - /// \brief Get the RRC UE PDU notifier of the UE. - ngap_rrc_ue_pdu_notifier& get_rrc_ue_pdu_notifier() override - { - srsran_assert(ngap_ue_context.has_value(), "ue={}: NGAP UE was not created", ue_index); - return ngap_ue_context.value().rrc_ue_pdu_notifier; - } - - /// \brief Get the RRC UE control notifier of the UE. - ngap_rrc_ue_control_notifier& get_rrc_ue_control_notifier() override - { - srsran_assert(ngap_ue_context.has_value(), "ue={}: NGAP UE was not created", ue_index); - return ngap_ue_context.value().rrc_ue_ctrl_notifier; - } - - /// \brief Add the context for the NGAP UE. - /// \param[in] rrc_ue_pdu_notifier The RRC UE PDU notifier for the UE. - /// \param[in] rrc_ue_ctrl_notifier The RRC UE ctrl notifier for the UE. - void add_ngap_ue_context(ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier, - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier) - { - ngap_ue_context.emplace(rrc_ue_pdu_notifier, rrc_ue_ctrl_notifier); - } - - bool ngap_ue_created() { return ngap_ue_context.has_value(); } - - // cu-cp ue - /// \brief Get the NGAP to RRC UE adapter of the UE. - ngap_rrc_ue_adapter& get_ngap_rrc_ue_adapter() { return ngap_rrc_ue_ev_notifier; } - - /// \brief Get the CU-CP to RRC UE adapter of the UE. - cu_cp_rrc_ue_adapter& get_cu_cp_rrc_ue_adapter() { return cu_cp_rrc_ue_ev_notifier; } - - /// \brief Get the RRC to CU-CP adapter of the UE. - rrc_ue_cu_cp_adapter& get_rrc_ue_cu_cp_adapter() { return rrc_ue_cu_cp_ev_notifier; } - - /// \brief Set/update the measurement context of the UE. - void update_meas_context(cell_meas_manager_ue_context meas_ctxt) { meas_context = std::move(meas_ctxt); } - - /// \brief Get the measurement context of the UE. - cell_meas_manager_ue_context& get_meas_context() { return meas_context; } - -private: - // common context - ue_index_t ue_index = ue_index_t::invalid; - ue_task_scheduler_impl task_sched; - security::security_context sec_context; - std::unique_ptr up_mng; - - // du ue context - cu_cp_ue_context ue_ctxt; - du_cell_index_t pcell_index = du_cell_index_t::invalid; - pci_t pci = INVALID_PCI; - - du_processor_rrc_ue_control_message_notifier* rrc_ue_notifier = nullptr; - du_processor_rrc_ue_srb_control_notifier* rrc_ue_srb_notifier = nullptr; - - // ngap ue context - std::optional ngap_ue_context; - - // cu-cp ue context - ngap_rrc_ue_adapter ngap_rrc_ue_ev_notifier; - cu_cp_rrc_ue_adapter cu_cp_rrc_ue_ev_notifier; - rrc_ue_cu_cp_adapter rrc_ue_cu_cp_ev_notifier; - cell_meas_manager_ue_context meas_context; -}; - -class ue_manager : public common_ue_manager, - public du_processor_ue_manager, - public ngap_ue_manager, - public ue_metrics_handler +class ue_manager : public ue_metrics_handler { public: explicit ue_manager(const ue_configuration& ue_config_, const up_resource_manager_cfg& up_config_, + const security_manager_config& sec_config_, timer_manager& timers, task_executor& cu_cp_exec); @@ -266,30 +71,31 @@ class ue_manager : public common_ue_manager, /// \brief Find the UE with the given UE index. /// \param[in] ue_index Index of the UE to be found. /// \return Pointer to the UE if found, nullptr otherwise. - common_ue* find_ue(ue_index_t ue_index) override; + cu_cp_ue* find_ue(ue_index_t ue_index); /// \brief Get the UE task scheduler of the specified UE, even if the DU UE context is not created. /// \param[in] ue_index Index of the UE. /// \return Pointer to the UE task scheduler if found, nullptr otherwise. - ue_task_scheduler* find_ue_task_scheduler(ue_index_t ue_index) override; + ue_task_scheduler* find_ue_task_scheduler(ue_index_t ue_index); - // du_processor_ue_manager + // du processor /// \brief Allocate resources for the UE in the CU-CP. /// \param[in] du_index Index of the DU the UE is connected to. /// \return ue_index of the created UE or ue_index_t::invalid in case of failure. - ue_index_t add_ue(du_index_t du_index) override; + ue_index_t add_ue(du_index_t du_index); - du_ue* set_ue_du_context(ue_index_t ue_index, gnb_du_id_t du_id, pci_t pci, rnti_t rnti) override; + /// \brief Set the DU context of the UE. + cu_cp_ue* set_ue_du_context(ue_index_t ue_index, gnb_du_id_t du_id, pci_t pci, rnti_t rnti); /// \brief Find the UE with the given UE index, thats DU context is set up. /// \param[in] ue_index Index of the UE to be found. /// \return Pointer to the DU UE if found, nullptr otherwise. - du_ue* find_du_ue(ue_index_t ue_index) override; + cu_cp_ue* find_du_ue(ue_index_t ue_index); /// \brief Get the number of UEs connected to a specific DU. /// \return Number of UEs. - size_t get_nof_du_ues(du_index_t du_index) override + size_t get_nof_du_ues(du_index_t du_index) { unsigned ue_count = 0; // Search allocated UE indexes @@ -302,36 +108,7 @@ class ue_manager : public common_ue_manager, return ue_count; } - // ngap_ue_manager - - /// \brief Add notifier to a UE for the given UE index. A RAN UE ID is allocated internally. If a new UE can't be - /// found or if a UE with the UE index was already setup, nulltpr is returned. - /// \param[in] ue_index Index of the UE to add the notifiers to. - /// \param[in] rrc_ue_pdu_notifier RRC UE PDU notifier for the UE. - /// \param[in] rrc_ue_ctrl_notifier RRC UE control notifier for the UE. - /// \return Pointer to the NGAP UE if found, nullptr otherwise. - ngap_ue* set_ue_ng_context(ue_index_t ue_index, - ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier_, - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier_) override; - - /// \brief Find the NGAP UE with the given UE index. - /// \param[in] ue_index Index of the UE to be found. - /// \return Pointer to the NGAP UE if found, nullptr otherwise. - ngap_ue* find_ngap_ue(ue_index_t ue_index) override; - - /// \brief Get the number of UEs connected to the AMF. - /// \return Number of UEs. - size_t get_nof_ngap_ues() override - { - unsigned ue_count = 0; - // Search allocated UE indexes - for (auto& ue : ues) { - if (ue.second.ngap_ue_created()) { - ue_count++; - } - } - return ue_count; - } + // ngap // cu-cp ue manager /// \brief Get the NGAP to RRC UE adapter of the UE. @@ -380,6 +157,7 @@ class ue_manager : public common_ue_manager, srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-UEMNG"); const ue_configuration ue_config; const up_resource_manager_cfg up_config; + const security_manager_config sec_config; // Manager of UE task schedulers. ue_task_scheduler_manager ue_task_scheds; diff --git a/lib/cu_cp/ue_security_manager/CMakeLists.txt b/lib/cu_cp/ue_security_manager/CMakeLists.txt new file mode 100644 index 0000000000..b09906aa31 --- /dev/null +++ b/lib/cu_cp/ue_security_manager/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Copyright 2021-2024 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +set(SOURCES + ue_security_manager_impl.cpp +) + +add_library(srsran_ue_security_manager STATIC ${SOURCES}) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/lib/cu_cp/ue_security_manager/ue_security_manager_impl.cpp b/lib/cu_cp/ue_security_manager/ue_security_manager_impl.cpp new file mode 100644 index 0000000000..6e856ae7b1 --- /dev/null +++ b/lib/cu_cp/ue_security_manager/ue_security_manager_impl.cpp @@ -0,0 +1,114 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "ue_security_manager_impl.h" + +using namespace srsran; +using namespace srs_cu_cp; + +ue_security_manager::ue_security_manager(const security_manager_config& cfg_) : + cfg(cfg_), logger(srslog::fetch_basic_logger("CU-CP")) +{ +} + +// up_ue_security_manager +bool ue_security_manager::is_security_context_initialized() const +{ + return sec_context.sel_algos.algos_selected; +} + +security::sec_as_config ue_security_manager::get_up_as_config() const +{ + return sec_context.get_as_config(security::sec_domain::up); +} + +security::sec_128_as_config ue_security_manager::get_up_128_as_config() const +{ + return sec_context.get_128_as_config(security::sec_domain::up); +} + +// ngap_ue_security_manager +bool ue_security_manager::init_security_context(security::security_context sec_ctxt) +{ + // Update the security context + sec_context = sec_ctxt; + + // Select security algorithms + logger.debug("Integrity protection algorithms preference list: {}", cfg.int_algo_pref_list); + logger.debug("Ciphering algorithms preference list: {}", cfg.enc_algo_pref_list); + logger.debug("Integrity protection algorithms supported list: {}", sec_context.supported_int_algos); + logger.debug("Ciphering algorithms preference list: {}", sec_context.supported_enc_algos); + if (not sec_context.select_algorithms(cfg.int_algo_pref_list, cfg.enc_algo_pref_list)) { + logger.error("Could not select security algorithm"); + return false; + } + logger.debug("Selected security algorithms integrity=NIA{} ciphering=NEA{}", + sec_context.sel_algos.integ_algo, + sec_context.sel_algos.cipher_algo); + + // Generate K_rrc_enc and K_rrc_int + sec_context.generate_as_keys(); + + return true; +} + +bool ue_security_manager::is_security_enabled() const +{ + return security_enabled; +} + +// rrc_ue_security_manager + +void ue_security_manager::enable_security() +{ + security_enabled = true; +} + +security::security_context ue_security_manager::get_security_context() const +{ + return sec_context; +} + +security::sec_selected_algos ue_security_manager::get_security_algos() const +{ + return sec_context.sel_algos; +} + +security::sec_as_config ue_security_manager::get_rrc_as_config() const +{ + return sec_context.get_as_config(security::sec_domain::rrc); +} + +security::sec_128_as_config ue_security_manager::get_rrc_128_as_config() const +{ + return sec_context.get_128_as_config(security::sec_domain::rrc); +} + +void ue_security_manager::update_security_context(security::security_context sec_ctxt) +{ + sec_context = sec_ctxt; +} + +void ue_security_manager::perform_horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn) +{ + sec_context.horizontal_key_derivation(target_pci, target_ssb_arfcn); +} \ No newline at end of file diff --git a/lib/cu_cp/ue_security_manager/ue_security_manager_impl.h b/lib/cu_cp/ue_security_manager/ue_security_manager_impl.h new file mode 100644 index 0000000000..c6aafb1625 --- /dev/null +++ b/lib/cu_cp/ue_security_manager/ue_security_manager_impl.h @@ -0,0 +1,63 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/cu_cp/security_manager_config.h" +#include + +namespace srsran::srs_cu_cp { + +/// UE security manager implementation +class ue_security_manager +{ +public: + ue_security_manager(const security_manager_config& cfg_); + ~ue_security_manager() = default; + + // up_ue_security_manager + [[nodiscard]] bool is_security_context_initialized() const; + [[nodiscard]] security::sec_as_config get_up_as_config() const; + [[nodiscard]] security::sec_128_as_config get_up_128_as_config() const; + + // ngap_ue_security_manager + bool init_security_context(security::security_context sec_ctxt); + [[nodiscard]] bool is_security_enabled() const; + + // rrc_ue_security_manager + void enable_security(); + [[nodiscard]] security::security_context get_security_context() const; + [[nodiscard]] security::sec_selected_algos get_security_algos() const; + [[nodiscard]] security::sec_as_config get_rrc_as_config() const; + [[nodiscard]] security::sec_128_as_config get_rrc_128_as_config() const; + void update_security_context(security::security_context sec_ctxt); + void perform_horizontal_key_derivation(pci_t target_pci, unsigned target_ssb_arfcn); + +private: + security_manager_config cfg; + security::security_context sec_context; + bool security_enabled = false; + + srslog::basic_logger& logger; +}; + +} // namespace srsran::srs_cu_cp diff --git a/lib/cu_cp/up_resource_manager/CMakeLists.txt b/lib/cu_cp/up_resource_manager/CMakeLists.txt index f3542bb25e..753fe576cd 100644 --- a/lib/cu_cp/up_resource_manager/CMakeLists.txt +++ b/lib/cu_cp/up_resource_manager/CMakeLists.txt @@ -19,7 +19,6 @@ # set(SOURCES - up_resource_manager_factory.cpp up_resource_manager_impl.cpp up_resource_manager_helpers.cpp ) diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h index 208e62d06e..5438cae351 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_helpers.h @@ -22,8 +22,8 @@ #pragma once +#include "up_resource_manager_impl.h" #include "srsran/cu_cp/cu_cp_types.h" // for SDAP config -#include "srsran/cu_cp/up_resource_manager.h" #include "srsran/pdcp/pdcp_config.h" namespace srsran { diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_impl.cpp b/lib/cu_cp/up_resource_manager/up_resource_manager_impl.cpp index ed1d8c2976..d91a24d24a 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_impl.cpp +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_impl.cpp @@ -27,41 +27,41 @@ using namespace srsran; using namespace srs_cu_cp; -up_resource_manager_impl::up_resource_manager_impl(const up_resource_manager_cfg& cfg_) : +up_resource_manager::up_resource_manager(const up_resource_manager_cfg& cfg_) : cfg(cfg_), logger(srslog::fetch_basic_logger("CU-CP")) { } -bool up_resource_manager_impl::validate_request( - const slotted_id_vector& setup_items) +bool up_resource_manager::validate_request( + const slotted_id_vector& setup_items) const { return is_valid(setup_items, context, cfg, logger); } -bool up_resource_manager_impl::validate_request(const cu_cp_pdu_session_resource_modify_request& pdu) +bool up_resource_manager::validate_request(const cu_cp_pdu_session_resource_modify_request& pdu) const { return is_valid(pdu, context, cfg, logger); } -bool up_resource_manager_impl::validate_request(const cu_cp_pdu_session_resource_release_command& pdu) +bool up_resource_manager::validate_request(const cu_cp_pdu_session_resource_release_command& pdu) const { return is_valid(pdu, context, cfg, logger); } -up_config_update up_resource_manager_impl::calculate_update( +up_config_update up_resource_manager::calculate_update( const slotted_id_vector& setup_items) { srsran_assert(is_valid(setup_items, context, cfg, logger), "Invalid PDU Session Resource Setup items."); return srsran::srs_cu_cp::calculate_update(setup_items, context, cfg, logger); } -up_config_update up_resource_manager_impl::calculate_update(const cu_cp_pdu_session_resource_modify_request& pdu) +up_config_update up_resource_manager::calculate_update(const cu_cp_pdu_session_resource_modify_request& pdu) { srsran_assert(is_valid(pdu, context, cfg, logger), "Invalid PDU Session Resource Modify request."); return srsran::srs_cu_cp::calculate_update(pdu, context, cfg, logger); } -up_config_update up_resource_manager_impl::calculate_update(const cu_cp_pdu_session_resource_release_command& pdu) +up_config_update up_resource_manager::calculate_update(const cu_cp_pdu_session_resource_release_command& pdu) { srsran_assert(is_valid(pdu, context, cfg, logger), "Invalid PDU Session Resource Release command."); return srsran::srs_cu_cp::calculate_update(pdu, context, cfg, logger); @@ -101,7 +101,7 @@ inline void apply_update_for_removed_drbs(up_pdu_session_context& pdu_sessi } } -bool up_resource_manager_impl::apply_config_update(const up_config_update_result& result) +bool up_resource_manager::apply_config_update(const up_config_update_result& result) { // Apply config update in an additive way. for (const auto& session : result.pdu_sessions_added_list) { @@ -148,18 +148,18 @@ bool up_resource_manager_impl::apply_config_update(const up_config_update_result return true; } -const up_pdu_session_context& up_resource_manager_impl::get_pdu_session_context(pdu_session_id_t psi) +const up_pdu_session_context& up_resource_manager::get_pdu_session_context(pdu_session_id_t psi) const { srsran_assert(context.pdu_sessions.find(psi) != context.pdu_sessions.end(), "{} not allocated", psi); return context.pdu_sessions.at(psi); } -bool up_resource_manager_impl::has_pdu_session(pdu_session_id_t pdu_session_id) +bool up_resource_manager::has_pdu_session(pdu_session_id_t pdu_session_id) const { return context.pdu_sessions.find(pdu_session_id) != context.pdu_sessions.end(); } -const up_drb_context& up_resource_manager_impl::get_drb_context(drb_id_t drb_id) +const up_drb_context& up_resource_manager::get_drb_context(drb_id_t drb_id) const { srsran_assert(context.drb_map.find(drb_id) != context.drb_map.end(), "{} not allocated", drb_id); const auto& psi = context.drb_map.at(drb_id); @@ -171,17 +171,17 @@ const up_drb_context& up_resource_manager_impl::get_drb_context(drb_id_t drb_id) return context.pdu_sessions.at(psi).drbs.at(drb_id); } -size_t up_resource_manager_impl::get_nof_drbs() +size_t up_resource_manager::get_nof_drbs() const { return context.drb_map.size(); } -size_t up_resource_manager_impl::get_nof_pdu_sessions() +size_t up_resource_manager::get_nof_pdu_sessions() const { return context.pdu_sessions.size(); } -size_t up_resource_manager_impl::get_nof_qos_flows(pdu_session_id_t psi) +size_t up_resource_manager::get_nof_qos_flows(pdu_session_id_t psi) const { size_t nof_qos_flows = 0; @@ -199,13 +199,13 @@ size_t up_resource_manager_impl::get_nof_qos_flows(pdu_session_id_t psi) return nof_qos_flows; } -size_t up_resource_manager_impl::get_total_nof_qos_flows() +size_t up_resource_manager::get_total_nof_qos_flows() const { // Return number of active QoS flows in all active sessions. return context.qos_flow_map.size(); } -std::vector up_resource_manager_impl::get_drbs() +std::vector up_resource_manager::get_drbs() const { std::vector drb_ids; for (const auto& drb : context.drb_map) { @@ -215,14 +215,15 @@ std::vector up_resource_manager_impl::get_drbs() return drb_ids; } -const std::map& up_resource_manager_impl::get_pdu_sessions_map() +const std::map& up_resource_manager::get_pdu_sessions_map() const { return context.pdu_sessions; } -std::vector up_resource_manager_impl::get_pdu_sessions() +std::vector up_resource_manager::get_pdu_sessions() const { std::vector pdu_session_ids; + pdu_session_ids.reserve(context.pdu_sessions.size()); for (const auto& session : context.pdu_sessions) { pdu_session_ids.push_back(session.first); } @@ -230,12 +231,12 @@ std::vector up_resource_manager_impl::get_pdu_sessions() return pdu_session_ids; } -up_context up_resource_manager_impl::get_up_context() +up_context up_resource_manager::get_up_context() const { return context; } -void up_resource_manager_impl::set_up_context(const up_context& ctx) +void up_resource_manager::set_up_context(const up_context& ctx) { context = ctx; } diff --git a/lib/cu_cp/up_resource_manager/up_resource_manager_impl.h b/lib/cu_cp/up_resource_manager/up_resource_manager_impl.h index 85c9dd12f6..afe6d83bb4 100644 --- a/lib/cu_cp/up_resource_manager/up_resource_manager_impl.h +++ b/lib/cu_cp/up_resource_manager/up_resource_manager_impl.h @@ -22,44 +22,82 @@ #pragma once -#include "srsran/cu_cp/up_resource_manager.h" +#include "srsran/cu_cp/up_context.h" #include namespace srsran { namespace srs_cu_cp { +/// \brief Update for a PDU session. +struct up_pdu_session_context_update { + up_pdu_session_context_update(pdu_session_id_t id_) : id(id_){}; + pdu_session_id_t id; + std::map drb_to_add; + std::vector drb_to_remove; +}; + +// Struct that contains all fields required to update the UP config based on an incoming +// PDU sessions resource setup request over NGAP. This config is then used to: +// * Initiate or modifiy the CU-UPs bearer context over E1AP +// * Modify the DU's UE context over F1AP +// * Modify the CU-UPs bearer context over E1AP (update TEIDs, etc) +// * Modify the UE's configuration over RRC signaling +// For PDU sessions to be setup the entire session context is included in the struct as this has been allocated by UP +// resource manager. For removal of PDU sessions or DRBs only the respective identifiers are included. +struct up_config_update { + bool initial_context_creation = true; // True if this is the first PDU session to be created. + std::map + pdu_sessions_to_setup_list; // List of PDU sessions to be added. + std::map + pdu_sessions_to_modify_list; // List of PDU sessions to be modified. + std::vector pdu_sessions_to_remove_list; // List of PDU sessions to be removed. + std::vector pdu_sessions_failed_to_modify_list; // List of PDU sessions that failed to be modified. + std::vector drb_to_remove_list; // List of DRBs to be removed. +}; + +// Response given back to the UP resource manager containing the full context +// that could be setup. +struct up_config_update_result { + std::vector pdu_sessions_added_list; // List of sessions that have been added. + std::vector pdu_sessions_modified_list; // List of sessions that have been modified. + std::vector pdu_sessions_removed_list; // List of sessions that have been removed. +}; + +/// \brief Free function to convert existing UP context into config update (useful to setup new UEs). +up_config_update to_config_update(const up_context& old_context); + /// UP resource manager implementation -class up_resource_manager_impl final : public up_resource_manager +class up_resource_manager { public: - up_resource_manager_impl(const up_resource_manager_cfg& cfg); - ~up_resource_manager_impl() = default; + up_resource_manager(const up_resource_manager_cfg& cfg); + ~up_resource_manager() = default; - bool - validate_request(const slotted_id_vector& setup_items) override; - bool validate_request(const cu_cp_pdu_session_resource_modify_request& pdu) override; - bool validate_request(const cu_cp_pdu_session_resource_release_command& pdu) override; + bool validate_request(const slotted_id_vector& setup_items) const; + bool validate_request(const cu_cp_pdu_session_resource_modify_request& pdu) const; + bool validate_request(const cu_cp_pdu_session_resource_release_command& pdu) const; up_config_update - calculate_update(const slotted_id_vector& setup_items) override; - up_config_update calculate_update(const cu_cp_pdu_session_resource_modify_request& pdu) override; - up_config_update calculate_update(const cu_cp_pdu_session_resource_release_command& pdu) override; - - bool apply_config_update(const up_config_update_result& config) override; - const up_pdu_session_context& get_pdu_session_context(pdu_session_id_t psi) override; - const up_drb_context& get_drb_context(drb_id_t drb_id) override; - bool has_pdu_session(pdu_session_id_t pdu_session_id) override; - size_t get_nof_drbs() override; - size_t get_nof_pdu_sessions() override; - size_t get_nof_qos_flows(pdu_session_id_t psi) override; - size_t get_total_nof_qos_flows() override; - std::vector get_pdu_sessions() override; - std::vector get_drbs() override; - up_context get_up_context() override; - void set_up_context(const up_context& ctx) override; - - const std::map& get_pdu_sessions_map() override; + calculate_update(const slotted_id_vector& setup_items); + up_config_update calculate_update(const cu_cp_pdu_session_resource_modify_request& pdu); + up_config_update calculate_update(const cu_cp_pdu_session_resource_release_command& pdu); + + bool apply_config_update(const up_config_update_result& config); + const up_pdu_session_context& get_pdu_session_context(pdu_session_id_t psi) const; + const up_drb_context& get_drb_context(drb_id_t drb_id) const; + bool has_pdu_session(pdu_session_id_t pdu_session_id) const; + size_t get_nof_drbs() const; + size_t get_nof_pdu_sessions() const; + size_t get_nof_qos_flows(pdu_session_id_t psi) const; + size_t get_total_nof_qos_flows() const; + std::vector get_pdu_sessions() const; + std::vector get_drbs() const; + + up_context get_up_context() const; + void set_up_context(const up_context& ctx); + + const std::map& get_pdu_sessions_map() const; private: bool valid_5qi(const five_qi_t five_qi); diff --git a/lib/du_high/du_high_impl.cpp b/lib/du_high/du_high_impl.cpp index 420ecd3c83..6b5d28067b 100644 --- a/lib/du_high/du_high_impl.cpp +++ b/lib/du_high/du_high_impl.cpp @@ -100,10 +100,10 @@ class du_high_slot_handler final : public mac_cell_slot_handler srslog::basic_logger& logger; }; -class scheduler_ue_metrics_null_notifier final : public scheduler_ue_metrics_notifier +class scheduler_ue_metrics_null_notifier final : public scheduler_metrics_notifier { public: - void report_metrics(span ue_metrics) override + void report_metrics(const scheduler_cell_metrics& metrics) override { // do nothing. } diff --git a/lib/du_high/du_high_impl.h b/lib/du_high/du_high_impl.h index 8560c1ce46..26b08eef9f 100644 --- a/lib/du_high/du_high_impl.h +++ b/lib/du_high/du_high_impl.h @@ -70,8 +70,8 @@ class du_high_impl final : public du_high // Connection between DU-high layers. std::unique_ptr adapters; - std::unique_ptr hub_metrics; - std::unique_ptr metrics_notifier; + std::unique_ptr hub_metrics; + std::unique_ptr metrics_notifier; // DU-high Layers. std::unique_ptr du_manager; diff --git a/lib/du_manager/du_ue/du_ue.h b/lib/du_manager/du_ue/du_ue.h index 204c35f48b..426bebe968 100644 --- a/lib/du_manager/du_ue/du_ue.h +++ b/lib/du_manager/du_ue/du_ue.h @@ -50,11 +50,11 @@ class du_ue_controller public: virtual ~du_ue_controller() = default; - /// \brief Disconnect the UE inter-layer notifiers. + /// \brief Stop all SRB and DRB traffic for a give UE. /// /// This method should be called as a first step in the deletion of a UE, to ensure traffic is not flowing through /// its bearers during the layer by layer UE context removal. - virtual async_task disconnect_notifiers() = 0; + virtual async_task handle_traffic_stop_request() = 0; /// \brief Stop DRB activity and the detection of RLF for this UE. /// @@ -62,6 +62,11 @@ class du_ue_controller /// state where it is ready to be deleted (e.g. pending SRB PDUs). virtual async_task handle_activity_stop_request() = 0; + /// \brief Stop activity/traffic for a subset of DRBs of a UE. + /// + /// This method can be called during a UE reconfiguration, when some DRBs are removed. + virtual async_task handle_drb_traffic_stop_request(span drbs_to_stop) = 0; + /// \brief Schedule task for a given UE. virtual void schedule_async_task(async_task task) = 0; diff --git a/lib/du_manager/du_ue/du_ue_controller_impl.cpp b/lib/du_manager/du_ue/du_ue_controller_impl.cpp index 3742abbbd7..7230058682 100644 --- a/lib/du_manager/du_ue/du_ue_controller_impl.cpp +++ b/lib/du_manager/du_ue/du_ue_controller_impl.cpp @@ -242,25 +242,13 @@ du_ue_controller_impl::du_ue_controller_impl(const du_ue_context& contex du_ue_controller_impl::~du_ue_controller_impl() {} -async_task du_ue_controller_impl::disconnect_notifiers() +async_task du_ue_controller_impl::handle_traffic_stop_request() { // > Disconnect RLF notifiers. rlf_handler->disconnect(); // > Disconnect bearers from within the UE execution context. - return execute_and_continue_on_blocking( - cfg.services.ue_execs.ctrl_executor(ue_index), cfg.services.du_mng_exec, [this]() { - // > Disconnect DRBs. - for (auto& drb_pair : bearers.drbs()) { - du_ue_drb& drb = *drb_pair.second; - drb.stop(); - } - - // > Disconnect SRBs. - for (du_ue_srb& srb : bearers.srbs()) { - srb.stop(); - } - }); + return create_stop_traffic_task(); } async_task du_ue_controller_impl::handle_activity_stop_request() @@ -269,14 +257,24 @@ async_task du_ue_controller_impl::handle_activity_stop_request() rlf_handler->disconnect(); // > Disconnect bearers from within the UE execution context. - return execute_and_continue_on_blocking( - cfg.services.ue_execs.ctrl_executor(ue_index), cfg.services.du_mng_exec, [this]() { - // > Disconnect DRBs. - for (auto& drb_pair : bearers.drbs()) { - du_ue_drb& drb = *drb_pair.second; - drb.stop(); - } - }); + return create_stop_drb_traffic_task(); +} + +async_task du_ue_controller_impl::handle_drb_traffic_stop_request(span drbs_to_stop) +{ + std::vector drbs(drbs_to_stop.begin(), drbs_to_stop.end()); + return run_in_ue_executor([this, drbs = std::move(drbs)]() { + auto& ue_drbs = bearers.drbs(); + for (drb_id_t drb_id : drbs) { + auto it = ue_drbs.find(drb_id); + if (it == ue_drbs.end()) { + logger.warning("ue={}: Failed to stop DRB {} activity. Cause: DRB not found", ue_index, drb_id); + continue; + } + it->second->stop(); + logger.debug("ue={}: DRB {} traffic was stopped", ue_index, drb_id); + } + }); } void du_ue_controller_impl::handle_rlf_detection(rlf_cause cause) @@ -291,19 +289,47 @@ void du_ue_controller_impl::handle_crnti_ce_detection() void du_ue_controller_impl::stop_drb_traffic() { - // > Disconnect DRBs. - logger.debug("ue={}: Stopping DRB traffic...", ue_index); - // Note: We use an async task rather than just an execute call, to ensure that this task is not dispatched after // the UE has already been deleted. - schedule_async_task(execute_and_continue_on_blocking( - cfg.services.ue_execs.ctrl_executor(ue_index), cfg.services.du_mng_exec, [this]() { - // > Disconnect DRBs. - for (auto& drb_pair : bearers.drbs()) { - du_ue_drb& drb = *drb_pair.second; - drb.stop(); - } - - logger.info("ue={}: DRB traffic stopped", ue_index); - })); + schedule_async_task(create_stop_drb_traffic_task()); +} + +async_task du_ue_controller_impl::create_stop_drb_traffic_task() +{ + logger.debug("ue={}: Stopping DRB traffic...", ue_index); + + return run_in_ue_executor([this]() { + // > Disconnect DRBs. + for (auto& drb_pair : bearers.drbs()) { + du_ue_drb& drb = *drb_pair.second; + drb.stop(); + } + logger.info("ue={}: DRB traffic stopped", ue_index); + }); +} + +async_task du_ue_controller_impl::create_stop_traffic_task() +{ + logger.debug("ue={}: Stopping SRB and DRB traffic...", ue_index); + + return run_in_ue_executor([this]() { + // > Disconnect DRBs. + for (auto& drb_pair : bearers.drbs()) { + du_ue_drb& drb = *drb_pair.second; + drb.stop(); + } + + // > Disconnect SRBs. + for (du_ue_srb& srb : bearers.srbs()) { + srb.stop(); + } + + logger.info("ue={}: SRB and DRB traffic stopped", ue_index); + }); +} + +async_task du_ue_controller_impl::run_in_ue_executor(unique_task task) +{ + return execute_and_continue_on_blocking( + cfg.services.ue_execs.ctrl_executor(ue_index), cfg.services.du_mng_exec, std::move(task)); } diff --git a/lib/du_manager/du_ue/du_ue_controller_impl.h b/lib/du_manager/du_ue/du_ue_controller_impl.h index f824ffb799..b0166b302a 100644 --- a/lib/du_manager/du_ue/du_ue_controller_impl.h +++ b/lib/du_manager/du_ue/du_ue_controller_impl.h @@ -37,16 +37,22 @@ class du_ue_controller_impl final : public du_ue ue_ran_resource_configurator ue_ran_res_); ~du_ue_controller_impl() override; - async_task disconnect_notifiers() override; + /// Launches a task to stop all the UE SRB and DRB traffic. + async_task handle_traffic_stop_request() override; + /// Launches a task to stop the UE DRB traffic due to inactivity. async_task handle_activity_stop_request() override; + /// Launches a task to stop the traffic for some UE DRBs. + async_task handle_drb_traffic_stop_request(span drbs_to_stop) override; + void schedule_async_task(async_task task) override { ue_db.schedule_async_task(ue_index, std::move(task)); } void handle_rlf_detection(rlf_cause cause) override; void handle_crnti_ce_detection() override; + /// Schedule a task to stop DRB traffic. void stop_drb_traffic() override; mac_ue_radio_link_notifier& get_mac_rlf_notifier() override { return *mac_rlf_notifier; } @@ -55,6 +61,11 @@ class du_ue_controller_impl final : public du_ue private: class rlf_state_machine; + async_task run_in_ue_executor(unique_task task); + + async_task create_stop_drb_traffic_task(); + async_task create_stop_traffic_task(); + du_ue_manager_repository& ue_db; const du_manager_params& cfg; srslog::basic_logger& logger = srslog::fetch_basic_logger("DU-MNG"); diff --git a/lib/du_manager/procedures/ue_configuration_procedure.cpp b/lib/du_manager/procedures/ue_configuration_procedure.cpp index 4ec6101d22..59ce98341c 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.cpp +++ b/lib/du_manager/procedures/ue_configuration_procedure.cpp @@ -62,7 +62,7 @@ void ue_configuration_procedure::operator()(coro_context Update DU UE bearers. - update_ue_context(); + CORO_AWAIT(update_ue_context()); // > Update MAC bearers. CORO_AWAIT_VALUE(mac_ue_reconfiguration_response mac_res, update_mac_mux_and_demux()); @@ -75,7 +75,7 @@ void ue_configuration_procedure::operator()(coro_context ue_configuration_procedure::update_ue_context() { // > Create DU UE SRB objects. for (srb_id_t srbid : request.srbs_to_setup) { @@ -183,11 +183,22 @@ void ue_configuration_procedure::update_ue_context() } ue->bearers.add_drb(std::move(drb)); } + + // Request traffic to stop for DRBs that are going to be removed. + return ue->handle_drb_traffic_stop_request(request.drbs_to_rem); } void ue_configuration_procedure::clear_old_ue_context() { - drbs_to_rem.clear(); + if (not drbs_to_rem.empty()) { + // Dispatch DRB context destruction to the respective UE executor. + task_executor& exec = du_params.services.ue_execs.ctrl_executor(ue->ue_index); + if (not exec.defer([drbs = std::move(drbs_to_rem)]() mutable { drbs.clear(); })) { + logger.warning("ue={}: Could not dispatch DRB removal task to UE executor. Destroying it the main DU manager " + "execution context", + ue->ue_index); + } + } } async_task ue_configuration_procedure::update_mac_mux_and_demux() diff --git a/lib/du_manager/procedures/ue_configuration_procedure.h b/lib/du_manager/procedures/ue_configuration_procedure.h index 41e4e95e1c..0585f3a946 100644 --- a/lib/du_manager/procedures/ue_configuration_procedure.h +++ b/lib/du_manager/procedures/ue_configuration_procedure.h @@ -43,8 +43,8 @@ class ue_configuration_procedure private: /// \brief Update DU UE bearers. This stage includes the creation/modification/removal of SRBs/DRBs, creation of RLC /// and F1-U bearers. - void update_ue_context(); - void clear_old_ue_context(); + async_task update_ue_context(); + void clear_old_ue_context(); /// \brief Update MAC MUX and DEMUX tables of the respective UE, given the newly added/modified/removed bearers. async_task update_mac_mux_and_demux(); diff --git a/lib/du_manager/procedures/ue_deletion_procedure.cpp b/lib/du_manager/procedures/ue_deletion_procedure.cpp index 466972015a..62a1b8d1ff 100644 --- a/lib/du_manager/procedures/ue_deletion_procedure.cpp +++ b/lib/du_manager/procedures/ue_deletion_procedure.cpp @@ -49,7 +49,7 @@ void ue_deletion_procedure::operator()(coro_context>& ctx) } // > Disconnect DRBs from F1-U and SRBs from F1-C to stop handling traffic in flight and delivery notifications. - CORO_AWAIT(disconnect_inter_layer_interfaces()); + CORO_AWAIT(stop_ue_bearer_traffic()); // > Remove UE from F1AP. du_params.f1ap.ue_mng.handle_ue_deletion_request(ue_index); @@ -77,11 +77,11 @@ async_task ue_deletion_procedure::launch_mac_ue_delete() return du_params.mac.ue_cfg.handle_ue_delete_request(mac_msg); } -async_task ue_deletion_procedure::disconnect_inter_layer_interfaces() +async_task ue_deletion_procedure::stop_ue_bearer_traffic() { // Note: If the DRB was not deleted on demand by the CU-CP via F1AP UE Context Modification Procedure, there is a // chance that the CU-UP will keep pushing new F1-U PDUs to the DU. To avoid dangling references during UE removal, // we start by first disconnecting the DRBs from the F1-U interface. - return ue->disconnect_notifiers(); + return ue->handle_traffic_stop_request(); } diff --git a/lib/du_manager/procedures/ue_deletion_procedure.h b/lib/du_manager/procedures/ue_deletion_procedure.h index 886e6ddb10..bcea5ce59e 100644 --- a/lib/du_manager/procedures/ue_deletion_procedure.h +++ b/lib/du_manager/procedures/ue_deletion_procedure.h @@ -46,7 +46,7 @@ class ue_deletion_procedure // Disconnects all the DRBs and SRBs associated with the UE. After the bearers have been disconnected, it is safe // to start the deletion of the associated bearer contexts. - async_task disconnect_inter_layer_interfaces(); + async_task stop_ue_bearer_traffic(); const du_ue_index_t ue_index; du_ue_manager_repository& ue_mng; diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_factory.cpp b/lib/e1ap/cu_cp/e1ap_cu_cp_factory.cpp index 925330ca16..8da195818c 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_factory.cpp +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_factory.cpp @@ -32,17 +32,11 @@ std::unique_ptr srsran::srs_cu_cp::create_e1ap(e1ap_message_notifier& e1ap_pdu_notifier_, e1ap_cu_up_processor_notifier& e1ap_cu_up_processor_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_, unsigned max_nof_supported_ues_) { - auto e1ap_cu_cp = std::make_unique(e1ap_pdu_notifier_, - e1ap_cu_up_processor_notifier_, - cu_cp_notifier_, - ue_mng_, - timers_, - ctrl_exec_, - max_nof_supported_ues_); + auto e1ap_cu_cp = std::make_unique( + e1ap_pdu_notifier_, e1ap_cu_up_processor_notifier_, cu_cp_notifier_, timers_, ctrl_exec_, max_nof_supported_ues_); return e1ap_cu_cp; } diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp index 7a5c0dbbe7..f2f2e40fb5 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.cpp @@ -24,8 +24,10 @@ #include "../common/e1ap_asn1_helpers.h" #include "../common/log_helpers.h" #include "e1ap_cu_cp_asn1_helpers.h" +#include "procedures/bearer_context_modification_procedure.h" +#include "procedures/bearer_context_release_procedure.h" +#include "procedures/bearer_context_setup_procedure.h" #include "srsran/asn1/e1ap/e1ap.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/ran/cause/e1ap_cause.h" using namespace srsran; @@ -37,7 +39,6 @@ using namespace srs_cu_cp; e1ap_cu_cp_impl::e1ap_cu_cp_impl(e1ap_message_notifier& e1ap_pdu_notifier_, e1ap_cu_up_processor_notifier& e1ap_cu_up_processor_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_, unsigned max_nof_supported_ues_) : @@ -45,7 +46,6 @@ e1ap_cu_cp_impl::e1ap_cu_cp_impl(e1ap_message_notifier& e1ap_pdu_notifie pdu_notifier(e1ap_message_notifier_with_logging(*this, e1ap_pdu_notifier_)), cu_up_processor_notifier(e1ap_cu_up_processor_notifier_), cu_cp_notifier(cu_cp_notifier_), - ue_mng(ue_mng_), ctrl_exec(ctrl_exec_), timers(timer_factory{timers_, ctrl_exec_}), ue_ctxt_list(timers, max_nof_supported_ues_, logger), @@ -235,12 +235,6 @@ void e1ap_cu_cp_impl::handle_bearer_context_inactivity_notification( // Get UE context e1ap_ue_context& ue_ctxt = ue_ctxt_list[int_to_gnb_cu_cp_ue_e1ap_id(msg->gnb_cu_cp_ue_e1ap_id)]; - auto* ue = ue_mng.find_ue(ue_ctxt.ue_ids.ue_index); - if (ue == nullptr) { - logger.warning("ue={}: Dropping InactivityNotification. UE does not exist", ue_ctxt.ue_ids.ue_index); - return; - } - cu_cp_inactivity_notification inactivity_notification; inactivity_notification.ue_index = ue_ctxt.ue_ids.ue_index; @@ -287,12 +281,14 @@ void e1ap_cu_cp_impl::handle_bearer_context_inactivity_notification( } // schedule forwarding of notification - ue->get_task_sched().schedule_async_task( - launch_async([this, inactivity_notification](coro_context>& ctx) { - CORO_BEGIN(ctx); - cu_cp_notifier.on_bearer_context_inactivity_notification_received(inactivity_notification); - CORO_RETURN(); - })); + if (!cu_cp_notifier.schedule_async_task( + ue_ctxt.ue_ids.ue_index, launch_async([this, inactivity_notification](coro_context>& ctx) { + CORO_BEGIN(ctx); + cu_cp_notifier.on_bearer_context_inactivity_notification_received(inactivity_notification); + CORO_RETURN(); + }))) { + logger.warning("ue={}: Dropping InactivityNotification. UE does not exist", ue_ctxt.ue_ids.ue_index); + } }; void e1ap_cu_cp_impl::handle_successful_outcome(const asn1::e1ap::successful_outcome_s& outcome) diff --git a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.h b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.h index e56ec7676c..7550a4983e 100644 --- a/lib/e1ap/cu_cp/e1ap_cu_cp_impl.h +++ b/lib/e1ap/cu_cp/e1ap_cu_cp_impl.h @@ -22,15 +22,10 @@ #pragma once -#include "procedures/bearer_context_modification_procedure.h" -#include "procedures/bearer_context_release_procedure.h" -#include "procedures/bearer_context_setup_procedure.h" #include "procedures/e1ap_transaction_manager.h" #include "ue_context/e1ap_cu_cp_ue_context.h" #include "srsran/asn1/e1ap/e1ap.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" -#include "srsran/ran/nr_cgi.h" #include "srsran/support/executors/task_executor.h" #include @@ -45,7 +40,6 @@ class e1ap_cu_cp_impl final : public e1ap_interface e1ap_cu_cp_impl(e1ap_message_notifier& e1ap_pdu_notifier_, e1ap_cu_up_processor_notifier& e1ap_cu_up_processor_notifier_, e1ap_cu_cp_notifier& cu_cp_notifier_, - common_ue_manager& ue_mng_, timer_manager& timers_, task_executor& ctrl_exec_, unsigned max_nof_supported_ues_); @@ -114,7 +108,6 @@ class e1ap_cu_cp_impl final : public e1ap_interface e1ap_message_notifier_with_logging pdu_notifier; e1ap_cu_up_processor_notifier& cu_up_processor_notifier; e1ap_cu_cp_notifier& cu_cp_notifier; - common_ue_manager& ue_mng; task_executor& ctrl_exec; timer_factory timers; diff --git a/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.cpp b/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.cpp index fe1f208492..8cd7b9c4de 100644 --- a/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.cpp +++ b/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.cpp @@ -22,6 +22,7 @@ #include "bearer_context_setup_procedure.h" #include "../e1ap_cu_cp_asn1_helpers.h" +#include "common/e1ap_asn1_utils.h" #include "cu_cp/ue_context/e1ap_bearer_transaction_manager.h" using namespace srsran; diff --git a/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.h b/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.h index 059d5e2a16..35b715cfd2 100644 --- a/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.h +++ b/lib/e1ap/cu_cp/procedures/bearer_context_setup_procedure.h @@ -24,9 +24,8 @@ #include "../e1ap_cu_cp_impl.h" #include "../ue_context/e1ap_cu_cp_ue_context.h" -#include "common/e1ap_asn1_utils.h" #include "srsran/asn1/e1ap/e1ap.h" -#include "srsran/e1ap/cu_cp/e1ap_cu_cp.h" +#include "srsran/e1ap/common/e1ap_message.h" #include "srsran/support/async/async_task.h" namespace srsran { diff --git a/lib/e2/common/e2_du_metrics_connector.cpp b/lib/e2/common/e2_du_metrics_connector.cpp index 03195b1c52..e7845c9408 100644 --- a/lib/e2/common/e2_du_metrics_connector.cpp +++ b/lib/e2/common/e2_du_metrics_connector.cpp @@ -29,9 +29,9 @@ e2_du_metrics_connector::e2_du_metrics_connector() ue_metrics_queue.resize(MAX_UE_METRICS); } -void e2_du_metrics_connector::report_metrics(span ue_metrics) +void e2_du_metrics_connector::report_metrics(const scheduler_cell_metrics& metrics) { - for (auto& ue_metric : ue_metrics) { + for (auto& ue_metric : metrics.ue_metrics) { if (ue_metrics_queue.size() == MAX_UE_METRICS) { ue_metrics_queue.pop_front(); } @@ -40,7 +40,7 @@ void e2_du_metrics_connector::report_metrics(span ue if (e2_meas_provider) { // Pass metrics to the E2 Measurement Provider. - e2_meas_provider->report_metrics(ue_metrics); + e2_meas_provider->report_metrics(metrics); } } diff --git a/lib/e2/common/e2ap_asn1_helpers.h b/lib/e2/common/e2ap_asn1_helpers.h index 2293112562..042427ee90 100644 --- a/lib/e2/common/e2ap_asn1_helpers.h +++ b/lib/e2/common/e2ap_asn1_helpers.h @@ -32,6 +32,7 @@ #include "srsran/e2/e2ap_configuration.h" #include "srsran/e2/e2sm/e2sm_manager.h" #include "srsran/ran/bcd_helpers.h" +#include "srsran/ran/gnb_du_id.h" #include "srsran/security/security.h" #include #include @@ -81,6 +82,11 @@ inline void fill_asn1_e2ap_setup_request(asn1::e2ap::e2setup_request_s& setup, uint32_t plmn_bcd = plmn_string_to_bcd(e2ap_config.plmn); gnb_id.global_gnb_id.plmn_id.from_number(plmn_bcd); + if (e2ap_config.gnb_du_id.has_value()) { + gnb_id.gnb_du_id_present = true; + gnb_id.gnb_du_id = gnb_du_id_to_int(e2ap_config.gnb_du_id.value()); + } + // RAN functions added if (e2ap_config.e2sm_kpm_enabled) { std::string ran_oid = e2sm_kpm_asn1_packer::oid; diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index e91267a9f8..76c96cf0f6 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -121,10 +121,10 @@ bool e2sm_kpm_du_meas_provider_impl::check_e2sm_kpm_metrics_definitions(span ue_metrics) +void e2sm_kpm_du_meas_provider_impl::report_metrics(const scheduler_cell_metrics& cell_metrics) { last_ue_metrics.clear(); - for (auto& ue_metric : ue_metrics) { + for (auto& ue_metric : cell_metrics.ue_metrics) { last_ue_metrics.push_back(ue_metric); } } @@ -300,7 +300,9 @@ bool e2sm_kpm_du_meas_provider_impl::get_cqi(const asn1::e2sm::label_info_list_l scheduler_ue_metrics ue_metrics = last_ue_metrics[0]; meas_record_item_c meas_record_item; - meas_record_item.set_integer() = (int)ue_metrics.cqi; + meas_record_item.set_integer() = ue_metrics.cqi_stats.get_nof_observations() > 0 + ? static_cast(std::roundf(ue_metrics.cqi_stats.get_mean())) + : 0; items.push_back(meas_record_item); meas_collected = true; diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h index 0bbc5f23b7..cdf6be044c 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h @@ -45,7 +45,7 @@ class e2sm_kpm_du_meas_provider_impl : public e2sm_kpm_meas_provider, public e2_ ~e2sm_kpm_du_meas_provider_impl() = default; /// scheduler_ue_metrics_notifier functions. - void report_metrics(span ue_metrics) override; + void report_metrics(const scheduler_cell_metrics& ue_metrics) override; void report_metrics(const rlc_metrics& metrics) override; /// e2sm_kpm_meas_provider functions. diff --git a/lib/fapi_adaptor/mac/messages/pucch.cpp b/lib/fapi_adaptor/mac/messages/pucch.cpp index 2be1df97a8..25ca08f73e 100644 --- a/lib/fapi_adaptor/mac/messages/pucch.cpp +++ b/lib/fapi_adaptor/mac/messages/pucch.cpp @@ -52,6 +52,28 @@ static unsigned convert_sr_bits_to_unsigned(sr_nof_bits value) return 0U; } +/// Fills the Format 0 parameters. +static void fill_format0_parameters(fapi::ul_pucch_pdu_builder& builder, const pucch_info& mac_pdu) +{ + // Hopping parameters. + const prb_interval& hop_prbs = mac_pdu.resources.second_hop_prbs; + const pucch_format_0& f0 = mac_pdu.format_0; + const bool intra_slot_freq_hop = hop_prbs.empty() ? false : true; + builder.set_hopping_information_parameters( + intra_slot_freq_hop, hop_prbs.start(), f0.group_hopping, f0.n_id_hopping, f0.initial_cyclic_shift); + + // Do not use pi/2 BPSK for UCI symbols. + static constexpr bool use_pi_to_bpsk = false; + // Format 0 does not support multi slot repetition. + pucch_repetition_tx_slot pucch_repetition = pucch_repetition_tx_slot::no_multi_slot; + builder.set_common_parameters(mac_pdu.format, pucch_repetition, use_pi_to_bpsk); + + // Format 0 does not support CSI. + static constexpr unsigned csi_part1_bit_length = 0U; + builder.set_bit_length_parameters( + convert_sr_bits_to_unsigned(f0.sr_bits), f0.harq_ack_nof_bits, csi_part1_bit_length); +} + /// Fills the Format 1 parameters. static void fill_format1_parameters(fapi::ul_pucch_pdu_builder& builder, const pucch_info& mac_pdu) { @@ -63,14 +85,14 @@ static void fill_format1_parameters(fapi::ul_pucch_pdu_builder& builder, const p intra_slot_freq_hop, hop_prbs.start(), f1.group_hopping, f1.n_id_hopping, f1.initial_cyclic_shift); // Do not use pi/2 BPSK for UCI symbols. - static const bool use_pi_to_bpsk = false; + static constexpr bool use_pi_to_bpsk = false; builder.set_common_parameters(mac_pdu.format, f1.slot_repetition, use_pi_to_bpsk); // Time domain occasion. builder.set_format1_parameters(f1.time_domain_occ); // Format 1 does not support CSI. - static const unsigned csi_part1_bit_length = 0U; + static constexpr unsigned csi_part1_bit_length = 0U; builder.set_bit_length_parameters( convert_sr_bits_to_unsigned(f1.sr_bits), f1.harq_ack_nof_bits, csi_part1_bit_length); } @@ -104,6 +126,8 @@ static void fill_format2_parameters(fapi::ul_pucch_pdu_builder& builder, const p static void fill_custom_parameters(fapi::ul_pucch_pdu_builder& builder, const pucch_info& mac_pdu) { switch (mac_pdu.format) { + case pucch_format::FORMAT_0: + fill_format0_parameters(builder, mac_pdu); case pucch_format::FORMAT_1: fill_format1_parameters(builder, mac_pdu); break; diff --git a/lib/fapi_adaptor/phy/messages/pucch.cpp b/lib/fapi_adaptor/phy/messages/pucch.cpp index c15773e718..54c323cbce 100644 --- a/lib/fapi_adaptor/phy/messages/pucch.cpp +++ b/lib/fapi_adaptor/phy/messages/pucch.cpp @@ -25,6 +25,36 @@ using namespace srsran; using namespace fapi_adaptor; +static void fill_format0_parameters(pucch_processor::format0_configuration& config, + const fapi::ul_pucch_pdu& fapi_pdu, + slot_point slot, + uint16_t num_rx_ant) +{ + config.slot = slot; + config.bwp_size_rb = fapi_pdu.bwp_size; + config.bwp_start_rb = fapi_pdu.bwp_start; + config.cp = fapi_pdu.cp; + config.starting_prb = fapi_pdu.prb_start; + if (fapi_pdu.intra_slot_frequency_hopping) { + config.second_hop_prb.emplace(fapi_pdu.second_hop_prb); + } + + config.n_id = fapi_pdu.nid_pucch_hopping; + config.nof_harq_ack = fapi_pdu.bit_len_harq; + config.sr_opportunity = fapi_pdu.sr_bit_len == 1U; + + // Fill the antenna port indices starting from 0. + config.ports.resize(num_rx_ant); + std::iota(config.ports.begin(), config.ports.end(), 0); + + config.initial_cyclic_shift = fapi_pdu.initial_cyclic_shift; + config.nof_symbols = fapi_pdu.nr_of_symbols; + config.start_symbol_index = fapi_pdu.start_symbol_index; + + // Fill PUCCH context for logging. + config.context = pucch_context(fapi_pdu.rnti); +} + static void fill_format1_parameters(pucch_processor::format1_configuration& config, const fapi::ul_pucch_pdu& fapi_pdu, slot_point slot, @@ -114,6 +144,9 @@ void srsran::fapi_adaptor::convert_pucch_fapi_to_phy(uplink_processor::pucch_pdu } switch (context.format) { + case pucch_format::FORMAT_0: + fill_format0_parameters(pdu.format0, fapi_pdu, slot_point(fapi_pdu.scs, sfn, slot), num_rx_ant); + break; case pucch_format::FORMAT_1: fill_format1_parameters(pdu.format1, fapi_pdu, slot_point(fapi_pdu.scs, sfn, slot), num_rx_ant); break; diff --git a/lib/ngap/ngap_factory.cpp b/lib/ngap/ngap_factory.cpp index e33f642719..9d7023b98f 100644 --- a/lib/ngap/ngap_factory.cpp +++ b/lib/ngap/ngap_factory.cpp @@ -32,17 +32,11 @@ std::unique_ptr srsran::srs_cu_cp::create_ngap(ngap_configuration& ngap_cfg_, ngap_cu_cp_notifier& cu_cp_ue_creation_notifier_, ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - ngap_ue_manager& ue_manager_, n2_connection_client& n2_gateway_handler_, timer_manager& timers_, task_executor& ctrl_exec_) { - auto ngap = std::make_unique(ngap_cfg_, - cu_cp_ue_creation_notifier_, - cu_cp_du_repository_notifier_, - ue_manager_, - n2_gateway_handler_, - timers_, - ctrl_exec_); + auto ngap = std::make_unique( + ngap_cfg_, cu_cp_ue_creation_notifier_, cu_cp_du_repository_notifier_, n2_gateway_handler_, timers_, ctrl_exec_); return ngap; } diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 9c8a6a8915..d55934fdba 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -47,7 +47,6 @@ using namespace srs_cu_cp; ngap_impl::ngap_impl(ngap_configuration& ngap_cfg_, ngap_cu_cp_notifier& cu_cp_notifier_, ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - ngap_ue_manager& ue_manager_, n2_connection_client& n2_gateway, timer_manager& timers_, task_executor& ctrl_exec_) : @@ -55,7 +54,6 @@ ngap_impl::ngap_impl(ngap_configuration& ngap_cfg_, ue_ctxt_list(logger), cu_cp_notifier(cu_cp_notifier_), cu_cp_du_repository_notifier(cu_cp_du_repository_notifier_), - ue_manager(ue_manager_), timers(timers_), ctrl_exec(ctrl_exec_), ev_mng(timer_factory{timers, ctrl_exec}), @@ -71,7 +69,9 @@ ngap_impl::ngap_impl(ngap_configuration& ngap_cfg_, // Note: For fwd declaration of member types, dtor cannot be trivial. ngap_impl::~ngap_impl() {} -bool ngap_impl::update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index) +bool ngap_impl::update_ue_index(ue_index_t new_ue_index, + ue_index_t old_ue_index, + ngap_cu_cp_ue_notifier& new_ue_notifier) { if (!ue_ctxt_list.contains(old_ue_index)) { logger.warning("Failed to transfer NGAP UE context from ue={} to ue={}. Old UE context does not exist", @@ -83,12 +83,13 @@ bool ngap_impl::update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index ue_ctxt_list[old_ue_index].logger.log_debug("Transferring NGAP UE context to ue={}", new_ue_index); // Notify CU-CP about creation of NGAP UE - if (!cu_cp_notifier.on_new_ngap_ue(new_ue_index)) { + ngap_cu_cp_ue_notifier* ue = cu_cp_notifier.on_new_ngap_ue(new_ue_index); + if (ue == nullptr) { logger.error("ue={}: Failed to transfer UE context", new_ue_index); return false; } - ue_ctxt_list.update_ue_index(new_ue_index, old_ue_index); + ue_ctxt_list.update_ue_index(new_ue_index, old_ue_index, new_ue_notifier); return true; } @@ -181,15 +182,8 @@ void ngap_impl::handle_initial_ue_message(const cu_cp_initial_ue_message& msg) } // Create UE context and store it - ue_ctxt_list.add_ue(msg.ue_index, ran_ue_id, timers, ctrl_exec); - - // Notify CU-CP about creation of NGAP UE - if (!cu_cp_notifier.on_new_ngap_ue(msg.ue_index)) { - logger.error("ue={}: Failed to create UE", msg.ue_index); - // Remove created UE context - ue_ctxt_list.remove_ue_context(msg.ue_index); - return; - } + ngap_cu_cp_ue_notifier* ue_notifier = cu_cp_notifier.on_new_ngap_ue(msg.ue_index); + ue_ctxt_list.add_ue(msg.ue_index, ran_ue_id, *ue_notifier, timers, ctrl_exec); ngap_ue_context& ue_ctxt = ue_ctxt_list[msg.ue_index]; @@ -224,7 +218,7 @@ void ngap_impl::handle_ul_nas_transport_message(const cu_cp_ul_nas_transport& ms ngap_ue_context& ue_ctxt = ue_ctxt_list[msg.ue_index]; - auto* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -254,7 +248,7 @@ void ngap_impl::handle_ul_nas_transport_message(const cu_cp_ul_nas_transport& ms fill_asn1_ul_nas_transport(ul_nas_transport_msg, msg); // Schedule transmission of UL NAS transport message to AMF - ue->get_task_sched().schedule_async_task(launch_async([this, ngap_msg](coro_context>& ctx) { + ue->schedule_async_task(launch_async([this, ngap_msg](coro_context>& ctx) { CORO_BEGIN(ctx); tx_pdu_notifier->on_new_message(ngap_msg); CORO_RETURN(); @@ -346,7 +340,7 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo return; } - auto* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -360,7 +354,7 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo } // start routine - ue->get_task_sched().schedule_async_task(launch_async( + ue->schedule_async_task(launch_async( msg->nas_pdu.copy(), ue->get_rrc_ue_pdu_notifier(), ue_ctxt.logger)); } @@ -385,7 +379,7 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont return; } - auto* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -424,14 +418,14 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont init_ctxt_setup_req.security_context.supported_enc_algos); // start routine - ue->get_task_sched().schedule_async_task( - launch_async(init_ctxt_setup_req, - ue_ctxt.ue_ids, - ue->get_rrc_ue_control_notifier(), - ue->get_rrc_ue_pdu_notifier(), - cu_cp_notifier, - *tx_pdu_notifier, - ue_ctxt.logger)); + ue->schedule_async_task(launch_async(init_ctxt_setup_req, + ue_ctxt.ue_ids, + ue->get_rrc_ue_control_notifier(), + ue->get_rrc_ue_pdu_notifier(), + cu_cp_notifier, + *ue, + *tx_pdu_notifier, + ue_ctxt.logger)); } void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_session_res_setup_request_s& request) @@ -455,7 +449,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ return; } - ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -465,7 +459,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ // Stop PDU session setup timer ue_ctxt.pdu_session_setup_timer.stop(); - if (!ue->get_rrc_ue_control_notifier().on_security_enabled()) { + if (!ue->is_security_enabled()) { ue_ctxt.logger.log_warning("Dropping PduSessionResourceSetupRequest. Security context does not exist"); send_error_indication(*tx_pdu_notifier, logger, ue_ctxt.ue_ids.ran_ue_id, ue_ctxt.ue_ids.amf_ue_id, {}); return; @@ -488,7 +482,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ msg.ue_aggregate_maximum_bit_rate_dl = ue_ctxt.aggregate_maximum_bit_rate_dl; // start routine - ue->get_task_sched().schedule_async_task(launch_async( + ue->schedule_async_task(launch_async( msg, request, ue_ctxt.ue_ids, ue->get_rrc_ue_pdu_notifier(), cu_cp_notifier, *tx_pdu_notifier, ue_ctxt.logger)); } @@ -523,7 +517,7 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu // Store last PDU session resource modify request ue_ctxt.last_pdu_session_resource_modify_request = asn1_request_pdu.copy(); - ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -544,14 +538,13 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu } // start routine - ue->get_task_sched().schedule_async_task( - launch_async(msg, - request, - ue_ctxt.ue_ids, - cu_cp_notifier, - *tx_pdu_notifier, - get_ngap_control_message_handler(), - ue_ctxt.logger)); + ue->schedule_async_task(launch_async(msg, + request, + ue_ctxt.ue_ids, + cu_cp_notifier, + *tx_pdu_notifier, + get_ngap_control_message_handler(), + ue_ctxt.logger)); } void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pdu_session_res_release_cmd_s& command) @@ -575,7 +568,7 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd return; } - ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -590,7 +583,7 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd fill_cu_cp_pdu_session_resource_release_command(msg, command); // start routine - ue->get_task_sched().schedule_async_task(launch_async( + ue->schedule_async_task(launch_async( msg, ue_ctxt.ue_ids, cu_cp_notifier, *tx_pdu_notifier, ue_ctxt.logger)); } @@ -653,7 +646,7 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r ue_ctxt_list.update_amf_ue_id(ran_ue_id, amf_ue_id); } - ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -668,7 +661,7 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r fill_cu_cp_ue_context_release_command(msg, cmd); // start routine - ue->get_task_sched().schedule_async_task(launch_async( + ue->schedule_async_task(launch_async( msg, ue_ctxt.ue_ids, stored_error_indications, cu_cp_notifier, *tx_pdu_notifier, ue_ctxt.logger)); } @@ -725,23 +718,28 @@ void ngap_impl::handle_handover_request(const asn1::ngap::ho_request_s& msg) return; } - auto* ue_task_sched = ue_manager.find_ue_task_scheduler(ho_request.ue_index); - srsran_assert(ue_task_sched != nullptr, - "ue={} amf_ue={}: UE for UE context doesn't exist", - ho_request.ue_index, - uint_to_amf_ue_id(msg->amf_ue_ngap_id)); - - // start handover routine - ue_task_sched->schedule_async_task( - launch_async(ho_request, - uint_to_amf_ue_id(msg->amf_ue_ngap_id), - ue_ctxt_list, - cu_cp_notifier, - cu_cp_du_repository_notifier, - *tx_pdu_notifier, - timers, - ctrl_exec, - logger)); + // Inititialize security context of target UE + if (!cu_cp_notifier.on_handover_request_received(ho_request.ue_index, ho_request.security_context)) { + logger.warning("Sending HandoverFailure. Couldn't initialize security context"); + tx_pdu_notifier->on_new_message(generate_handover_failure(msg->amf_ue_ngap_id)); + return; + } + + if (!cu_cp_notifier.schedule_async_task( + ho_request.ue_index, + launch_async(ho_request, + uint_to_amf_ue_id(msg->amf_ue_ngap_id), + ue_ctxt_list, + cu_cp_notifier, + cu_cp_du_repository_notifier, + *tx_pdu_notifier, + timers, + ctrl_exec, + logger))) { + logger.warning("Sending HandoverFailure. Couldn't schedule handover resource allocation procedure"); + tx_pdu_notifier->on_new_message(generate_handover_failure(msg->amf_ue_ngap_id)); + return; + } } void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) @@ -779,7 +777,7 @@ void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) ngap_ue_context& ue_ctxt = ue_ctxt_list[ue_index]; - ngap_ue* ue = ue_manager.find_ngap_ue(ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -789,7 +787,7 @@ void ngap_impl::handle_error_indication(const asn1::ngap::error_ind_s& msg) ue_ctxt.logger.log_info("Received ErrorIndication{}", msg_cause.empty() ? "" : ". Cause: " + msg_cause); // Request UE release - ue->get_task_sched().schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { + ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); CORO_AWAIT(handle_ue_context_release_request( cu_cp_ue_context_release_request{ue_index, {}, ngap_cause_radio_network_t::unspecified})); @@ -901,7 +899,7 @@ ngap_impl::handle_handover_preparation_request(const ngap_handover_preparation_r ngap_ue_context& ue_ctxt = ue_ctxt_list[msg.ue_index]; - ngap_ue* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -916,7 +914,6 @@ ngap_impl::handle_handover_preparation_request(const ngap_handover_preparation_r *tx_pdu_notifier, ue->get_rrc_ue_control_notifier(), cu_cp_notifier, - ue->get_up_resource_manager(), ev_mng, timer_factory{timers, ctrl_exec}, ue_ctxt.logger); @@ -960,18 +957,19 @@ void ngap_impl::remove_ue_context(ue_index_t ue_index) void ngap_impl::schedule_error_indication(ue_index_t ue_index, ngap_cause_t cause, std::optional amf_ue_id) { - ngap_ue* ue = ue_manager.find_ngap_ue(ue_index); + ngap_ue_context& ue_ctxt = ue_ctxt_list[ue_index]; + auto* ue = ue_ctxt.get_cu_cp_ue(); + srsran_assert(ue != nullptr, "ue={} amf_ue={}: UE for UE context doesn't exist", ue_index, amf_ue_id.has_value() ? "" : fmt::format("amf_ue={} ", amf_ue_id.value())); - ue->get_task_sched().schedule_async_task( - launch_async([this, ue_index, cause, amf_ue_id](coro_context>& ctx) { - CORO_BEGIN(ctx); - send_error_indication(*tx_pdu_notifier, logger, ue_ctxt_list[ue_index].ue_ids.ran_ue_id, amf_ue_id, cause); - CORO_RETURN(); - })); + ue->schedule_async_task(launch_async([this, ue_index, cause, amf_ue_id](coro_context>& ctx) { + CORO_BEGIN(ctx); + send_error_indication(*tx_pdu_notifier, logger, ue_ctxt_list[ue_index].ue_ids.ran_ue_id, amf_ue_id, cause); + CORO_RETURN(); + })); } void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) @@ -979,7 +977,7 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) if (ue_ctxt_list.contains(ue_index)) { ngap_ue_context& ue_ctxt = ue_ctxt_list[ue_index]; - auto* ue = ue_manager.find_ngap_ue(ue_ctxt.ue_ids.ue_index); + auto* ue = ue_ctxt.get_cu_cp_ue(); srsran_assert(ue != nullptr, "ue={} ran_ue={} amf_ue={}: UE for UE context doesn't exist", ue_ctxt.ue_ids.ue_index, @@ -991,7 +989,7 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) ue_ctxt.logger.log_warning("PDU session setup timer expired after {}ms. Releasing UE from DU", ue_ctxt.pdu_session_setup_timer.duration().count()); - ue->get_task_sched().schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { + ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); CORO_AWAIT( cu_cp_notifier.on_new_ue_context_release_command({ue_index, ngap_cause_radio_network_t::unspecified})); @@ -1002,7 +1000,7 @@ void ngap_impl::on_pdu_session_setup_timer_expired(ue_index_t ue_index) ue_ctxt.pdu_session_setup_timer.duration().count()); // Request UE release - ue->get_task_sched().schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { + ue->schedule_async_task(launch_async([this, ue_index](coro_context>& ctx) { CORO_BEGIN(ctx); CORO_AWAIT(handle_ue_context_release_request( cu_cp_ue_context_release_request{ue_index, {}, ngap_cause_radio_network_t::unspecified})); diff --git a/lib/ngap/ngap_impl.h b/lib/ngap/ngap_impl.h index 5c9c28a303..1c8370d083 100644 --- a/lib/ngap/ngap_impl.h +++ b/lib/ngap/ngap_impl.h @@ -28,7 +28,6 @@ #include "procedures/ngap_transaction_manager.h" #include "ue_context/ngap_ue_context.h" #include "srsran/asn1/ngap/ngap.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/ngap/gateways/n2_connection_client.h" #include "srsran/ngap/ngap.h" #include "srsran/ngap/ngap_configuration.h" @@ -45,13 +44,13 @@ class ngap_impl final : public ngap_interface ngap_impl(ngap_configuration& ngap_cfg_, ngap_cu_cp_notifier& cu_cp_notifier_, ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier_, - ngap_ue_manager& ue_manager_, n2_connection_client& n2_gateway, timer_manager& timers_, task_executor& ctrl_exec_); ~ngap_impl(); - bool update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index) override; + bool + update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index, ngap_cu_cp_ue_notifier& new_ue_notifier) override; // ngap connection manager functions bool handle_amf_tnl_connection_request() override; @@ -178,7 +177,6 @@ class ngap_impl final : public ngap_interface ngap_cu_cp_notifier& cu_cp_notifier; ngap_cu_cp_du_repository_notifier& cu_cp_du_repository_notifier; - ngap_ue_manager& ue_manager; timer_manager& timers; task_executor& ctrl_exec; diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp index 399d929a39..3f32958a1e 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.cpp @@ -36,7 +36,6 @@ ngap_handover_preparation_procedure::ngap_handover_preparation_procedure( ngap_message_notifier& amf_notifier_, ngap_rrc_ue_control_notifier& rrc_ue_notifier_, ngap_cu_cp_notifier& cu_cp_notifier_, - up_resource_manager& up_manager_, ngap_transaction_manager& ev_mng_, timer_factory timers, ngap_ue_logger& logger_) : @@ -46,7 +45,6 @@ ngap_handover_preparation_procedure::ngap_handover_preparation_procedure( amf_notifier(amf_notifier_), rrc_ue_notifier(rrc_ue_notifier_), cu_cp_notifier(cu_cp_notifier_), - up_manager(up_manager_), ev_mng(ev_mng_), logger(logger_), tng_reloc_prep_timer(timers.create_timer()) @@ -105,18 +103,7 @@ void ngap_handover_preparation_procedure::operator()(coro_context& pdu_sessions = up_manager.get_pdu_sessions_map(); - // create a map of all PDU sessions and their associated QoS flows - for (const auto& pdu_session : pdu_sessions) { - std::vector qos_flows; - for (const auto& drb : pdu_session.second.drbs) { - for (const auto& qos_flow : drb.second.qos_flows) { - qos_flows.push_back(qos_flow.first); - } - } - ho_ue_context.pdu_sessions.insert({pdu_session.first, qos_flows}); - } + ho_ue_context.pdu_sessions = request.pdu_sessions; ho_ue_context.rrc_container = rrc_ue_notifier.on_handover_preparation_message_required(); } diff --git a/lib/ngap/procedures/ngap_handover_preparation_procedure.h b/lib/ngap/procedures/ngap_handover_preparation_procedure.h index 906326493f..b57cc9e808 100644 --- a/lib/ngap/procedures/ngap_handover_preparation_procedure.h +++ b/lib/ngap/procedures/ngap_handover_preparation_procedure.h @@ -25,7 +25,6 @@ #include "../ngap_context.h" #include "../ue_context/ngap_ue_context.h" #include "ngap_transaction_manager.h" -#include "srsran/cu_cp/ue_manager.h" #include "srsran/ngap/ngap.h" #include "srsran/support/async/async_task.h" @@ -41,7 +40,6 @@ class ngap_handover_preparation_procedure ngap_message_notifier& amf_notifier_, ngap_rrc_ue_control_notifier& rrc_ue_notifier_, ngap_cu_cp_notifier& cu_cp_notifier_, - up_resource_manager& up_manager_, ngap_transaction_manager& ev_mng_, timer_factory timers, ngap_ue_logger& logger_); @@ -57,7 +55,6 @@ class ngap_handover_preparation_procedure ngap_message_notifier& amf_notifier; ngap_rrc_ue_control_notifier& rrc_ue_notifier; ngap_cu_cp_notifier& cu_cp_notifier; - up_resource_manager& up_manager; ngap_transaction_manager& ev_mng; ngap_ue_logger& logger; diff --git a/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp b/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp index 432dba01a2..ad700ad67b 100644 --- a/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp +++ b/lib/ngap/procedures/ngap_handover_resource_allocation_procedure.cpp @@ -93,17 +93,18 @@ bool ngap_handover_resource_allocation_procedure::create_ngap_ue(ue_index_t ue_i return false; } - // Create UE context and store it - ue_ctxt_list.add_ue(ue_index, ran_ue_id, timers, task_exec); - // Notify CU-CP about creation of NGAP UE - if (!cu_cp_ue_creation_notifier.on_new_ngap_ue(ue_index)) { + ngap_cu_cp_ue_notifier* ue_notifier = cu_cp_ue_creation_notifier.on_new_ngap_ue(ue_index); + if (ue_notifier == nullptr) { logger.error("ue={}: Failed to create UE", ue_index); // Remove created UE context ue_ctxt_list.remove_ue_context(ue_index); return false; } + // Create UE context and store it + ue_ctxt_list.add_ue(ue_index, ran_ue_id, *ue_notifier, timers, task_exec); + ue_ctxt_list[ue_index].logger.log_debug("Created UE"); return true; diff --git a/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp b/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp index a4749794c6..3d131b4313 100644 --- a/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp +++ b/lib/ngap/procedures/ngap_initial_context_setup_procedure.cpp @@ -38,6 +38,7 @@ ngap_initial_context_setup_procedure::ngap_initial_context_setup_procedure( ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier_, ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier_, ngap_cu_cp_notifier& cu_cp_notifier_, + ngap_cu_cp_ue_notifier& cu_cp_ue_notifier_, ngap_message_notifier& amf_notifier_, ngap_ue_logger& logger_) : request(request_), @@ -45,6 +46,7 @@ ngap_initial_context_setup_procedure::ngap_initial_context_setup_procedure( rrc_ue_ctrl_notifier(rrc_ue_ctrl_notifier_), rrc_ue_pdu_notifier(rrc_ue_pdu_notifier_), cu_cp_notifier(cu_cp_notifier_), + cu_cp_ue_notifier(cu_cp_ue_notifier_), amf_notifier(amf_notifier_), logger(logger_) { @@ -57,7 +59,29 @@ void ngap_initial_context_setup_procedure::operator()(coro_context @@ -37,19 +38,26 @@ struct ngap_ue_ids { }; struct ngap_ue_context { - ngap_ue_ids ue_ids; - uint64_t aggregate_maximum_bit_rate_dl = 0; - unique_timer pdu_session_setup_timer = {}; - bool release_requested = false; - bool release_scheduled = false; + ngap_ue_ids ue_ids; + ngap_cu_cp_ue_notifier* ue = nullptr; + uint64_t aggregate_maximum_bit_rate_dl = 0; + unique_timer pdu_session_setup_timer = {}; + bool release_requested = false; + bool release_scheduled = false; byte_buffer last_pdu_session_resource_modify_request; // To check if a received modify request is a duplicate ngap_ue_logger logger; - ngap_ue_context(ue_index_t ue_index_, ran_ue_id_t ran_ue_id_, timer_manager& timers_, task_executor& task_exec_) : - ue_ids({ue_index_, ran_ue_id_}), logger("NGAP", {ue_index_, ran_ue_id_}) + ngap_ue_context(ue_index_t ue_index_, + ran_ue_id_t ran_ue_id_, + ngap_cu_cp_ue_notifier& ue_notifier_, + timer_manager& timers_, + task_executor& task_exec_) : + ue_ids({ue_index_, ran_ue_id_}), ue(&ue_notifier_), logger("NGAP", {ue_index_, ran_ue_id_}) { pdu_session_setup_timer = timers_.create_unique_timer(task_exec_); } + + [[nodiscard]] ngap_cu_cp_ue_notifier* get_cu_cp_ue() const { return ue; } }; class ngap_ue_context_list @@ -134,7 +142,11 @@ class ngap_ue_context_list return &it->second; } - ngap_ue_context& add_ue(ue_index_t ue_index, ran_ue_id_t ran_ue_id, timer_manager& timers, task_executor& task_exec) + ngap_ue_context& add_ue(ue_index_t ue_index, + ran_ue_id_t ran_ue_id, + ngap_cu_cp_ue_notifier& ue_notifier, + timer_manager& timers, + task_executor& task_exec) { srsran_assert(ue_index != ue_index_t::invalid, "Invalid ue_index={}", ue_index); srsran_assert(ran_ue_id != ran_ue_id_t::invalid, "Invalid ran_ue={}", ran_ue_id); @@ -142,7 +154,7 @@ class ngap_ue_context_list logger.debug("ue={} ran_ue={}: NGAP UE context created", ue_index, ran_ue_id); ues.emplace(std::piecewise_construct, std::forward_as_tuple(ran_ue_id), - std::forward_as_tuple(ue_index, ran_ue_id, timers, task_exec)); + std::forward_as_tuple(ue_index, ran_ue_id, ue_notifier, timers, task_exec)); ue_index_to_ran_ue_id.emplace(ue_index, ran_ue_id); return ues.at(ran_ue_id); } @@ -175,7 +187,7 @@ class ngap_ue_context_list ue.logger.set_prefix({ue.ue_ids.ue_index, ran_ue_id, amf_ue_id}); } - void update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index) + void update_ue_index(ue_index_t new_ue_index, ue_index_t old_ue_index, ngap_cu_cp_ue_notifier& new_ue_notifier) { srsran_assert(new_ue_index != ue_index_t::invalid, "Invalid new_ue_index={}", new_ue_index); srsran_assert(old_ue_index != ue_index_t::invalid, "Invalid old_ue_index={}", old_ue_index); @@ -189,6 +201,7 @@ class ngap_ue_context_list // Update UE context ues.at(ran_ue_id).ue_ids.ue_index = new_ue_index; + ues.at(ran_ue_id).ue = &new_ue_notifier; // Update lookups ue_index_to_ran_ue_id.emplace(new_ue_index, ran_ue_id); diff --git a/lib/ofh/compression/packing_utils_neon.h b/lib/ofh/compression/packing_utils_neon.h index df1857d6ba..1ea1e75d37 100644 --- a/lib/ofh/compression/packing_utils_neon.h +++ b/lib/ofh/compression/packing_utils_neon.h @@ -111,8 +111,10 @@ inline void pack_prb_9b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) /// \note Each of the input registers stores four unique REs. inline void pack_prb_16b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) { - /// Number of bytes used by 1 packed PRB with IQ samples compressed to 9 bits. + /// Number of bytes used by 1 packed PRB with IQ samples compressed to 16 bits. static constexpr unsigned BYTES_PER_PRB_16BIT_COMPRESSION = 48; + static constexpr unsigned NEON_REG_SIZE_BYTES = 16; + static const uint8x16_t shuffle_mask_u8 = vcombine_u8(vcreate_u8(0x0607040502030001), vcreate_u8(0x0e0f0c0d0a0b0809)); int8x16x3_t regs_shuffled_s16; @@ -121,7 +123,9 @@ inline void pack_prb_16b_big_endian(compressed_prb& c_prb, int16x8x3_t regs) regs_shuffled_s16.val[2] = vqtbl1q_s8(vreinterpretq_s8_s16(regs.val[2]), shuffle_mask_u8); int8_t* data = reinterpret_cast(c_prb.get_byte_buffer().data()); - vst1q_s8_x3(data, regs_shuffled_s16); + vst1q_s8(data, regs_shuffled_s16.val[0]); + vst1q_s8(data + NEON_REG_SIZE_BYTES, regs_shuffled_s16.val[1]); + vst1q_s8(data + NEON_REG_SIZE_BYTES * 2, regs_shuffled_s16.val[2]); c_prb.set_stored_size(BYTES_PER_PRB_16BIT_COMPRESSION); } diff --git a/lib/ofh/transmitter/CMakeLists.txt b/lib/ofh/transmitter/CMakeLists.txt index 6ac8cb5401..c8cd78f707 100644 --- a/lib/ofh/transmitter/CMakeLists.txt +++ b/lib/ofh/transmitter/CMakeLists.txt @@ -35,4 +35,5 @@ add_library(srsran_ofh_transmitter STATIC ${SOURCES}) target_link_libraries(srsran_ofh_transmitter srsran_ran srsran_instrumentation - srslog) + srslog + srsvec) diff --git a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp index 0a77068521..75177cbcdc 100644 --- a/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp +++ b/lib/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl.cpp @@ -25,6 +25,7 @@ #include "scoped_frame_buffer.h" #include "srsran/phy/support/resource_grid_context.h" #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/srsvec/conversion.h" #include using namespace srsran; @@ -105,8 +106,9 @@ void data_flow_uplane_downlink_data_impl::enqueue_section_type_1_message_symbol_ const resource_grid_reader& grid) { // Temporary buffer used to store IQ data when the RU operating bandwidth is not the same to the cell bandwidth. + // TODO: cf_t constructor initializes with 0s. std::array temp_buffer; - if (SRSRAN_UNLIKELY(ru_nof_prbs != grid.get_nof_subc())) { + if (SRSRAN_UNLIKELY(ru_nof_prbs * NOF_SUBCARRIERS_PER_RB != grid.get_nof_subc())) { // Zero out the elements that won't be filled after reading the resource grid. std::fill(temp_buffer.begin() + grid.get_nof_subc(), temp_buffer.end(), 0); } @@ -133,8 +135,13 @@ void data_flow_uplane_downlink_data_impl::enqueue_section_type_1_message_symbol_ ofh_tracer << trace_event("ofh_uplane_pool_access", pool_access_tp); span iq_data; - if (SRSRAN_LIKELY(ru_nof_prbs == grid.get_nof_subc())) { - iq_data = grid.get_view(context.port, symbol_id); + if (SRSRAN_LIKELY(ru_nof_prbs * NOF_SUBCARRIERS_PER_RB == grid.get_nof_subc())) { + span iq_data_cbf16 = grid.get_view(context.port, symbol_id); + + // TODO: Convert compressor to cbf16_t. + span temp_iq_data(temp_buffer.data(), ru_nof_prbs * NOF_SUBCARRIERS_PER_RB); + srsvec::convert(temp_iq_data, iq_data_cbf16); + iq_data = temp_iq_data; } else { span temp_iq_data(temp_buffer.data(), ru_nof_prbs * NOF_SUBCARRIERS_PER_RB); grid.get(temp_iq_data.first(grid.get_nof_subc()), context.port, symbol_id, 0); diff --git a/lib/phy/support/resource_grid_impl.h b/lib/phy/support/resource_grid_impl.h index 17756fc71f..380a04b46a 100644 --- a/lib/phy/support/resource_grid_impl.h +++ b/lib/phy/support/resource_grid_impl.h @@ -38,16 +38,17 @@ class resource_grid_mapper; class resource_grid_impl : public resource_grid { private: - std::atomic empty = {}; - unsigned nof_ports; - unsigned nof_symb; - unsigned nof_subc; + std::array temp; + std::atomic empty = {}; + unsigned nof_ports; + unsigned nof_symb; + unsigned nof_subc; /// \brief Stores the resource grid data. /// /// The resource grid buffer is a three-dimensional array with the dimensions representing, in order, subcarriers, /// OFDM symbols and antenna ports. - dynamic_tensor(resource_grid_dimensions::all), cf_t, resource_grid_dimensions> rg_buffer; + dynamic_tensor(resource_grid_dimensions::all), cbf16_t, resource_grid_dimensions> rg_buffer; /// Resource grid writer implementation. resource_grid_writer_impl writer; diff --git a/lib/phy/support/resource_grid_reader_impl.cpp b/lib/phy/support/resource_grid_reader_impl.cpp index 30db24f906..6103449150 100644 --- a/lib/phy/support/resource_grid_reader_impl.cpp +++ b/lib/phy/support/resource_grid_reader_impl.cpp @@ -21,6 +21,7 @@ */ #include "resource_grid_reader_impl.h" +#include "srsran/srsvec/conversion.h" #include "srsran/srsvec/copy.h" using namespace srsran; @@ -78,7 +79,56 @@ span resource_grid_reader_impl::get(span sy get_nof_ports()); // Get view of the OFDM symbol subcarriers. - span symb = data.get_view({l, port}).subspan(k_init, mask.size()); + span symb = data.get_view({l, port}).subspan(k_init, mask.size()); + + srsran_assert(mask.count() <= symbols.size(), + "The number ones in the mask (i.e., {}) exceeds the number of symbols (i.e., {}).", + mask.count(), + symbols.size()); + + unsigned mask_count = mask.count(); + srsran_assert(mask_count <= symbols.size(), + "The number of active subcarriers (i.e., {}) exceeds the number of symbols (i.e., {}).", + mask_count, + symbols.size()); + + // Do a straight copy if the elements of the mask are all contiguous. + if (mask_count and mask.is_contiguous()) { + srsvec::convert(symbols.first(mask_count), symb.subspan(mask.find_lowest(), mask_count)); + return symbols.last(symbols.size() - mask_count); + } + + mask.for_each(0, mask.size(), [symb, &symbols](unsigned i_subc) { + symbols.front() = to_cf(symb[i_subc]); + symbols = symbols.last(symbols.size() - 1); + }); + + return symbols; +} + +span resource_grid_reader_impl::get(span symbols, + unsigned port, + unsigned l, + unsigned k_init, + const bounded_bitset& mask) const +{ + srsran_assert(k_init + mask.size() <= get_nof_subc(), + "The initial subcarrier index (i.e., {}) plus the mask size (i.e., {}) exceeds the maximum number of " + "subcarriers (i.e., {})", + k_init, + mask.size(), + get_nof_subc()); + srsran_assert(l < get_nof_symbols(), + "Symbol index (i.e., {}) exceeds the maximum number of symbols (i.e., {})", + l, + get_nof_symbols()); + srsran_assert(port < get_nof_ports(), + "Port index (i.e., {}) exceeds the maximum number of ports (i.e., {})", + port, + get_nof_ports()); + + // Get view of the OFDM symbol subcarriers. + span symb = data.get_view({l, port}).subspan(k_init, mask.size()); srsran_assert(mask.count() <= symbols.size(), "The number ones in mask {} exceeds the number of symbols {}.", @@ -129,21 +179,46 @@ void resource_grid_reader_impl::get(span symbols, get_nof_ports()); // Access the OFDM symbol from the resource grid. - span rg_symbol = data.get_view({l, port}); + span rg_symbol = data.get_view({l, port}); // Copy resource elements. if (stride == 1) { - srsvec::copy(symbols, rg_symbol.subspan(k_init, symbols.size())); + srsvec::convert(symbols, rg_symbol.subspan(k_init, symbols.size())); } else { std::generate(symbols.begin(), symbols.end(), [&rg_symbol, stride, n = k_init]() mutable { - cf_t temp = rg_symbol[n]; + cf_t temp = to_cf(rg_symbol[n]); n += stride; return temp; }); } } -span resource_grid_reader_impl::get_view(unsigned port, unsigned l) const +void resource_grid_reader_impl::get(span symbols, unsigned port, unsigned l, unsigned k_init) const +{ + srsran_assert( + k_init + symbols.size() <= get_nof_subc(), + "The initial subcarrier index (i.e., {}) plus the number of symbols (i.e., {}) exceeds the maximum number of " + "subcarriers (i.e., {})", + k_init, + symbols.size(), + get_nof_subc()); + srsran_assert(l < get_nof_symbols(), + "Symbol index (i.e., {}) exceeds the maximum number of symbols (i.e., {})", + l, + get_nof_symbols()); + srsran_assert(port < get_nof_ports(), + "Port index (i.e., {}) exceeds the maximum number of ports (i.e., {})", + port, + get_nof_ports()); + + // Access the OFDM symbol from the resource grid. + span rg_symbol = data.get_view({l, port}); + + // Copy resource elements. + srsvec::copy(symbols, rg_symbol.subspan(k_init, symbols.size())); +} + +span resource_grid_reader_impl::get_view(unsigned port, unsigned l) const { srsran_assert(l < get_nof_symbols(), "Symbol index (i.e., {}) exceeds the maximum number of symbols (i.e., {})", diff --git a/lib/phy/support/resource_grid_reader_impl.h b/lib/phy/support/resource_grid_reader_impl.h index dca8cbe380..45f4dd5fbf 100644 --- a/lib/phy/support/resource_grid_reader_impl.h +++ b/lib/phy/support/resource_grid_reader_impl.h @@ -30,7 +30,7 @@ namespace srsran { class resource_grid_reader_impl : public resource_grid_reader { public: - using storage_type = tensor(resource_grid_dimensions::all), cf_t, resource_grid_dimensions>; + using storage_type = tensor(resource_grid_dimensions::all), cbf16_t, resource_grid_dimensions>; /// Constructs a resource grid reader implementation from a tensor. resource_grid_reader_impl(const storage_type& data_, const std::atomic& empty_) : data(data_), empty(empty_) @@ -59,11 +59,21 @@ class resource_grid_reader_impl : public resource_grid_reader unsigned k_init, const bounded_bitset& mask) const override; + // See interface for documentation. + span get(span symbols, + unsigned port, + unsigned l, + unsigned k_init, + const bounded_bitset& mask) const override; + // See interface for documentation. void get(span symbols, unsigned port, unsigned l, unsigned k_init, unsigned stride) const override; // See interface for documentation. - span get_view(unsigned port, unsigned l) const override; + void get(span symbols, unsigned port, unsigned l, unsigned k_init) const override; + + // See interface for documentation. + span get_view(unsigned port, unsigned l) const override; /// Checks if a port is empty. bool is_port_empty(unsigned i_port) const { return (empty & (1U << i_port)) != 0; } diff --git a/lib/phy/support/resource_grid_writer_impl.cpp b/lib/phy/support/resource_grid_writer_impl.cpp index 9089b9dc37..09cdc5f1e9 100644 --- a/lib/phy/support/resource_grid_writer_impl.cpp +++ b/lib/phy/support/resource_grid_writer_impl.cpp @@ -22,7 +22,7 @@ #include "resource_grid_writer_impl.h" #include "srsran/adt/interval.h" #include "srsran/phy/support/resource_grid.h" -#include "srsran/srsvec/copy.h" +#include "srsran/srsvec/conversion.h" using namespace srsran; @@ -56,7 +56,7 @@ span resource_grid_writer_impl::put(unsigned srsran_assert(port_range.contains(port), "Port identifier (i.e., {}) is out of range {}.", port, port_range); // Get view of the OFDM symbol subcarriers. - span symb = data.get_view({l, port}).subspan(k_init, mask.size()); + span symb = data.get_view({l, port}).subspan(k_init, mask.size()); clear_empty(port); @@ -68,12 +68,12 @@ span resource_grid_writer_impl::put(unsigned // Do a straight copy if the elements of the mask are all contiguous. if (mask_count and mask.is_contiguous()) { - srsvec::copy(symb.subspan(mask.find_lowest(), mask_count), symbols.first(mask_count)); + srsvec::convert(symb.subspan(mask.find_lowest(), mask_count), symbols.first(mask_count)); return symbols.last(symbols.size() - mask_count); } mask.for_each(0, mask.size(), [&symb, &symbols](unsigned i_subc) { - symb[i_subc] = symbols.front(); + symb[i_subc] = to_cbf16(symbols.front()); symbols = symbols.last(symbols.size() - 1); }); @@ -98,10 +98,10 @@ void resource_grid_writer_impl::put(unsigned port, unsigned l, unsigned k_init, get_nof_ports()); // Select destination OFDM symbol from the resource grid. - span rg_symbol = data.get_view({l, port}); + span rg_symbol = data.get_view({l, port}); // Copy resource elements. - srsvec::copy(rg_symbol.subspan(k_init, symbols.size()), symbols); + srsvec::convert(rg_symbol.subspan(k_init, symbols.size()), symbols); clear_empty(port); } @@ -129,7 +129,7 @@ void resource_grid_writer_impl::put(unsigned port, get_nof_ports()); // Insert symbols. - span rg_symbol = data.get_view({l, port}); + span rg_symbol = data.get_view({l, port}); for (unsigned i_symbol = 0, i_re = k_init; i_symbol != nof_symbols; ++i_symbol) { rg_symbol[i_re] = symbols[i_symbol]; i_re += stride; diff --git a/lib/phy/support/resource_grid_writer_impl.h b/lib/phy/support/resource_grid_writer_impl.h index eb12da678b..ad2f0cef22 100644 --- a/lib/phy/support/resource_grid_writer_impl.h +++ b/lib/phy/support/resource_grid_writer_impl.h @@ -30,7 +30,7 @@ namespace srsran { class resource_grid_writer_impl : public resource_grid_writer { public: - using storage_type = tensor(resource_grid_dimensions::all), cf_t, resource_grid_dimensions>; + using storage_type = tensor(resource_grid_dimensions::all), cbf16_t, resource_grid_dimensions>; /// Constructs a resource grid writer implementation from a tensor. resource_grid_writer_impl(storage_type& data_, std::atomic& empty_) : data(data_), empty(empty_) {} diff --git a/lib/phy/upper/channel_processors/pucch_demodulator_impl.cpp b/lib/phy/upper/channel_processors/pucch_demodulator_impl.cpp index a4e4d2a03c..a133d1c814 100644 --- a/lib/phy/upper/channel_processors/pucch_demodulator_impl.cpp +++ b/lib/phy/upper/channel_processors/pucch_demodulator_impl.cpp @@ -118,10 +118,10 @@ void pucch_demodulator_impl::get_data_re_ests(const resource_grid_reader& for (unsigned i_port = 0, i_port_end = config.rx_ports.size(); i_port != i_port_end; ++i_port) { // Get a view of the data RE destination buffer for a single Rx port. - span re_port_buffer = ch_re.get_view({i_port}); + span re_port_buffer = ch_re.get_view({i_port}); // Get a view of the channel estimates destination buffer for a single Rx port and Tx layer. - span ests_port_buffer = ch_estimates.get_view({i_port, 0}); + span ests_port_buffer = ch_estimates.get_view({i_port, 0}); for (unsigned i_symbol = config.start_symbol_index, i_symbol_end = config.start_symbol_index + config.nof_symbols; i_symbol != i_symbol_end; @@ -130,7 +130,7 @@ void pucch_demodulator_impl::get_data_re_ests(const resource_grid_reader& re_port_buffer = resource_grid.get(re_port_buffer, i_port, i_symbol, first_subc, re_mask); // View over the channel estimation coefficients for a single OFDM symbol. - span ests_symbol = channel_ests.get_symbol_ch_estimate(i_symbol, i_port); + span ests_symbol = channel_ests.get_symbol_ch_estimate(i_symbol, i_port); // Copy channel estimation coefficients of the data RE into the destination buffer. re_mask.for_each(0, re_mask.size(), [&ests_port_buffer, &ests_symbol, &first_subc](unsigned bitpos) { diff --git a/lib/phy/upper/channel_processors/pucch_demodulator_impl.h b/lib/phy/upper/channel_processors/pucch_demodulator_impl.h index e1a7255883..6b0ee2072b 100644 --- a/lib/phy/upper/channel_processors/pucch_demodulator_impl.h +++ b/lib/phy/upper/channel_processors/pucch_demodulator_impl.h @@ -93,7 +93,7 @@ class pucch_demodulator_impl : public pucch_demodulator /// \brief Buffer used to transfer channel modulation symbols from the resource grid to the equalizer. /// \remark The symbols are arranged in two dimensions, i.e., resource element and receive port. static_tensor(channel_equalizer::re_list::dims::nof_dims), - cf_t, + cbf16_t, pucch_constants::MAX_NOF_RE * MAX_PORTS, channel_equalizer::re_list::dims> ch_re; @@ -111,7 +111,7 @@ class pucch_demodulator_impl : public pucch_demodulator /// and transmit layer. static_tensor( channel_equalizer::ch_est_list::dims::nof_dims), - cf_t, + cbf16_t, pucch_constants::MAX_NOF_RE * MAX_PORTS, channel_equalizer::ch_est_list::dims> ch_estimates; @@ -124,6 +124,8 @@ class pucch_demodulator_impl : public pucch_demodulator /// Indicates the Resource Elements containing control data symbols within a PRB, as per TS38.211 Section 6.4.1.3.2.2. const re_prb_mask format2_prb_re_mask = {true, false, true, true, false, true, true, false, true, true, false, true}; + /// Temporary channel estimates for an OFDM symbol. + std::array temp_ests_symbol; /// PRB mask indicating the used PRB within the resource grid. bounded_bitset prb_mask; }; diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.cpp b/lib/phy/upper/channel_processors/pucch_detector_impl.cpp index 27827772a2..a73da4536f 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.cpp +++ b/lib/phy/upper/channel_processors/pucch_detector_impl.cpp @@ -24,7 +24,8 @@ /// \brief PUCCH detector definition for Formats 0 and 1. #include "pucch_detector_impl.h" -#include "srsran/srsvec/copy.h" +#include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/srsvec/conversion.h" #include "srsran/srsvec/mean.h" using namespace srsran; @@ -314,70 +315,54 @@ void pucch_detector_impl::extract_data_and_estimates(const resource_grid_reader& const static_vector& antenna_ports) { for (uint8_t port : antenna_ports) { - unsigned i_symbol = 0; - unsigned skip = 0; - unsigned symbol_index = first_symbol + 1; - span sequence_slice = time_spread_sequence.get_view({port}); - span estimate_slice = ch_estimates.get_view({port}); + unsigned i_symbol = 0; + unsigned skip = 0; + unsigned symbol_index = first_symbol + 1; + span sequence_slice = time_spread_sequence.get_view({port}); + span estimate_slice = ch_estimates.get_view({port}); for (; i_symbol != nof_data_symbols_pre_hop; ++i_symbol, skip += NRE, symbol_index += 2) { // Index of the first subcarrier assigned to PUCCH, before hopping. - unsigned k_init = NRE * first_prb; - span sequence_chunk = sequence_slice.subspan(skip, NRE); + unsigned k_init = NRE * first_prb; + span sequence_chunk = sequence_slice.subspan(skip, NRE); grid.get(sequence_chunk, port, symbol_index, k_init); - span tmp = estimates.get_symbol_ch_estimate(symbol_index, port); + span tmp = estimates.get_symbol_ch_estimate(symbol_index, port); srsvec::copy(estimate_slice.subspan(skip, NRE), tmp.subspan(k_init, NRE)); } for (; i_symbol != nof_data_symbols; ++i_symbol, skip += NRE, symbol_index += 2) { // Index of the first subcarrier assigned to PUCCH, after hopping. Note that we only enter this loop if // second_prb.has_value(). - unsigned k_init = NRE * second_prb.value(); - span sequence_chunk = sequence_slice.subspan(skip, NRE); + unsigned k_init = NRE * second_prb.value(); + span sequence_chunk = sequence_slice.subspan(skip, NRE); grid.get(sequence_chunk, port, symbol_index, k_init); - span tmp_in = estimates.get_symbol_ch_estimate(symbol_index, port).subspan(k_init, NRE); - span tmp_out = estimate_slice.subspan(skip, NRE); + span tmp_in = estimates.get_symbol_ch_estimate(symbol_index, port).subspan(k_init, NRE); + span tmp_out = estimate_slice.subspan(skip, NRE); srsvec::copy(tmp_out, tmp_in); } } } // Computest the indices of the cyclic shifts for all symbols. -static void compute_alpha_indices(span indices, - unsigned m0, - unsigned start_symbol, - unsigned nof_symbols, - unsigned n_id, - unsigned n_sf, - unsigned nof_symbols_per_slot, - pseudo_random_generator& prg) +static void compute_alpha_indices(span indices, + unsigned start_symbol, + unsigned nof_symbols, + const slot_point& slot, + const cyclic_prefix& cp, + unsigned n_id, + unsigned m0, + pucch_helper& helper) { srsran_assert(indices.size() == nof_symbols / 2, "The number of alpha indices {} does not match with the number of allocated symbols {}.", indices.size(), nof_symbols); - constexpr unsigned CHIPS_PER_SYMBOL = 8; - // Initialize the pseduorandom generator. - prg.init(n_id); - // Create the required PR numbers. - prg.advance(CHIPS_PER_SYMBOL * (nof_symbols_per_slot * n_sf + start_symbol)); - std::array c_values_buffer; - span c_values_all(c_values_buffer); - prg.generate(c_values_all, 1.0F); - - unsigned offset = CHIPS_PER_SYMBOL; // Only every other symbol, starting from the second one, contains data. - for (unsigned i_symbol = 1, i_alpha = 0; i_symbol < nof_symbols; - i_symbol += 2, ++i_alpha, offset += 2 * CHIPS_PER_SYMBOL) { - // Compute n_cs - span c_values = c_values_all.subspan(offset, CHIPS_PER_SYMBOL); - unsigned n_cs = std::accumulate(c_values.begin(), c_values.end(), 0U, [n = 0U](unsigned a, float b) mutable { - return (a + ((b < 0) ? 1U : 0U) * (1U << (n++))); - }); + for (unsigned i_symbol = 1, i_alpha = 0; i_symbol < nof_symbols; i_symbol += 2, ++i_alpha) { // Compute alpha index. - indices[i_alpha] = (m0 + n_cs) % NRE; + indices[i_alpha] = helper.get_alpha_index(slot, cp, n_id, start_symbol + i_symbol, m0, 0); } } @@ -391,20 +376,16 @@ void pucch_detector_impl::marginalize_w_and_r_out(const format1_configuration& c unsigned group_index = config.n_id % 30; unsigned sequence_number = 0; - unsigned nof_symbols_per_slot = get_nsymb_per_slot(config.cp); - // Get slot number in radio frame. - unsigned n_sf = config.slot.slot_index(); - span w_star = get_w_star(nof_data_symbols_pre_hop, time_domain_occ); compute_alpha_indices(alpha_indices, - config.initial_cyclic_shift, config.start_symbol_index, config.nof_symbols, + config.slot, + config.cp, config.n_id, - n_sf, - nof_symbols_per_slot, - *pseudo_random); + config.initial_cyclic_shift, + helper); detected_symbol = 0; unsigned offset = 0; diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.h b/lib/phy/upper/channel_processors/pucch_detector_impl.h index 5f54d6f67f..0ea8dcaaae 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.h +++ b/lib/phy/upper/channel_processors/pucch_detector_impl.h @@ -25,6 +25,7 @@ #pragma once +#include "../signal_processors/pucch/pucch_helper.h" #include "pucch_detector_format0.h" #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/upper/channel_processors/pucch_detector.h" @@ -59,12 +60,11 @@ class pucch_detector_impl : public pucch_detector std::unique_ptr equalizer_, std::unique_ptr detector_format0_) : low_papr(std::move(low_papr_)), - pseudo_random(std::move(pseudo_random_)), + helper(std::move(pseudo_random_)), equalizer(std::move(equalizer_)), detector_format0(std::move(detector_format0_)) { srsran_assert(low_papr, "Invalid Low PAPR sequence generator."); - srsran_assert(pseudo_random, "Invalid pseudo-random sequence generator."); srsran_assert(equalizer, "Invalid equalizer."); srsran_assert(detector_format0, "PUCCH Format 0 detector."); } @@ -100,7 +100,7 @@ class pucch_detector_impl : public pucch_detector /// Collection of low-PAPR sequences. std::unique_ptr low_papr; /// Pseudorandom sequence generator. - std::unique_ptr pseudo_random; + pucch_helper helper; /// Channel equalizer. std::unique_ptr equalizer; /// PUCCH Format 0 detector. @@ -108,7 +108,7 @@ class pucch_detector_impl : public pucch_detector /// \brief Tensor for storing the spread data sequence. /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. static_tensor(channel_equalizer::re_list::dims::nof_dims), - cf_t, + cbf16_t, MAX_ALLOCATED_RE_F1 * MAX_PORTS / 2, channel_equalizer::re_list::dims> time_spread_sequence; @@ -116,7 +116,7 @@ class pucch_detector_impl : public pucch_detector /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. static_tensor( channel_equalizer::ch_est_list::dims::nof_dims), - cf_t, + cbf16_t, MAX_ALLOCATED_RE_F1 * MAX_PORTS / 2, channel_equalizer::ch_est_list::dims> ch_estimates; diff --git a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h index e6f12e00db..8e0767c21a 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h @@ -31,6 +31,7 @@ #include "srsran/phy/upper/channel_processors/pusch/pusch_demodulator.h" #include "srsran/phy/upper/equalization/channel_equalizer.h" #include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" +#include "srsran/srsvec/conversion.h" namespace srsran { @@ -92,7 +93,7 @@ class pusch_demodulator_impl : public pusch_demodulator // Extract RE for each port and symbol. for (unsigned i_port = 0, i_port_end = rx_ports.size(); i_port != i_port_end; ++i_port) { // Get a view of the port data RE. - span re_port_buffer = data_re.get_view<>({i_port}); + span re_port_buffer = data_re.get_view<>({i_port}); // Copy grid data resource elements into the buffer. re_port_buffer = grid.get(re_port_buffer, rx_ports[i_port], i_symbol, init_subc, re_mask); @@ -126,10 +127,10 @@ class pusch_demodulator_impl : public pusch_demodulator for (unsigned i_layer = 0, i_layer_end = channel_estimate.size().nof_tx_layers; i_layer != i_layer_end; ++i_layer) { for (unsigned i_port = 0, i_port_end = rx_ports.size(); i_port != i_port_end; ++i_port) { // Get a view of the channel estimates buffer for a single Rx port. - span ch_port_buffer = data_estimates.get_view({i_port, i_layer}); + span ch_port_buffer = data_estimates.get_view({i_port, i_layer}); // View of the channel estimation for an OFDM symbol. - span symbol_estimates = channel_estimate.get_symbol_ch_estimate(i_symbol, i_port, i_layer); + span symbol_estimates = channel_estimate.get_symbol_ch_estimate(i_symbol, i_port, i_layer); // Get view of the selected area of the grid. symbol_estimates = symbol_estimates.subspan(init_subc, re_mask.size()); @@ -150,7 +151,7 @@ class pusch_demodulator_impl : public pusch_demodulator // Skip DM-RS estimates. re_mask.for_each(0, re_mask.size(), [&symbol_estimates, &ch_port_buffer](unsigned i_re) { // Copy RE. - ch_port_buffer.front() = symbol_estimates[i_re]; + ch_port_buffer.front() = to_cf(symbol_estimates[i_re]); // Advance buffer. ch_port_buffer = ch_port_buffer.last(ch_port_buffer.size() - 1); @@ -175,7 +176,7 @@ class pusch_demodulator_impl : public pusch_demodulator /// Buffer used to transfer channel modulation symbols from the resource grid to the equalizer. dynamic_tensor(channel_equalizer::re_list::dims::nof_dims), - cf_t, + cbf16_t, channel_equalizer::re_list::dims> ch_re; @@ -188,7 +189,7 @@ class pusch_demodulator_impl : public pusch_demodulator /// Buffer used to transfer channel estimation coefficients from the channel estimate to the equalizer. dynamic_tensor( channel_equalizer::ch_est_list::dims::nof_dims), - cf_t, + cbf16_t, channel_equalizer::ch_est_list::dims> ch_estimates; diff --git a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp index 2dec59dce3..239aa69224 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp @@ -188,7 +188,7 @@ void pusch_processor_impl::process(span data, i_symbol != i_symbol_end; ++i_symbol) { // Extract channel estimates for the OFDM symbol, port and layer. - span ce = ch_estimate.get_symbol_ch_estimate(i_symbol, i_port, i_layer); + span ce = ch_estimate.get_symbol_ch_estimate(i_symbol, i_port, i_layer); // Set DC to zero. ce[dc_position] = 0; diff --git a/lib/phy/upper/equalization/equalize_mmse_1xn.h b/lib/phy/upper/equalization/equalize_mmse_1xn.h index 6fbf8ab86f..e9a6df8240 100644 --- a/lib/phy/upper/equalization/equalize_mmse_1xn.h +++ b/lib/phy/upper/equalization/equalize_mmse_1xn.h @@ -60,8 +60,8 @@ void equalize_mmse_1xn(span symbols_out, for (unsigned i_port = 0; i_port != RX_PORTS; ++i_port) { // Get the input RE and channel estimate coefficient. - cf_t re_in = ch_symbols[{i_re, i_port}]; - cf_t ch_est = ch_estimates[{i_re, i_port}] * tx_scaling; + cf_t re_in = to_cf(ch_symbols[{i_re, i_port}]); + cf_t ch_est = to_cf(ch_estimates[{i_re, i_port}]) * tx_scaling; // Compute the channel square norm. float ch_est_norm = std::norm(ch_est); diff --git a/lib/phy/upper/equalization/equalize_zf_1xn.h b/lib/phy/upper/equalization/equalize_zf_1xn.h index ed5d92bdfb..cce293fd5a 100644 --- a/lib/phy/upper/equalization/equalize_zf_1xn.h +++ b/lib/phy/upper/equalization/equalize_zf_1xn.h @@ -54,8 +54,8 @@ void equalize_zf_1xn(span symbols_out, #if defined(__AVX2__) || defined(__ARM_NEON) // Views over the input data. - std::array, MAX_PORTS> port_symbols; - std::array, MAX_PORTS> port_ests; + std::array, MAX_PORTS> port_symbols; + std::array, MAX_PORTS> port_ests; for (unsigned i_port = 0; i_port != RX_PORTS; ++i_port) { port_symbols[i_port] = ch_symbols.get_view({i_port}); @@ -75,8 +75,8 @@ void equalize_zf_1xn(span symbols_out, for (unsigned i_port = 0; i_port != RX_PORTS; ++i_port) { // Get the input RE and channel estimate coefficients. - simd_cf_t re_in = srsran_simd_cfi_loadu(port_symbols[i_port].data() + i_re); - simd_cf_t ch_est = srsran_simd_cfi_loadu(port_ests[i_port].data() + i_re); + simd_cf_t re_in = srsran_simd_cbf16_loadu(port_symbols[i_port].data() + i_re); + simd_cf_t ch_est = srsran_simd_cbf16_loadu(port_ests[i_port].data() + i_re); // Compute the channel square norm. simd_f_t ch_est_norm = srsran_simd_cf_norm_sq(ch_est); @@ -136,12 +136,12 @@ void equalize_zf_1xn(span symbols_out, for (; i_re != nof_re; ++i_re) { float ch_mod_sq = 0.0F; float nvar_acc = 0.0F; - cf_t re_out = 0.0F; + cf_t re_out = cf_t(); for (unsigned i_port = 0; i_port != RX_PORTS; ++i_port) { // Get the input RE and channel estimate coefficient. - cf_t re_in = ch_symbols[{i_re, i_port}]; - cf_t ch_est = ch_estimates[{i_re, i_port}]; + cf_t re_in = to_cf(ch_symbols[{i_re, i_port}]); + cf_t ch_est = to_cf(ch_estimates[{i_re, i_port}]); // Compute the channel square norm. float ch_est_norm = std::norm(ch_est); diff --git a/lib/phy/upper/equalization/equalize_zf_2xn.h b/lib/phy/upper/equalization/equalize_zf_2xn.h index 668e55a558..df0deefb94 100644 --- a/lib/phy/upper/equalization/equalize_zf_2xn.h +++ b/lib/phy/upper/equalization/equalize_zf_2xn.h @@ -63,13 +63,13 @@ void equalize_zf_2xn(span eq_symbols, } // Views over input channel symbols, organized by receive port. - std::array, nof_ports> symbols_in; + std::array, nof_ports> symbols_in; for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { symbols_in[i_port] = ch_symbols.get_view<>({i_port}); } // Views over channel estimates, organized by receive port and transmit layer. - std::array, nof_layers>, nof_ports> ch_estimates; + std::array, nof_layers>, nof_ports> ch_estimates; for (unsigned i_layer = 0; i_layer != nof_layers; ++i_layer) { for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { ch_estimates[i_port][i_layer] = ch_estimates_.get_view<>({i_port, i_layer}); @@ -88,14 +88,14 @@ void equalize_zf_2xn(span eq_symbols, std::array, nof_ports> ch; for (unsigned i_layer = 0; i_layer != nof_layers; ++i_layer) { for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { - ch[i_port][i_layer] = srsran_simd_cfi_loadu(ch_estimates[i_port][i_layer].data() + i_re); + ch[i_port][i_layer] = srsran_simd_cbf16_loadu(ch_estimates[i_port][i_layer].data() + i_re); } } // Input Resource Elements. std::array re_in; for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { - re_in[i_port] = srsran_simd_cfi_loadu(symbols_in[i_port].data() + i_re); + re_in[i_port] = srsran_simd_cbf16_loadu(symbols_in[i_port].data() + i_re); } // Calculate the product of the channel matrix (recall, it's an Nx2 matrix) and its hermitian transpose. @@ -185,7 +185,7 @@ void equalize_zf_2xn(span eq_symbols, std::array, nof_ports> ch_conj; for (unsigned i_layer = 0; i_layer != nof_layers; ++i_layer) { for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { - ch[i_port][i_layer] = ch_estimates[i_port][i_layer][i_re]; + ch[i_port][i_layer] = to_cf(ch_estimates[i_port][i_layer][i_re]); ch_conj[i_port][i_layer] = std::conj(ch[i_port][i_layer]); } } @@ -193,7 +193,7 @@ void equalize_zf_2xn(span eq_symbols, // Input Resource Elements. std::array re_in; for (unsigned i_port = 0; i_port != nof_ports; ++i_port) { - re_in[i_port] = symbols_in[i_port][i_re]; + re_in[i_port] = to_cf(symbols_in[i_port][i_re]); } // Calculate the product of the channel matrix (recall, it's an Nx2 matrix) and its hermitian transpose. diff --git a/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.cpp b/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.cpp index 59a636c0d4..de326e9885 100644 --- a/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.cpp +++ b/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.cpp @@ -24,6 +24,7 @@ #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/srsvec/add.h" #include "srsran/srsvec/compare.h" +#include "srsran/srsvec/conversion.h" #include "srsran/srsvec/convolution.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/dot_prod.h" @@ -247,7 +248,7 @@ void port_channel_estimator_average_impl::compute(channel_estimate& es for (unsigned i_symbol = cfg.first_symbol, last_symbol = cfg.first_symbol + cfg.nof_symbols; i_symbol != last_symbol; ++i_symbol) { - span symbol_ch_estimate = estimate.get_symbol_ch_estimate(i_symbol, port, i_layer); + span symbol_ch_estimate = estimate.get_symbol_ch_estimate(i_symbol, port, i_layer); srsvec::sc_prod( symbol_ch_estimate, std::polar(1.0F, TWOPI * symbol_start_epochs[i_symbol] * cfo), symbol_ch_estimate); } @@ -373,13 +374,30 @@ void port_channel_estimator_average_impl::compute_layer_hop(srsran::channel_esti time_alignment_s += estimate_time_alignment(filtered_pilots_lse, pattern, hop, cfg.scs, *ta_estimator); + // Extract RB mask lowest and highest RB. Also, determine if the allocation is contiguous. + int lowest_rb = hop_rb_mask.find_lowest(); + int highest_rb = hop_rb_mask.find_highest(); + unsigned rb_count = hop_rb_mask.count(); + srsran_assert(highest_rb >= lowest_rb, "Invalid hop RB mask."); + bool is_contiguous = (static_cast(highest_rb + 1 - lowest_rb) == rb_count); + // Interpolate frequency domain. - span ce_freq = span(freq_response).first(hop_rb_mask.count() * NRE); + unsigned nof_re = rb_count * NRE; + span ce_freq = span(freq_response).first(nof_re); freq_interpolator->interpolate(ce_freq, filtered_pilots_lse, interpolator_cfg); + // Convert interpolation result to complex BFloat16. + span ce_freq_cbf16 = span(freq_response_cbf16).first(nof_re); + srsvec::convert(ce_freq_cbf16, ce_freq); + // Map frequency response to channel estimates. for (unsigned i_symbol = first_symbol; i_symbol != last_symbol; ++i_symbol) { - span symbol_fr_resp = estimate.get_symbol_ch_estimate(i_symbol, port, i_layer); + span symbol_fr_resp = estimate.get_symbol_ch_estimate(i_symbol, port, i_layer); + + if (is_contiguous) { + srsvec::copy(symbol_fr_resp.subspan(lowest_rb * NRE, nof_re), ce_freq.first(nof_re)); + continue; + } unsigned i_prb_ce = 0; hop_rb_mask.for_each(0, hop_rb_mask.size(), [&](unsigned i_prb) { diff --git a/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.h b/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.h index aad0a06936..5d3a00f14f 100644 --- a/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.h +++ b/lib/phy/upper/signal_processors/port_channel_estimator_average_impl.h @@ -146,6 +146,8 @@ class port_channel_estimator_average_impl : public port_channel_estimator /// Buffer of frequency response coefficients. std::array freq_response; + /// Buffer of frequency response coefficients in \c bfloat16. + std::array freq_response_cbf16; /// Buffer for the OFDM symbols starting epochs within the current slot. std::array aux_symbol_start_epochs; diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 16f5c98dea..3d99b89779 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -454,13 +454,24 @@ static std::shared_ptr create_ul_processor_factory(con std::shared_ptr uci_proc_factory = create_pusch_processor_factory_sw(pusch_config); report_fatal_error_if_not(uci_proc_factory, "Invalid PUSCH processor factory for UCI."); + // The PUSCH processor pool shall be blocking if PUSCH decoder operates in synchronous mode; + bool pusch_processor_pool_blocking = (config.pusch_decoder_executor == nullptr); + + // If PUSCH decoders operate in asynchronous mode the number of PUSCH regular processors is equal to the maximum + // number of enqueued PUSCH transmissions. Otherwise, the number of PUSCH regular processors is equal to number of UL + // threads. + unsigned nof_regular_processors = config.max_pusch_concurrency; + if (pusch_processor_pool_blocking) { + nof_regular_processors = config.max_ul_thread_concurrency; + } + // Create PUSCH processor pool factory. pusch_processor_pool_factory_config pusch_proc_pool_config; pusch_proc_pool_config.factory = pusch_factory; pusch_proc_pool_config.uci_factory = uci_proc_factory; - pusch_proc_pool_config.nof_regular_processors = config.max_pusch_concurrency; + pusch_proc_pool_config.nof_regular_processors = nof_regular_processors; pusch_proc_pool_config.nof_uci_processors = config.max_ul_thread_concurrency; - pusch_proc_pool_config.blocking = false; + pusch_proc_pool_config.blocking = pusch_processor_pool_blocking; pusch_factory = create_pusch_processor_pool(pusch_proc_pool_config); report_fatal_error_if_not(pusch_factory, "Invalid PUSCH processor pool factory."); diff --git a/lib/rlc/rlc_tx_am_entity.cpp b/lib/rlc/rlc_tx_am_entity.cpp index dd63662c5a..9337ef3e9d 100644 --- a/lib/rlc/rlc_tx_am_entity.cpp +++ b/lib/rlc/rlc_tx_am_entity.cpp @@ -750,7 +750,7 @@ void rlc_tx_am_entity::handle_status_pdu(rlc_am_status_pdu status) l2_tracer << trace_event{"handle_status", status_tp}; - update_mac_buffer_state(/* is_locked = */ true); + update_mac_buffer_state(/* is_locked = */ true, /* force_notify */ true); // Trigger recycling of discarded PDUs in ue_executor pdu_recycler.clear_by_executor(ue_executor); @@ -899,7 +899,8 @@ void rlc_tx_am_entity::handle_changed_buffer_state() if (not pending_buffer_state.test_and_set(std::memory_order_seq_cst)) { logger.log_debug("Triggering buffer state update to lower layer"); // Redirect handling of status to pcell_executor - if (not pcell_executor.defer([this]() { update_mac_buffer_state(/* is_locked = */ false); })) { + if (not pcell_executor.defer( + [this]() { update_mac_buffer_state(/* is_locked = */ false, /* force_notify */ false); })) { logger.log_error("Failed to enqueue buffer state update"); } } else { @@ -907,11 +908,11 @@ void rlc_tx_am_entity::handle_changed_buffer_state() } } -void rlc_tx_am_entity::update_mac_buffer_state(bool is_locked) +void rlc_tx_am_entity::update_mac_buffer_state(bool is_locked, bool force_notify) { pending_buffer_state.clear(std::memory_order_seq_cst); unsigned bs = is_locked ? get_buffer_state_nolock() : get_buffer_state(); - if (not(bs > MAX_DL_PDU_LENGTH && prev_buffer_state > MAX_DL_PDU_LENGTH)) { + if (force_notify || bs <= MAX_DL_PDU_LENGTH || prev_buffer_state <= MAX_DL_PDU_LENGTH) { logger.log_debug("Sending buffer state update to lower layer. bs={}", bs); lower_dn.on_buffer_state_update(bs); } else { @@ -1096,7 +1097,7 @@ void rlc_tx_am_entity::on_expired_poll_retransmit_timer() retx_queue.size()); } - update_mac_buffer_state(/* is_locked = */ true); + update_mac_buffer_state(/* is_locked = */ true, /* force_notify */ true); } /* * - include a poll in an AMD PDU as described in clause 5.3.3.2. diff --git a/lib/rlc/rlc_tx_am_entity.h b/lib/rlc/rlc_tx_am_entity.h index 0b0b35826c..e129529cd2 100644 --- a/lib/rlc/rlc_tx_am_entity.h +++ b/lib/rlc/rlc_tx_am_entity.h @@ -340,7 +340,8 @@ class rlc_tx_am_entity : public rlc_tx_entity, public rlc_tx_am_status_handler, /// /// Safe execution from: pcell_executor /// \param is_locked provides info whether the \c mutex is already locked or not. - void update_mac_buffer_state(bool is_locked); + /// \param force_notify forces a notification of the lower layer regardless of the current/previous buffer state. + void update_mac_buffer_state(bool is_locked, bool force_notify); /// Lock-free version of \c get_buffer_state() /// \return Provides the current buffer state diff --git a/lib/rrc/CMakeLists.txt b/lib/rrc/CMakeLists.txt index 4e949b91f9..8fee7d1d3a 100644 --- a/lib/rrc/CMakeLists.txt +++ b/lib/rrc/CMakeLists.txt @@ -35,6 +35,6 @@ set(SOURCES ) add_library(srsran_rrc STATIC ${SOURCES}) -target_link_libraries(srsran_rrc srsran_up_resource_manager srsran_security srsran_pdcp rrc_nr_asn1) +target_link_libraries(srsran_rrc srsran_up_resource_manager srsran_ue_security_manager srsran_security srsran_pdcp rrc_nr_asn1) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) \ No newline at end of file diff --git a/lib/rrc/rrc_du_impl.cpp b/lib/rrc/rrc_du_impl.cpp index 74507aeaea..f5f056c4b4 100644 --- a/lib/rrc/rrc_du_impl.cpp +++ b/lib/rrc/rrc_du_impl.cpp @@ -108,7 +108,7 @@ bool rrc_du_impl::handle_served_cell_list(const std::vector(resource_mng, - *msg.f1ap_pdu_notifier, + std::make_unique(*msg.f1ap_pdu_notifier, nas_notifier, ngap_ctrl_notifier, *msg.rrc_ue_cu_cp_notifier, *msg.measurement_notifier, + *msg.cu_cp_ue_notifier, msg.ue_index, msg.c_rnti, rrc_cell, ue_cfg, - *msg.sec_context, msg.du_to_cu_container.copy(), - *msg.ue_task_sched, msg.rrc_context)); if (res.second) { diff --git a/lib/rrc/rrc_du_impl.h b/lib/rrc/rrc_du_impl.h index 72d1c95ee5..d9813ed8ad 100644 --- a/lib/rrc/rrc_du_impl.h +++ b/lib/rrc/rrc_du_impl.h @@ -46,7 +46,7 @@ class rrc_du_impl : public rrc_du_interface bool handle_served_cell_list(const std::vector& served_cell_list) override; // rrc_du_ue_repository - rrc_ue_interface* add_ue(up_resource_manager& up_resource_mng, const rrc_ue_creation_message& msg) override; + rrc_ue_interface* add_ue(const rrc_ue_creation_message& msg) override; void release_ues() override; // rrc_ue_handler diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp index 834342305f..719369de5f 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.cpp @@ -34,22 +34,22 @@ rrc_reestablishment_procedure::rrc_reestablishment_procedure( const asn1::rrc_nr::rrc_reest_request_s& request_, rrc_ue_context_t& context_, const byte_buffer& du_to_cu_container_, - up_resource_manager& up_resource_mng_, rrc_ue_setup_proc_notifier& rrc_ue_setup_notifier_, rrc_ue_reestablishment_proc_notifier& rrc_ue_reest_notifier_, rrc_ue_srb_handler& srb_notifier_, rrc_ue_context_update_notifier& cu_cp_notifier_, + rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, rrc_ue_nas_notifier& nas_notifier_, rrc_ue_event_manager& event_mng_, rrc_ue_logger& logger_) : reestablishment_request(request_), context(context_), du_to_cu_container(du_to_cu_container_), - up_resource_mng(up_resource_mng_), rrc_ue_setup_notifier(rrc_ue_setup_notifier_), rrc_ue_reest_notifier(rrc_ue_reest_notifier_), srb_notifier(srb_notifier_), cu_cp_notifier(cu_cp_notifier_), + cu_cp_ue_notifier(cu_cp_ue_notifier_), nas_notifier(nas_notifier_), event_mng(event_mng_), logger(logger_) @@ -246,13 +246,13 @@ void rrc_reestablishment_procedure::transfer_reestablishment_context_and_update_ } // Transfer UP context from old UE - up_resource_mng.set_up_context(old_ue_reest_context.up_ctx); + cu_cp_notifier.on_up_context_setup_required(old_ue_reest_context.up_ctx); // Update security keys // freq_and_timing must be present, otherwise the RRC UE would've never been created - uint32_t ssb_arfcn = context.cfg.meas_timings.begin()->freq_and_timing.value().carrier_freq; - context.sec_context = old_ue_reest_context.sec_context; - context.sec_context.horizontal_key_derivation(context.cell.pci, ssb_arfcn); + uint32_t ssb_arfcn = context.cfg.meas_timings.begin()->freq_and_timing.value().carrier_freq; + cu_cp_ue_notifier.update_security_context(old_ue_reest_context.sec_context); + cu_cp_ue_notifier.perform_horizontal_key_derivation(context.cell.pci, ssb_arfcn); logger.log_debug("Refreshed keys horizontally. pci={} ssb-arfcn={}", context.cell.pci, ssb_arfcn); } diff --git a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h index 5cfb6b6314..a5f6572900 100644 --- a/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h +++ b/lib/rrc/ue/procedures/rrc_reestablishment_procedure.h @@ -38,11 +38,11 @@ class rrc_reestablishment_procedure rrc_reestablishment_procedure(const asn1::rrc_nr::rrc_reest_request_s& request_, rrc_ue_context_t& context_, const byte_buffer& du_to_cu_container_, - up_resource_manager& up_resource_mng_, rrc_ue_setup_proc_notifier& rrc_setup_notifier_, rrc_ue_reestablishment_proc_notifier& rrc_ue_notifier_, rrc_ue_srb_handler& srb_notifier_, rrc_ue_context_update_notifier& cu_cp_notifier_, + rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, rrc_ue_nas_notifier& nas_notifier_, rrc_ue_event_manager& event_mng_, rrc_ue_logger& logger_); @@ -74,11 +74,11 @@ class rrc_reestablishment_procedure const asn1::rrc_nr::rrc_reest_request_s& reestablishment_request; rrc_ue_context_t& context; const byte_buffer& du_to_cu_container; - up_resource_manager& up_resource_mng; rrc_ue_setup_proc_notifier& rrc_ue_setup_notifier; rrc_ue_reestablishment_proc_notifier& rrc_ue_reest_notifier; // handler to the parent RRC UE object rrc_ue_srb_handler& srb_notifier; // for creating SRBs rrc_ue_context_update_notifier& cu_cp_notifier; // notifier to the CU-CP + rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier; // notifier to the CU-CP UE rrc_ue_nas_notifier& nas_notifier; // notifier to the NGAP rrc_ue_event_manager& event_mng; // event manager for the RRC UE entity rrc_ue_logger& logger; diff --git a/lib/rrc/ue/procedures/rrc_security_mode_command_procedure.cpp b/lib/rrc/ue/procedures/rrc_security_mode_command_procedure.cpp index 6dd804de45..f1967a4432 100644 --- a/lib/rrc/ue/procedures/rrc_security_mode_command_procedure.cpp +++ b/lib/rrc/ue/procedures/rrc_security_mode_command_procedure.cpp @@ -29,11 +29,11 @@ using namespace asn1::rrc_nr; rrc_security_mode_command_procedure::rrc_security_mode_command_procedure( rrc_ue_context_t& context_, - security::security_context sec_ctx_, + security::sec_selected_algos security_algos_, rrc_ue_security_mode_command_proc_notifier& rrc_ue_notifier_, rrc_ue_event_manager& event_mng_, rrc_ue_logger& logger_) : - context(context_), rrc_ue(rrc_ue_notifier_), event_mng(event_mng_), logger(logger_) + context(context_), security_algos(security_algos_), rrc_ue(rrc_ue_notifier_), event_mng(event_mng_), logger(logger_) { } @@ -46,69 +46,32 @@ void rrc_security_mode_command_procedure::operator()(coro_context rrc_context_) : ue_index(ue_index_), c_rnti(c_rnti_), cell(cell_), cfg(cfg_), - sec_context(sec_context_), transfer_context(rrc_context_), logger(srslog::fetch_basic_logger("RRC")) { if (transfer_context.has_value()) { - // Update security config. - sec_context = transfer_context.value().sec_context; - sec_context.horizontal_key_derivation(cell.pci, cell.ssb_arfcn); - logger.debug("ue={} refreshed keys horizontally. pci={} ssb-arfcn={}", ue_index, cell.pci, cell.ssb_arfcn); - security_enabled = true; - // Handle handover preparation info. if (!transfer_context.value().handover_preparation_info.empty()) { asn1::rrc_nr::ho_prep_info_s ho_prep; diff --git a/lib/rrc/ue/rrc_ue_context.h b/lib/rrc/ue/rrc_ue_context.h index 8a39958bf7..7390dc9b58 100644 --- a/lib/rrc/ue/rrc_ue_context.h +++ b/lib/rrc/ue/rrc_ue_context.h @@ -25,7 +25,6 @@ #include "rrc_ue_srb_context.h" #include "srsran/asn1/rrc_nr/ul_ccch_msg_ies.h" #include "srsran/asn1/rrc_nr/ul_dcch_msg_ies.h" -#include "srsran/cu_cp/up_resource_manager.h" #include "srsran/rrc/rrc_cell_context.h" #include "srsran/rrc/rrc_ue.h" #include "srsran/rrc/rrc_ue_config.h" @@ -44,21 +43,18 @@ class rrc_ue_context_t const rnti_t c_rnti_, const rrc_cell_context& cell_, const rrc_ue_cfg_t& cfg_, - security::security_context& sec_context_, std::optional rrc_context_); const ue_index_t ue_index; // UE index assigned by the DU processor const rnti_t c_rnti; // current C-RNTI const rrc_cell_context cell; // current cell const rrc_ue_cfg_t cfg; - security::security_context& sec_context; rrc_state state = rrc_state::idle; std::optional meas_cfg; std::optional five_g_tmsi; uint64_t setup_ue_id; asn1::rrc_nr::establishment_cause_opts connection_cause; std::map srbs; - bool security_enabled = false; std::optional capabilities; std::optional capabilities_list; std::optional transfer_context; // Context of old UE when created through mobility. diff --git a/lib/rrc/ue/rrc_ue_impl.cpp b/lib/rrc/ue/rrc_ue_impl.cpp index cddc342fe5..d3b6c02081 100644 --- a/lib/rrc/ue/rrc_ue_impl.cpp +++ b/lib/rrc/ue/rrc_ue_impl.cpp @@ -31,36 +31,39 @@ using namespace srsran; using namespace srs_cu_cp; using namespace asn1::rrc_nr; -rrc_ue_impl::rrc_ue_impl(up_resource_manager& up_resource_mng_, - rrc_pdu_f1ap_notifier& f1ap_pdu_notifier_, +rrc_ue_impl::rrc_ue_impl(rrc_pdu_f1ap_notifier& f1ap_pdu_notifier_, rrc_ue_nas_notifier& nas_notif_, rrc_ue_control_notifier& ngap_ctrl_notif_, rrc_ue_context_update_notifier& cu_cp_notif_, rrc_ue_measurement_notifier& measurement_notifier_, + rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, const ue_index_t ue_index_, const rnti_t c_rnti_, const rrc_cell_context cell_, const rrc_ue_cfg_t& cfg_, - security::security_context& security_context_, const byte_buffer du_to_cu_container_, - ue_task_scheduler& task_sched_, std::optional rrc_context) : - context(ue_index_, c_rnti_, cell_, cfg_, security_context_, rrc_context), - up_resource_mng(up_resource_mng_), + context(ue_index_, c_rnti_, cell_, cfg_, rrc_context), f1ap_pdu_notifier(f1ap_pdu_notifier_), nas_notifier(nas_notif_), ngap_ctrl_notifier(ngap_ctrl_notif_), cu_cp_notifier(cu_cp_notif_), measurement_notifier(measurement_notifier_), + cu_cp_ue_notifier(cu_cp_ue_notifier_), du_to_cu_container(du_to_cu_container_), - task_sched(task_sched_), logger("RRC", {ue_index_, c_rnti_}), - event_mng(std::make_unique(task_sched_.get_timer_factory())) + event_mng(std::make_unique(cu_cp_ue_notifier.get_timer_factory())) { srsran_assert(context.cell.bands.empty() == false, "Band must be present in RRC cell configuration."); srsran_assert(context.cfg.rrc_procedure_timeout_ms > 0, "RRC procedure timeout cannot be zero."); + // Update security context and keys if (rrc_context.has_value()) { + if (!rrc_context.value().is_inter_cu_handover) { + cu_cp_ue_notifier.update_security_context(rrc_context.value().sec_context); + } + cu_cp_ue_notifier.perform_horizontal_key_derivation(cell_.pci, cell_.ssb_arfcn); + // Create SRBs. for (const auto& srb : rrc_context.value().srbs) { srb_creation_message srb_msg{}; @@ -88,11 +91,12 @@ void rrc_ue_impl::create_srb(const srb_creation_message& msg) context.srbs.emplace( std::piecewise_construct, std::forward_as_tuple(msg.srb_id), - std::forward_as_tuple(msg.ue_index, msg.srb_id, task_sched.get_timer_factory(), task_sched.get_executor())); + std::forward_as_tuple( + msg.ue_index, msg.srb_id, cu_cp_ue_notifier.get_timer_factory(), cu_cp_ue_notifier.get_executor())); auto& srb_context = context.srbs.at(msg.srb_id); if (msg.srb_id == srb_id_t::srb2 || msg.enable_security) { - security::sec_as_config sec_cfg = context.sec_context.get_as_config(security::sec_domain::rrc); + security::sec_as_config sec_cfg = cu_cp_ue_notifier.get_rrc_as_config(); srb_context.enable_full_security(security::truncate_config(sec_cfg)); } @@ -127,14 +131,13 @@ void rrc_ue_impl::on_new_as_security_context() "Attempted to configure security, but there is no interface to PDCP"); context.srbs.at(srb_id_t::srb1) - .enable_rx_security(security::integrity_enabled::on, - security::ciphering_enabled::off, - context.sec_context.get_128_as_config(security::sec_domain::rrc)); + .enable_rx_security( + security::integrity_enabled::on, security::ciphering_enabled::off, cu_cp_ue_notifier.get_rrc_128_as_config()); context.srbs.at(srb_id_t::srb1) - .enable_tx_security(security::integrity_enabled::on, - security::ciphering_enabled::off, - context.sec_context.get_128_as_config(security::sec_domain::rrc)); - context.security_enabled = true; + .enable_tx_security( + security::integrity_enabled::on, security::ciphering_enabled::off, cu_cp_ue_notifier.get_rrc_128_as_config()); + + cu_cp_ue_notifier.enable_security(); } void rrc_ue_impl::on_security_context_sucessful() @@ -143,20 +146,18 @@ void rrc_ue_impl::on_security_context_sucessful() "Attempted to configure security, but there is no interface to PDCP"); context.srbs.at(srb_id_t::srb1) - .enable_rx_security(security::integrity_enabled::on, - security::ciphering_enabled::on, - context.sec_context.get_128_as_config(security::sec_domain::rrc)); + .enable_rx_security( + security::integrity_enabled::on, security::ciphering_enabled::on, cu_cp_ue_notifier.get_rrc_128_as_config()); context.srbs.at(srb_id_t::srb1) - .enable_tx_security(security::integrity_enabled::on, - security::ciphering_enabled::on, - context.sec_context.get_128_as_config(security::sec_domain::rrc)); + .enable_tx_security( + security::integrity_enabled::on, security::ciphering_enabled::on, cu_cp_ue_notifier.get_rrc_128_as_config()); } -async_task rrc_ue_impl::handle_init_security_context(const security::security_context& sec_ctx) +async_task rrc_ue_impl::handle_init_security_context() { - context.sec_context = sec_ctx; // Launch RRC security mode procedure - return launch_async(context, sec_ctx, *this, *event_mng, logger); + return launch_async( + context, cu_cp_ue_notifier.get_security_algos(), *this, *event_mng, logger); } byte_buffer rrc_ue_impl::get_packed_handover_preparation_message() @@ -176,7 +177,7 @@ byte_buffer rrc_ue_impl::get_packed_handover_preparation_message() void rrc_ue_impl::on_ue_release_required(const ngap_cause_t& cause) { - task_sched.schedule_async_task(launch_async([this, cause](coro_context>& ctx) mutable { + cu_cp_ue_notifier.schedule_async_task(launch_async([this, cause](coro_context>& ctx) mutable { CORO_BEGIN(ctx); CORO_AWAIT(cu_cp_notifier.on_ue_release_required({context.ue_index, {}, cause})); diff --git a/lib/rrc/ue/rrc_ue_impl.h b/lib/rrc/ue/rrc_ue_impl.h index d73528ca20..3b8dcd565f 100644 --- a/lib/rrc/ue/rrc_ue_impl.h +++ b/lib/rrc/ue/rrc_ue_impl.h @@ -26,7 +26,6 @@ #include "rrc_ue_context.h" #include "rrc_ue_logger.h" #include "srsran/asn1/rrc_nr/ul_dcch_msg.h" -#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/rrc/rrc_ue.h" namespace srsran { @@ -36,19 +35,17 @@ namespace srs_cu_cp { class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller { public: - rrc_ue_impl(up_resource_manager& up_resource_mng_, - rrc_pdu_f1ap_notifier& f1ap_pdu_notifier_, + rrc_ue_impl(rrc_pdu_f1ap_notifier& f1ap_pdu_notifier_, rrc_ue_nas_notifier& nas_notif_, rrc_ue_control_notifier& ngap_ctrl_notif_, rrc_ue_context_update_notifier& cu_cp_notif_, rrc_ue_measurement_notifier& measurement_notifier_, + rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier_, const ue_index_t ue_index_, const rnti_t c_rnti_, const rrc_cell_context cell_, const rrc_ue_cfg_t& cfg_, - security::security_context& security_context_, const byte_buffer du_to_cu_container, - ue_task_scheduler& task_sched, std::optional rrc_context); ~rrc_ue_impl(); @@ -84,7 +81,6 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller rrc_ue_release_context get_rrc_ue_release_context(bool requires_rrc_msg) override; rrc_ue_transfer_context get_transfer_context() override; std::optional generate_meas_config(std::optional current_meas_config) override; - bool handle_new_security_context(const security::security_context& sec_context) override; byte_buffer get_rrc_handover_command(const rrc_reconfiguration_procedure_request& request, unsigned transaction_id) override; @@ -119,20 +115,18 @@ class rrc_ue_impl final : public rrc_ue_interface, public rrc_ue_controller void on_new_dl_dcch(srb_id_t srb_id, const asn1::rrc_nr::dl_dcch_msg_s& dl_ccch_msg) override; void on_new_as_security_context() override; void on_security_context_sucessful() override; - bool get_security_enabled() override { return context.security_enabled; } - // initializes the security context and triggers the SMC procedure - async_task handle_init_security_context(const security::security_context& sec_ctx) override; + // Triggers the SMC procedure + async_task handle_init_security_context() override; rrc_ue_context_t context; - up_resource_manager& up_resource_mng; // UP resource manager rrc_pdu_f1ap_notifier& f1ap_pdu_notifier; // PDU notifier to the F1AP rrc_ue_nas_notifier& nas_notifier; // PDU notifier to the NGAP rrc_ue_control_notifier& ngap_ctrl_notifier; // Control message notifier to the NGAP rrc_ue_context_update_notifier& cu_cp_notifier; // notifier to the CU-CP rrc_ue_measurement_notifier& measurement_notifier; // cell measurement notifier + rrc_ue_cu_cp_ue_notifier& cu_cp_ue_notifier; // cu-cp ue notifier byte_buffer du_to_cu_container; // initial RRC message from DU to CU - ue_task_scheduler& task_sched; rrc_ue_logger logger; // RRC procedures handling diff --git a/lib/rrc/ue/rrc_ue_message_handlers.cpp b/lib/rrc/ue/rrc_ue_message_handlers.cpp index e05debcc53..6b202378f9 100644 --- a/lib/rrc/ue/rrc_ue_message_handlers.cpp +++ b/lib/rrc/ue/rrc_ue_message_handlers.cpp @@ -109,29 +109,29 @@ void rrc_ue_impl::handle_rrc_setup_request(const asn1::rrc_nr::rrc_setup_request context.connection_cause.value = request_ies.establishment_cause.value; // Launch RRC setup procedure - task_sched.schedule_async_task(launch_async(context, - request_ies.establishment_cause.value, - du_to_cu_container, - *this, - get_rrc_ue_srb_handler(), - nas_notifier, - *event_mng, - logger)); + cu_cp_ue_notifier.schedule_async_task(launch_async(context, + request_ies.establishment_cause.value, + du_to_cu_container, + *this, + get_rrc_ue_srb_handler(), + nas_notifier, + *event_mng, + logger)); } void rrc_ue_impl::handle_rrc_reest_request(const asn1::rrc_nr::rrc_reest_request_s& msg) { - task_sched.schedule_async_task(launch_async(msg, - context, - du_to_cu_container, - up_resource_mng, - *this, - *this, - get_rrc_ue_srb_handler(), - cu_cp_notifier, - nas_notifier, - *event_mng, - logger)); + cu_cp_ue_notifier.schedule_async_task(launch_async(msg, + context, + du_to_cu_container, + *this, + *this, + get_rrc_ue_srb_handler(), + cu_cp_notifier, + cu_cp_ue_notifier, + nas_notifier, + *event_mng, + logger)); } void rrc_ue_impl::stop() @@ -415,10 +415,10 @@ std::optional rrc_ue_impl::generate_meas_config(std::optional dist(0, 1); - span data = rg_buffer.get_data(); + span data = rg_buffer.get_data(); std::generate(data.begin(), data.end(), [&rgen, &dist]() { return dist(rgen); }); } @@ -80,18 +81,44 @@ class ru_dummy_rx_resource_grid : public resource_grid_reader return get(symbols, nof_symbols); } + // See resource_grid_reader for documentation. + span get(span symbols, + unsigned port, + unsigned l, + unsigned k_init, + const bounded_bitset& mask) const override + { + // Count number of elements. + unsigned nof_symbols = mask.count(); + + return get(symbols, nof_symbols); + } + // See resource_grid_reader for documentation. void get(span symbols, unsigned port, unsigned l, unsigned k_init, unsigned stride) const override + { + srsvec::convert(symbols, rg_buffer.get_data().first(symbols.size())); + } + + // See resource_grid_reader for documentation. + void get(span symbols, unsigned port, unsigned l, unsigned k_init) const override { srsvec::copy(symbols, rg_buffer.get_data().first(symbols.size())); } // See resource_grid_reader for documentation. - span get_view(unsigned port, unsigned l) const override { return rg_buffer.get_view({l, port}); } + span get_view(unsigned port, unsigned l) const override { return rg_buffer.get_view({l, port}); } private: /// Gets a number of symbols. span get(span symbols, unsigned nof_symbols) const + { + srsvec::convert(symbols.first(nof_symbols), rg_buffer.get_data().first(nof_symbols)); + + return symbols.last(symbols.size() - nof_symbols); + } + /// Gets a number of symbols. + span get(span symbols, unsigned nof_symbols) const { srsvec::copy(symbols.first(nof_symbols), rg_buffer.get_data().first(nof_symbols)); @@ -102,7 +129,7 @@ class ru_dummy_rx_resource_grid : public resource_grid_reader /// /// The resource grid buffer is a three-dimensional array with the dimensions representing, in order, subcarriers, /// OFDM symbols and antenna ports. - dynamic_tensor(resource_grid_dimensions::all), cf_t, resource_grid_dimensions> rg_buffer; + dynamic_tensor(resource_grid_dimensions::all), cbf16_t, resource_grid_dimensions> rg_buffer; }; } // namespace srsran diff --git a/lib/scheduler/cell_scheduler.cpp b/lib/scheduler/cell_scheduler.cpp index 6d5809777d..f18079fc45 100644 --- a/lib/scheduler/cell_scheduler.cpp +++ b/lib/scheduler/cell_scheduler.cpp @@ -84,6 +84,9 @@ void cell_scheduler::handle_crc_indication(const ul_crc_indication& crc_ind) void cell_scheduler::run_slot(slot_point sl_tx) { + // Mark the start of the slot. + auto slot_start_tp = std::chrono::high_resolution_clock::now(); + // If there are skipped slots, handle them. Otherwise, the cell grid and cached results are not correctly cleared. if (SRSRAN_LIKELY(res_grid.slot_tx().valid())) { while (SRSRAN_UNLIKELY(res_grid.slot_tx() + 1 != sl_tx)) { @@ -102,9 +105,6 @@ void cell_scheduler::run_slot(slot_point sl_tx) pucch_alloc.slot_indication(sl_tx); uci_alloc.slot_indication(sl_tx); - // > Mark slot start for logging purposes. - result_logger.on_slot_start(); - // > SSB scheduling. ssb_sch.run_slot(res_grid, sl_tx); @@ -130,12 +130,16 @@ void cell_scheduler::run_slot(slot_point sl_tx) // > Schedule UE DL and UL data. ue_sched.run_slot(sl_tx, cell_cfg.cell_index); + // > Mark stop of the slot processing + auto slot_stop_tp = std::chrono::high_resolution_clock::now(); + auto slot_dur = std::chrono::duration_cast(slot_stop_tp - slot_start_tp); + // > Log processed events. event_logger.log(); // > Log the scheduler results. - result_logger.on_scheduler_result(last_result()); + result_logger.on_scheduler_result(last_result(), slot_dur); // > Push the scheduler results to the metrics handler. - metrics.push_result(sl_tx, last_result()); + metrics.push_result(sl_tx, last_result(), slot_dur); } diff --git a/lib/scheduler/common_scheduling/ra_scheduler.cpp b/lib/scheduler/common_scheduling/ra_scheduler.cpp index 01ca0ccc62..cb11339a0d 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.cpp +++ b/lib/scheduler/common_scheduling/ra_scheduler.cpp @@ -400,7 +400,7 @@ bool ra_scheduler::is_slot_candidate_for_rar(cell_slot_resource_allocator& slot_ // Check for space in PDCCH result list. We check for space in PDSCH later, once the k0 is known. if (slot_res_alloc.result.dl.dl_pdcchs.full()) { - log_postponed_rar(pending_rars.front(), "No PDCCH space for RAR."); + log_postponed_rar(pending_rars.front(), "PDCCH grants limit reached", pdcch_slot); return false; } @@ -504,7 +504,7 @@ unsigned ra_scheduler::schedule_rar(const pending_rar_t& rar, cell_resource_allo // > Check space in DL sched result for RAR. if (pdsch_alloc.result.dl.rar_grants.full()) { // early exit. - log_postponed_rar(rar, "No PDSCH space for RAR."); + log_postponed_rar(rar, "RAR grants limit reached", pdcch_slot); return 0; } @@ -541,13 +541,13 @@ unsigned ra_scheduler::schedule_rar(const pending_rar_t& rar, cell_resource_allo if (max_nof_allocs == 0) { // Early exit. - log_postponed_rar(rar, "Not enough PRBs available for RAR PDSCH."); + log_postponed_rar(rar, "Not enough PRBs available for RAR PDSCH", pdcch_slot); return 0; } if (pdsch_time_res_index == pdsch_td_res_alloc_list.size()) { // Early exit. - log_postponed_rar(rar, "No PDSCH time domain resource found for RAR."); + log_postponed_rar(rar, "No PDSCH time domain resource found for RAR", pdcch_slot); return 0; } @@ -595,7 +595,7 @@ unsigned ra_scheduler::schedule_rar(const pending_rar_t& rar, cell_resource_allo } max_nof_allocs = msg3_candidates.size(); if (max_nof_allocs == 0) { - log_postponed_rar(rar, "No PUSCH time domain resource found for Msg3."); + log_postponed_rar(rar, "No PUSCH time domain resource found for Msg3"); return 0; } rar_crbs.resize(get_nof_pdsch_prbs_required(pdsch_time_res_index, max_nof_allocs).nof_prbs); @@ -605,6 +605,7 @@ unsigned ra_scheduler::schedule_rar(const pending_rar_t& rar, cell_resource_allo const search_space_id ss_id = cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common.ra_search_space_id; pdcch_dl_information* pdcch = pdcch_sch.alloc_dl_pdcch_common(pdcch_alloc, rar.ra_rnti, ss_id, aggr_lvl); if (pdcch == nullptr) { + log_postponed_rar(rar, "No PDCCH space for RAR", pdcch_slot); return 0; } @@ -659,7 +660,7 @@ void ra_scheduler::fill_rar_grant(cell_resource_allocator& res_alloc, const vrb_interval vrbs = msg3_crb_to_vrb(cell_cfg, msg3_candidate.crbs); auto& pending_msg3 = pending_msg3s[to_value(rar_request.tc_rntis[i]) % MAX_NOF_MSG3]; - srsran_sanity_check(pending_msg3.harq.empty(), "Pending Msg3 should not have been added if HARQ is busy."); + srsran_sanity_check(pending_msg3.harq.empty(), "Pending Msg3 should not have been added if HARQ is busy"); // Allocate Msg3 UL HARQ pending_msg3.harq.new_tx(msg3_alloc.slot, sched_cfg.max_nof_msg3_harq_retxs); @@ -816,7 +817,13 @@ sch_prbs_tbs ra_scheduler::get_nof_pdsch_prbs_required(unsigned time_res_idx, un [std::min(nof_ul_grants, (unsigned)rar_data[time_res_idx].prbs_tbs_per_nof_grants.size()) - 1]; } -void ra_scheduler::log_postponed_rar(const pending_rar_t& rar, const char* cause_str) const +void ra_scheduler::log_postponed_rar(const pending_rar_t& rar, + const char* cause_str, + std::optional sl) const { - logger.debug("RAR allocation for ra-rnti={} was postponed. Cause: {}", rar.ra_rnti, cause_str); + if (sl.has_value()) { + logger.debug("RAR allocation for ra-rnti={} was postponed. Cause: {} at slot={}", rar.ra_rnti, cause_str, *sl); + } else { + logger.debug("RAR allocation for ra-rnti={} was postponed. Cause: {}", rar.ra_rnti, cause_str); + } } diff --git a/lib/scheduler/common_scheduling/ra_scheduler.h b/lib/scheduler/common_scheduling/ra_scheduler.h index 65a03af9e9..6cacb8b29d 100644 --- a/lib/scheduler/common_scheduling/ra_scheduler.h +++ b/lib/scheduler/common_scheduling/ra_scheduler.h @@ -110,7 +110,8 @@ class ra_scheduler void handle_pending_crc_indications_impl(cell_resource_allocator& res_alloc); - void log_postponed_rar(const pending_rar_t& rar, const char* cause_str) const; + void + log_postponed_rar(const pending_rar_t& rar, const char* cause_str, std::optional sl = std::nullopt) const; /// Delete RARs that are out of the RAR window. void update_pending_rars(slot_point pdcch_slot); diff --git a/lib/scheduler/logging/scheduler_metric_handler.cpp b/lib/scheduler/logging/scheduler_metric_handler.cpp index cd0ba57f6f..cc2ee0d968 100644 --- a/lib/scheduler/logging/scheduler_metric_handler.cpp +++ b/lib/scheduler/logging/scheduler_metric_handler.cpp @@ -24,8 +24,8 @@ using namespace srsran; -scheduler_metrics_handler::scheduler_metrics_handler(msecs metrics_report_period, - scheduler_ue_metrics_notifier& notifier_) : +scheduler_metrics_handler::scheduler_metrics_handler(msecs metrics_report_period, + scheduler_metrics_notifier& notifier_) : notifier(notifier_), report_period(metrics_report_period) { } @@ -82,11 +82,12 @@ void scheduler_metrics_handler::handle_pucch_sinr(ue_metric_context& u, float si void scheduler_metrics_handler::handle_csi_report(ue_metric_context& u, const csi_report_data& csi) { + // Add new CQI and RI observations if they are available in the CSI report. if (csi.first_tb_wideband_cqi.has_value()) { - u.last_cqi = csi.first_tb_wideband_cqi->to_uint(); + u.data.cqi.update(csi.first_tb_wideband_cqi->to_uint()); } if (csi.ri.has_value()) { - u.last_ri = csi.ri->to_uint(); + u.data.ri.update(csi.ri->to_uint()); } } @@ -188,20 +189,35 @@ void scheduler_metrics_handler::handle_dl_buffer_state_indication(const dl_buffe } } +void scheduler_metrics_handler::handle_error_indication() +{ + error_indication_counter++; +} + void scheduler_metrics_handler::report_metrics() { - static_vector metrics_report; + next_report.ue_metrics.clear(); for (ue_metric_context& ue : ues) { // Compute statistics of the UE metrics and push the result to the report. - metrics_report.push_back(ue.compute_report(report_period)); + next_report.ue_metrics.push_back(ue.compute_report(report_period)); } + next_report.nof_error_indications = error_indication_counter; + next_report.average_decision_latency = decision_latency_sum / report_period_slots; + next_report.latency_histogram = decision_latency_hist; + + // Reset cell-wide metric counters. + error_indication_counter = 0; + decision_latency_sum = std::chrono::microseconds{0}; + decision_latency_hist = {}; + // Report all UE metrics in a batch. - notifier.report_metrics(metrics_report); + notifier.report_metrics(next_report); } -void scheduler_metrics_handler::handle_slot_result(const sched_result& slot_result) +void scheduler_metrics_handler::handle_slot_result(const sched_result& slot_result, + std::chrono::microseconds slot_decision_latency) { for (const dl_msg_alloc& dl_grant : slot_result.dl.ue_grants) { auto it = rnti_to_ue_index_lookup.find(dl_grant.pdsch_cfg.rnti); @@ -241,9 +257,17 @@ void scheduler_metrics_handler::handle_slot_result(const sched_result& slot_resu u.data.ul_mcs += ul_grant.pusch_cfg.mcs_index.to_uint(); u.data.nof_puschs++; } + + // Process latency. + decision_latency_sum += slot_decision_latency; + unsigned bin_idx = slot_decision_latency.count() / scheduler_cell_metrics::nof_usec_per_bin; + bin_idx = std::min(bin_idx, scheduler_cell_metrics::latency_hist_bins - 1); + decision_latency_hist[bin_idx]++; } -void scheduler_metrics_handler::push_result(slot_point sl_tx, const sched_result& slot_result) +void scheduler_metrics_handler::push_result(slot_point sl_tx, + const sched_result& slot_result, + std::chrono::microseconds slot_decision_latency) { if (report_period_slots == 0) { // The SCS common is now known. @@ -251,7 +275,7 @@ void scheduler_metrics_handler::push_result(slot_point sl_tx, const sched_result report_period_slots = usecs{report_period} / slot_dur; } - handle_slot_result(slot_result); + handle_slot_result(slot_result, slot_decision_latency); ++slot_counter; if (slot_counter >= report_period_slots) { @@ -266,8 +290,8 @@ scheduler_metrics_handler::ue_metric_context::compute_report(std::chrono::millis scheduler_ue_metrics ret{}; ret.pci = pci; ret.rnti = rnti; - ret.cqi = last_cqi; - ret.ri = last_ri; + ret.cqi_stats = data.cqi; + ret.ri_stats = data.ri; uint8_t mcs = data.nof_dl_cws > 0 ? std::roundf(static_cast(data.dl_mcs) / data.nof_dl_cws) : 0; ret.dl_mcs = sch_mcs_index{mcs}; mcs = data.nof_puschs > 0 ? std::roundf(static_cast(data.ul_mcs) / data.nof_puschs) : 0; diff --git a/lib/scheduler/logging/scheduler_metrics_handler.h b/lib/scheduler/logging/scheduler_metrics_handler.h index 6853806811..53d34762b2 100644 --- a/lib/scheduler/logging/scheduler_metrics_handler.h +++ b/lib/scheduler/logging/scheduler_metrics_handler.h @@ -59,6 +59,10 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche unsigned nof_pusch_rsrp_reports = 0; unsigned dl_prbs_used = 0; unsigned ul_prbs_used = 0; + /// CQI statistics over the metrics report interval. + sample_statistics cqi; + /// RI statistics over the metrics report interval. + sample_statistics ri; }; // This user provided constructor is added here to fix a Clang compilation error related to the use of nested types @@ -69,8 +73,6 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche unsigned nof_prbs; du_ue_index_t ue_index; rnti_t rnti; - uint8_t last_cqi = 0; - uint8_t last_ri = 1; unsigned last_bsr = 0; std::optional last_phr; std::optional last_ta; @@ -81,19 +83,26 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche void reset(); }; - scheduler_ue_metrics_notifier& notifier; + scheduler_metrics_notifier& notifier; const std::chrono::milliseconds report_period; /// Derived value. unsigned report_period_slots = 0; - /// \brief This type is used so that multiple threads can access different positions concurrently. + + unsigned error_indication_counter = 0; + std::chrono::microseconds decision_latency_sum{0}; + std::array decision_latency_hist{}; + slotted_id_table ues; std::unordered_map rnti_to_ue_index_lookup; - /// \brief Counter of number of slots elapsed since the last report. + + /// Counter of number of slots elapsed since the last report. unsigned slot_counter = 0; + scheduler_cell_metrics next_report; + public: /// \brief Creates a scheduler UE metrics handler. In case the metrics_report_period is zero, no metrics are reported. - explicit scheduler_metrics_handler(msecs metrics_report_period, scheduler_ue_metrics_notifier& notifier); + explicit scheduler_metrics_handler(msecs metrics_report_period, scheduler_metrics_notifier& notifier); /// \brief Register creation of a UE. void handle_ue_creation(du_ue_index_t ue_index, rnti_t rnti, pci_t pcell_pci, unsigned num_prbs) override; @@ -122,8 +131,11 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche /// \brief Handle DL Buffer Status indication. void handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& dl_bs); + /// \brief Handle Error Indication reported to the scheduler for a given cell. + void handle_error_indication(); + /// \brief Handle results stored in the scheduler result and push new entry. - void push_result(slot_point sl_tx, const sched_result& slot_result); + void push_result(slot_point sl_tx, const sched_result& slot_result, std::chrono::microseconds slot_decision_latency); /// \brief Checks whether the metrics reporting is active. bool connected() const { return report_period != std::chrono::nanoseconds{0}; } @@ -132,7 +144,7 @@ class scheduler_metrics_handler final : public harq_timeout_handler, public sche void handle_pucch_sinr(ue_metric_context& u, float sinr); void handle_csi_report(ue_metric_context& u, const csi_report_data& csi); void report_metrics(); - void handle_slot_result(const sched_result& slot_result); + void handle_slot_result(const sched_result& slot_result, std::chrono::microseconds slot_decision_latency); }; } // namespace srsran diff --git a/lib/scheduler/logging/scheduler_result_logger.cpp b/lib/scheduler/logging/scheduler_result_logger.cpp index 174b6a61cc..0cdeedd9e5 100644 --- a/lib/scheduler/logging/scheduler_result_logger.cpp +++ b/lib/scheduler/logging/scheduler_result_logger.cpp @@ -31,10 +31,8 @@ scheduler_result_logger::scheduler_result_logger(bool log_broadcast_, pci_t pci_ { } -void scheduler_result_logger::log_debug(const sched_result& result) +void scheduler_result_logger::log_debug(const sched_result& result, std::chrono::microseconds decision_latency) { - auto slot_stop_tp = std::chrono::high_resolution_clock::now(); - if (log_broadcast) { for (const ssb_information& ssb_info : result.dl.bc.ssb_info) { fmt::format_to( @@ -295,7 +293,6 @@ void scheduler_result_logger::log_debug(const sched_result& result) } if (fmtbuf.size() > 0) { - auto decision_latency = std::chrono::duration_cast(slot_stop_tp - slot_start_tp); const unsigned nof_pdschs = result.dl.paging_grants.size() + result.dl.rar_grants.size() + result.dl.ue_grants.size() + result.dl.bc.sibs.size(); const unsigned nof_puschs = result.ul.puschs.size(); @@ -311,10 +308,8 @@ void scheduler_result_logger::log_debug(const sched_result& result) } } -void scheduler_result_logger::log_info(const sched_result& result) +void scheduler_result_logger::log_info(const sched_result& result, std::chrono::microseconds decision_latency) { - auto slot_stop_tp = std::chrono::high_resolution_clock::now(); - if (log_broadcast) { for (const sib_information& sib_info : result.dl.bc.sibs) { fmt::format_to(fmtbuf, @@ -386,7 +381,6 @@ void scheduler_result_logger::log_info(const sched_result& result) } if (fmtbuf.size() > 0) { - auto decision_latency = std::chrono::duration_cast(slot_stop_tp - slot_start_tp); const unsigned nof_pdschs = result.dl.paging_grants.size() + result.dl.rar_grants.size() + result.dl.ue_grants.size() + result.dl.bc.sibs.size(); const unsigned nof_puschs = result.ul.puschs.size(); @@ -402,14 +396,15 @@ void scheduler_result_logger::log_info(const sched_result& result) } } -void scheduler_result_logger::on_scheduler_result(const sched_result& result) +void scheduler_result_logger::on_scheduler_result(const sched_result& result, + std::chrono::microseconds decision_latency) { if (not enabled) { return; } if (logger.debug.enabled()) { - log_debug(result); + log_debug(result, decision_latency); } else { - log_info(result); + log_info(result, decision_latency); } } diff --git a/lib/scheduler/logging/scheduler_result_logger.h b/lib/scheduler/logging/scheduler_result_logger.h index c145278c16..fceb043b9a 100644 --- a/lib/scheduler/logging/scheduler_result_logger.h +++ b/lib/scheduler/logging/scheduler_result_logger.h @@ -33,27 +33,23 @@ class scheduler_result_logger public: explicit scheduler_result_logger(bool log_broadcast_, pci_t pci_); - void on_slot_start() - { - if (enabled) { - slot_start_tp = std::chrono::high_resolution_clock::now(); - } - } - - void on_scheduler_result(const sched_result& result); + /// Log scheduler result for a specific cell and slot. + /// \param[in] result Scheduling result for this slot. + /// \param[in] slot_latency Latency that it took for the scheduler to make the decision for the slot. + void on_scheduler_result(const sched_result& result, + std::chrono::microseconds slot_latency = std::chrono::microseconds{0}); private: - void log_debug(const sched_result& result); + void log_debug(const sched_result& result, std::chrono::microseconds slot_latency); - void log_info(const sched_result& result); + void log_info(const sched_result& result, std::chrono::microseconds slot_latency); srslog::basic_logger& logger; bool log_broadcast; bool enabled; const pci_t pci; - std::chrono::time_point slot_start_tp; - fmt::memory_buffer fmtbuf; + fmt::memory_buffer fmtbuf; }; } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index eeb993f697..ccdae5bbe3 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -604,6 +604,9 @@ void ue_event_manager::handle_error_indication(slot_point // Log event. du_cells[cell_index].ev_logger->enqueue(scheduler_event_logger::error_indication_event{sl_tx, event}); + + // Report metrics. + metrics_handler.handle_error_indication(); }); } diff --git a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h index e5bb7a255f..772622495b 100644 --- a/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h +++ b/lib/scheduler/ue_scheduling/ue_fallback_scheduler.h @@ -302,7 +302,7 @@ class ue_fallback_scheduler // TODO: Find proper values for these 2 parameters. // Set the max number of slots the scheduler can look ahead in the resource grid (with respect to the current slot) to // find PDSCH space for SRB0 or SRB1. - const unsigned max_dl_slots_ahead_sched = 8U; + const unsigned max_dl_slots_ahead_sched = 4U; // Set the max number of attempts the scheduler can do while running through the nested loops over the PDSCH time // allocation indices and the ahead slots for all UEs. This is to avoid excessive long iterations in case many UEs. // NOTE: max_dl_sched_attempts = (max_dl_slots_ahead_sched + 1) * max_pdsch_time_res guarantees that at 1 UE will be diff --git a/lib/security/security.cpp b/lib/security/security.cpp index b36b28ee5b..f3e4044708 100644 --- a/lib/security/security.cpp +++ b/lib/security/security.cpp @@ -106,12 +106,12 @@ void security_context::horizontal_key_derivation(pci_t target_pci, unsigned targ generate_as_keys(); } -sec_128_as_config security_context::get_128_as_config(sec_domain domain) +sec_128_as_config security_context::get_128_as_config(sec_domain domain) const { return truncate_config(get_as_config(domain)); } -sec_as_config security_context::get_as_config(sec_domain domain) +sec_as_config security_context::get_as_config(sec_domain domain) const { srsran_sanity_check(sel_algos.algos_selected, "Tried to get AS config, but no algorithms are selected"); sec_as_config as_cfg; diff --git a/tests/benchmarks/du_high/du_high_benchmark.cpp b/tests/benchmarks/du_high/du_high_benchmark.cpp index 8e7d26bbe1..d3c88dee72 100644 --- a/tests/benchmarks/du_high/du_high_benchmark.cpp +++ b/tests/benchmarks/du_high/du_high_benchmark.cpp @@ -205,13 +205,13 @@ static void print_args(const bench_params& params) fmt::print("- Max DL RB grant size [RBs]: {}\n", params.max_dl_rb_grant); } -class dummy_metrics_handler : public scheduler_ue_metrics_notifier +class dummy_metrics_handler : public scheduler_metrics_notifier { public: - void report_metrics(span ue_metrics) override + void report_metrics(const scheduler_cell_metrics& metrics) override { unsigned sum_dl_bs = 0; - for (const auto& ue : ue_metrics) { + for (const auto& ue : metrics.ue_metrics) { sum_dl_bs += ue.dl_bs; } tot_dl_bs.store(sum_dl_bs, std::memory_order_relaxed); @@ -668,7 +668,7 @@ class du_high_bench } template - bool run_slot_until(const StopCondition& cond_func, unsigned slot_timeout = 1000) + bool run_slot_until(const StopCondition& cond_func, unsigned slot_timeout = 100000) { unsigned count = 0; for (; count < slot_timeout; ++count) { @@ -744,7 +744,7 @@ class du_high_bench not is_tdd_full_ul_slot(cfg.cells[to_du_cell_index(0)].tdd_ul_dl_cfg_common.value(), slot_point(next_sl_tx - tx_rx_delay - 1).slot_index()); }; - run_slot_until(next_ul_slot); + report_fatal_error_if_not(run_slot_until(next_ul_slot), "No slot for Msg3 was detected"); // Received Msg3 with UL-CCCH message. mac_rx_data_indication rx_ind; @@ -753,6 +753,7 @@ class du_high_bench rx_ind.pdus.push_back(mac_rx_pdu{ rnti, 0, 0, byte_buffer::create({0x34, 0x1e, 0x4f, 0xc0, 0x4f, 0xa6, 0x06, 0x3f, 0x00, 0x00, 0x00}).value()}); du_hi->get_pdu_handler().handle_rx_data_indication(std::move(rx_ind)); + test_logger.info("rnti={}: Msg3 forwarded to DU-high", rnti); // Wait for Msg4. auto dl_pdu_sched = [this, rnti]() { @@ -761,7 +762,8 @@ class du_high_bench } return false; }; - run_slot_until(dl_pdu_sched); + report_fatal_error_if_not(run_slot_until(dl_pdu_sched), "Msg4 with RRC Setup was not scheduled"); + test_logger.info("rnti={}: DU-high scheduled Msg4 (containing RRC Setup)", rnti); // Push MAC UL SDU that will trigger UE Context Setup. // Note: MAC UL SDU will make the UE go out of fallback mode. diff --git a/tests/benchmarks/phy/upper/equalization/channel_equalizer_benchmark.cpp b/tests/benchmarks/phy/upper/equalization/channel_equalizer_benchmark.cpp index b86ab82e7a..2c19974a0d 100644 --- a/tests/benchmarks/phy/upper/equalization/channel_equalizer_benchmark.cpp +++ b/tests/benchmarks/phy/upper/equalization/channel_equalizer_benchmark.cpp @@ -123,24 +123,24 @@ int main(int argc, char** argv) unsigned nof_subcarriers = nof_prb * NRE; // Create input and output data tensors. - dynamic_tensor(re_dims::nof_dims), cf_t, re_dims> rx_symbols( + dynamic_tensor(re_dims::nof_dims), cbf16_t, re_dims> rx_symbols( {nof_subcarriers * nof_ofdm_symbols, nof_rx_ports}); std::vector eq_symbols(nof_subcarriers * nof_ofdm_symbols * nof_tx_layers); std::vector eq_noise_vars(nof_subcarriers * nof_ofdm_symbols * nof_tx_layers); // Create channel estimates tensor. - dynamic_tensor(ch_dims::nof_dims), cf_t, ch_dims> channel_ests( + dynamic_tensor(ch_dims::nof_dims), cbf16_t, ch_dims> channel_ests( {nof_subcarriers * nof_ofdm_symbols, nof_rx_ports, nof_tx_layers}); for (unsigned i_rx_port = 0; i_rx_port != nof_rx_ports; ++i_rx_port) { // Generate Rx symbols. - span symbols = rx_symbols.get_view<>({i_rx_port}); + span symbols = rx_symbols.get_view<>({i_rx_port}); std::generate( symbols.begin(), symbols.end(), [&symbol_dist]() { return cf_t(symbol_dist(rgen), symbol_dist(rgen)); }); for (unsigned i_tx_layer = 0; i_tx_layer != nof_tx_layers; ++i_tx_layer) { // Generate estimates. - span ests = channel_ests.get_view<>({i_rx_port, i_tx_layer}); + span ests = channel_ests.get_view<>({i_rx_port, i_tx_layer}); std::generate(ests.begin(), ests.end(), [&ch_mag_dist, &ch_phase_dist]() { return std::polar(ch_mag_dist(rgen), ch_phase_dist(rgen)); }); diff --git a/tests/benchmarks/scheduler/scheduler_test_doubles.h b/tests/benchmarks/scheduler/scheduler_test_doubles.h index 64ffa44824..7655d2cebc 100644 --- a/tests/benchmarks/scheduler/scheduler_test_doubles.h +++ b/tests/benchmarks/scheduler/scheduler_test_doubles.h @@ -34,10 +34,10 @@ class sched_cfg_dummy_notifier : public sched_configuration_notifier void on_ue_delete_response(du_ue_index_t ue_index) override {} }; -class sched_dummy_metric_notifier final : public scheduler_ue_metrics_notifier +class sched_dummy_metric_notifier final : public scheduler_metrics_notifier { public: - void report_metrics(span ue_metrics) override {} + void report_metrics(const scheduler_cell_metrics& metrics) override {} }; } // namespace srsran diff --git a/tests/e2e/tests/reestablishment.py b/tests/e2e/tests/reestablishment.py index 27e117f58b..1c57001024 100644 --- a/tests/e2e/tests/reestablishment.py +++ b/tests/e2e/tests/reestablishment.py @@ -51,6 +51,8 @@ ue_validate_no_reattaches, ) +_ONLY_RERUN = ["failed to start", "Attach timeout reached", "StatusCode.ABORTED", "socket is already closed"] + @mark.parametrize( "band, common_scs, bandwidth, noise_spd", @@ -62,12 +64,12 @@ ), ) @mark.zmq -@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "StatusCode.ABORTED"]) +@mark.flaky(reruns=2, only_rerun=_ONLY_RERUN) # pylint: disable=too-many-arguments,too-many-locals def test_zmq_reestablishment_sequentially( retina_manager: RetinaTestManager, retina_data: RetinaTestData, - ue_32: Tuple[UEStub, ...], + ue_8: Tuple[UEStub, ...], fivegc: FiveGCStub, gnb: GNBStub, metrics_summary: MetricsSummary, @@ -85,7 +87,7 @@ def test_zmq_reestablishment_sequentially( for reest_ue_attach_info_dict, other_ue_attach_info_dict in _iterator_over_attached_ues( retina_manager=retina_manager, retina_data=retina_data, - ue_array=ue_32, + ue_array=ue_8, fivegc=fivegc, gnb=gnb, metrics_summary=metrics_summary, @@ -129,7 +131,7 @@ def test_zmq_reestablishment_sequentially( (param(3, 15, 50, 0, id="band:%s-scs:%s-bandwidth:%s-noise:%s"),), ) @mark.zmq -@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "StatusCode.ABORTED"]) +@mark.flaky(reruns=2, only_rerun=_ONLY_RERUN) # pylint: disable=too-many-arguments,too-many-locals def test_zmq_reestablishment_sequentially_full_rate( retina_manager: RetinaTestManager, @@ -197,7 +199,7 @@ def test_zmq_reestablishment_sequentially_full_rate( ), ) @mark.zmq -@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "StatusCode.ABORTED"]) +@mark.flaky(reruns=2, only_rerun=_ONLY_RERUN) # pylint: disable=too-many-arguments,too-many-locals def test_zmq_reestablishment_parallel( retina_manager: RetinaTestManager, @@ -262,7 +264,7 @@ def test_zmq_reestablishment_parallel( (param(3, 15, 50, 0, id="band:%s-scs:%s-bandwidth:%s-noise:%s"),), ) @mark.zmq -@mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "StatusCode.ABORTED"]) +@mark.flaky(reruns=2, only_rerun=_ONLY_RERUN) # pylint: disable=too-many-arguments,too-many-locals def test_zmq_reestablishment_parallel_full_rate( retina_manager: RetinaTestManager, diff --git a/tests/e2e/tests/viavi.py b/tests/e2e/tests/viavi.py index 515bfcd6e3..1debe471ff 100644 --- a/tests/e2e/tests/viavi.py +++ b/tests/e2e/tests/viavi.py @@ -47,7 +47,7 @@ from .steps.stub import GNB_STARTUP_TIMEOUT, handle_start_error, stop _OMIT_VIAVI_FAILURE_LIST = ["authentication"] -_POD_ERROR = "Error creating the pod" +_FLAKY_ERROR_LIST = ["Error creating the pod", "Viavi API call timed out"] # pylint: disable=too-many-instance-attributes @@ -203,7 +203,7 @@ def test_viavi_manual( @mark.viavi @mark.flaky( reruns=2, - only_rerun=[_POD_ERROR], + only_rerun=_FLAKY_ERROR_LIST, ) # pylint: disable=too-many-arguments, too-many-locals def test_viavi( @@ -259,7 +259,7 @@ def test_viavi( @mark.viavi_debug @mark.flaky( reruns=2, - only_rerun=[_POD_ERROR], + only_rerun=_FLAKY_ERROR_LIST, ) # pylint: disable=too-many-arguments, too-many-locals def test_viavi_debug( @@ -544,7 +544,13 @@ def get_str_number_criteria(number_criteria: float) -> str: """ Get string number criteria """ - return f"{number_criteria:.2e}" if abs(number_criteria) > 1000 else str(number_criteria) + if number_criteria >= 1_000_000_000: + return f"{number_criteria / 1_000_000_000:.1f}G" + if number_criteria >= 1_000_000: + return f"{number_criteria / 1_000_000:.1f}M" + if number_criteria >= 1_000: + return f"{number_criteria / 1_000:.1f}K" + return str(number_criteria) def get_viavi_configuration_from_testname(campaign_filename: str, test_name: str, timeout: int) -> _ViaviConfiguration: diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 0788f9555d..2d144ca058 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -37,11 +37,12 @@ expected_dl_bitrate_high: &expected_dl_bitrate_high 1400000000 expected_ul_bitrate_high: &expected_ul_bitrate_high 100000000 expected_dl_bitrate_low: &expected_dl_bitrate_low 14000 expected_ul_bitrate_low: &expected_ul_bitrate_low 1000 +test_timeout: &test_timeout 2700 # 45 * 60 tests: - campaign_filename: *campaign_filename test_name: "1UE ideal UDP bidirectional" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "1UE ideal UDP bidirectional" max_pdschs_per_slot: 8 @@ -55,7 +56,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal UDP bidirectional" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "32UE ideal UDP bidirectional" max_pdschs_per_slot: 1 @@ -69,7 +70,7 @@ tests: - campaign_filename: *campaign_filename test_name: "1UE fading UDP uplink" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "1UE fading UDP uplink" max_pdschs_per_slot: 8 @@ -83,7 +84,7 @@ tests: - campaign_filename: *campaign_filename test_name: "1UE fading noise UDP uplink" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "1UE fading noise UDP uplink" max_pdschs_per_slot: 8 @@ -97,7 +98,7 @@ tests: - campaign_filename: *campaign_filename test_name: "1UE ideal TCP downlink" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "1UE ideal TCP downlink" max_pdschs_per_slot: 8 @@ -111,7 +112,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal TCP downlink" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "32UE ideal TCP downlink" max_pdschs_per_slot: 1 @@ -125,7 +126,7 @@ tests: - campaign_filename: *campaign_filename test_name: "1UE fading TCP downlink" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "1UE fading TCP downlink" max_pdschs_per_slot: 8 @@ -137,23 +138,23 @@ tests: fail_if_kos: false warning_as_errors: true - - campaign_filename: *campaign_filename - test_name: "32UE fading TCP bidirectional" - test_timeout: 2700 # 45 * 60 - gnb_extra_commands: *gnb_extra_commands - id: "32UE fading TCP bidirectional" - max_pdschs_per_slot: 1 - max_puschs_per_slot: 1 - enable_qos_viavi: false - # test/fail criteria - expected_dl_bitrate: *expected_dl_bitrate_low - expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: false - warning_as_errors: false + # - campaign_filename: *campaign_filename + # test_name: "32UE fading TCP bidirectional" + # test_timeout: *test_timeout + # gnb_extra_commands: *gnb_extra_commands + # id: "32UE fading TCP bidirectional" + # max_pdschs_per_slot: 1 + # max_puschs_per_slot: 1 + # enable_qos_viavi: false + # # test/fail criteria + # expected_dl_bitrate: *expected_dl_bitrate_low + # expected_ul_bitrate: *expected_ul_bitrate_low + # fail_if_kos: false + # warning_as_errors: false - campaign_filename: *campaign_filename test_name: "32UE ideal UDP attach-detach with traffic" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "32UE ideal UDP attach-detach with traffic" max_pdschs_per_slot: 1 @@ -165,23 +166,23 @@ tests: fail_if_kos: true warning_as_errors: true - - campaign_filename: *campaign_filename - test_name: "32UE fading UDP attach-detach with traffic" - test_timeout: 2700 # 45 * 60 - gnb_extra_commands: *gnb_extra_commands - id: "32UE fading UDP attach-detach with traffic" - max_pdschs_per_slot: 1 - max_puschs_per_slot: 1 - enable_qos_viavi: false - # test/fail criteria - expected_dl_bitrate: *expected_dl_bitrate_low - expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: false - warning_as_errors: false + # - campaign_filename: *campaign_filename + # test_name: "32UE fading UDP attach-detach with traffic" + # test_timeout: *test_timeout + # gnb_extra_commands: *gnb_extra_commands + # id: "32UE fading UDP attach-detach with traffic" + # max_pdschs_per_slot: 1 + # max_puschs_per_slot: 1 + # enable_qos_viavi: false + # # test/fail criteria + # expected_dl_bitrate: *expected_dl_bitrate_low + # expected_ul_bitrate: *expected_ul_bitrate_low + # fail_if_kos: false + # warning_as_errors: false - campaign_filename: *campaign_filename test_name: "1UE birth-death UDP bidirectional" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "1UE birth-death UDP bidirectional" max_pdschs_per_slot: 8 @@ -193,23 +194,23 @@ tests: fail_if_kos: false warning_as_errors: true - - campaign_filename: *campaign_filename - test_name: "32UE birth-death UDP bidirectional" - test_timeout: 2700 # 45 * 60 - gnb_extra_commands: *gnb_extra_commands - id: "32UE birth-death UDP bidirectional" - max_pdschs_per_slot: 1 - max_puschs_per_slot: 1 - enable_qos_viavi: false - # test/fail criteria - expected_dl_bitrate: *expected_dl_bitrate_low - expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: false - warning_as_errors: true + # - campaign_filename: *campaign_filename + # test_name: "32UE birth-death UDP bidirectional" + # test_timeout: *test_timeout + # gnb_extra_commands: *gnb_extra_commands + # id: "32UE birth-death UDP bidirectional" + # max_pdschs_per_slot: 1 + # max_puschs_per_slot: 1 + # enable_qos_viavi: false + # # test/fail criteria + # expected_dl_bitrate: *expected_dl_bitrate_low + # expected_ul_bitrate: *expected_ul_bitrate_low + # fail_if_kos: false + # warning_as_errors: true - campaign_filename: *campaign_filename test_name: "32UE ideal ping" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "32UE ideal ping" max_pdschs_per_slot: 1 @@ -223,7 +224,7 @@ tests: - campaign_filename: *campaign_filename test_name: "32UE ideal ping with traffic" - test_timeout: 2700 # 45 * 60 + test_timeout: *test_timeout gnb_extra_commands: *gnb_extra_commands id: "32UE ideal ping with traffic" max_pdschs_per_slot: 1 diff --git a/tests/integrationtests/ngap/ngap_integration_test.cpp b/tests/integrationtests/ngap/ngap_integration_test.cpp index 880ded8832..c6f2c542b0 100644 --- a/tests/integrationtests/ngap/ngap_integration_test.cpp +++ b/tests/integrationtests/ngap/ngap_integration_test.cpp @@ -141,7 +141,7 @@ class ngap_integration_test : public ::testing::Test nw_config.non_blocking_mode = true; adapter = std::make_unique(nw_config); - ngap = create_ngap(cfg, cu_cp_notifier, cu_cp_paging_notifier, ue_mng, *adapter, timers, ctrl_worker); + ngap = create_ngap(cfg, cu_cp_notifier, cu_cp_paging_notifier, *adapter, timers, ctrl_worker); } ngap_configuration cfg; @@ -149,7 +149,7 @@ class ngap_integration_test : public ::testing::Test up_resource_manager_cfg up_config; timer_manager timers; manual_task_worker ctrl_worker{128}; - ue_manager ue_mng{ue_config, up_config, timers, ctrl_worker}; + ue_manager ue_mng{ue_config, up_config, {}, timers, ctrl_worker}; dummy_ngap_cu_cp_notifier cu_cp_notifier{ue_mng}; dummy_ngap_cu_cp_paging_notifier cu_cp_paging_notifier; std::unique_ptr adapter; diff --git a/tests/test_doubles/mac/dummy_scheduler_ue_metric_notifier.h b/tests/test_doubles/mac/dummy_scheduler_ue_metric_notifier.h index 9e84f50fa3..dcbb627fdc 100644 --- a/tests/test_doubles/mac/dummy_scheduler_ue_metric_notifier.h +++ b/tests/test_doubles/mac/dummy_scheduler_ue_metric_notifier.h @@ -27,15 +27,12 @@ namespace srsran { /// Sink for scheduler UE metrics. -class dummy_scheduler_ue_metrics_notifier : public scheduler_ue_metrics_notifier +class dummy_scheduler_ue_metrics_notifier : public scheduler_metrics_notifier { public: - std::vector last_ue_metrics; + scheduler_cell_metrics last_metrics; - void report_metrics(span ue_metrics) override - { - last_ue_metrics = std::vector(ue_metrics.begin(), ue_metrics.end()); - } + void report_metrics(const scheduler_cell_metrics& metrics) override { last_metrics = metrics; } }; -} // namespace srsran \ No newline at end of file +} // namespace srsran diff --git a/tests/unittests/apps/services/metrics_plotter_stdout_test.cpp b/tests/unittests/apps/services/metrics_plotter_stdout_test.cpp index 84b0d94750..3973a44932 100644 --- a/tests/unittests/apps/services/metrics_plotter_stdout_test.cpp +++ b/tests/unittests/apps/services/metrics_plotter_stdout_test.cpp @@ -30,15 +30,15 @@ using namespace srsran; /// This is meant to visually and (currently still) manually verify the correct /// metrics formatting and plotting. -static std::vector reports; +static scheduler_cell_metrics reports; void fill_metrics_single_ue() { scheduler_ue_metrics ue; - ue.pci = 500; - ue.rnti = to_rnti(0x4601); - ue.cqi = 4; - ue.ri = 1; + ue.pci = 500; + ue.rnti = to_rnti(0x4601); + ue.cqi_stats.update(4); + ue.ri_stats.update(1); ue.dl_mcs = 28; ue.dl_brate_kbps = 1 * 1024; // 1Mbit ue.dl_nof_ok = 900; @@ -52,7 +52,7 @@ void fill_metrics_single_ue() ue.ul_nof_nok = 1; ue.bsr = 8192; ue.dl_bs = 100000; - reports.push_back(ue); + reports.ue_metrics.push_back(ue); } int main() diff --git a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h index 3d90e339eb..c94d2a85e3 100644 --- a/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h +++ b/tests/unittests/cu_cp/cell_meas_manager/cell_meas_manager_test_helpers.h @@ -66,7 +66,8 @@ class cell_meas_manager_test : public ::testing::Test timer_manager timers; ue_configuration ue_config; up_resource_manager_cfg up_config; - ue_manager ue_mng{ue_config, up_config, timers, ctrl_worker}; + security_manager_config sec_config; + ue_manager ue_mng{ue_config, up_config, sec_config, timers, ctrl_worker}; }; } // namespace srs_cu_cp diff --git a/tests/unittests/cu_cp/cu_cp_test.cpp b/tests/unittests/cu_cp/cu_cp_test.cpp index fe302dd46b..0cf27c8ef7 100644 --- a/tests/unittests/cu_cp/cu_cp_test.cpp +++ b/tests/unittests/cu_cp/cu_cp_test.cpp @@ -26,6 +26,7 @@ #include "srsran/asn1/ngap/ngap_pdu_contents.h" #include "srsran/ngap/ngap_types.h" #include "srsran/ran/cu_types.h" +#include "srsran/support/test_utils.h" #include using namespace srsran; diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.cpp b/tests/unittests/cu_cp/cu_cp_test_messages.cpp index 8cb60c7009..f6da61d19c 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.cpp +++ b/tests/unittests/cu_cp/cu_cp_test_messages.cpp @@ -40,10 +40,12 @@ cu_cp_ue_context_release_command srsran::srs_cu_cp::generate_ue_context_release_ } cu_cp_pdu_session_resource_setup_request -srsran::srs_cu_cp::generate_pdu_session_resource_setup(unsigned num_pdu_sessions, unsigned num_qos_flows) +srsran::srs_cu_cp::generate_pdu_session_resource_setup(ue_index_t ue_index, + unsigned num_pdu_sessions, + unsigned num_qos_flows) { cu_cp_pdu_session_resource_setup_request req; - req.ue_index = uint_to_ue_index(0); + req.ue_index = ue_index; req.ue_aggregate_maximum_bit_rate_dl = 1000; @@ -85,12 +87,12 @@ srsran::srs_cu_cp::generate_pdu_session_resource_setup(unsigned num_pdu_sessions return req; }; -cu_cp_pdu_session_resource_release_command srsran::srs_cu_cp::generate_pdu_session_resource_release() +cu_cp_pdu_session_resource_release_command srsran::srs_cu_cp::generate_pdu_session_resource_release(ue_index_t ue_index) { cu_cp_pdu_session_resource_release_command cmd; pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(1); - cmd.ue_index = uint_to_ue_index(0); + cmd.ue_index = ue_index; cu_cp_pdu_session_res_to_release_item_rel_cmd pdu_session_res_to_release_item_rel_cmd; pdu_session_res_to_release_item_rel_cmd.pdu_session_id = pdu_session_id; @@ -102,11 +104,11 @@ cu_cp_pdu_session_resource_release_command srsran::srs_cu_cp::generate_pdu_sessi return cmd; }; -cu_cp_pdu_session_resource_modify_request srsran::srs_cu_cp::generate_pdu_session_resource_modification(unsigned psi, - unsigned qfi) +cu_cp_pdu_session_resource_modify_request +srsran::srs_cu_cp::generate_pdu_session_resource_modification(ue_index_t ue_index, unsigned psi, unsigned qfi) { cu_cp_pdu_session_resource_modify_request request; - request.ue_index = uint_to_ue_index(0); + request.ue_index = ue_index; cu_cp_pdu_session_res_modify_item_mod_req modify_item; modify_item.pdu_session_id = uint_to_pdu_session_id(psi); diff --git a/tests/unittests/cu_cp/cu_cp_test_messages.h b/tests/unittests/cu_cp/cu_cp_test_messages.h index 2fb0cc3241..6bd4a5c1cc 100644 --- a/tests/unittests/cu_cp/cu_cp_test_messages.h +++ b/tests/unittests/cu_cp/cu_cp_test_messages.h @@ -36,15 +36,16 @@ namespace srs_cu_cp { cu_cp_ue_context_release_command generate_ue_context_release_command(ue_index_t ue_index); /// \brief Generate a dummy PDU Session Resource Setup request. -cu_cp_pdu_session_resource_setup_request generate_pdu_session_resource_setup(unsigned num_pdu_sessions = 1, - unsigned num_qos_flows = 1); +cu_cp_pdu_session_resource_setup_request generate_pdu_session_resource_setup(ue_index_t ue_index = ue_index_t::min, + unsigned num_pdu_sessions = 1, + unsigned num_qos_flows = 1); /// \brief Generate a dummy PDU Session Resource Release Command. -cu_cp_pdu_session_resource_release_command generate_pdu_session_resource_release(); +cu_cp_pdu_session_resource_release_command generate_pdu_session_resource_release(ue_index_t ue_index = ue_index_t::min); /// \brief Generate a dummy PDU Session Resource Modification Request. -cu_cp_pdu_session_resource_modify_request generate_pdu_session_resource_modification(unsigned psi = 1, - unsigned qfi = 2); +cu_cp_pdu_session_resource_modify_request +generate_pdu_session_resource_modification(ue_index_t ue_index = ue_index_t::min, unsigned psi = 1, unsigned qfi = 2); /// \brief Generate a dummy PDU Session Resource Modification Request with QoS flow to remove item. cu_cp_pdu_session_resource_modify_request diff --git a/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.cpp b/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.cpp index dc0c209330..39b67309ab 100644 --- a/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.cpp @@ -37,7 +37,7 @@ cu_up_processor_test::cu_up_processor_test() cu_up_cfg.cu_up_index = uint_to_cu_up_index(0); cu_up_processor_obj = - create_cu_up_processor(std::move(cu_up_cfg), e1ap_notifier, cu_cp_notifier, ue_mng, task_sched, ctrl_worker); + create_cu_up_processor(std::move(cu_up_cfg), e1ap_notifier, cu_cp_notifier, task_sched, ctrl_worker); } cu_up_processor_test::~cu_up_processor_test() diff --git a/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.h b/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.h index c427ac9ff6..ea0ac8e677 100644 --- a/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.h +++ b/tests/unittests/cu_cp/cu_up_processor/cu_up_processor_test_helpers.h @@ -28,7 +28,7 @@ #include "lib/cu_cp/cu_up_processor/cu_up_processor_impl_interface.h" #include "lib/cu_cp/task_schedulers/cu_up_task_scheduler.h" #include "lib/cu_cp/ue_manager/ue_manager_impl.h" -#include "tests/unittests/e1ap/common/test_helpers.h" +#include "tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/support/executors/manual_task_worker.h" #include "srsran/support/test_utils.h" @@ -49,9 +49,9 @@ class cu_up_processor_test : public ::testing::Test timer_manager timers; dummy_e1ap_message_notifier e1ap_notifier; - dummy_e1ap_cu_cp_notifier cu_cp_notifier; manual_task_worker ctrl_worker{128}; - ue_manager ue_mng{{}, {}, timers, ctrl_worker}; + ue_manager ue_mng{{}, {}, {}, timers, ctrl_worker}; + dummy_e1ap_cu_cp_notifier cu_cp_notifier{ue_mng}; std::unique_ptr cu_up_processor_obj; uint16_t max_nof_cu_ups = 4; cu_up_task_scheduler task_sched{timers, ctrl_worker, max_nof_cu_ups, test_logger}; diff --git a/tests/unittests/cu_cp/du_processor/CMakeLists.txt b/tests/unittests/cu_cp/du_processor/CMakeLists.txt index 465f06cb72..620395f3f9 100644 --- a/tests/unittests/cu_cp/du_processor/CMakeLists.txt +++ b/tests/unittests/cu_cp/du_processor/CMakeLists.txt @@ -33,6 +33,7 @@ target_link_libraries(du_processor_test_helpers srslog) set(SOURCES + du_configuration_manager_test.cpp du_processor_test.cpp ) diff --git a/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp b/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp new file mode 100644 index 0000000000..a0a9e350fb --- /dev/null +++ b/tests/unittests/cu_cp/du_processor/du_configuration_manager_test.cpp @@ -0,0 +1,117 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "lib/cu_cp/du_processor/du_configuration_manager.h" +#include "srsran/ran/nr_cgi_helpers.h" +#include "srsran/rrc/rrc_config.h" +#include + +using namespace srsran; +using namespace srs_cu_cp; + +static rrc_cfg_t create_basic_rrc_config() +{ + rrc_cfg_t cfg{}; + cfg.gnb_id = {411, 22}; + return cfg; +} + +static cu_cp_served_cell_info create_basic_served_cell_info() +{ + cu_cp_served_cell_info cell_info; + cell_info.nr_cgi.mcc = 1; + cell_info.nr_cgi.mnc = 1; + cell_info.nr_cgi.plmn = "00101"; + cell_info.nr_cgi.plmn_hex = "00f110"; + cell_info.nr_cgi.nci = config_helpers::make_nr_cell_identity({411, 22}, 0x1); + cell_info.five_gs_tac = 7; + cell_info.nr_pci = 1; + return cell_info; +} + +static du_setup_request create_basic_du_setup_request() +{ + du_setup_request req; + req.gnb_du_id = gnb_du_id_t::min; + req.gnb_du_name = "srsdu"; + auto& cell = req.gnb_du_served_cells_list.emplace_back(); + cell.served_cell_info = create_basic_served_cell_info(); + cell.gnb_du_sys_info.emplace(); + cell.gnb_du_sys_info->mib_msg = byte_buffer::create({0x0, 0x1, 0x2}).value(); + cell.gnb_du_sys_info->sib1_msg = byte_buffer::create({0x3, 0x4, 0x5}).value(); + return req; +} + +class du_configuration_manager_test : public ::testing::Test +{ +public: + du_configuration_manager_test() : du_cfg_mng(rrc_cfg) {} + + rrc_cfg_t rrc_cfg = create_basic_rrc_config(); + du_configuration_manager du_cfg_mng; +}; + +TEST_F(du_configuration_manager_test, when_instance_created_then_it_has_no_dus) +{ + ASSERT_EQ(du_cfg_mng.nof_dus(), 0); +} + +TEST_F(du_configuration_manager_test, when_du_config_handler_is_created_then_it_has_no_context) +{ + auto du_cfg_updater = du_cfg_mng.create_du_handler(); + ASSERT_NE(du_cfg_updater, nullptr); + ASSERT_FALSE(du_cfg_updater->has_context()); +} + +TEST_F(du_configuration_manager_test, when_du_is_setup_successfully_then_context_is_updated) +{ + auto du_cfg_updater = du_cfg_mng.create_du_handler(); + auto setup_req = create_basic_du_setup_request(); + auto ret = du_cfg_updater->handle_new_du_config(setup_req); + ASSERT_TRUE(ret.has_value()) << "DU setup failed: " << ret.error().cause_str; + ASSERT_EQ(du_cfg_mng.nof_dus(), 1); +} + +TEST_F(du_configuration_manager_test, when_du_cfg_handler_goes_out_of_scope_then_du_config_is_removed) +{ + { + auto du_cfg_updater = du_cfg_mng.create_du_handler(); + auto setup_req = create_basic_du_setup_request(); + auto ret = du_cfg_updater->handle_new_du_config(setup_req); + ASSERT_EQ(du_cfg_mng.nof_dus(), 1); + } + ASSERT_EQ(du_cfg_mng.nof_dus(), 0); +} + +TEST_F(du_configuration_manager_test, when_du_has_duplicate_du_id_then_setup_fails) +{ + auto du_cfg_updater = du_cfg_mng.create_du_handler(); + auto setup_req = create_basic_du_setup_request(); + auto ret = du_cfg_updater->handle_new_du_config(setup_req); + ASSERT_TRUE(ret.has_value()); + + auto du_cfg_updater2 = du_cfg_mng.create_du_handler(); + ret = du_cfg_updater2->handle_new_du_config(setup_req); + ASSERT_FALSE(ret.has_value()); + ASSERT_EQ(du_cfg_mng.nof_dus(), 1); + fmt::print("DU creation failed with error: {}\n", ret.error().cause_str); +} diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test.cpp index 459e925146..65145d6132 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test.cpp @@ -20,6 +20,7 @@ * */ +#include "../du_processor_test_messages.h" #include "du_processor_test_helpers.h" #include "lib/cu_cp/du_processor/du_processor.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp index e7e50c4a89..eb1b6c4d69 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp @@ -21,9 +21,10 @@ */ #include "du_processor_test_helpers.h" +#include "../du_processor_test_messages.h" +#include "lib/cu_cp/cu_cp_controller/common_task_scheduler.h" #include "tests/unittests/cu_cp/test_helpers.h" -#include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" -#include "srsran/support/async/async_test_utils.h" +#include "tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.h" #include using namespace srsran; @@ -42,7 +43,8 @@ class dummy_task_sched final : public common_task_scheduler } // namespace -du_processor_test::du_processor_test() : common_task_sched(std::make_unique()) +du_processor_test::du_processor_test() : + rrc_cfg{gnb_id_t{411, 22}}, common_task_sched(std::make_unique()), du_cfg_mgr{rrc_cfg} { test_logger.set_level(srslog::basic_levels::debug); cu_cp_logger.set_level(srslog::basic_levels::debug); @@ -52,6 +54,7 @@ du_processor_test::du_processor_test() : common_task_sched(std::make_uniqueget_f1ap_interface().handle_ue_rrc_context_creation_request(req); } diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h index dcd593f1f3..46a6470246 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h @@ -22,20 +22,17 @@ #pragma once -#include "../du_processor_test_messages.h" #include "../test_helpers.h" #include "du_processor_test_helpers.h" +#include "lib/cu_cp/du_processor/du_configuration_manager.h" #include "lib/cu_cp/du_processor/du_processor.h" #include "lib/cu_cp/du_processor/du_processor_factory.h" #include "lib/cu_cp/ue_manager/ue_manager_impl.h" -#include "lib/f1ap/common/asn1_helpers.h" #include "tests/unittests/f1ap/common/test_helpers.h" -#include "tests/unittests/f1ap/cu_cp/f1ap_cu_test_helpers.h" #include "tests/unittests/rrc/test_helpers.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/rrc/rrc.h" +#include "srsran/support/async/async_test_utils.h" #include "srsran/support/executors/manual_task_worker.h" -#include "srsran/support/test_utils.h" #include namespace srsran { @@ -55,11 +52,22 @@ class du_processor_test : public ::testing::Test srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP"); - timer_manager timers; - manual_task_worker ctrl_worker{128}; - ue_configuration ue_config; - up_resource_manager_cfg up_config; - ue_manager ue_mng{ue_config, up_config, timers, ctrl_worker}; + rrc_cfg_t rrc_cfg; + timer_manager timers; + manual_task_worker ctrl_worker{128}; + ue_configuration ue_config; + up_resource_manager_cfg up_config; + + security_manager_config sec_config{{security::integrity_algorithm::nia2, + security::integrity_algorithm::nia1, + security::integrity_algorithm::nia3, + security::integrity_algorithm::nia0}, + {security::ciphering_algorithm::nea0, + security::ciphering_algorithm::nea2, + security::ciphering_algorithm::nea1, + security::ciphering_algorithm::nea3}}; + + ue_manager ue_mng{ue_config, up_config, sec_config, timers, ctrl_worker}; dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; dummy_du_processor_cu_cp_notifier cu_cp_notifier{&ue_mng}; dummy_du_connection_notifier du_conn_notifier; @@ -68,6 +76,7 @@ class du_processor_test : public ::testing::Test dummy_rrc_ue_cu_cp_adapter rrc_ue_cu_cp_notifier; dummy_rrc_du_cu_cp_adapter rrc_du_cu_cp_notifier; std::unique_ptr common_task_sched; + du_configuration_manager du_cfg_mgr; std::unique_ptr du_processor_obj; async_task t; diff --git a/tests/unittests/cu_cp/du_processor_test_messages.cpp b/tests/unittests/cu_cp/du_processor_test_messages.cpp index 6039a81763..6d8c0cea50 100644 --- a/tests/unittests/cu_cp/du_processor_test_messages.cpp +++ b/tests/unittests/cu_cp/du_processor_test_messages.cpp @@ -32,7 +32,7 @@ using namespace srs_cu_cp; void srsran::srs_cu_cp::generate_valid_f1_setup_request(du_setup_request& setup_request, gnb_du_id_t gnb_du_id, - unsigned nrcell_id, + nr_cell_id_t nrcell_id, pci_t pci) { f1ap_message f1setup_msg = test_helpers::generate_f1_setup_request(gnb_du_id, nrcell_id, pci); @@ -85,15 +85,16 @@ void srsran::srs_cu_cp::generate_f1_setup_request_with_too_many_cells(du_setup_r } ue_rrc_context_creation_request -srsran::srs_cu_cp::generate_ue_rrc_context_creation_request(ue_index_t ue_index, rnti_t c_rnti, unsigned nrcell_id) +srsran::srs_cu_cp::generate_ue_rrc_context_creation_request(ue_index_t ue_index, rnti_t c_rnti, nr_cell_id_t nrcell_id) { ue_rrc_context_creation_request req = {}; req.ue_index = ue_index; req.c_rnti = c_rnti; - asn1::f1ap::nr_cgi_s asn1_cgi; - asn1_cgi.nr_cell_id.from_number(nrcell_id); - asn1_cgi.plmn_id.from_string("02f899"); - req.cgi = cgi_from_asn1(asn1_cgi); + req.cgi.mcc = 61441; + req.cgi.mnc = 65281; + req.cgi.plmn = "00101"; + req.cgi.plmn_hex = "00f110"; + req.cgi.nci = nrcell_id; asn1::unbounded_octstring tmp; tmp.from_string( "5c00b001117aec701061e0007c20408d07810020a2090480ca8000f800000000008370842000088165000048200002069a06aa49880002" diff --git a/tests/unittests/cu_cp/du_processor_test_messages.h b/tests/unittests/cu_cp/du_processor_test_messages.h index c0f6842039..143e672ff9 100644 --- a/tests/unittests/cu_cp/du_processor_test_messages.h +++ b/tests/unittests/cu_cp/du_processor_test_messages.h @@ -34,8 +34,9 @@ namespace srs_cu_cp { /// \brief Generate a valid dummy F1 Setup Request. void generate_valid_f1_setup_request(du_setup_request& setup_request, gnb_du_id_t gnb_du_id = int_to_gnb_du_id(0x11), - unsigned nrcell_id = config_helpers::make_nr_cell_identity(gnb_id_t{411, 22}, 0), - pci_t pci = 0); + nr_cell_id_t nrcell_id = config_helpers::make_nr_cell_identity(gnb_id_t{411, 22}, + 0), + pci_t pci = 0); /// \brief Generate a dummy F1 Setup Request base to extend. void generate_f1_setup_request_base(du_setup_request& setup_request); @@ -50,9 +51,9 @@ void generate_f1_setup_request_with_too_many_cells(du_setup_request& set /// \param[in] nrcell_id The NR Cell Id to use. /// \return The dummy UE Creation Message. ue_rrc_context_creation_request generate_ue_rrc_context_creation_request( - ue_index_t ue_index, - rnti_t c_rnti, - unsigned nrcell_id = config_helpers::make_nr_cell_identity(gnb_id_t{411, 22}, 0)); + ue_index_t ue_index, + rnti_t c_rnti, + nr_cell_id_t nrcell_id = config_helpers::make_nr_cell_identity(gnb_id_t{411, 22}, 0)); } // namespace srs_cu_cp } // namespace srsran diff --git a/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp b/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp index ee4e2b3403..64c458d85b 100644 --- a/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp +++ b/tests/unittests/cu_cp/mobility/handover_reconfiguration_routine_test.cpp @@ -77,14 +77,14 @@ class handover_reconfiguration_routine_test : public mobility_test rnti_t source_rnti = to_rnti(0x4601); dummy_du_processor_rrc_ue_control_message_notifier source_rrc_ue_notifier; dummy_f1ap_ue_context_manager source_f1ap_ue_ctxt_mng; - du_ue* source_ue = nullptr; + cu_cp_ue* source_ue = nullptr; // target UE parameters. du_index_t target_du_index = uint_to_du_index(1); unsigned target_pci = 2; rnti_t target_rnti = to_rnti(0x4601); dummy_du_processor_rrc_ue_control_message_notifier target_rrc_ue_notifier; - du_ue* target_ue = nullptr; + cu_cp_ue* target_ue = nullptr; async_task t; std::optional> t_launcher; diff --git a/tests/unittests/cu_cp/mobility/mobility_test_helpers.h b/tests/unittests/cu_cp/mobility/mobility_test_helpers.h index c3fde183fe..d4cca9eba3 100644 --- a/tests/unittests/cu_cp/mobility/mobility_test_helpers.h +++ b/tests/unittests/cu_cp/mobility/mobility_test_helpers.h @@ -46,11 +46,21 @@ class mobility_test : public cu_cp_test srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP"); - manual_task_worker ctrl_worker{128}; - timer_manager timers; - ue_configuration ue_config; - up_resource_manager_cfg up_config; - ue_manager ue_mng{ue_config, up_config, timers, ctrl_worker}; + manual_task_worker ctrl_worker{128}; + timer_manager timers; + ue_configuration ue_config; + up_resource_manager_cfg up_config; + + security_manager_config sec_config{{security::integrity_algorithm::nia2, + security::integrity_algorithm::nia1, + security::integrity_algorithm::nia3, + security::integrity_algorithm::nia0}, + {security::ciphering_algorithm::nea0, + security::ciphering_algorithm::nea2, + security::ciphering_algorithm::nea1, + security::ciphering_algorithm::nea3}}; + + ue_manager ue_mng{ue_config, up_config, sec_config, timers, ctrl_worker}; dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; dummy_cu_cp_ue_context_manipulation_handler cu_cp_handler; }; diff --git a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp b/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp index ee078fbedd..45973410df 100644 --- a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.cpp @@ -32,16 +32,7 @@ cu_cp_routine_manager_test::cu_cp_routine_manager_test() test_logger.set_level(srslog::basic_levels::debug); cu_cp_logger.set_level(srslog::basic_levels::debug); srslog::init(); - drb_cfg = {}; - drb_cfg.five_qi_config[uint_to_five_qi(9)] = {}; - drb_cfg.five_qi_config[uint_to_five_qi(9)].pdcp.tx.sn_size = pdcp_sn_size::size12bits; - drb_cfg.five_qi_config[uint_to_five_qi(9)].pdcp.rx.sn_size = pdcp_sn_size::size12bits; - drb_cfg.five_qi_config[uint_to_five_qi(7)] = {}; - drb_cfg.five_qi_config[uint_to_five_qi(7)].pdcp.tx.sn_size = pdcp_sn_size::size12bits; - drb_cfg.five_qi_config[uint_to_five_qi(7)].pdcp.rx.sn_size = pdcp_sn_size::size12bits; - - rrc_ue_up_resource_manager = std::make_unique(drb_cfg); // create routine manager routine_mng = std::make_unique(ue_mng, default_security_indication, cu_cp_logger); diff --git a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h b/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h index accff2878d..0e7907325e 100644 --- a/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h +++ b/tests/unittests/cu_cp/routines/cu_cp_routine_manager_test_helpers.h @@ -25,7 +25,9 @@ #include "../test_helpers.h" #include "lib/cu_cp/routine_managers/cu_cp_routine_manager.h" #include "lib/cu_cp/ue_manager/ue_manager_impl.h" -#include "lib/cu_cp/up_resource_manager/up_resource_manager_impl.h" +#include "srsran/pdcp/pdcp_config.h" +#include "srsran/ran/five_qi.h" +#include "srsran/support/executors/manual_task_worker.h" #include namespace srsran { @@ -46,7 +48,15 @@ class cu_cp_routine_manager_test : public ::testing::Test ue_configuration ue_config{std::chrono::seconds{10}}; srsran::security::sec_as_config security_cfg; security_indication_t default_security_indication = {}; - up_resource_manager_cfg drb_cfg; + + pdcp_config pdcp_cfg{pdcp_rb_type::drb, + pdcp_rlc_mode::am, + {}, + {}, + {pdcp_sn_size::size12bits}, + {pdcp_sn_size::size12bits}}; + + up_resource_manager_cfg up_config{{{uint_to_five_qi(9), {pdcp_cfg}}, {uint_to_five_qi(7), {pdcp_cfg}}}}; timer_manager timers; manual_task_worker ctrl_worker{128}; @@ -54,12 +64,11 @@ class cu_cp_routine_manager_test : public ::testing::Test dummy_f1ap_ue_context_manager f1ap_ue_ctxt_mng; dummy_ngap_control_message_handler ngap_control_handler; dummy_ue_task_scheduler ue_task_sched{timers, ctrl_worker}; - ue_manager ue_mng{ue_config, drb_cfg, timers, ctrl_worker}; + ue_manager ue_mng{ue_config, up_config, {}, timers, ctrl_worker}; dummy_du_processor_rrc_ue_control_message_notifier rrc_ue_ctrl_notifier; dummy_du_processor_rrc_ue_srb_control_notifier rrc_ue_srb_ctrl_notifier; dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; dummy_cu_cp_ue_removal_handler ue_removal_handler{&ue_mng}; - std::unique_ptr rrc_ue_up_resource_manager; std::unique_ptr routine_mng; }; diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp b/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp index b2ed06443e..8b25d64ef9 100644 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp +++ b/tests/unittests/cu_cp/routines/pdu_session_resource_modification_routine_test.cpp @@ -20,11 +20,10 @@ * */ +#include "../cu_cp_test_messages.h" #include "cu_cp_routine_manager_test_helpers.h" -#include "lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h" #include "pdu_session_resource_routine_test_helpers.h" #include "srsran/support/async/async_test_utils.h" -#include "srsran/support/test_utils.h" #include using namespace srsran; @@ -49,7 +48,11 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi void start_procedure(const cu_cp_pdu_session_resource_modify_request& msg) { t = routine_mng->start_pdu_session_resource_modification_routine( - msg, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, *rrc_ue_up_resource_manager); + msg, + e1ap_bearer_ctxt_mng, + f1ap_ue_ctxt_mng, + rrc_ue_ctrl_notifier, + ue_mng.find_ue(msg.ue_index)->get_up_resource_manager()); t_launcher.emplace(t); } @@ -58,7 +61,7 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi const cu_cp_pdu_session_resource_modify_response& result() { return t.get(); } // Preamble to setup a initial PDU session. - void setup_pdu_session() + void setup_pdu_session(ue_index_t ue_index) { // Set expected results for sub-procedures. e1ap_bearer_ctxt_mng.set_first_message_outcome({true, {1}, {}}); @@ -71,14 +74,15 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi ASSERT_FALSE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); // Run setup procedure. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); async_task setup_task = - routine_mng->start_pdu_session_resource_setup_routine(request, - security_cfg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - *rrc_ue_up_resource_manager); + routine_mng->start_pdu_session_resource_setup_routine( + request, + security_cfg, + e1ap_bearer_ctxt_mng, + f1ap_ue_ctxt_mng, + rrc_ue_ctrl_notifier, + ue_mng.find_ue(request.ue_index)->get_up_resource_manager()); lazy_task_launcher setup_launcher(setup_task); // Verify successful outcome. @@ -91,7 +95,8 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi rrc_ue_ctrl_notifier.reset(); } - void modify_pdu_session_and_add_qos_flow(unsigned psi, unsigned drb_id, unsigned qfi, bool success) + void + modify_pdu_session_and_add_qos_flow(ue_index_t ue_index, unsigned psi, unsigned drb_id, unsigned qfi, bool success) { // Set expected results for sub-procedures. bearer_context_outcome_t first_bearer_ctxt_mod_outcome; @@ -120,10 +125,14 @@ class pdu_session_resource_modification_test : public pdu_session_resource_routi ASSERT_FALSE(e1ap_bearer_ctxt_mng.second_e1ap_request.has_value()); // Run PDU session modification. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(psi, qfi); + cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index, psi, qfi); async_task modify_task = routine_mng->start_pdu_session_resource_modification_routine( - request, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, *rrc_ue_up_resource_manager); + request, + e1ap_bearer_ctxt_mng, + f1ap_ue_ctxt_mng, + rrc_ue_ctrl_notifier, + ue_mng.find_ue(request.ue_index)->get_up_resource_manager()); lazy_task_launcher modify_launcher(modify_task); // Verify content of UE context modification. @@ -156,7 +165,8 @@ TEST_F(pdu_session_resource_modification_test, when_modification_request_with_inactive_pdu_session_arrives_then_modification_fails) { // Test Preamble. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(1, 1); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index, 1, 1); // Start modification routine (without setting any results). start_procedure(request); @@ -170,13 +180,14 @@ TEST_F(pdu_session_resource_modification_test, TEST_F(pdu_session_resource_modification_test, when_bearer_ctxt_modification_fails_then_pdu_session_modification_fails) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Set expected results for sub-procedures. set_expected_results({false}, {}, {}, false); // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(1, 2); + cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index, 1, 2); start_procedure(request); // Verify content of initial bearer modification request. @@ -205,7 +216,8 @@ TEST_F(pdu_session_resource_modification_test, when_bearer_ctxt_modification_fai TEST_F(pdu_session_resource_modification_test, when_ue_ctxt_modification_fails_then_pdu_session_modification_fails) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Set expected results for sub-procedures. bearer_context_outcome_t first_bearer_ctxt_mod_outcome; @@ -219,7 +231,7 @@ TEST_F(pdu_session_resource_modification_test, when_ue_ctxt_modification_fails_t set_expected_results(first_bearer_ctxt_mod_outcome, {false}, {}, false); // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(); + cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index); start_procedure(request); // Verify content of UE context modification. @@ -235,7 +247,8 @@ TEST_F(pdu_session_resource_modification_test, when_second_bearer_ctxt_modification_fails_then_pdu_session_modification_fails) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Set expected results for sub-procedures. bearer_context_outcome_t first_bearer_ctxt_mod_outcome; @@ -255,7 +268,7 @@ TEST_F(pdu_session_resource_modification_test, set_expected_results(first_bearer_ctxt_mod_outcome, ue_cxt_mod_outcome, second_bearer_ctxt_mod_outcome, false); // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(); + cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index); start_procedure(request); // Verify content of 2nd bearer context modification request. @@ -275,7 +288,8 @@ TEST_F(pdu_session_resource_modification_test, TEST_F(pdu_session_resource_modification_test, when_rrc_reconfiguration_fails_then_pdu_session_modification_fails) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Set expected results for sub-procedures. bearer_context_outcome_t first_bearer_ctxt_mod_outcome; @@ -300,7 +314,7 @@ TEST_F(pdu_session_resource_modification_test, when_rrc_reconfiguration_fails_th set_expected_results(first_bearer_ctxt_mod_outcome, ue_cxt_mod_outcome, second_bearer_ctxt_mod_outcome, false); // Start modification routine. - cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(); + cu_cp_pdu_session_resource_modify_request request = generate_pdu_session_resource_modification(ue_index); start_procedure(request); // Verify content of UE context modification. @@ -317,20 +331,22 @@ TEST_F(pdu_session_resource_modification_test, when_valid_modification_arrives_and_subprocedures_succeed_then_pdu_session_modification_succeeds) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Run PDU session modification and add second QoS flow. - modify_pdu_session_and_add_qos_flow(1, 2, 2, true); + modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, true); } TEST_F(pdu_session_resource_modification_test, when_valid_modification_arrives_and_qos_flow_can_be_removed_then_pdu_session_modification_succeeds) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Run PDU session modification and add second QoS flow. - modify_pdu_session_and_add_qos_flow(1, 2, 2, true); + modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, true); // Test body. @@ -393,36 +409,39 @@ TEST_F(pdu_session_resource_modification_test, TEST_F(pdu_session_resource_modification_test, when_many_qos_flows_are_added_pdu_session_modification_succeeds) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Add QoS flows until maximum number of DRBs is reached. for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow(1, i, i, true); + modify_pdu_session_and_add_qos_flow(ue_index, 1, i, i, true); } } TEST_F(pdu_session_resource_modification_test, when_one_to_many_qos_flows_are_added_last_pdu_session_modification_fails) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Add QoS flows until maximum number of DRBs is reached. for (unsigned i = 2; i <= MAX_NOF_DRBS; ++i) { - modify_pdu_session_and_add_qos_flow(1, i, i, true); + modify_pdu_session_and_add_qos_flow(ue_index, 1, i, i, true); } // Try to add one more QoS flow but addtion should fail. - modify_pdu_session_and_add_qos_flow(1, MAX_NOF_DRBS + 1, MAX_NOF_DRBS + 1, false); + modify_pdu_session_and_add_qos_flow(ue_index, 1, MAX_NOF_DRBS + 1, MAX_NOF_DRBS + 1, false); } TEST_F(pdu_session_resource_modification_test, when_valid_modification_is_received_twice_then_second_modification_fails) { // Test Preamble - Setup a single PDU session initially. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); // Run PDU session modification and add second QoS flow. - modify_pdu_session_and_add_qos_flow(1, 2, 2, true); + modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, true); // Run PDU session modification again and try to add same QoS flow. - modify_pdu_session_and_add_qos_flow(1, 2, 2, false); + modify_pdu_session_and_add_qos_flow(ue_index, 1, 2, 2, false); } diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp b/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp index 1618bc1485..44bee02c6b 100644 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp +++ b/tests/unittests/cu_cp/routines/pdu_session_resource_release_routine_test.cpp @@ -20,6 +20,7 @@ * */ +#include "../cu_cp_test_messages.h" #include "cu_cp_routine_manager_test_helpers.h" #include "pdu_session_resource_routine_test_helpers.h" #include "srsran/support/async/async_test_utils.h" @@ -41,13 +42,14 @@ class pdu_session_resource_release_test : public pdu_session_resource_routine_te f1ap_ue_ctxt_mng.set_ue_context_modification_outcome(ue_context_modification_outcome); e1ap_bearer_ctxt_mng.set_second_message_outcome(bearer_context_modification_outcome); - t = routine_mng->start_pdu_session_resource_release_routine(msg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - ngap_control_handler, - rrc_ue_ctrl_notifier, - ue_task_sched, - *rrc_ue_up_resource_manager); + t = routine_mng->start_pdu_session_resource_release_routine( + msg, + e1ap_bearer_ctxt_mng, + f1ap_ue_ctxt_mng, + ngap_control_handler, + rrc_ue_ctrl_notifier, + ue_task_sched, + ue_mng.find_ue(msg.ue_index)->get_up_resource_manager()); t_launcher.emplace(t); } @@ -64,10 +66,10 @@ class pdu_session_resource_release_test : public pdu_session_resource_routine_te return true; } - void setup_pdu_session() + void setup_pdu_session(ue_index_t ue_index) { // Setup single PDU session. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); std::optional> setup_launcher; bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; @@ -81,12 +83,13 @@ class pdu_session_resource_release_test : public pdu_session_resource_routine_te rrc_ue_ctrl_notifier.set_rrc_reconfiguration_outcome(true); async_task setup_task = - routine_mng->start_pdu_session_resource_setup_routine(request, - security_cfg, - e1ap_bearer_ctxt_mng, - f1ap_ue_ctxt_mng, - rrc_ue_ctrl_notifier, - *rrc_ue_up_resource_manager); + routine_mng->start_pdu_session_resource_setup_routine( + request, + security_cfg, + e1ap_bearer_ctxt_mng, + f1ap_ue_ctxt_mng, + rrc_ue_ctrl_notifier, + ue_mng.find_ue(request.ue_index)->get_up_resource_manager()); setup_launcher.emplace(setup_task); } @@ -97,9 +100,10 @@ class pdu_session_resource_release_test : public pdu_session_resource_routine_te TEST_F(pdu_session_resource_release_test, when_ue_context_modification_failure_received_then_release_succeeds) { // Test Preamble. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(); + cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); // Start PDU SESSION RESOURCE RELEASE routine. bearer_context_outcome_t bearer_context_modification_outcome{false}; @@ -112,9 +116,10 @@ TEST_F(pdu_session_resource_release_test, when_ue_context_modification_failure_r TEST_F(pdu_session_resource_release_test, when_bearer_context_modification_failure_received_then_release_succeeds) { // Test Preamble. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(); + cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); // Start PDU SESSION RESOURCE RELEASE routine. bearer_context_outcome_t bearer_context_modification_outcome{true}; @@ -128,8 +133,9 @@ TEST_F(pdu_session_resource_release_test, when_bearer_context_modification_failu TEST_F(pdu_session_resource_release_test, when_empty_pdu_session_release_command_received_then_release_fails) { // Test Preamble. - cu_cp_pdu_session_resource_release_command command = {}; // empty message - command.ue_index = uint_to_ue_index(0); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_release_command command = {}; // empty message + command.ue_index = ue_index; // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_modification_outcome{true}; @@ -145,9 +151,10 @@ TEST_F(pdu_session_resource_release_test, when_empty_pdu_session_release_command TEST_F(pdu_session_resource_release_test, when_all_sub_actions_succeed_then_release_succeeds) { // Test Preamble. - setup_pdu_session(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + setup_pdu_session(ue_index); - cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(); + cu_cp_pdu_session_resource_release_command command = generate_pdu_session_resource_release(ue_index); // Start PDU SESSION RESOURCE RELEASE routine. start_procedure(command, {true}, {true}); diff --git a/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp b/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp index d2520131aa..d37d16a2c2 100644 --- a/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp +++ b/tests/unittests/cu_cp/routines/pdu_session_resource_setup_routine_test.cpp @@ -20,11 +20,10 @@ * */ +#include "../cu_cp_test_messages.h" #include "cu_cp_routine_manager_test_helpers.h" -#include "lib/e1ap/cu_cp/e1ap_cu_cp_asn1_helpers.h" #include "pdu_session_resource_routine_test_helpers.h" #include "srsran/support/async/async_test_utils.h" -#include "srsran/support/test_utils.h" #include using namespace srsran; @@ -48,8 +47,12 @@ class pdu_session_resource_setup_test : public pdu_session_resource_routine_test void start_procedure(const cu_cp_pdu_session_resource_setup_request& msg) { - t = routine_mng->start_pdu_session_resource_setup_routine( - msg, security_cfg, e1ap_bearer_ctxt_mng, f1ap_ue_ctxt_mng, rrc_ue_ctrl_notifier, *rrc_ue_up_resource_manager); + t = routine_mng->start_pdu_session_resource_setup_routine(msg, + security_cfg, + e1ap_bearer_ctxt_mng, + f1ap_ue_ctxt_mng, + rrc_ue_ctrl_notifier, + ue_mng.find_ue(msg.ue_index)->get_up_resource_manager()); t_launcher.emplace(t); } @@ -96,7 +99,8 @@ class pdu_session_resource_setup_test : public pdu_session_resource_routine_test TEST_F(pdu_session_resource_setup_test, when_pdu_session_setup_request_with_unconfigured_fiveqi_received_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Tweak 5QI of first QoS flow request.pdu_session_res_setup_items.begin() ->qos_flow_setup_request_items.begin() @@ -123,7 +127,8 @@ TEST_F(pdu_session_resource_setup_test, when_pdu_session_setup_request_with_unco TEST_F(pdu_session_resource_setup_test, when_bearer_context_setup_failure_received_then_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{false, {}, {}}; @@ -142,7 +147,8 @@ TEST_F(pdu_session_resource_setup_test, when_bearer_context_setup_failure_receiv TEST_F(pdu_session_resource_setup_test, when_ue_context_modification_failure_received_then_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; @@ -160,7 +166,8 @@ TEST_F(pdu_session_resource_setup_test, when_ue_context_modification_failure_rec TEST_F(pdu_session_resource_setup_test, when_bearer_context_modification_failure_received_then_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; @@ -194,7 +201,8 @@ TEST_F(pdu_session_resource_setup_test, when_bearer_context_modification_failure TEST_F(pdu_session_resource_setup_test, when_rrc_reconfiguration_fails_then_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; @@ -212,7 +220,8 @@ TEST_F(pdu_session_resource_setup_test, when_rrc_reconfiguration_fails_then_setu TEST_F(pdu_session_resource_setup_test, when_rrc_reconfiguration_succeeds_then_setup_succeeds) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; @@ -255,7 +264,8 @@ TEST_F(pdu_session_resource_setup_test, when_rrc_reconfiguration_succeeds_then_s TEST_F(pdu_session_resource_setup_test, when_pdu_session_setup_for_existing_session_arrives_then_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; @@ -288,8 +298,9 @@ TEST_F(pdu_session_resource_setup_test, when_pdu_session_setup_for_existing_sess TEST_F(pdu_session_resource_setup_test, when_empty_pdu_session_setup_request_received_then_setup_fails) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = {}; // empty message - request.ue_index = uint_to_ue_index(0); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = {}; // empty message + request.ue_index = ue_index; // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {}, {}}; @@ -314,7 +325,8 @@ TEST_F(pdu_session_resource_setup_test, when_empty_pdu_session_setup_request_rec TEST_F(pdu_session_resource_setup_test, when_setup_for_pdu_sessions_with_two_qos_flows_received_setup_succeeds) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(1, 2); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 1, 2); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; // first session success, second failed @@ -354,7 +366,8 @@ TEST_F(pdu_session_resource_setup_test, when_setup_for_two_pdu_sessions_is_requested_but_only_first_could_be_setup_at_cuup_setup_succeeds_with_fail_list) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(2); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 2, 1); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {2}}; // first session success, second failed @@ -380,7 +393,8 @@ TEST_F(pdu_session_resource_setup_test, TEST_F(pdu_session_resource_setup_test, when_setup_for_two_pdu_sessions_is_requested_and_both_succeed_setup_succeeds) { // Test Preamble. - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(2); + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 2, 1); // Start PDU SESSION RESOURCE SETUP routine. bearer_context_outcome_t bearer_context_setup_outcome{true, {1, 2}, {}}; // first session success, second failed @@ -406,9 +420,11 @@ TEST_F(pdu_session_resource_setup_test, when_setup_for_two_pdu_sessions_is_reque /// Test with two consecutive requests. Both with one PDU session. TEST_F(pdu_session_resource_setup_test, when_two_consecutive_setups_arrive_bearer_setup_and_modification_succeed) { + ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + // Initial PDU SESSION RESOURCE SETUP procdure using default executor. { - cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(1); + cu_cp_pdu_session_resource_setup_request request = generate_pdu_session_resource_setup(ue_index, 1); bearer_context_outcome_t bearer_context_setup_outcome{true, {1}, {}}; // PDU session 1 setup success, no failure ue_context_outcome_t ue_context_modification_outcome{true, {1}}; @@ -440,7 +456,8 @@ TEST_F(pdu_session_resource_setup_test, when_two_consecutive_setups_arrive_beare { // Generate 2nd request for different PDU session ID (we generate a request for two sessions and delete the first) - cu_cp_pdu_session_resource_setup_request request2 = generate_pdu_session_resource_setup(2, 1); + // ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); + cu_cp_pdu_session_resource_setup_request request2 = generate_pdu_session_resource_setup(ue_index, 2); request2.pdu_session_res_setup_items.erase(uint_to_pdu_session_id(1)); // Modify 5QI such that a new DRB is going to be created. diff --git a/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp b/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp index 5997495b62..444cc4db67 100644 --- a/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp +++ b/tests/unittests/cu_cp/routines/ue_context_release_routine_test.cpp @@ -20,6 +20,7 @@ * */ +#include "../cu_cp_test_messages.h" #include "cu_cp_routine_manager_test_helpers.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/support/async/async_test_utils.h" @@ -45,7 +46,7 @@ class ue_context_release_test : public cu_cp_routine_manager_test ue_index_t add_ue(pci_t pci, rnti_t c_rnti) { ue_index_t ue_index = ue_mng.add_ue(du_index_t::min); - du_ue* ue = ue_mng.set_ue_du_context(ue_index, int_to_gnb_du_id(0), pci, c_rnti); + cu_cp_ue* ue = ue_mng.set_ue_du_context(ue_index, int_to_gnb_du_id(0), pci, c_rnti); // Set parameters from creation message ue->set_pcell_index(du_cell_index_t::min); ue->set_rrc_ue_notifier(rrc_ue_ctrl_notifier); diff --git a/tests/unittests/cu_cp/test_helpers.h b/tests/unittests/cu_cp/test_helpers.h index c1aff631b6..a3e32d74ab 100644 --- a/tests/unittests/cu_cp/test_helpers.h +++ b/tests/unittests/cu_cp/test_helpers.h @@ -22,19 +22,14 @@ #pragma once -#include "cu_cp_test_messages.h" -#include "du_processor_test_messages.h" #include "lib/cu_cp/cu_cp_controller/node_connection_notifier.h" #include "lib/cu_cp/cu_cp_impl_interface.h" #include "lib/cu_cp/cu_up_processor/cu_up_processor_impl_interface.h" #include "lib/cu_cp/du_processor/du_processor.h" #include "lib/cu_cp/ue_manager/ue_manager_impl.h" -#include "tests/unittests/ngap/ngap_test_helpers.h" #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/support/async/async_task.h" -#include "srsran/support/async/async_test_utils.h" #include "srsran/support/async/fifo_async_task_scheduler.h" -#include "srsran/support/test_utils.h" #include #include #include @@ -599,12 +594,6 @@ struct dummy_du_processor_rrc_ue_control_message_notifier : public du_processor_ byte_buffer get_packed_handover_preparation_message() override { return byte_buffer{}; } - bool on_new_security_context(const security::security_context& sec_context) override - { - logger.info("Received a new security context."); - return true; - } - byte_buffer on_new_rrc_handover_command(byte_buffer cmd) override { return byte_buffer{}; } byte_buffer on_rrc_handover_command_required(const rrc_reconfiguration_procedure_request& request, @@ -655,8 +644,7 @@ struct dummy_du_processor_rrc_du_ue_notifier : public du_processor_rrc_du_ue_not return true; } - rrc_ue_interface* on_ue_creation_request(up_resource_manager& up_resource_mng, - const rrc_ue_creation_message& msg) override + rrc_ue_interface* on_ue_creation_request(const rrc_ue_creation_message& msg) override { logger.info("Received a UE creation request"); return nullptr; diff --git a/tests/unittests/cu_cp/ue_manager/ue_manager_test.cpp b/tests/unittests/cu_cp/ue_manager/ue_manager_test.cpp index abc28fac25..1d663416e9 100644 --- a/tests/unittests/cu_cp/ue_manager/ue_manager_test.cpp +++ b/tests/unittests/cu_cp/ue_manager/ue_manager_test.cpp @@ -145,29 +145,6 @@ TEST_F(ue_manager_test, when_ue_exists_then_removal_successful) // check that the UE has been removed ASSERT_EQ(ue_mng.get_nof_du_ues(du_index), 0U); - - // No NGAP context has been added, so the UE should be completely removed - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), 0U); -} - -/// Test successful removal of a DU UE -TEST_F(ue_manager_test, when_ngap_ue_context_exists_then_du_ue_removal_successful) -{ - du_index_t du_index = uint_to_du_index(0); - ue_index_t ue_index = ue_mng.add_ue(du_index); - rnti_t rnti = to_rnti(0x4601); - - auto* ue = ue_mng.set_ue_du_context(ue_index, int_to_gnb_du_id(0), MIN_PCI, rnti); - - // add a NGAP context - auto* ue_ngap = ue_mng.set_ue_ng_context(ue->get_ue_index(), rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - // check that the UE has been created - ASSERT_NE(ue_ngap, nullptr); - - ue_mng.remove_ue(ue->get_ue_index()); - - // check that the UE has been removed - ASSERT_EQ(ue_mng.get_nof_ues(), 0U); } /// Test creation of multiple DU UEs @@ -260,178 +237,3 @@ TEST_F(ue_manager_test, when_more_than_max_ues_added_then_ue_not_created) // check that the UE has not been added ASSERT_EQ(ue_mng.get_nof_du_ues(du_index), MAX_NOF_UES_PER_DU); } - -////////////////////////////////////////////////////////////////////////////////////// -/* NGAP UE */ -////////////////////////////////////////////////////////////////////////////////////// - -/// Test creation of NGAP UE before creation of a DU UE -TEST_F(ue_manager_test, when_ue_not_created_then_ngap_ue_not_added) -{ - auto* ue = ue_mng.set_ue_ng_context(uint_to_ue_index(0), rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the UE has not been added - ASSERT_EQ(ue, nullptr); - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), 0U); -} - -/// Test successful creation of a NGAP UE -TEST_F(ue_manager_test, when_ue_created_then_then_ngap_ue_added) -{ - ue_index_t ue_index = create_ue(uint_to_du_index(0), int_to_gnb_du_id(0), MIN_PCI, to_rnti(0x4601)); - - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the NGAP UE has been added - ASSERT_NE(ue, nullptr); - ASSERT_NE(ue_mng.find_ngap_ue(ue->get_ue_index()), nullptr); - - // check that the UE index is valid - ASSERT_NE(ue->get_ue_index(), ue_index_t::invalid); - - // check that the number of NGAP UEs is 1 - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), 1U); -} - -/// Test finding invalid UE index -TEST_F(ue_manager_test, when_ue_index_invalid_then_ngap_ue_not_found) -{ - ue_index_t ue_index = create_ue(uint_to_du_index(0), int_to_gnb_du_id(0), MIN_PCI, to_rnti(0x4601)); - - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the NGAP UE has been created - ASSERT_NE(ue, nullptr); - - // check that ue with invalid UE index is not found - ASSERT_EQ(ue_mng.find_ngap_ue(ue_index_t::invalid), nullptr); -} - -/// Test duplicate UE creation -TEST_F(ue_manager_test, when_ngap_context_already_exits_then_ue_not_added) -{ - ue_index_t ue_index = create_ue(uint_to_du_index(0), int_to_gnb_du_id(0), MIN_PCI, to_rnti(0x4601)); - - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the NGAP UE has been created - ASSERT_NE(ue, nullptr); - - // check that the number of NGAP UEs is 1 - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), 1U); - - auto* ue2 = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the UE has not been added - ASSERT_EQ(ue2, nullptr); - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), 1U); -} - -/// Test successful removal of a NGAP UE -TEST_F(ue_manager_test, when_du_ue_context_exists_then_ngap_ue_removal_successful) -{ - du_index_t du_index = uint_to_du_index(0); - ue_index_t ue_index = create_ue(du_index, int_to_gnb_du_id(0), MIN_PCI, to_rnti(0x4601)); - - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - ue_mng.remove_ue(ue->get_ue_index()); - - // check that the UE has been removed - ASSERT_EQ(ue_mng.get_nof_ues(), 0U); -} - -/// Test successful removal of a NGAP UE -TEST_F(ue_manager_test, when_ngap_ue_exists_then_removal_successful) -{ - du_index_t du_index = uint_to_du_index(0); - - ue_index_t ue_index = create_ue(du_index, int_to_gnb_du_id(0), MIN_PCI, to_rnti(0x4601)); - - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - ue_mng.remove_ue(ue->get_ue_index()); - - // check that the DU UE has been removed - ASSERT_EQ(ue_mng.get_nof_du_ues(du_index), 0U); - - // check that the NGAP UE has been removed - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), 0U); -} - -/// Test creation of multiple DU UEs -TEST_F(ue_manager_test, when_multiple_ngap_ues_added_then_ues_exist) -{ - // reduce log level to avoid flooding the log - ue_mng_logger.set_level(srslog::basic_levels::warning); - test_logger.set_level(srslog::basic_levels::warning); - - for (unsigned du_idx = du_index_to_uint(du_index_t::min); du_idx <= max_nof_dus - 1; du_idx++) { - unsigned du_offset = du_idx * MAX_NOF_UES_PER_DU; - - for (unsigned it = to_value(rnti_t::MIN_CRNTI); it < unsigned(to_value(rnti_t::MIN_CRNTI) + MAX_NOF_UES_PER_DU); - it++) { - ue_index_t ue_index = create_ue(uint_to_du_index(du_idx), int_to_gnb_du_id(0), MIN_PCI, to_rnti(du_offset + it)); - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the UE has been created - ASSERT_NE(ue, nullptr); - ASSERT_NE(ue_mng.find_ngap_ue(ue->get_ue_index()), nullptr); - - // check that the UE index is valid - ASSERT_NE(ue->get_ue_index(), ue_index_t::invalid); - - // check that the number of NGAP UEs is increased - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), du_offset + it - to_value(rnti_t::MIN_CRNTI) + 1); - } - } - - // reset log level - ue_mng_logger.set_level(srslog::basic_levels::debug); - test_logger.set_level(srslog::basic_levels::debug); - - // check that the maximum number of NGAP UEs has been reached - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), ue_config.max_nof_supported_ues); -} - -/// Test creation of unsupported number of NGAP UEs -TEST_F(ue_manager_test, when_more_than_max_ues_added_then_ngap_ue_not_created) -{ - // reduce log level to avoid flooding the log - ue_mng_logger.set_level(srslog::basic_levels::warning); - test_logger.set_level(srslog::basic_levels::warning); - - for (unsigned du_idx = du_index_to_uint(du_index_t::min); du_idx <= max_nof_dus - 1; du_idx++) { - unsigned du_offset = du_idx * MAX_NOF_UES_PER_DU; - - for (unsigned it = to_value(rnti_t::MIN_CRNTI); it < unsigned(to_value(rnti_t::MIN_CRNTI) + MAX_NOF_UES_PER_DU); - it++) { - ue_index_t ue_index = create_ue(uint_to_du_index(du_idx), int_to_gnb_du_id(0), MIN_PCI, to_rnti(du_offset + it)); - auto* ue = ue_mng.set_ue_ng_context(ue_index, rrc_ue_pdu_notifier, rrc_ue_pdu_notifier); - - // check that the UE has been created - ASSERT_NE(ue, nullptr); - ASSERT_NE(ue_mng.find_ngap_ue(ue->get_ue_index()), nullptr); - - // check that the UE index is valid - ASSERT_NE(ue->get_ue_index(), ue_index_t::invalid); - - // check that the number of NGAP UEs is increased - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), du_offset + it - to_value(rnti_t::MIN_CRNTI) + 1); - } - } - - // reset log level - ue_mng_logger.set_level(srslog::basic_levels::debug); - test_logger.set_level(srslog::basic_levels::debug); - - // check that the maximum number of NGAP UEs has been reached - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), ue_config.max_nof_supported_ues); - - // Try allocating an additional UE index - ue_index_t ue_index = ue_mng.add_ue(du_index_t::max); - ASSERT_EQ(ue_index, ue_index_t::invalid); - - // check that the UE has not been added - ASSERT_EQ(ue_mng.get_nof_ngap_ues(), ue_config.max_nof_supported_ues); -} diff --git a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.cpp b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.cpp index 03593cd61e..5381d162a9 100644 --- a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.cpp +++ b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.cpp @@ -27,7 +27,7 @@ using namespace srsran; using namespace srs_cu_cp; -ue_manager_test::ue_manager_test() : ue_mng(ue_config, up_config, timers, cu_worker) +ue_manager_test::ue_manager_test() : ue_mng(ue_config, up_config, sec_config, timers, cu_worker) { test_logger.set_level(srslog::basic_levels::debug); ue_mng_logger.set_level(srslog::basic_levels::debug); diff --git a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h index efda0bd382..4ad5a15b78 100644 --- a/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h +++ b/tests/unittests/cu_cp/ue_manager/ue_manager_test_helpers.h @@ -26,6 +26,7 @@ #include "lib/cu_cp/ue_manager/ue_manager_impl.h" #include "tests/unittests/ngap/test_helpers.h" #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/support/executors/manual_task_worker.h" #include #include @@ -49,6 +50,7 @@ class ue_manager_test : public ::testing::Test ue_configuration ue_config{std::chrono::seconds{7200}, max_nof_dus* MAX_NOF_UES_PER_DU}; up_resource_manager_cfg up_config; + security_manager_config sec_config; timer_manager timers; manual_task_worker cu_worker{128}; ue_manager ue_mng; diff --git a/tests/unittests/cu_cp/up_resource_manager/up_resource_manager_test.cpp b/tests/unittests/cu_cp/up_resource_manager/up_resource_manager_test.cpp index f1e5173d27..296d74b7eb 100644 --- a/tests/unittests/cu_cp/up_resource_manager/up_resource_manager_test.cpp +++ b/tests/unittests/cu_cp/up_resource_manager/up_resource_manager_test.cpp @@ -21,8 +21,8 @@ */ #include "../cu_cp_test_messages.h" +#include "lib/cu_cp/up_resource_manager/up_resource_manager_impl.h" #include "srsran/adt/byte_buffer.h" -#include "srsran/cu_cp/up_resource_manager.h" #include "srsran/support/test_utils.h" #include @@ -40,41 +40,32 @@ class up_resource_manager_test : public ::testing::Test srslog::basic_logger& rrc_logger = srslog::fetch_basic_logger("RRC", false); rrc_logger.set_level(srslog::basic_levels::debug); rrc_logger.set_hex_dump_max_size(32); - - up_resource_manager_cfg cfg; - cfg.five_qi_config[uint_to_five_qi(9)] = {}; - pdcp_config p_cfg; - p_cfg.rb_type = pdcp_rb_type::drb; - p_cfg.rlc_mode = pdcp_rlc_mode::am; - cfg.five_qi_config[uint_to_five_qi(9)].pdcp = p_cfg; - cfg.five_qi_config[uint_to_five_qi(7)].pdcp = p_cfg; - manager = create_up_resource_manager(cfg); } void setup_initial_pdu_session() { cu_cp_pdu_session_resource_setup_request msg = generate_pdu_session_resource_setup(); - ASSERT_TRUE(manager->validate_request(msg.pdu_session_res_setup_items)); + ASSERT_TRUE(manager.validate_request(msg.pdu_session_res_setup_items)); // No DRB present - ASSERT_EQ(manager->get_nof_drbs(), 0); + ASSERT_EQ(manager.get_nof_drbs(), 0); // single PDU Session/DRB could be added const auto psi = uint_to_pdu_session_id(1); - up_config_update update = manager->calculate_update(msg.pdu_session_res_setup_items); + up_config_update update = manager.calculate_update(msg.pdu_session_res_setup_items); ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 1); ASSERT_EQ(update.pdu_sessions_to_setup_list.at(psi).drb_to_add.size(), 1); // Assume DRB setup was successful. up_config_update_result result; result.pdu_sessions_added_list.push_back(update.pdu_sessions_to_setup_list.at(psi)); - manager->apply_config_update(result); + manager.apply_config_update(result); // Verify PDU session and DRB were added - ASSERT_EQ(manager->get_nof_drbs(), 1); - ASSERT_EQ(manager->get_nof_pdu_sessions(), 1); - ASSERT_EQ(manager->get_nof_qos_flows(psi), 1); - ASSERT_EQ(manager->get_total_nof_qos_flows(), 1); + ASSERT_EQ(manager.get_nof_drbs(), 1); + ASSERT_EQ(manager.get_nof_pdu_sessions(), 1); + ASSERT_EQ(manager.get_nof_qos_flows(psi), 1); + ASSERT_EQ(manager.get_total_nof_qos_flows(), 1); } // This helper modifies the existing PDU session by adding a new QoS flow that should be mapped on a new DRB. @@ -84,8 +75,8 @@ class up_resource_manager_test : public ::testing::Test cu_cp_pdu_session_resource_modify_request msg = generate_pdu_session_resource_modification(); const auto psi = uint_to_pdu_session_id(1); - ASSERT_TRUE(manager->validate_request(msg)); - up_config_update update = manager->calculate_update(msg); + ASSERT_TRUE(manager.validate_request(msg)); + up_config_update update = manager.calculate_update(msg); // Verify calculated update. ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 0); @@ -95,13 +86,13 @@ class up_resource_manager_test : public ::testing::Test // Apply update. up_config_update_result result; result.pdu_sessions_modified_list.push_back(update.pdu_sessions_to_modify_list.at(psi)); - manager->apply_config_update(result); + manager.apply_config_update(result); // One PDU session with two QoS flows on two bearers. - ASSERT_EQ(manager->get_nof_pdu_sessions(), 1); - ASSERT_EQ(manager->get_total_nof_qos_flows(), 2); - ASSERT_EQ(manager->get_nof_drbs(), 2); - ASSERT_EQ(manager->get_nof_qos_flows(psi), 2); + ASSERT_EQ(manager.get_nof_pdu_sessions(), 1); + ASSERT_EQ(manager.get_total_nof_qos_flows(), 2); + ASSERT_EQ(manager.get_nof_drbs(), 2); + ASSERT_EQ(manager.get_nof_qos_flows(psi), 2); } void TearDown() override @@ -111,7 +102,9 @@ class up_resource_manager_test : public ::testing::Test } public: - std::unique_ptr manager; + pdcp_config pdcp_cfg{pdcp_rb_type::drb, pdcp_rlc_mode::am}; + up_resource_manager_cfg cfg{{{uint_to_five_qi(9), {pdcp_cfg}}, {uint_to_five_qi(7), {pdcp_cfg}}}}; + up_resource_manager manager{cfg}; }; TEST_F(up_resource_manager_test, when_initial_pdu_session_is_created_new_drb_is_set_up) @@ -122,29 +115,29 @@ TEST_F(up_resource_manager_test, when_initial_pdu_session_is_created_new_drb_is_ TEST_F(up_resource_manager_test, when_same_pdu_session_is_created_no_new_drb_is_set_up) { cu_cp_pdu_session_resource_setup_request msg = generate_pdu_session_resource_setup(); - ASSERT_TRUE(manager->validate_request(msg.pdu_session_res_setup_items)); + ASSERT_TRUE(manager.validate_request(msg.pdu_session_res_setup_items)); // single DRB should be added - up_config_update update = manager->calculate_update(msg.pdu_session_res_setup_items); + up_config_update update = manager.calculate_update(msg.pdu_session_res_setup_items); ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 1); ASSERT_EQ(update.pdu_sessions_to_setup_list.at(uint_to_pdu_session_id(1)).drb_to_add.size(), 1); // Assume DRB setup was successful. up_config_update_result result; result.pdu_sessions_added_list.push_back(update.pdu_sessions_to_setup_list.at(uint_to_pdu_session_id(1))); - manager->apply_config_update(result); + manager.apply_config_update(result); - ASSERT_EQ(manager->get_nof_drbs(), 1); + ASSERT_EQ(manager.get_nof_drbs(), 1); // if same request is received again, no DRB should be added - ASSERT_FALSE(manager->validate_request(msg.pdu_session_res_setup_items)); + ASSERT_FALSE(manager.validate_request(msg.pdu_session_res_setup_items)); } TEST_F(up_resource_manager_test, when_drb_is_added_pdcp_config_is_valid) { cu_cp_pdu_session_resource_setup_request msg = generate_pdu_session_resource_setup(); - ASSERT_TRUE(manager->validate_request(msg.pdu_session_res_setup_items)); - up_config_update update = manager->calculate_update(msg.pdu_session_res_setup_items); + ASSERT_TRUE(manager.validate_request(msg.pdu_session_res_setup_items)); + up_config_update update = manager.calculate_update(msg.pdu_session_res_setup_items); // Verify DRB config ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 1); @@ -156,9 +149,9 @@ TEST_F(up_resource_manager_test, when_drb_is_added_pdcp_config_is_valid) TEST_F(up_resource_manager_test, when_pdu_session_setup_with_two_qos_flows_both_are_mapped_on_own_drb) { - cu_cp_pdu_session_resource_setup_request msg = generate_pdu_session_resource_setup(1, 2); - ASSERT_TRUE(manager->validate_request(msg.pdu_session_res_setup_items)); - up_config_update update = manager->calculate_update(msg.pdu_session_res_setup_items); + cu_cp_pdu_session_resource_setup_request msg = generate_pdu_session_resource_setup(ue_index_t::min, 1, 2); + ASSERT_TRUE(manager.validate_request(msg.pdu_session_res_setup_items)); + up_config_update update = manager.calculate_update(msg.pdu_session_res_setup_items); // Verify created DRBs. ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 1); @@ -183,7 +176,7 @@ TEST_F(up_resource_manager_test, when_inexiting_qos_flow_gets_removed_removal_fa cu_cp_pdu_session_resource_modify_request msg = generate_pdu_session_resource_modification_with_qos_flow_removal(uint_to_qos_flow_id(9)); - ASSERT_FALSE(manager->validate_request(msg)); + ASSERT_FALSE(manager.validate_request(msg)); } /// Note: From TS 38.413 Sec 8.2.3.1 "PDU Session Resource Modify" it's not entirely clear what should happen in @@ -199,7 +192,7 @@ TEST_F(up_resource_manager_test, when_only_existing_qos_flow_gets_removed_remova cu_cp_pdu_session_resource_modify_request msg = generate_pdu_session_resource_modification_with_qos_flow_removal(uint_to_qos_flow_id(1)); - ASSERT_FALSE(manager->validate_request(msg)); + ASSERT_FALSE(manager.validate_request(msg)); } TEST_F(up_resource_manager_test, when_existing_qos_flow_gets_removed_removal_succeeds_and_associated_drb_is_released) @@ -213,9 +206,9 @@ TEST_F(up_resource_manager_test, when_existing_qos_flow_gets_removed_removal_suc generate_pdu_session_resource_modification_with_qos_flow_removal(uint_to_qos_flow_id(2)); const auto psi = uint_to_pdu_session_id(1); - ASSERT_TRUE(manager->validate_request(msg)); + ASSERT_TRUE(manager.validate_request(msg)); - up_config_update update = manager->calculate_update(msg); + up_config_update update = manager.calculate_update(msg); // Verify calculated update. ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 0); @@ -226,13 +219,13 @@ TEST_F(up_resource_manager_test, when_existing_qos_flow_gets_removed_removal_suc // Apply update. up_config_update_result result; result.pdu_sessions_modified_list.push_back(update.pdu_sessions_to_modify_list.at(psi)); - manager->apply_config_update(result); + manager.apply_config_update(result); // One PDU session with one QoS flows using one DRB. - ASSERT_EQ(manager->get_nof_pdu_sessions(), 1); - ASSERT_EQ(manager->get_total_nof_qos_flows(), 1); - ASSERT_EQ(manager->get_nof_drbs(), 1); - ASSERT_EQ(manager->get_nof_qos_flows(psi), 1); + ASSERT_EQ(manager.get_nof_pdu_sessions(), 1); + ASSERT_EQ(manager.get_total_nof_qos_flows(), 1); + ASSERT_EQ(manager.get_nof_drbs(), 1); + ASSERT_EQ(manager.get_nof_qos_flows(psi), 1); } TEST_F(up_resource_manager_test, when_pdu_session_gets_removed_all_resources_are_removed) @@ -245,14 +238,14 @@ TEST_F(up_resource_manager_test, when_pdu_session_gets_removed_all_resources_are // Attempt to create new session with same PSI fails. cu_cp_pdu_session_resource_setup_request setup_msg = generate_pdu_session_resource_setup(); - ASSERT_FALSE(manager->validate_request(setup_msg.pdu_session_res_setup_items)); + ASSERT_FALSE(manager.validate_request(setup_msg.pdu_session_res_setup_items)); // Remove existing session. cu_cp_pdu_session_resource_release_command release_msg = generate_pdu_session_resource_release(); - ASSERT_TRUE(manager->validate_request(release_msg)); + ASSERT_TRUE(manager.validate_request(release_msg)); // Calculate update - up_config_update update = manager->calculate_update(release_msg); + up_config_update update = manager.calculate_update(release_msg); // Verify calculated update. ASSERT_EQ(update.pdu_sessions_to_setup_list.size(), 0); @@ -263,12 +256,12 @@ TEST_F(up_resource_manager_test, when_pdu_session_gets_removed_all_resources_are // Apply update. up_config_update_result result; result.pdu_sessions_removed_list.push_back(update.pdu_sessions_to_remove_list.front()); - manager->apply_config_update(result); + manager.apply_config_update(result); // All resources are removed. - ASSERT_EQ(manager->get_nof_pdu_sessions(), 0); - ASSERT_EQ(manager->get_total_nof_qos_flows(), 0); - ASSERT_EQ(manager->get_nof_drbs(), 0); + ASSERT_EQ(manager.get_nof_pdu_sessions(), 0); + ASSERT_EQ(manager.get_total_nof_qos_flows(), 0); + ASSERT_EQ(manager.get_nof_drbs(), 0); // Setting up initial PDU session is possible again. setup_initial_pdu_session(); diff --git a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h index a9b8884c4a..5b453454e8 100644 --- a/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h +++ b/tests/unittests/du_manager/procedures/du_manager_procedure_test_helpers.h @@ -46,16 +46,20 @@ class du_ue_dummy : public du_ue, public mac_ue_radio_link_notifier, public rlc_ fifo_async_task_scheduler* ue_ctrl_loop; - async_task disconnect_notifiers() override + async_task handle_traffic_stop_request() override { ue_notifiers_disconnected = true; return launch_no_op_task(); } async_task handle_activity_stop_request() override { return launch_no_op_task(); } - void schedule_async_task(async_task task) override { ue_ctrl_loop->schedule(std::move(task)); } - void handle_rlf_detection(rlf_cause cause) override {} - void handle_crnti_ce_detection() override {} - void stop_drb_traffic() override {} + async_task handle_drb_traffic_stop_request(span /*unused*/) override + { + return launch_no_op_task(); + } + void schedule_async_task(async_task task) override { ue_ctrl_loop->schedule(std::move(task)); } + void handle_rlf_detection(rlf_cause cause) override {} + void handle_crnti_ce_detection() override {} + void stop_drb_traffic() override {} mac_ue_radio_link_notifier& get_mac_rlf_notifier() override { return *this; } void on_rlf_detected() override {} void on_crnti_ce_received() override {} diff --git a/tests/unittests/e1ap/common/test_helpers.h b/tests/unittests/e1ap/common/test_helpers.h index ef22f19d25..3d04194559 100644 --- a/tests/unittests/e1ap/common/test_helpers.h +++ b/tests/unittests/e1ap/common/test_helpers.h @@ -281,22 +281,4 @@ class dummy_e1ap_message_notifier : public e1ap_message_notifier srslog::basic_logger& logger; }; -/// Dummy notifier just printing the received msg. -class dummy_e1ap_cu_cp_notifier : public srs_cu_cp::e1ap_cu_cp_notifier -{ -public: - dummy_e1ap_cu_cp_notifier() : logger(srslog::fetch_basic_logger("TEST")){}; - - void on_bearer_context_inactivity_notification_received(const srs_cu_cp::cu_cp_inactivity_notification& msg) override - { - last_msg = msg; - logger.info("Received an inactivity notification"); - } - - srs_cu_cp::cu_cp_inactivity_notification last_msg; - -private: - srslog::basic_logger& logger; -}; - } // namespace srsran diff --git a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.cpp b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.cpp index 14a104e5f2..3692ea3793 100644 --- a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.cpp +++ b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.cpp @@ -34,7 +34,7 @@ e1ap_cu_cp_test::e1ap_cu_cp_test() srslog::init(); e1ap = create_e1ap( - e1ap_pdu_notifier, cu_up_processor_notifier, cu_cp_notifier, ue_mng, timers, ctrl_worker, max_nof_supported_ues); + e1ap_pdu_notifier, cu_up_processor_notifier, cu_cp_notifier, timers, ctrl_worker, max_nof_supported_ues); } e1ap_cu_cp_test::~e1ap_cu_cp_test() diff --git a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h index f4185d25fb..9054238346 100644 --- a/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h +++ b/tests/unittests/e1ap/cu_cp/e1ap_cu_cp_test_helpers.h @@ -37,6 +37,32 @@ namespace srsran { namespace srs_cu_cp { +/// Dummy notifier just printing the received msg. +class dummy_e1ap_cu_cp_notifier : public srs_cu_cp::e1ap_cu_cp_notifier +{ +public: + dummy_e1ap_cu_cp_notifier(srs_cu_cp::ue_manager& ue_mng_) : + ue_mng(ue_mng_), logger(srslog::fetch_basic_logger("TEST")){}; + + void on_bearer_context_inactivity_notification_received(const srs_cu_cp::cu_cp_inactivity_notification& msg) override + { + last_msg = msg; + logger.info("Received an inactivity notification"); + } + + bool schedule_async_task(ue_index_t ue_index, async_task task) override + { + srsran_assert(ue_mng.find_ue_task_scheduler(ue_index) != nullptr, "UE task scheduler must be present"); + return ue_mng.find_ue_task_scheduler(ue_index)->schedule_async_task(std::move(task)); + } + + srs_cu_cp::cu_cp_inactivity_notification last_msg; + +private: + ue_manager& ue_mng; + srslog::basic_logger& logger; +}; + /// \brief Reusable E1AP gateway test class for CU-CP unit tests. This class includes: /// a) Requests a new CU-UP connection to the CU-CP. /// b) Logs and stores the last transmitted/received PDU by/from the CU-CP. @@ -121,9 +147,9 @@ class e1ap_cu_cp_test : public ::testing::Test timer_manager timers; dummy_e1ap_pdu_notifier e1ap_pdu_notifier; dummy_e1ap_cu_up_processor_notifier cu_up_processor_notifier; - dummy_e1ap_cu_cp_notifier cu_cp_notifier; manual_task_worker ctrl_worker{128}; - ue_manager ue_mng{{}, {}, timers, ctrl_worker}; + ue_manager ue_mng{{}, {}, {}, timers, ctrl_worker}; + dummy_e1ap_cu_cp_notifier cu_cp_notifier{ue_mng}; std::unique_ptr e1ap; unsigned max_nof_supported_ues = 1024 * 4; }; diff --git a/tests/unittests/e2/common/e2_test_helpers.h b/tests/unittests/e2/common/e2_test_helpers.h index 982ea7e867..c5db2eec9f 100644 --- a/tests/unittests/e2/common/e2_test_helpers.h +++ b/tests/unittests/e2/common/e2_test_helpers.h @@ -292,7 +292,7 @@ class dummy_e2_du_metrics : public e2_du_metrics_interface } private: - std::unique_ptr e2_meas_provider; + std::unique_ptr e2_meas_provider; }; class dummy_f1ap_ue_id_translator : public srs_du::f1ap_ue_id_translator diff --git a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp index 3cc48e1030..660770bddb 100644 --- a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp @@ -48,10 +48,10 @@ class e2_rlc_metrics_notifier : public e2_du_metrics_notifier, public e2_du_metr public: void get_metrics(scheduler_ue_metrics& ue_metrics) override {} - void report_metrics(span ue_metrics) override + void report_metrics(const scheduler_cell_metrics& metrics) override { if (e2_meas_provider) { - e2_meas_provider->report_metrics(ue_metrics); + e2_meas_provider->report_metrics(metrics); } } diff --git a/tests/unittests/ngap/ngap_handover_test.cpp b/tests/unittests/ngap/ngap_handover_test.cpp index 5853d0e702..afde9a3594 100644 --- a/tests/unittests/ngap/ngap_handover_test.cpp +++ b/tests/unittests/ngap/ngap_handover_test.cpp @@ -21,6 +21,7 @@ */ #include "ngap_test_helpers.h" +#include "tests/unittests/ngap/ngap_test_messages.h" #include "srsran/ngap/ngap_handover.h" #include "srsran/ran/cu_types.h" #include "srsran/ran/lcid.h" @@ -62,12 +63,10 @@ TEST_F(ngap_test, when_source_gnb_handover_preparation_triggered_then_ho_command add_pdu_session_to_up_manager(ue_index, uint_to_pdu_session_id(1), uint_to_drb_id(0), uint_to_qos_flow_id(0)); auto& ue = test_ues.at(ue_index); - ue.rrc_ue_notifier.set_ho_preparation_message({}); + ue.rrc_ue_ho_prep_handler.set_ho_preparation_message({}); - ngap_handover_preparation_request request = {}; - request.ue_index = ue_index; - request.gnb_id = {1, 22}; - request.nci = 1; + ngap_handover_preparation_request request = generate_handover_preparation_request( + ue_index, ue_mng.find_ue(ue_index)->get_up_resource_manager().get_pdu_sessions_map(), {1, 22}, 1); // Action 1: Launch HO preparation procedure test_logger.info("Launch source NGAP handover preparation procedure"); diff --git a/tests/unittests/ngap/ngap_nas_message_test.cpp b/tests/unittests/ngap/ngap_nas_message_test.cpp index aa9502eb4d..65b183e625 100644 --- a/tests/unittests/ngap/ngap_nas_message_test.cpp +++ b/tests/unittests/ngap/ngap_nas_message_test.cpp @@ -47,10 +47,10 @@ class ngap_nas_message_routine_test : public ngap_test bool was_dl_nas_transport_forwarded(const test_ue& ue) const { - return ue.rrc_ue_notifier.last_nas_pdu.length() == nas_pdu_len; + return ue.rrc_ue_dl_nas_handler.last_nas_pdu.length() == nas_pdu_len; } - bool was_dl_nas_transport_dropped(const test_ue& ue) const { return ue.rrc_ue_notifier.last_nas_pdu.empty(); } + bool was_dl_nas_transport_dropped(const test_ue& ue) const { return ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty(); } bool was_ul_nas_transport_forwarded() const { diff --git a/tests/unittests/ngap/ngap_pdu_session_resource_release_procedure_test.cpp b/tests/unittests/ngap/ngap_pdu_session_resource_release_procedure_test.cpp index b489dde344..298b035dd4 100644 --- a/tests/unittests/ngap/ngap_pdu_session_resource_release_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_pdu_session_resource_release_procedure_test.cpp @@ -31,7 +31,7 @@ using namespace srs_cu_cp; class ngap_pdu_session_resource_release_procedure_test : public ngap_test { protected: - ue_index_t start_procedure(const pdu_session_id_t pdu_session_id) + ue_index_t start_procedure(const pdu_session_id_t pdu_session_id, bool enable_security = true) { ue_index_t ue_index = create_ue(); @@ -47,6 +47,11 @@ class ngap_pdu_session_resource_release_procedure_test : public ngap_test // Inject PDU Session Resource Setup request run_pdu_session_resource_setup(ue_index, pdu_session_id); + if (enable_security) { + // Mark security as enabled + ue_mng.find_ue(ue_index)->get_security_manager().enable_security(); + } + return ue_index; } diff --git a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp index 2f503075f3..786deef0ae 100644 --- a/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_pdu_session_resource_setup_procedure_test.cpp @@ -31,7 +31,7 @@ using namespace srs_cu_cp; class ngap_pdu_session_resource_setup_procedure_test : public ngap_test { protected: - ue_index_t start_procedure() + ue_index_t start_procedure(bool enable_security = true) { ue_index_t ue_index = create_ue(); @@ -44,6 +44,11 @@ class ngap_pdu_session_resource_setup_procedure_test : public ngap_test // Inject Initial Context Setup Request run_initial_context_setup(ue_index); + if (enable_security) { + // Mark security as enabled + ue_mng.find_ue(ue_index)->get_security_manager().enable_security(); + } + return ue_index; } @@ -174,10 +179,10 @@ TEST_F(ngap_pdu_session_resource_setup_procedure_test, TEST_F(ngap_pdu_session_resource_setup_procedure_test, when_security_not_enabled_then_pdu_session_setup_failed) { // Test preamble - ue_index_t ue_index = this->start_procedure(); + ue_index_t ue_index = this->start_procedure(false); auto& ue = test_ues.at(ue_index); - ue.rrc_ue_notifier.set_security_enabled(false); + ue.rrc_ue_security_handler.set_security_enabled(false); // Inject PDU Session Resource Setup Request pdu_session_id_t pdu_session_id = uint_to_pdu_session_id(test_rgen::uniform_int( diff --git a/tests/unittests/ngap/ngap_test_helpers.cpp b/tests/unittests/ngap/ngap_test_helpers.cpp index cae2bc4759..12699ffc35 100644 --- a/tests/unittests/ngap/ngap_test_helpers.cpp +++ b/tests/unittests/ngap/ngap_test_helpers.cpp @@ -48,7 +48,7 @@ ngap_test::ngap_test() cfg.slice_configurations.push_back(slice_cfg); cfg.pdu_session_setup_timeout = std::chrono::seconds(2); - ngap = create_ngap(cfg, cu_cp_notifier, cu_cp_paging_notifier, ue_mng, n2_gw, timers, ctrl_worker); + ngap = create_ngap(cfg, cu_cp_notifier, cu_cp_paging_notifier, n2_gw, timers, ctrl_worker); cu_cp_notifier.connect_ngap(ngap->get_ngap_ue_context_removal_handler()); @@ -76,8 +76,8 @@ ue_index_t ngap_test::create_ue(rnti_t rnti) test_ues.emplace(ue_index, test_ue(ue_index)); test_ue& new_test_ue = test_ues.at(ue_index); - // Add UE to NGAP notifier - cu_cp_notifier.add_ue(ue_index, new_test_ue.rrc_ue_notifier, new_test_ue.rrc_ue_notifier); + ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue( + new_test_ue.rrc_ue_dl_nas_handler, new_test_ue.rrc_ue_security_handler, new_test_ue.rrc_ue_ho_prep_handler); // generate and inject valid initial ue message cu_cp_initial_ue_message msg = generate_initial_ue_message(ue_index); @@ -103,8 +103,8 @@ ue_index_t ngap_test::create_ue_without_init_ue_message(rnti_t rnti) test_ues.emplace(ue_index, test_ue(ue_index)); test_ue& new_test_ue = test_ues.at(ue_index); - // Add UE to NGAP notifier - cu_cp_notifier.add_ue(ue_index, new_test_ue.rrc_ue_notifier, new_test_ue.rrc_ue_notifier); + ue_mng.get_ngap_rrc_ue_adapter(ue_index).connect_rrc_ue( + new_test_ue.rrc_ue_dl_nas_handler, new_test_ue.rrc_ue_security_handler, new_test_ue.rrc_ue_ho_prep_handler); return ue_index; } @@ -149,7 +149,7 @@ void ngap_test::add_pdu_session_to_up_manager(ue_index_t ue_index, drb_id_t drb_id, qos_flow_id_t qos_flow_id) { - auto& up_mng = ue_mng.find_ngap_ue(ue_index)->get_up_resource_manager(); + auto& up_mng = ue_mng.find_ue(ue_index)->get_up_resource_manager(); up_config_update_result result; up_pdu_session_context_update ctxt_update{pdu_session_id}; std::map qos_flows; diff --git a/tests/unittests/ngap/ngap_test_helpers.h b/tests/unittests/ngap/ngap_test_helpers.h index 6eeb8a2b5c..340b6d749b 100644 --- a/tests/unittests/ngap/ngap_test_helpers.h +++ b/tests/unittests/ngap/ngap_test_helpers.h @@ -42,13 +42,15 @@ class ngap_test : public ::testing::Test class test_ue { public: - test_ue(ue_index_t ue_index_) : ue_index(ue_index_) {} + test_ue(ue_index_t ue_index_) : ue_index(ue_index_), rrc_ue_dl_nas_handler(ue_index_) {} ue_index_t ue_index = ue_index_t::invalid; std::optional amf_ue_id; std::optional ran_ue_id; - dummy_ngap_rrc_ue_notifier rrc_ue_notifier; + dummy_rrc_dl_nas_message_handler rrc_ue_dl_nas_handler; + dummy_rrc_ue_init_security_context_handler rrc_ue_security_handler; + dummy_rrc_ue_handover_preparation_handler rrc_ue_ho_prep_handler; }; ngap_test(); @@ -86,10 +88,20 @@ class ngap_test : public ::testing::Test std::unordered_map test_ues; - ngap_configuration cfg; - timer_manager timers; - manual_task_worker ctrl_worker{128}; - ue_manager ue_mng{{}, {}, timers, ctrl_worker}; + ngap_configuration cfg; + timer_manager timers; + manual_task_worker ctrl_worker{128}; + + security_manager_config sec_config{{security::integrity_algorithm::nia2, + security::integrity_algorithm::nia1, + security::integrity_algorithm::nia3, + security::integrity_algorithm::nia0}, + {security::ciphering_algorithm::nea0, + security::ciphering_algorithm::nea2, + security::ciphering_algorithm::nea1, + security::ciphering_algorithm::nea3}}; + + ue_manager ue_mng{{}, {}, sec_config, timers, ctrl_worker}; dummy_n2_gateway n2_gw; dummy_ngap_cu_cp_notifier cu_cp_notifier{ue_mng}; dummy_ngap_cu_cp_paging_notifier cu_cp_paging_notifier; diff --git a/tests/unittests/ngap/ngap_test_messages.cpp b/tests/unittests/ngap/ngap_test_messages.cpp index a4d587bad4..2e0a922729 100644 --- a/tests/unittests/ngap/ngap_test_messages.cpp +++ b/tests/unittests/ngap/ngap_test_messages.cpp @@ -25,6 +25,7 @@ #include "srsran/asn1/ngap/common.h" #include "srsran/asn1/ngap/ngap_ies.h" #include "srsran/asn1/ngap/ngap_pdu_contents.h" +#include "srsran/ngap/ngap_handover.h" #include "srsran/ngap/ngap_message.h" #include "srsran/ngap/ngap_types.h" #include "srsran/ran/cu_types.h" @@ -904,3 +905,27 @@ ngap_message srsran::srs_cu_cp::generate_valid_handover_command(amf_ue_id_t amf_ return ngap_msg; } + +ngap_handover_preparation_request srsran::srs_cu_cp::generate_handover_preparation_request( + ue_index_t ue_index, + const std::map& pdu_sessions, + gnb_id_t gnb_id, + nr_cell_id_t nci) +{ + ngap_handover_preparation_request request = {}; + request.ue_index = ue_index; + request.gnb_id = gnb_id; + request.nci = nci; + // create a map of all PDU sessions and their associated QoS flows + for (const auto& pdu_session : pdu_sessions) { + std::vector qos_flows; + for (const auto& drb : pdu_session.second.drbs) { + for (const auto& qos_flow : drb.second.qos_flows) { + qos_flows.push_back(qos_flow.first); + } + } + request.pdu_sessions.insert({pdu_session.first, qos_flows}); + } + + return request; +} \ No newline at end of file diff --git a/tests/unittests/ngap/ngap_test_messages.h b/tests/unittests/ngap/ngap_test_messages.h index 6520cf3041..052e25f4e4 100644 --- a/tests/unittests/ngap/ngap_test_messages.h +++ b/tests/unittests/ngap/ngap_test_messages.h @@ -25,7 +25,9 @@ #include "srsran/asn1/ngap/ngap.h" #include "srsran/asn1/ngap/ngap_ies.h" #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/cu_cp/up_context.h" #include "srsran/ngap/ngap.h" +#include "srsran/ngap/ngap_handover.h" #include "srsran/ngap/ngap_types.h" namespace srsran { @@ -212,5 +214,12 @@ ngap_message generate_valid_handover_request(amf_ue_id_t amf_ue_id); /// \brief Generate a valid dummy Handover Command message. ngap_message generate_valid_handover_command(amf_ue_id_t amf_ue_id, ran_ue_id_t ran_ue_id); +/// \brief Generate a handover preparation request. +ngap_handover_preparation_request +generate_handover_preparation_request(ue_index_t ue_index, + const std::map& pdu_sessions, + gnb_id_t gnb_id = {1, 22}, + nr_cell_id_t nci = 1); + } // namespace srs_cu_cp } // namespace srsran diff --git a/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp b/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp index c80341c967..54acaf150c 100644 --- a/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp +++ b/tests/unittests/ngap/ngap_ue_context_management_procedure_test.cpp @@ -182,6 +182,8 @@ TEST_F(ngap_ue_context_management_procedure_test, when_invalid_initial_context_s auto& ue = test_ues.at(ue_index); + ue.rrc_ue_security_handler.set_security_enabled(false); + // Inject Initial Context Setup Request ngap_message init_context_setup_request = generate_invalid_initial_context_setup_request_message(ue.amf_ue_id.value(), ue.ran_ue_id.value()); @@ -411,35 +413,35 @@ TEST_F(ngap_ue_context_management_procedure_test, when_ue_context_is_tranfered_a ASSERT_NE(ran_id, ran_ue_id_t::invalid); // Clear NAS PDU. - ue.rrc_ue_notifier.last_nas_pdu.clear(); - ASSERT_TRUE(ue.rrc_ue_notifier.last_nas_pdu.empty()); + ue.rrc_ue_dl_nas_handler.last_nas_pdu.clear(); + ASSERT_TRUE(ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); // Inject new DL NAS transport from core. ngap_message dl_nas_transport = generate_downlink_nas_transport_message(amf_id, ue.ran_ue_id.value()); ngap->handle_message(dl_nas_transport); // Check NAS PDU has been passed to RRC. - ASSERT_FALSE(ue.rrc_ue_notifier.last_nas_pdu.empty()); + ASSERT_FALSE(ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); // Clear PDU again. - ue.rrc_ue_notifier.last_nas_pdu.clear(); + ue.rrc_ue_dl_nas_handler.last_nas_pdu.clear(); // Create new UE object (with own RRC UE notifier). ue_index_t target_ue_index = create_ue_without_init_ue_message(rnti_t::MAX_CRNTI); ASSERT_NE(target_ue_index, ue_index_t::invalid); ASSERT_NE(target_ue_index, ue_index); auto& target_ue = test_ues.at(target_ue_index); - ASSERT_TRUE(target_ue.rrc_ue_notifier.last_nas_pdu.empty()); + ASSERT_TRUE(target_ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); // Transfer NGAP UE context to new target UE. - ngap->update_ue_index(target_ue_index, ue_index); + ngap->update_ue_index(target_ue_index, ue_index, ue_mng.find_ue(target_ue_index)->get_ngap_cu_cp_ue_notifier()); // Inject NAS message again. ngap->handle_message(dl_nas_transport); // Check that RRC notifier of initial UE has not been called. - ASSERT_TRUE(ue.rrc_ue_notifier.last_nas_pdu.empty()); + ASSERT_TRUE(ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); // Verify that RRC notifier of target UE has indeed benn called. - ASSERT_FALSE(target_ue.rrc_ue_notifier.last_nas_pdu.empty()); + ASSERT_FALSE(target_ue.rrc_ue_dl_nas_handler.last_nas_pdu.empty()); } diff --git a/tests/unittests/ngap/test_helpers.h b/tests/unittests/ngap/test_helpers.h index 6469dac2bc..e99d744261 100644 --- a/tests/unittests/ngap/test_helpers.h +++ b/tests/unittests/ngap/test_helpers.h @@ -22,14 +22,14 @@ #pragma once +#include "lib/cu_cp/ue_manager/ue_manager_impl.h" #include "ngap_test_messages.h" #include "srsran/adt/byte_buffer.h" #include "srsran/cu_cp/cu_cp_types.h" -#include "srsran/cu_cp/ue_manager.h" +#include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/ngap/gateways/n2_connection_client.h" #include "srsran/ngap/ngap_message.h" #include "srsran/security/security.h" -#include "srsran/support/async/fifo_async_task_scheduler.h" #include #include @@ -134,46 +134,24 @@ class dummy_ngap_rrc_ue_notifier : public ngap_rrc_ue_pdu_notifier, public ngap_ logger.info("Received a NAS PDU"); } - async_task on_new_security_context(const security::security_context& sec_context) override + async_task on_new_security_context() override { logger.info("Received a new security context"); - - bool result = true; - - // NIA0 is not allowed - security::preferred_integrity_algorithms inc_algo_pref_list = {security::integrity_algorithm::nia2, - security::integrity_algorithm::nia1, - security::integrity_algorithm::nia3, - security::integrity_algorithm::nia0}; - security::preferred_ciphering_algorithms ciph_algo_pref_list = {security::ciphering_algorithm::nea0, - security::ciphering_algorithm::nea2, - security::ciphering_algorithm::nea1, - security::ciphering_algorithm::nea3}; - - security::security_context tmp_ctxt; - tmp_ctxt = sec_context; - - result = tmp_ctxt.select_algorithms(inc_algo_pref_list, ciph_algo_pref_list); - - return launch_async([result](coro_context>& ctx) { + return launch_async([](coro_context>& ctx) { CORO_BEGIN(ctx); - CORO_RETURN(result); + CORO_RETURN(true); }); } - bool on_security_enabled() override { return security_enabled; } - byte_buffer on_handover_preparation_message_required() override { return ho_preparation_message.copy(); } void set_ho_preparation_message(byte_buffer ho_preparation_message_) { ho_preparation_message = std::move(ho_preparation_message_); } - void set_security_enabled(bool enabled) { security_enabled = enabled; } byte_buffer last_nas_pdu; byte_buffer ho_preparation_message; - bool security_enabled = true; byte_buffer last_handover_command; private: @@ -213,39 +191,36 @@ class dummy_ngap_cu_cp_paging_notifier : public ngap_cu_cp_du_repository_notifie class dummy_ngap_cu_cp_notifier : public ngap_cu_cp_notifier { public: - dummy_ngap_cu_cp_notifier(ngap_ue_manager& ue_manager_) : - ue_manager(ue_manager_), logger(srslog::fetch_basic_logger("TEST")){}; + dummy_ngap_cu_cp_notifier(ue_manager& ue_mng_) : ue_mng(ue_mng_), logger(srslog::fetch_basic_logger("TEST")){}; void connect_ngap(ngap_ue_context_removal_handler& ngap_handler_) { ngap_handler = &ngap_handler_; } - void add_ue(ue_index_t ue_index, - ngap_rrc_ue_pdu_notifier& rrc_ue_pdu_notifier, - ngap_rrc_ue_control_notifier& rrc_ue_ctrl_notifier) + ngap_cu_cp_ue_notifier* on_new_ngap_ue(ue_index_t ue_index) override { - ue_notifiers_map.emplace(ue_index, ngap_ue_notifiers{&rrc_ue_pdu_notifier, &rrc_ue_ctrl_notifier}); - } - - bool on_new_ngap_ue(ue_index_t ue_index) override - { - srsran_assert(ue_notifiers_map.find(ue_index) != ue_notifiers_map.end(), "UE context must be present"); - auto& ue_notifier = ue_notifiers_map.at(ue_index); - - srsran_assert(ue_notifier.rrc_ue_pdu_notifier != nullptr, "rrc_ue_pdu_notifier must not be nullptr"); - srsran_assert(ue_notifier.rrc_ue_ctrl_notifier != nullptr, "rrc_ue_ctrl_notifier must not be nullptr"); - last_ue = ue_index; - // Add NGAP UE to UE manager - ngap_ue* ue = - ue_manager.set_ue_ng_context(ue_index, *ue_notifier.rrc_ue_pdu_notifier, *ue_notifier.rrc_ue_ctrl_notifier); - + auto* ue = ue_mng.find_ue(ue_index); if (ue == nullptr) { logger.error("ue={}: Failed to create UE", ue_index); - return false; + return nullptr; } logger.info("ue={}: NGAP UE was created", ue_index); - return true; + return &ue->get_ngap_cu_cp_ue_notifier(); + } + + bool schedule_async_task(ue_index_t ue_index, async_task task) override + { + srsran_assert(ue_mng.find_ue_task_scheduler(ue_index) != nullptr, "UE task scheduler must be present"); + return ue_mng.find_ue_task_scheduler(ue_index)->schedule_async_task(std::move(task)); + } + + bool on_handover_request_received(ue_index_t ue_index, security::security_context sec_ctxt) override + { + srsran_assert(ue_mng.find_ue(ue_index) != nullptr, "UE must be present"); + logger.info("Received a handover request"); + + return ue_mng.find_ue(ue_index)->get_security_manager().init_security_context(sec_ctxt); } async_task @@ -366,19 +341,70 @@ class dummy_ngap_cu_cp_notifier : public ngap_cu_cp_notifier std::optional last_created_ue_index; private: - ngap_ue_manager& ue_manager; + ue_manager& ue_mng; srslog::basic_logger& logger; ngap_ue_context_removal_handler* ngap_handler = nullptr; - struct ngap_ue_notifiers { - ngap_rrc_ue_pdu_notifier* rrc_ue_pdu_notifier = nullptr; - ngap_rrc_ue_control_notifier* rrc_ue_ctrl_notifier = nullptr; - }; + uint64_t ue_id = ue_index_to_uint(srs_cu_cp::ue_index_t::min); +}; + +class dummy_rrc_dl_nas_message_handler : public rrc_dl_nas_message_handler +{ +public: + dummy_rrc_dl_nas_message_handler(ue_index_t ue_index_) : + ue_index(ue_index_), logger(srslog::fetch_basic_logger("TEST")){}; + + void handle_dl_nas_transport_message(byte_buffer nas_pdu) override + { + logger.info("ue={}: Received a DL NAS transport message", ue_index); + last_nas_pdu = std::move(nas_pdu); + } - std::map ue_notifiers_map; + byte_buffer last_nas_pdu; - uint64_t ue_id = ue_index_to_uint(srs_cu_cp::ue_index_t::min); +private: + ue_index_t ue_index = ue_index_t::invalid; + srslog::basic_logger& logger; +}; + +class dummy_rrc_ue_init_security_context_handler : public rrc_ue_init_security_context_handler +{ +public: + dummy_rrc_ue_init_security_context_handler() : logger(srslog::fetch_basic_logger("TEST")){}; + + void set_security_enabled(bool enabled) { security_enabled = enabled; } + + async_task handle_init_security_context() override + { + logger.info("Received a new security context"); + + return launch_async([](coro_context>& ctx) mutable { + CORO_BEGIN(ctx); + CORO_RETURN(true); + }); + } + +private: + bool security_enabled = true; + srslog::basic_logger& logger; +}; + +class dummy_rrc_ue_handover_preparation_handler : public rrc_ue_handover_preparation_handler +{ +public: + dummy_rrc_ue_handover_preparation_handler() : logger(srslog::fetch_basic_logger("TEST")){}; + + void set_ho_preparation_message(byte_buffer ho_preparation_message_) + { + ho_preparation_message = std::move(ho_preparation_message_); + } + + byte_buffer get_packed_handover_preparation_message() override { return ho_preparation_message.copy(); } + +private: + srslog::basic_logger& logger; + byte_buffer ho_preparation_message; }; } // namespace srs_cu_cp diff --git a/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp index 0576d1602b..41c08d3241 100644 --- a/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_data_flow_uplane_downlink_data_impl_test.cpp @@ -138,8 +138,8 @@ class ofh_data_flow_uplane_downlink_data_impl_fixture : public ::testing::TestWi void initialize_grid_reader() { - for (uint8_t symbol = 0; symbol != MAX_NSYMB_PER_SLOT; ++symbol) { - for (uint16_t k = 0, e = MAX_NOF_PRBS * NOF_SUBCARRIERS_PER_RB; k != e; ++k) { + for (uint8_t symbol = 0; symbol != nof_symbols; ++symbol) { + for (uint16_t k = 0, e = ru_nof_prbs * NOF_SUBCARRIERS_PER_RB; k != e; ++k) { rg_reader_spy.write( resource_grid_reader_spy::expected_entry_t{0, symbol, k, (k > 200) ? cf_t{1, 1} : cf_t{1, 0}}); } @@ -266,8 +266,8 @@ TEST(ofh_data_flow_uplane_downlink_data_impl, dependencies.frame_pool = std::make_shared(units::bytes(frame_size), 2); resource_grid_reader_spy rg_reader_spy(1, context.symbol_range.length(), config.ru_nof_prbs); - for (uint8_t symbol = 0; symbol != MAX_NSYMB_PER_SLOT; ++symbol) { - for (uint16_t k = 0, e = MAX_NOF_PRBS * NOF_SUBCARRIERS_PER_RB; k != e; ++k) { + for (uint8_t symbol = 0; symbol != context.symbol_range.length(); ++symbol) { + for (uint16_t k = 0, e = config.ru_nof_prbs * NOF_SUBCARRIERS_PER_RB; k != e; ++k) { rg_reader_spy.write( resource_grid_reader_spy::expected_entry_t{0, symbol, k, (k > 200) ? cf_t{1, 1} : cf_t{1, 0}}); } @@ -319,8 +319,8 @@ TEST(ofh_data_flow_uplane_downlink_data_impl, frame_buffer_size_of_nof_prbs_gene dependencies.ecpri_builder = std::move(temp); } resource_grid_reader_spy rg_reader_spy(1, context.symbol_range.length(), config.ru_nof_prbs); - for (uint8_t symbol = 0; symbol != MAX_NSYMB_PER_SLOT; ++symbol) { - for (uint16_t k = 0, e = MAX_NOF_PRBS * NOF_SUBCARRIERS_PER_RB; k != e; ++k) { + for (uint8_t symbol = 0; symbol != context.symbol_range.length(); ++symbol) { + for (uint16_t k = 0, e = config.ru_nof_prbs * NOF_SUBCARRIERS_PER_RB; k != e; ++k) { rg_reader_spy.write( resource_grid_reader_spy::expected_entry_t{0, symbol, k, (k > 200) ? cf_t{1, 1} : cf_t{1, 0}}); } diff --git a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp index 20f7df7262..bd52e5c92b 100644 --- a/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp +++ b/tests/unittests/ofh/transmitter/ofh_uplink_request_handler_impl_test.cpp @@ -138,10 +138,18 @@ class resource_grid_dummy : public resource_grid { return {}; } - + span get(span symbols, + unsigned port, + unsigned l, + unsigned k_init, + const bounded_bitset& mask) const override + { + return {}; + } void get(span symbols, unsigned port, unsigned l, unsigned k_init, unsigned stride) const override {} + void get(span symbols, unsigned port, unsigned l, unsigned k_init) const override {} - span get_view(unsigned port, unsigned l) const override { return {}; } + span get_view(unsigned port, unsigned l) const override { return {}; } }; resource_grid_reader_dummy reader; diff --git a/tests/unittests/phy/support/resource_grid_mapper_test.cpp b/tests/unittests/phy/support/resource_grid_mapper_test.cpp index 82203caa78..cc44a6e229 100644 --- a/tests/unittests/phy/support/resource_grid_mapper_test.cpp +++ b/tests/unittests/phy/support/resource_grid_mapper_test.cpp @@ -49,7 +49,12 @@ using MultiplePRGParams = std::tuple< namespace srsran { -static float ASSERT_MAX_ERROR = 1e-5; +// Gets the tolerance from an expected value. +static float get_tolerance(cf_t expected_value) +{ + // The tolerance is calculated from the complex number based in brain float (BF16) precision. + return std::max(std::abs(expected_value) / 256.0F, 1e-5F); +} static std::ostream& operator<<(std::ostream& os, span data) { @@ -60,7 +65,9 @@ static std::ostream& operator<<(std::ostream& os, span data) static bool operator==(span lhs, span rhs) { return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](cf_t lhs_val, cf_t rhs_val) { - return (std::abs(lhs_val - rhs_val) < ASSERT_MAX_ERROR); + float expected_error = std::min(get_tolerance(lhs_val), get_tolerance(rhs_val)); + float error = std::abs(lhs_val - rhs_val); + return (error < expected_error); }); } diff --git a/tests/unittests/phy/support/resource_grid_test.cpp b/tests/unittests/phy/support/resource_grid_test.cpp index 16f20b6ca9..7b92e2c818 100644 --- a/tests/unittests/phy/support/resource_grid_test.cpp +++ b/tests/unittests/phy/support/resource_grid_test.cpp @@ -32,6 +32,13 @@ using namespace srsran; static std::mt19937 rgen(0); +// Gets the tolerance from an expected value. +static float get_tolerance(cf_t expected_value) +{ + // The tolerance is calculated from the complex number based in brain float (BF16) precision. + return std::max(std::abs(expected_value) / 256.0F, 1e-5F); +} + // Creates a resource grid. static std::unique_ptr create_resource_grid(unsigned nof_ports, unsigned nof_symbols, unsigned nof_subc) { @@ -127,8 +134,8 @@ void test_mask_bitset(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub count++; } - TESTASSERT_EQ(gold.real(), value.real()); - TESTASSERT_EQ(gold.imag(), value.imag()); + float error = std::abs(gold - value); + TESTASSERT(error < get_tolerance(gold), "{} != {}", gold, value); } } } @@ -145,8 +152,8 @@ void test_mask_bitset(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub cf_t gold = symbols_gold[i]; cf_t value = symbols[i]; - TESTASSERT_EQ(gold.real(), value.real()); - TESTASSERT_EQ(gold.imag(), value.imag()); + float error = std::abs(gold - value); + TESTASSERT(error < get_tolerance(gold), "{} != {}", gold, value); } } @@ -199,8 +206,8 @@ void test_consecutive(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub count++; } - TESTASSERT_EQ(gold.real(), value.real()); - TESTASSERT_EQ(gold.imag(), value.imag()); + float error = std::abs(gold - value); + TESTASSERT(error < get_tolerance(gold), "{} != {}", gold, value); } } } @@ -214,18 +221,18 @@ void test_consecutive(unsigned nof_ports, unsigned nof_symbols, unsigned nof_sub cf_t gold = symbols_gold[i]; cf_t value = symbols[i]; - TESTASSERT_EQ(gold.real(), value.real()); - TESTASSERT_EQ(gold.imag(), value.imag()); + float error = std::abs(gold - value); + TESTASSERT(error < get_tolerance(gold), "{} != {}", gold, value); } // Test view contents - span view = grid->get_reader().get_view(port_gold, symbol_idx).subspan(k_init, nof_subc - k_init); + span view = grid->get_reader().get_view(port_gold, symbol_idx).subspan(k_init, nof_subc - k_init); for (unsigned i = 0; i != nof_elements; ++i) { cf_t gold = symbols_gold[i]; - cf_t value = view[i]; + cf_t value = to_cf(view[i]); - TESTASSERT_EQ(gold.real(), value.real()); - TESTASSERT_EQ(gold.imag(), value.imag()); + float error = std::abs(gold - value); + TESTASSERT(error < get_tolerance(gold), "{} != {}", gold, value); } } diff --git a/tests/unittests/phy/support/resource_grid_test_doubles.h b/tests/unittests/phy/support/resource_grid_test_doubles.h index bd8fec5a5e..a5c1764e5a 100644 --- a/tests/unittests/phy/support/resource_grid_test_doubles.h +++ b/tests/unittests/phy/support/resource_grid_test_doubles.h @@ -266,7 +266,7 @@ class resource_grid_reader_spy : public resource_grid_reader using expected_entry_t = resource_grid_writer_spy::expected_entry_t; resource_grid_reader_spy(unsigned max_ports_ = 0, unsigned max_symb_ = 0, unsigned max_prb_ = 0) : - max_ports(max_ports_), max_symb(max_symb_), max_prb(max_prb_) + max_ports(max_ports_), max_symb(max_symb_), max_prb(max_prb_), temp_view(max_prb * NRE) { } @@ -296,6 +296,22 @@ class resource_grid_reader_spy : public resource_grid_reader return symbols; } + span get(span symbols, + unsigned port, + unsigned l, + unsigned k_init, + const bounded_bitset& mask) const override + { + ++count; + mask.for_each(0, mask.size(), [&](unsigned i_subc) { + symbols.front() = get(static_cast(port), l, k_init + i_subc); + symbols = symbols.last(symbols.size() - 1); + }); + + // Consume buffer. + return symbols; + } + void get(span symbols, unsigned port, unsigned l, unsigned k_init, unsigned stride = 1) const override { ++count; @@ -305,10 +321,31 @@ class resource_grid_reader_spy : public resource_grid_reader } } - span get_view(unsigned port, unsigned l) const override + void get(span symbols, unsigned port, unsigned l, unsigned k_init) const override { - srsran_assert(false, "Unimplemented method"); - return {}; + ++count; + cbf16_t* symbol_ptr = symbols.data(); + for (unsigned k = k_init, k_end = k_init + symbols.size(); k != k_end; ++k) { + *(symbol_ptr++) = to_cbf16(get(port, l, k)); + } + } + + span get_view(unsigned port, unsigned l) const override + { + ++count; + + // Fill temporal view with NAN. + cf_t nan = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + std::fill(temp_view.begin(), temp_view.end(), to_cbf16(nan)); + + // Write the available entries. + for (auto& e : entries) { + if ((std::get<0>(e.first) == port) && (std::get<1>(e.first) == l)) { + temp_view[std::get<2>(e.first)] = e.second; + } + } + + return temp_view; } void write(span entries_) @@ -346,6 +383,9 @@ class resource_grid_reader_spy : public resource_grid_reader /// Stores the resource grid written entries. std::map entries; + /// Temporal storage of the method get_view(). It is overwritten every time get_view() is called. + mutable std::vector temp_view; + cf_t get(uint8_t port, uint8_t symbol, uint16_t subcarrier) const { // Generate key. diff --git a/tests/unittests/phy/upper/channel_processors/pucch_demodulator_format2_test.cpp b/tests/unittests/phy/upper/channel_processors/pucch_demodulator_format2_test.cpp index 7d9e850710..3955b25280 100644 --- a/tests/unittests/phy/upper/channel_processors/pucch_demodulator_format2_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pucch_demodulator_format2_test.cpp @@ -24,6 +24,7 @@ #include "srsran/phy/support/support_factories.h" #include "srsran/phy/upper/channel_processors/channel_processor_factories.h" #include "srsran/ran/pucch/pucch_constants.h" +#include "srsran/srsvec/conversion.h" #include "fmt/ostream.h" #include @@ -47,9 +48,15 @@ std::ostream& operator<<(std::ostream& os, test_case_t test_case) return os; } -static bool operator==(const std::vector& a, const std::vector& b) +std::ostream& operator<<(std::ostream& os, span data) { - return std::equal(a.cbegin(), a.cend(), b.cbegin(), [](log_likelihood_ratio x, log_likelihood_ratio y) { + fmt::print(os, "[{}]", data); + return os; +} + +static bool operator==(span a, span b) +{ + return std::equal(a.begin(), a.end(), b.begin(), [](log_likelihood_ratio x, log_likelihood_ratio y) { return ((x - y >= -1) && (x - y <= 1)); }); } @@ -130,7 +137,7 @@ class PucchDemodulatorFixture : public ::testing::TestWithParam estimates = test_case.estimates.read(); - srsvec::copy(channel_est.get_path_ch_estimate(0, 0), estimates); + srsvec::convert(channel_est.get_path_ch_estimate(0, 0), estimates); // Set noise variance. channel_est.set_noise_variance(test_case.context.noise_var, 0); @@ -149,7 +156,7 @@ TEST_P(PucchDemodulatorFixture, PucchDemodulatorVectorTest) demodulator->demodulate(uci_data, rg_spy, channel_est, config); // Assert UCI codeword matches. - ASSERT_EQ(uci_expected, uci_data); + ASSERT_EQ(span(uci_expected), span(uci_data)); } // Creates test suite that combines all possible parameters. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp index f802d7c745..0311c367d3 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp @@ -25,14 +25,14 @@ #include "pusch_demodulator_test_data.h" #include "srsran/phy/upper/channel_processors/pusch/factories.h" #include "srsran/phy/upper/equalization/equalization_factories.h" -#include "srsran/srsvec/compare.h" +#include "srsran/srsvec/conversion.h" #include "fmt/ostream.h" #include namespace srsran { // Maximum allowed error. -constexpr log_likelihood_ratio::value_type LLR_MAX_ERROR = 1; +constexpr log_likelihood_ratio::value_type LLR_MAX_ERROR = 12; std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) { @@ -150,8 +150,8 @@ TEST_P(PuschDemodulatorFixture, PuschDemodulatorUnittest) chan_estimates.set_noise_variance(test_case.context.noise_var, config.rx_ports[i_rx_port], i_layer); // Copy port channel estimates. - srsvec::copy(chan_estimates.get_path_ch_estimate(config.rx_ports[i_rx_port], i_layer), - estimates.get_view(ch_dims::rx_port)>({i_rx_port, i_layer})); + srsvec::convert(chan_estimates.get_path_ch_estimate(config.rx_ports[i_rx_port], i_layer), + estimates.get_view(ch_dims::rx_port)>({i_rx_port, i_layer})); } } diff --git a/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp b/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp index fcff82f00e..acabebc2c6 100644 --- a/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp +++ b/tests/unittests/phy/upper/equalization/channel_equalizer_test.cpp @@ -28,8 +28,8 @@ using namespace srsran; -static constexpr float max_abs_eq_symbol_error = 1e-2; -static constexpr float max_abs_eq_nvar_error = 1e-3; +static constexpr float max_abs_eq_symbol_error = 0.2F; +static constexpr float max_abs_eq_nvar_error = 0.1F; namespace srsran { @@ -95,11 +95,11 @@ using ch_dims = channel_equalizer::ch_est_list::dims; class ChannelEqualizerFixture : public ::testing::TestWithParam { protected: - dynamic_tensor(re_dims::nof_dims), cf_t, re_dims> rx_symbols; - dynamic_tensor(ch_dims::nof_dims), cf_t, ch_dims> test_ch_estimates; - std::vector eq_symbols_expected; - std::vector eq_symbols_actual; - std::vector eq_noise_vars_expected; + dynamic_tensor(re_dims::nof_dims), cbf16_t, re_dims> rx_symbols; + dynamic_tensor(ch_dims::nof_dims), cbf16_t, ch_dims> test_ch_estimates; + std::vector eq_symbols_expected; + std::vector eq_symbols_actual; + std::vector eq_noise_vars_expected; std::vector eq_noise_vars_actual; diff --git a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp index 1107656ee4..1b1a6ecfee 100644 --- a/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp +++ b/tests/unittests/phy/upper/signal_processors/dmrs_pusch_estimator_test.cpp @@ -117,7 +117,7 @@ class DmrsPuschEstimatorFixture : public ::testing::TestWithParam }; } // namespace -static constexpr float tolerance = 0.001; +static constexpr float tolerance = 0.01; TEST_P(DmrsPuschEstimatorFixture, Creation) { @@ -153,7 +153,7 @@ TEST_P(DmrsPuschEstimatorFixture, Creation) for (unsigned i_port = 0; i_port != ch_estimate_dims.nof_rx_ports; ++i_port) { for (unsigned i_layer = 0; i_layer != ch_estimate_dims.nof_tx_layers; ++i_layer) { - span path = ch_est.get_path_ch_estimate(i_port, i_layer); + span path = ch_est.get_path_ch_estimate(i_port, i_layer); srsvec::zero(path); } } @@ -171,20 +171,20 @@ TEST_P(DmrsPuschEstimatorFixture, Creation) for (unsigned i_port = 0; i_port != ch_estimate_dims.nof_rx_ports; ++i_port) { for (unsigned i_layer = 0; i_layer != ch_estimate_dims.nof_tx_layers; ++i_layer) { for (unsigned i_symbol = 0; i_symbol != ch_estimate_dims.nof_symbols; ++i_symbol) { - span current_symbol = ch_est.get_symbol_ch_estimate(i_symbol, i_port, i_layer); + span current_symbol = ch_est.get_symbol_ch_estimate(i_symbol, i_port, i_layer); if ((i_port != i_layer) || (i_symbol < config.first_symbol)) { - ASSERT_TRUE(std::all_of(current_symbol.begin(), current_symbol.end(), [](cf_t a) { - return (a == cf_t(0, 0)); + ASSERT_TRUE(std::all_of(current_symbol.begin(), current_symbol.end(), [](cbf16_t a) { + return (a.real.value() == 0) && (a.imag.value() == 0); })) << "REs should be zero on cross paths and on not allocated symbols."; continue; } cf_t value = cf_t(1, 0); bool is_ok = true; auto check_symbol = [current_symbol, &value, &is_ok](unsigned i_prb) { - unsigned i_re = i_prb * NRE; - span current_prb = current_symbol.subspan(i_re, NRE); - is_ok = is_ok && std::all_of(current_prb.begin(), current_prb.end(), [value](cf_t a) { - return (std::abs(a - value) < tolerance); + unsigned i_re = i_prb * NRE; + span current_prb = current_symbol.subspan(i_re, NRE); + is_ok = is_ok && std::all_of(current_prb.begin(), current_prb.end(), [value](cbf16_t a) { + return (std::abs(to_cf(a) - value) < tolerance); }); }; config.rb_mask.for_each(0, config.rb_mask.size(), check_symbol); @@ -202,8 +202,8 @@ TEST_P(DmrsPuschEstimatorFixture, Creation) static bool are_estimates_ok(span expected, const channel_estimate& computed) { - unsigned old_symbol = 15; - span computed_symbol; + unsigned old_symbol = 15; + span computed_symbol; for (const auto& this_expected : expected) { unsigned i_symbol = this_expected.symbol; @@ -215,7 +215,7 @@ static bool are_estimates_ok(span tolerance) { + if (std::abs(to_cf(computed_symbol[i_sc]) - value) > tolerance) { return false; } } diff --git a/tests/unittests/phy/upper/signal_processors/port_channel_estimator_test.cpp b/tests/unittests/phy/upper/signal_processors/port_channel_estimator_test.cpp index 5b2a957161..963162db61 100644 --- a/tests/unittests/phy/upper/signal_processors/port_channel_estimator_test.cpp +++ b/tests/unittests/phy/upper/signal_processors/port_channel_estimator_test.cpp @@ -96,9 +96,9 @@ std::shared_ptr ChannelEstFixture::ch_est_factor bool are_estimates_ok(span expected, const channel_estimate& computed) { - constexpr float tolerance = 5e-4; - unsigned old_symbol = 15; - span computed_symbol; + constexpr float tolerance = 1e-2; + unsigned old_symbol = 15; + span computed_symbol; for (const auto& this_expected : expected) { unsigned i_symbol = this_expected.symbol; @@ -110,7 +110,7 @@ bool are_estimates_ok(span exp computed_symbol = computed.get_symbol_ch_estimate(i_symbol, 0, 0); } - if (std::abs(computed_symbol[i_sc] - value) > tolerance) { + if (std::abs(to_cf(computed_symbol[i_sc]) - value) > tolerance) { return false; } } diff --git a/tests/unittests/rlc/rlc_tx_am_test.cpp b/tests/unittests/rlc/rlc_tx_am_test.cpp index 5416a2c1e2..0dae890a07 100644 --- a/tests/unittests/rlc/rlc_tx_am_test.cpp +++ b/tests/unittests/rlc/rlc_tx_am_test.cpp @@ -22,7 +22,7 @@ #include "lib/rlc/rlc_tx_am_entity.h" #include "tests/test_doubles/pdcp/pdcp_pdu_generator.h" -#include "srsran/adt/byte_buffer_chain.h" +#include "srsran/ran/pdsch/pdsch_constants.h" #include "srsran/support/executors/manual_task_worker.h" #include #include @@ -133,11 +133,13 @@ class rlc_tx_am_test : public ::testing::Test, public ::testing::WithParamInterf } /// \brief Obtains full RLC AMD PDUs from generated SDUs that are passed through an RLC AM entity - /// \param[out] out_pdus Pre-allocated array of size n_pdus for the resulting RLC AMD PDUs /// \param[in] n_pdus Length of the out_pdus array /// \param[in] sdu_size Size of SDU that is passed through RLC AM entity - void tx_full_pdus(byte_buffer_chain* out_pdus, uint32_t n_pdus, uint32_t sdu_size = 1) + /// \return A vector of resulting RLC AMD PDUs + std::vector> tx_full_pdus(uint32_t n_pdus, uint32_t sdu_size = 1) { + std::vector> out_pdus; + out_pdus.reserve(n_pdus); uint32_t n_bsr = tester->bsr_count; // Push "n_pdus" SDUs into RLC @@ -163,10 +165,10 @@ class rlc_tx_am_test : public ::testing::Test, public ::testing::WithParamInterf pdu_buf.resize(data_pdu_size); size_t pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - out_pdus[i] = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); + out_pdus.push_back(std::move(pdu_buf)); // Check PDU size - EXPECT_EQ(out_pdus[i].length(), data_pdu_size); + EXPECT_EQ(out_pdus[i].size(), data_pdu_size); // Check PDU payload EXPECT_TRUE( std::equal(out_pdus[i].begin() + header_size, out_pdus[i].end(), sdu_bufs[i].begin(), sdu_bufs[i].end())); @@ -182,28 +184,31 @@ class rlc_tx_am_test : public ::testing::Test, public ::testing::WithParamInterf EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, expect_buffer_state); // pull_pdu does not push BSR to lower layer EXPECT_EQ(tester->bsr_count, n_bsr); + + return out_pdus; } /// \brief Obtains RLC AMD PDU segments from generated SDUs that are passed through an RLC AM entity - /// \param[out] out_pdus Pre-allocated array of size n_pdus for the resulting RLC AMD PDU segments /// \param[in] n_pdus Length of the out_pdus array /// \param[in] pdu_size Maximum size of each PDU that is read from RLC AM entity /// \param[in] n_sdus Number of SDUs to push into RLC AM entity /// \param[in] sdu_size Size of each SDU that is pushed into RLC AM entity - void tx_segmented_pdus(byte_buffer_chain* out_pdus, - uint32_t n_pdus, - uint32_t pdu_size, - uint32_t n_sdus, - uint32_t sdu_size, - uint32_t expect_remaining_bytes = 0) + /// \return A vector of resulting RLC AMD PDUs + std::vector> tx_segmented_pdus(uint32_t n_pdus, + uint32_t pdu_size, + uint32_t n_sdus, + uint32_t sdu_size, + uint32_t expect_remaining_bytes = 0) { + std::vector> out_pdus; + out_pdus.reserve(n_pdus); uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; uint32_t header_so_size = 2; uint32_t n_bsr = tester->bsr_count; // Precondition - ASSERT_LT(pdu_size, sdu_size + header_min_size) << "PDU size fits whole SDU; PDUs won't be segmented"; + EXPECT_LT(pdu_size, sdu_size + header_min_size) << "PDU size fits whole SDU; PDUs won't be segmented"; // Push "n_sdus" SDUs into RLC auto sdu_bufs = std::vector(n_sdus); @@ -229,22 +234,22 @@ class rlc_tx_am_test : public ::testing::Test, public ::testing::WithParamInterf seg_buf.resize(pdu_size); size_t seg_len = rlc->pull_pdu(seg_buf); seg_buf.resize(seg_len); - out_pdus[i] = byte_buffer_chain::create(byte_buffer::create(seg_buf).value()).value(); + out_pdus.push_back(std::move(seg_buf)); // Check PDU size - EXPECT_GT(out_pdus[i].length(), header_size); - EXPECT_LE(out_pdus[i].length(), pdu_size); + EXPECT_GT(out_pdus[i].size(), header_size); + EXPECT_LE(out_pdus[i].size(), pdu_size); // Check PDU payload auto pdu_begin = out_pdus[i].begin() + header_size; auto pdu_end = out_pdus[i].end(); auto sdu_begin = sdu_bufs[sdu_idx].begin() + sdu_so; - ASSERT_TRUE(std::equal(pdu_begin, pdu_end, sdu_begin)) + EXPECT_TRUE(std::equal(pdu_begin, pdu_end, sdu_begin)) << "sdu_idx=" << sdu_idx << ", sdu_so=" << sdu_so << ", i=" << i << ", header_size=" << header_size; // Check remaining buffer state uint32_t rem_sdus = n_sdus - sdu_idx - 1; - uint32_t rem_seg_bytes = sdu_bufs[sdu_idx].length() - sdu_so - out_pdus[i].length() + header_size; + uint32_t rem_seg_bytes = sdu_bufs[sdu_idx].length() - sdu_so - out_pdus[i].size() + header_size; uint32_t rem_seg_hdr = rem_seg_bytes > 0 ? header_min_size + header_so_size : 0; EXPECT_EQ(rlc->get_buffer_state(), rem_sdus * (sdu_size + header_min_size) + rem_seg_bytes + rem_seg_hdr); // actual buffer state changes @@ -276,12 +281,14 @@ class rlc_tx_am_test : public ::testing::Test, public ::testing::WithParamInterf sdu_idx++; sdu_so = 0; } else { - sdu_so += out_pdus[i].length() - header_size; + sdu_so += out_pdus[i].size() - header_size; } } EXPECT_EQ(rlc->get_buffer_state(), expect_remaining_bytes); EXPECT_EQ(tester->bsr, expect_buffer_state); // pull_pdu does not push BSR to lower layer EXPECT_EQ(tester->bsr_count, n_bsr); + + return out_pdus; } void tick() @@ -312,15 +319,10 @@ TEST_P(rlc_tx_am_test, create_new_entity) TEST_P(rlc_tx_am_test, tx_without_segmentation) { - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, 4); - tx_full_pdus(pdus, n_pdus, 5); + const uint32_t n_pdus = 5; + + tx_full_pdus(n_pdus, 4); + tx_full_pdus(n_pdus, 5); } TEST_P(rlc_tx_am_test, tx_small_grant_) @@ -335,24 +337,8 @@ TEST_P(rlc_tx_am_test, tx_small_grant_) const uint32_t so_size = 2; const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_segmented_pdus(pdus, n_pdus, pdu_size, n_sdus, sdu_size); - tx_segmented_pdus(pdus, n_pdus, pdu_size, n_sdus, sdu_size); + tx_segmented_pdus(n_pdus, pdu_size, n_sdus, sdu_size); + tx_segmented_pdus(n_pdus, pdu_size, n_sdus, sdu_size); } TEST_P(rlc_tx_am_test, tx_insufficient_space_new_sdu) @@ -671,15 +657,10 @@ TEST_P(rlc_tx_am_test, sdu_discard_with_pdcp_sn_wraparound) TEST_P(rlc_tx_am_test, invalid_status_report_ack_sn_larger_than_tx_next) { - const uint32_t sdu_size = 4; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; + const uint32_t sdu_size = 4; + const uint32_t n_pdus = 5; - tx_full_pdus(pdus, n_pdus, sdu_size); + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); // NACK SN=3 rlc_am_status_pdu status_pdu(sn_size); @@ -698,17 +679,12 @@ TEST_P(rlc_tx_am_test, invalid_status_report_ack_sn_larger_than_tx_next) TEST_P(rlc_tx_am_test, retx_pdu_without_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 rlc_am_status_nack nack = {}; @@ -728,10 +704,9 @@ TEST_P(rlc_tx_am_test, retx_pdu_without_segmentation) pdu_buf.resize(sdu_size + header_min_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); - EXPECT_EQ(retx_pdu, pdus[nack.nack_sn]); + EXPECT_EQ(pdu_buf, pdus[nack.nack_sn]); pcell_worker.run_pending_tasks(); EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, sdu_size + header_min_size); @@ -751,19 +726,14 @@ TEST_P(rlc_tx_am_test, retx_pdu_without_segmentation) TEST_P(rlc_tx_am_test, retx_pdu_with_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t so_size = 2; - const uint32_t header_max_size = header_min_size + so_size; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t so_size = 2; + const uint32_t header_max_size = header_min_size + so_size; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 rlc_am_status_nack nack = {}; @@ -786,17 +756,16 @@ TEST_P(rlc_tx_am_test, retx_pdu_with_segmentation) pdu_buf.resize(1 + header_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); EXPECT_TRUE( - std::equal(retx_pdu.begin() + header_size, retx_pdu.end(), pdus[nack.nack_sn].begin() + header_min_size + i)); + std::equal(pdu_buf.begin() + header_size, pdu_buf.end(), pdus[nack.nack_sn].begin() + header_min_size + i)); EXPECT_EQ(tester->bsr_count, n_bsr); // Check SI rlc_si_field si; rlc_si_field si_expect; - si = static_cast((*retx_pdu.begin() >> 4) & 0b11); + si = static_cast((*pdu_buf.begin() >> 4) & 0b11); if (i == 0) { // first segment si_expect = rlc_si_field::first_segment; @@ -826,17 +795,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_with_segmentation) TEST_P(rlc_tx_am_test, retx_pdu_first_segment_without_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 0:1 rlc_am_status_nack nack = {}; @@ -860,13 +824,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_first_segment_without_segmentation) pdu_buf.resize(sdu_size + header_min_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); EXPECT_TRUE( - std::equal(retx_pdu.begin() + header_min_size, retx_pdu.end(), pdus[nack.nack_sn].begin() + header_min_size)); + std::equal(pdu_buf.begin() + header_min_size, pdu_buf.end(), pdus[nack.nack_sn].begin() + header_min_size)); // Check SI - EXPECT_EQ(static_cast((*retx_pdu.begin() >> 4) & 0b11), rlc_si_field::first_segment); + EXPECT_EQ(static_cast((*pdu_buf.begin() >> 4) & 0b11), rlc_si_field::first_segment); pcell_worker.run_pending_tasks(); EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, nack.so_end - nack.so_start + 1 + header_min_size); @@ -886,19 +849,14 @@ TEST_P(rlc_tx_am_test, retx_pdu_first_segment_without_segmentation) TEST_P(rlc_tx_am_test, retx_pdu_middle_segment_without_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t so_size = 2; - const uint32_t header_max_size = header_min_size + so_size; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t so_size = 2; + const uint32_t header_max_size = header_min_size + so_size; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 1:1 rlc_am_status_nack nack = {}; @@ -922,14 +880,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_middle_segment_without_segmentation) pdu_buf.resize(sdu_size + header_max_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); - EXPECT_TRUE(std::equal(retx_pdu.begin() + header_max_size, - retx_pdu.end(), - pdus[nack.nack_sn].begin() + header_min_size + nack.so_start)); + EXPECT_TRUE(std::equal( + pdu_buf.begin() + header_max_size, pdu_buf.end(), pdus[nack.nack_sn].begin() + header_min_size + nack.so_start)); // Check SI - EXPECT_EQ(static_cast((*retx_pdu.begin() >> 4) & 0b11), rlc_si_field::middle_segment); + EXPECT_EQ(static_cast((*pdu_buf.begin() >> 4) & 0b11), rlc_si_field::middle_segment); pcell_worker.run_pending_tasks(); EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, nack.so_end - nack.so_start + 1 + header_max_size); @@ -949,19 +905,14 @@ TEST_P(rlc_tx_am_test, retx_pdu_middle_segment_without_segmentation) TEST_P(rlc_tx_am_test, retx_pdu_last_segment_without_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t so_size = 2; - const uint32_t header_max_size = header_min_size + so_size; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t so_size = 2; + const uint32_t header_max_size = header_min_size + so_size; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 1:3 rlc_am_status_nack nack = {}; @@ -985,14 +936,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_last_segment_without_segmentation) pdu_buf.resize(sdu_size + header_max_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); - EXPECT_TRUE(std::equal(retx_pdu.begin() + header_max_size, - retx_pdu.end(), - pdus[nack.nack_sn].begin() + header_min_size + nack.so_start)); + EXPECT_TRUE(std::equal( + pdu_buf.begin() + header_max_size, pdu_buf.end(), pdus[nack.nack_sn].begin() + header_min_size + nack.so_start)); // Check SI - EXPECT_EQ(static_cast((*retx_pdu.begin() >> 4) & 0b11), rlc_si_field::last_segment); + EXPECT_EQ(static_cast((*pdu_buf.begin() >> 4) & 0b11), rlc_si_field::last_segment); pcell_worker.run_pending_tasks(); EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, nack.so_end - nack.so_start + 1 + header_max_size); @@ -1017,27 +966,13 @@ TEST_P(rlc_tx_am_test, retx_of_sn_under_segmentation_is_trimmed_to_already_sent_ const uint32_t n_splits = 3; - const uint32_t n_pdus = n_sdus * n_splits - 1; - const uint32_t header_size = (sn_size == rlc_am_sn_size::size12bits ? 2 : 3); - const uint32_t so_size = 2; - const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; + const uint32_t n_pdus = n_sdus * n_splits - 1; + const uint32_t header_size = (sn_size == rlc_am_sn_size::size12bits ? 2 : 3); + const uint32_t so_size = 2; + const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); const uint32_t unsent_sdu_bytes = sdu_size / n_splits - so_size; // subtract 2 extra bytes from 1st segment (no SO) - tx_segmented_pdus(pdus, n_pdus, pdu_size, n_sdus, sdu_size, unsent_sdu_bytes + header_size + so_size); + tx_segmented_pdus(n_pdus, pdu_size, n_sdus, sdu_size, unsent_sdu_bytes + header_size + so_size); // The rest of the SDU under segmentation is waiting for transmission EXPECT_EQ(rlc->get_buffer_state(), unsent_sdu_bytes + header_size + so_size); @@ -1084,27 +1019,13 @@ TEST_P(rlc_tx_am_test, retx_of_sn_under_segmentation_is_ignored_for_unsent_bytes const uint32_t n_splits = 3; - const uint32_t n_pdus = n_sdus * n_splits - 1; - const uint32_t header_size = (sn_size == rlc_am_sn_size::size12bits ? 2 : 3); - const uint32_t so_size = 2; - const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; + const uint32_t n_pdus = n_sdus * n_splits - 1; + const uint32_t header_size = (sn_size == rlc_am_sn_size::size12bits ? 2 : 3); + const uint32_t so_size = 2; + const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); const uint32_t unsent_sdu_bytes = sdu_size / n_splits - so_size; // subtract 2 extra bytes from 1st segment (no SO) - tx_segmented_pdus(pdus, n_pdus, pdu_size, n_sdus, sdu_size, unsent_sdu_bytes + header_size + so_size); + tx_segmented_pdus(n_pdus, pdu_size, n_sdus, sdu_size, unsent_sdu_bytes + header_size + so_size); // The rest of the SDU under segmentation is waiting for transmission EXPECT_EQ(rlc->get_buffer_state(), unsent_sdu_bytes + header_size + so_size); @@ -1161,27 +1082,13 @@ TEST_P(rlc_tx_am_test, retx_only_sent_bytes_of_sn_under_segmentation) const uint32_t n_splits = 3; - const uint32_t n_pdus = n_sdus * n_splits - 1; - const uint32_t header_size = (sn_size == rlc_am_sn_size::size12bits ? 2 : 3); - const uint32_t so_size = 2; - const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; + const uint32_t n_pdus = n_sdus * n_splits - 1; + const uint32_t header_size = (sn_size == rlc_am_sn_size::size12bits ? 2 : 3); + const uint32_t so_size = 2; + const uint32_t pdu_size = header_size + so_size + (sdu_size / n_splits); const uint32_t unsent_sdu_bytes = sdu_size / n_splits - so_size; // subtract 2 extra bytes from 1st segment (no SO) - tx_segmented_pdus(pdus, n_pdus, pdu_size, n_sdus, sdu_size, unsent_sdu_bytes + header_size + so_size); + tx_segmented_pdus(n_pdus, pdu_size, n_sdus, sdu_size, unsent_sdu_bytes + header_size + so_size); // NACK SN=4 2:65535 => this SN is currently under segmentation; ReTx only the parts that haven't been sent yet. rlc_am_status_nack nack = {}; @@ -1220,17 +1127,12 @@ TEST_P(rlc_tx_am_test, retx_only_sent_bytes_of_sn_under_segmentation) TEST_P(rlc_tx_am_test, retx_pdu_segment_invalid_so_start_and_so_end) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 4:4 rlc_am_status_nack nack = {}; @@ -1254,13 +1156,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_segment_invalid_so_start_and_so_end) pdu_buf.resize(sdu_size + header_min_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); EXPECT_TRUE( - std::equal(retx_pdu.begin() + header_min_size, retx_pdu.end(), pdus[nack.nack_sn].begin() + header_min_size)); + std::equal(pdu_buf.begin() + header_min_size, pdu_buf.end(), pdus[nack.nack_sn].begin() + header_min_size)); // Check SI - EXPECT_EQ(static_cast((*retx_pdu.begin() >> 4) & 0b11), rlc_si_field::full_sdu); + EXPECT_EQ(static_cast((*pdu_buf.begin() >> 4) & 0b11), rlc_si_field::full_sdu); pcell_worker.run_pending_tasks(); EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, sdu_size + header_min_size); @@ -1280,17 +1181,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_segment_invalid_so_start_and_so_end) TEST_P(rlc_tx_am_test, retx_pdu_segment_invalid_so_start_larger_than_so_end) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=3 3:2 rlc_am_status_nack nack = {}; @@ -1314,11 +1210,10 @@ TEST_P(rlc_tx_am_test, retx_pdu_segment_invalid_so_start_larger_than_so_end) pdu_buf.resize(sdu_size + header_min_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[nack.nack_sn].begin(), pdus[nack.nack_sn].end(), "pdus[{}]:", nack.nack_sn); EXPECT_TRUE( - std::equal(retx_pdu.begin() + header_min_size, retx_pdu.end(), pdus[nack.nack_sn].begin() + header_min_size)); + std::equal(pdu_buf.begin() + header_min_size, pdu_buf.end(), pdus[nack.nack_sn].begin() + header_min_size)); pcell_worker.run_pending_tasks(); EXPECT_EQ(rlc->get_buffer_state(), 0); EXPECT_EQ(tester->bsr, nack.so_end + 1 + header_min_size); @@ -1336,24 +1231,47 @@ TEST_P(rlc_tx_am_test, retx_pdu_segment_invalid_so_start_larger_than_so_end) EXPECT_EQ(tester->highest_delivered_pdcp_sn_list.front(), 2); } +TEST_P(rlc_tx_am_test, retx_many_pdus_and_notify_mac) +{ + const uint32_t sdu_size = 1500; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = MAX_DL_PDU_LENGTH / sdu_size + 1; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; + + // NACK everything + rlc_am_status_pdu status_pdu(sn_size); + status_pdu.ack_sn = n_pdus; + + for (uint32_t nack_sn = 0; nack_sn < n_pdus; nack_sn++) { + rlc_am_status_nack nack = {}; + nack.nack_sn = nack_sn; + status_pdu.push_nack(nack); + } + rlc->on_status_pdu(std::move(status_pdu)); + pcell_worker.run_pending_tasks(); + EXPECT_EQ(rlc->get_buffer_state(), n_pdus * (sdu_size + header_min_size)); + EXPECT_EQ(tester->bsr, n_pdus * (sdu_size + header_min_size)); + EXPECT_EQ(tester->bsr_count, ++n_bsr); + + // Verify transmit notification for queued SDUs + ASSERT_EQ(tester->highest_transmitted_pdcp_sn_list.size(), n_pdus); + for (uint32_t pdcp_sn = 0; pdcp_sn < n_pdus; pdcp_sn++) { + EXPECT_EQ(tester->highest_transmitted_pdcp_sn_list.front(), pdcp_sn); + tester->highest_transmitted_pdcp_sn_list.pop_front(); + } + + // Verify delivery notification for fully ACK'ed SDUs is zero + ASSERT_EQ(tester->highest_delivered_pdcp_sn_list.size(), 0); +} + TEST_P(rlc_tx_am_test, invalid_nack_nack_sn_outside_rx_window) { - const uint32_t sdu_size = 4; - const uint32_t n_pdus = 12; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); + const uint32_t sdu_size = 4; + const uint32_t n_pdus = 12; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); // ACK up until 5 rlc_am_status_pdu status_pdu0(sn_size); @@ -1401,22 +1319,10 @@ TEST_P(rlc_tx_am_test, invalid_nack_nack_sn_outside_rx_window) TEST_P(rlc_tx_am_test, invalid_nack_sn_larger_than_ack_sn) { - const uint32_t sdu_size = 4; - const uint32_t n_pdus = 12; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); + const uint32_t sdu_size = 4; + const uint32_t n_pdus = 12; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); // ACK up until 5 rlc_am_status_pdu status_pdu0(sn_size); @@ -1489,17 +1395,12 @@ TEST_P(rlc_tx_am_test, invalid_nack_sn_larger_than_ack_sn) TEST_P(rlc_tx_am_test, retx_insufficient_space) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t short_size = header_min_size; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t short_size = header_min_size; + const uint32_t n_pdus = 5; + + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); EXPECT_EQ(rlc->get_buffer_state(), 0); uint32_t n_bsr = tester->bsr_count; @@ -1541,14 +1442,9 @@ TEST_P(rlc_tx_am_test, retx_insufficient_space) TEST_P(rlc_tx_am_test, retx_pdu_range_without_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; uint32_t sn_start = cardinality(to_number(sn_size)) - 2; uint32_t nack_sn = sn_start + 1; @@ -1561,8 +1457,8 @@ TEST_P(rlc_tx_am_test, retx_pdu_range_without_segmentation) st.poll_sn = sn_start; rlc->set_state(st); - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=nack_sn..nack_sn+range-1 rlc_am_status_nack nack = {}; @@ -1586,10 +1482,9 @@ TEST_P(rlc_tx_am_test, retx_pdu_range_without_segmentation) pdu_buf.resize(sdu_size + header_min_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[i - sn_start].begin(), pdus[i - sn_start].end(), "pdus[{}]:", i - sn_start); - EXPECT_TRUE(std::equal(retx_pdu.begin() + 1, retx_pdu.end(), pdus[i - sn_start].begin() + 1)); // skip header P bit + EXPECT_TRUE(std::equal(pdu_buf.begin() + 1, pdu_buf.end(), pdus[i - sn_start].begin() + 1)); // skip header P bit EXPECT_EQ(rlc->get_buffer_state(), (nack_sn + range - 1 - i) * (sdu_size + header_min_size)); EXPECT_EQ(tester->bsr, range * (sdu_size + header_min_size)); EXPECT_EQ(tester->bsr_count, n_bsr); @@ -1609,14 +1504,9 @@ TEST_P(rlc_tx_am_test, retx_pdu_range_without_segmentation) TEST_P(rlc_tx_am_test, retx_pdu_range_wraparound) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; uint32_t sn_start = cardinality(to_number(sn_size)) - 2; uint32_t nack_sn = sn_start + 1; @@ -1629,8 +1519,8 @@ TEST_P(rlc_tx_am_test, retx_pdu_range_wraparound) st.poll_sn = sn_start; rlc->set_state(st); - tx_full_pdus(pdus, n_pdus, sdu_size); - uint32_t n_bsr = tester->bsr_count; + std::vector> pdus = tx_full_pdus(n_pdus, sdu_size); + uint32_t n_bsr = tester->bsr_count; // NACK SN=nack_sn..nack_sn+range-1 rlc_am_status_nack nack = {}; @@ -1654,13 +1544,12 @@ TEST_P(rlc_tx_am_test, retx_pdu_range_wraparound) pdu_buf.resize(sdu_size + header_min_size); pdu_len = rlc->pull_pdu(pdu_buf); pdu_buf.resize(pdu_len); - byte_buffer_chain retx_pdu = byte_buffer_chain::create(byte_buffer::create(pdu_buf).value()).value(); - logger.debug(retx_pdu.begin(), retx_pdu.end(), "retx_pdu:"); + logger.debug(pdu_buf.begin(), pdu_buf.end(), "retx_pdu:"); logger.debug(pdus[i - sn_start].begin(), pdus[i - sn_start].end(), "pdus[{}]:", i - sn_start); - ASSERT_EQ(retx_pdu.length(), pdus[i - sn_start].length()); + ASSERT_EQ(pdu_buf.size(), pdus[i - sn_start].size()); // compare PDUs, ignore P bit in first header byte - EXPECT_EQ(*retx_pdu.begin() & 0x4, *pdus[i - sn_start].begin() & 0x4); // mask P bit - EXPECT_TRUE(std::equal(retx_pdu.begin() + 1, retx_pdu.end(), pdus[i - sn_start].begin() + 1)); // check rest + EXPECT_EQ(*pdu_buf.begin() & 0x4, *pdus[i - sn_start].begin() & 0x4); // mask P bit + EXPECT_TRUE(std::equal(pdu_buf.begin() + 1, pdu_buf.end(), pdus[i - sn_start].begin() + 1)); // check rest EXPECT_EQ(rlc->get_buffer_state(), (nack_sn + range - 1 - i) * (sdu_size + header_min_size)); EXPECT_EQ(tester->bsr, range * (sdu_size + header_min_size)); EXPECT_EQ(tester->bsr_count, n_bsr); @@ -1816,18 +1705,12 @@ TEST_P(rlc_tx_am_test, status_report_trim) TEST_P(rlc_tx_am_test, expired_poll_retransmit_timer_triggers_retx) { - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - + const uint32_t n_pdus = 5; const uint32_t sdu_size = 10; const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; const uint32_t pdu_size = header_min_size + sdu_size; - tx_full_pdus(pdus, n_pdus, sdu_size); + tx_full_pdus(n_pdus, sdu_size); uint32_t expect_mac_bsr = tester->bsr; uint32_t n_bsr = tester->bsr_count; @@ -1895,18 +1778,12 @@ TEST_P(rlc_tx_am_test, expired_poll_retransmit_timer_triggers_retx) TEST_P(rlc_tx_am_test, expired_poll_retransmit_timer_sets_polling_bit) { - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - + const uint32_t n_pdus = 5; const uint32_t sdu_size = 10; const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; const uint32_t pdu_size = header_min_size + sdu_size; - tx_full_pdus(pdus, n_pdus, sdu_size); + tx_full_pdus(n_pdus, sdu_size); // push SDU to SDU queue so that it is not empty uint32_t n_bsr = tester->bsr_count; @@ -1990,18 +1867,12 @@ TEST_P(rlc_tx_am_test, expired_poll_retransmit_timer_sets_polling_bit) TEST_P(rlc_tx_am_test, expired_poll_retransmit_increments_retx_counter) { - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - + const uint32_t n_pdus = 5; const uint32_t sdu_size = 10; const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; const uint32_t pdu_size = header_min_size + sdu_size; - tx_full_pdus(pdus, n_pdus, sdu_size); + tx_full_pdus(n_pdus, sdu_size); for (uint32_t n_retx = 0; n_retx <= config.max_retx_thresh; n_retx++) { uint32_t expect_mac_bsr = tester->bsr; @@ -2046,16 +1917,11 @@ TEST_P(rlc_tx_am_test, expired_poll_retransmit_increments_retx_counter) TEST_P(rlc_tx_am_test, retx_count_ignores_pending_retx) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; + + tx_full_pdus(n_pdus, sdu_size); uint32_t n_bsr = tester->bsr_count; for (uint32_t n_retx = 0; n_retx <= config.max_retx_thresh; n_retx++) { @@ -2087,16 +1953,11 @@ TEST_P(rlc_tx_am_test, retx_count_ignores_pending_retx) TEST_P(rlc_tx_am_test, retx_count_trigger_max_retx_without_segmentation) { - const uint32_t sdu_size = 4; - const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; - const uint32_t n_pdus = 5; - byte_buffer_chain pdus[n_pdus] = {byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value(), - byte_buffer_chain::create().value()}; - - tx_full_pdus(pdus, n_pdus, sdu_size); + const uint32_t sdu_size = 4; + const uint32_t header_min_size = sn_size == rlc_am_sn_size::size12bits ? 2 : 3; + const uint32_t n_pdus = 5; + + tx_full_pdus(n_pdus, sdu_size); uint32_t n_bsr = tester->bsr_count; for (uint32_t n_retx = 0; n_retx <= config.max_retx_thresh; n_retx++) { diff --git a/tests/unittests/rrc/CMakeLists.txt b/tests/unittests/rrc/CMakeLists.txt index f4d2153875..16492c7afd 100644 --- a/tests/unittests/rrc/CMakeLists.txt +++ b/tests/unittests/rrc/CMakeLists.txt @@ -36,5 +36,5 @@ set(SOURCES add_executable(rrc_ue_test ${SOURCES}) target_include_directories(rrc_ue_test PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(rrc_ue_test rrc_ue_test_helpers srsran_rrc srsran_cu_cp_cell_meas_manager srsran_support srslog gtest gtest_main) +target_link_libraries(rrc_ue_test rrc_ue_test_helpers srsran_rrc srsran_cu_cp srsran_support srslog gtest gtest_main) gtest_discover_tests(rrc_ue_test PROPERTIES "LABELS;rrc_ue") diff --git a/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp b/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp index e597dcbb5e..f939ae9428 100644 --- a/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp +++ b/tests/unittests/rrc/rrc_ue_capability_transfer_proc_test.cpp @@ -75,9 +75,10 @@ class rrc_ue_capability_transfer_proc_test : public rrc_ue_test_helper, public : init_sec_ctx.k = sk_gnb; std::fill(init_sec_ctx.supported_int_algos.begin(), init_sec_ctx.supported_int_algos.end(), true); std::fill(init_sec_ctx.supported_enc_algos.begin(), init_sec_ctx.supported_enc_algos.end(), true); + ue_mng.find_ue(allocated_ue_index)->get_security_manager().init_security_context(init_sec_ctx); // Trigger SMC - async_task t = get_rrc_ue_security_handler()->handle_init_security_context(init_sec_ctx); + async_task t = get_rrc_ue_security_handler()->handle_init_security_context(); lazy_task_launcher t_launcher(t); // Receive SMC complete diff --git a/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp b/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp index 7f0c0bd672..2fe086e1ee 100644 --- a/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp +++ b/tests/unittests/rrc/rrc_ue_smc_proc_test.cpp @@ -89,9 +89,10 @@ TEST_F(rrc_ue_smc, when_key_provided_smc_generated) init_sec_ctx.k = sk_gnb; std::fill(init_sec_ctx.supported_int_algos.begin(), init_sec_ctx.supported_int_algos.end(), true); std::fill(init_sec_ctx.supported_enc_algos.begin(), init_sec_ctx.supported_enc_algos.end(), true); + ue_mng.find_ue(allocated_ue_index)->get_security_manager().init_security_context(init_sec_ctx); // Trigger SMC - async_task t = get_rrc_ue_security_handler()->handle_init_security_context(init_sec_ctx); + async_task t = get_rrc_ue_security_handler()->handle_init_security_context(); lazy_task_launcher t_launcher(t); ASSERT_FALSE(t.ready()); @@ -115,9 +116,10 @@ TEST_F(rrc_ue_smc, when_reply_missing_procedure_timeout) init_sec_ctx.k = sk_gnb; std::fill(init_sec_ctx.supported_int_algos.begin(), init_sec_ctx.supported_int_algos.end(), true); std::fill(init_sec_ctx.supported_enc_algos.begin(), init_sec_ctx.supported_enc_algos.end(), true); + ue_mng.find_ue(allocated_ue_index)->get_security_manager().init_security_context(init_sec_ctx); // Trigger SMC - async_task t = get_rrc_ue_security_handler()->handle_init_security_context(init_sec_ctx); + async_task t = get_rrc_ue_security_handler()->handle_init_security_context(); lazy_task_launcher t_launcher(t); ASSERT_FALSE(t.ready()); diff --git a/tests/unittests/rrc/rrc_ue_test_helpers.h b/tests/unittests/rrc/rrc_ue_test_helpers.h index 41b0e52996..5483417843 100644 --- a/tests/unittests/rrc/rrc_ue_test_helpers.h +++ b/tests/unittests/rrc/rrc_ue_test_helpers.h @@ -23,6 +23,7 @@ #pragma once #include "../cu_cp/test_helpers.h" +#include "lib/cu_cp/ue_manager/cu_cp_ue_impl.h" #include "lib/rrc/ue/rrc_ue_impl.h" #include "rrc_ue_test_messages.h" #include "test_helpers.h" @@ -38,7 +39,7 @@ namespace srsran { namespace srs_cu_cp { // Free-function to generate dummy security context (used by e.g. Mobility tests) -static security::security_context generate_security_context() +static security::security_context generate_security_context(ue_security_manager& sec_mng) { const char* sk_gnb_cstr = "8d2abb1a4349319ea4276295c33d107a6e274495cb9bc2433fb7d7ca4c3f7646"; @@ -66,6 +67,8 @@ static security::security_context generate_security_context() // Generate K_rrc_enc and K_rrc_int sec_ctxt.generate_as_keys(); + sec_mng.update_security_context(sec_ctxt); + return sec_ctxt; } @@ -76,25 +79,22 @@ class rrc_ue_test_helper protected: void init() { + // add UE to UE manager + allocated_ue_index = ue_mng.add_ue(du_index_t::min); + // create RRC UE rrc_ue_creation_message rrc_ue_create_msg{}; - rrc_ue_create_msg.ue_index = ALLOCATED_UE_INDEX; + rrc_ue_create_msg.ue_index = allocated_ue_index; rrc_ue_create_msg.c_rnti = to_rnti(0x1234); bool ret = rrc_ue_create_msg.du_to_cu_container.resize(1); (void)ret; rrc_ue_create_msg.f1ap_pdu_notifier = &rrc_ue_f1ap_notifier; rrc_ue_create_msg.rrc_ue_cu_cp_notifier = &rrc_ue_cu_cp_notifier; rrc_ue_create_msg.measurement_notifier = &rrc_ue_cu_cp_notifier; + rrc_ue_create_msg.cu_cp_ue_notifier = &ue_mng.find_ue(allocated_ue_index)->get_rrc_ue_cu_cp_ue_notifier(); rrc_ue_create_msg.cell.bands.push_back(nr_band::n78); + rrc_ue_cfg_t ue_cfg; - ue_cfg.int_algo_pref_list = {security::integrity_algorithm::nia2, - security::integrity_algorithm::nia1, - security::integrity_algorithm::nia3, - security::integrity_algorithm::nia0}; - ue_cfg.enc_algo_pref_list = {security::ciphering_algorithm::nea0, - security::ciphering_algorithm::nea2, - security::ciphering_algorithm::nea1, - security::ciphering_algorithm::nea3}; // Add meas timing rrc_meas_timing meas_timing; meas_timing.freq_and_timing.emplace(); @@ -107,19 +107,17 @@ class rrc_ue_test_helper ue_cfg.meas_timings.push_back(meas_timing); ue_cfg.rrc_procedure_timeout_ms = rrc_procedure_timeout_ms; - rrc_ue = std::make_unique(*up_resource_mng, - *rrc_ue_create_msg.f1ap_pdu_notifier, + rrc_ue = std::make_unique(*rrc_ue_create_msg.f1ap_pdu_notifier, rrc_ue_ngap_notifier, rrc_ue_ngap_notifier, *rrc_ue_create_msg.rrc_ue_cu_cp_notifier, *rrc_ue_create_msg.measurement_notifier, + *rrc_ue_create_msg.cu_cp_ue_notifier, rrc_ue_create_msg.ue_index, rrc_ue_create_msg.c_rnti, rrc_ue_create_msg.cell, ue_cfg, - sec_ctxt, std::move(rrc_ue_create_msg.du_to_cu_container), - task_sched_handle, std::optional{}); ASSERT_NE(rrc_ue, nullptr); @@ -197,15 +195,18 @@ class rrc_ue_test_helper std::fill(init_sec_ctx.supported_int_algos.begin(), init_sec_ctx.supported_int_algos.end(), true); std::fill(init_sec_ctx.supported_enc_algos.begin(), init_sec_ctx.supported_enc_algos.end(), true); - // Trigger SMC - get_rrc_ue_control_message_handler()->handle_new_security_context(init_sec_ctx); + ue_mng.find_ue(allocated_ue_index)->get_security_manager().init_security_context(init_sec_ctx); + + // Configure PDCP entity security on SRB1 + rrc_ue_security_mode_command_proc_notifier& rrc_ue_notifier = *rrc_ue; + rrc_ue_notifier.on_new_as_security_context(); } void create_srb2() { init_security_context(); srb_creation_message msg; - msg.ue_index = ALLOCATED_UE_INDEX; + msg.ue_index = allocated_ue_index; msg.srb_id = srb_id_t::srb2; rrc_ue->get_rrc_ue_srb_handler().create_srb(msg); } @@ -293,12 +294,12 @@ class rrc_ue_test_helper void check_ue_release_not_requested() { - ASSERT_NE(rrc_ue_cu_cp_notifier.last_cu_cp_ue_context_release_request.ue_index, ALLOCATED_UE_INDEX); + ASSERT_NE(rrc_ue_cu_cp_notifier.last_cu_cp_ue_context_release_request.ue_index, allocated_ue_index); } void check_ue_release_requested() { - ASSERT_EQ(rrc_ue_cu_cp_notifier.last_cu_cp_ue_context_release_request.ue_index, ALLOCATED_UE_INDEX); + ASSERT_EQ(rrc_ue_cu_cp_notifier.last_cu_cp_ue_context_release_request.ue_index, allocated_ue_index); } void receive_smc_complete() @@ -340,8 +341,8 @@ class rrc_ue_test_helper { rrc_ue_reestablishment_context_response reest_context = {}; reest_context.ue_index = ue_index; - reest_context.sec_context = generate_security_context(); - reest_context.old_ue_fully_attached = true; + reest_context.sec_context = generate_security_context(ue_mng.find_ue(allocated_ue_index)->get_security_manager()); + reest_context.old_ue_fully_attached = true; logger.debug("Adding reestablishment context for ue={}", ue_index); @@ -420,17 +421,26 @@ class rrc_ue_test_helper 92); } - const ue_index_t ALLOCATED_UE_INDEX = uint_to_ue_index(23); - rrc_cfg_t cfg{}; // empty config - security::security_context sec_ctxt = {}; + ue_index_t allocated_ue_index; + rrc_cfg_t cfg{}; // empty config + + security_manager_config sec_config{{security::integrity_algorithm::nia2, + security::integrity_algorithm::nia1, + security::integrity_algorithm::nia3, + security::integrity_algorithm::nia0}, + {security::ciphering_algorithm::nea0, + security::ciphering_algorithm::nea2, + security::ciphering_algorithm::nea1, + security::ciphering_algorithm::nea3}}; + + timer_manager timers; + manual_task_worker ctrl_worker{64}; + dummy_rrc_f1ap_pdu_notifier rrc_ue_f1ap_notifier; + dummy_rrc_ue_ngap_adapter rrc_ue_ngap_notifier; + dummy_rrc_ue_cu_cp_adapter rrc_ue_cu_cp_notifier; + + ue_manager ue_mng{{}, {}, sec_config, timers, ctrl_worker}; - timer_manager timers; - manual_task_worker ctrl_worker{64}; - std::unique_ptr up_resource_mng = - create_up_resource_manager(up_resource_manager_cfg{cfg.drb_config}); - dummy_rrc_f1ap_pdu_notifier rrc_ue_f1ap_notifier; - dummy_rrc_ue_ngap_adapter rrc_ue_ngap_notifier; - dummy_rrc_ue_cu_cp_adapter rrc_ue_cu_cp_notifier; std::unique_ptr rrc_ue; srslog::basic_logger& logger = srslog::fetch_basic_logger("TEST", false); dummy_ue_task_scheduler task_sched_handle{timers, ctrl_worker}; diff --git a/tests/unittests/rrc/test_helpers.h b/tests/unittests/rrc/test_helpers.h index 2795e76ddc..37b8b801b7 100644 --- a/tests/unittests/rrc/test_helpers.h +++ b/tests/unittests/rrc/test_helpers.h @@ -25,7 +25,6 @@ #include "srsran/cu_cp/cu_cp_types.h" #include "srsran/rrc/rrc_du.h" #include "srsran/rrc/rrc_ue.h" -#include "srsran/support/async/fifo_async_task_scheduler.h" namespace srsran { namespace srs_cu_cp { @@ -120,20 +119,28 @@ class dummy_rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public }); } - async_task on_ue_removal_required() override + async_task on_ue_release_required(const cu_cp_ue_context_release_request& request) override { - logger.info("UE removal requested"); + logger.info("ue={}: Requested a UE release", request.ue_index); + last_cu_cp_ue_context_release_request = request; + return launch_async([](coro_context>& ctx) mutable { CORO_BEGIN(ctx); CORO_RETURN(); }); } - async_task on_ue_release_required(const cu_cp_ue_context_release_request& request) override + void on_up_context_setup_required(up_context ctxt) override { logger.info("UP context setup requested"); } + + up_context on_up_context_required() override { - logger.info("ue={}: Requested a UE release", request.ue_index); - last_cu_cp_ue_context_release_request = request; + logger.info("UP context requested"); + return up_context{}; + } + async_task on_ue_removal_required() override + { + logger.info("UE removal requested"); return launch_async([](coro_context>& ctx) mutable { CORO_BEGIN(ctx); CORO_RETURN(); diff --git a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp index e68b2adced..865c728b96 100644 --- a/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/paging_scheduler_test.cpp @@ -125,7 +125,6 @@ class base_paging_sched_tester mac_logger.set_context(current_slot.sfn(), current_slot.slot_index()); test_logger.set_context(current_slot.sfn(), current_slot.slot_index()); - sched_res_logger.on_slot_start(); bench->res_grid.slot_indication(current_slot); bench->pdcch_sch.slot_indication(current_slot); diff --git a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp index dfa4aaa4ef..111bc0d6ab 100644 --- a/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/ra_scheduler_test.cpp @@ -94,7 +94,6 @@ class base_ra_scheduler_test { mac_logger.set_context(next_slot.sfn(), next_slot.slot_index()); test_logger.set_context(next_slot.sfn(), next_slot.slot_index()); - result_logger.on_slot_start(); res_grid.slot_indication(next_slot); next_slot++; diff --git a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp index abdea928c6..ff54d58a38 100644 --- a/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp +++ b/tests/unittests/scheduler/common_scheduling/sib1_scheduler_test.cpp @@ -333,8 +333,6 @@ void test_sib1_scheduler(subcarrier_spacing scs_common, // Run the test for 10000 slots. const size_t test_length_slots = 10000; for (size_t sl_idx = 0; sl_idx < test_length_slots; sl_idx++) { - t_bench.sched_res_logger.on_slot_start(); - // Run SIB1 scheduler. sib1_sched.run_slot(t_bench.res_grid, t_bench.sl_tx); @@ -398,8 +396,6 @@ void test_sib1_periodicity(sib1_rtx_periodicity sib1_rtx_period, ssb_periodicity // Run the test for 10000 slots. const size_t test_length_slots = 10000; for (size_t sl_idx = 0; sl_idx < test_length_slots; sl_idx++) { - t_bench.sched_res_logger.on_slot_start(); - // Run SIB1 scheduler. sib1_sched.run_slot(t_bench.res_grid, t_bench.sl_tx); @@ -450,8 +446,6 @@ void test_ssb_sib1_collision(uint32_t freq_arfcn, // Run the test for 10000 slots. const size_t test_length_slots = 100; for (size_t sl_idx = 0; sl_idx < test_length_slots; sl_idx++) { - t_bench.sched_res_logger.on_slot_start(); - // Clear the SSB list of it is not empty. auto& ssb_list = t_bench.get_slot_res_grid().result.dl.bc.ssb_info; if (not ssb_list.empty()) { @@ -725,8 +719,6 @@ class sib1_tdd_partial_slot_test : public ::testing::TestWithParam last_report; + scheduler_cell_metrics last_report; - void report_metrics(span ue_metrics) override - { - last_report.assign(ue_metrics.begin(), ue_metrics.end()); - } + void report_metrics(const scheduler_cell_metrics& metrics) override { last_report = metrics; } }; class scheduler_metrics_handler_tester : public ::testing::Test { protected: scheduler_metrics_handler_tester( - std::chrono::milliseconds period = std::chrono::milliseconds{test_rgen::uniform_int(1, 100)}) : + std::chrono::milliseconds period = std::chrono::milliseconds{test_rgen::uniform_int(2, 100)}) : report_period(period), metrics(period, metrics_notif) { metrics.handle_ue_creation(test_ue_index, to_rnti(0x4601), pci_t{0}, nof_prbs); } - void run_slot(const sched_result& sched_res) + void run_slot(const sched_result& sched_res, std::chrono::microseconds latency = std::chrono::microseconds{0}) { - metrics.push_result(next_sl_tx, sched_res); + metrics.push_result(next_sl_tx, sched_res, latency); ++next_sl_tx; slot_count++; } void get_next_metric() { - metrics_notif.last_report.clear(); + metrics_notif.last_report = {}; sched_result sched_res; - while (metrics_notif.last_report.empty()) { + while (metrics_notif.last_report.ue_metrics.empty()) { run_slot(sched_res); } } @@ -76,20 +73,20 @@ class scheduler_metrics_handler_tester : public ::testing::Test TEST_F(scheduler_metrics_handler_tester, metrics_sent_with_defined_periodicity) { unsigned nof_reports = test_rgen::uniform_int(1, 10); - ASSERT_TRUE(metrics_notif.last_report.empty()); + ASSERT_TRUE(metrics_notif.last_report.ue_metrics.empty()); for (unsigned i = 0; i != nof_reports; ++i) { get_next_metric(); - ASSERT_EQ(metrics_notif.last_report.size(), 1); + ASSERT_EQ(metrics_notif.last_report.ue_metrics.size(), 1); ASSERT_EQ(slot_count, report_period.count() * (i + 1)); - ASSERT_EQ(metrics_notif.last_report[0].rnti, to_rnti(0x4601)); + ASSERT_EQ(metrics_notif.last_report.ue_metrics[0].rnti, to_rnti(0x4601)); } } TEST_F(scheduler_metrics_handler_tester, when_no_events_took_place_then_metrics_are_zero) { this->get_next_metric(); - scheduler_ue_metrics ue_metrics = metrics_notif.last_report[0]; + scheduler_ue_metrics ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_brate_kbps, 0); @@ -103,8 +100,11 @@ TEST_F(scheduler_metrics_handler_tester, when_no_events_took_place_then_metrics_ ASSERT_EQ(ue_metrics.pusch_snr_db, 0); ASSERT_EQ(ue_metrics.pusch_rsrp_db, -std::numeric_limits::infinity()); ASSERT_EQ(ue_metrics.pucch_snr_db, 0); - ASSERT_EQ(ue_metrics.cqi, 0); ASSERT_EQ(ue_metrics.bsr, 0); + + // Check that the CQI and RI statistics have no observations. + ASSERT_EQ(ue_metrics.cqi_stats.get_nof_observations(), 0); + ASSERT_EQ(ue_metrics.ri_stats.get_nof_observations(), 0); } TEST_F(scheduler_metrics_handler_tester, compute_nof_dl_oks_and_noks) @@ -120,13 +120,13 @@ TEST_F(scheduler_metrics_handler_tester, compute_nof_dl_oks_and_noks) } this->get_next_metric(); - scheduler_ue_metrics ue_metrics = metrics_notif.last_report[0]; + scheduler_ue_metrics ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_nof_ok, nof_acks); ASSERT_EQ(ue_metrics.dl_nof_nok, nof_nacks); this->get_next_metric(); - ue_metrics = metrics_notif.last_report[0]; + ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_nof_ok, 0) << "Nof DL OKs not reset"; ASSERT_EQ(ue_metrics.dl_nof_nok, 0) << "Nof DL NOKs not reset"; @@ -150,14 +150,14 @@ TEST_F(scheduler_metrics_handler_tester, compute_nof_ul_oks_and_noks) } this->get_next_metric(); - scheduler_ue_metrics ue_metrics = metrics_notif.last_report[0]; + scheduler_ue_metrics ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.pci, pci_t{0}); ASSERT_EQ(ue_metrics.ul_nof_ok, nof_acks); ASSERT_EQ(ue_metrics.ul_nof_nok, nof_nacks); this->get_next_metric(); - ue_metrics = metrics_notif.last_report[0]; + ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.ul_nof_ok, 0) << "Nof DL OKs not reset"; ASSERT_EQ(ue_metrics.ul_nof_nok, 0) << "Nof DL NOKs not reset"; @@ -181,13 +181,13 @@ TEST_F(scheduler_metrics_handler_tester, compute_mcs) run_slot(res); } - scheduler_ue_metrics ue_metrics = metrics_notif.last_report[0]; + scheduler_ue_metrics ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_mcs, dl_mcs); ASSERT_EQ(ue_metrics.ul_mcs, ul_mcs); this->get_next_metric(); - ue_metrics = metrics_notif.last_report[0]; + ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_mcs, 0) << "DL MCS not reset"; ASSERT_EQ(ue_metrics.ul_mcs, 0) << "UL MCS not reset"; @@ -207,7 +207,7 @@ TEST_F(scheduler_metrics_handler_tester, compute_bitrate) metrics.handle_crc_indication(crc_pdu, ul_tbs); this->get_next_metric(); - scheduler_ue_metrics ue_metrics = metrics_notif.last_report[0]; + scheduler_ue_metrics ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.pci, pci_t{0}); ASSERT_EQ(ue_metrics.dl_brate_kbps, static_cast(dl_tbs.value() * 8) / report_period.count()); @@ -215,7 +215,7 @@ TEST_F(scheduler_metrics_handler_tester, compute_bitrate) // Slot with no ACKs. this->get_next_metric(); - ue_metrics = metrics_notif.last_report[0]; + ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_brate_kbps, 0) << "DL bitrate not reset"; ASSERT_EQ(ue_metrics.ul_brate_kbps, 0) << "UL bitrate not reset"; @@ -228,8 +228,45 @@ TEST_F(scheduler_metrics_handler_tester, compute_bitrate) metrics.handle_crc_indication(crc_pdu, ul_tbs); this->get_next_metric(); - ue_metrics = metrics_notif.last_report[0]; + ue_metrics = metrics_notif.last_report.ue_metrics[0]; ASSERT_EQ(ue_metrics.rnti, to_rnti(0x4601)); ASSERT_EQ(ue_metrics.dl_brate_kbps, 0) << "NACKs should not count for bitrate"; ASSERT_EQ(ue_metrics.ul_brate_kbps, 0) << "NACKs should not count for bitrate"; +} + +TEST_F(scheduler_metrics_handler_tester, compute_latency_metric) +{ + using usecs = std::chrono::microseconds; + std::vector samples = {usecs{10}, usecs{50}, usecs{150}, usecs{300}, usecs{500}}; + samples.resize(report_period.count()); + + sched_result sched_res; + for (unsigned i = 0; i != samples.size(); ++i) { + ASSERT_TRUE(metrics_notif.last_report.ue_metrics.empty()); + this->run_slot(sched_res, samples[i]); + } + ASSERT_FALSE(metrics_notif.last_report.ue_metrics.empty()); + scheduler_cell_metrics cell_metrics = metrics_notif.last_report; + + unsigned expected_avg = std::accumulate(samples.begin(), samples.end(), usecs{0}).count() / report_period.count(); + ASSERT_EQ(cell_metrics.average_decision_latency.count(), expected_avg); + + for (unsigned i = 0; i != cell_metrics.latency_histogram.size(); ++i) { + unsigned expected = std::count_if(samples.begin(), samples.end(), [i](usecs u) { + unsigned bin = u.count() / scheduler_cell_metrics::nof_usec_per_bin; + bin = std::min(bin, scheduler_cell_metrics::latency_hist_bins - 1); + return bin == i; + }); + ASSERT_EQ(cell_metrics.latency_histogram[i], expected); + } +} + +TEST_F(scheduler_metrics_handler_tester, compute_error_indications) +{ + metrics.handle_error_indication(); + metrics.handle_error_indication(); + this->get_next_metric(); + ASSERT_EQ(metrics_notif.last_report.nof_error_indications, 2); + this->get_next_metric(); + ASSERT_EQ(metrics_notif.last_report.nof_error_indications, 0); } \ No newline at end of file diff --git a/tests/unittests/scheduler/test_utils/config_generators.cpp b/tests/unittests/scheduler/test_utils/config_generators.cpp index 5cc078cbe4..bbf4cbea8b 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.cpp +++ b/tests/unittests/scheduler/test_utils/config_generators.cpp @@ -35,10 +35,10 @@ class dummy_sched_configuration_notifier : public sched_configuration_notifier void on_ue_delete_response(du_ue_index_t ue_index) override {} }; -class dummy_scheduler_ue_metrics_notifier : public scheduler_ue_metrics_notifier +class dummy_scheduler_ue_metrics_notifier : public scheduler_metrics_notifier { public: - void report_metrics(span ue_metrics) override {} + void report_metrics(const scheduler_cell_metrics& metrics) override {} }; class dummy_sched_metrics_ue_configurator : public sched_metrics_ue_configurator diff --git a/tests/unittests/scheduler/test_utils/config_generators.h b/tests/unittests/scheduler/test_utils/config_generators.h index 9040c1c9a0..5370ae480e 100644 --- a/tests/unittests/scheduler/test_utils/config_generators.h +++ b/tests/unittests/scheduler/test_utils/config_generators.h @@ -310,7 +310,7 @@ class test_sched_config_manager const cell_config_builder_params builder_params; scheduler_expert_config expert_cfg; std::unique_ptr cfg_notifier; - std::unique_ptr metric_notifier; + std::unique_ptr metric_notifier; std::unique_ptr ue_metrics_configurator; sched_cell_configuration_request_message default_cell_req; diff --git a/tests/unittests/scheduler/test_utils/dummy_test_components.h b/tests/unittests/scheduler/test_utils/dummy_test_components.h index 9451cc0e8f..b82b5c2822 100644 --- a/tests/unittests/scheduler/test_utils/dummy_test_components.h +++ b/tests/unittests/scheduler/test_utils/dummy_test_components.h @@ -162,10 +162,10 @@ class sched_cfg_dummy_notifier : public sched_configuration_notifier void on_ue_delete_response(du_ue_index_t ue_index) override { last_ue_index_deleted = ue_index; } }; -class scheduler_ue_metrics_dummy_notifier : public scheduler_ue_metrics_notifier +class scheduler_ue_metrics_dummy_notifier : public scheduler_metrics_notifier { public: - void report_metrics(span ue_metrics) override {} + void report_metrics(const scheduler_cell_metrics& ue_metrics) override {} }; class scheduler_harq_timeout_dummy_handler : public harq_timeout_handler diff --git a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp index 8b5eeaa8a2..5f017a4bd5 100644 --- a/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/fallback_scheduler_test.cpp @@ -200,7 +200,6 @@ class base_fallback_tester mac_logger.set_context(current_slot.sfn(), current_slot.slot_index()); test_logger.set_context(current_slot.sfn(), current_slot.slot_index()); - result_logger.on_slot_start(); bench->res_grid.slot_indication(current_slot); bench->pdcch_sch.slot_indication(current_slot); diff --git a/tests/unittests/srsvec/CMakeLists.txt b/tests/unittests/srsvec/CMakeLists.txt index 6a80b08d02..fc2bce855b 100644 --- a/tests/unittests/srsvec/CMakeLists.txt +++ b/tests/unittests/srsvec/CMakeLists.txt @@ -40,7 +40,7 @@ add_test(srsvec_binary_test srsvec_binary_test) add_executable(srsvec_convert_test srsvec_convert_test.cpp) target_link_libraries(srsvec_convert_test srsvec srslog gtest gtest_main) -gtest_discover_tests(srsvec_convert_test) +add_test(srsvec_convert_test srsvec_convert_test) add_executable(srsvec_division_test srsvec_division_test.cpp) target_link_libraries(srsvec_division_test srsvec srslog) diff --git a/tests/unittests/support/CMakeLists.txt b/tests/unittests/support/CMakeLists.txt index 537b4c67e6..6759157240 100644 --- a/tests/unittests/support/CMakeLists.txt +++ b/tests/unittests/support/CMakeLists.txt @@ -76,6 +76,10 @@ add_executable(ring_buffer_pool_test ring_buffer_pool_test.cpp) target_link_libraries(ring_buffer_pool_test srsran_support gtest gtest_main) add_test(ring_buffer_pool_test ring_buffer_pool_test) +add_executable(unbounded_object_pool_test unbounded_object_pool_test.cpp) +target_link_libraries(unbounded_object_pool_test srsran_support gtest gtest_main) +add_test(unbounded_object_pool_test unbounded_object_pool_test) + add_executable(fixed_size_memory_pool_test fixed_size_memory_pool_test.cpp) target_link_libraries(fixed_size_memory_pool_test srsran_support gtest gtest_main) add_test(fixed_size_memory_pool_test fixed_size_memory_pool_test) diff --git a/tests/unittests/support/unbounded_object_pool_test.cpp b/tests/unittests/support/unbounded_object_pool_test.cpp new file mode 100644 index 0000000000..e3b3a94da4 --- /dev/null +++ b/tests/unittests/support/unbounded_object_pool_test.cpp @@ -0,0 +1,64 @@ +/* + * + * Copyright 2021-2024 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsran/support/memory_pool/unbounded_object_pool.h" +#include + +using namespace srsran; + +class unbounded_object_pool_test : public ::testing::Test +{ +protected: + constexpr static size_t init_capacity = 8; + unbounded_object_pool pool{init_capacity}; +}; + +TEST_F(unbounded_object_pool_test, pool_initiated_with_provided_capacity) +{ + ASSERT_EQ(pool.current_capacity_approx(), init_capacity); +} + +TEST_F(unbounded_object_pool_test, pool_allocates_objects_within_capacity) +{ + auto obj = pool.get(); + ASSERT_NE(obj, nullptr); + ASSERT_EQ(pool.current_capacity_approx(), init_capacity - 1); + *obj = 42; + obj.reset(); + ASSERT_EQ(pool.current_capacity_approx(), init_capacity); +} + +TEST_F(unbounded_object_pool_test, pool_allocates_objects_beyond_initial_capacity) +{ + std::vector::ptr> objs; + for (unsigned i = 0; i != init_capacity; ++i) { + objs.push_back(pool.get()); + ASSERT_NE(objs.back(), nullptr); + } + auto obj = pool.get(); + ASSERT_NE(obj, nullptr); + + // pool capacity grew. + objs.clear(); + obj.reset(); + ASSERT_GT(pool.current_capacity_approx(), init_capacity); +}