diff --git a/srsenb/hdr/stack/enb_stack_base.h b/srsenb/hdr/stack/enb_stack_base.h index a69ab7c4c..339215b16 100644 --- a/srsenb/hdr/stack/enb_stack_base.h +++ b/srsenb/hdr/stack/enb_stack_base.h @@ -23,6 +23,7 @@ #define SRSLTE_ENB_STACK_BASE_H #include "srslte/interfaces/enb_interfaces.h" +#include "srsue/hdr/stack/upper/gw.h" #include namespace srsenb { @@ -57,13 +58,23 @@ typedef struct { int stack_hex_limit; } stack_log_args_t; +// Expert arguments to create GW without core NW typedef struct { + std::string ip_addr; + srsue::gw_args_t gw_args; + uint8_t drb_lcid; + uint16_t rnti; +} core_less_args_t; + +typedef struct { + std::string type; mac_args_t mac; s1ap_args_t s1ap; pcap_args_t mac_pcap; pcap_args_t s1ap_pcap; stack_log_args_t log; embms_args_t embms; + core_less_args_t coreless; } stack_args_t; struct stack_metrics_t; diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h new file mode 100644 index 000000000..f936e4f5f --- /dev/null +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -0,0 +1,121 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE 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. + * + * srsLTE 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/. + * + */ + +/****************************************************************************** + * File: gnb_stack_nr.h + * Description: L2/L3 gNB stack class. + *****************************************************************************/ + +#ifndef SRSLTE_GNB_STACK_NR_H +#define SRSLTE_GNB_STACK_NR_H + +#include "srsenb/hdr/stack/mac/mac_nr.h" +#include "srsenb/hdr/stack/rrc/rrc_nr.h" +#include "srsenb/hdr/stack/upper/pdcp_nr.h" +#include "srsenb/hdr/stack/upper/rlc_nr.h" +#include "upper/gtpu.h" +#include "upper/s1ap.h" +#include "upper/sdap.h" + +#include "srslte/common/log_filter.h" + +#include "enb_stack_base.h" +#include "srsenb/hdr/enb.h" +#include "srslte/interfaces/gnb_interfaces.h" + +// This is needed for GW +#include "srslte/interfaces/ue_interfaces.h" +#include "srsue/hdr/stack/upper/gw.h" + +namespace srsenb { + +class gnb_stack_nr final : public srsenb::enb_stack_base, + public stack_interface_phy_nr, + public srsue::stack_interface_gw, + public srslte::task_handler_interface, + public srslte::thread +{ +public: + explicit gnb_stack_nr(srslte::logger* logger_); + ~gnb_stack_nr() final; + + int init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rrc_cfg_, phy_interface_stack_nr* phy_); + int init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rrc_cfg_); + + // eNB stack base interface + void stop() final; + std::string get_type() final; + bool get_metrics(srsenb::stack_metrics_t* metrics) final; + + // PHY->MAC interface + int sf_indication(const uint32_t tti); + + // Temporary GW interface + void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking); + bool is_lcid_enabled(uint32_t lcid); + bool switch_on(); + void run_tti(uint32_t tti); + + // Task Handling interface + srslte::timer_handler::unique_timer get_unique_timer() final { return timers.get_unique_timer(); } + srslte::task_multiqueue::queue_handler make_task_queue() final { return pending_tasks.get_queue_handler(); } + void enqueue_background_task(std::function f) final; + void notify_background_task_result(srslte::move_task_t task) final; + void defer_callback(uint32_t duration_ms, std::function func) final; + void defer_task(srslte::move_task_t task) final; + +private: + void run_thread() final; + void run_tti_impl(); + + // args + srsenb::stack_args_t args = {}; + srslte::logger* logger = nullptr; + phy_interface_stack_nr* phy = nullptr; + + // timers + srslte::timer_handler timers; + + // derived + std::unique_ptr m_mac; + std::unique_ptr m_rlc; + std::unique_ptr m_pdcp; + std::unique_ptr m_sdap; + std::unique_ptr m_rrc; + std::unique_ptr m_gw; + // std::unique_ptr m_ngap; + // std::unique_ptr m_gtpu; + + // state + bool running = false; + uint32_t current_tti = 10240; + + // Thread + static const int STACK_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD + srslte::task_multiqueue pending_tasks; + std::vector deferred_stack_tasks; ///< enqueues stack tasks from within. Avoids locking + srslte::task_thread_pool background_tasks; ///< Thread pool used for long, low-priority tasks + int sync_queue_id = -1, background_queue_id = -1; +}; + +} // namespace srsenb + +#endif // SRSLTE_GNB_STACK_NR_H \ No newline at end of file diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 471e07110..1f89bc94f 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -33,7 +33,6 @@ #include "srslte/common/threads.h" #include "srslte/common/timeout.h" #include "srslte/interfaces/gnb_interfaces.h" -#include "srsue/hdr/stack/upper/gw.h" #include #include @@ -49,13 +48,6 @@ struct rrc_nr_cfg_sr_t { uint32_t sf_mapping[80]; uint32_t nof_subframes; }; -// Expert arguments to create GW without core NW -struct core_less_args_t { - std::string ip_addr; - srsue::gw_args_t gw_args; - uint8_t drb_lcid; - uint16_t rnti; -}; struct rrc_nr_cfg_t { asn1::rrc_nr::mib_s mib; diff --git a/srsenb/src/stack/CMakeLists.txt b/srsenb/src/stack/CMakeLists.txt index cd5f9f6dc..9310ed98d 100644 --- a/srsenb/src/stack/CMakeLists.txt +++ b/srsenb/src/stack/CMakeLists.txt @@ -25,4 +25,9 @@ add_subdirectory(upper) set(SOURCES enb_stack_lte.cc) add_library(srsenb_stack STATIC ${SOURCES}) -target_link_libraries(srsenb_stack) \ No newline at end of file +target_link_libraries(srsenb_stack) + +if(ENABLE_5GNR) + add_library(srsgnb_stack STATIC gnb_stack_nr.cc) + target_link_libraries(srsgnb_stack) +endif() \ No newline at end of file diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc new file mode 100644 index 000000000..802e29f5c --- /dev/null +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -0,0 +1,208 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE 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. + * + * srsLTE 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 "srsenb/hdr/stack/gnb_stack_nr.h" +#include "srslte/srslte.h" +#include + +namespace srsenb { + +gnb_stack_nr::gnb_stack_nr(srslte::logger* logger_) : logger(logger_), timers(128), thread("gNB"), background_tasks(1) +{ + m_mac.reset(new mac_nr()); + m_rlc.reset(new rlc_nr("RLC")); + m_pdcp.reset(new pdcp_nr(this, "PDCP")); + m_rrc.reset(new rrc_nr(&timers)); + m_sdap.reset(new sdap()); + m_gw.reset(new srsue::gw()); + // m_gtpu.reset(new srsenb::gtpu()); + + sync_queue_id = pending_tasks.add_queue(); + background_queue_id = pending_tasks.add_queue(); +} + +gnb_stack_nr::~gnb_stack_nr() +{ + stop(); +} + +std::string gnb_stack_nr::get_type() +{ + return "nr"; +} + +int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rrc_cfg_, phy_interface_stack_nr* phy_) +{ + phy = phy_; + if (init(args_, rrc_cfg_)) { + return SRSLTE_ERROR; + } + return SRSLTE_SUCCESS; +} + +int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rrc_cfg_) +{ + args = args_; + + // verify configuration correctness + // gtpu_log.init("GTPU", logger); + // gtpu_log.set_level(args.log.gtpu_level); + // gtpu_log.set_hex_limit(args.log.gtpu_hex_limit); + + // Init all layers + mac_nr_args_t mac_args = {}; + mac_args.log_level = args.log.mac_level; + mac_args.log_hex_limit = args.log.mac_hex_limit; + mac_args.pcap = args.mac_pcap; + mac_args.sched = args.mac.sched; + mac_args.rnti = args.coreless.rnti; + m_mac->init(mac_args, phy, m_rlc.get(), m_rrc.get()); + + m_rlc->init(m_pdcp.get(), m_rrc.get(), m_mac.get(), &timers); + + pdcp_nr_args_t pdcp_args = {}; + pdcp_args.log_level = args.log.pdcp_level; + pdcp_args.log_hex_limit = args.log.pdcp_hex_limit; + m_pdcp->init(pdcp_args, m_rlc.get(), m_rrc.get(), m_sdap.get()); + + m_rrc->init(rrc_cfg_, phy, m_mac.get(), m_rlc.get(), m_pdcp.get(), nullptr, nullptr); + + m_sdap->init(m_pdcp.get(), nullptr); + + m_gw->init(args.coreless.gw_args, logger, this); + char* err_str = nullptr; + if (m_gw->setup_if_addr(args.coreless.drb_lcid, + LIBLTE_MME_PDN_TYPE_IPV4, + htonl(inet_addr(args.coreless.ip_addr.c_str())), + nullptr, + err_str)) { + printf("Error configuring TUN interface\n"); + } + + // TODO: add NGAP + // m_gtpu->init(args.s1ap.gtp_bind_addr, args.s1ap.mme_addr, + // args.expert.m1u_multiaddr, args.expert.m1u_if_addr, nullptr, >pu_log, + // args.expert.enable_mbsfn); + + running = true; + + start(STACK_MAIN_THREAD_PRIO); + + return SRSLTE_SUCCESS; +} + +void gnb_stack_nr::stop() +{ + if (running) { + m_gw->stop(); + // m_gtpu->stop(); + m_rrc->stop(); + m_pdcp->stop(); + m_mac->stop(); + + running = false; + } +} + +bool gnb_stack_nr::switch_on() +{ + // Nothing to be done here + return true; +} + +void gnb_stack_nr::run_thread() +{ + while (running) { + srslte::move_task_t task{}; + pending_tasks.wait_pop(&task); + if (running) { + task(); + } + } +} + +void gnb_stack_nr::run_tti(uint32_t tti) +{ + current_tti = tti; + pending_tasks.push(sync_queue_id, [this]() { run_tti_impl(); }); +} + +void gnb_stack_nr::run_tti_impl() +{ + // m_ngap->run_tti(); + timers.step_all(); +} + +/******************************************************** + * + * Interface for upper layer timers + * + *******************************************************/ + +bool gnb_stack_nr::get_metrics(srsenb::stack_metrics_t* metrics) +{ + m_mac->get_metrics(metrics->mac); + m_rrc->get_metrics(metrics->rrc); + return true; +} + +int gnb_stack_nr::sf_indication(const uint32_t tti) +{ + return m_mac->sf_indication(tti); +} + +// Temporary GW interface +void gnb_stack_nr::write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) +{ + m_pdcp->write_sdu(args.coreless.rnti, lcid, std::move(sdu)); +} + +bool gnb_stack_nr::is_lcid_enabled(uint32_t lcid) +{ + return (lcid == args.coreless.drb_lcid); +} + +/*************************** + * Task Handling Interface + **************************/ + +void gnb_stack_nr::enqueue_background_task(std::function f) +{ + background_tasks.push_task(std::move(f)); +} + +void gnb_stack_nr::notify_background_task_result(srslte::move_task_t task) +{ + // run the notification in the stack thread + pending_tasks.push(background_queue_id, std::move(task)); +} + +void gnb_stack_nr::defer_callback(uint32_t duration_ms, std::function func) +{ + timers.defer_callback(duration_ms, func); +} + +void gnb_stack_nr::defer_task(srslte::move_task_t task) +{ + deferred_stack_tasks.push_back(std::move(task)); +} + +} // namespace srsenb \ No newline at end of file