bsc: Introduce Osmux infra and one test for osmo-bsc

Test verifies once osmux is enabled in osmo-bsc, BSSMAP RESET (ACK)
contains Osmux Support IE and that it correctly handles BSSMAP ASsign
Req with Osmux CID.

Related: OS#2551
Depends: osmo-bsc 6de754cdde5319af3059d8fc6abf85037ec7eacc
Depends: titan.ProtocolModules.BSSMAP Iaf1e137269c0da20b2c96fd104b57edf336693af
Change-Id: If69c716dc06d61d810c32d1720a237c7535baca8
This commit is contained in:
Pau Espin 2019-05-20 19:31:47 +02:00 committed by Harald Welte
parent b2c6b38f3f
commit c6a53dbb2a
8 changed files with 129 additions and 34 deletions

View File

@ -54,6 +54,7 @@ const RanOps BSC_MS_RanOps := {
decode_dtap := false,
role_ms := true,
protocol := RAN_PROTOCOL_BSSAP,
use_osmux := false,
sccp_addr_local := omit,
sccp_addr_peer := omit
}

View File

@ -60,6 +60,7 @@ const RanOps MSC_RanOps := {
decode_dtap := false,
role_ms := false,
protocol := RAN_PROTOCOL_BSSAP,
use_osmux := false,
sccp_addr_local := omit,
sccp_addr_peer := omit
}

View File

