Skip to content

Commit

Permalink
GH-1 Implements send data to uplink test in spgwu
Browse files Browse the repository at this point in the history
  • Loading branch information
navarrothiago committed Jun 18, 2020
1 parent 926c10b commit 89c5d90
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 14 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ docker-create-network: ## Create macvlan with subnet 192.168.15.0 using enp0s20f

docker-setup-network: ## Connect maclan on container openair-cn-cup and create spgwu interfaces
docker network connect macvlan-enp0s20f0u1 openair-cn-cups
docker-config-spgwu-iface

docker-config-spgwu-iface: ## Create and configure spgwu interefaces
$(PROJECT_DIR)/configs/config-spgwu-interface.sh
Expand All @@ -72,3 +71,6 @@ docker-build: ## Build docker image

run-spgwu: ## Run spgwu
$(PROJECT_DIR)/build/spgw_u/build/spgwu -c ./etc/spgw_u-dev.conf -o

kill-spgwu: ## Kill spgwu
echo "TODO"
3 changes: 3 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhisto
&& chown -R $UNAME /commandhistory \
&& echo $SNIPPET >> "/home/$UNAME/.bashrc"

RUN apt-get update && \
apt-get -y install tcpdump

USER root
#USER $UNAME

Expand Down
2 changes: 2 additions & 0 deletions src/spgwu/simpleswitch/pfcp_session.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ namespace pfcp {


public:
// This IE shall contain the unique identifier allocated by the CP
// function identifying the session.
pfcp::fseid_t cp_fseid;
uint64_t seid; // User plane

Expand Down
1 change: 1 addition & 0 deletions src/spgwu/simpleswitch/pfcp_switch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ void pfcp_switch::send_to_core(char* const ip_packet, const ssize_t len)
//Logger::pfcp_switch().info( "pfcp_switch::send_to_core %d bytes ", len);
struct sockaddr_in dst; // no clear
dst.sin_addr.s_addr = ((struct iphdr*)ip_packet)->daddr;
Logger::pfcp_switch().info("destination %s", inet_ntoa(dst.sin_addr));
dst.sin_family = AF_INET;
if((bytes_sent = sendto(sock_w, ip_packet, len, 0, (struct sockaddr *)&dst, sizeof(dst))) < 0) {
Logger::pfcp_switch().error( "sendto failed rc=%d:%s", bytes_sent, strerror (errno));
Expand Down
2 changes: 0 additions & 2 deletions src/spgwu/simpleswitch/spgwu_s1u.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@ void spgwu_s1u::handle_receive(char* recv_buffer, const std::size_t bytes_transf

struct iphdr* iph = (struct iphdr*)&recv_buffer[gtp_payload_offset];
if (iph->version == 4) {
// Section 8.2.24 TS 29 244
// The "Access" and "Core" values denote a downlink and uplink traffic direction respectively.
pfcp_switch_inst->pfcp_session_look_up_pack_in_access(iph, gtp_payload_length, r_endpoint, tunnel_id);
} else if (iph->version == 6) {
pfcp_switch_inst->pfcp_session_look_up_pack_in_access((struct ipv6hdr*)iph, gtp_payload_length, r_endpoint, tunnel_id);
Expand Down
15 changes: 11 additions & 4 deletions test/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
# Locate GTest
# Locate GTest.
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
enable_testing()

# pcapplusplus.
include_directories("/usr/local/include/pcapplusplus")

# Enable SPDLOG debug.
add_definitions("-DSPDLOG_DEBUG_ON")

# Change visibily off all private to public.
# Easy for testing.
# add_definitions("-Dprivate=public")

################################################################################
# Specific part for oai_spgw_u folder

add_definitions("-DPACKAGE_NAME=\"SPGW-U\"")
add_definitions("-DSPDLOG_DEBUG_ON")

include_directories(${SRC_TOP_DIR}/oai_spgwu)
include_directories(${SRC_TOP_DIR}/common)
Expand All @@ -25,6 +32,7 @@ include_directories(${SRC_TOP_DIR}/../build/ext/spdlog/include)

set(SRC_TEST
gtpu_l4_stack_test.cpp
packet_stats.cpp
spgwu_tests.cpp
${SRC_TOP_DIR}/oai_spgwu/options.cpp
${SRC_TOP_DIR}/itti/itti.cpp
Expand All @@ -34,7 +42,6 @@ set(SRC_TEST

add_executable(spgwu-test ${SRC_TEST})
target_link_libraries (spgwu-test ${ASAN} -Wl,--start-group CN_UTILS SPGWU SPGW_SWITCH UDP GTPV1U PFCP 3GPP_COMMON_TYPES gflags glog dl double-conversion folly -Wl,--end-group
m rt config++ event boost_system ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} /usr/local/lib/libPcap++.a /usr/local/lib/libPacket++.a /usr/local/lib/libCommon++.a)
m rt config++ event boost_system ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} /usr/local/lib/libPacket++.a /usr/local/lib/libPcap++.a /usr/local/lib/libCommon++.a pcap)

# add_test(NAME ${BINARY} COMMAND ${BINARY})
#
55 changes: 55 additions & 0 deletions test/integration/packet_stats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "packet_stats.hpp"
#include <PcapLiveDevice.h>
#include <IPv4Layer.h>
#include <iostream>

packet_stats::packet_stats(const std::string& destination_address)
: m_destination_address(destination_address)
{
clear();
}

packet_stats::~packet_stats()
{
}

void packet_stats::on_packet_arrives(pcpp::RawPacket *packet, pcpp::PcapLiveDevice *dev, void *cookie)
{
// extract the stats object form the cookie
packet_stats *stats = (packet_stats *)cookie;

// parsed the raw packet
pcpp::Packet parsedPacket(packet);

// collect stats from packet
stats->consume_packet(parsedPacket);
}

bool packet_stats::on_packet_arrives_blocking_mode(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void* cookie)
{
on_packet_arrives(packet, dev, cookie);
return false;
}

void packet_stats::consume_packet(pcpp::Packet &packet)
{
if (packet.isPacketOfType(pcpp::IPv4)) {
auto destination_addresss = static_cast<pcpp::IPv4Layer*>(packet.getLayerOfType(pcpp::IPv4))->getDstIpAddress();
std::cout << "Destination address " << destination_addresss.toString() << std::endl;

if(destination_addresss == m_destination_address){
m_ipv4_count++;
}
}
}

void packet_stats::clear()
{
m_ipv4_count = 0;
}


unsigned int packet_stats::get_ipv4_count() const
{
return m_ipv4_count;
}
22 changes: 22 additions & 0 deletions test/integration/packet_stats.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <RawPacket.h>
#include <PcapLiveDevice.h>
#include <Packet.h>

/**
* @brief Class for packet stats.
*/
class packet_stats
{
public:
packet_stats(const std::string& destination_address);
virtual ~packet_stats();
static void on_packet_arrives(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void* cookie);
static bool on_packet_arrives_blocking_mode(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void* cookie);
void consume_packet(pcpp::Packet& packet);
void clear();
unsigned int get_ipv4_count() const;
private:
unsigned int m_ipv4_count;
std::string m_destination_address;
};

145 changes: 138 additions & 7 deletions test/integration/spgwu_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
#include <IPv4Layer.h>
#include <Packet.h>
#include <RawPacket.h>
#include <stdlib.h>
#include <PcapLiveDeviceList.h>
#include <PlatformSpecificUtils.h>

// includes for spgwu components
#include "spgwu_tests_utils.hpp"

// for test fixture
#include "3gpp_29.244.h"
#include "packet_stats.hpp"

class SpgwuTests : public ::testing::Test
{
public:
Expand All @@ -21,22 +28,34 @@ class SpgwuTests : public ::testing::Test
*/
SpgwuTests()
: m_clientPort(8000),
m_newPacket(100)
m_newPacket(100),
m_source_address("192.168.15.1"),
m_destination_address("10.0.0.1"),
m_sgi_iface("eth0")

{
init_spgwu_app();
init_gtp_packet();
mp_gptu_client = std::make_shared<gtpu_l4_stack_test>(spgwu_cfg.s1_up.addr4, m_clientPort, spgwu_cfg.s1_up.thread_rd_sched_params);
}

void SetUp()
{
}

void TearDown()
{
}

void init_gtp_packet()
{
memset(&m_serverAddr, 0, sizeof(m_serverAddr));
m_serverAddr.sin_family = AF_INET;
m_serverAddr.sin_port = htons(2152);
m_serverAddr.sin_addr.s_addr = INADDR_ANY;

// create a new IPv4 layer.
m_newIPLayer = pcpp::IPv4Layer(pcpp::IPv4Address(std::string("192.168.15.1")), pcpp::IPv4Address(std::string("10.0.0.1")));
m_newIPLayer = pcpp::IPv4Layer(pcpp::IPv4Address(m_source_address), pcpp::IPv4Address(m_destination_address));
m_newIPLayer.getIPv4Header()->ipId = htons(2000);
m_newIPLayer.getIPv4Header()->timeToLive = 64;

Expand All @@ -61,10 +80,6 @@ class SpgwuTests : public ::testing::Test
m_header.message_length = m_gtpuPacket.size();
}

void TearDown()
{
}

void init_spgwu_app()
{
// char *argv[] = {"program-name", "arg1", "arg2", ..., "argn", NULL}
Expand Down Expand Up @@ -124,26 +139,41 @@ class SpgwuTests : public ::testing::Test

// gtpu client.
std::shared_ptr<gtpu_l4_stack_test> mp_gptu_client;

// server address.
struct sockaddr_in m_serverAddr;

// server port.
u_int32_t m_clientPort;

// IP PDU
pcpp::IPv4Layer m_newIPLayer;

// create a packet with initial capacity of 100 bytes (will grow automatically if needed)
pcpp::Packet m_newPacket;

// T-PDU (IP datagram).
u_int32_t m_payloadLength;
std::vector<char> m_gtpuPacket;

// m_header.
struct gtpuhdr m_header;

// Source address for gtp packet.
std::string m_source_address;

// Destination address for gtp packet.
std::string m_destination_address;

// SGi interface. TODO navarrothiago Get it from config file.
std::string m_sgi_iface;
};

// Inject G_PDU to spgwu_s1u stack using gtpu_l4_stack client.
// Create GTP packet - https://pcapplusplus.github.io/docs/tutorials/packet-crafting#packet-creation
// Send GTP packet to network device - https://pcapplusplus.github.io/docs/tutorials/capture-packets#sending-packets
// Receive GTPU_ERROR_INDICATION
TEST_F(SpgwuTests, send_GTPU_G_PDU_received_GTPU_ERROR_INDICATION)
TEST_F(SpgwuTests, DISABLED_send_GTPU_G_PDU_received_GTPU_ERROR_INDICATION)
{
// Message expected to be received.
mp_gptu_client->message_type_expected(GTPU_ERROR_INDICATION);
Expand All @@ -155,3 +185,104 @@ TEST_F(SpgwuTests, send_GTPU_G_PDU_received_GTPU_ERROR_INDICATION)
// pause, cin.get is portable
std::cin.get();
}

TEST_F(SpgwuTests, send_GTPU_G_PDU_success)
{
pfcp::fteid_t fteid;
memset(&fteid, 0, sizeof(pfcp::fteid_t));
fteid.ch = true;
uint64_t lseid = 0;
uint8_t cause = pfcp::CAUSE_VALUE_SYSTEM_FAILURE;

// Table 7.5.2.2-1: Create PDR IE within PFCP Session Establishment Request
// Check pfcp::pfcp_pdr::look_up_pack_in_access
pfcp::create_pdr create_pdr;
create_pdr.set(pfcp::pdr_id_t());

// Create PDI IE for Create PDR.
pfcp::pdi pdi;
pdi.set(pfcp::source_interface_t{pfcp::INTERFACE_VALUE_ACCESS});
pdi.set(pfcp::ue_ip_address_t{
ipv6d : 0, // This bit is only applicable to the UE IP address IE in the PDI IE and whhen V6 bit is set to "1". If this bit is set to "1", then the IPv6 Prefix Delegation Bits field shall be present, otherwise the UP function shall consider IPv6 prefix is default /64.
sd : 0, // This bit is only applicable to the UE IP Address IE in the PDI IE. It shall be set to "0" and ignored by the receiver in IEs other than PDI IE. In the PDI IE, if this bit is set to "0", this indicates a Source IP address; if this bit is set to "1", this indicates a Destination IP address.
v4 : 1, // If this bit is set to "1", then the IPv4 address field shall be present in the UE IP Address, otherwise the IPv4 address field shall not be present.
v6 : 0, // If this bit is set to "1", then the IPv6 address field shall be present in the UE IP Address, otherwise the IPv6 address field shall not be present.
ipv4_address : *m_newPacket.getLayerOfType<pcpp::IPv4Layer>()->getSrcIpAddress().toInAddr()
});
pdi.set(fteid);
pdi.set(pfcp::sdf_filter_t());
create_pdr.set(pdi);

// Create Outer Header Removal IE.
create_pdr.set(pfcp::outer_header_removal_t{
.outer_header_removal_description = OUTER_HEADER_REMOVAL_GTPU_UDP_IPV4});

// Create precedence for Create PDR IE.
create_pdr.set(pfcp::precedence_t{0});
std::shared_ptr<pfcp::pfcp_pdr> pdr = std::make_shared<pfcp::pfcp_pdr>(create_pdr);

// Create paramenter for Create FAR IE.
pfcp::far_id_t far_id = {0};
pfcp::apply_action_t far_apply_action;
far_apply_action.forw = true;
far_apply_action.dupl = false;
pfcp::forwarding_parameters fowarding_parameters;
fowarding_parameters.set(pfcp::destination_interface_t{pfcp::INTERFACE_VALUE_CORE});

// Create FAR
pfcp::create_far create_far;
create_far.set(far_id);
create_far.set(far_apply_action);
create_far.set(fowarding_parameters);
create_pdr.set(far_id);

// Create source request.
std::shared_ptr<itti_sxab_session_establishment_request> sreq;
task_id_t origin = TASK_FIRST, destination = TASK_FIRST;
sreq = std::make_shared<itti_sxab_session_establishment_request>(origin, destination);

// Initialize IE in request.
pfcp::fseid_t fseid;
memset(&fseid, 0, sizeof(pfcp::fseid_t));
sreq->pfcp_ies.set(fseid);
sreq->pfcp_ies.set(create_pdr);
sreq->pfcp_ies.set(create_far);

std::shared_ptr<itti_sxab_session_establishment_response> resp;
resp = std::make_shared<itti_sxab_session_establishment_response>(origin, destination);

// Session establishment request.
pfcp_switch_inst->handle_pfcp_session_establishment_request(sreq, resp.get());
ASSERT_EQ(resp->pfcp_ies.created_pdrs.size(), 1);
auto teid = resp->pfcp_ies.created_pdrs[0].local_fteid.second.teid;
ASSERT_EQ(teid, 1);


// Find the interface by IP address.
// Check SGi in spgw_u-dev.conf file.
pcpp::PcapLiveDevice *dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByName(m_sgi_iface);
ASSERT_TRUE(dev != NULL);
ASSERT_TRUE(dev->open());

// Create the stats object
packet_stats stats(m_destination_address);

// start capture in async mode. Give a callback function to call to whenever a packet is captured and the stats object as the cookie
ASSERT_TRUE(dev->startCapture(packet_stats::on_packet_arrives, &stats));

// Send data to core access. It should apply the Rules.
Logger::gtpv1_u().debug("send_GTPU_G_PDU");
mp_gptu_client->send_g_pdu(m_serverAddr, teid, m_gtpuPacket.data() + sizeof(m_header), m_payloadLength);

// Sleep for 10 seconds in main thread, in the meantime packets are captured in the async thread
PCAP_SLEEP(4);

// Expect to receive some data in pdn interface.
ASSERT_GT(stats.get_ipv4_count(), 0);

// Pause.
std::cin.get();

// Stop capturing packets.
dev->stopCapture();
}
Loading

0 comments on commit 89c5d90

Please sign in to comment.