diff --git a/lib/include/srslte/common/task_scheduler.h b/lib/include/srslte/common/task_scheduler.h index ed564f8f7..6036c60af 100644 --- a/lib/include/srslte/common/task_scheduler.h +++ b/lib/include/srslte/common/task_scheduler.h @@ -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 func) { timers.defer_callback(duration_ms, func); } + template + void defer_callback(uint32_t duration_ms, F&& func) + { + timers.defer_callback(duration_ms, std::forward(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 func) + template + void defer_callback(uint32_t duration_ms, F&& func) { - sched->defer_callback(duration_ms, std::move(func)); + sched->defer_callback(duration_ms, std::forward(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 func) + template + void defer_callback(uint32_t duration_ms, F&& func) { - sched->defer_callback(duration_ms, std::move(func)); + sched->defer_callback(duration_ms, std::forward(func)); } private: diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index d22875ea5..aade71e50 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -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::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 buffer; }; std::unordered_map 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); diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 5054ac028..67dce11a6 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -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(), diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index f4027bb10..a739f8b59 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -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& 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& 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; } /**************************************************************************** diff --git a/srsenb/test/upper/gtpu_test.cc b/srsenb/test/upper/gtpu_test.cc index 15abb173f..37ecb7ba4 100644 --- a/srsenb/test/upper/gtpu_test.cc +++ b/srsenb/test/upper/gtpu_test.cc @@ -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);