Commit 508d4fc4 authored by sagar arora's avatar sagar arora

Merge branch 'releasev1.4.0' into 'master'

Release v1.4.0

See merge request oai/cn5g/oai-cn5g-udm!26
parents 1731eeab 49909bf5
# RELEASE NOTES: #
## v1.4.0 -- July 2022 ##
* Fix HTTP/2 support
* NRF Registration and heartbeat exchange
* Official images produced by CI are pushed to `oaisoftwarealliance` Docker-Hub Team account
* Reduce image size
## v1.3.0 -- January 2022 ##
* Experimental support for Event Exposure
......
......@@ -15,6 +15,7 @@ At the moment, it contains the following network elements:
* Unified Data Management (**UDM**)
* Unified Data Repository (**UDR**)
* User Plane Function (**UPF**)
* Network Slicing Selection Function (**NSSF**)
Each has its own repository: this repository (`oai-cn5g-udm`) is meant for UDM.
......
......@@ -50,6 +50,9 @@ def UDM_BASE_IMAGE_TAG = params.UdmBaseImageTag
// Merge Request Link
def gitlabMergeRequestLink
// Docker Hub account to push to
def DH_Account = "oaisoftwarealliance"
//-------------------------------------------------------------------------------
// Pipeline start
pipeline {
......@@ -183,7 +186,7 @@ pipeline {
echo "Maybe a previous build went wrong"
}
// In case of push to `develop` branch we build from scratch
myShCmd('docker build --no-cache --target oai-udm --tag oai-udm:' + udm_tag + ' --file docker/Dockerfile.udm.ubuntu18 --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > archives/udm_docker_image_build.log 2>&1', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd('docker build --no-cache --target oai-udm --tag oai-udm:' + udm_tag + ' --file docker/Dockerfile.udm.ubuntu18 . > archives/udm_docker_image_build.log 2>&1', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
}
if ("MERGE".equals(env.gitlabActionType)) {
try {
......@@ -198,6 +201,9 @@ pipeline {
myShCmd('docker image tag oai-udm-base:' + UDM_BASE_IMAGE_TAG + ' oai-udm-base:latest', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd('docker build --no-cache --target oai-udm --tag oai-udm:' + udm_tag + ' --file ci-scripts/docker/Dockerfile.ci.ubuntu.18.04 . > archives/udm_docker_image_build.log 2>&1', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
}
// Putting a place holder to try out on the flattening of image.
// If not satisfactory, we can remove it.
myShCmd('python3 ./ci-scripts/flatten_image.py --tag oai-udm:' + udm_tag, rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd('docker image ls >> archives/udm_docker_image_build.log', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
// We will keep also the TMP image in U18 case.
if ("MERGE".equals(env.gitlabActionType)) {
......@@ -240,10 +246,14 @@ pipeline {
}
myShCmd('sudo podman image prune --force', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
// Copy the RHEL Host certificates for building
myShCmd('mkdir -p tmp/ca tmp/entitlement', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('cp /etc/pki/entitlement/*pem tmp/entitlement', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo cp /etc/rhsm/ca/redhat-uep.pem tmp/ca', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo podman build --no-cache --target oai-udm --tag oai-udm:' + udm_tag + ' --file docker/Dockerfile.udm.rhel8 --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > archives/udm_podman_image_build.log 2>&1', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('mkdir -p ./etc-pki-entitlement ./rhsm-conf ./rhsm-ca', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('cp /etc/pki/entitlement/*pem ./etc-pki-entitlement', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo cp /etc/rhsm/rhsm.conf ./rhsm-conf', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo cp /etc/rhsm/ca/*.pem ./rhsm-ca', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo podman build --no-cache --target oai-udm --tag oai-udm:' + udm_tag + ' --file docker/Dockerfile.udm.rhel8 . > archives/udm_podman_image_build.log 2>&1', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
// Putting a place holder to try out on the flattening of image.
// If not satisfactory, we can remove it.
myShCmd('python3 ./ci-scripts/flatten_image.py --tag oai-udm:' + udm_tag, rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo podman image ls >> archives/udm_podman_image_build.log', rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
if ("MERGE".equals(env.gitlabActionType)) {
myShCmd('sudo podman image tag oai-udm:' + udm_tag + ' oai-udm:' + rhel_udm_tag, rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
......@@ -409,6 +419,36 @@ pipeline {
}
}
}
stage ('Testing the tutorials') {
steps {
script {
gitlabCommitStatus(name: "Test tutorials") {
localStatus = build job: 'OAI-CN5G-Tutorials-Check',
parameters: [
string(name: 'UDM_TAG', value: String.valueOf(udm_tag)),
string(name: 'UDM_BRANCH', value: String.valueOf(udm_branch))
], propagate: false
localResult = localStatus.getResult()
if (localStatus.resultIsBetterOrEqualTo('SUCCESS')) {
echo "Tutorials Test Job is OK"
} else {
echo "Tutorials Test Job is KO"
sh "ci-scripts/fail.sh"
}
}
}
}
post {
always {
script {
copyArtifacts(projectName: 'OAI-CN5G-Tutorials-Check',
filter: '*_results_oai_cn5g*.html',
selector: lastCompleted())
}
}
}
}
}
}
// For the moment it is Docker-Hub, but we might have a new one internally.
......@@ -421,9 +461,9 @@ pipeline {
[$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.DockerHubCredentials}", usernameVariable: 'DH_Username', passwordVariable: 'DH_Password']
]) {
myShCmd("echo ${DH_Password} | docker login --username ${DH_Username} --password-stdin", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker image tag oai-udm:develop ${DH_Username}/oai-udm:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker push ${DH_Username}/oai-udm:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker rmi ${DH_Username}/oai-udm:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker image tag oai-udm:develop ${DH_Account}/oai-udm:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker push ${DH_Account}/oai-udm:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker rmi ${DH_Account}/oai-udm:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker logout", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
}
}
......
......@@ -139,6 +139,16 @@ then
exit 1
fi
# When running in a container, in /home folder
IS_CONTAINER=`egrep -c "docker|kubepods|podman|buildah|libpod" /proc/self/cgroup || true`
if [ $IS_CONTAINER -ne 0 ]
then
if [ $PWD = "/home/src" ]
then
git config --global --add safe.directory /home
fi
fi
# Merge request scenario
MERGE_COMMMIT=`git log -n1 --pretty=format:%H`
......
......@@ -54,9 +54,9 @@ RUN apt-get update && \
net-tools \
tzdata \
bc \
tshark \
perl \
libasan4 \
libgssapi-krb5-2 \
libpsl5 \
librtmp1 \
libldap-2.4-2 \
......@@ -77,6 +77,7 @@ COPY --from=oai-udm-builder \
/usr/local/lib/libpistache.so \
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 \
/usr/lib/libboost_system.so.1.67.0 \
/usr/local/lib/libnghttp2.so.14 \
/usr/local/lib/libnghttp2_asio.so.1 \
/usr/local/lib/
......
"""
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
"""
import argparse
import re
import subprocess
import sys
def main() -> None:
args = _parse_args()
status = perform_flattening(args.tag)
sys.exit(status)
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description='Flattening Image')
parser.add_argument(
'--tag', '-t',
action='store',
required=True,
help='Image Tag in image-name:image tag format',
)
return parser.parse_args()
def perform_flattening(tag):
# First detect which docker/podman command to use
cli = ''
image_prefix = ''
cmd = 'which podman || true'
podman_check = subprocess.check_output(cmd, shell=True, universal_newlines=True)
if re.search('podman', podman_check.strip()):
cli = 'sudo podman'
image_prefix = 'localhost/'
if cli == '':
cmd = 'which docker || true'
docker_check = subprocess.check_output(cmd, shell=True, universal_newlines=True)
if re.search('docker', docker_check.strip()):
cli = 'docker'
image_prefix = ''
if cli == '':
print ('No docker / podman installed: quitting')
return -1
print (f'Flattening {tag}')
# Creating a container
cmd = cli + ' run --name test-flatten --entrypoint /bin/true -d ' + tag
print (cmd)
subprocess.check_output(cmd, shell=True, universal_newlines=True)
# Export / Import trick
cmd = cli + ' export test-flatten | ' + cli + ' import '
# Bizarro syntax issue with podman
if cli == 'docker':
cmd += ' --change "ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" '
else:
cmd += ' --change "ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" '
cmd += ' --change "WORKDIR /openair-udm" '
cmd += ' --change "EXPOSE 80/tcp" '
cmd += ' --change "CMD [\\"/openair-udm/bin/oai_udm\\", \\"-c\\", \\"/openair-udm/etc/udm.conf\\", \\"-o\\"]" '
cmd += ' --change "ENTRYPOINT [\\"/bin/bash\\", \\"/openair-udm/bin/entrypoint.sh\\"]" '
cmd += ' - ' + image_prefix + tag
print (cmd)
subprocess.check_output(cmd, shell=True, universal_newlines=True)
# Remove container
cmd = cli + ' rm -f test-flatten'
print (cmd)
subprocess.check_output(cmd, shell=True, universal_newlines=True)
# At this point the original image is a dangling image.
# CI pipeline will clean up (`image prune --force`)
return 0
if __name__ == '__main__':
main()
......@@ -809,7 +809,7 @@ class HtmlReport():
result = re.search('oai-udm *ci-tmp', line)
else:
result = re.search('oai-udm *develop', line)
if result is not None:
if result is not None and not status:
if variant == 'docker':
result = re.search('ago *([0-9A-Z]+)', line)
else:
......
......@@ -32,8 +32,12 @@ FROM registry.access.redhat.com/ubi8/ubi:latest AS oai-udm-builder
ARG NEEDED_GIT_PROXY
COPY tmp/ca/redhat-uep.pem /etc/rhsm/ca
COPY tmp/entitlement/*.pem /etc/pki/entitlement
# Copy the entitlements
COPY ./etc-pki-entitlement /etc/pki/entitlement
# Copy the subscription manager configurations
COPY ./rhsm-conf /etc/rhsm
COPY ./rhsm-ca /etc/rhsm/ca
RUN rm -f /etc/rhsm-host && \
yum repolist --disablerepo=* && \
......@@ -53,8 +57,8 @@ RUN rm -f /etc/rhsm-host && \
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf
# Some GIT configuration command quite useful
RUN /bin/bash -c "if [[ -v NEEDED_GIT_PROXY ]]; then git config --global http.proxy $NEEDED_GIT_PROXY; fi" && \
git config --global https.postBuffer 123289600 && \
RUN /bin/bash -c "if [[ -v NEEDED_GIT_PROXY ]]; then git config --global http.proxy $NEEDED_GIT_PROXY; fi"
RUN git config --global https.postBuffer 123289600 && \
git config --global https.maxRequestBuffer 123289600 && \
git config --global core.compression 0 && \
git config --global http.sslverify false
......@@ -85,10 +89,9 @@ RUN yum update -y && \
nettle \
libubsan \
libasan \
liblsan \
libevent && \
yum clean all -y && \
rm -rf /var/cache/yum && \
rm -rf /var/cache/yum /var/cache/dnf && \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf
......
......@@ -43,8 +43,8 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/*
# Some GIT configuration command quite useful
RUN /bin/bash -c "if [[ -v NEEDED_GIT_PROXY ]]; then git config --global http.proxy $NEEDED_GIT_PROXY; fi" && \
git config --global https.postBuffer 123289600 && \
RUN /bin/bash -c "if [[ -v NEEDED_GIT_PROXY ]]; then git config --global http.proxy $NEEDED_GIT_PROXY; fi"
RUN git config --global https.postBuffer 123289600 && \
git config --global https.maxRequestBuffer 123289600 && \
git config --global core.compression 0 && \
git config --global http.sslverify false
......@@ -74,9 +74,9 @@ RUN apt-get update && \
net-tools \
tzdata \
bc \
tshark \
perl \
libasan4 \
libgssapi-krb5-2 \
libpsl5 \
librtmp1 \
libldap-2.4-2 \
......@@ -97,6 +97,7 @@ COPY --from=oai-udm-builder \
/usr/local/lib/libpistache.so \
/usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 \
/usr/lib/libboost_system.so.1.67.0 \
/usr/local/lib/libnghttp2.so.14 \
/usr/local/lib/libnghttp2_asio.so.1 \
/usr/local/lib/
......
......@@ -23,6 +23,7 @@ UDM =
# STRING, {"yes", "no"},
USE_FQDN_DNS = "@USE_FQDN_DNS@"; # Set to yes if UDM will relying on a DNS to resolve UDR's FQDN
USE_HTTP2 = "@USE_HTTP2@"; # Set to yes to enable HTTP2 for AUSF server
REGISTER_NRF = "@REGISTER_NRF@"; # Set to 'yes' if UDM resgisters to an NRF
}
UDR:{
......@@ -31,5 +32,12 @@ UDM =
API_VERSION = "@UDR_VERSION_NB@"; # YOUR API VERSION FOR UDR CONFIG HERE
FQDN = "@UDR_FQDN@" # YOUR UDR FQDN CONFIG HERE
};
NRF :
{
IPV4_ADDRESS = "@NRF_IPV4_ADDRESS@"; # YOUR NRF CONFIG HERE
PORT = @NRF_PORT@; # YOUR NRF CONFIG HERE (default: 80)
API_VERSION = "@NRF_API_VERSION@"; # YOUR NRF API VERSION HERE
FQDN = "@NRF_FQDN@"; # YOUR NRF FQDN HERE
};
};
\ No newline at end of file
......@@ -7,9 +7,14 @@ SBI_PORT=${SBI_PORT:-80}
UDR_PORT=${UDR_PORT:-80}
SBI_HTTP2_PORT=${SBI_HTTP2_PORT:-8080}
USE_HTTP2=${USE_HTTP2:-no}
REGISTER_NRF=${REGISTER_NRF:-no}
NRF_PORT=${NRF_PORT:-80}
NRF_API_VERSION=${NRF_API_VERSION:-v1}
NRF_FQDN=${NRF_FQDN:-oai-nrf}
if [[ ${USE_FQDN_DNS} == "yes" ]];then
UDR_IP_ADDRESS=${UDR_IP_ADDRESS:-0.0.0.0}
NRF_IPV4_ADDRESS=${NRF_IPV4_ADDRESS:-0.0.0.0}
fi
......
{
"files.associations": {
"cstdlib": "cpp",
"algorithm": "cpp",
"*.h++": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"functional": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"ratio": "cpp",
"regex": "cpp",
"set": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cfenv": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp"
}
}
\ No newline at end of file
......@@ -49,7 +49,8 @@ UECMRegistrationInfoRetrievalApiImpl::UECMRegistrationInfoRetrievalApiImpl(
// &supportedFeatures, const Pistache::Optional<Snssai> &singleNssai, const
// Pistache::Optional<std::string> &dnn, Pistache::Http::ResponseWriter
// &response) {
// response.send(Pistache::Http::Code::Ok, "Do some magic\n");
// response.send(Pistache::Http::Code::Ok, "This API has not been implemented
// yet!\n");
//}
} // namespace api
......
......@@ -86,10 +86,12 @@ void udm_http2_server::start() {
// Confirm/Delete Auth
server.handle(
NUDM_UE_AU_BASE + udm_cfg.sbi.api_version,
NUDM_UE_AU_BASE + udm_cfg.sbi.api_version + "/",
[&](const request& request, const response& response) {
request.on_data([&](const uint8_t* data, std::size_t len) {
std::string msg((char*) data, len);
Logger::udm_server().info(
"Request URI: %s", request.uri().path.c_str());
try {
std::vector<std::string> split_q;
boost::split(split_q, request.uri().path, boost::is_any_of("/"));
......@@ -126,7 +128,7 @@ void udm_http2_server::start() {
});
server.handle(
NUDM_SDM_BASE + udm_cfg.sbi.api_version,
NUDM_SDM_BASE + udm_cfg.sbi.api_version + "/",
[&](const request& request, const response& response) {
request.on_data([&](const uint8_t* data, std::size_t len) {
std::string msg((char*) data, len);
......@@ -277,6 +279,7 @@ void udm_http2_server::generate_auth_data_request_handler(
void udm_http2_server::confirm_auth_handler(
const std::string& supi, const oai::udm::model::AuthEvent& authEvent,
const response& response) {
Logger::udm_ueau().info("Handle Authentication Confirmation");
nlohmann::json response_data = {};
long http_code = 0;
std::string location;
......
/*
* 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 FILE_3GPP_29_510_nssf_SEEN
#define FILE_3GPP_29_510_nssf_SEEN
#include <vector>
#include <nlohmann/json.hpp>
// Section 28.4, TS23.003
typedef struct s_nssai {
uint8_t sST;
std::string sD;
s_nssai(const uint8_t& sst, const std::string sd) : sST(sst), sD(sd) {}
s_nssai() : sST(), sD() {}
s_nssai(const s_nssai& p) : sST(p.sST), sD(p.sD) {}
bool operator==(const struct s_nssai& s) const {
if ((s.sST == this->sST) && (s.sD.compare(this->sD) == 0)) {
return true;
} else {
return false;
}
}
s_nssai& operator=(const s_nssai& s) {
sST = s.sST;
sD = s.sD;
return *this;
}
} snssai_t;
typedef struct dnai_s {
} dnai_t;
typedef struct patch_item_s {
std::string op;
std::string path;
// std::string from;
std::string value;
nlohmann::json to_json() const {
nlohmann::json json_data = {};
json_data["op"] = op;
json_data["path"] = path;
json_data["value"] = value;
return json_data;
}
} patch_item_t;
#define UDM_CURL_TIMEOUT_MS 100L
#define NNRF_NFM_BASE "/nnrf-nfm/"
#define UDM_NF_REGISTER_URL "/nf-instances/"
#endif
\ No newline at end of file
......@@ -71,6 +71,7 @@ void Logger::_init(
m_udm_ueau = new _Logger("udm_ueau", m_sinks, ss.str().c_str());
m_udm_uecm = new _Logger("udm_uecm", m_sinks, ss.str().c_str());
m_udm_sdm = new _Logger("udm_sdm", m_sinks, ss.str().c_str());
m_udm_nrf = new _Logger("udm_nrf", m_sinks, ss.str().c_str());
m_udm_server = new _Logger("udm_server", m_sinks, ss.str().c_str());
m_udm_app = new _Logger("udm_app", m_sinks, ss.str().c_str());
}
......
......@@ -88,6 +88,7 @@ class Logger {
static _Logger& udm_uecm() { return *singleton().m_udm_uecm; }
static _Logger& udm_ee() { return *singleton().m_udm_ee; }
static _Logger& udm_sdm() { return *singleton().m_udm_sdm; }
static _Logger& udm_nrf() { return *singleton().m_udm_nrf; }
static _Logger& udm_server() { return *singleton().m_udm_server; }
static _Logger& udm_app() { return *singleton().m_udm_app; }
......@@ -113,6 +114,7 @@ class Logger {
_Logger* m_udm_uecm;
_Logger* m_udm_ee;
_Logger* m_udm_sdm;
_Logger* m_udm_nrf;
_Logger* m_udm_server;
_Logger* m_udm_app;
};
......
......@@ -123,4 +123,42 @@ enum http_response_codes_e {
HTTP_RESPONSE_CODE_GATEWAY_TIMEOUT = 504
};
typedef struct supi_range_s {
std::string start;
std::string end;
std::string pattern;
} supi_range_t;
typedef struct supi_range_udm_info_item_s {
supi_range_t supi_range;
} supi_range_udm_info_item_t;
typedef struct identity_range_s {
std::string start;
std::string end;
std::string pattern;
} identity_range_t;
typedef struct identity_range_udm_info_item_s {
identity_range_t identity_range;
} identity_range_udm_info_item_t;
typedef struct internal_grpid_s {
std::string start;
std::string end;
std::string pattern;
} internal_grpid_range_t;
typedef struct internal_grpid_udm_info_item_s {
internal_grpid_range_t int_grpid_range;
} internal_grpid_range_udm_info_item_t;
typedef struct udm_info_s {
std::string groupid;
std::vector<supi_range_udm_info_item_t> supi_ranges;
std::vector<identity_range_udm_info_item_t> gpsi_ranges;
std::vector<identity_range_udm_info_item_t> ext_grp_id_ranges;
std::vector<std::string> routing_indicators;
std::vector<internal_grpid_range_udm_info_item_t> int_grp_id_ranges;
} udm_info_t;
#endif
......@@ -28,6 +28,7 @@ bool fqdn::resolve(
const std::string& host_name, std::string& address, uint32_t& port,
uint8_t& addr_type, const std::string& protocol) {
try {
Logger::udm_app().debug("Resolving DNS:- %s", host_name.c_str());
boost::asio::io_context io_context = {};
boost::asio::ip::tcp::resolver resolver{io_context};
......
......@@ -86,12 +86,19 @@ int main(int argc, char** argv) {
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
// Event subsystem
udm_event ev;
// Config
udm_cfg.load(Options::getlibconfigConfig());
udm_cfg.display();
// UDM application layer
udm_app_inst = new udm_app(Options::getlibconfigConfig());
udm_app_inst = new udm_app(Options::getlibconfigConfig(), ev);
// Task Manager
task_manager tm(ev);
std::thread task_manager_thread(&task_manager::run, &tm);
// PID file
// Currently hard-coded value. TODO: add as config option.
......
......@@ -32,6 +32,9 @@ add_library (UDM STATIC
udm_client.cpp
udm_config.cpp
udm_event.cpp
udm_profile.cpp
task_manager.cpp
udm_nrf.cpp
)
/*
* 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
*/
/*! \file task_manager.cpp
\brief
\author
\company Eurecom
\date 2020
\email: Tien-Thinh.Nguyen@eurecom.fr
*/
#include "task_manager.hpp"
#include <unistd.h>
#include <iostream>
#include <thread>
#include "logger.hpp"
using namespace oai::udm::app;
//------------------------------------------------------------------------------
task_manager::task_manager(udm_event& ev) : event_sub_(ev) {
struct itimerspec its;
sfd = timerfd_create(CLOCK_MONOTONIC, 0);
/* Start the timer */
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 1000 * 1000;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
if (timerfd_settime(sfd, TFD_TIMER_ABSTIME, &its, NULL) == -1) {
Logger::udm_app().error("Failed to set timer for task manager");
}
}
//------------------------------------------------------------------------------
void task_manager::run() {
manage_tasks();
}
//------------------------------------------------------------------------------
void task_manager::manage_tasks() {
// starting from current time
uint64_t t = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
while (1) {
event_sub_.task_tick(t);
t++;
wait_for_cycle();
}
}
//------------------------------------------------------------------------------
void task_manager::wait_for_cycle() {
uint64_t exp;
ssize_t res;
if (sfd > 0) {
res = read(sfd, &exp, sizeof(exp));
if ((res < 0) || (res != sizeof(exp))) {
Logger::udm_app().error("Failed in task manager timer wait");
}
}
}
/*
* 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
*/
/*! \file task_manager.hpp
\brief
\author
\company Eurecom
\date 2020
\email: Tien-Thinh.Nguyen@eurecom.fr
*/
#ifndef TASK_MANAGER_H_
#define TASK_MANAGER_H_
#include "udm_event.hpp"
#include <linux/types.h>
#include <sys/timerfd.h>
using namespace oai::udm::app;
namespace oai {
namespace udm {
namespace app {
class udm_event;
class task_manager {
public:
task_manager(udm_event& ev);
/*
* Manage the tasks
* @param [void]
* @return void
*/
void manage_tasks();
/*
* Run the tasks (for the moment, simply call function manage_tasks)
* @param [void]
* @return void
*/
void run();
private:
/*
* Make sure that the task tick run every 1ms
* @param [void]
* @return void
*/
void wait_for_cycle();
udm_event& event_sub_;
int sfd;
};
} // namespace app
} // namespace udm
} // namespace oai
#endif
This diff is collapsed.
......@@ -55,7 +55,7 @@ namespace oai::udm::app {
// class ausf_config;
class udm_app {
public:
explicit udm_app(const std::string& config_file);
explicit udm_app(const std::string& config_file, udm_event& ev);
udm_app(udm_app const&) = delete;
void operator=(udm_app const&) = delete;
......@@ -191,6 +191,14 @@ class udm_app {
void handle_ee_ue_reachability_for_data(
const std::string& ue_id, uint8_t status, uint8_t http_version);
/*
* Increase the value of SQN with a value of 32
* @param [const std::string&] c_sqn: Current value in form of string
* @param [std::string&] n_sqn: New value in form of string
* @return void
*/
void increment_sqn(const std::string& c_sqn, std::string& n_sqn);
private:
util::uint_generator<uint32_t> evsub_id_generator;
std::map<evsub_id_t, std::shared_ptr<oai::udm::model::CreatedEeSubscription>>
......@@ -199,7 +207,7 @@ class udm_app {
mutable std::shared_mutex m_mutex_udm_event_subscriptions;
// for Event Handling
udm_event event_sub;
udm_event& event_sub;
bs2::connection loss_of_connectivity_connection;
bs2::connection ue_reachability_for_data_connection;
};
......
......@@ -71,7 +71,7 @@ udm_client::~udm_client() {
long udm_client::curl_http_client(
std::string remoteUri, std::string method, std::string& response,
std::string msgBody) {
Logger::udm_ueau().info("Send HTTP message with body %s", msgBody.c_str());
Logger::udm_app().info("Send HTTP message with body %s", msgBody.c_str());
uint32_t str_len = msgBody.length();
char* body_data = (char*) malloc(str_len + 1);
......@@ -139,10 +139,10 @@ long udm_client::curl_http_client(
std::string json_data_response = {};
std::string resMsg = {};
bool is_response_ok = true;
Logger::udm_ueau().info("Get response with httpcode (%d)", httpCode);
Logger::udm_app().info("Got response with httpcode (%d)", httpCode);
if (httpCode == 0) {
Logger::udm_ueau().info(
Logger::udm_app().info(
"Cannot get response when calling %s", remoteUri.c_str());
// free curl before returning
curl_slist_free_all(headers);
......@@ -157,11 +157,11 @@ long udm_client::curl_http_client(
httpCode != HTTP_RESPONSE_CODE_NO_CONTENT) {
is_response_ok = false;
if (response.size() < 1) {
Logger::udm_ueau().info("There's no content in the response");
Logger::udm_app().info("There's no content in the response");
// TODO: send context response error
return httpCode;
}
Logger::udm_ueau().info("Wrong response code");
Logger::udm_app().info("Wrong response code");
return httpCode;
}
......@@ -174,17 +174,17 @@ long udm_client::curl_http_client(
try {
response_data = nlohmann::json::parse(json_data_response);
} catch (nlohmann::json::exception& e) {
Logger::udm_ueau().info("Could not get Json content from the response");
Logger::udm_app().info("Could not get Json content from the response");
// Set the default Cause
response_data["error"]["cause"] = "504 Gateway Timeout";
}
Logger::udm_ueau().info(
Logger::udm_app().info(
"Get response with jsonData: %s", json_data_response.c_str());
std::string cause = response_data["error"]["cause"];
Logger::udm_ueau().info("Call Network Function services failure");
Logger::udm_ueau().info("Cause value: %s", cause.c_str());
Logger::udm_app().info("Call Network Function services failure");
Logger::udm_app().info("Cause value: %s", cause.c_str());
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
......
......@@ -34,6 +34,7 @@
#include "if.hpp"
#include "logger.hpp"
#include "fqdn.hpp"
#include "udm.h"
#include "string.hpp"
extern "C" {
......@@ -57,8 +58,13 @@ udm_config::udm_config() : instance(0), pid_dir(), udm_name(), sbi() {
udr_addr.port = 80;
udr_addr.api_version = "v1";
udr_addr.fqdn = {};
nrf_addr.ipv4_addr.s_addr = INADDR_ANY;
nrf_addr.port = 80;
nrf_addr.api_version = "v1";
nrf_addr.fqdn = {};
use_fqdn_dns = false;
use_http2 = false;
register_nrf = false;
}
//------------------------------------------------------------------------------
......@@ -146,6 +152,14 @@ int udm_config::load(const std::string& config_file) {
use_fqdn_dns = false;
}
support_features.lookupValue(
UDM_CONFIG_STRING_SUPPORTED_FEATURES_REGISTER_NRF, opt);
if (boost::iequals(opt, "yes")) {
register_nrf = true;
} else {
register_nrf = false;
}
support_features.lookupValue(
UDM_CONFIG_STRING_SUPPORT_FEATURES_USE_HTTP2, opt);
if (boost::iequals(opt, "yes")) {
......@@ -221,6 +235,63 @@ int udm_config::load(const std::string& config_file) {
Logger::udm_app().error("%s : %s", nfex.what(), nfex.getPath());
return RETURNerror;
}
// NRF
if (register_nrf) {
try {
std::string astring = {};
const Setting& nrf_cfg = udm_cfg[UDM_CONFIG_STRING_NRF];
struct in_addr nrf_ipv4_addr = {};
unsigned int nrf_port = 0;
std::string nrf_api_version = {};
if (!use_fqdn_dns) {
nrf_cfg.lookupValue(UDM_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(UDM_CONFIG_STRING_NRF_PORT, nrf_port))) {
Logger::udm_app().error(UDM_CONFIG_STRING_NRF_PORT "failed");
throw(UDM_CONFIG_STRING_NRF_PORT "failed");
}
nrf_addr.port = nrf_port;
if (!(nrf_cfg.lookupValue(
UDM_CONFIG_STRING_API_VERSION, nrf_api_version))) {
Logger::udm_app().error(UDM_CONFIG_STRING_API_VERSION "failed");
throw(UDM_CONFIG_STRING_API_VERSION "failed");
}
nrf_addr.api_version = nrf_api_version;
} else {
nrf_cfg.lookupValue(UDM_CONFIG_STRING_FQDN_DNS, 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;
// We hardcode nrf port from config for the moment
if (!(nrf_cfg.lookupValue(UDM_CONFIG_STRING_NRF_PORT, nrf_port))) {
Logger::udm_app().error(UDM_CONFIG_STRING_NRF_PORT "failed");
throw(UDM_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::udm_app().error("%s : %s", nfex.what(), nfex.getPath());
return RETURNerror;
}
}
return RETURNok;
}
......@@ -242,6 +313,8 @@ void udm_config::display() {
Logger::config().info(
" Api Version...........: %s", sbi.api_version.c_str());
Logger::config().info("- Supported Features:");
Logger::config().info(
" REGISTER NRF .. ......: %s", register_nrf ? "Yes" : "No");
Logger::config().info(
" Use FQDN ..............: %s", use_fqdn_dns ? "Yes" : "No");
Logger::config().info(
......@@ -254,9 +327,16 @@ void udm_config::display() {
Logger::config().info(" Port..................: %lu ", udr_addr.port);
Logger::config().info(
" API version...........: %s", udr_addr.api_version.c_str());
Logger::config().info("- NRF:");
Logger::config().info(
" IPv4 Addr ............: %s",
inet_ntoa(*((struct in_addr*) &nrf_addr.ipv4_addr)));
Logger::config().info(" Port .................: %lu ", nrf_addr.port);
Logger::config().info(
" API version ..........: %s", nrf_addr.api_version.c_str());
if (use_fqdn_dns)
Logger::config().info(
" FQDN..................: %s", udr_addr.fqdn.c_str());
" FQDN..................: %s", nrf_addr.fqdn.c_str());
}
//------------------------------------------------------------------------------
......@@ -311,4 +391,73 @@ int udm_config::load_interface(
return RETURNok;
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_slice_selection_subscription_data_retrieval_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id) {
return get_udr_url_base() + "/subscription-data/" + supi + "/" +
plmn_id.getMcc() + plmn_id.getMnc() + "/provisioned-data/am-data";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_access_and_mobility_subscription_data_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id) {
return get_udr_url_base() + "/subscription-data/" + supi + "/" +
plmn_id.getMcc() + plmn_id.getMnc() + "/provisioned-data/am-data";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_session_management_subscription_data_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id) {
return get_udr_url_base() + "/subscription-data/" + supi + "/" +
plmn_id.getMcc() + plmn_id.getMnc() + "/provisioned-data/sm-data";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_smf_selection_subscription_data_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id) {
return get_udr_url_base() + "/subscription-data/" + supi + "/" +
plmn_id.getMcc() + plmn_id.getMnc() +
"/provisioned-data/smf-selection-subscription-data";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_sdm_subscriptions_uri(const std::string& supi) {
return get_udr_url_base() + "/subscription-data/" + supi +
"/context-data/sdm-subscriptions";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_authentication_subscription_uri(
const std::string& supi) {
return get_udr_url_base() + "/subscription-data/" + supi +
NUDR_AUTHENTICATION_SUBSCRIPTION_ENDPOINT;
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_authentication_status_uri(
const std::string& supi) {
return get_udr_url_base() + "/subscription-data/" + supi +
"/authentication-data/authentication-status";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_amf_3gpp_registration_uri(
const std::string& supi) {
return get_udr_url_base() + "/subscription-data/" + supi +
"/context-data/amf-3gpp-access";
}
//------------------------------------------------------------------------------
std::string udm_config::get_udm_ueau_base() {
return std::string(inet_ntoa(*((struct in_addr*) &udr_addr.ipv4_addr))) +
":" + std::to_string(udr_addr.port) + NUDM_UE_AU_BASE +
udr_addr.api_version;
}
//------------------------------------------------------------------------------
std::string udm_config::get_udr_url_base() {
return std::string(inet_ntoa(*((struct in_addr*) &udr_addr.ipv4_addr))) +
":" + std::to_string(udr_addr.port) + NUDR_DATA_REPOSITORY +
udr_addr.api_version;
}
} // namespace oai::udm::config
......@@ -39,6 +39,7 @@
#include <vector>
#include "udm_config.hpp"
#include "PlmnId.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
......@@ -62,8 +63,13 @@
#define UDM_CONFIG_STRING_UDR_IPV4_ADDRESS "IPV4_ADDRESS"
#define UDM_CONFIG_STRING_UDR_PORT "PORT"
#define UDM_CONFIG_STRING_NRF "NRF"
#define UDM_CONFIG_STRING_NRF_IPV4_ADDRESS "IPV4_ADDRESS"
#define UDM_CONFIG_STRING_NRF_PORT "PORT"
#define UDM_CONFIG_STRING_SUPPORT_FEATURES "SUPPORT_FEATURES"
#define UDM_CONFIG_STRING_SUPPORT_FEATURES_USE_FQDN_DNS "USE_FQDN_DNS"
#define UDM_CONFIG_STRING_SUPPORTED_FEATURES_REGISTER_NRF "REGISTER_NRF"
#define UDM_CONFIG_STRING_SUPPORT_FEATURES_USE_HTTP2 "USE_HTTP2"
#define UDM_CONFIG_STRING_FQDN_DNS "FQDN"
......@@ -81,6 +87,13 @@ typedef struct interface_cfg_s {
std::string api_version;
} interface_cfg_t;
typedef struct nf_addr_s {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
std::string fqdn;
} nf_addr_t;
class udm_config {
public:
udm_config();
......@@ -88,6 +101,21 @@ class udm_config {
int load(const std::string& config_file);
int load_interface(const Setting& if_cfg, interface_cfg_t& cfg);
void display();
std::string get_udr_slice_selection_subscription_data_retrieval_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id);
std::string get_udr_access_and_mobility_subscription_data_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id);
std::string get_udr_session_management_subscription_data_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id);
std::string get_udr_smf_selection_subscription_data_uri(
const std::string& supi, const oai::udm::model::PlmnId& plmn_id);
std::string get_udr_url_base();
std::string get_udr_sdm_subscriptions_uri(const std::string& supi);
std::string get_udr_authentication_subscription_uri(const std::string& supi);
std::string get_udr_authentication_status_uri(const std::string& supi);
std::string get_udr_amf_3gpp_registration_uri(const std::string& supi);
std::string get_udm_ueau_base();
unsigned int instance;
std::string pid_dir;
......@@ -96,13 +124,10 @@ class udm_config {
interface_cfg_t sbi;
unsigned int sbi_http2_port;
struct {
struct in_addr ipv4_addr;
unsigned int port;
std::string api_version;
std::string fqdn;
} udr_addr;
nf_addr_t udr_addr;
nf_addr_t nrf_addr;
bool register_nrf;
bool use_fqdn_dns;
bool use_http2;
};
......
......@@ -30,6 +30,18 @@
#include "udm_event.hpp"
using namespace oai::udm::app;
bs2::connection udm_event::subscribe_task_nf_heartbeat(
const task_sig_t::slot_type& sig, uint64_t period, uint64_t start) {
/* Wrap the actual callback in a lambda. The latter checks whether the
* current time is after start time, and ensures that the callback is only
* called every X ms with X being the period time. This way, it is possible
* to register to be notified every X ms instead of every ms, which provides
* greater freedom to implementations. */
auto f = [period, start, sig](uint64_t t) {
if (t >= start && (t - start) % period == 0) sig(t);
};
return task_tick.connect(f);
}
//------------------------------------------------------------------------------
bs2::connection udm_event::subscribe_loss_of_connectivity(
const loss_of_connectivity_sig_t::slot_type& sig) {
......
......@@ -35,8 +35,10 @@ namespace bs2 = boost::signals2;
#include "udm.h"
#include "udm_event_sig.hpp"
#include "task_manager.hpp"
namespace oai::udm::app {
class task_manager;
class udm_event {
public:
udm_event(){};
......@@ -50,7 +52,20 @@ class udm_event {
// class register/handle event
friend class udm_app;
friend class udm_nrf;
friend class task_manager;
//------------------------------------------------------------------------------
/*
* Subscribe to the task tick event
* @param [const task_sig_t::slot_type &] sig
* @param [uint64_t] period: interval between two events
* @param [uint64_t] start:
* @return void
*/
bs2::connection subscribe_task_nf_heartbeat(
const task_sig_t::slot_type& sig, uint64_t period, uint64_t start = 0);
//------------------------------------------------------------------------------
/*
* Subscribe to UE Loss of Connectivity Status signal
* @param [const loss_of_connectivity_sig_t::slot_type&] sig: slot_type
......@@ -72,6 +87,8 @@ class udm_event {
const ue_reachability_for_data_sig_t::slot_type& sig);
private:
task_sig_t task_tick;
loss_of_connectivity_sig_t
loss_of_connectivity; // Signal for Loss of Connectivity Report
ue_reachability_for_data_sig_t
......
......@@ -37,6 +37,10 @@ namespace bs2 = boost::signals2;
namespace oai::udm::app {
typedef bs2::signal_type<
void(uint64_t), bs2::keywords::mutex_type<bs2::dummy_mutex>>::type
task_sig_t;
// Signal for Loss of Connectivity
// SUPI, Connectivity status, HTTP version
typedef bs2::signal_type<
......
/*
* 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
*/
/*! \file udm_nrf.cpp
\brief
\author Tien-Thinh NGUYEN Rohan Kharade
\company Eurecom
\date 2020
\email:
*/
#include "udm_nrf.hpp"
#include "udm_app.hpp"
#include "udm_profile.hpp"
#include "udm_client.hpp"
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <curl/curl.h>
#include <pistache/http.h>
#include <pistache/mime.h>
#include <nlohmann/json.hpp>
#include <stdexcept>
#include "logger.hpp"
#include "udm.h"
using namespace oai::udm::app;
using namespace oai::udm::config;
// using json = nlohmann::json;
extern udm_config udm_cfg;
extern udm_nrf* udm_nrf_inst;
udm_client* udm_client_instance = nullptr;
//------------------------------------------------------------------------------
udm_nrf::udm_nrf(udm_event& ev) : m_event_sub(ev) {}
//---------------------------------------------------------------------------------------------
void udm_nrf::get_udm_api_root(std::string& api_root) {
api_root =
std::string(inet_ntoa(*((struct in_addr*) &udm_cfg.nrf_addr.ipv4_addr))) +
":" + std::to_string(udm_cfg.nrf_addr.port) + NNRF_NFM_BASE +
udm_cfg.nrf_addr.api_version;
}
//---------------------------------------------------------------------------------------------
void udm_nrf::generate_udm_profile(
udm_profile& udm_nf_profile, std::string& udm_instance_id) {
// TODO: remove hardcoded values
udm_nf_profile.set_nf_instance_id(udm_instance_id);
udm_nf_profile.set_nf_instance_name("OAI-UDM");
udm_nf_profile.set_fqdn("oai-udm");
udm_nf_profile.set_nf_type("UDM");
udm_nf_profile.set_nf_status("REGISTERED");
udm_nf_profile.set_nf_heartBeat_timer(50);
udm_nf_profile.set_nf_priority(1);
udm_nf_profile.set_nf_capacity(100);
// udm_nf_profile.set_fqdn(udm_cfg.fqdn);
udm_nf_profile.add_nf_ipv4_addresses(udm_cfg.sbi.addr4); // N4's Addr
// UDM info (Hardcoded for now)
// ToDo: If none of these parameters are provided, the UDM can serve any
// external group and any SUPI or GPSI managed by the PLMN of the UDM
// instance. If "supiRanges", "gpsiRanges" and
// "externalGroupIdentifiersRanges" attributes are absent, and "groupId" is
// present, the SUPIs / GPSIs / ExternalGroups served by this UDM instance is
// determined by the NRF (see 3GPP TS 23.501 [2], clause 6.2.6.2)
udm_info_t udm_info_item;
udm_info_item.groupid = "oai-udm-testgroupid";
udm_info_item.routing_indicators.push_back("0210");
udm_info_item.routing_indicators.push_back("9876");
supi_range_udm_info_item_t supi_ranges;
supi_ranges.supi_range.start = "208950000000031";
supi_ranges.supi_range.pattern = "^imsi-20895[31-131]{10}$";
supi_ranges.supi_range.end = "208950000000131";
udm_info_item.supi_ranges.push_back(supi_ranges);
identity_range_udm_info_item_t gpsi_ranges;
gpsi_ranges.identity_range.start = "752740000";
gpsi_ranges.identity_range.pattern = "^gpsi-75274[0-9]{4}$";
gpsi_ranges.identity_range.end = "752749999";
udm_info_item.gpsi_ranges.push_back(gpsi_ranges);
udm_nf_profile.set_udm_info(udm_info_item);
// ToDo:- Add remaining fields
// identity_range_udm_info_item_t ext_grp_id_ranges;
// internal_grpid_range_udm_info_item_t int_grp_id_ranges;
// UDM info item end
udm_nf_profile.display();
}
//---------------------------------------------------------------------------------------------
void udm_nrf::register_to_nrf() {
// generate UUID
udm_instance_id = to_string(boost::uuids::random_generator()());
nlohmann::json response_data = {};
// Generate NF Profile
udm_profile udm_nf_profile;
generate_udm_profile(udm_nf_profile, udm_instance_id);
// Send NF registeration request
std::string udm_api_root = {};
std::string response = {};
std::string method = {"PUT"};
get_udm_api_root(udm_api_root);
std::string remoteUri = udm_api_root + UDM_NF_REGISTER_URL + udm_instance_id;
nlohmann::json json_data = {};
udm_nf_profile.to_json(json_data);
Logger::udm_nrf().info("Sending NF registeration request");
udm_client_instance->curl_http_client(
remoteUri, method, response, json_data.dump().c_str());
try {
response_data = nlohmann::json::parse(response);
if (response.find("REGISTERED") != 0) {
start_event_nf_heartbeat(remoteUri);
}
} catch (nlohmann::json::exception& e) {
Logger::udm_nrf().info("NF registeration procedure failed");
}
}
//---------------------------------------------------------------------------------------------
void udm_nrf::start_event_nf_heartbeat(std::string& remoteURI) {
// get current time
uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
struct itimerspec its;
its.it_value.tv_sec = HEART_BEAT_TIMER; // seconds
its.it_value.tv_nsec = 0; // 100 * 1000 * 1000; //100ms
const uint64_t interval =
its.it_value.tv_sec * 1000 +
its.it_value.tv_nsec / 1000000; // convert sec, nsec to msec
task_connection = m_event_sub.subscribe_task_nf_heartbeat(
boost::bind(&udm_nrf::trigger_nf_heartbeat_procedure, this, _1), interval,
ms + interval);
}
//---------------------------------------------------------------------------------------------
void udm_nrf::trigger_nf_heartbeat_procedure(uint64_t ms) {
_unused(ms);
oai::udm::model::PatchItem patch_item = {};
std::vector<oai::udm::model::PatchItem> patch_items;
//{"op":"replace","path":"/nfStatus", "value": "REGISTERED"}
patch_item.setOp("replace");
patch_item.setPath("/nfStatus");
patch_item.setValue("REGISTERED");
patch_items.push_back(patch_item);
Logger::udm_app().info("Sending NF heartbeat request");
std::string response = {};
std::string method = {"PATCH"};
nlohmann::json json_data = nlohmann::json::array();
for (auto i : patch_items) {
nlohmann::json item = {};
to_json(item, i);
json_data.push_back(item);
}
std::string udm_api_root = {};
get_udm_api_root(udm_api_root);
std::string remoteUri = udm_api_root + UDM_NF_REGISTER_URL + udm_instance_id;
udm_client_instance->curl_http_client(
remoteUri, method, response, json_data.dump().c_str());
if (!response.empty()) task_connection.disconnect();
}
\ No newline at end of file
/*
* 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
*/
/*! \file udm_client.hpp
\author Tien-Thinh NGUYEN
\company Eurecom
\date 2020
\email:
*/
#ifndef FILE_UDM_NRF_SEEN
#define FILE_UDM_NRF_SEEN
#include <map>
#include <thread>
#include <curl/curl.h>
#include "logger.hpp"
#include "udm_config.hpp"
#include "udm_event.hpp"
#include "udm_profile.hpp"
namespace oai {
namespace udm {
namespace app {
class udm_nrf {
private:
public:
udm_profile udm_nf_profile; // UDM profile
std::string udm_instance_id; // UDM instance id
// timer_id_t timer_udm_heartbeat;
udm_nrf(udm_event& ev);
udm_nrf(udm_nrf const&) = delete;
void operator=(udm_nrf const&) = delete;
void generate_uuid();
/*
* Start event nf heartbeat procedure
* @param [void]
* @return void
*/
void start_event_nf_heartbeat(std::string& remoteURI);
/*
* Trigger NF heartbeat procedure
* @param [void]
* @return void
*/
void trigger_nf_heartbeat_procedure(uint64_t ms);
/*
* Generate a UDM profile for this instance
* @param [void]
* @return void
*/
void generate_udm_profile(
udm_profile& udm_nf_profile, std::string& udm_instance_id);
/*
* Trigger NF instance registration to NRF
* @param [void]
* @return void
*/
void register_to_nrf();
/*
* Get udm API Root
* @param [std::string& ] api_root: udm's API Root
* @return void
*/
void get_udm_api_root(std::string& api_root);
private:
udm_event& m_event_sub;
bs2::connection task_connection;
};
} // namespace app
} // namespace udm
} // namespace oai
#endif /* FILE_UDM_NRF_SEEN */
This diff is collapsed.
/*
* 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
*/
/*! \file udm_profile.hpp
\brief
\author Tien-Thinh NGUYEN
\company Eurecom
\date 2021
\email: Tien-Thinh.Nguyen@eurecom.fr
*/
#ifndef FILE_UDM_PROFILE_HPP_SEEN
#define FILE_UDM_PROFILE_HPP_SEEN
#include <arpa/inet.h>
#include <netinet/in.h>
#include <nlohmann/json.hpp>
#include <shared_mutex>
#include <vector>
#include "logger.hpp"
#include "3gpp_29.510.h"
#include "udm.h"
namespace oai {
namespace udm {
namespace app {
class udm_profile : public std::enable_shared_from_this<udm_profile> {
public:
udm_profile()
: nf_type("NF_TYPE_UNKNOWN"),
heartBeat_timer(0),
snssais(),
fqdn(),
ipv4_addresses(),
priority(0),
capacity(0) {
nf_instance_name = {};
nf_status = {};
}
udm_profile(const std::string& id)
: nf_instance_id(id),
heartBeat_timer(0),
snssais(),
fqdn(),
ipv4_addresses(),
priority(0),
capacity(0),
nf_type("NF_TYPE_UNKNOWN") {
nf_instance_name = {};
nf_status = {};
}
udm_profile& operator=(const udm_profile& s) {
nf_instance_id = s.nf_instance_id;
heartBeat_timer = s.heartBeat_timer;
snssais = s.snssais;
fqdn = s.fqdn;
ipv4_addresses = s.ipv4_addresses;
priority = s.priority;
capacity = s.capacity;
nf_type = s.nf_type;
nf_instance_name = s.nf_instance_name;
nf_status = s.nf_status;
udm_info = s.udm_info;
return *this;
}
// udm_profile(udm_profile &b) = delete;
virtual ~udm_profile() {
// Logger::udm_app().debug("Delete udm Profile instance...");
}
/*
* Set NF instance ID
* @param [const std::string &] instance_id: instance id
* @return void
*/
void set_nf_instance_id(const std::string& instance_id);
/*
* Get NF instance ID
* @param [std::string &] instance_id: store instance id
* @return void:
*/
void get_nf_instance_id(std::string& instance_id) const;
/*
* Get NF instance ID
* @param [std::string &] instance_id: store instance id
* @return void:
*/
std::string get_nf_instance_id() const;
/*
* Set NF instance name
* @param [const std::string &] instance_name: instance name
* @return void
*/
void set_nf_instance_name(const std::string& instance_name);
/*
* Get NF instance ID
* @param [std::string &] instance_name: store instance name
* @return void:
*/
void get_nf_instance_name(std::string& instance_name) const;
/*
* Get NF instance name
* @param
* @return [std::string] instance name
*/
std::string get_nf_instance_name() const;
/*
* Set NF instance status
* @param [const std::string &] status: instance status
* @return void
*/
void set_nf_status(const std::string& status);
/*
* Get NF instance status
* @param [std::string &] status: store instance status
* @return void:
*/
void get_nf_status(std::string& status) const;
/*
* Get NF status
* @param
* @return [std::string] instance status
*/
std::string get_nf_status() const;
/*
* Get NF type
* @param
* @return [std::string] nf type
*/
std::string get_nf_type() const;
/*
* Set NF type
* @param [const nf_type_t &] type: nf type
* @return void
*/
void set_nf_type(const std::string& type);
/*
* Set NF instance heartBeat_timer
* @param [const std::string &] timer: heartBeat_timer
* @return void
*/
void set_nf_heartBeat_timer(const int32_t& timer);
/*
* Get NF instance heartBeat_timer
* @param [std::string &] timer: store heartBeat_timer
* @return void:
*/
void get_nf_heartBeat_timer(int32_t& timer) const;
/*
* Get NF heartBeat_timer
* @param void
* @return heartBeat_timer
*/
int32_t get_nf_heartBeat_timer() const;
/*
* Set NF instance priority
* @param [const uint16_t] p: instance priority
* @return void
*/
void set_nf_priority(const uint16_t& p);
/*
* Get NF instance priority
* @param [uint16_t] p: store instance priority
* @return void:
*/
void get_nf_priority(uint16_t& p) const;
/*
* Get NF instance priority
* @param void
* @return [uint16_t] instance priority
*/
uint16_t get_nf_priority() const;
/*
* Set NF instance capacity
* @param [const uint16_t] c: instance capacity
* @return void
*/
void set_nf_capacity(const uint16_t& c);
/*
* Get NF instance priority
* @param [uint16_t ] c: store instance capacity
* @return void:
*/
void get_nf_capacity(uint16_t& c) const;
/*
* Get NF instance priority
* @param void
* @return [uint16_t ] instance capacity
*/
uint16_t get_nf_capacity() const;
/*
* Set NF instance SNSSAIs
* @param [std::vector<snssai_t> &] s: SNSSAIs
* @return void
*/
void set_nf_snssais(const std::vector<snssai_t>& s);
/*
* Add SNSSAI
* @param [snssai_t &] s: SNSSAI
* @return void
*/
void add_snssai(const snssai_t& s);
/*
* Get NF instance SNSSAIs
* @param [std::vector<snssai_t> &] s: store instance's SNSSAIs
* @return void:
*/
void get_nf_snssais(std::vector<snssai_t>& s) const;
/*
* Get NF fqdn
* @param
* @return [std::string] nf fqdn
*/
std::string get_fqdn() const;
/*
* Set NF fqdn
* @param [const fqdn_t &] fqdn: nf fqdn
* @return void
*/
void set_fqdn(const std::string& fqdn);
/*
* Set NF instance ipv4_addresses
* @param [std::vector<struct in_addr> &] a: ipv4_addresses
* @return void
*/
void set_nf_ipv4_addresses(const std::vector<struct in_addr>& a);
/*
* Add an IPv4 address to the list of addresses
* @param [const struct in_addr &] a: ipv4_address
* @return void
*/
void add_nf_ipv4_addresses(const struct in_addr& a);
/*
* Get NF instance ipv4_addresses
* @param [std::vector<struct in_addr> &] a: store instance's ipv4_addresses
* @return void:
*/
void get_nf_ipv4_addresses(std::vector<struct in_addr>& a) const;
/*
* Set udm info
* @param [udm_info_t &] s: udm info
* @return void
*/
void set_udm_info(const udm_info_t& s);
/*
* Get NF instance udm info
* @param [udm_info_t &] s: store instance's udm info
* @return void:
*/
void get_udm_info(udm_info_t& s) const;
/*
* Print related-information for NF profile
* @param void
* @return void:
*/
void display() const;
/*
* Represent NF profile as json object
* @param [nlohmann::json &] data: Json data
* @return void
*/
void to_json(nlohmann::json& data) const;
/*
* Covert from a json represetation to udm profile
* @param [nlohmann::json &] data: Json data
* @return void
*/
void from_json(const nlohmann::json& data);
/*
* Handle heartbeart timeout event
* @param [uint64_t] ms: current time
* @return void
*/
void handle_heartbeart_timeout(uint64_t ms);
protected:
// From NFProfile (Section 6.1.6.2.2@3GPP TS 29.510 V16.0.0 (2019-06))
std::string nf_instance_id;
std::string nf_instance_name;
std::string nf_type;
std::string nf_status;
int32_t heartBeat_timer;
std::vector<snssai_t> snssais;
std::string fqdn;
std::vector<struct in_addr> ipv4_addresses;
uint16_t priority;
uint16_t capacity;
udm_info_t udm_info;
};
} // namespace app
} // namespace udm
} // namespace oai
#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