Commit 6764287a authored by Raphael Defosseux's avatar Raphael Defosseux

Merge branch 'prepare-public-release' into 'develop'

Adding NRF client

See merge request oai/cn5g/oai-cn5g-upf-vpp!6
parents 68b73303 3d1ad18d
# RELEASE NOTES: # # RELEASE NOTES: #
## vX.X.X -- YYY 2021 ## ## v1.2.0 -- September 2021 ##
* Initial release * Initial Public Release
* Full support for Ubuntu18 and RHEL7
* CI Build support
## v1.0.0 -- January 2021 ##
* Initial Private Release
This diff is collapsed.
`oai-cn5g-upf-vpp` repository is distributed under **Apache V2.0 License**.
For more details of the license, refer to [LICENSE](LICENSE) file in the same directory.
However, it also includes OAI code or third party-software indicated below.
* **`src/nrf_client.py`** is dstributed under `OAI Public License V1.1`.
...@@ -18,14 +18,26 @@ At the moment, it contains the following network elements: ...@@ -18,14 +18,26 @@ At the moment, it contains the following network elements:
Each has its own repository: this repository (`oai-cn5g-upf-vpp`) is meant for UPF. Each has its own repository: this repository (`oai-cn5g-upf-vpp`) is meant for UPF.
This `UPF` repository contains mainly patches / hacks over 2 open-source projects:
- [Vector Packet Processing](https://github.com/fdio/vpp.git)
- [User Plane Gateway (UPG) based on VPP](https://github.com/travelping/upg-vpp)
# Licence info # Licence info
It is distributed under `OAI Public License V1.1`. As this repository contains mainly patches over 2 open-source projects that are
See [OAI Website for more details](https://www.openairinterface.org/?page_id=698). distributed under Apache V2, it is distributed under `Apache V2.0 License`.
See [Apache Website for more details](http://www.apache.org/licenses/LICENSE-2.0).
The text for `OAI Public License V1.1` is also available under [LICENSE](LICENSE) The text for `Apache V2.0 License` is also available under [LICENSE](LICENSE)
file at the root of this repository. file at the root of this repository.
Some part(s) of the repository that are decorrelated from the 2 original open-source
projects may be under another LICENSE type.
Check the [NOTICE](NOTICE.md) file for more details.
# Where to start # Where to start
The Openair-CN-5G UPF code is written, executed, and tested on UBUNTU server bionic version. The Openair-CN-5G UPF code is written, executed, and tested on UBUNTU server bionic version.
...@@ -63,10 +75,11 @@ openair-cn5g-upf-vpp ...@@ -63,10 +75,11 @@ openair-cn5g-upf-vpp
│   └── scripts │   └── scripts
├── ci-scripts ├── ci-scripts
├── docker ├── docker
├── docker-compose
├── docs ├── docs
│   └── images │   └── images
── scripts ── scripts
├── patches │   ├── patches
├── tests │   └── upf_conf
└── upf_conf └── src
</pre> </pre>
#!/bin/bash
set -eo pipefail
STATUS=0
AMF_PORT_FOR_NGAP=38412
AMF_PORT_FOR_N11_HTTP=80
AMF_IP_NGAP_INTERFACE=$(ifconfig $AMF_INTERFACE_NAME_FOR_NGAP | grep inet | awk {'print $2'})
AMF_IP_N11_INTERFACE=$(ifconfig $AMF_INTERFACE_NAME_FOR_N11 | grep inet | awk {'print $2'})
N2_PORT_STATUS=$(netstat -Snpl | grep -o "$AMF_IP_NGAP_INTERFACE:$AMF_PORT_FOR_NGAP")
N11_PORT_STATUS=$(netstat -tnpl | grep -o "$AMF_IP_N11_INTERFACE:$AMF_PORT_FOR_N11_HTTP")
#Check if entrypoint properly configured the conf file and no parameter is unset (optional)
NB_UNREPLACED_AT=`cat /openair-amf/etc/*.conf | grep -v contact@openairinterface.org | grep -c @ || true`
if [ $NB_UNREPLACED_AT -ne 0 ]; then
STATUS=1
echo "Healthcheck error: configuration file is not configured properly"
fi
if [[ -z $N2_PORT_STATUS ]]; then
STATUS=1
echo "Healthcheck error: N2 SCTP port $AMF_PORT_FOR_NGAP is not listening"
fi
if [[ -z $N11_PORT_STATUS ]]; then
STATUS=1
echo "Healthcheck error: N11/SBI TCP/HTTP port $AMF_PORT_FOR_N11_HTTP is not listening"
fi
#host="${MYSQL_SERVER}"
#user="${MYSQL_USER:-root}"
#export MYSQL_PWD="${MYSQL_PASS}"
#args=(
# -h"$host"
# -u"$user"
# --silent
#)
#if ! command -v mysql &> /dev/null; then
# echo "Installing mysql command"
# apt update
# apt-get -y install mysql-client
#else
# if select="$(echo 'SELECT 1' | mysql "${args[@]}")" && [ "$select" = '1' ]; then
# database_check=$(mysql -h$host -u$user -D oai_db --silent -e "SELECT * FROM users;")
# if [[ -z $database_check ]]; then
# echo "Healthcheck error: oai_db not populated"
# STATUS=1
# fi
# STATUS=0
# else
# echo "Healthcheck error: Mysql port inactive"
# STATUS=1
# fi
#fi
exit $STATUS
version: '3.8'
services:
mysql:
container_name: "mysql"
image: mysql:5.7
volumes:
- ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
- ./mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
environment:
- TZ=Europe/Paris
- MYSQL_DATABASE=oai_db
- MYSQL_USER=test
- MYSQL_PASSWORD=test
- MYSQL_ROOT_PASSWORD=linux
healthcheck:
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
interval: 10s
timeout: 5s
retries: 5
networks:
public_net_cp:
ipv4_address: 192.168.71.131
oai-nrf:
container_name: "oai-nrf"
image: oai-nrf:latest
environment:
- NRF_INTERFACE_NAME_FOR_SBI=eth0
- NRF_INTERFACE_PORT_FOR_SBI=80
- NRF_INTERFACE_HTTP2_PORT_FOR_SBI=8080
- NRF_API_VERSION=v1
- INSTANCE=0
- PID_DIRECTORY=/var/run
networks:
public_net_cp:
ipv4_address: 192.168.71.130
volumes:
- ./nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh
healthcheck:
test: /bin/bash -c "/openair-nrf/bin/nrf-healthcheck.sh"
interval: 10s
timeout: 5s
retries: 5
oai-amf:
container_name: "oai-amf"
image: oai-amf:latest
environment:
- TZ=Europe/paris
- INSTANCE=0
- PID_DIRECTORY=/var/run
- MCC=208
- MNC=95
- REGION_ID=128
- AMF_SET_ID=1
- SERVED_GUAMI_MCC_0=208
- SERVED_GUAMI_MNC_0=95
- SERVED_GUAMI_REGION_ID_0=128
- SERVED_GUAMI_AMF_SET_ID_0=1
- SERVED_GUAMI_MCC_1=460
- SERVED_GUAMI_MNC_1=11
- SERVED_GUAMI_REGION_ID_1=10
- SERVED_GUAMI_AMF_SET_ID_1=1
- PLMN_SUPPORT_MCC=208
- PLMN_SUPPORT_MNC=95
- PLMN_SUPPORT_TAC=0xa000
- SST_0=222
- SD_0=123
- SST_1=1
- SD_1=12
- AMF_INTERFACE_NAME_FOR_NGAP=eth0
- AMF_INTERFACE_NAME_FOR_N11=eth0
- SMF_INSTANCE_ID_0=1
- SMF_FQDN_0=oai-smf
- SMF_IPV4_ADDR_0=192.168.71.133
- SMF_HTTP_VERSION_0=v1
- SMF_INSTANCE_ID_1=2
- SMF_FQDN_1=oai-smf
- SMF_IPV4_ADDR_1=0.0.0.0
- SMF_HTTP_VERSION_1=v1
- MYSQL_SERVER=192.168.71.131
- 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
- SMF_SELECTION=no
- USE_FQDN_DNS=no
- NRF_FQDN=oai-nrf
- NRF_API_VERSION=v1
- EXTERNAL_AUSF=no
- AUSF_IPV4_ADDRESS=127.0.0.1
- AUSF_PORT=80
- AUSF_API_VERSION=v1
- AUSF_FQDN=localhost
depends_on:
- mysql
- vpp-upf
- oai-ext-dn
volumes:
- ./amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh
healthcheck:
test: /bin/bash -c "/openair-amf/bin/amf-healthcheck.sh"
interval: 10s
timeout: 15s
retries: 5
networks:
public_net_cp:
ipv4_address: 192.168.71.132
oai-smf:
container_name: "oai-smf"
image: oai-smf:latest
environment:
- TZ=Europe/Paris
- INSTANCE=0
- PID_DIRECTORY=/var/run
- SMF_INTERFACE_NAME_FOR_N4=eth0
- SMF_INTERFACE_NAME_FOR_SBI=eth0
- SMF_INTERFACE_PORT_FOR_SBI=80
- SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090
- SMF_API_VERSION=v1
- DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129
- DEFAULT_DNS_SEC_IPV4_ADDRESS=8.8.8.8
- AMF_FQDN=oai-amf
- AMF_IPV4_ADDRESS=192.168.71.132
- AMF_PORT=80
- AMF_API_VERSION=v1
- UDM_IPV4_ADDRESS=127.0.0.1
- UDM_FQDN=localhost
- UDM_PORT=80
- UDM_API_VERSION=v1
- UPF_FQDN_0=gw1.vppupf.node.5gcn.mnc95.mcc208.3gppnetwork.org
- UPF_IPV4_ADDRESS=192.168.71.202
- NRF_FQDN=oai-nrf
- NRF_IPV4_ADDRESS=0.0.0.0
- NRF_PORT=80
- NRF_API_VERSION=v1
- REGISTER_NRF=no
- DISCOVER_UPF=no
- USE_NETWORK_INSTANCE=yes
- USE_FQDN_DNS=no
extra_hosts:
- "gw1.vppupf.node.5gcn.mnc95.mcc208.3gppnetwork.org:192.168.71.202"
depends_on:
- oai-amf
volumes:
- ./smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh
healthcheck:
test: /bin/bash -c "/openair-smf/bin/smf-healthcheck.sh"
interval: 10s
timeout: 5s
retries: 5
networks:
public_net_cp:
ipv4_address: 192.168.71.133
vpp-upf:
image: oai-upf-vpp:latest
privileged: true
container_name: vpp-upf
environment:
- NWI_N3=access.oai.org
- NWI_N6=core.oai.org
- GW_ID=1
- MNC03=95
- MCC=208
- REALM=3gppnetwork.org
- NETWORK_UE_IP=12.1.1.0/24
- N3_IPV4_ADDRESS_REMOTE=192.168.72.141 # GNB IP Address
- N4_IPV4_ADDRESS_REMOTE=192.168.71.133 # SMF IP Address
- N6_IPV4_ADDRESS_REMOTE=192.168.73.135 # EXT-DN IP Address
- VPP_MAIN_CORE=0
- VPP_CORE_WORKER=1
# - VPP_PLUGIN_PATH=/usr/lib64/vpp_plugins/ # RHEL7
- VPP_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/vpp_plugins/ # Ubntu18.04
- INTERFACE_ACCESS=eth0
- INTERFACE_CORE=eth1
- INTERFACE_CP=eth2
- NSSAI_SD_0=222
- SST=123
- DNN=default
- REGISTER_NRF=yes
- NRF_IP_ADDR=192.168.71.130
- NRF_PORT=8080
- HTTP_VERSION=2
healthcheck:
test: /bin/bash -c "pgrep vpp"
interval: 10s
timeout: 5s
retries: 5
networks:
public_net_cp:
ipv4_address: 192.168.71.134
public_net_access:
ipv4_address: 192.168.72.134
public_net_core:
ipv4_address: 192.168.73.134
oai-ext-dn:
image: ubuntu:bionic
privileged: true
container_name: oai-ext-dn
entrypoint: /bin/bash -c \
"apt update; apt install -y iptables iproute2 iputils-ping;"\
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
"ip route add 12.1.1.0/24 via 192.168.73.202 dev eth0; sleep infinity"
command: ["/bin/bash", "-c", "trap : TERM INT; sleep infinity & wait"]
depends_on:
- vpp-upf
networks:
public_net_core:
ipv4_address: 192.168.73.135
networks:
public_net_cp:
name: oai-public-cp
ipam:
config:
- subnet: 192.168.71.0/24
driver_opts:
com.docker.network.bridge.name: "cn5g-public"
public_net_access:
name: oai-public-access
ipam:
config:
- subnet: 192.168.72.0/24
driver_opts:
com.docker.network.bridge.name: "cn5g-access"
public_net_core:
name: oai-public-core
ipam:
config:
- subnet: 192.168.73.0/24
driver_opts:
com.docker.network.bridge.name: "cn5g-core"
#!/bin/bash
set -eo pipefail
STATUS=0
NRF_IP_SBI_INTERFACE=$(ifconfig $NRF_INTERFACE_NAME_FOR_SBI | grep inet | awk {'print $2'})
NRF_SBI_PORT_STATUS=$(netstat -tnpl | grep -o "$NRF_IP_SBI_INTERFACE:$NRF_INTERFACE_PORT_FOR_SBI")
#Check if entrypoint properly configured the conf file and no parameter is unset(optional)
NB_UNREPLACED_AT=`cat /openair-nrf/etc/*.conf | grep -v contact@openairinterface.org | grep -c @ || true`
if [ $NB_UNREPLACED_AT -ne 0 ]; then
STATUS=1
echo "Healthcheck error: UNHEALTHY configuration file is not configured properly"
fi
if [[ -z $NRF_SBI_PORT_STATUS ]]; then
STATUS=1
echo "Healthcheck error: UNHEALTHY SBI TCP/HTTP port $NRF_INTERFACE_PORT_FOR_SBI is not listening."
fi
exit $STATUS
\ No newline at end of file
#!/bin/bash
set -eo pipefail
STATUS=0
SMF_IP_SBI_INTERFACE=$(ifconfig $SMF_INTERFACE_NAME_FOR_SBI | grep inet | awk {'print $2'})
#Check if entrypoint properly configured the conf file and no parameter is unset(optional)
SMF_SBI_PORT_STATUS=$(netstat -tnpl | grep -o "$SMF_IP_SBI_INTERFACE:$SMF_INTERFACE_PORT_FOR_SBI")
NB_UNREPLACED_AT=`cat /openair-smf/etc/*.conf | grep -v contact@openairinterface.org | grep -c @ || true`
if [ $NB_UNREPLACED_AT -ne 0 ]; then
STATUS=-1
echo "Healthcheck error: UNHEALTHY configuration file is not configured properly"
fi
if [[ -z $SMF_SBI_PORT_STATUS ]]; then
STATUS=-1
echo "Healthcheck error: UNHEALTHY SBI TCP/HTTP port $SMF_INTERFACE_PORT_FOR_SBI is not listening."
fi
exit $STATUS
...@@ -60,7 +60,7 @@ RUN wget http://repo.openfusion.net/centos7-x86_64/hyperscan-devel-5.3.0-1.of.el ...@@ -60,7 +60,7 @@ RUN wget http://repo.openfusion.net/centos7-x86_64/hyperscan-devel-5.3.0-1.of.el
&& rpm -i *.rpm && rpm -i *.rpm
WORKDIR /vpp-upf WORKDIR /vpp-upf
COPY scripts/ /vpp-upf/scripts COPY . .
# Applying vpp patches # Applying vpp patches
RUN git clone -b stable/2101 https://github.com/fdio/vpp.git && \ RUN git clone -b stable/2101 https://github.com/fdio/vpp.git && \
...@@ -91,7 +91,8 @@ RUN yum repolist --disablerepo=* && \ ...@@ -91,7 +91,8 @@ RUN yum repolist --disablerepo=* && \
tshark \ tshark \
tzdata\ tzdata\
iproute \ iproute \
wget && \ wget \
https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm && \
wget http://repo.openfusion.net/centos7-x86_64/hyperscan-devel-5.3.0-1.of.el7.x86_64.rpm \ wget http://repo.openfusion.net/centos7-x86_64/hyperscan-devel-5.3.0-1.of.el7.x86_64.rpm \
http://repo.openfusion.net/centos7-x86_64/hyperscan-5.3.0-1.of.el7.x86_64.rpm && \ http://repo.openfusion.net/centos7-x86_64/hyperscan-5.3.0-1.of.el7.x86_64.rpm && \
rpm -i *.rpm && \ rpm -i *.rpm && \
...@@ -99,14 +100,18 @@ RUN yum repolist --disablerepo=* && \ ...@@ -99,14 +100,18 @@ RUN yum repolist --disablerepo=* && \
yum remove -y wget && \ yum remove -y wget && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
RUN yum install -y python-pip && pip install termcolor
WORKDIR /openair-upf/bin WORKDIR /openair-upf/bin
COPY --from=vpp-upf-builder /vpp-upf/scripts/entrypoint.sh . COPY --from=vpp-upf-builder /vpp-upf/scripts/entrypoint.sh .
COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vpp . COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vpp .
COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vppctl . COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vppctl .
COPY --from=vpp-upf-builder /vpp-upf/src/nrf_client.py .
WORKDIR /openair-upf/etc WORKDIR /openair-upf/etc
COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/init.conf . COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/init.conf .
COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/startup_debug.conf . COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/startup_debug.conf .
COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/upf_profile.json .
WORKDIR /usr/lib64 WORKDIR /usr/lib64
COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/lib/ . COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/lib/ .
......
...@@ -53,7 +53,7 @@ RUN git config --global https.postBuffer 123289600 && \ ...@@ -53,7 +53,7 @@ RUN git config --global https.postBuffer 123289600 && \
git config --global http.sslverify false git config --global http.sslverify false
WORKDIR /vpp-upf WORKDIR /vpp-upf
COPY scripts/ /vpp-upf/scripts COPY . .
# Applying vpp patches # Applying vpp patches
RUN git clone -b stable/2101 https://github.com/fdio/vpp.git && \ RUN git clone -b stable/2101 https://github.com/fdio/vpp.git && \
...@@ -93,16 +93,23 @@ RUN apt-get update && \ ...@@ -93,16 +93,23 @@ RUN apt-get update && \
iproute2 \ iproute2 \
iputils-ping \ iputils-ping \
vim \ vim \
python \
python-pip \
libcurl4-openssl-dev \
libssl-dev \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN pip install pycurl termcolor
WORKDIR /openair-upf/bin WORKDIR /openair-upf/bin
COPY --from=vpp-upf-builder /vpp-upf/scripts/entrypoint.sh . COPY --from=vpp-upf-builder /vpp-upf/scripts/entrypoint.sh .
COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vpp . COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vpp .
COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vppctl . COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/bin/vppctl .
COPY --from=vpp-upf-builder /vpp-upf/src/nrf_client.py .
WORKDIR /openair-upf/etc WORKDIR /openair-upf/etc
COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/init.conf . COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/init.conf .
COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/startup_debug.conf . COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/startup_debug.conf .
COPY --from=vpp-upf-builder /vpp-upf/scripts/upf_conf/upf_profile.json .
WORKDIR /usr/lib/x86_64-linux-gnu/ WORKDIR /usr/lib/x86_64-linux-gnu/
COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/lib/ . COPY --from=vpp-upf-builder /vpp-upf/vpp/build-root/install-vpp-native/vpp/lib/ .
......
...@@ -19,7 +19,7 @@ Here in our network configuration, we need to pass the "GIT PROXY" configuration ...@@ -19,7 +19,7 @@ Here in our network configuration, we need to pass the "GIT PROXY" configuration
## 3.1 On a Ubuntu 18.04 Host ## ## 3.1 On a Ubuntu 18.04 Host ##
```bash ```bash
$ docker build --target oai-upf-vpp --tag vpp-upg:develop \ $ docker build --target oai-upf-vpp --tag oai-upf-vpp:latest \
--file docker/Dockerfile.upf-vpp.ubuntu18 \ --file docker/Dockerfile.upf-vpp.ubuntu18 \
--build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" .
``` ```
...@@ -27,7 +27,7 @@ $ docker build --target oai-upf-vpp --tag vpp-upg:develop \ ...@@ -27,7 +27,7 @@ $ docker build --target oai-upf-vpp --tag vpp-upg:develop \
## 3.2 On a RHEL 7 Host ## ## 3.2 On a RHEL 7 Host ##
```bash ```bash
$ docker build --target oai-upf-vpp --tag vpp-upg:develop \ $ docker build --target oai-upf-vpp --tag oai-upf-vpp:latest \
--file docker/Dockerfile.upf-vpp.rhel7 \ --file docker/Dockerfile.upf-vpp.rhel7 \
--build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" . --build-arg NEEDED_GIT_PROXY="http://proxy.eurecom.fr:8080" .
``` ```
#!/usr/bin/env bash #!/usr/bin/env bash
#"""
#/*
# * 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 nrf_client.py
# \author Rohan KHARADE
# \date 2021
# \email: rohan.kharade@openairinterface.org
#*/
#"""
# files are common to docker and native installation # files are common to docker and native installation
#____________ #____________
# init.conf => upf config # init.conf => upf config
...@@ -10,12 +39,19 @@ ...@@ -10,12 +39,19 @@
set -euo pipefail set -euo pipefail
CONFIG_DIR="/openair-upf/etc" CONFIG_DIR="/openair-upf/etc"
SGI_IPV4=$(ifconfig $INTERFACE_CORE | grep "inet " | awk '{print $2}')
ACCESS_IPV4=$(ifconfig $INTERFACE_ACCESS | grep "inet " | awk '{print $2}')
CORE_IPV4=$(ifconfig $INTERFACE_CP | grep "inet " | awk '{print $2}')
N3_IPV4_ADDRESS_LOCAL=$(ifconfig $INTERFACE_ACCESS | grep "inet " | awk '{print $2}' | cut -d"." -f1-3)".202"
N4_IPV4_ADDRESS_LOCAL=$(ifconfig $INTERFACE_CP | grep "inet " | awk '{print $2}' | cut -d"." -f1-3)".202"
N6_IPV4_ADDRESS_LOCAL=$(ifconfig $INTERFACE_CORE | grep "inet " | awk '{print $2}' | cut -d"." -f1-3)".202"
############################### ###############################
# UPF Config # UPF Config
############################### ###############################
array=(${CONFIG_DIR}/*.conf ${CONFIG_DIR}/*.json)
for c in ${CONFIG_DIR}/*.conf; do for c in "${array[@]}"; do
# grep variable names (format: ${VAR}) from template to be rendered # grep variable names (format: ${VAR}) from template to be rendered
VARS=$(grep -oP '@[a-zA-Z0-9_]+@' ${c} | sort | uniq | xargs) VARS=$(grep -oP '@[a-zA-Z0-9_]+@' ${c} | sort | uniq | xargs)
# create sed expressions for substituting each occurrence of ${VAR} # create sed expressions for substituting each occurrence of ${VAR}
...@@ -44,21 +80,20 @@ done ...@@ -44,21 +80,20 @@ done
# Near future we will have multiple interfaces (e.g. two n6 interface for edge computing case) # Near future we will have multiple interfaces (e.g. two n6 interface for edge computing case)
# We define in this order in docker-compose -> it is alphabetical order # We define in this order in docker-compose -> it is alphabetical order
# #
SGI_IPV4=$(ifconfig $INTERFACE_SGI | grep "inet " | awk '{print $2}')
ip link set $INTERFACE_ACCESS down ip link set $INTERFACE_ACCESS down
ip link set $INTERFACE_ACCESS name access ip link set $INTERFACE_ACCESS name n3
ip link set access up ip link set n3 up
ip link set $INTERFACE_CORE down ip link set $INTERFACE_CP down
ip link set $INTERFACE_CORE name core ip link set $INTERFACE_CP name n4
ip link set core up ip link set n4 up
ip link set $INTERFACE_SGI down ip link set $INTERFACE_CORE down
ip link set $INTERFACE_SGI name sgi ip link set $INTERFACE_CORE name n6
ip link set sgi up ip link set n6 up
ip route add $NETWORK_UE_IP via $SGI_IPV4 dev sgi ip route add $NETWORK_UE_IP via $SGI_IPV4 dev n6
echo "Done setting the configuration" echo "Done setting the configuration"
......
#!/bin/sh -x #!/bin/bash
#"""
#/*
# * 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 nrf_client.py
# \author Rohan KHARADE
# \date 2021
# \email: rohan.kharade@openairinterface.org
#*/
#"""
if [ $(id -u) -ne 0 ]; then if [ $(id -u) -ne 0 ]; then
exec sudo -E "$0" "$@" exec sudo -E "$0" "$@"
...@@ -25,10 +54,11 @@ while getopts ":r" opt; do ...@@ -25,10 +54,11 @@ while getopts ":r" opt; do
;; ;;
esac esac
done done
shift $((OPTIND-1)) shift $((OPTIND-1))
if test -z "$1"; then if test -z "$1"; then
$APP $ARGS $APP $ARGS &
elif test "$1" = "debug"; then elif test "$1" = "debug"; then
shift shift
gdb -ex 'set print pretty on' -ex 'run' --args $APP $ARGS $@ gdb -ex 'set print pretty on' -ex 'run' --args $APP $ARGS $@
...@@ -37,3 +67,11 @@ else ...@@ -37,3 +67,11 @@ else
exit 1 exit 1
fi fi
if [[ ${REGISTER_NRF} == "yes" ]];then
sleep 5
NRF_APP="$base/bin/nrf_client.py"
NRF_ARGS=" --nrf_ip="$NRF_IP_ADDR" --nrf_port="$NRF_PORT" --http_version="$HTTP_VERSION
python $NRF_APP $NRF_ARGS
fi
version: '3.8'
services:
mysql:
container_name: mysql
image: mysql:5.7
volumes:
- ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
- ./mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
environment:
- TZ=Europe/Paris
- MYSQL_DATABASE=oai_db
- MYSQL_USER=test
- MYSQL_PASSWORD=test
- MYSQL_ROOT_PASSWORD=linux
healthcheck:
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
interval: 10s
timeout: 5s
retries: 5
networks:
public_net:
ipv4_address: 192.168.74.200
oai-smf:
image: oai-smf:vpp-upf
depends_on: [oai-vpp]
container_name: oai-smf
privileged: true
networks:
public_net:
ipv4_address: 192.168.74.196
environment:
INSTANCE: 1
PID_DIRECTORY: /var/run
SMF_INTERFACE_NAME_FOR_N4: eth0
SMF_INTERFACE_NAME_FOR_SBI: eth0
SMF_INTERFACE_PORT_FOR_SBI: 80
SMF_INTERFACE_HTTP2_PORT_FOR_SBI: 8080
SMF_API_VERSION: v1
DEFAULT_DNS_IPV4_ADDRESS: 8.8.8.8
DEFAULT_DNS_SEC_IPV4_ADDRESS: 8.8.4.4
UE_IP_ADDRESS_POOL: '10.1.1.2 - 10.1.1.200'
AMF_IPV4_ADDRESS: 192.168.74.195
AMF_PORT: 80
AMF_API_VERSION: v1
UDM_IPV4_ADDRESS: 192.168.74.194
UDM_PORT: 80
UDM_API_VERSION: v1
UPF_IPV4_ADDRESS: 192.168.74.202
USE_NETWORK_INSTANCE: 'yes'
DISCOVER_UPF: 'no'
NRF_API_VERSION: 'v1'
NRF_IPV4_ADDRESS: '127.0.0.1'
NRF_PORT: '8080'
REGISTER_NRF: 'no'
healthcheck:
test: /bin/bash -c "pgrep oai_smf"
interval: 10s
timeout: 5s
retries: 5
extra_hosts:
- "gw1.vppupf.node.5gcn.mnc95.mcc208.3gppnetwork.org:192.168.74.202"
oai-amf:
image: oai-amf:develop
depends_on: [oai-smf, mysql]
container_name: oai-amf
privileged: true
networks:
public_net:
ipv4_address: 192.168.74.195
environment:
INSTANCE: 1
PID_DIRECTORY: /var/run
MCC: '208'
MNC: '95'
REGION_ID: '128'
AMF_SET_ID: 1
SERVED_GUAMI_MCC_0: '208'
SERVED_GUAMI_MCC_1: '460'
SERVED_GUAMI_MNC_0: '95'
SERVED_GUAMI_MNC_1: '11'
SERVED_GUAMI_REGION_ID_0: '95'
SERVED_GUAMI_REGION_ID_1: '11'
SERVED_GUAMI_AMF_SET_ID_0: '1'
SERVED_GUAMI_AMF_SET_ID_1: '1'
PLMN_SUPPORT_MCC: '208'
PLMN_SUPPORT_MNC: '95'
PLMN_SUPPORT_TAC: '0xa000'
SST_0: '222'
SST_1: '1'
SD_0: '123'
SD_1: '12'
SMF_SELECTION: 'no'
SMF_INSTANCE_ID_0: 1
SMF_INSTANCE_ID_1: 2
SMF_IPV4_ADDR_0: 192.168.74.196
SMF_IPV4_ADDR_1: 127.0.0.1
SMF_HTTP_VERSION_0: v1
SMF_HTTP_VERSION_1: v1
AMF_INTERFACE_NAME_FOR_NGAP: eth0
AMF_INTERFACE_NAME_FOR_N11: eth0
AUSF_IPV4_ADDRESS: 192.168.74.205
AUSF_API_VERSION: 'v1'
AUSF_PORT: 80
NRF_IPV4_ADDRESS: 192.168.74.206
NRF_API_VERSION: 'v1'
NRF_PORT: 80
MYSQL_SERVER: 192.168.74.200
MYSQL_USER: 'root'
MYSQL_PASS: 'linux'
MYSQL_DB: 'oai_db'
OPERATOR_KEY: '63bfa50ee6523365ff14c1f45f88737d'
NF_REGISTRATION: 'no'
healthcheck:
test: /bin/bash -c "pgrep oai_amf"
interval: 10s
timeout: 5s
retries: 5
oai-vpp:
image: vpp-upg:develop
privileged: true
container_name: vpp-upf
networks:
public_net_access:
ipv4_address: 192.168.75.197
public_net:
ipv4_address: 192.168.74.197
public_net_sgi_lan:
ipv4_address: 192.168.76.197
environment:
NWI_CORE : "core.oai"
NWI_ACCESS : "access.oai"
NWI_SGI : "sgi.oai"
GW_ID: "1"
MNC03: "95"
MCC : "208"
REALM: "3gppnetwork.org"
NETWORK_UE_IP: "12.1.1.0/24"
N3_IPV4_ADDRESS_REMOTE: "192.168.75.198"
N3_IPV4_ADDRESS_LOCAL : "192.168.75.202"
N4_IPV4_ADDRESS_REMOTE: "192.168.74.196"
N4_IPV4_ADDRESS_LOCAL : "192.168.74.202"
N6_IPV4_ADDRESS_REMOTE: "192.168.76.205"
N6_IPV4_ADDRESS_LOCAL : "192.168.76.202"
VPP_MAIN_CORE : 0
VPP_CORE_WORKER: 1
# VPP_PLUGIN_PATH: "/usr/lib64/vpp_plugins/" # RHEL7
VPP_PLUGIN_PATH: "/usr/lib/x86_64-linux-gnu/vpp_plugins/" # Ubntu18.04
INTERFACE_ACCESS: "eth0"
INTERFACE_CORE: "eth1"
INTERFACE_SGI: "eth2"
healthcheck:
test: /bin/bash -c "pgrep vpp"
interval: 10s
timeout: 5s
retries: 5
oai-nat:
image: ubuntu:bionic
privileged: true
container_name: oai-nat
networks:
public_net:
ipv4_address: 192.168.74.205
public_net_sgi_lan:
ipv4_address: 192.168.76.205
entrypoint: /bin/bash -c \
"apt update; apt install -y iptables iproute2 iputils-ping net-tools python iperf3;"\
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
"ip route add 12.1.1.0/24 via 192.168.76.202 dev eth1; sleep infinity"
gnbsim:
image: gnbsim:latest
depends_on: [oai-amf]
privileged: true
container_name: gnbsim
environment:
MCC: 208
MNC: 95
GNBID: 1
TAC: '0x00a000'
SST: '222'
SD: '00007b'
PagingDRX: 'v32'
RANUENGAPID: 0
IMEISV: '35609204079514'
MSIN: '0000000031'
RoutingIndicator: 1234
ProtectionScheme: 'null'
KEY: '0C0A34601D4F07677303652C0462535B'
OPc: '63bfa50ee6523365ff14c1f45f88737d'
DNN: 'default'
URL: 'http://192.168.76.205:8000'
NRCellID: 1
NGAPPeerAddr: '192.168.74.195'
GTPuLocalAddr: '192.168.75.198'
GTPuIFname: 'eth0'
networks:
public_net:
ipv4_address: 192.168.74.198
public_net_access:
ipv4_address: 192.168.75.198
healthcheck:
test: /bin/bash -c "ifconfig gtp-gnb"
interval: 10s
timeout: 5s
retries: 5
networks:
public_net:
name: oai-public-net
ipam:
config:
- subnet: 192.168.74.0/24
public_net_access:
name: oai-public-access
ipam:
config:
- subnet: 192.168.75.0/24
public_net_sgi_lan:
name: oai-public-sgi-lan
ipam:
config:
- subnet: 192.168.76.0/24
ip table add 1 ip table add 1
ip table add 2 ip table add 2
create host-interface name sgi create host-interface name n6
set interface mtu 1500 host-sgi set interface mtu 1500 host-n6
set interface ip table host-sgi 1 set interface ip table host-n6 1
set interface ip address host-sgi @N6_IPV4_ADDRESS_LOCAL@/24 set interface ip address host-n6 @N6_IPV4_ADDRESS_LOCAL@/24
set interface state host-sgi up set interface state host-n6 up
create host-interface name core create host-interface name n4
set interface mtu 1500 host-core set interface mtu 1500 host-n4
set interface ip table host-core 0 set interface ip table host-n4 0
set interface ip address host-core @N4_IPV4_ADDRESS_LOCAL@/24 set interface ip address host-n4 @N4_IPV4_ADDRESS_LOCAL@/24
set interface state host-core up set interface state host-n4 up
create host-interface name access create host-interface name n3
set interface mtu 1500 host-access set interface mtu 1500 host-n3
set interface ip table host-access 2 set interface ip table host-n3 2
set interface ip address host-access @N3_IPV4_ADDRESS_LOCAL@/24 set interface ip address host-n3 @N3_IPV4_ADDRESS_LOCAL@/24
set interface state host-access up set interface state host-n3 up
ip route add 0.0.0.0/0 table 2 via @N3_IPV4_ADDRESS_REMOTE@ host-access ip route add 0.0.0.0/0 table 2 via @N3_IPV4_ADDRESS_REMOTE@ host-n3
ip route add 0.0.0.0/0 table 0 via @N4_IPV4_ADDRESS_REMOTE@ host-core ip route add 0.0.0.0/0 table 0 via @N4_IPV4_ADDRESS_REMOTE@ host-n4
ip route add 0.0.0.0/0 table 1 via @N6_IPV4_ADDRESS_REMOTE@ host-sgi ip route add 0.0.0.0/0 table 1 via @N6_IPV4_ADDRESS_REMOTE@ host-n6
upf pfcp endpoint ip @N4_IPV4_ADDRESS_LOCAL@ vrf 0 upf pfcp endpoint ip @N4_IPV4_ADDRESS_LOCAL@ vrf 0
upf node-id fqdn gw@GW_ID@.vppupf.node.5gcn.mnc@MNC03@.mcc@MCC@.@REALM@ upf node-id fqdn gw@GW_ID@.vppupf.node.5gcn.mnc@MNC03@.mcc@MCC@.@REALM@
upf nwi name @NWI_CORE@ vrf 0 upf nwi name @NWI_N3@ vrf 2
upf nwi name @NWI_ACCESS@ vrf 2 upf nwi name @NWI_N6@ vrf 1
upf nwi name @NWI_SGI@ vrf 1
upf specification release 16 upf specification release 16
upf gtpu endpoint ip @N3_IPV4_ADDRESS_LOCAL@ nwi @NWI_ACCESS@ teid 0x000004d2/2 upf gtpu endpoint ip @N3_IPV4_ADDRESS_LOCAL@ nwi @NWI_N3@ teid 0x000004d2/2
{
"capacity": 100,
"fqdn": "gw@GW_ID@.vppupf.node.5gcn.mnc@MNC03@.mcc@MCC@.@REALM@",
"heartBeatTimer": 10,
"ipv4Addresses": ["@N4_IPV4_ADDRESS_LOCAL@"],
"json_data": null,
"nfInstanceName": "OAI-UPF-VPP",
"nfServices": [],
"nfStatus": "REGISTERED",
"nfType": "UPF",
"priority": 1,
"sNssais": [{
"sd": "@NSSAI_SD_0@",
"sst": @SST@
}],
"upfInfo": {
"sNssaiUpfInfoList": [{
"dnnUpfInfoList": [{
"dnn": "@DNN@"
}],
"sNssai": {
"sd": "@NSSAI_SD_0@",
"sst": @SST@
}
}],
"interfaceUpfInfoList": [{
"endpointFqdn": "@NWI_N3@",
"interfaceType": "N3",
"ipv4EndpointAddresses": ["@ACCESS_IPV4@"],
"networkInstance": "@NWI_N3@"
}, {
"endpointFqdn": "@NWI_N6@",
"interfaceType": "N6",
"ipv4EndpointAddresses": ["@CORE_IPV4@"],
"networkInstance": "@NWI_N6@"
}]
}
}
This diff is collapsed.
#!/usr/bin/env python
"""
/*
* 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 nrf_client.py
\author Rohan KHARADE
\date 2018
\email: rohan.kharade@openairinterface.org
*/
"""
import time, sys, json, logging, uuid, pycurl, argparse, atexit
from termcolor import colored
logging.basicConfig(format='%(asctime)s] %(filename)s: %(levelname)s '
'- %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
class upf_profile(object):
def __init__(self, nrf_ip = None, nrf_port = None, http_version = None):
self.logger = logging.getLogger("upf")
atexit.register(self.goodbye) # register a message to print out when exit
message = " NRF UPF client started "
self.logger.info(message)
#@@@@@@@@ Initialize arguments #@@@@@@@@
self.nrf_ip = nrf_ip
self.nrf_port = nrf_port
self.http_version = http_version
self.status_code = 0
self.uuid = uuid.uuid4()
self.url = 'http://'+str(self.nrf_ip)+':'+str(self.nrf_port)+'/nnrf-nfm/v1/nf-instances/'+str(self.uuid)
self.curl = pycurl.Curl()
self.headers = ["Content-Type:application/json"]
self.dir_config = '/openair-upf/'
self.file_name = self.dir_config+'etc/upf_profile.json'
self.conf_file = open(self.file_name,)
self.upf_profile = json.load(self.conf_file)
#@@@@@@@@ Initialize upf profile #@@@@@@@@
self.upf_profile['nfInstanceId'] = str(self.uuid)
self.capacity = self.upf_profile['capacity']
self.fqdn = self.upf_profile['fqdn']
self.heartBeatTimer = self.upf_profile['heartBeatTimer']
self.ipv4Addresses = self.upf_profile['ipv4Addresses']
self.nfInstanceId = self.upf_profile['nfInstanceId']
self.nfInstanceName = self.upf_profile['nfInstanceName']
self.nfStatus = self.upf_profile['nfStatus']
self.nfType = self.upf_profile['nfType']
self.priority = self.upf_profile['priority']
self.sNssais = self.upf_profile['sNssais']
self.upfInfo = self.upf_profile['upfInfo']
message = " UPF profile is parsed "
self.logger.info(message)
def display_upf_profile(self):
message = " Display UPF profile "
self.logger.info(message)
print(colored('[*] UPF Profile \n \t fqdn = '+self.fqdn+ \
'\n \t capacity = '+str(self.capacity)+ \
'\n \t heartBeatTimer = '+str(self.heartBeatTimer)+ \
'\n \t ipv4Addresses = '+u", ".join(self.ipv4Addresses)+ \
'\n \t nfInstanceId = '+self.nfInstanceId+ \
'\n \t nfInstanceName = '+self.nfInstanceName+ \
'\n \t nfStatus = '+self.nfStatus+ \
'\n \t nfType = '+self.nfType+ \
'\n \t priority = '+str(self.priority)+ \
'\n \t sNssais = '+json.dumps(self.sNssais)+ \
'\n \t upfInfo = '+json.dumps(self.upfInfo,indent=6) \
,'green'))
def trigger_nf_registration(self):
message = " Sending NF registration request (HTTP Version - "+str(self.http_version)+")"
self.logger.info(message)
self.curl.setopt(self.curl.URL, self.url)
self.curl.setopt(self.curl.HTTPHEADER, self.headers)
self.curl.setopt(self.curl.CUSTOMREQUEST, 'PUT')
self.curl.setopt(self.curl.POSTFIELDS, json.dumps(self.upf_profile))
if(str(self.http_version) == '2'):
self.curl.setopt(self.curl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
response=self.curl.perform()
self.status_code=self.curl.getinfo(self.curl.RESPONSE_CODE)
if self.status_code == 201 or self.status_code == 200:
message = " Succussfully registered at NRF !!"
self.logger.info(message)
self.trigger_nf_heartbeat()
else:
print(colored('\n\n NF registration failed \n\n', 'red'))
def trigger_nf_heartbeat(self):
patch_data = [{"op": "replace","path": "/nfStatus","value": "REGISTERED"}]
while True:
message = " Sending NF heartbeat requset (HTTP Version - "+str(self.http_version)+") !!"
self.logger.info(message)
time.sleep(5)
self.curl.setopt(self.curl.CUSTOMREQUEST, 'PATCH')
self.curl.setopt(self.curl.POSTFIELDS, json.dumps(patch_data))
response=self.curl.perform()
self.status_code=self.curl.getinfo(self.curl.RESPONSE_CODE)
if self.status_code == 204:
message = " Succussfully received NF heartbeat response !!"
self.logger.info(message)
else:
print(colored('\n\n NF heartbeat procedure failed \n\n', 'red'))
def goodbye(self):
print(colored('\n\n\n [*] You are now leaving OAI-NRF framework .....\n\n\n', 'yellow'))
sys.exit(0)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Process commandline arguments and override configurations')
parser.add_argument('--nrf_ip', metavar='[number]', action='store', type=str,
required=False, default='192.168.71.130',
help='set the nrf ip address. default = 192.168.71.130')
parser.add_argument('--nrf_port', metavar='[number]', action='store', type=str,
required=False, default='8080',
help='set the nrf port. default = 8080')
parser.add_argument('--http_version', metavar='[number]', action='store', type=str,
required=False, default='2',
help='set the nrf ip address. default = 2')
args = parser.parse_args()
nrf_client = upf_profile(args.nrf_ip, args.nrf_port, args.http_version)
nrf_client.display_upf_profile()
nrf_client.trigger_nf_registration()
"""
* Usage of nrf client -->
$ python nrf_client.py -h
usage: nrf_client.py [-h] [--nrf_ip [number]] [--nrf_port [number]]
[--http_version [number]]
Process commandline arguments and override configurations
optional arguments:
-h, --help show this help message and exit
--nrf_ip [number] set the nrf ip address. default = 192.168.71.130
--nrf_port [number] set the nrf port. default = 8080
--http_version [number] set the nrf ip address. default = 2
"""
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