module STP_Tests_IPA { /* Osmocom STP test suite in in TTCN-3 * (C) 2019 Harald Welte * All rights reserved. * * Released under the terms of GNU General Public License, Version 2 or * (at your option) any later version. * * SPDX-License-Identifier: GPL-2.0-or-later */ friend module STP_Tests_IPA_M3UA; import from General_Types all; import from Osmocom_Types all; import from IPL4asp_Types all; import from Misc_Helpers all; import from TELNETasp_PortType all; import from Osmocom_VTY_Functions all; import from SCCP_Types all; import from SCCP_Templates all; import from SCCPasp_Types all; import from SCCP_Emulation all; import from IPA_Types all; import from IPA_CodecPort all; import from IPA_Emulation all; import from M3UA_Emulation all; import from M3UA_CodecPort all; import from MTP3asp_Types all; import from MTP3asp_PortType all; import from STP_Tests_Common all; private const integer MAX_NR_IPA := 8; type record of charstring AspNameArray; modulepar { charstring mp_stp_ipa_ip := "127.0.0.1"; charstring mp_local_ipa_ip := "127.0.0.1"; integer mp_stp_ipa_port := 5000; //integer mp_local_ipa_port := 20000; /* local ASPs. Set in .cfg file: */ IpaConfigs mp_ipa_configs := {} } type record IpaConfig { /* Name of the ASP in the STP, (eg. to access it over VTY) */ charstring asp_name, /* Name of the AS in the STP, (eg. to access it over VTY) */ charstring as_name, /* Whether local side is a TCP/SCTP server */ boolean is_server, /* STP-side SCTP (or TCP) port for M3UA */ integer remote_port, /* local M3UA base port on TTCN3 side */ integer local_port }; type record of IpaConfig IpaConfigs; type component IPA_CT extends Test_CT { /* for IPA we use the IPA_Emulation and not directly IPA_CodecPort to avoid * having to re-invent IPA CCM handling here */ port MTP3asp_PT IPA[MAX_NR_IPA]; port IPA_SP_PT IPA_CTRL[MAX_NR_IPA]; port IPA_CFG_PT IPA_CFG[MAX_NR_IPA]; var IPA_Emulation_CT vc_IPA[MAX_NR_IPA]; var IPA_CCM_Parameters g_ccm_pars[MAX_NR_IPA]; var IpaConfigs g_ipa_configs; } friend function ipa_build_configs(template (omit) Misc_Helpers.ro_charstring asps := omit) return IpaConfigs { if (not isvalue(asps)) { return mp_ipa_configs; } var IpaConfigs ipa_configs := {}; for (var integer i := 0; i < lengthof(asps); i := i + 1) { var boolean found := false; for (var integer j := 0; j < lengthof(mp_ipa_configs); j := j + 1) { if (mp_ipa_configs[j].asp_name == valueof(asps[i])) { found := true; ipa_configs := ipa_configs & {mp_ipa_configs[j]}; break; } } if (not found) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Could not find ASP ", asps[i], ", check your configuration")); } } return ipa_configs; } private function f_vty_cs7_listen_ipa_cmd(charstring cmd, integer ipa_port := 5000) runs on IPA_CT { f_vty_config2(VTY, {"cs7 instance 0", "listen ipa " & int2str(ipa_port)}, cmd); } friend function f_vty_cs7_ipa_as_cmd(charstring as_name, charstring cmd) runs on IPA_CT { f_vty_config2(VTY, {"cs7 instance 0", "as " & as_name & " ipa"}, cmd); } private function f_ipa_asp_cfg_str(in IpaConfig cfg) return charstring { var charstring str; str := "asp " & cfg.asp_name; str := str & " " & int2str(cfg.local_port); str := str & " " & int2str(cfg.remote_port); str := str & " ipa"; return str; } private function f_vty_cs7_ipa_asp_cmd(IpaConfig cfg, charstring cmd) runs on IPA_CT { var charstring asp_cfg_str := f_ipa_asp_cfg_str(cfg); f_vty_config2(VTY, {"cs7 instance 0", asp_cfg_str}, cmd); } friend function f_IPA_send(integer idx, octetstring data) runs on IPA_CT { var MTP3_Field_sio sio := { ni := '00'B, prio := '00'B, si := '0011'B }; IPA[idx].send(t_ASP_MTP3_TRANSFERreq(sio, 0, 0, 0, data)); } friend function f_IPA_exp(integer idx, template (present) octetstring data, float timeout_val := 5.0) runs on IPA_CT { timer T := timeout_val; T.start; alt { [] IPA[idx].receive(t_ASP_MTP3_TRANSFERind(?, ?, ?, ?, data)) { setverdict(pass); } [] IPA[idx].receive { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unexpected data on IPA port while waiting for ", data)); } [] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for IPA[", idx, "] ", data)); } } } /* Test if traffic is routed from idx_tx to idx_rx */ private function f_test_traffic(integer idx_tx, integer idx_rx) runs on IPA_CT { var octetstring data := f_SCCP_UDT(); f_IPA_send(idx_tx, data); f_IPA_exp(idx_rx, data); } friend function f_init_ipa(template (omit) IpaConfigs ipa_configs := omit) runs on IPA_CT { var integer i; f_init_common(); if (not istemplatekind(ipa_configs, "omit")) { g_ipa_configs := valueof(ipa_configs); } else { g_ipa_configs := mp_ipa_configs; } for (i := 0; i < lengthof(g_ipa_configs); i:=i+1) { vc_IPA[i] := IPA_Emulation_CT.create("IPA" & int2str(i)); map(vc_IPA[i]:IPA_PORT, system:IPA_CODEC_PT); connect(self:IPA[i], vc_IPA[i]:MTP3_SP_PORT); connect(self:IPA_CTRL[i], vc_IPA[i]:IPA_SP_PORT); connect(self:IPA_CFG[i], vc_IPA[i]:CFG_PORT); g_ccm_pars[i] := c_IPA_default_ccm_pars; g_ccm_pars[i].name := g_ipa_configs[i].as_name; } } friend function f_connect_ipa(integer idx, boolean exp_act := true) runs on IPA_CT { vc_IPA[idx].start(IPA_Emulation.main_client(mp_stp_ipa_ip, g_ipa_configs[idx].remote_port, mp_local_ipa_ip, g_ipa_configs[idx].local_port, g_ccm_pars[idx])); IPA_CTRL[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)); alt { [exp_act] IPA_CTRL[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)); [not exp_act] IPA_CTRL[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)); [] IPA_CTRL[idx].receive(tr_ASP_IPA_EV(?)) { repeat; } } } friend function f_listen_ipa(integer idx) runs on IPA_CT { vc_IPA[idx].start(IPA_Emulation.main_server(mp_local_ipa_ip, g_ipa_configs[idx].local_port)); /* wait for incoming connection to IPA port before proceeding */ var integer st := 0; timer T := 10.0; T.start; alt { [st == 0] IPA_CTRL[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { st := 1; repeat; } [st == 1] IPA_CTRL[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_RESP)) { st := 2; repeat; } [st == 2] IPA_CTRL[idx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) { setverdict(pass); } [] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No connection to IPA[", idx, "] Port")); } } } /* "accept-asp-connections pre-configured" and client from unknown ASP source * (but known AS/ipa_unit_name) */ testcase TC_unknown_client_nodynamic() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); /* Build an ASP unknown (port) from osmo-stp: */ ipa_configs[0].asp_name := "ipa-asp-unknown"; ipa_configs[0].local_port := 3000; f_init_common(); f_vty_cs7_listen_ipa_cmd("accept-asp-connections pre-configured", ipa_configs[0].remote_port); f_init_ipa(ipa_configs := ipa_configs); f_connect_ipa(0, false); /* switch back to default */ f_vty_cs7_listen_ipa_cmd("accept-asp-connections dynamic-permitted", ipa_configs[0].remote_port); setverdict(pass); } /* "accept-asp-connections pre-configured" and client from known ASP (TCP endpoint) * but unknown AS (ipa_unit_name) */ testcase TC_unknown_as_client_nodynamic() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); /* Build an AS unknown (ipa_unit_id) from osmo-stp: */ ipa_configs[0].as_name := "ipa-as-unknown"; f_init_common(); f_vty_cs7_listen_ipa_cmd("accept-asp-connections pre-configured", ipa_configs[0].remote_port); f_init_ipa(ipa_configs := ipa_configs); f_connect_ipa(0, false); /* switch back to default */ f_vty_cs7_listen_ipa_cmd("accept-asp-connections dynamic-permitted", ipa_configs[0].remote_port); setverdict(pass); } /* "accept-asp-connections pre-configured" and client from known source (ASP & AS) */ testcase TC_known_client_nodynamic() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); f_init_common(); f_vty_cs7_listen_ipa_cmd("accept-asp-connections pre-configured", ipa_configs[0].remote_port); f_init_ipa(ipa_configs := ipa_configs); f_connect_ipa(0); /* switch back to default */ f_vty_cs7_listen_ipa_cmd("accept-asp-connections dynamic-permitted", ipa_configs[0].remote_port); setverdict(pass); } /* "accept-asp-connections dynamic-permitted" and client from unknown ASP source * (but known AS/ipa_unit_name) */ testcase TC_unknown_client_dynamic() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); /* Build an ASP unknown (port) from osmo-stp: */ ipa_configs[0].asp_name := "ipa-asp-unknown"; ipa_configs[0].local_port := 3001; f_init_common(); f_init_ipa(ipa_configs := ipa_configs); f_connect_ipa(0); setverdict(pass); } /* "accept-asp-connections dynamic-permitted" and client from known ASP (TCP endpoint) * but unknown AS (ipa_unit_name) */ testcase TC_unknown_as_client_dynamic() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); /* Build an AS unknown (ipa_unit_id) from osmo-stp: */ ipa_configs[0].as_name := "ipa-as-unknown"; f_init_common(); f_init_ipa(ipa_configs := ipa_configs); f_connect_ipa(0, false); setverdict(pass); } private function f_tc_tmt_override(boolean unknown_dynamic_asp) runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-override-sender", "ipa-asp-override-receiver0", "ipa-asp-override-receiver1" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); if (unknown_dynamic_asp) { ipa_configs[0].local_port := 3002; ipa_configs[1].local_port := 3003; ipa_configs[2].local_port := 3004; } f_init_ipa(ipa_configs := ipa_configs); /* bring up the 'sender' side (single ASP in AS) */ f_connect_ipa(0); /* activate the first 'receiver' side ASP */ f_connect_ipa(1); /* verify traffic is routed from sender to [sole] receiver */ f_test_traffic(0, 1); /* activate the second 'receiver' side ASP */ f_connect_ipa(2); /* verify traffic is routed from sender to new receiver */ f_test_traffic(0, 2); setverdict(pass); } /* test "traffic-mode override" behavior */ testcase TC_tmt_override() runs on IPA_CT { f_tc_tmt_override(false); } /* test "traffic-mode override" behavior, with "accept-asp-connections dynamic-permitted" and clients from unknown ASPs */ testcase TC_unknown_client_dynamic_tmt_override() runs on IPA_CT { f_tc_tmt_override(true); } private altstep as_count_rx(integer idx, template (present) octetstring exp, inout integer counter) runs on IPA_CT { [] IPA[idx].receive(t_ASP_MTP3_TRANSFERind(?, ?, ?, ?, exp)) { counter := counter + 1; } } private function f_tc_tmt_loadshare_roundrobin(boolean unknown_dynamic_asp) runs on IPA_CT { var integer i; var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0", "ipa-asp-loadshare-receiver0", "ipa-asp-loadshare-receiver1" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); if (unknown_dynamic_asp) { ipa_configs[0].local_port := 3005; ipa_configs[1].local_port := 3006; ipa_configs[2].local_port := 3007; } f_init_ipa(ipa_configs := ipa_configs); f_vty_cs7_ipa_as_cmd(ipa_configs[1].as_name, "traffic-mode roundrobin"); /* bring up the 'sender' side (single ASP in AS) */ f_connect_ipa(0); /* activate the first 'receiver' side ASP */ f_connect_ipa(1); /* verify traffic is routed from sender to [sole] receiver */ for (i := 0; i < 10; i := i+1) { f_test_traffic(0, 1); } /* activate the second 'receiver' side ASP */ f_connect_ipa(2); /* verify traffic is routed from sender to new receiver */ const integer iter_per_asp := 5; var integer num_rx[2] := { 0, 0 }; for (i := 0; i < 2*iter_per_asp; i := i+1) { var octetstring data := f_SCCP_UDT(); f_IPA_send(0, data); alt { [] as_count_rx(1, data, num_rx[0]); [] as_count_rx(2, data, num_rx[1]); } } /* FIXME: check for extraneous messages? */ for (i := 0; i < 2; i := i+1) { if (num_rx[i] != iter_per_asp) { setverdict(fail, "Received ", num_rx[i], " out of expected ", iter_per_asp, "DATA messages at IPA port ", i); } } setverdict(pass); f_vty_cs7_ipa_as_cmd(ipa_configs[1].as_name, "no traffic-mode"); } /* test "traffic-mode load-share" behavior */ testcase TC_tmt_loadshare_roundrobin() runs on IPA_CT { f_tc_tmt_loadshare_roundrobin(false); } private altstep as_count_rx_sls(integer idx, template (present) octetstring exp, inout Integers sls_counter, inout integer rx_counter) runs on IPA_CT { var ASP_MTP3_TRANSFERind rx; [] IPA[idx].receive(t_ASP_MTP3_TRANSFERind(?, ?, ?, ?, exp)) -> value rx { var integer sls := rx.sls; /* This should in general be 0 in IPA. */ sls_counter[sls] := sls_counter[sls] + 1; rx_counter := rx_counter + 1; } } private function f_tc_tmt_loadshare_sls(boolean unknown_dynamic_asp) runs on IPA_CT { var integer i; var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-sender0", "ipa-asp-loadshare-sender1", "ipa-asp-loadshare-receiver0", "ipa-asp-loadshare-receiver1" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); if (unknown_dynamic_asp) { ipa_configs[0].local_port := 9998; ipa_configs[1].local_port := 9999; } f_init_ipa(ipa_configs := ipa_configs); f_vty_config3(VTY, {"cs7 instance 0", "as " & ipa_configs[2].as_name & " ipa"}, { "traffic-mode loadshare", "binding-table reset" }); /* bring up the 'sender' side (single ASP in AS) */ f_connect_ipa(0); /* activate the first 'receiver' side ASP */ f_connect_ipa(2); /* verify traffic is routed from sender to [sole] receiver */ for (i := 0; i < 10; i := i+1) { f_test_traffic(0, 2); } /* activate the second 'receiver' side ASP */ f_connect_ipa(3); /* Since we are using dynamic ASPs, they were unknown by STP until they got connected. * Hence, reset the binding-table so that load is now properly spread among them: */ f_vty_cs7_ipa_as_cmd(ipa_configs[2].as_name, "binding-table reset"); /* verify traffic is routed from sender to new receiver */ const integer iter_per_asp := 20; const integer NUM_SLS := 16; /* SLS in ITU is 4 bits. */ var integer num_rx_1 := 0; var integer num_rx_2 := 0; var Integers sls_num_rx_1 := {}; var Integers sls_num_rx_2 := {}; for (i := 0; i < NUM_SLS; i := i + 1) { sls_num_rx_1 := sls_num_rx_1 & {0}; sls_num_rx_2 := sls_num_rx_2 & {0}; } for (i := 0; i < iter_per_asp; i := i+1) { var octetstring data := f_SCCP_UDT(); f_IPA_send(0, data); alt { [] as_count_rx_sls(2, data, sls_num_rx_1, num_rx_1); [] as_count_rx_sls(3, data, sls_num_rx_2, num_rx_2); } } /* All traffic should still be sent to the same receiver, since * OPC+DPC+SLS cannot change in IPA ASPs. * However, depending on how the SLS seed tables were allocated, it can * be that STP was routing through Alternative Route and now that the * 2nd receiver is up it is now routing to it (Normal Route). Account * for both scenarios. */ if (not ((num_rx_1 == iter_per_asp and num_rx_2 == 0) or (num_rx_2 == iter_per_asp and num_rx_1 == 0))) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Expected all traffic through same receiver!"); } /* activate the second 'sender' side ASP */ f_connect_ipa(1); num_rx_1 := 0; num_rx_2 := 0; sls_num_rx_1 := {}; sls_num_rx_2 := {}; for (i := 0; i < NUM_SLS; i := i + 1) { sls_num_rx_1 := sls_num_rx_1 & {0}; sls_num_rx_2 := sls_num_rx_2 & {0}; } for (i := 0; i < 2*iter_per_asp; i := i+1) { var octetstring data := f_SCCP_UDT(); f_IPA_send(i mod 2, data); alt { [] as_count_rx_sls(2, data, sls_num_rx_1, num_rx_1); [] as_count_rx_sls(3, data, sls_num_rx_2, num_rx_2); } } /* Make sure traffic was sent over both ASPs and that it was distributed: */ if (num_rx_1 == 0) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Rx 0 packets in 1st ASP!"); } if (num_rx_2 == 0) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Rx 0 packets in 2nd ASP!"); } if (num_rx_1 + num_rx_2 != 2*iter_per_asp) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Rx ", num_rx_1 + num_rx_2 ," packets in total vs exp ", 2*iter_per_asp)); } setverdict(pass); f_vty_cs7_ipa_as_cmd(ipa_configs[2].as_name, "no traffic-mode"); } /* test "traffic-mode load-share" behavior */ testcase TC_tmt_loadshare_sls() runs on IPA_CT { f_tc_tmt_loadshare_sls(false); } /* test "traffic-mode loadshare" behavior, with "accept-asp-connections dynamic-permitted" and clients from unknown ASPs */ testcase TC_unknown_client_dynamic_tmt_loadshare() runs on IPA_CT { f_tc_tmt_loadshare_sls(true); } /* Test AS Loadsharing, (distributing traffic within linksets/ASs of a combined linkset). * STP routing table is configured with 1 combined linkset towards PC 32 mask /14 with 2 * AS routes ("ipa-as-LS0-0", "ipa-as-LS0-1") with same priority, each using 1 * ASP ("ipa-asp-LS0-0-0", "ipa-asp-LS0-1-0"). * We take advantage of the fact that AS "ipa-as-loadshare-receiver" is never used * to transmit in other tests and use it here for the routing of its configured * "point-code override dpc 32" towards the "ipa-as-LS0-{0,1}" in the STP config. */ private function f_tc_combinedlset_loadshare(boolean unknown_dynamic_asp) runs on IPA_CT { var integer i; var Misc_Helpers.ro_charstring asps := { "ipa-asp-loadshare-receiver0", "ipa-asp-loadshare-receiver1", "ipa-asp-LS0-0-0", "ipa-asp-LS0-1-0" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); if (unknown_dynamic_asp) { ipa_configs[0].local_port := 9998; ipa_configs[1].local_port := 9999; } f_init_ipa(ipa_configs := ipa_configs); /* bring up the 'sender' side (single ASP in AS) */ f_connect_ipa(0); /* activate the first 'receiver' side ASP */ f_connect_ipa(2); /* verify traffic is routed from sender to [sole] receiver */ for (i := 0; i < 10; i := i+1) { f_test_traffic(0, 2); } /* activate the second 'receiver' side ASP */ f_connect_ipa(3); /* verify traffic is routed from sender to new receiver */ const integer iter_per_asp := 20; const integer NUM_SLS := 16; /* SLS in ITU is 4 bits. */ var integer num_rx_1 := 0; var integer num_rx_2 := 0; var Integers sls_num_rx_1 := {}; var Integers sls_num_rx_2 := {}; for (i := 0; i < NUM_SLS; i := i + 1) { sls_num_rx_1 := sls_num_rx_1 & {0}; sls_num_rx_2 := sls_num_rx_2 & {0}; } for (i := 0; i < iter_per_asp; i := i+1) { var octetstring data := f_SCCP_UDT(); f_IPA_send(0, data); alt { [] as_count_rx_sls(2, data, sls_num_rx_1, num_rx_1); [] as_count_rx_sls(3, data, sls_num_rx_2, num_rx_2); } } /* All traffic should still be sent to the same receiver, since * OPC+DPC+SLS cannot change in IPA ASPs. * However, depending on how the SLS seed tables were allocated, it can * be that STP was routing through Alternative Route and now that the * 2nd receiver is up it is now routing to it (Normal Route). Account * for both scenarios. */ if (not ((num_rx_1 == iter_per_asp and num_rx_2 == 0) or (num_rx_2 == iter_per_asp and num_rx_1 == 0))) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Expected all traffic through same receiver!"); } /* activate the second 'sender' side ASP */ f_connect_ipa(1); num_rx_1 := 0; num_rx_2 := 0; sls_num_rx_1 := {}; sls_num_rx_2 := {}; for (i := 0; i < NUM_SLS; i := i + 1) { sls_num_rx_1 := sls_num_rx_1 & {0}; sls_num_rx_2 := sls_num_rx_2 & {0}; } for (i := 0; i < 2*iter_per_asp; i := i+1) { var octetstring data := f_SCCP_UDT(); f_IPA_send(i mod 2, data); alt { [] as_count_rx_sls(2, data, sls_num_rx_1, num_rx_1); [] as_count_rx_sls(3, data, sls_num_rx_2, num_rx_2); } } /* Make sure traffic was sent over both ASPs and that it was distributed: */ if (num_rx_1 == 0) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Rx 0 packets in 1st ASP!"); } if (num_rx_2 == 0) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Rx 0 packets in 2nd ASP!"); } if (num_rx_1 + num_rx_2 != 2*iter_per_asp) { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Rx ", num_rx_1 + num_rx_2 ," packets in total vs exp ", 2*iter_per_asp)); } setverdict(pass); } testcase TC_combinedlset_loadshare() runs on IPA_CT { f_tc_combinedlset_loadshare(false); } /* same as above, with "accept-asp-connections dynamic-permitted" and clients from unknown ASPs */ testcase TC_unknown_client_dynamic_combinedlset_loadshare() runs on IPA_CT { f_tc_combinedlset_loadshare(true); } private function f_IPA_ping(integer idx) runs on IPA_CT { var IpaCcmMsgtype ipa_ping_msg := IPAC_MSGT_PING; var IpaCcmMsgtype ipa_pong_msg := IPAC_MSGT_PONG; var octetstring ipa_ping_data := int2oct(enum2int(ipa_ping_msg), 1); var octetstring ipa_pong_data := int2oct(enum2int(ipa_pong_msg), 1); timer T := 3.0; T.start; IPA_CTRL[idx].send(valueof(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_ping_data))); alt { [] IPA_CTRL[idx].receive(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_pong_data)) { setverdict(pass); } [] IPA_CTRL[idx].receive(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_ping_data)) { /* Answer any PING from peer meanwhile: */ IPA_CTRL[0].send(valueof(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_pong_data))); repeat; } } } testcase TC_beat() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-override-sender" }; var IpaConfigs ipa_configs := ipa_build_configs(asps); f_init_common(); f_init_ipa(ipa_configs := ipa_configs); f_connect_ipa(0); f_ipa_cfg_chg_ccm_enabled(IPA_CFG[0], false); f_IPA_ping(0); } private function f_TC_beat_timeout(Misc_Helpers.ro_charstring asps) runs on IPA_CT { var IpaConfigs ipa_configs := ipa_build_configs(asps); var ASP_MTP3_TRANSFERind rx; var float timeout_val := 3.0 + 1.0; var IpaCcmMsgtype ipa_ping_msg := IPAC_MSGT_PING; var IpaCcmMsgtype ipa_pong_msg := IPAC_MSGT_PONG; var octetstring ipa_ping_data := int2oct(enum2int(ipa_ping_msg), 1); var octetstring ipa_pong_data := int2oct(enum2int(ipa_pong_msg), 1); f_init_common(); f_init_ipa(ipa_configs := ipa_configs); f_vty_cs7_ipa_asp_cmd(ipa_configs[0], "timer xua beat 3"); if (ipa_configs[0].is_server) { f_listen_ipa(0); } else { f_connect_ipa(0); } /* receive CCM IPA PING: */ f_ipa_cfg_chg_ccm_enabled(IPA_CFG[0], false); IPA_CTRL[0].receive(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_ping_data)); log("1st PING received"); IPA_CTRL[0].send(valueof(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_pong_data))); /* Make sure next HEARBEAT arrives around the time we configured. * Do not answer this nor next heardbeat: */ IPA_CTRL[0].receive(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_ping_data)); log("2nd PING received"); IPA_CTRL[0].receive(t_ASP_IPA_UD(IPAC_PROTO_CCM, ipa_ping_data)); log("3rd PING received"); /* After 2*T(beat), IUT should figure out peer is not responding and terminate the conn: */ timer T := timeout_val; T.start; alt { [] IPA_CTRL[0].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)) { setverdict(pass); } [] IPA[0].receive(t_ASP_MTP3_TRANSFERind(?, ?, ?, ?, ?)) -> value rx { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unexpected IPA ", rx, " while waiting for connClosed")); } [] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for IPA connClosed")); } } /* return to default value: */ f_vty_cs7_ipa_asp_cmd(g_ipa_configs[0], "timer xua beat 30"); } /* Test the IUT sends heartbeat procedure when needed. */ testcase TC_beat_timeout() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-override-sender" }; f_TC_beat_timeout(asps); } /* Test the IUT sends heartbeat procedure when needed. */ testcase TC_clnt_beat_timeout() runs on IPA_CT { var Misc_Helpers.ro_charstring asps := { "ipa-asp-client0" }; f_TC_beat_timeout(asps); } control { execute( TC_unknown_client_nodynamic() ); execute( TC_unknown_as_client_nodynamic() ); execute( TC_known_client_nodynamic() ); execute( TC_unknown_client_dynamic() ); execute( TC_unknown_as_client_dynamic() ); execute( TC_tmt_override() ); execute( TC_unknown_client_dynamic_tmt_override() ); execute( TC_tmt_loadshare_roundrobin() ); execute( TC_tmt_loadshare_sls() ); execute( TC_unknown_client_dynamic_tmt_loadshare() ); execute( TC_combinedlset_loadshare() ); execute( TC_unknown_client_dynamic_combinedlset_loadshare() ); execute( TC_beat() ); execute( TC_beat_timeout() ); execute( TC_clnt_beat_timeout() ); } }