added support for optional ue static ip address (rebase #225)

This commit is contained in:
Joseph Giovatto 2018-09-21 20:17:35 -04:00 committed by Andre Puschmann
parent 185242d5f5
commit fa99aa590e
7 changed files with 126 additions and 34 deletions

View File

@ -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<std::string, uint64_t> get_ip_to_imsi() const;
private:
hss();
virtual ~hss();
@ -125,6 +128,8 @@ private:
uint16_t mcc;
uint16_t mnc;
std::map<std::string, uint64_t> m_ip_to_imsi;
};
} // namespace srsepc

View File

@ -29,6 +29,7 @@
#include "srsepc/hdr/spgw/spgw.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <set>
#include <sys/socket.h>
#include <sys/un.h>
@ -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<std::string, uint64_t>& 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<std::string, uint64_t>& 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<uint32_t, spgw_tunnel_ctx*> m_teid_to_tunnel_ctx; // Map control TEID to tunnel ctx. Usefull to get
// reply ctrl TEID, UE IP, etc.
std::set<uint32_t> m_ue_ip_addr_pool;
std::map<uint64_t, struct in_addr> 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

View File

@ -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<std::string, uint64_t>& 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);

View File

@ -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<std::string> 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<uint64_t, hss_ue_ctx_t*>(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<std::string, uint64_t> hss::get_ip_to_imsi(void) const
{
return m_ip_to_imsi;
}
} // namespace srsepc

View File

@ -456,7 +456,7 @@ int main(int argc, char* argv[])
}
spgw* spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args, &gtpu_log, &spgw_gtpc_log, &spgw_log)) {
if (spgw->init(&args.spgw_args, &gtpu_log, &spgw_gtpc_log, &spgw_log, hss->get_ip_to_imsi())) {
cout << "Error initializing SP-GW" << endl;
exit(1);
}

View File

@ -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<std::string, uint64_t>& 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<std::string, uint64_t>& ip_to_imsi)
{
std::map<std::string, uint64_t>::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<std::string, uint64_t>::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<std::string, uint64_t>::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<uint64_t, struct in_addr>::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

View File

@ -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<std::string, uint64_t>& 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;
}