diff --git a/srsepc/hdr/hss/hss.h b/srsepc/hdr/hss/hss.h index 19f25769b..88227af87 100644 --- a/srsepc/hdr/hss/hss.h +++ b/srsepc/hdr/hss/hss.h @@ -69,6 +69,7 @@ typedef struct { uint8_t sqn[6]; uint16_t qci; uint8_t last_rand[16]; + std::string static_ip_addr; } hss_ue_ctx_t; class hss : public hss_interface_nas @@ -84,6 +85,8 @@ public: virtual bool resync_sqn(uint64_t imsi, uint8_t* auts); + std::map get_ip_to_imsi() const; + private: hss(); virtual ~hss(); @@ -125,6 +128,8 @@ private: uint16_t mcc; uint16_t mnc; + + std::map m_ip_to_imsi; }; } // namespace srsepc diff --git a/srsepc/hdr/spgw/gtpc.h b/srsepc/hdr/spgw/gtpc.h index a823c08ab..9adb38ac6 100644 --- a/srsepc/hdr/spgw/gtpc.h +++ b/srsepc/hdr/spgw/gtpc.h @@ -29,6 +29,7 @@ #include "srsepc/hdr/spgw/spgw.h" #include "srslte/asn1/gtpc.h" #include "srslte/interfaces/epc_interfaces.h" +#include #include #include @@ -39,16 +40,20 @@ class spgw::gtpc : public gtpc_interface_gtpu public: gtpc(); virtual ~gtpc(); - int init(spgw_args_t* args, spgw* spgw, gtpu_interface_gtpc* gtpu, srslte::log_filter* gtpc_log); + int init(spgw_args_t* args, + spgw* spgw, + gtpu_interface_gtpc* gtpu, + srslte::log_filter* gtpc_log, + const std::map& ip_to_imsi); void stop(); srslte::error_t init_s11(spgw_args_t *args); - srslte::error_t init_ue_ip(spgw_args_t* args); + srslte::error_t init_ue_ip(spgw_args_t* args, const std::map& ip_to_imsi); int get_s11(); uint64_t get_new_ctrl_teid(); uint64_t get_new_user_teid(); - in_addr_t get_new_ue_ipv4(); + in_addr_t get_new_ue_ipv4(uint64_t imsi); void handle_s11_pdu(srslte::byte_buffer_t* msg); bool send_s11_pdu(const srslte::gtpc_pdu& pdu); @@ -90,6 +95,9 @@ public: std::map m_teid_to_tunnel_ctx; // Map control TEID to tunnel ctx. Usefull to get // reply ctrl TEID, UE IP, etc. + std::set m_ue_ip_addr_pool; + std::map m_imsi_to_ip; + srslte::log_filter* m_gtpc_log; srslte::byte_buffer_pool* m_pool; }; @@ -109,17 +117,5 @@ inline uint64_t spgw::gtpc::get_new_user_teid() return m_next_user_teid++; } -inline in_addr_t spgw::gtpc::get_new_ue_ipv4() -{ - m_h_next_ue_ip++; - return ntohl(m_h_next_ue_ip); -} - -inline srslte::error_t spgw::gtpc::init_ue_ip(spgw_args_t* args) -{ - m_h_next_ue_ip = ntohl(inet_addr(args->sgi_if_addr.c_str())); - return srslte::ERROR_NONE; -} - } // namespace srsepc #endif // SRSEPC_SPGW_H diff --git a/srsepc/hdr/spgw/spgw.h b/srsepc/hdr/spgw/spgw.h index 85a4f786c..b69911460 100644 --- a/srsepc/hdr/spgw/spgw.h +++ b/srsepc/hdr/spgw/spgw.h @@ -75,7 +75,11 @@ class spgw : public thread public: static spgw* get_instance(void); static void cleanup(void); - int init(spgw_args_t* args, srslte::log_filter* gtpu_log, srslte::log_filter* gtpc_log, srslte::log_filter* spgw_log); + int init(spgw_args_t* args, + srslte::log_filter* gtpu_log, + srslte::log_filter* gtpc_log, + srslte::log_filter* spgw_log, + const std::map& ip_to_imsi); void stop(); void run_thread(); @@ -84,14 +88,6 @@ private: virtual ~spgw(); static spgw* m_instance; - srslte::error_t init_sgi_if(spgw_args_t* args); - srslte::error_t init_s1u(spgw_args_t* args); - srslte::error_t init_ue_ip(spgw_args_t* args); - - uint64_t get_new_ctrl_teid(); - uint64_t get_new_user_teid(); - in_addr_t get_new_ue_ipv4(); - spgw_tunnel_ctx_t* create_gtp_ctx(struct srslte::gtpc_create_session_request* cs_req); bool delete_gtp_ctx(uint32_t ctrl_teid); diff --git a/srsepc/src/hss/hss.cc b/srsepc/src/hss/hss.cc index db6124fd6..3ce32f342 100644 --- a/srsepc/src/hss/hss.cc +++ b/srsepc/src/hss/hss.cc @@ -116,7 +116,7 @@ bool hss::read_db_file(std::string db_filename) std::string line; while (std::getline(m_db_file, line)) { if (line[0] != '#') { - uint column_size = 9; + uint column_size = 10; std::vector split = split_string(line, ','); if (split.size() != column_size) { m_hss_log->error("Error parsing UE database. Wrong number of columns in .csv\n"); @@ -166,6 +166,24 @@ bool hss::read_db_file(std::string db_filename) m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN : "); ue_ctx->qci = atoi(split[8].c_str()); m_hss_log->debug("Default Bearer QCI: %d\n", ue_ctx->qci); + + if (split[9] == std::string("dynamic")) { + ue_ctx->static_ip_addr = "0.0.0.0"; + } else { + char buf[128]; + if (inet_ntop(AF_INET, split[9].c_str(), buf, sizeof(buf))) { + if (m_ip_to_imsi.insert(std::make_pair(split[8], ue_ctx->imsi)).second) { + ue_ctx->static_ip_addr = split[9]; + m_hss_log->info("static ip addr %s\n", ue_ctx->static_ip_addr.c_str()); + } else { + m_hss_log->info("duplicate static ip addr %s\n", split[9].c_str()); + return false; + } + } else { + m_hss_log->info("invalid static ip addr %s, %s\n", split[9].c_str(), strerror(errno)); + return false; + } + } m_imsi_to_ue_ctx.insert(std::pair(ue_ctx->imsi, ue_ctx)); } } @@ -234,6 +252,12 @@ bool hss::write_db_file(std::string db_filename) m_db_file << hex_string(it->second->sqn, 6); m_db_file << ","; m_db_file << it->second->qci; + if (it->second->static_ip_addr != "0.0.0.0") { + m_db_file << ","; + m_db_file << it->second->static_ip_addr; + } else { + m_db_file << ",dynamic"; + } m_db_file << std::endl; it++; } @@ -698,4 +722,10 @@ std::string hss::hex_string(uint8_t* hex, int size) } return ss.str(); } + +std::map hss::get_ip_to_imsi(void) const +{ + return m_ip_to_imsi; +} + } // namespace srsepc diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index 88030ff9b..90a9ac2b9 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -456,7 +456,7 @@ int main(int argc, char* argv[]) } spgw* spgw = spgw::get_instance(); - if (spgw->init(&args.spgw_args, >pu_log, &spgw_gtpc_log, &spgw_log)) { + if (spgw->init(&args.spgw_args, >pu_log, &spgw_gtpc_log, &spgw_log, hss->get_ip_to_imsi())) { cout << "Error initializing SP-GW" << endl; exit(1); } diff --git a/srsepc/src/spgw/gtpc.cc b/srsepc/src/spgw/gtpc.cc index cd0ebef6e..ba3a06cfc 100644 --- a/srsepc/src/spgw/gtpc.cc +++ b/srsepc/src/spgw/gtpc.cc @@ -54,7 +54,11 @@ spgw::gtpc::~gtpc() return; } -int spgw::gtpc::init(spgw_args_t* args, spgw* spgw, gtpu_interface_gtpc* gtpu, srslte::log_filter* gtpc_log) +int spgw::gtpc::init(spgw_args_t* args, + spgw* spgw, + gtpu_interface_gtpc* gtpu, + srslte::log_filter* gtpc_log, + const std::map& ip_to_imsi) { srslte::error_t err; m_pool = srslte::byte_buffer_pool::get_instance(); @@ -74,7 +78,7 @@ int spgw::gtpc::init(spgw_args_t* args, spgw* spgw, gtpu_interface_gtpc* gtpu, s } // Init IP pool - err = init_ue_ip(args); + err = init_ue_ip(args, ip_to_imsi); if (err != srslte::ERROR_NONE) { m_gtpc_log->console("Could not initialize the IP pool.\n"); return -1; @@ -442,7 +446,7 @@ spgw_tunnel_ctx_t* spgw::gtpc::create_gtpc_ctx(const struct srslte::gtpc_create_ // Setup uplink user TEID uint64_t spgw_uplink_user_teid = get_new_user_teid(); // Allocate UE IP - in_addr_t ue_ip = get_new_ue_ipv4(); + in_addr_t ue_ip = get_new_ue_ipv4(cs_req.imsi); uint8_t default_bearer_id = 5; @@ -535,4 +539,64 @@ bool spgw::gtpc::free_all_queued_packets(spgw_tunnel_ctx_t* tunnel_ctx) return true; } +srslte::error_t spgw::gtpc::init_ue_ip(spgw_args_t* args, const std::map& ip_to_imsi) +{ + std::map::const_iterator iter = ip_to_imsi.find(args->sgi_if_addr); + + // check for collision w/our ip address + if (iter != ip_to_imsi.end()) { + m_gtpc_log->error("SPGW: static ip addr %s for imsi %lu, is reserved for the epc tun interface\n", + iter->first.c_str(), iter->second); + return srslte::ERROR_OUT_OF_BOUNDS; + } + + // load our imsi to ip lookup table + for (std::map::const_iterator iter = ip_to_imsi.begin(); iter != ip_to_imsi.end(); ++iter) { + struct in_addr in_addr; + in_addr.s_addr = inet_addr(iter->first.c_str()); + if (!m_imsi_to_ip.insert(std::make_pair(iter->second, in_addr)).second) { + m_gtpc_log->error("SPGW: duplicate imsi %lu for static ip address %s.\n", iter->second, iter->first.c_str()); + return srslte::ERROR_OUT_OF_BOUNDS; + } + } + + // XXX TODO add an upper bound to ip addr range via config, use 254 for now + // first address is allocated to the epc tun interface, start w/next addr + for (uint32_t n = 1; n < 254; ++n) { + struct in_addr ue_addr; + ue_addr.s_addr = inet_addr(args->sgi_if_addr.c_str()) + htonl(n); + + std::map::const_iterator iter = ip_to_imsi.find(inet_ntoa(ue_addr)); + if (iter != ip_to_imsi.end()) { + m_gtpc_log->debug("SPGW: init_ue_ip ue ip addr %s is reserved for imsi %lu, not adding to pool\n", + iter->first.c_str(), iter->second); + } else { + m_ue_ip_addr_pool.insert(ue_addr.s_addr); + m_gtpc_log->debug("SPGW: init_ue_ip ue ip addr %s is added to pool\n", inet_ntoa(ue_addr)); + } + } + return srslte::ERROR_NONE; +} + +in_addr_t spgw::gtpc::get_new_ue_ipv4(uint64_t imsi) +{ + struct in_addr ue_addr; + + std::map::const_iterator iter = m_imsi_to_ip.find(imsi); + if (iter != m_imsi_to_ip.end()) { + ue_addr = iter->second; + m_gtpc_log->info("SPGW: get_new_ue_ipv4 static ip addr %s\n", inet_ntoa(ue_addr)); + } else { + if (m_ue_ip_addr_pool.empty()) { + m_gtpc_log->error("SPGW: ue address pool is empty\n"); + ue_addr.s_addr = 0; + } else { + ue_addr.s_addr = *m_ue_ip_addr_pool.begin(); + m_ue_ip_addr_pool.erase(ue_addr.s_addr); + m_gtpc_log->info("SPGW: get_new_ue_ipv4 pool ip addr %s\n", inet_ntoa(ue_addr)); + } + } + return ue_addr.s_addr; +} + } // namespace srsepc diff --git a/srsepc/src/spgw/spgw.cc b/srsepc/src/spgw/spgw.cc index 021fffe1b..a683a37be 100644 --- a/srsepc/src/spgw/spgw.cc +++ b/srsepc/src/spgw/spgw.cc @@ -70,10 +70,11 @@ void spgw::cleanup() pthread_mutex_unlock(&spgw_instance_mutex); } -int spgw::init(spgw_args_t* args, - srslte::log_filter* gtpu_log, - srslte::log_filter* gtpc_log, - srslte::log_filter* spgw_log) +int spgw::init(spgw_args_t* args, + srslte::log_filter* gtpu_log, + srslte::log_filter* gtpc_log, + srslte::log_filter* spgw_log, + const std::map& ip_to_imsi) { srslte::error_t err; m_pool = srslte::byte_buffer_pool::get_instance(); @@ -88,7 +89,7 @@ int spgw::init(spgw_args_t* args, } // Init GTP-C - if (m_gtpc->init(args, this, m_gtpu, gtpc_log) != 0) { + if (m_gtpc->init(args, this, m_gtpu, gtpc_log, ip_to_imsi) != 0) { m_spgw_log->console("Could not initialize the S1-U interface.\n"); return -1; }