Commit 182acb4d authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

First version for N1 Message Notify Procedure

parent ef5b7fa4
......@@ -874,6 +874,13 @@ void amf_app::add_promise(
curl_handle_responses_n2_sm.emplace(id, p);
}
//---------------------------------------------------------------------------------------------
void amf_app::add_promise(
uint32_t pid, boost::shared_ptr<boost::promise<nlohmann::json>>& p) {
std::unique_lock lock(m_curl_handle_responses_n11);
curl_handle_responses_n11.emplace(pid, p);
}
//------------------------------------------------------------------------------
void amf_app::trigger_process_response(uint32_t pid, std::string n2_sm) {
Logger::amf_app().debug(
......@@ -887,3 +894,18 @@ void amf_app::trigger_process_response(uint32_t pid, std::string n2_sm) {
curl_handle_responses_n2_sm.erase(pid);
}
}
//------------------------------------------------------------------------------
void amf_app::trigger_process_response(
uint32_t pid, nlohmann::json& json_data) {
Logger::amf_app().debug(
"Trigger process response: Set promise with ID %u "
"to ready",
pid);
std::unique_lock lock(m_curl_handle_responses_n11);
if (curl_handle_responses_n11.count(pid) > 0) {
curl_handle_responses_n11[pid]->set_value(json_data);
// Remove this promise from list
curl_handle_responses_n11.erase(pid);
}
}
......@@ -37,6 +37,7 @@
#include "amf_module_from_config.hpp"
#include "amf_profile.hpp"
#include "itti.hpp"
#include "itti_msg_n11.hpp"
#include "itti_msg_amf_app.hpp"
#include "ue_context.hpp"
#include "amf_subscription.hpp"
......@@ -268,11 +269,13 @@ class amf_app {
return util::uint_uid_generator<uint64_t>::get_instance().get_uid();
}
void trigger_process_response(uint32_t pid, uint32_t http_code);
void add_promise(
uint32_t pid, boost::shared_ptr<boost::promise<std::string>>& p);
void add_promise(
uint32_t pid, boost::shared_ptr<boost::promise<nlohmann::json>>& p);
void trigger_process_response(uint32_t pid, uint32_t http_code);
void trigger_process_response(uint32_t pid, std::string n2_sm);
void trigger_process_response(uint32_t pid, nlohmann::json& json_data);
private:
std::map<long, std::shared_ptr<ue_context>> amf_ue_ngap_id2ue_ctx;
......@@ -286,6 +289,10 @@ class amf_app {
mutable std::shared_mutex m_curl_handle_responses_n2_sm;
std::map<uint32_t, boost::shared_ptr<boost::promise<std::string>>>
curl_handle_responses_n2_sm;
mutable std::shared_mutex m_curl_handle_responses_n11;
std::map<uint32_t, boost::shared_ptr<boost::promise<nlohmann::json>>>
curl_handle_responses_n11;
};
} // namespace amf_application
......
......@@ -192,6 +192,12 @@ typedef struct {
std::string fqdn;
} smf_inst_t;
typedef struct nf_addr_s {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} nf_addr_t;
class amf_config {
public:
amf_config();
......@@ -228,24 +234,35 @@ class amf_config {
bool use_fqdn_dns;
bool use_http2;
} support_features;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} nrf_addr;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} ausf_addr;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} nssf_addr;
/*
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} nrf_addr;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} ausf_addr;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} udm_addr;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
} nssf_addr;
*/
nf_addr_t nrf_addr;
nf_addr_t ausf_addr;
nf_addr_t udm_addr;
nf_addr_t nssf_addr;
};
} // namespace config
......
......@@ -3740,15 +3740,75 @@ bool amf_n1::check_requested_nssai(
//------------------------------------------------------------------------------
bool amf_n1::get_slice_selection_subscription_data(
const std::shared_ptr<nas_context>& nc, nssai_t& nssai) const {
const std::shared_ptr<nas_context>& nc, nssai_t& nssai) {
// TODO: UDM selection (from NRF or configuration file)
if (amf_cfg.support_features.enable_external_udm) {
std::shared_ptr<ue_context> uc = {};
if (!find_ue_context(
nc.get()->ran_ue_ngap_id, nc.get()->amf_ue_ngap_id, uc)) {
Logger::amf_n1().warn("Cannot find the UE context");
return false;
}
std::shared_ptr<itti_n11_slice_selection_subscription_data> itti_msg =
std::make_shared<itti_n11_slice_selection_subscription_data>(
TASK_AMF_N1, TASK_AMF_N11);
// Generate a promise and associate this promise to the ITTI message
uint32_t promise_id = amf_app_inst->generate_promise_id();
Logger::amf_n1().debug("Promise ID generated %d", promise_id);
boost::shared_ptr<boost::promise<nlohmann::json>> p =
boost::make_shared<boost::promise<nlohmann::json>>();
boost::shared_future<nlohmann::json> f = p->get_future();
amf_app_inst->add_promise(promise_id, p);
itti_msg->http_version = 1;
itti_msg->supi = uc.get()->supi;
itti_msg->plmn.mcc = uc.get()->cgi.mcc;
itti_msg->plmn.mnc = uc.get()->cgi.mnc;
itti_msg->promise_id = promise_id;
int ret = itti_inst->send_msg(itti_msg);
if (0 != ret) {
Logger::ngap().error(
"Could not send ITTI message %s to task TASK_AMF_N2",
itti_msg->get_msg_name());
}
bool result = false;
boost::future_status status;
// wait for timeout or ready
status = f.wait_for(boost::chrono::milliseconds(FUTURE_STATUS_TIMEOUT_MS));
if (status == boost::future_status::ready) {
assert(f.is_ready());
assert(f.has_value());
assert(!f.has_exception());
// Wait for the result from APP and send reply to AMF
nlohmann::json nssai = f.get();
if (!nssai.empty()) {
Logger::ngap().debug("Got NSSAI from UDM", nssai.dump().c_str());
} else {
return false;
}
} else {
return false;
}
} else {
// TODO: get from the conf file
return get_slice_selection_subscription_data_from_conf_file(nc, nssai);
}
return true;
}
//------------------------------------------------------------------------------
bool amf_n1::get_slice_selection_subscription_data_from_conf_file(
const std::shared_ptr<nas_context>& nc, nssai_t& nssai) {
// TODO:
return true;
}
//------------------------------------------------------------------------------
bool amf_n1::get_network_slice_selection(
const std::string& nf_instance_id,
......
......@@ -221,12 +221,14 @@ class amf_n1 {
bool reroute_registration_request(std::shared_ptr<nas_context>& nc);
bool get_slice_selection_subscription_data(
const std::shared_ptr<nas_context>& nc, nssai_t& nssai) const;
const std::shared_ptr<nas_context>& nc, nssai_t& nssai);
bool get_slice_selection_subscription_data_from_conf_file(
const std::shared_ptr<nas_context>& nc, nssai_t& nssai);
bool check_requested_nssai(
const std::shared_ptr<nas_context>& nc, const nssai_t& nssai) const;
bool get_network_slice_selection(
const std::string& nf_instance_id,
slice_info_fo_registration_t& slice_info,
slice_info_for_registration_t& slice_info,
authorized_network_slice_info_t& authorized_network_slice_info) const;
void send_n1_message_notity(
const std::shared_ptr<nas_context>& nc,
......
......@@ -137,6 +137,15 @@ void amf_n11_task(void*) {
dynamic_cast<itti_sbi_notify_subscribed_event*>(msg);
amf_n11_inst->handle_itti_message(ref(*m));
} break;
case N11_SLICE_SELECTION_SUBSCRIPTION_DATA: {
Logger::amf_n11().info(
"Receive Slice Selection Subscription Data Retrieval Request, "
"handling ...");
itti_n11_slice_selection_subscription_data* m =
dynamic_cast<itti_n11_slice_selection_subscription_data*>(msg);
amf_n11_inst->handle_itti_message(ref(*m));
} break;
case TERMINATE: {
if (itti_msg_terminate* terminate =
dynamic_cast<itti_msg_terminate*>(msg)) {
......@@ -570,6 +579,91 @@ void amf_n11::handle_itti_message(itti_sbi_notify_subscribed_event& itti_msg) {
return;
}
//------------------------------------------------------------------------------
void amf_n11::handle_itti_message(
itti_n11_slice_selection_subscription_data& itti_msg) {
Logger::amf_n11().debug(
"Send Slice Selection Subscription Data Retrieval to UDM (HTTP version "
"%d)",
itti_msg.http_version);
std::string url =
std::string(inet_ntoa(*((struct in_addr*) &amf_cfg.udm_addr.ipv4_addr))) +
":" + std::to_string(amf_cfg.udm_addr.port) + "/nudm-sdm/" +
amf_cfg.udm_addr.api_version + "/" + itti_msg.supi + "/nssai";
nlohmann::json json_data = {};
json_data["plmn-id"]["mcc"] = itti_msg.plmn.mcc;
json_data["plmn-id"]["mnc"] = itti_msg.plmn.mnc;
std::string body = json_data.dump();
Logger::amf_n11().debug(
"Send Slice Selection Subscription Data Retrieval to UDM, URL %s",
url.c_str());
Logger::amf_n11().debug("MSG body: \n %s", body.c_str());
curl_global_init(CURL_GLOBAL_ALL);
CURL* curl = curl = curl_easy_init();
std::unique_ptr<std::string> httpData(new std::string());
nlohmann::json response_data = {};
if (curl) {
CURLcode res = {};
struct curl_slist* headers = nullptr;
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 (itti_msg.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("Response from UDM, HTTP Code: %d", httpCode);
if (static_cast<http_response_codes_e>(httpCode) !=
http_response_codes_e::HTTP_RESPONSE_CODE_200_OK) {
try {
response_data = nlohmann::json::parse(*httpData.get());
} catch (nlohmann::json::exception& e) {
Logger::amf_n11().warn("Could not parse JSON from the UDM response");
}
} else {
Logger::amf_n11().warn("Could not get NSSAI from UDM");
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
// Notify to the result
if (itti_msg.promise_id > 0) {
amf_app_inst->trigger_process_response(itti_msg.promise_id, response_data);
return;
}
return;
}
//------------------------------------------------------------------------------
bool amf_n11::smf_selection_from_configuration(
std::string& smf_addr, std::string& smf_api_version) {
......
......@@ -59,6 +59,8 @@ class amf_n11 {
void handle_itti_message(itti_nsmf_pdusession_release_sm_context& itti_msg);
void handle_itti_message(itti_pdu_session_resource_setup_response& itti_msg);
void handle_itti_message(itti_sbi_notify_subscribed_event& itti_msg);
void handle_itti_message(
itti_n11_slice_selection_subscription_data& itti_msg);
void send_pdu_session_update_sm_context_request(
std::string supi, std::shared_ptr<pdu_session_context> psc,
......
......@@ -205,6 +205,7 @@ class itti_n11_slice_selection_subscription_data : public itti_msg_n11 {
uint8_t http_version;
std::string supi;
plmn_t plmn;
uint32_t promise_id;
};
#endif
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