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

Merge branch 'custom_api_configuration' into 'develop'

Custom api configuration

See merge request oai/cn5g/oai-cn5g-amf!125
parents 592b3719 26742b0a
......@@ -151,6 +151,13 @@ void amf_app_task(void*) {
amf_app_inst->handle_itti_message(ref(*m));
} break;
case SBI_AMF_CONFIGURATION: {
Logger::amf_app().debug("Received N11_AMF_CONFIGURATION");
itti_sbi_amf_configuration* m =
dynamic_cast<itti_sbi_amf_configuration*>(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) {
......@@ -698,6 +705,40 @@ void amf_app::handle_itti_message(itti_sbi_n1n2_message_unsubscribe& itti_msg) {
}
}
//------------------------------------------------------------------------------
void amf_app::handle_itti_message(itti_sbi_amf_configuration& itti_msg) {
Logger::amf_app().info(
"Handle an SBIAMFConfiguration 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 = {};
response_data["content"] = {};
if (read_amf_configuration(response_data["content"])) {
Logger::amf_app().debug(
"AMF configuration:\n %s", response_data["content"].dump().c_str());
response_data["httpResponseCode"] = 200; // 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;
}
}
//---------------------------------------------------------------------------------------------
bool amf_app::read_amf_configuration(nlohmann::json& json_data) {
amf_cfg.to_json(json_data);
return true;
}
//---------------------------------------------------------------------------------------------
void amf_app::add_n1n2_message_subscription(
const std::string& ue_ctx_id, const n1n2sub_id_t& sub_id,
......
......@@ -152,6 +152,15 @@ class amf_app {
*/
void handle_itti_message(itti_sbi_n1n2_message_unsubscribe& itti_msg);
/*
* Handle ITTI message (SBI AMF configuration)
* @param [itti_sbi_amf_configuration&]: ITTI message
* @return void
*/
void handle_itti_message(itti_sbi_amf_configuration& itti_msg);
bool read_amf_configuration(nlohmann::json& json_data);
/*
* Verify if a UE context associated with an AMF UE NGAP ID exist
* @param [const long&] amf_ue_ngap_id: AMF UE NGAP ID
......
......@@ -812,6 +812,12 @@ void amf_config::display() {
Logger::config().info(
" Use HTTP2..............: %s",
support_features.use_http2 ? "Yes" : "No");
// SHOULD BE REMOVED
nlohmann::json json_data = {};
to_json(json_data);
Logger::config().info(
" JSON..............:\n %s", json_data.dump().c_str());
}
//------------------------------------------------------------------------------
......@@ -911,4 +917,52 @@ std::string amf_config::get_ausf_ue_authentications_uri() {
ausf_addr.api_version + "/ue-authentications";
}
//------------------------------------------------------------------------------
void amf_config::to_json(nlohmann::json& json_data) const {
json_data["instance"] = instance;
json_data["pid_dir"] = pid_dir;
json_data["amf_name"] = AMF_Name; // TODO: amf_name
json_data["guami"] = guami.to_json();
json_data["guami_list"] = nlohmann::json::array();
for (auto s : guami_list) {
json_data["guami_list"].push_back(s.to_json());
}
json_data["relativeAMFCapacity"] = relativeAMFCapacity;
json_data["plmn_list"] = nlohmann::json::array();
for (auto s : plmn_list) {
json_data["plmn_list"].push_back(s.to_json());
}
json_data["is_emergency_support"] = is_emergency_support;
json_data["auth_para"] = auth_para.to_json();
json_data["n2"] = n2.to_json();
json_data["n11"] = n11.to_json();
json_data["n11"]["sbi_http2_port"] = sbi_http2_port;
json_data["support_features"] = support_features.to_json();
if (support_features.enable_external_nrf) {
json_data["nrf"] = nrf_addr.to_json();
}
if (support_features.enable_external_nssf) {
json_data["nrf"] = nssf_addr.to_json();
}
if (support_features.enable_external_ausf) {
json_data["nrf"] = ausf_addr.to_json();
}
if (support_features.enable_external_udm) {
json_data["nrf"] = udm_addr.to_json();
}
json_data["smf_pool"] = nlohmann::json::array();
for (auto s : smf_pool) {
json_data["smf_pool"].push_back(s.to_json());
}
}
} // namespace config
......@@ -34,6 +34,7 @@
#include <sys/socket.h>
#include <libconfig.h++>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
......@@ -124,6 +125,15 @@ typedef struct {
std::string mysql_pass;
std::string mysql_db;
std::string random;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["mysql_server"] = mysql_server;
json_data["mysql_user"] = mysql_user;
json_data["mysql_pass"] = mysql_pass;
json_data["mysql_db"] = mysql_db;
json_data["random"] = random;
return json_data;
}
} auth_conf;
typedef struct interface_cfg_s {
......@@ -133,6 +143,20 @@ typedef struct interface_cfg_s {
struct in6_addr addr6;
unsigned int mtu;
unsigned int port;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["if_name"] = this->if_name;
json_data["addr4"] = inet_ntoa(this->addr4);
json_data["network4"] = inet_ntoa(this->network4);
char str_addr6[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &this->addr6, str_addr6, sizeof(str_addr6));
json_data["addr6"] = str_addr6;
json_data["mtu"] = this->mtu;
json_data["port"] = this->port;
return json_data;
}
} interface_cfg_t;
typedef struct itti_cfg_s {
......@@ -149,6 +173,16 @@ typedef struct guami_s {
std::string regionID;
std::string AmfSetID;
std::string AmfPointer;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["mcc"] = mcc;
json_data["mnc"] = mnc;
json_data["regionID"] = regionID;
json_data["AmfSetID"] = AmfSetID;
json_data["AmfPointer"] = AmfPointer;
return json_data;
}
} guami_t;
typedef struct slice_s {
......@@ -168,6 +202,13 @@ typedef struct slice_s {
if (this->sd <= s.sd) return false;
}
}
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["sst"] = sst;
json_data["sd"] = sd;
return json_data;
}
} slice_t;
typedef struct plmn_support_item_s {
......@@ -175,11 +216,36 @@ typedef struct plmn_support_item_s {
std::string mnc;
uint32_t tac;
std::vector<slice_t> slice_list;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["mcc"] = this->mcc;
json_data["mnc"] = mnc;
json_data["tac"] = tac;
json_data["slice_list"] = nlohmann::json::array();
for (auto s : slice_list) {
json_data["slice_list"].push_back(s.to_json());
}
return json_data;
}
} plmn_item_t;
typedef struct {
uint8_t prefered_integrity_algorithm[8];
uint8_t prefered_ciphering_algorithm[8];
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["prefered_integrity_algorithm"] = nlohmann::json::array();
json_data["prefered_ciphering_algorithm"] = nlohmann::json::array();
for (auto s : prefered_integrity_algorithm) {
json_data["prefered_integrity_algorithm"].push_back(s);
}
for (auto s : prefered_ciphering_algorithm) {
json_data["prefered_ciphering_algorithm"].push_back(s);
}
return json_data;
}
} nas_conf_t;
typedef struct {
......@@ -190,12 +256,33 @@ typedef struct {
std::string version;
bool selected;
std::string fqdn;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["id"] = this->id;
json_data["ipv4"] = this->ipv4;
json_data["port"] = this->port;
json_data["http2_port"] = this->http2_port;
json_data["version"] = this->version;
json_data["selected"] = this->selected;
json_data["fqdn"] = this->fqdn;
return json_data;
}
} smf_inst_t;
typedef struct nf_addr_s {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["ipv4_addr"] = inet_ntoa(this->ipv4_addr);
json_data["port"] = this->port;
json_data["api_version"] = this->api_version;
return json_data;
}
} nf_addr_t;
class amf_config {
......@@ -268,6 +355,13 @@ class amf_config {
*/
void display();
/*
* Represent AMF's config as json object
* @param [nlohmann::json &] json_data: Json data
* @return void
*/
void to_json(nlohmann::json& json_data) const;
unsigned int instance;
std::string pid_dir;
interface_cfg_t n2;
......@@ -297,6 +391,19 @@ class amf_config {
bool enable_external_nssf;
bool use_fqdn_dns;
bool use_http2;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["enable_nf_registration"] = this->enable_nf_registration;
json_data["enable_nrf_selection"] = this->enable_nrf_selection;
json_data["enable_external_nrf"] = this->enable_external_nrf;
json_data["enable_smf_selection"] = this->enable_smf_selection;
json_data["enable_external_ausf"] = this->enable_external_ausf;
json_data["enable_external_udm"] = this->enable_external_udm;
json_data["enable_external_nssf"] = this->enable_external_nssf;
json_data["use_fqdn_dns"] = this->use_fqdn_dns;
json_data["use_http2"] = this->use_http2;
return json_data;
}
} support_features;
nf_addr_t nrf_addr;
......
......@@ -94,6 +94,7 @@ typedef enum {
N11_NETWORK_SLICE_SELECTION_INFORMATION,
N11_NF_INSTANCE_DISCOVERY,
N11_N1_MESSAGE_NOTIFY,
SBI_AMF_CONFIGURATION,
SBI_EVENT_EXPOSURE_REQUEST,
SBI_NOTIFICATION_DATA,
SBI_NOTIFY_SUBSCRIBED_EVENT,
......
......@@ -210,4 +210,19 @@ class itti_sbi_n1n2_message_unsubscribe : public itti_sbi_msg {
uint8_t http_version;
uint32_t promise_id;
};
//-----------------------------------------------------------------------------
class itti_sbi_amf_configuration : public itti_sbi_msg {
public:
itti_sbi_amf_configuration(
const task_id_t orig, const task_id_t dest, uint32_t pid)
: itti_sbi_msg(SBI_AMF_CONFIGURATION, orig, dest),
http_version(1),
promise_id(pid) {}
const char* get_msg_name() { return "SBI_AMF_CONFIGURATION"; };
uint8_t http_version;
uint32_t promise_id;
};
#endif /* ITTI_MSG_SBI_HPP_INCLUDED_ */
......@@ -8,6 +8,8 @@ void AMFApiServer::init(size_t thr) {
opts.flags(Pistache::Tcp::Options::ReuseAddr);
opts.maxRequestSize(PISTACHE_SERVER_MAX_PAYLOAD);
m_httpEndpoint->init(opts);
m_aMFConfigurationApiImpl->init();
m_individualSubscriptionDocumentApiImpl->init();
m_individualSubscriptionDocumentApiImplEventExposure->init();
m_individualUeContextDocumentApiImpl->init();
......@@ -24,6 +26,9 @@ void AMFApiServer::init(size_t thr) {
}
void AMFApiServer::start() {
if (m_aMFConfigurationApiImpl != nullptr)
Logger::amf_server().debug("AMF handler for AMFConfigurationApiImpl");
if (m_individualSubscriptionDocumentApiImpl != nullptr)
Logger::amf_server().debug(
"AMF handler for IndividualSubscriptionDocumentApiImpl");
......
......@@ -7,6 +7,7 @@
#include <unistd.h>
#endif
#include "AMFConfigurationApiImpl.h"
#include "IndividualSubscriptionDocumentApiImpl.h"
#include "IndividualSubscriptionDocumentApiImplEventExposure.h"
#include "IndividualUeContextDocumentApiImpl.h"
......@@ -34,6 +35,9 @@ class AMFApiServer {
: m_httpEndpoint(std::make_shared<Pistache::Http::Endpoint>(address)) {
m_router = std::make_shared<Pistache::Rest::Router>();
m_address = address.host() + ":" + (address.port()).toString();
m_aMFConfigurationApiImpl =
std::make_shared<AMFConfigurationApiImpl>(m_router, amf_app_inst);
m_individualSubscriptionDocumentApiImpl =
std::make_shared<IndividualSubscriptionDocumentApiImpl>(
m_router, amf_app_inst);
......@@ -80,6 +84,8 @@ class AMFApiServer {
private:
std::shared_ptr<Pistache::Http::Endpoint> m_httpEndpoint;
std::shared_ptr<Pistache::Rest::Router> m_router;
std::shared_ptr<AMFConfigurationApiImpl> m_aMFConfigurationApiImpl;
std::shared_ptr<IndividualSubscriptionDocumentApiImpl>
m_individualSubscriptionDocumentApiImpl;
std::shared_ptr<IndividualSubscriptionDocumentApiImplEventExposure>
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "AMFConfigurationApi.h"
#include "Helpers.h"
#include "amf_config.hpp"
extern config::amf_config amf_cfg;
namespace oai::amf::api {
using namespace oai::amf::helpers;
AMFConfigurationApi::AMFConfigurationApi(
std::shared_ptr<Pistache::Rest::Router> rtr) {
router = rtr;
}
void AMFConfigurationApi::init() {
setupRoutes();
}
void AMFConfigurationApi::setupRoutes() {
using namespace Pistache::Rest;
Routes::Get(
*router, base + amf_cfg.sbi_api_version + "/configuration/",
Routes::bind(&AMFConfigurationApi::read_configuration_handler, this));
// Default handler, called when a route is not found
router->addCustomHandler(Routes::bind(
&AMFConfigurationApi::configuration_api_default_handler, this));
}
void AMFConfigurationApi::read_configuration_handler(
const Pistache::Rest::Request& request,
Pistache::Http::ResponseWriter response) {
try {
this->read_configuration(response);
} catch (nlohmann::detail::exception& e) {
// send a 400 error
response.send(Pistache::Http::Code::Bad_Request, e.what());
return;
} catch (Pistache::Http::HttpError& e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception& e) {
// send a 500 error
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
return;
}
}
void AMFConfigurationApi::configuration_api_default_handler(
const Pistache::Rest::Request&, Pistache::Http::ResponseWriter response) {
response.send(
Pistache::Http::Code::Not_Found, "The requested method does not exist");
}
} // namespace oai::amf::api
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef AMFConfigurationApi_H_
#define AMFConfigurationApi_H_
#include <pistache/http.h>
#include <pistache/http_headers.h>
#include <pistache/optional.h>
#include <pistache/router.h>
namespace oai::amf::api {
class AMFConfigurationApi {
public:
AMFConfigurationApi(std::shared_ptr<Pistache::Rest::Router>);
virtual ~AMFConfigurationApi() {}
void init();
const std::string base = "/namf-oai/";
private:
void setupRoutes();
void read_configuration_handler(
const Pistache::Rest::Request& request,
Pistache::Http::ResponseWriter response);
void configuration_api_default_handler(
const Pistache::Rest::Request& request,
Pistache::Http::ResponseWriter response);
std::shared_ptr<Pistache::Rest::Router> router;
virtual void read_configuration(Pistache::Http::ResponseWriter& response) = 0;
};
} // namespace oai::amf::api
#endif
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include <AMFConfigurationApiImpl.h>
#include "logger.hpp"
extern itti_mw* itti_inst;
namespace oai::amf::api {
using namespace oai::amf::model;
AMFConfigurationApiImpl::AMFConfigurationApiImpl(
std::shared_ptr<Pistache::Rest::Router> rtr, amf_app* amf_app_inst)
: AMFConfigurationApi(rtr), m_amf_app(amf_app_inst) {}
void AMFConfigurationApiImpl::read_configuration(
Pistache::Http::ResponseWriter& response) {
Logger::amf_server().debug("Receive AMFConfiguration, handling...");
// 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 AMFConfiguration in amf_app
std::shared_ptr<itti_sbi_amf_configuration> itti_msg =
std::make_shared<itti_sbi_amf_configuration>(
TASK_AMF_SBI, TASK_AMF_APP, promise_id);
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
// result includes json content 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;
nlohmann::json json_data = {};
if (result.find("httpResponseCode") != result.end()) {
http_response_code = result["httpResponseCode"].get<int>();
}
if (http_response_code == 200) {
if (result.find("content") != result.end()) {
json_data = result["content"];
}
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType("application/json"));
response.send(Pistache::Http::Code::Ok, json_data.dump().c_str());
} else {
// Problem details
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 oai::amf::api
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this
* file except in compliance with the License. You may obtain a copy of the
* License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef AMF_CONFIGURATION_API_IMPL_H_
#define AMF_CONFIGURATION_API_IMPL_H_
#include "amf_app.hpp"
#include <AMFConfigurationApi.h>
#include <pistache/http.h>
#include <pistache/optional.h>
namespace oai::amf::api {
using namespace oai::amf::model;
class AMFConfigurationApiImpl : public oai::amf::api::AMFConfigurationApi {
private:
amf_application::amf_app* m_amf_app;
public:
AMFConfigurationApiImpl(
std::shared_ptr<Pistache::Rest::Router>, amf_app* amf_app_inst);
~AMFConfigurationApiImpl() {}
void read_configuration(Pistache::Http::ResponseWriter& response);
};
} // namespace oai::amf::api
#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