blob: 0fb30755d2698f42ce8a3a41b6613bed948942e7 [file] [log] [blame]
Vadim Yanitskiy95cd9352024-05-31 18:29:17 +07001/* OsmoS1GW (S1AP Gateway) test suite in TTCN-3
2 *
3 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4 * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
5 *
6 * All rights reserved.
7 *
8 * Released under the terms of GNU General Public License, Version 2 or
9 * (at your option) any later version.
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
14module S1GW_Tests {
15
16import from General_Types all;
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070017import from Osmocom_Types all;
Vadim Yanitskiy95cd9352024-05-31 18:29:17 +070018import from Native_Functions all;
19import from IPL4asp_Types all;
20import from Misc_Helpers all;
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070021
22import from S1AP_CodecPort all;
23import from S1AP_CodecPort_CtrlFunct all;
Vadim Yanitskiy95cd9352024-05-31 18:29:17 +070024import from S1AP_Types all;
25import from S1AP_Templates all;
26import from S1AP_PDU_Descriptions all;
27import from S1AP_IEs all;
28import from S1AP_PDU_Contents all;
29import from S1AP_Constants all;
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070030
Vadim Yanitskiycce57cb2024-06-12 06:38:31 +070031import from SCTP_Templates all;
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070032import from S1AP_Server all;
33
34modulepar {
Vadim Yanitskiy7cdbc1d2024-06-18 04:49:11 +070035 charstring mp_s1gw_enb_ip; /* eNB facing address of the S1GW */
36 charstring mp_s1gw_mme_ip; /* MME facing address of the S1GW */
37 charstring mp_mme_bind_ip; /* MME address on which we get connections from S1GW */
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070038}
39
40private type record of ConnHdlr ConnHdlrList;
41
42type component ConnHdlr extends S1APSRV_ConnHdlr {
43 port S1AP_CODEC_PT S1AP_ENB;
44 var ConnectionId g_s1ap_conn_id := -1;
45};
46
47type component test_CT {
Vadim Yanitskiy9ce73fe2024-06-12 05:08:36 +070048 timer g_Tguard;
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070049 var S1AP_Server_CT vc_S1APSRV;
50};
51
Vadim Yanitskiy9ce73fe2024-06-12 05:08:36 +070052private altstep as_Tguard() runs on test_CT {
53 [] g_Tguard.timeout {
54 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
55 }
56}
57
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070058template Global_ENB_ID
59ts_Global_ENB_ID(integer enb_id := 0,
60 OCT3 plmn_id := '00f110'O) := {
61 pLMNidentity := plmn_id,
62 eNB_ID := {
63 macroENB_ID := int2bit(enb_id, 20)
64 },
65 iE_Extensions := omit
66}
67
Vadim Yanitskiy9ce73fe2024-06-12 05:08:36 +070068function f_init(float Tval := 20.0) runs on test_CT {
69 g_Tguard.start(Tval);
70 activate(as_Tguard());
71}
72
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070073function f_init_s1ap_srv() runs on test_CT {
74 var S1APSRV_ConnParams cpars := {
75 local_ip := mp_mme_bind_ip,
76 local_port := 36412
77 };
78
79 vc_S1APSRV := S1AP_Server_CT.create("S1APSRV-" & testcasename());
80 vc_S1APSRV.start(S1AP_Server.main(cpars));
81}
82
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +070083type record ConnHdlrPars {
84 Global_ENB_ID genb_id
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070085};
86
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +070087template (value) ConnHdlrPars
88t_ConnHdlrPars(integer enb_id := 0) := {
89 genb_id := ts_Global_ENB_ID(enb_id)
90}
91
Vadim Yanitskiyced53d32024-06-11 03:19:06 +070092type function void_fn(ConnHdlrPars pars) runs on ConnHdlr;
93
94function f_ConnHdlr_spawn(void_fn fn, ConnHdlrPars pars)
95runs on test_CT return ConnHdlr {
96 var ConnHdlr vc_conn;
97
98 vc_conn := ConnHdlr.create("ConnHdlr-" & testcasename());
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +070099 if (vc_S1APSRV.running) {
100 connect(vc_conn:S1AP_CONN, vc_S1APSRV:S1AP_CLIENT);
101 connect(vc_conn:S1AP_PROC, vc_S1APSRV:S1AP_PROC);
102 }
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700103 vc_conn.start(derefers(fn)(pars));
104
105 return vc_conn;
106}
107
108function f_ConnHdlr_connect() runs on ConnHdlr {
109 var Result res;
Vadim Yanitskiycce57cb2024-06-12 06:38:31 +0700110 timer T;
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700111
112 map(self:S1AP_ENB, system:S1AP_CODEC_PT);
Vadim Yanitskiycce57cb2024-06-12 06:38:31 +0700113
114 /* initiate SCTP connection establishment */
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700115 res := S1AP_CodecPort_CtrlFunct.f_IPL4_connect(S1AP_ENB,
Vadim Yanitskiy7cdbc1d2024-06-18 04:49:11 +0700116 mp_s1gw_enb_ip, 36412,
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700117 "0.0.0.0", 0, -1,
Vadim Yanitskiyceb04772024-06-12 06:37:47 +0700118 { sctp := c_SctpTuple_S1AP });
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700119 if (not ispresent(res.connId)) {
120 setverdict(fail, "Could not create an S1AP socket, check your configuration");
121 mtc.stop;
122 }
123 g_s1ap_conn_id := res.connId;
124
Vadim Yanitskiycce57cb2024-06-12 06:38:31 +0700125 /* wait for the establishment confirmation */
126 T.start(2.0);
127 alt {
128 [] S1AP_ENB.receive(tr_SctpAssocChange(SCTP_COMM_UP, g_s1ap_conn_id)) {
129 log("eNB connection established");
130 }
131 [] S1AP_ENB.receive(PortEvent:{sctpEvent := ?}) { repeat; }
132 [] T.timeout {
133 setverdict(fail, "eNB connection establishment timeout");
134 self.stop;
135 }
136 }
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700137}
138
139function f_ConnHdlr_disconnect() runs on ConnHdlr {
140 var Result res;
141
142 S1AP_CodecPort_CtrlFunct.f_IPL4_close(S1AP_ENB, g_s1ap_conn_id,
Vadim Yanitskiyceb04772024-06-12 06:37:47 +0700143 { sctp := c_SctpTuple_S1AP });
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700144 g_s1ap_conn_id := -1;
145 unmap(self:S1AP_ENB, system:S1AP_CODEC_PT);
146
147 S1AP_CONN.receive(S1APSRV_Event:S1APSRV_EVENT_CONN_DOWN);
148
149 log("eNB connection closed");
150}
151
Vadim Yanitskiy876a60f2024-06-12 19:50:47 +0700152function f_ConnHdlr_expect_shutdown() runs on ConnHdlr {
153 S1AP_ENB.receive(tr_SctpShutDownEvent(g_s1ap_conn_id));
154 S1AP_ENB.receive(tr_SctpAssocChange(SCTP_SHUTDOWN_COMP, g_s1ap_conn_id));
155 S1AP_ENB.receive(PortEvent:{connClosed := ?});
156}
157
Vadim Yanitskiy91cf9722024-06-18 03:11:11 +0700158function f_ConnHdlr_tx_s1ap_from_enb(template (value) S1AP_PDU pdu)
159runs on ConnHdlr {
160 S1AP_ENB.send(t_S1AP_Send(g_s1ap_conn_id, pdu));
161}
162
163function f_ConnHdlr_tx_s1ap_from_mme(template (value) S1AP_PDU pdu)
164runs on ConnHdlr {
165 S1AP_CONN.send(pdu);
166}
167
168function f_ConnHdlr_rx_s1ap_from_enb(out S1AP_PDU pdu,
169 template (present) S1AP_PDU tr_pdu := ?,
170 float Tval := 0.5)
171runs on ConnHdlr {
172 timer T := Tval;
173
174 T.start;
175 alt {
176 [] S1AP_CONN.receive(tr_pdu) -> value pdu {
177 setverdict(pass);
178 T.stop;
179 }
180 [] S1AP_CONN.receive(S1AP_PDU:?) -> value pdu {
181 setverdict(fail, "Rx unexpected S1AP PDU from eNB: ", pdu);
182 T.stop;
183 }
184 [] T.timeout {
185 setverdict(fail, "Timeout waiting for S1AP PDU from eNB: ", tr_pdu);
186 }
187 }
188}
189
190function f_ConnHdlr_rx_s1ap_from_mme(out S1AP_PDU pdu,
191 template (present) S1AP_PDU tr_pdu := ?,
192 float Tval := 0.5)
193runs on ConnHdlr {
194 var S1AP_RecvFrom recv;
195 timer T := Tval;
196
197 T.start;
198 alt {
199 [] S1AP_ENB.receive(t_S1AP_RecvFrom(tr_pdu)) -> value recv {
200 pdu := recv.msg;
201 setverdict(pass);
202 T.stop;
203 }
204 [] S1AP_ENB.receive(t_S1AP_RecvFrom(?)) -> value recv {
205 pdu := recv.msg;
206 setverdict(fail, "Rx unexpected S1AP PDU from MME: ", pdu);
207 T.stop;
208 }
209 [] T.timeout {
210 setverdict(fail, "Timeout waiting for S1AP PDU from MME: ", tr_pdu);
211 }
212 }
213}
214
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700215function f_ConnHdlr_setup(Global_ENB_ID genb_id) runs on ConnHdlr {
216 var S1AP_PDU pdu;
217 timer T;
218
219 var SupportedTAs supported_tas_dummy := {
220 {
221 tAC := '0000'O,
222 broadcastPLMNs := { '00f000'O },
223 iE_Extensions := omit
224 }
225 };
226
Vadim Yanitskiy91cf9722024-06-18 03:11:11 +0700227 f_ConnHdlr_tx_s1ap_from_enb(ts_S1AP_SetupReq(genb_id,
228 supported_tas_dummy,
229 v32));
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700230 T.start(1.0);
231 alt {
232 [] S1AP_CONN.receive(S1APSRV_Event:S1APSRV_EVENT_CONN_UP) { repeat; }
233 [] S1AP_CONN.receive(tr_S1AP_SetupReq) {
234 setverdict(pass);
235 T.stop;
236 }
237 [] S1AP_CONN.receive(S1AP_PDU:?) -> value pdu {
238 setverdict(fail, "Rx unexpected S1AP PDU: ", pdu);
239 T.stop;
240 }
241 [] T.timeout {
242 setverdict(fail, "Timeout waiting for S1AP SetupReq");
243 }
244 }
245}
246
247
248function f_TC_setup(ConnHdlrPars pars) runs on ConnHdlr {
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700249 f_ConnHdlr_register(pars.genb_id);
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700250
251 f_ConnHdlr_connect();
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700252 f_ConnHdlr_setup(pars.genb_id);
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700253 f_sleep(0.5); /* keep the connection idle for some time */
254 f_ConnHdlr_disconnect();
255
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700256 f_ConnHdlr_unregister(pars.genb_id);
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700257}
258testcase TC_setup() runs on test_CT {
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700259 var ConnHdlrPars pars := valueof(t_ConnHdlrPars);
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700260 var ConnHdlr vc_conn;
261
Vadim Yanitskiy9ce73fe2024-06-12 05:08:36 +0700262 f_init();
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700263 f_init_s1ap_srv();
264
265 vc_conn := f_ConnHdlr_spawn(refers(f_TC_setup), pars);
266 vc_conn.done;
267}
268testcase TC_setup_multi() runs on test_CT {
269 var ConnHdlrList vc_conns := { };
270
Vadim Yanitskiy9ce73fe2024-06-12 05:08:36 +0700271 f_init();
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700272 f_init_s1ap_srv();
273
274 for (var integer i := 0; i < 42; i := i + 1) {
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700275 var ConnHdlrPars pars := valueof(t_ConnHdlrPars(i));
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700276 var ConnHdlr vc_conn := f_ConnHdlr_spawn(refers(f_TC_setup), pars);
277 vc_conns := vc_conns & { vc_conn };
278 }
279
280 for (var integer i := 0; i < 42; i := i + 1) {
281 vc_conns[i].done;
282 }
283}
Vadim Yanitskiy95cd9352024-05-31 18:29:17 +0700284
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700285
286/* MME terminates connection, expect S1GW to terminate the eNB connection */
287function f_TC_conn_term_by_mme(ConnHdlrPars pars) runs on ConnHdlr {
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700288 f_ConnHdlr_register(pars.genb_id);
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700289
290 f_ConnHdlr_connect();
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700291 f_ConnHdlr_setup(pars.genb_id);
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700292 f_sleep(0.5); /* keep the connection idle for some time */
293
294 /* MME (S1AP_Server_CT) terminates connection */
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700295 f_ConnHdlr_close_conn(pars.genb_id);
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700296 /* expect our eNB connection to be released gracefully */
Vadim Yanitskiy876a60f2024-06-12 19:50:47 +0700297 f_ConnHdlr_expect_shutdown();
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700298
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700299 f_ConnHdlr_unregister(pars.genb_id);
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700300}
301testcase TC_conn_term_by_mme() runs on test_CT {
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700302 var ConnHdlrPars pars := valueof(t_ConnHdlrPars);
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700303 var ConnHdlr vc_conn;
304
305 f_init();
306 f_init_s1ap_srv();
307
308 vc_conn := f_ConnHdlr_spawn(refers(f_TC_conn_term_by_mme), pars);
309 vc_conn.done;
310}
311
312
313/* MME is not available, expect S1GW to terminate the eNB connection */
314function f_TC_conn_term_mme_unavail(ConnHdlrPars pars) runs on ConnHdlr {
315 /* establish an eNB connection to the S1GW */
316 f_ConnHdlr_connect();
317 /* expect our eNB connection to be released gracefully */
Vadim Yanitskiy876a60f2024-06-12 19:50:47 +0700318 f_ConnHdlr_expect_shutdown();
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700319 setverdict(pass);
320}
321testcase TC_conn_term_mme_unavail() runs on test_CT {
Vadim Yanitskiy6dddcd42024-06-18 03:53:11 +0700322 var ConnHdlrPars pars := valueof(t_ConnHdlrPars);
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700323 var ConnHdlr vc_conn;
324
325 f_init();
326 f_init_s1ap_srv();
327 vc_S1APSRV.stop;
328
329 vc_conn := f_ConnHdlr_spawn(refers(f_TC_conn_term_mme_unavail), pars);
330 vc_conn.done;
331}
332
Vadim Yanitskiy91cf9722024-06-18 03:11:11 +0700333function f_TC_e_rab_setup(ConnHdlrPars pars) runs on ConnHdlr {
334 const integer mme_id := 7;
335 const integer enb_id := 9;
336 const integer erab_id := 6;
337 var S1AP_PDU pdu;
338
339 f_ConnHdlr_register(pars.genb_id);
340 f_ConnHdlr_connect();
341 f_ConnHdlr_setup(pars.genb_id);
342
343 log("eNB -> [S1GW] -> MME: E-RAB SETUP REQUEST");
344 var template (value) E_RABToBeSetupListBearerSUReq items_req;
345 var E_RABToBeSetupItemBearerSUReq item_req := {
346 e_RAB_ID := erab_id,
347 e_RABlevelQoSParameters := {
348 qCI := 5,
349 allocationRetentionPriority := {
350 priorityLevel := 1,
351 pre_emptionCapability := shall_not_trigger_pre_emption,
352 pre_emptionVulnerability := not_pre_emptable,
353 iE_Extensions := omit
354 },
355 gbrQosInformation := omit,
356 iE_Extensions := omit
357 },
358 transportLayerAddress := -,
359 gTP_TEID := f_rnd_octstring(4),
360 nAS_PDU := ''O,
361 iE_Extensions := omit
362 };
363
364 /* eNB -> S1GW */
365 item_req.transportLayerAddress := oct2bit(f_inet_addr("1.2.3.4"));
366 items_req := ts_S1AP_RABToBeSetupListBearerSUReq(item_req);
367 f_ConnHdlr_tx_s1ap_from_enb(ts_S1AP_RABSetupReq(mme_id, enb_id, items_req));
368
369 /* S1GW -> MME */
370 item_req.transportLayerAddress := oct2bit(f_inet_addr(mp_s1gw_mme_ip));
371 items_req := ts_S1AP_RABToBeSetupListBearerSUReq(item_req);
372 f_ConnHdlr_rx_s1ap_from_enb(pdu, tr_S1AP_RABSetupReq(mme_id, enb_id, items_req));
373
374
375 log("eNB <- [S1GW] <- MME: E-RAB SETUP RESPONSE");
376 var template (value) E_RABSetupListBearerSURes items_res;
377 var E_RABSetupItemBearerSURes item_res := {
378 e_RAB_ID := erab_id,
379 transportLayerAddress := -,
380 gTP_TEID := f_rnd_octstring(4),
381 iE_Extensions := omit
382 };
383
384 /* MME -> S1GW */
385 item_res.transportLayerAddress := oct2bit(f_inet_addr("4.3.2.1"));
386 items_res := ts_S1AP_RABSetupListBearerSURes(item_res);
387 f_ConnHdlr_tx_s1ap_from_mme(ts_S1AP_RABSetupRsp(mme_id, enb_id, items_res));
388
389 /* S1GW -> eNB */
390 item_res.transportLayerAddress := oct2bit(f_inet_addr(mp_s1gw_enb_ip));
391 items_res := ts_S1AP_RABSetupListBearerSURes(item_res);
392 f_ConnHdlr_rx_s1ap_from_mme(pdu, tr_S1AP_RABSetupRsp(mme_id, enb_id, items_res));
393
394 f_ConnHdlr_disconnect();
395 f_ConnHdlr_unregister(pars.genb_id);
396}
397testcase TC_e_rab_setup() runs on test_CT {
398 var ConnHdlrPars pars := valueof(t_ConnHdlrPars);
399 var ConnHdlr vc_conn;
400
401 f_init();
402 f_init_s1ap_srv();
403
404 vc_conn := f_ConnHdlr_spawn(refers(f_TC_e_rab_setup), pars);
405 vc_conn.done;
406}
407
Vadim Yanitskiy95cd9352024-05-31 18:29:17 +0700408control {
Vadim Yanitskiyced53d32024-06-11 03:19:06 +0700409 execute( TC_setup() );
410 execute( TC_setup_multi() );
Vadim Yanitskiycf96dd32024-06-12 06:54:05 +0700411 execute( TC_conn_term_by_mme() );
412 execute( TC_conn_term_mme_unavail() );
Vadim Yanitskiy91cf9722024-06-18 03:11:11 +0700413 execute( TC_e_rab_setup() );
Vadim Yanitskiy95cd9352024-05-31 18:29:17 +0700414}
415
416}