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.
master
Andre Puschmann 3 years ago
parent 908c469f30
commit 255ddb1329

@ -40,6 +40,9 @@ public:
/// Provide information whether the requested configuration was applied successfully by the UE /// 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; 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 /// 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; 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 * @brief Signal user activity (i.e. DL/UL traffic) for given RNTI
* *

@ -126,6 +126,7 @@ public:
// Note: RRC processes activity asynchronously, so there is no need to use x2_task_queue // Note: RRC processes activity asynchronously, so there is no need to use x2_task_queue
rrc.set_activity_user(eutra_rnti); rrc.set_activity_user(eutra_rnti);
} }
void sgnb_release_ack(uint16_t eutra_rnti) final { rrc.sgnb_release_ack(eutra_rnti); }
// gtpu_interface_pdcp // gtpu_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu); void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu);

@ -89,6 +89,7 @@ public:
{ {
return rrc.sgnb_reconfiguration_complete(eutra_rnti, reconfig_response); 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 // X2 data interface
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) final void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) final
{ {

@ -131,6 +131,7 @@ public:
void sgnb_addition_ack(uint16_t eutra_rnti, const sgnb_addition_ack_params_t params) override; 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_reject(uint16_t eutra_rnti) override;
void sgnb_addition_complete(uint16_t eutra_rnti, uint16_t nr_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 // rrc_interface_pdcp
void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override; void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override;

@ -49,12 +49,30 @@ public:
uint16_t nr_rnti; /// RNTI assigned to UE on NR carrier 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(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); 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_eutra_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_caps);
void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg); void handle_ue_meas_report(const asn1::rrc::meas_report_s& msg);
void start_sgnb_release();
bool is_endc_supported(); bool is_endc_supported();
private: private:
@ -70,6 +88,7 @@ private:
// vars // vars
bool endc_supported = false; bool endc_supported = false;
rrc_endc_cfg_t endc_cfg = {}; 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; asn1::rrc::rrc_conn_recfg_complete_s pending_recfg_complete;
// fixed ENDC variables // 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 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 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 guards
// FSM transition handlers // 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_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); void handle_rrc_reest(wait_add_complete_st& s, const rrc_reest_rx_ev& ev);
protected: protected:
// states // states
state_list<endc_deactivated_st, wait_sgnb_add_req_resp_st, prepare_recfg_st, wait_add_complete_st, endc_activated_st> state_list<endc_deactivated_st,
wait_sgnb_add_req_resp_st,
prepare_recfg_st,
wait_add_complete_st,
endc_activated_st,
wait_sgnb_rel_req_resp_st>
states{this, states{this,
endc_deactivated_st{}, endc_deactivated_st{},
wait_sgnb_add_req_resp_st{}, wait_sgnb_add_req_resp_st{},
prepare_recfg_st{this}, prepare_recfg_st{this},
wait_add_complete_st{}, wait_add_complete_st{},
endc_activated_st{}}; endc_activated_st{},
wait_sgnb_rel_req_resp_st{}};
// transitions // transitions
using fsm = rrc_endc; 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< 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< 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_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 // clang-format on
}; };

@ -88,6 +88,7 @@ public:
// Interface for EUTRA RRC // Interface for EUTRA RRC
int sgnb_addition_request(uint16_t rnti, const sgnb_addition_req_params_t& params); 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_reconfiguration_complete(uint16_t rnti, asn1::dyn_octstring reconfig_response);
int sgnb_release_request(uint16_t nr_rnti);
// Interfaces for NGAP // Interfaces for NGAP
int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key); int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key);

@ -80,6 +80,14 @@ public:
eutra_stack->sgnb_addition_complete(eutra_rnti, nr_rnti); 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 void set_activity_user(uint16_t eutra_rnti) override
{ {
if (eutra_stack == nullptr) { if (eutra_stack == nullptr) {
@ -88,6 +96,14 @@ public:
eutra_stack->set_activity_user(eutra_rnti); 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 // pdcp_interface_gtpu
void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) override void write_sdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t sdu, int pdcp_sn = -1) override
{ {

@ -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) 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); 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 // 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) void rrc::sgnb_addition_reject(uint16_t eutra_rnti)
{ {
logger.error("Received SgNB addition reject for rnti=%d", 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) 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); 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{});
} }
/******************************************************************************* /*******************************************************************************

@ -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 //! 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) 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); 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) {} 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) 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 // change GTPU tunnel RNTI to match NR RNTI
rrc_enb->gtpu->mod_bearer_rnti(rrc_ue->rnti, ev.params.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() bool rrc::ue::rrc_endc::is_endc_supported()

@ -511,6 +511,16 @@ int rrc_nr::sgnb_reconfiguration_complete(uint16_t eutra_rnti, asn1::dyn_octstri
return SRSRAN_SUCCESS; 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 UE class

Loading…
Cancel
Save