moved GW out of the UE stack. This is important to keep concurrency out of the stack once it becomes single-threaded

master
Francisco Paisana 6 years ago committed by Andre Puschmann
parent c7be984819
commit 10a56e2a84

@ -223,13 +223,6 @@ public:
virtual std::string get_rb_name(uint32_t lcid) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
// PDCP interface for GW
class pdcp_interface_gw
{
public:
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) = 0;
virtual bool is_lcid_enabled(uint32_t lcid) = 0;
};
// PDCP interface for RRC // PDCP interface for RRC
class pdcp_interface_rrc class pdcp_interface_rrc
@ -270,6 +263,13 @@ public:
virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0; virtual void write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t sdu) = 0;
}; };
class pdcp_interface_gw
{
public:
virtual void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) = 0;
virtual bool is_lcid_enabled(uint32_t lcid) = 0;
};
// RLC interface for RRC // RLC interface for RRC
class rlc_interface_rrc class rlc_interface_rrc
{ {
@ -921,6 +921,17 @@ public:
virtual void radio_failure() = 0; virtual void radio_failure() = 0;
}; };
// STACK interface for GW
class stack_interface_gw : public pdcp_interface_gw
{
public:
virtual bool switch_on() = 0;
};
class gw_interface_stack : public gw_interface_nas, public gw_interface_rrc, public gw_interface_pdcp
{
};
// Combined interface for PHY to access stack (MAC and RRC) // Combined interface for PHY to access stack (MAC and RRC)
class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_interface_phy_lte class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_interface_phy_lte
{ {

@ -35,7 +35,6 @@
#include "srslte/radio/radio.h" #include "srslte/radio/radio.h"
#include "srslte/upper/pdcp.h" #include "srslte/upper/pdcp.h"
#include "srslte/upper/rlc.h" #include "srslte/upper/rlc.h"
#include "upper/gw.h"
#include "upper/nas.h" #include "upper/nas.h"
#include "upper/usim.h" #include "upper/usim.h"
@ -48,7 +47,7 @@
namespace srsue { namespace srsue {
class ue_stack_lte : public ue_stack_base, public stack_interface_phy_lte class ue_stack_lte final : public ue_stack_base, public stack_interface_phy_lte, public stack_interface_gw
{ {
public: public:
ue_stack_lte(); ue_stack_lte();
@ -57,8 +56,8 @@ public:
std::string get_type(); std::string get_type();
int init(const stack_args_t& args_, srslte::logger* logger_); int init(const stack_args_t& args_, srslte::logger* logger_);
int init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_); int init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_, gw_interface_stack* gw_);
bool switch_on(); bool switch_on() final;
bool switch_off(); bool switch_off();
void stop(); void stop();
@ -102,21 +101,18 @@ public:
void run_tti(const uint32_t tti) { mac.run_tti(tti); } void run_tti(const uint32_t tti) { mac.run_tti(tti); }
// Interface for GW
void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking) final
{
pdcp.write_sdu(lcid, std::move(sdu), blocking);
}
bool is_lcid_enabled(uint32_t lcid) final { return pdcp.is_lcid_enabled(lcid); }
private: private:
bool running; bool running;
srsue::stack_args_t args; srsue::stack_args_t args;
// logging
srslte::logger* logger;
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter nas_log;
srslte::log_filter gw_log;
srslte::log_filter usim_log;
srslte::log_filter pool_log;
// stack components // stack components
srsue::mac mac; srsue::mac mac;
srslte::mac_pcap mac_pcap; srslte::mac_pcap mac_pcap;
@ -125,11 +121,22 @@ private:
srslte::pdcp pdcp; srslte::pdcp pdcp;
srsue::rrc rrc; srsue::rrc rrc;
srsue::nas nas; srsue::nas nas;
srsue::gw gw;
std::unique_ptr<usim_base> usim; std::unique_ptr<usim_base> usim;
srslte::logger* logger;
// Radio and PHY log are in ue.cc
srslte::log_filter mac_log;
srslte::log_filter rlc_log;
srslte::log_filter pdcp_log;
srslte::log_filter rrc_log;
srslte::log_filter nas_log;
srslte::log_filter usim_log;
srslte::log_filter pool_log;
// RAT-specific interfaces // RAT-specific interfaces
phy_interface_stack_lte* phy; phy_interface_stack_lte* phy;
gw_interface_stack* gw;
}; };
} // namespace srsue } // namespace srsue

