Commit 32357948 authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼

software/ors-amarisoft: Add fixed-ips option for core network

This option will give fixed IP to each SIM card.
parent c1f2b72e
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
[template] [template]
filename = instance.cfg filename = instance.cfg
md5sum = 5cf7674e2f6c3afb1b2f6b7646457284 md5sum = 2e131f4542e059b48349ec0411241c31
[template-ors] [template-ors]
filename = instance-ors.cfg filename = instance-ors.cfg
...@@ -96,7 +96,7 @@ md5sum = 601d6237059fa665d3f3ffb6a78ad9ca ...@@ -96,7 +96,7 @@ md5sum = 601d6237059fa665d3f3ffb6a78ad9ca
[template-core-network] [template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg _update_hash_filename_ = instance-core-network.jinja2.cfg
md5sum = 4d05284cd328f5fce054b8f227097e25 md5sum = 326e194e9c98d58d926f89521bb95df5
[template-ue] [template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg _update_hash_filename_ = instance-ue.jinja2.cfg
...@@ -108,7 +108,7 @@ md5sum = c5f581ba01654b2aec46000abf8d0e35 ...@@ -108,7 +108,7 @@ md5sum = c5f581ba01654b2aec46000abf8d0e35
[ue_db.jinja2.cfg] [ue_db.jinja2.cfg]
filename = config/ue_db.jinja2.cfg filename = config/ue_db.jinja2.cfg
md5sum = 87a273c99ce64192506811d7718c2b36 md5sum = 3b901e8733e6afff8940c6c318da4493
[enb.jinja2.cfg] [enb.jinja2.cfg]
filename = config/enb.jinja2.cfg filename = config/enb.jinja2.cfg
...@@ -128,7 +128,7 @@ md5sum = 959523597e29b048e45ebf58f7ea4c5b ...@@ -128,7 +128,7 @@ md5sum = 959523597e29b048e45ebf58f7ea4c5b
[mme.jinja2.cfg] [mme.jinja2.cfg]
filename = config/mme.jinja2.cfg filename = config/mme.jinja2.cfg
md5sum = bee16b3b94fd57f5a19ea7b1f5955533 md5sum = 25ae6b1022548183293f0ef0c54532a7
[dnsmasq-core-network.jinja2.cfg] [dnsmasq-core-network.jinja2.cfg]
filename = config/dnsmasq-core-network.jinja2.cfg filename = config/dnsmasq-core-network.jinja2.cfg
......
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
first_ip_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv4-network', '')).first) + 2 }}", first_ip_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv4-network', '')).first) + 2 }}",
last_ip_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv4-network', '')).last) - 1 }}", last_ip_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv4-network', '')).last) - 1 }}",
{% endif %} {% endif %}
ip_addr_shift: 2,
p_cscf_addr: ["{{ slap_configuration.get('tun-ipv4-addr', '') }}"], p_cscf_addr: ["{{ slap_configuration.get('tun-ipv4-addr', '') }}"],
erabs: [ erabs: [
......
...@@ -14,6 +14,13 @@ ue_db: [ ...@@ -14,6 +14,13 @@ ue_db: [
K: "{{ s.get('k', '') }}", K: "{{ s.get('k', '') }}",
impu: "{{ s.get('impu', '') }}", impu: "{{ s.get('impu', '') }}",
impi: "{{ s.get('impi', '') }}", impi: "{{ s.get('impi', '') }}",
{%- if "ip" in s %}
pdn_list:[{
access_point_name: "internet",
default: true,
ipv4_addr: "{{ s['ip'] }}"
}]
{%- endif %}
} }
{%- endfor -%} {%- endfor -%}
] ]
......
...@@ -44,6 +44,12 @@ ...@@ -44,6 +44,12 @@
"title": "Use IPv4", "title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses", "description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean" "type": "boolean"
},
"fixed_ips": {
"default": false,
"title": "Fixed IP for the UE",
"description": "Set to true to force a static IPv4 for each UE. If true, the number of UE is limited.",
"type": "boolean"
} }
} }
} }
{%- set dns_slave_instance_list = [] %} {%- set dns_slave_instance_list = [] %}
{%- set sim_slave_instance_list = [] %} {%- set sim_slave_instance_list = [] %}
{%- set fixed_ip = slapparameter_dict.get("fixed_ips", False) %}
{%- for slave in slave_instance_list %} {%- for slave in slave_instance_list %}
{%- set slave_parameters = json_module.loads(slave['_']) %} {%- set slave_parameters = json_module.loads(slave['_']) %}
{%- if slave_parameters.get('subdomain', '') != '' %} {%- if slave_parameters.get('subdomain', '') != '' %}
...@@ -19,8 +20,38 @@ ...@@ -19,8 +20,38 @@
recipe = slapos.cookbook:publish.serialised recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ slave_reference }} -slave-reference = {{ slave_reference }}
info = Your SIM card with IMSI {{ slave_parameters.get('imsi', '') }} has been attached to service ${slap-configuration:instance-title}. info = Your SIM card with IMSI {{ slave_parameters.get('imsi', '') }} has been attached to service ${slap-configuration:instance-title}.
{%- if fixed_ip %}
ipv4 = ${sim-ip-configuration:{{slave_reference}}}
{%- endif %}
{%- endfor %} {%- endfor %}
[sim-ip-configuration]
recipe = slapos.recipe.build
sim-slave-instance-list = {{ dumps(sim_slave_instance_list) }}
ipv4-network = {{ slap_configuration.get('tun-ipv4-network', '') }}
init =
import netaddr
import json
network = netaddr.IPNetwork(options['ipv4-network'])
slave_list = options['sim-slave-instance-list']
# if we don't have enough IPv4 addresses in the network, don't force it
# should we make a promise fail ?
if len(slave_list) + 2 > network.size:
for s in slave_list:
options[s['slave_reference']] = "Too many SIM for the IPv4 network"
else:
# calculate the IP addresses of each SIM
sim_list = []
first_addr = netaddr.IPAddress(network.first)
for i, s in enumerate(sorted(slave_list, key=lambda x: json.loads(x['_'])['imsi'])):
ip = str(first_addr + 2 + i)
options[s['slave_reference']] = ip
slave_parameters = json.loads(s['_'])
slave_parameters['ip'] = ip
s['_'] = json.dumps(slave_parameters)
options['sim-with-ip-list'] = slave_list
{%- for slave in dns_slave_instance_list %} {%- for slave in dns_slave_instance_list %}
{%- set slave_parameters = json_module.loads(slave['_']) %} {%- set slave_parameters = json_module.loads(slave['_']) %}
{% set slave_reference = slave.get('slave_reference', '') %} {% set slave_reference = slave.get('slave_reference', '') %}
...@@ -70,7 +101,11 @@ configuration.gtp_addr = 127.0.1.100 ...@@ -70,7 +101,11 @@ configuration.gtp_addr = 127.0.1.100
configuration.ims_addr = 127.0.0.1 configuration.ims_addr = 127.0.0.1
configuration.ims_bind = 127.0.0.2 configuration.ims_bind = 127.0.0.2
ue_db_path = ${ue-db-config:output} ue_db_path = ${ue-db-config:output}
{%- if fixed_ip %}
sim_list = ${sim-ip-configuration:sim-with-ip-list}
{%- else %}
sim_list = {{ dumps(sim_slave_instance_list) }} sim_list = {{ dumps(sim_slave_instance_list) }}
{%- endif %}
[monitor-httpd-conf-parameter] [monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
......
...@@ -195,6 +195,7 @@ extra-context = ...@@ -195,6 +195,7 @@ extra-context =
raw iperf3_location ${iperf3:location} raw iperf3_location ${iperf3:location}
raw dnsmasq_location ${dnsmasq:location} raw dnsmasq_location ${dnsmasq:location}
key slave_instance_list slap-configuration:slave-instance-list key slave_instance_list slap-configuration:slave-instance-list
section slap_configuration slap-configuration
[dynamic-template-ue] [dynamic-template-ue]
< = jinja2-template-base < = jinja2-template-base
......
...@@ -47,6 +47,7 @@ setup( ...@@ -47,6 +47,7 @@ setup(
'slapos.cookbook', 'slapos.cookbook',
'pcpp', 'pcpp',
'xmltodict', 'xmltodict',
'netaddr'
], ],
zip_safe=True, zip_safe=True,
test_suite='test', test_suite='test',
......
...@@ -29,6 +29,7 @@ import os ...@@ -29,6 +29,7 @@ import os
import json import json
import glob import glob
import requests import requests
import netaddr
from test import yamlpp_load from test import yamlpp_load
...@@ -40,14 +41,6 @@ setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass( ...@@ -40,14 +41,6 @@ setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
param_dict = { param_dict = {
'testing': True, 'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17, 'tx_gain': 17,
'rx_gain': 17, 'rx_gain': 17,
'dl_earfcn': 36100, 'dl_earfcn': 36100,
...@@ -232,20 +225,47 @@ def test_mme_conf(self): ...@@ -232,20 +225,47 @@ def test_mme_conf(self):
conf = yamlpp_load(conf_file) conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn']) self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self): def getSimParam(id=0):
return {
'sim_algo': 'milenage',
'imsi': '{0:015}'.format(1010000000000 + id),
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu%s' % '{0:03}'.format(id),
'impi': 'impi%s@amarisoft.com' % '{0:03}'.format(id)
}
def test_sim_card(self, nb_sim_cards, fixed_ips, tun_network):
conf_file = glob.glob(os.path.join( conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0] self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file) conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split(): first_ip = netaddr.IPAddress(tun_network.first)
self.assertEqual(conf['ue_db'][0][n], param_dict[n]) for i in range(nb_sim_cards):
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k']) params = getSimParam(i)
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16)) for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][i][n], params[n], "%s doesn't match" % n)
self.assertEqual(conf['ue_db'][i]['K'], params['k'])
self.assertEqual(conf['ue_db'][i]['amf'], int(params['amf'], 16))
p = self.requestSlaveInstanceWithId(i).getConnectionParameterDict()
p = json.loads(p['_'])
self.assertIn('info', p)
if fixed_ips:
self.assertIn('ipv4', p)
if nb_sim_cards + 2 > tun_network.size:
self.assertEqual(p['ipv4'], "Too many SIM for the IPv4 network")
else:
ip = str(first_ip + 2 + i)
self.assertEqual(p['ipv4'], ip)
self.assertEqual(conf['ue_db'][i]['pdn_list'][0]['access_point_name'], "internet")
self.assertTrue(conf['ue_db'][i]['pdn_list'][0]['default'])
self.assertEqual(conf['ue_db'][i]['pdn_list'][0]['ipv4_addr'], ip)
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self): def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_']) parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
...@@ -304,16 +324,6 @@ class TestCoreNetworkParameters(ORSTestCase): ...@@ -304,16 +324,6 @@ class TestCoreNetworkParameters(ORSTestCase):
def test_mme_conf(self): def test_mme_conf(self):
test_mme_conf(self) test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase): class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod @classmethod
def getInstanceParameterDict(cls): def getInstanceParameterDict(cls):
...@@ -351,20 +361,66 @@ class TestCoreNetworkMonitorGadgetUrl(ORSTestCase): ...@@ -351,20 +361,66 @@ class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
test_monitor_gadget_url(self) test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase): class TestSimCard(ORSTestCase):
nb_sim_cards = 1
fixed_ips = False
tun_network = netaddr.IPNetwork('192.168.10.0/24')
@classmethod @classmethod
def requestDefaultInstance(cls, state='started'): def requestDefaultInstance(cls, state='started'):
default_instance = super( default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state) ORSTestCase, cls).requestDefaultInstance(state=state)
cls._updateSlaposResource(
os.path.join(
cls.slap._instance_root, default_instance.getId()),
tun={"ipv4_network": str(cls.tun_network)}
)
cls.requestSlaveInstance() cls.requestSlaveInstance()
return default_instance return default_instance
@classmethod @classmethod
def requestSlaveInstance(cls): def requestSlaveInstance(cls):
return requestSlaveInstance(cls) for i in range(cls.nb_sim_cards):
cls.requestSlaveInstanceWithId(i)
@classmethod @classmethod
def getInstanceParameterDict(cls): def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})} return {'_': json.dumps({'testing': True, 'fixed_ips': cls.fixed_ips})}
@classmethod @classmethod
def getInstanceSoftwareType(cls): def getInstanceSoftwareType(cls):
return "core-network" return "core-network"
def test_sim_card(self): @classmethod
test_sim_card(self) def requestSlaveInstanceWithId(cls, id=0):
software_url = cls.getSoftwareURL()
param_dict = getSimParam(id)
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD-%s" % id,
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
@classmethod
def _updateSlaposResource(cls, partition_path, **kw):
# we can update the .slapos-resourcefile from top partition because buildout
# will search for a .slapos-resource in upper directories until it finds one
with open(os.path.join(partition_path, '.slapos-resource'), 'r+') as f:
resource = json.load(f)
resource.update(kw)
f.seek(0)
f.truncate()
json.dump(resource, f, indent=2)
def test_sim_card(cls):
test_sim_card(cls, cls.nb_sim_cards, cls.fixed_ips, cls.tun_network)
class TestSimCardManySim(TestSimCard):
nb_sim_cards = 10
class TestSimCardFixedIps(TestSimCard):
fixed_ips = True
class TestSimCardManySimFixedIps(TestSimCard):
nb_sim_cards = 10
fixed_ips = True
class TestSimCardTooManySimFixedIps(TestSimCard):
nb_sim_cards = 10
fixed_ips = True
tun_network = netaddr.IPNetwork("192.168.10.0/29")
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