gtpu,bugfix - handle the case when gtpu fails to allocate buffer for end marker. Also, added a timer that when expired, it autoremoves the GTPU handover tunnel

This commit is contained in:
Francisco 2021-03-18 18:23:32 +00:00 committed by Francisco Paisana
parent dde8157bf1
commit 977c194cbc
5 changed files with 95 additions and 37 deletions

View File

@ -42,7 +42,11 @@ public:
srslte::task_queue_handle make_task_queue(uint32_t qsize) { return external_tasks.get_queue_handler(qsize); }
//! Delays a task processing by duration_ms
void defer_callback(uint32_t duration_ms, std::function<void()> func) { timers.defer_callback(duration_ms, func); }
template <typename F>
void defer_callback(uint32_t duration_ms, F&& func)
{
timers.defer_callback(duration_ms, std::forward<F>(func));
}
//! Enqueues internal task to be run in next tic
void defer_task(srslte::move_task_t func) { internal_tasks.push_back(std::move(func)); }
@ -114,9 +118,10 @@ public:
{
sched->notify_background_task_result(std::move(task));
}
void defer_callback(uint32_t duration_ms, std::function<void()> func)
template <typename F>
void defer_callback(uint32_t duration_ms, F&& func)
{
sched->defer_callback(duration_ms, std::move(func));
sched->defer_callback(duration_ms, std::forward<F>(func));
}
void defer_task(srslte::move_task_t func) { sched->defer_task(std::move(func)); }
@ -136,9 +141,10 @@ public:
sched->notify_background_task_result(std::move(task));
}
srslte::task_queue_handle make_task_queue() { return sched->make_task_queue(); }
void defer_callback(uint32_t duration_ms, std::function<void()> func)
template <typename F>
void defer_callback(uint32_t duration_ms, F&& func)
{
sched->defer_callback(duration_ms, std::move(func));
sched->defer_callback(duration_ms, std::forward<F>(func));
}
private:

View File