@ -27,6 +27,7 @@
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/interfaces_common.h" #include "srslte/common/interfaces_common.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "tft_packet_filter.h" #include "tft_packet_filter.h"
@ -35,22 +36,20 @@
namespace srsue { namespace srsue {
class gw_args_t struct gw_args_t {
{ struct log_args_t {
public: std::string gw_level;
int gw_hex_limit;
} log;
std::string tun_dev_name; std::string tun_dev_name;
std::string tun_dev_netmask; std::string tun_dev_netmask;
}; };
class gw class gw : public gw_interface_stack, public thread
:public gw_interface_pdcp
,public gw_interface_nas
,public gw_interface_rrc
,public thread
{ {
public: public:
gw(); gw();
void init(pdcp_interface_gw* pdcp_, nas_interface_gw* nas_, srslte::log* gw_log_, gw_args_t); int init(const gw_args_t& args_, srslte::logger* logger_, stack_interface_gw* stack);
void stop(); void stop();
void get_metrics(gw_metrics_t &m); void get_metrics(gw_metrics_t &m);
@ -71,11 +70,9 @@ public:
private: private:
static const int GW_THREAD_PRIO = 7; static const int GW_THREAD_PRIO = 7;
pdcp_interface_gw *pdcp; stack_interface_gw* stack;
nas_interface_gw *nas;
srslte::byte_buffer_pool *pool; srslte::byte_buffer_pool *pool;
srslte::log *gw_log; srslte::logger* logger;
gw_args_t args; gw_args_t args;
@ -87,6 +84,8 @@ private:
bool if_up; bool if_up;
uint32_t default_lcid = 0; uint32_t default_lcid = 0;
srslte::log_filter log;
uint32_t current_ip_addr; uint32_t current_ip_addr;
uint8_t current_if_id[8]; uint8_t current_if_id[8];

@ -79,6 +79,7 @@ typedef struct {
phy_args_t phy; phy_args_t phy;
stack_args_t stack; stack_args_t stack;
gw_args_t gw;
expert_args_t expert; expert_args_t expert;
} all_args_t; } all_args_t;
@ -110,6 +111,7 @@ private:
std::unique_ptr<ue_radio_base> radio; std::unique_ptr<ue_radio_base> radio;
std::unique_ptr<ue_phy_base> phy; std::unique_ptr<ue_phy_base> phy;
std::unique_ptr<ue_stack_base> stack; std::unique_ptr<ue_stack_base> stack;
std::unique_ptr<gw> gw_inst;
// Generic logger members // Generic logger members
srslte::logger* logger = nullptr; srslte::logger* logger = nullptr;

@ -120,8 +120,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("log.pdcp_hex_limit", bpo::value<int>(&args->stack.log.pdcp_hex_limit), "PDCP log hex dump limit") ("log.pdcp_hex_limit", bpo::value<int>(&args->stack.log.pdcp_hex_limit), "PDCP log hex dump limit")
("log.rrc_level", bpo::value<string>(&args->stack.log.rrc_level), "RRC log level") ("log.rrc_level", bpo::value<string>(&args->stack.log.rrc_level), "RRC log level")
("log.rrc_hex_limit", bpo::value<int>(&args->stack.log.rrc_hex_limit), "RRC log hex dump limit") ("log.rrc_hex_limit", bpo::value<int>(&args->stack.log.rrc_hex_limit), "RRC log hex dump limit")
("log.gw_level", bpo::value<string>(&args->stack.log.gw_level), "GW log level") ("log.gw_level", bpo::value<string>(&args->gw.log.gw_level), "GW log level")
("log.gw_hex_limit", bpo::value<int>(&args->stack.log.gw_hex_limit), "GW log hex dump limit") ("log.gw_hex_limit", bpo::value<int>(&args->gw.log.gw_hex_limit), "GW log hex dump limit")
("log.nas_level", bpo::value<string>(&args->stack.log.nas_level), "NAS log level") ("log.nas_level", bpo::value<string>(&args->stack.log.nas_level), "NAS log level")
("log.nas_hex_limit", bpo::value<int>(&args->stack.log.nas_hex_limit), "NAS log hex dump limit") ("log.nas_hex_limit", bpo::value<int>(&args->stack.log.nas_hex_limit), "NAS log hex dump limit")
("log.usim_level", bpo::value<string>(&args->stack.log.usim_level), "USIM log level") ("log.usim_level", bpo::value<string>(&args->stack.log.usim_level), "USIM log level")
@ -143,8 +143,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("usim.pin", bpo::value<string>(&args->stack.usim.pin), "PIN in case real SIM card is used") ("usim.pin", bpo::value<string>(&args->stack.usim.pin), "PIN in case real SIM card is used")
("usim.reader", bpo::value<string>(&args->stack.usim.reader)->default_value(""), "Force specific PCSC reader. Default: Try all available readers.") ("usim.reader", bpo::value<string>(&args->stack.usim.reader)->default_value(""), "Force specific PCSC reader. Default: Try all available readers.")
("gw.ip_devname", bpo::value<string>(&args->stack.gw.tun_dev_name)->default_value("tun_srsue"), "Name of the tun_srsue device") ("gw.ip_devname", bpo::value<string>(&args->gw.tun_dev_name)->default_value("tun_srsue"), "Name of the tun_srsue device")
("gw.ip_netmask", bpo::value<string>(&args->stack.gw.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the tun_srsue device") ("gw.ip_netmask", bpo::value<string>(&args->gw.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the tun_srsue device")
/* Downlink Channel emulator section */ /* Downlink Channel emulator section */
("channel.dl.enable", bpo::value<bool>(&args->phy.dl_channel_args.enable)->default_value(false), "Enable/Disable internal Downlink channel emulator") ("channel.dl.enable", bpo::value<bool>(&args->phy.dl_channel_args.enable)->default_value(false), "Enable/Disable internal Downlink channel emulator")
@ -423,7 +423,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
args->stack.log.nas_level = args->log.all_level; args->stack.log.nas_level = args->log.all_level;
} }
if (!vm.count("log.gw_level")) { if (!vm.count("log.gw_level")) {
args->stack.log.gw_level = args->log.all_level; args->gw.log.gw_level = args->log.all_level;
} }
if (!vm.count("log.usim_level")) { if (!vm.count("log.usim_level")) {
args->stack.log.usim_level = args->log.all_level; args->stack.log.usim_level = args->log.all_level;
@ -451,7 +451,7 @@ void parse_args(all_args_t* args, int argc, char* argv[])
args->stack.log.nas_hex_limit = args->log.all_hex_limit; args->stack.log.nas_hex_limit = args->log.all_hex_limit;
} }
if (!vm.count("log.gw_hex_limit")) { if (!vm.count("log.gw_hex_limit")) {
args->stack.log.gw_hex_limit = args->log.all_hex_limit; args->gw.log.gw_hex_limit = args->log.all_hex_limit;
} }
if (!vm.count("log.usim_hex_limit")) { if (!vm.count("log.usim_hex_limit")) {
args->stack.log.usim_hex_limit = args->log.all_hex_limit; args->stack.log.usim_hex_limit = args->log.all_hex_limit;

@ -38,9 +38,13 @@ std::string ue_stack_lte::get_type()
return "lte"; return "lte";
} }
int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_) int ue_stack_lte::init(const stack_args_t& args_,
srslte::logger* logger_,
phy_interface_stack_lte* phy_,
gw_interface_stack* gw_)
{ {
phy = phy_; phy = phy_;
gw = gw_;
if (init(args_, logger_)) { if (init(args_, logger_)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -60,7 +64,6 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
pdcp_log.init("PDCP", logger); pdcp_log.init("PDCP", logger);
rrc_log.init("RRC ", logger); rrc_log.init("RRC ", logger);
nas_log.init("NAS ", logger); nas_log.init("NAS ", logger);
gw_log.init("GW ", logger);
usim_log.init("USIM", logger); usim_log.init("USIM", logger);
pool_log.init("POOL", logger); pool_log.init("POOL", logger);
@ -72,7 +75,6 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
pdcp_log.set_level(args.log.pdcp_level); pdcp_log.set_level(args.log.pdcp_level);
rrc_log.set_level(args.log.rrc_level); rrc_log.set_level(args.log.rrc_level);
nas_log.set_level(args.log.nas_level); nas_log.set_level(args.log.nas_level);
gw_log.set_level(args.log.gw_level);
usim_log.set_level(args.log.usim_level); usim_log.set_level(args.log.usim_level);
mac_log.set_hex_limit(args.log.mac_hex_limit); mac_log.set_hex_limit(args.log.mac_hex_limit);
@ -80,7 +82,6 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
pdcp_log.set_hex_limit(args.log.pdcp_hex_limit); pdcp_log.set_hex_limit(args.log.pdcp_hex_limit);
rrc_log.set_hex_limit(args.log.rrc_hex_limit); rrc_log.set_hex_limit(args.log.rrc_hex_limit);
nas_log.set_hex_limit(args.log.nas_hex_limit); nas_log.set_hex_limit(args.log.nas_hex_limit);
gw_log.set_hex_limit(args.log.gw_hex_limit);
usim_log.set_hex_limit(args.log.usim_hex_limit); usim_log.set_hex_limit(args.log.usim_hex_limit);
// Set up pcap // Set up pcap
@ -102,10 +103,9 @@ int ue_stack_lte::init(const stack_args_t& args_, srslte::logger* logger_)
mac.init(phy, &rlc, &rrc, &mac_log); mac.init(phy, &rlc, &rrc, &mac_log);
rlc.init(&pdcp, &rrc, &rlc_log, &mac, 0 /* RB_ID_SRB0 */); rlc.init(&pdcp, &rrc, &rlc_log, &mac, 0 /* RB_ID_SRB0 */);
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); pdcp.init(&rlc, &rrc, gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
nas.init(usim.get(), &rrc, &gw, &nas_log, args.nas); nas.init(usim.get(), &rrc, gw, &nas_log, args.nas);
gw.init(&pdcp, &nas, &gw_log, args.gw); rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &mac, &rrc_log, args.rrc);
rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), &gw, &mac, &rrc_log, args.rrc);
running = true; running = true;
@ -124,7 +124,6 @@ void ue_stack_lte::stop()
// Stop RLC and PDCP before GW to avoid locking on queue // Stop RLC and PDCP before GW to avoid locking on queue
rlc.stop(); rlc.stop();
pdcp.stop(); pdcp.stop();
gw.stop();
mac.stop(); mac.stop();
if (args.pcap.enable) { if (args.pcap.enable) {
@ -173,7 +172,6 @@ bool ue_stack_lte::get_metrics(stack_metrics_t* metrics)
if (RRC_STATE_CONNECTED == rrc.get_state()) { if (RRC_STATE_CONNECTED == rrc.get_state()) {
mac.get_metrics(metrics->mac); mac.get_metrics(metrics->mac);
rlc.get_metrics(metrics->rlc); rlc.get_metrics(metrics->rlc);
gw.get_metrics(metrics->gw);
nas.get_metrics(&metrics->nas); nas.get_metrics(&metrics->nas);
return true; return true;
} }
@ -186,4 +184,4 @@ bool ue_stack_lte::is_rrc_connected()
return rrc.is_connected(); return rrc.is_connected();
} }
} } // namespace srsue

