diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2022-03-08 14:03:33 +0100 |
---|---|---|
committer | pespin <pespin@sysmocom.de> | 2022-04-11 12:04:55 +0000 |
commit | 77fdd0b5aa968e5826ef1ccf329589348bb1920e (patch) | |
tree | 2ccee743e4ac7235ac727f32d10cd220ecfc7eb6 | |
parent | 93ad8143f18f2ea8a8b9d0e05faa682be10119ac (diff) |
ggsn: Initial testing of open5gs Gy interface
Related: SYS#5276
Change-Id: I10027d4f8adc6b47ce97b90514d1f13e9aa3d40d
-rw-r--r-- | ggsn_tests/GGSN_Tests.ttcn | 138 | ||||
-rw-r--r-- | library/DIAMETER_Templates.ttcn | 121 | ||||
-rw-r--r-- | library/Osmocom_Types.ttcn | 1 | ||||
-rw-r--r-- | pgw/PGW_Tests.ttcn | 4 |
4 files changed, 249 insertions, 15 deletions
diff --git a/ggsn_tests/GGSN_Tests.ttcn b/ggsn_tests/GGSN_Tests.ttcn index 203dcbf1..7f6f67ce 100644 --- a/ggsn_tests/GGSN_Tests.ttcn +++ b/ggsn_tests/GGSN_Tests.ttcn @@ -39,6 +39,7 @@ module GGSN_Tests { const integer GTP1C_PORT := 2123; const integer GTP1U_PORT := 2152; const integer PCRF_PORT := 3868; + const integer OCS_PORT := 3869; type enumerated GGSN_Impl { GGSN_IMPL_OSMOCOM, @@ -128,6 +129,10 @@ module GGSN_Tests { var DIAMETER_Emulation_CT vc_Gx; port DIAMETER_PT Gx_UNIT; port DIAMETEREM_PROC_PT Gx_PROC; + var DIAMETER_Emulation_CT vc_Gy; + port DIAMETER_PT Gy_UNIT; + port DIAMETEREM_PROC_PT Gy_PROC; + var integer g_gy_validity_time := 0; /* In seconds. 0 => disabled, !0 => grant over CC-Time period */ } private function f_init_vty() runs on GT_CT { @@ -203,7 +208,10 @@ module GGSN_Tests { unitdata_cb := refers(DiameterForwardUnitdataCallback), raw := true /* handler mode (single component for all IMSI)) */ }; - var DIAMETER_conn_parameters pars := { + var DIAMETER_conn_parameters pars; + + /* Gx setup: */ + pars := { remote_ip := m_ggsn_ip_gtpc, remote_sctp_port := -1, local_ip := m_bind_ip_gtpc, @@ -219,7 +227,25 @@ module GGSN_Tests { connect(vc_Gx:DIAMETER_PROC, self:Gx_PROC); vc_Gx.start(DIAMETER_Emulation.main(ops, pars, id)); + /* Gy setup: */ + pars := { + remote_ip := m_ggsn_ip_gtpc, + remote_sctp_port := -1, + local_ip := m_bind_ip_gtpc, + local_sctp_port := OCS_PORT, + origin_host := "ocs.localdomain", + origin_realm := "localdomain", + auth_app_id := c_DIAMETER_CREDIT_CONTROL_AID, + vendor_app_id := omit + }; + vc_Gy := DIAMETER_Emulation_CT.create(id); + map(vc_Gy:DIAMETER, system:DIAMETER_CODEC_PT); + connect(vc_Gy:DIAMETER_UNIT, self:Gy_UNIT); + connect(vc_Gy:DIAMETER_PROC, self:Gy_PROC); + vc_Gy.start(DIAMETER_Emulation.main(ops, pars, id)); + f_diameter_wait_capability(Gx_UNIT); + f_diameter_wait_capability(Gy_UNIT); /* Give some time for our emulation to get out of SUSPECT list of SUT (3 watchdong ping-pongs): * RFC6733 sec 5.1 * RFC3539 sec 3.4.1 [5] @@ -425,9 +451,9 @@ module GGSN_Tests { } } - private altstep as_DIA_CCR(DCC_NONE_CC_Request_Type req_type) runs on GT_CT { + private altstep as_DIA_Gx_CCR(DCC_NONE_CC_Request_Type req_type) runs on GT_CT { var PDU_DIAMETER rx_dia; - [] Gx_UNIT.receive(tr_DIA_CCR(req_type := req_type)) -> value rx_dia { + [] Gx_UNIT.receive(tr_DIA_Gx_CCR(req_type := req_type)) -> value rx_dia { var template (omit) AVP avp; var octetstring sess_id; var AVP_Unsigned32 req_num; @@ -438,7 +464,7 @@ module GGSN_Tests { avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_DCC_NONE_CC_Request_Number); req_num := valueof(avp.avp_data.avp_DCC_NONE_CC_Request_Number); - Gx_UNIT.send(ts_DIA_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, + Gx_UNIT.send(ts_DIA_Gx_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, req_type, req_num)); } [] Gx_UNIT.receive(PDU_DIAMETER:?) -> value rx_dia { @@ -447,6 +473,34 @@ module GGSN_Tests { } } + private altstep as_DIA_Gy_CCR(DCC_NONE_CC_Request_Type req_type) runs on GT_CT { + var PDU_DIAMETER rx_dia; + [] Gy_UNIT.receive(tr_DIA_Gy_CCR(req_type := req_type)) -> value rx_dia { + var template (value) PDU_DIAMETER tx_dia; + var template (omit) AVP avp; + var octetstring sess_id; + var AVP_Unsigned32 req_num; + + avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id); + sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id); + + avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_DCC_NONE_CC_Request_Number); + req_num := valueof(avp.avp_data.avp_DCC_NONE_CC_Request_Number); + if (g_gy_validity_time > 0) { + tx_dia := ts_DIA_Gy_CCA_ValidityTime(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, + req_type, req_num, g_gy_validity_time); + } else { + tx_dia := ts_DIA_Gy_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, + req_type, req_num); + } + Gy_UNIT.send(tx_dia); + } + [] Gy_UNIT.receive(PDU_DIAMETER:?) -> value rx_dia { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Received unexpected DIAMETER Gy", rx_dia)); + } + } + /* send a PDP context activation */ function f_pdp_ctx_act(inout PdpContext ctx, template OCT1 exp_cause := '80'O) runs on GT_CT return CreatePDPContextResponse { var Gtp1cUnitdata ud; @@ -460,7 +514,10 @@ module GGSN_Tests { T_default.start; d := activate(pingpong()); if (Gx_PROC.checkstate("Connected")) { - as_DIA_CCR(INITIAL_REQUEST); + as_DIA_Gx_CCR(INITIAL_REQUEST); + } + if (Gy_PROC.checkstate("Connected")) { + as_DIA_Gy_CCR(INITIAL_REQUEST); } alt { [] GTPC.receive(tr_GTPC_MsgType(g_peer_c, createPDPContextResponse, ctx.teic)) -> value ud { @@ -522,7 +579,10 @@ module GGSN_Tests { T_default.start; d := activate(pingpong()); if (Gx_PROC.checkstate("Connected") and expect_diameter) { - as_DIA_CCR(TERMINATION_REQUEST); + as_DIA_Gx_CCR(TERMINATION_REQUEST); + } + if (Gy_PROC.checkstate("Connected") and expect_diameter) { + as_DIA_Gy_CCR(TERMINATION_REQUEST); } alt { [] GTPC.receive(tr_GTPC_MsgType(g_peer_c, deletePDPContextResponse, expect_teid)) -> value ud { @@ -1938,7 +1998,8 @@ module GGSN_Tests { T_next.start; alt { - [Gx_PROC.checkstate("Connected")] as_DIA_CCR(INITIAL_REQUEST) { repeat; } + [Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(INITIAL_REQUEST) { repeat; } + [Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(INITIAL_REQUEST) { repeat; } [] pingpong(); [] T_next.timeout { f_send_gtpc(ts_GTPC_CreatePDP(g_peer_c, g_c_seq_nr, ctx[next_req_ctx].imsi, g_restart_ctr, @@ -1992,7 +2053,8 @@ module GGSN_Tests { rx_resp_ctx := 0; T_next.start; alt { - [Gx_PROC.checkstate("Connected")] as_DIA_CCR(TERMINATION_REQUEST) { repeat; } + [Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(TERMINATION_REQUEST) { repeat; } + [Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(TERMINATION_REQUEST) { repeat; } [] pingpong(); [] T_next.timeout { f_send_gtpc(ts_GTPC_DeletePDP(g_peer_c, g_c_seq_nr, ctx[next_req_ctx].teic_remote, ctx[next_req_ctx].nsapi, '1'B)); @@ -2044,7 +2106,8 @@ module GGSN_Tests { T_next.start; alt { - [Gx_PROC.checkstate("Connected")] as_DIA_CCR(INITIAL_REQUEST) { repeat; } + [Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(INITIAL_REQUEST) { repeat; } + [Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(INITIAL_REQUEST) { repeat; } [] pingpong(); [] T_next.timeout { if (cont_req) { @@ -2093,7 +2156,7 @@ module GGSN_Tests { rx_resp_ctx := 0; T_next.start; alt { - [Gx_PROC.checkstate("Connected")] as_DIA_CCR(TERMINATION_REQUEST) { repeat; } + [Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(TERMINATION_REQUEST) { repeat; } [] pingpong(); [] T_next.timeout { f_send_gtpc(ts_GTPC_DeletePDP(g_peer_c, g_c_seq_nr, teic_list[next_req_ctx], '0001'B, '1'B)); @@ -2124,6 +2187,56 @@ module GGSN_Tests { f_shutdown_helper(); } + /* Test charging over Gy interface. */ + testcase TC_gy_charging_cc_time() runs on GT_CT { + var default d; + + g_gy_validity_time := 3; /* Grant access for 3 seconds, needs to be re-validated afterwards */ + f_init(); + var PdpContext ctx := valueof(t_DefinePDP(f_rnd_imsi('26242'H), '1234'O, c_ApnInternet, valueof(t_EuaIPv4Dyn))); + ctx.pco_req := valueof(ts_PCO_IPv4_DNS_CONT); + f_pdp_ctx_act(ctx); + + var OCT4 dns1_addr := f_PCO_extract_proto(ctx.pco_neg, '000d'O); + + /* Send some UL traffic: */ + var OCT4 saddr := ctx.eua.endUserAddress.endUserAddressIPv4.ipv4_address; + f_send_gtpu(ctx, f_gen_icmpv4_echo(saddr, dns1_addr)); + f_wait_icmp4_echo_reply(ctx); + + T_default.start(10.0); + d := activate(pingpong()); + + g_gy_validity_time := 2; + /* First update reports octests/pkt on both UL/DL (see icmp ping-pong above) */ + as_DIA_Gy_CCR(UPDATE_REQUEST); + + /* Second update: 0 ul/dl pkt/octet should be reported, since nothing was sent */ + as_DIA_Gy_CCR(UPDATE_REQUEST); + + /* Third update: make sure report contains again octets/pkts for both UL/DL: */ + f_send_gtpu(ctx, f_gen_icmpv4_echo(saddr, dns1_addr)); + f_wait_icmp4_echo_reply(ctx); + f_send_gtpu(ctx, f_gen_icmpv4_echo(saddr, dns1_addr)); + f_wait_icmp4_echo_reply(ctx); + as_DIA_Gy_CCR(UPDATE_REQUEST); + + /* Let the CCA reach the GGSN */ + f_sleep(0.5); + deactivate(d); + T_default.stop; + + /* Send some data and validate it is reported in the TERMINATION_REQUEST + * (triggered by PFCP Session Deletion Response): */ + f_send_gtpu(ctx, f_gen_icmpv4_echo(saddr, dns1_addr)); + f_wait_icmp4_echo_reply(ctx); + + f_pdp_ctx_del(ctx, '1'B); + + + f_shutdown_helper(); + } + control { execute(TC_pdp4_act_deact()); execute(TC_pdp4_act_deact_ipcp()); @@ -2170,5 +2283,10 @@ module GGSN_Tests { execute(TC_lots_of_concurrent_pdp_ctx()); /* Keep at the end, crashes older osmo-ggsn versions (OS#5469): */ execute(TC_addr_pool_exhaustion()); + + /* open5gs specific tests: */ + if (m_ggsn_impl == GGSN_IMPL_OPEN5GS) { + execute(TC_gy_charging_cc_time()); + } } } diff --git a/library/DIAMETER_Templates.ttcn b/library/DIAMETER_Templates.ttcn index f7244d81..24b9cd89 100644 --- a/library/DIAMETER_Templates.ttcn +++ b/library/DIAMETER_Templates.ttcn @@ -100,6 +100,8 @@ type enumerated DIAMETER_Resultcode { DIAMETER_ERROR_EAP_CODE_UNKNOWN (5048) }; +/* Gy : 3GPP TS 32.299 7.1.6, RFC4006 3.1 */ +const uint32_t c_DIAMETER_CREDIT_CONTROL_AID := 4; /* 3GPP TS 29.272 Section 7.1.8 */ const uint32_t c_DIAMETER_3GPP_Gx_AID := 16777238; const uint32_t c_DIAMETER_3GPP_S6_AID := 16777251; @@ -860,6 +862,56 @@ template (value) GenericAVP ts_AVP_3GPP_PdnType(template (value) AAA_3GPP_PDN_Ty } } +/* RFC4006 8.16 Multiple-Services-Credit-Control AVP */ +template (value) GenericAVP ts_AVP_Multiple_Services_Credit_Control(template (value) AVP_list content) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_Multiple_Services_Credit_Control), + avp_data := { + avp_DCC_NONE_Multiple_Services_Credit_Control := content + } + } +} + +/* RFC4006 8.17 Granted-Service-Unit AVP */ +template (value) GenericAVP ts_AVP_Granted_Service_Unit(template (value) AVP_list content) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_Granted_Service_Unit), + avp_data := { + avp_DCC_NONE_Granted_Service_Unit := content + } + } +} + +/* RFC4006 8.21 CC-Time AVP */ +template (value) GenericAVP ts_AVP_CC_Time(uint32_t cc_time_val) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_CC_Time), + avp_data := { + avp_DCC_NONE_CC_Time := int2oct(cc_time_val, 4) + } + } +} + +/* RFC4006 8.23 CC-Total-Octets AVP */ +template (value) GenericAVP ts_AVP_CC_Total_Octets(uint64_t cc_total_octets_val) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_CC_Total_Octets), + avp_data := { + avp_DCC_NONE_CC_Total_Octets := int2oct(cc_total_octets_val, 8) + } + } +} + +/* RFC4006 8.33 Validity-Time AVP */ +template (value) GenericAVP ts_AVP_Validity_Time(uint32_t validity_time_val) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_Validity_Time), + avp_data := { + avp_DCC_NONE_Validity_Time := int2oct(validity_time_val, 4) + } + } +} + /* 5.3.2 Capabilities Exchange Answer */ @@ -1101,7 +1153,7 @@ tr_DIA_ULA(template (present) AVP_list sub_data := ?, /* RFC 4006 3.1. Credit-Control-Request (CCR) Command */ template (present) PDU_DIAMETER -tr_DIA_CCR(template (present) DCC_NONE_CC_Request_Type req_type := INITIAL_REQUEST) +tr_DIA_Gx_CCR(template (present) DCC_NONE_CC_Request_Type req_type := INITIAL_REQUEST) := tr_DIAMETER(flags:='11000000'B, cmd_code:=Credit_Control, app_id:=int2oct(c_DIAMETER_3GPP_Gx_AID, 4), avps := superset( @@ -1113,15 +1165,28 @@ tr_DIA_CCR(template (present) DCC_NONE_CC_Request_Type req_type := INITIAL_REQUE tr_AVP_CcReqType(req_type), tr_AVP_CcReqNum(?) )); +template (present) PDU_DIAMETER +tr_DIA_Gy_CCR(template (present) DCC_NONE_CC_Request_Type req_type := INITIAL_REQUEST) +:= tr_DIAMETER(flags:='11000000'B, cmd_code:=Credit_Control, + app_id:=int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4), + avps := superset( + tr_AVP_SessionId, + tr_AVP_OriginHost, + tr_AVP_OriginRealm, + tr_AVP_DestinationRealm, + tr_AVP_AuthAppId(int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4)), + tr_AVP_CcReqType(req_type), + tr_AVP_CcReqNum(?) + )); + /* RFC 4006 3.2. Credit-Control-Answer (CCA) Command */ template (value) PDU_DIAMETER -ts_DIA_CCA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, +ts_DIA_Gx_CCA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, template (value) octetstring sess_id, template (value) DCC_NONE_CC_Request_Type req_type, template (value) AVP_Unsigned32 req_num) - := ts_DIAMETER(flags:='01000000'B, cmd_code:=Credit_Control, app_id:=int2oct(c_DIAMETER_3GPP_Gx_AID, 4), hbh_id:=hbh_id, ete_id:=ete_id, avps := { @@ -1137,6 +1202,56 @@ ts_DIA_CCA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, // supported features // origin }); +template (value) PDU_DIAMETER +ts_DIA_Gy_CCA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, + template (value) octetstring sess_id, + template (value) DCC_NONE_CC_Request_Type req_type, + template (value) AVP_Unsigned32 req_num) +:= ts_DIAMETER(flags:='01000000'B, cmd_code:=Credit_Control, + app_id:=int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4), hbh_id:=hbh_id, ete_id:=ete_id, + avps := { + ts_AVP_SessionId(sess_id), + ts_AVP_ResultCode(DIAMETER_SUCCESS), + ts_AVP_OriginHost("ocs.localdomain"), + ts_AVP_OriginRealm("localdomain"), + ts_AVP_AuthAppId(int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4)), + ts_AVP_CcReqType(req_type), + ts_AVP_CcReqNum(req_num)//, + // qos + // default eps bearer qos + // supported features + // origin + }); +/* Same as ts_DIA_Gy_CCA, but with extra AVP to grant access for limited amount of seconds */ +template (value) PDU_DIAMETER +ts_DIA_Gy_CCA_ValidityTime(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, + template (value) octetstring sess_id, + template (value) DCC_NONE_CC_Request_Type req_type, + template (value) AVP_Unsigned32 req_num, + uint32_t validity_time) +:= ts_DIAMETER(flags:='01000000'B, cmd_code:=Credit_Control, + app_id:=int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4), hbh_id:=hbh_id, ete_id:=ete_id, + avps := { + ts_AVP_SessionId(sess_id), + ts_AVP_ResultCode(DIAMETER_SUCCESS), + ts_AVP_OriginHost("ocs.localdomain"), + ts_AVP_OriginRealm("localdomain"), + ts_AVP_AuthAppId(int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4)), + ts_AVP_CcReqType(req_type), + ts_AVP_CcReqNum(req_num), + ts_AVP_Multiple_Services_Credit_Control({ + ts_AVP_Validity_Time(validity_time), + ts_AVP_Granted_Service_Unit({ + //ts_AVP_CC_Time(validity_time*2), + ts_AVP_CC_Total_Octets(1000) + }) + }) + //, + // qos + // default eps bearer qos + // supported features + // origin + }); /* RFC 6733, section 5.5.1 "Device-Watchdog-Request" */ template (value) PDU_DIAMETER diff --git a/library/Osmocom_Types.ttcn b/library/Osmocom_Types.ttcn index 472b389d..b698a2e3 100644 --- a/library/Osmocom_Types.ttcn +++ b/library/Osmocom_Types.ttcn @@ -16,6 +16,7 @@ type integer uint8_t (0..255) with { variant "unsigned 8 bit" }; type integer uint16_t (0..65535) with { variant "unsigned 16 bit" }; type integer uint24_t (0..16777215) with { variant "unsigned 24 bit" }; type integer uint32_t (0..4294967295) with { variant "unsigned 32 bit" }; +type integer uint64_t (0..18446744073709551615) with { variant "unsigned 64 bit" }; type integer int8_t (-128..127) with { variant "8 bit" }; type integer int16_t (-32768..32767) with { variant "16 bit" }; diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn index a65ca435..9846dabe 100644 --- a/pgw/PGW_Tests.ttcn +++ b/pgw/PGW_Tests.ttcn @@ -221,7 +221,7 @@ function f_gen_msisdn(integer suffix) return hexstring { private altstep as_DIA_CCR(DCC_NONE_CC_Request_Type req_type) runs on PGW_Session_CT { var PDU_DIAMETER rx_dia; - [] DIAMETER.receive(tr_DIA_CCR(req_type := req_type)) -> value rx_dia { + [] DIAMETER.receive(tr_DIA_Gx_CCR(req_type := req_type)) -> value rx_dia { var template (omit) AVP avp; var octetstring sess_id; var AVP_Unsigned32 req_num; @@ -232,7 +232,7 @@ private altstep as_DIA_CCR(DCC_NONE_CC_Request_Type req_type) runs on PGW_Sessio avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_DCC_NONE_CC_Request_Number); req_num := valueof(avp.avp_data.avp_DCC_NONE_CC_Request_Number); - DIAMETER.send(ts_DIA_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, + DIAMETER.send(ts_DIA_Gx_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, req_type, req_num)); } [] DIAMETER.receive(PDU_DIAMETER:?) -> value rx_dia { |