Commit dd0fcfc4 authored by Stefan Spettel's avatar Stefan Spettel

feat(pcf): Added policy association to PDU session

Signed-off-by: default avatarStefan Spettel <stefan.spettel@eurecom.fr>
parent 4ca31398
...@@ -451,6 +451,12 @@ std::string smf_pdu_session::toString() const { ...@@ -451,6 +451,12 @@ std::string smf_pdu_session::toString() const {
} }
} }
} }
if (policy_ptr) {
s.append("\t Policy Decision:").append("\n");
s.append(policy_ptr->toString());
}
return s; return s;
} }
...@@ -1502,21 +1508,21 @@ void smf_context::handle_pdu_session_create_sm_context_request( ...@@ -1502,21 +1508,21 @@ void smf_context::handle_pdu_session_create_sm_context_request(
// Step 5. Create SM Policy Association with PCF or local PCC rules // Step 5. Create SM Policy Association with PCF or local PCC rules
std::string smContextRef = std::to_string(smreq->scid); std::string smContextRef = std::to_string(smreq->scid);
oai::smf_server::model::SmPolicyDecision policy_decision; sp.get()->policy_ptr = std::make_shared<n7::policy_association>();
n7::policy_association policy_ass;
bool use_pcf_policy = false; bool use_pcf_policy = false;
if (!smf_cfg.use_local_pcc_rules) { if (!smf_cfg.use_local_pcc_rules) {
policy_ass.set_context( sp.get()->policy_ptr->set_context(
smf_supi_to_string(smreq->req.get_supi()), smreq->req.get_dnn(), snssai, smf_supi_to_string(smreq->req.get_supi()), smreq->req.get_dnn(), snssai,
plmn, smreq->req.get_pdu_session_id(), plmn, smreq->req.get_pdu_session_id(),
smreq->req.get_pdu_session_type()); smreq->req.get_pdu_session_type());
// TODO what is the exact meaning of SCID? Is this unique per registration // TODO what is the exact meaning of SCID? Is this unique per registration
// or unique per PDU session? // or unique per PDU session?
policy_ass.id = smreq->scid; sp.get()->policy_ptr->id = smreq->scid;
n7::sm_policy_status_code status = n7::sm_policy_status_code status =
n7::smf_n7::get_instance().create_sm_policy_association(policy_ass); n7::smf_n7::get_instance().create_sm_policy_association(
*sp->policy_ptr);
if (status != n7::sm_policy_status_code::CREATED) { if (status != n7::sm_policy_status_code::CREATED) {
Logger::smf_n7().info( Logger::smf_n7().info(
"PCF SM Policy Association Creation was not successful. Continue " "PCF SM Policy Association Creation was not successful. Continue "
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include "smf_event.hpp" #include "smf_event.hpp"
#include "smf_procedure.hpp" #include "smf_procedure.hpp"
#include "uint_generator.hpp" #include "uint_generator.hpp"
#include "smf_n7.hpp"
extern "C" { extern "C" {
#include "Ngap_PDUSessionAggregateMaximumBitRate.h" #include "Ngap_PDUSessionAggregateMaximumBitRate.h"
...@@ -560,6 +561,8 @@ class smf_pdu_session : public std::enable_shared_from_this<smf_pdu_session> { ...@@ -560,6 +561,8 @@ class smf_pdu_session : public std::enable_shared_from_this<smf_pdu_session> {
bool released; // release session request bool released; // release session request
std::shared_ptr<n7::policy_association> policy_ptr;
uint32_t pdu_session_id; uint32_t pdu_session_id;
std::string dnn; // associated DNN std::string dnn; // associated DNN
snssai_t snssai; // associated SNSSAI snssai_t snssai; // associated SNSSAI
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
#include "3gpp_29.500.h" #include "3gpp_29.500.h"
#include "ProblemDetails.h" #include "ProblemDetails.h"
#include "uint_generator.hpp"
#include <regex>
using namespace smf; using namespace smf;
using namespace smf::n7; using namespace smf::n7;
...@@ -61,9 +64,13 @@ uint32_t smf_n7::select_pcf(const SmPolicyContextData& context) { ...@@ -61,9 +64,13 @@ uint32_t smf_n7::select_pcf(const SmPolicyContextData& context) {
policy_storages.insert(1, storage); policy_storages.insert(1, storage);
return 1; // ID is always 1, only one PF return 1; // ID is always 1, only one PF
} else { } else {
return -1; Logger::smf_n7().info("Did not find PCF");
return 0;
} }
} }
// TODO for now, only use first PCF
return 1;
} }
sm_policy_status_code smf_n7::create_sm_policy_association( sm_policy_status_code smf_n7::create_sm_policy_association(
...@@ -87,9 +94,22 @@ sm_policy_status_code smf_n7::create_sm_policy_association( ...@@ -87,9 +94,22 @@ sm_policy_status_code smf_n7::create_sm_policy_association(
return sm_policy_status_code::PCF_NOT_AVAILABLE; return sm_policy_status_code::PCF_NOT_AVAILABLE;
} }
return it->second->create_policy_association(association); sm_policy_status_code res =
it->second->create_policy_association(association);
if (res == sm_policy_status_code::CREATED) {
if (association.id == 0) {
association.id =
util::uint_uid_generator<uint64_t>::get_instance().get_uid();
}
association.pcf_id = pcf_id;
Logger::smf_n7().debug(
"Successfully created policy association with ID: %lu ",
association.id);
}
// return store->create_policy_association(association); return res;
} }
smf_n7::~smf_n7() { smf_n7::~smf_n7() {
...@@ -183,6 +203,7 @@ sm_policy_status_code smf_pcf_client::create_policy_association( ...@@ -183,6 +203,7 @@ sm_policy_status_code smf_pcf_client::create_policy_association(
Logger::smf_n7().info("Sending PCF SM policy association creation request"); Logger::smf_n7().info("Sending PCF SM policy association creation request");
std::string response_data; std::string response_data;
std::string response_headers;
// generate a promise for the curl handle // generate a promise for the curl handle
uint32_t promise_id = smf_sbi_inst->generate_promise_id(); uint32_t promise_id = smf_sbi_inst->generate_promise_id();
...@@ -197,8 +218,8 @@ sm_policy_status_code smf_pcf_client::create_policy_association( ...@@ -197,8 +218,8 @@ sm_policy_status_code smf_pcf_client::create_policy_association(
// Create a new curl easy handle and add to the multi handle // Create a new curl easy handle and add to the multi handle
if (!smf_sbi_inst->curl_create_handle( if (!smf_sbi_inst->curl_create_handle(
root_uri, json_data.dump(), response_data, pid_ptr, "POST", root_uri, json_data.dump(), response_data, response_headers, pid_ptr,
smf_cfg.http_version)) { "POST", smf_cfg.http_version)) {
Logger::smf_sbi().warn( Logger::smf_sbi().warn(
"Could not create a new handle to send message to PCF"); "Could not create a new handle to send message to PCF");
smf_sbi_inst->remove_promise(promise_id); smf_sbi_inst->remove_promise(promise_id);
...@@ -213,10 +234,22 @@ sm_policy_status_code smf_pcf_client::create_policy_association( ...@@ -213,10 +234,22 @@ sm_policy_status_code smf_pcf_client::create_policy_association(
Logger::smf_sbi().debug("Response data %s", response_data.c_str()); Logger::smf_sbi().debug("Response data %s", response_data.c_str());
if (response_code == http_status_code_e::HTTP_STATUS_CODE_201_CREATED) { if (response_code == http_status_code_e::HTTP_STATUS_CODE_201_CREATED) {
from_json(response_data, association.decision); std::regex rgx("Location: *(.*)");
std::smatch match;
if (std::regex_search(response_headers, match, rgx)) {
association.pcf_location = match[1];
nlohmann::json j = nlohmann::json::parse(response_data);
from_json(j, association.decision);
Logger::smf_n7().info( Logger::smf_n7().info(
"Successfully created SM Policy Association for SUPI %s", "Successfully created SM Policy Association for SUPI %s",
association.context.getSupi().c_str()); association.context.getSupi().c_str());
} else {
Logger::smf_n7().debug(
"SM Policy Association response does not contain Location!");
return sm_policy_status_code::INTERNAL_ERROR;
}
return sm_policy_status_code::CREATED; return sm_policy_status_code::CREATED;
} }
......
...@@ -66,8 +66,8 @@ enum class sm_policy_status_code { ...@@ -66,8 +66,8 @@ enum class sm_policy_status_code {
struct policy_association { struct policy_association {
oai::smf_server::model::SmPolicyDecision decision; oai::smf_server::model::SmPolicyDecision decision;
oai::smf_server::model::SmPolicyContextData context; oai::smf_server::model::SmPolicyContextData context;
uint32_t id = -1; uint64_t id = 0;
uint32_t pcf_id = -1; uint64_t pcf_id = 0;
std::string pcf_location; std::string pcf_location;
void set_context( void set_context(
...@@ -96,6 +96,23 @@ struct policy_association { ...@@ -96,6 +96,23 @@ struct policy_association {
context.setPduSessionType(pdu_session_type_model); context.setPduSessionType(pdu_session_type_model);
context.setDnn(dnn); context.setDnn(dnn);
} }
std::string toString() {
std::string s = "";
if (decision.pccRulesIsSet()) {
s.append("\t\tPCC Rules:\n");
for (auto it : decision.getPccRules()) {
s.append("\t\t\t\t").append(it.second.getPccRuleId()).append("\n");
}
}
if (decision.traffContDecsIsSet()) {
s.append("\t\tTraffic Control Descriptions:\n");
for (auto it : decision.getTraffContDecs()) {
s.append("\t\t\t\t").append(it.second.getTcId()).append("\n");
}
}
return s;
}
}; };
/** /**
...@@ -231,10 +248,9 @@ class smf_pcf_client : public policy_storage { ...@@ -231,10 +248,9 @@ class smf_pcf_client : public policy_storage {
*/ */
class smf_n7 { class smf_n7 {
public: public:
const uint32_t ASSOCIATIONS_SIZE = 1024;
const uint32_t PCF_CLIENTS = 16; const uint32_t PCF_CLIENTS = 16;
smf_n7() : associations(ASSOCIATIONS_SIZE), policy_storages(PCF_CLIENTS){}; smf_n7() : policy_storages(PCF_CLIENTS){};
smf_n7(smf_n7 const&) = delete; smf_n7(smf_n7 const&) = delete;
void operator=(smf_n7 const&) = delete; void operator=(smf_n7 const&) = delete;
virtual ~smf_n7(); virtual ~smf_n7();
...@@ -261,6 +277,30 @@ class smf_n7 { ...@@ -261,6 +277,30 @@ class smf_n7 {
sm_policy_status_code create_sm_policy_association( sm_policy_status_code create_sm_policy_association(
policy_association& association); policy_association& association);
/**
* @brief Removes an SM Policy Association on the PCF. The params pcf_id and
* id of the association parameter need to be set
*
* @param association input: pcf_id and id need to be set and exist
* @return sm_policy_status_code OK in case of success, otherwise NOT_FOUND,
* INTERNAL_ERROR, PCF_NOT_AVAILABLE
*/
sm_policy_status_code remove_sm_policy_association(
const policy_association& association);
/**
* @brief Updates an SM Policy Association, requires the triggers to be set as
* defined in 3GPP TS 29.512
*
* @param association The association to update
* @param update_data The update context data
* @return sm_policy_status_code OK in case of success, otherwise NOT_FOUND,
* INTERNAL_ERROR, PCF_NOT_AVAILABLE
*/
sm_policy_status_code update_sm_policy_association(
policy_association& association,
const oai::smf_server::model::SmPolicyUpdateContextData& update_data);
private: private:
/** /**
* @brief Allows the discovery of a PCF, either via NRF or local * @brief Allows the discovery of a PCF, either via NRF or local
...@@ -279,7 +319,6 @@ class smf_n7 { ...@@ -279,7 +319,6 @@ class smf_n7 {
// amount of objects is known upfront. // amount of objects is known upfront.
folly::AtomicHashMap<uint32_t, std::shared_ptr<policy_storage>> folly::AtomicHashMap<uint32_t, std::shared_ptr<policy_storage>>
policy_storages; policy_storages;
folly::AtomicHashMap<uint32_t, smf::n7::policy_association> associations;
}; };
} // namespace smf::n7 } // namespace smf::n7
#endif /* FILE_SMF_N4_HPP_SEEN */ #endif /* FILE_SMF_N4_HPP_SEEN */
...@@ -1198,6 +1198,66 @@ bool smf_sbi::curl_create_handle( ...@@ -1198,6 +1198,66 @@ bool smf_sbi::curl_create_handle(
return true; return true;
} }
// TODO we should not repeat ourselves... propose to make a private function
// which does curl_init
//------------------------------------------------------------------------------
bool smf_sbi::curl_create_handle(
const std::string& uri, const std::string& data, std::string& response_data,
std::string& response_headers, uint32_t* promise_id,
const std::string& method, uint8_t http_version) {
// Create handle for a curl request
CURL* curl = curl_easy_init();
if ((curl == nullptr) or (headers == nullptr)) {
Logger::smf_sbi().error("Cannot initialize a new Curl Handle");
return false;
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, uri.c_str());
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(curl, CURLOPT_PRIVATE, promise_id);
if (method.compare("POST") == 0)
curl_easy_setopt(curl, CURLOPT_POST, 1);
else if (method.compare("PATCH") == 0)
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
else if (method.compare("PUT") == 0)
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
else
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, NF_CURL_TIMEOUT_MS);
curl_easy_setopt(curl, CURLOPT_INTERFACE, smf_cfg.sbi.if_name.c_str());
if (http_version == 2) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
// We use a self-signed test server, skip verification during debugging
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(
curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
}
// Hook up data handling function.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &response_headers);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
if (method.compare("DELETE") != 0) {
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.length());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
}
// Add to the multi handle
curl_multi_add_handle(curl_multi, curl);
handles.push_back(curl);
// Curl cmd will actually be performed in perform_curl_multi
perform_curl_multi(
0); // TODO: current time as parameter if curl is performed per event
return true;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
bool smf_sbi::curl_create_handle( bool smf_sbi::curl_create_handle(
const std::string& uri, std::string& response_data, uint32_t* promise_id, const std::string& uri, std::string& response_data, uint32_t* promise_id,
......
...@@ -199,6 +199,23 @@ class smf_sbi { ...@@ -199,6 +199,23 @@ class smf_sbi {
std::string& response_data, uint32_t* promise_id, std::string& response_data, uint32_t* promise_id,
const std::string& method, uint8_t http_version = 1); const std::string& method, uint8_t http_version = 1);
/*
* Create Curl handle for multi curl with support of response headers
* @param [const std::string &] uri: URI of the subscribed NF
* @param [const std::string& ] data: data to be sent
* @param [std::string &] response_data: response data
* @param [std::string &] response_headers: all response headers
* @param [uint32_t* ] promise_id: pointer to the promise id
* @param [const std::string&] method: HTTP method
* @param [bool] is_multipart: use multipart or json format
* @return true if a handle was created successfully, otherwise return false
*/
bool curl_create_handle(
const std::string& uri, const std::string& data,
std::string& response_data, std::string& response_headers,
uint32_t* promise_id, const std::string& method,
uint8_t http_version = 1);
/* /*
* Create Curl handle for multi curl * Create Curl handle for multi curl
* @param [const std::string &] uri: URI of the subscribed NF * @param [const std::string &] uri: URI of the subscribed NF
......
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