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

master
Francisco 4 years ago committed by Francisco Paisana
parent dde8157bf1
commit 977c194cbc

@ -42,7 +42,11 @@ public:
srslte::task_queue_handle make_task_queue(uint32_t qsize) { return external_tasks.get_queue_handler(qsize); } srslte::task_queue_handle make_task_queue(uint32_t qsize) { return external_tasks.get_queue_handler(qsize); }
//! Delays a task processing by duration_ms //! 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 //! Enqueues internal task to be run in next tic
void defer_task(srslte::move_task_t func) { internal_tasks.push_back(std::move(func)); } 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)); 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)); } 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)); sched->notify_background_task_result(std::move(task));
} }
srslte::task_queue_handle make_task_queue() { return sched->make_task_queue(); } 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: private:

@ -16,6 +16,7 @@
#include "common_enb.h" #include "common_enb.h"
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/task_scheduler.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/interfaces/enb_gtpu_interfaces.h" #include "srslte/interfaces/enb_gtpu_interfaces.h"
#include "srslte/phy/common/phy_common.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 class gtpu final : public gtpu_interface_rrc, public gtpu_interface_pdcp
{ {
public: 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_, int init(std::string gtp_bind_addr_,
std::string mme_addr_, std::string mme_addr_,
@ -75,6 +76,7 @@ private:
std::string mme_addr; std::string mme_addr;
srsenb::pdcp_interface_gtpu* pdcp = nullptr; srsenb::pdcp_interface_gtpu* pdcp = nullptr;
srslog::basic_logger& logger; srslog::basic_logger& logger;
srslte::task_sched_handle task_sched;
// Class to create // Class to create
class m1u_handler class m1u_handler
@ -104,16 +106,17 @@ private:
const uint32_t undefined_pdcp_sn = std::numeric_limits<uint32_t>::max(); const uint32_t undefined_pdcp_sn = std::numeric_limits<uint32_t>::max();
struct tunnel { struct tunnel {
bool dl_enabled = true; bool dl_enabled = true;
bool fwd_teid_in_present = false; bool fwd_teid_in_present = false;
bool prior_teid_in_present = false; bool prior_teid_in_present = false;
uint16_t rnti = SRSLTE_INVALID_RNTI; uint16_t rnti = SRSLTE_INVALID_RNTI;
uint32_t lcid = SRSENB_N_RADIO_BEARERS; uint32_t lcid = SRSENB_N_RADIO_BEARERS;
uint32_t teid_in = 0; uint32_t teid_in = 0;
uint32_t teid_out = 0; uint32_t teid_out = 0;
uint32_t spgw_addr = 0; uint32_t spgw_addr = 0;
uint32_t fwd_teid_in = 0; ///< forward Rx SDUs to this TEID 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 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::multimap<uint32_t, srslte::unique_byte_buffer_t> buffer;
}; };
std::unordered_map<uint32_t, tunnel> tunnels; 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 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 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); int create_dl_fwd_tunnel(uint32_t rx_teid_in, uint32_t tx_teid_in);

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

@ -9,6 +9,7 @@
* the distribution. * the distribution.
* *
*/ */
#include "srslte/upper/gtpu.h" #include "srslte/upper/gtpu.h"
#include "srsenb/hdr/stack/upper/gtpu.h" #include "srsenb/hdr/stack/upper/gtpu.h"
#include "srslte/common/network_utils.h" #include "srslte/common/network_utils.h"
@ -26,7 +27,9 @@
using namespace srslte; using namespace srslte;
namespace srsenb { 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_, int gtpu::init(std::string gtp_bind_addr_,
std::string mme_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.dl_enabled = false;
after_tun.prior_teid_in_present = true; after_tun.prior_teid_in_present = true;
after_tun.prior_teid_in = teid_in; 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 // 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; return;
} }
if (header.teid != 0 && tunnels.count(header.teid) == 0) { tunnel* rx_tunnel = nullptr;
// Received G-PDU for non-existing and non-zero TEID. if (header.teid != 0) {
// Sending GTP-U error indication auto it = tunnels.find(header.teid);
error_indication(addr.sin_addr.s_addr, addr.sin_port, header.teid); if (it == tunnels.end()) {
return; // 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) { switch (header.message_type) {
@ -345,22 +377,27 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
} }
} break; } break;
case GTPU_MSG_END_MARKER: { case GTPU_MSG_END_MARKER: {
tunnel& old_tun = tunnels.find(header.teid)->second; uint16_t rnti = rx_tunnel->rnti;
uint16_t rnti = old_tun.rnti;
logger.info("Received GTPU End Marker for rnti=0x%x.", 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 // 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 should be forwarded to TeNB if forwarding is activated
end_marker(old_tun.fwd_teid_in); end_marker(rx_tunnel->fwd_teid_in);
old_tun.fwd_teid_in_present = false; rx_tunnel->fwd_teid_in_present = false;
} else { } else {
// TeNB switches paths, and flush PDUs that have been buffered // 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) { for (uint32_t new_teidin : bearer_tunnels) {
tunnel& new_tun = tunnels.at(new_teidin); tunnel& new_tun = tunnels.at(new_teidin);
if (new_teidin != old_tun.teid_in and new_tun.prior_teid_in_present and if (new_teidin != rx_tunnel->teid_in and new_tun.prior_teid_in_present and
new_tun.prior_teid_in == old_tun.teid_in) { new_tun.prior_teid_in == rx_tunnel->teid_in) {
rem_tunnel(new_tun.prior_teid_in);
new_tun.prior_teid_in_present = false; new_tun.prior_teid_in_present = false;
set_tunnel_status(new_tun.teid_in, true); 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; break;
} }
default: default:
logger.warning("Unhandled GTPU message type=%d", header.message_type);
break; break;
} }
} }
@ -471,13 +509,22 @@ void gtpu::echo_response(in_addr_t addr, in_port_t port, uint16_t seq)
/**************************************************************************** /****************************************************************************
* GTP-U END MARKER * GTP-U END MARKER
***************************************************************************/ ***************************************************************************/
void gtpu::end_marker(uint32_t teidin) bool gtpu::end_marker(uint32_t teidin)
{ {
logger.info("TX GTPU End Marker."); 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 = {}; gtpu_header_t header = {};
unique_byte_buffer_t pdu = make_byte_buffer(); 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
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL; 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); servaddr.sin_port = htons(GTPU_PORT);
sendto(fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); sendto(fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in));
return true;
} }
/**************************************************************************** /****************************************************************************

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

Loading…
Cancel
Save