enb,rrc: split RLF counter and timer handling for DL/UL/RLC

this patch splits the counter and timer handling for PHY DL, PHY UL,
and RLC errors and makes sure that, for example, a successful DL
does not cancel the UL RLF timer, and vice versa.

They all use the same timeout value which is user-configurable.
master
Andre Puschmann 4 years ago
parent f9c0009d23
commit b61be7878a

@ -194,7 +194,7 @@ private:
const static uint32_t LCID_REM_USER = 0xffff0001; const static uint32_t LCID_REM_USER = 0xffff0001;
const static uint32_t LCID_REL_USER = 0xffff0002; const static uint32_t LCID_REL_USER = 0xffff0002;
const static uint32_t LCID_ACT_USER = 0xffff0004; const static uint32_t LCID_ACT_USER = 0xffff0004;
const static uint32_t LCID_RTX_USER = 0xffff0005; const static uint32_t LCID_RLC_RTX = 0xffff0005;
const static uint32_t LCID_RADLINK_DL = 0xffff0006; const static uint32_t LCID_RADLINK_DL = 0xffff0006;
const static uint32_t LCID_RADLINK_UL = 0xffff0007; const static uint32_t LCID_RADLINK_UL = 0xffff0007;

@ -46,8 +46,8 @@ public:
void set_radiolink_dl_state(bool crc_res); void set_radiolink_dl_state(bool crc_res);
void set_radiolink_ul_state(bool crc_res); void set_radiolink_ul_state(bool crc_res);
void activity_timer_expired(const activity_timeout_type_t type); void activity_timer_expired(const activity_timeout_type_t type);
void rlf_timer_expired(); void rlf_timer_expired(uint32_t timeout_id);
void max_retx_reached(); void max_rlc_retx_reached();
rrc_state_t get_state(); rrc_state_t get_state();
void get_metrics(rrc_ue_metrics_t& ue_metrics) const; void get_metrics(rrc_ue_metrics_t& ue_metrics) const;
@ -157,9 +157,12 @@ public:
bool is_csfb = false; bool is_csfb = false;
private: private:
// args srsran::timer_handler::unique_timer activity_timer; // for basic DL/UL activity timeout
srsran::unique_timer activity_timer;
srsran::unique_timer rlf_release_timer; /// Radio link failure handling uses distinct timers for PHY (DL and UL) and RLC signaled RLF
srsran::timer_handler::unique_timer phy_dl_rlf_timer; // can be stopped through recovered DL activity
srsran::timer_handler::unique_timer phy_ul_rlf_timer; // can be stopped through recovered UL activity
srsran::timer_handler::unique_timer rlc_rlf_timer; // can only be stoped through UE reestablishment
/// cached ASN1 fields for RRC config update checking, and ease of context transfer during HO /// cached ASN1 fields for RRC config update checking, and ease of context transfer during HO
ue_var_cfg_t current_ue_cfg; ue_var_cfg_t current_ue_cfg;

