Skip to content
Snippets Groups Projects
Commit ce0f5943 authored by Stefan Spettel's avatar Stefan Spettel
Browse files

refact(pcf): Integrated new config framework in pcf_config

parent a9879063
No related branches found
No related tags found
1 merge request!18Created generic configuration framework to be used by all NFs
......@@ -21,34 +21,43 @@
##### Base configuration #####
# Name of the component, used towards NRF. Valid values: any string
# Name of the component, used towards NRF. Valid values: any string, DEFAULT="PCF"
name: "PCF"
# Directories where policy configuration is stored
# Directories where policy configuration is stored, absolute path
pcc_rules_directory: "/openair-pcf/policies/pcc_rules"
traffic_rules_directory: "/openair-pcf/policies/traffic_rules"
policy_decisions_directory: "/openair-pcf/policies/policy_decisions"
##### Options to enable/disable #####
# If "yes": Register to NRF
# If "on": Register to NRF, DEFAULT= off
register_nrf: on
# If "yes": Send only HTTP/2 requests
# If "on": Send only HTTP/2 requests, DEFAULT=off
use_http2: off
##### Local interface #####
# Local SBI interface, you can choose any key, but it must be unique
# Local SBI interface
## name: Name of the NIC to read the IP address from
## Port: unsigned int between 0-65,535
## http_version: Allowed values: "1", "2"
## api_version: Allowed values: "v1", "v2", used to create the 3GPP API version for the SBI URL
local_sbi_interface:
name: "eth0"
port: 80
http_version: 1
api_version: "v1"
# Local HTTP2 SBI interface, optional. When configured, HTTP2 server is used
local_sbi_interface_http2:
name: "eth0"
port: 8080
http_version: 2
api_version: "v1"
##### Next hop interfaces #####
# Next hop SBI interfaces, you can choose any key, but it must be unique
## url: has to follow this scheme: http://<name>:<port>/
# Next hop SBI interfaces
## url: has to follow this scheme: http://<name>:<port>
## api_version: Allowed values: "v1", "v2", used to create the 3GPP API version for the SBI URL
nrf:
url: "http://oai-nrf:80/"
url: "http://oai-nrf:80"
api_version: "v1"
......@@ -44,7 +44,7 @@ target_sources(${NF_TARGET_LIB} PRIVATE
endif()
## CONFIG used in NF_TARGET_API (API library)
#target_include_directories(${NF_TARGET_API_LIB} PUBLIC ${CONFIG_DIR})
#target_sources(${NF_TARGET_API_LIB} PRIVATE
# ${CONFIG_SRC_FILES}
# )
target_include_directories(${NF_TARGET_API_LIB} PUBLIC ${CONFIG_DIR})
target_sources(${NF_TARGET_API_LIB} PRIVATE
${CONFIG_SRC_FILES}
)
......@@ -52,16 +52,18 @@ bool config::validate() const {
for (const auto& key : m_mandatory_keys) {
const auto it = m_config.find(key);
if (it == m_config.end()) {
logger::logger_registry::get_logger(LOGGER_NAME).error(
"Mandatory configuration %s does not exist in configuration", key);
logger::logger_registry::get_logger(LOGGER_NAME)
.error(
"Mandatory configuration %s does not exist in configuration",
key);
success = false;
}
}
for (const auto& conf : m_config) {
if (!conf.second->validate()) {
logger::logger_registry::get_logger(LOGGER_NAME).error(
"Validation of %s not successful", conf.first);
logger::logger_registry::get_logger(LOGGER_NAME)
.error("Validation of %s not successful", conf.first);
success = false;
}
}
......@@ -79,7 +81,6 @@ std::string config::to_string() const {
std::string others_out;
for (const auto& conf : m_config) {
std::string val = fmt::format(
BASE_FORMATTER, "-", conf.first, COLUMN_WIDTH,
conf.second->to_string(" "));
......@@ -98,8 +99,10 @@ std::string config::to_string() const {
sbi_out.append(val);
break;
case config_type_e::INVALID:
logger::logger_registry::get_logger(LOGGER_NAME).error(
"General error in configuration. Invalid type of: %s", conf.first);
logger::logger_registry::get_logger(LOGGER_NAME)
.error(
"General error in configuration. Invalid type of: %s",
conf.first);
others_out.append(val);
break;
}
......@@ -133,9 +136,18 @@ bool config::get_support_feature(const std::string& name) const {
return get<option_config_value>(name).value;
}
const network_interface& config::get_network_interface(
const sbi_interface& config::get_sbi_interface(const std::string& name) const {
return get<sbi_interface>(name);
}
const local_interface& config::get_local_interface(
const std::string& name) const {
return get<local_interface>(name);
}
const local_sbi_interface& config::get_local_sbi_interface(
const std::string& name) const {
return get<network_interface>(name);
return get<local_sbi_interface>(name);
}
template<typename T>
......
......@@ -39,9 +39,9 @@
namespace oai::config {
const int COLUMN_WIDTH = 20;
const int COLUMN_WIDTH = 20;
const std::string BASE_FORMATTER = " {} {:.<{}}: {}\n";
const std::string LOGGER_NAME = "config ";
const std::string LOGGER_NAME = "config ";
class config_iface {
public:
......@@ -51,10 +51,12 @@ class config_iface {
* @param name name of the configuration
* @param val value of the configuration
*/
virtual void set_configuration(const std::string& name, std::unique_ptr<config_type> val) = 0;
virtual void set_configuration(
const std::string& name, std::unique_ptr<config_type> val) = 0;
/**
* Set a configuration of any type with name to be mandatory, used for validation
* Set a configuration of any type with name to be mandatory, used for
* validation
* @param name name of the configuration
*/
virtual void set_configuration_mandatory(const std::string& name) = 0;
......@@ -73,45 +75,72 @@ class config_iface {
*/
[[nodiscard]] virtual std::string to_string() const = 0;
// The get method is not defined here, as we cannot have virtual template members
// Annoying that I cannot have a virtual template method just called "get"
// The get method is not defined here, as we cannot have virtual template
// members Annoying that I cannot have a virtual template method just called
// "get"
/**
* Get a string base configuration
* @throws std::invalid_argument when name does not exist in configuration
* @param name of the configuration
* @return value
*/
[[nodiscard]] virtual const std::string& get_base_conf_val(const std::string& name) const = 0;
[[nodiscard]] virtual const std::string& get_base_conf_val(
const std::string& name) const = 0;
/**
* Get a boolean configuration
* @throws std::invalid_argument when name does not exist in configuration
* @param name of the configuration
* @return value
*/
[[nodiscard]] virtual bool get_support_feature(const std::string& name) const = 0;
[[nodiscard]] virtual bool get_support_feature(
const std::string& name) const = 0;
/**
* Get a network interface configuration
* Get a SBI interface configuration
* @throws std::invalid_argument when name does not exist in configuration
* @param name of the configuration
* @return value
*/
[[nodiscard]] virtual const network_interface& get_network_interface(const std::string& name) const = 0 ;
[[nodiscard]] virtual const sbi_interface& get_sbi_interface(
const std::string& name) const = 0;
/**
* Get a local SBI interface configuration
* @throws std::invalid_argument when name does not exist in configuration
* @param name of the configuration
* @return value
*/
[[nodiscard]] virtual const local_sbi_interface& get_local_sbi_interface(
const std::string& name) const = 0;
/**
* Get a local interface configuration
* @throws std::invalid_argument when name does not exist in configuration
* @param name of the configuration
* @return value
*/
[[nodiscard]] virtual const local_interface& get_local_interface(
const std::string& name) const = 0;
/**
* Display the to_string method to the config logger
*/
virtual void display() const = 0;
virtual ~config_iface() = default;
};
class config : public config_iface{
class config : public config_iface {
public:
explicit config(bool log_stdout, bool log_rot_file) {
logger::logger_registry::register_logger(PACKAGE_NAME, LOGGER_NAME, log_stdout, log_rot_file);
explicit config(
const std::string& nf_name, bool log_stdout, bool log_rot_file) {
logger::logger_registry::register_logger(
nf_name, LOGGER_NAME, log_stdout, log_rot_file);
}
void set_configuration(const std::string& name, std::unique_ptr<config_type> val) override;
void set_configuration(
const std::string& name, std::unique_ptr<config_type> val) override;
void set_configuration_mandatory(const std::string& name) override;
......@@ -129,16 +158,24 @@ class config : public config_iface{
template<typename T>
[[nodiscard]] const T& get(const std::string& name) const;
[[nodiscard]] const std::string& get_base_conf_val(const std::string& name) const override;
[[nodiscard]] const std::string& get_base_conf_val(
const std::string& name) const override;
[[nodiscard]] bool get_support_feature(const std::string& name) const override;
[[nodiscard]] bool get_support_feature(
const std::string& name) const override;
[[nodiscard]] const network_interface& get_network_interface(const std::string& name) const override;
[[nodiscard]] const sbi_interface& get_sbi_interface(
const std::string& name) const override;
[[nodiscard]] const local_interface& get_local_interface(
const std::string& name) const override;
[[nodiscard]] const local_sbi_interface& get_local_sbi_interface(
const std::string& name) const override;
void display() const override;
private:
std::map<std::string, std::unique_ptr<config_type>> m_config;
std::vector<std::string> m_mandatory_keys;
......@@ -146,5 +183,4 @@ class config : public config_iface{
mutable std::shared_mutex m_config_mutex;
};
}
\ No newline at end of file
} // namespace oai::config
\ No newline at end of file
......@@ -28,18 +28,38 @@
*/
#include "config_types.hpp"
#include "fmt/format.h"
#include "config.hpp"
#include "conversions.hpp"
#include "algorithm"
#include "logger_base.hpp"
#include "if.hpp"
#include "common_defs.h"
#include <fmt/format.h>
#include <algorithm>
#include <regex>
#include <string>
using namespace oai::config;
const std::string INNER_LIST_ELEM = "+";
bool sbi_interface::validate() const {
// TODO validation
bool config_type::matches_regex(
const std::string& value, const std::string& regex) {
std::regex re(regex);
if (!std::regex_match(value, re)) {
logger::logger_registry::get_logger(LOGGER_NAME)
.error("%s does not follow regex specification: %s", value, regex);
return false;
}
return true;
}
bool sbi_interface::validate() {
if (!matches_regex(url, URL_REGEX)) {
return false;
}
set = true;
return true;
}
......@@ -59,8 +79,26 @@ config_type_e sbi_interface::get_config_type() const {
return type;
}
bool local_interface::validate() const {
// TODO validation
bool sbi_interface::is_set() const {
return set;
}
bool local_interface::validate() {
unsigned int _mtu{};
in_addr _addr4{};
in_addr _netmask{};
if (get_inet_addr_infos_from_iface(if_name, _addr4, _netmask, _mtu) ==
RETURNerror) {
logger::logger_registry::get_logger(LOGGER_NAME)
.error(
"Error in reading configuration from network interface %s",
if_name);
return false;
}
mtu = _mtu;
addr4 = _addr4;
set = true;
return true;
}
......@@ -73,15 +111,15 @@ std::string local_interface::to_string(const std::string& indent) const {
out.append(indent).append(fmt::format(
BASE_FORMATTER, INNER_LIST_ELEM, "IPv4 Address ", inner_width, ip4));
if (!ip6.empty()) {
if (ip6 != "::") {
out.append(indent).append(fmt::format(
BASE_FORMATTER, INNER_LIST_ELEM, "IPv6 Address", inner_width, ip4));
BASE_FORMATTER, INNER_LIST_ELEM, "IPv6 Address", inner_width, ip6));
}
out.append(indent).append(
fmt::format(BASE_FORMATTER, INNER_LIST_ELEM, "MTU", inner_width, mtu));
out.append(indent).append(fmt::format(
BASE_FORMATTER, INNER_LIST_ELEM, "Interface name: ", inner_width,
iface_name));
if_name));
out.append(indent).append(
fmt::format(BASE_FORMATTER, INNER_LIST_ELEM, "Port", inner_width, port));
......@@ -92,11 +130,16 @@ config_type_e local_interface::get_config_type() const {
return type;
}
bool local_sbi_interface::validate() const {
bool local_interface::is_set() const {
return set;
}
bool local_sbi_interface::validate() {
bool sbi_validate = validate_sbi_api_version(api_version);
if (!sbi_validate) {
return false;
}
set = true;
return local_interface::validate();
}
......@@ -106,9 +149,20 @@ std::string local_sbi_interface::to_string(const std::string& indent) const {
out.append(indent).append(fmt::format(
BASE_FORMATTER, INNER_LIST_ELEM, "API Version", inner_width,
api_version));
std::string http_version = use_http2 ? "2" : "1";
out.append(indent).append(fmt::format(
BASE_FORMATTER, INNER_LIST_ELEM, "HTTP Version", inner_width,
http_version));
return out;
}
bool local_sbi_interface::is_set() const {
return set;
}
bool network_interface::validate_sbi_api_version(const std::string& v) {
auto it =
std::find(allowed_api_versions.begin(), allowed_api_versions.end(), v);
......@@ -125,23 +179,45 @@ std::string string_config_value::to_string(const std::string&) const {
return out.append(value);
}
bool string_config_value::validate() const {
return false;
bool string_config_value::validate() {
set = true;
return true;
}
config_type_e string_config_value::get_config_type() const {
return type;
}
bool string_config_value::is_set() const {
return set;
}
std::string option_config_value::to_string(const std::string&) const {
std::string val = value ? "Yes" : "No";
return val;
}
bool option_config_value::validate() const {
bool option_config_value::validate() {
set = true;
return true;
}
config_type_e option_config_value::get_config_type() const {
return type;
}
bool option_config_value::is_set() const {
return set;
}
option_config_value factory::get_option_config(bool val) {
option_config_value v;
v.value = val;
return v;
}
string_config_value factory::get_string_config(const std::string& val) {
string_config_value v;
v.value = val;
return v;
}
......@@ -38,16 +38,24 @@ namespace oai::config {
const std::vector<std::string> allowed_api_versions{"v1", "v2"};
const std::string URL_REGEX = "http://.*:[0-9]*";
// Only used for pretty-printing
enum class config_type_e { STRING, OPTION, SBI, LOCAL, INVALID };
class config_type {
public:
[[nodiscard]] virtual std::string to_string(
const std::string& indent) const = 0;
[[nodiscard]] virtual bool validate() const = 0;
const std::string& indent) const = 0;
[[nodiscard]] virtual bool validate() = 0;
[[nodiscard]] virtual config_type_e get_config_type() const = 0;
[[nodiscard]] virtual bool is_set() const = 0;
static bool matches_regex(const std::string& value, const std::string& regex);
virtual ~config_type() = default;
};
......@@ -57,11 +65,13 @@ class string_config_value : public config_type {
std::string regex;
[[nodiscard]] std::string to_string(const std::string& indent) const override;
[[nodiscard]] bool validate() const override;
[[nodiscard]] bool validate() override;
[[nodiscard]] config_type_e get_config_type() const override;
[[nodiscard]] bool is_set() const override;
private:
config_type_e type = config_type_e::STRING;
bool set = false;
};
class option_config_value : public config_type {
......@@ -69,11 +79,13 @@ class option_config_value : public config_type {
bool value = false;
[[nodiscard]] std::string to_string(const std::string& indent) const override;
[[nodiscard]] bool validate() const override;
[[nodiscard]] bool validate() override;
[[nodiscard]] config_type_e get_config_type() const override;
[[nodiscard]] bool is_set() const override;
private:
config_type_e type = config_type_e::OPTION;
bool set = false;
};
class network_interface : public config_type {
......@@ -86,39 +98,53 @@ class sbi_interface : public network_interface {
std::string api_version;
std::string url;
[[nodiscard]] bool validate() const override;
[[nodiscard]] bool validate() override;
[[nodiscard]] std::string to_string(const std::string& indent) const override;
[[nodiscard]] config_type_e get_config_type() const override;
[[nodiscard]] bool is_set() const override;
private:
config_type_e type = config_type_e::SBI;
bool set = false;
};
class local_interface : public network_interface {
public:
std::string iface_name;
in_addr addr4;
in6_addr addr6;
unsigned int mtu;
uint16_t port;
std::string if_name{};
in_addr addr4{};
in6_addr addr6{};
unsigned int mtu{};
uint16_t port{};
[[nodiscard]] bool validate() const override;
[[nodiscard]] bool validate() override;
[[nodiscard]] std::string to_string(const std::string& indent) const override;
[[nodiscard]] config_type_e get_config_type() const override;
[[nodiscard]] bool is_set() const override;
private:
config_type_e type = config_type_e::LOCAL;
bool set = false;
};
class local_sbi_interface : public local_interface {
public:
std::string api_version;
bool use_http2 = false;
[[nodiscard]] bool validate() const override;
[[nodiscard]] bool validate() override;
[[nodiscard]] std::string to_string(const std::string& indent) const override;
[[nodiscard]] bool is_set() const override;
private:
config_type_e type = config_type_e::LOCAL;
bool set = false;
};
class factory {
public:
static option_config_value get_option_config(bool val);
static string_config_value get_string_config(const std::string& val);
};
} // namespace oai::config
\ No newline at end of file
......@@ -99,8 +99,8 @@ struct convert<oai::config::local_interface> {
if (!node["name"] || !node["port"]) {
return false;
}
val.port = node["port"].as<uint16_t>();
val.iface_name = node["name"].as<std::string>();
val.port = node["port"].as<uint16_t>();
val.if_name = node["name"].as<std::string>();
return true;
}
};
......@@ -109,14 +109,18 @@ template<>
struct convert<oai::config::local_sbi_interface> {
static bool decode(const Node& node, oai::config::local_sbi_interface& val) {
auto iface = node.as<oai::config::local_interface>();
if (!node["api_version"]) {
if (!node["api_version"] || !node["http_version"]) {
return false;
}
val.port = iface.port;
val.iface_name = iface.iface_name;
val.api_version = node["api_version"].as<std::string>();
val.port = iface.port;
val.if_name = iface.if_name;
val.api_version = node["api_version"].as<std::string>();
auto http_version = node["http_version"].as<std::string>();
if (http_version == "2") {
val.use_http2 = true;
}
return true;
}
};
......
......@@ -14,7 +14,6 @@
* limitations under the License.
*/
#include "common_defs.h"
#include "logger.hpp"
#include "pcf-api-server.hpp"
#include "pcf-http2-server.hpp"
......@@ -24,7 +23,6 @@
#include "pistache/http.h"
#include "nf_launch.hpp"
#include <algorithm>
#include <iostream>
#include <csignal>
#include <thread>
......@@ -35,11 +33,13 @@ using namespace oai::pcf::app;
using namespace oai::pcf::config;
using namespace oai::utils;
using namespace oai::config;
std::unique_ptr<pcf_app> pcf_app_inst;
// TODO Stefan: I am not happy with these global variables
// We could make a singleton getInstance in config
// or we handle everything in smf_app init and have a reference to config there
std::unique_ptr<pcf_config> pcf_cfg = std::make_unique<pcf_config>();
std::unique_ptr<pcf_config> pcf_cfg;
std::unique_ptr<PCFApiServer> pcf_api_server_1;
std::unique_ptr<pcf_http2_server> pcf_api_server_2;
......@@ -86,36 +86,42 @@ int main(int argc, char** argv) {
std::signal(SIGINT, signal_handler_sigint);
// Event subsystem
pcf_event ev;
// Config
if (pcf_cfg->load(oai::utils::options::getlibconfigConfig()) == RETURNerror) {
exit(-1);
pcf_cfg = std::make_unique<pcf_config>(
oai::utils::options::getlibconfigConfig(),
oai::utils::options::getlogStdout(),
oai::utils::options::getlogRotFilelog());
if (!pcf_cfg->init()) {
pcf_cfg->display();
return 1;
}
pcf_cfg->display();
// Event subsystem
pcf_event ev;
// PCF application layer
pcf_app_inst = std::make_unique<pcf_app>(ev);
std::string v4_address = conv::toString(pcf_cfg->sbi.addr4);
// PCF Pistache API server (HTTP1)
Pistache::Address addr(v4_address, Pistache::Port(pcf_cfg->sbi.http1_port));
Pistache::Address addr(v4_address, Pistache::Port(pcf_cfg->sbi.port));
PCFApiServer test(addr, pcf_app_inst);
pcf_api_server_1 = std::make_unique<PCFApiServer>(addr, pcf_app_inst);
pcf_api_server_1->init(2);
std::thread pcf_http1_manager(&PCFApiServer::start, pcf_api_server_1.get());
// PCF NGHTTP API server (HTTP2)
pcf_api_server_2 = std::make_unique<pcf_http2_server>(
v4_address, pcf_cfg->sbi.http2_port, pcf_app_inst);
std::thread pcf_http2_manager(
&pcf_http2_server::start, pcf_api_server_2.get());
if (pcf_cfg->sbi_http2.is_set()) {
// PCF NGHTTP API server (HTTP2)
pcf_api_server_2 = std::make_unique<pcf_http2_server>(
v4_address, pcf_cfg->sbi_http2.port, pcf_app_inst);
std::thread pcf_http2_manager(
&pcf_http2_server::start, pcf_api_server_2.get());
pcf_http2_manager.join();
}
pcf_http1_manager.join();
pcf_http2_manager.join();
Logger::pcf_app().info("HTTP servers successfully stopped. Exiting");
......
......@@ -21,339 +21,81 @@
/*! \file pcf_config.cpp
\brief
\author Rohan Kharade
\company Openairinterface Software Allianse
\author Rohan Kharade, Stefan Spettel
\company OpenAirInterface Software Alliance
\date 2022
\email: rohan.kharade@openairinterface.org
*/
#include <config_yaml_file.hpp>
#include "pcf_config.hpp"
#include "common_defs.h"
#include "conversions.hpp"
#include "if.hpp"
#include "string.hpp"
#include "fqdn.hpp"
#include <fstream>
#include <nlohmann/json.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
using namespace oai::config;
#include <cstdlib>
#include <iomanip>
#include <iostream>
bool oai::pcf::config::pcf_config::init() {
// Default configuration
std::unique_ptr<config_type> use_http2 =
std::make_unique<option_config_value>(
factory::get_option_config(USE_HTTP2_DEFAULT_VALUE));
std::unique_ptr<config_type> register_nrf =
std::make_unique<option_config_value>(
factory::get_option_config(REGISTER_NRF_DEFAULT_VALUE));
std::unique_ptr<config_type> pcf_name = std::make_unique<string_config_value>(
factory::get_string_config(NAME_DEFAULT_VALUE));
using namespace std;
using namespace libconfig;
m_cfg->set_configuration(PCF_CONFIG_STRING_USE_HTTP2, std::move(use_http2));
m_cfg->set_configuration(
PCF_CONFIG_STRING_REGISTER_NRF, std::move(register_nrf));
m_cfg->set_configuration(PCF_CONFIG_STRING_NAME, std::move(pcf_name));
namespace oai::pcf::config {
// C includes
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
m_cfg->set_configuration_mandatory(PCF_CONFIG_STRING_TRAFFIC_RULES_DIR);
m_cfg->set_configuration_mandatory(PCF_CONFIG_STRING_POLICY_DECISIONS_DIR);
m_cfg->set_configuration_mandatory(PCF_CONFIG_STRING_PCC_RULES_DIR);
//------------------------------------------------------------------------------
// int pcf_config::execute() { return RETURNok; }
m_cfg->set_configuration_mandatory(PCF_CONFIG_STRING_SBI_IFACE);
//------------------------------------------------------------------------------
int pcf_config::load_interface(const Setting& if_cfg, interface_cfg_t& cfg) {
if_cfg.lookupValue(PCF_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(PCF_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::pcf_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::pcf_app().error(
"Bad value " PCF_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::pcf_app().error(
"In conversion: Bad value " PCF_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(PCF_CONFIG_STRING_SBI_PORT_HTTP1, cfg.http1_port);
if_cfg.lookupValue(PCF_CONFIG_STRING_SBI_PORT_HTTP2, cfg.http2_port);
}
return RETURNok;
}
//------------------------------------------------------------------------------
int pcf_config::check_directory(
const Setting& pcf_cfg, const std::string& path_config, std::string& path) {
try {
pcf_cfg.lookupValue(path_config, path);
struct stat info;
if (stat(path.c_str(), &info) != 0) {
Logger::pcf_app().info("Path %s cannot be accessed.", path.c_str());
return RETURNerror;
} else if (!(info.st_mode & S_IFDIR)) {
Logger::pcf_app().info("Path %s is not a directory.", path.c_str());
return RETURNerror;
}
} catch (const SettingNotFoundException& nfex) {
Logger::pcf_app().info("Configuration %s is not set.", path_config.c_str());
return RETURNerror;
}
return RETURNok;
}
//------------------------------------------------------------------------------
int pcf_config::load(const string& config_file) {
Config cfg;
// Read the file. If there is an error, report it and exit.
yaml_file file;
try {
cfg.readFile(config_file.c_str());
} catch (const FileIOException& fioex) {
Logger::pcf_app().error(
"I/O error while reading file %s - %s", config_file.c_str(),
fioex.what());
throw;
} catch (const ParseException& pex) {
Logger::pcf_app().error(
"Parse error at %s:%d - %s", pex.getFile(), pex.getLine(),
pex.getError());
throw;
}
const Setting& root = cfg.getRoot();
if (root.exists(PCF_CONFIG_STRING_PCF_CONFIG) == false) {
Logger::pcf_app().error(
"Setting does not exist: " + std::string{PCF_CONFIG_STRING_PCF_CONFIG});
return RETURNerror;
file.read_from_file(m_config_path, *m_cfg);
} catch (std::runtime_error& err) {
return false;
}
const Setting& pcf_cfg = root[PCF_CONFIG_STRING_PCF_CONFIG];
try {
pcf_cfg.lookupValue(PCF_CONFIG_STRING_FQDN, fqdn);
util::trim(fqdn);
} catch (const SettingNotFoundException& nfex) {
Logger::pcf_app().info(
"%s : %s, No FQDN configured", nfex.what(), nfex.getPath());
// this is only mandatory when REGISTER_NRF is set
if (m_cfg->get_support_feature(PCF_CONFIG_STRING_REGISTER_NRF)) {
m_cfg->set_configuration_mandatory(PCF_CONFIG_STRING_NRF);
}
if (check_directory(
pcf_cfg, PCF_CONFIG_STRING_PCC_RULES_DIRECTORY, pcc_rules_path) !=
RETURNok) {
Logger::pcf_app().error(
"PCC Rules Path is not set or not a valid directory. Exiting");
return RETURNerror;
}
if (check_directory(
pcf_cfg, PCF_CONFIG_STRING_POLICY_DECISIONS_DIRECTORY,
policy_decisions_path) != RETURNok) {
Logger::pcf_app().error(
"Policy Decisions Path is not set or not a valid directory. Exiting");
return RETURNerror;
bool validated = m_cfg->validate();
if (!validated) {
logger::logger_registry::get_logger(LOGGER_NAME)
.error("Configuration validation not successful!");
return false;
}
if (check_directory(
pcf_cfg, PCF_CONFIG_STRING_TRAFFIC_RULES_DIRECTORY,
traffic_rules_path) != RETURNok) {
Logger::pcf_app().warn(
"Traffic Rules Path is not set or not a valid directory. This feature "
"is disabled.");
}
try {
const Setting& nw_if_cfg = pcf_cfg[PCF_CONFIG_STRING_INTERFACES];
const Setting& sbi_cfg = nw_if_cfg[PCF_CONFIG_STRING_SBI_INTERFACE];
load_interface(sbi_cfg, sbi);
set_direct_variables();
return true;
}
sbi_cfg.lookupValue(PCF_CONFIG_STRING_API_VERSION, sbi_api_version);
} catch (const SettingNotFoundException& nfex) {
Logger::pcf_app().error("%s : %s", nfex.what(), nfex.getPath());
return RETURNerror;
}
// Support features
void oai::pcf::config::pcf_config::set_direct_variables() {
sbi = m_cfg->get_local_sbi_interface(PCF_CONFIG_STRING_SBI_IFACE);
try {
const Setting& support_features =
pcf_cfg[PCF_CONFIG_STRING_SUPPORT_FEATURES];
string opt;
support_features.lookupValue(
PCF_CONFIG_STRING_SUPPORT_FEATURES_REGISTER_NRF, opt);
if (boost::iequals(opt, "yes")) {
pcf_features.register_nrf = true;
} else {
pcf_features.register_nrf = false;
}
support_features.lookupValue(
PCF_CONFIG_STRING_SUPPORT_FEATURES_USE_FQDN_DNS, opt);
if (boost::iequals(opt, "yes")) {
pcf_features.use_fqdn = true;
} else {
pcf_features.use_fqdn = false;
}
support_features.lookupValue(
PCF_CONFIG_STRING_SUPPORT_FEATURES_USE_HTTP2, opt);
if (boost::iequals(opt, "yes")) {
pcf_features.use_http2 = true;
} else {
pcf_features.use_http2 = false;
}
} catch (const SettingNotFoundException& nfex) {
Logger::pcf_app().error(
"%s : %s, using defaults", nfex.what(), nfex.getPath());
return -1;
sbi_http2 =
m_cfg->get_local_sbi_interface(PCF_CONFIG_STRING_SBI_IFACE_HTTP2);
} catch (std::invalid_argument&) {
}
try {
string astring = {};
// NRF
if (pcf_features.register_nrf) {
const Setting& nrf_cfg = pcf_cfg[PCF_CONFIG_STRING_NRF];
struct in_addr nrf_ipv4_addr = {};
unsigned int nrf_port = {0};
std::string nrf_api_version = {};
if (!pcf_features.use_fqdn) {
nrf_cfg.lookupValue(PCF_CONFIG_STRING_NRF_IPV4_ADDRESS, astring);
IPV4_STR_ADDR_TO_INADDR(
util::trim(astring).c_str(), nrf_ipv4_addr,
"BAD IPv4 ADDRESS FORMAT FOR NRF !");
nrf_addr.ipv4_addr = nrf_ipv4_addr;
if (!(nrf_cfg.lookupValue(PCF_CONFIG_STRING_NRF_PORT, nrf_port))) {
Logger::pcf_app().error(PCF_CONFIG_STRING_NRF_PORT "failed");
throw(PCF_CONFIG_STRING_NRF_PORT "failed");
}
nrf_addr.port = nrf_port;
if (!(nrf_cfg.lookupValue(
PCF_CONFIG_STRING_API_VERSION, nrf_api_version))) {
Logger::pcf_app().error(PCF_CONFIG_STRING_API_VERSION "failed");
throw(PCF_CONFIG_STRING_API_VERSION "failed");
}
nrf_addr.api_version = nrf_api_version;
} else {
nrf_cfg.lookupValue(PCF_CONFIG_STRING_FQDN, astring);
uint8_t addr_type = {0};
std::string address = {};
fqdn::resolve(astring, address, nrf_port, addr_type);
if (addr_type != 0) { // IPv6
// TODO:
throw("DO NOT SUPPORT IPV6 ADDR FOR NRF!");
} else { // IPv4
IPV4_STR_ADDR_TO_INADDR(
util::trim(address).c_str(), nrf_ipv4_addr,
"BAD IPv4 ADDRESS FORMAT FOR NRF !");
nrf_addr.ipv4_addr = nrf_ipv4_addr;
// nrf_addr.port = nrf_port;
// We hardcode nrf port from config for the moment
if (!(nrf_cfg.lookupValue(PCF_CONFIG_STRING_NRF_PORT, nrf_port))) {
Logger::pcf_app().error(PCF_CONFIG_STRING_NRF_PORT "failed");
throw(PCF_CONFIG_STRING_NRF_PORT "failed");
}
nrf_addr.port = nrf_port;
nrf_addr.api_version = "v1"; // TODO: to get API version from DNS
nrf_addr.fqdn = astring;
}
}
}
} catch (const SettingNotFoundException& nfex) {
Logger::pcf_app().error("%s : %s", nfex.what(), nfex.getPath());
return RETURNerror;
}
return RETURNok;
nrf_addr = m_cfg->get_sbi_interface(PCF_CONFIG_STRING_NRF);
pcc_rules_path = m_cfg->get_base_conf_val(PCF_CONFIG_STRING_PCC_RULES_DIR);
policy_decisions_path =
m_cfg->get_base_conf_val(PCF_CONFIG_STRING_POLICY_DECISIONS_DIR);
traffic_rules_path =
m_cfg->get_base_conf_val(PCF_CONFIG_STRING_TRAFFIC_RULES_DIR);
pcf_features.register_nrf =
m_cfg->get_support_feature(PCF_CONFIG_STRING_REGISTER_NRF);
pcf_features.use_http2 =
m_cfg->get_support_feature(PCF_CONFIG_STRING_USE_HTTP2);
}
//------------------------------------------------------------------------------
void pcf_config::display() {
Logger::pcf_app().info(
"==== OPENAIRINTERFACE %s v%s ====", PACKAGE_NAME, PACKAGE_VERSION);
Logger::pcf_app().info("Configuration:");
Logger::pcf_app().info("- FQDN ..................: %s", fqdn.c_str());
Logger::pcf_app().info(
"- Policies Path..........: %s", policy_decisions_path.c_str());
Logger::pcf_app().info(
"- PCC Rules Path.........: %s", pcc_rules_path.c_str());
Logger::pcf_app().info(
"- Traffic Rules Path.....: %s", traffic_rules_path.c_str());
Logger::pcf_app().info("- SBI:");
Logger::pcf_app().info(" iface ............: %s", sbi.if_name.c_str());
Logger::pcf_app().info(" ipv4.addr ........: %s", inet_ntoa(sbi.addr4));
Logger::pcf_app().info(" ipv4.mask ........: %s", inet_ntoa(sbi.network4));
Logger::pcf_app().info(" mtu ..............: %d", sbi.mtu);
Logger::pcf_app().info(" http1_port .......: %u", sbi.http1_port);
Logger::pcf_app().info(" http2_port .......: %u", sbi.http2_port);
Logger::pcf_app().info(" api_version ......: %s", sbi_api_version.c_str());
if (pcf_features.register_nrf) {
Logger::pcf_app().info("- NRF:");
Logger::pcf_app().info(
" IPv4 Addr ...........: %s",
inet_ntoa(*((struct in_addr*) &nrf_addr.ipv4_addr)));
Logger::pcf_app().info(" Port ................: %lu ", nrf_addr.port);
Logger::pcf_app().info(
" API version .........: %s", nrf_addr.api_version.c_str());
if (pcf_features.use_fqdn)
Logger::pcf_app().info(
" FQDN ................: %s", nrf_addr.fqdn.c_str());
}
Logger::pcf_app().info("- Supported Features:");
Logger::pcf_app().info(
" Register to NRF........: %s",
pcf_features.register_nrf ? "Yes" : "No");
Logger::pcf_app().info(
" Use FQDN ..............: %s", pcf_features.use_fqdn ? "Yes" : "No");
Logger::pcf_app().info(
" Use HTTP2..............: %s", pcf_features.use_http2 ? "Yes" : "No");
void oai::pcf::config::pcf_config::display() {
m_cfg->display();
}
//------------------------------------------------------------------------------
// bool pcf_config::get_slice_config(nlohmann::json& slice_config) {
// slice_config = pcf_slice_config;
// return true;
// }
//------------------------------------------------------------------------------
// bool pcf_config::get_api_list(nlohmann::json &api_list) {
// api_list["OAI-PCF"] = {
// {"Organisation", "Openairinterface Software Aliance"},
// {"Description", "OAI-PCF initial Release"},
// {"Version", "1.0.0"},
// {"Supported APIs",
// {{"API", "Network Slice Information (Document)"},
// {"Method", "GET"},
// {"URI Path",
// "/npcf-nsselection/<api_version>/network-slice-information"},
// {"Details",
// "Retrieve the Network Slice Selection Information (PDU
// Session)"}}}};
// return true;
// }
//------------------------------------------------------------------------------
} // namespace oai::pcf::config
......@@ -21,138 +21,74 @@
/*! \file pcf_config.hpp
\brief
\author Rohan Kharade
\company Openairinterface Software Allianse
\author Rohan Kharade, Stefan Spettel
\company OpenAirInterface Software Alliance
\date 2022
\email: rohan.kharade@openairinterface.org
*/
#ifndef FILE_PCF_CONFIG_HPP_SEEN
#define FILE_PCF_CONFIG_HPP_SEEN
#pragma once
#include "3gpp_29.510.h"
#include "logger.hpp"
#include <libconfig.h++>
#include <mutex>
#include <netinet/in.h>
#include <nlohmann/json.hpp>
#include <stdbool.h>
#include <stdint.h>
#include <string>
#include <unistd.h>
// using namespace oai::pcf::model;
#define PCF_CONFIG_STRING_PCF_CONFIG "PCF"
#define PCF_CONFIG_STRING_FQDN "FQDN"
#define PCF_CONFIG_STRING_PCF_SLICE_CONFIG "PCF_SLICE_CONFIG"
#define PCF_CONFIG_STRING_INTERFACES "INTERFACES"
#define PCF_CONFIG_STRING_INTERFACE_NAME "INTERFACE_NAME"
#define PCF_CONFIG_STRING_IPV4_ADDRESS "IPV4_ADDRESS"
#define PCF_CONFIG_STRING_SBI_PORT_HTTP1 "HTTP1_PORT"
#define PCF_CONFIG_STRING_SBI_PORT_HTTP2 "HTTP2_PORT"
#define PCF_CONFIG_STRING_SBI_INTERFACE "SBI"
#define PCF_CONFIG_STRING_API_VERSION "API_VERSION"
#define PCF_CONFIG_STRING_NETWORK_IPV4 "NETWORK_IPV4"
#define PCF_CONFIG_STRING_NETWORK_IPV6 "NETWORK_IPV6"
#define PCF_CONFIG_STRING_ADDRESS_PREFIX_DELIMITER "/"
#define PCF_CONFIG_STRING_ITTI_TASKS "ITTI_TASKS"
#define PCF_CONFIG_STRING_ITTI_TIMER_SCHED_PARAMS "ITTI_TIMER_SCHED_PARAMS"
#define PCF_CONFIG_STRING_SBI_SCHED_PARAMS "SBI_SCHED_PARAMS"
#define PCF_CONFIG_STRING_SUPPORT_FEATURES "SUPPORT_FEATURES"
#define PCF_CONFIG_STRING_SUPPORT_FEATURES_REGISTER_NRF "REGISTER_NRF"
#define PCF_CONFIG_STRING_NRF "NRF"
#define PCF_CONFIG_STRING_NRF_IPV4_ADDRESS "IPV4_ADDRESS"
#define PCF_CONFIG_STRING_NRF_PORT "PORT"
#define PCF_CONFIG_STRING_NRF_HTTP_VERSION "HTTP_VERSION"
#define PCF_CONFIG_STRING_SUPPORT_FEATURES_USE_HTTP2 "USE_HTTP2"
#define PCF_CONFIG_STRING_SUPPORT_FEATURES_USE_FQDN_DNS "USE_FQDN"
#define PCF_CONFIG_STRING_PCC_RULES_DIRECTORY "PCC_RULES_DIRECTORY"
#define PCF_CONFIG_STRING_POLICY_DECISIONS_DIRECTORY \
"POLICY_DECISIONS_DIRECTORY"
#define PCF_CONFIG_STRING_TRAFFIC_RULES_DIRECTORY "TRAFFIC_RULES_DIRECTORY"
#include "config.hpp"
namespace oai::pcf::config {
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 http1_port;
unsigned int http2_port;
} interface_cfg_t;
const std::string NAME_DEFAULT_VALUE = "PCF";
const bool REGISTER_NRF_DEFAULT_VALUE = false;
const bool USE_HTTP2_DEFAULT_VALUE = false;
const std::string PCF_CONFIG_STRING_REGISTER_NRF = "register_nrf";
const std::string PCF_CONFIG_STRING_USE_HTTP2 = "use_http2";
const std::string PCF_CONFIG_STRING_NAME = "name";
const std::string PCF_CONFIG_STRING_PCC_RULES_DIR = "pcc_rules_directory";
const std::string PCF_CONFIG_STRING_POLICY_DECISIONS_DIR =
"policy_decisions_directory";
const std::string PCF_CONFIG_STRING_TRAFFIC_RULES_DIR =
"traffic_rules_directory";
const std::string PCF_CONFIG_STRING_SBI_IFACE = "local_sbi_interface";
const std::string PCF_CONFIG_STRING_SBI_IFACE_HTTP2 =
"local_sbi_interface_http2";
const std::string PCF_CONFIG_STRING_NRF = "nrf";
struct support_features {
bool register_nrf;
bool use_http2;
};
class pcf_config {
protected:
private:
int load_interface(const libconfig::Setting& if_cfg, interface_cfg_t& cfg);
int check_directory(
const libconfig::Setting& pcf_cfg, const std::string& path_config,
std::string& path);
public:
/* Reader/writer lock for this configuration */
std::mutex m_rw_lock;
std::string pid_dir;
unsigned int instance;
std::string fqdn;
interface_cfg_t sbi;
std::string sbi_api_version;
std::string gateway;
oai::config::local_sbi_interface sbi;
oai::config::local_sbi_interface sbi_http2;
std::string pcc_rules_path;
std::string policy_decisions_path;
std::string traffic_rules_path;
struct {
bool register_nrf;
bool use_fqdn;
bool use_http2;
struct {
struct in_addr ipv4_addr;
unsigned int port;
unsigned int http_version;
std::string api_version;
std::string fqdn;
} nrf_addr;
} pcf_features;
struct {
struct in_addr ipv4_addr;
unsigned int port;
unsigned int http_version;
std::string api_version;
std::string fqdn;
} nrf_addr;
oai::config::sbi_interface nrf_addr;
// struct {
// struct in_addr ipv4_addr;
// unsigned int port;
// unsigned int http_version;
// std::string api_version;
// std::string fqdn;
// } smf_addr;
support_features pcf_features;
pcf_config() : m_rw_lock(), pid_dir(), instance(0) {
sbi.http1_port = 8080;
sbi.http2_port = 80;
explicit pcf_config(
const std::string& config_path, bool log_stdout, bool log_rot_file)
: pcf_features() {
m_cfg =
std::make_unique<oai::config::config>("pcf", log_stdout, log_rot_file);
m_config_path = config_path;
};
void lock() { m_rw_lock.lock(); };
void unlock() { m_rw_lock.unlock(); };
int load(const std::string& config_file);
int execute();
/**
* Initialize the configuration, sets mandatory values for validation, sets
* default values, reads YAML configuration file and validates the
* configuration
* @return True on success
*/
bool init();
void display();
static bool parse_config();
private:
std::unique_ptr<oai::config::config_iface> m_cfg;
std::string m_config_path;
void set_direct_variables();
};
} // namespace oai::pcf::config
#endif /* FILE_PCF_CONFIG_HPP_SEEN */
......@@ -58,11 +58,8 @@ pcf_nrf::pcf_nrf(pcf_event& ev) : m_event_sub(ev) {
//------------------------------------------------------------------------------
void pcf_nrf::generate_nrf_api_url() {
m_nrf_url = "";
m_nrf_url.append(conv::toString(pcf_cfg->nrf_addr.ipv4_addr))
.append(":")
.append(to_string(pcf_cfg->nrf_addr.port))
.append(NNRF_NFM_BASE)
m_nrf_url = pcf_cfg->nrf_addr.url;
m_nrf_url.append(NNRF_NFM_BASE)
.append(pcf_cfg->nrf_addr.api_version)
.append(NNRF_DISC_INSTANCES)
.append(m_pcf_instance_id);
......@@ -86,7 +83,7 @@ void pcf_nrf::generate_pcf_profile() {
nf_service.service_instance_id = SM_POLICY_API_NAME;
nf_service.service_name = SM_POLICY_API_NAME;
nf_service_version_t version = {};
version.api_version_in_uri = pcf_cfg->sbi_api_version;
version.api_version_in_uri = pcf_cfg->sbi.api_version;
version.api_full_version = "1.0.0"; // TODO: to be updated
nf_service.versions.push_back(version);
nf_service.scheme = "http";
......@@ -96,8 +93,7 @@ void pcf_nrf::generate_pcf_profile() {
// TODO: use only one IP address from cfg for now
endpoint.ipv4_address = pcf_cfg->sbi.addr4;
endpoint.transport = "TCP";
endpoint.port = pcf_cfg->sbi.http1_port;
if (pcf_cfg->pcf_features.use_http2) endpoint.port = pcf_cfg->sbi.http2_port;
endpoint.port = pcf_cfg->sbi.port;
nf_service.ip_endpoints.push_back(endpoint);
m_nf_instance_profile.add_nf_service(nf_service);
......
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