Commit 339f4777 authored by gauthier's avatar gauthier

spgwu part1

parent 41560bed
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_app.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "conversions.hpp"
#include "itti.hpp"
#include "logger.hpp"
#include "pfcp_switch.hpp"
#include "spgwu_app.hpp"
#include "spgwu_config.hpp"
#include "spgwu_s1u.hpp"
#include "spgwu_sx.hpp"
#include <stdexcept>
using namespace oai::cn::proto::pfcp;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::spgwu;
using namespace std;
// C includes
spgwu_sx *spgwu_sx_inst = nullptr;
spgwu_s1u *spgwu_s1u_inst = nullptr;
extern itti_mw *itti_inst;
extern pfcp_switch *pfcp_switch_inst;
extern spgwu_app *spgwu_app_inst;
extern spgwu_config spgwu_cfg;
void spgwu_app_task (void*);
//------------------------------------------------------------------------------
void spgwu_app_task (void *args_p)
{
const task_id_t task_id = TASK_SPGWU_APP;
itti_inst->notify_task_ready(task_id);
do {
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch (msg->msg_type) {
case SXAB_SESSION_ESTABLISHMENT_REQUEST:
spgwu_app_inst->handle_itti_msg(std::static_pointer_cast<itti_sxab_session_establishment_request>(shared_msg));
break;
case SXAB_SESSION_MODIFICATION_REQUEST:
spgwu_app_inst->handle_itti_msg(std::static_pointer_cast<itti_sxab_session_modification_request>(shared_msg));
break;
case SXAB_SESSION_DELETION_REQUEST:
spgwu_app_inst->handle_itti_msg(std::static_pointer_cast<itti_sxab_session_deletion_request>(shared_msg));
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
switch (to->arg1_user) {
case TASK_SPGWU_PFCP_SWITCH_MIN_COMMIT_INTERVAL:
pfcp_switch_inst->time_out_min_commit_interval(to->timer_id);
break;
case TASK_SPGWU_PFCP_SWITCH_MAX_COMMIT_INTERVAL:
pfcp_switch_inst->time_out_max_commit_interval(to->timer_id);
break;
default:
;
}
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::spgwu_app().info( "Received terminate message");
return;
}
break;
default:
Logger::spgwu_app().info( "no handler for ITTI msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
spgwu_app::spgwu_app (const std::string& config_file)
{
Logger::spgwu_app().startup("Starting...");
spgwu_cfg.load(config_file);
spgwu_cfg.execute();
spgwu_cfg.display();
// teid_s11_cp = 0;
// teid_s5s8_cp = 0;
// teid_s5s8_up = 0;
// imsi2sgwu_eps_bearer_context = {};
// s11lteid2sgwu_eps_bearer_context = {};
// s5s8lteid2sgwu_contexts = {};
// s5s8uplteid = {};
if (itti_inst->create_task(TASK_SPGWU_APP, spgwu_app_task, nullptr) ) {
Logger::spgwu_app().error( "Cannot create task TASK_SPGWU_APP" );
throw std::runtime_error( "Cannot create task TASK_SPGWU_APP" );
}
try {
spgwu_sx_inst = new spgwu_sx();
} catch (std::exception& e) {
Logger::spgwu_app().error( "Cannot create SPGWU_SX: %s", e.what() );
throw e;
}
try {
spgwu_s1u_inst = new spgwu_s1u();
} catch (std::exception& e) {
Logger::spgwu_app().error( "Cannot create SPGWU_S1U: %s", e.what() );
throw e;
}
try {
pfcp_switch_inst = new pfcp_switch();
} catch (std::exception& e) {
Logger::spgwu_app().error( "Cannot create PFCP_SWITCH: %s", e.what() );
throw e;
}
Logger::spgwu_app().startup( "Started" );
}
//------------------------------------------------------------------------------
spgwu_app::~spgwu_app()
{
if (spgwu_sx_inst) delete spgwu_sx_inst;
}
//------------------------------------------------------------------------------
void spgwu_app::handle_itti_msg (std::shared_ptr<core::itti::itti_sxab_session_establishment_request> m)
{
Logger::spgwu_sx().info("Received SXAB_SESSION_ESTABLISHMENT_REQUEST seid " SEID_FMT " ", m->seid);
itti_sxab_session_establishment_response *sx_resp = new itti_sxab_session_establishment_response(TASK_SPGWU_APP, TASK_SPGWU_SX);
pfcp_switch_inst->handle_pfcp_session_establishment_request(m, sx_resp);
core::pfcp::node_id_t node_id = {};
spgwu_cfg.get_pfcp_node_id(node_id);
sx_resp->pfcp_ies.set(node_id);
sx_resp->trxn_id = m->trxn_id;
sx_resp->seid = m->pfcp_ies.cp_fseid.second.seid; // Mandatory IE, but... may be bad to do this
sx_resp->r_endpoint = m->r_endpoint;
sx_resp->l_endpoint = m->l_endpoint;
std::shared_ptr<itti_sxab_session_establishment_response> msg = std::shared_ptr<itti_sxab_session_establishment_response>(sx_resp);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::spgwu_app().error( "Could not send ITTI message %s to task TASK_PGWC_SX", sx_resp->get_msg_name());
}
}
//------------------------------------------------------------------------------
void spgwu_app::handle_itti_msg (std::shared_ptr<core::itti::itti_sxab_session_modification_request> m)
{
Logger::spgwu_sx().info("Received SXAB_SESSION_MODIFICATION_REQUEST seid " SEID_FMT " ", m->seid);
itti_sxab_session_modification_response *sx_resp = new itti_sxab_session_modification_response(TASK_SPGWU_APP, TASK_SPGWU_SX);
pfcp_switch_inst->handle_pfcp_session_modification_request(m, sx_resp);
sx_resp->trxn_id = m->trxn_id;
sx_resp->r_endpoint = m->r_endpoint;
sx_resp->l_endpoint = m->l_endpoint;
std::shared_ptr<itti_sxab_session_modification_response> msg = std::shared_ptr<itti_sxab_session_modification_response>(sx_resp);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::spgwu_app().error( "Could not send ITTI message %s to task TASK_PGWC_SX", sx_resp->get_msg_name());
}
}
//------------------------------------------------------------------------------
void spgwu_app::handle_itti_msg (std::shared_ptr<core::itti::itti_sxab_session_deletion_request> m)
{
Logger::spgwu_sx().info("Received SXAB_SESSION_DELETION_REQUEST seid " SEID_FMT " ", m->seid);
itti_sxab_session_deletion_response *sx_resp = new itti_sxab_session_deletion_response(TASK_SPGWU_APP, TASK_SPGWU_SX);
pfcp_switch_inst->handle_pfcp_session_deletion_request(m, sx_resp);
sx_resp->trxn_id = m->trxn_id;
sx_resp->r_endpoint = m->r_endpoint;
sx_resp->l_endpoint = m->l_endpoint;
std::shared_ptr<itti_sxab_session_deletion_response> msg = std::shared_ptr<itti_sxab_session_deletion_response>(sx_resp);
int ret = itti_inst->send_msg(msg);
if (RETURNok != ret) {
Logger::spgwu_app().error( "Could not send ITTI message %s to task TASK_PGWC_SX", sx_resp->get_msg_name());
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_app.hpp
\author Lionel GAUTHIER
\date 2018
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SPGWU_APP_HPP_SEEN
#define FILE_SPGWU_APP_HPP_SEEN
#include "common_root_types.h"
#include "itti_msg_sxab.hpp"
#include <boost/atomic.hpp>
#include <map>
#include <string>
#include <thread>
#include <memory>
#include <map>
#include <set>
namespace oai::cn::nf::spgwu {
class spgwu_app {
private:
std::thread::id thread_id;
std::thread thread;
// teid generators (linear)
// boost::atomic<teid_t> teid_sxab_cp;
// boost::atomic<teid_t> teid_s5s8_up;
// /* There shall be only one pair of TEID-C per UE over the S11 and the S4 interfaces. The same tunnel shall be
// shared for the control messages related to the same UE operation. A TEID-C on the S11/S4 interface shall be
// released after all its associated EPS bearers are deleted.*/
// std::map<imsi64_t, std::shared_ptr<sgwu_eps_bearer_context>> imsi2sgwu_eps_bearer_context;
// std::map<teid_t, std::shared_ptr<sgwu_eps_bearer_context>> s11lteid2sgwu_eps_bearer_context;
//
// std::map<teid_t, std::pair<std::shared_ptr<sgwu_eps_bearer_context>, std::shared_ptr<sgwu_pdn_connection>>> s5s8lteid2sgwu_contexts;
// std::set<teid_t> s5s8uplteid; // In case of overflow of generator of teid_t
//
// teid_t generate_s11_cp_teid();
// bool is_s11c_teid_exist(const teid_t& teid_s11_cp) const;
//
// bool is_s5s8sgwu_teid_2_sgwu_contexts(const teid_t& sgwu_teid) const;
//
// // s11lteid2sgwu_eps_bearer_context collection
// bool is_s11sgwu_teid_2_sgwu_eps_bearer_context(const teid_t& sgwu_teid) const;
//
// bool is_imsi64_2_sgwu_eps_bearer_context(const imsi64_t& imsi64) const;
// void set_imsi64_2_sgwu_eps_bearer_context(const imsi64_t& imsi64, std::shared_ptr<sgwu_eps_bearer_context> sebc);
//
// teid_t generate_s5s8_cp_teid();
// bool is_s5s8c_teid_exist(const teid_t& teid_s5s8_cp)const;
//
// bool is_s5s8u_teid_exist(const teid_t& teid_s5s8_up) const;
public:
// key is S11 S-GW local teid, value is S11 tunnel id pair
// map<teid_t, int> s11teid2mme_hashtable;
// key is paa, value is S11 s-gw local teid
//obj_hash_table_uint64_t *ip2s11teid;
// key is S1-U S-GW local teid
////hash_table_t *s1uteid2enb_hashtable;
// the key of this hashtable is the S11 s-gw local teid.
//hash_table_ts_t *s11_bearer_context_information_hashtable;
/* The TEID-C shall be unique per PDN-Connection on GTP based S2a, S2b, S5 and S8 interfaces. The same
tunnel shall be shared for the control messages related to all bearers associated to
the PDN-Connection. A TEID-C on the S2a/S2b/S5/S8 interface shall be released after all its associated EPS bearers are deleted. */
//gtpv1u_data_t gtpv1u_data;
spgwu_app(const std::string& config_file);
~spgwu_app();
spgwu_app(spgwu_app const&) = delete;
void operator=(spgwu_app const&) = delete;
teid_t generate_s5s8_up_teid();
// void handle_itti_msg core::(itti::itti_sxab_heartbeat_request& m);
// void handle_itti_msg (core::itti::itti_sxab_heartbeat_response& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_pfd_management_request& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_pfd_management_response& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_association_setup_request& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_association_setup_response& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_association_update_request& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_association_update_response& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_association_release_request& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_association_release_response& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_version_not_supported_response& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_node_report_request& m);
// void handle_itti_msg (core::itti::itti_sxab_pfcp_node_report_response& m);
void handle_itti_msg (std::shared_ptr<core::itti::itti_sxab_session_establishment_request> m);
void handle_itti_msg (std::shared_ptr<core::itti::itti_sxab_session_modification_request> m);
void handle_itti_msg (std::shared_ptr<core::itti::itti_sxab_session_deletion_request> m);
// void handle_itti_msg (core::itti::itti_sxab_session_deletion_response& m);
// void handle_itti_msg (core::itti::itti_sxab_session_report_request& m);
// void handle_itti_msg (core::itti::itti_sxab_session_report_response& m);
};
}
#endif /* FILE_SPGWU_APP_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_config.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "3gpp_29.274.hpp"
#include "async_shell_cmd.hpp"
#include "common_defs.h"
#include "get_gateway_netlink.hpp"
#include "if.hpp"
#include "logger.hpp"
#include "spgwu_config.hpp"
#include "string.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <cstdlib>
#include <iomanip>
#include <iostream>
using namespace std;
using namespace libconfig;
using namespace oai::cn::nf::spgwu;
// C includes
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
//------------------------------------------------------------------------------
int spgwu_config::execute ()
{
return RETURNok;
}
//------------------------------------------------------------------------------
int spgwu_config::get_pfcp_node_id(oai::cn::core::pfcp::node_id_t& node_id)
{
node_id = {};
if (sx.addr4.s_addr) {
node_id.node_id_type = oai::cn::core::pfcp::NODE_ID_TYPE_IPV4_ADDRESS;
node_id.u1.ipv4_address = sx.addr4;
return RETURNok;
}
if (sx.addr6.s6_addr32[0] | sx.addr6.s6_addr32[1] | sx.addr6.s6_addr32[2] | sx.addr6.s6_addr32[3]) {
node_id.node_id_type = oai::cn::core::pfcp::NODE_ID_TYPE_IPV6_ADDRESS;
node_id.u1.ipv6_address = sx.addr6;
return RETURNok;
}
return RETURNerror;
}
//------------------------------------------------------------------------------
int spgwu_config::get_pfcp_fseid(oai::cn::core::pfcp::fseid_t& fseid)
{
int rc = RETURNerror;
fseid = {};
if (sx.addr4.s_addr) {
fseid.v4 = 1;
fseid.ipv4_address = sx.addr4;
rc = RETURNok;
}
if (sx.addr6.s6_addr32[0] | sx.addr6.s6_addr32[1] | sx.addr6.s6_addr32[2] | sx.addr6.s6_addr32[3]) {
fseid.v6 = 1;
fseid.ipv6_address = sx.addr6;
rc = RETURNok;
}
return rc;
}
//------------------------------------------------------------------------------
int spgwu_config::load_interface(const Setting& if_cfg, interface_cfg_t& cfg)
{
if_cfg.lookupValue(SPGWU_CONFIG_STRING_INTERFACE_NAME, cfg.if_name);
util::trim(cfg.if_name);
if (not boost::iequals(cfg.if_name, "none")) {
std::string address = {};
if_cfg.lookupValue(SPGWU_CONFIG_STRING_IPV4_ADDRESS, address);
util::trim(address);
if (boost::iequals(address, "read")) {
if (get_inet_addr_infos_from_iface(cfg.if_name, cfg.addr4, cfg.network4, cfg.mtu)) {
Logger::spgwu_app().error("Could not read %s network interface configuration", cfg.if_name);
return RETURNerror;
}
} else {
std::vector<std::string> words;
boost::split(words, address, boost::is_any_of("/"), boost::token_compress_on);
if (words.size() != 2) {
Logger::spgwu_app().error("Bad value " SPGWU_CONFIG_STRING_IPV4_ADDRESS " = %s in config file", address.c_str());
return RETURNerror;
}
unsigned char buf_in_addr[sizeof(struct in6_addr)]; // you never know...
if (inet_pton (AF_INET, util::trim(words.at(0)).c_str(), buf_in_addr) == 1) {
memcpy (&cfg.addr4, buf_in_addr, sizeof (struct in_addr));
} else {
Logger::spgwu_app().error("In conversion: Bad value " SPGWU_CONFIG_STRING_IPV4_ADDRESS " = %s in config file", util::trim(words.at(0)).c_str());
return RETURNerror;
}
cfg.network4.s_addr = htons(ntohs(cfg.addr4.s_addr) & 0xFFFFFFFF << (32 - std::stoi (util::trim(words.at(1)))));
}
if_cfg.lookupValue(SPGWU_CONFIG_STRING_PORT, cfg.port);
if_cfg.lookupValue(SPGWU_CONFIG_STRING_CPU_ID_THREAD_LOOP_READ, cfg.cpu_id_thread_loop_read);
}
return RETURNok;
}
//------------------------------------------------------------------------------
int spgwu_config::load(const string& config_file)
{
Config cfg;
unsigned char buf_in_addr[sizeof (struct in_addr)+1];
unsigned char buf_in6_addr[sizeof (struct in6_addr)+1];
// Read the file. If there is an error, report it and exit.
try
{
cfg.readFile(config_file.c_str());
}
catch(const FileIOException &fioex)
{
Logger::spgwu_app().error("I/O error while reading file %s - %s", config_file.c_str(), fioex.what());
throw fioex;
}
catch(const ParseException &pex)
{
Logger::spgwu_app().error("Parse error at %s:%d - %s", pex.getFile(), pex.getLine(), pex.getError());
throw pex;
}
const Setting& root = cfg.getRoot();
try
{
const Setting& spgwu_cfg = root[SPGWU_CONFIG_STRING_SPGWU_CONFIG];
spgwu_cfg.lookupValue(SPGWU_CONFIG_STRING_INSTANCE, instance);
spgwu_cfg.lookupValue(SPGWU_CONFIG_STRING_PID_DIRECTORY, pid_dir);
util::trim(pid_dir);
const Setting& nw_if_cfg = spgwu_cfg[SPGWU_CONFIG_STRING_INTERFACES];
const Setting& s1_up_cfg = nw_if_cfg[SPGWU_CONFIG_STRING_INTERFACE_S1U_S12_S4_UP];
load_interface(s1_up_cfg, s1_up);
const Setting& sx_cfg = nw_if_cfg[SPGWU_CONFIG_STRING_INTERFACE_SX];
load_interface(sx_cfg, sx);
const Setting& sgi_cfg = nw_if_cfg[SPGWU_CONFIG_STRING_INTERFACE_SGI];
load_interface(sgi_cfg, sgi);
if ((boost::iequals(sgi.if_name, "none")) || (boost::iequals(sgi.if_name, "default_gateway"))) {
if (cn::util::get_gateway_and_iface(gateway, sgi.if_name)) {
std::string copy = sgi.if_name;
if (get_inet_addr_infos_from_iface(sgi.if_name, sgi.addr4, sgi.network4, sgi.mtu)) {
Logger::spgwu_app().error("Could not read %s network interface configuration from system", sgi.if_name);
return RETURNerror;
}
} else {
Logger::spgwu_app().error("Could not find SGi interface and SGi gateway");
return RETURNerror;
}
}
const Setting& pdn_network_list_cfg = spgwu_cfg[SPGWU_CONFIG_STRING_PDN_NETWORK_LIST];
int count = pdn_network_list_cfg.getLength();
for (int i = 0; i < count; i++) {
pdn_cfg_t pdn_cfg = {};
const Setting &pdn_network_cfg = pdn_network_list_cfg[i];
string network_ipv4 = {};
if (pdn_network_cfg.lookupValue(SPGWU_CONFIG_STRING_NETWORK_IPV4, network_ipv4)) {
std::vector<std::string> ips = {};
boost::split(ips, network_ipv4, boost::is_any_of(SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER), boost::token_compress_on);
if (ips.size() != 2) {
Logger::spgwu_app().error("Bad value %s : %s in config file %s", SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER, network_ipv4.c_str(), config_file.c_str());
throw ("Bad value %s : %s in config file %s", SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER, network_ipv4.c_str(), config_file.c_str());
}
if (inet_pton (AF_INET, util::trim(ips.at(0)).c_str(), buf_in_addr) == 1) {
memcpy (&pdn_cfg.network_ipv4, buf_in_addr, sizeof (struct in_addr));
} else {
Logger::spgwu_app().error("CONFIG: BAD IPV4 NETWORK ADDRESS in " SPGWU_CONFIG_STRING_PDN_NETWORK_LIST " PDN item %d", i);
throw ("CONFIG: BAD NETWORK ADDRESS in " SPGWU_CONFIG_STRING_PDN_NETWORK_LIST);
}
pdn_cfg.prefix_ipv4 = std::stoul (ips.at(1),nullptr,0);
}
string network_ipv6 = {};
if (pdn_network_cfg.lookupValue(SPGWU_CONFIG_STRING_NETWORK_IPV6, network_ipv6)) {
std::vector<std::string> ips = {};
boost::split(ips, network_ipv6, boost::is_any_of(SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER), boost::token_compress_on);
if (ips.size() != 2) {
Logger::spgwu_app().error("Bad value %s : %s in config file %s", SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER, network_ipv6.c_str(), config_file.c_str());
throw ("Bad value %s : %s in config file %s", SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER, network_ipv6.c_str(), config_file.c_str());
}
if (inet_pton (AF_INET6, util::trim(ips.at(0)).c_str(), buf_in6_addr) == 1) {
memcpy (&pdn_cfg.network_ipv6, buf_in6_addr, sizeof (struct in6_addr));
} else {
Logger::spgwu_app().error("CONFIG: BAD IPV6 NETWORK ADDRESS in " SPGWU_CONFIG_STRING_PDN_NETWORK_LIST " PDN item %d", i);
throw ("CONFIG: BAD IPV6 NETWORK ADDRESS in " SPGWU_CONFIG_STRING_PDN_NETWORK_LIST);
}
pdn_cfg.prefix_ipv6 = std::stoul (ips.at(1),nullptr,0);
Logger::spgwu_app().info( " %s......: %s/%d", ips.at(0).c_str(), oai::cn::core::toString(pdn_cfg.network_ipv6).c_str(), pdn_cfg.prefix_ipv6);
}
pdn_cfg.snat = false;
std::string astring = {};
if (pdn_network_cfg.lookupValue(SPGWU_CONFIG_STRING_SNAT, astring)) {
if (boost::iequals(astring, "yes")) {
pdn_cfg.snat = true;
}
}
pdns.push_back(pdn_cfg);
}
const Setting& spgwc_list_cfg = spgwu_cfg[SPGWU_CONFIG_STRING_SPGWC_LIST];
count = spgwc_list_cfg.getLength();
for (int i = 0; i < count; i++) {
pdn_cfg_t pdn_cfg = {};
const Setting &spgwc_cfg = spgwc_list_cfg[i];
string address = {};
if (spgwc_cfg.lookupValue(SPGWU_CONFIG_STRING_IPV4_ADDRESS, address)) {
core::pfcp::node_id_t n = {};
n.node_id_type = oai::cn::core::pfcp::NODE_ID_TYPE_IPV4_ADDRESS; // actually
if (inet_pton (AF_INET, util::trim(address).c_str(), buf_in_addr) == 1) {
memcpy (&n.u1.ipv4_address, buf_in_addr, sizeof (struct in_addr));
} else {
Logger::spgwu_app().error("CONFIG: BAD IPV4 ADDRESS in " SPGWU_CONFIG_STRING_SPGWC_LIST " item %d", i);
throw ("CONFIG: BAD ADDRESS in " SPGWU_CONFIG_STRING_SPGWC_LIST);
}
spgwcs.push_back(n);
} else {
// TODO IPV6_ADDRESS, FQDN
throw ("Bad value in section %s : item no %d in config file %s", SPGWU_CONFIG_STRING_SPGWC_LIST, i, config_file.c_str());
}
}
}
catch(const SettingNotFoundException &nfex)
{
Logger::spgwu_app().error("%s : %s", nfex.what(), nfex.getPath());
return RETURNerror;
}
return RETURNok;
}
//------------------------------------------------------------------------------
void spgwu_config::display ()
{
Logger::spgwu_app().info("==== EURECOM %s v%s ====", PACKAGE_NAME, PACKAGE_VERSION);
Logger::spgwu_app().info( "Configuration:");
Logger::spgwu_app().info( "- Instance ..............: %d", instance);
Logger::spgwu_app().info( "- PID dir ...............: %s", pid_dir.c_str());
Logger::spgwu_app().info( "-S1u_S12_S4:");
Logger::spgwu_app().info( " iface ............: %s", s1_up.if_name.c_str());
Logger::spgwu_app().info( " ipv4.addr ........: %s", inet_ntoa (s1_up.addr4));
Logger::spgwu_app().info( " ipv4.mask ........: %s", inet_ntoa (s1_up.network4));
Logger::spgwu_app().info( " mtu ..............: %d", s1_up.mtu);
Logger::spgwu_app().info( " port .............: %d", s1_up.port);
Logger::spgwu_app().info( "- SXA-SXB:");
Logger::spgwu_app().info( " iface ............: %s", sx.if_name.c_str());
Logger::spgwu_app().info( " ipv4.addr ........: %s", inet_ntoa (sx.addr4));
Logger::spgwu_app().info( " ipv4.mask ........: %s", inet_ntoa (sx.network4));
Logger::spgwu_app().info( " mtu ..............: %d", sx.mtu);
Logger::spgwu_app().info( " port .............: %u", sx.port);
Logger::spgwu_app().info( "- SGi:");
Logger::spgwu_app().info( " iface ............: %s", sgi.if_name.c_str());
Logger::spgwu_app().info( " ipv4.addr ........: %s", inet_ntoa (sgi.addr4));
Logger::spgwu_app().info( " ipv4.mask ........: %s", inet_ntoa (sgi.network4));
Logger::spgwu_app().info( " mtu ..............: %d", sgi.mtu);
Logger::spgwu_app().info( " gateway ..........: %s", gateway.c_str());
Logger::spgwu_app().info( "- PDN networks:");
int i = 1;
for (auto it : pdns) {
Logger::spgwu_app().info( " PDN %d ............: snat %s", i, (it.snat) ? "yes":"no");
if (it.prefix_ipv4) {
Logger::spgwu_app().info( " NW .............: %s/%d", oai::cn::core::toString(it.network_ipv4).c_str(), it.prefix_ipv4);
}
if (it.prefix_ipv6) {
Logger::spgwu_app().info( " NW .............: %s/%d", oai::cn::core::toString(it.network_ipv6).c_str(), it.prefix_ipv6);
}
i++;
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_config.hpp
* \brief
* \author Lionel Gauthier
* \company Eurecom
* \email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SPGWU_CONFIG_HPP_SEEN
#define FILE_SPGWU_CONFIG_HPP_SEEN
#include "3gpp_29.244.h"
#include <libconfig.h++>
#include <mutex>
#include <netinet/in.h>
#include <stdint.h>
#include <stdbool.h>
#include <string>
namespace oai::cn::nf::spgwu {
#define SPGWU_CONFIG_STRING_SPGWU_CONFIG "SPGW-U"
#define SPGWU_CONFIG_STRING_PID_DIRECTORY "PID_DIRECTORY"
#define SPGWU_CONFIG_STRING_INSTANCE "INSTANCE"
#define SPGWU_CONFIG_STRING_INTERFACES "INTERFACES"
#define SPGWU_CONFIG_STRING_INTERFACE_NAME "INTERFACE_NAME"
#define SPGWU_CONFIG_STRING_IPV4_ADDRESS "IPV4_ADDRESS"
#define SPGWU_CONFIG_STRING_PORT "PORT"
#define SPGWU_CONFIG_STRING_CPU_ID_THREAD_LOOP_READ "CPU_ID_THREAD_LOOP_READ"
#define SPGWU_CONFIG_STRING_INTERFACE_SGI "SGI"
#define SPGWU_CONFIG_STRING_INTERFACE_SX "SX"
#define SPGWU_CONFIG_STRING_INTERFACE_S1U_S12_S4_UP "S1U_S12_S4_UP"
#define SPGWU_CONFIG_STRING_PDN_NETWORK_LIST "PDN_NETWORK_LIST"
#define SPGWU_CONFIG_STRING_NETWORK_IPV4 "NETWORK_IPV4"
#define SPGWU_CONFIG_STRING_NETWORK_IPV6 "NETWORK_IPV6"
#define SPGWU_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER "/"
#define SPGWU_CONFIG_STRING_SNAT "SNAT"
#define SPGWU_CONFIG_STRING_MAX_PFCP_SESSIONS "MAX_PFCP_SESSIONS"
#define SPGWU_CONFIG_STRING_SPGWC_LIST "SPGW-C_LIST"
#define SPGW_ABORT_ON_ERROR true
#define SPGW_WARN_ON_ERROR false
typedef struct interface_cfg_s {
std::string if_name;
struct in_addr addr4;
struct in_addr network4;
struct in6_addr addr6;
unsigned int mtu;
unsigned int port;
int cpu_id_thread_loop_read;
} interface_cfg_t;
typedef struct pdn_cfg_s {
struct in_addr network_ipv4;
int prefix_ipv4;
struct in6_addr network_ipv6;
int prefix_ipv6;
bool snat;
} pdn_cfg_t;
class spgwu_config {
private:
int load_interface(const libconfig::Setting& if_cfg, interface_cfg_t& cfg);
public:
/* Reader/writer lock for this configuration */
std::mutex m_rw_lock;
std::string pid_dir;
unsigned int instance;
interface_cfg_t s1_up;
interface_cfg_t sgi;
interface_cfg_t sx;
std::string gateway;
uint32_t max_pfcp_sessions;
std::vector<pdn_cfg_t> pdns;
std::vector<oai::cn::core::pfcp::node_id_t> spgwcs;
spgwu_config() : m_rw_lock(), pid_dir(), instance(0), s1_up(), sgi(), gateway(),sx(), pdns(), spgwcs(), max_pfcp_sessions(100) {};
void lock() {m_rw_lock.lock();};
void unlock() {m_rw_lock.unlock();};
int load(const std::string& config_file);
int execute();
void display();
int get_pfcp_node_id(oai::cn::core::pfcp::node_id_t& node_id);
int get_pfcp_fseid(oai::cn::core::pfcp::fseid_t& fseid);
};
} // namespace spgwu
#endif /* FILE_SPGWU_CONFIG_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_pfcp_association.cpp
\brief
\author Lionel GAUTHIER
\date 2019
\email: lionel.gauthier@eurecom.fr
*/
#include "common_defs.h"
#include "logger.hpp"
#include "pfcp_switch.hpp"
#include "spgwu_pfcp_association.hpp"
#include "spgwu_sx.hpp"
using namespace oai::cn::core;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::spgwu;
using namespace std;
extern itti_mw *itti_inst;
extern pfcp_switch *pfcp_switch_inst;
extern spgwu_sx *spgwu_sx_inst;
//------------------------------------------------------------------------------
void pfcp_association::notify_add_session(const oai::cn::core::pfcp::fseid_t& cp_fseid)
{
std::unique_lock<std::mutex> l(m_sessions);
sessions.insert(cp_fseid);
}
//------------------------------------------------------------------------------
bool pfcp_association::has_session(const oai::cn::core::pfcp::fseid_t& cp_fseid)
{
std::unique_lock<std::mutex> l(m_sessions);
auto it = sessions.find(cp_fseid);
if (it != sessions.end()) {
return true;
} else {
return false;
}
}
//------------------------------------------------------------------------------
void pfcp_association::notify_del_session(const oai::cn::core::pfcp::fseid_t& cp_fseid)
{
std::unique_lock<std::mutex> l(m_sessions);
sessions.erase(cp_fseid);
}
//------------------------------------------------------------------------------
void pfcp_association::del_sessions()
{
std::unique_lock<std::mutex> l(m_sessions);
for (std::set<core::pfcp::fseid_t>::iterator it=sessions.begin(); it!=sessions.end();) {
pfcp_switch_inst->remove_pfcp_session(*it);
sessions.erase(it++);
}
}
//------------------------------------------------------------------------------
bool pfcp_associations::add_association(oai::cn::core::pfcp::node_id_t& node_id, oai::cn::core::pfcp::recovery_time_stamp_t& recovery_time_stamp)
{
std::shared_ptr<pfcp_association> sa = {};
if (remove_peer_candidate_node(node_id, sa)) {
sa->recovery_time_stamp = recovery_time_stamp;
sa->function_features = {};
std::size_t hash_node_id = std::hash<oai::cn::core::pfcp::node_id_t>{}(node_id);
associations.insert((int32_t)hash_node_id, sa);
trigger_heartbeat_request_procedure(sa);
return true;
}
return false;
}
//------------------------------------------------------------------------------
bool pfcp_associations::add_association(oai::cn::core::pfcp::node_id_t& node_id, oai::cn::core::pfcp::recovery_time_stamp_t& recovery_time_stamp, oai::cn::core::pfcp::cp_function_features_t&
function_features)
{
std::shared_ptr<pfcp_association> sa = {};
if (remove_peer_candidate_node(node_id, sa)) {
sa->recovery_time_stamp = recovery_time_stamp;
sa->set(function_features);
std::size_t hash_node_id = std::hash<oai::cn::core::pfcp::node_id_t>{}(node_id);
associations.insert((int32_t)hash_node_id, sa);
trigger_heartbeat_request_procedure(sa);
return true;
}
return false;
}
//------------------------------------------------------------------------------
bool pfcp_associations::get_association(const oai::cn::core::pfcp::node_id_t& node_id, std::shared_ptr<pfcp_association>& sa) const
{
std::size_t hash_node_id = std::hash<oai::cn::core::pfcp::node_id_t>{}(node_id);
auto pit = associations.find((int32_t)hash_node_id);
if ( pit == associations.end() )
return false;
else {
sa = pit->second;
return true;
}
}
//------------------------------------------------------------------------------
bool pfcp_associations::get_association(const oai::cn::core::pfcp::fseid_t& cp_fseid, std::shared_ptr<pfcp_association>& sa) const
{
folly::AtomicHashMap<int32_t, std::shared_ptr<pfcp_association>>::iterator it;
FOR_EACH (it, associations) {
std::shared_ptr<pfcp_association> a = it->second;
if (it->second->has_session(cp_fseid)) {
sa = it->second;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
bool pfcp_associations::remove_peer_candidate_node(oai::cn::core::pfcp::node_id_t& node_id, std::shared_ptr<pfcp_association>& s)
{
for (std::vector<std::shared_ptr<pfcp_association>>::iterator it=pending_associations.begin(); it < pending_associations.end(); ++it) {
if ((*it)->node_id == node_id) {
s = *it;
pending_associations.erase(it);
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
bool pfcp_associations::add_peer_candidate_node(const oai::cn::core::pfcp::node_id_t& node_id)
{
for (std::vector<std::shared_ptr<pfcp_association>>::iterator it=pending_associations.begin(); it < pending_associations.end(); ++it) {
if ((*it)->node_id == node_id) {
// TODO purge sessions of this node
Logger::spgwu_sx().info( "TODO purge sessions of this node");
pending_associations.erase(it);
break;
}
}
pfcp_association* association = new pfcp_association(node_id);
std::shared_ptr<pfcp_association> s = std::shared_ptr<pfcp_association>(association);
pending_associations.push_back(s);
return true;
//start_timer = itti_inst->timer_setup(0,0, TASK_SPGWU_SX, TASK_MME_S11_TIMEOUT_SEND_GTPU_PING, 0);
}
//------------------------------------------------------------------------------
void pfcp_associations::trigger_heartbeat_request_procedure(std::shared_ptr<pfcp_association>& s)
{
s->timer_heartbeat = itti_inst->timer_setup(5,0, TASK_SPGWU_SX, TASK_SPGWU_SX_TRIGGER_HEARTBEAT_REQUEST, s->hash_node_id);
}
//------------------------------------------------------------------------------
void pfcp_associations::initiate_heartbeat_request(core::itti::timer_id_t timer_id, uint64_t arg2_user)
{
size_t hash = (size_t)arg2_user;
for (auto it : associations) {
if (it.second->hash_node_id == hash) {
Logger::spgwu_sx().info( "PFCP HEARTBEAT PROCEDURE hash %u starting", hash);
it.second->num_retries_timer_heartbeat = 0;
spgwu_sx_inst->send_heartbeat_request(it.second);
}
}
}
//------------------------------------------------------------------------------
void pfcp_associations::timeout_heartbeat_request(core::itti::timer_id_t timer_id, uint64_t arg2_user)
{
size_t hash = (size_t)arg2_user;
for (auto it : associations) {
if (it.second->hash_node_id == hash) {
Logger::spgwu_sx().info( "PFCP HEARTBEAT PROCEDURE hash %u TIMED OUT", hash);
if (it.second->num_retries_timer_heartbeat < PFCP_ASSOCIATION_HEARTBEAT_MAX_RETRIES) {
it.second->num_retries_timer_heartbeat++;
spgwu_sx_inst->send_heartbeat_request(it.second);
} else {
it.second->del_sessions();
core::pfcp::node_id_t node_id = it.second->node_id;
std::size_t hash_node_id = it.second->hash_node_id;
associations.erase((uint32_t)hash_node_id);
add_peer_candidate_node(node_id);
break;
}
}
}
}
//------------------------------------------------------------------------------
void pfcp_associations::handle_receive_heartbeat_response(const uint64_t trxn_id)
{
for (auto it : associations) {
if (it.second->trxn_id_heartbeat == trxn_id) {
itti_inst->timer_remove(it.second->timer_heartbeat);
trigger_heartbeat_request_procedure(it.second);
return;
}
}
Logger::spgwu_sx().info( "PFCP HEARTBEAT PROCEDURE trxn_id %d NOT FOUND", trxn_id);
}
//------------------------------------------------------------------------------
void pfcp_associations::notify_add_session(const oai::cn::core::pfcp::node_id_t& node_id, const oai::cn::core::pfcp::fseid_t& cp_fseid)
{
std::shared_ptr<pfcp_association> sa = {};
if (get_association(node_id, sa)) {
sa->notify_add_session(cp_fseid);
}
}
//------------------------------------------------------------------------------
void pfcp_associations::notify_del_session(const oai::cn::core::pfcp::fseid_t& cp_fseid)
{
std::shared_ptr<pfcp_association> sa = {};
if (get_association(cp_fseid, sa)) {
sa->notify_del_session(cp_fseid);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_pfcp_association.hpp
\author Lionel GAUTHIER
\date 2019
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SPGWU_PFCP_ASSOCIATION_HPP_SEEN
#define FILE_SPGWU_PFCP_ASSOCIATION_HPP_SEEN
#include "3gpp_29.244.h"
#include "itti.hpp"
#include <folly/AtomicHashMap.h>
#include <folly/AtomicLinkedList.h>
#include <mutex>
#include <vector>
namespace oai::cn::nf::spgwu {
#define PFCP_ASSOCIATION_HEARTBEAT_MAX_RETRIES 5
class pfcp_association {
public:
oai::cn::core::pfcp::node_id_t node_id;
std::size_t hash_node_id;
oai::cn::core::pfcp::recovery_time_stamp_t recovery_time_stamp;
std::pair<bool,oai::cn::core::pfcp::cp_function_features_t> function_features;
//
mutable std::mutex m_sessions;
std::set<oai::cn::core::pfcp::fseid_t> sessions;
//
oai::cn::core::itti::timer_id_t timer_heartbeat;
int num_retries_timer_heartbeat;
uint64_t trxn_id_heartbeat;
oai::cn::core::itti::timer_id_t timer_association;
pfcp_association(const oai::cn::core::pfcp::node_id_t& node_id) :
node_id(node_id), recovery_time_stamp(), function_features(), m_sessions(), sessions() {
hash_node_id = std::hash<oai::cn::core::pfcp::node_id_t>{}(node_id);
timer_heartbeat = ITTI_INVALID_TIMER_ID;
num_retries_timer_heartbeat = 0;
trxn_id_heartbeat = 0;
}
pfcp_association(const oai::cn::core::pfcp::node_id_t& node_id, oai::cn::core::pfcp::recovery_time_stamp_t& recovery_time_stamp) :
node_id(node_id), recovery_time_stamp(recovery_time_stamp), function_features(), m_sessions(), sessions() {
hash_node_id = std::hash<oai::cn::core::pfcp::node_id_t>{}(node_id);
timer_heartbeat = ITTI_INVALID_TIMER_ID;
num_retries_timer_heartbeat = 0;
trxn_id_heartbeat = 0;
}
pfcp_association(const oai::cn::core::pfcp::node_id_t& ni, oai::cn::core::pfcp::recovery_time_stamp_t& rts, oai::cn::core::pfcp::cp_function_features_t& uff):
node_id(ni), recovery_time_stamp(rts), m_sessions(), sessions() {
hash_node_id = std::hash<oai::cn::core::pfcp::node_id_t>{}(node_id);
function_features.first = true;
function_features.second = uff;
timer_heartbeat = ITTI_INVALID_TIMER_ID;
num_retries_timer_heartbeat = 0;
trxn_id_heartbeat = 0;
}
// pfcp_association(pfcp_association const & p)
// {
// node_id = p.node_id;
// hash_node_id = p.hash_node_id;
// recovery_time_stamp = p.recovery_time_stamp;
// function_features = p.function_features;
// sessions = p.sessions;
// num_sessions = p.num_sessions;
// timer_heartbeat = p.timer_heartbeat;
// num_retries_timer_heartbeat = p.num_retries_timer_heartbeat;
// trxn_id_heartbeat = p.trxn_id_heartbeat;
// }
void notify_add_session(const oai::cn::core::pfcp::fseid_t& cp_fseid);
bool has_session(const oai::cn::core::pfcp::fseid_t& cp_fseid);
void notify_del_session(const oai::cn::core::pfcp::fseid_t& cp_fseid);
void del_sessions();
void set(const oai::cn::core::pfcp::cp_function_features_t& ff) {function_features.first = true; function_features.second = ff;};
};
#define PFCP_MAX_ASSOCIATIONS 16
class pfcp_associations {
private:
std::vector<std::shared_ptr<pfcp_association>> pending_associations;
folly::AtomicHashMap<int32_t, std::shared_ptr<pfcp_association>> associations;
pfcp_associations() : associations(PFCP_MAX_ASSOCIATIONS), pending_associations() {};
void trigger_heartbeat_request_procedure(std::shared_ptr<pfcp_association>& s);
bool remove_peer_candidate_node(oai::cn::core::pfcp::node_id_t& node_id, std::shared_ptr<pfcp_association>& s);
public:
static pfcp_associations& get_instance()
{
static pfcp_associations instance;
return instance;
}
pfcp_associations(pfcp_associations const&) = delete;
void operator=(pfcp_associations const&) = delete;
bool add_association(oai::cn::core::pfcp::node_id_t& node_id, oai::cn::core::pfcp::recovery_time_stamp_t& recovery_time_stamp);
bool add_association(oai::cn::core::pfcp::node_id_t& node_id, oai::cn::core::pfcp::recovery_time_stamp_t& recovery_time_stamp, oai::cn::core::pfcp::cp_function_features_t& function_features);
bool get_association(const oai::cn::core::pfcp::node_id_t& node_id, std::shared_ptr<pfcp_association>& sa) const;
bool get_association(const oai::cn::core::pfcp::fseid_t& cp_fseid, std::shared_ptr<pfcp_association>& sa) const;
void notify_add_session(const oai::cn::core::pfcp::node_id_t& node_id, const oai::cn::core::pfcp::fseid_t& cp_fseid);
void notify_del_session(const oai::cn::core::pfcp::fseid_t& cp_fseid);
bool add_peer_candidate_node(const oai::cn::core::pfcp::node_id_t& node_id);
void initiate_heartbeat_request(oai::cn::core::itti::timer_id_t timer_id, uint64_t arg2_user);
void timeout_heartbeat_request(oai::cn::core::itti::timer_id_t timer_id, uint64_t arg2_user);
void handle_receive_heartbeat_response(const uint64_t trxn_id);
};
}
#endif /* FILE_SPGWU_PFCP_ASSOCIATION_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_sx.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "common_defs.h"
#include "itti.hpp"
#include "logger.hpp"
#include "spgwu_config.hpp"
#include "spgwu_pfcp_association.hpp"
#include "spgwu_sx.hpp"
#include <boost/asio.hpp>
#include <boost/asio/ip/address.hpp>
#include <chrono>
#include <ctime>
#include <stdexcept>
using namespace oai::cn::core;
using namespace oai::cn::proto::pfcp;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::spgwu;
using namespace std;
extern itti_mw *itti_inst;
extern spgwu_config spgwu_cfg;
extern spgwu_sx *spgwu_sx_inst;
void spgwu_sx_task (void*);
//------------------------------------------------------------------------------
void spgwu_sx_task (void *args_p)
{
const task_id_t task_id = TASK_SPGWU_SX;
itti_inst->notify_task_ready(task_id);
do {
std::shared_ptr<itti_msg> shared_msg = itti_inst->receive_msg(task_id);
auto *msg = shared_msg.get();
switch (msg->msg_type) {
case SXAB_HEARTBEAT_REQUEST:
if (itti_sxab_heartbeat_request* m = dynamic_cast<itti_sxab_heartbeat_request*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_HEARTBEAT_RESPONSE:
if (itti_sxab_heartbeat_response* m = dynamic_cast<itti_sxab_heartbeat_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_ASSOCIATION_SETUP_REQUEST:
if (itti_sxab_association_setup_request* m = dynamic_cast<itti_sxab_association_setup_request*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_ASSOCIATION_SETUP_RESPONSE:
if (itti_sxab_association_setup_response* m = dynamic_cast<itti_sxab_association_setup_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_ASSOCIATION_UPDATE_REQUEST:
if (itti_sxab_association_update_request* m = dynamic_cast<itti_sxab_association_update_request*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_ASSOCIATION_UPDATE_RESPONSE:
if (itti_sxab_association_update_response* m = dynamic_cast<itti_sxab_association_update_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_ASSOCIATION_RELEASE_REQUEST:
if (itti_sxab_association_release_request* m = dynamic_cast<itti_sxab_association_release_request*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_ASSOCIATION_RELEASE_RESPONSE:
if (itti_sxab_association_release_response* m = dynamic_cast<itti_sxab_association_release_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_VERSION_NOT_SUPPORTED_RESPONSE:
if (itti_sxab_version_not_supported_response* m = dynamic_cast<itti_sxab_version_not_supported_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_NODE_REPORT_RESPONSE:
if (itti_sxab_node_report_response* m = dynamic_cast<itti_sxab_node_report_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_SESSION_SET_DELETION_REQUEST:
if (itti_sxab_session_set_deletion_request* m = dynamic_cast<itti_sxab_session_set_deletion_request*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_SESSION_ESTABLISHMENT_RESPONSE:
if (itti_sxab_session_establishment_response* m = dynamic_cast<itti_sxab_session_establishment_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_SESSION_MODIFICATION_RESPONSE:
if (itti_sxab_session_modification_response* m = dynamic_cast<itti_sxab_session_modification_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_SESSION_DELETION_RESPONSE:
if (itti_sxab_session_deletion_response* m = dynamic_cast<itti_sxab_session_deletion_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_SESSION_REPORT_RESPONSE:
if (itti_sxab_session_report_response* m = dynamic_cast<itti_sxab_session_report_response*>(msg)) {
spgwu_sx_inst->handle_itti_msg(ref(*m));
}
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::spgwu_sx().info( "TIME-OUT event timer id %d", to->timer_id);
switch (to->arg1_user) {
case TASK_SPGWU_SX_TRIGGER_HEARTBEAT_REQUEST:
pfcp_associations::get_instance().initiate_heartbeat_request(to->timer_id, to->arg2_user);
break;
case TASK_SPGWU_SX_TIMEOUT_HEARTBEAT_REQUEST:
pfcp_associations::get_instance().timeout_heartbeat_request(to->timer_id, to->arg2_user);
break;
case TASK_SPGWU_SX_TIMEOUT_ASSOCIATION_REQUEST:
//TODO spgwu_sx_inst->time_out_event_association_request(to->timer_id, to->arg1_user, to->arg2_user);
break;
default:
;
}
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::spgwu_sx().info( "Received terminate message");
return;
}
break;
default:
Logger::spgwu_sx().info( "no handler for msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
spgwu_sx::spgwu_sx () : pfcp_l4_stack(std::string(inet_ntoa(spgwu_cfg.sx.addr4)), spgwu_cfg.sx.port)
{
Logger::spgwu_sx().startup("Starting...");
// TODO refine this, look at RFC5905
std::tm tm_epoch = {0};// Feb 8th, 2036
tm_epoch.tm_year = 2036 - 1900; // years count from 1900
tm_epoch.tm_mon = 2 - 1; // months count from January=0
tm_epoch.tm_mday = 8; // days count from 1
std::time_t time_epoch = std::mktime(&tm_epoch);
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::time_t ellapsed = now_c - time_epoch;
recovery_time_stamp = ellapsed;
// TODO load from config when features available ?
up_function_features = {};
up_function_features.bucp = 0;
up_function_features.ddnd = 0;
up_function_features.dlbd = 0;
up_function_features.trst = 0;
up_function_features.ftup = 1;
up_function_features.pfdm = 0;
up_function_features.heeu = 0;
up_function_features.treu = 0;
up_function_features.empu = 0;
up_function_features.pdiu = 0;
up_function_features.udbc = 0;
up_function_features.quoac = 0;
up_function_features.trace = 0;
up_function_features.frrt = 0;
if (itti_inst->create_task(TASK_SPGWU_SX, spgwu_sx_task, nullptr) ) {
Logger::spgwu_sx().error( "Cannot create task TASK_SPGWU_SX" );
throw std::runtime_error( "Cannot create task TASK_SPGWU_SX" );
}
for (std::vector<oai::cn::core::pfcp::node_id_t>::const_iterator it = spgwu_cfg.spgwcs.begin(); it != spgwu_cfg.spgwcs.end(); ++it) {
start_association(*it);
}
Logger::spgwu_sx().startup( "Started" );
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_heartbeat_request(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_heartbeat_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SPGWU_SX, error, trxn_id);
if (!error) {
if (not msg_ies_container.recovery_time_stamp.first) {
// Should be detected by lower layers
Logger::spgwu_sx().warn("Received SX HEARTBEAT REQUEST without recovery time stamp IE!, ignore message");
return;
}
Logger::spgwu_sx().info("Received SX HEARTBEAT REQUEST");
send_heartbeat_response(remote_endpoint, trxn_id);
}
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_heartbeat_response(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_heartbeat_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SPGWU_SX, error, trxn_id);
if (!error) {
if (not msg_ies_container.recovery_time_stamp.first) {
// Should be detected by lower layers
Logger::spgwu_sx().warn("Received SX HEARTBEAT RESPONSE without recovery time stamp IE!, ignore message");
return;
}
Logger::spgwu_sx().info("Received SX HEARTBEAT RESPONSE");
pfcp_associations::get_instance().handle_receive_heartbeat_response(trxn_id);
}
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_association_setup_response(pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_association_setup_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SPGWU_SX, error, trxn_id);
if (!error) {
if (not msg_ies_container.node_id.first) {
// Should be detected by lower layers
Logger::spgwu_sx().warn("Received SX ASSOCIATION SETUP RESPONSE without node id IE!, ignore message");
return;
}
if (not msg_ies_container.recovery_time_stamp.first) {
// Should be detected by lower layers
Logger::spgwu_sx().warn("Received SX ASSOCIATION SETUP RESPONSE without recovery time stamp IE!, ignore message");
return;
}
Logger::spgwu_sx().info("Received SX ASSOCIATION SETUP RESPONSE");
if (msg_ies_container.cp_function_features.first) {
pfcp_associations::get_instance().add_association(msg_ies_container.node_id.second, msg_ies_container.recovery_time_stamp.second, msg_ies_container.cp_function_features.second);
} else {
pfcp_associations::get_instance().add_association(msg_ies_container.node_id.second, msg_ies_container.recovery_time_stamp.second);
}
}
// else ignore ?
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_session_establishment_request(pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_session_establishment_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SPGWU_SX, error, trxn_id);
if (!error) {
itti_sxab_session_establishment_request *itti_msg = new itti_sxab_session_establishment_request(TASK_SPGWU_SX, TASK_SPGWU_APP);
itti_msg->pfcp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->trxn_id = trxn_id;
itti_msg->seid = msg.get_seid();
std::shared_ptr<itti_sxab_session_establishment_request> i = std::shared_ptr<itti_sxab_session_establishment_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::spgwu_sx().error( "Could not send ITTI message %s to task TASK_SPGWU_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_session_modification_request(pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_session_modification_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SPGWU_SX, error, trxn_id);
if (!error) {
itti_sxab_session_modification_request *itti_msg = new itti_sxab_session_modification_request(TASK_SPGWU_SX, TASK_SPGWU_APP);
itti_msg->pfcp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->trxn_id = trxn_id;
itti_msg->seid = msg.get_seid();
std::shared_ptr<itti_sxab_session_modification_request> i = std::shared_ptr<itti_sxab_session_modification_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::spgwu_sx().error( "Could not send ITTI message %s to task TASK_SPGWU_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_session_deletion_request(pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_session_deletion_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_SPGWU_SX, error, trxn_id);
if (!error) {
itti_sxab_session_deletion_request *itti_msg = new itti_sxab_session_deletion_request(TASK_SPGWU_SX, TASK_SPGWU_APP);
itti_msg->pfcp_ies = msg_ies_container;
itti_msg->r_endpoint = remote_endpoint;
itti_msg->trxn_id = trxn_id;
itti_msg->seid = msg.get_seid();
std::shared_ptr<itti_sxab_session_deletion_request> i = std::shared_ptr<itti_sxab_session_deletion_request>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::spgwu_sx().error( "Could not send ITTI message %s to task TASK_SPGWU_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive_pfcp_msg(pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
//Logger::spgwu_sx().trace( "handle_receive_pfcp_msg msg type %d length %d", msg.get_message_type(), msg.get_message_length());
switch (msg.get_message_type()) {
case PFCP_ASSOCIATION_SETUP_RESPONSE:
handle_receive_association_setup_response(msg, remote_endpoint);
break;
case PFCP_SESSION_ESTABLISHMENT_REQUEST:
handle_receive_session_establishment_request(msg, remote_endpoint);
break;
case PFCP_SESSION_MODIFICATION_REQUEST:
handle_receive_session_modification_request(msg, remote_endpoint);
break;
case PFCP_SESSION_DELETION_REQUEST:
handle_receive_session_deletion_request(msg, remote_endpoint);
break;
case PFCP_HEARTBEAT_REQUEST:
handle_receive_heartbeat_request(msg, remote_endpoint);
break;
case PFCP_HEARTBEAT_RESPONSE:
handle_receive_heartbeat_response(msg, remote_endpoint);
break;
case PFCP_PFCP_PFD_MANAGEMENT_REQUEST:
case PFCP_PFCP_PFD_MANAGEMENT_RESPONSE:
case PFCP_ASSOCIATION_SETUP_REQUEST:
case PFCP_ASSOCIATION_UPDATE_REQUEST:
case PFCP_ASSOCIATION_UPDATE_RESPONSE:
case PFCP_ASSOCIATION_RELEASE_REQUEST:
case PFCP_ASSOCIATION_RELEASE_RESPONSE:
case PFCP_VERSION_NOT_SUPPORTED_RESPONSE:
case PFCP_NODE_REPORT_REQUEST:
case PFCP_NODE_REPORT_RESPONSE:
case PFCP_SESSION_SET_DELETION_REQUEST:
case PFCP_SESSION_SET_DELETION_RESPONSE:
case PFCP_SESSION_ESTABLISHMENT_RESPONSE:
case PFCP_SESSION_MODIFICATION_RESPONSE:
case PFCP_SESSION_DELETION_RESPONSE:
case PFCP_SESSION_REPORT_REQUEST:
case PFCP_SESSION_REPORT_RESPONSE:
Logger::spgwu_sx().info( "handle_receive_pfcp_msg msg %d length %d, not handled, discarded!", msg.get_message_type(), msg.get_message_length());
break;
default:
Logger::spgwu_sx().info( "unhandled msg %d length %d, unknown, discarded!", msg.get_message_type(), msg.get_message_length());
}
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_itti_msg (itti_sxab_session_establishment_response& msg)
{
send_sx_msg(msg);
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_itti_msg (itti_sxab_session_modification_response& msg)
{
send_sx_msg(msg);
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_itti_msg (itti_sxab_session_deletion_response& msg)
{
send_sx_msg(msg);
}
//------------------------------------------------------------------------------
void spgwu_sx::send_sx_msg(itti_sxab_session_establishment_response& i)
{
send_response(i.r_endpoint, i.seid, i.pfcp_ies, i.trxn_id);
}
//------------------------------------------------------------------------------
void spgwu_sx::send_sx_msg(itti_sxab_session_modification_response& i)
{
send_response(i.r_endpoint, i.seid, i.pfcp_ies, i.trxn_id);
}
//------------------------------------------------------------------------------
void spgwu_sx::send_sx_msg(itti_sxab_session_deletion_response& i)
{
send_response(i.r_endpoint, i.seid, i.pfcp_ies, i.trxn_id);
}
//------------------------------------------------------------------------------
void spgwu_sx::start_association(const core::pfcp::node_id_t& node_id)
{
pfcp_associations::get_instance().add_peer_candidate_node(node_id);
itti_sxab_association_setup_request a(TASK_SPGWU_SX, TASK_SPGWU_SX);
a.trxn_id = generate_trxn_id();
oai::cn::core::pfcp::node_id_t this_node_id = {};
if (spgwu_cfg.get_pfcp_node_id(this_node_id) == RETURNok) {
a.pfcp_ies.set(this_node_id);
core::pfcp::recovery_time_stamp_t r = {.recovery_time_stamp = (uint32_t)recovery_time_stamp};
a.pfcp_ies.set(r);
a.pfcp_ies.set(up_function_features);
if (node_id.node_id_type == core::pfcp::NODE_ID_TYPE_IPV4_ADDRESS) {
//a.l_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(spgwu_cfg.sx.addr4), 0);
a.r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(htobe32(node_id.u1.ipv4_address.s_addr)), 8805);
send_sx_msg(a);
} else {
Logger::spgwu_sx().warn( "TODO start_association() node_id IPV6, FQDN!");
}
}
}
//------------------------------------------------------------------------------
void spgwu_sx::send_sx_msg(itti_sxab_association_setup_request& i)
{
send_request(i.r_endpoint, i.pfcp_ies, TASK_SPGWU_SX, i.trxn_id);
}
//------------------------------------------------------------------------------
void spgwu_sx::send_sx_msg(const core::pfcp::fseid_t& cp_fseid, const oai::cn::proto::pfcp::pfcp_session_report_request& s)
{
itti_sxab_session_report_request isrr(TASK_SPGWU_SX, TASK_SPGWU_SX);
isrr.trxn_id = generate_trxn_id();
isrr.pfcp_ies = s;
oai::cn::core::pfcp::node_id_t this_node_id = {};
if (spgwu_cfg.get_pfcp_node_id(this_node_id) == RETURNok) {
if (this_node_id.node_id_type == core::pfcp::NODE_ID_TYPE_IPV4_ADDRESS) {
//a.l_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(spgwu_cfg.sx.addr4), 0);
isrr.r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(htobe32(this_node_id.u1.ipv4_address.s_addr)), 8805);
send_sx_msg(isrr);
} else {
Logger::spgwu_sx().warn( "TODO start_association() node_id IPV6, FQDN!");
}
}
}
//------------------------------------------------------------------------------
void spgwu_sx::send_heartbeat_request(std::shared_ptr<pfcp_association>& a)
{
oai::cn::proto::pfcp::pfcp_heartbeat_request h = {};
core::pfcp::recovery_time_stamp_t r = {.recovery_time_stamp = (uint32_t)recovery_time_stamp};
h.set(r);
core::pfcp::node_id_t& node_id = a->node_id;
if (node_id.node_id_type == core::pfcp::NODE_ID_TYPE_IPV4_ADDRESS) {
a->timer_heartbeat = itti_inst->timer_setup(5,0, TASK_SPGWU_SX, TASK_SPGWU_SX_TIMEOUT_HEARTBEAT_REQUEST, a->hash_node_id);
boost::asio::ip::udp::endpoint r_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(htobe32(node_id.u1.ipv4_address.s_addr)), 8805);
a->trxn_id_heartbeat = generate_trxn_id();
send_request(r_endpoint, h, TASK_SPGWU_SX, a->trxn_id_heartbeat);
} else {
Logger::spgwu_sx().warn( "TODO send_heartbeat_request() node_id IPV6, FQDN!");
}
}
//------------------------------------------------------------------------------
void spgwu_sx::send_heartbeat_response(const boost::asio::ip::udp::endpoint& r_endpoint, const uint64_t trxn_id)
{
oai::cn::proto::pfcp::pfcp_heartbeat_response h = {};
core::pfcp::recovery_time_stamp_t r = {.recovery_time_stamp = (uint32_t)recovery_time_stamp};
h.set(r);
send_response(r_endpoint, h, trxn_id);
}
//------------------------------------------------------------------------------
void spgwu_sx::handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint)
{
Logger::spgwu_sx().info( "handle_receive(%d bytes)", bytes_transferred);
//std::cout << string_to_hex(recv_buffer, bytes_transferred) << std::endl;
std::istringstream iss(std::istringstream::binary);
iss.rdbuf()->pubsetbuf(recv_buffer,bytes_transferred);
pfcp_msg msg = {};
msg.remote_port = remote_endpoint.port();
try {
msg.load_from(iss);
handle_receive_pfcp_msg(msg, remote_endpoint);
} catch (pfcp_exception& e) {
Logger::spgwu_sx().info( "handle_receive exception %s", e.what());
}
}
//------------------------------------------------------------------------------
void spgwu_sx::time_out_itti_event(const uint32_t timer_id)
{
bool handled = false;
time_out_event(timer_id, TASK_SPGWU_SX, handled);
if (!handled) {
Logger::spgwu_sx().error( "Timer %d not Found", timer_id);
}
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file spgwu_sx.hpp
\author Lionel GAUTHIER
\date 2019
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_SGWU_SX_HPP_SEEN
#define FILE_SGWU_SX_HPP_SEEN
#include "pfcp.hpp"
#include "itti_msg_sxab.hpp"
#include "msg_pfcp.hpp"
#include "spgwu_pfcp_association.hpp"
#include <boost/asio.hpp>
#include <boost/asio/ip/address.hpp>
#include <thread>
namespace oai::cn::nf::spgwu {
#define TASK_SPGWU_SX_TRIGGER_HEARTBEAT_REQUEST (0)
#define TASK_SPGWU_SX_TIMEOUT_HEARTBEAT_REQUEST (1)
#define TASK_SPGWU_SX_TIMEOUT_ASSOCIATION_REQUEST (2)
class spgwu_sx : public oai::cn::proto::pfcp::pfcp_l4_stack {
private:
std::thread::id thread_id;
std::thread thread;
uint64_t recovery_time_stamp; //timestamp in seconds
core::pfcp::up_function_features_t up_function_features;
void start_association(const core::pfcp::node_id_t& node_id);
public:
spgwu_sx();
spgwu_sx(spgwu_sx const&) = delete;
void operator=(spgwu_sx const&) = delete;
void handle_itti_msg (core::itti::itti_sxab_heartbeat_request& s) {};
void handle_itti_msg (core::itti::itti_sxab_heartbeat_response& s) {};
void handle_itti_msg (core::itti::itti_sxab_association_setup_request& s) {};
void handle_itti_msg (core::itti::itti_sxab_association_setup_response& s) {};
void handle_itti_msg (core::itti::itti_sxab_association_update_request& s) {};
void handle_itti_msg (core::itti::itti_sxab_association_update_response& s) {};
void handle_itti_msg (core::itti::itti_sxab_association_release_request& s) {};
void handle_itti_msg (core::itti::itti_sxab_association_release_response& s) {};
void handle_itti_msg (core::itti::itti_sxab_version_not_supported_response& s) {};
void handle_itti_msg (core::itti::itti_sxab_node_report_response& s) {};
void handle_itti_msg (core::itti::itti_sxab_session_set_deletion_request& s) {};
void handle_itti_msg (core::itti::itti_sxab_session_establishment_response& s);
void handle_itti_msg (core::itti::itti_sxab_session_modification_response& s);
void handle_itti_msg (core::itti::itti_sxab_session_deletion_response& s);
void handle_itti_msg (core::itti::itti_sxab_session_report_response& s) {};
void send_sx_msg (core::itti::itti_sxab_heartbeat_request& s) {};
void send_sx_msg (core::itti::itti_sxab_heartbeat_response& s) {};
void send_sx_msg (core::itti::itti_sxab_association_setup_request& s);
void send_sx_msg (core::itti::itti_sxab_association_setup_response& s) {};
void send_sx_msg (core::itti::itti_sxab_association_update_request& s) {};
void send_sx_msg (core::itti::itti_sxab_association_update_response& s) {};
void send_sx_msg (core::itti::itti_sxab_association_release_request& s) {};
void send_sx_msg (core::itti::itti_sxab_association_release_response& s) {};
void send_sx_msg (core::itti::itti_sxab_version_not_supported_response& s) {};
void send_sx_msg (core::itti::itti_sxab_node_report_request& s) {};
void send_sx_msg (core::itti::itti_sxab_session_set_deletion_response& s) {};
void send_sx_msg (core::itti::itti_sxab_session_establishment_response& s);
void send_sx_msg (core::itti::itti_sxab_session_modification_response& s);
void send_sx_msg (core::itti::itti_sxab_session_deletion_response& s);
void send_sx_msg (core::itti::itti_sxab_session_report_request& s) {};
void send_sx_msg(const core::pfcp::fseid_t& cp_fseid, const oai::cn::proto::pfcp::pfcp_session_report_request& s);
void send_heartbeat_request(std::shared_ptr<pfcp_association>& a);
void send_heartbeat_response(const boost::asio::ip::udp::endpoint& r_endpoint, const uint64_t trxn_id);
void handle_receive_pfcp_msg( proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint);
// node related
void handle_receive_heartbeat_request(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_heartbeat_response(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_association_setup_response(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
// session related
void handle_receive_session_establishment_request(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_session_modification_request(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void handle_receive_session_deletion_request(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint);
void time_out_itti_event(const uint32_t timer_id);
};
}
#endif /* FILE_SGWU_SX_HPP_SEEN */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment