mirror of https://github.com/PentHertz/srsLTE.git
Fix GTPU RRC reestablishment handling
- GTPU bearers rnti is correctly updated during RRC reestablishment - Create rnti_map_t typedef for circular maps of rntis - Failed GTPU rnti creation is now handled - Extend indirect GTPU tunnel timeout to 2000msec - Support EIA0 during S1 Handover
This commit is contained in:
parent
24a7ea9c6a
commit
cdd3932e73
|
@ -37,9 +37,20 @@ class static_circular_map
|
|||
using obj_t = std::pair<K, T>;
|
||||
|
||||
public:
|
||||
using key_type = K;
|
||||
using mapped_type = T;
|
||||
using value_type = std::pair<K, T>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = std::pair<K, T>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
iterator() = default;
|
||||
iterator(static_circular_map<K, T, N>* map, size_t idx_) : ptr(map), idx(idx_)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
INCLUDES
|
||||
*******************************************************************************/
|
||||
|
||||
#include "srsran/adt/circular_map.h"
|
||||
#include "srsran/common/common_lte.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -57,6 +58,10 @@ constexpr uint32_t drb_to_lcid(lte_drb drb_id)
|
|||
#define SRSENB_MAX_BUFFER_SIZE_BYTES 12756
|
||||
#define SRSENB_BUFFER_HEADER_OFFSET 1024
|
||||
|
||||
/// Typedef of circular map container which key corresponding to rnti value and that can be used across layers
|
||||
template <typename UEObject>
|
||||
using rnti_map_t = srsran::static_circular_map<uint16_t, UEObject, SRSENB_MAX_UES>;
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSENB_COMMON_ENB_H
|
||||
|
|
|
@ -145,9 +145,9 @@ private:
|
|||
sched_interface::dl_pdu_mch_t mch = {};
|
||||
|
||||
/* Map of active UEs */
|
||||
srsran::static_circular_map<uint16_t, std::unique_ptr<ue>, 64> ue_db;
|
||||
std::map<uint16_t, std::unique_ptr<ue> > ues_to_rem;
|
||||
uint16_t last_rnti = 70;
|
||||
rnti_map_t<std::unique_ptr<ue> > ue_db;
|
||||
std::map<uint16_t, std::unique_ptr<ue> > ues_to_rem;
|
||||
uint16_t last_rnti = 70;
|
||||
|
||||
srsran::static_blocking_queue<std::unique_ptr<ue>, 32> ue_pool; ///< Pool of pre-allocated UE objects
|
||||
void prealloc_ue(uint32_t nof_ue);
|
||||
|
|
|
@ -88,6 +88,9 @@ public:
|
|||
|
||||
bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gtpu_interface_rrc* gtpu_);
|
||||
|
||||
/// Called after RRCReestablishmentComplete, to add E-RABs of old rnti
|
||||
void reestablish_bearers(bearer_cfg_handler&& old_rnti_bearers);
|
||||
|
||||
int add_erab(uint8_t erab_id,
|
||||
const asn1::s1ap::erab_level_qos_params_s& qos,
|
||||
const asn1::bounded_bitstring<1, 160, true, true>& addr,
|
||||
|
|
|
@ -128,8 +128,8 @@ private:
|
|||
pdcp_interface_gtpu* pdcp = nullptr;
|
||||
srslog::basic_logger& logger;
|
||||
|
||||
srsran::static_circular_map<uint16_t, ue_lcid_tunnel_list, SRSENB_MAX_UES> ue_teidin_db;
|
||||
tunnel_list_t tunnels;
|
||||
rnti_map_t<ue_lcid_tunnel_list> ue_teidin_db;
|
||||
tunnel_list_t tunnels;
|
||||
};
|
||||
|
||||
using gtpu_tunnel_state = gtpu_tunnel_manager::tunnel_state;
|
||||
|
|
|
@ -114,6 +114,8 @@ bool security_cfg_handler::set_security_capabilities(const asn1::s1ap::ue_securi
|
|||
case srsran::INTEGRITY_ALGORITHM_ID_EIA0:
|
||||
// Null integrity is not supported
|
||||
logger.info("Skipping EIA0 as RRC integrity algorithm. Null integrity is not supported.");
|
||||
sec_cfg.integ_algo = srsran::INTEGRITY_ALGORITHM_ID_EIA0;
|
||||
integ_algo_found = true;
|
||||
break;
|
||||
case srsran::INTEGRITY_ALGORITHM_ID_128_EIA1:
|
||||
// “first bit” – 128-EIA1,
|
||||
|
@ -211,6 +213,14 @@ bearer_cfg_handler::bearer_cfg_handler(uint16_t rnti_, const rrc_cfg_t& cfg_, gt
|
|||
rnti(rnti_), cfg(&cfg_), gtpu(gtpu_), logger(&srslog::fetch_basic_logger("RRC"))
|
||||
{}
|
||||
|
||||
void bearer_cfg_handler::reestablish_bearers(bearer_cfg_handler&& old_rnti_bearers)
|
||||
{
|
||||
erab_info_list = std::move(old_rnti_bearers.erab_info_list);
|
||||
erabs = std::move(old_rnti_bearers.erabs);
|
||||
current_drbs = std::move(old_rnti_bearers.current_drbs);
|
||||
old_rnti_bearers.current_drbs.clear();
|
||||
}
|
||||
|
||||
int bearer_cfg_handler::add_erab(uint8_t erab_id,
|
||||
const asn1::s1ap::erab_level_qos_params_s& qos,
|
||||
const asn1::bounded_bitstring<1, 160, true, true>& addr,
|
||||
|
|
|
@ -96,6 +96,8 @@ uint16_t compute_mac_i(uint16_t crnti,
|
|||
|
||||
// Compute MAC-I
|
||||
switch (integ_algo) {
|
||||
case srsran::INTEGRITY_ALGORITHM_ID_EIA0:
|
||||
return 0;
|
||||
case srsran::INTEGRITY_ALGORITHM_ID_128_EIA1:
|
||||
srsran::security_128_eia1(&k_rrc_int[16],
|
||||
0xffffffff, // 32-bit all to ones
|
||||
|
@ -115,7 +117,7 @@ uint16_t compute_mac_i(uint16_t crnti,
|
|||
mac_key);
|
||||
break;
|
||||
default:
|
||||
printf("Unsupported integrity algorithm %d.", integ_algo);
|
||||
srsran::console_stderr("ERROR: Unsupported integrity algorithm %d.\n", integ_algo);
|
||||
}
|
||||
|
||||
uint16_t short_mac_i = (((uint16_t)mac_key[2] << 8u) | (uint16_t)mac_key[3]);
|
||||
|
|
|
@ -523,10 +523,16 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg)
|
|||
static_cast<unsigned>(rrc_event_type::con_reest_req),
|
||||
static_cast<unsigned>(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",
|
||||
|
@ -535,7 +541,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);
|
||||
|
@ -590,9 +595,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -663,8 +672,8 @@ void rrc::ue::handle_rrc_con_reest_complete(rrc_conn_reest_complete_s* msg, srsr
|
|||
parent->pdcp->enable_integrity(rnti, srb_to_lcid(lte_srb::srb1));
|
||||
parent->pdcp->enable_encryption(rnti, srb_to_lcid(lte_srb::srb1));
|
||||
|
||||
// Reestablish current DRBs during ConnectionReconfiguration
|
||||
bearer_list = std::move(parent->users.at(old_reest_rnti)->bearer_list);
|
||||
// Reestablish E-RABs of old rnti during ConnectionReconfiguration
|
||||
bearer_list.reestablish_bearers(std::move(parent->users.at(old_reest_rnti)->bearer_list));
|
||||
|
||||
// remove old RNTI
|
||||
parent->rem_user_thread(old_reest_rnti);
|
||||
|
|
|
@ -99,7 +99,11 @@ const gtpu_tunnel* gtpu_tunnel_manager::add_tunnel(uint16_t rnti, uint32_t lcid,
|
|||
tun->spgw_addr = spgw_addr;
|
||||
|
||||
if (not ue_teidin_db.contains(rnti)) {
|
||||
ue_teidin_db.insert(rnti, ue_lcid_tunnel_list());
|
||||
auto ret = ue_teidin_db.insert(rnti, ue_lcid_tunnel_list());
|
||||
if (ret.is_error()) {
|
||||
logger.error("Failed to allocate rnti=0x%x", rnti);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto& ue_tunnels = ue_teidin_db[rnti];
|
||||
|
||||
|
@ -130,16 +134,20 @@ bool gtpu_tunnel_manager::update_rnti(uint16_t old_rnti, uint16_t new_rnti)
|
|||
auto* old_rnti_ptr = find_rnti_tunnels(old_rnti);
|
||||
logger.info("Modifying bearer rnti. Old rnti: 0x%x, new rnti: 0x%x", old_rnti, new_rnti);
|
||||
|
||||
// Change RNTI bearers map
|
||||
ue_teidin_db.insert(new_rnti, std::move(*old_rnti_ptr));
|
||||
ue_teidin_db.erase(old_rnti);
|
||||
|
||||
// Change TEID in existing tunnels
|
||||
auto* new_rnti_ptr = find_rnti_tunnels(new_rnti);
|
||||
for (lcid_tunnel& bearer : *new_rnti_ptr) {
|
||||
// create new RNTI and update TEIDs of old rnti to reflect new rnti
|
||||
if (not ue_teidin_db.insert(new_rnti, ue_lcid_tunnel_list())) {
|
||||
logger.error("Failure to create new rnti=0x%x", new_rnti);
|
||||
return false;
|
||||
}
|
||||
std::swap(ue_teidin_db[new_rnti], *old_rnti_ptr);
|
||||
auto& new_rnti_obj = ue_teidin_db[new_rnti];
|
||||
for (lcid_tunnel& bearer : new_rnti_obj) {
|
||||
tunnels[bearer.teid].rnti = new_rnti;
|
||||
}
|
||||
|
||||
// Leave old_rnti as zombie to be removed later
|
||||
old_rnti_ptr->clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -246,10 +254,14 @@ void gtpu_tunnel_manager::set_tunnel_priority(uint32_t before_teid, uint32_t aft
|
|||
}
|
||||
};
|
||||
|
||||
// Schedule auto-removal of this indirect tunnel
|
||||
// Schedule auto-removal of the indirect tunnel in case the End Marker is not received
|
||||
// TS 36.300 - On detection of the "end marker", the target eNB may also initiate the release of the data forwarding
|
||||
// resource. However, the release of the data forwarding resource is implementation dependent and could
|
||||
// also be based on other mechanisms (e.g. timer-based mechanism).
|
||||
before_tun.rx_timer = task_sched.get_unique_timer();
|
||||
before_tun.rx_timer.set(500, [this, before_teid](uint32_t tid) {
|
||||
// This will self-destruct the callback object
|
||||
before_tun.rx_timer.set(2000, [this, before_teid](uint32_t tid) {
|
||||
// Note: This will self-destruct the callback object
|
||||
logger.info("Forwarding tunnel " TEID_IN_FMT "being closed after timeout=2000 msec", before_teid);
|
||||
remove_tunnel(before_teid);
|
||||
});
|
||||
before_tun.rx_timer.run();
|
||||
|
|
|
@ -329,7 +329,7 @@ int test_gtpu_direct_tunneling(tunnel_test_event event)
|
|||
TESTASSERT(tenb_pdcp.last_sdu == nullptr);
|
||||
if (event == tunnel_test_event::wait_end_marker_timeout) {
|
||||
// TEST: EndMarker does not reach TeNB, but there is a timeout that will resume the new GTPU tunnel
|
||||
for (size_t i = 0; i < 1000; ++i) {
|
||||
for (size_t i = 0; i < 2001; ++i) {
|
||||
task_sched.tic();
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue