From 10a56e2a8459b69f972259d08e15ef0f965063e5 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 19 Jun 2019 19:12:33 +0100 Subject: [PATCH] moved GW out of the UE stack. This is important to keep concurrency out of the stack once it becomes single-threaded --- lib/include/srslte/interfaces/ue_interfaces.h | 25 ++- srsue/hdr/stack/ue_stack_lte.h | 39 +++-- srsue/hdr/stack/upper/gw.h | 25 ++- srsue/hdr/ue.h | 2 + srsue/src/main.cc | 12 +- srsue/src/stack/ue_stack_lte.cc | 20 ++- srsue/src/stack/upper/gw.cc | 152 +++++++++--------- srsue/src/ue.cc | 19 ++- srsue/test/upper/nas_test.cc | 25 ++- 9 files changed, 191 insertions(+), 128 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 542424bca..a1abc8f45 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -223,13 +223,6 @@ public: 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 class pdcp_interface_rrc @@ -270,6 +263,13 @@ public: 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 class rlc_interface_rrc { @@ -921,6 +921,17 @@ public: 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) class stack_interface_phy_lte : public mac_interface_phy_lte, public rrc_interface_phy_lte { diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index 8b6cff320..acb652169 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -35,7 +35,6 @@ #include "srslte/radio/radio.h" #include "srslte/upper/pdcp.h" #include "srslte/upper/rlc.h" -#include "upper/gw.h" #include "upper/nas.h" #include "upper/usim.h" @@ -48,7 +47,7 @@ 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: ue_stack_lte(); @@ -57,8 +56,8 @@ public: std::string get_type(); 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_); - bool switch_on(); + int init(const stack_args_t& args_, srslte::logger* logger_, phy_interface_stack_lte* phy_, gw_interface_stack* gw_); + bool switch_on() final; bool switch_off(); void stop(); @@ -102,21 +101,18 @@ public: 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: bool running; 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 srsue::mac mac; srslte::mac_pcap mac_pcap; @@ -125,11 +121,22 @@ private: srslte::pdcp pdcp; srsue::rrc rrc; srsue::nas nas; - srsue::gw gw; std::unique_ptr 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 phy_interface_stack_lte* phy; + gw_interface_stack* gw; }; } // namespace srsue diff --git a/srsue/hdr/stack/upper/gw.h b/srsue/hdr/stack/upper/gw.h index f89605c52..86626c789 100644 --- a/srsue/hdr/stack/upper/gw.h +++ b/srsue/hdr/stack/upper/gw.h @@ -27,6 +27,7 @@ #include "srslte/common/common.h" #include "srslte/common/interfaces_common.h" #include "srslte/common/log.h" +#include "srslte/common/log_filter.h" #include "srslte/common/threads.h" #include "srslte/interfaces/ue_interfaces.h" #include "tft_packet_filter.h" @@ -35,22 +36,20 @@ namespace srsue { -class gw_args_t -{ -public: +struct gw_args_t { + struct log_args_t { + std::string gw_level; + int gw_hex_limit; + } log; std::string tun_dev_name; std::string tun_dev_netmask; }; -class gw - :public gw_interface_pdcp - ,public gw_interface_nas - ,public gw_interface_rrc - ,public thread +class gw : public gw_interface_stack, public thread { public: 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 get_metrics(gw_metrics_t &m); @@ -71,11 +70,9 @@ public: private: static const int GW_THREAD_PRIO = 7; - pdcp_interface_gw *pdcp; - nas_interface_gw *nas; - + stack_interface_gw* stack; srslte::byte_buffer_pool *pool; - srslte::log *gw_log; + srslte::logger* logger; gw_args_t args; @@ -87,6 +84,8 @@ private: bool if_up; uint32_t default_lcid = 0; + srslte::log_filter log; + uint32_t current_ip_addr; uint8_t current_if_id[8]; diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 2bd0f50f9..2c4967e8c 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -79,6 +79,7 @@ typedef struct { phy_args_t phy; stack_args_t stack; + gw_args_t gw; expert_args_t expert; } all_args_t; @@ -110,6 +111,7 @@ private: std::unique_ptr radio; std::unique_ptr phy; std::unique_ptr stack; + std::unique_ptr gw_inst; // Generic logger members srslte::logger* logger = nullptr; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 8cd59ac3d..0ab9f0312 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -120,8 +120,8 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("log.pdcp_hex_limit", bpo::value(&args->stack.log.pdcp_hex_limit), "PDCP log hex dump limit") ("log.rrc_level", bpo::value(&args->stack.log.rrc_level), "RRC log level") ("log.rrc_hex_limit", bpo::value(&args->stack.log.rrc_hex_limit), "RRC log hex dump limit") - ("log.gw_level", bpo::value(&args->stack.log.gw_level), "GW log level") - ("log.gw_hex_limit", bpo::value(&args->stack.log.gw_hex_limit), "GW log hex dump limit") + ("log.gw_level", bpo::value(&args->gw.log.gw_level), "GW log level") + ("log.gw_hex_limit", bpo::value(&args->gw.log.gw_hex_limit), "GW log hex dump limit") ("log.nas_level", bpo::value(&args->stack.log.nas_level), "NAS log level") ("log.nas_hex_limit", bpo::value(&args->stack.log.nas_hex_limit), "NAS log hex dump limit") ("log.usim_level", bpo::value(&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(&args->stack.usim.pin), "PIN in case real SIM card is used") ("usim.reader", bpo::value(&args->stack.usim.reader)->default_value(""), "Force specific PCSC reader. Default: Try all available readers.") - ("gw.ip_devname", bpo::value(&args->stack.gw.tun_dev_name)->default_value("tun_srsue"), "Name of the tun_srsue device") - ("gw.ip_netmask", bpo::value(&args->stack.gw.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the tun_srsue device") + ("gw.ip_devname", bpo::value(&args->gw.tun_dev_name)->default_value("tun_srsue"), "Name of the tun_srsue device") + ("gw.ip_netmask", bpo::value(&args->gw.tun_dev_netmask)->default_value("255.255.255.0"), "Netmask of the tun_srsue device") /* Downlink Channel emulator section */ ("channel.dl.enable", bpo::value(&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; } 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")) { 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; } 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")) { args->stack.log.usim_hex_limit = args->log.all_hex_limit; diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index b630275ec..8269cb2c5 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -38,9 +38,13 @@ std::string ue_stack_lte::get_type() 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_; + gw = gw_; if (init(args_, logger_)) { 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); rrc_log.init("RRC ", logger); nas_log.init("NAS ", logger); - gw_log.init("GW ", logger); usim_log.init("USIM", 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); rrc_log.set_level(args.log.rrc_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); 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); rrc_log.set_hex_limit(args.log.rrc_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); // 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); 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); - 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); + pdcp.init(&rlc, &rrc, gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); + nas.init(usim.get(), &rrc, gw, &nas_log, args.nas); + rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &mac, &rrc_log, args.rrc); running = true; @@ -124,7 +124,6 @@ void ue_stack_lte::stop() // Stop RLC and PDCP before GW to avoid locking on queue rlc.stop(); pdcp.stop(); - gw.stop(); mac.stop(); 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()) { mac.get_metrics(metrics->mac); rlc.get_metrics(metrics->rlc); - gw.get_metrics(metrics->gw); nas.get_metrics(&metrics->nas); return true; } @@ -186,4 +184,4 @@ bool ue_stack_lte::is_rrc_connected() return rrc.is_connected(); } -} \ No newline at end of file +} // namespace srsue diff --git a/srsue/src/stack/upper/gw.cc b/srsue/src/stack/upper/gw.cc index a87c4ae33..a65961149 100644 --- a/srsue/src/stack/upper/gw.cc +++ b/srsue/src/stack/upper/gw.cc @@ -39,15 +39,18 @@ gw::gw() : if_up(false), default_lcid(0), thread("GW") 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(); - pdcp = pdcp_; - nas = nas_; - gw_log = gw_log_; + stack = stack_; + logger = logger_; args = args_; 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); dl_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_sock_fd = socket(AF_INET, SOCK_DGRAM, 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)) { - 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_addr.s_addr =inet_addr("127.0.0.1"); bzero(mbsfn_ports, SRSLTE_N_MCH_LCIDS*sizeof(uint32_t)); + + return SRSLTE_SUCCESS; } 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.ul_tput_mbps = (ul_tput_bytes*8/(double)1e6)/secs; - gw_log->info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", - m.dl_tput_mbps, m.ul_tput_mbps); + log.info("RX throughput: %4.6f Mbps. TX throughput: %4.6f Mbps.\n", m.dl_tput_mbps, m.ul_tput_mbps); memcpy(&metrics_time[1], &metrics_time[2], sizeof(struct timeval)); 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) { - 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; 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 { // Only handle IPv4 and IPv6 packets 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) { int n = write(tun_fd, pdu->msg, pdu->N_bytes); 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 { - 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) { - 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; //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); 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 { int n = write(tun_fd, pdu->msg, pdu->N_bytes); 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; if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV4 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){ err = setup_if_addr4(ip_addr, err_str); - if(err!= SRSLTE_SUCCESS){ + if (err != SRSLTE_SUCCESS) { return err; } } if(pdn_type == LIBLTE_MME_PDN_TYPE_IPV6 || pdn_type == LIBLTE_MME_PDN_TYPE_IPV4V6 ){ err = setup_if_addr6(ipv6_if_addr, err_str); - if(err!= SRSLTE_SUCCESS){ + if (err != SRSLTE_SUCCESS) { return err; } } @@ -194,17 +201,17 @@ int gw::apply_traffic_flow_template(const uint8_t& switch (tft->tft_op_code) { case LIBLTE_MME_TFT_OPERATION_CODE_CREATE_NEW_TFT: for (int i = 0; i < tft->packet_filter_list_size; i++) { - gw_log->info("New packet filter for TFT\n"); - tft_packet_filter_t filter(erab_id, lcid, tft->packet_filter_list[i], gw_log); + log.info("New packet filter for TFT\n"); + 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)); 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; } } break; default: - gw_log->error("Unhandled TFT OP code\n"); + log.error("Unhandled TFT OP code\n"); return SRSLTE_ERROR_CANT_START; } return SRSLTE_SUCCESS; @@ -230,14 +237,14 @@ void gw::run_thread() srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, true); 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; } const static uint32_t ATTACH_WAIT_TOUT = 40; // 4 sec 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; while(run_enable) @@ -245,11 +252,11 @@ void gw::run_thread() 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); } else { - gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); - gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); + log.error("GW pdu buffer full - gw receive thread exiting.\n"); + log.console("GW pdu buffer full - gw receive thread exiting.\n"); 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) { struct iphdr *ip_pkt = (struct iphdr*)pdu->msg; struct ipv6hdr *ip6_pkt = (struct ipv6hdr*)pdu->msg; @@ -261,20 +268,20 @@ void gw::run_thread() } else if (ip_pkt->version == 6){ pkt_len = ntohs(ip6_pkt->payload_len)+40; } 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; } - 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 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) { - gw_log->info( + log.info( "LCID=%d not active, requesting NAS attach (%d/%d)\n", default_lcid, attach_wait, ATTACH_WAIT_TOUT); - if (!nas->attach_request()) { - gw_log->warning("Could not re-establish the connection\n"); + if (not stack->switch_on()) { + log.warning("Could not re-establish the connection\n"); } } usleep(100000); @@ -289,14 +296,14 @@ void gw::run_thread() uint8_t lcid = check_tft_filter_match(pdu); // Send PDU directly to PDCP - if (pdcp->is_lcid_enabled(lcid)) { + if (stack->is_lcid_enabled(lcid)) { pdu->set_timestamp(); ul_tput_bytes += pdu->N_bytes; - pdcp->write_sdu(lcid, std::move(pdu), false); + stack->write_sdu(lcid, std::move(pdu), false); do { pdu = srslte::allocate_unique_buffer(*pool); 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); } } while(!pdu); @@ -304,30 +311,31 @@ void gw::run_thread() } }else{ 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 { - 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{ - gw_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.error("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; } } 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) { std::lock_guard lock(tft_mutex); - uint8_t lcid = default_lcid; + uint8_t lcid = default_lcid; for (std::pair& filter_pair : tft_filter_map) { bool match = filter_pair.second.match(pdu); if (match) { 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; } } @@ -337,7 +345,7 @@ uint8_t gw::check_tft_filter_match(const srslte::unique_byte_buffer_t& pdu) /**************************/ /* TUN Interface Helpers */ /**************************/ -int gw::init_if(char *err_str) +int gw::init_if(char* err_str) { if (if_up) { return SRSLTE_ERROR_ALREADY_STARTED; @@ -345,10 +353,10 @@ int gw::init_if(char *err_str) // Construct the TUN device 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) { 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; } @@ -359,7 +367,7 @@ int gw::init_if(char *err_str) ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1] = 0; if (0 > ioctl(tun_fd, TUNSETIFF, &ifr)) { 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); return SRSLTE_ERROR_CANT_START; } @@ -368,14 +376,14 @@ int gw::init_if(char *err_str) sock = socket(AF_INET, SOCK_DGRAM, 0); if (0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) { 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); return SRSLTE_ERROR_CANT_START; } ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) { 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); return SRSLTE_ERROR_CANT_START; } @@ -384,22 +392,22 @@ int gw::init_if(char *err_str) struct in6_addr in6p; char addr_str[INET6_ADDRSTRLEN]; 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); } 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; 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 (!if_up) { if (init_if(err_str)) { - gw_log->error("init_if failed\n"); + log.error("init_if failed\n"); 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); if (0 > ioctl(sock, SIOCSIFADDR, &ifr)) { 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); 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()); if (0 > ioctl(sock, SIOCSIFNETMASK, &ifr)) { 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); return SRSLTE_ERROR_CANT_START; } @@ -427,7 +435,7 @@ int gw::setup_if_addr4(uint32_t ip_addr, char *err_str) 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 in6_ifreq ifr6; @@ -443,7 +451,7 @@ int gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) if (!match) { if (!if_up) { if( init_if(err_str) ) { - gw_log->error("init_if failed\n"); + log.error("init_if failed\n"); 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; 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; } @@ -469,7 +477,7 @@ int gw::setup_if_addr6(uint8_t *ipv6_if_id, char *err_str) if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { 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; } @@ -496,19 +504,19 @@ bool gw::find_ipv6_addr(struct in6_addr *in6_out) char buf[1024]; } 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 if_index = if_nametoindex(args.tun_dev_name.c_str()); if(if_index == 0){ - gw_log->error("Could not find interface index\n"); + log.error("Could not find interface index\n"); goto err_out; } // Open NETLINK socket fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 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; } @@ -529,18 +537,18 @@ bool gw::find_ipv6_addr(struct in6_addr *in6_out) // Time to send and recv the message from kernel n = send(fd, &req, req.n.nlmsg_len, 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; } n = recv(fd, buf, sizeof(buf), 0); if (n < 0) { - gw_log->error("Error receiving from NETLINK socket\n"); + log.error("Error receiving from NETLINK socket\n"); goto err_out; } if (n == 0) { - gw_log->error("Nothing received from NETLINK Socket\n"); + log.error("Nothing received from NETLINK Socket\n"); 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)){ //Chack NL message type - if (nlmp->nlmsg_type == NLMSG_DONE){ - gw_log->error("Reach end of NETLINK message without finding IPv6 address.\n"); + if (nlmp->nlmsg_type == NLMSG_DONE) { + log.error("Reach end of NETLINK message without finding IPv6 address.\n"); goto err_out; } 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; } - gw_log->debug("NETLINK message type %d\n", nlmp->nlmsg_type); + log.debug("NETLINK message type %d\n", nlmp->nlmsg_type); //Get IFA message rtmp = (struct ifaddrmsg *)NLMSG_DATA(nlmp); @@ -600,14 +608,14 @@ void gw::del_ipv6_addr(struct in6_addr *in6p) //Get Interface Index if_index = if_nametoindex(args.tun_dev_name.c_str()); if(if_index == 0){ - gw_log->error("Could not find interface index\n"); + log.error("Could not find interface index\n"); goto out; } // Open netlink socket fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 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; } @@ -632,7 +640,7 @@ void gw::del_ipv6_addr(struct in6_addr *in6p) status = send(fd, &req, req.n.nlmsg_len, 0); if (status < 0) { - gw_log->error("Error sending NETLINK message\n"); + log.error("Error sending NETLINK message\n"); goto out; } diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 9ed1bd0ae..358d9a5fb 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -79,6 +79,12 @@ int ue::init(const all_args_t& args_, srslte::logger* logger_) return SRSLTE_ERROR; } + std::unique_ptr gw_ptr(new gw()); + if (!gw_ptr) { + log.console("Error creating a GW instance.\n"); + return SRSLTE_ERROR; + } + std::unique_ptr lte_phy = std::unique_ptr(new srsue::phy()); if (!lte_phy) { 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; } - 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"); return SRSLTE_ERROR; } + if (gw_ptr->init(args.gw, logger, lte_stack.get())) { + log.console("Error initializing GW.\n"); + return SRSLTE_ERROR; + } + // move ownership stack = std::move(lte_stack); + gw_inst = std::move(gw_ptr); phy = std::move(lte_phy); radio = std::move(lte_radio); } else { @@ -206,6 +218,10 @@ void ue::stop() stack->stop(); } + if (gw_inst) { + gw_inst->stop(); + } + if (phy) { phy->stop(); } @@ -239,6 +255,7 @@ bool ue::get_metrics(ue_metrics_t* m) phy->get_metrics(&m->phy); radio->get_metrics(&m->rf); stack->get_metrics(&m->stack); + gw_inst->get_metrics(m->stack.gw); return true; } diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 4ce45b8db..b467638c9 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -137,6 +137,22 @@ private: 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 { 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"; srsue::nas nas; srsue::gw gw; + stack_dummy stack(&pdcp_dummy, &nas); nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg); gw_args_t gw_args; 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 - nas.attach_request(); + stack.switch_on(); // this will time out in the first place