@ -39,15 +39,18 @@ gw::gw() : if_up(false), default_lcid(0), thread("GW")
current_ip_addr = 0; current_ip_addr = 0;
} }
void gw::init(pdcp_interface_gw* pdcp_, nas_interface_gw* nas_, srslte::log* gw_log_, gw_args_t args_) int gw::init(const gw_args_t& args_, srslte::logger* logger_, stack_interface_gw* stack_)
{ {
pool = srslte::byte_buffer_pool::get_instance(); pool = srslte::byte_buffer_pool::get_instance();
pdcp = pdcp_; stack = stack_;
nas = nas_; logger = logger_;
gw_log = gw_log_;
args = args_; args = args_;
run_enable = true; run_enable = true;
log.init("GW ", logger);
log.set_level(args.log.gw_level);
log.set_hex_limit(args.log.gw_hex_limit);
gettimeofday(&metrics_time[1], NULL); gettimeofday(&metrics_time[1], NULL);
dl_tput_bytes = 0; dl_tput_bytes = 0;
ul_tput_bytes = 0; ul_tput_bytes = 0;
@ -55,16 +58,20 @@ void gw::init(pdcp_interface_gw* pdcp_, nas_interface_gw* nas_, srslte::log* gw_
// MBSFN // MBSFN
mbsfn_sock_fd = socket(AF_INET, SOCK_DGRAM, 0); mbsfn_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (mbsfn_sock_fd < 0) { if (mbsfn_sock_fd < 0) {
gw_log->error("Failed to create MBSFN sink socket\n"); log.error("Failed to create MBSFN sink socket\n");
return SRSLTE_ERROR;
} }
if (fcntl(mbsfn_sock_fd, F_SETFL, O_NONBLOCK)) { if (fcntl(mbsfn_sock_fd, F_SETFL, O_NONBLOCK)) {
gw_log->error("Failed to set non-blocking MBSFN sink socket\n"); log.error("Failed to set non-blocking MBSFN sink socket\n");
return SRSLTE_ERROR;
} }
mbsfn_sock_addr.sin_family = AF_INET; mbsfn_sock_addr.sin_family = AF_INET;
mbsfn_sock_addr.sin_addr.s_addr =inet_addr("127.0.0.1"); mbsfn_sock_addr.sin_addr.s_addr =inet_addr("127.0.0.1");
bzero(mbsfn_ports, SRSLTE_N_MCH_LCIDS*sizeof(uint32_t)); bzero(mbsfn_ports, SRSLTE_N_MCH_LCIDS*sizeof(uint32_t));
return SRSLTE_SUCCESS;
} }
void gw::stop() void gw::stop()
@ -104,8 +111,7 @@ void gw::get_metrics(gw_metrics_t &m)
m.dl_tput_mbps = (dl_tput_bytes*8/(double)1e6)/secs; m.dl_tput_mbps = (dl_tput_bytes*8/(double)1e6)/secs;
m.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs; m.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs;
gw_log->info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", log.info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", m.dl_tput_mbps, m.ul_tput_mbps);
m.dl_tput_mbps, m.ul_tput_mbps);
memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval));
dl_tput_bytes = 0; dl_tput_bytes = 0;
@ -117,10 +123,10 @@ void gw::get_metrics(gw_metrics_t &m)
*******************************************************************************/ *******************************************************************************/
void gw::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) void gw::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
{ {
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU. Stack latency: %ld us\n", pdu->get_latency_us()); log.info_hex(pdu->msg, pdu->N_bytes, "RX PDU. Stack latency: %ld us\n", pdu->get_latency_us());
dl_tput_bytes += pdu->N_bytes; dl_tput_bytes += pdu->N_bytes;
if (!if_up) { if (!if_up) {
gw_log->warning("TUN/TAP not up - dropping gw RX message\n"); log.warning("TUN/TAP not up - dropping gw RX message\n");
} else { } else {
// Only handle IPv4 and IPv6 packets // Only handle IPv4 and IPv6 packets
struct iphdr* ip_pkt = (struct iphdr*)pdu->msg; struct iphdr* ip_pkt = (struct iphdr*)pdu->msg;
@ -128,10 +134,10 @@ void gw::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
if (ip_pkt->version == 4 || ip_pkt->version == 6) { if (ip_pkt->version == 4 || ip_pkt->version == 6) {
int n = write(tun_fd, pdu->msg, pdu->N_bytes); int n = write(tun_fd, pdu->msg, pdu->N_bytes);
if (n > 0 && (pdu->N_bytes != (uint32_t)n)) { if (n > 0 && (pdu->N_bytes != (uint32_t)n)) {
gw_log->warning("DL TUN/TAP write failure. Wanted to write %d B but only wrote %d B.\n", pdu->N_bytes, n); log.warning("DL TUN/TAP write failure. Wanted to write %d B but only wrote %d B.\n", pdu->N_bytes, n);
} }
} else { } else {
gw_log->error("Unsupported IP version. Dropping packet with %d B\n", pdu->N_bytes); log.error("Unsupported IP version. Dropping packet with %d B\n", pdu->N_bytes);
} }
} }
} }
@ -140,7 +146,8 @@ void gw::write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
{ {
if(pdu->N_bytes>2) if(pdu->N_bytes>2)
{ {
gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX MCH PDU (%d B). Stack latency: %ld us\n", pdu->N_bytes, pdu->get_latency_us()); log.info_hex(
pdu->msg, pdu->N_bytes, "RX MCH PDU (%d B). Stack latency: %ld us\n", pdu->N_bytes, pdu->get_latency_us());
dl_tput_bytes += pdu->N_bytes; dl_tput_bytes += pdu->N_bytes;
//Hack to drop initial 2 bytes //Hack to drop initial 2 bytes
@ -150,11 +157,11 @@ void gw::write_pdu_mch(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
memcpy(&dst_addr.s_addr, &pdu->msg[16],4); memcpy(&dst_addr.s_addr, &pdu->msg[16],4);
if (!if_up) { if (!if_up) {
gw_log->warning("TUN/TAP not up - dropping gw RX message\n"); log.warning("TUN/TAP not up - dropping gw RX message\n");
} else { } else {
int n = write(tun_fd, pdu->msg, pdu->N_bytes); int n = write(tun_fd, pdu->msg, pdu->N_bytes);
if(n > 0 && (pdu->N_bytes != (uint32_t) n) ) { if(n > 0 && (pdu->N_bytes != (uint32_t) n) ) {
gw_log->warning("DL TUN/TAP write failure\n"); log.warning("DL TUN/TAP write failure\n");
} }
} }
} }
@ -168,13 +175,13 @@ int gw::setup_if_addr(uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t
int err; int err;
if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV4 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){ if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV4 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){
err = setup_if_addr4(ip_addr, err_str); err = setup_if_addr4(ip_addr, err_str);
if(err!= SRSLTE_SUCCESS){ if (err != SRSLTE_SUCCESS) {
return err; return err;
} }
} }
if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV6 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){ if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV6 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){
err = setup_if_addr6(ipv6_if_addr, err_str); err = setup_if_addr6(ipv6_if_addr, err_str);
if(err!= SRSLTE_SUCCESS){ if (err != SRSLTE_SUCCESS) {
return err; return err;
} }
} }
@ -194,17 +201,17 @@ int gw::apply_traffic_flow_template(const uint8_t&
switch (tft->tft_op_code) { switch (tft->tft_op_code) {
case LIBLTE_MME_TFT_OPERATION_CODE_CREATE_NEW_TFT: case LIBLTE_MME_TFT_OPERATION_CODE_CREATE_NEW_TFT:
for (int i = 0; i < tft->packet_filter_list_size; i++) { for (int i = 0; i < tft->packet_filter_list_size; i++) {
gw_log->info("New packet filter for TFT\n"); log.info("New packet filter for TFT\n");
tft_packet_filter_t filter(erab_id, lcid, tft->packet_filter_list[i], gw_log); tft_packet_filter_t filter(erab_id, lcid, tft->packet_filter_list[i], &log);
auto it = tft_filter_map.insert(std::make_pair(filter.eval_precedence, filter)); auto it = tft_filter_map.insert(std::make_pair(filter.eval_precedence, filter));
if (it.second == false) { if (it.second == false) {
gw_log->error("Error inserting TFT Packet Filter\n"); log.error("Error inserting TFT Packet Filter\n");
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
} }
break; break;
default: default:
gw_log->error("Unhandled TFT OP code\n"); log.error("Unhandled TFT OP code\n");
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -230,14 +237,14 @@ void gw::run_thread()
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, true); srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, true);
if (!pdu) { if (!pdu) {
gw_log->error("Fatal Error: Couldn't allocate PDU in run_thread().\n"); log.error("Fatal Error: Couldn't allocate PDU in run_thread().\n");
return; return;
} }
const static uint32_t ATTACH_WAIT_TOUT = 40; // 4 sec const static uint32_t ATTACH_WAIT_TOUT = 40; // 4 sec
uint32_t attach_wait = 0; uint32_t attach_wait = 0;
gw_log->info("GW IP packet receiver thread run_enable\n"); log.info("GW IP packet receiver thread run_enable\n");
running = true; running = true;
while(run_enable) while(run_enable)
@ -245,11 +252,11 @@ void gw::run_thread()
if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) { if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) {
N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx);
} else { } else {
gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); log.error("GW pdu buffer full - gw receive thread exiting.\n");
gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); log.console("GW pdu buffer full - gw receive thread exiting.\n");
break; break;
} }
gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx); log.debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx);
if (N_bytes > 0) { if (N_bytes > 0) {
struct iphdr *ip_pkt = (struct iphdr*)pdu->msg; struct iphdr *ip_pkt = (struct iphdr*)pdu->msg;
struct ipv6hdr *ip6_pkt = (struct ipv6hdr*)pdu->msg; struct ipv6hdr *ip6_pkt = (struct ipv6hdr*)pdu->msg;
@ -261,20 +268,20 @@ void gw::run_thread()
} else if (ip_pkt->version == 6){ } else if (ip_pkt->version == 6){
pkt_len = ntohs(ip6_pkt->payload_len)+40; pkt_len = ntohs(ip6_pkt->payload_len)+40;
} else { } else {
gw_log->error_hex(pdu->msg, pdu->N_bytes, "Unsupported IP version. Dropping packet.\n"); log.error_hex(pdu->msg, pdu->N_bytes, "Unsupported IP version. Dropping packet.\n");
continue; continue;
} }
gw_log->debug("IPv%d packet total length: %d Bytes\n", ip_pkt->version, pkt_len); log.debug("IPv%d packet total length: %d Bytes\n", ip_pkt->version, pkt_len);
// Check if entire packet was received // Check if entire packet was received
if (pkt_len == pdu->N_bytes) { if (pkt_len == pdu->N_bytes) {
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); log.info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
while (run_enable && !pdcp->is_lcid_enabled(default_lcid) && attach_wait < ATTACH_WAIT_TOUT) { while (run_enable && !stack->is_lcid_enabled(default_lcid) && attach_wait < ATTACH_WAIT_TOUT) {
if (!attach_wait) { if (!attach_wait) {
gw_log->info( log.info(
"LCID=%d not active, requesting NAS attach (%d/%d)\n", default_lcid, attach_wait, ATTACH_WAIT_TOUT); "LCID=%d not active, requesting NAS attach (%d/%d)\n", default_lcid, attach_wait, ATTACH_WAIT_TOUT);
if (!nas->attach_request()) { if (not stack->switch_on()) {
gw_log->warning("Could not re-establish the connection\n"); log.warning("Could not re-establish the connection\n");
} }
} }
usleep(100000); usleep(100000);
@ -289,14 +296,14 @@ void gw::run_thread()
uint8_t lcid = check_tft_filter_match(pdu); uint8_t lcid = check_tft_filter_match(pdu);
// Send PDU directly to PDCP // Send PDU directly to PDCP
if (pdcp->is_lcid_enabled(lcid)) { if (stack->is_lcid_enabled(lcid)) {
pdu->set_timestamp(); pdu->set_timestamp();
ul_tput_bytes += pdu->N_bytes; ul_tput_bytes += pdu->N_bytes;
pdcp->write_sdu(lcid, std::move(pdu), false); stack->write_sdu(lcid, std::move(pdu), false);
do { do {
pdu = srslte::allocate_unique_buffer(*pool); pdu = srslte::allocate_unique_buffer(*pool);
if (!pdu) { if (!pdu) {
gw_log->error("Fatal Error: Couldn't allocate PDU in run_thread().\n"); log.error("Fatal Error: Couldn't allocate PDU in run_thread().\n");
usleep(100000); usleep(100000);
} }
} while(!pdu); } while(!pdu);
@ -304,19 +311,20 @@ void gw::run_thread()
} }
}else{ }else{
idx += N_bytes; idx += N_bytes;
gw_log->debug("Entire packet not read from socket. Total Length %d, N_Bytes %d.\n", ip_pkt->tot_len, pdu->N_bytes); log.debug(
"Entire packet not read from socket. Total Length %d, N_Bytes %d.\n", ip_pkt->tot_len, pdu->N_bytes);
} }
} else { } else {
gw_log->error("IP Version not handled. Version %d\n", ip_pkt->version); log.error("IP Version not handled. Version %d\n", ip_pkt->version);
} }
}else{ }else{
gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n"); log.error("Failed to read from TUN interface - gw receive thread exiting.\n");
gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n"); log.console("Failed to read from TUN interface - gw receive thread exiting.\n");
break; break;
} }
} }
running = false; running = false;
gw_log->info("GW IP receiver thread exiting.\n"); log.info("GW IP receiver thread exiting.\n");
} }
uint8_t gw::check_tft_filter_match(const srslte::unique_byte_buffer_t& pdu) uint8_t gw::check_tft_filter_match(const srslte::unique_byte_buffer_t& pdu)
@ -327,7 +335,7 @@ uint8_t gw::check_tft_filter_match(const srslte::unique_byte_buffer_t& pdu)
bool match = filter_pair.second.match(pdu); bool match = filter_pair.second.match(pdu);
if (match) { if (match) {
lcid = filter_pair.second.lcid; lcid = filter_pair.second.lcid;
gw_log->debug("Found filter match -- EPS bearer Id %d, LCID %d\n", filter_pair.second.eps_bearer_id, lcid); log.debug("Found filter match -- EPS bearer Id %d, LCID %d\n", filter_pair.second.eps_bearer_id, lcid);
break; break;
} }
} }
@ -337,7 +345,7 @@ uint8_t gw::check_tft_filter_match(const srslte::unique_byte_buffer_t& pdu)
/**************************/ /**************************/
/* TUN Interface Helpers */ /* TUN Interface Helpers */
/**************************/ /**************************/
int gw::init_if(char *err_str) int gw::init_if(char* err_str)
{ {
if (if_up) { if (if_up) {
return SRSLTE_ERROR_ALREADY_STARTED; return SRSLTE_ERROR_ALREADY_STARTED;
@ -345,10 +353,10 @@ int gw::init_if(char *err_str)
// Construct the TUN device // Construct the TUN device
tun_fd = open("/dev/net/tun", O_RDWR); tun_fd = open("/dev/net/tun", O_RDWR);
gw_log->info("TUN file descriptor = %d\n", tun_fd); log.info("TUN file descriptor = %d\n", tun_fd);
if (0 > tun_fd) { if (0 > tun_fd) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to open TUN device: %s\n", err_str); log.debug("Failed to open TUN device: %s\n", err_str);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -359,7 +367,7 @@ int gw::init_if(char *err_str)
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0; ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0;
if (0 > ioctl(tun_fd, TUNSETIFF, &ifr)) { if (0 > ioctl(tun_fd, TUNSETIFF, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to set TUN device name: %s\n", err_str); log.debug("Failed to set TUN device name: %s\n", err_str);
close(tun_fd); close(tun_fd);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -368,14 +376,14 @@ int gw::init_if(char *err_str)
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
if (0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) { if (0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to bring up socket: %s\n", err_str); log.debug("Failed to bring up socket: %s\n", err_str);
close(tun_fd); close(tun_fd);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
ifr.ifr_flags |= IFF_UP | IFF_RUNNING; ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if (0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) { if (0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to set socket flags: %s\n", err_str); log.debug("Failed to set socket flags: %s\n", err_str);
close(tun_fd); close(tun_fd);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -384,22 +392,22 @@ int gw::init_if(char *err_str)
struct in6_addr in6p; struct in6_addr in6p;
char addr_str[INET6_ADDRSTRLEN]; char addr_str[INET6_ADDRSTRLEN];
if(find_ipv6_addr(&in6p)){ if(find_ipv6_addr(&in6p)){
gw_log->debug("Found link-local IPv6 address: %s\n",inet_ntop(AF_INET6, &in6p, addr_str,INET6_ADDRSTRLEN) ); log.debug("Found link-local IPv6 address: %s\n", inet_ntop(AF_INET6, &in6p, addr_str, INET6_ADDRSTRLEN));
del_ipv6_addr(&in6p); del_ipv6_addr(&in6p);
} else { } else {
gw_log->warning("Could not find link-local IPv6 address.\n"); log.warning("Could not find link-local IPv6 address.\n");
} }
if_up = true; if_up = true;
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int gw::setup_if_addr4(uint32_t ip_addr, char *err_str) int gw::setup_if_addr4(uint32_t ip_addr, char* err_str)
{ {
if (ip_addr != current_ip_addr) { if (ip_addr != current_ip_addr) {
if (!if_up) { if (!if_up) {
if (init_if(err_str)) { if (init_if(err_str)) {
gw_log->error("init_if failed\n"); log.error("init_if failed\n");
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
} }
@ -410,7 +418,7 @@ int gw::setup_if_addr4(uint32_t ip_addr, char *err_str)
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr); ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip_addr);
if (0 > ioctl(sock, SIOCSIFADDR, &ifr)) { if (0 > ioctl(sock, SIOCSIFADDR, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to set socket address: %s\n", err_str); log.debug("Failed to set socket address: %s\n", err_str);
close(tun_fd); close(tun_fd);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -418,7 +426,7 @@ int gw::setup_if_addr4(uint32_t ip_addr, char *err_str)
((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(args.tun_dev_netmask.c_str()); ((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr(args.tun_dev_netmask.c_str());
if (0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) { if (0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->debug("Failed to set socket netmask: %s\n", err_str); log.debug("Failed to set socket netmask: %s\n", err_str);
close(tun_fd); close(tun_fd);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -427,7 +435,7 @@ int gw::setup_if_addr4(uint32_t ip_addr, char *err_str)
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
int gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) int gw::setup_if_addr6(uint8_t* ipv6_if_id, char* err_str)
{ {
struct sockaddr_in6 sai; struct sockaddr_in6 sai;
struct in6_ifreq ifr6; struct in6_ifreq ifr6;
@ -443,7 +451,7 @@ int gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str)
if (!match) { if (!match) {
if (!if_up) { if (!if_up) {
if( init_if(err_str) ) { if( init_if(err_str) ) {
gw_log->error("init_if failed\n"); log.error("init_if failed\n");
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
} }
@ -453,7 +461,7 @@ int gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str)
ifr.ifr_addr.sa_family = AF_INET6; ifr.ifr_addr.sa_family = AF_INET6;
if(inet_pton(AF_INET6, "fe80::", (void *)&sai.sin6_addr) <= 0) { if(inet_pton(AF_INET6, "fe80::", (void *)&sai.sin6_addr) <= 0) {
gw_log->error("Bad address\n"); log.error("Bad address\n");
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -469,7 +477,7 @@ int gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str)
if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) {
err_str = strerror(errno); err_str = strerror(errno);
gw_log->error("Could not set IPv6 Link local address. Error %s\n", err_str); log.error("Could not set IPv6 Link local address. Error %s\n", err_str);
return SRSLTE_ERROR_CANT_START; return SRSLTE_ERROR_CANT_START;
} }
@ -496,19 +504,19 @@ bool gw::find_ipv6_addr(struct in6_addr *in6_out)
char buf[1024]; char buf[1024];
} req; } req;
gw_log->debug("Trying to obtain IPv6 addr of %s interface\n", args.tun_dev_name.c_str()); log.debug("Trying to obtain IPv6 addr of %s interface\n", args.tun_dev_name.c_str());
//Get Interface Index //Get Interface Index
if_index = if_nametoindex(args.tun_dev_name.c_str()); if_index = if_nametoindex(args.tun_dev_name.c_str());
if(if_index == 0){ if(if_index == 0){
gw_log->error("Could not find interface index\n"); log.error("Could not find interface index\n");
goto err_out; goto err_out;
} }
// Open NETLINK socket // Open NETLINK socket
fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (fd < 0) { if (fd < 0) {
gw_log->error("Error openning NETLINK socket -- %s\n", strerror(errno)); log.error("Error openning NETLINK socket -- %s\n", strerror(errno));
goto err_out; goto err_out;
} }
@ -529,18 +537,18 @@ bool gw::find_ipv6_addr(struct in6_addr *in6_out)
// Time to send and recv the message from kernel // Time to send and recv the message from kernel
n = send(fd, &req, req.n.nlmsg_len, 0); n = send(fd, &req, req.n.nlmsg_len, 0);
if (n < 0) { if (n < 0) {
gw_log->error("Error sending NETLINK message to kernel -- %s", strerror(errno)); log.error("Error sending NETLINK message to kernel -- %s", strerror(errno));
goto err_out; goto err_out;
} }
n = recv(fd, buf, sizeof(buf), 0); n = recv(fd, buf, sizeof(buf), 0);
if (n < 0) { if (n < 0) {
gw_log->error("Error receiving from NETLINK socket\n"); log.error("Error receiving from NETLINK socket\n");
goto err_out; goto err_out;
} }
if (n == 0) { if (n == 0) {
gw_log->error("Nothing received from NETLINK Socket\n"); log.error("Nothing received from NETLINK Socket\n");
goto err_out; goto err_out;
} }
@ -548,15 +556,15 @@ bool gw::find_ipv6_addr(struct in6_addr *in6_out)
for (nlmp = (struct nlmsghdr *)buf; NLMSG_OK (nlmp, n); nlmp = NLMSG_NEXT (nlmp, n)){ for (nlmp = (struct nlmsghdr *)buf; NLMSG_OK (nlmp, n); nlmp = NLMSG_NEXT (nlmp, n)){
//Chack NL message type //Chack NL message type
if (nlmp->nlmsg_type == NLMSG_DONE){ if (nlmp->nlmsg_type == NLMSG_DONE) {
gw_log->error("Reach end of NETLINK message without finding IPv6 address.\n"); log.error("Reach end of NETLINK message without finding IPv6 address.\n");
goto err_out; goto err_out;
} }
if (nlmp->nlmsg_type == NLMSG_ERROR) { if (nlmp->nlmsg_type == NLMSG_ERROR) {
gw_log->error("NLMSG_ERROR in NETLINK reply\n"); log.error("NLMSG_ERROR in NETLINK reply\n");
goto err_out; goto err_out;
} }
gw_log->debug("NETLINK message type %d\n", nlmp->nlmsg_type); log.debug("NETLINK message type %d\n", nlmp->nlmsg_type);
//Get IFA message //Get IFA message
rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp); rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp);
@ -600,14 +608,14 @@ void gw::del_ipv6_addr(struct in6_addr *in6p)
//Get Interface Index //Get Interface Index
if_index = if_nametoindex(args.tun_dev_name.c_str()); if_index = if_nametoindex(args.tun_dev_name.c_str());
if(if_index == 0){ if(if_index == 0){
gw_log->error("Could not find interface index\n"); log.error("Could not find interface index\n");
goto out; goto out;
} }
// Open netlink socket // Open netlink socket
fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (fd < 0) { if (fd < 0) {
gw_log->error("Error openning NETLINK socket -- %s\n", strerror(errno)); log.error("Error openning NETLINK socket -- %s\n", strerror(errno));
goto out; goto out;
} }
@ -632,7 +640,7 @@ void gw::del_ipv6_addr(struct in6_addr *in6p)
status = send(fd, &req, req.n.nlmsg_len, 0); status = send(fd, &req, req.n.nlmsg_len, 0);
if (status < 0) { if (status < 0) {
gw_log->error("Error sending NETLINK message\n"); log.error("Error sending NETLINK message\n");
goto out; goto out;
} }

@ -79,6 +79,12 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
std::unique_ptr<gw> gw_ptr(new gw());
if (!gw_ptr) {
log.console("Error creating a GW instance.\n");
return SRSLTE_ERROR;
}
std::unique_ptr<srsue::phy> lte_phy = std::unique_ptr<srsue::phy>(new srsue::phy()); std::unique_ptr<srsue::phy> lte_phy = std::unique_ptr<srsue::phy>(new srsue::phy());
if (!lte_phy) { if (!lte_phy) {
log.console("Error creating LTE PHY instance.\n"); log.console("Error creating LTE PHY instance.\n");
@ -102,13 +108,19 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_)
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (lte_stack->init(args.stack, logger, lte_phy.get())) { if (lte_stack->init(args.stack, logger, lte_phy.get(), gw_ptr.get())) {
log.console("Error initializing stack.\n"); log.console("Error initializing stack.\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (gw_ptr->init(args.gw, logger, lte_stack.get())) {
log.console("Error initializing GW.\n");
return SRSLTE_ERROR;
}
// move ownership // move ownership
stack = std::move(lte_stack); stack = std::move(lte_stack);
gw_inst = std::move(gw_ptr);
phy = std::move(lte_phy); phy = std::move(lte_phy);
radio = std::move(lte_radio); radio = std::move(lte_radio);
} else { } else {
@ -206,6 +218,10 @@ void ue::stop()
stack->stop(); stack->stop();
} }
if (gw_inst) {
gw_inst->stop();
}
if (phy) { if (phy) {
phy->stop(); phy->stop();
} }
@ -239,6 +255,7 @@ bool ue::get_metrics(ue_metrics_t* m)
phy->get_metrics(&m->phy); phy->get_metrics(&m->phy);
radio->get_metrics(&m->rf); radio->get_metrics(&m->rf);
stack->get_metrics(&m->stack); stack->get_metrics(&m->stack);
gw_inst->get_metrics(m->stack.gw);
return true; return true;
} }

@ -137,6 +137,22 @@ private:
found_plmn_t plmns; found_plmn_t plmns;
}; };
class stack_dummy : public stack_interface_gw
{
public:
stack_dummy(pdcp_interface_gw* pdcp_, srsue::nas* nas_) : pdcp(pdcp_), nas(nas_) {}
bool switch_on() final { return nas->attach_request(); }
void write_sdu(uint32_t lcid, srslte::unique_byte_buffer_t sdu, bool blocking)
{
pdcp->write_sdu(lcid, std::move(sdu), blocking);
}
bool is_lcid_enabled(uint32_t lcid) { return pdcp->is_lcid_enabled(lcid); }
pdcp_interface_gw* pdcp = nullptr;
srsue::nas* nas = nullptr;
bool running = false;
};
class gw_dummy : public gw_interface_nas, public gw_interface_pdcp class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
{ {
int setup_if_addr(uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str) int setup_if_addr(uint32_t lcid, uint8_t pdn_type, uint32_t ip_addr, uint8_t* ipv6_if_id, char* err_str)
@ -256,15 +272,20 @@ int mme_attach_request_test()
nas_cfg.apn_name = "test123"; nas_cfg.apn_name = "test123";
srsue::nas nas; srsue::nas nas;
srsue::gw gw; srsue::gw gw;
stack_dummy stack(&pdcp_dummy, &nas);
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg); nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
gw_args_t gw_args; gw_args_t gw_args;
gw_args.tun_dev_name = "tun0"; gw_args.tun_dev_name = "tun0";
gw.init(&pdcp_dummy, &nas, &gw_log, gw_args); gw_args.log.gw_level = "debug";
gw_args.log.gw_hex_limit = 100000;
srslte::logger_stdout def_logstdout;
srslte::logger* logger = &def_logstdout;
gw.init(gw_args, logger, &stack);
// trigger test // trigger test
nas.attach_request(); stack.switch_on();
// this will time out in the first place // this will time out in the first place

Loading…
Cancel
Save