Commit 31c75155 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

Merge branch 'nrf-selection' into 'develop'

NRF Selection

See merge request oai/cn5g/oai-cn5g-amf!64
parents c0f30330 7b0cdfb1
......@@ -85,6 +85,10 @@ services:
- AUSF_PORT=80
- AUSF_API_VERSION=v1
- AUSF_FQDN=localhost
- NSSF_IPV4_ADDRESS=0.0.0.0
- NSSF_PORT=80
- NSSF_API_VERSION=v1
- NSSF_FQDN=localhost
depends_on:
- cicd_mysql
networks:
......
......@@ -96,13 +96,21 @@ AMF =
API_VERSION = "@AUSF_API_VERSION@"; # YOUR AUSF API VERSION FOR SBI CONFIG HERE
FQDN = "@AUSF_FQDN@" # YOUR AUSF FQDN CONFIG HERE
};
NSSF :
{
IPV4_ADDRESS = "@NSSF_IPV4_ADDRESS@"; # YOUR NSSF CONFIG HERE
PORT = @NSSF_PORT@; # YOUR NSSF CONFIG HERE (default: 80)
API_VERSION = "@NSSF_API_VERSION@"; # YOUR NSSF API VERSION FOR SBI CONFIG HERE
FQDN = "@NSSF_FQDN@" # YOUR NSSF FQDN CONFIG HERE
};
};
SUPPORT_FEATURES:
{
# STRING, {"yes", "no"},
NF_REGISTRATION = "@NF_REGISTRATION@"; # Set to yes if AMF resgisters to an NRF
NRF_SELECTION = "@NRF_SELECTION@"; # Set to yes to enable NRF discovery and selection
SMF_SELECTION = "@SMF_SELECTION@"; # Set to yes to enable SMF discovery and selection
EXTERNAL_AUSF = "@EXTERNAL_AUSF@"; # Set to yes if AMF works with an external AUSF
EXTERNAL_UDM = "@EXTERNAL_UDM@"; # Set to yes if AMF works with an external UDM
......
......@@ -7,7 +7,14 @@ CONFIG_DIR="/openair-amf/etc"
# Default values
EXTERNAL_AUSF=${EXTERNAL_AUSF:-no}
EXTERNAL_UDM=${EXTERNAL_UDM:-no}
NRF_SELECTION=${NRF_SELECTION:-no}
NSSF_IPV4_ADDRESS=${NSSF_IPV4_ADDRESS:-0.0.0.0}
NSSF_PORT=${NSSF_PORT:-80}
NSSF_API_VERSION=${NSSF_API_VERSION:-v2}
NSSF_FQDN=${NSSF_FQDN:-oai-nssf}
if [[ ${USE_FQDN_DNS} == "yes" ]];then
NSSF_IPV4_ADDR=${NSSF_IPV4_ADDR_0:-0.0.0.0}
SMF_IPV4_ADDR_0=${SMF_IPV4_ADDR_0:-0.0.0.0}
SMF_IPV4_ADDR_1=${SMF_IPV4_ADDR_1:-0.0.0.0}
NRF_IPV4_ADDRESS=${NRF_IPV4_ADDRESS:-0.0.0.0}
......
......@@ -78,6 +78,7 @@ amf_config::amf_config() {
nas_cfg = {};
smf_pool = {};
support_features.enable_nf_registration = false;
support_features.enable_nrf_selection = false;
support_features.enable_smf_selection = false;
support_features.enable_external_ausf = false;
support_features.enable_external_udm = false;
......@@ -237,6 +238,14 @@ int amf_config::load(const std::string& config_file) {
support_features.enable_nf_registration = false;
}
support_features_cfg.lookupValue(
AMF_CONFIG_STRING_SUPPORT_FEATURES_NRF_SELECTION, opt);
if (boost::iequals(opt, "yes")) {
support_features.enable_nrf_selection = true;
} else {
support_features.enable_nrf_selection = false;
}
support_features_cfg.lookupValue(
AMF_CONFIG_STRING_SUPPORT_FEATURES_SMF_SELECTION, opt);
if (boost::iequals(opt, "yes")) {
......@@ -456,6 +465,48 @@ int amf_config::load(const std::string& config_file) {
}
}
// NSSF
if (support_features.enable_nrf_selection) {
const Setting& nssf_cfg = new_if_cfg[AMF_CONFIG_STRING_NSSF];
struct in_addr nssf_ipv4_addr = {};
unsigned int nssf_port = {};
std::string nssf_api_version = {};
if (!support_features.use_fqdn_dns) {
nssf_cfg.lookupValue(AMF_CONFIG_STRING_IPV4_ADDRESS, address);
IPV4_STR_ADDR_TO_INADDR(
util::trim(address).c_str(), nssf_ipv4_addr,
"BAD IPv4 ADDRESS FORMAT FOR NSSF !");
nssf_addr.ipv4_addr = nssf_ipv4_addr;
if (!(nssf_cfg.lookupValue(AMF_CONFIG_STRING_PORT, nssf_port))) {
Logger::amf_app().error(AMF_CONFIG_STRING_PORT "failed");
throw(AMF_CONFIG_STRING_PORT "failed");
}
nssf_addr.port = nssf_port;
if (!(nssf_cfg.lookupValue(
AMF_CONFIG_STRING_API_VERSION, nssf_api_version))) {
Logger::amf_app().error(AMF_CONFIG_STRING_API_VERSION "failed");
throw(AMF_CONFIG_STRING_API_VERSION "failed");
}
nssf_addr.api_version = nssf_api_version;
} else {
std::string nssf_fqdn = {};
nssf_cfg.lookupValue(AMF_CONFIG_STRING_FQDN_DNS, nssf_fqdn);
uint8_t addr_type = {};
fqdn::resolve(nssf_fqdn, address, nssf_port, addr_type);
if (addr_type != 0) { // IPv6: TODO
throw("DO NOT SUPPORT IPV6 ADDR FOR NSSF!");
} else { // IPv4
IPV4_STR_ADDR_TO_INADDR(
util::trim(address).c_str(), nssf_ipv4_addr,
"BAD IPv4 ADDRESS FORMAT FOR NSSF !");
nssf_addr.ipv4_addr = nssf_ipv4_addr;
nssf_addr.port = nssf_port;
nssf_addr.api_version = "v1"; // TODO: get API version
}
}
}
} catch (const SettingNotFoundException& nfex) {
Logger::amf_app().error(
"%s : %s, using defaults", nfex.what(), nfex.getPath());
......@@ -607,6 +658,15 @@ void amf_config::display() {
" API version ...........: %s", nrf_addr.api_version.c_str());
}
if (support_features.enable_nrf_selection) {
Logger::config().info("- NSSF:");
Logger::config().info(
" IP Addr ...............: %s", inet_ntoa(nssf_addr.ipv4_addr));
Logger::config().info(" Port ..................: %d", nssf_addr.port);
Logger::config().info(
" API version ...........: %s", nssf_addr.api_version.c_str());
}
if (support_features.enable_external_ausf) {
Logger::config().info("- AUSF:");
Logger::config().info(
......@@ -634,6 +694,9 @@ void amf_config::display() {
Logger::config().info(
" NF Registration .......: %s",
support_features.enable_nf_registration ? "Yes" : "No");
Logger::config().info(
" NRF Selection .........: %s",
support_features.enable_nrf_selection ? "Yes" : "No");
Logger::config().info(
" SMF Selection .........: %s",
support_features.enable_smf_selection ? "Yes" : "No");
......
......@@ -67,6 +67,8 @@
#define AMF_CONFIG_STRING_AUSF "AUSF"
#define AMF_CONFIG_STRING_NSSF "NSSF"
#define AMF_CONFIG_STRING_SCHED_PARAMS "SCHED_PARAMS"
#define AMF_CONFIG_STRING_THREAD_RD_CPU_ID "CPU_ID"
#define AMF_CONFIG_STRING_THREAD_RD_SCHED_POLICY "SCHED_POLICY"
......@@ -102,6 +104,7 @@
"ORDERED_SUPPORTED_CIPHERING_ALGORITHM_LIST"
#define AMF_CONFIG_STRING_SUPPORT_FEATURES "SUPPORT_FEATURES"
#define AMF_CONFIG_STRING_SUPPORT_FEATURES_NF_REGISTRATION "NF_REGISTRATION"
#define AMF_CONFIG_STRING_SUPPORT_FEATURES_NRF_SELECTION "NRF_SELECTION"
#define AMF_CONFIG_STRING_SUPPORT_FEATURES_SMF_SELECTION "SMF_SELECTION"
#define AMF_CONFIG_STRING_SUPPORT_FEATURES_EXTERNAL_AUSF "EXTERNAL_AUSF"
#define AMF_CONFIG_STRING_SUPPORT_FEATURES_EXTERNAL_UDM "EXTERNAL_UDM"
......@@ -204,6 +207,7 @@ class amf_config {
struct {
bool enable_nf_registration;
bool enable_nrf_selection;
bool enable_smf_selection;
bool enable_external_ausf;
bool enable_external_udm;
......@@ -222,6 +226,12 @@ class amf_config {
unsigned int port;
std::string api_version;
} ausf_addr;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} nssf_addr;
};
} // namespace config
......
......@@ -330,7 +330,14 @@ void amf_n11::handle_itti_message(itti_nsmf_pdusession_create_sm_context& smf) {
std::string smf_addr = {};
std::string smf_api_version = {};
if (!psc.get()->smf_available) {
if (amf_cfg.support_features.enable_smf_selection) {
if (amf_cfg.support_features.enable_nrf_selection) {
if (!discover_smf_from_nsi_info(
smf_addr, smf_api_version, psc.get()->snssai, psc.get()->plmn,
psc.get()->dnn)) {
Logger::amf_n11().error("NRF Selection, no NRF candidate is available");
return;
}
} else if (amf_cfg.support_features.enable_smf_selection) {
// use NRF to find suitable SMF based on snssai, plmn and dnn
if (!discover_smf(
smf_addr, smf_api_version, psc.get()->snssai, psc.get()->plmn,
......@@ -892,11 +899,134 @@ void amf_n11::curl_http_client(
curl_global_cleanup();
free_wrapper((void**) &body_data);
}
//-----------------------------------------------------------------------------------------------------
bool amf_n11::discover_smf_from_nsi_info(
std::string& smf_addr, std::string& smf_api_version, const snssai_t snssai,
const plmn_t plmn, const std::string dnn) {
Logger::amf_n11().debug(
"Send NS Selection to NSSF to discover the appropriate NRF");
bool result = true;
std::string nrf_addr = {};
std::string nrf_port = {};
std::string nrf_api_version = {};
uint8_t http_version = 1;
if (amf_cfg.support_features.use_http2) http_version = 2;
// Get NSI information from NSSF
nlohmann::json slice_info = {};
nlohmann::json snssai_info = {};
snssai_info["sst"] = snssai.sST;
if (!snssai.sD.empty()) snssai_info["sd"] = snssai.sD;
slice_info["sNssai"] = snssai_info;
slice_info["roamingIndication"] = "NON_ROAMING";
// ToDo Add TAI
std::string url = std::string(inet_ntoa(
*((struct in_addr*) &amf_cfg.nssf_addr.ipv4_addr))) +
":" + std::to_string(amf_cfg.nssf_addr.port) +
"/nnssf-nsselection/" + amf_cfg.nssf_addr.api_version +
"/network-slice-information?nf-type=AMF&nf-id=abc&slice-"
"info-request-for-pdu-session=" +
slice_info.dump();
curl_global_init(CURL_GLOBAL_ALL);
CURL* curl = curl = curl_easy_init();
if (curl) {
CURLcode res = {};
struct curl_slist* headers = nullptr;
// headers = curl_slist_append(headers, "charsets: utf-8");
headers = curl_slist_append(headers, "content-type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT_MS);
curl_easy_setopt(curl, CURLOPT_INTERFACE, amf_cfg.n11.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);
}
// Response information
long httpCode = {0};
std::unique_ptr<std::string> httpData(new std::string());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpData.get());
// curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
Logger::amf_n11().debug(
"NS Selection, response from NSSF, HTTP Code: %d", httpCode);
if (httpCode == 200) {
Logger::amf_n11().debug(
"NS Selection, got successful response from NSSF");
nlohmann::json response_data = {};
try {
response_data = nlohmann::json::parse(*httpData.get());
} catch (nlohmann::json::exception& e) {
Logger::amf_n11().warn(
"NS Selection, could not parse json from the NRF "
"response");
}
Logger::amf_n11().debug(
"NS Selection, response from NSSF, json data: \n %s",
response_data.dump().c_str());
// Process data to obtain NRF info
if (response_data.find("nsiInformation") != response_data.end()) {
std::string nrf_id = response_data["nsiInformation"]["nrfId"];
std::string nsi_id = response_data["nsiInformation"]["nsiId"];
std::vector<std::string> split_result;
boost::split(split_result, nrf_id, boost::is_any_of("/"));
nrf_api_version = split_result[split_result.size() - 2].c_str();
std::string nrf_endpoint =
split_result[split_result.size() - 4].c_str();
std::vector<std::string> split_nrf_endpoint;
boost::split(split_nrf_endpoint, nrf_endpoint, boost::is_any_of(":"));
nrf_port = split_nrf_endpoint[split_nrf_endpoint.size() - 1].c_str();
nrf_addr = split_nrf_endpoint[split_nrf_endpoint.size() - 2].c_str();
}
} else {
Logger::amf_n11().warn("NS Selection, could not get response from NSSF");
result = false;
}
Logger::amf_n11().debug(
"NS Selection, NRF Addr: %s, NRF Port: %s, NRF Api Version: %s",
nrf_addr.c_str(), nrf_port.c_str(), nrf_api_version.c_str());
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
if (!result) return result;
Logger::amf_n11().debug("NSI Inforation is successfully retrieved from NSSF");
if (!discover_smf(
smf_addr, smf_api_version, snssai, plmn, dnn, nrf_addr, nrf_port,
nrf_api_version))
return false;
return true;
}
//-----------------------------------------------------------------------------------------------------
bool amf_n11::discover_smf(
std::string& smf_addr, std::string& smf_api_version, const snssai_t snssai,
const plmn_t plmn, const std::string dnn) {
const plmn_t plmn, const std::string dnn, const std::string& nrf_addr,
const std::string& nrf_port, const std::string& nrf_api_version) {
Logger::amf_n11().debug(
"Send NFDiscovery to NRF to discover the available SMFs");
bool result = true;
......@@ -905,12 +1035,17 @@ bool amf_n11::discover_smf(
if (amf_cfg.support_features.use_http2) http_version = 2;
nlohmann::json json_data = {};
std::string url = {};
// TODO: remove hardcoded values
std::string url =
std::string(inet_ntoa(*((struct in_addr*) &amf_cfg.nrf_addr.ipv4_addr))) +
":" + std::to_string(amf_cfg.nrf_addr.port) + "/nnrf-disc/" +
amf_cfg.nrf_addr.api_version +
"/nf-instances?target-nf-type=SMF&requester-nf-type=AMF";
if (!nrf_addr.empty() & !nrf_port.empty() & !nrf_api_version.empty()) {
url = nrf_addr + ":" + nrf_port + "/nnrf-disc/" + nrf_api_version +
"/nf-instances?target-nf-type=SMF&requester-nf-type=AMF";
} else
url = std::string(
inet_ntoa(*((struct in_addr*) &amf_cfg.nrf_addr.ipv4_addr))) +
":" + std::to_string(amf_cfg.nrf_addr.port) + "/nnrf-disc/" +
amf_cfg.nrf_addr.api_version +
"/nf-instances?target-nf-type=SMF&requester-nf-type=AMF";
curl_global_init(CURL_GLOBAL_ALL);
CURL* curl = curl = curl_easy_init();
......
......@@ -39,6 +39,10 @@
#include "itti_msg_sbi.hpp"
#include "pdu_session_context.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
namespace amf_application {
class amf_n11 {
......@@ -76,11 +80,19 @@ class amf_n11 {
std::string remoteUri, std::string Method, std::string msgBody,
std::string& response, uint8_t http_version = 1);
bool discover_smf(
bool discover_smf_from_nsi_info(
std::string& smf_addr, std::string& smf_api_version,
const snssai_t snssai, const plmn_t plmn, const std::string dnn);
bool discover_smf(
std::string& smf_addr, std::string& smf_api_version,
const snssai_t snssai, const plmn_t plmn, const std::string dnn,
const std::string& nrf_addr = {}, const std::string& nrf_port = {},
const std::string& nrf_api_version = {});
void register_nf_instance(
std::shared_ptr<itti_n11_register_nf_instance_request> msg);
bool send_ue_authentication_request(
oai::amf::model::AuthenticationInfo& auth_info,
oai::amf::model::UEAuthenticationCtx& ue_auth_ctx, uint8_t http_version);
......
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