mirror of https://github.com/PentHertz/srsLTE.git
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.
This commit is contained in:
parent
cb32cb4ed7
commit
13649e4e19
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> 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;
|
||||
|
|
|
@ -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<uint8_t> 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);
|
||||
|
|
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint32_t lcid);
|
||||
|
||||
private:
|
||||
srsue::rlc_interface_pdcp* rlc = nullptr;
|
||||
srsue::rrc_interface_pdcp* rrc = nullptr;
|
||||
|
|
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus() = 0;
|
||||
|
||||
// COUNT, HFN and SN helpers
|
||||
uint32_t HFN(uint32_t count);
|
||||
uint32_t SN(uint32_t count);
|
||||
|
|
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus() override;
|
||||
|
||||
private:
|
||||
srsue::rlc_interface_pdcp* rlc = nullptr;
|
||||
srsue::rrc_interface_pdcp* rrc = nullptr;
|
||||
|
|
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus() override { return {}; }
|
||||
|
||||
// State variable getters (useful for testing)
|
||||
uint32_t nof_discard_timers() { return discard_timers_map.size(); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -238,6 +238,14 @@ bool pdcp::set_bearer_state(uint32_t lcid, const srslte::pdcp_lte_state_t& state
|
|||
return true;
|
||||
}
|
||||
|
||||
std::map<uint32_t, srslte::unique_byte_buffer_t> pdcp::get_buffered_pdus(uint32_t lcid)
|
||||
{
|
||||
if (not valid_lcid(lcid)) {
|
||||
return {};
|
||||
}
|
||||
return pdcp_array[lcid]->get_buffered_pdus();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
RLC interface
|
||||
*******************************************************************************/
|
||||
|
|
|
@ -371,4 +371,9 @@ void pdcp_entity_lte::set_bearer_state(const pdcp_lte_state_t& state)
|
|||
st = state;
|
||||
}
|
||||
|
||||
std::map<uint32_t, srslte::unique_byte_buffer_t> pdcp_entity_lte::get_buffered_pdus()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace srslte
|
||||
|
|
|
@ -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<uint16_t, bearer_map> rnti_bearers;
|
||||
|
||||
typedef struct {
|
||||
uint16_t rnti;
|
||||
uint16_t lcid;
|
||||
} rnti_lcid_t;
|
||||
std::map<uint32_t, rnti_lcid_t> 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<srslte::unique_byte_buffer_t> buffer;
|
||||
};
|
||||
std::unordered_map<uint32_t, tunnel> tunnels;
|
||||
std::map<uint16_t, std::array<std::vector<uint32_t>, 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
|
||||
|
|
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override;
|
||||
|
||||
private:
|
||||
class user_interface_rlc : public srsue::rlc_interface_pdcp
|
||||
{
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "srsenb/hdr/stack/upper/gtpu.h"
|
||||
#include "srslte/common/network_utils.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/ip.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -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<uint32_t>& 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<uint32_t>& 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<uint32_t, rnti_lcid_t>::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<uint32_t>& 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<uint32_t>& 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<uint32_t, srslte::unique_byte_buffer_t> 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<uint32_t, rnti_lcid_t>::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<uint32_t, rnti_lcid_t>::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<const uint32_t, rnti_lcid_t>& 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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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<uint32_t, srslte::unique_byte_buffer_t> 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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -130,7 +130,7 @@ public:
|
|||
};
|
||||
std::map<uint16_t, std::map<uint32_t, lcid_cfg_t> > 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;
|
||||
|
|
Loading…
Reference in New Issue