From cf4935afca1c6ebefbfc128a6e77526b22d15bf9 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Mon, 21 Nov 2022 17:15:46 +0100 Subject: [PATCH] upf: test Session Mod, test Network Instance Add tests and enhance the upf test suite to be closer to real world usage: - properly verify the F-TEIDs chosen by osmo-upf. - add tests with two-step session creation, i.e. with a Session Establishment followed by Session Modification indicating the remote F-TEID to use on the core side, as is the usual case. - Add module parameters for network instances to use in the test; dynamically configure osmo-upf's "netinst" config via VTY. - pass Network Instance in Create PDR, verify that osmo-upf returns the matching GTP IP addresses in Created PDR. Related: SYS#6192 SYS#5599 Change-Id: I440466f1cc9689391869ac2579a4497ef6008adb --- upf/CPF_ConnectionHandler.ttcn | 5 - upf/UPF_Tests.ttcn | 468 +++++++++++++++++++++++++++++++-- upf/osmo-upf.cfg | 2 + 3 files changed, 442 insertions(+), 33 deletions(-) diff --git a/upf/CPF_ConnectionHandler.ttcn b/upf/CPF_ConnectionHandler.ttcn index 25f99b947..f983ff0b7 100644 --- a/upf/CPF_ConnectionHandler.ttcn +++ b/upf/CPF_ConnectionHandler.ttcn @@ -47,11 +47,6 @@ function f_next_seid() runs on CPF_ConnHdlr return OCT8 { return int2oct(g_next_seid_state, 8); } -function f_next_local_teid() runs on CPF_ConnHdlr return OCT4 { - g_next_local_teid_state := g_next_local_teid_state + 1; - return int2oct(g_next_local_teid_state, 4); -} - function f_next_remote_teid() runs on CPF_ConnHdlr return OCT4 { g_next_remote_teid_state := g_next_remote_teid_state + 1; return int2oct(g_next_remote_teid_state, 4); diff --git a/upf/UPF_Tests.ttcn b/upf/UPF_Tests.ttcn index b5c65d262..5db143a69 100644 --- a/upf/UPF_Tests.ttcn +++ b/upf/UPF_Tests.ttcn @@ -42,6 +42,11 @@ modulepar { charstring mp_pfcp_ip_upf := "127.0.0.1"; charstring mp_pfcp_ip_local := "127.0.0.2"; + charstring mp_netinst_access_ip_1 := "127.0.1.1"; + charstring mp_netinst_access_ip_2 := "127.0.1.2"; + charstring mp_netinst_core_ip_1 := "127.0.2.1"; + charstring mp_netinst_core_ip_2 := "127.0.2.2"; + /* When testing with gtp mockup, actions will not show. */ boolean mp_verify_gtp_actions := false; } @@ -162,13 +167,60 @@ type record PFCP_session { GTP_Action gtp } +/* _r and _l means 'remote' and 'local', from the perspective of the osmo-upf process. */ +type record GTP_Action_tunend { + /* the PDR Id detecting packets from this side */ + integer pdr_id, + /* IP packets arriving from this side are arriving on ip_l */ + charstring ip_l, + + /* the FAR Id forwarding packets to this side */ + integer far_id +} + +/* _r and _l means 'remote' and 'local', from the perspective of the osmo-upf process. */ +type record GTP_Action_tun { + /* the PDR Id detecting packets from this side */ + integer pdr_id, + /* GTP arriving from this side is arriving on gtp_ip_l with teid_l */ + charstring gtp_ip_l, + OCT4 teid_l, + + /* the FAR Id forwarding packets to this side */ + integer far_id, + /* GTP going out to this side should be sent to gtp_ip_r with teid_r */ + charstring gtp_ip_r, + OCT4 teid_r +} + +type union GTP_Action_core { + /* For kind = "tunend", the local IP that the UE has on 'the internet' */ + GTP_Action_tunend tunend, + /* For kind = "tunmap", the second GTP tunnel */ + GTP_Action_tun tunmap +} + +/* State of what GTP functionality osmo-upf should put in place, after a PFCP request was ACKed by it. + * _r and _l means 'remote' and 'local', from the perspective of the osmo-upf process. + * + * tunend: + * Access UPF Core + * GTP-r:127.0.0.2,0x1 <-FAR-1-- | 192.168.0.1 <-PDR-1-- + * --PDR-2-> GTP-l:127.0.0.1,0x2 | --FAR-2-> (IP destination is in each GTP payload) + * + * tunmap: + * Access UPF Core + * GTP-r:127.0.0.2,0x1 <-FAR-1-- | 127.0.0.1,0x1 <-PDR-1-- + * --PDR-2-> GTP-l:127.0.0.1,0x2 | --FAR-2-> GTP-r:127.0.0.3,0x2 + */ type record GTP_Action { /* kind = ("tunend"|"tunmap") */ charstring kind, - charstring gtp_access_ip, - OCT4 teid_access_r, - OCT4 teid_access_l, - charstring core_ip, + /* The access side GTP tunnel. (The 'Access' side is always GTP.) */ + GTP_Action_tun access, + /* The core side GTP tunnel (tunmap) or local IP (tunend) */ + GTP_Action_core core, + /* Reference to the PFCP Session that created this GTP action: PFCP session's F-SEID as seen from osmo-upf */ charstring pfcp_peer, OCT8 seid_l }; @@ -176,17 +228,26 @@ type record GTP_Action { type record of GTP_Action GTP_Action_List; private function f_parse_gtp_action(out GTP_Action ret, charstring str) return boolean { + /* Parse a string like + * "GTP:tunend GTP-access-r:127.0.0.2 TEID-access-r:0x94f0001 TEID-access-l:0x1 IP-core-l:192.168.44.241 PFCP-peer:127.0.0.2 SEID-l:0x1 PDR:1,2" + */ var GTP_Action a; if (not f_get_name_val(a.kind, str, "GTP")) { return false; } - if (not f_get_name_val(a.gtp_access_ip, str, "GTP-access")) { + if (not f_get_name_val(a.access.gtp_ip_r, str, "GTP-access-r")) { return false; } - if (not f_get_name_val_oct4(a.teid_access_r, str, "TEID-r")) { + if (not f_get_name_val_oct4(a.access.teid_r, str, "TEID-access-r")) { return false; } - if (not f_get_name_val_oct4(a.teid_access_l, str, "TEID-l")) { + if (not f_get_name_val(a.access.gtp_ip_l, str, "GTP-access-l")) { + return false; + } + if (not f_get_name_val_oct4(a.access.teid_l, str, "TEID-access-l")) { + return false; + } + if (not f_get_name_val_int(a.access.pdr_id, str, "PDR-access")) { return false; } if (not f_get_name_val(a.pfcp_peer, str, "PFCP-peer")) { @@ -195,9 +256,39 @@ private function f_parse_gtp_action(out GTP_Action ret, charstring str) return b if (not f_get_name_val_oct8(a.seid_l, str, "SEID-l")) { return false; } - if (not f_get_name_val(a.core_ip, str, "IP-core")) { - return false; + if (a.kind == "tunend") { + if (not f_get_name_val_int(a.core.tunend.pdr_id, str, "PDR-core")) { + return false; + } + if (not f_get_name_val(a.core.tunend.ip_l, str, "IP-core-l")) { + return false; + } + /* in these tests, the PDR Id and its FAR Id are always the same: PDR for incoming on Access matches its + * FAR that forwards to Core. */ + a.core.tunend.far_id := a.access.pdr_id; + a.access.far_id := a.core.tunend.pdr_id; + } else if (a.kind == "tunmap") { + if (not f_get_name_val(a.core.tunmap.gtp_ip_r, str, "GTP-core-r")) { + return false; + } + if (not f_get_name_val_oct4(a.core.tunmap.teid_r, str, "TEID-core-r")) { + return false; + } + if (not f_get_name_val(a.core.tunmap.gtp_ip_l, str, "GTP-core-l")) { + return false; + } + if (not f_get_name_val_oct4(a.core.tunmap.teid_l, str, "TEID-core-l")) { + return false; + } + if (not f_get_name_val_int(a.core.tunmap.pdr_id, str, "PDR-core")) { + return false; + } + /* in these tests, the PDR Id and its FAR Id are always the same: PDR for incoming on Access matches its + * FAR that forwards to Core. */ + a.core.tunmap.far_id := a.access.pdr_id; + a.access.far_id := a.core.tunmap.pdr_id; } + ret := a; return true; } @@ -417,6 +508,16 @@ private function f_vty_expect_no_active_sessions(TELNETasp_PT vty_pt) { setverdict(pass); } +private function f_vty_netinst_cfg(TELNETasp_PT vty_pt, ro_charstring netinst_cmds) +{ + f_vty_enter_config(vty_pt); + f_vty_transceive(vty_pt, "netinst"); + for (var integer i := 0; i < lengthof(netinst_cmds); i := i + 1) { + f_vty_transceive(vty_pt, netinst_cmds[i]); + } + f_vty_transceive_ret(vty_pt, "end"); +} + function f_init_vty(charstring id := "foo") runs on test_CT { if (UPFVTY.checkstate("Mapped")) { /* skip initialization if already executed once */ @@ -435,6 +536,15 @@ function f_init(float guard_timeout := 30.0) runs on test_CT { activate(as_Tguard()); f_init_vty("VirtCPF"); + + /* Clear out and set up default network instance config */ + f_vty_netinst_cfg(UPFVTY, + { "clear", + "add access " & mp_netinst_access_ip_1, + "add access2 " & mp_netinst_access_ip_2, + "add core " & mp_netinst_core_ip_1, + "add core2 " & mp_netinst_core_ip_2 + }); } friend function f_shutdown_helper() runs on test_CT { @@ -500,6 +610,7 @@ private function f_assoc_release() runs on CPF_ConnHdlr { PFCP.receive(tr_PFCP_Assoc_Release_Resp(cause := tr_PFCP_Cause(REQUEST_ACCEPTED))); } +/* Collection of what a test intends to send to osmo-upf */ type record PFCP_Ruleset { Create_PDR_list pdr, Create_FAR_list far @@ -508,17 +619,18 @@ type record PFCP_Ruleset { /* Add to r a rule set that does GTP decapsulation (half of encapsulation/decapsulation): * Receive GTP on src_iface = ACCESS by a local F-TEID to be chosen by osmo-upf. * Dispatch GTP payload as plain IP on dest_iface = CORE. */ -private function f_ruleset_add_GTP_decaps(inout PFCP_Ruleset r) { - var integer pdr_id := lengthof(r.pdr) + 1; - var integer far_id := lengthof(r.far) + 1; - +private function f_ruleset_add_GTP_decaps(inout PFCP_Ruleset r, + integer pdr_id, + charstring src_netinst, + integer far_id) { r.pdr := r.pdr & { valueof( ts_PFCP_Create_PDR( pdr_id, ts_PFCP_PDI( ACCESS, - local_F_TEID := ts_PFCP_F_TEID_choose_v4()), + local_F_TEID := ts_PFCP_F_TEID_choose_v4(), + network_instance := ts_PFCP_Network_Instance(src_netinst)), ts_PFCP_Outer_Header_Removal(GTP_U_UDP_IPV4), far_id ) @@ -537,13 +649,11 @@ private function f_ruleset_add_GTP_decaps(inout PFCP_Ruleset r) { /* Add to r a rule set that does GTP encapsulation (half of encapsulation/decapsulation) */ private function f_ruleset_add_GTP_encaps(inout PFCP_Ruleset r, + integer pdr_id, charstring ue_addr_v4 := "192.168.23.42", + integer far_id, OCT4 remote_teid, OCT4 gtp_dest_addr_v4) { - - var integer pdr_id := lengthof(r.pdr) + 1; - var integer far_id := lengthof(r.far) + 1; - r.pdr := r.pdr & { valueof( ts_PFCP_Create_PDR( @@ -572,6 +682,87 @@ private function f_ruleset_add_GTP_encaps(inout PFCP_Ruleset r, }; } +/* Add to r a rule set that forwards GTP from one tunnel to another, i.e. one direction of a tunmap */ +private function f_ruleset_add_GTP_forw(inout PFCP_Ruleset r, + integer pdr_id, + e_PFCP_Src_Iface src_iface, + charstring src_netinst, + integer far_id, + e_PFCP_Dest_Iface dest_iface, + F_TEID dest_remote_f_teid) { + r.pdr := r.pdr & { + valueof( + ts_PFCP_Create_PDR( + pdr_id, + ts_PFCP_PDI( + src_iface, + local_F_TEID := ts_PFCP_F_TEID_choose_v4(), + network_instance := ts_PFCP_Network_Instance(src_netinst)), + ts_PFCP_Outer_Header_Removal(GTP_U_UDP_IPV4), + far_id + ) + ) + }; + r.far := r.far & { + valueof( + ts_PFCP_Create_FAR( + far_id, + ts_PFCP_Apply_Action_FORW(), + valueof(ts_PFCP_Forwarding_Parameters(dest_iface, + ts_PFCP_Outer_Header_Creation_GTP_ipv4(dest_remote_f_teid.teid, + dest_remote_f_teid.ipv4_address))) + ) + ) + }; +} + +/* Add to r a DROP rule from src_iface to dest_iface */ +private function f_ruleset_add_GTP_drop(inout PFCP_Ruleset r, + integer pdr_id, + e_PFCP_Src_Iface src_iface, + charstring src_netinst, + integer far_id, + e_PFCP_Dest_Iface dest_iface) { + r.pdr := r.pdr & { + valueof( + ts_PFCP_Create_PDR( + pdr_id, + ts_PFCP_PDI( + src_iface, + local_F_TEID := ts_PFCP_F_TEID_choose_v4(), + network_instance := ts_PFCP_Network_Instance(src_netinst)), + ts_PFCP_Outer_Header_Removal(GTP_U_UDP_IPV4), + far_id + ) + ) + }; + r.far := r.far & { + valueof( + ts_PFCP_Create_FAR( + far_id, + ts_PFCP_Apply_Action_DROP, + fp := omit + ) + ) + }; +} + +private function f_tunmap_upd_far_to_core(GTP_Action gtp) return Update_FAR +{ + return valueof( + ts_PFCP_Update_FAR( + gtp.core.tunmap.far_id, + ts_PFCP_Apply_Action_FORW(), + valueof(ts_PFCP_Update_Forwarding_Parameters( + CORE, + ts_PFCP_Outer_Header_Creation_GTP_ipv4(gtp.core.tunmap.teid_r, + f_inet_addr(gtp.core.tunmap.gtp_ip_r)) + ) + ) + ) + ); +} + /* Return two PDR+FAR rulesets that involve a src=CP-Function. Such rulesets are emitted by certain third party CPF, and * osmo-upf should ACK the creation but ignore the rules (no-op). This function models rulesets seen in the field, so we * can confirm that osmo-upf ACKs and ignores. */ @@ -630,18 +821,87 @@ private function f_ruleset_noop() return PFCP_Ruleset return r; } -/* Return a rule set that does GTP encapsulation/decapsulation */ -private function f_ruleset_tunend(GTP_Action gtp) return PFCP_Ruleset +/* Return a rule set that does GTP encapsulation and decapsulation, in both directions. */ +private function f_ruleset_tunend(GTP_Action gtp, charstring netinst_access := "access") return PFCP_Ruleset { var PFCP_Ruleset rules := { {}, {} }; - f_ruleset_add_GTP_decaps(rules); - f_ruleset_add_GTP_encaps(rules, gtp.core_ip, gtp.teid_access_r, f_inet_addr(gtp.gtp_access_ip)); + f_ruleset_add_GTP_decaps(rules, + pdr_id := gtp.access.pdr_id, + src_netinst := netinst_access, + far_id := gtp.core.tunend.far_id); + f_ruleset_add_GTP_encaps(rules, + gtp.core.tunend.pdr_id, + gtp.core.tunend.ip_l, + gtp.access.far_id, + gtp.access.teid_r, + f_inet_addr(gtp.access.gtp_ip_r)); return rules; } -/* Run a PFCP Session Establishment procedure */ -private function f_session_est(inout PFCP_session s, PFCP_Ruleset rules) runs on CPF_ConnHdlr { +/* Return a rule set that does GTP tunnel forwarding in both directions. + * If core_gtp_known == true, place full FORW rules in both directions. + * If core_gtp_known == false, keep the Core side as DROP: this allows testing the usual/realistic case, where upon + * Session Establishment, the core side PGW has not yet provided the destination GTP F-TEID, which will follow later in + * a Session Modification. (This test suite has already configured which GTP F-TEID will be used on the core side, but + * we're omitting it from Session Establishment, until it is time to use it in f_session_mod()). */ +private function f_ruleset_tunmap(GTP_Action gtp, boolean core_gtp_known := true, + charstring netinst_access := "access", + charstring netinst_core := "core") return PFCP_Ruleset +{ + var PFCP_Ruleset rules := { {}, {} }; + /* Access to Core */ + if (core_gtp_known) { + f_ruleset_add_GTP_forw(rules, + pdr_id := gtp.access.pdr_id, + src_iface := ACCESS, + src_netinst := netinst_access, + far_id := gtp.core.tunmap.far_id, + dest_iface := CORE, + dest_remote_f_teid := valueof(ts_PFCP_F_TEID_ipv4(gtp.core.tunmap.teid_r, + f_inet_addr(gtp.core.tunmap.gtp_ip_r)))); + } else { + /* The Core remote GTP will follow in a Session Modification, for now set Core->Access to DROP */ + f_ruleset_add_GTP_drop(rules, + pdr_id := gtp.access.pdr_id, + src_iface := ACCESS, + src_netinst := netinst_access, + far_id := gtp.core.tunmap.far_id, + dest_iface := CORE); + } + /* Core to Access */ + f_ruleset_add_GTP_forw(rules, + pdr_id := gtp.core.tunmap.pdr_id, + src_iface := CORE, + src_netinst := netinst_core, + far_id := gtp.access.far_id, + dest_iface := ACCESS, + dest_remote_f_teid := valueof(ts_PFCP_F_TEID_ipv4(gtp.access.teid_r, + f_inet_addr(gtp.access.gtp_ip_r)))); + return rules; +} +/* From a PFCP Session Establishment Response, retrieve the F_TEID returned in the Created PDR IE for the given PDR Id + */ +private function f_get_created_local_f_teid(PDU_PFCP sess_est_resp, integer pdr_id) return F_TEID +{ + for (var integer i := 0; + i < lengthof(sess_est_resp.message_body.pfcp_session_establishment_response.created_PDR_list); + i := i + 1) { + var Created_PDR cpdr := sess_est_resp.message_body.pfcp_session_establishment_response.created_PDR_list[i]; + if (oct2int(cpdr.grouped_ie.pdr_id.rule_id) != pdr_id) { + continue; + } + log("osmo-upf has chosen local F-TEID: PDR-" & int2str(pdr_id) & " = ", cpdr.grouped_ie.local_F_TEID); + return cpdr.grouped_ie.local_F_TEID; + } + setverdict(fail, "PDR Id " & int2str(pdr_id) & " not found in PFCP message"); + mtc.stop; +} + +/* Run a PFCP Session Establishment procedure */ +private function f_session_est(inout PFCP_session s, PFCP_Ruleset rules) runs on CPF_ConnHdlr +{ + log("f_session_est: rules = ", rules); PFCP.send(ts_PFCP_Session_Est_Req(ts_PFCP_Node_ID_ipv4(f_inet_addr(g_pars.local_addr)), ts_PFCP_F_SEID_ipv4(f_inet_addr(g_pars.local_addr), s.cp_seid), rules.pdr, rules.far)); @@ -650,9 +910,27 @@ private function f_session_est(inout PFCP_session s, PFCP_Ruleset rules) runs on PFCP.receive(tr_PFCP_Session_Est_Resp(s.cp_seid)) -> value pfcp; s.up_seid := pfcp.message_body.pfcp_session_establishment_response.UP_F_SEID.seid; s.gtp.seid_l := s.up_seid; + + var F_TEID access_local_f_teid := f_get_created_local_f_teid(pfcp, s.gtp.access.pdr_id); + s.gtp.access.gtp_ip_l := f_inet_ntoa(access_local_f_teid.ipv4_address); + s.gtp.access.teid_l := access_local_f_teid.teid; + + if (ischosen(s.gtp.core.tunmap)) { + var F_TEID core_local_f_teid := f_get_created_local_f_teid(pfcp, s.gtp.core.tunmap.pdr_id); + s.gtp.core.tunmap.gtp_ip_l := f_inet_ntoa(core_local_f_teid.ipv4_address); + s.gtp.core.tunmap.teid_l := core_local_f_teid.teid; + } log("established PFCP session: ", s); } +/* Run a PFCP Session Modification procedure */ +private function f_session_mod(inout PFCP_session s) runs on CPF_ConnHdlr +{ + PFCP.send(ts_PFCP_Session_Mod_Req(s.up_seid, f_tunmap_upd_far_to_core(s.gtp))); + PFCP.receive(tr_PFCP_Session_Mod_Resp(s.cp_seid)); + log("modified PFCP session: ", s); +} + private function f_create_PFCP_session_tunend() runs on CPF_ConnHdlr return PFCP_session { var PFCP_session s := { @@ -660,12 +938,60 @@ private function f_create_PFCP_session_tunend() runs on CPF_ConnHdlr return PFCP cp_seid := f_next_seid(), gtp := { kind := "tunend", - gtp_access_ip := "127.0.0.2", - teid_access_r := f_next_remote_teid(), - teid_access_l := f_next_local_teid(), - core_ip := f_next_ue_addr(), + access := { + pdr_id := 1, + /* gtp_ip_l and teid_l will be returned by Session Establishment Response, Created PDR */ + gtp_ip_l := "", + teid_l := '00000000'O, + far_id := 2, + gtp_ip_r := "127.0.0.2", + teid_r := f_next_remote_teid() + }, + core := { + tunend := { + pdr_id := 2, + ip_l := f_next_ue_addr(), + far_id := 1 + } + }, pfcp_peer := g_pars.local_addr, seid_l := '0000000000000000'O + /* seid_l will be returned by Session Establishment Response */ + } + }; + return s; +} + +private function f_create_PFCP_session_tunmap() runs on CPF_ConnHdlr return PFCP_session +{ + var PFCP_session s := { + up_seid := -, + cp_seid := f_next_seid(), + gtp := { + kind := "tunmap", + access := { + pdr_id := 1, + /* gtp_ip_l and teid_l will be returned by Session Establishment Response, Created PDR */ + gtp_ip_l := "", + teid_l := '00000000'O, + far_id := 2, + gtp_ip_r := "127.0.0.2", + teid_r := f_next_remote_teid() + }, + core := { + tunmap := { + pdr_id := 2, + /* gtp_ip_l and teid_l will be returned by Session Establishment Response, Created PDR */ + gtp_ip_l := "", + teid_l := '00000000'O, + far_id := 1, + gtp_ip_r := "127.0.0.3", + teid_r := f_next_remote_teid() + } + }, + pfcp_peer := g_pars.local_addr, + seid_l := '0000000000000000'O + /* seid_l will be returned by Session Establishment Response */ } }; return s; @@ -778,12 +1104,98 @@ testcase TC_session_est_noop() runs on test_CT { f_shutdown_helper(); } +/* Verify that the Network Instance IE in Create PDR chooses the right local address for a tunmap session */ +private function f_tc_session_est_tunmap(charstring id) runs on CPF_ConnHdlr { + f_assoc_setup(); + var PFCP_session s := f_create_PFCP_session_tunmap(); + f_session_est(s, f_ruleset_tunmap(s.gtp)); + f_sleep(1.0); + f_vty_expect_session_active(UPFVTY, s); + f_session_del(s); + f_vty_expect_no_active_sessions(UPFVTY); + f_vty_expect_no_gtp_actions(UPFVTY); + f_assoc_release(); + setverdict(pass); +} +testcase TC_session_est_tunmap() runs on test_CT { + var CPF_ConnHdlr vc_conn; + + f_init(guard_timeout := 15.0); + + vc_conn := f_start_handler(refers(f_tc_session_est_tunmap)); + vc_conn.done; + f_shutdown_helper(); +} + +/* Set up a tunmap session with a partial Session Establishment, followed by a Session Modification to complete it. */ +private function f_session_est_mod_tunmap(charstring netinst_access, charstring expect_gtp_ip_access, + charstring netinst_core, charstring expect_gtp_ip_core) runs on CPF_ConnHdlr { + f_assoc_setup(); + var PFCP_session s := f_create_PFCP_session_tunmap(); + f_session_est(s, f_ruleset_tunmap(s.gtp, core_gtp_known := false, + netinst_access := netinst_access, netinst_core := netinst_core)); + /* The locally chosen GTP IP addresses where osmo-upf receives GTP traffic were chosen by netinst_access / + * netinst_core and are returned in s.gtp.access.gtp_ip_l / s.gtp.core.tunmap.gtp_ip_l. Verify that the netinst + * names have returned their matching IP addresses. */ + if (s.gtp.access.gtp_ip_l != expect_gtp_ip_access) { + setverdict(fail, "Network Instance '" & netinst_access & "' should have yielded GTP IP " & + expect_gtp_ip_access & " but osmo-upf chose " & s.gtp.access.gtp_ip_l); + mtc.stop; + } + if (s.gtp.core.tunmap.gtp_ip_l != expect_gtp_ip_core) { + setverdict(fail, "Network Instance '" & netinst_core & "' should have yielded GTP IP " & + expect_gtp_ip_core & " but osmo-upf chose " & s.gtp.core.tunmap.gtp_ip_l); + mtc.stop; + } + + f_sleep(1.0); + f_vty_expect_session_status(UPFVTY, s, PFCP_session_inactive); + + f_session_mod(s); + f_sleep(1.0); + f_vty_expect_session_active(UPFVTY, s); + f_session_del(s); + f_vty_expect_no_active_sessions(UPFVTY); + f_vty_expect_no_gtp_actions(UPFVTY); + f_assoc_release(); + setverdict(pass); +} +/* Run f_session_est_mod_tunmap() with the first Network Instances */ +private function f_tc_session_est_mod_tunmap(charstring id) runs on CPF_ConnHdlr { + f_session_est_mod_tunmap("access", mp_netinst_access_ip_1, "core", mp_netinst_core_ip_1); +} +/* Run f_session_est_mod_tunmap() with the second Network Instances */ +private function f_tc_session_est_mod_tunmap2(charstring id) runs on CPF_ConnHdlr { + f_session_est_mod_tunmap("access2", mp_netinst_access_ip_2, "core2", mp_netinst_core_ip_2); +} +testcase TC_session_est_mod_tunmap() runs on test_CT { + var CPF_ConnHdlr vc_conn; + + f_init(guard_timeout := 15.0); + + vc_conn := f_start_handler(refers(f_tc_session_est_mod_tunmap)); + vc_conn.done; + f_shutdown_helper(); +} +testcase TC_session_est_mod_tunmap2() runs on test_CT { + var CPF_ConnHdlr vc_conn; + + f_init(guard_timeout := 15.0); + + vc_conn := f_start_handler(refers(f_tc_session_est_mod_tunmap2)); + vc_conn.done; + f_shutdown_helper(); +} + control { execute( TC_assoc_node_id_v4() ); execute( TC_assoc_node_id_fqdn() ); execute( TC_session_est_tunend() ); execute( TC_session_term_by_assoc_rel() ); execute( TC_session_est_noop() ); + execute( TC_session_est_tunmap() ); + execute( TC_session_est_mod_tunmap() ); + execute( TC_session_est_mod_tunmap2() ); } } diff --git a/upf/osmo-upf.cfg b/upf/osmo-upf.cfg index f84a4aecb..c354d8d57 100644 --- a/upf/osmo-upf.cfg +++ b/upf/osmo-upf.cfg @@ -14,3 +14,5 @@ gtp mockup nft mockup +#netinst +# the netinst cfg is cleared and setup dynamically in UPF_Tests.ttcn