Commit c95fe15a authored by Stefan Spettel's avatar Stefan Spettel

feat(smf): Added client call to PCF to create SM Policy Association and merged into smf_context

Signed-off-by: default avatarStefan Spettel <stefan.spettel@eurecom.fr>
parent e6edca22
...@@ -55,6 +55,7 @@ add_library (SMF STATIC ...@@ -55,6 +55,7 @@ add_library (SMF STATIC
smf_pco.cpp smf_pco.cpp
smf_procedure.cpp smf_procedure.cpp
smf_n4.cpp smf_n4.cpp
smf_n7.cpp
smf_sbi.cpp smf_sbi.cpp
smf_event.cpp smf_event.cpp
smf_profile.cpp smf_profile.cpp
......
...@@ -46,12 +46,18 @@ ...@@ -46,12 +46,18 @@
#include "smf_n1.hpp" #include "smf_n1.hpp"
#include "smf_sbi.hpp" #include "smf_sbi.hpp"
#include "smf_n2.hpp" #include "smf_n2.hpp"
#include "smf_n7.hpp"
#include "smf_paa_dynamic.hpp" #include "smf_paa_dynamic.hpp"
#include "smf_pfcp_association.hpp" #include "smf_pfcp_association.hpp"
#include "smf_procedure.hpp" #include "smf_procedure.hpp"
#include "3gpp_conversions.hpp" #include "3gpp_conversions.hpp"
#include "string.hpp" #include "string.hpp"
#include "EventNotification.h" #include "EventNotification.h"
#include "SmPolicyContextData.h"
#include "SmPolicyDecision.h"
#include "PlmnId.h"
#include "Snssai.h"
#include "PduSessionType.h"
extern "C" { extern "C" {
#include "Ngap_AssociatedQosFlowItem.h" #include "Ngap_AssociatedQosFlowItem.h"
...@@ -1493,10 +1499,72 @@ void smf_context::handle_pdu_session_create_sm_context_request( ...@@ -1493,10 +1499,72 @@ void smf_context::handle_pdu_session_create_sm_context_request(
// Maximum Data Rate // Maximum Data Rate
// TODO: (Optional) Secondary authentication/authorization // TODO: (Optional) Secondary authentication/authorization
// TODO: Step 5. PCF selection // Step 5. PCF selection
// TODO: Step 5.1. SM Policy Association Establishment to get default PCC
// rules for this PDU session from PCF For the moment, SMF uses the local std::string smContextRef = std::to_string(smreq->scid);
// policy (e.g., default QoS rule) oai::smf_server::model::SmPolicyDecision policy_decision;
bool use_pcf_policy = false;
if (!smf_cfg.use_local_pcc_rules) {
std::string pcf_addr;
std::string pcf_api_version;
oai::smf_server::model::Snssai snssai_model;
snssai_model.setSst(snssai.sST);
snssai_model.setSd(snssai.sD);
oai::smf_server::model::PlmnId plmn_id_model;
std::string mnc_string = std::to_string(plmn.mnc_digit1) +
std::to_string(plmn.mnc_digit2) +
std::to_string(plmn.mnc_digit3);
std::string mcc_string = std::to_string(plmn.mcc_digit1) +
std::to_string(plmn.mcc_digit2) +
std::to_string(plmn.mcc_digit3);
plmn_id_model.setMnc(mnc_string);
plmn_id_model.setMcc(mcc_string);
// get the PCF (either from config file, DNS or NRF based on local config)
bool pcf_found = n7::smf_n7::get_instance().discover_pcf(
pcf_addr, pcf_api_version, snssai_model, plmn_id_model, dnn);
if (pcf_found) {
oai::smf_server::model::SmPolicyContextData context;
context.setPduSessionId(pdu_session_id);
std::string supi_string = smf_supi_to_string(smreq->req.get_supi());
// TODO only support imsi SUPI, not NAI
context.setSupi("imsi-" + supi_string);
oai::smf_server::model::PduSessionType pdu_session_type;
// hacky
pdu_session_type_t pdu_type = smreq->req.get_pdu_session_type();
from_json(pdu_type.toString(), pdu_session_type);
context.setPduSessionType(pdu_session_type);
context.setDnn(smreq->req.get_dnn());
// TODO which notification URI should we use for PCF updates?
// atm it is
// {apiRoot}/nsmf-pdusession/{apiVersion}/sm-contexts-policy/{smContextRef}
std::string notification_uri =
smreq->req.get_api_root() + "-policy/" + smContextRef;
n7::sm_policy_status_code status =
n7::smf_n7::get_instance().create_sm_policy_association(
pcf_addr, pcf_api_version, context, policy_decision);
if (status != n7::sm_policy_status_code::CREATED) {
Logger::smf_n7().info(
"PCF SM Policy Association Creation was not successful. Continue "
"using local rules");
use_pcf_policy = false;
// Here, the standard says that we could reject the PDU session or allow
// the PDU session applying local policies 29.512 Chapter 4.2.2.2
// TODO I propose to have this behavior configurable, for now we
// continue
} else {
use_pcf_policy = true;
}
} else {
Logger::smf_n7().info(
"PCF can not be found. Continue with local PCC rules");
}
}
// TODO use the PCC rules also for QoS and other policy information
// Step 6. PCO // Step 6. PCO
// section 6.2.4.2, TS 24.501 // section 6.2.4.2, TS 24.501
...@@ -1722,7 +1790,6 @@ void smf_context::handle_pdu_session_create_sm_context_request( ...@@ -1722,7 +1790,6 @@ void smf_context::handle_pdu_session_create_sm_context_request(
"Send ITTI msg to SMF APP to trigger the response of Server"); "Send ITTI msg to SMF APP to trigger the response of Server");
pdu_session_create_sm_context_response sm_context_response = {}; pdu_session_create_sm_context_response sm_context_response = {};
std::string smContextRef = std::to_string(smreq->scid);
// headers: Location: contains the URI of the newly created resource, // headers: Location: contains the URI of the newly created resource,
// according to the structure: // according to the structure:
// {apiRoot}/nsmf-pdusession/{apiVersion}/sm-contexts/{smContextRef} // {apiRoot}/nsmf-pdusession/{apiVersion}/sm-contexts/{smContextRef}
......
...@@ -22,19 +22,35 @@ ...@@ -22,19 +22,35 @@
/*! \file smf_n7.cpp /*! \file smf_n7.cpp
\author Stefan Spettel \author Stefan Spettel
\company Openairinterface Software Alliance \company Openairinterface Software Alliance
\date 2021 \date 2022
\email: stefan.spettel@gmx.at \email: stefan.spettel@eurecom.fr
*/ */
#include "smf_n7.hpp" #include "smf_n7.hpp"
#include "smf_config.hpp" #include "smf_config.hpp"
#include "fqdn.hpp" #include "fqdn.hpp"
#include "smf_sbi.hpp"
#include "nlohmann/json.hpp"
#include "3gpp_29.500.h"
#include "ProblemDetails.h"
using namespace smf; using namespace smf;
using namespace smf::n7; using namespace smf::n7;
using namespace oai::smf_server::model; using namespace oai::smf_server::model;
extern smf_config smf_cfg; extern smf_config smf_cfg;
extern smf_sbi* smf_sbi_inst;
sm_policy_status_code smf_n7::create_sm_policy_association(
const std::string pcf_addr, const std::string pcf_api_version,
const oai::smf_server::model::SmPolicyContextData& context,
oai::smf_server::model::SmPolicyDecision& policy_decision) {
// TODO abstraction: Here we should choose between local PCC rules and PCF
// client
return policy_api_client.send_create_policy_association(
pcf_addr, pcf_api_version, context, policy_decision);
}
bool smf_n7::discover_pcf( bool smf_n7::discover_pcf(
std::string& addr, std::string& api_version, const Snssai snssai, std::string& addr, std::string& api_version, const Snssai snssai,
...@@ -100,3 +116,101 @@ bool smf_n7::discover_pcf_from_config_file( ...@@ -100,3 +116,101 @@ bool smf_n7::discover_pcf_from_config_file(
} }
} }
} }
smf_n7::~smf_n7() {
Logger::smf_n7().info("Deleting SMF N7 instance...");
}
///////////////////////////////////////////////////////////////////////////
/////////////////////// smf_pcf_client ////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
sm_policy_status_code smf_pcf_client::send_create_policy_association(
const std::string pcf_addr, const std::string pcf_api_version,
const SmPolicyContextData& context, SmPolicyDecision& policy_decision) {
nlohmann::json json_data;
to_json(json_data, context);
Logger::smf_n7().info("Sending PCF SM policy association creation request");
std::string url = "http://" + pcf_addr + "/" + sm_api_name + "/" +
pcf_api_version + "/" + sm_api_policy_resource_part;
std::string response_data;
// generate a promise for the curl handle
uint32_t promise_id = smf_sbi_inst->generate_promise_id();
Logger::smf_sbi().debug("Promise ID generated %d", promise_id);
uint32_t* pid_ptr = &promise_id;
boost::shared_ptr<boost::promise<uint32_t>> p =
boost::make_shared<boost::promise<uint32_t>>();
boost::shared_future<uint32_t> f;
f = p->get_future();
smf_sbi_inst->add_promise(promise_id, p);
// Create a new curl easy handle and add to the multi handle
if (!smf_sbi_inst->curl_create_handle(
url, json_data.dump(), response_data, pid_ptr, "POST",
smf_cfg.http_version)) {
Logger::smf_sbi().warn(
"Could not create a new handle to send message to PCF");
smf_sbi_inst->remove_promise(promise_id);
return sm_policy_status_code::INTERNAL_ERROR;
}
// Wait for the response
// TODO what happens if PCF is not reachable? Should check that scenario
// TODO it seems that it just hangs and is stuck "forever".. The problem is
// that the CURL ERROR CODE in curl_release_handles are just ignored. e.g when
// I have an error code 28, does that mean that this thread is just stuck?
uint32_t response_code = smf_sbi_inst->get_available_response(f);
Logger::smf_sbi().debug("Got result for promise ID %d", promise_id);
Logger::smf_sbi().debug("Response data %s", response_data.c_str());
if (response_code == http_status_code_e::HTTP_STATUS_CODE_201_CREATED) {
from_json(response_data, policy_decision);
Logger::smf_n7().info(
"Successfully created SM Policy Association for SUPI %s",
context.getSupi().c_str());
return sm_policy_status_code::CREATED;
}
// failure case
ProblemDetails problem_details;
from_json(response_data, problem_details);
std::string info = "";
sm_policy_status_code response;
switch (response_code) {
case http_status_code_e::HTTP_STATUS_CODE_403_FORBIDDEN:
info = "SM Policy Association Creation Forbidden";
response = sm_policy_status_code::CONTEXT_DENIED;
break;
case http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST:
if (problem_details.getCause() == "USER_UNKNOWN") {
response = sm_policy_status_code::USER_UNKOWN;
info = "SM Policy Association Creation: Unknown User";
} else {
response = sm_policy_status_code::INVALID_PARAMETERS;
info = "SM Policy Association Creation: Bad Request";
}
break;
case http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR:
response = sm_policy_status_code::INTERNAL_ERROR;
info = "SM Policy Association Creation: Internal Error";
break;
default:
response = sm_policy_status_code::INTERNAL_ERROR;
info =
"SM Policy Association Creation: Unknown Error Code from "
"PCF: " +
response_code;
}
Logger::smf_n7().warn(
"%s -- Details: %s - %s", info.c_str(),
problem_details.getCause().c_str(), problem_details.getDetail().c_str());
return response;
}
\ No newline at end of file
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
/*! \file smf_n7.hpp /*! \file smf_n7.hpp
\author Stefan Spettel \author Stefan Spettel
\company Openairinterface Software Alliance \company Openairinterface Software Alliance
\date 2021 \date 2022
\email: stefan.spettel@gmx.at \email: stefan.spettel@eurecom.fr
*/ */
#ifndef FILE_SMF_N7_HPP_SEEN #ifndef FILE_SMF_N7_HPP_SEEN
...@@ -48,7 +48,22 @@ enum class sm_policy_status_code { ...@@ -48,7 +48,22 @@ enum class sm_policy_status_code {
CONTEXT_DENIED, CONTEXT_DENIED,
NOT_FOUND, NOT_FOUND,
OK, OK,
PCF_NOT_AVAILABLE PCF_NOT_AVAILABLE,
INTERNAL_ERROR
};
/**
*
*/
class smf_pcf_client {
public:
const std::string sm_api_name = "npcf-smpolicycontrol";
const std::string sm_api_policy_resource_part = "sm-policies";
sm_policy_status_code send_create_policy_association(
const std::string pcf_addr, const std::string pcf_api_version,
const oai::smf_server::model::SmPolicyContextData& context,
oai::smf_server::model::SmPolicyDecision& policy_decision);
}; };
/** /**
...@@ -59,15 +74,28 @@ enum class sm_policy_status_code { ...@@ -59,15 +74,28 @@ enum class sm_policy_status_code {
*/ */
class smf_n7 { class smf_n7 {
public: public:
smf_n7(){};
smf_n7(smf_n7 const&) = delete;
void operator=(smf_n7 const&) = delete;
virtual ~smf_n7();
static smf_n7& get_instance() { static smf_n7& get_instance() {
static smf_n7 instance; static smf_n7 instance;
return instance; return instance;
} }
explicit smf_n7(); /**
* @brief Creates a SM Policy Association (as defined in 3GPP TS 29.512)
virtual ~smf_n7(); * towards the PCF specified with pcf_addr.
*
* @param pcf_addr PCF address in format ip:port (see discover_pcf)
* @param pcf_api_version PCF API version
* @param context context data, the mandatory parameters need to be set
* @param policy_decision policy decision received from the PCF (is empty on
* error)
* @return smf::n7::sm_policy_status_code Status code depending on the result
* from the PCF API
*/
smf::n7::sm_policy_status_code create_sm_policy_association( smf::n7::sm_policy_status_code create_sm_policy_association(
const std::string pcf_addr, const std::string pcf_api_version, const std::string pcf_addr, const std::string pcf_api_version,
const oai::smf_server::model::SmPolicyContextData& context, const oai::smf_server::model::SmPolicyContextData& context,
...@@ -101,13 +129,9 @@ class smf_n7 { ...@@ -101,13 +129,9 @@ class smf_n7 {
std::string& addr, std::string& api_version, std::string& addr, std::string& api_version,
const oai::smf_server::model::Snssai snssai, const oai::smf_server::model::Snssai snssai,
const oai::smf_server::model::PlmnId plmn_id, const std::string dnn); const oai::smf_server::model::PlmnId plmn_id, const std::string dnn);
};
/** smf_pcf_client policy_api_client = {};
* @brief Client which handles the SMPolicyControl API (3GPP TS 29.512) };
*
*/
class smf_pcf_client {};
} // namespace smf::n7 } // namespace smf::n7
#endif /* FILE_SMF_N4_HPP_SEEN */ #endif /* FILE_SMF_N4_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