add gtpu test for tunneling

master
Francisco 4 years ago committed by Francisco Paisana
parent 13649e4e19
commit 56ec2c286e

@ -360,7 +360,7 @@ public:
class pdcp_interface_gtpu
{
public:
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, uint32_t pdcp_sn = -1) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn = -1) = 0;
virtual std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) = 0;
};
@ -371,7 +371,7 @@ 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, uint32_t pdcp_sn = -1) = 0;
virtual void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int 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;
@ -467,8 +467,10 @@ class gtpu_interface_rrc
{
public:
struct bearer_props {
uint32_t dl_forward_from_teidin = 0;
uint32_t buffer_until_teidin_flush = 0;
bool forward_from_teidin_present = false;
bool flush_before_teidin_present = false;
uint32_t forward_from_teidin = 0;
uint32_t flush_before_teidin = 0;
};
virtual uint32_t

@ -57,6 +57,8 @@ namespace srslte {
#define GTPU_MSG_END_MARKER 254
#define GTPU_MSG_DATA_PDU 255
#define GTPU_EXT_HEADER_PDCP_PDU_NUMBER 0b11000000
struct gtpu_header_t {
uint8_t flags = 0;
uint8_t message_type = 0;

@ -41,8 +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, const bearer_props* props) override;
uint32_t add_bearer(uint16_t rnti,
uint32_t lcid,
uint32_t addr,
uint32_t teid_out,
const bearer_props* props = nullptr) 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;
@ -103,6 +106,8 @@ private:
m1u_handler m1u;
struct tunnel {
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;

@ -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, uint32_t pdcp_sn = -1) override;
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int 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;

@ -154,21 +154,25 @@ uint32_t gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t
{
// Allocate a TEID for the incoming tunnel
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;
tunnel& new_tun = tunnels[teid_in];
new_tun.teid_in = teid_in;
new_tun.rnti = rnti;
new_tun.lcid = lcid;
new_tun.spgw_addr = addr;
new_tun.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;
if (props->flush_before_teidin_present) {
tunnel& after_tun = tunnels.at(props->flush_before_teidin);
after_tun.prior_teid_in_present = true;
after_tun.prior_teid_in = teid_in;
}
// 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) {
if (props->forward_from_teidin_present) {
if (create_dl_fwd_tunnel(props->forward_from_teidin, teid_in) != SRSLTE_SUCCESS) {
rem_tunnel(teid_in);
return 0;
}
@ -240,10 +244,10 @@ void gtpu::rem_tunnel(uint32_t teidin)
logger.warning("Removing GTPU tunnel TEID In=0x%x", teidin);
return;
}
if (it->second.fwd_teid_in > 0) {
if (it->second.fwd_teid_in_present) {
// Forward End Marker to forwarding tunnel, before deleting tunnel
end_marker(it->second.fwd_teid_in);
it->second.fwd_teid_in = 0;
it->second.fwd_teid_in_present = false;
}
auto ue_it = ue_teidin_db.find(it->second.rnti);
std::vector<uint32_t>& lcid_tunnels = ue_it->second[it->second.lcid];
@ -288,9 +292,9 @@ 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: {
auto& tunnel = tunnels.find(header.teid)->second;
uint16_t rnti = tunnel.rnti;
uint16_t lcid = tunnel.lcid;
auto& rx_tun = tunnels.find(header.teid)->second;
uint16_t rnti = rx_tun.rnti;
uint16_t lcid = rx_tun.lcid;
if (lcid < SRSENB_N_SRB || lcid >= SRSENB_N_RADIO_BEARERS) {
logger.error("Invalid LCID for DL PDU: %d - dropping packet", lcid);
@ -307,22 +311,25 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
if (ntohs(ip_pkt->tot_len) != pdu->N_bytes) {
logger.error("IP Len and PDU N_bytes mismatch");
}
logger.debug("Rx S1-U PDU -- IP version %d, Total length %d", int(ip_pkt->version), ntohs(ip_pkt->tot_len));
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());
logger.debug("Rx S1-U PDU -- IPv%d, src=%s, dst=%s, length=%d",
int(ip_pkt->version),
srslte::gtpu_ntoa(ip_pkt->saddr).c_str(),
srslte::gtpu_ntoa(ip_pkt->daddr).c_str(),
ntohs(ip_pkt->tot_len));
}
if (tunnel.fwd_teid_in > 0) {
if (rx_tun.fwd_teid_in_present) {
tunnel& tx_tun = tunnels.at(rx_tun.fwd_teid_in);
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) {
send_pdu_to_tunnel(rnti, lcid, std::move(pdu), tx_tun.teid_out, tx_tun.spgw_addr);
} else if (rx_tun.prior_teid_in_present) {
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));
rx_tun.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) {
if (header.flags & GTPU_FLAGS_EXTENDED_HDR and header.next_ext_hdr_type == GTPU_EXT_HEADER_PDCP_PDU_NUMBER) {
pdcp_sn = (header.ext_buffer[1] << 8u) + header.ext_buffer[0];
}
pdcp->write_sdu(rnti, lcid, std::move(pdu), pdcp_sn);
@ -334,20 +341,21 @@ void gtpu::handle_gtpu_s1u_rx_packet(srslte::unique_byte_buffer_t pdu, const soc
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) {
if (old_tun.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 = 0;
old_tun.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];
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) {
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) {
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.prior_teid_in_present = false;
new_tun.buffer.clear();
}
}
@ -375,6 +383,7 @@ int gtpu::create_dl_fwd_tunnel(uint32_t rx_teid_in, uint32_t tx_teid_in)
}
tunnel &rx_tun = rx_tun_pair->second, &tx_tun = tx_tun_pair->second;
rx_tun.fwd_teid_in_present = true;
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,

@ -139,7 +139,7 @@ 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, uint32_t pdcp_sn)
void pdcp::write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn)
{
if (users.count(rnti)) {
if (rnti != SRSLTE_MRNTI) {

@ -55,13 +55,13 @@ public:
void reestablish(uint16_t rnti) override {}
};
class pdcp_dummy : public pdcp_interface_rrc
class pdcp_dummy : public pdcp_interface_rrc, public pdcp_interface_gtpu
{
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, uint32_t pdcp_sn) override {}
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int 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 {}
@ -70,6 +70,10 @@ public:
bool get_bearer_state(uint16_t rnti, uint32_t lcid, srslte::pdcp_lte_state_t* state) override { return true; }
bool set_bearer_state(uint16_t rnti, uint32_t lcid, const srslte::pdcp_lte_state_t& state) override { return true; }
void reestablish(uint16_t rnti) override {}
std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus(uint16_t rnti, uint32_t lcid) override
{
return {};
}
};
class s1ap_dummy : public s1ap_interface_rrc

@ -22,7 +22,12 @@ target_link_libraries(erab_setup_test srsenb_rrc rrc_asn1 s1ap_asn1 srslte_commo
add_executable(rrc_meascfg_test rrc_meascfg_test.cc)
target_link_libraries(rrc_meascfg_test test_helpers)
add_executable(gtpu_test gtpu_test.cc)
target_link_libraries(gtpu_test srslte_common s1ap_asn1 srsenb_upper srslte_upper ${SCTP_LIBRARIES})
add_test(rrc_mobility_test rrc_mobility_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(erab_setup_test erab_setup_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(rrc_meascfg_test rrc_meascfg_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../..)
add_test(plmn_test plmn_test)
add_test(gtpu_test gtpu_test)

@ -0,0 +1,152 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#include "srslte/asn1/s1ap.h"
#include <linux/ip.h>
#include <numeric>
#include "srsenb/hdr/stack/upper/gtpu.h"
#include "srsenb/test/common/dummy_classes.h"
#include "srslte/common/network_utils.h"
#include "srslte/common/test_common.h"
#include "srslte/upper/gtpu.h"
namespace srsenb {
class stack_tester : public stack_interface_gtpu_lte
{
public:
int s1u_fd;
void add_gtpu_s1u_socket_handler(int fd) { s1u_fd = fd; }
void add_gtpu_m1u_socket_handler(int fd) {}
};
class pdcp_tester : public pdcp_dummy
{
public:
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn) override
{
last_sdu = std::move(sdu);
last_pdcp_sn = pdcp_sn;
last_rnti = rnti;
last_lcid = lcid;
}
srslte::unique_byte_buffer_t last_sdu;
int last_pdcp_sn = -1;
uint16_t last_rnti = SRSLTE_INVALID_RNTI;
uint32_t last_lcid = 0;
};
int GTPU_PORT = 2152;
srslte::unique_byte_buffer_t encode_gtpu_packet(srslte::span<uint8_t> data,
uint32_t teid,
const struct sockaddr_in& src_sockaddr_in,
const struct sockaddr_in& dest_sockaddr_in)
{
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance());
struct iphdr ip_pkt;
ip_pkt.version = 4;
ip_pkt.tot_len = htons(data.size() + sizeof(struct iphdr));
ip_pkt.saddr = src_sockaddr_in.sin_addr.s_addr;
ip_pkt.daddr = dest_sockaddr_in.sin_addr.s_addr;
memcpy(pdu->msg, &ip_pkt, sizeof(struct iphdr));
pdu->N_bytes = sizeof(struct iphdr);
memcpy(pdu->msg + pdu->N_bytes, data.data(), data.size());
pdu->N_bytes += data.size();
// header
srslte::gtpu_header_t header;
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
header.message_type = GTPU_MSG_DATA_PDU;
header.length = pdu->N_bytes;
header.teid = teid;
gtpu_write_header(&header, pdu.get(), srslte::log_ref("GTPU"));
return pdu;
}
srslte::unique_byte_buffer_t read_socket(int fd)
{
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance());
pdu->N_bytes = read(fd, pdu->msg, pdu->get_tailroom());
return pdu;
}
int test_gtpu_direct_tunneling()
{
uint16_t rnti = 0x46, rnti2 = 0x50;
uint32_t drb1 = 3;
uint32_t mme_teidout1 = 1, mme_teidout2 = 2;
const char * mme_addr_str = "127.0.0.1", *senb_addr_str = "127.0.1.1", *tenb_addr_str = "127.0.1.2";
struct sockaddr_in senb_sockaddr, mme_sockaddr, tenb_sockaddr;
srslte::net_utils::set_sockaddr(&senb_sockaddr, senb_addr_str, GTPU_PORT);
srslte::net_utils::set_sockaddr(&mme_sockaddr, mme_addr_str, GTPU_PORT);
srslte::net_utils::set_sockaddr(&tenb_sockaddr, tenb_addr_str, GTPU_PORT);
uint32_t tenb_addr = ntohl(tenb_sockaddr.sin_addr.s_addr), mme_addr = ntohl(mme_sockaddr.sin_addr.s_addr);
// Initiate layers
srsenb::gtpu senb_gtpu(srslog::fetch_basic_logger("GTPU1")), tenb_gtpu(srslog::fetch_basic_logger("GTPU2"));
stack_tester senb_stack, tenb_stack;
pdcp_tester senb_pdcp, tenb_pdcp;
senb_gtpu.init(senb_addr_str, mme_addr_str, "", "", &senb_pdcp, &senb_stack, false);
tenb_gtpu.init(tenb_addr_str, mme_addr_str, "", "", &tenb_pdcp, &tenb_stack, false);
// create tunnels MME-SeNB and MME-TeNB
uint32_t senb_teid_in = senb_gtpu.add_bearer(rnti, drb1, mme_addr, mme_teidout1);
uint32_t tenb_teid_in = tenb_gtpu.add_bearer(rnti, drb1, mme_addr, mme_teidout2);
// create direct tunnel SeNB-TeNB
gtpu::bearer_props props;
props.flush_before_teidin_present = true;
props.flush_before_teidin = tenb_teid_in;
uint32_t dl_tenb_teid_in = tenb_gtpu.add_bearer(rnti2, drb1, 0, 0, &props);
props = {};
props.forward_from_teidin_present = true;
props.forward_from_teidin = senb_teid_in;
senb_gtpu.add_bearer(rnti, drb1, tenb_addr, dl_tenb_teid_in, &props);
std::vector<uint8_t> data_vec(10);
std::iota(data_vec.begin(), data_vec.end(), 0);
// TEST: verify that incoming DL data is forwarded through SeNB-TeNB tunnel
srslte::unique_byte_buffer_t pdu = encode_gtpu_packet(data_vec, senb_teid_in, mme_sockaddr, senb_sockaddr);
std::vector<uint8_t> encoded_data(pdu->msg + 8u, pdu->msg + pdu->N_bytes);
senb_gtpu.handle_gtpu_s1u_rx_packet(std::move(pdu), mme_sockaddr);
tenb_gtpu.handle_gtpu_s1u_rx_packet(read_socket(tenb_stack.s1u_fd), senb_sockaddr);
TESTASSERT(tenb_pdcp.last_sdu != nullptr);
TESTASSERT(tenb_pdcp.last_sdu->N_bytes == encoded_data.size() and
memcmp(tenb_pdcp.last_sdu->msg, encoded_data.data(), encoded_data.size()) == 0);
TESTASSERT(tenb_pdcp.last_rnti == rnti2);
TESTASSERT(tenb_pdcp.last_lcid == drb1);
return SRSLTE_SUCCESS;
}
} // namespace srsenb
int main()
{
// Setup logging.
srslog::sink& log_sink = srslog::fetch_stdout_sink();
srslog::log_channel* chan = srslog::create_log_channel("gtpu_test", log_sink);
srslte::srslog_wrapper log_wrapper(*chan);
// Start the log backend.
srslog::init();
srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_DEBUG);
srslte::logmap::set_default_hex_limit(100000);
TESTASSERT(srsenb::test_gtpu_direct_tunneling() == SRSLTE_SUCCESS);
}

@ -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, uint32_t pdcp_sn) override
void write_sdu(uint16_t rnti, uint32_t lcid, srslte::unique_byte_buffer_t sdu, int pdcp_sn) override
{
last_sdu.rnti = rnti;
last_sdu.lcid = lcid;

Loading…
Cancel
Save