@ -16,6 +16,7 @@
#include "common_enb.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/enb_gtpu_interfaces.h"
#include "srslte/phy/common/phy_common.h"
@ -34,7 +35,7 @@ class stack_interface_gtpu_lte;
class gtpu final : public gtpu_interface_rrc, public gtpu_interface_pdcp
{
public:
explicit gtpu(srslog::basic_logger& logger);
explicit gtpu(srslte::task_sched_handle task_sched_, srslog::basic_logger& logger);
int init(std::string gtp_bind_addr_,
std::string mme_addr_,
@ -75,6 +76,7 @@ private:
std::string mme_addr;
srsenb::pdcp_interface_gtpu* pdcp = nullptr;
srslog::basic_logger& logger;
srslte::task_sched_handle task_sched;
// Class to create
class m1u_handler
@ -104,16 +106,17 @@ private:
const uint32_t undefined_pdcp_sn = std::numeric_limits<uint32_t>::max();
struct tunnel {
bool dl_enabled = true;
bool fwd_teid_in_present = false;
bool prior_teid_in_present = false;
uint16_t rnti = SRSLTE_INVALID_RNTI;
uint32_t lcid = SRSENB_N_RADIO_BEARERS;
uint32_t teid_in = 0;
uint32_t teid_out = 0;
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
bool dl_enabled = true;
bool fwd_teid_in_present = false;
bool prior_teid_in_present = false;
uint16_t rnti = SRSLTE_INVALID_RNTI;
uint32_t lcid = SRSENB_N_RADIO_BEARERS;
uint32_t teid_in = 0;
uint32_t teid_out = 0;
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
srslte::unique_timer rx_timer;
std::multimap<uint32_t, srslte::unique_byte_buffer_t> buffer;
};
std::unordered_map<uint32_t, tunnel> tunnels;
@ -129,7 +132,7 @@ private:
void echo_response(in_addr_t addr, in_port_t port, uint16_t seq);
void error_indication(in_addr_t addr, in_port_t port, uint32_t err_teid);
void end_marker(uint32_t teidin);
bool end_marker(uint32_t teidin);
int create_dl_fwd_tunnel(uint32_t rx_teid_in, uint32_t tx_teid_in);

View File

@ -33,7 +33,7 @@ enb_stack_lte::enb_stack_lte(srslog::sink& log_sink) :
pdcp(&task_sched, pdcp_logger),
mac(&task_sched, mac_logger),
rlc(rlc_logger),
gtpu(gtpu_logger),
gtpu(&task_sched, gtpu_logger),
s1ap(&task_sched, s1ap_logger),
rrc(&task_sched),
mac_pcap(),

View File

@ -9,6 +9,7 @@
* the distribution.
*
*/
#include "srslte/upper/gtpu.h"
#include "srsenb/hdr/stack/upper/gtpu.h"
#include "srslte/common/network_utils.h"
@ -26,7 +27,9 @@
using namespace srslte;
namespace srsenb {
gtpu::gtpu(srslog::basic_logger& logger) : m1u(this), logger(logger) {}
gtpu::gtpu(srslte::task_sched_handle task_sched_, srslog::basic_logger& logger) :
m1u(this), task_sched(task_sched_), logger(logger)
{}
int gtpu::init(std::string gtp_bind_addr_,
std::string mme_addr_,
@ -174,6 +177,26 @@ uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t
after_tun.dl_enabled = false;
after_tun.prior_teid_in_present = true;
after_tun.prior_teid_in = teid_in;
// Schedule autoremoval of this indirect tunnel
uint32_t after_teidin = after_tun.teid_in;
uint32_t before_teidin = new_tun.teid_in;
new_tun.rx_timer = task_sched.get_unique_timer();
new_tun.rx_timer.set(500, [this, before_teidin, after_teidin](uint32_t tid) {
auto it = tunnels.find(after_teidin);
if (it != tunnels.end()) {
tunnel& after_tun = it->second;
if (after_tun.prior_teid_in_present) {
after_tun.prior_teid_in_present = false;
set_tunnel_status(after_tun.teid_in, true);
}
// else: indirect tunnel already removed
} else {
logger.info("Callback to automatic indirect tunnel deletion called for non-existent TEID=%d", after_teidin);
}
// This will self-destruct the callback object
rem_tunnel(before_teidin);
});
new_tun.rx_timer.run();
}
// Connect tunnels if forwarding is activated
@ -301,11 +324,20 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
return;
}
if (header.teid != 0 && tunnels.count(header.teid) == 0) {
// Received G-PDU for non-existing and non-zero TEID.
// Sending GTP-U error indication
error_indication(addr.sin_addr.s_addr, addr.sin_port, header.teid);
return;
tunnel* rx_tunnel = nullptr;
if (header.teid != 0) {
auto it = tunnels.find(header.teid);
if (it == tunnels.end()) {
// Received G-PDU for non-existing and non-zero TEID.
// Sending GTP-U error indication
error_indication(addr.sin_addr.s_addr, addr.sin_port, header.teid);
}
rx_tunnel = &it->second;
if (rx_tunnel->rx_timer.is_valid()) {
// Restart Rx timer
rx_tunnel->rx_timer.run();
}
}
switch (header.message_type) {
@ -345,22 +377,27 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
}
} break;
case GTPU_MSG_END_MARKER: {
tunnel& old_tun = tunnels.find(header.teid)->second;
uint16_t rnti = old_tun.rnti;
uint16_t rnti = rx_tunnel->rnti;
logger.info("Received GTPU End Marker for rnti=0x%x.", rnti);
// TS 36.300, Sec 10.1.2.2.1 - Path Switch upon handover
if (old_tun.fwd_teid_in_present) {
if (rx_tunnel->fwd_teid_in_present) {
// END MARKER should be forwarded to TeNB if forwarding is activated
end_marker(old_tun.fwd_teid_in);
old_tun.fwd_teid_in_present = false;
end_marker(rx_tunnel->fwd_teid_in);
rx_tunnel->fwd_teid_in_present = false;
} else {
// TeNB switches paths, and flush PDUs that have been buffered
std::vector<uint32_t>& bearer_tunnels = ue_teidin_db.find(old_tun.rnti)->second[old_tun.lcid];
auto rnti_it = ue_teidin_db.find(rnti);
if (rnti_it == ue_teidin_db.end()) {
logger.error("No rnti=0x%x entry for associated TEID=%d", rnti, header.teid);
return;
}
std::vector<uint32_t>& bearer_tunnels = rnti_it->second[rx_tunnel->lcid];
for (uint32_t new_teidin : bearer_tunnels) {
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) {
if (new_teidin != 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;
set_tunnel_status(new_tun.teid_in, true);
}
@ -369,6 +406,7 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
break;
}
default:
logger.warning("Unhandled GTPU message type=%d", header.message_type);
break;
}
}
@ -471,13 +509,22 @@ void gtpu::echo_response(in_addr_t addr, in_port_t port, uint16_t seq)
/****************************************************************************
* GTP-U END MARKER
***************************************************************************/
void gtpu::end_marker(uint32_t teidin)
bool gtpu::end_marker(uint32_t teidin)
{
logger.info("TX GTPU End Marker.");
tunnel& tunnel = tunnels.find(teidin)->second;
auto it = tunnels.find(teidin);
if (it == tunnels.end()) {
logger.error("TEID=%d not found to send the end marker to", teidin);
return false;
}
tunnel& tunnel = it->second;
gtpu_header_t header = {};
unique_byte_buffer_t pdu = make_byte_buffer();
if (pdu == nullptr) {
logger.warning("Failed to allocate buffer to send End Marker to TEID=%d", teidin);
return false;
}
// header
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
@ -493,6 +540,7 @@ void gtpu::end_marker(uint32_t teidin)
servaddr.sin_port = htons(GTPU_PORT);
sendto(fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in));
return true;
}
/****************************************************************************

View File

@ -148,9 +148,10 @@ int test_gtpu_direct_tunneling()
logger1.set_hex_dump_max_size(2048);
srslog::basic_logger& logger2 = srslog::fetch_basic_logger("GTPU2");
logger2.set_hex_dump_max_size(2048);
srsenb::gtpu senb_gtpu(logger1), tenb_gtpu(logger2);
stack_tester senb_stack, tenb_stack;
pdcp_tester senb_pdcp, tenb_pdcp;
srslte::task_scheduler task_sched;
srsenb::gtpu senb_gtpu(&task_sched, logger1), tenb_gtpu(&task_sched, logger2);
stack_tester senb_stack, tenb_stack;
pdcp_tester senb_pdcp, tenb_pdcp;
senb_gtpu.init(senb_addr_str, sgw_addr_str, "", "", &senb_pdcp, &senb_stack, false);
tenb_gtpu.init(tenb_addr_str, sgw_addr_str, "", "", &tenb_pdcp, &tenb_stack, false);