Alexander Couzens | 89b4eff | 2022-11-25 17:35:12 +0000 | [diff] [blame] | 1 | module BSC_Tests_OML { |
| 2 | |
| 3 | /* Integration Tests for OsmoBSC A-bis OML (Organization & Maintenance Link) |
| 4 | * |
| 5 | * (C) 2019 by Harald Welte <laforge@gnumonks.org> |
| 6 | * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> |
| 7 | * Author: Alexander Couzens <acouzens@sysmocom.de> |
| 8 | * All rights reserved. |
| 9 | * |
| 10 | * Released under the terms of GNU General Public License, Version 2 or |
| 11 | * (at your option) any later version. |
| 12 | * |
| 13 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 14 | */ |
| 15 | |
| 16 | /* The tests only require a BSC with VTY and OML to be present. */ |
| 17 | |
| 18 | import from General_Types all; |
| 19 | import from Osmocom_Types all; |
| 20 | import from AbisOML_Types all; |
| 21 | import from IPA_Emulation all; |
| 22 | import from IPA_Types all; |
| 23 | import from Misc_Helpers all; |
| 24 | import from Osmocom_VTY_Functions all; |
| 25 | import from TELNETasp_PortType all; |
| 26 | |
| 27 | import from BSC_Tests all; |
| 28 | |
| 29 | const integer NUM_TRX := 8; |
| 30 | |
| 31 | type record of uint16_t ArfcnList; |
| 32 | type record length(3) of IPA_CCM_Parameters IPA_CCM_Parameters_multiple; |
| 33 | |
| 34 | modulepar { |
| 35 | charstring mp_oml_ip := "127.0.0.1"; |
| 36 | integer mp_oml_port := 3002; |
| 37 | ArfcnList mp_arfcn := { 100, 101, 102, 103, 104, 105, 106, 107 }; |
| 38 | OML_FOM_T200 mp_t200 := { |
| 39 | sdcch_5ms := 30, |
| 40 | facch_f_5ms := 36, |
| 41 | facch_h_5ms := 36, |
| 42 | sacch_tch_sapi0_10ms := 168, |
| 43 | sacch_sdcch_10ms := 52, |
| 44 | sdcch_sapi3_5ms := 33, |
| 45 | sacch_rch_sapi3_10ms := 168 |
| 46 | }; |
| 47 | uint8_t mp_max_ta := 63; |
| 48 | uint8_t mp_load_threshold := 10; |
| 49 | uint8_t mp_load_ind_period := 1; |
| 50 | uint8_t mp_rach_b_thresh := 90; |
| 51 | uint16_t mp_loadavg_slots := 1000; |
| 52 | uint8_t mp_air_timer := 100; |
| 53 | uint8_t mp_ny1 := 10; |
| 54 | uint8_t mp_bsic := 63; |
| 55 | |
| 56 | IPA_CCM_Parameters_multiple mp_ccm_pars := { |
| 57 | { |
| 58 | ser_nr := "", |
| 59 | name := "", |
| 60 | location1 := "", |
| 61 | location2 := "", |
| 62 | equip_version := "", |
| 63 | sw_version := "", |
| 64 | ip_addr := "", |
| 65 | mac_addr := "", |
| 66 | unit_id := "1234/0/0", |
| 67 | osmo_rand := "" |
| 68 | }, |
| 69 | { |
| 70 | ser_nr := "", |
| 71 | name := "", |
| 72 | location1 := "", |
| 73 | location2 := "", |
| 74 | equip_version := "", |
| 75 | sw_version := "", |
| 76 | ip_addr := "", |
| 77 | mac_addr := "", |
| 78 | unit_id := "1235/0/0", |
| 79 | osmo_rand := "" |
| 80 | }, |
| 81 | { |
| 82 | ser_nr := "", |
| 83 | name := "", |
| 84 | location1 := "", |
| 85 | location2 := "", |
| 86 | equip_version := "", |
| 87 | sw_version := "", |
| 88 | ip_addr := "", |
| 89 | mac_addr := "", |
| 90 | unit_id := "1236/0/0", |
| 91 | osmo_rand := "" |
| 92 | } |
| 93 | }; |
| 94 | }; |
| 95 | |
| 96 | /* BSC side OML component */ |
| 97 | type component BTS_OML_CT { |
| 98 | /* IPA client */ |
| 99 | var IPA_Client client[3]; |
| 100 | |
| 101 | /* Port for OML */ |
| 102 | port IPA_OML_PT OML[3]; |
| 103 | |
| 104 | /* VTY */ |
| 105 | port TELNETasp_PT BSCVTY; |
| 106 | |
| 107 | /* As rxed by Get Attributes Response NM_ATT_MANUF_ID IE, see f_oml_getattr() */ |
| 108 | var bitstring g_bts_features[3]; |
| 109 | |
| 110 | /* global test case guard timer */ |
| 111 | timer T_oml_guard := 60.0; |
| 112 | }; |
| 113 | |
| 114 | private altstep as_Tguard() runs on BTS_OML_CT { |
| 115 | [] T_oml_guard.timeout { |
| 116 | setverdict(fail, "Timeout of T_guard"); |
| 117 | mtc.stop; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | private altstep as_IPA_evt(integer idx := 0) runs on BTS_OML_CT { |
| 122 | var ASP_IPA_Event evt; |
| 123 | [] OML[idx].receive(ASP_IPA_Event:?) -> value evt { |
| 124 | log("Ignoring ", evt); |
| 125 | repeat; |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | function f_init_vty() runs on BTS_OML_CT { |
| 130 | if (BSCVTY.checkstate("Mapped")) { |
| 131 | /* skip initialization if already executed once */ |
| 132 | return; |
| 133 | } |
| 134 | map(self:BSCVTY, system:BSCVTY); |
| 135 | f_vty_set_prompts(BSCVTY); |
| 136 | f_vty_transceive(BSCVTY, "enable"); |
| 137 | |
| 138 | f_vty_enter_config(BSCVTY); |
| 139 | f_vty_transceive(BSCVTY, "bsc"); |
| 140 | f_vty_transceive(BSCVTY, "no bts-setup-ramping"); |
| 141 | f_vty_transceive(BSCVTY, "end"); |
| 142 | } |
| 143 | |
| 144 | function f_init_oml(charstring id, integer num_instance := 1) runs on BTS_OML_CT { |
| 145 | activate(as_Tguard()); |
| 146 | for (var uint8_t idx := 0; idx < num_instance; idx := idx + 1) { |
| 147 | client[idx].id := id & "-" & int2str(idx); |
| 148 | client[idx].vc_IPA := IPA_Emulation_CT.create(id & "-IPA-" & int2str(idx)) alive; |
| 149 | client[idx].ccm_pars := mp_ccm_pars[idx]; |
| 150 | |
| 151 | map(client[idx].vc_IPA:IPA_PORT, system:IPA); |
| 152 | connect(client[idx].vc_IPA:IPA_OML_PORT, self:OML[idx]); |
| 153 | client[idx].vc_IPA.start(IPA_Emulation.main_client(mp_oml_ip, mp_oml_port, "", 10000 + idx, client[idx].ccm_pars)); |
| 154 | |
| 155 | T_oml_guard.start; |
| 156 | |
| 157 | OML[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)); |
| 158 | OML[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)); |
| 159 | |
| 160 | activate(as_IPA_evt(idx)); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | function f_oml_send_swact(integer idx := 0) runs on BTS_OML_CT |
| 165 | { |
| 166 | OML[idx].send(ts_OML_SwActivatedRep(NM_OC_SITE_MANAGER, {255, 255, 255})); |
| 167 | OML[idx].send(ts_OML_SwActivatedRep(NM_OC_BTS, {0, 255, 255})); |
| 168 | OML[idx].send(ts_OML_SwActivatedRep(NM_OC_BASEB_TRANSC, {0, 0, 255})); |
| 169 | OML[idx].send(ts_OML_SwActivatedRep(NM_OC_RADIO_CARRIER, {0, 0, 255})); |
| 170 | for (var uint8_t i := 0; i < 8; i := i + 1) { |
| 171 | OML[idx].send(ts_OML_SwActivatedRep(NM_OC_CHANNEL, {0, 0, i})); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | function f_oml_send_state_chg_evt_rep( |
| 176 | integer idx, |
| 177 | template (value) OML_FOM_OperationalState opstate, |
| 178 | template (value) OML_FOM_AvailabilityStatus avstate) runs on BTS_OML_CT |
| 179 | { |
| 180 | OML[idx].send(ts_OML_StateChgEvtRep(NM_OC_SITE_MANAGER, {255, 255, 255}, opstate, avstate)); |
| 181 | OML[idx].send(ts_OML_StateChgEvtRep(NM_OC_BTS, {0, 255, 255}, opstate, avstate)); |
| 182 | OML[idx].send(ts_OML_StateChgEvtRep(NM_OC_BASEB_TRANSC, {0, 0, 255}, opstate, avstate)); |
| 183 | OML[idx].send(ts_OML_StateChgEvtRep(NM_OC_RADIO_CARRIER, {0, 0, 255}, opstate, avstate)); |
| 184 | for (var uint8_t i := 0; i < 8; i := i + 1) { |
| 185 | OML[idx].send(ts_OML_StateChgEvtRep(NM_OC_CHANNEL, {0, 0, i}, opstate, avstate)); |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | |
| 190 | /* Send an OML message and expect no response at all */ |
| 191 | private function f_oml_send_exp_no_resp(template (value) OML_PDU tx, charstring err_msg, |
| 192 | float tout := 5.0, integer idx := 0) runs on BTS_OML_CT |
| 193 | { |
| 194 | timer T := tout; |
| 195 | |
| 196 | OML[idx].send(tx); |
| 197 | T.start; |
| 198 | alt { |
| 199 | [] OML[idx].receive { |
| 200 | setverdict(fail, err_msg); |
| 201 | } |
| 202 | [] T.timeout { |
| 203 | setverdict(pass); |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | private function f_oml_exp_rx(template OML_PDU exp_rx, charstring err_msg, integer idx := 0) |
| 209 | runs on BTS_OML_CT return OML_PDU |
| 210 | { |
| 211 | var OML_PDU rx; |
| 212 | timer T := 5.0; |
| 213 | |
| 214 | T.start; |
| 215 | alt { |
| 216 | [] OML[idx].receive(exp_rx) -> value rx { |
| 217 | setverdict(pass); |
| 218 | } |
| 219 | [] OML[idx].receive { repeat; } |
| 220 | [] T.timeout { |
| 221 | setverdict(fail, "Timeout waiting for ", err_msg); |
| 222 | } |
| 223 | } |
| 224 | return rx; |
| 225 | } |
| 226 | |
| 227 | /* Send an OML message and expect a failure event report in response */ |
| 228 | private function f_oml_send_exp_fail_rep(template (value) OML_PDU tx, charstring err_msg, |
| 229 | template OML_FOM_EventType evt := ?, |
| 230 | template OML_FOM_Severity severity := ?, |
| 231 | template OML_FOM_ProbableCause cause := ?, |
| 232 | float tout := 5.0, integer idx := 0) runs on BTS_OML_CT |
| 233 | { |
| 234 | var template OML_FOM_ObjectClass obj_class := ?; |
| 235 | var template OML_FOM_ObjectInstance obj_inst := ?; |
| 236 | if (ischosen(tx.u.fom)) { |
| 237 | obj_class := tx.u.fom.hdr.obj_class; |
| 238 | obj_inst := tx.u.fom.hdr.obj_inst; |
| 239 | } |
| 240 | var template OML_PDU exp_fail := tr_OML_FailureEvtRep(obj_class,obj_inst, evt, severity, cause); |
| 241 | |
| 242 | OML[idx].send(tx); |
| 243 | f_oml_exp_rx(exp_fail, "Failure Event Report"); |
| 244 | } |
| 245 | |
| 246 | /* Send an OML message and expect it to be NACKed with specified cause */ |
| 247 | private function f_oml_send_exp_nack(template (value) OML_PDU tx, template OML_FOM_NackCause exp_cause, |
| 248 | float tout := 5.0, integer idx := 0) runs on BTS_OML_CT |
| 249 | { |
| 250 | timer T := 5.0; |
| 251 | |
| 252 | var template OML_PDU exp_nack := f_OML_make_nack_exp(valueof(tx), exp_cause); |
| 253 | var template OML_PDU exp_ack := f_OML_make_ack_exp(valueof(tx)); |
| 254 | var OML_PDU rx; |
| 255 | |
| 256 | OML[idx].send(tx); |
| 257 | T.start; |
| 258 | alt { |
| 259 | [] OML[idx].receive(exp_ack) -> value rx { |
| 260 | setverdict(fail, "Unexpected ACK ", rx); |
| 261 | } |
| 262 | [] OML[idx].receive(exp_nack) -> value rx { |
| 263 | setverdict(pass); |
| 264 | } |
| 265 | [] OML[idx].receive { repeat; } |
| 266 | [] T.timeout { |
| 267 | setverdict(fail, "Timeout waiting for NACK ", exp_nack); |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | testcase TC_oml_nothing() runs on BTS_OML_CT { |
| 273 | f_init_oml(testcasename()); |
| 274 | f_sleep(40.0); |
| 275 | setverdict(pass); |
| 276 | } |
| 277 | |
| 278 | /* Test bts setup ramping. |
| 279 | * Enable bts setup ramping (limit how many BTS will be setuped within a time interval. |
| 280 | * 1. Send 3x BTS to configure |
| 281 | * 2. Wait until BTS0 and BTS1 is configured (need both to be sure, when the bts setup ramp interval got restartet). |
| 282 | * 3. BTS2 must setup within a time window (it should be 10 seconds, but have -+ 3 seconds to be on the save side). |
| 283 | */ |
| 284 | testcase TC_oml_bts_setup_ramp() runs on BTS_OML_CT { |
| 285 | var template (value) OML_PDU ts_nm_site_change_event := ts_OML_StateChgEvtRep(NM_OC_SITE_MANAGER, {255, 255, 255}, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); |
| 286 | var template OML_PDU tr_nm_site_op_start := tr_OML_Opstart(NM_OC_SITE_MANAGER, {255, 255, 255}); |
| 287 | |
| 288 | f_init_vty(); |
| 289 | |
| 290 | f_vty_enter_config(BSCVTY); |
| 291 | f_vty_transceive(BSCVTY, "bsc"); |
| 292 | f_vty_transceive(BSCVTY, "bts-setup-ramping"); |
| 293 | f_vty_transceive(BSCVTY, "bts-setup-ramping-step-size 1"); |
| 294 | f_vty_transceive(BSCVTY, "bts-setup-ramping-step-interval 10"); |
| 295 | f_vty_transceive(BSCVTY, "end"); |
| 296 | |
| 297 | f_init_oml(testcasename(), 3); |
| 298 | |
| 299 | f_oml_send_swact(0); |
| 300 | f_oml_send_swact(1); |
| 301 | f_oml_send_swact(2); |
| 302 | f_sleep(1.0); |
| 303 | OML[0].send(ts_nm_site_change_event); |
| 304 | OML[1].send(ts_nm_site_change_event); |
| 305 | OML[2].send(ts_nm_site_change_event); |
| 306 | OML[0].receive(tr_nm_site_op_start); |
| 307 | |
| 308 | /* OML[2]: we expect at least no OP start for 7 seconds */ |
| 309 | timer T_no_op := 7.0; |
| 310 | /* OML[2] we expect at least the OP start within 13 seconds */ |
| 311 | timer T_op := 13.0; |
| 312 | alt { |
| 313 | [] OML[1].receive(tr_nm_site_op_start) { T_no_op.start; T_op.start; repeat; } |
| 314 | [] OML[2].receive(tr_nm_site_op_start) { |
| 315 | if (T_no_op.running) { |
| 316 | setverdict(fail, "OP Start came to early. T_no_op is still running"); |
| 317 | } else if (T_op.running) { |
| 318 | setverdict(pass); |
| 319 | } else { |
| 320 | setverdict(fail, "OP Start came far too early."); |
| 321 | } |
| 322 | } |
| 323 | [] T_op.timeout { setverdict(fail, "Timeout. No OP Start PDU for OML[2]."); } |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | control { |
| 328 | /* execute( TC_oml_nothing() ); */ |
| 329 | execute( TC_oml_bts_setup_ramp() ); |
| 330 | } |
| 331 | |
| 332 | /* BTS: |
| 333 | * - Evt: Disabled/Locked |
| 334 | * - SW ACT |
| 335 | * - Evt: Disabled/Dependency |
| 336 | * - SET BTS ATTR |
| 337 | * - Opstart |
| 338 | * - Chg Adm State Unlocked |
| 339 | * - Evt: Disabled/Dependency/Unlocked |
| 340 | * - Evt: Enabled/0 (after last channel unlocked?) |
| 341 | */ |
| 342 | |
| 343 | /* Radio Carrier: |
| 344 | * - Evt: Disabled/Offline after SW ACT |
| 345 | * - Set Radio Carrier Attributes ? (->NACL) |
| 346 | * - Evt: Disabled/Dependency |
| 347 | * - Set Radio Carrier Attributes ? |
| 348 | * - Opstart |
| 349 | * - Chg Adm State Unlocked |
| 350 | * - Evt: |
| 351 | */ |
| 352 | |
| 353 | /* Baseband Transceiver: |
| 354 | * - Evt: Disabled/Locked |
| 355 | * - SW Activation |
| 356 | * - Evt: Disabled/Dependency after SW ACT |
| 357 | * - IPA RSL Connect |
| 358 | * - Opstart |
| 359 | * - Chg Admin Unlocked |
| 360 | * - Evt: Disabled/Dependency/Unlocked |
| 361 | */ |
| 362 | |
| 363 | /* Channel: |
| 364 | * - Evt: Not Installed/Locked |
| 365 | * - Evt: Disabled/Dependency (after SW ACT Rep on BB Transc) |
| 366 | * - Set Channel Attr |
| 367 | * - Opstart |
| 368 | * - Evt: Disabled/Offline |
| 369 | * - Chg Admin Unlocked |
| 370 | * - Evt: Disabled/OK/Unlocked |
| 371 | * - Evt: Enabled/OK (after BB TRANSC Opstart) |
| 372 | */ |
| 373 | |
| 374 | }; |