@ -89,6 +89,9 @@ type component test_CT extends CTRL_Adapter_CT {
/* are we initialized yet */
var boolean g_initialized := false;
/* Osmux is enabled through VTY */
var boolean g_osmux_enabled := false;
/* global test case guard timer */
timer T_guard := 30.0;
@ -140,16 +143,16 @@ private function f_shutdown_helper() runs on test_CT {
private function f_legacy_bssap_reset() runs on test_CT {
var BSSAP_N_UNITDATA_ind ud_ind;
timer T := 5.0;
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0)));
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
T.start;
alt {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck)) {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) {
log("Received RESET-ACK in response to RESET, we're ready to go!");
}
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) -> value ud_ind {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled))) -> value ud_ind {
log("Respoding to inbound RESET with RESET-ACK");
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
ts_BSSMAP_ResetAck));
ts_BSSMAP_ResetAck(g_osmux_enabled)));
repeat;
}
[] BSSAP.receive { repeat; }
@ -257,15 +260,15 @@ altstep as_Tguard() runs on test_CT {
mtc.stop;
}
/* always respond with RESET ACK to RESET */
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) -> value ud_ind {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled))) -> value ud_ind {
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
ts_BSSMAP_ResetAck));
ts_BSSMAP_ResetAck(g_osmux_enabled)));
repeat;
}
}
altstep no_bssmap_reset() runs on test_CT {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled))) {
setverdict(fail, "unexpected BSSMAP Reset");
mtc.stop;
}
@ -289,6 +292,22 @@ function f_init_mgcp(charstring id) runs on test_CT {
vc_MGCP.start(MGCP_Emulation.main(ops, mgcp_pars, id));
}
/* Enable or disable (current default) Osmux. When enabling, BSSMAP Reset
* contains extra IE (OsmuxSupport) and osmo-bsc will handle AssignReq with
* OsmuxCID IE.
*/
private function f_vty_allow_osmux(boolean allow) runs on test_CT {
f_vty_enter_cfg_msc(BSCVTY, 0);
if (allow) {
f_vty_transceive(BSCVTY, "osmux on");
} else {
f_vty_transceive(BSCVTY, "osmux off");
}
f_vty_transceive(BSCVTY, "exit");
f_vty_transceive(BSCVTY, "exit");
g_osmux_enabled := allow;
}
function f_init_vty(charstring id := "foo") runs on test_CT {
if (BSCVTY.checkstate("Mapped")) {
/* skip initialization if already executed once */
@ -302,7 +321,7 @@ function f_init_vty(charstring id := "foo") runs on test_CT {
/* global initialization function
* \param nr_bts Number of BTSs we should start/bring up
* \param handler_mode Start an RSL_Emulation_CT component (true) or not (false) */
function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false) runs on test_CT {
function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false, boolean allow_osmux := false) runs on test_CT {
var integer i;
if (g_initialized) {
@ -313,10 +332,15 @@ function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false) runs o
T_guard.start;
activate(as_Tguard());
f_init_vty("VirtMSC");
f_vty_allow_osmux(allow_osmux);
/* Call a function of our 'parent component' RAN_Adapter_CT to start the
* MSC-side BSSAP emulation */
if (handler_mode) {
f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", MSC_RanOps);
var RanOps ranops := MSC_RanOps;
ranops.use_osmux := g_osmux_enabled;
f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", ranops);
f_ran_adapter_start(g_bssap);
} else {
f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", omit);
@ -328,7 +352,6 @@ function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false) runs o
f_ipa_ctrl_start(mp_bsc_ip, mp_bsc_ctrl_port);
f_init_mgcp("VirtMSC");
f_init_vty("VirtMSC");
for (i := 0; i < nr_bts; i := i+1) {
/* wait until osmo-bts-omldummy has respawned */
@ -605,15 +628,24 @@ testcase TC_assignment_cic_only() runs on test_CT {
}
/* generate an assignment request for either AoIP or SCCPlite */
function f_gen_ass_req() return PDU_BSSAP {
function f_gen_ass_req(boolean osmux_enabled := false) return PDU_BSSAP {
var PDU_BSSAP ass_cmd;
var BSSMAP_IE_Osmo_OsmuxCID osmux_cid := valueof(ts_OsmuxCID(0));
if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla));
if (osmux_enabled) {
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla, osmux_cid));
} else {
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla));
}
} else {
var BSSMAP_IE_CircuitIdentityCode cic := valueof(ts_BSSMAP_IE_CIC(0,1));
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit));
if (osmux_enabled) {
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit, osmux_cid));
} else {
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit));
}
}
return ass_cmd;
}
@ -632,13 +664,22 @@ function f_gen_handover_req() return PDU_BSSAP {
}
/* generate an assignment complete template for either AoIP or SCCPlite */
function f_gen_exp_compl() return template PDU_BSSAP {
function f_gen_exp_compl(boolean expect_osmux := false) return template PDU_BSSAP {
var template PDU_BSSAP exp_compl;
var BSSMAP_IE_Osmo_OsmuxCID osmux_cid := valueof(ts_OsmuxCID(0));
if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?);
if (expect_osmux) {
exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?, osmux_cid);
} else {
exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?, omit);
}
} else {
/* CIC is optional "*" as the MSC allocated it */
exp_compl := tr_BSSMAP_AssignmentComplete(*, omit);
if (expect_osmux) {
exp_compl := tr_BSSMAP_AssignmentComplete(*, omit, osmux_cid);
} else {
exp_compl := tr_BSSMAP_AssignmentComplete(*, omit);
}
}
return exp_compl;
}
@ -1002,9 +1043,9 @@ testcase TC_chan_rel_a_reset() runs on test_CT {
IPA_RSL[0].clear;
/* perform BSSAP RESET, expect RESET ACK and DISC.ind on connection */
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0)));
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
interleave {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck)) { }
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
[] BSSAP.receive(tr_BSSAP_DISC_ind(dt.sccp_conn_id, ?, ?)) { }
}
@ -1491,9 +1532,9 @@ testcase TC_paging_imsi_a_reset() runs on test_CT {
f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
/* Perform a BSSMAP Reset and wait for ACK */
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0)));
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
alt {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck)) { }
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
[] BSSAP.receive { repeat; }
}
@ -1945,8 +1986,8 @@ type record CodecListTest {
type record of CodecListTest CodecListTests
private function f_TC_assignment_codec(charstring id) runs on MSC_ConnHdlr {
var PDU_BSSAP ass_cmd := f_gen_ass_req();
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
var PDU_BSSAP ass_cmd := f_gen_ass_req(g_pars.use_osmux);
var template PDU_BSSAP exp_compl := f_gen_exp_compl(g_pars.use_osmux);
/* puzzle together the ASSIGNMENT REQ for given codec[s] */
if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
@ -2568,6 +2609,31 @@ testcase TC_assignment_codec_req_fr_hr() runs on test_CT {
setverdict(pass);
}
testcase TC_assignment_osmux() runs on test_CT {
var TestHdlrParams pars := f_gen_test_hdlr_pars();
var MSC_ConnHdlr vc_conn;
/* See note above */
var RSL_IE_Body mr_conf := {
other := {
len := 2,
payload := '2804'O
}
};
pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecAMR_H}));
pars.ass_codec_list.codecElements[0].s0_7 := '00000100'B; /* 5,90k */
pars.ass_codec_list.codecElements[0].s8_15 := '00000111'B;
pars.expect_mr_conf_ie := mr_conf;
pars.use_osmux := true;
f_init(1, true, true);
f_sleep(1.0);
vc_conn := f_start_handler(refers(f_TC_assignment_codec), pars);
vc_conn.done;
}
/* test the procedure of the MSC requesting a Classmark Update:
* a) BSSMAP Classmark Request should result in RR CLASSMARK ENQUIRY,
* b) L3 RR CLASSMARK CHANGE should result in BSSMAP CLASSMARK UPDATE */
@ -3993,6 +4059,8 @@ control {
execute( TC_assignment_codec_req_hr_fr() );
execute( TC_assignment_codec_req_fr_hr() );
execute( TC_assignment_osmux() );
/* RLL Establish Indication on inactive DCHAN / SAPI */
execute( TC_rll_est_ind_inact_lchan() );
execute( TC_rll_est_ind_inval_sapi1() );

View File

@ -263,6 +263,7 @@ altstep as_Media_ipacc() runs on MSC_ConnHdlr {
* MGW level media handling */
altstep as_Media_mgw(boolean norepeat := false) runs on MSC_ConnHdlr {
var MgcpCommand mgcp_cmd;
var MgcpOsmuxCID osmux_cid;
[] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
var SDP_Message sdp;
@ -289,7 +290,12 @@ altstep as_Media_mgw(boolean norepeat := false) runs on MSC_ConnHdlr {
int2str(mgcp_conn.sample_rate))),
valueof(ts_SDP_ptime(mgcp_conn.ptime)) } ));
var template MgcpResponse mgcp_resp;
mgcp_resp := ts_CRCX_ACK(mgcp_cmd.line.trans_id, mgcp_conn.conn_id, sdp);
if (g_pars.use_osmux and f_MgcpCmd_contains_par(mgcp_cmd, "X-OSMUX")) {
osmux_cid := f_MgcpCmd_extract_osmux_cid(mgcp_cmd);
mgcp_resp := ts_CRCX_ACK_osmux(mgcp_cmd.line.trans_id, mgcp_conn.conn_id, osmux_cid, sdp);
} else {
mgcp_resp := ts_CRCX_ACK(mgcp_cmd.line.trans_id, mgcp_conn.conn_id, sdp);
}
f_mgcp_par_append(mgcp_resp.params, ts_MgcpParSpecEP(g_media.mgcp_ep));
MGCP.send(mgcp_resp);
g_media.mgcp_conn[cid].crcx_seen := g_media.mgcp_conn[cid].crcx_seen + 1;
@ -364,8 +370,8 @@ runs on RAN_Emulation_CT return template PDU_BSSAP {
var template PDU_BSSAP resp := omit;
/* answer all RESET with a RESET ACK */
if (match(bssap, tr_BSSMAP_Reset)) {
resp := ts_BSSMAP_ResetAck;
if (match(bssap, tr_BSSMAP_Reset(g_ran_ops.use_osmux))) {
resp := ts_BSSMAP_ResetAck(g_ran_ops.use_osmux);
}
return resp;
@ -377,6 +383,7 @@ const RanOps MSC_RanOps := {
decode_dtap := false,
role_ms := false,
protocol := RAN_PROTOCOL_BSSAP,
use_osmux := false,
sccp_addr_local := omit,
sccp_addr_peer := omit
}
@ -431,7 +438,8 @@ type record TestHdlrParams {
TestHdlrEncrParams encr optional,
TestHdlrParamsLcls lcls,
TestHdlrParamsHandover handover optional,
boolean aoip
boolean aoip,
boolean use_osmux
};
/* Note: Do not use valueof() to get a value of this template, use
@ -455,7 +463,8 @@ template (value) TestHdlrParams t_def_TestHdlrPars := {
adjust_cx_exp := true
},
handover := omit,
aoip := true
aoip := true,
use_osmux := false
}
function f_create_chan_and_exp() runs on MSC_ConnHdlr {

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<testsuite name='BSC_Tests' tests='105' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
<testsuite name='BSC_Tests' tests='106' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
<testcase classname='BSC_Tests' name='TC_ctrl_msc_connection_status' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ctrl_msc0_connection_status' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ctrl' time='MASKED'/>
@ -46,6 +46,7 @@
<testcase classname='BSC_Tests' name='TC_assignment_codec_hr_exhausted_req_fr_hr' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_req_hr_fr' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_req_fr_hr' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_osmux' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_rll_est_ind_inact_lchan' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_rll_est_ind_inval_sapi1' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_rll_est_ind_inval_sapi3' time='MASKED'/>

View File

@ -143,6 +143,19 @@ module MGCP_Templates {
sdp := sdp
}
template MgcpResponse ts_CRCX_ACK_osmux(MgcpTransId trans_id, MgcpConnectionId conn_id, MgcpOsmuxCID osmux_cid, template SDP_Message sdp := omit) := {
line := {
code := "200",
trans_id := trans_id,
string := "OK"
},
params:= {
ts_MgcpParConnectionId(conn_id),
ts_MgcpParOsmuxCID(osmux_cid)
},
sdp := sdp
}
template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, MgcpConnectionId conn_id, template SDP_Message sdp := omit) := {
line := t_MgcpCmdLine("MDCX", trans_id, ep),
params := {

View File

@ -465,9 +465,9 @@ private function f_bssap_wait_for_reset() runs on RAN_Emulation_CT {
T.start;
alt {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) -> value ud_ind {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_ran_ops.use_osmux))) -> value ud_ind {
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
ts_BSSMAP_ResetAck));
ts_BSSMAP_ResetAck(g_ran_ops.use_osmux)));
}
[] as_reset_ack();
[] BSSAP.receive {
@ -483,10 +483,10 @@ private function f_bssap_wait_for_reset() runs on RAN_Emulation_CT {
function f_bssap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on RAN_Emulation_CT {
timer T := 5.0;
BSSAP.send(ts_BSSAP_UNITDATA_req(peer, own, ts_BSSMAP_Reset(0)));
BSSAP.send(ts_BSSAP_UNITDATA_req(peer, own, ts_BSSMAP_Reset(0, g_ran_ops.use_osmux)));
T.start;
alt {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(own, peer, tr_BSSMAP_ResetAck)) {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(own, peer, tr_BSSMAP_ResetAck(g_ran_ops.use_osmux))) {
log("Received RESET-ACK in response to RESET, we're ready to go!");
}
[] as_reset_ack();
@ -650,6 +650,7 @@ type record RanOps {
boolean decode_dtap,
boolean role_ms,
RanProtocol protocol,
boolean use_osmux,
/* needed for performing BSSMAP RESET */
SCCP_PAR_Address sccp_addr_local optional,
SCCP_PAR_Address sccp_addr_peer optional
@ -727,10 +728,10 @@ private altstep as_reset_ack() runs on RAN_Emulation_CT {
var RANAP_N_UNITDATA_ind rud_ind;
#endif
#ifdef RAN_EMULATION_BSSAP
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) -> value ud_ind {
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_ran_ops.use_osmux))) -> value ud_ind {
log("Respoding to inbound RESET with RESET-ACK");
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
ts_BSSMAP_ResetAck));
ts_BSSMAP_ResetAck(g_ran_ops.use_osmux)));
repeat;
}
#endif

View File

@ -209,6 +209,7 @@ const RanOps BSC_RanOps := {
decode_dtap := true,
role_ms := true,
protocol := RAN_PROTOCOL_BSSAP,
use_osmux := false,
sccp_addr_local := omit,
sccp_addr_peer := omit
}