From 9464f36714eedf290e48b50a99d06dc644f49ebe Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 6 May 2021 16:25:03 +0100 Subject: [PATCH] make eNB UE release timer after RLF detection configurable --- srsenb/enb.conf.example | 2 + srsenb/hdr/enb.h | 1 + srsenb/hdr/stack/rrc/rrc_config.h | 1 + srsenb/hdr/stack/rrc/rrc_ue.h | 7 ++-- srsenb/src/enb_cfg_parser.cc | 5 ++- srsenb/src/main.cc | 1 + srsenb/src/stack/rrc/rrc_ue.cc | 67 ++++++++++++++++++------------- 7 files changed, 51 insertions(+), 33 deletions(-) diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index ce64a9dae..ca2654dbf 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -305,6 +305,7 @@ enable = false # rrc_inactivity_timer Inactivity timeout used to remove UE context from RRC (in milliseconds). # max_prach_offset_us: Maximum allowed RACH offset (in us) # nof_prealloc_ues: Number of UE memory resources to preallocate during eNB initialization for faster UE creation (Default 8) +# rlf_release_timer_ms: Time taken by eNB to release UE context after it detects an RLF # eea_pref_list: Ordered preference list for the selection of encryption algorithm (EEA) (default: EEA0, EEA2, EEA1). # eia_pref_list: Ordered preference list for the selection of integrity algorithm (EIA) (default: EIA2, EIA1, EIA0). # gtpu_tunnel_timeout: Time that GTPU takes to release indirect forwarding tunnel since the last received GTPU PDU (0 for no timer). @@ -330,6 +331,7 @@ enable = false #max_nof_kos = 100 #max_prach_offset_us = 30 #nof_prealloc_ues = 8 +#rlf_release_timer_ms = 4000 #eea_pref_list = EEA0, EEA2, EEA1 #eia_pref_list = EIA2, EIA1, EIA0 #gtpu_tunnel_timeout = 0 diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 71b897974..eece0fb9e 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -96,6 +96,7 @@ struct general_args_t { uint32_t max_mac_dl_kos; uint32_t max_mac_ul_kos; uint32_t gtpu_indirect_tunnel_timeout; + uint32_t rlf_release_timer_ms; }; struct all_args_t { diff --git a/srsenb/hdr/stack/rrc/rrc_config.h b/srsenb/hdr/stack/rrc/rrc_config.h index 041f492e8..fb5e7ca5a 100644 --- a/srsenb/hdr/stack/rrc/rrc_config.h +++ b/srsenb/hdr/stack/rrc/rrc_config.h @@ -61,6 +61,7 @@ struct rrc_cfg_t { cell_list_t cell_list_nr; uint32_t max_mac_dl_kos; uint32_t max_mac_ul_kos; + uint32_t rlf_release_timer_ms; }; constexpr uint32_t UE_PCELL_CC_IDX = 0; diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 8e48c7816..0ac8484a1 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -40,8 +40,9 @@ public: std::string to_string(const activity_timeout_type_t& type); void set_activity_timeout(const activity_timeout_type_t type); - void set_rlf_timeout(); void set_activity(); + void start_rlf_timer(); + void stop_rlf_timer(); void set_radiolink_dl_state(bool crc_res); void set_radiolink_ul_state(bool crc_res); void activity_timer_expired(const activity_timeout_type_t type); @@ -158,8 +159,8 @@ public: private: // args - srsran::timer_handler::unique_timer activity_timer; - srsran::timer_handler::unique_timer rlf_timer; + srsran::unique_timer activity_timer; + srsran::unique_timer rlf_release_timer; /// cached ASN1 fields for RRC config update checking, and ease of context transfer during HO ue_var_cfg_t current_ue_cfg; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 110bb564f..44ba97fb0 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1160,8 +1160,9 @@ int set_derived_args(all_args_t* args_, rrc_cfg_t* rrc_cfg_, phy_cfg_t* phy_cfg_ rrc_cfg_->enb_id = args_->stack.s1ap.enb_id; // Set max number of KOs - rrc_cfg_->max_mac_dl_kos = args_->general.max_mac_dl_kos; - rrc_cfg_->max_mac_ul_kos = args_->general.max_mac_ul_kos; + rrc_cfg_->max_mac_dl_kos = args_->general.max_mac_dl_kos; + rrc_cfg_->max_mac_ul_kos = args_->general.max_mac_ul_kos; + rrc_cfg_->rlf_release_timer_ms = args_->general.rlf_release_timer_ms; // Set sync queue capacity to 1 for ZMQ if (args_->rf.device_name == "zmq") { diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index c8a842dc7..bc79431d3 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -219,6 +219,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.max_mac_dl_kos", bpo::value(&args->general.max_mac_dl_kos)->default_value(100), "Maximum number of consecutive KOs in DL before triggering the UE's release") ("expert.max_mac_ul_kos", bpo::value(&args->general.max_mac_ul_kos)->default_value(100), "Maximum number of consecutive KOs in UL before triggering the UE's release") ("expert.gtpu_tunnel_timeout", bpo::value(&args->stack.gtpu_indirect_tunnel_timeout_msec)->default_value(0), "Maximum time that GTPU takes to release indirect forwarding tunnel since the last received GTPU PDU. (0 for infinity)") + ("expert.rlf_release_timer_ms", bpo::value(&args->general.rlf_release_timer_ms)->default_value(4000), "Time taken by eNB to release UE context after it detects an RLF") // eMBMS section diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 12192230e..d3d910c8c 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -56,10 +56,14 @@ int rrc::ue::init() // Configure apply_setup_phy_common(parent->cfg.sibs[1].sib2().rr_cfg_common, true); - rlf_timer = parent->task_sched.get_unique_timer(); - activity_timer = parent->task_sched.get_unique_timer(); + rlf_release_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_rlf_timeout(); + + // Set timeout to release UE context after RLF detection + uint32_t deadline_ms = parent->cfg.rlf_release_timer_ms; + rlf_release_timer.set(deadline_ms, [this](uint32_t tid) { rlf_timer_expired(); }); + parent->logger.info("Setting RLF timer for rnti=0x%x to %dms", rnti, deadline_ms); mobility_handler = make_rnti_obj(rnti, this); return SRSRAN_SUCCESS; @@ -93,6 +97,20 @@ 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) { parent->logger.debug( @@ -102,13 +120,13 @@ void rrc::ue::set_radiolink_dl_state(bool crc_res) if (crc_res) { consecutive_kos_dl = 0; consecutive_kos_ul = 0; - rlf_timer.stop(); + stop_rlf_timer(); return; } // Count KOs in MAC and trigger release if it goes above a certain value. // This is done to detect out-of-coverage UEs - if (rlf_timer.is_running()) { + if (rlf_release_timer.is_running()) { // RLF timer already running, no need to count KOs return; } @@ -129,13 +147,13 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res) if (crc_res) { consecutive_kos_dl = 0; consecutive_kos_ul = 0; - rlf_timer.stop(); + stop_rlf_timer(); return; } // Count KOs in MAC and trigger release if it goes above a certain value. // This is done to detect out-of-coverage UEs - if (rlf_timer.is_running()) { + if (rlf_release_timer.is_running()) { // RLF timer already running, no need to count KOs return; } @@ -149,7 +167,7 @@ void rrc::ue::set_radiolink_ul_state(bool crc_res) void rrc::ue::activity_timer_expired(const activity_timeout_type_t type) { - rlf_timer.stop(); + stop_rlf_timer(); if (parent) { parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); @@ -182,7 +200,7 @@ void rrc::ue::rlf_timer_expired() { activity_timer.stop(); if (parent) { - parent->logger.info("RLF timer for rnti=0x%x expired after %d ms", rnti, rlf_timer.time_elapsed()); + parent->logger.info("RLF timer for rnti=0x%x expired after %d ms", rnti, rlf_release_timer.time_elapsed()); if (parent->s1ap->user_exists(rnti)) { parent->s1ap->user_release(rnti, asn1::s1ap::cause_radio_network_opts::radio_conn_with_ue_lost); @@ -203,28 +221,12 @@ void rrc::ue::max_retx_reached() parent->logger.info("Max retx reached for rnti=0x%x", rnti); // Give UE time to start re-establishment - rlf_timer.run(); + start_rlf_timer(); mac_ctrl.handle_max_retx(); } } -void rrc::ue::set_rlf_timeout() -{ - uint32_t deadline_s = 0; - uint32_t deadline_ms = 0; - - deadline_ms = static_cast((get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t310.to_number()) + - (get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t311.to_number()) + - (get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.n310.to_number())); - deadline_s = deadline_ms / 1000; - deadline_ms = deadline_ms % 1000; - - uint32_t deadline = deadline_s * 1e3 + deadline_ms; - rlf_timer.set(deadline, [this](uint32_t tid) { rlf_timer_expired(); }); - parent->logger.info("Setting RLF timer for rnti=0x%x to %dms", rnti, deadline); -} - void rrc::ue::set_activity_timeout(const activity_timeout_type_t type) { uint32_t deadline_s = 0; @@ -514,10 +516,16 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) static_cast(rrc_event_type::con_reest_req), static_cast(procedure_result_code::none), rnti); + const rrc_conn_reest_request_r8_ies_s& req_r8 = msg->crit_exts.rrc_conn_reest_request_r8(); + uint16_t old_rnti = req_r8.ue_id.c_rnti.to_number(); + + srsran::console( + "User 0x%x requesting RRC Reestablishment as 0x%x. Cause: %s\n", rnti, old_rnti, req_r8.reest_cause.to_string()); if (not parent->s1ap->is_mme_connected()) { parent->logger.error("MME isn't connected. Sending Connection Reject"); - send_connection_reject(procedure_result_code::error_mme_not_connected); + send_connection_reest_rej(procedure_result_code::error_mme_not_connected); + srsran::console("User 0x%x RRC Reestablishment Request rejected\n", rnti); return; } parent->logger.debug("rnti=0x%x, phyid=0x%x, smac=0x%x, cause=%s", @@ -526,7 +534,6 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) (uint32_t)msg->crit_exts.rrc_conn_reest_request_r8().ue_id.short_mac_i.to_number(), msg->crit_exts.rrc_conn_reest_request_r8().reest_cause.to_string()); if (is_idle()) { - uint16_t old_rnti = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.c_rnti.to_number(); uint16_t old_pci = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.pci; const enb_cell_common* old_cell = parent->cell_common_list->get_pci(old_pci); auto ue_it = parent->users.find(old_rnti); @@ -581,9 +588,13 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) } else { parent->logger.error("Received ConnectionReestablishment for rnti=0x%x without context", old_rnti); send_connection_reest_rej(procedure_result_code::error_unknown_rnti); + srsran::console( + "User 0x%x RRC Reestablishment Request rejected. Cause: no rnti=0x%x context available\n", rnti, old_rnti); } } else { parent->logger.error("Received ReestablishmentRequest from an rnti=0x%x not in IDLE", rnti); + send_connection_reest_rej(procedure_result_code::error_unknown_rnti); + srsran::console("ERROR: User 0x%x requesting Reestablishment is not in RRC_IDLE\n", rnti); } }