avoid loss of pdcp sdus' SNs buffered in gtpu during handover

This commit is contained in:
Francisco 2021-02-02 22:16:25 +00:00 committed by Francisco Paisana
parent 9e25e95545
commit c4a50b7de0
3 changed files with 30 additions and 13 deletions

View File

@ -100,6 +100,7 @@ private:
};
m1u_handler m1u;
const uint32_t undefined_pdcp_sn = std::numeric_limits<uint32_t>::max();
struct tunnel {
bool dl_enabled = true;
bool fwd_teid_in_present = false;
@ -111,7 +112,7 @@ private:
uint32_t spgw_addr = 0;
uint32_t fwd_teid_in = 0; ///< forward Rx SDUs to this TEID
uint32_t prior_teid_in = 0; ///< buffer bearer SDUs until this TEID receives an End Marker
std::vector<srslte::unique_byte_buffer_t> buffer;
std::multimap<uint32_t, srslte::unique_byte_buffer_t> buffer;
};
std::unordered_map<uint32_t, tunnel> tunnels;
std::map<uint16_t, std::array<std::vector<uint32_t>, SRSENB_N_RADIO_BEARERS> > ue_teidin_db;

View File

@ -190,8 +190,11 @@ void gtpu::set_tunnel_status(uint32_t teidin, bool dl_active)
}
tun_it->second.dl_enabled = dl_active;
if (dl_active) {
for (auto& sdu : tun_it->second.buffer) {
pdcp->write_sdu(tun_it->second.rnti, tun_it->second.lcid, std::move(sdu));
for (auto& sdu_it : tun_it->second.buffer) {
pdcp->write_sdu(tun_it->second.rnti,
tun_it->second.lcid,
std::move(sdu_it.second),
sdu_it.first == undefined_pdcp_sn ? -1 : sdu_it.first);
}
tun_it->second.buffer.clear();
}
@ -318,14 +321,16 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
if (rx_tun.fwd_teid_in_present) {
tunnel& tx_tun = tunnels.at(rx_tun.fwd_teid_in);
send_pdu_to_tunnel(tx_tun, std::move(pdu));
} else if (not rx_tun.dl_enabled) {
rx_tun.buffer.push_back(std::move(pdu));
} else {
uint32_t pdcp_sn = -1;
uint32_t pdcp_sn = undefined_pdcp_sn;
if (header.flags & GTPU_FLAGS_EXTENDED_HDR and header.next_ext_hdr_type == GTPU_EXT_HEADER_PDCP_PDU_NUMBER) {
pdcp_sn = (header.ext_buffer[1] << 8u) + header.ext_buffer[2];
}
pdcp->write_sdu(rnti, lcid, std::move(pdu), pdcp_sn);
if (not rx_tun.dl_enabled) {
rx_tun.buffer.insert(std::make_pair(pdcp_sn, std::move(pdu)));
} else {
pdcp->write_sdu(rnti, lcid, std::move(pdu), pdcp_sn == undefined_pdcp_sn ? -1 : pdcp_sn);
}
}
} break;
case GTPU_MSG_END_MARKER: {
@ -345,12 +350,8 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
tunnel& new_tun = tunnels.at(new_teidin);
if (new_teidin != old_tun.teid_in and new_tun.prior_teid_in_present and
new_tun.prior_teid_in == old_tun.teid_in) {
for (srslte::unique_byte_buffer_t& sdu : new_tun.buffer) {
pdcp->write_sdu(new_tun.rnti, new_tun.lcid, std::move(sdu));
}
new_tun.dl_enabled = true;
new_tun.prior_teid_in_present = false;
new_tun.buffer.clear();
set_tunnel_status(new_tun.teid_in, true);
}
}
}

View File

@ -183,8 +183,20 @@ int test_gtpu_direct_tunneling()
std::vector<uint8_t> encoded_data;
srslte::span<uint8_t> pdu_view{};
// TEST: GTPU buffers incoming PDCP buffered SNs until the TEID is explicitly activated
tenb_gtpu.handle_gtpu_s1u_rx_packet(read_socket(tenb_stack.s1u_fd), senb_sockaddr);
TESTASSERT(tenb_pdcp.last_sdu == nullptr);
tenb_gtpu.handle_gtpu_s1u_rx_packet(read_socket(tenb_stack.s1u_fd), senb_sockaddr);
TESTASSERT(tenb_pdcp.last_sdu == nullptr);
tenb_gtpu.set_tunnel_status(dl_tenb_teid_in, true);
pdu_view = srslte::make_span(tenb_pdcp.last_sdu);
TESTASSERT(std::count(pdu_view.begin() + PDU_HEADER_SIZE, pdu_view.end(), 7) == 10);
TESTASSERT(tenb_pdcp.last_rnti == rnti2);
TESTASSERT(tenb_pdcp.last_lcid == drb1);
TESTASSERT(tenb_pdcp.last_pdcp_sn == (int)7);
// TEST: verify that PDCP buffered SNs have been forwarded through SeNB->TeNB tunnel
for (size_t sn = 6; sn < 10; ++sn) {
for (size_t sn = 8; sn < 10; ++sn) {
tenb_gtpu.handle_gtpu_s1u_rx_packet(read_socket(tenb_stack.s1u_fd), senb_sockaddr);
pdu_view = srslte::make_span(tenb_pdcp.last_sdu);
TESTASSERT(std::count(pdu_view.begin() + PDU_HEADER_SIZE, pdu_view.end(), sn) == 10);
@ -249,4 +261,7 @@ int main()
srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_DEBUG);
srslte::logmap::set_default_hex_limit(100000);
TESTASSERT(srsenb::test_gtpu_direct_tunneling() == SRSLTE_SUCCESS);
srslog::flush();
srslte::console("Success");
}