VNF Onboarding Walkthrough¶
NOTE: this section uses pre-SOL006 descriptors which need to be converted before trying in Release 9+
Introduction¶
This section uses NextEPC (an open-source implementation of a 4G/5G packet core) to go through most of the steps described in the onboarding guidelines, in order to provide a concrete example on how to build a complete VNF Package from scratch.
The example is meant to be used for educational purposes and not for a real-life implementation of an EPC. It may change over time to cover more use cases. A Linux machine is required to follow the complete procedure. In addition to the procedure, here you can find some resources related to it:
VNF Requirements¶
Day-0 Requirements¶
The following table describes the components description and associated images.
VDU | Description | Image name |
---|---|---|
spgwmme | Single VDU containing SGW, PGW and MME | nextepc-spgwmme-base |
hss | HSS VDU | nextepc-hss-base |
And here the NFVI requirements (for this example, as the VNF has no strict requirements)
VDU | vCPU | RAM (GB) | Storage (GB) | EPA Features |
---|---|---|---|---|
spgwmme | 2 | 4 | 10 | CPU Pinning, Huge Pages & SRIOV in S1/SGI |
hss | 1 | 2 | 10 | - |
The topology of the VNF would be as follows:
Finally, we will use cloud-init files to set a hostname and password (just as example, since OSM VCA supports SSH key authentication). The password will be kept as a variable, so it can be passed at instantiation time.
#cloud-config
hostname: nextepc-hss
password: {{ password }}
chpasswd: { expire: False }
ssh_pwauth: True
#cloud-config
hostname: nextepc-spgw
password: {{ password }}
chpasswd: { expire: False }
ssh_pwauth: True
Day-1 Requirements¶
For this sample VNF, we will assume that establishing the session between the MME and HSS, and starting the main services, is enough to consider that the EPC is ready to start serving subscribers. This VNF does not expose an API, so we will configure it with Linux commands through SSH.
SPGW-MME Day-1 operations include:
Enabling its 3 additional interfaces:
sudo ip link set ens4 up && sudo dhclient ens4
sudo ip link set ens5 up && sudo dhclient ens5
sudo ip link set ens6 up && sudo dhclient ens6
Replacing the HSS and SPGW IP addresses in the configuration file of the MME component. We will need to pass both IP addresses as instantiation parameters (as of OSM Release 6.0.2, there is no automatic detection of non-management IP addressing)
sudo sed -i 's/$hss_ip/HSS_IP/g' /etc/nextepc/freeDiameter/mme.conf
sudo sed -i 's/$spgw_ip/SPGW_IP/g' /etc/nextepc/freeDiameter/mme.conf
Restarting the MME daemon
sudo systemctl restart nextepc-mmed
HSS Day-1 operations include:
Enabling its additional interface:
sudo ip link set ens4 up && sudo dhclient ens4
Replacing the HSS and SPGW IP addresses in the configuration file of the HSS component. We will need to pass both IP addresses as instantiation parameters as well.
sudo sed -i 's/$hss_ip/HSS_IP/g' /etc/nextepc/freeDiameter/hss.conf
sudo sed -i 's/$spgw_ip/SPGW_IP/g' /etc/nextepc/freeDiameter/hss.conf
Restarting the HSS daemon
sudo systemctl restart nextepc-hssd
Day-2 Requirements¶
For day-2 operations, we will enable the possibility of reconfiguring and monitoring the SPGW.
SPGW reconfiguration includes adding static routes. We will need to pass variables for prefix and next-hop.
sudo route add -net PREFIX gw NEXTHOP
SPGW KPIs will include CPU and Memory metrics collection from the NFVI, through the VIM.
Building the VNF Package for Day-0¶
Generate base VNF and NS packages. Our VNF includes 2 VDUs, but we will specify just one and add the other one later.
osm package-create --base-directory ~/vEPC --image nextepc-spgwmme-base --vcpu 2 --memory 4096 --storage 10 --interfaces 3 --vendor OSM_VNFONB_TF vnf vEPC
Modify the VNFD (at ~/vEPC/vEPC_vnf/vEPC_vnfd.yaml), to replace the names of our first VDU and its connection points.
...
vdu:
- id: spgwmme
name: spgwmme
description: spgwmme
...
interface:
- name: eth0
type: EXTERNAL
virtual-interface:
type: PARAVIRT
external-connection-point-ref: spgwmme-mgmt
- name: eth1
type: EXTERNAL
virtual-interface:
type: PARAVIRT
external-connection-point-ref: spgwmme-s1
- name: eth2
type: EXTERNAL
virtual-interface:
type: PARAVIRT
external-connection-point-ref: spgwmme-sgi
- name: eth3
type: EXTERNAL
virtual-interface:
type: PARAVIRT
external-connection-point-ref: spgwmme-s6a
...
Add the second VDU, you can copy and paste the first one, adapting the number of interfaces and VM Flavor.
...
vdu:
...
- id: hss
name: hss
description: hss
count: 1
vm-flavor:
vcpu-count: 1
memory-mb: 2048
storage-gb: 10
image: 'nextepc-hss-base'
interface:
- name: eth0
type: EXTERNAL
virtual-interface:
type: PARAVIRT
external-connection-point-ref: hss-mgmt
- name: eth1
type: EXTERNAL
virtual-interface:
type: PARAVIRT
external-connection-point-ref: hss-s6a
...
Modify the s6a connection point to be ‘internal’ one, mapped to internal CPs and VLD to interconnect both VDUs.
...
vdu:
- id: spgwmme
...
interface:
...
- name: eth3
type: INTERNAL
virtual-interface:
type: PARAVIRT
internal-connection-point-ref: spgwmme-s6a
internal-connection-point:
- id: spgwmme-s6a
name: spgwmme-s6a
type: VPORT
...
vdu:
- id: hss
...
interface:
...
- name: eth1
type: INTERNAL
virtual-interface:
type: PARAVIRT
internal-connection-point-ref: hss-s6a
internal-connection-point:
- id: hss-s6a
name: hss-s6a
type: VPORT
...
internal-vld:
- id: s6a
internal-connection-point:
- id-ref: spgwmme-s6a
- id-ref: hss-s6a
name: s6a
...
Modify the external connection points that will be exposed to the Network Service level, and set the management one.
...
connection-point:
- name: spgwmme-mgmt
- name: spgwmme-s1
- name: spgwmme-sgi
- name: hss-mgmt
mgmt-interface:
cp: spgwmme-mgmt
...
We will set a particular subnet prefix for our internal VLD, to be able to set our own IP addresses at instantiation time.
...
ip-profiles:
- name: s6a
description: s6a network
ip-profile-params:
ip-version: ipv4
subnet-address: 10.0.6.0/24
dhcp-params:
enabled: true
...
internal-vld:
- id: s6a
ip-profile-ref: s6a
...
Now, let’s add the EPA requirements to the SPGW VDU.
...
vdu:
- id: spgwmme
guest-epa:
cpu-pinning-policy: DEDICATED
mempage-size: LARGE
...
interface:
...
- name: eth1
type: EXTERNAL
virtual-interface:
type: SRIOV
external-connection-point-ref: spgwmme-s1
- name: eth2
type: EXTERNAL
virtual-interface:
type: SRIOV
external-connection-point-ref: spgwmme-sgi
...
Finally, let’s specify the cloud-init file names in the descriptor, and copy them to the corresponding folder (~/vEPC/vEPC_vnf/cloud_init/)
...
vdu:
- id: spgwmme
cloud-init-file: spgwmme-init
...
vdu:
- id: hss
cloud-init-file: hss-init
...
At this point, it is ideal to validate if your package has the correct format:
# Validating the VNFD
osm package-validate vEPC/vEPC_vnf/
Building the VNF Package for Day-1¶
Let’s start with the SPGW day-1 operations by populating the descriptor with ‘initial config primitives’. The management interface is already set at the “spgw_mgmt” CP, so OSM will connect to this machine when defining a configuration at the VNF level. A ‘config’ primitive is required to pass the parameters for SSH connection. The only parameter that is auto-populated is ‘rw_mgmt_ip’ (the management IP address), the other ones will need to be provided at instantiation time. Note that we are setting names for primitives (operations), order of execution, parameters, and the juju charm that will implement all of them.
...
vnf-configuration:
initial-config-primitive:
- seq: '1'
name: config
parameter:
- name: ssh-hostname
value: <rw_mgmt_ip>
- name: ssh-username
value: ubuntu
- name: ssh-password
value: <password>
- seq: '2'
name: configure-spgw
parameter:
- name: spgw-ip
data-type: STRING
value: <spgw_ip>
- name: hss-ip
data-type: STRING
value: <hss_ip>
- seq: '3'
name: restart-spgw
juju:
charm: spgwcharm
...
Now, let’s modify the descriptor to include operations for the HSS VDU. For this, we will use a configuration block at the VDU level, and specify the management interface for this particular VDU.
...
vdu:
...
- id: hss
...
interface:
- name: eth0
type: EXTERNAL
mgmt-interface: true
...
vdu-configuration:
initial-config-primitive:
- seq: '1'
name: config
parameter:
- name: ssh-hostname
value: <rw_mgmt_ip>
- name: ssh-username
value: ubuntu
- name: ssh-password
value: <password>
- seq: '2'
name: configure-hss
parameter:
- name: spgw-ip
data-type: STRING
value: <spgw_ip>
- name: hss-ip
data-type: STRING
value: <hss_ip>
- seq: '3'
name: restart-hss
juju:
charm: hsscharm
...
Validate your package again, just in case:
# Validating the VNFD
osm package-validate vEPC/vEPC_vnf/
Finally, we need to build the ‘spgwcharm’ and ‘hsscharm’ that will implement these operations. Let’s start with the SPGW.
# Prepare the environment
snap install charm --classic
mkdir -p ~/charms/layers
export JUJU_REPOSITORY=~/charms
export LAYER_PATH=$JUJU_REPOSITORY/layers
cd $LAYER_PATH
charm create spgwcharm
cd spgwcharm
# Modify the layer.yaml file
includes:
- layer:basic
- layer:vnfproxy
# Modify the metadata.yaml file
name: spgwcharm
summary: NextEPC SPGW Charm
maintainer: Your name <youremail@yourdomain.com>
description: |
This is an example of a proxy charm deployed by Open Source Mano.
tags:
- nfv
subordinate: false
series:
- trusty
- xenial
# Create and modify the actions.yaml file
configure-spgw:
description: "Configures the SPGW"
params:
hss-ip:
description: "HSS IP"
type: string
default: "0.0.0.0"
spgw-ip:
description: "SPGW IP"
type: string
default: "0.0.0.0"
restart-spgw:
description: "Restarts the service of the VNF"
# Create the 'actions' folder and populate executable files for each action, with the same content:
mkdir actions
cat <<'EOF' >> actions/configure-spgw
#!/usr/bin/env python3
import sys
sys.path.append('lib')
from charms.reactive import main
from charms.reactive import set_state
from charmhelpers.core.hookenv import action_fail, action_name
"""
`set_state` only works here because it's flushed to disk inside the `main()`
loop. remove_state will need to be called inside the action method.
"""
set_state('actions.{}'.format(action_name()))
try:
main()
except Exception as e:
action_fail(repr(e))
EOF
chmod +x actions/configure-spgw
# Same procedure for the 'restart-spgw' action
cat <<'EOF' >> actions/restart-spgw
#!/usr/bin/env python3
import sys
sys.path.append('lib')
from charms.reactive import main
from charms.reactive import set_state
from charmhelpers.core.hookenv import action_fail, action_name
"""
`set_state` only works here because it's flushed to disk inside the `main()`
loop. remove_state will need to be called inside the action method.
"""
set_state('actions.{}'.format(action_name()))
try:
main()
except Exception as e:
action_fail(repr(e))
EOF
chmod +x actions/restart-spgw
# Fill in the contents of the 'reactive' file (reactive/spgwcharm.py)
from charms.reactive import when, when_not, set_flag
from charmhelpers.core.hookenv import (
action_get,
action_fail,
action_set,
config,
status_set,
)
from charms.reactive import (
remove_state as remove_flag,
set_state as set_flag,
when, when_not
)
import charms.sshproxy
@when('actions.configure-spgw')
def configure_spgw():
hss_ip = action_get('hss-ip')
spgw_ip = action_get('spgw-ip')
cmd1 = "sudo ip link set ens4 up && sudo dhclient ens4"
charms.sshproxy._run(cmd1)
cmd2 = "sudo ip link set ens5 up && sudo dhclient ens5"
charms.sshproxy._run(cmd2)
cmd3 = "sudo ip link set ens6 up && sudo dhclient ens6"
charms.sshproxy._run(cmd3)
cmd3='sudo sed -i "\'s/$hss_ip/{}/g\'" /etc/nextepc/freeDiameter/mme.conf'.format(hss_ip)
charms.sshproxy._run(cmd3)
cmd4='sudo sed -i "\'s/$spgw_ip/{}/g\'" /etc/nextepc/freeDiameter/mme.conf'.format(spgw_ip)
charms.sshproxy._run(cmd4)
remove_flag('actions.configure-spgw')
@when('actions.restart-spgw')
def restart_spgw():
cmd = "sudo systemctl restart nextepc-mmed"
charms.sshproxy._run(cmd)
remove_flag('actions.restart-spgw')
Proceed in a similar way for the HSS, and provide the following contents to the reactive file:
cd $LAYER_PATH
charm create hsscharm
cd hsscharm
# Modify the layer.yaml file
includes:
- layer:basic
- layer:vnfproxy
# Modify the metadata.yaml file
name: hsscharm
summary: NextEPC HSS Charm
maintainer: Your name <youremail@yourdomain.com>
description: |
This is an example of a proxy charm deployed by Open Source Mano.
tags:
- nfv
subordinate: false
series:
- trusty
- xenial
# Create and modify the actions.yaml file
configure-hss:
description: "Configures the HSS"
params:
hss-ip:
description: "HSS IP"
type: string
default: "0.0.0.0"
spgw-ip:
description: "SPGW IP"
type: string
default: "0.0.0.0"
restart-hss:
description: "Restarts the service of the VNF"
# Create the 'actions' folder and populate executable files for each action, with the same content:
mkdir actions
cat <<'EOF' >> actions/configure-hss
#!/usr/bin/env python3
import sys
sys.path.append('lib')
from charms.reactive import main
from charms.reactive import set_state
from charmhelpers.core.hookenv import action_fail, action_name
"""
`set_state` only works here because it's flushed to disk inside the `main()`
loop. remove_state will need to be called inside the action method.
"""
set_state('actions.{}'.format(action_name()))
try:
main()
except Exception as e:
action_fail(repr(e))
EOF
chmod +x actions/configure-hss
# Same procedure for the 'restart-hss' action
cat <<'EOF' >> actions/restart-hss
#!/usr/bin/env python3
import sys
sys.path.append('lib')
from charms.reactive import main
from charms.reactive import set_state
from charmhelpers.core.hookenv import action_fail, action_name
"""
`set_state` only works here because it's flushed to disk inside the `main()`
loop. remove_state will need to be called inside the action method.
"""
set_state('actions.{}'.format(action_name()))
try:
main()
except Exception as e:
action_fail(repr(e))
EOF
chmod +x actions/restart-hss
# Fill in the contents of the 'reactive' file (reactive/hsscharm.py)
from charms.reactive import when, when_not, set_flag
from charmhelpers.core.hookenv import (
action_get,
action_fail,
action_set,
config,
status_set,
)
from charms.reactive import (
remove_state as remove_flag,
set_state as set_flag,
when, when_not
)
import charms.sshproxy
@when('actions.configure-hss')
def configure_hss():
spgw_ip = action_get('spgw-ip')
hss_ip = action_get('hss-ip')
cmd1 = "sudo ip link set ens4 up && sudo dhclient ens4"
charms.sshproxy._run(cmd1)
cmd2= 'sudo sed -i "\'s/$hss_ip/{}/g\'" /etc/nextepc/freeDiameter/hss.conf'.format(hss_ip)
charms.sshproxy._run(cmd2)
cmd3= 'sudo sed -i "\'s/$spgw_ip/{}/g\'" /etc/nextepc/freeDiameter/hss.conf'.format(spgw_ip)
charms.sshproxy._run(cmd3)
remove_flag('actions.configure-hss')
@when('actions.restart-hss')
def restart_hss():
cmd = "sudo systemctl restart nextepc-hssd"
charms.sshproxy._run(cmd)
remove_flag('actions.restart-hss')
Charms need to be built and copied into the package, but we can do this in a later stage after Day-2 operations have been defined.
Building the VNF Package for Day-2¶
As defined earlier, the only VDU containing reconfiguration primitives is the SPGW. Let’s add it to the descriptor first. We can define default values in this kind of primitive.
...
vnf-configuration:
...
config-primitive:
- name: add-route
parameter:
- name: external-prefix
data-type: STRING
default-value: '8.8.8.8/32'
- name: next-hop
data-type: STRING
default-value: '192.168.2.1'
Back to the SPGW charm folder, modify the actions.yaml file to include this new primitive, ading the respective executable file at the ‘actions’ folder, and finally adding the primitive at the ‘reactive’ file.
# Modify the actions.yaml file
...
add-route:
description: "Adds a route to the SPGW"
params:
external-prefix:
description: "Destinaton prefix IP"
type: string
default: "8.8.8.8/32"
next-hop:
description: "SGI next hop"
type: string
default: "192.168.2.1"
# Populate the executable file for the new action, in the 'actions' folder:
cat <<'EOF' >> actions/add-route
#!/usr/bin/env python3
import sys
sys.path.append('lib')
from charms.reactive import main
from charms.reactive import set_state
from charmhelpers.core.hookenv import action_fail, action_name
"""
`set_state` only works here because it's flushed to disk inside the `main()`
loop. remove_state will need to be called inside the action method.
"""
set_state('actions.{}'.format(action_name()))
try:
main()
except Exception as e:
action_fail(repr(e))
EOF
chmod +x actions/add-route
# Fill in the contents of the 'reactive' file (reactive/spgwcharm.py)
...
@when('actions.add-route')
def add_route():
prefix = action_get('external-prefix')
next_hop = action_get('next-hop')
cmd = "sudo route add -net " + prefix + " gw " + next_hop
charms.sshproxy._run(cmd)
remove_flag('actions.add-route')
Build both charms and copy them to the VNF folder
cd ~/charms/layers/spgwcharm
sudo -E charm build
cp -r ~/charms/builds/spgwcharm ~/vEPC/vEPC_vnf/charms/
cd ~/charms/layers/hsscharm
sudo -E charm build
cp -r ~/charms/builds/hsscharm ~/vEPC/vEPC_vnf/charms/
We also defined monitoring as part of our day-2 operations. Modify the descriptor to monitor CPU and Memory metrics of the SPGW.
vdu:
...
- id: spgwmme
...
monitoring-param:
- id: "spgw_cpu_util"
nfvi-metric: "cpu_utilization"
- id: "spgw_memory_util"
nfvi-metric: "average_memory_utilization"
...
monitoring-param:
- id: "spgw_cpu_util"
name: "spgw_cpu_util"
aggregation-type: AVERAGE
vdu-monitoring-param:
vdu-ref: "spgwmme"
vdu-monitoring-param-ref: "spgw_cpu_util"
- id: "spgw_memory_util"
name: "spgw_memory_util"
aggregation-type: AVERAGE
vdu-monitoring-param:
vdu-ref: "spgwmme"
vdu-monitoring-param-ref: "spgw_memory_util"
Run a final validation of your package:
# Validating the VNFD
osm package-validate vEPC/vEPC_vnf/
Testing the VNF Package¶
To test the VNF package, you need to first include it into a NS Package, let’s create one.
osm package-create --base-directory ~/vEPC --vendor OSM_VNFONB_TF ns vEPC
Its content should be similar to the following one, where VLDs are mapped to the external connection points of the VNF. Management external network is expected to be already present at the VIM (‘vim-network-name’ attribute). Note that, for this example, we are setting some subnets and IP address values, to be requested to the VIM’s IPAM to match some pre-existing configurations inside the VNF.
nsd:nsd-catalog:
nsd:
- id: vEPC_nsd
name: vEPC_nsd
short-name: vEPC_nsd
description: Generated by OSM package generator
vendor: OSM_VNFONB_TF
version: '1.0'
constituent-vnfd:
- member-vnf-index: 1
vnfd-id-ref: vEPC_vnfd
ip-profiles:
- name: s1
description: s1 network
ip-profile-params:
ip-version: ipv4
subnet-address: 192.168.0.0/24
dhcp-params:
enabled: true
- name: sgi
description: s1 network
ip-profile-params:
ip-version: ipv4
subnet-address: 192.168.2.0/24
dhcp-params:
enabled: true
vld:
- id: management
name: management
short-name: management
type: ELAN
mgmt-network: 'true'
vim-network-name: osm-ext
vnfd-connection-point-ref:
- member-vnf-index-ref: 1
vnfd-id-ref: vEPC_vnfd
vnfd-connection-point-ref: spgwmme-mgmt
- member-vnf-index-ref: 1
vnfd-id-ref: vEPC_vnfd
vnfd-connection-point-ref: hss-mgmt
- id: s1
name: s1
short-name: s1
type: ELAN
ip-profile-ref: s1
vnfd-connection-point-ref:
- member-vnf-index-ref: 1
vnfd-id-ref: vEPC_vnfd
vnfd-connection-point-ref: spgwmme-s1
ip-address: 192.168.0.11
- id: sgi
name: sgi
short-name: sgi
type: ELAN
ip-profile-ref: sgi
vnfd-connection-point-ref:
- member-vnf-index-ref: 1
vnfd-id-ref: vEPC_vnfd
vnfd-connection-point-ref: spgwmme-sgi
ip-address: 192.168.2.11
Now, validate your descriptors against the OSM’s Information Model, using the tool in the devops repository. For example:
# Validating the NSD
osm package-validate vEPC/vEPC_ns/
Now that you now your descriptors are valid, compress both packages and upload them to OSM.
cd ~/vEPC
tar -cvzf vEPC_vnfd.tar.gz vEPC_vnf/
tar -cvzf vEPC_nsd.tar.gz vEPC_ns/
osm vnfd-create vEPC_vnfd.tar.gz
osm nsd-create vEPC_nsd.tar.gz
Prepare a file, which you could call ‘params.yaml’, with the instantiaton parameters. Note that it also includes a ‘vnf’ block that modifies the internal VLD at instantiation time to set its IP addresses (at VIM IPAM level) so they match with the ones we are providing.
additionalParamsForVnf:
- member-vnf-index: '1'
additionalParams:
spgw_ip: '10.0.6.15'
hss_ip: '10.0.6.20'
password: 'osm4u'
vnf:
- member-vnf-index: '1'
internal-vld:
- name: s6a
internal-connection-point:
- id-ref: spgwmme-s6a
ip-address: 10.0.6.15
- id-ref: hss-s6a
ip-address: 10.0.6.20
Instantiate the VNF! Make sure you have registered a VIM with the compute and EPA requirements you need for the VNF.
osm ns-create --ns_name EPC1 --nsd_name vEPC_nsd --ssh_keys ~/.ssh/id_rsa.pub --config_file params.yaml --vim_account [VIM_ACCOUNT]
Monitor the primitives execution status and NS status with the following commands. Remember that the instantiation flow from Release 7 onwards is as follows: (1) Charm execution enviroment preparation and VM Instantiation (in parallel), (2) Primitives execution
osm ns-list
juju switch [NS_ID]
juju status
juju debug-log
When the NS reaches the ‘configured’ state, ssh to the HSS or SPGW/MME, and check if the HSS - MME session is established. This means that Day-1 operations worked.
ubuntu@nextepc-spgw:~$ sudo netstat -anlp | grep 10.0.6
...
sctp 0 0 10.0.6.15:3868 10.0.6.20:55662 ESTABLISHED
We can also test Day-2 reconfiguration operations by running the primitive that adds routes to the SPGW (no host routes allowed in this example). This can be done through the OSM UI or the CLI, for example:
osm ns-action --vnf_name 1 --action_name add-route --params '{external-prefix: "8.8.8.0/24", next-hop: "192.168.2.1"}' epc1
Finally, visit the Prometheus GUI at OSM IP (port 9091), or Grafana Dashboard at port 3000 and look for the ‘osm_cpu_utilization’ and ‘osm_average_memory_utilization’ metrics.