pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/37920?usp=email )
Change subject: s1gw: Add initial PFCP support emulating UPF ......................................................................
s1gw: Add initial PFCP support emulating UPF
Change-Id: If2b135e113d2568092e90ac9b6c5f651ab30f5d0 --- M library/PFCP_Emulation.ttcn M s1gw/ConnHdlr.ttcn M s1gw/S1GW_Tests.ttcn M s1gw/gen_links.sh M s1gw/osmo-s1gw.config M s1gw/regen_makefile.sh 6 files changed, 144 insertions(+), 32 deletions(-)
Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified
diff --git a/library/PFCP_Emulation.ttcn b/library/PFCP_Emulation.ttcn index d5a15a2..d872367 100644 --- a/library/PFCP_Emulation.ttcn +++ b/library/PFCP_Emulation.ttcn @@ -199,4 +199,12 @@ } }
+altstep as_pfcp_ignore(PFCPEM_PT pt, template PDU_PFCP pfcp_expect := ?) +{ + [] pt.receive(pfcp_expect) { + log("Ignoring ", pfcp_expect); + repeat; + } +} + } diff --git a/s1gw/ConnHdlr.ttcn b/s1gw/ConnHdlr.ttcn index e4cff0c..12c7414 100644 --- a/s1gw/ConnHdlr.ttcn +++ b/s1gw/ConnHdlr.ttcn @@ -19,6 +19,11 @@ import from IPL4asp_Types all; import from Misc_Helpers all;
+import from PFCP_Types all; +import from PFCP_Emulation all; +import from PFCP_Templates all; +import from PFCP_CodecPort all; + import from S1AP_CodecPort all; import from S1AP_CodecPort_CtrlFunct all; import from S1AP_Types all; @@ -31,13 +36,15 @@ import from SCTP_Templates all; import from S1AP_Server all;
-type component ConnHdlr extends S1APSRV_ConnHdlr { +type component ConnHdlr extends S1APSRV_ConnHdlr, PFCP_ConnHdlr { + var ConnHdlrPars g_pars; port S1AP_CODEC_PT S1AP_ENB; var ConnectionId g_s1ap_conn_id := -1; }; type record of ConnHdlr ConnHdlrList;
type record ConnHdlrPars { + integer idx, Global_ENB_ID genb_id };
@@ -52,11 +59,19 @@ }
template (value) ConnHdlrPars -t_ConnHdlrPars(integer enb_id := 0) := { - genb_id := ts_Global_ENB_ID(enb_id) +t_ConnHdlrPars(integer idx := 0) := { + idx := idx, + genb_id := ts_Global_ENB_ID(idx) }
-type function void_fn(ConnHdlrPars pars) runs on ConnHdlr; +type function void_fn(charstring id) runs on ConnHdlr; + +function f_ConnHdlr_init(void_fn fn, charstring id, ConnHdlrPars pars) +runs on ConnHdlr { + g_pars := pars; + fn.apply(id); +} +
function f_ConnHdlr_connect(charstring local_addr, charstring remote_addr) runs on ConnHdlr { var Result res; @@ -209,4 +224,50 @@ } }
+altstep as_pfcp_handle_assoc_setup_req(template (present) PDU_PFCP exp_rx := tr_PFCP_Assoc_Setup_Req(), boolean do_repeat := false) +runs on ConnHdlr +{ + var PDU_PFCP rx; + + [] PFCP.receive(exp_rx) -> value rx { + var Node_ID upf_node_id := valueof(ts_PFCP_Node_ID_fqdn("\07osmocom\03org")); + PFCP.send(ts_PFCP_Assoc_Setup_Resp(rx.sequence_number, upf_node_id, + ts_PFCP_Cause(REQUEST_ACCEPTED), + 1234)); + if (do_repeat) { + repeat; + } + } +} + +private function f_pfcp_wait_assoc_setup(template (present) PDU_PFCP exp_rx := tr_PFCP_Assoc_Setup_Req(), + float wait_time := 10.0) +runs on ConnHdlr +{ + timer T := wait_time; + T.start; + alt { + [] as_pfcp_handle_assoc_setup_req(exp_rx); + [] PFCP.receive(PDU_PFCP:?) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Got an unexpected PFCP message, was waiting for ", exp_rx)); + } + [] T.timeout { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Timeout waiting for PFCP ", exp_rx)); + } + } + T.stop; +} + +function f_ConnHdlr_register_pfcp() runs on ConnHdlr +{ + f_pfcp_register(); + if (g_pars.idx == 0) { + /* First ConnHdlr answers the AssocSetup: */ + activate(as_pfcp_handle_assoc_setup_req(do_repeat := true)); + } else { + activate(as_pfcp_ignore(PFCP, tr_PFCP_Assoc_Setup_Req())); + } +} } diff --git a/s1gw/S1GW_Tests.ttcn b/s1gw/S1GW_Tests.ttcn index 1f4bb71..9448ed5 100644 --- a/s1gw/S1GW_Tests.ttcn +++ b/s1gw/S1GW_Tests.ttcn @@ -28,20 +28,28 @@ import from S1AP_PDU_Contents all; import from S1AP_Constants all;
+import from PFCP_Types all; +import from PFCP_Emulation all; +import from PFCP_Templates all; +import from PFCP_CodecPort all; + import from SCTP_Templates all; import from S1AP_Server all; import from ConnHdlr all;
modulepar { - charstring mp_s1gw_enb_ip; /* eNB facing address of the S1GW */ - charstring mp_s1gw_mme_ip; /* MME facing address of the S1GW */ - charstring mp_enb_bind_ip; /* eNB address to use locally when connecting to S1GW */ - charstring mp_mme_bind_ip; /* MME address on which we get connections from S1GW */ + charstring mp_s1gw_enb_ip := "127.0.1.1"; /* eNB facing address of the S1GW */ + charstring mp_s1gw_mme_ip := "127.0.2.1"; /* MME facing address of the S1GW */ + charstring mp_s1gw_upf_ip := "127.0.3.1"; /* UPF facing address of the S1GW */ + charstring mp_enb_bind_ip := "127.0.1.10"; /* eNB address to use locally when connecting to S1GW */ + charstring mp_mme_bind_ip := "127.0.2.10"; /* MME address on which we get connections from S1GW */ + charstring mp_upf_bind_ip := "127.0.3.10"; /* UPF address on which we get connections from S1GW */ }
type component test_CT { timer g_Tguard; var S1AP_Server_CT vc_S1APSRV; + var PFCP_Emulation_CT vc_PFCP; };
private altstep as_Tguard() runs on test_CT { @@ -50,9 +58,18 @@ } }
-function f_init(float Tval := 20.0) runs on test_CT { +function f_init(boolean s1apsrv_start := true, + boolean upf_start := true, + float Tval := 20.0) runs on test_CT { g_Tguard.start(Tval); activate(as_Tguard()); + + if (s1apsrv_start) { + f_init_s1ap_srv(); + } + if (upf_start) { + f_init_pfcp(); + } }
function f_init_s1ap_srv() runs on test_CT { @@ -65,36 +82,54 @@ vc_S1APSRV.start(S1AP_Server.main(cpars)); }
+function f_init_pfcp() runs on test_CT { + var PFCP_Emulation_Cfg pfcp_cfg := { + pfcp_bind_ip := mp_upf_bind_ip, + pfcp_bind_port := PFCP_PORT, + pfcp_remote_ip := mp_s1gw_upf_ip, + pfcp_remote_port := PFCP_PORT, + role := UPF + }; + + vc_PFCP := PFCP_Emulation_CT.create("PFCP-" & testcasename()) alive; + vc_PFCP.start(PFCP_Emulation.main(pfcp_cfg)); +} + function f_ConnHdlr_spawn(void_fn fn, ConnHdlrPars pars) runs on test_CT return ConnHdlr { var ConnHdlr vc_conn; + var charstring id := "ConnHdlr-" & testcasename() & "-" & int2str(pars.idx);
- vc_conn := ConnHdlr.create("ConnHdlr-" & testcasename()) alive; - if (vc_S1APSRV.running) { + vc_conn := ConnHdlr.create(id) alive; + if (isbound(vc_S1APSRV) and vc_S1APSRV.running) { connect(vc_conn:S1AP_CONN, vc_S1APSRV:S1AP_CLIENT); connect(vc_conn:S1AP_PROC, vc_S1APSRV:S1AP_PROC); } - vc_conn.start(derefers(fn)(pars)); + if (isbound(vc_PFCP) and vc_PFCP.running) { + connect(vc_conn:PFCP, vc_PFCP:CLIENT); + connect(vc_conn:PFCP_PROC, vc_PFCP:CLIENT_PROC); + } + vc_conn.start(f_ConnHdlr_init(fn, id, pars));
return vc_conn; }
-function f_TC_setup(ConnHdlrPars pars) runs on ConnHdlr { - f_ConnHdlr_register(pars.genb_id); +function f_TC_setup(charstring id) runs on ConnHdlr { + f_ConnHdlr_register_pfcp(); + f_ConnHdlr_register(g_pars.genb_id);
f_ConnHdlr_connect(mp_enb_bind_ip, mp_s1gw_enb_ip); - f_ConnHdlr_setup(pars.genb_id); + f_ConnHdlr_setup(g_pars.genb_id); f_sleep(0.5); /* keep the connection idle for some time */ f_ConnHdlr_disconnect();
- f_ConnHdlr_unregister(pars.genb_id); + f_ConnHdlr_unregister(g_pars.genb_id); } testcase TC_setup() runs on test_CT { var ConnHdlrPars pars := valueof(t_ConnHdlrPars); var ConnHdlr vc_conn;
f_init(); - f_init_s1ap_srv();
vc_conn := f_ConnHdlr_spawn(refers(f_TC_setup), pars); vc_conn.done; @@ -103,7 +138,6 @@ var ConnHdlrList vc_conns := { };
f_init(); - f_init_s1ap_srv();
for (var integer i := 0; i < 42; i := i + 1) { var ConnHdlrPars pars := valueof(t_ConnHdlrPars(i)); @@ -118,26 +152,26 @@
/* MME terminates connection, expect S1GW to terminate the eNB connection */ -function f_TC_conn_term_by_mme(ConnHdlrPars pars) runs on ConnHdlr { - f_ConnHdlr_register(pars.genb_id); +function f_TC_conn_term_by_mme(charstring id) runs on ConnHdlr { + f_ConnHdlr_register_pfcp(); + f_ConnHdlr_register(g_pars.genb_id);
f_ConnHdlr_connect(mp_enb_bind_ip, mp_s1gw_enb_ip); - f_ConnHdlr_setup(pars.genb_id); + f_ConnHdlr_setup(g_pars.genb_id); f_sleep(0.5); /* keep the connection idle for some time */
/* MME (S1AP_Server_CT) terminates connection */ - f_ConnHdlr_close_conn(pars.genb_id); + f_ConnHdlr_close_conn(g_pars.genb_id); /* expect our eNB connection to be released gracefully */ f_ConnHdlr_expect_shutdown();
- f_ConnHdlr_unregister(pars.genb_id); + f_ConnHdlr_unregister(g_pars.genb_id); } testcase TC_conn_term_by_mme() runs on test_CT { var ConnHdlrPars pars := valueof(t_ConnHdlrPars); var ConnHdlr vc_conn;
f_init(); - f_init_s1ap_srv();
vc_conn := f_ConnHdlr_spawn(refers(f_TC_conn_term_by_mme), pars); vc_conn.done; @@ -145,7 +179,8 @@
/* MME is not available, expect S1GW to terminate the eNB connection */ -function f_TC_conn_term_mme_unavail(ConnHdlrPars pars) runs on ConnHdlr { +function f_TC_conn_term_mme_unavail(charstring id) runs on ConnHdlr { + f_ConnHdlr_register_pfcp(); /* establish an eNB connection to the S1GW */ f_ConnHdlr_connect(mp_enb_bind_ip, mp_s1gw_enb_ip); /* expect our eNB connection to be released gracefully */ @@ -156,21 +191,22 @@ var ConnHdlrPars pars := valueof(t_ConnHdlrPars); var ConnHdlr vc_conn;
- f_init(); + f_init(s1apsrv_start := false);
vc_conn := f_ConnHdlr_spawn(refers(f_TC_conn_term_mme_unavail), pars); vc_conn.done; }
-function f_TC_e_rab_setup(ConnHdlrPars pars) runs on ConnHdlr { +function f_TC_e_rab_setup(charstring id) runs on ConnHdlr { const integer mme_id := 7; const integer enb_id := 9; const integer erab_id := 6; var S1AP_PDU pdu;
- f_ConnHdlr_register(pars.genb_id); + f_ConnHdlr_register_pfcp(); + f_ConnHdlr_register(g_pars.genb_id); f_ConnHdlr_connect(mp_enb_bind_ip, mp_s1gw_enb_ip); - f_ConnHdlr_setup(pars.genb_id); + f_ConnHdlr_setup(g_pars.genb_id);
log("eNB <- [S1GW] <- MME: E-RAB SETUP REQUEST"); var template (value) E_RABToBeSetupListBearerSUReq items_req; @@ -224,14 +260,13 @@ f_ConnHdlr_rx_s1ap_from_enb(pdu, tr_S1AP_RABSetupRsp(mme_id, enb_id, items_res));
f_ConnHdlr_disconnect(); - f_ConnHdlr_unregister(pars.genb_id); + f_ConnHdlr_unregister(g_pars.genb_id); } testcase TC_e_rab_setup() runs on test_CT { var ConnHdlrPars pars := valueof(t_ConnHdlrPars); var ConnHdlr vc_conn;
f_init(); - f_init_s1ap_srv();
vc_conn := f_ConnHdlr_spawn(refers(f_TC_e_rab_setup), pars); vc_conn.done; diff --git a/s1gw/gen_links.sh b/s1gw/gen_links.sh index fd54815..ef8bdde 100755 --- a/s1gw/gen_links.sh +++ b/s1gw/gen_links.sh @@ -17,6 +17,10 @@ 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
+DIR=$BASEDIR/titan.ProtocolModules.PFCP_v15.1.0/src +FILES="PFCP_Types.ttcn" +gen_links $DIR $FILES + DIR=../library/s1ap FILES="S1AP_CommonDataTypes.asn S1AP_Constants.asn S1AP_Containers.asn S1AP_IEs.asn " FILES+="S1AP_PDU_Contents.asn S1AP_PDU_Descriptions.asn " @@ -25,6 +29,7 @@
DIR=../library FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn " +FILES+="PFCP_CodecPort.ttcn PFCP_CodecPort_CtrlFunct.ttcn PFCP_CodecPort_CtrlFunctDef.cc PFCP_Emulation.ttcn PFCP_Templates.ttcn " FILES+="S1AP_CodecPort.ttcn S1AP_CodecPort_CtrlFunctDef.cc S1AP_CodecPort_CtrlFunct.ttcn " FILES+="SCTP_Templates.ttcn " gen_links $DIR $FILES diff --git a/s1gw/osmo-s1gw.config b/s1gw/osmo-s1gw.config index f4a4a73..a04d1cf 100644 --- a/s1gw/osmo-s1gw.config +++ b/s1gw/osmo-s1gw.config @@ -13,7 +13,9 @@ {osmo_s1gw, [{s1gw_bind_addr, "127.0.1.1"}, %% S1GW bind address for incoming eNB connections {mme_loc_addr, "127.0.2.1"}, %% local address for outgoing connections to the MME - {mme_rem_addr, "127.0.2.10"} %% remote address for outgoing connections to the MME + {mme_rem_addr, "127.0.2.10"}, %% remote address for outgoing connections to the MME + {pfcp_loc_addr, "127.0.3.1"}, %% local address for outgoing connections to the UPF + {pfcp_rem_addr, "127.0.3.10"} %% local address for outgoing connections to the UPF ]}, %% ================================================================================ %% kernel config diff --git a/s1gw/regen_makefile.sh b/s1gw/regen_makefile.sh index 7eef51b..8c32b3d 100755 --- a/s1gw/regen_makefile.sh +++ b/s1gw/regen_makefile.sh @@ -8,6 +8,7 @@ IPL4asp_PT.cc IPL4asp_discovery.cc Native_FunctionDefs.cc + PFCP_CodecPort_CtrlFunctDef.cc S1AP_CodecPort_CtrlFunctDef.cc S1AP_EncDec.cc TCCConversion.cc