Commit 79655dbd authored by gauthier's avatar gauthier

prepare handling of SPGW-U Failure in PGW-C 3GPP TS 23.007 (17.1A.4 PGW-U Failure)

parent 6a68aff2
......@@ -118,7 +118,7 @@ ENDIF(STATIC_LINKING)
################################################################
# Build type
################################################################
add_list_string_option(CMAKE_BUILD_TYPE "RelWithDebInfo" "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." Debug Release
add_list_string_option(CMAKE_BUILD_TYPE "RelWithDebInfo" "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." Debug Release
RelWithDebInfo MinSizeRel)
Message("Build type is ${CMAKE_BUILD_TYPE}")
if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
......@@ -177,7 +177,7 @@ set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -std=c++17 -Os -s")
################################################################
# Git Version
# Git Version
################################################################
set(GIT_BRANCH "UNKNOWN")
set(GIT_COMMIT_HASH "UNKNOWN")
......@@ -201,7 +201,7 @@ if(GIT_FOUND)
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Get the latest commit date of the working branch
execute_process(
COMMAND git log -1 --format=%cd
......@@ -310,5 +310,5 @@ if(${SGW_AUTOTEST})
SET(GTPV1U_LIB GTPV1U)
endif(${SGW_AUTOTEST})
target_link_libraries (spgwc ${ASAN} -Wl,--start-group CN_UTILS SGWC PGWC ${GTPV1U_LIB} GTPV2C PFCP 3GPP_COMMON_TYPES -Wl,--end-group pthread m rt config++ event boost_system )
target_link_libraries (spgwc ${ASAN} -Wl,--start-group CN_UTILS SGWC PGWC ${GTPV1U_LIB} GTPV2C PFCP 3GPP_COMMON_TYPES gflags glog dl double-conversion folly -Wl,--end-group pthread m rt config++ event boost_system )
/*
* 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 "pgw_pfcp_association.hpp"
#include "pgwc_sxab.hpp"
using namespace oai::cn::core;
using namespace oai::cn::core::itti;
using namespace oai::cn::nf::pgwc;
using namespace std;
extern itti_mw *itti_inst;
extern pgwc_sxab *pgwc_sxab_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();) {
// ???->remove_pfcp_session(*it);
// sessions.erase(it++);
// }
// }
//------------------------------------------------------------------------------
void pfcp_association::restore_sx_sessions()
{
std::unique_lock<std::mutex> l(m_sessions);
for (std::set<core::pfcp::fseid_t>::iterator it=sessions.begin(); it!=sessions.end();) {
;
}
}
//------------------------------------------------------------------------------
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, bool& restore_sx_sessions)
{
std::shared_ptr<pfcp_association> sa = std::shared_ptr<pfcp_association>(nullptr);
if (get_association(node_id, sa)) {
itti_inst->timer_remove(sa->timer_heartbeat);
if (sa->recovery_time_stamp == recovery_time_stamp) {
restore_sx_sessions = false;
} else {
restore_sx_sessions = true;
}
sa->recovery_time_stamp = recovery_time_stamp;
sa->function_features = {};
} else {
restore_sx_sessions = false;
pfcp_association* association = new pfcp_association(node_id, recovery_time_stamp);
sa = std::shared_ptr<pfcp_association>(association);
sa->recovery_time_stamp = recovery_time_stamp;
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;
}
//------------------------------------------------------------------------------
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::up_function_features_s& function_features, bool& restore_sx_sessions)
{
std::shared_ptr<pfcp_association> sa = std::shared_ptr<pfcp_association>(nullptr);
if (get_association(node_id, sa)) {
itti_inst->timer_remove(sa->timer_heartbeat);
if (sa->recovery_time_stamp == recovery_time_stamp) {
restore_sx_sessions = false;
} else {
restore_sx_sessions = true;
}
sa->recovery_time_stamp = recovery_time_stamp;
sa->function_features.first = true;
sa->function_features.second = function_features;
} else {
restore_sx_sessions = false;
pfcp_association* association = new pfcp_association(node_id, recovery_time_stamp, function_features);
sa = std::shared_ptr<pfcp_association>(association);
sa->recovery_time_stamp = recovery_time_stamp;
sa->function_features.first = true;
sa->function_features.second = 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;
}
//------------------------------------------------------------------------------
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;
}
//------------------------------------------------------------------------------
void pfcp_associations::restore_sx_sessions(const oai::cn::core::pfcp::node_id_t& node_id)
{
std::shared_ptr<pfcp_association> sa = {};
if (get_association(node_id, sa)) {
sa->restore_sx_sessions();
}
}
//------------------------------------------------------------------------------
void pfcp_associations::trigger_heartbeat_request_procedure(std::shared_ptr<pfcp_association>& s)
{
s->timer_heartbeat = itti_inst->timer_setup(PFCP_ASSOCIATION_HEARTBEAT_INTERVAL_SEC,0, TASK_PGWC_SX, TASK_PGWC_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_node_id = (size_t)arg2_user;
auto pit = associations.find((int32_t)hash_node_id);
if ( pit == associations.end() )
return;
else {
Logger::pgwc_sx().info( "PFCP HEARTBEAT PROCEDURE hash %u starting", hash_node_id);
pit->second->num_retries_timer_heartbeat = 0;
pgwc_sxab_inst->send_heartbeat_request(pit->second);
}
}
//------------------------------------------------------------------------------
void pfcp_associations::timeout_heartbeat_request(core::itti::timer_id_t timer_id, uint64_t arg2_user)
{
size_t hash_node_id = (size_t)arg2_user;
auto pit = associations.find((int32_t)hash_node_id);
if ( pit == associations.end() )
return;
else {
if (pit->second->num_retries_timer_heartbeat < PFCP_ASSOCIATION_HEARTBEAT_MAX_RETRIES) {
Logger::pgwc_sx().info( "PFCP HEARTBEAT PROCEDURE hash %u TIMED OUT (retrie %d)", hash_node_id, pit->second->num_retries_timer_heartbeat);
pit->second->num_retries_timer_heartbeat++;
pgwc_sxab_inst->send_heartbeat_request(pit->second);
} else {
Logger::pgwc_sx().warn( "PFCP HEARTBEAT PROCEDURE FAILED after %d retries! TODO", PFCP_ASSOCIATION_HEARTBEAT_MAX_RETRIES);
}
}
}
//------------------------------------------------------------------------------
void pfcp_associations::handle_receive_heartbeat_response(const uint64_t trxn_id)
{
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->trxn_id_heartbeat == trxn_id) {
itti_inst->timer_remove(it->second->timer_heartbeat);
trigger_heartbeat_request_procedure(it->second);
return;
}
}
}
//------------------------------------------------------------------------------
bool pfcp_associations::select_up_node(oai::cn::core::pfcp::node_id_t& node_id, const int node_selection_criteria)
{
node_id = {};
if (associations.empty()) {
return false;
}
folly::AtomicHashMap<int32_t, std::shared_ptr<pfcp_association>>::iterator it;
FOR_EACH (it, associations) {
std::shared_ptr<pfcp_association> a = it->second;
// TODO
switch (node_selection_criteria) {
case NODE_SELECTION_CRITERIA_BEST_MAX_HEARBEAT_RTT:
case NODE_SELECTION_CRITERIA_MIN_PFCP_SESSIONS:
case NODE_SELECTION_CRITERIA_MIN_UP_TIME:
case NODE_SELECTION_CRITERIA_MAX_AVAILABLE_BW:
case NODE_SELECTION_CRITERIA_NONE:
default:
node_id = it->second->node_id;
return true;
break;
}
}
return false;
}
//------------------------------------------------------------------------------
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 pgw_pfcp_association.hpp
\author Lionel GAUTHIER
\date 2019
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_PGW_PFCP_ASSOCIATION_HPP_SEEN
#define FILE_PGW_PFCP_ASSOCIATION_HPP_SEEN
#include "3gpp_29.244.h"
#include "itti.hpp"
#include <folly/AtomicHashMap.h>
#include <vector>
namespace oai::cn::nf::pgwc {
#define PFCP_ASSOCIATION_HEARTBEAT_INTERVAL_SEC 10
#define PFCP_ASSOCIATION_HEARTBEAT_MAX_RETRIES 2
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::up_function_features_s> 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;
explicit 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::up_function_features_s& 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;
timer_association = {};
}
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),
timer_heartbeat(p.timer_heartbeat),
num_retries_timer_heartbeat(p.num_retries_timer_heartbeat),
trxn_id_heartbeat(p.trxn_id_heartbeat),
timer_association(0) {}
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 restore_sx_sessions();
void set(const oai::cn::core::pfcp::up_function_features_s& ff) {function_features.first = true; function_features.second = ff;};
};
enum node_selection_criteria_e {
NODE_SELECTION_CRITERIA_BEST_MAX_HEARBEAT_RTT = 0,
NODE_SELECTION_CRITERIA_MIN_PFCP_SESSIONS = 1,
NODE_SELECTION_CRITERIA_MIN_UP_TIME = 2,
NODE_SELECTION_CRITERIA_MAX_AVAILABLE_BW = 3,
NODE_SELECTION_CRITERIA_NONE = 4
};
#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);
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& restore_sx_sessions);
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::up_function_features_s& function_features, bool& restore_sx_sessions);
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);
void restore_sx_sessions(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);
bool select_up_node(oai::cn::core::pfcp::node_id_t& node_id, const int node_selection_criteria);
};
}
#endif /* FILE_PGW_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 pgwc_sxab.cpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#include "common_defs.h"
#include "itti.hpp"
#include "logger.hpp"
#include "pgw_config.hpp"
#include "pgwc_sxab.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::pgwc;
using namespace std;
extern itti_mw *itti_inst;
extern pgw_config pgw_cfg;
extern pgwc_sxab *pgwc_sxab_inst;
void pgwc_sxab_task (void*);
//------------------------------------------------------------------------------
void pgwc_sxab_task (void *args_p)
{
const task_id_t task_id = TASK_PGWC_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)) {
pgwc_sxab_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_HEARTBEAT_RESPONSE:
if (itti_sxab_heartbeat_response* m = dynamic_cast<itti_sxab_heartbeat_response*>(msg)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_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)) {
pgwc_sxab_inst->handle_itti_msg(ref(*m));
}
break;
case SXAB_SESSION_ESTABLISHMENT_REQUEST:
if (itti_sxab_session_establishment_request* m = dynamic_cast<itti_sxab_session_establishment_request*>(msg)) {
pgwc_sxab_inst->send_sx_msg(ref(*m));
}
break;
case SXAB_SESSION_MODIFICATION_REQUEST:
if (itti_sxab_session_modification_request* m = dynamic_cast<itti_sxab_session_modification_request*>(msg)) {
pgwc_sxab_inst->send_sx_msg(ref(*m));
}
break;
case SXAB_SESSION_DELETION_REQUEST:
if (itti_sxab_session_deletion_request* m = dynamic_cast<itti_sxab_session_deletion_request*>(msg)) {
pgwc_sxab_inst->send_sx_msg(ref(*m));
}
break;
case SXAB_SESSION_REPORT_RESPONSE:
if (itti_sxab_session_report_response* m = dynamic_cast<itti_sxab_session_report_response*>(msg)) {
pgwc_sxab_inst->handle_itti_msg(ref(*m));
}
break;
case TIME_OUT:
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
Logger::pgwc_sx().info( "TIME-OUT event timer id %d", to->timer_id);
switch (to->arg1_user) {
case TASK_PGWC_SX_TRIGGER_HEARTBEAT_REQUEST:
pfcp_associations::get_instance().initiate_heartbeat_request(to->timer_id, to->arg2_user);
break;
case TASK_PGWC_SX_TIMEOUT_HEARTBEAT_REQUEST:
pfcp_associations::get_instance().timeout_heartbeat_request(to->timer_id, to->arg2_user);
break;
default:
;
}
}
break;
case TERMINATE:
if (itti_msg_terminate *terminate = dynamic_cast<itti_msg_terminate*>(msg)) {
Logger::pgwc_sx().info( "Received terminate message");
return;
}
break;
default:
Logger::pgwc_sx().info( "no handler for msg type %d", msg->msg_type);
}
} while (true);
}
//------------------------------------------------------------------------------
pgwc_sxab::pgwc_sxab() : pfcp_l4_stack(string(inet_ntoa(pgw_cfg.sx.addr4)), pgw_cfg.sx.port)
{
Logger::pgwc_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 may load this from config
cp_function_features = {};
cp_function_features.ovrl = 0;
cp_function_features.load = 0;
if (itti_inst->create_task(TASK_PGWC_SX, pgwc_sxab_task, nullptr) ) {
Logger::pgwc_sx().error( "Cannot create task TASK_PGWC_SX" );
throw std::runtime_error( "Cannot create task TASK_PGWC_SX" );
}
Logger::pgwc_sx().startup( "Started" );
}
//------------------------------------------------------------------------------
void pgwc_sxab::handle_receive_pfcp_msg(pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
Logger::pgwc_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_REQUEST:
handle_receive_association_setup_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_SESSION_ESTABLISHMENT_RESPONSE:
handle_receive_session_establishment_response(msg, remote_endpoint);
break;
case PFCP_SESSION_MODIFICATION_RESPONSE:
handle_receive_session_modification_response(msg, remote_endpoint);
break;
case PFCP_SESSION_DELETION_RESPONSE:
handle_receive_session_deletion_response(msg, remote_endpoint);
break;
case PFCP_PFCP_PFD_MANAGEMENT_REQUEST:
case PFCP_PFCP_PFD_MANAGEMENT_RESPONSE:
case PFCP_ASSOCIATION_SETUP_RESPONSE:
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_REQUEST:
case PFCP_SESSION_MODIFICATION_REQUEST:
case PFCP_SESSION_DELETION_REQUEST:
case PFCP_SESSION_REPORT_REQUEST:
case PFCP_SESSION_REPORT_RESPONSE:
Logger::pgwc_sx().info( "handle_receive_pfcp_msg msg %d length %d, not handled, discarded!", msg.get_message_type(), msg.get_message_length());
break;
default:
Logger::pgwc_sx().info( "handle_receive_pfcp_msg msg %d length %d, unknown, discarded!", msg.get_message_type(), msg.get_message_length());
}
}
//------------------------------------------------------------------------------
void pgwc_sxab::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_PGWC_SX, error, trxn_id);
if (!error) {
if (not msg_ies_container.recovery_time_stamp.first) {
// Should be detected by lower layers
Logger::pgwc_sx().warn("Received SX HEARTBEAT REQUEST without recovery time stamp IE!, ignore message");
return;
}
send_heartbeat_response(remote_endpoint, trxn_id);
}
}
//------------------------------------------------------------------------------
void pgwc_sxab::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_PGWC_SX, error, trxn_id);
if (!error) {
if (not msg_ies_container.recovery_time_stamp.first) {
// Should be detected by lower layers
Logger::pgwc_sx().warn("Received SX HEARTBEAT REQUEST without recovery time stamp IE!, ignore message");
return;
}
pfcp_associations::get_instance().handle_receive_heartbeat_response(trxn_id);
}
}
//------------------------------------------------------------------------------
void pgwc_sxab::handle_receive_association_setup_request(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_association_setup_request msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_PGWC_SX, error, trxn_id);
if (!error) {
if (not msg_ies_container.node_id.first) {
// Should be detected by lower layers
Logger::pgwc_sx().warn("Received SX ASSOCIATION SETUP REQUEST without node id IE!, ignore message");
return;
}
if (not msg_ies_container.recovery_time_stamp.first) {
// Should be detected by lower layers
Logger::pgwc_sx().warn("Received SX ASSOCIATION SETUP REQUEST without recovery time stamp IE!, ignore message");
return;
}
bool restore_sx_sessions = false;
if (msg_ies_container.up_function_features.first) {
// Should be detected by lower layers
pfcp_associations::get_instance().add_association(msg_ies_container.node_id.second, msg_ies_container.recovery_time_stamp.second, msg_ies_container.up_function_features.second, restore_sx_sessions);
} else {
pfcp_associations::get_instance().add_association(msg_ies_container.node_id.second, msg_ies_container.recovery_time_stamp.second, restore_sx_sessions);
}
// always yes (for the time being)
itti_sxab_association_setup_response a(TASK_SPGWU_SX, TASK_SPGWU_SX);
a.trxn_id = trxn_id;
oai::cn::core::pfcp::cause_t cause = {.cause_value = oai::cn::core::pfcp::CAUSE_VALUE_REQUEST_ACCEPTED};
a.pfcp_ies.set(cause);
oai::cn::core::pfcp::node_id_t node_id = {};
if (pgw_cfg.get_pfcp_node_id(node_id) == RETURNok) {
a.pfcp_ies.set(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(cp_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(pgw_cfg.sx.addr4), 0);
a.r_endpoint = remote_endpoint;
send_sx_msg(a);
} else {
Logger::pgwc_sx().warn("Received SX ASSOCIATION SETUP REQUEST TODO node_id IPV6, FQDN!, ignore message");
return;
}
} else {
Logger::pgwc_sx().warn("Received SX ASSOCIATION SETUP REQUEST could not set node id!, ignore message");
return;
}
if (restore_sx_sessions) {
pfcp_associations::get_instance().restore_sx_sessions(msg_ies_container.node_id.second);
}
}
}
//------------------------------------------------------------------------------
void pgwc_sxab::handle_receive_session_establishment_response(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_session_establishment_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_PGWC_SX, error, trxn_id);
if (!error) {
itti_sxab_session_establishment_response *itti_msg = new itti_sxab_session_establishment_response(TASK_PGWC_SX, TASK_PGWC_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_response> i = std::shared_ptr<itti_sxab_session_establishment_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::pgwc_sx().error( "Could not send ITTI message %s to task TASK_PGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void pgwc_sxab::handle_receive_session_modification_response(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_session_modification_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_PGWC_SX, error, trxn_id);
if (!error) {
itti_sxab_session_modification_response *itti_msg = new itti_sxab_session_modification_response(TASK_PGWC_SX, TASK_PGWC_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_response> i = std::shared_ptr<itti_sxab_session_modification_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::pgwc_sx().error( "Could not send ITTI message %s to task TASK_PGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void pgwc_sxab::handle_receive_session_deletion_response(proto::pfcp::pfcp_msg& msg, const boost::asio::ip::udp::endpoint& remote_endpoint)
{
bool error = true;
uint64_t trxn_id = 0;
pfcp_session_deletion_response msg_ies_container = {};
msg.to_core_type(msg_ies_container);
handle_receive_message_cb(msg, remote_endpoint, TASK_PGWC_SX, error, trxn_id);
if (!error) {
itti_sxab_session_deletion_response *itti_msg = new itti_sxab_session_deletion_response(TASK_PGWC_SX, TASK_PGWC_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_response> i = std::shared_ptr<itti_sxab_session_deletion_response>(itti_msg);
int ret = itti_inst->send_msg(i);
if (RETURNok != ret) {
Logger::pgwc_sx().error( "Could not send ITTI message %s to task TASK_PGWC_APP", i->get_msg_name());
}
}
// else ignore
}
//------------------------------------------------------------------------------
void pgwc_sxab::send_sx_msg(itti_sxab_association_setup_response& i)
{
send_response(i.r_endpoint, i.pfcp_ies, i.trxn_id);
}
//------------------------------------------------------------------------------
void pgwc_sxab::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_PGWC_SX, TASK_PGWC_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_PGWC_SX, a->trxn_id_heartbeat);
} else {
Logger::pgwc_sx().warn( "TODO send_heartbeat_request() node_id IPV6, FQDN!");
}
}
//------------------------------------------------------------------------------
void pgwc_sxab::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 pgwc_sxab::send_sx_msg(itti_sxab_session_establishment_request& i)
{
send_request(i.r_endpoint, i.seid, i.pfcp_ies, TASK_PGWC_SX, i.trxn_id);
}
//------------------------------------------------------------------------------
void pgwc_sxab::send_sx_msg(itti_sxab_session_modification_request& i)
{
send_request(i.r_endpoint, i.seid, i.pfcp_ies, TASK_PGWC_SX, i.trxn_id);
}
//------------------------------------------------------------------------------
void pgwc_sxab::send_sx_msg(itti_sxab_session_deletion_request& i)
{
send_request(i.r_endpoint, i.seid, i.pfcp_ies, TASK_PGWC_SX, i.trxn_id);
}
//------------------------------------------------------------------------------
void pgwc_sxab::handle_receive(char* recv_buffer, const std::size_t bytes_transferred, boost::asio::ip::udp::endpoint& remote_endpoint)
{
Logger::pgwc_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::pgwc_sx().info( "handle_receive exception %s", e.what());
}
}
//------------------------------------------------------------------------------
void pgwc_sxab::time_out_itti_event(const uint32_t timer_id)
{
bool handled = false;
time_out_event(timer_id, TASK_PGWC_SX, handled);
if (!handled) {
Logger::pgwc_sx().error( "Timer %d not Found", timer_id);
}
}
......@@ -87,7 +87,7 @@ bool pfcp_associations::add_association(oai::cn::core::pfcp::node_id_t& node_id,
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&
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_s&
function_features)
{
std::shared_ptr<pfcp_association> sa = {};
......@@ -117,7 +117,7 @@ bool pfcp_associations::get_association(const oai::cn::core::pfcp::node_id_t& no
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)) {
......
......@@ -44,7 +44,7 @@ namespace oai::cn::nf::spgwu {
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;
std::pair<bool,oai::cn::core::pfcp::cp_function_features_s> function_features;
//
mutable std::mutex m_sessions;
std::set<oai::cn::core::pfcp::fseid_t> sessions;
......@@ -69,7 +69,7 @@ namespace oai::cn::nf::spgwu {
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):
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_s& 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;
......@@ -77,6 +77,7 @@ namespace oai::cn::nf::spgwu {
timer_heartbeat = ITTI_INVALID_TIMER_ID;
num_retries_timer_heartbeat = 0;
trxn_id_heartbeat = 0;
timer_association = {};
}
// pfcp_association(pfcp_association const & p)
// {
......@@ -94,16 +95,16 @@ namespace oai::cn::nf::spgwu {
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;};
void set(const oai::cn::core::pfcp::cp_function_features_s& 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);
......@@ -119,14 +120,17 @@ namespace oai::cn::nf::spgwu {
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 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_s& 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 restore_sx_sessions(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);
......
......@@ -50,7 +50,7 @@ private:
std::thread thread;
uint64_t recovery_time_stamp; //timestamp in seconds
core::pfcp::up_function_features_t up_function_features;
core::pfcp::up_function_features_s up_function_features;
void start_association(const core::pfcp::node_id_t& node_id);
......@@ -92,7 +92,7 @@ public:
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);
......
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