Commit acfd9e62 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

N1 n2 message subscribe

parent 6228e61b
......@@ -45,6 +45,7 @@
#include "comUt.hpp"
#include "RegistrationContextContainer.h"
#include "GlobalRanNodeId.h"
#include "UeN1N2InfoSubscriptionCreatedData.h"
using namespace ngap;
using namespace nas;
......@@ -136,6 +137,20 @@ void amf_app_task(void*) {
amf_app_inst->handle_itti_message(ref(*m));
} break;
case SBI_N1N2_MESSAGE_SUBSCRIBE: {
Logger::amf_app().debug("Received SBI_N1N2_MESSAGE_SUBSCRIBE");
itti_sbi_n1n2_message_subscribe* m =
dynamic_cast<itti_sbi_n1n2_message_subscribe*>(msg);
amf_app_inst->handle_itti_message(ref(*m));
} break;
case SBI_N1N2_MESSAGE_UNSUBSCRIBE: {
Logger::amf_app().debug("Received SBI_N1N2_MESSAGE_UNSUBSCRIBE");
itti_sbi_n1n2_message_unsubscribe* m =
dynamic_cast<itti_sbi_n1n2_message_unsubscribe*>(msg);
amf_app_inst->handle_itti_message(ref(*m));
} break;
case TIME_OUT: {
if (itti_msg_timeout* to = dynamic_cast<itti_msg_timeout*>(msg)) {
switch (to->arg1_user) {
......@@ -272,6 +287,11 @@ evsub_id_t amf_app::generate_ev_subscription_id() {
return evsub_id_generator.get_uid();
}
//------------------------------------------------------------------------------
n1n2sub_id_t amf_app::generate_n1n2_message_subscription_id() {
return n1n2sub_id_generator.get_uid();
}
//------------------------------------------------------------------------------
void amf_app::handle_itti_message(
itti_n1n2_message_transfer_request& itti_msg) {
......@@ -612,6 +632,110 @@ void amf_app::handle_itti_message(itti_sbi_n1_message_notification& itti_msg) {
return;
}
//------------------------------------------------------------------------------
void amf_app::handle_itti_message(itti_sbi_n1n2_message_subscribe& itti_msg) {
Logger::amf_app().info(
"Handle an N1N2MessageSubscribe from a NF (HTTP version "
"%d)",
itti_msg.http_version);
// Generate a subscription ID Id and store the corresponding information in a
// map (subscription id, info)
n1n2sub_id_t n1n2sub_id = generate_n1n2_message_subscription_id();
std::shared_ptr<oai::amf::model::UeN1N2InfoSubscriptionCreateData>
subscription_data =
std::make_shared<oai::amf::model::UeN1N2InfoSubscriptionCreateData>(
itti_msg.subscription_data);
add_n1n2_message_subscription(
itti_msg.ue_cxt_id, n1n2sub_id, subscription_data);
std::string location =
amf_cfg.get_amf_n1n2_message_subscribe_uri(itti_msg.ue_cxt_id) + "/" +
std::to_string((uint32_t) n1n2sub_id);
// Trigger the response from AMF API Server
oai::amf::model::UeN1N2InfoSubscriptionCreatedData created_data = {};
created_data.setN1n2NotifySubscriptionId(
std::to_string((uint32_t) n1n2sub_id));
nlohmann::json created_data_json = {};
to_json(created_data_json, created_data);
nlohmann::json response_data = {};
response_data["createdData"] = created_data;
response_data["httpResponseCode"] = 201; // TODO:
response_data["location"] = location;
// Notify to the result
if (itti_msg.promise_id > 0) {
trigger_process_response(itti_msg.promise_id, response_data);
return;
}
}
//------------------------------------------------------------------------------
void amf_app::handle_itti_message(itti_sbi_n1n2_message_unsubscribe& itti_msg) {
Logger::amf_app().info(
"Handle an N1N2MessageUnSubscribe from a NF (HTTP version "
"%d)",
itti_msg.http_version);
// Process the request and trigger the response from AMF API Server
nlohmann::json response_data = {};
if (remove_n1n2_message_subscription(
itti_msg.ue_cxt_id, itti_msg.subscription_id)) {
response_data["httpResponseCode"] = 204; // TODO:
} else {
response_data["httpResponseCode"] = 400; // TODO:
oai::amf::model::ProblemDetails problem_details = {};
// TODO set problem_details
to_json(response_data["ProblemDetails"], problem_details);
}
// Notify to the result
if (itti_msg.promise_id > 0) {
trigger_process_response(itti_msg.promise_id, response_data);
return;
}
}
//---------------------------------------------------------------------------------------------
void amf_app::add_n1n2_message_subscription(
const std::string& ue_ctx_id, const n1n2sub_id_t& sub_id,
std::shared_ptr<oai::amf::model::UeN1N2InfoSubscriptionCreateData>&
subscription_data) {
Logger::amf_app().debug("Add an N1N2 Message Subscribe (Sub ID %d)", sub_id);
std::unique_lock lock(m_n1n2_message_subscribe);
n1n2_message_subscribe.emplace(
std::make_pair(ue_ctx_id, sub_id), subscription_data);
}
//---------------------------------------------------------------------------------------------
bool amf_app::remove_n1n2_message_subscription(
const std::string& ue_ctx_id, const std::string& sub_id) {
Logger::amf_app().debug(
"Remove an N1N2 Message Subscribe (UE Context ID %s, Sub ID %s)",
ue_ctx_id.c_str(), sub_id.c_str());
// Verify Subscription ID
n1n2sub_id_t n1n2sub_id = {};
try {
n1n2sub_id = std::stoi(sub_id);
} catch (const std::exception& err) {
Logger::amf_app().warn(
"Received a Unsubscribe Request, couldn't find the corresponding "
"subscription");
return false;
}
// Remove from the list
std::unique_lock lock(m_n1n2_message_subscribe);
if (n1n2_message_subscribe.erase(std::make_pair(ue_ctx_id, n1n2sub_id)) == 1)
return true;
else
return false;
return true;
}
//------------------------------------------------------------------------------
uint32_t amf_app::generate_tmsi() {
return tmsi_generator.get_uid();
......@@ -672,6 +796,7 @@ evsub_id_t amf_app::handle_event_exposure_subscription(
return evsub_id;
}
//---------------------------------------------------------------------------------------------
bool amf_app::handle_event_exposure_delete(const std::string& subscription_id) {
// verify Subscription ID
evsub_id_t sub_id = {};
......@@ -873,11 +998,13 @@ void amf_app::trigger_nf_deregistration() const {
}
}
//---------------------------------------------------------------------------------------------
void amf_app::add_promise(
const uint32_t pid, const boost::shared_ptr<boost::promise<uint32_t>>& p) {
std::unique_lock lock(m_curl_handle_responses_smf);
curl_handle_responses_smf.emplace(pid, p);
}
//---------------------------------------------------------------------------------------------
void amf_app::add_promise(
const uint32_t id,
......@@ -894,6 +1021,7 @@ void amf_app::add_promise(
curl_handle_responses_n11.emplace(pid, p);
}
//---------------------------------------------------------------------------------------------
void amf_app::trigger_process_response(
const uint32_t pid, const uint32_t http_code) {
Logger::amf_app().debug(
......@@ -907,6 +1035,7 @@ void amf_app::trigger_process_response(
curl_handle_responses_smf.erase(pid);
}
}
//------------------------------------------------------------------------------
void amf_app::trigger_process_response(
const uint32_t pid, const std::string& n2_sm) {
......
......@@ -44,6 +44,7 @@
#include "itti_msg_sbi.hpp"
#include "amf_msg.hpp"
#include "ProblemDetails.h"
#include "UeN1N2InfoSubscriptionCreateData.h"
#include "uint_generator.hpp"
#include <boost/thread.hpp>
......@@ -95,6 +96,14 @@ class amf_app {
std::map<uint32_t, boost::shared_ptr<boost::promise<nlohmann::json>>>
curl_handle_responses_n11;
util::uint_generator<uint32_t> n1n2sub_id_generator;
std::map<
std::pair<std::string, uint32_t>,
std::shared_ptr<oai::amf::model::UeN1N2InfoSubscriptionCreateData>>
n1n2_message_subscribe;
mutable std::shared_mutex m_n1n2_message_subscribe;
public:
explicit amf_app(const amf_config& amf_cfg);
amf_app(amf_app const&) = delete;
......@@ -129,6 +138,20 @@ class amf_app {
*/
void handle_itti_message(itti_sbi_n1_message_notification& itti_msg);
/*
* Handle ITTI message (SBI N1N2 Message Subscribe)
* @param [itti_sbi_n1n2_subscribe_message&]: ITTI message
* @return void
*/
void handle_itti_message(itti_sbi_n1n2_message_subscribe& itti_msg);
/*
* Handle ITTI message (SBI N1N2 Message UnSubscribe)
* @param [itti_sbi_n1n2_unsubscribe_message&]: ITTI message
* @return void
*/
void handle_itti_message(itti_sbi_n1n2_message_unsubscribe& itti_msg);
/*
* Verify if a UE context associated with an AMF UE NGAP ID exist
* @param [const long&] amf_ue_ngap_id: AMF UE NGAP ID
......@@ -260,6 +283,37 @@ class amf_app {
*/
evsub_id_t generate_ev_subscription_id();
/*
* Generate an N1N2MessageSubscribe ID
* @param [void]
* @return the generated reference
*/
n1n2sub_id_t generate_n1n2_message_subscription_id();
/*
* Add an N1N2MessageSubscribe subscription to the list
* @param [const std::string&] ue_ctx_id: UE Context ID
* @param [const n1n2sub_id_t&] sub_id: Subscription ID
* @param [std::shared_ptr<oai::amf::model::UeN1N2InfoSubscriptionCreateData>]
* oai::amf::model::UeN1N2InfoSubscriptionCreateData: a shared pointer stored
* information of the subscription
* @return void
*/
void add_n1n2_message_subscription(
const std::string& ue_ctx_id, const n1n2sub_id_t& sub_id,
std::shared_ptr<oai::amf::model::UeN1N2InfoSubscriptionCreateData>&
subscription);
/*
* Remove an N1N2MessageSubscribe subscription from the list
* @param [const std::string&] ue_ctx_id: UE Context ID
* @param [const std::string&] sub_id: Subscription ID
* @return true if the subscription is deleted successfully, otherwise return
* false
*/
bool remove_n1n2_message_subscription(
const std::string& ue_ctx_id, const std::string& sub_id);
/*
* Trigger NF instance registration to NRF
* @param [void]
......
......@@ -856,6 +856,20 @@ int amf_config::load_interface(
return RETURNok;
}
//------------------------------------------------------------------------------
std::string amf_config::get_amf_n1n2_message_subscribe_uri(
const std::string& ue_cxt_id) {
unsigned int sbi_port = 80;
if (support_features.use_http2) {
sbi_port = sbi_http2_port;
} else {
sbi_port = n11.port;
}
return std::string(inet_ntoa(*((struct in_addr*) &n11.addr4))) + ":" +
std::to_string(sbi_port) + NAMF_COMMUNICATION_BASE + sbi_api_version +
"/ue-contexts/" + ue_cxt_id + "/n1-n2-messages/subscriptions";
}
//------------------------------------------------------------------------------
std::string amf_config::get_nrf_nf_discovery_service_uri() {
return std::string(inet_ntoa(*((struct in_addr*) &nrf_addr.ipv4_addr))) +
......
......@@ -219,6 +219,13 @@ class amf_config {
*/
int load_interface(const Setting& if_cfg, interface_cfg_t& cfg);
/*
* Get the URI of AMF N1N2MessageSubscribe
* @param [const std::string&] ue_cxt_id: UE Context Id
* @return URI in string format
*/
std::string get_amf_n1n2_message_subscribe_uri(const std::string& ue_cxt_id);
/*
* Get the URI of NRF NF Discovery Service
* @param void
......
......@@ -55,6 +55,8 @@ typedef uint32_t evsub_id_t;
#define INVALID_EVSUB_ID ((evsub_id_t) 0x00000000)
#define UNASSIGNED_EVSUB_ID ((evsub_id_t) 0x00000000)
typedef uint32_t n1n2sub_id_t;
constexpr uint64_t SECONDS_SINCE_FIRST_EPOCH = 2208988800;
#define UE_AGGREGATE_MAXIMUM_BIT_RATE_DL 300000000
......
......@@ -98,6 +98,8 @@ typedef enum {
SBI_NOTIFICATION_DATA,
SBI_NOTIFY_SUBSCRIBED_EVENT,
SBI_N1_MESSAGE_NOTIFICATION,
SBI_N1N2_MESSAGE_SUBSCRIBE,
SBI_N1N2_MESSAGE_UNSUBSCRIBE,
HANDOVER_REQUIRED,
HANDOVER_REQUEST_ACK,
HANDOVER_NOTIFY,
......
......@@ -34,7 +34,9 @@
#include "pistache/http.h"
#include "amf_msg.hpp"
#include "N1MessageNotification.h"
#include "UeN1N2InfoSubscriptionCreateData.h"
// using namespace oai::amf::model;
using namespace amf_application;
class itti_sbi_msg : public itti_msg {
......@@ -147,4 +149,65 @@ class itti_sbi_n1_message_notification : public itti_sbi_msg {
uint8_t http_version;
};
//-----------------------------------------------------------------------------
class itti_sbi_n1n2_message_subscribe : public itti_sbi_msg {
public:
itti_sbi_n1n2_message_subscribe(
const task_id_t orig, const task_id_t dest, uint32_t pid)
: itti_sbi_msg(SBI_N1N2_MESSAGE_SUBSCRIBE, orig, dest),
ue_cxt_id(),
subscription_data(),
http_version(1),
promise_id(pid) {}
itti_sbi_n1n2_message_subscribe(const itti_sbi_n1n2_message_subscribe& i)
: itti_sbi_msg(i),
ue_cxt_id(i.ue_cxt_id),
subscription_data(i.subscription_data),
http_version(1),
promise_id() {}
itti_sbi_n1n2_message_subscribe(
const itti_sbi_n1n2_message_subscribe& i, const task_id_t orig,
const task_id_t dest)
: itti_sbi_msg(i, orig, dest),
ue_cxt_id(i.ue_cxt_id),
subscription_data(i.subscription_data),
http_version(i.http_version),
promise_id(i.promise_id) {}
const char* get_msg_name() { return "SBI_N1N2_MESSAGE_SUBSCRIBE"; };
std::string ue_cxt_id;
oai::amf::model::UeN1N2InfoSubscriptionCreateData subscription_data;
uint8_t http_version;
uint32_t promise_id;
};
//-----------------------------------------------------------------------------
class itti_sbi_n1n2_message_unsubscribe : public itti_sbi_msg {
public:
itti_sbi_n1n2_message_unsubscribe(
const task_id_t orig, const task_id_t dest, uint32_t pid)
: itti_sbi_msg(SBI_N1N2_MESSAGE_SUBSCRIBE, orig, dest),
ue_cxt_id(),
subscription_id(),
http_version(1),
promise_id(pid) {}
itti_sbi_n1n2_message_unsubscribe(const itti_sbi_n1n2_message_unsubscribe& i)
: itti_sbi_msg(i),
ue_cxt_id(i.ue_cxt_id),
subscription_id(i.subscription_id),
http_version(1),
promise_id() {}
itti_sbi_n1n2_message_unsubscribe(
const itti_sbi_n1n2_message_unsubscribe& i, const task_id_t orig,
const task_id_t dest)
: itti_sbi_msg(i, orig, dest),
ue_cxt_id(i.ue_cxt_id),
subscription_id(i.subscription_id),
http_version(i.http_version),
promise_id(i.promise_id) {}
const char* get_msg_name() { return "SBI_N1N2_MESSAGE_UNSUBSCRIBE"; };
std::string ue_cxt_id;
std::string subscription_id;
uint8_t http_version;
uint32_t promise_id;
};
#endif /* ITTI_MSG_SBI_HPP_INCLUDED_ */
......@@ -27,6 +27,7 @@
#include <nlohmann/json.hpp>
#include "ProblemDetails.h"
#include "amf.hpp"
#include <string>
namespace oai {
......@@ -40,7 +41,7 @@ class N1N2IndividualSubscriptionDocumentApi {
virtual ~N1N2IndividualSubscriptionDocumentApi() {}
void init();
const std::string base = "/namf-comm/";
const std::string base = NAMF_COMMUNICATION_BASE;
private:
void setupRoutes();
......
......@@ -27,6 +27,8 @@
#include "ProblemDetails.h"
#include "UeN1N2InfoSubscriptionCreateData.h"
#include "UeN1N2InfoSubscriptionCreatedData.h"
#include "amf.hpp"
#include <string>
namespace oai {
......@@ -42,7 +44,7 @@ class N1N2SubscriptionsCollectionForIndividualUEContextsDocumentApi {
virtual ~N1N2SubscriptionsCollectionForIndividualUEContextsDocumentApi() {}
void init();
const std::string base = "/namf-comm/";
const std::string base = NAMF_COMMUNICATION_BASE;
private:
void setupRoutes();
......
......@@ -13,6 +13,7 @@
#include "N1N2IndividualSubscriptionDocumentApiImpl.h"
extern itti_mw* itti_inst;
namespace oai {
namespace amf {
namespace api {
......@@ -26,10 +27,71 @@ N1N2IndividualSubscriptionDocumentApiImpl::
void N1N2IndividualSubscriptionDocumentApiImpl::n1_n2_message_un_subscribe(
const std::string& ueContextId, const std::string& subscriptionId,
Pistache::Http::ResponseWriter& response) {
response.send(
Pistache::Http::Code::Ok,
"N1N2IndividualSubscriptionDocumentApiImpl::n1_n2_message_un_subscribe "
"API has not been implemented yet!\n");
Logger::amf_server().debug("Receive N1N2MessageUnsubscribe, handling...");
Logger::amf_server().debug(
"UE Context ID %s, Subscription ID %s", ueContextId.c_str(),
subscriptionId.c_str());
// Generate a promise and associate this promise to the ITTI message
uint32_t promise_id = m_amf_app->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();
m_amf_app->add_promise(promise_id, p);
// Handle the N1N2UnsubscribeMessage in amf_app
std::shared_ptr<itti_sbi_n1n2_message_unsubscribe> itti_msg =
std::make_shared<itti_sbi_n1n2_message_unsubscribe>(
TASK_AMF_SBI, TASK_AMF_APP, promise_id);
itti_msg->ue_cxt_id = ueContextId;
itti_msg->subscription_id = subscriptionId;
itti_msg->http_version = 1;
itti_msg->promise_id = promise_id;
int ret = itti_inst->send_msg(itti_msg);
if (0 != ret) {
Logger::amf_server().error(
"Could not send ITTI message %s to task TASK_AMF_APP",
itti_msg->get_msg_name());
}
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
// result includes location, UeN1N2InfoSubscriptionCreatedData, and http
// response code
nlohmann::json result = f.get();
Logger::amf_server().debug("Got result for promise ID %d", promise_id);
// process data
uint32_t http_response_code = 0;
if (result.find("httpResponseCode") != result.end()) {
http_response_code = result["httpResponseCode"].get<int>();
}
if (http_response_code == 204) {
response.send(Pistache::Http::Code::No_Content);
} else {
// Problem//details
nlohmann::json json_data = {};
if (result.find("ProblemDetails") != result.end()) {
json_data = result["ProblemDetails"];
}
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType("application/problem+json"));
response.send(
Pistache::Http::Code(http_response_code), json_data.dump().c_str());
}
}
}
} // namespace api
......
......@@ -12,7 +12,9 @@
*/
#include "N1N2SubscriptionsCollectionForIndividualUEContextsDocumentApiImpl.h"
#include "itti.hpp"
extern itti_mw* itti_inst;
namespace oai {
namespace amf {
namespace api {
......@@ -32,10 +34,75 @@ void N1N2SubscriptionsCollectionForIndividualUEContextsDocumentApiImpl::
const UeN1N2InfoSubscriptionCreateData&
ueN1N2InfoSubscriptionCreateData,
Pistache::Http::ResponseWriter& response) {
response.send(
Pistache::Http::Code::Ok,
"N1N2SubscriptionsCollectionForIndividualUEContextsDocumentApiImpl::n1_"
"n2_message_subscribe API has not been implemented yet!\n");
Logger::amf_server().debug("Receive N1N2MessageSubscribe, handling...");
Logger::amf_server().debug("UE Context ID (%s)", ueContextId.c_str());
// Generate a promise and associate this promise to the ITTI message
uint32_t promise_id = m_amf_app->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();
m_amf_app->add_promise(promise_id, p);
// Handle the N1N2SubscribeMessage in amf_app
std::shared_ptr<itti_sbi_n1n2_message_subscribe> itti_msg =
std::make_shared<itti_sbi_n1n2_message_subscribe>(
TASK_AMF_SBI, TASK_AMF_APP, promise_id);
itti_msg->ue_cxt_id = ueContextId;
itti_msg->subscription_data = ueN1N2InfoSubscriptionCreateData;
itti_msg->http_version = 1;
itti_msg->promise_id = promise_id;
int ret = itti_inst->send_msg(itti_msg);
if (0 != ret) {
Logger::amf_server().error(
"Could not send ITTI message %s to task TASK_AMF_APP",
itti_msg->get_msg_name());
}
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
// result includes location, UeN1N2InfoSubscriptionCreatedData, and http
// response code
nlohmann::json result = f.get();
Logger::amf_server().debug("Got result for promise ID %d", promise_id);
// process data
std::string location = {};
uint32_t http_response_code = 0;
if (result.find("location") != result.end()) {
location = result["location"].get<std::string>();
}
if (result.find("httpResponseCode") != result.end()) {
http_response_code = result["httpResponseCode"].get<int>();
}
// UeN1N2InfoSubscriptionCreatedData
nlohmann::json json_data = {};
if (result.find("createdData") != result.end()) {
json_data = result["createdData"];
}
if (http_response_code == 201) { // TODO:
response.headers().add<Pistache::Http::Header::Location>(
location); // Location header
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType("application/json"));
response.send(Pistache::Http::Code::Created, json_data.dump().c_str());
} else {
response.send(Pistache::Http::Code(http_response_code));
}
}
}
} // namespace api
......
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