diff --git a/hnbgw/HNBGW_Tests.ttcn b/hnbgw/HNBGW_Tests.ttcn index 81d9f1a06..7429c389b 100644 --- a/hnbgw/HNBGW_Tests.ttcn +++ b/hnbgw/HNBGW_Tests.ttcn @@ -57,6 +57,11 @@ import from MGCP_Templates all; import from MGCP_CodecPort all; import from SDP_Types all; +import from PFCP_Types all; +import from PFCP_Emulation all; +import from PFCP_Templates all; +import from PFCP_CodecPort all; + modulepar { /* IP address at which the HNodeB can be reached */ charstring mp_hnodeb_ip := "127.0.0.1"; @@ -91,6 +96,13 @@ modulepar { sio := '83'O, rctx := 2 }; + + /* IP address at which we listen for PFCP to emulate a UPF in ttcn3 */ + charstring mp_pfcp_ip_local := "127.0.0.1"; + + /* IP address from which the SUT (osmo-hnbgw) sends PFCP requests, and to which the ttcn3 UPF emulation sends + * PFCP responses. */ + charstring mp_pfcp_ip_remote := "127.0.0.2"; } function MSC_UnitdataCallback(RANAP_PDU ranap) runs on RAN_Emulation_CT return template RANAP_PDU { @@ -168,7 +180,8 @@ type record TestHdlrParams { boolean ps_domain, MgcpParameters mgcp_pars optional, HnbConfig hnb optional, - boolean separate_sccp_cr + boolean separate_sccp_cr, + charstring pfcp_local_addr } /* We extend: @@ -176,7 +189,7 @@ type record TestHdlrParams { * RAN_ConnHdlr (for the Iu side, emulating the MSC) * MGCP_ConnHdlr (for the MGCP side, emulating the MGW) */ -type component ConnHdlr extends RAN_ConnHdlr, MGCP_ConnHdlr, RUA_ConnHdlr { +type component ConnHdlr extends RAN_ConnHdlr, MGCP_ConnHdlr, RUA_ConnHdlr, PFCP_ConnHdlr { var integer g_sccp_conn_id; var TestHdlrParams g_pars; timer g_Tguard; @@ -267,6 +280,23 @@ function f_init_mgcp(charstring id) runs on test_CT { vc_MGCP.start(MGCP_Emulation.main(ops, pars, id)); } +function f_init_pfcp(charstring id) runs on ConnHdlr { + id := id & "-PFCP"; + + var PFCP_Emulation_Cfg pfcp_cfg := { + pfcp_bind_ip := mp_pfcp_ip_local, + pfcp_bind_port := PFCP_PORT, + pfcp_remote_ip := mp_pfcp_ip_remote, + pfcp_remote_port := PFCP_PORT, + role := UPF + }; + + vc_PFCP := PFCP_Emulation_CT.create(id) alive; + connect(self:PFCP, vc_PFCP:CLIENT); + connect(self:PFCP_PROC, vc_PFCP:CLIENT_PROC); + vc_PFCP.start(PFCP_Emulation.main(pfcp_cfg)); +} + function f_init_hnodeb(charstring id, integer hnb_idx, RuaOps rua_ops) runs on test_CT { id := id & "-Iuh" & int2str(hnb_idx); @@ -417,6 +447,9 @@ type function void_fn(charstring id, TestHdlrParams pars) runs on ConnHdlr; function f_init_handler(TestHdlrParams pars, float t_guard := 20.0) runs on ConnHdlr { /* make parameters available via component variable */ g_pars := pars; + + f_init_pfcp(testcasename()); + /* start guard timer and activate it as default */ g_Tguard.start(t_guard); activate(as_Tguard_ConnHdlr()); @@ -643,7 +676,8 @@ t_pars(integer imsi_suffix, boolean ps_domain := false, integer hnb_idx := 0, imsi := f_gen_imsi(imsi_suffix), ps_domain := ps_domain, hnb := omit, /* filled in later */ - separate_sccp_cr := separate_sccp_cr + separate_sccp_cr := separate_sccp_cr, + pfcp_local_addr := mp_pfcp_ip_local } /* Create an Iuh connection; send InitialUE; expect it to appear on new SCCP conenction */ @@ -1139,8 +1173,152 @@ testcase TC_ranap_ps_mo_disconnect() runs on test_CT { vc_conn.done; } +type record FTeid { + HostName addr, + OCT4 teid +} + +type record FTeids { + FTeid local, + FTeid remote +} +/* 'local' and 'remote' refer to the GTP information from the UPF's point of view: + * HNB UPF CN + * access.remote <---> access.local | core.local <---> core.remote + */ +type record GtpParameters { + FTeids core, + FTeids access +} + +/* HNB UPF CN + * access.remote <---> access.local | core.local <---> core.remote + * 127.0.0.4 127.0.0.3 127.0.0.2 127.0.0.1 + * 0x44004400 0x30303030 0x22002200 0x10101010 + */ +template GtpParameters t_GtpParameters := { + core := { + local := { + addr := "127.0.0.2", + teid := '22002200'O + }, + remote := { + addr := "127.0.0.1", + teid := '10101010'O + } + }, + access := { + local := { + addr := "127.0.0.3", + teid := '30303030'O + }, + remote := { + addr := "127.0.0.4", + teid := '44004400'O + } + } +} + +friend function f_tc_ps_rab_assignment(charstring id, TestHdlrParams pars) runs on ConnHdlr { + var RANAP_PDU tx; + var RANAP_PDU rx; + timer T := 5.0; + + f_init_handler(pars); + + f_pfcp_register(); + + var PDU_PFCP m; + var Node_ID upf_node_id := valueof(ts_PFCP_Node_ID_fqdn("\07osmocom\03org")); + + PFCP.receive(tr_PFCP_Assoc_Setup_Req()) -> value m; + PFCP.send(ts_PFCP_Assoc_Setup_Resp(m.sequence_number, upf_node_id, + ts_PFCP_Cause(REQUEST_ACCEPTED), 1234)); + + tx := f_build_initial_ue(g_pars); + f_iuh2iu_connect(tx); + + var GtpParameters gtp_pars := valueof(t_GtpParameters); + var template RAB_SetupOrModifyList rab_sml; + + /* Send RAB Assignment Request */ + rab_sml := ts_RAB_SML_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.core.remote.addr), gtp_pars.core.remote.teid); + tx := valueof(ts_RANAP_RabAssReq(rab_sml)); + BSSAP.send(tx); + + /* Expect PFCP Session Establishment Request. */ + PFCP.receive(tr_PFCP_Session_Est_Req()) -> value m; + var F_SEID hnbgw_f_seid := m.message_body.pfcp_session_establishment_request.CP_F_SEID; + var PFCP_Session_Establishment_Request serq := m.message_body.pfcp_session_establishment_request; + + /* Acting as UPF, invent a new PFCP SEID to send to HNBGW. Respond to the Session Establishment. + * The PFCP response must have the same sequence_number as the request. */ + var F_SEID up_f_seid := valueof(ts_PFCP_F_SEID_ipv4("127.0.0.1", '1111111111111111'O)); + var template PDU_PFCP r := ts_PFCP_Session_Est_Resp(m.sequence_number, upf_node_id, hnbgw_f_seid.seid); + r.message_body.pfcp_session_establishment_response := { + offending_ie := omit, + UP_F_SEID := up_f_seid, + created_PDR_list := { + ts_PFCP_Created_PDR(pdr_id := serq.create_PDR_list[0].grouped_ie.pdr_id, + local_F_TEID := ts_PFCP_F_TEID_ipv4(gtp_pars.core.local.teid, + gtp_pars.core.local.addr)), + ts_PFCP_Created_PDR(pdr_id := serq.create_PDR_list[1].grouped_ie.pdr_id, + local_F_TEID := ts_PFCP_F_TEID_ipv4(gtp_pars.access.local.teid, + gtp_pars.access.local.addr)) + }, + load_control_information := omit, + overload_control_information := omit, + node_list := omit, + failed_rule_id := omit, + created_traffic_endpoint_list := omit + }; + PFCP.send(r); + + /* Expect on Iuh: RAB Assignment Request with IP/port from PFCP Session Est Resp */ + rab_sml := ts_RAB_SML_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.access.local.addr), + gtp_pars.access.local.teid); + rx := valueof(ts_RANAP_RabAssReq(rab_sml)); + RUA.receive(rx); + + /* Send back RAB Assignment Response via Iuh */ + var template RAB_SetupOrModifiedList rab_smdl; + rab_smdl := ts_RAB_SMdL_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.access.remote.addr), + gtp_pars.access.remote.teid); + tx := valueof(ts_RANAP_RabAssResp(rab_smdl)); + RUA.send(tx); + T.start; + + PFCP.receive(tr_PFCP_Session_Mod_Req(up_f_seid.seid)) -> value m; + r := ts_PFCP_Session_Mod_Resp(m.sequence_number, hnbgw_f_seid.seid); + PFCP.send(r); + + rab_smdl := ts_RAB_SMdL_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.core.local.addr), gtp_pars.core.local.teid); + BSSAP.receive(tr_RANAP_RabAssResp(rab_smdl)); + + f_sleep(2.0); + tx := valueof(ts_RANAP_IuReleaseCommand(ts_RanapCause_om_intervention)); + f_iu2iuh(tx); + + tx := valueof(ts_RANAP_IuReleaseComplete()); + f_iuh2iu(tx); + + PFCP.receive(tr_PFCP_Session_Del_Req(up_f_seid.seid)) -> value m; + PFCP.send(ts_PFCP_Session_Del_Resp(m.sequence_number, hnbgw_f_seid.seid)); + + f_sleep(2.0); +} + +testcase TC_ps_rab_assignment() runs on test_CT { + var ConnHdlr vc_conn; + f_init(); + f_start_hnbs(); + f_sleep(1.0); + + vc_conn := f_start_handler_with_pars(refers(f_tc_ps_rab_assignment), t_pars(7, ps_domain := true)); + vc_conn.done; +} control { execute(TC_hnb_register()); @@ -1156,6 +1334,7 @@ control { execute(TC_rab_assign_mgcp_to()); execute(TC_ranap_cs_mo_disconnect()); execute(TC_ranap_ps_mo_disconnect()); + execute(TC_ps_rab_assignment()); } } diff --git a/hnbgw/gen_links.sh b/hnbgw/gen_links.sh index aabc8c0fc..4be3b535d 100755 --- a/hnbgw/gen_links.sh +++ b/hnbgw/gen_links.sh @@ -22,6 +22,7 @@ FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types gen_links $DIR $FILES # Required by MGCP and IPA +# Required by PFCP/UDP DIR=$BASEDIR/titan.TestPorts.IPL4asp/src FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" gen_links $DIR $FILES @@ -76,6 +77,10 @@ DIR=$BASEDIR/titan.TestPorts.TELNETasp/src FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn" gen_links $DIR $FILES +DIR=$BASEDIR/titan.ProtocolModules.PFCP_v15.1.0/src +FILES="PFCP_Types.ttcn" +gen_links $DIR $FILES + DIR=../library/hnbap FILES="HNBAP_CommonDataTypes.asn HNBAP_Constants.asn HNBAP_Containers.asn HNBAP_IEs.asn HNBAP_PDU_Contents.asn HNBAP_PDU_Descriptions.asn " FILES+="HNBAP_EncDec.cc HNBAP_Types.ttcn HNBAP_Templates.ttcn " @@ -95,6 +100,7 @@ DIR=../library FILES="Iuh_Types.ttcn Iuh_CodecPort.ttcn Iuh_CodecPort_CtrlFunctDef.cc Iuh_CodecPort_CtrlFunct.ttcn Iuh_Emulation.ttcn DNS_Helpers.ttcn " FILES+="MGCP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc " FILES+="RAN_Adapter.ttcnpp RAN_Emulation.ttcnpp BSSAP_CodecPort.ttcn SCCP_Templates.ttcn " +FILES+="PFCP_CodecPort.ttcn PFCP_CodecPort_CtrlFunct.ttcn PFCP_CodecPort_CtrlFunctDef.cc PFCP_Emulation.ttcn PFCP_Templates.ttcn " FILES+="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc IuUP_Emulation.ttcn " FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn " diff --git a/hnbgw/osmo-hnbgw.cfg b/hnbgw/osmo-hnbgw.cfg index f11f61363..e4dfed2ac 100644 --- a/hnbgw/osmo-hnbgw.cfg +++ b/hnbgw/osmo-hnbgw.cfg @@ -33,3 +33,8 @@ hnbgw remote-addr msc iups remote-addr sgsn + pfcp + remote-addr 127.0.0.1 + local-addr 127.0.0.2 + local-port 8805 + timer pfcp x26 5 diff --git a/hnbgw/regen_makefile.sh b/hnbgw/regen_makefile.sh index 47f7ee838..13db985bc 100755 --- a/hnbgw/regen_makefile.sh +++ b/hnbgw/regen_makefile.sh @@ -27,6 +27,7 @@ FILES=" RANAP_EncDec.cc MGCP_CodecPort_CtrlFunctDef.cc UD_PT.cc + PFCP_CodecPort_CtrlFunctDef.cc " export CPPFLAGS_TTCN3=" diff --git a/library/ranap/RANAP_Templates.ttcn b/library/ranap/RANAP_Templates.ttcn index 11947d9a1..7fac3a488 100644 --- a/library/ranap/RANAP_Templates.ttcn +++ b/library/ranap/RANAP_Templates.ttcn @@ -1291,6 +1291,86 @@ template RAB_SetupOrModifyList tr_RAB_SML(template (present) RAB_ID rab_id, } } } +template (value) TransportLayerInformation ts_TLI_ps(template (value) TransportLayerAddress tla, + template (value) GTP_TEI gtp_tei) := { + transportLayerAddress := tla, + iuTransportAssociation := { + gTP_TEI := gtp_tei + }, + iE_Extensions := omit +} +template TransportLayerInformation tr_TLI_ps(template TransportLayerAddress tla, + template (value) GTP_TEI gtp_tei) := { + transportLayerAddress := tla, + iuTransportAssociation := { + gTP_TEI := gtp_tei + }, + iE_Extensions := * +} + +template (value) RAB_SetupOrModifyList ts_RAB_SML_ps(template (value) RAB_ID rab_id, + template (value) TransportLayerAddress tla, + template (value) GTP_TEI gtp_tei) := { { + { + id := id_RAB_SetupOrModifyItem, + firstCriticality := reject, + firstValue := { + rAB_SetupOrModifyItemFirst := { + rAB_ID := rab_id, + nAS_SynchronisationIndicator := omit, + rAB_Parameters := ts_RabParams, + userPlaneInformation := ts_UserPlaneInfo, + transportLayerInformation := ts_TLI_ps(tla, gtp_tei), + service_Handover := omit, + iE_Extensions := omit + } + }, + secondCriticality := ignore, + secondValue := { + rAB_SetupOrModifyItemSecond := { + pDP_TypeInformation := omit, + dataVolumeReportingIndication := omit, + dl_GTP_PDU_SequenceNumber := omit, + ul_GTP_PDU_SequenceNumber := omit, + dl_N_PDU_SequenceNumber := omit, + ul_N_PDU_SequenceNumber := omit, + iE_Extensions := omit + } + } + } +} } +template RAB_SetupOrModifyList tr_RAB_SML_ps(template (present) RAB_ID rab_id, + template TransportLayerAddress tla, + template (value) GTP_TEI gtp_tei) := { { + { + id := id_RAB_SetupOrModifyItem, + firstCriticality := reject, + firstValue := { + rAB_SetupOrModifyItemFirst := { + rAB_ID := rab_id, + nAS_SynchronisationIndicator := *, + rAB_Parameters := ts_RabParams, + userPlaneInformation := ts_UserPlaneInfo, + transportLayerInformation := tr_TLI_ps(tla, gtp_tei), + service_Handover := *, + iE_Extensions := * + } + }, + secondCriticality := ignore, + secondValue := { + rAB_SetupOrModifyItemSecond := { + pDP_TypeInformation := omit, + dataVolumeReportingIndication := omit, + dl_GTP_PDU_SequenceNumber := omit, + ul_GTP_PDU_SequenceNumber := omit, + dl_N_PDU_SequenceNumber := omit, + ul_N_PDU_SequenceNumber := omit, + iE_Extensions := omit + } + } + } +} } + template (value) RAB_SetupOrModifiedList ts_RAB_SMdL(template (value) RAB_ID rab_id, template (value) TransportLayerAddress tla, template (value) BindingID binding_id) := { { @@ -1311,6 +1391,26 @@ template (value) RAB_SetupOrModifiedList ts_RAB_SMdL(template (value) RAB_ID rab } } } +template (value) RAB_SetupOrModifiedList ts_RAB_SMdL_ps(template (value) RAB_ID rab_id, + template (value) TransportLayerAddress tla, + template (value) GTP_TEI gtp_tei) := { { + { + id := id_RAB_SetupOrModifiedItem, + criticality := ignore, + value_ := { + rAB_SetupOrModifiedItem := { + rAB_ID := rab_id, + transportLayerAddress := tla, + iuTransportAssociation := { + gTP_TEI := gtp_tei + }, + dl_dataVolumes := omit, + iE_Extensions := omit + } + } + } +} } + template RAB_SetupOrModifiedList tr_RAB_SMdL(template (present) RAB_ID rab_id, template TransportLayerAddress tla, template BindingID binding_id) := { {