Skip to content
Snippets Groups Projects
Commit 81d7d69d authored by Raphael Defosseux's avatar Raphael Defosseux
Browse files

Merge branch 'qos_models' into 'develop'

feat(pcf): Add possibility to read QoS values from file

See merge request !39
parents 53d27f9a 3f9ae92a
No related branches found
No related tags found
1 merge request!39feat(pcf): Add possibility to read QoS values from file
Pipeline #41585 passed
...@@ -292,6 +292,7 @@ add_executable(pcf ...@@ -292,6 +292,7 @@ add_executable(pcf
include(${BUILD_TOP_DIR}/pcf/used_common_files.cmake) include(${BUILD_TOP_DIR}/pcf/used_common_files.cmake)
include(${SRC_TOP_DIR}/${MOUNTED_COMMON}/logger/logger.cmake) include(${SRC_TOP_DIR}/${MOUNTED_COMMON}/logger/logger.cmake)
include(${SRC_TOP_DIR}/${MOUNTED_COMMON}/config/config.cmake) include(${SRC_TOP_DIR}/${MOUNTED_COMMON}/config/config.cmake)
include_directories(${SRC_TOP_DIR}/${MOUNTED_COMMON}/utils)
IF(STATIC_LINKING) IF(STATIC_LINKING)
SET(CMAKE_EXE_LINKER_FLAGS "-static") SET(CMAKE_EXE_LINKER_FLAGS "-static")
......
...@@ -45,7 +45,7 @@ oai::config::pcf::pcf_config::pcf_config( ...@@ -45,7 +45,7 @@ oai::config::pcf::pcf_config::pcf_config(
sbi_interface("SBI", "oai-pcf", 80, "v1", "eth0"), sbi_interface("SBI", "oai-pcf", 80, "v1", "eth0"),
policy_config( policy_config(
DEFAULT_POLICY_DECISIONS_PATH, DEFAULT_PCC_RULES_PATH, DEFAULT_POLICY_DECISIONS_PATH, DEFAULT_PCC_RULES_PATH,
DEFAULT_TRAFFIC_RULES_PATH)); DEFAULT_TRAFFIC_RULES_PATH, DEFAULT_QOS_DATA_PATH));
auto nrf = std::make_shared<nf>( auto nrf = std::make_shared<nf>(
NRF_CONFIG_NAME, "oai-nrf", NRF_CONFIG_NAME, "oai-nrf",
......
...@@ -39,6 +39,7 @@ const std::string DEFAULT_TRAFFIC_RULES_PATH = ...@@ -39,6 +39,7 @@ const std::string DEFAULT_TRAFFIC_RULES_PATH =
"/openair-pcf/policies/traffic_rules"; "/openair-pcf/policies/traffic_rules";
const std::string DEFAULT_POLICY_DECISIONS_PATH = const std::string DEFAULT_POLICY_DECISIONS_PATH =
"/openair-pcf/policies/policy_decisions"; "/openair-pcf/policies/policy_decisions";
const std::string DEFAULT_QOS_DATA_PATH = "/openair-pcf/policies/qos_data";
class pcf_config : public oai::config::config { class pcf_config : public oai::config::config {
public: public:
......
...@@ -37,14 +37,15 @@ using namespace oai::config::pcf; ...@@ -37,14 +37,15 @@ using namespace oai::config::pcf;
policy_config::policy_config( policy_config::policy_config(
const std::string& policy_decisions_path, const std::string& pcc_rules_path, const std::string& policy_decisions_path, const std::string& pcc_rules_path,
const std::string& traffic_rules_path) { const std::string& traffic_rules_path, const std::string& qos_data_path) {
m_config_name = "Policy"; m_config_name = "Policy";
m_traffic_rules_path = m_traffic_rules_path =
string_config_value("Traffic Rules", traffic_rules_path); string_config_value("Traffic Rules", traffic_rules_path);
m_pcc_rules_path = string_config_value("PCC Rules", pcc_rules_path); m_pcc_rules_path = string_config_value("PCC Rules", pcc_rules_path);
m_policy_decisions_path = m_policy_decisions_path =
string_config_value("Policy Decisions", policy_decisions_path); string_config_value("Policy Decisions", policy_decisions_path);
m_set = true; m_qos_data_path = string_config_value("QoS Data", qos_data_path);
m_set = true;
} }
void policy_config::from_yaml(const YAML::Node& node) { void policy_config::from_yaml(const YAML::Node& node) {
...@@ -57,23 +58,31 @@ void policy_config::from_yaml(const YAML::Node& node) { ...@@ -57,23 +58,31 @@ void policy_config::from_yaml(const YAML::Node& node) {
if (node["traffic_rules_path"]) { if (node["traffic_rules_path"]) {
m_traffic_rules_path.from_yaml(node["traffic_rules_path"]); m_traffic_rules_path.from_yaml(node["traffic_rules_path"]);
} }
if (node["qos_data_path"]) {
m_qos_data_path.from_yaml(node["qos_data_path"]);
}
} }
std::string policy_config::to_string(const std::string& indent) const { std::string policy_config::to_string(const std::string& indent) const {
if (!m_set) return ""; if (!m_set) return "";
std::string out; std::string out;
unsigned int inner_width = get_inner_width(indent.length()); std::string title_fmt = get_title_formatter(0);
out.append(m_config_name).append("\n"); std::string value_fmt = get_value_formatter(1);
out.append(indent).append(fmt::format(title_fmt, m_config_name));
out.append(indent).append(fmt::format( out.append(indent).append(fmt::format(
BASE_FORMATTER, OUTER_LIST_ELEM, value_fmt, m_policy_decisions_path.get_config_name(),
m_policy_decisions_path.get_config_name(), inner_width,
m_policy_decisions_path.get_value())); m_policy_decisions_path.get_value()));
out.append(indent).append(fmt::format( out.append(indent).append(fmt::format(
BASE_FORMATTER, OUTER_LIST_ELEM, m_pcc_rules_path.get_config_name(), value_fmt, m_pcc_rules_path.get_config_name(),
inner_width, m_pcc_rules_path.get_value())); m_pcc_rules_path.get_value()));
out.append(indent).append(fmt::format(
value_fmt, m_traffic_rules_path.get_config_name(),
m_traffic_rules_path.get_value()));
out.append(indent).append(fmt::format( out.append(indent).append(fmt::format(
BASE_FORMATTER, OUTER_LIST_ELEM, m_traffic_rules_path.get_config_name(), value_fmt, m_qos_data_path.get_config_name(),
inner_width, m_traffic_rules_path.get_value())); m_qos_data_path.get_value()));
return out; return out;
} }
...@@ -89,6 +98,10 @@ const std::string& policy_config::get_traffic_rules_path() const { ...@@ -89,6 +98,10 @@ const std::string& policy_config::get_traffic_rules_path() const {
return m_traffic_rules_path.get_value(); return m_traffic_rules_path.get_value();
} }
const std::string& policy_config::get_qos_data_path() const {
return m_qos_data_path.get_value();
}
pcf_config_type::pcf_config_type( pcf_config_type::pcf_config_type(
const std::string& name, const std::string& host, const sbi_interface& sbi, const std::string& name, const std::string& host, const sbi_interface& sbi,
const policy_config& policy) const policy_config& policy)
......
...@@ -37,11 +37,13 @@ class policy_config : public config_type { ...@@ -37,11 +37,13 @@ class policy_config : public config_type {
string_config_value m_pcc_rules_path; string_config_value m_pcc_rules_path;
string_config_value m_policy_decisions_path; string_config_value m_policy_decisions_path;
string_config_value m_traffic_rules_path; string_config_value m_traffic_rules_path;
string_config_value m_qos_data_path;
public: public:
explicit policy_config( explicit policy_config(
const std::string& policy_decisions_path, const std::string& policy_decisions_path,
const std::string& pcc_rules_path, const std::string& traffic_rules_path); const std::string& pcc_rules_path, const std::string& traffic_rules_path,
const std::string& qos_data_path);
void from_yaml(const YAML::Node& node) override; void from_yaml(const YAML::Node& node) override;
...@@ -49,6 +51,7 @@ class policy_config : public config_type { ...@@ -49,6 +51,7 @@ class policy_config : public config_type {
[[nodiscard]] const std::string& get_pcc_rules_path() const; [[nodiscard]] const std::string& get_pcc_rules_path() const;
[[nodiscard]] const std::string& get_policy_decisions_path() const; [[nodiscard]] const std::string& get_policy_decisions_path() const;
[[nodiscard]] const std::string& get_traffic_rules_path() const; [[nodiscard]] const std::string& get_traffic_rules_path() const;
[[nodiscard]] const std::string& get_qos_data_path() const;
}; };
class pcf_config_type : public nf { class pcf_config_type : public nf {
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "pcf_config.hpp" #include "pcf_config.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "Snssai.h" #include "Snssai.h"
#include "conv.hpp"
using namespace oai::pcf::app; using namespace oai::pcf::app;
using namespace oai::config::pcf; using namespace oai::config::pcf;
...@@ -52,6 +53,7 @@ bool policy_provisioning_file::read_all_policy_files() { ...@@ -52,6 +53,7 @@ bool policy_provisioning_file::read_all_policy_files() {
std::vector<YAML::Node> traffic_controls; std::vector<YAML::Node> traffic_controls;
std::vector<YAML::Node> pcc_rules; std::vector<YAML::Node> pcc_rules;
std::vector<YAML::Node> policy_decisions; std::vector<YAML::Node> policy_decisions;
std::vector<YAML::Node> qos_data;
if (!read_all_files_in_dir( if (!read_all_files_in_dir(
pcf_cfg->get_pcf_policy().get_traffic_rules_path(), pcf_cfg->get_pcf_policy().get_traffic_rules_path(),
...@@ -70,50 +72,55 @@ bool policy_provisioning_file::read_all_policy_files() { ...@@ -70,50 +72,55 @@ bool policy_provisioning_file::read_all_policy_files() {
"Could not load mandatory policy decisions configuration"); "Could not load mandatory policy decisions configuration");
return false; return false;
} }
if (!read_all_files_in_dir(
pcf_cfg->get_pcf_policy().get_qos_data_path(), qos_data)) {
Logger::pcf_app().warn("Could not load QoS Data files");
}
auto traffic_control_objects = auto traffic_control_objects =
convert_yaml_to_model<TrafficControlData>(traffic_controls); convert_yaml_to_model<TrafficControlData>(traffic_controls);
auto pcc_rule_objects = convert_yaml_to_model<PccRule>(pcc_rules); auto pcc_rule_objects = convert_yaml_to_model<PccRule>(pcc_rules);
auto qos_data_objects = convert_yaml_to_model<QosData>(qos_data);
if (traffic_control_objects.empty()) { if (traffic_control_objects.empty()) {
Logger::pcf_app().warn("No traffic control descriptions are loaded"); Logger::pcf_app().warn("No traffic control descriptions are loaded");
} }
if (qos_data_objects.empty()) {
Logger::pcf_app().warn("No QoS data descriptions are loaded");
}
if (pcc_rule_objects.empty()) { if (pcc_rule_objects.empty()) {
Logger::pcf_app().warn("No mandatory PCC rules are loaded"); Logger::pcf_app().warn("No mandatory PCC rules are loaded");
return false; return false;
} }
// we need to manually adjust the IDs of the PCC rules and traffic controls // we need to manually adjust the IDs of the PCC rules and traffic controls
for (auto traffic : traffic_control_objects) { for (auto& traffic : traffic_control_objects) {
traffic.second.setTcId(traffic.first); traffic.second.setTcId(traffic.first);
traffic_control_objects[traffic.first] = traffic.second;
} }
for (auto pcc : pcc_rule_objects) { for (auto& qos : qos_data_objects) {
qos.second.setQosId(qos.first);
}
for (auto& pcc : pcc_rule_objects) {
pcc.second.setPccRuleId(pcc.first); pcc.second.setPccRuleId(pcc.first);
// check if traffic control data exists auto reftc = pcc.second.getRefTcData();
auto reftc = pcc.second.getRefTcData(); remove_ids_not_in_map<TrafficControlData>(
auto traffic_it = reftc.begin(); traffic_control_objects, reftc, "Traffic Rules", pcc.first);
while (traffic_it != reftc.end()) {
auto traffic_exists = traffic_control_objects.find(*traffic_it); auto refqos = pcc.second.getRefQosData();
if (traffic_exists == traffic_control_objects.end()) { remove_ids_not_in_map<QosData>(
Logger::pcf_app().warn( qos_data_objects, refqos, "QoS Data", pcc.first);
"You have referenced Traffic Control ID %s in PCC Rule %s, but it "
"does not exist. It is removed from this PCC rule",
(*traffic_it).c_str(), pcc.first.c_str());
traffic_it = reftc.erase(traffic_it);
} else {
++traffic_it;
}
}
pcc.second.setRefTcData(reftc); pcc.second.setRefTcData(reftc);
pcc.second.setRefQosData(refqos);
} }
// Now parse the decisions (manually as it is not a model) // Now parse the decisions (manually as it is not a model)
for (auto node : policy_decisions) { for (auto node : policy_decisions) {
for (auto it = node.begin(); it != node.end(); ++it) { for (auto it = node.begin(); it != node.end(); ++it) {
SmPolicyDecision decision = decision_from_rules( SmPolicyDecision decision = decision_from_rules(
it->second, pcc_rule_objects, traffic_control_objects); it->second, pcc_rule_objects, traffic_control_objects,
qos_data_objects);
if (!decision.pccRulesIsSet()) { if (!decision.pccRulesIsSet()) {
Logger::pcf_app().warn( Logger::pcf_app().warn(
"Decision %s could not be parsed. It is ignored", "Decision %s could not be parsed. It is ignored",
...@@ -156,7 +163,8 @@ bool policy_provisioning_file::read_all_policy_files() { ...@@ -156,7 +163,8 @@ bool policy_provisioning_file::read_all_policy_files() {
SmPolicyDecision policy_provisioning_file::decision_from_rules( SmPolicyDecision policy_provisioning_file::decision_from_rules(
const YAML::Node& node, const std::map<std::string, PccRule>& pcc_rules, const YAML::Node& node, const std::map<std::string, PccRule>& pcc_rules,
const std::map<std::string, TrafficControlData>& traffic_control) { const std::map<std::string, TrafficControlData>& traffic_control,
const std::map<std::string, QosData>& qos_data) {
SmPolicyDecision decision = {}; SmPolicyDecision decision = {};
std::map<std::string, PccRule> used_rules; std::map<std::string, PccRule> used_rules;
...@@ -187,7 +195,9 @@ SmPolicyDecision policy_provisioning_file::decision_from_rules( ...@@ -187,7 +195,9 @@ SmPolicyDecision policy_provisioning_file::decision_from_rules(
return {}; return {};
} }
std::map<std::string, TrafficControlData> used_traffic_control; std::map<std::string, TrafficControlData> used_traffic_control;
// now add the TrafficControlDescriptions std::map<std::string, QosData> used_qos_data;
// now add the TrafficControlDescriptions and QosData
for (const auto& rule : used_rules) { for (const auto& rule : used_rules) {
for (const auto& traffic : rule.second.getRefTcData()) { for (const auto& traffic : rule.second.getRefTcData()) {
auto found = traffic_control.find(traffic); auto found = traffic_control.find(traffic);
...@@ -195,63 +205,71 @@ SmPolicyDecision policy_provisioning_file::decision_from_rules( ...@@ -195,63 +205,71 @@ SmPolicyDecision policy_provisioning_file::decision_from_rules(
used_traffic_control.insert(std::make_pair(traffic, found->second)); used_traffic_control.insert(std::make_pair(traffic, found->second));
} }
} }
for (const auto& qos : rule.second.getRefQosData()) {
auto found = qos_data.find(qos);
if (found != qos_data.end()) {
used_qos_data.insert(std::make_pair(qos, found->second));
}
}
} }
if (!used_rules.empty()) { if (!used_rules.empty()) {
decision.setPccRules(used_rules); decision.setPccRules(used_rules);
decision.setTraffContDecs(used_traffic_control); decision.setTraffContDecs(used_traffic_control);
decision.setQosDecs(used_qos_data);
return decision; return decision;
} }
return {}; return {};
} }
void policy_provisioning_file::replace_json_string_with_int(nlohmann::json& j) {
for (const auto& elem : j.items()) {
if (elem.value().is_primitive()) {
try {
std::string e = elem.value();
if (e == "true") j[elem.key()] = true;
if (e == "false") j[elem.key()] = false;
int val = std::stoi(e);
j[elem.key()] = val; // replace with int
} catch (std::invalid_argument& ex) {
}
} else {
replace_json_string_with_int(elem.value());
}
}
}
template<class T> template<class T>
std::map<std::string, T> policy_provisioning_file::convert_yaml_to_model( std::map<std::string, T> policy_provisioning_file::convert_yaml_to_model(
const std::vector<YAML::Node>& nodes) { const std::vector<YAML::Node>& nodes) {
std::map<std::string, T> objects_map; std::map<std::string, T> objects_map;
// here we convert YAML to json so we can use the already existing JSON parser
// https://stackoverflow.com/questions/43902941/emitting-json-with-yaml-cpp
for (const auto& node : nodes) { for (const auto& node : nodes) {
YAML::Emitter emitter; auto j = oai::utils::conversions::yaml_to_json(node);
emitter << YAML::DoubleQuoted << YAML::Flow << YAML::BeginSeq << node;
std::string json_string(emitter.c_str() + 1);
nlohmann::json j = nlohmann::json::parse(json_string);
// this is a bit hacky but the problem is that YAML emits ints as strings
replace_json_string_with_int(j);
for (const auto& elem : j.items()) { for (const auto& elem : j.items()) {
T obj; T obj;
from_json(elem.value(), obj); try {
std::stringstream stream; from_json(elem.value(), obj);
if (obj.validate(stream)) { std::stringstream stream;
objects_map.insert(std::make_pair(elem.key(), obj)); if (obj.validate(stream)) {
Logger::pcf_app().debug( objects_map.insert(std::make_pair(elem.key(), obj));
"Rule %s successfully parsed.", elem.key().c_str()); Logger::pcf_app().debug(
} else { "Rule %s successfully parsed.", elem.key().c_str());
} else {
Logger::pcf_app().warn(
"Error while parsing rule %s: %s", elem.key(),
stream.str().c_str());
}
} catch (std::exception& e) {
Logger::pcf_app().warn( Logger::pcf_app().warn(
"Error while parsing rules: %s", stream.str().c_str()); "Error while parsing rule %s: %s", elem.key(), e.what());
} }
} }
} }
return objects_map; return objects_map;
} }
template<class T>
void policy_provisioning_file::remove_ids_not_in_map(
const std::map<std::string, T>& map, std::vector<std::string>& ids,
const std::string& error_msg_type, const std::string& pcc_id) {
auto it = ids.begin();
while (it != ids.end()) {
auto traffic_exists = map.find(*it);
if (traffic_exists == map.end()) {
Logger::pcf_app().warn(
"You have referenced %s ID %s in PCC Rule %s, but it "
"does not exist. It is removed from this PCC rule",
error_msg_type, *it, pcc_id);
it = ids.erase(it);
} else {
++it;
}
}
}
bool policy_provisioning_file::read_all_files_in_dir( bool policy_provisioning_file::read_all_files_in_dir(
const std::string& dir_path, std::vector<YAML::Node>& yaml_output) { const std::string& dir_path, std::vector<YAML::Node>& yaml_output) {
if (!exists(dir_path)) { if (!exists(dir_path)) {
......
...@@ -57,13 +57,17 @@ class policy_provisioning_file { ...@@ -57,13 +57,17 @@ class policy_provisioning_file {
const YAML::Node& node, const YAML::Node& node,
const std::map<std::string, oai::model::pcf::PccRule>& pcc_rules, const std::map<std::string, oai::model::pcf::PccRule>& pcc_rules,
const std::map<std::string, oai::model::pcf::TrafficControlData>& const std::map<std::string, oai::model::pcf::TrafficControlData>&
traffic_control); traffic_control,
const std::map<std::string, oai::model::pcf::QosData>& qos_data);
template<class T> template<class T>
static std::map<std::string, T> convert_yaml_to_model( static std::map<std::string, T> convert_yaml_to_model(
const std::vector<YAML::Node>& nodes); const std::vector<YAML::Node>& nodes);
static void replace_json_string_with_int(nlohmann::json& j); template<class T>
static void remove_ids_not_in_map(
const std::map<std::string, T>& map, std::vector<std::string>& ids,
const std::string& error_msg_type, const std::string& pcc_id);
std::shared_ptr<oai::pcf::app::sm_policy::policy_storage> m_policy_storage; std::shared_ptr<oai::pcf::app::sm_policy::policy_storage> m_policy_storage;
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment