pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42501?usp=email )
Change subject: pgw: Test v6 and v4v6 PDU session userplane ......................................................................
pgw: Test v6 and v4v6 PDU session userplane
Change-Id: Idf009b9118db8117c547a1bb0f27afdfa3f03924 --- M library/GTPv2_Templates.ttcn M pgw/PGW_Tests.cfg M pgw/PGW_Tests.ttcn M pgw/expected-results.xml M pgw/open5gs-smf.yaml M pgw/open5gs-upf.yaml M pgw/testenv.sh 7 files changed, 220 insertions(+), 42 deletions(-)
Approvals: fixeria: Looks good to me, but someone else must approve pespin: Looks good to me, approved osmith: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/library/GTPv2_Templates.ttcn b/library/GTPv2_Templates.ttcn index 539251c..d318ace 100644 --- a/library/GTPv2_Templates.ttcn +++ b/library/GTPv2_Templates.ttcn @@ -388,7 +388,21 @@ ts_GTP2C_PdnAddrAlloc('001'B, {iPv4_Address:=addr}); template (present) PDN_AddressAllocation tr_GTP2C_PdnAddrAlloc_v4(template (present) OCT4 addr) := - ts_GTP2C_PdnAddrAlloc('001'B, {iPv4_Address:=addr}); + tr_GTP2C_PdnAddrAlloc('001'B, {iPv4_Address:=addr}); + +template (value) PDN_AddressAllocation +ts_GTP2C_PdnAddrAlloc_v6(template (value) IPv6 addr) := + ts_GTP2C_PdnAddrAlloc('010'B, {iPv6_Address:=addr}); +template (present) PDN_AddressAllocation +tr_GTP2C_PdnAddrAlloc_v6(template (present) IPv6 addr) := + tr_GTP2C_PdnAddrAlloc('010'B, {iPv6_Address:=addr}); + +template (value) PDN_AddressAllocation +ts_GTP2C_PdnAddrAlloc_v4v6(template (value) IPv4_IPv6 addr) := + ts_GTP2C_PdnAddrAlloc('011'B, {iPv4_IPv6:=addr}); +template (present) PDN_AddressAllocation +tr_GTP2C_PdnAddrAlloc_v4v6(template (present) IPv4_IPv6 addr) := + tr_GTP2C_PdnAddrAlloc('011'B, {iPv4_IPv6:=addr});
/* 8.15 */ template (value) Bearer_QoS @@ -903,6 +917,27 @@ tr_PDU_GTP2C(omit, seq, { echoResponse := ? }, omit);
+private function f_ts_PDN_AddressAllocation_request(template (value) BIT3 pdn_type) +return template (value) PDN_AddressAllocation +{ + var template (value) PDN_AddressAllocation paa; + select (valueof(pdn_type)) { + case ('001'B) { + paa := ts_GTP2C_PdnAddrAlloc_v4('00000000'O); + } + case ('010'B) { + paa := ts_GTP2C_PdnAddrAlloc_v6({ prefixLength := 64, + iPv6_Address := '00000000000000000000000000000000'O }); + } + case ('011'B) { + paa := ts_GTP2C_PdnAddrAlloc_v4v6({ prefixLength := 64, + iPv6_Address := '00000000000000000000000000000000'O, + iPv4_Address := '00000000'O }); + } + } + + return paa; +}
template (present) PDU_GTPCv2 ts_GTP2C_CreateSessionReq(template (value) hexstring imsi, template (omit) hexstring msisdn, @@ -926,7 +961,7 @@ accessPointName := ts_GTP2C_APN(apn), selectionMode := ts_GTP2C_SelectionMode(0), pDN_Type := ts_GTP2C_PdnType(pdn_type), - pDN_AddressAllocation := ts_GTP2C_PdnAddrAlloc('001'B, {iPv4_Address:='00000000'O}), + pDN_AddressAllocation := f_ts_PDN_AddressAllocation_request(pdn_type), maxAPN_Restriction := ts_GTP2C_ApnRestriction(0), ambr := ts_GTP2C_Ambr(102400, 102400), linkedEPS_Bearer_ID := omit, diff --git a/pgw/PGW_Tests.cfg b/pgw/PGW_Tests.cfg index 68688c1..d280a6d 100644 --- a/pgw/PGW_Tests.cfg +++ b/pgw/PGW_Tests.cfg @@ -17,6 +17,7 @@ PGW_Tests.mp_run_prog_log_path := "./run_prog" PGW_Tests.mp_run_prog_as_user := "osmocom" # testenv.sh sets this to $USER PGW_Tests.mp_ping_hostname := "10.45.0.1" +PGW_Tests.mp_ping_hostname6 := "cafe::1" PGW_Tests.mp_pcrf_local_ip:= "127.0.0.202" PGW_Tests.mp_ocs_local_ip:= "127.0.0.202" PGW_Tests.mp_aaa_local_ip:= "127.0.0.202" diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn index a670881..85d5820 100644 --- a/pgw/PGW_Tests.ttcn +++ b/pgw/PGW_Tests.ttcn @@ -35,6 +35,7 @@ charstring mp_run_prog_log_path := "/tmp"; charstring mp_run_prog_as_user := "laforge"; charstring mp_ping_hostname := "10.45.0.1"; + charstring mp_ping_hostname6 := "cafe::1";
charstring mp_pcrf_local_ip := "127.0.0.9"; integer mp_pcrf_local_port := 3868; @@ -117,8 +118,8 @@
/* Address allocation */ var OCT4 g_ip4_addr; + var OCT8 g_ip6_interface_id; var OCT16 g_ip6_addr; - var integer g_ip6_plen;
/* Store last received Gy message */ var PDU_DIAMETER g_rx_gy; @@ -674,6 +675,58 @@ return omit; }
+private function f_create_sess_tun() runs on PGW_Session_CT +{ + var template (value) UECUPS_AddrType user_addr_type; + var template (value) OCT4_20n user_addr; + + select (g_pars.pdn_type) { + case (GTP2C_PDN_IPv4) { + user_addr_type := IPV4; + user_addr := g_ip4_addr; + } + case (GTP2C_PDN_IPv6) { + user_addr_type := IPV6; + user_addr := g_ip6_addr; + } + case (GTP2C_PDN_IPv4v6) { + user_addr_type := IPV4V6; + user_addr := g_ip4_addr & g_ip6_addr; + } + } + + var template (value) UECUPS_CreateTun uecups_create := ts_UECUPS_CreateTun( + tx_teid := oct2int(g_pars.bearer.teid_remote), + rx_teid := oct2int(g_pars.bearer.teid_local), + user_addr_type := user_addr_type, + user_addr := user_addr, + local_gtp_ep := ts_UECUPS_SockAddr(f_inet_addr(mp_local_hostname_u)), + remote_gtp_ep := ts_UECUPS_SockAddr(g_gtpu4_remote), + tun_dev_name := g_pars.tun_dev_name, + tun_netns_name := g_pars.tun_netns_name + ); + + /* create tunnel in daemon */ + f_gtp1u_create_tunnel(uecups_create); +} + +private function f_perform_ipv6_slaac() runs on PGW_Session_CT +{ + var UECUPS_IPv6SLAACInd ipv6slaac_ind; + var template (value) UECUPS_IPv6SLAAC ipv6slaac; + ipv6slaac := ts_UECUPS_IPv6SLAAC( + local_gtp_ep := ts_UECUPS_SockAddr(f_inet_addr(mp_local_hostname_u)), + rx_teid := oct2int(g_pars.bearer.teid_local) + ); + f_gtp1u_ipv6_slaac(ipv6slaac); + GTP1U[0].receive(UECUPS_IPv6SLAACInd:?) -> value ipv6slaac_ind; + log("5GC assigned IPv6 global prefix: ", ipv6slaac_ind.ipv6_prefix, " -> ", f_inet6_ntoa(ipv6slaac_ind.ipv6_prefix & '0000000000000000'O)); + + /* Use the first global IPv6 address in the IPv6 prefix picked by osmo-uecups: */ + g_ip6_addr := ipv6slaac_ind.ipv6_user_addr; + log("Using IPv6 global address: ", g_ip6_addr); +} + /* process one to-be-created bearer context */ private function process_bctx_create(BearerContextGrouped bctx) runs on PGW_Session_CT { @@ -702,26 +755,10 @@ g_gtpu6_remote := rx_fteid.iPv6_Address; }
- var template (value) UECUPS_CreateTun uecups_create := ts_UECUPS_CreateTun( - tx_teid := oct2int(g_pars.bearer.teid_remote), - rx_teid := oct2int(g_pars.bearer.teid_local), - user_addr_type := IPV4, - user_addr := '00000000'O, - local_gtp_ep := valueof(ts_UECUPS_SockAddr(f_inet_addr(mp_local_hostname_u))), - remote_gtp_ep := valueof(ts_UECUPS_SockAddr(g_gtpu4_remote)), - tun_dev_name := g_pars.tun_dev_name, - tun_netns_name := g_pars.tun_netns_name - ); - - /* create tunnel in daemon */ - if (isbound(g_ip4_addr)) { - uecups_create.user_addr := g_ip4_addr; - f_gtp1u_create_tunnel(uecups_create); - } - if (isbound(g_ip6_addr)) { - uecups_create.user_addr_type := IPV6; - uecups_create.user_addr := g_ip6_addr; - f_gtp1u_create_tunnel(uecups_create); + f_create_sess_tun(); + if (g_pars.pdn_type == GTP2C_PDN_IPv6 or + g_pars.pdn_type == GTP2C_PDN_IPv4v6) { + f_perform_ipv6_slaac(); } }
@@ -780,13 +817,29 @@ var PDN_Address_and_Prefix paa := resp.pDN_AddressAllocation.pDN_Address_and_Prefix; if (ischosen(paa.iPv4_Address)) { g_ip4_addr := paa.iPv4_Address; + log("PGW assigned UE IPv4 address: ", f_inet_ntoa(g_ip4_addr)); } else if (ischosen(paa.iPv6_Address)) { - g_ip6_addr := paa.iPv6_Address.iPv6_Address; - g_ip6_plen := paa.iPv6_Address.prefixLength; + if (paa.iPv6_Address.prefixLength != 64) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Got IPv6 Prefix Length ", + paa.iPv6_Address.prefixLength, " vs exp 64")); + } + g_ip6_interface_id := substr(paa.iPv6_Address.iPv6_Address, 8, 8); + log("PGW assigned IPv6 Interface Id: ", g_ip6_interface_id); + g_ip6_addr := 'FE80000000000000'O & g_ip6_interface_id; + log("PGW assigned IPv6 link-local Address: ", f_inet6_ntoa(g_ip6_addr)); } else if (ischosen(paa.iPv4_IPv6)) { + if (paa.iPv4_IPv6.prefixLength != 64) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Got IPv6 Prefix Length ", + paa.iPv4_IPv6.prefixLength, " vs exp 64")); + } g_ip4_addr := paa.iPv4_IPv6.iPv4_Address; - g_ip6_addr := paa.iPv4_IPv6.iPv6_Address; - g_ip6_plen := paa.iPv4_IPv6.prefixLength; + log("PGW assigned UE IPv4 address: ", f_inet_ntoa(g_ip4_addr)); + g_ip6_interface_id := substr(paa.iPv4_IPv6.iPv6_Address, 8, 8); + log("PGW assigned IPv6 Interface Id: ", g_ip6_interface_id); + g_ip6_addr := 'FE80000000000000'O & g_ip6_interface_id; + log("PGW assigned IPv6 link-local Address: ", f_inet6_ntoa(g_ip6_addr)); } var integer i; for (i := 0; i < lengthof(resp.bearerContextGrouped); i := i+1) { @@ -920,14 +973,19 @@ }
/* execute ping command and wait for result */ -private function f_ping4(charstring host, integer interval := 1, integer count := 10) runs on PGW_Session_CT +private function f_ping(charstring host, integer interval := 1, integer count := 10) runs on PGW_Session_CT { - if (not isbound(g_ip4_addr)) { - Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "f_ping4(): g_ip4_addr is unset!"); - } - /* command will be filled in by f_gtp1u_ping() below: */ + /* command will be filled in by f_gtp1u_ping4() below: */ var UECUPS_StartProgram sprog := f_run_prog_init(""); - f_gtp1u_ping(sprog, host, interval, count, f_inet_ntoa(g_ip4_addr), + var charstring bind_addr; + + if (f_addr_is_ipv6(host)) { + bind_addr := f_inet6_ntoa(g_ip6_addr); + } else { + bind_addr := f_inet_ntoa(g_ip4_addr); + } + + f_gtp1u_ping(sprog, host, interval, count, bind_addr, redirect_output := true, redirect_output_path_prefix := f_run_prog_unique_log_path()); } @@ -957,21 +1015,25 @@ } testcase TC_createSession() runs on PGW_Test_CT { var PGW_Session_CT vc_conn; - var SessionPars pars := valueof(t_SessionPars('001010123456789'H, "tun22")); + var SessionPars pars := valueof(t_SessionPars('001010123456789'H, + "tun22", + pdn_type := GTP2C_PDN_IPv4)); f_init(); vc_conn := f_start_handler(refers(f_TC_createSession), pars); vc_conn.done; }
-/* create a session, then execute a ping command on the user plane */ +/* create a IPv4 session, then execute a ping command on the user plane */ private function f_TC_createSession_ping4() runs on PGW_Session_CT { f_s5s8_create_session(); - f_ping4(mp_ping_hostname); + f_ping(mp_ping_hostname); setverdict(pass); } testcase TC_createSession_ping4() runs on PGW_Test_CT { var PGW_Session_CT vc_conn; - var SessionPars pars := valueof(t_SessionPars('001010123456789'H, "tun23")); + var SessionPars pars := valueof(t_SessionPars('001010123456789'H, + "tun23", + pdn_type := GTP2C_PDN_IPv4)); f_init(); vc_conn := f_start_handler(refers(f_TC_createSession_ping4), pars); vc_conn.done; @@ -993,6 +1055,74 @@ } }
+/* create a IPv6 session, then execute a ping command on the user plane */ +private function f_TC_createSession_ping6() runs on PGW_Session_CT { + f_s5s8_create_session(); + f_ping(mp_ping_hostname6); + setverdict(pass); +} +testcase TC_createSession_ping6() runs on PGW_Test_CT { + var PGW_Session_CT vc_conn; + var SessionPars pars := valueof(t_SessionPars('001010123456789'H, + "tun23", + pdn_type := GTP2C_PDN_IPv6)); + f_init(); + vc_conn := f_start_handler(refers(f_TC_createSession_ping6), pars); + vc_conn.done; +} +testcase TC_createSession_ping6_256() runs on PGW_Test_CT { + var PGW_Session_CT vc_conn[256]; + var integer i; + + f_init(); + + for (i := 0; i < sizeof(vc_conn); i:=i+1) { + var charstring tundev := "ping" & int2str(i); + var SessionPars pars := valueof(t_SessionPars(f_gen_imsi(i), + tundev, + pdn_type := GTP2C_PDN_IPv6)); + vc_conn[i] := f_start_handler(refers(f_TC_createSession_ping6), pars); + } + + for (i := 0; i < lengthof(vc_conn); i:=i+1) { + vc_conn[i].done; + } +} + +/* create a IPv4v6 session, then execute a ping command on the user plane */ +private function f_TC_createSession_ping46() runs on PGW_Session_CT { + f_s5s8_create_session(); + f_ping(mp_ping_hostname); + f_ping(mp_ping_hostname6); + setverdict(pass); +} +testcase TC_createSession_ping46() runs on PGW_Test_CT { + var PGW_Session_CT vc_conn; + var SessionPars pars := valueof(t_SessionPars('001010123456789'H, + "tun23", + pdn_type := GTP2C_PDN_IPv4v6)); + f_init(); + vc_conn := f_start_handler(refers(f_TC_createSession_ping46), pars); + vc_conn.done; +} +testcase TC_createSession_ping46_256() runs on PGW_Test_CT { + var PGW_Session_CT vc_conn[256]; + var integer i; + + f_init(); + + for (i := 0; i < sizeof(vc_conn); i:=i+1) { + var charstring tundev := "ping" & int2str(i); + var SessionPars pars := valueof(t_SessionPars(f_gen_imsi(i), + tundev, + pdn_type := GTP2C_PDN_IPv4v6)); + vc_conn[i] := f_start_handler(refers(f_TC_createSession_ping46), pars); + } + + for (i := 0; i < lengthof(vc_conn); i:=i+1) { + vc_conn[i].done; + } +}
/* create a session, then delete it again */ private function f_TC_createSession_deleteSession() runs on PGW_Session_CT { @@ -1033,7 +1163,7 @@ f_validate_gy_cc_report(g_rx_gy, VALIDITY_TIME, (3..4), 0, 0);
d := activate(as_DIA_Gy_CCR(UPDATE_REQUEST)); - f_ping4(mp_ping_hostname); + f_ping(mp_ping_hostname); /* Let the CCA reach the PGW */ f_sleep(0.5); deactivate(d); @@ -1126,6 +1256,10 @@ execute( TC_createSession() ); execute( TC_createSession_ping4() ); execute( TC_createSession_ping4_256() ); + execute( TC_createSession_ping6() ); + execute( TC_createSession_ping6_256() ); + execute( TC_createSession_ping46() ); + execute( TC_createSession_ping46_256() ); execute( TC_createSession_deleteSession() ); execute( TC_deleteSession_unknown() ); execute( TC_gy_charging_cc_time() ); diff --git a/pgw/expected-results.xml b/pgw/expected-results.xml index 3945b4d..459e59c 100644 --- a/pgw/expected-results.xml +++ b/pgw/expected-results.xml @@ -4,6 +4,10 @@ <testcase classname='PGW_Tests' name='TC_createSession' time='MASKED'/> <testcase classname='PGW_Tests' name='TC_createSession_ping4' time='MASKED'/> <testcase classname='PGW_Tests' name='TC_createSession_ping4_256' time='MASKED'/> + <testcase classname='PGW_Tests' name='TC_createSession_ping6' time='MASKED'/> + <testcase classname='PGW_Tests' name='TC_createSession_ping6_256' time='MASKED'/> + <testcase classname='PGW_Tests' name='TC_createSession_ping46' time='MASKED'/> + <testcase classname='PGW_Tests' name='TC_createSession_ping46_256' time='MASKED'/> <testcase classname='PGW_Tests' name='TC_createSession_deleteSession' time='MASKED'/> <testcase classname='PGW_Tests' name='TC_deleteSession_unknown' time='MASKED'/> <testcase classname='PGW_Tests' name='TC_gy_charging_cc_time' time='MASKED'/> diff --git a/pgw/open5gs-smf.yaml b/pgw/open5gs-smf.yaml index 49ec84b..34aabc3 100644 --- a/pgw/open5gs-smf.yaml +++ b/pgw/open5gs-smf.yaml @@ -49,8 +49,8 @@ - subnet: 10.45.0.0/16 gateway: 10.45.0.1 dnn: internet - - subnet: cafe::/64 - gateway: cafe::1 + - subnet: 2001:db8:cafe::/48 + gateway: 2001:db8:cafe::1 dnn: internet dns: - 8.8.8.8 diff --git a/pgw/open5gs-upf.yaml b/pgw/open5gs-upf.yaml index e65914e..39c47d5 100644 --- a/pgw/open5gs-upf.yaml +++ b/pgw/open5gs-upf.yaml @@ -22,8 +22,8 @@ gateway: 10.45.0.1 dnn: internet dev: ogstun46 - - subnet: cafe::/64 - gateway: cafe::1 + - subnet: 2001:db8:cafe::/48 + gateway: 2001:db8:cafe::1 dnn: internet dev: ogstun46
diff --git a/pgw/testenv.sh b/pgw/testenv.sh index 2abf999..7f155d1 100755 --- a/pgw/testenv.sh +++ b/pgw/testenv.sh @@ -46,6 +46,10 @@ sudo ip link set ogstun4 up sudo ip link set ogstun6 up sudo ip link set ogstun46 up + + # The IPv4 route is added automatically when setting the interface addr above: + sudo ip route add "10.45.0.0/16" dev "ogstun46" || true + sudo ip -6 route add "2001:db8:cafe::/48" dev "ogstun46" || true }
del_tun() {