mirror of https://github.com/PentHertz/srsLTE.git
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:
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); }
|
||||
|
||||
//! 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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue