From 13649e4e19c2831b94abeef9cd9175f57d022c41 Mon Sep 17 00:00:00 2001 From: Francisco Date: Thu, 28 Jan 2021 17:22:19 +0000 Subject: [PATCH] Implement new GTPU functionality: - multiple tunnels per E-RAB - data forwarding between connected GTPU tunnels - forwarding GTPU End Marker between connected tunnels - TeNB GTPU handles in-sequence delivery when multiple tunnels for the same ERAB exist. --- .../srslte/interfaces/enb_interfaces.h | 45 ++- lib/include/srslte/upper/gtpu.h | 19 +- lib/include/srslte/upper/pdcp.h | 3 + lib/include/srslte/upper/pdcp_entity_base.h | 2 + lib/include/srslte/upper/pdcp_entity_lte.h | 2 + lib/include/srslte/upper/pdcp_entity_nr.h | 2 + lib/src/upper/gtpu.cc | 15 +- lib/src/upper/pdcp.cc | 8 + lib/src/upper/pdcp_entity_lte.cc | 5 + srsenb/hdr/stack/upper/gtpu.h | 53 +-- srsenb/hdr/stack/upper/pdcp.h | 5 +- srsenb/src/stack/upper/gtpu.cc | 336 +++++++++++------- srsenb/src/stack/upper/pdcp.cc | 15 +- srsenb/test/common/dummy_classes.h | 14 +- srsenb/test/upper/test_helpers.h | 2 +- 15 files changed, 334 insertions(+), 192 deletions(-) diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 8437b5059..9c92b30db 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -360,25 +360,26 @@ public: class pdcp_interface_gtpu { public: - virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; + virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn = -1) = 0; + virtual std::map get_buffered_pdus(uint16_t rnti, uint32_t lcid) = 0; }; // PDCP interface for RRC class pdcp_interface_rrc { public: - virtual void reset(uint16_t rnti) = 0; - virtual void add_user(uint16_t rnti) = 0; - virtual void rem_user(uint16_t rnti) = 0; - virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; - virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) = 0; - virtual void del_bearer(uint16_t rnti, uint32_t lcid) = 0; - virtual void config_security(uint16_t rnti, uint32_t lcid, srslte::as_security_config_t sec_cfg) = 0; - virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0; - virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0; - virtual bool get_bearer_state(uint16_t rnti, uint32_t lcid, srslte::pdcp_lte_state_t* state) = 0; - virtual bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srslte::pdcp_lte_state_t& state) = 0; - virtual void reestablish(uint16_t rnti) = 0; + virtual void reset(uint16_t rnti) = 0; + virtual void add_user(uint16_t rnti) = 0; + virtual void rem_user(uint16_t rnti) = 0; + virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn = -1) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) = 0; + virtual void del_bearer(uint16_t rnti, uint32_t lcid) = 0; + virtual void config_security(uint16_t rnti, uint32_t lcid, srslte::as_security_config_t sec_cfg) = 0; + virtual void enable_integrity(uint16_t rnti, uint32_t lcid) = 0; + virtual void enable_encryption(uint16_t rnti, uint32_t lcid) = 0; + virtual bool get_bearer_state(uint16_t rnti, uint32_t lcid, srslte::pdcp_lte_state_t* state) = 0; + virtual bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srslte::pdcp_lte_state_t& state) = 0; + virtual void reestablish(uint16_t rnti) = 0; }; // PDCP interface for RLC @@ -465,10 +466,16 @@ public: class gtpu_interface_rrc { public: - virtual uint32_t add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) = 0; - virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; - virtual void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) = 0; - virtual void rem_user(uint16_t rnti) = 0; + struct bearer_props { + uint32_t dl_forward_from_teidin = 0; + uint32_t buffer_until_teidin_flush = 0; + }; + + virtual uint32_t + add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, const bearer_props* props = nullptr) = 0; + virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; + virtual void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) = 0; + virtual void rem_user(uint16_t rnti) = 0; }; // S1AP interface for RRC @@ -482,12 +489,12 @@ public: }; virtual void - initial_ue(uint16_t rnti, asn1::s1ap::rrc_establishment_cause_e cause, srslte::unique_byte_buffer_t pdu) = 0; + initial_ue(uint16_t rnti, asn1::s1ap::rrc_establishment_cause_e cause, srslte::unique_byte_buffer_t pdu) = 0; virtual void initial_ue(uint16_t rnti, asn1::s1ap::rrc_establishment_cause_e cause, srslte::unique_byte_buffer_t pdu, uint32_t m_tmsi, - uint8_t mmec) = 0; + uint8_t mmec) = 0; virtual void write_pdu(uint16_t rnti, srslte::unique_byte_buffer_t pdu) = 0; virtual bool user_exists(uint16_t rnti) = 0; diff --git a/lib/include/srslte/upper/gtpu.h b/lib/include/srslte/upper/gtpu.h index c283da44a..39449154b 100644 --- a/lib/include/srslte/upper/gtpu.h +++ b/lib/include/srslte/upper/gtpu.h @@ -57,15 +57,16 @@ namespace srslte { #define GTPU_MSG_END_MARKER 254 #define GTPU_MSG_DATA_PDU 255 -typedef struct { - uint8_t flags; - uint8_t message_type; - uint16_t length; - uint32_t teid; - uint16_t seq_number; - uint8_t n_pdu; - uint8_t next_ext_hdr_type; -} gtpu_header_t; +struct gtpu_header_t { + uint8_t flags = 0; + uint8_t message_type = 0; + uint16_t length = 0; + uint32_t teid = 0; + uint16_t seq_number = 0; + uint8_t n_pdu = 0; + uint8_t next_ext_hdr_type = 0; + std::vector ext_buffer; +}; bool gtpu_read_header(srslte::byte_buffer_t* pdu, gtpu_header_t* header, srslte::log_ref gtpu_log); bool gtpu_write_header(gtpu_header_t* header, srslte::byte_buffer_t* pdu, srslte::log_ref gtpu_log); diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index ab7b1e052..d4002f274 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -57,6 +57,9 @@ public: void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) override; void write_pdu_pcch(unique_byte_buffer_t sdu) override; + // eNB-only methods + std::map get_buffered_pdus(uint32_t lcid); + private: srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr; diff --git a/lib/include/srslte/upper/pdcp_entity_base.h b/lib/include/srslte/upper/pdcp_entity_base.h index a07b21630..312b1cef6 100644 --- a/lib/include/srslte/upper/pdcp_entity_base.h +++ b/lib/include/srslte/upper/pdcp_entity_base.h @@ -115,6 +115,8 @@ public: virtual void get_bearer_state(pdcp_lte_state_t* state) = 0; virtual void set_bearer_state(const pdcp_lte_state_t& state) = 0; + virtual std::map get_buffered_pdus() = 0; + // COUNT, HFN and SN helpers uint32_t HFN(uint32_t count); uint32_t SN(uint32_t count); diff --git a/lib/include/srslte/upper/pdcp_entity_lte.h b/lib/include/srslte/upper/pdcp_entity_lte.h index c634dae1e..44dfec476 100644 --- a/lib/include/srslte/upper/pdcp_entity_lte.h +++ b/lib/include/srslte/upper/pdcp_entity_lte.h @@ -60,6 +60,8 @@ public: void get_bearer_state(pdcp_lte_state_t* state) override; void set_bearer_state(const pdcp_lte_state_t& state) override; + std::map get_buffered_pdus() override; + private: srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr; diff --git a/lib/include/srslte/upper/pdcp_entity_nr.h b/lib/include/srslte/upper/pdcp_entity_nr.h index 70457c1d5..bfe090487 100644 --- a/lib/include/srslte/upper/pdcp_entity_nr.h +++ b/lib/include/srslte/upper/pdcp_entity_nr.h @@ -59,6 +59,8 @@ public: void get_bearer_state(pdcp_lte_state_t* state) override; void set_bearer_state(const pdcp_lte_state_t& state) override; + std::map get_buffered_pdus() override { return {}; } + // State variable getters (useful for testing) uint32_t nof_discard_timers() { return discard_timers_map.size(); } diff --git a/lib/src/upper/gtpu.cc b/lib/src/upper/gtpu.cc index ba687a386..c0a309ed6 100644 --- a/lib/src/upper/gtpu.cc +++ b/lib/src/upper/gtpu.cc @@ -81,10 +81,15 @@ bool gtpu_write_header(gtpu_header_t* header, srslte::byte_buffer_t* pdu, srslte // E if (header->flags & GTPU_FLAGS_EXTENDED_HDR) { *ptr = header->next_ext_hdr_type; + ptr++; + for (size_t i = 0; i < header->ext_buffer.size(); ++i) { + *ptr = header->ext_buffer[i]; + ptr++; + } } else { *ptr = 0; + ptr++; } - ptr++; } return true; } @@ -126,6 +131,14 @@ bool gtpu_read_header(srslte::byte_buffer_t* pdu, gtpu_header_t* header, srslte: header->next_ext_hdr_type = *ptr; ptr++; + + if ((header->flags & GTPU_FLAGS_EXTENDED_HDR) && (header->next_ext_hdr_type == 0b11000000)) { + header->ext_buffer.resize(4); + for (size_t i = 0; i < 4; ++i) { + header->ext_buffer[i] = *ptr; + ptr++; + } + } } else { pdu->msg += GTPU_BASE_HEADER_LEN; pdu->N_bytes -= GTPU_BASE_HEADER_LEN; diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index d12f83f4d..06d3282a9 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -238,6 +238,14 @@ bool pdcp::set_bearer_state(uint32_t lcid, const srslte::pdcp_lte_state_t& state return true; } +std::map pdcp::get_buffered_pdus(uint32_t lcid) +{ + if (not valid_lcid(lcid)) { + return {}; + } + return pdcp_array[lcid]->get_buffered_pdus(); +} + /******************************************************************************* RLC interface *******************************************************************************/ diff --git a/lib/src/upper/pdcp_entity_lte.cc b/lib/src/upper/pdcp_entity_lte.cc index 06bdf003f..f7a8a9b04 100644 --- a/lib/src/upper/pdcp_entity_lte.cc +++ b/lib/src/upper/pdcp_entity_lte.cc @@ -371,4 +371,9 @@ void pdcp_entity_lte::set_bearer_state(const pdcp_lte_state_t& state) st = state; } +std::map pdcp_entity_lte::get_buffered_pdus() +{ + return {}; +} + } // namespace srslte diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index 9240d17db..3ac8e4692 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -41,10 +41,11 @@ public: void stop(); // gtpu_interface_rrc - uint32_t add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) override; - void rem_bearer(uint16_t rnti, uint32_t lcid) override; - void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) override; - void rem_user(uint16_t rnti) override; + uint32_t + add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, const bearer_props* props) override; + void rem_bearer(uint16_t rnti, uint32_t lcid) override; + void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) override; + void rem_user(uint16_t rnti) override; // gtpu_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) override; @@ -56,6 +57,14 @@ public: private: static const int GTPU_PORT = 2152; + void rem_tunnel(uint32_t teidin); + void send_pdu_to_tunnel(uint16_t rnti, + uint32_t lcid, + srslte::unique_byte_buffer_t pdu, + uint32_t teidout, + uint32_t spgw_addr, + int pdcp_sn = -1); + srslte::byte_buffer_pool* pool = nullptr; stack_interface_gtpu_lte* stack = nullptr; @@ -93,18 +102,18 @@ private: }; m1u_handler m1u; - typedef struct { - uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; - uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; - uint32_t spgw_addrs[SRSENB_N_RADIO_BEARERS]; - } bearer_map; - std::map rnti_bearers; - - typedef struct { - uint16_t rnti; - uint16_t lcid; - } rnti_lcid_t; - std::map teidin_to_rntilcid_map; + struct tunnel { + 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 + std::vector buffer; + }; + std::unordered_map tunnels; + std::map, SRSENB_N_RADIO_BEARERS> > ue_teidin_db; // Tx sequence number for signaling messages uint32_t tx_seq = 0; @@ -114,16 +123,16 @@ 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); + + int create_dl_fwd_tunnel(uint32_t rx_teid_in, uint32_t tx_teid_in); /**************************************************************************** * TEID to RNIT/LCID helper functions ***************************************************************************/ - uint32_t next_teid_in = 0; - uint32_t allocate_teidin(uint16_t rnti, uint16_t lcid); - void free_teidin(uint16_t rnti, uint16_t lcid); - void free_teidin(uint16_t rnti); - rnti_lcid_t teidin_to_rntilcid(uint32_t teidin); - uint32_t rntilcid_to_teidin(uint16_t rnti, uint16_t lcid); + uint32_t next_teid_in = 0; + + tunnel* get_tunnel(uint32_t teidin); }; } // namespace srsenb diff --git a/srsenb/hdr/stack/upper/pdcp.h b/srsenb/hdr/stack/upper/pdcp.h index 735b03ca8..7cbf85f45 100644 --- a/srsenb/hdr/stack/upper/pdcp.h +++ b/srsenb/hdr/stack/upper/pdcp.h @@ -38,7 +38,7 @@ public: void reset(uint16_t rnti) override; void add_user(uint16_t rnti) override; void rem_user(uint16_t rnti) override; - void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override; + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn = -1) override; void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) override; void del_bearer(uint16_t rnti, uint32_t lcid) override; void config_security(uint16_t rnti, uint32_t lcid, srslte::as_security_config_t cfg_sec) override; @@ -48,6 +48,9 @@ public: bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srslte::pdcp_lte_state_t& state) override; void reestablish(uint16_t rnti) override; + // pdcp_interface_gtpu + std::map get_buffered_pdus(uint16_t rnti, uint32_t lcid) override; + private: class user_interface_rlc : public srsue::rlc_interface_pdcp { diff --git a/srsenb/src/stack/upper/gtpu.cc b/srsenb/src/stack/upper/gtpu.cc index e43003cf2..a6e44e2cc 100644 --- a/srsenb/src/stack/upper/gtpu.cc +++ b/srsenb/src/stack/upper/gtpu.cc @@ -13,7 +13,6 @@ #include "srsenb/hdr/stack/upper/gtpu.h" #include "srslte/common/network_utils.h" #include -#include #include #include #include @@ -90,6 +89,19 @@ void gtpu::stop() // gtpu_interface_pdcp void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t pdu) +{ + send_pdu_to_tunnel(rnti, + lcid, + std::move(pdu), + tunnels[ue_teidin_db[rnti][lcid][0]].teid_out, + tunnels[ue_teidin_db[rnti][lcid][0]].spgw_addr); +} +void gtpu::send_pdu_to_tunnel(uint16_t rnti, + uint32_t lcid, + srslte::unique_byte_buffer_t pdu, + uint32_t teidout, + uint32_t spgw_addr, + int pdcp_sn) { logger.info(pdu->msg, pdu->N_bytes, "TX PDU, RNTI: 0x%x, LCID: %d, n_bytes=%d", rnti, lcid, pdu->N_bytes); @@ -112,11 +124,21 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL; header.message_type = GTPU_MSG_DATA_PDU; header.length = pdu->N_bytes; - header.teid = rnti_bearers[rnti].teids_out[lcid]; + header.teid = teidout; + + if (pdcp_sn >= 0) { + header.flags |= GTPU_FLAGS_EXTENDED_HDR; + header.next_ext_hdr_type = 0b11000000; + header.ext_buffer.resize(4u); + header.ext_buffer[0] = 0x01u; + header.ext_buffer[1] = (pdcp_sn >> 8u) & 0xffu; + header.ext_buffer[2] = pdcp_sn & 0xffu; + header.ext_buffer[3] = 0; + } struct sockaddr_in servaddr; servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]); + servaddr.sin_addr.s_addr = htonl(spgw_addr); servaddr.sin_port = htons(GTPU_PORT); if (!gtpu_write_header(&header, pdu.get(), gtpu_log)) { @@ -128,12 +150,31 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t } } -/* Warning: This function is called before calling gtpu::init() during MCCH initialization. - */ -uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) +uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, const bearer_props* props) { // Allocate a TEID for the incoming tunnel - uint32_t teid_in = allocate_teidin(rnti, lcid); + uint32_t teid_in = ++next_teid_in; + tunnel& tunnel = tunnels[teid_in]; + tunnel.teid_in = teid_in; + tunnel.rnti = rnti; + tunnel.lcid = lcid; + tunnel.spgw_addr = addr; + tunnel.teid_out = teid_out; + + ue_teidin_db[rnti][lcid].push_back(teid_in); + + if (props != nullptr) { + tunnel.prior_teid_in = props->buffer_until_teidin_flush; + + // Connect tunnels if forwarding is activated + if (props->dl_forward_from_teidin > 0) { + if (create_dl_fwd_tunnel(props->dl_forward_from_teidin, teid_in) != SRSLTE_SUCCESS) { + rem_tunnel(teid_in); + return 0; + } + } + } + logger.info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x", rnti, lcid, @@ -141,42 +182,27 @@ uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, teid_in); - // Initialize maps if it's a new RNTI - if (rnti_bearers.count(rnti) == 0) { - for (int i = 0; i < SRSENB_N_RADIO_BEARERS; i++) { - rnti_bearers[rnti].teids_in[i] = 0; - rnti_bearers[rnti].teids_out[i] = 0; - rnti_bearers[rnti].spgw_addrs[i] = 0; - } - } - - rnti_bearers[rnti].teids_in[lcid] = teid_in; - rnti_bearers[rnti].teids_out[lcid] = teid_out; - rnti_bearers[rnti].spgw_addrs[lcid] = addr; - return teid_in; } void gtpu::rem_bearer(uint16_t rnti, uint32_t lcid) { + auto ue_it = ue_teidin_db.find(rnti); + if (ue_it == ue_teidin_db.end()) { + logger.warning("Removing bearer rnti=0x%x, lcid=%d", rnti, lcid); + return; + } + std::vector& lcid_tuns = ue_it->second[lcid]; + + while (not lcid_tuns.empty()) { + rem_tunnel(lcid_tuns.back()); + } logger.info("Removing bearer for rnti: 0x%x, lcid: %d", rnti, lcid); - // Remove from TEID from map - free_teidin(rnti, lcid); - - // Remove - rnti_bearers[rnti].teids_in[lcid] = 0; - rnti_bearers[rnti].teids_out[lcid] = 0; - - // Remove RNTI if all bearers are removed - bool rem = true; - for (int i = 0; i < SRSENB_N_RADIO_BEARERS; i++) { - if (rnti_bearers[rnti].teids_in[i] != 0) { - rem = false; - } - } - if (rem) { - rnti_bearers.erase(rnti); + bool rem_ue = std::all_of( + ue_it->second.begin(), ue_it->second.end(), [](const std::vector& list) { return list.empty(); }); + if (rem_ue) { + ue_teidin_db.erase(ue_it); } } @@ -184,40 +210,59 @@ void gtpu::mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) { logger.info("Modifying bearer rnti. Old rnti: 0x%x, new rnti: 0x%x", old_rnti, new_rnti); - if (rnti_bearers.count(new_rnti) != 0) { - logger.error("New rnti already exists, aborting."); + if (ue_teidin_db.count(new_rnti) != 0) { + gtpu_log->error("New rnti already exists, aborting.\n"); return; } - if (rnti_bearers.count(old_rnti) == 0) { - logger.error("Old rnti does not exist, aborting."); + auto old_it = ue_teidin_db.find(old_rnti); + if (old_it == ue_teidin_db.end()) { + gtpu_log->error("Old rnti does not exist, aborting.\n"); return; } // Change RNTI bearers map - auto entry = rnti_bearers.find(old_rnti); - if (entry != rnti_bearers.end()) { - auto const value = std::move(entry->second); - rnti_bearers.erase(entry); - rnti_bearers.insert({new_rnti, std::move(value)}); - } + ue_teidin_db.insert(std::make_pair(new_rnti, std::move(old_it->second))); + ue_teidin_db.erase(old_it); // Change TEID - for (std::map::iterator it = teidin_to_rntilcid_map.begin(); - it != teidin_to_rntilcid_map.end(); - it++) { - if (it->second.rnti == old_rnti) { - it->second.rnti = new_rnti; + auto new_it = ue_teidin_db.find(new_rnti); + for (auto& bearer : new_it->second) { + for (uint32_t teid : bearer) { + tunnels[teid].rnti = new_rnti; } } } +void gtpu::rem_tunnel(uint32_t teidin) +{ + auto it = tunnels.find(teidin); + if (it == tunnels.end()) { + logger.warning("Removing GTPU tunnel TEID In=0x%x", teidin); + return; + } + if (it->second.fwd_teid_in > 0) { + // Forward End Marker to forwarding tunnel, before deleting tunnel + end_marker(it->second.fwd_teid_in); + it->second.fwd_teid_in = 0; + } + auto ue_it = ue_teidin_db.find(it->second.rnti); + std::vector& lcid_tunnels = ue_it->second[it->second.lcid]; + lcid_tunnels.erase(std::remove(lcid_tunnels.begin(), lcid_tunnels.end(), teidin), lcid_tunnels.end()); + tunnels.erase(it); + logger.debug("TEID In=%d erased", teidin); +} + void gtpu::rem_user(uint16_t rnti) { - // Free from TEID map - free_teidin(rnti); - - // Remove user from RNTI map - rnti_bearers.erase(rnti); + logger.info("Removing rnti=0x%x", rnti); + auto ue_it = ue_teidin_db.find(rnti); + if (ue_it != ue_teidin_db.end()) { + for (auto& bearer : ue_it->second) { + while (not bearer.empty()) { + rem_tunnel(bearer.back()); + } + } + } } void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const sockaddr_in& addr) @@ -230,7 +275,7 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc return; } - if (header.teid != 0 && teidin_to_rntilcid_map.count(header.teid) == 0) { + 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); @@ -243,24 +288,15 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc echo_response(addr.sin_addr.s_addr, addr.sin_port, header.seq_number); break; case GTPU_MSG_DATA_PDU: { - rnti_lcid_t rnti_lcid = teidin_to_rntilcid(header.teid); - uint16_t rnti = rnti_lcid.rnti; - uint16_t lcid = rnti_lcid.lcid; - - bool user_exists = (rnti_bearers.count(rnti) > 0); - - if (not user_exists) { - logger.error("Unrecognized TEID In=%d for DL PDU. Dropping packet", header.teid); - return; - } + auto& tunnel = tunnels.find(header.teid)->second; + uint16_t rnti = tunnel.rnti; + uint16_t lcid = tunnel.lcid; if (lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) { logger.error("Invalid LCID for DL PDU: %d - dropping packet", lcid); return; } - logger.info(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes); - struct iphdr* ip_pkt = (struct iphdr*)pdu->msg; if (ip_pkt->version != 4 && ip_pkt->version != 6) { logger.error("Invalid IP version to SPGW"); @@ -275,12 +311,47 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc logger.debug("Rx S1-U PDU -- IP src addr %s", srslte::gtpu_ntoa(ip_pkt->saddr).c_str()); logger.debug("Rx S1-U PDU -- IP dst addr %s", srslte::gtpu_ntoa(ip_pkt->daddr).c_str()); } - pdcp->write_sdu(rnti, lcid, std::move(pdu)); + + if (tunnel.fwd_teid_in > 0) { + logger.info("Forwarding GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes); + send_pdu_to_tunnel(rnti, lcid, std::move(pdu), tunnel.teid_out, tunnel.spgw_addr); + } else if (tunnel.prior_teid_in > 0) { + logger.info( + pdu->msg, pdu->N_bytes, "Buffering RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes); + tunnel.buffer.push_back(std::move(pdu)); + } else { + logger.info(pdu->msg, pdu->N_bytes, "RX GTPU PDU rnti=0x%x, lcid=%d, n_bytes=%d", rnti, lcid, pdu->N_bytes); + uint32_t pdcp_sn = -1; + if (header.flags & GTPU_FLAGS_EXTENDED_HDR and header.next_ext_hdr_type == 0b11000000) { + pdcp_sn = (header.ext_buffer[1] << 8u) + header.ext_buffer[0]; + } + pdcp->write_sdu(rnti, lcid, std::move(pdu), pdcp_sn); + } } break; case GTPU_MSG_END_MARKER: { - rnti_lcid_t rnti_lcid = teidin_to_rntilcid(header.teid); - uint16_t rnti = rnti_lcid.rnti; + tunnel& old_tun = tunnels.find(header.teid)->second; + uint16_t rnti = old_tun.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 > 0) { + // END MARKER should be forwarded to TeNB if forwarding is activated + end_marker(old_tun.fwd_teid_in); + old_tun.fwd_teid_in = 0; + } 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]; + for (uint32_t new_teidin : bearer_tunnels) { + tunnel& new_tun = tunnels.find(new_teidin)->second; + if (new_teidin != old_tun.teid_in 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.prior_teid_in = 0; + new_tun.buffer.clear(); + } + } + } break; } default: @@ -293,6 +364,36 @@ void gtpu::handle_gtpu_m1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc m1u.handle_rx_packet(std::move(pdu), addr); } +/// Connect created tunnel with pre-existing tunnel for data forwarding +int gtpu::create_dl_fwd_tunnel(uint32_t rx_teid_in, uint32_t tx_teid_in) +{ + auto rx_tun_pair = tunnels.find(rx_teid_in); + auto tx_tun_pair = tunnels.find(tx_teid_in); + if (rx_tun_pair == tunnels.end() or tx_tun_pair == tunnels.end()) { + logger.error("Failed to create forwarding tunnel between teids 0x%x and 0x%x", rx_teid_in, tx_teid_in); + return SRSLTE_ERROR; + } + + tunnel &rx_tun = rx_tun_pair->second, &tx_tun = tx_tun_pair->second; + rx_tun.fwd_teid_in = tx_teid_in; + logger.info("Creating forwarding tunnel for rnti=0x%x, lcid=%d, in={0x%x, 0x%x}->out={0x%x, 0x%x}", + rx_tun.rnti, + rx_tun.lcid, + rx_tun.teid_out, + rx_tun.spgw_addr, + tx_tun.teid_out, + tx_tun.spgw_addr); + + // Get all buffered PDCP PDUs, and forward them through tx tunnel + std::map pdus = pdcp->get_buffered_pdus(rx_tun.rnti, rx_tun.lcid); + for (auto& pdu_pair : pdus) { + send_pdu_to_tunnel( + rx_tun.rnti, rx_tun.lcid, std::move(pdu_pair.second), tx_tun.teid_out, tx_tun.spgw_addr, pdu_pair.first); + } + + return SRSLTE_SUCCESS; +} + /**************************************************************************** * GTP-U Error Indication ***************************************************************************/ @@ -352,72 +453,45 @@ void gtpu::echo_response(in_addr_t addr, in_port_t port, uint16_t seq) sendto(fd, pdu->msg, 12, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); } +/**************************************************************************** + * GTP-U END MARKER + ***************************************************************************/ +void gtpu::end_marker(uint32_t teidin) +{ + logger.info("TX GTPU End Marker."); + tunnel& tunnel = tunnels.find(teidin)->second; + + gtpu_header_t header = {}; + unique_byte_buffer_t pdu = allocate_unique_buffer(*pool); + + // header + header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL; + header.message_type = GTPU_MSG_END_MARKER; + header.teid = tunnel.teid_out; + header.length = 0; + + gtpu_write_header(&header, pdu.get(), gtpu_log); + + struct sockaddr_in servaddr; + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(tunnel.spgw_addr); + servaddr.sin_port = htons(GTPU_PORT); + + sendto(fd, pdu->msg, 12, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); +} + /**************************************************************************** * TEID to RNTI/LCID helper functions ***************************************************************************/ -uint32_t gtpu::allocate_teidin(uint16_t rnti, uint16_t lcid) -{ - uint32_t teid_in = ++next_teid_in; - if (teidin_to_rntilcid_map.count(teid_in) != 0) { - logger.error("TEID In already exists"); - return 0; - } - rnti_lcid_t rnti_lcid = {rnti, lcid}; - teidin_to_rntilcid_map[teid_in] = rnti_lcid; - logger.debug("TEID In=%d added", teid_in); - return teid_in; -} -void gtpu::free_teidin(uint16_t rnti, uint16_t lcid) +gtpu::tunnel* gtpu::get_tunnel(uint32_t teidin) { - for (std::map::iterator it = teidin_to_rntilcid_map.begin(); - it != teidin_to_rntilcid_map.end();) { - if (it->second.rnti == rnti && it->second.lcid == lcid) { - logger.debug("TEID In=%d erased", it->first); - it = teidin_to_rntilcid_map.erase(it); - } else { - it++; - } - } -} - -void gtpu::free_teidin(uint16_t rnti) -{ - for (std::map::iterator it = teidin_to_rntilcid_map.begin(); - it != teidin_to_rntilcid_map.end();) { - if (it->second.rnti == rnti) { - logger.debug("TEID In=%d erased", it->first); - it = teidin_to_rntilcid_map.erase(it); - } else { - it++; - } - } -} - -gtpu::rnti_lcid_t gtpu::teidin_to_rntilcid(uint32_t teidin) -{ - rnti_lcid_t rnti_lcid = {}; - if (teidin_to_rntilcid_map.count(teidin) == 0) { + auto it = tunnels.find(teidin); + if (it == tunnels.end()) { logger.error("TEID=%d In does not exist.", teidin); - return rnti_lcid; + return nullptr; } - rnti_lcid.rnti = teidin_to_rntilcid_map[teidin].rnti; - rnti_lcid.lcid = teidin_to_rntilcid_map[teidin].lcid; - return rnti_lcid; -} - -uint32_t gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid) -{ - uint32_t teidin = 0; - for (const std::pair& item : teidin_to_rntilcid_map) { - if (item.second.rnti == rnti and item.second.lcid == lcid) { - teidin = item.first; - } - } - if (teidin == 0) { - logger.error("Could not find TEID. RNTI=0x%x, LCID=%d.", rnti, lcid); - } - return teidin; + return &it->second; } /**************************************************************************** diff --git a/srsenb/src/stack/upper/pdcp.cc b/srsenb/src/stack/upper/pdcp.cc index 2b43bf7a2..3ae5245a1 100644 --- a/srsenb/src/stack/upper/pdcp.cc +++ b/srsenb/src/stack/upper/pdcp.cc @@ -15,8 +15,8 @@ namespace srsenb { -pdcp::pdcp(srslte::task_sched_handle task_sched_, srslog::basic_logger& logger) : - task_sched(task_sched_), logger(logger), pool(srslte::byte_buffer_pool::get_instance()) +pdcp::pdcp(srslte::task_sched_handle task_sched_, srslog::basic_logger& logger_) : + task_sched(task_sched_), logger(logger_), pool(srslte::byte_buffer_pool::get_instance()) {} void pdcp::init(rlc_interface_pdcp* rlc_, rrc_interface_pdcp* rrc_, gtpu_interface_pdcp* gtpu_) @@ -139,10 +139,11 @@ void pdcp::write_pdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t } } -void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) +void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn) { if (users.count(rnti)) { if (rnti != SRSLTE_MRNTI) { + // TODO: Handle PDCP SN coming from GTPU users[rnti].pdcp->write_sdu(lcid, std::move(sdu)); } else { users[rnti].pdcp->write_sdu_mch(lcid, std::move(sdu)); @@ -150,6 +151,14 @@ void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t } } +std::map pdcp::get_buffered_pdus(uint16_t rnti, uint32_t lcid) +{ + if (users.count(rnti)) { + return users[rnti].pdcp->get_buffered_pdus(lcid); + } + return {}; +} + void pdcp::user_interface_gtpu::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) { gtpu->write_pdu(rnti, lcid, std::move(pdu)); diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index 24bbb4cb8..ac141f8eb 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -61,7 +61,7 @@ public: void reset(uint16_t rnti) override {} void add_user(uint16_t rnti) override {} void rem_user(uint16_t rnti) override {} - void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override {} + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn) override {} void add_bearer(uint16_t rnti, uint32_t lcid, srslte::pdcp_config_t cnfg) override {} void del_bearer(uint16_t rnti, uint32_t lcid) override {} void config_security(uint16_t rnti, uint32_t lcid, srslte::as_security_config_t sec_cfg_) override {} @@ -124,10 +124,14 @@ public: class gtpu_dummy : public gtpu_interface_rrc { public: - uint32_t add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out) override { return 0; } - void rem_bearer(uint16_t rnti, uint32_t lcid) override {} - void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) override {} - void rem_user(uint16_t rnti) override {} + uint32_t + add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, const bearer_props* props) override + { + return 0; + } + void rem_bearer(uint16_t rnti, uint32_t lcid) override {} + void mod_bearer_rnti(uint16_t old_rnti, uint16_t new_rnti) override {} + void rem_user(uint16_t rnti) override {} }; } // namespace srsenb diff --git a/srsenb/test/upper/test_helpers.h b/srsenb/test/upper/test_helpers.h index ecae153d2..a5b65e8a1 100644 --- a/srsenb/test/upper/test_helpers.h +++ b/srsenb/test/upper/test_helpers.h @@ -130,7 +130,7 @@ public: }; std::map > bearers; - void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu) override + void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn) override { last_sdu.rnti = rnti; last_sdu.lcid = lcid;