From 255ddb1329b2a61748e83437bf4aa39f0379d912 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 14 Oct 2021 17:43:09 +0200 Subject: [PATCH] enb,gnb: add basic support for sgnb release procedure the procedure is currently started when the EUTRA UE object is deleted (after RRC release) in order to clean-up the ENDC resources on the gNB. --- .../srsran/interfaces/enb_x2_interfaces.h | 10 ++++++ srsenb/hdr/stack/enb_stack_lte.h | 1 + srsenb/hdr/stack/gnb_stack_nr.h | 1 + srsenb/hdr/stack/rrc/rrc.h | 1 + srsenb/hdr/stack/rrc/rrc_endc.h | 36 +++++++++++++++++-- srsenb/hdr/stack/rrc/rrc_nr.h | 1 + srsenb/hdr/x2_adapter.h | 16 +++++++++ srsenb/src/stack/rrc/rrc.cc | 34 +++++++++++++++--- srsenb/src/stack/rrc/rrc_endc.cc | 20 +++++++++++ srsenb/src/stack/rrc/rrc_nr.cc | 10 ++++++ 10 files changed, 123 insertions(+), 7 deletions(-) diff --git a/lib/include/srsran/interfaces/enb_x2_interfaces.h b/lib/include/srsran/interfaces/enb_x2_interfaces.h index 5d3b871dc..367fa7d9a 100644 --- a/lib/include/srsran/interfaces/enb_x2_interfaces.h +++ b/lib/include/srsran/interfaces/enb_x2_interfaces.h @@ -40,6 +40,9 @@ public: /// Provide information whether the requested configuration was applied successfully by the UE virtual int sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstring reconfig_response) = 0; + + /// Trigger release for specific UE + virtual int sgnb_release_request(uint16_t nr_rnti) = 0; }; /// X2AP inspired interface for response from NR RRC to EUTRA RRC @@ -82,6 +85,13 @@ public: */ virtual void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) = 0; + /** + * @brief Signal release of all UE resources on the NR cell + * + * @param eutra_rnti The RNTI that the EUTRA RRC used to request the SgNB addition + */ + virtual void sgnb_release_ack(uint16_t eutra_rnti) = 0; + /** * @brief Signal user activity (i.e. DL/UL traffic) for given RNTI * diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index cb5053f46..ef7544697 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -126,6 +126,7 @@ public: // Note: RRC processes activity asynchronously, so there is no need to use x2_task_queue rrc.set_activity_user(eutra_rnti); } + void sgnb_release_ack(uint16_t eutra_rnti) final { rrc.sgnb_release_ack(eutra_rnti); } // gtpu_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu); diff --git a/srsenb/hdr/stack/gnb_stack_nr.h b/srsenb/hdr/stack/gnb_stack_nr.h index 2161b8ca9..3ae39545f 100644 --- a/srsenb/hdr/stack/gnb_stack_nr.h +++ b/srsenb/hdr/stack/gnb_stack_nr.h @@ -89,6 +89,7 @@ public: { return rrc.sgnb_reconfiguration_complete(eutra_rnti, reconfig_response); }; + int sgnb_release_request(uint16_t nr_rnti) final { return rrc.sgnb_release_request(nr_rnti); }; // X2 data interface void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) final { diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 25ee18bb2..5a1c2adb3 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -131,6 +131,7 @@ public: void sgnb_addition_ack(uint16_t eutra_rnti, const sgnb_addition_ack_params_t params) override; void sgnb_addition_reject(uint16_t eutra_rnti) override; void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) override; + void sgnb_release_ack(uint16_t eutra_rnti) override; // rrc_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override; diff --git a/srsenb/hdr/stack/rrc/rrc_endc.h b/srsenb/hdr/stack/rrc/rrc_endc.h index 3f82acb10..9d41171ab 100644 --- a/srsenb/hdr/stack/rrc/rrc_endc.h +++ b/srsenb/hdr/stack/rrc/rrc_endc.h @@ -49,12 +49,30 @@ public: uint16_t nr_rnti; /// RNTI assigned to UE on NR carrier }; + /** + * @brief Called from EUTRA-RRC when EN-DC (for UE) shall be removed/released + * + */ + struct sgnb_rel_req_ev { + uint16_t nr_rnti; /// RNTI assigned to UE on NR carrier + }; + + /** + * @brief Event sent from NR-RRC to EUTRA when UE has been removed from SgNB + * + * sent in response to SgNB Release Request + */ + struct sgnb_rel_req_ack_ev {}; + rrc_endc(srsenb::rrc::ue* outer_ue, const rrc_endc_cfg_t& endc_cfg_); + ~rrc_endc(); bool fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg); void handle_eutra_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_caps); void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg); + void start_sgnb_release(); + bool is_endc_supported(); private: @@ -70,6 +88,7 @@ private: // vars bool endc_supported = false; rrc_endc_cfg_t endc_cfg = {}; + uint16_t nr_rnti = SRSRAN_INVALID_RNTI; // C-RNTI assigned to UE on NR side asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete; // fixed ENDC variables @@ -94,22 +113,30 @@ private: }; struct wait_add_complete_st {}; // user needs to complete RA procedure and send C-RNTI CE struct endc_activated_st {}; // user has enabled EN-DC successfully and is currently served + struct wait_sgnb_rel_req_resp_st {}; // release EN-DC // FSM guards // FSM transition handlers void handle_sgnb_add_req_ack(wait_sgnb_add_req_resp_st& s, const sgnb_add_req_ack_ev& ev); + void handle_sgnb_rel_req(endc_activated_st& s, const sgnb_rel_req_ev& ev); void handle_rrc_reest(wait_add_complete_st& s, const rrc_reest_rx_ev& ev); protected: // states - state_list + state_list states{this, endc_deactivated_st{}, wait_sgnb_add_req_resp_st{}, prepare_recfg_st{this}, wait_add_complete_st{}, - endc_activated_st{}}; + endc_activated_st{}, + wait_sgnb_rel_req_resp_st{}}; // transitions using fsm = rrc_endc; @@ -123,8 +150,11 @@ protected: row< wait_sgnb_add_req_resp_st, endc_deactivated_st, sgnb_add_req_reject_ev >, row< prepare_recfg_st, wait_add_complete_st, rrc_recfg_sent_ev >, row< wait_add_complete_st, endc_activated_st, sgnb_add_complete_ev >, - row< wait_add_complete_st, endc_deactivated_st, rrc_reest_rx_ev, &fsm::handle_rrc_reest > + row< wait_add_complete_st, endc_deactivated_st, rrc_reest_rx_ev, &fsm::handle_rrc_reest >, // +---------------------------+--------------------------+------------------------+------------------------------+-------------------------+ + row< endc_activated_st, wait_sgnb_rel_req_resp_st, sgnb_rel_req_ev, &fsm::handle_sgnb_rel_req >, + row< wait_sgnb_rel_req_resp_st, endc_deactivated_st, sgnb_rel_req_ack_ev > + >; // clang-format on }; diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 5341bbbb9..394a657f8 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -88,6 +88,7 @@ public: // Interface for EUTRA RRC int sgnb_addition_request(uint16_t rnti, const sgnb_addition_req_params_t& params); int sgnb_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response); + int sgnb_release_request(uint16_t nr_rnti); // Interfaces for NGAP int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key); diff --git a/srsenb/hdr/x2_adapter.h b/srsenb/hdr/x2_adapter.h index df5d0f8c8..30c619dee 100644 --- a/srsenb/hdr/x2_adapter.h +++ b/srsenb/hdr/x2_adapter.h @@ -80,6 +80,14 @@ public: eutra_stack->sgnb_addition_complete(eutra_rnti, nr_rnti); } + void sgnb_release_ack(uint16_t eutra_rnti) override + { + if (eutra_stack == nullptr) { + return; + } + eutra_stack->sgnb_release_ack(eutra_rnti); + } + void set_activity_user(uint16_t eutra_rnti) override { if (eutra_stack == nullptr) { @@ -88,6 +96,14 @@ public: eutra_stack->set_activity_user(eutra_rnti); } + int sgnb_release_request(uint16_t nr_rnti) override + { + if (nr_stack == nullptr) { + return SRSRAN_ERROR; + } + return nr_stack->sgnb_release_request(nr_rnti); + } + // pdcp_interface_gtpu void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) override { diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 9e478f8ca..f4fbd6245 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -570,22 +570,48 @@ void rrc::set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_st void rrc::sgnb_addition_ack(uint16_t eutra_rnti, sgnb_addition_ack_params_t params) { logger.info("Received SgNB addition acknowledgement for rnti=%d", eutra_rnti); - users.at(eutra_rnti)->endc_handler->trigger(ue::rrc_endc::sgnb_add_req_ack_ev{params}); + auto ue_it = users.find(eutra_rnti); + if (ue_it == users.end()) { + logger.warning("rnti=0x%x does not exist", eutra_rnti); + return; + } + ue_it->second->endc_handler->trigger(ue::rrc_endc::sgnb_add_req_ack_ev{params}); // trigger RRC Reconfiguration to send NR config to UE - users.at(eutra_rnti)->send_connection_reconf(); + ue_it->second->send_connection_reconf(); } void rrc::sgnb_addition_reject(uint16_t eutra_rnti) { logger.error("Received SgNB addition reject for rnti=%d", eutra_rnti); - users.at(eutra_rnti)->endc_handler->trigger(ue::rrc_endc::sgnb_add_req_reject_ev{}); + auto ue_it = users.find(eutra_rnti); + if (ue_it == users.end()) { + logger.warning("rnti=0x%x does not exist", eutra_rnti); + return; + } + ue_it->second->endc_handler->trigger(ue::rrc_endc::sgnb_add_req_reject_ev{}); } void rrc::sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_rnti) { logger.info("User rnti=0x%x successfully enabled EN-DC", eutra_rnti); - users.at(eutra_rnti)->endc_handler->trigger(ue::rrc_endc::sgnb_add_complete_ev{nr_rnti}); + auto ue_it = users.find(eutra_rnti); + if (ue_it == users.end()) { + logger.warning("rnti=0x%x does not exist", eutra_rnti); + return; + } + ue_it->second->endc_handler->trigger(ue::rrc_endc::sgnb_add_complete_ev{nr_rnti}); +} + +void rrc::sgnb_release_ack(uint16_t eutra_rnti) +{ + logger.info("Received SgNB release acknowledgement for rnti=%d", eutra_rnti); + auto ue_it = users.find(eutra_rnti); + if (ue_it == users.end()) { + logger.warning("rnti=0x%x does not exist", eutra_rnti); + return; + } + ue_it->second->endc_handler->trigger(ue::rrc_endc::sgnb_rel_req_ack_ev{}); } /******************************************************************************* diff --git a/srsenb/src/stack/rrc/rrc_endc.cc b/srsenb/src/stack/rrc/rrc_endc.cc index ae6a720d8..a0b16707a 100644 --- a/srsenb/src/stack/rrc/rrc_endc.cc +++ b/srsenb/src/stack/rrc/rrc_endc.cc @@ -42,6 +42,11 @@ rrc::ue::rrc_endc::rrc_endc(rrc::ue* outer_ue, const rrc_endc_cfg_t& endc_cfg_) } } +rrc::ue::rrc_endc::~rrc_endc() +{ + start_sgnb_release(); +} + //! Method to add NR fields to a RRC Connection Reconfiguration Message bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg) { @@ -285,6 +290,12 @@ void rrc::ue::rrc_endc::start_sgnb_addition() trigger(sgnb_add_req); } +void rrc::ue::rrc_endc::start_sgnb_release() +{ + sgnb_rel_req_ev sgnb_rel_req{nr_rnti}; + trigger(sgnb_rel_req); +} + rrc::ue::rrc_endc::prepare_recfg_st::prepare_recfg_st(rrc_endc* parent_) : logger(parent_->logger) {} void rrc::ue::rrc_endc::prepare_recfg_st::enter(rrc_endc* f, const sgnb_add_req_ack_ev& ev) @@ -313,6 +324,15 @@ void rrc::ue::rrc_endc::handle_sgnb_add_req_ack(wait_sgnb_add_req_resp_st& s, co // change GTPU tunnel RNTI to match NR RNTI rrc_enb->gtpu->mod_bearer_rnti(rrc_ue->rnti, ev.params.nr_rnti); + + // store RNTI for later + nr_rnti = ev.params.nr_rnti; +} + +void rrc::ue::rrc_endc::handle_sgnb_rel_req(endc_activated_st& s, const sgnb_rel_req_ev& ev) +{ + logger.info("Triggering SgNB release"); + rrc_enb->rrc_nr->sgnb_release_request(nr_rnti); } bool rrc::ue::rrc_endc::is_endc_supported() diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index d107e3afe..e496b01b2 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -511,6 +511,16 @@ int rrc_nr::sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstri return SRSRAN_SUCCESS; } +int rrc_nr::sgnb_release_request(uint16_t nr_rnti) +{ + task_sched.defer_task([this, nr_rnti]() { + // remove user + rem_user(nr_rnti); + rrc_eutra->sgnb_release_ack(nr_rnti); + }); + return SRSRAN_SUCCESS; +} + /******************************************************************************* UE class