use of more space efficient sorted vector structure for lcid tunnels of a rnti

This commit is contained in:
Francisco 2021-03-24 13:02:29 +00:00 committed by Francisco Paisana
parent eba0edea4a
commit c201eb7708
3 changed files with 61 additions and 37 deletions

View File

@ -246,6 +246,14 @@ private:
size_t count = 0;
};
/**
* Operates like a circular map, but automatically assigns the ID/key to inserted objects in a monotonically
* increasing way. The assigned IDs are not necessarily contiguous, as they are selected based on the available slots
* in the circular map
* @tparam K type of ID/key
* @tparam T object being inserted
* @tparam MAX_N maximum size of pool
*/
template <typename K, typename T, size_t MAX_N>
class static_id_obj_pool : private static_circular_map<K, T, MAX_N>
{

View File

@ -15,6 +15,7 @@
#include <unordered_map>
#include "common_enb.h"
#include "srsran/adt/bounded_vector.h"
#include "srsran/adt/circular_map.h"
#include "srsran/common/buffer_pool.h"
#include "srsran/common/task_scheduler.h"
@ -56,14 +57,23 @@ class gtpu_tunnel_manager
{
public:
const static size_t MAX_TUNNELS_PER_UE = 4;
using lcid_teid_list = std::vector<uint32_t>;
using ue_lcid_tunnel_list = srsran::static_circular_map<uint16_t, lcid_teid_list, MAX_TUNNELS_PER_UE>;
struct lcid_tunnel {
uint32_t lcid;
uint32_t teid;
bool operator<(const lcid_tunnel& other) const
{
return lcid < other.lcid or (lcid == other.lcid and teid < other.teid);
}
bool operator==(const lcid_tunnel& other) const { return lcid == other.lcid and teid == other.teid; }
};
using ue_lcid_tunnel_list = srsran::bounded_vector<lcid_tunnel, MAX_TUNNELS_PER_UE>;
gtpu_tunnel_manager();
gtpu_tunnel* find_tunnel(uint32_t teid);
ue_lcid_tunnel_list* find_rnti_tunnels(uint16_t rnti);
srsran::span<uint32_t> find_rnti_lcid_tunnels(uint16_t rnti, uint32_t lcid);
gtpu_tunnel* find_tunnel(uint32_t teid);
ue_lcid_tunnel_list* find_rnti_tunnels(uint16_t rnti);
srsran::span<lcid_tunnel> find_rnti_lcid_tunnels(uint16_t rnti, uint32_t lcid);
gtpu_tunnel* add_tunnel(uint16_t rnti, uint32_t lcid, uint32_t teidout, uint32_t spgw_addr);
bool update_rnti(uint16_t old_rnti, uint16_t new_rnti);

View File

@ -45,21 +45,28 @@ gtpu_tunnel_manager::ue_lcid_tunnel_list* gtpu_tunnel_manager::find_rnti_tunnels
return &ue_teidin_db[rnti];
}
srsran::span<uint32_t> gtpu_tunnel_manager::find_rnti_lcid_tunnels(uint16_t rnti, uint32_t lcid)
srsran::span<gtpu_tunnel_manager::lcid_tunnel> gtpu_tunnel_manager::find_rnti_lcid_tunnels(uint16_t rnti, uint32_t lcid)
{
if (lcid < SRSENB_N_SRB or lcid >= SRSENB_N_RADIO_BEARERS) {
logger.warning("Searching for bearer with invalid lcid=%d", lcid);
return {};
}
auto* ue_ptr = find_rnti_tunnels(rnti);
if (ue_ptr == nullptr or not ue_ptr->contains(lcid)) {
if (ue_ptr == nullptr) {
return {};
}
return (*ue_ptr)[lcid];
auto lcid_it_begin = std::lower_bound(ue_ptr->begin(), ue_ptr->end(), lcid_tunnel{lcid, 0});
auto lcid_it_end = std::lower_bound(ue_ptr->begin(), ue_ptr->end(), lcid_tunnel{lcid + 1, 0});
return srsran::span<lcid_tunnel>(&(*lcid_it_begin), &(*lcid_it_end));
}
gtpu_tunnel* gtpu_tunnel_manager::add_tunnel(uint16_t rnti, uint32_t lcid, uint32_t teidout, uint32_t spgw_addr)
{
if (lcid < SRSENB_N_SRB or lcid >= SRSENB_N_RADIO_BEARERS) {
logger.warning("Adding TEID with invalid parmaters");
return nullptr;
}
auto ret_pair = tunnels.insert(gtpu_tunnel());
if (not ret_pair) {
logger.warning("Adding new GTPU TEID In");
@ -75,10 +82,15 @@ gtpu_tunnel* gtpu_tunnel_manager::add_tunnel(uint16_t rnti, uint32_t lcid, uint3
if (not ue_teidin_db.contains(rnti)) {
ue_teidin_db.insert(rnti, ue_lcid_tunnel_list());
}
if (not ue_teidin_db[rnti].contains(lcid)) {
ue_teidin_db[rnti].insert(lcid, std::vector<uint32_t>());
auto& ue_tunnels = ue_teidin_db[rnti];
if (ue_tunnels.full()) {
logger.error("The number of TEIDs per UE exceeded for rnti=0x%x", rnti);
tunnels.erase(tun->teid_in);
return nullptr;
}
ue_teidin_db[rnti][lcid].push_back(tun->teid_in);
ue_tunnels.push_back(lcid_tunnel{lcid, tun->teid_in});
std::sort(ue_tunnels.begin(), ue_tunnels.end());
fmt::memory_buffer str_buffer;
srsran::gtpu_ntoa(str_buffer, htonl(spgw_addr));
@ -107,10 +119,8 @@ bool gtpu_tunnel_manager::update_rnti(uint16_t old_rnti, uint16_t new_rnti)
// Change TEID in existing tunnels
auto* new_rnti_ptr = find_rnti_tunnels(new_rnti);
for (auto& bearer : *new_rnti_ptr) {
for (uint32_t teid : bearer.second) {
tunnels[teid].rnti = new_rnti;
}
for (lcid_tunnel& bearer : *new_rnti_ptr) {
tunnels[bearer.teid].rnti = new_rnti;
}
return true;
@ -124,11 +134,11 @@ bool gtpu_tunnel_manager::remove_tunnel(uint32_t teidin)
return false;
}
gtpu_tunnel& tun = it->second;
srsran_assert(ue_teidin_db.contains(tun.rnti) or ue_teidin_db[tun.rnti].contains(tun.lcid),
"inconsistency in internal data structs");
std::vector<uint32_t>& lcids = ue_teidin_db[tun.rnti][tun.lcid];
lcids.erase(std::remove(lcids.begin(), lcids.end(), teidin), lcids.end());
// erase keeping the relative order
auto& ue = ue_teidin_db[tun.rnti];
auto lcid_it = std::find(ue.begin(), ue.end(), lcid_tunnel{tun.lcid, tun.teid_in});
ue.erase(lcid_it);
logger.info("TEID In=%d for rnti=0x%x erased", teidin, tun.rnti);
tunnels.erase(it);
@ -137,18 +147,16 @@ bool gtpu_tunnel_manager::remove_tunnel(uint32_t teidin)
bool gtpu_tunnel_manager::remove_bearer(uint16_t rnti, uint32_t lcid)
{
ue_lcid_tunnel_list* ue_ptr = find_rnti_tunnels(rnti);
if (ue_ptr == nullptr or not ue_ptr->contains(lcid)) {
logger.warning("Removing rnti=0x%x, lcid=%d", rnti, lcid);
srsran::span<lcid_tunnel> to_rem = find_rnti_lcid_tunnels(rnti, lcid);
if (to_rem.empty()) {
return false;
}
logger.info("Removing rnti=0x%x,lcid=%d", rnti, lcid);
lcid_teid_list& lcid_list = (*ue_ptr)[lcid];
for (uint32_t teid : lcid_list) {
srsran_expect(tunnels.erase(teid) > 0, "Inconsistency detected between two internal data structures");
for (lcid_tunnel& lcid_tun : to_rem) {
srsran_expect(tunnels.erase(lcid_tun.teid) > 0, "Inconsistency detected between two internal data structures");
}
ue_ptr->erase(lcid);
ue_teidin_db[rnti].erase(to_rem.begin(), to_rem.end());
return true;
}
@ -160,10 +168,8 @@ bool gtpu_tunnel_manager::remove_rnti(uint16_t rnti)
}
logger.info("Removing rnti=0x%x", rnti);
for (auto& lcid_pair : ue_teidin_db[rnti]) {
for (uint32_t teid : lcid_pair.second) {
srsran_expect(tunnels.erase(teid) > 0, "Inconsistency detected between two internal data structures");
}
for (lcid_tunnel& ue_tuns : ue_teidin_db[rnti]) {
srsran_expect(tunnels.erase(ue_tuns.teid) > 0, "Inconsistency detected between two internal data structures");
}
ue_teidin_db.erase(rnti);
return true;
@ -249,12 +255,12 @@ void gtpu::stop()
// gtpu_interface_pdcp
void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu)
{
srsran::span<uint32_t> teids = tunnels.find_rnti_lcid_tunnels(rnti, lcid);
srsran::span<gtpu_tunnel_manager::lcid_tunnel> teids = tunnels.find_rnti_lcid_tunnels(rnti, lcid);
if (teids.empty()) {
logger.warning("The rnti=0x%x,lcid=%d does not have any active tunnel", rnti, lcid);
return;
}
gtpu_tunnel& tx_tun = *tunnels.find_tunnel(teids[0]);
gtpu_tunnel& tx_tun = *tunnels.find_tunnel(teids[0].teid);
log_message(tx_tun, false, srsran::make_span(pdu));
send_pdu_to_tunnel(tx_tun, std::move(pdu));
}
@ -415,10 +421,10 @@ void gtpu::handle_end_marker(gtpu_tunnel& rx_tunnel)
rem_tunnel(rx_tunnel.teid_in);
} else {
// TeNB switches paths, and flushes PDUs that have been buffered
srsran::span<uint32_t> lcid_tunnels = tunnels.find_rnti_lcid_tunnels(rnti, rx_tunnel.lcid);
for (uint32_t new_teidin : lcid_tunnels) {
gtpu_tunnel* new_tun = tunnels.find_tunnel(new_teidin);
if (new_teidin != rx_tunnel.teid_in and new_tun->prior_teid_in_present and
srsran::span<gtpu_tunnel_manager::lcid_tunnel> lcid_tunnels = tunnels.find_rnti_lcid_tunnels(rnti, rx_tunnel.lcid);
for (auto& lcid_tun : lcid_tunnels) {
gtpu_tunnel* new_tun = tunnels.find_tunnel(lcid_tun.teid);
if (new_tun->teid_in != rx_tunnel.teid_in and new_tun->prior_teid_in_present and
new_tun->prior_teid_in == rx_tunnel.teid_in) {
rem_tunnel(new_tun->prior_teid_in);
new_tun->prior_teid_in_present = false;