blob: 64546fd9fdad07b1cd25c89a91ff3575d7be084e [file] [log] [blame]
Pau Espin Pedrol0696c602021-03-16 14:25:37 +01001# osmo_gsm_tester: specifics for running an Open5GS EPC
2#
3# Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Pau Espin Pedrol <pespin@sysmocom.de>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20import os
21import pprint
22import copy
23
24from ..core import log, util, config, template, process, remote
25from ..core import schema
26from . import epc
27from .pcrf_open5gs import Open5gsPCRF
28from .upf_open5gs import Open5gsUPF
29from .smf_open5gs import Open5gsSMF
30from .hss_open5gs import Open5gsHSS
31from .mme_open5gs import Open5gsMME
32from .sgwc_open5gs import Open5gsSGWC
33from .sgwu_open5gs import Open5gsSGWU
34
35def on_register_schemas():
36 config_schema = {
37 'db_host': schema.STR,
38 }
39 schema.register_config_schema('epc', config_schema)
40
41class Open5gsEPC(epc.EPC):
Pau Espin Pedrold7760592021-03-31 13:35:04 +020042##############
43# PROTECTED
44##############
Pau Espin Pedrol0696c602021-03-16 14:25:37 +010045 REMOTE_DIR = '/osmo-gsm-tester-open5gs'
46
47 def __init__(self, testenv, run_node):
Andre Puschmannb9c96122021-05-10 16:39:44 +020048 super().__init__(testenv, run_node, 'open5gs')
Pau Espin Pedrol0696c602021-03-16 14:25:37 +010049 self.run_dir = None
50 self.pcrf = None
51 self.upf = None
52 self.smf = None
53 self.mme = None
54 self.hss = None
55 self.sgwc = None
56 self.sgwu = None
57 self.subscriber_list = []
58
Pau Espin Pedrold7760592021-03-31 13:35:04 +020059 def configure(self):
Andre Puschmannb9c96122021-05-10 16:39:44 +020060 values = super().configure(['open5gs'])
Pau Espin Pedrold7760592021-03-31 13:35:04 +020061 db_host = values['epc']['db_host']
62 db_uri = 'mongodb://'+db_host+'/open5gs'
63 config.overlay(values, dict(epc=dict(db_uri=db_uri,
Pau Espin Pedrolbe5156c2021-05-12 18:01:29 +020064 apn_name=self.apn_name(),
65 tun_name=self.tun_name(),
Pau Espin Pedrold7760592021-03-31 13:35:04 +020066 tun_addr=self.tun_addr(),
Pau Espin Pedrolbe5156c2021-05-12 18:01:29 +020067 tun_netmask=self.tun_netmask(),
Pau Espin Pedrold7760592021-03-31 13:35:04 +020068 addr_smf=self.priv_addr_smf(),
69 addr_upf=self.priv_addr_upf(),
70 addr_sgwc=self.priv_addr_sgwc(),
71 addr_sgwu=self.priv_addr_sgwu(),
72 )))
73 self.fill_subscribers_mongodb(values['epc']['db_host'], 27017)
74 self.pcrf = Open5gsPCRF(self.testenv, self)
75 self.upf = Open5gsUPF(self.testenv, self)
76 self.smf = Open5gsSMF(self.testenv, self)
77 self.hss = Open5gsHSS(self.testenv, self)
78 self.mme = Open5gsMME(self.testenv, self)
79 self.sgwc = Open5gsSGWC(self.testenv, self)
80 self.sgwu = Open5gsSGWU(self.testenv, self)
81 self.pcrf.configure(copy.deepcopy(values))
82 self.upf.configure(copy.deepcopy(values))
83 self.smf.configure(copy.deepcopy(values))
84 self.hss.configure(copy.deepcopy(values))
85 self.mme.configure(copy.deepcopy(values))
86 self.sgwc.configure(copy.deepcopy(values))
87 self.sgwu.configure(copy.deepcopy(values))
88
89 def gen_priv_addr(self, suffix):
90 if ':' in self.addr():
91 raise log.Error('IPv6 not implemented!')
92 public_suffix = self.addr()[self.addr().rindex('.')+1:]
93 return '127.0.' + public_suffix + '.' + str(suffix)
94
95########################
96# PUBLIC - INTERNAL API
97########################
98
Pau Espin Pedrol0696c602021-03-16 14:25:37 +010099 def cleanup(self):
100 if self.pcrf:
101 self.pcrf.cleanup()
102 if self.upf:
103 self.upf.cleanup()
104 if self.smf:
105 self.smf.cleanup()
106 if self.hss:
107 self.hss.cleanup()
108 if self.mme:
109 self.mme.cleanup()
110 if self.sgwc:
111 self.sgwc.cleanup()
112 if self.sgwu:
113 self.sgwu.cleanup()
114
Pau Espin Pedrold7760592021-03-31 13:35:04 +0200115 def priv_addr_smf(self):
116 return self.gen_priv_addr(1)
Pau Espin Pedrol0696c602021-03-16 14:25:37 +0100117
Pau Espin Pedrold7760592021-03-31 13:35:04 +0200118 def priv_addr_upf(self):
119 return self.gen_priv_addr(2)
120
121 def priv_addr_sgwc(self):
122 return self.gen_priv_addr(3)
123
124 def priv_addr_sgwu(self):
125 return self.gen_priv_addr(4)
126
Pau Espin Pedrolbe5156c2021-05-12 18:01:29 +0200127 def tun_name(self):
128 return "ogstun"
129
130 def tun_netmask(self):
131 return "24"
132
133 def apn_name(self):
134 return "internet"
135
Pau Espin Pedrold7760592021-03-31 13:35:04 +0200136###################
137# PUBLIC (test API included)
138###################
Pau Espin Pedrol0696c602021-03-16 14:25:37 +0100139 def start(self):
Andre Puschmann0bedacd2021-05-10 20:49:47 +0200140 self.log('Starting open5gs')
Pau Espin Pedrol0696c602021-03-16 14:25:37 +0100141 self.run_dir = util.Dir(self.testenv.test().get_run_dir().new_dir(self.name()))
142 self.configure()
143 self.pcrf.start()
144 self.upf.start()
145 self.smf.start()
146 self.hss.start()
147 self.mme.start()
148 self.sgwc.start()
149 self.sgwu.start()
150
151 def subscriber_add(self, modem, msisdn=None, algo_str=None):
152 if msisdn is None:
153 msisdn = modem.msisdn()
154
155 if algo_str is None:
156 algo_str = modem.auth_algo() or 'milenage'
157
158 if algo_str == 'milenage':
159 if not modem.ki():
160 raise log.Error("Auth algo milenage selected but no KI specified")
161 if not modem.opc():
162 raise log.Error("Auth algo milenage selected but no OPC specified")
163 else:
164 raise log.Error("Open5Gs only supports auth algo: milenage")
165
166 subscriber_id = len(self.subscriber_list) # list index
167 self.subscriber_list.append({'id': subscriber_id, 'imsi': modem.imsi(), 'msisdn': msisdn, 'auth_algo': algo_str, 'ki': modem.ki(), 'opc': modem.opc(), 'apn_ipaddr': modem.apn_ipaddr()})
168 return subscriber_id
169
170 def fill_subscribers_mongodb(self, server, port):
171 import pymongo
172
173 myclient = pymongo.MongoClient("mongodb://" + str(server) + ":" + str(port) + "/")
174 mydb = myclient["open5gs"]
175 mycol = mydb["subscribers"]
176
177 for s in self.subscriber_list:
178 self.log('Insert subscriber to DB', msisdn=s['msisdn'], imsi=s['imsi'], subscriber_id=s['id'],
179 algo_str=s['auth_algo'])
180 slice_data = [ { \
181 "sst": 1, \
182 "default_indicator": True, \
183 "session": [ \
184 { \
Pau Espin Pedrolbe5156c2021-05-12 18:01:29 +0200185 "name": self.apn_name(), \
Pau Espin Pedrol0696c602021-03-16 14:25:37 +0100186 "type": 3, "pcc_rule": [], "ambr": {"uplink": {"value": 1, "unit": 0}, "downlink": {"value": 1, "unit": 0}}, \
187 "qos": { "index": 9, "arp": {"priority_level": 8, "pre_emption_capability": 1, "pre_emption_vulnerability": 1} } \
188 } \
189 ] \
190 } ]
191
192 sub_data = {'imsi': s['imsi'], \
193 'subscribed_rau_tau_timer': 12, \
194 'network_access_mode': 2, \
195 'subscriber_status': 0, \
196 "access_restriction_data": 32, \
197 'slice': slice_data, \
198 'ambr': {"uplink": {"value": 1, "unit": 0}, "downlink": {"value": 1, "unit": 0}}, \
199 'security': {'k': s['ki'], 'amf': '8000', 'op': None, 'opc': s['opc']},
200 'schema_version': 1, \
201 '__v': 0}
202 x = mycol.insert_one(sub_data)
203 self.dbg("Added subscriber with Inserted ID : " + str(x.inserted_id))
204 s['inserted_id'] = x.inserted_id
205
206 def enb_is_connected(self, enb):
207 # Match against sample mmed line: "eNB-S1 accepted[172.18.50.101]:50867"
208 if not self.mme or not self.mme.running():
209 return False
210 stdout_lines = (self.mme.process.get_stdout() or '').splitlines()
211 for l in stdout_lines:
212 if 'eNB' in l and 'accepted' in l and enb.addr() in l:
213 return True
214 return False
215
216 def running(self):
217 return self.pcrf and self.upf and self.smf and self.hss and \
218 self.mme and self.sgwc and self.sgwu and \
219 self.pcrf.running() and self.upf.running() and self.smf.running() and \
220 self.hss.running() and self.mme.running() and self.sgwc.running() and \
221 self.sgwu.running()
222
223 def tun_addr(self):
224 return '172.16.0.1'
225
226 def get_kpis(self):
227 return {}
228
229# vim: expandtab tabstop=4 shiftwidth=4