diff --git a/lib/include/srsran/interfaces/ue_gw_interfaces.h b/lib/include/srsran/interfaces/ue_gw_interfaces.h index 057cef5d2..90fe4acfa 100644 --- a/lib/include/srsran/interfaces/ue_gw_interfaces.h +++ b/lib/include/srsran/interfaces/ue_gw_interfaces.h @@ -21,14 +21,24 @@ namespace srsue { class gw_interface_nas { public: - virtual int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, - uint8_t pdn_type, - uint32_t ip_addr, - uint8_t* ipv6_if_id, - char* err_str) = 0; + /** + * Informs GW about new EPS default bearer being created after attach accept + * along with the assigned IP address. + */ + virtual int + setup_if_addr(uint32_t eps_bearer_id, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str) = 0; + + /** + * Inform GW about the deactivation of a EPS bearer, e.g. during + * detach + */ + virtual int deactivate_eps_bearer(const uint32_t eps_bearer_id) = 0; + + /** + * Informs GW about new traffic flow templates and their associated EPS bearer ID + * All TFT are applied to a dedicated EPS bearer that has a linked default bearer + */ virtual int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) = 0; typedef enum { @@ -50,7 +60,6 @@ class gw_interface_rrc { public: virtual void add_mch_port(uint32_t lcid, uint32_t port) = 0; - virtual int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) = 0; virtual bool is_running() = 0; }; diff --git a/lib/include/srsran/interfaces/ue_interfaces.h b/lib/include/srsran/interfaces/ue_interfaces.h index 4027b1458..b55a5266b 100644 --- a/lib/include/srsran/interfaces/ue_interfaces.h +++ b/lib/include/srsran/interfaces/ue_interfaces.h @@ -28,7 +28,9 @@ namespace srsue { class stack_interface_rrc { public: - virtual srsran::tti_point get_current_tti() = 0; + virtual srsran::tti_point get_current_tti() = 0; + virtual void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) = 0; + virtual void remove_eps_bearer(uint8_t eps_bearer_id) = 0; }; // Combined interface for PHY to access stack (MAC and RRC) diff --git a/lib/include/srsran/interfaces/ue_pdcp_interfaces.h b/lib/include/srsran/interfaces/ue_pdcp_interfaces.h index 9c3968da0..bdcf4c40f 100644 --- a/lib/include/srsran/interfaces/ue_pdcp_interfaces.h +++ b/lib/include/srsran/interfaces/ue_pdcp_interfaces.h @@ -25,7 +25,7 @@ public: virtual void reestablish(uint32_t lcid) = 0; virtual void reset() = 0; virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1) = 0; - virtual void add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) = 0; + virtual int add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) = 0; virtual void del_bearer(uint32_t lcid) = 0; virtual void change_lcid(uint32_t old_lcid, uint32_t new_lcid) = 0; virtual void config_security(uint32_t lcid, const srsran::as_security_config_t& sec_cfg) = 0; @@ -50,19 +50,23 @@ public: virtual void notify_failure(uint32_t lcid, const srsran::pdcp_sn_vector_t& pdcp_sn) = 0; }; -class pdcp_interface_gw +// Data-plane interface for Stack after EPS bearer to LCID conversion +class pdcp_interface_stack { public: - virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) = 0; - virtual bool is_lcid_enabled(uint32_t lcid) = 0; + virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1) = 0; + virtual bool is_lcid_enabled(uint32_t lcid) = 0; }; -// STACK interface for GW -class stack_interface_gw : public pdcp_interface_gw +// STACK interface for GW (based on EPS-bearer IDs) +class stack_interface_gw { public: virtual bool is_registered() = 0; virtual bool start_service_request() = 0; + virtual void write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) = 0; + ///< Allow GW to query if a radio bearer for a given EPS bearer ID is currently active + virtual bool has_active_radio_bearer(uint32_t eps_bearer_id) = 0; }; } // namespace srsue diff --git a/lib/include/srsran/interfaces/ue_rrc_interfaces.h b/lib/include/srsran/interfaces/ue_rrc_interfaces.h index c4f20d2c8..96071af1d 100644 --- a/lib/include/srsran/interfaces/ue_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/ue_rrc_interfaces.h @@ -72,7 +72,6 @@ public: virtual bool is_connected() = 0; virtual void paging_completed(bool outcome) = 0; virtual const char* get_rb_name(uint32_t lcid) = 0; - virtual uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) = 0; virtual bool has_nr_dc() = 0; }; diff --git a/lib/include/srsran/test/ue_test_interfaces.h b/lib/include/srsran/test/ue_test_interfaces.h index 0b7ad541f..3df9d9605 100644 --- a/lib/include/srsran/test/ue_test_interfaces.h +++ b/lib/include/srsran/test/ue_test_interfaces.h @@ -27,6 +27,8 @@ public: stack_test_dummy() {} srsran::tti_point get_current_tti() override { return srsran::tti_point{tti % 10240}; } + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) final{}; + void remove_eps_bearer(uint8_t eps_bearer_id) final{}; // Testing utility functions void run_tti() diff --git a/lib/include/srsran/upper/pdcp.h b/lib/include/srsran/upper/pdcp.h index ffa27897c..d7e1ff918 100644 --- a/lib/include/srsran/upper/pdcp.h +++ b/lib/include/srsran/upper/pdcp.h @@ -26,14 +26,10 @@ class pdcp : public srsue::pdcp_interface_rlc, public srsue::pdcp_interface_rrc public: pdcp(srsran::task_sched_handle task_sched_, const char* logname); virtual ~pdcp(); - void init(srsue::rlc_interface_pdcp* rlc_, - srsue::rrc_interface_pdcp* rrc_, - srsue::rrc_interface_pdcp* rrc_nr_, - srsue::gw_interface_pdcp* gw_); void init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_); void stop(); - // GW interface + // Stack interface bool is_lcid_enabled(uint32_t lcid); // RRC interface @@ -42,7 +38,7 @@ public: void reset() override; void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, int sn = -1) override; void write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu); - void add_bearer(uint32_t lcid, pdcp_config_t cnfg) override; + int add_bearer(uint32_t lcid, pdcp_config_t cnfg) override; void add_bearer_mrb(uint32_t lcid, pdcp_config_t cnfg); void del_bearer(uint32_t lcid) override; void change_lcid(uint32_t old_lcid, uint32_t new_lcid) override; @@ -75,7 +71,6 @@ public: private: srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr; - srsue::rrc_interface_pdcp* rrc_nr = nullptr; srsue::gw_interface_pdcp* gw = nullptr; srsran::task_sched_handle task_sched; srslog::basic_logger& logger; @@ -95,4 +90,5 @@ private: }; } // namespace srsran + #endif // SRSRAN_PDCP_H diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 385b80051..2c45a0de1 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -30,15 +30,6 @@ pdcp::~pdcp() pdcp_array_mrb.clear(); } -void pdcp::init(srsue::rlc_interface_pdcp* rlc_, - srsue::rrc_interface_pdcp* rrc_, - srsue::rrc_interface_pdcp* rrc_nr_, - srsue::gw_interface_pdcp* gw_) -{ - init(rlc_, rrc_, gw_); - rrc_nr = rrc_nr_; -} - void pdcp::init(srsue::rlc_interface_pdcp* rlc_, srsue::rrc_interface_pdcp* rrc_, srsue::gw_interface_pdcp* gw_) { rlc = rlc_; @@ -88,7 +79,7 @@ void pdcp::write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, int sn) if (valid_lcid(lcid)) { pdcp_array.at(lcid)->write_sdu(std::move(sdu), sn); } else { - logger.warning("Writing sdu: lcid=%d. Deallocating sdu", lcid); + logger.warning("LCID %d doesn't exist. Deallocating SDU", lcid); } } @@ -99,39 +90,40 @@ void pdcp::write_sdu_mch(uint32_t lcid, unique_byte_buffer_t sdu) } } -void pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg) +int pdcp::add_bearer(uint32_t lcid, pdcp_config_t cfg) { - if (not valid_lcid(lcid)) { - std::unique_ptr entity; - // For now we create an pdcp entity lte for nr due to it's maturity - if (cfg.rat == srsran::srsran_rat_t::lte) { - entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); - } else if (cfg.rat == srsran::srsran_rat_t::nr) { - if (rrc_nr == nullptr) { - logger.warning("Cannot add PDCP entity - missing rrc_nr parent pointer"); - return; - } - entity.reset(new pdcp_entity_lte{rlc, rrc_nr, gw, task_sched, logger, lcid}); - } - - if (not entity->configure(cfg)) { - logger.error("Can not configure PDCP entity"); - return; - } - - if (not pdcp_array.insert(std::make_pair(lcid, std::move(entity))).second) { - logger.error("Error inserting PDCP entity in to array."); - return; - } - logger.info( - "Add %s (lcid=%d, bearer_id=%d, sn_len=%dbits)", rrc->get_rb_name(lcid), lcid, cfg.bearer_id, cfg.sn_len); - { - std::lock_guard lock(cache_mutex); - valid_lcids_cached.insert(lcid); - } - } else { - logger.info("Bearer %s already configured.", rrc->get_rb_name(lcid)); + if (valid_lcid(lcid)) { + logger.error("Bearer %s already configured.", rrc->get_rb_name(lcid)); + return SRSRAN_ERROR; } + + std::unique_ptr entity; + + // For now we create an pdcp entity lte for nr due to it's maturity + if (cfg.rat == srsran::srsran_rat_t::lte) { + entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); + } else if (cfg.rat == srsran::srsran_rat_t::nr) { + entity.reset(new pdcp_entity_lte{rlc, rrc, gw, task_sched, logger, lcid}); + } + + if (not entity->configure(cfg)) { + logger.error("Can not configure PDCP entity"); + return SRSRAN_ERROR; + } + + if (not pdcp_array.insert(std::make_pair(lcid, std::move(entity))).second) { + logger.error("Error inserting PDCP entity in to array."); + return SRSRAN_ERROR; + } + + { + std::lock_guard lock(cache_mutex); + valid_lcids_cached.insert(lcid); + } + + logger.info("Add %s (lcid=%d, bearer_id=%d, sn_len=%dbits)", rrc->get_rb_name(lcid), lcid, cfg.bearer_id, cfg.sn_len); + + return SRSRAN_SUCCESS; } void pdcp::add_bearer_mrb(uint32_t lcid, pdcp_config_t cfg) diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index b7a388428..389130857 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -448,7 +448,7 @@ int rlc::add_bearer_mrb(uint32_t lcid) std::unique_ptr rlc_entity = std::unique_ptr(new rlc_um_lte(logger, lcid, pdcp, rrc, timers)); // configure and add to array - if (rlc_entity or rlc_entity->configure(rlc_config_t::mch_config()) == false) { + if (not rlc_entity or rlc_entity->configure(rlc_config_t::mch_config()) == false) { logger.error("Error configuring RLC entity."); return SRSRAN_ERROR; } diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index 931891e1d..a53b37fc6 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -64,7 +64,7 @@ public: // Temporary GW interface void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu); - bool is_lcid_enabled(uint32_t lcid); + bool has_active_radio_bearer(uint32_t eps_bearer_id); bool switch_on(); void run_tti(uint32_t tti); diff --git a/srsenb/src/stack/gnb_stack_nr.cc b/srsenb/src/stack/gnb_stack_nr.cc index 223798334..9f3d93f06 100644 --- a/srsenb/src/stack/gnb_stack_nr.cc +++ b/srsenb/src/stack/gnb_stack_nr.cc @@ -86,7 +86,6 @@ int gnb_stack_nr::init(const srsenb::stack_args_t& args_, const rrc_nr_cfg_t& rr m_gw->init(args.coreless.gw_args, this); char* err_str = nullptr; if (m_gw->setup_if_addr(5, - args.coreless.drb_lcid, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr(args.coreless.ip_addr.c_str())), nullptr, @@ -179,9 +178,9 @@ void gnb_stack_nr::write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) m_pdcp->write_sdu(args.coreless.rnti, lcid, std::move(sdu)); } -bool gnb_stack_nr::is_lcid_enabled(uint32_t lcid) +bool gnb_stack_nr::has_active_radio_bearer(uint32_t eps_bearer_id) { - return (lcid == args.coreless.drb_lcid); + return (eps_bearer_id == args.coreless.drb_lcid); } } // namespace srsenb diff --git a/srsue/hdr/stack/bearer_manager.h b/srsue/hdr/stack/bearer_manager.h new file mode 100644 index 000000000..b954bd6e8 --- /dev/null +++ b/srsue/hdr/stack/bearer_manager.h @@ -0,0 +1,70 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSUE_BEARER_MANAGER_H +#define SRSUE_BEARER_MANAGER_H + +#include "srsran/common/common.h" +#include "srsran/common/rwlock_guard.h" +#include "srsran/srslog/srslog.h" +#include +#include + +namespace srsue { + +/** + * @brief Helper class to manage the mapping between EPS bearer and radio bearer + * + * The class maps EPS bearers that are known to NAS and GW and radio bearer (RB) that + * are only known to RRC. Since the lifetime of a EPS bearer is usually longer + * than the lifetime of a RB, the GW needs to query the Stack to check whether a + * given EPS bearer is active, i.e. a DRB is established, or not. + * + * The class also maps between RATs since each LCID can exist on either EUTRA or NR RATs, or both. + * + * Since the access of this class is happening from two different threads (GW+RRC/Stack) + * it's public interface is protected. + * + */ +class bearer_manager +{ +public: + bearer_manager(); + ~bearer_manager(); + + // RRC interface + /// Registers EPS bearer with PDCP RAT type and LCID + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid); + + /// EPS bearer is removed from map when the associated DRB is deleted (e.g. after connection release) + void remove_eps_bearer(uint8_t eps_bearer_id); + + // GW interface + bool has_active_radio_bearer(uint32_t eps_bearer_id); + + // Stack interface to retrieve active RB + struct radio_bearer_t { + srsran::srsran_rat_t rat; + uint32_t lcid; + }; + radio_bearer_t& get_radio_bearer(uint32_t eps_bearer_id); + +private: + pthread_rwlock_t rwlock = {}; /// RW lock to protect access from RRC/GW threads + srslog::basic_logger& logger; + std::map eps_rb_map; + radio_bearer_t invalid_rb = {srsran::srsran_rat_t::nulltype, 0}; +}; + +} // namespace srsue + +#endif // SRSUE_BEARER_MANAGER_H \ No newline at end of file diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index abe9910c3..0f6a3fef4 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -193,8 +193,6 @@ private: srsran::s_tmsi_t ue_identity; bool ue_identity_configured = false; - bool drb_up = false; - // PHY controller state machine std::unique_ptr phy_ctrl; @@ -382,6 +380,7 @@ private: void release_drb(uint32_t drb_id); uint32_t get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id); uint32_t get_drb_id_for_eps_bearer(const uint32_t& eps_bearer_id); + uint32_t get_eps_bearer_id_for_drb_id(const uint32_t& drb_id); void add_mrb(uint32_t lcid, uint32_t port); // Helpers for setting default values diff --git a/srsue/hdr/stack/rrc/rrc_nr.h b/srsue/hdr/stack/rrc/rrc_nr.h index 5e4f3e6ff..642bdbf4f 100644 --- a/srsue/hdr/stack/rrc/rrc_nr.h +++ b/srsue/hdr/stack/rrc/rrc_nr.h @@ -20,6 +20,7 @@ #include "srsran/common/common_nr.h" #include "srsran/common/stack_procedure.h" #include "srsran/common/task_scheduler.h" +#include "srsran/interfaces/ue_interfaces.h" #include "srsran/interfaces/ue_nr_interfaces.h" #include "srsran/interfaces/ue_rrc_interfaces.h" #include "srsue/hdr/stack/upper/gw.h" @@ -29,7 +30,6 @@ namespace srsue { class usim_interface_rrc_nr; class pdcp_interface_rrc; class rlc_interface_rrc; -class stack_interface_rrc; // Expert arguments to create GW without proper RRC struct core_less_args_t { diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index 493962ce6..2c81c017b 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -31,6 +31,7 @@ #include "upper/nas.h" #include "upper/usim.h" +#include "bearer_manager.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/multiqueue.h" #include "srsran/common/string_helpers.h" @@ -159,12 +160,13 @@ public: } // Interface for GW - void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) final; - - bool is_lcid_enabled(uint32_t lcid) final { return pdcp.is_lcid_enabled(lcid); } + void write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) final; + bool has_active_radio_bearer(uint32_t eps_bearer_id) final; // Interface for RRC tti_point get_current_tti() final { return current_tti; } + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) final; + void remove_eps_bearer(uint8_t eps_bearer_id) final; srsran::ext_task_sched_handle get_task_sched() { return {&task_sched}; } @@ -228,6 +230,8 @@ private: srsue::nas nas; std::unique_ptr usim; + bearer_manager bearers; // helper to manage mapping between EPS and radio bearers + // Metrics helper uint32_t ul_dropped_sdus = 0; }; diff --git a/srsue/hdr/stack/ue_stack_nr.h b/srsue/hdr/stack/ue_stack_nr.h index 661cfc373..dbb4cf0cb 100644 --- a/srsue/hdr/stack/ue_stack_nr.h +++ b/srsue/hdr/stack/ue_stack_nr.h @@ -102,11 +102,13 @@ public: } // Interface for GW - void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) final; - bool is_lcid_enabled(uint32_t lcid) final { return pdcp->is_lcid_enabled(lcid); } + void write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) final; + bool has_active_radio_bearer(uint32_t eps_bearer_id) final { return true; /* TODO: add EPS to LCID mapping */ } // Interface for RRC srsran::tti_point get_current_tti() { return srsran::tti_point{0}; }; + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) final{}; + void remove_eps_bearer(uint8_t eps_bearer_id) final{}; private: void run_thread() final; diff --git a/srsue/hdr/stack/upper/gw.h b/srsue/hdr/stack/upper/gw.h index 3011e84c4..f4bf13ab2 100644 --- a/srsue/hdr/stack/upper/gw.h +++ b/srsue/hdr/stack/upper/gw.h @@ -21,6 +21,7 @@ #include "srsran/interfaces/ue_gw_interfaces.h" #include "srsran/srslog/srslog.h" #include "tft_packet_filter.h" +#include #include #include @@ -53,19 +54,17 @@ public: // NAS interface int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_addr, char* err_str); + int deactivate_eps_bearer(const uint32_t eps_bearer_id); int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft); void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms); // RRC interface void add_mch_port(uint32_t lcid, uint32_t port); - int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid); bool is_running(); private: @@ -75,19 +74,19 @@ private: gw_args_t args = {}; - bool running = false; + std::atomic running = {false}; bool run_enable = false; int32_t netns_fd = 0; int32_t tun_fd = 0; struct ifreq ifr = {}; int32_t sock = 0; bool if_up = false; - uint32_t default_lcid = 0; + + static const int NOT_ASSIGNED = -1; + int32_t default_eps_bearer_id = NOT_ASSIGNED; srslog::basic_logger& logger; - std::map eps_lcid; // Mapping between eps bearer ID and LCID - uint32_t current_ip_addr = 0; uint8_t current_if_id[8]; diff --git a/srsue/hdr/stack/upper/nas.h b/srsue/hdr/stack/upper/nas.h index e2d33fe33..eaac627e6 100644 --- a/srsue/hdr/stack/upper/nas.h +++ b/srsue/hdr/stack/upper/nas.h @@ -231,6 +231,9 @@ private: void airplane_mode_sim_switch_off(); void airplane_mode_sim_switch_on(); + // Misc helpers + void clear_eps_bearer(); + // FSM Helpers void enter_state(emm_state_t state_); void enter_emm_null(); diff --git a/srsue/hdr/stack/upper/tft_packet_filter.h b/srsue/hdr/stack/upper/tft_packet_filter.h index b7c806096..1f03f5434 100644 --- a/srsue/hdr/stack/upper/tft_packet_filter.h +++ b/srsue/hdr/stack/upper/tft_packet_filter.h @@ -59,14 +59,12 @@ class tft_packet_filter_t { public: tft_packet_filter_t(uint8_t eps_bearer_id_, - uint8_t lcid_, const LIBLTE_MME_PACKET_FILTER_STRUCT& tft_, srslog::basic_logger& logger); bool match(const srsran::unique_byte_buffer_t& pdu); bool filter_contains(uint16_t filtertype); uint8_t eps_bearer_id{}; - uint8_t lcid = {}; uint8_t id = {}; uint8_t eval_precedence = {}; uint32_t active_filters = {}; @@ -108,15 +106,12 @@ public: explicit tft_pdu_matcher(srslog::basic_logger& logger) : logger(logger) {} ~tft_pdu_matcher(){}; - void set_default_lcid(const uint8_t lcid); - uint8_t check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu); + int check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu, uint8_t& eps_bearer_id); int apply_traffic_flow_template(const uint8_t& erab_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft); private: srslog::basic_logger& logger; - uint8_t default_lcid = 0; std::mutex tft_mutex; typedef std::map tft_filter_map_t; tft_filter_map_t tft_filter_map; diff --git a/srsue/src/stack/CMakeLists.txt b/srsue/src/stack/CMakeLists.txt index c2834833e..1d2e9e1aa 100644 --- a/srsue/src/stack/CMakeLists.txt +++ b/srsue/src/stack/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(mac) add_subdirectory(rrc) add_subdirectory(upper) -set(SOURCES ue_stack_lte.cc) +set(SOURCES ue_stack_lte.cc bearer_manager.cc) add_library(srsue_stack STATIC ${SOURCES}) add_subdirectory(mac_nr) diff --git a/srsue/src/stack/bearer_manager.cc b/srsue/src/stack/bearer_manager.cc new file mode 100644 index 000000000..9b2d4c87e --- /dev/null +++ b/srsue/src/stack/bearer_manager.cc @@ -0,0 +1,69 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsue/hdr/stack/bearer_manager.h" + +namespace srsue { + +bearer_manager::bearer_manager() : logger(srslog::fetch_basic_logger("STCK", false)) +{ + pthread_rwlock_init(&rwlock, nullptr); +} + +bearer_manager::~bearer_manager() +{ + pthread_rwlock_destroy(&rwlock); +} + +void bearer_manager::add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) +{ + srsran::rwlock_write_guard rw_lock(rwlock); + auto it = eps_rb_map.find(eps_bearer_id); + if (it != eps_rb_map.end()) { + logger.error("EPS bearer ID %d already registered", eps_bearer_id); + return; + } + eps_rb_map.emplace(eps_bearer_id, radio_bearer_t{rat, lcid}); + logger.info("Registered EPS bearer ID %d for lcid=%d over %s-PDCP", eps_bearer_id, lcid, to_string(rat).c_str()); +} + +/// EPS bearer is removed from map when the associated DRB is deleted (e.g. after connection release) +void bearer_manager::remove_eps_bearer(uint8_t eps_bearer_id) +{ + srsran::rwlock_write_guard rw_lock(rwlock); + auto it = eps_rb_map.find(eps_bearer_id); + if (it == eps_rb_map.end()) { + logger.error("Can't remove EPS bearer ID %d", eps_bearer_id); + return; + } + eps_rb_map.erase(it); + logger.info("Removed mapping for EPS bearer ID %d", eps_bearer_id); +} + +// GW interface +bool bearer_manager::has_active_radio_bearer(uint32_t eps_bearer_id) +{ + srsran::rwlock_read_guard rw_lock(rwlock); + return eps_rb_map.find(eps_bearer_id) != eps_rb_map.end(); +} + +// Stack interface +bearer_manager::radio_bearer_t& bearer_manager::get_radio_bearer(uint32_t eps_bearer_id) +{ + srsran::rwlock_read_guard rw_lock(rwlock); + if (eps_rb_map.find(eps_bearer_id) != eps_rb_map.end()) { + return eps_rb_map.at(eps_bearer_id); + } + return invalid_rb; +} + +} // namespace srsue \ No newline at end of file diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index d738ef8f1..b97956247 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -53,7 +53,6 @@ rrc::rrc(stack_interface_rrc* stack_, srsran::task_sched_handle task_sched_) : task_sched(task_sched_), state(RRC_STATE_IDLE), last_state(RRC_STATE_CONNECTED), - drb_up(false), logger(srslog::fetch_basic_logger("RRC")), measurements(new rrc_meas()), cell_searcher(this), @@ -191,11 +190,6 @@ bool rrc::is_connected() return (RRC_STATE_CONNECTED == state); } -bool rrc::have_drb() -{ - return drb_up; -} - /* * * RRC State Machine @@ -1113,7 +1107,6 @@ void rrc::leave_connected() srsran::console("RRC IDLE\n"); logger.info("Leaving RRC_CONNECTED state"); state = RRC_STATE_IDLE; - drb_up = false; security_is_activated = false; // 1> reset MAC; @@ -2669,19 +2662,24 @@ void rrc::add_drb(const drb_to_add_mod_s& drb_cnfg) } mac->setup_lcid(lcid, log_chan_group, priority, prioritized_bit_rate, bucket_size_duration); - drbs[drb_cnfg.drb_id] = drb_cnfg; - drb_up = true; - logger.info("Added DRB Id %d (LCID=%d)", drb_cnfg.drb_id, lcid); - // Update LCID if gw is running - if (gw->is_running()) { - gw->update_lcid(drb_cnfg.eps_bearer_id, lcid); + uint8_t eps_bearer_id = 5; // default? + if (drb_cnfg.eps_bearer_id_present) { + eps_bearer_id = drb_cnfg.eps_bearer_id; } + + // register EPS bearer over LTE PDCP + stack->add_eps_bearer(eps_bearer_id, srsran::srsran_rat_t::lte, lcid); + + drbs[drb_cnfg.drb_id] = drb_cnfg; + logger.info("Added DRB Id %d (LCID=%d)", drb_cnfg.drb_id, lcid); } void rrc::release_drb(uint32_t drb_id) { if (drbs.find(drb_id) != drbs.end()) { logger.info("Releasing DRB Id %d", drb_id); + // remove EPS bearer associated with this DRB from Stack (GW will trigger service request if needed) + stack->remove_eps_bearer(get_eps_bearer_id_for_drb_id(drb_id)); drbs.erase(drb_id); } else { logger.error("Couldn't release DRB Id %d. Doesn't exist.", drb_id); @@ -2704,6 +2702,17 @@ uint32_t rrc::get_lcid_for_eps_bearer(const uint32_t& eps_bearer_id) return lcid; } +uint32_t rrc::get_eps_bearer_id_for_drb_id(const uint32_t& drb_id) +{ + // check if this bearer id exists and return it's LCID + for (auto& drb : drbs) { + if (drb.first == drb_id) { + return drb.second.eps_bearer_id; + } + } + return 0; +} + uint32_t rrc::get_drb_id_for_eps_bearer(const uint32_t& eps_bearer_id) { // check if this bearer id exists and return it's LCID diff --git a/srsue/src/stack/rrc/rrc_nr.cc b/srsue/src/stack/rrc/rrc_nr.cc index 18ee3375a..079a97e39 100644 --- a/srsue/src/stack/rrc/rrc_nr.cc +++ b/srsue/src/stack/rrc/rrc_nr.cc @@ -1362,7 +1362,10 @@ bool rrc_nr::apply_drb_add_mod(const drb_to_add_mod_s& drb_cfg) srsran::pdcp_config_t pdcp_cfg = make_drb_pdcp_config_t(drb_cfg.drb_id, true, drb_cfg.pdcp_cfg); pdcp->add_bearer(lcid, pdcp_cfg); - gw->update_lcid(eps_bearer_id, lcid); + + // register EPS bearer over NR PDCP + stack->add_eps_bearer(eps_bearer_id, srsran::srsran_rat_t::nr, lcid); + return true; } diff --git a/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc b/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc index a05d2813a..185386a01 100644 --- a/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc +++ b/srsue/src/stack/rrc/test/ue_rrc_nr_test.cc @@ -66,7 +66,7 @@ class dummy_pdcp : public pdcp_interface_rrc void reestablish(uint32_t lcid){}; void reset(){}; void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu, int sn = -1){}; - void add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg){}; + int add_bearer(uint32_t lcid, srsran::pdcp_config_t cnfg) { return SRSRAN_SUCCESS; }; void del_bearer(uint32_t lcid){}; void change_lcid(uint32_t old_lcid, uint32_t new_lcid){}; void config_security(uint32_t lcid, const srsran::as_security_config_t& sec_cfg){}; @@ -81,7 +81,6 @@ class dummy_pdcp : public pdcp_interface_rrc class dummy_gw : public gw_interface_rrc { void add_mch_port(uint32_t lcid, uint32_t port){}; - int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) { return SRSRAN_SUCCESS; }; bool is_running() { return true; }; }; @@ -102,6 +101,8 @@ class dummy_sim : public usim_interface_rrc_nr class dummy_stack : public stack_interface_rrc { srsran::tti_point get_current_tti() { return srsran::tti_point(); }; + void add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid){}; + void remove_eps_bearer(uint8_t eps_bearer_id){}; }; int rrc_nr_cap_request_test() diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 0898c0c85..40f0eb0a9 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -214,10 +214,11 @@ int ue_stack_lte::init(const stack_args_t& args_) nas.init(usim.get(), &rrc, gw, args.nas); mac_nr_args_t mac_nr_args = {}; - mac_nr.init(mac_nr_args, phy_nr, &rlc, &rrc_nr); + mac_nr.init(mac_nr_args, phy_nr, &rlc_nr, &rrc_nr); rlc_nr.init(&pdcp_nr, &rrc_nr, task_sched.get_timer_handler(), 0 /* RB_ID_SRB0 */); pdcp_nr.init(&rlc_nr, &rrc_nr, gw); - rrc_nr.init(phy_nr, &mac_nr, &rlc, &pdcp, gw, &rrc, usim.get(), task_sched.get_timer_handler(), nullptr, args.rrc_nr); + rrc_nr.init( + phy_nr, &mac_nr, &rlc_nr, &pdcp_nr, gw, &rrc, usim.get(), task_sched.get_timer_handler(), this, args.rrc_nr); rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &rrc_nr, args.rrc); running = true; @@ -338,26 +339,58 @@ void ue_stack_lte::run_thread() * Stack Interfaces **********************************************************************************************************************/ +/******************** + * RRC Interface + *******************/ + +void ue_stack_lte::add_eps_bearer(uint8_t eps_bearer_id, srsran::srsran_rat_t rat, uint32_t lcid) +{ + bearers.add_eps_bearer(eps_bearer_id, rat, lcid); +} + +void ue_stack_lte::remove_eps_bearer(uint8_t eps_bearer_id) +{ + bearers.remove_eps_bearer(eps_bearer_id); +} + /******************** * GW Interface *******************/ /** - * Push GW SDU to stack - * @param lcid + * GW calls write_sdu() to push SDU for EPS bearer to stack. + * If the EPS bearer ID is valid it will deliver the PDU to the + * registered PDCP entity. + * + * @param eps_bearer_id * @param sdu - * @param blocking */ -void ue_stack_lte::write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) +void ue_stack_lte::write_sdu(uint32_t eps_bearer_id, srsran::unique_byte_buffer_t sdu) { - auto task = [this, lcid](srsran::unique_byte_buffer_t& sdu) { pdcp.write_sdu(lcid, std::move(sdu)); }; - bool ret = gw_queue_id.try_push(std::bind(task, std::move(sdu))).has_value(); + auto bearer = bearers.get_radio_bearer(eps_bearer_id); + auto task = [this, eps_bearer_id, bearer](srsran::unique_byte_buffer_t& sdu) { + // route SDU to PDCP entity + if (bearer.rat == srsran_rat_t::lte) { + pdcp.write_sdu(bearer.lcid, std::move(sdu)); + } else if (bearer.rat == srsran_rat_t::nr) { + pdcp_nr.write_sdu(bearer.lcid, std::move(sdu)); + } else { + stack_logger.warning("Can't deliver SDU for EPS bearer %d. Dropping it.", eps_bearer_id); + } + }; + + bool ret = gw_queue_id.try_push(std::bind(task, std::move(sdu))).has_value(); if (not ret) { - pdcp_logger.info("GW SDU with lcid=%d was discarded.", lcid); + pdcp_logger.info("GW SDU with lcid=%d was discarded.", bearer.lcid); ul_dropped_sdus++; } } +bool ue_stack_lte::has_active_radio_bearer(uint32_t eps_bearer_id) +{ + return bearers.has_active_radio_bearer(eps_bearer_id); +} + /** * Check whether nas is attached * @return bool wether NAS is in EMM_REGISTERED diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index 33ed31c5f..bd52f665b 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -111,7 +111,7 @@ bool ue_stack_nr::switch_on() { // statically setup TUN (will be done through RRC later) char* err_str = nullptr; - if (gw->setup_if_addr(5, 4, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.1.3")), nullptr, err_str)) { + if (gw->setup_if_addr(5, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.1.3")), nullptr, err_str)) { printf("Error configuring TUN interface\n"); } return true; diff --git a/srsue/src/stack/upper/gw.cc b/srsue/src/stack/upper/gw.cc index cac140b87..e92433dbe 100644 --- a/srsue/src/stack/upper/gw.cc +++ b/srsue/src/stack/upper/gw.cc @@ -166,7 +166,6 @@ void gw::write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) NAS interface *******************************************************************************/ int gw::setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_addr, @@ -186,46 +185,34 @@ int gw::setup_if_addr(uint32_t eps_bearer_id, } } - eps_lcid[eps_bearer_id] = lcid; - default_lcid = lcid; - tft_matcher.set_default_lcid(lcid); + default_eps_bearer_id = static_cast(eps_bearer_id); // Setup a thread to receive packets from the TUN device start(GW_THREAD_PRIO); return SRSRAN_SUCCESS; } +int gw::deactivate_eps_bearer(const uint32_t eps_bearer_id) +{ + // only deactivation of default bearer + if (eps_bearer_id == static_cast(default_eps_bearer_id)) { + logger.debug("Deactivating EPS bearer %d", eps_bearer_id); + default_eps_bearer_id = NOT_ASSIGNED; + return SRSRAN_SUCCESS; + } + logger.error("Couldn't deactivate EPS bearer %d", eps_bearer_id); + return SRSRAN_ERROR; +} bool gw::is_running() { return running; } -int gw::update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) -{ - auto it = eps_lcid.find(eps_bearer_id); - if (it != eps_lcid.end()) { - uint32_t old_lcid = eps_lcid[eps_bearer_id]; - logger.debug("Found EPS bearer %d. Update old lcid %d to new lcid %d", eps_bearer_id, old_lcid, new_lcid); - eps_lcid[eps_bearer_id] = new_lcid; - if (old_lcid == default_lcid) { - logger.debug("Defaulting new lcid %d", new_lcid); - default_lcid = new_lcid; - tft_matcher.set_default_lcid(new_lcid); - } - // TODO: update need filters if not the default lcid - } else { - logger.error("Did not found EPS bearer %d for updating LCID.", eps_bearer_id); - return SRSRAN_ERROR; - } - return SRSRAN_SUCCESS; -} - int gw::apply_traffic_flow_template(const uint8_t& erab_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { - return tft_matcher.apply_traffic_flow_template(erab_id, lcid, tft); + return tft_matcher.apply_traffic_flow_template(erab_id, tft); } void gw::set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms) @@ -299,8 +286,8 @@ void gw::run_thread() if (pkt_len == pdu->N_bytes) { logger.info(pdu->msg, pdu->N_bytes, "TX PDU"); - // Make sure UE is attached - while (run_enable && !stack->is_registered() && register_wait < REGISTER_WAIT_TOUT) { + // Make sure UE is attached and has default EPS bearer activated + while (run_enable && default_eps_bearer_id == NOT_ASSIGNED && register_wait < REGISTER_WAIT_TOUT) { if (!register_wait) { logger.info("UE is not attached, waiting for NAS attach (%d/%d)", register_wait, REGISTER_WAIT_TOUT); } @@ -310,12 +297,18 @@ void gw::run_thread() register_wait = 0; // If we are still not attached by this stage, drop packet - if (run_enable && !stack->is_registered()) { + if (run_enable && default_eps_bearer_id == NOT_ASSIGNED) { continue; } + // Beyond this point we should have a activated default EPS bearer + srsran_assert(default_eps_bearer_id != NOT_ASSIGNED, "Default EPS bearer not activated"); + + uint8_t eps_bearer_id = default_eps_bearer_id; + tft_matcher.check_tft_filter_match(pdu, eps_bearer_id); + // Wait for service request if necessary - while (run_enable && !stack->is_lcid_enabled(default_lcid) && service_wait < SERVICE_WAIT_TOUT) { + while (run_enable && !stack->has_active_radio_bearer(eps_bearer_id) && service_wait < SERVICE_WAIT_TOUT) { if (!service_wait) { logger.info( "UE does not have service, waiting for NAS service request (%d/%d)", service_wait, SERVICE_WAIT_TOUT); @@ -331,21 +324,18 @@ void gw::run_thread() break; } - uint8_t lcid = tft_matcher.check_tft_filter_match(pdu); // Send PDU directly to PDCP - if (stack->is_lcid_enabled(lcid)) { - pdu->set_timestamp(); - ul_tput_bytes += pdu->N_bytes; - stack->write_sdu(lcid, std::move(pdu)); - do { - pdu = srsran::make_byte_buffer(); - if (!pdu) { - logger.error("Fatal Error: Couldn't allocate PDU in run_thread()."); - usleep(100000); - } - } while (!pdu); - idx = 0; - } + pdu->set_timestamp(); + ul_tput_bytes += pdu->N_bytes; + stack->write_sdu(eps_bearer_id, std::move(pdu)); + do { + pdu = srsran::make_byte_buffer(); + if (!pdu) { + logger.error("Fatal Error: Couldn't allocate PDU in run_thread()."); + usleep(100000); + } + } while (!pdu); + idx = 0; } else { idx += N_bytes; logger.debug("Entire packet not read from socket. Total Length %d, N_Bytes %d.", ip_pkt->tot_len, pdu->N_bytes); diff --git a/srsue/src/stack/upper/nas.cc b/srsue/src/stack/upper/nas.cc index 3633e70e6..adcbea366 100644 --- a/srsue/src/stack/upper/nas.cc +++ b/srsue/src/stack/upper/nas.cc @@ -161,32 +161,38 @@ void nas::run_tti() } } -/******************************************************************************* - * FSM Helperse - ******************************************************************************/ -void nas::enter_emm_null() +// Helper method to inform GW about remove default EPS bearer +void nas::clear_eps_bearer() { // Deactivate EPS bearer according to Sec. 5.5.2.2.2 logger.debug("Clearing EPS bearer context"); + for (const auto& bearer : eps_bearer) { + if (bearer.second.type == DEFAULT_EPS_BEARER) { + gw->deactivate_eps_bearer(bearer.second.eps_bearer_id); + } + } eps_bearer.clear(); +} + +/******************************************************************************* + * FSM Helpers + ******************************************************************************/ +void nas::enter_emm_null() +{ + clear_eps_bearer(); state.set_null(); } void nas::enter_emm_deregistered_initiated() { - // Deactivate EPS bearer according to Sec. 5.5.2.2.2 - logger.debug("Clearing EPS bearer context"); - eps_bearer.clear(); + clear_eps_bearer(); state.set_deregistered_initiated(); } void nas::enter_emm_deregistered(emm_state_t::deregistered_substate_t substate) { // TODO Start cell selection. - - // Deactivate EPS bearer according to Sec. 5.5.2.2.2 - logger.debug("Clearing EPS bearer context"); - eps_bearer.clear(); + clear_eps_bearer(); state.set_deregistered(substate); } @@ -1010,6 +1016,14 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); + // make sure we don't already have a default EPS bearer activated + for (const auto& bearer : eps_bearer) { + if (bearer.second.type == DEFAULT_EPS_BEARER) { + logger.error("Only one default EPS bearer supported."); + return; + } + } + if ((cfg.apn_protocol == "ipv4" && LIBLTE_MME_PDN_TYPE_IPV6 == act_def_eps_bearer_context_req.pdn_addr.pdn_type) || (cfg.apn_protocol == "ipv6" && LIBLTE_MME_PDN_TYPE_IPV4 == act_def_eps_bearer_context_req.pdn_addr.pdn_type)) { logger.error("Failed to attach -- Mismatch between PDN protocol and PDN type in attach accept."); @@ -1045,7 +1059,6 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) // Setup GW char* err_str = nullptr; if (gw->setup_if_addr(act_def_eps_bearer_context_req.eps_bearer_id, - rrc->get_lcid_for_eps_bearer(act_def_eps_bearer_context_req.eps_bearer_id), LIBLTE_MME_PDN_TYPE_IPV4, ip_addr, nullptr, @@ -1078,7 +1091,6 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) // Setup GW char* err_str = nullptr; if (gw->setup_if_addr(act_def_eps_bearer_context_req.eps_bearer_id, - rrc->get_lcid_for_eps_bearer(act_def_eps_bearer_context_req.eps_bearer_id), LIBLTE_MME_PDN_TYPE_IPV6, 0, ipv6_if_id, @@ -1129,7 +1141,6 @@ void nas::parse_attach_accept(uint32_t lcid, unique_byte_buffer_t pdu) char* err_str = nullptr; if (gw->setup_if_addr(act_def_eps_bearer_context_req.eps_bearer_id, - rrc->get_lcid_for_eps_bearer(act_def_eps_bearer_context_req.eps_bearer_id), LIBLTE_MME_PDN_TYPE_IPV4V6, ip_addr, ipv6_if_id, @@ -1564,7 +1575,7 @@ void nas::parse_activate_dedicated_eps_bearer_context_request(uint32_t lcid, uni } // apply packet filters to GW - gw->apply_traffic_flow_template(request.eps_bearer_id, rrc->get_lcid_for_eps_bearer(request.eps_bearer_id), tft); + gw->apply_traffic_flow_template(request.eps_bearer_id, tft); send_activate_dedicated_eps_bearer_context_accept(request.proc_transaction_id, request.eps_bearer_id); } @@ -1593,6 +1604,9 @@ void nas::parse_deactivate_eps_bearer_context_request(unique_byte_buffer_t pdu) eps_bearer_map_t::iterator it = eps_bearer.find(request.eps_bearer_id); eps_bearer.erase(it); + // inform GW about removed EPS bearer + gw->deactivate_eps_bearer(request.eps_bearer_id); + logger.info("Removed EPS bearer context (eps_bearer_id=%d)", request.eps_bearer_id); send_deactivate_eps_bearer_context_accept(request.proc_transaction_id, request.eps_bearer_id); @@ -1951,7 +1965,7 @@ void nas::send_detach_request(bool switch_off) } if (switch_off) { - enter_emm_deregistered_initiated(); + enter_emm_deregistered(emm_state_t::deregistered_substate_t::null); } else { // we are expecting a response from the core state.set_deregistered_initiated(); diff --git a/srsue/src/stack/upper/test/gw_test.cc b/srsue/src/stack/upper/test/gw_test.cc index 3fa169784..9aa26226a 100644 --- a/srsue/src/stack/upper/test/gw_test.cc +++ b/srsue/src/stack/upper/test/gw_test.cc @@ -23,10 +23,10 @@ public: bool is_registered() { return true; } bool start_service_request() { return true; }; void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { return; } - bool is_lcid_enabled(uint32_t lcid) { return true; } + bool has_active_radio_bearer(uint32_t eps_bearer_id) { return true; } }; -int gw_change_lcid_test() +int gw_test() { srsue::gw_args_t gw_args; gw_args.tun_dev_name = "tun1"; @@ -43,8 +43,7 @@ int gw_change_lcid_test() char* err_str = nullptr; int rtn = 0; - rtn = gw.setup_if_addr( - eps_bearer_id, old_lcid, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.56.32")), nullptr, err_str); + rtn = gw.setup_if_addr(eps_bearer_id, LIBLTE_MME_PDN_TYPE_IPV4, htonl(inet_addr("192.168.56.32")), nullptr, err_str); if (rtn != SRSRAN_SUCCESS) { srslog::fetch_basic_logger("TEST", false) @@ -53,8 +52,8 @@ int gw_change_lcid_test() return SRSRAN_SUCCESS; } - TESTASSERT(gw.update_lcid(eps_bearer_id, new_lcid) == SRSRAN_SUCCESS); - TESTASSERT(gw.update_lcid(non_existing_eps_bearer_id, new_lcid) == SRSRAN_ERROR); + TESTASSERT(gw.deactivate_eps_bearer(eps_bearer_id) == SRSRAN_SUCCESS); + TESTASSERT(gw.deactivate_eps_bearer(non_existing_eps_bearer_id) == SRSRAN_ERROR); gw.stop(); return SRSRAN_SUCCESS; } @@ -63,7 +62,7 @@ int main(int argc, char** argv) { srslog::init(); - TESTASSERT(gw_change_lcid_test() == SRSRAN_SUCCESS); + TESTASSERT(gw_test() == SRSRAN_SUCCESS); return SRSRAN_SUCCESS; } diff --git a/srsue/src/stack/upper/test/nas_test.cc b/srsue/src/stack/upper/test/nas_test.cc index 0769167af..11f52a7a6 100644 --- a/srsue/src/stack/upper/test/nas_test.cc +++ b/srsue/src/stack/upper/test/nas_test.cc @@ -63,18 +63,19 @@ using namespace srsran; namespace srsran { // fake classes -class pdcp_dummy : public rrc_interface_pdcp, public pdcp_interface_gw +class pdcp_dummy : public rrc_interface_pdcp, public pdcp_interface_stack { public: - void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu) {} - void write_pdu_bcch_bch(unique_byte_buffer_t pdu) {} - void write_pdu_bcch_dlsch(unique_byte_buffer_t pdu) {} - void write_pdu_pcch(unique_byte_buffer_t pdu) {} - void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t sdu) {} - const char* get_rb_name(uint32_t lcid) { return "lcid"; } - void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) {} - bool is_lcid_enabled(uint32_t lcid) { return false; } - void notify_pdcp_integrity_error(uint32_t lcid) {} + void write_pdu(uint32_t lcid, unique_byte_buffer_t pdu) override {} + void write_pdu_bcch_bch(unique_byte_buffer_t pdu) override {} + void write_pdu_bcch_dlsch(unique_byte_buffer_t pdu) override {} + void write_pdu_pcch(unique_byte_buffer_t pdu) override {} + void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t sdu) override {} + const char* get_rb_name(uint32_t lcid) override { return "lcid"; } + void write_sdu(uint32_t lcid, unique_byte_buffer_t sdu, int sn = -1) override {} + bool is_eps_bearer_id_enabled(uint32_t eps_bearer_id) { return false; } + void notify_pdcp_integrity_error(uint32_t lcid) override {} + bool is_lcid_enabled(uint32_t lcid) override { return false; } }; class rrc_dummy : public rrc_interface_nas @@ -131,7 +132,7 @@ private: class test_stack_dummy : public srsue::stack_test_dummy, public stack_interface_gw, public thread { public: - test_stack_dummy(pdcp_interface_gw* pdcp_) : pdcp(pdcp_), thread("DUMMY STACK") {} + test_stack_dummy(pdcp_interface_stack* pdcp_) : pdcp(pdcp_), thread("DUMMY STACK") {} void init(srsue::nas* nas_) { nas = nas_; @@ -139,7 +140,7 @@ public: } bool switch_on() { return true; } void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) { pdcp->write_sdu(lcid, std::move(sdu)); } - bool is_lcid_enabled(uint32_t lcid) { return pdcp->is_lcid_enabled(lcid); } + bool has_active_radio_bearer(uint32_t eps_bearer_id) { return true; } bool is_registered() { return true; } @@ -162,7 +163,7 @@ public: running = false; wait_thread_finish(); } - pdcp_interface_gw* pdcp = nullptr; + pdcp_interface_stack* pdcp = nullptr; srsue::nas* nas = nullptr; std::atomic running = {false}; }; @@ -170,7 +171,6 @@ public: class gw_dummy : public gw_interface_nas, public gw_interface_pdcp { int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, @@ -178,8 +178,8 @@ class gw_dummy : public gw_interface_nas, public gw_interface_pdcp { return SRSRAN_SUCCESS; } + int deactivate_eps_bearer(const uint32_t eps_bearer_id) { return SRSRAN_SUCCESS; } int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { return SRSRAN_SUCCESS; diff --git a/srsue/src/stack/upper/test/tft_test.cc b/srsue/src/stack/upper/test/tft_test.cc index 9b1ae415a..1b8fd8f5d 100644 --- a/srsue/src/stack/upper/test/tft_test.cc +++ b/srsue/src/stack/upper/test/tft_test.cc @@ -99,7 +99,6 @@ uint8_t ipv6_unmatched_packet_lport[] = { 0x80, 0x61, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; #define EPS_BEARER_ID 6 -#define LCID 1 int tft_filter_test_ipv6_combined() { @@ -150,7 +149,7 @@ int tft_filter_test_ipv6_combined() packet_filter.filter_size = sizeof(ipv6_filter); memcpy(packet_filter.filter, ipv6_filter, sizeof(ipv6_filter)); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -199,7 +198,7 @@ int tft_filter_test_single_local_port() packet_filter.filter_size = 3; memcpy(packet_filter.filter, filter_message, 3); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -245,7 +244,7 @@ int tft_filter_test_single_remote_port() packet_filter.filter_size = 3; memcpy(packet_filter.filter, filter_message, 3); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -294,7 +293,7 @@ int tft_filter_test_ipv4_local_addr() packet_filter.filter_size = filter_size; memcpy(packet_filter.filter, filter_message, filter_size); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -342,7 +341,7 @@ int tft_filter_test_ipv4_remote_addr() packet_filter.filter_size = filter_size; memcpy(packet_filter.filter, filter_message, filter_size); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); @@ -391,7 +390,7 @@ int tft_filter_test_ipv4_tos() packet_filter.filter_size = filter_size; memcpy(packet_filter.filter, filter_message, filter_size); - srsue::tft_packet_filter_t filter(EPS_BEARER_ID, LCID, packet_filter, logger); + srsue::tft_packet_filter_t filter(EPS_BEARER_ID, packet_filter, logger); // Check filter TESTASSERT(filter.match(ip_msg1)); diff --git a/srsue/src/stack/upper/tft_packet_filter.cc b/srsue/src/stack/upper/tft_packet_filter.cc index a0de74636..b31f6bf8d 100644 --- a/srsue/src/stack/upper/tft_packet_filter.cc +++ b/srsue/src/stack/upper/tft_packet_filter.cc @@ -24,11 +24,9 @@ extern "C" { namespace srsue { tft_packet_filter_t::tft_packet_filter_t(uint8_t eps_bearer_id_, - uint8_t lcid_, const LIBLTE_MME_PACKET_FILTER_STRUCT& tft, srslog::basic_logger& logger) : eps_bearer_id(eps_bearer_id_), - lcid(lcid_), id(tft.id), eval_precedence(tft.eval_precedence), active_filters(0), @@ -380,23 +378,28 @@ bool tft_packet_filter_t::match_port(const srsran::unique_byte_buffer_t& pdu) return true; } -uint8_t tft_pdu_matcher::check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu) +/** + * Checks whether the provided PDU matches any configured TFT. + * If it finds a match, it updates the eps_bearer_id parameter. + * @param pdu Reference to the PDU to check. + * @param eps_bearer_id Reference to variable to store EPS bearer ID. + * @return SRSRAN_SUCCESS if a reference could be found, SRSRAN_ERROR otherwise. + */ +int tft_pdu_matcher::check_tft_filter_match(const srsran::unique_byte_buffer_t& pdu, uint8_t& eps_bearer_id) { std::lock_guard lock(tft_mutex); - uint8_t lcid = default_lcid; for (std::pair& filter_pair : tft_filter_map) { bool match = filter_pair.second.match(pdu); if (match) { - lcid = filter_pair.second.lcid; - logger.debug("Found filter match -- EPS bearer Id %d, LCID %d", filter_pair.second.eps_bearer_id, lcid); - break; + eps_bearer_id = filter_pair.second.eps_bearer_id; + logger.debug("Found filter match -- EPS bearer Id %d", filter_pair.second.eps_bearer_id); + return SRSRAN_SUCCESS; } } - return lcid; + return SRSRAN_ERROR; } int tft_pdu_matcher::apply_traffic_flow_template(const uint8_t& erab_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { std::lock_guard lock(tft_mutex); @@ -404,7 +407,7 @@ int tft_pdu_matcher::apply_traffic_flow_template(const uint8_t& case LIBLTE_MME_TFT_OPERATION_CODE_CREATE_NEW_TFT: for (int i = 0; i < tft->packet_filter_list_size; i++) { logger.info("New packet filter for TFT"); - tft_packet_filter_t filter(erab_id, lcid, tft->packet_filter_list[i], logger); + tft_packet_filter_t filter(erab_id, tft->packet_filter_list[i], logger); auto it = tft_filter_map.insert(std::make_pair(filter.eval_precedence, filter)); if (it.second == false) { logger.error("Error inserting TFT Packet Filter"); @@ -419,9 +422,4 @@ int tft_pdu_matcher::apply_traffic_flow_template(const uint8_t& return SRSRAN_SUCCESS; } -void tft_pdu_matcher::set_default_lcid(const uint8_t lcid) -{ - default_lcid = lcid; -} - } // namespace srsue diff --git a/srsue/src/test/ttcn3/hdr/ttcn3_ue.h b/srsue/src/test/ttcn3/hdr/ttcn3_ue.h index f72f04652..1af0418fe 100644 --- a/srsue/src/test/ttcn3/hdr/ttcn3_ue.h +++ b/srsue/src/test/ttcn3/hdr/ttcn3_ue.h @@ -53,16 +53,15 @@ public: void write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu); void write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu); int setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str); - int update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid); bool is_running(); + int deactivate_eps_bearer(const uint32_t eps_bearer_id); + int apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft); void set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms_ = 0); @@ -71,7 +70,7 @@ public: void send_queued_data(); - void loop_back_pdu_with_tft(uint32_t input_lcid, srsran::unique_byte_buffer_t pdu); + void loop_back_pdu_with_tft(srsran::unique_byte_buffer_t pdu); private: std::unique_ptr phy; @@ -82,9 +81,11 @@ private: test_loop_mode_state_t test_loop_mode = TEST_LOOP_INACTIVE; srsran::timer_handler::unique_timer pdu_delay_timer; - std::map > pdu_queue; // A PDU queue for each DRB + block_queue pdu_queue; // PDU for UL data tft_pdu_matcher tft_matcher; + int default_eps_bearer_id = -1; + all_args_t args = {}; }; diff --git a/srsue/src/test/ttcn3/src/ttcn3_dut.cc b/srsue/src/test/ttcn3/src/ttcn3_dut.cc index 29006774f..a39f8d64c 100644 --- a/srsue/src/test/ttcn3/src/ttcn3_dut.cc +++ b/srsue/src/test/ttcn3/src/ttcn3_dut.cc @@ -72,6 +72,8 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args_t all_args = {}; + all_args.stack.pkt_trace.enable = "mac,nas"; + all_args.stack.pkt_trace.mac_pcap.enable = args->mac_pcap.enable; all_args.stack.pkt_trace.mac_pcap.filename = args->mac_pcap.filename; @@ -83,6 +85,8 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args.log.all_hex_limit = args->log_hex_level; all_args.phy.log.phy_level = args->log_level; + + all_args.stack.log.stack_level = args->log_level; all_args.stack.log.mac_level = args->log_level; all_args.stack.log.rlc_level = args->log_level; all_args.stack.log.pdcp_level = args->log_level; @@ -91,6 +95,7 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[]) all_args.stack.log.gw_level = args->log_level; all_args.stack.log.usim_level = args->log_level; all_args.phy.log.phy_hex_limit = args->log_hex_level; + all_args.stack.log.stack_hex_limit = args->log_hex_level; all_args.stack.log.mac_hex_limit = args->log_hex_level; all_args.stack.log.rlc_hex_limit = args->log_hex_level; all_args.stack.log.pdcp_hex_limit = args->log_hex_level; diff --git a/srsue/src/test/ttcn3/src/ttcn3_ue.cc b/srsue/src/test/ttcn3/src/ttcn3_ue.cc index f6ebabd9b..6435a6cc8 100644 --- a/srsue/src/test/ttcn3/src/ttcn3_ue.cc +++ b/srsue/src/test/ttcn3/src/ttcn3_ue.cc @@ -153,6 +153,7 @@ void ttcn3_ue::add_mch_port(uint32_t lcid, uint32_t port) {} void ttcn3_ue::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) { logger.debug(pdu->msg, pdu->N_bytes, "Rx PDU (%d B) on lcid=%d", pdu->N_bytes, lcid); + switch (test_loop_mode) { case TEST_LOOP_INACTIVE: logger.warning("Test loop inactive. Dropping PDU."); @@ -163,13 +164,13 @@ void ttcn3_ue::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) case TEST_LOOP_MODE_B_ACTIVE: // Section 5.4.4 in TS 36.509 if (pdu_delay_timer.is_running()) { - pdu_queue[lcid].push(std::move(pdu)); + pdu_queue.push(std::move(pdu)); } else { if (pdu_delay_timer.is_set()) { - pdu_queue[lcid].push(std::move(pdu)); + pdu_queue.push(std::move(pdu)); pdu_delay_timer.run(); // timer is already set } else { - loop_back_pdu_with_tft(lcid, std::move(pdu)); + loop_back_pdu_with_tft(std::move(pdu)); } } break; @@ -180,12 +181,12 @@ void ttcn3_ue::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) } void ttcn3_ue::write_pdu_mch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) {} int ttcn3_ue::setup_if_addr(uint32_t eps_bearer_id, - uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str) { + default_eps_bearer_id = static_cast(eps_bearer_id); return 0; } @@ -194,16 +195,16 @@ bool ttcn3_ue::is_running() return true; } -int ttcn3_ue::update_lcid(uint32_t eps_bearer_id, uint32_t new_lcid) +int ttcn3_ue::deactivate_eps_bearer(const uint32_t eps_bearer_id) { + default_eps_bearer_id = -1; return SRSRAN_SUCCESS; } int ttcn3_ue::apply_traffic_flow_template(const uint8_t& eps_bearer_id, - const uint8_t& lcid, const LIBLTE_MME_TRAFFIC_FLOW_TEMPLATE_STRUCT* tft) { - return tft_matcher.apply_traffic_flow_template(eps_bearer_id, lcid, tft); + return tft_matcher.apply_traffic_flow_template(eps_bearer_id, tft); } void ttcn3_ue::set_test_loop_mode(const test_loop_mode_state_t mode, const uint32_t ip_pdu_delay_ms_) @@ -249,18 +250,27 @@ void ttcn3_ue::send_queued_data() return; } - for (auto& bearer_pdu_queue : pdu_queue) { - logger.info("Delivering %zd buffered PDUs for LCID=%d", bearer_pdu_queue.second.size(), bearer_pdu_queue.first); - while (not bearer_pdu_queue.second.empty()) { - srsran::unique_byte_buffer_t pdu; - bearer_pdu_queue.second.try_pop(&pdu); - loop_back_pdu_with_tft(bearer_pdu_queue.first, std::move(pdu)); - } + logger.info("Delivering %zd buffered UL PDUs", pdu_queue.size()); + while (not pdu_queue.empty()) { + srsran::unique_byte_buffer_t pdu; + pdu_queue.try_pop(&pdu); + loop_back_pdu_with_tft(std::move(pdu)); } } -void ttcn3_ue::loop_back_pdu_with_tft(uint32_t input_lcid, srsran::unique_byte_buffer_t pdu) +void ttcn3_ue::loop_back_pdu_with_tft(srsran::unique_byte_buffer_t pdu) { - logger.info(pdu->msg, pdu->N_bytes, "Rx PDU (%d B) on lcid=%d, looping back", pdu->N_bytes, input_lcid); - stack->write_sdu(input_lcid, std::move(pdu)); + if (default_eps_bearer_id == -1) { + logger.error("No default EPS bearer activated. Dropping PDU."); + } + + uint8_t target_eps_bearer_id = default_eps_bearer_id; + if (tft_matcher.check_tft_filter_match(pdu, target_eps_bearer_id) == SRSRAN_SUCCESS) { + logger.debug("Updated EPS bearer"); + } + + logger.info( + pdu->msg, pdu->N_bytes, "Rx PDU (%d B) looping back on eps_bearer_id=%d", pdu->N_bytes, target_eps_bearer_id); + + stack->write_sdu(target_eps_bearer_id, std::move(pdu)); }