@ -174,7 +174,7 @@ uint32_t rrc::get_nof_users()
void rrc::max_retx_attempted(uint16_t rnti) void rrc::max_retx_attempted(uint16_t rnti)
{ {
rrc_pdu p = {rnti, LCID_RTX_USER, false, nullptr}; rrc_pdu p = {rnti, LCID_RLC_RTX, false, nullptr};
if (not rx_pdu_queue.try_push(std::move(p))) { if (not rx_pdu_queue.try_push(std::move(p))) {
logger.error("Failed to push max Retx event to RRC queue"); logger.error("Failed to push max Retx event to RRC queue");
} }
@ -943,8 +943,8 @@ void rrc::tti_clock()
case LCID_RADLINK_UL: case LCID_RADLINK_UL:
user_it->second->set_radiolink_ul_state(p.arg); user_it->second->set_radiolink_ul_state(p.arg);
break; break;
case LCID_RTX_USER: case LCID_RLC_RTX:
user_it->second->max_retx_reached(); user_it->second->max_rlc_retx_reached();
break; break;
case LCID_EXIT: case LCID_EXIT:
logger.info("Exiting thread"); logger.info("Exiting thread");

@ -56,13 +56,18 @@ int rrc::ue::init()
// Configure // Configure
apply_setup_phy_common(parent->cfg.sibs[1].sib2().rr_cfg_common, true); apply_setup_phy_common(parent->cfg.sibs[1].sib2().rr_cfg_common, true);
rlf_release_timer = parent->task_sched.get_unique_timer(); phy_dl_rlf_timer = parent->task_sched.get_unique_timer();
activity_timer = parent->task_sched.get_unique_timer(); phy_ul_rlf_timer = parent->task_sched.get_unique_timer();
rlc_rlf_timer = parent->task_sched.get_unique_timer();
activity_timer = parent->task_sched.get_unique_timer();
set_activity_timeout(MSG3_RX_TIMEOUT); // next UE response is Msg3 set_activity_timeout(MSG3_RX_TIMEOUT); // next UE response is Msg3
// Set timeout to release UE context after RLF detection // Set timeout to release UE context after RLF detection
uint32_t deadline_ms = parent->cfg.rlf_release_timer_ms; uint32_t deadline_ms = parent->cfg.rlf_release_timer_ms;
rlf_release_timer.set(deadline_ms, [this](uint32_t tid) { rlf_timer_expired(); }); auto timer_expire_func = [this](uint32_t tid) { rlf_timer_expired(tid); };
phy_dl_rlf_timer.set(deadline_ms, timer_expire_func);
phy_ul_rlf_timer.set(deadline_ms, timer_expire_func);
rlc_rlf_timer.set(deadline_ms, timer_expire_func);
parent->logger.info("Setting RLF timer for rnti=0x%x to %dms", rnti, deadline_ms); parent->logger.info("Setting RLF timer for rnti=0x%x to %dms", rnti, deadline_ms);
mobility_handler = make_rnti_obj<rrc_mobility>(rnti, this); mobility_handler = make_rnti_obj<rrc_mobility>(rnti, this);
@ -97,44 +102,34 @@ void rrc::ue::set_activity()
} }
} }
void rrc::ue::start_rlf_timer()
{
rlf_release_timer.run();
parent->logger.info("RLF timer started for rnti=0x%x (duration=%dms)", rnti, rlf_release_timer.duration());
}
void rrc::ue::stop_rlf_timer()
{
if (rlf_release_timer.is_running()) {
parent->logger.info("RLF timer stopped for rnti=0x%x (time elapsed=%dms)", rnti, rlf_release_timer.time_elapsed());
}
rlf_release_timer.stop();
}
void rrc::ue::set_radiolink_dl_state(bool crc_res) void rrc::ue::set_radiolink_dl_state(bool crc_res)
{ {
parent->logger.debug( parent->logger.debug(
"Radio-Link downlink state for rnti=0x%x: crc_res=%d, consecutive_ko=%d", rnti, crc_res, consecutive_kos_dl); "Radio-Link downlink state for rnti=0x%x: crc_res=%d, consecutive_ko=%d", rnti, crc_res, consecutive_kos_dl);
// If received OK, restart counter and stop RLF timer // If received OK, restart DL counter and stop RLF timer
if (crc_res) { if (crc_res) {
consecutive_kos_dl = 0; consecutive_kos_dl = 0;
consecutive_kos_ul = 0; if (phy_dl_rlf_timer.is_running()) {
stop_rlf_timer(); parent->logger.info(
"DL RLF timer stopped for rnti=0x%x (time elapsed=%dms)", rnti, phy_dl_rlf_timer.time_elapsed());
phy_dl_rlf_timer.stop();
}
return; return;
} }
// Count KOs in MAC and trigger release if it goes above a certain value. // Count KOs in MAC and trigger release if it goes above a certain value.
// This is done to detect out-of-coverage UEs // This is done to detect out-of-coverage UEs
if (rlf_release_timer.is_running()) { if (phy_dl_rlf_timer.is_running()) {
// RLF timer already running, no need to count KOs // RLF timer already running, no need to count KOs
return; return;
} }
consecutive_kos_dl++; consecutive_kos_dl++;
if (consecutive_kos_dl > parent->cfg.max_mac_dl_kos) { if (consecutive_kos_dl > parent->cfg.max_mac_dl_kos) {
parent->logger.info("Max KOs in DL reached, triggering release rnti=0x%x", rnti); parent->logger.info("Max KOs in DL reached, starting RLF timer rnti=0x%x", rnti);
max_retx_reached(); mac_ctrl.handle_max_retx();
phy_dl_rlf_timer.run();
} }
} }
@ -143,31 +138,34 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res)
parent->logger.debug( parent->logger.debug(
"Radio-Link uplink state for rnti=0x%x: crc_res=%d, consecutive_ko=%d", rnti, crc_res, consecutive_kos_ul); "Radio-Link uplink state for rnti=0x%x: crc_res=%d, consecutive_ko=%d", rnti, crc_res, consecutive_kos_ul);
// If received OK, restart counter and stop RLF timer // If received OK, restart UL counter and stop RLF timer
if (crc_res) { if (crc_res) {
consecutive_kos_dl = 0;
consecutive_kos_ul = 0; consecutive_kos_ul = 0;
stop_rlf_timer(); if (phy_ul_rlf_timer.is_running()) {
parent->logger.info(
"UL RLF timer stopped for rnti=0x%x (time elapsed=%dms)", rnti, phy_ul_rlf_timer.time_elapsed());
phy_ul_rlf_timer.stop();
}
return; return;
} }
// Count KOs in MAC and trigger release if it goes above a certain value. // Count KOs in MAC and trigger release if it goes above a certain value.
// This is done to detect out-of-coverage UEs // This is done to detect out-of-coverage UEs
if (rlf_release_timer.is_running()) { if (phy_ul_rlf_timer.is_running()) {
// RLF timer already running, no need to count KOs // RLF timer already running, no need to count KOs
return; return;
} }
consecutive_kos_ul++; consecutive_kos_ul++;
if (consecutive_kos_ul > parent->cfg.max_mac_ul_kos) { if (consecutive_kos_ul > parent->cfg.max_mac_ul_kos) {
parent->logger.info("Max KOs in UL reached, triggering release rnti=0x%x", rnti); parent->logger.info("Max KOs in UL reached, starting RLF timer rnti=0x%x", rnti);
max_retx_reached(); mac_ctrl.handle_max_retx();
phy_ul_rlf_timer.run();
} }
} }
void rrc::ue::activity_timer_expired(const activity_timeout_type_t type) void rrc::ue::activity_timer_expired(const activity_timeout_type_t type)
{ {
stop_rlf_timer();
if (parent) { if (parent) {
parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed());
@ -196,11 +194,17 @@ void rrc::ue::activity_timer_expired(const activity_timeout_type_t type)
state = RRC_STATE_RELEASE_REQUEST; state = RRC_STATE_RELEASE_REQUEST;
} }
void rrc::ue::rlf_timer_expired() void rrc::ue::rlf_timer_expired(uint32_t timeout_id)
{ {
activity_timer.stop(); activity_timer.stop();
if (parent) { if (parent) {
parent->logger.info("RLF timer for rnti=0x%x expired after %d ms", rnti, rlf_release_timer.time_elapsed()); if (timeout_id == phy_dl_rlf_timer.id()) {
parent->logger.info("DL RLF timer for rnti=0x%x expired after %d ms", rnti, phy_dl_rlf_timer.time_elapsed());
} else if (timeout_id == phy_ul_rlf_timer.id()) {
parent->logger.info("UL RLF timer for rnti=0x%x expired after %d ms", rnti, phy_ul_rlf_timer.time_elapsed());
} else if (timeout_id == rlc_rlf_timer.id()) {
parent->logger.info("RLC RLF timer for rnti=0x%x expired after %d ms", rnti, rlc_rlf_timer.time_elapsed());
}
if (parent->s1ap->user_exists(rnti)) { if (parent->s1ap->user_exists(rnti)) {
parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost); parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost);
@ -215,14 +219,13 @@ void rrc::ue::rlf_timer_expired()
state = RRC_STATE_RELEASE_REQUEST; state = RRC_STATE_RELEASE_REQUEST;
} }
void rrc::ue::max_retx_reached() void rrc::ue::max_rlc_retx_reached()
{ {
if (parent) { if (parent) {
parent->logger.info("Max retx reached for rnti=0x%x", rnti); parent->logger.info("Max RLC retx reached for rnti=0x%x", rnti);
// Give UE time to start re-establishment
start_rlf_timer();
// Turn off DRB scheduling but give UE chance to start re-establishment
rlc_rlf_timer.run();
mac_ctrl.handle_max_retx(); mac_ctrl.handle_max_retx();
} }
} }
@ -582,6 +585,11 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg)
parent->logger.debug("rnti=0x%x EUTRA capabilities: %s", rnti, js.to_string().c_str()); parent->logger.debug("rnti=0x%x EUTRA capabilities: %s", rnti, js.to_string().c_str());
} }
if (parent->users.at(old_rnti)->rlc_rlf_timer.is_running()) {
parent->logger.info("Stopping RLC RLF timer for old rnti=0x%x", old_rnti);
parent->users.at(old_rnti)->rlc_rlf_timer.stop();
}
old_reest_rnti = old_rnti; old_reest_rnti = old_rnti;
state = RRC_STATE_WAIT_FOR_CON_REEST_COMPLETE; state = RRC_STATE_WAIT_FOR_CON_REEST_COMPLETE;
set_activity_timeout(UE_INACTIVITY_TIMEOUT); set_activity_timeout(UE_INACTIVITY_TIMEOUT);

Loading…
Cancel
Save