Commit e12d77f9 authored by sagar arora's avatar sagar arora

Merge branch 'Release-v1.4.0' into 'master'

Release v1.4.0

See merge request oai/cn5g/oai-cn5g-amf!135
parents 40c7eeec 6097341d
# RELEASE NOTES: #
## v1.4.0 -- July 2022 ##
* Fix SCTP NG Shutdown issue
* Fix 100% CPU consumption issue
* Fix RAN UE ID display
* Fix issue for TMSI and GUTI value
* Fix for handling S-NSSAI
* Remove OPC value from AMF configuration
* Support for Ubuntu 20.04 bare-metal installation
* Official images produced by CI are pushed to `oaisoftwarealliance` Docker-Hub Team account
* Reduce image size
## v1.3.0 -- January 2022 ##
* Periodic Registration Update
......
......@@ -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-amf`) is meant for AMF.
......
......@@ -420,30 +420,25 @@ check_install_amf_deps(){
# PPA has 1.67
$SUDO add-apt-repository ppa:mhier/libboost-latest --yes
$SUDO $INSTALLER update
if [ $IS_CONTAINER -eq 0 ]; then
specific_packages="libconfig++-dev libasio-dev libboost-all-dev mysql-server"
else
specific_packages="libconfig++-dev"
fi
;;
*)
if [ $IS_CONTAINER -eq 0 ]; then
specific_packages="libconfig++-dev libasio-dev libboost-all-dev mysql-server"
else
specific_packages="libconfig++-dev libasio-dev libboost-all-dev"
fi
;;
"ubuntu20.04")
specific_packages="libconfig++-dev libasio-dev libboost-all-dev libmysqlclient-dev"
;;
esac
# removed libspdlog-dev
PACKAGE_LIST="\
$specific_packages \
mysql-server \
mysql-client \
libmysqlclient-dev \
guile-2.0-dev \
libcurl4-gnutls-dev \
libevent-dev \
libgcrypt11-dev \
libgcrypt?-dev \
libgmp-dev \
libhogweed? \
libidn2-0-dev \
......@@ -462,7 +457,7 @@ check_install_amf_deps(){
pkg-config \
ninja-build \
wget \
libasan2"
libasan?"
elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then
PACKAGE_LIST="\
guile-devel \
......@@ -500,7 +495,7 @@ check_install_amf_deps(){
"ubuntu18.04")
$SUDO $INSTALLER remove $OPTION libboost1.65-dev || true
$SUDO $INSTALLER install $OPTION libboost1.67-dev
;;
;;
esac
fi
......
......@@ -29,45 +29,61 @@ AMF_CONF[@SERVED_GUAMI_AMF_SET_ID_1@]='1'
AMF_CONF[@PLMN_SUPPORT_MCC@]='208'
AMF_CONF[@PLMN_SUPPORT_MNC@]='95'
AMF_CONF[@PLMN_SUPPORT_TAC@]='0xa000'
AMF_CONF[@SST_0@]='222'
AMF_CONF[@SD_0@]='123'
AMF_CONF[@SST_0@]='128'
AMF_CONF[@SD_0@]='128'
AMF_CONF[@SST_1@]='1'
AMF_CONF[@SD_1@]='12'
AMF_CONF[@SD_1@]='1'
AMF_CONF[@AMF_INTERFACE_NAME_FOR_NGAP@]='wlo1'
AMF_CONF[@AMF_INTERFACE_NAME_FOR_N11@]='wlo1'
AMF_CONF[@AMF_INTERFACE_NAME_FOR_NGAP@]='eth0'
AMF_CONF[@AMF_INTERFACE_NAME_FOR_N11@]='eth0'
AMF_CONF[@EXTERNAL_AUSF@]='no'
AMF_CONF[@EXTERNAL_UDM@]='no'
AMF_CONF[@EXTERNAL_NRF@]='no'
AMF_CONF[@EXTERNAL_NSSF@]='no'
AMF_CONF[@USE_FQDN_DNS@]='no'
AMF_CONF[@USE_HTTP2@]='no'
AMF_CONF[@NF_REGISTRATION@]='no'
AMF_CONF[@SMF_SELECTION@]='no'
AMF_CONF[@SMF_INSTANCE_ID_0@]='1'
AMF_CONF[@SMF_IPV4_ADDR_0@]='192.168.122.1'
AMF_CONF[@SMF_IPV4_ADDR_0@]='192.168.22.208'
AMF_CONF[@SMF_HTTP_VERSION_0@]='v1'
AMF_CONF[@SMF_FQDN_0@]='localhost'
AMF_CONF[@SMF_FQDN_0@]='oai-smf'
AMF_CONF[@SMF_INSTANCE_ID_1@]='2'
AMF_CONF[@SMF_IPV4_ADDR_1@]='192.168.122.2'
AMF_CONF[@SMF_IPV4_ADDR_1@]='192.168.22.207'
AMF_CONF[@SMF_HTTP_VERSION_1@]='v1'
AMF_CONF[@SMF_FQDN_1@]='localhost'
AMF_CONF[@SMF_FQDN_1@]='oai-smf2'
AMF_CONF[@NRF_IPV4_ADDRESS@]='192.168.1.23'
AMF_CONF[@NRF_IPV4_ADDRESS@]='192.168.22.195'
AMF_CONF[@NRF_PORT@]='80'
AMF_CONF[@NRF_API_VERSION@]='v1'
AMF_CONF[@NRF_FQDN@]='localhost'
AMF_CONF[@NRF_FQDN@]='oai-nrf'
AMF_CONF[@AUSF_IPV4_ADDRESS@]='192.168.1.23'
AMF_CONF[@AUSF_IPV4_ADDRESS@]='192.168.22.199'
AMF_CONF[@AUSF_PORT@]='80'
AMF_CONF[@AUSF_API_VERSION@]='v1'
AMF_CONF[@AUSF_FQDN@]='localhost'
AMF_CONF[@AUSF_FQDN@]='oai-ausf'
AMF_CONF[@NSSF_IPV4_ADDRESS@]='192.168.22.214'
AMF_CONF[@NSSF_PORT@]='80'
AMF_CONF[@NSSF_API_VERSION@]='v1'
AMF_CONF[@NSSF_FQDN@]='oai-nssf'
AMF_CONF[@UDM_IPV4_ADDRESS@]='192.168.22.209'
AMF_CONF[@UDM_PORT@]='80'
AMF_CONF[@UDM_API_VERSION@]='v1'
AMF_CONF[@UDM_FQDN@]='oai-udm'
AMF_CONF[@NRF_SELECTION@]='no'
AMF_CONF[@INT_ALGO_LIST@]='[ "NIA0" , "NIA1" , "NIA2" ]'
AMF_CONF[@CIPH_ALGO_LIST@]='[ "NEA0" , "NEA1" , "NEA2" ]'
AMF_CONF[@MYSQL_SERVER@]='127.0.0.1'
AMF_CONF[@MYSQL_USER@]='root'
AMF_CONF[@MYSQL_PASS@]='linux'
AMF_CONF[@MYSQL_DB@]='oai_db'
AMF_CONF[@OPERATOR_KEY@]='63bfa50ee6523365ff14c1f45f88737d'
for K in "${!AMF_CONF[@]}"; do
egrep -lRZ "$K" $PREFIX | xargs -0 -l sed -i -e "s|$K|${AMF_CONF[$K]}|g"
......
......@@ -182,7 +182,9 @@ pipeline {
success {
script {
sh 'echo "DEPLOYMENT: OK" > archives/deployment_status.log'
sh 'python3 ./ci-scripts/routeCheck.py --mode=Add --userName=' + dsT_host_user + ' --hostName=' + dsT_host
if (dsT_host_flag) {
sh 'python3 ./ci-scripts/routeCheck.py --mode=Add --userName=' + dsT_host_user + ' --hostName=' + dsT_host
}
}
}
unsuccessful {
......@@ -242,7 +244,9 @@ pipeline {
steps {
script {
echo '\u2705 \u001B[32mUn-Deploy AMF\u001B[0m'
sh 'python3 ./ci-scripts/routeCheck.py --mode=Delete --userName=' + dsT_host_user + ' --hostName=' + dsT_host
if (dsT_host_flag) {
sh 'python3 ./ci-scripts/routeCheck.py --mode=Delete --userName=' + dsT_host_user + ' --hostName=' + dsT_host
}
dir('ci-scripts/dsTesterDockerCompose') {
sh 'docker-compose down > ../../archives/compose_normal_down.log 2>&1'
}
......@@ -259,7 +263,9 @@ pipeline {
sh 'docker logs cicd-oai-amf > archives/logs/oai_amf.log'
}
// Remove any leftover containers/networks
sh 'python3 ./ci-scripts/routeCheck.py --mode=Delete --userName=' + dsT_host_user + ' --hostName=' + dsT_host
if (dsT_host_flag) {
sh 'python3 ./ci-scripts/routeCheck.py --mode=Delete --userName=' + dsT_host_user + ' --hostName=' + dsT_host
}
dir('ci-scripts/dsTesterDockerCompose') {
sh 'docker-compose down > ../../archives/compose_l_down.log 2>&1'
}
......
......@@ -50,6 +50,9 @@ def AMF_BASE_IMAGE_TAG = params.AmfBaseImageTag
// Merge Request Link
def gitlabMergeRequestLink
// Docker Hub account to push to
def DH_Account = "oaisoftwarealliance"
//-------------------------------------------------------------------------------
// Pipeline start
pipeline {
......@@ -135,7 +138,6 @@ pipeline {
echo "MR TITLE is ${env.gitlabMergeRequestTitle}"
gitCommitAuthorEmailAddr = env.gitlabUserEmail
echo "GitLab Usermail is ${gitCommitAuthorEmailAddr}"
sh "git fetch --prune --unshallow"
shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" ' + env.gitlabMergeRequestLastCommit
shortenShaOne = shortenShaOne.trim()
sh "./ci-scripts/doGitLabMerge.sh --src-branch ${env.gitlabSourceBranch} --src-commit ${env.gitlabMergeRequestLastCommit} --target-branch ${env.gitlabTargetBranch} --target-commit ${GIT_COMMIT}"
......@@ -186,7 +188,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-amf --tag oai-amf:' + amf_tag + ' --file docker/Dockerfile.amf.ubuntu18 --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > archives/amf_docker_image_build.log 2>&1', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd('docker build --no-cache --target oai-amf --tag oai-amf:' + amf_tag + ' --file docker/Dockerfile.amf.ubuntu18 . > archives/amf_docker_image_build.log 2>&1', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
}
if ("MERGE".equals(env.gitlabActionType)) {
try {
......@@ -201,6 +203,9 @@ pipeline {
myShCmd('docker image tag oai-amf-base:' + AMF_BASE_IMAGE_TAG + ' oai-amf-base:latest', rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd('docker build --no-cache --target oai-amf --tag oai-amf:' + amf_tag + ' --file ci-scripts/docker/Dockerfile.ci.ubuntu.18.04 . > archives/amf_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-amf:' + amf_tag, rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd('docker image ls >> archives/amf_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)) {
......@@ -243,10 +248,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-amf --tag oai-amf:' + amf_tag + ' --file docker/Dockerfile.amf.rhel8 --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . > archives/amf_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-amf --tag oai-amf:' + amf_tag + ' --file docker/Dockerfile.amf.rhel8 . > archives/amf_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-amf:' + amf_tag, rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
myShCmd('sudo podman image ls >> archives/amf_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-amf:' + amf_tag + ' oai-amf:' + rhel_amf_tag, rem_rhel_host_flag, rem_rhel_host_user, rem_rhel_host)
......@@ -439,6 +448,36 @@ pipeline {
}
}
}
stage ('Testing the tutorials') {
steps {
script {
gitlabCommitStatus(name: "Test tutorials") {
localStatus = build job: 'OAI-CN5G-Tutorials-Check',
parameters: [
string(name: 'AMF_TAG', value: String.valueOf(amf_tag)),
string(name: 'AMF_BRANCH', value: String.valueOf(amf_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.
......@@ -451,9 +490,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-amf:develop ${DH_Username}/oai-amf:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker push ${DH_Username}/oai-amf:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker rmi ${DH_Username}/oai-amf:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker image tag oai-amf:develop ${DH_Account}/oai-amf:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker push ${DH_Account}/oai-amf:develop", rem_u18_host_flag, rem_u18_host_user, rem_u18_host)
myShCmd("docker rmi ${DH_Account}/oai-amf: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)
}
}
......
......@@ -198,8 +198,14 @@ class HtmlReport():
self.file.write(' </tr>\n')
def testSummaryHeader(self):
self.file.write(' <h2>DS Tester Summary</h2>\n')
cwd = os.getcwd()
if not os.path.isfile(cwd + '/DS-TEST-RESULTS/dsTester_Summary.txt'):
self.file.write(' <br>\n')
self.file.write(' <div class="alert alert-warning">\n')
self.file.write(' <strong>NO TESTING DONE BEFORE MIGRATION TO NEW RAN EMULATOR <span class="glyphicon glyphicon-warning-sign"></span></strong>\n')
self.file.write(' </div>\n')
return True
self.file.write(' <h2>DS Tester Summary</h2>\n')
finalStatusOK = False
if os.path.isfile(cwd + '/DS-TEST-RESULTS/dcamf.yaml'):
cmd = f'egrep -c "final-result: pass" DS-TEST-RESULTS/dcamf.yaml || true'
......@@ -226,6 +232,9 @@ class HtmlReport():
def testSummaryDetails(self):
self.file.write(' <br>\n')
cwd = os.getcwd()
if not os.path.isfile(cwd + '/DS-TEST-RESULTS/dsTester_Summary.txt'):
return
self.file.write(' <button data-toggle="collapse" data-target="#ds-tester-details">More details on DsTester results</button>\n')
self.file.write(' <div id="ds-tester-details" class="collapse">\n')
self.file.write(' <table class="table-bordered" width = "60%" align = "center" border = 1>\n')
......@@ -234,7 +243,6 @@ class HtmlReport():
self.file.write(' <th>Test Status</th>\n')
self.file.write(' <th>Test Details</th>\n')
self.file.write(' </tr>\n')
cwd = os.getcwd()
if os.path.isfile(cwd + '/DS-TEST-RESULTS/dcamf.yaml'):
with open(cwd + '/DS-TEST-RESULTS/dcamf.yaml') as f:
data = yaml.load(f)
......
......@@ -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`
......
......@@ -37,7 +37,9 @@ RUN cp -Rf /openair-amf-ext-ref /openair-amf/build/ext
# Building AMF
WORKDIR /openair-amf/build/scripts
RUN ./build_amf --clean --Verbose --build-type Release --jobs && \
RUN ldconfig && \
./build_amf --clean --Verbose --build-type Release --jobs && \
ldd /openair-amf/build/amf/build/amf && \
mv /openair-amf/build/amf/build/amf /openair-amf/build/amf/build/oai_amf
#---------------------------------------------------------------------
......@@ -56,8 +58,8 @@ RUN apt-get update && \
bc \
openssl \
perl \
tshark \
libasan4 \
libgssapi-krb5-2 \
libldap-2.4-2 \
libconfig++9v5 \
libsctp1 \
......@@ -81,6 +83,7 @@ COPY --from=oai-amf-builder \
WORKDIR /usr/local/lib
COPY --from=oai-amf-builder \
/usr/local/lib/libnghttp2.so.14 \
/usr/local/lib/libnghttp2_asio.so.1 \
/usr/lib/libboost_system.so.1.67.0 \
/usr/lib/libboost_thread.so.1.67.0 \
......@@ -88,7 +91,8 @@ COPY --from=oai-amf-builder \
/usr/local/lib/libpistache.so \
./
RUN ldconfig
RUN ldconfig && \
ldd /openair-amf/bin/oai_amf
# Copying template configuration files
WORKDIR /openair-amf/etc
......
......@@ -73,7 +73,6 @@ services:
- MYSQL_USER=root
- MYSQL_PASS=linux
- MYSQL_DB=oai_db
- OPERATOR_KEY=63bfa50ee6523365ff14c1f45f88737d
- NRF_IPV4_ADDRESS=0.0.0.0
- NRF_PORT=80
- NF_REGISTRATION=no
......@@ -85,6 +84,10 @@ services:
- AUSF_PORT=80
- AUSF_API_VERSION=v1
- AUSF_FQDN=localhost
- UDM_IPV4_ADDRESS=0.0.0.0
- UDM_PORT=80
- UDM_API_VERSION=v1
- UDM_FQDN=localhost
- NSSF_IPV4_ADDRESS=0.0.0.0
- NSSF_PORT=80
- NSSF_API_VERSION=v1
......
"""
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-amf" '
cmd += ' --change "EXPOSE 80/tcp" '
cmd += ' --change "EXPOSE 9090/tcp" '
if cli == 'docker':
cmd += ' --change "EXPOSE 38412/sctp" '
cmd += ' --change "CMD [\\"/openair-amf/bin/oai_amf\\", \\"-c\\", \\"/openair-amf/etc/amf.conf\\", \\"-o\\"]" '
cmd += ' --change "ENTRYPOINT [\\"/bin/bash\\", \\"/openair-amf/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()
......@@ -603,7 +603,7 @@ class HtmlReport():
status = False
if nfType == 'AMF':
section_start_pattern = 'build_amf --clean --Verbose --build-type Release --jobs'
section_end_pattern = 'FROM ubuntu:bionic as oai-amf$'
section_end_pattern = 'FROM .* as oai-amf$'
pass_pattern = 'amf installed'
section_status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
......@@ -653,7 +653,7 @@ class HtmlReport():
if os.path.isfile(cwd + '/archives/' + logFileName):
if nfType == 'AMF':
section_start_pattern = 'build_amf --clean --Verbose --build-type Release --jobs'
section_end_pattern = 'FROM ubuntu:bionic as oai-amf$'
section_end_pattern = 'FROM .* as oai-amf$'
section_status = False
with open(cwd + '/archives/' + logFileName, 'r') as logfile:
for line in logfile:
......@@ -723,7 +723,7 @@ class HtmlReport():
for variant in variants:
logFileName = 'amf_' + variant + '_image_build.log'
if os.path.isfile(cwd + '/archives/' + logFileName):
section_start_pattern = 'FROM ubuntu:bionic as oai-amf$'
section_start_pattern = 'FROM .* as oai-amf$'
section_end_pattern = 'WORKDIR /openair-amf/etc'
section_status = False
status = False
......@@ -843,7 +843,7 @@ class HtmlReport():
result = re.search('oai-amf *ci-tmp', line)
else:
result = re.search('oai-amf *develop', line)
if result is not None:
if result is not None and not status:
result = re.search('ago *([0-9A-Z ]+)', line)
if result is not None:
size = result.group(1)
......
......@@ -32,8 +32,12 @@ FROM registry.access.redhat.com/ubi8/ubi:latest AS oai-amf-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=* && \
......@@ -55,8 +59,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 http.sslverify false
# Copying source code
......@@ -69,7 +73,9 @@ RUN ./build_amf --install-deps --force
# Building AMF
WORKDIR /openair-amf/build/scripts
RUN ./build_amf --clean --Verbose --build-type Release --jobs && \
RUN ldconfig && \
./build_amf --clean --Verbose --build-type Release --jobs && \
ldd /openair-amf/build/amf/build/amf && \
mv /openair-amf/build/amf/build/amf /openair-amf/build/amf/build/oai_amf
#---------------------------------------------------------------------
......@@ -86,7 +92,8 @@ RUN yum update -y && \
psmisc \
net-tools \
libevent && \
rm -rf /var/lib/apt/lists/*
yum clean all -y && \
rm -rf /var/cache/yum /var/cache/dnf
# Copying executable and generated libraries
WORKDIR /openair-amf/bin
......@@ -116,7 +123,8 @@ COPY --from=oai-amf-builder \
/usr/lib64/libicuuc.so.60 \
/usr/lib64/
RUN ldconfig
RUN ldconfig && \
ldd /openair-amf/bin/oai_amf
# Copying template configuration files
WORKDIR /openair-amf/etc
......
......@@ -44,8 +44,8 @@ RUN apt-get update && \
&& rm -rf /var/lib/apt/lists/*
# Some GIT configuration commands 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 http.sslverify false
# Copying source code
......@@ -58,7 +58,9 @@ RUN ./build_amf --install-deps --force
# Building AMF
WORKDIR /openair-amf/build/scripts
RUN ./build_amf --clean --Verbose --build-type Release --jobs && \
RUN ldconfig && \
./build_amf --clean --Verbose --build-type Release --jobs && \
ldd /openair-amf/build/amf/build/amf && \
mv /openair-amf/build/amf/build/amf /openair-amf/build/amf/build/oai_amf
#---------------------------------------------------------------------
......@@ -77,8 +79,8 @@ RUN apt-get update && \
bc \
openssl \
perl \
tshark \
libasan4 \
libgssapi-krb5-2 \
libldap-2.4-2 \
libconfig++9v5 \
libsctp1 \
......@@ -102,6 +104,7 @@ COPY --from=oai-amf-builder \
WORKDIR /usr/local/lib
COPY --from=oai-amf-builder \
/usr/local/lib/libnghttp2.so.14 \
/usr/local/lib/libnghttp2_asio.so.1 \
/usr/lib/libboost_system.so.1.67.0 \
/usr/lib/libboost_thread.so.1.67.0 \
......@@ -109,7 +112,8 @@ COPY --from=oai-amf-builder \
/usr/local/lib/libpistache.so \
./
RUN ldconfig
RUN ldconfig && \
ldd /openair-amf/bin/oai_amf
# Copying template configuration files
WORKDIR /openair-amf/etc
......
......@@ -51,14 +51,14 @@ Based on document **3GPP TS 23.501 V16.0.0 §6.2.1**.
| 10 | Transparent proxy for routing SM messages | :x: | |
| 11 | Access Authentication | :heavy_check_mark: | |
| 12 | Access Authorization | :heavy_check_mark: | |
| 13 | Provide transport for SMS messages between UE and SMSF. | :x: | |
| 13 | Provide transport for SMS messages between UE and SMSF | :x: | |
| 14 | Security Anchor Functionality (SEAF) | :heavy_check_mark: | |
| 15 | Location Services management for regulatory services | :x: | |
| 16 | Provide transport for Location Services messages between | | |
| | UE and LMF as well as between RAN and LMF. | :x: | |
| 17 | EPS Bearer ID allocation for interworking with EPS. | :x: | |
| | UE and LMF as well as between RAN and LMF | :heavy_check_mark: | |
| 17 | EPS Bearer ID allocation for interworking with EPS | :x: | |
| 18 | UE mobility event notification | :heavy_check_mark: | |
| 19 | Support for Control Plane CIoT 5GS Optimisation. | :x: | |
| 19 | Support for Control Plane CIoT 5GS Optimisation | :x: | |
| 20 | Provisioning of external parameters | :x: | |
| 21 | Support non-3GPP access networks | :x: | |
......@@ -28,7 +28,7 @@ AMF =
RELATIVE_CAPACITY = 30;
# Display statistics about whole system (in seconds)
STATISTICS_TIMER_INTERVAL = 20; # YOUR CONFIG HERE
STATISTICS_TIMER_INTERVAL = 20;
CORE_CONFIGURATION:
{
......@@ -37,7 +37,7 @@ AMF =
GUAMI:
{
MCC = "@MCC@"; MNC = "@MNC@"; RegionID = "@REGION_ID@"; AMFSetID = "@AMF_SET_ID@"; AMFPointer = "1" # YOUR GUAMI CONFIG HERE
MCC = "@MCC@"; MNC = "@MNC@"; RegionID = "@REGION_ID@"; AMFSetID = "@AMF_SET_ID@"; AMFPointer = "1"
}
SERVED_GUAMI_LIST = (
......@@ -47,10 +47,11 @@ AMF =
PLMN_SUPPORT_LIST = (
{
MCC = "@PLMN_SUPPORT_MCC@"; MNC = "@PLMN_SUPPORT_MNC@"; TAC = @PLMN_SUPPORT_TAC@; # YOUR PLMN CONFIG HERE
MCC = "@PLMN_SUPPORT_MCC@"; MNC = "@PLMN_SUPPORT_MNC@"; TAC = @PLMN_SUPPORT_TAC@;
SLICE_SUPPORT_LIST = (
{SST = "@SST_0@"; SD = "@SD_0@"}, # YOUR NSSAI CONFIG HERE
{SST = "@SST_1@"; SD = "@SD_1@"} # YOUR NSSAI CONFIG HERE
{SST = "@SST_0@"; SD = "@SD_0@"},
{SST = "@SST_1@"; SD = "@SD_1@"},
{SST = "@SST_2@"; SD = "@SD_2@"}
)
}
);
......@@ -60,49 +61,57 @@ AMF =
# AMF binded interface for N1/N2 interface (NGAP)
NGAP_AMF:
{
INTERFACE_NAME = "@AMF_INTERFACE_NAME_FOR_NGAP@"; # YOUR NETWORK CONFIG HERE
INTERFACE_NAME = "@AMF_INTERFACE_NAME_FOR_NGAP@";
IPV4_ADDRESS = "read";
PORT = 38412; # YOUR NETWORK CONFIG HERE
PPID = 60; # YOUR NETWORK CONFIG HERE
PORT = 38412;
PPID = 60;
};
# AMF binded interface for SBI (N11 (SMF)/N12 (AUSF), etc.)
N11:
{
INTERFACE_NAME = "@AMF_INTERFACE_NAME_FOR_N11@"; # YOUR NETWORK CONFIG HERE
INTERFACE_NAME = "@AMF_INTERFACE_NAME_FOR_N11@";
IPV4_ADDRESS = "read";
PORT = 80; # YOUR NETWORK CONFIG HERE
API_VERSION = "v1"; # YOUR AMF API VERSION CONFIG HERE
HTTP2_PORT = 8080; # YOUR NETWORK CONFIG HERE
PORT = 80;
API_VERSION = "v1";
HTTP2_PORT = 8080;
SMF_INSTANCES_POOL = (
{SMF_INSTANCE_ID = @SMF_INSTANCE_ID_0@; IPV4_ADDRESS = "@SMF_IPV4_ADDR_0@"; PORT = "80"; HTTP2_PORT = 8080, VERSION = "@SMF_HTTP_VERSION_0@"; FQDN = "@SMF_FQDN_0@", SELECTED = "true"}, # YOUR SMF CONFIG HERE
{SMF_INSTANCE_ID = @SMF_INSTANCE_ID_1@; IPV4_ADDRESS = "@SMF_IPV4_ADDR_1@"; PORT = "80"; HTTP2_PORT = 8080, VERSION = "@SMF_HTTP_VERSION_1@"; FQDN = "@SMF_FQDN_1@", SELECTED = "false"} # YOUR SMF CONFIG HERE
{SMF_INSTANCE_ID = @SMF_INSTANCE_ID_0@; IPV4_ADDRESS = "@SMF_IPV4_ADDR_0@"; PORT = "80"; HTTP2_PORT = 8080, VERSION = "@SMF_HTTP_VERSION_0@"; FQDN = "@SMF_FQDN_0@", SELECTED = "true"},
{SMF_INSTANCE_ID = @SMF_INSTANCE_ID_1@; IPV4_ADDRESS = "@SMF_IPV4_ADDR_1@"; PORT = "80"; HTTP2_PORT = 8080, VERSION = "@SMF_HTTP_VERSION_1@"; FQDN = "@SMF_FQDN_1@", SELECTED = "false"}
);
};
NRF :
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 FOR SBI CONFIG HERE
FQDN = "@NRF_FQDN@" # YOUR NRF FQDN CONFIG HERE
IPV4_ADDRESS = "@NRF_IPV4_ADDRESS@";
PORT = @NRF_PORT@; # Default: 80
API_VERSION = "@NRF_API_VERSION@";
FQDN = "@NRF_FQDN@"
};
AUSF :
{
IPV4_ADDRESS = "@AUSF_IPV4_ADDRESS@"; # YOUR AUSF CONFIG HERE
PORT = @AUSF_PORT@; # YOUR AUSF CONFIG HERE (default: 80)
API_VERSION = "@AUSF_API_VERSION@"; # YOUR AUSF API VERSION FOR SBI CONFIG HERE
FQDN = "@AUSF_FQDN@" # YOUR AUSF FQDN CONFIG HERE
IPV4_ADDRESS = "@AUSF_IPV4_ADDRESS@";
PORT = @AUSF_PORT@; # Default: 80
API_VERSION = "@AUSF_API_VERSION@";
FQDN = "@AUSF_FQDN@"
};
UDM :
{
IPV4_ADDRESS = "@UDM_IPV4_ADDRESS@";
PORT = @UDM_PORT@; # Default: 80
API_VERSION = "v2";
FQDN = "@UDM_FQDN@";
};
NSSF :
{
IPV4_ADDRESS = "@NSSF_IPV4_ADDRESS@"; # YOUR NSSF CONFIG HERE
PORT = @NSSF_PORT@; # YOUR NSSF CONFIG HERE (default: 80)
API_VERSION = "@NSSF_API_VERSION@"; # YOUR NSSF API VERSION FOR SBI CONFIG HERE
FQDN = "@NSSF_FQDN@" # YOUR NSSF FQDN CONFIG HERE
IPV4_ADDRESS = "@NSSF_IPV4_ADDRESS@";
PORT = @NSSF_PORT@; # Default: 80
API_VERSION = "@NSSF_API_VERSION@";
FQDN = "@NSSF_FQDN@"
};
};
......@@ -111,11 +120,13 @@ AMF =
# STRING, {"yes", "no"},
NF_REGISTRATION = "@NF_REGISTRATION@"; # Set to yes if AMF resgisters to an NRF
NRF_SELECTION = "@NRF_SELECTION@"; # Set to yes to enable NRF discovery and selection
EXTERNAL_NRF = "@EXTERNAL_NRF@"; # Set to yes if AMF works with an external NRF
SMF_SELECTION = "@SMF_SELECTION@"; # Set to yes to enable SMF discovery and selection
EXTERNAL_AUSF = "@EXTERNAL_AUSF@"; # Set to yes if AMF works with an external AUSF
EXTERNAL_UDM = "@EXTERNAL_UDM@"; # Set to yes if AMF works with an external UDM
EXTERNAL_NSSF = "@EXTERNAL_NSSF@"; # Set to yes if AMF works with an external NSSF
USE_FQDN_DNS = "@USE_FQDN_DNS@"; # Set to yes if AMF relies on a DNS to resolve NRF/SMF/UDM/AUSF's FQDN
USE_HTTP2 = "@USE_HTTP2@"; # Set to yes to enable HTTP2 for AMF server
USE_HTTP2 = "@USE_HTTP2@"; # Set to yes to enable HTTP2 for AMF server
}
AUTHENTICATION:
......@@ -125,9 +136,6 @@ AMF =
MYSQL_user = "@MYSQL_USER@"; # Database server login
MYSQL_pass = "@MYSQL_PASS@"; # Database server password
MYSQL_db = "@MYSQL_DB@"; # Your database name
## OP
OPERATOR_key = "@OPERATOR_KEY@"; # OP key matching your database
RANDOM = "true";
};
......@@ -136,10 +144,8 @@ AMF =
ORDERED_SUPPORTED_INTEGRITY_ALGORITHM_LIST = @INT_ALGO_LIST@; #Default [ "NIA0" , "NIA1" , "NIA2" ];
ORDERED_SUPPORTED_CIPHERING_ALGORITHM_LIST = @CIPH_ALGO_LIST@; #Default [ "NEA0" , "NEA1" , "NEA2" ];
};
};
MODULES =
{
NGAP_MESSAGE = (
......
......@@ -5,9 +5,17 @@ set -euo pipefail
CONFIG_DIR="/openair-amf/etc"
# Default values
EXTERNAL_NRF=${EXTERNAL_NRF:-no}
EXTERNAL_NSSF=${EXTERNAL_NSSF:-no}
EXTERNAL_AUSF=${EXTERNAL_AUSF:-no}
EXTERNAL_UDM=${EXTERNAL_UDM:-no}
UDM_IPV4_ADDRESS=${UDM_IPV4_ADDRESS:-0.0.0.0}
UDM_PORT=${UDM_PORT:-80}
UDM_API_VERSION=${UDM_API_VERSION:-v2}
UDM_FQDN=${UDM_FQDN:-oai-udm}
EXTERNAL_NRF=${EXTERNAL_NRF:-no}
NRF_SELECTION=${NRF_SELECTION:-no}
EXTERNAL_NSSF=${EXTERNAL_NSSF:-no}
NSSF_IPV4_ADDRESS=${NSSF_IPV4_ADDRESS:-0.0.0.0}
NSSF_PORT=${NSSF_PORT:-80}
NSSF_API_VERSION=${NSSF_API_VERSION:-v2}
......@@ -15,6 +23,13 @@ NSSF_FQDN=${NSSF_FQDN:-oai-nssf}
INT_ALGO_LIST=${INT_ALGO_LIST:-'[ "NIA0" , "NIA1" , "NIA2" ]'}
CIPH_ALGO_LIST=${CIPH_ALGO_LIST:-'[ "NEA0" , "NEA1" , "NEA2" ]'}
USE_HTTP2=${USE_HTTP2:-no}
SST_0=${SST_0:-128}
SD_0=${SD_0:-128}
SST_1=${SST_1:-1}
SD_1=${SD_1:-0xFFFFFF}
SST_2=${SST_2:-130}
SD_2=${SD_2:-130}
OPERATOR_KEY=${OPERATOR_KEY:-'63bfa50ee6523365ff14c1f45f88737d'}
if [[ ${USE_FQDN_DNS} == "yes" ]];then
NSSF_IPV4_ADDR=${NSSF_IPV4_ADDR_0:-0.0.0.0}
......@@ -22,6 +37,7 @@ if [[ ${USE_FQDN_DNS} == "yes" ]];then
SMF_IPV4_ADDR_1=${SMF_IPV4_ADDR_1:-0.0.0.0}
NRF_IPV4_ADDRESS=${NRF_IPV4_ADDRESS:-0.0.0.0}
AUSF_IPV4_ADDRESS=${AUSF_IPV4_ADDRESS:-0.0.0.0}
UDM_IPV4_ADDRESS=${UDM_IPV4_ADDRESS:-0.0.0.0}
fi
for c in ${CONFIG_DIR}/*.conf; do
......
......@@ -38,10 +38,6 @@ include_directories(${SRC_TOP_DIR}/sbi/amf_server)
include_directories(${SRC_TOP_DIR}/sbi/amf_server/api)
include_directories(${SRC_TOP_DIR}/sbi/amf_server/impl)
include_directories(${SRC_TOP_DIR}/sbi/amf_server/model)
include_directories(${SRC_TOP_DIR}/sbi/smf_client)
include_directories(${SRC_TOP_DIR}/sbi/smf_client/api)
include_directories(${SRC_TOP_DIR}/sbi/smf_client/inputs)
include_directories(${SRC_TOP_DIR}/sbi/smf_client/model)
include_directories(${SRC_TOP_DIR}/sctp)
include_directories(${SRC_TOP_DIR}/secu_algorithms/5gaka)
include_directories(${SRC_TOP_DIR}/secu_algorithms/nas_enc_int)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -27,6 +27,7 @@
*/
#include "amf_module_from_config.hpp"
#include "common_defs.h"
#include <iostream>
#include <string>
......@@ -58,7 +59,7 @@ int amf_modules::load(const std::string& config_file) {
const Setting& modules = root[MODULES_CONFIG_STRING_AMF_MODULES];
} catch (const SettingNotFoundException& nfex) {
Logger::amf_app().error("%s : %s", nfex.what(), nfex.getPath());
return -1;
return RETURNerror;
}
const Setting& modules = root[MODULES_CONFIG_STRING_AMF_MODULES];
const Setting& msg = modules[MODULES_CONFIG_STRING_AMF_MODULES_NGAP_MESSAGE];
......
......@@ -50,15 +50,24 @@ namespace config {
class amf_modules {
public:
/*
* Load AMF modules configuration
* @param [const std::string&] config_file: Configuration file
* @return RETURNclear/RETURNerror/RETURNok
*/
int load(const std::string& config_file);
/*
* Display the AMF modules configuration parameters
* @param void
* @return void
*/
void display();
void makeModulesAlive();
private:
std::string msgName; // vector to store more msgs
Ngap_NGAP_PDU_PR typeOfMsg;
Ngap_ProcedureCode_t procedureCode;
// NGSetupRequestMsg *ngSetupRequest;
};
} // namespace config
......
......@@ -75,11 +75,11 @@ class event_exposure_msg {
bool m_supi_is_set;
bool m_any_ue; // anyUE, Conditional
// subsChangeNotifyUri:
// subsChangeNotifyCorrelationId:
// groupId:
// gpsi:
// pei:
// subsChangeNotifyUri
// subsChangeNotifyCorrelationId
// groupId
// gpsi
// pei
// options: AmfEventMode
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -43,48 +43,270 @@ class amf_n2 : public ngap::ngap_app {
public:
amf_n2(const std::string& address, const uint16_t port_num);
~amf_n2();
/*
* Handle ITTI message (New SCTP Association)
* @param [itti_new_sctp_association&]: ITTI message
* @return void
*/
void handle_itti_message(itti_new_sctp_association& new_assoc);
/*
* Handle ITTI message (Downlink NAS Transfer)
* @param [itti_downlink_nas_transfer&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ng_setup_request& ngsetupreq);
/*
* Handle ITTI message (Downlink NAS Transfer)
* @param [itti_downlink_nas_transfer&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ng_reset&);
/*
* Handle ITTI message (SCTP Shutdown)
* @param [itti_ng_shutdown&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ng_shutdown&);
/*
* Handle ITTI message (InitialUEMessage)
* @param [itti_initial_ue_message&]: ITTI message
* @return void
*/
void handle_itti_message(itti_initial_ue_message& init_ue_msg);
/*
* Handle ITTI message (ULNASTransport)
* @param [itti_ul_nas_transport&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ul_nas_transport& ul_nas_transport);
/*
* Handle ITTI message (DLNASTransport)
* @param [itti_dl_nas_transport&]: ITTI message
* @return void
*/
void handle_itti_message(itti_dl_nas_transport& dl_nas_transport);
/*
* Handle ITTI message (InitialContextSetupRequest)
* @param [itti_initial_context_setup_request&]: ITTI message
* @return void
*/
void handle_itti_message(itti_initial_context_setup_request& itti_msg);
/*
* Handle ITTI message (PDUSessionResourceSetupRequest)
* @param [itti_pdu_session_resource_setup_request&]: ITTI message
* @return void
*/
void handle_itti_message(itti_pdu_session_resource_setup_request& itti_msg);
/*
* Handle ITTI message (PDUSessionResourceModifyRequest)
* @param [itti_pdu_session_resource_modify_request&]: ITTI message
* @return void
*/
void handle_itti_message(itti_pdu_session_resource_modify_request& itti_msg);
/*
* Handle ITTI message (PDUSessionResourceReleaseCommand)
* @param [itti_pdu_session_resource_release_command&]: ITTI message
* @return void
*/
void handle_itti_message(itti_pdu_session_resource_release_command& itti_msg);
/*
* Handle ITTI message (PDUSessionResourceReleaseRequest)
* @param [itti_ue_context_release_request&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ue_context_release_request& itti_msg);
/*
* Handle ITTI message (PDUSessionResourceReleaseComplete)
* @param [itti_ue_context_release_complete&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ue_context_release_complete& itti_msg);
void handle_itti_message(itti_ue_radio_capability_indication& itti_msg);
/*
* Handle ITTI message (UEContextReleaseCommand)
* @param [itti_ue_context_release_command&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ue_context_release_command& itti_msg);
/*
* Handle ITTI message (UECapabilityIndication)
* @param [itti_ue_radio_capability_indication&]: ITTI message
* @return void
*/
void handle_itti_message(itti_ue_radio_capability_indication& itti_msg);
/*
* Handle ITTI message (HandoverRequired)
* @param [itti_handover_required&]: ITTI message
* @return void
*/
bool handle_itti_message(itti_handover_required& itti_msg);
/*
* Handle ITTI message (HandoverRequestAck)
* @param [itti_handover_request_Ack&]: ITTI message
* @return void
*/
void handle_itti_message(itti_handover_request_Ack& itti_msg);
/*
* Handle ITTI message (HandoverNotify)
* @param [itti_handover_notify&]: ITTI message
* @return void
*/
void handle_itti_message(itti_handover_notify& itti_msg);
/*
* Handle ITTI message (UplinkRANStatusTransfer)
* @param [itti_uplink_ran_status_transfer&]: ITTI message
* @return void
*/
void handle_itti_message(itti_uplink_ran_status_transfer& itti_msg);
/*
* Handle ITTI message (RerouteNAS)
* @param [itti_rereoute_nas&]: ITTI message
* @return void
*/
void handle_itti_message(itti_rereoute_nas& itti_msg);
/*
* Handle ITTI message (Paging)
* @param [itti_paging&]: ITTI message
* @return void
*/
void handle_itti_message(itti_paging& itti_msg);
/*
* Send Handover Preparaton Failure message
* @param [const unsigned long] amf_ue_ngap_id: AMF UE NGAP ID
* @param [const uint32_t] ran_ue_ngap_id: RAN UE NGAP ID
* @param [const sctp_assoc_id_t&] gnb_assoc_id: gNB Association ID
* @return void
*/
void send_handover_preparation_failure(
const unsigned long amf_ue_ngap_id, const uint32_t ran_ue_ngap_id,
const sctp_assoc_id_t& gnb_assoc_id);
void handle_itti_message(itti_paging& itti_msg);
bool verifyPlmn(std::vector<SupportedItem_t> list);
std::vector<SupportedItem_t> get_common_plmn(
std::vector<SupportedItem_t> list);
/*
* Get list of common PLMN between AMF and gNB
* @param [const std::vector<SupportedItem_t>&] list: Supported TA list from
* gNB
* @param [std::vector<SupportedItem_t>&] result: list of common TA
* @return true if there's at least 1 common TA, otherwise return false
*/
bool get_common_plmn(
const std::vector<SupportedItem_t>& list,
std::vector<SupportedItem_t>& result);
/*
* Get UE NGAP context associated with a RAN UE NGAP ID
* @param [const uint32_t&] ran_ue_ngap_id: RAN UE NGAP ID
* @return shared pointer to the UE NGAP context
*/
std::shared_ptr<ue_ngap_context> ran_ue_id_2_ue_ngap_context(
const uint32_t& ran_ue_ngap_id) const;
/*
* Verify whether a UE NGAP context associated with a RAN UE NGAP ID exist
* @param [const uint32_t&] ran_ue_ngap_id: RAN UE NGAP ID
* @return true if exist, otherwise return false
*/
bool is_ran_ue_id_2_ue_ngap_context(const uint32_t& ran_ue_ngap_id) const;
/*
* Store UE NGAP context associated with a RAN UE NGAP ID
* @param [const uint32_t&] ran_ue_ngap_id: RAN UE NGAP ID
* @param [const std::shared_ptr<ue_ngap_context>&] unc: pointer to UE NGAP
* context
* @return void
*/
void set_ran_ue_ngap_id_2_ue_ngap_context(
const uint32_t& ran_ue_ngap_id, std::shared_ptr<ue_ngap_context> unc);
const uint32_t& ran_ue_ngap_id,
const std::shared_ptr<ue_ngap_context>& unc);
/*
* Remove UE NGAP context associated with a RAN UE NGAP ID
* @param [const uint32_t&] ran_ue_ngap_id: RAN UE NGAP ID
* @return void
*/
void remove_ran_ue_ngap_id_2_ngap_context(const uint32_t& ran_ue_ngap_id);
/*
* Remove UE Context associated with a RAN UE NGAP ID
* @param [const uint32_t&] ran_ue_ngap_id: RAN UE NGAP ID
* @return void
*/
void remove_ue_context_with_ran_ue_ngap_id(const uint32_t& ran_ue_ngap_id);
/*
* Get UE NGAP context associated with a AMF UE NGAP ID
* @param [const unsigned long&] amf_ue_ngap_id: AMF UE NGAP ID
* @return shared pointer to the UE NGAP context
*/
std::shared_ptr<ue_ngap_context> amf_ue_id_2_ue_ngap_context(
const unsigned long& amf_ue_ngap_id) const;
/*
* Verify whether a UE NGAP context associated with a AMF UE NGAP ID exist
* @param [const unsigned long&] amf_ue_ngap_id: AMF UE NGAP ID
* @return true if exist, otherwise return false
*/
bool is_amf_ue_id_2_ue_ngap_context(
const unsigned long& amf_ue_ngap_id) const;
/*
* Store UE NGAP context associated with a AMF UE NGAP ID
* @param [const unsigned long&] amf_ue_ngap_id: AMF UE NGAP ID
* @param [const std::shared_ptr<ue_ngap_context>&] unc: pointer to UE NGAP
* context
* @return void
*/
void set_amf_ue_ngap_id_2_ue_ngap_context(
const unsigned long& amf_ue_ngap_id,
std::shared_ptr<ue_ngap_context> unc);
/*
* Remove UE NGAP context associated with a AMF UE NGAP ID
* @param [const unsigned long&] amf_ue_ngap_id: AMF UE NGAP ID
* @return void
*/
void remove_amf_ue_ngap_id_2_ue_ngap_context(
const unsigned long& amf_ue_ngap_id);
/*
* Remove UE Context associated with a AMF UE NGAP ID
* @param [const unsigned long&] amf_ue_ngap_id: AMF UE NGAP ID
* @return void
*/
void remove_ue_context_with_amf_ue_ngap_id(
const unsigned long& amf_ue_ngap_id);
/*
* Get list of UE Context associated with a gNB
* @param [const sctp_assoc_id_t&] gnb_assoc_id: gNB Association ID
* @param [std::vector<std::shared_ptr<ue_ngap_context>>&] ue_contexts: vector
* of UE Context
* @return void
*/
void get_ue_ngap_contexts(
const sctp_assoc_id_t& gnb_assoc_id,
std::vector<std::shared_ptr<ue_ngap_context>>& ue_contexts);
private:
std::map<uint32_t, std::shared_ptr<ue_ngap_context>>
ranid2uecontext; // ran ue ngap id
......
......@@ -151,6 +151,7 @@ void nf_profile::get_nf_snssais(std::vector<snssai_t>& s) const {
void nf_profile::add_snssai(const snssai_t& s) {
snssais.push_back(s);
}
//------------------------------------------------------------------------------
void nf_profile::set_nf_ipv4_addresses(const std::vector<struct in_addr>& a) {
ipv4_addresses = a;
......@@ -165,6 +166,10 @@ void nf_profile::get_nf_ipv4_addresses(std::vector<struct in_addr>& a) const {
a = ipv4_addresses;
}
//------------------------------------------------------------------------------
void nf_profile::delete_nf_ipv4_addresses() {
ipv4_addresses.clear();
}
//------------------------------------------------------------------------------
void nf_profile::display() const {
Logger::amf_app().debug("NF instance info");
......@@ -296,6 +301,11 @@ void amf_profile::get_nf_services(std::vector<nf_service_t>& n) const {
n = nf_services;
}
//------------------------------------------------------------------------------
void amf_profile::delete_nf_services() {
nf_services.clear();
}
//------------------------------------------------------------------------------
void amf_profile::set_custom_info(const nlohmann::json& c) {
custom_info = c;
......
......@@ -267,6 +267,12 @@ class nf_profile : public std::enable_shared_from_this<nf_profile> {
*/
void get_nf_ipv4_addresses(std::vector<struct in_addr>& a) const;
/*
* Remove all NF instance ipv4_addresses
* @param void
* @return void:
*/
void delete_nf_ipv4_addresses();
/*
* Print related-information for NF profile
* @param void
......@@ -349,6 +355,12 @@ class amf_profile : public nf_profile {
*/
void get_nf_services(std::vector<nf_service_t>& n) const;
/*
* Delete all NF services
* @param void
* @return void:
*/
void delete_nf_services();
/*
* Set custom info
* @param [const nlohmann::json &] c: custom info to be set
......
......@@ -30,6 +30,16 @@
#include "logger.hpp"
//------------------------------------------------------------------------------
statistics::statistics() : m_ue_infos(), m_gnbs() {
gNB_connected = 0;
UE_connected = 0;
UE_registred = 0;
}
//------------------------------------------------------------------------------
statistics::~statistics() {}
//------------------------------------------------------------------------------
void statistics::display() {
Logger::amf_app().info("");
......@@ -80,7 +90,7 @@ void statistics::display() {
i = 0;
for (auto const& ue : ue_infos) {
Logger::amf_app().info(
"|%7d|%22s|%18s|%15s|%16d|%11d| %3s,%3s |%7d|", i + 1,
"|%7d|%22s|%18s|%15s|%16ld|%11ld| %3s,%3s |%7d|", i + 1,
ue.second.registerStatus.c_str(), ue.second.imsi.c_str(),
ue.second.guti.c_str(), ue.second.ranid, ue.second.amfid,
ue.second.mcc.c_str(), ue.second.mnc.c_str(), ue.second.cellId);
......@@ -92,19 +102,14 @@ void statistics::display() {
Logger::amf_app().info("");
}
//------------------------------------------------------------------------------
statistics::statistics() {
gNB_connected = 0;
UE_connected = 0;
UE_registred = 0;
}
//------------------------------------------------------------------------------
void statistics::update_ue_info(const ue_info_t& ue_info) {
if (!(ue_info.imsi.size() > 0)) {
Logger::amf_app().warn("Update UE Info with invalid IMSI");
return;
}
std::unique_lock lock(m_ue_infos);
if (ue_infos.count(ue_info.imsi) > 0) {
ue_infos.erase(ue_info.imsi);
ue_infos.insert(std::pair<std::string, ue_info_t>(ue_info.imsi, ue_info));
......@@ -120,6 +125,7 @@ void statistics::update_ue_info(const ue_info_t& ue_info) {
//------------------------------------------------------------------------------
void statistics::update_5gmm_state(
const std::string& imsi, const std::string& state) {
std::unique_lock lock(m_ue_infos);
if (ue_infos.count(imsi) > 0) {
ue_info_t ue_info = ue_infos.at(imsi);
ue_info.registerStatus = state;
......@@ -134,6 +140,32 @@ void statistics::update_5gmm_state(
}
}
void statistics::remove_gnb(const uint32_t gnb_id) {}
//------------------------------------------------------------------------------
statistics::~statistics() {}
void statistics::remove_gnb(const uint32_t& gnb_id) {
std::unique_lock lock(m_gnbs);
if (gnbs.count(gnb_id) > 0) {
gnbs.erase(gnb_id);
gNB_connected -= 1;
}
}
//------------------------------------------------------------------------------
void statistics::add_gnb(const uint32_t& gnb_id, const gnb_infos& gnb) {
std::unique_lock lock(m_gnbs);
gnbs.insert(std::pair<uint32_t, gnb_infos>(gnb_id, gnb));
gNB_connected += 1;
}
//------------------------------------------------------------------------------
void statistics::update_gnb(const uint32_t& gnb_id, const gnb_infos& gnb) {
std::unique_lock lock(m_gnbs);
if (gnbs.count(gnb_id) > 0) {
gnbs[gnb_id] = gnb;
}
}
//------------------------------------------------------------------------------
uint32_t statistics::get_number_connected_gnbs() const {
std::shared_lock lock(m_gnbs);
return gnbs.size();
}
......@@ -76,20 +76,69 @@ typedef struct ue_info_s {
class statistics {
public:
void display();
statistics();
~statistics();
/*
* Display the AMF configuration parameters
* @param void
* @return void
*/
void display();
/*
* Update UE information
* @param [const ue_info_t&] ue_info: UE information
* @return void
*/
void update_ue_info(const ue_info_t& ue_info);
/*
* Update UE 5GMM state
* @param [const std::string&] imsi: UE IMSI
* @param [const std::string&] state: UE State
* @return void
*/
void update_5gmm_state(const std::string& imsi, const std::string& state);
void remove_gnb(const uint32_t gnb_id);
/*
* Remove gNB from the list connected gNB to this AMF
* @param [const uint32_t] gnb_id: gNB ID
* @return void
*/
void remove_gnb(const uint32_t& gnb_id);
/*
* Add gNB to the list connected gNB to this AMF
* @param [const uint32_t&] gnb_id: gNB ID
* @param [const gnb_infos&] gnb: gNB Info
* @return void
*/
void add_gnb(const uint32_t& gnb_id, const gnb_infos& gnb);
/*
* Update gNB info
* @param [const uint32_t&] gnb_id: gNB ID
* @param [const gnb_infos&] gnb: gNB Info
* @return void
*/
void update_gnb(const uint32_t& gnb_id, const gnb_infos& gnb);
/*
* Get number of connected gNBs
* @param void
* @return number of connected gNBs
*/
uint32_t get_number_connected_gnbs() const;
public:
uint32_t gNB_connected;
uint32_t UE_connected;
uint32_t UE_registred;
// uint32_t system_pdu_sessions;
std::map<uint32_t, gnb_infos> gnbs;
mutable std::shared_mutex m_gnbs;
std::map<std::string, ue_info_t> ue_infos;
mutable std::shared_mutex m_ue_infos;
};
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -28,7 +28,7 @@ enum class http_response_codes_e {
HTTP_RESPONSE_CODE_200_OK = 200,
HTTP_RESPONSE_CODE_201_CREATED = 201,
HTTP_RESPONSE_CODE_202_ACCEPTED = 202,
HTTP_RESPONSE_CODE_204_UPDATED = 204,
HTTP_RESPONSE_CODE_204_NO_CONTENT = 204,
HTTP_RESPONSE_CODE_BAD_REQUEST = 400,
HTTP_RESPONSE_CODE_UNAUTHORIZED = 401,
HTTP_RESPONSE_CODE_FORBIDDEN = 403,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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