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.
This commit is contained in:
Andre Puschmann 2021-10-14 17:43:09 +02:00
parent 908c469f30
commit 255ddb1329
10 changed files with 123 additions and 7 deletions

View File

@ -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
*

View File

@ -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);

View File

@ -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
{

View File

@ -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;

View File

@ -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<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,
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
};

View File

@ -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);

View File

@ -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
{

View File

@ -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{});
}
/*******************************************************************************

View File

@ -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()

View File

@ -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