pespin submitted this change.

View Change

Approvals: Jenkins Builder: Verified fixeria: Looks good to me, approved osmith: Looks good to me, but someone else must approve
5gc: Retrieve open5gs-amfd /ue-info and validate handover metrics

Given we don't control the metrics endpoint in the IUT it doesn't make
sense to spend time creating type records for all json attributes being
dumped. Simply use JSON_Generic_val and add a few helpers/templates
around it.

Related: SYS#8270
Change-Id: I8cd11f24791dd86530b6ce5007b01b47e24fdaf8
---
M 5gc/C5G_Tests.default
M 5gc/C5G_Tests.ttcn
M 5gc/ConnHdlr.ttcn
A 5gc/OGS_UEInfo.ttcn
M 5gc/gen_links.sh
M 5gc/regen_makefile.sh
A library/JSON_Generic_Templates.ttcn
7 files changed, 178 insertions(+), 2 deletions(-)

diff --git a/5gc/C5G_Tests.default b/5gc/C5G_Tests.default
index 3280e81..b03f59e 100644
--- a/5gc/C5G_Tests.default
+++ b/5gc/C5G_Tests.default
@@ -2,7 +2,8 @@
FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;

[TESTPORT_PARAMETERS]
-
+*.TCP.noDelay := "yes" // turn off nagle
+*.HTTP.use_notification_ASPs := "yes"

[MODULE_PARAMETERS]

diff --git a/5gc/C5G_Tests.ttcn b/5gc/C5G_Tests.ttcn
index 85e0bae..36ac4fd 100644
--- a/5gc/C5G_Tests.ttcn
+++ b/5gc/C5G_Tests.ttcn
@@ -19,6 +19,8 @@
import from Osmocom_Types all;
import from GSM_Types all;

+import from TCCEncoding_Functions all;
+
import from DNS_Helpers all;

import from Milenage_Functions all;
@@ -48,6 +50,10 @@

import from GTPv1U_Emulation all;

+import from OGS_UEInfo all;
+import from JSON_Generic all;
+import from JSON_Generic_Templates all;
+
import from ConnHdlr all;

modulepar {
@@ -68,6 +74,8 @@
charstring mp_ping_hostname6 := "cafe::1";
charstring mp_pcscf_hostname4 := "127.0.0.7";
charstring mp_pcscf_hostname6 := "fd02:db8:18::7";
+ charstring mp_5gc_amf_metrics_hostname := "127.0.0.5";
+ integer mp_5gc_amf_metrics_port := 9090;

charstring mp_run_prog_log_path := "/tmp";
charstring mp_run_prog_as_user := "osmocom";
@@ -102,6 +110,7 @@
{
idx := idx,
imsi := f_concat_pad(lengthof(mp_imsi), substr(mp_imsi, 0, lengthof(mp_imsi) - 6), idx),
+ imsi_str := f_dec_TBCD(imsi_hex2oct(f_concat_pad(lengthof(mp_imsi), substr(mp_imsi, 0, lengthof(mp_imsi) - 6), idx))),
imeisv := f_rnd_imeisv(),
usim_key := mp_usim_key,
usim_opc := mp_usim_opc,
@@ -1027,6 +1036,12 @@
f_pdu_sess_create_tun();
f_ping(g_pars.ue_pars.sess_pars.run_prog_pars.ping_hostname);

+ f_OGS_UEInfo_init(mp_5gc_amf_metrics_hostname, mp_5gc_amf_metrics_port);
+ var JSON_generic_val json := f_OGS_UEInfo_get_ue_handover(g_pars.ue_pars.imsi_str);
+ if (not match(json, tr_OGS_UEInfo_ue_handover(attempted := 1, completed := 1, rejected := 0))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Handover UeInfo mismatch"));
+ }
+
f_pdu_sess_release();
f_deregister();
}
@@ -1071,6 +1086,12 @@
/* Test UE can still use the network after HO cancel: */
f_ping(g_pars.ue_pars.sess_pars.run_prog_pars.ping_hostname);

+ f_OGS_UEInfo_init(mp_5gc_amf_metrics_hostname, mp_5gc_amf_metrics_port);
+ var JSON_generic_val json := f_OGS_UEInfo_get_ue_handover(g_pars.ue_pars.imsi_str);
+ if (not match(json, tr_OGS_UEInfo_ue_handover(attempted := 1, completed := 0, rejected := 1))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Handover UeInfo mismatch"));
+ }
+
f_pdu_sess_release();
f_deregister();
}
@@ -1135,6 +1156,12 @@
f_ping(g_pars.ue_pars.sess_pars.run_prog_pars.ping_hostname);

log("0: Handover 1->0 successful!");
+ f_OGS_UEInfo_init(mp_5gc_amf_metrics_hostname, mp_5gc_amf_metrics_port);
+ var JSON_generic_val json := f_OGS_UEInfo_get_ue_handover(g_pars.ue_pars.imsi_str);
+ if (not match(json, tr_OGS_UEInfo_ue_handover(attempted := 2, completed := 2, rejected := 0))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Handover UeInfo mismatch"));
+ }
+
f_pdu_sess_release();
f_deregister();

@@ -1153,6 +1180,11 @@
f_ping(g_pars.ue_pars.sess_pars.run_prog_pars.ping_hostname);

log("1: Handover 0->1 successful!");
+ f_OGS_UEInfo_init(mp_5gc_amf_metrics_hostname, mp_5gc_amf_metrics_port);
+ var JSON_generic_val json := f_OGS_UEInfo_get_ue_handover(g_pars.ue_pars.imsi_str);
+ if (not match(json, tr_OGS_UEInfo_ue_handover(attempted := 1, completed := 1, rejected := 0))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Handover UeInfo mismatch"));
+ }

/* Now initiate handover 1->0: */
f_handover_inter_ngran_n2_source(tgt_idx := 0, direct_forwarding_avail := direct_path_available);
diff --git a/5gc/ConnHdlr.ttcn b/5gc/ConnHdlr.ttcn
index 3332f9d..a000830 100644
--- a/5gc/ConnHdlr.ttcn
+++ b/5gc/ConnHdlr.ttcn
@@ -49,6 +49,8 @@
import from GTPv1U_Emulation all;
import from UECUPS_Types all;

+import from OGS_UEInfo all;
+
/* (maximum) number of emulated gNBs */
const integer NUM_NGRAN := 2;

@@ -82,6 +84,7 @@
type record UeParams {
integer idx,
HEX15n imsi,
+ charstring imsi_str,
HEX16n imeisv,
octetstring usim_key,
octetstring usim_opc,
@@ -141,7 +144,7 @@
inout charstring, Handover_Xn_Pars, Handover_n2_Pars;
} with { extension "internal" };

-type component ConnHdlr extends NGAP_ConnHdlr, GTP1U_ConnHdlr {
+type component ConnHdlr extends NGAP_ConnHdlr, GTP1U_ConnHdlr, OGS_UEInfo_CT {
port ConnHdlr_Coord_PT COORD;

var ConnHdlrPars g_pars;
diff --git a/5gc/OGS_UEInfo.ttcn b/5gc/OGS_UEInfo.ttcn
new file mode 100644
index 0000000..e463006
--- /dev/null
+++ b/5gc/OGS_UEInfo.ttcn
@@ -0,0 +1,88 @@
+/* open5gs-amfd http://AMF_IP:9090/ue-info */
+module OGS_UEInfo {
+
+import from Misc_Helpers all;
+
+import from HTTP_Adapter all;
+import from HTTPmsg_Types all;
+
+import from JSON_Generic_Null_Def all;
+import from JSON_Generic all;
+import from JSON_Generic_Templates all;
+
+const integer c_OGS_UEInfo_default_http_port := 9090;
+
+template (present) JSON_generic_val
+tr_OGS_UEInfo_ue_handover(template (present) integer attempted := ?,
+ template (present) integer completed := ?,
+ template (present) integer rejected := ?) :=
+tr_JSON_generic_val_object({
+ { "attempted", tr_JSON_generic_val_integer(attempted) },
+ { "completed", tr_JSON_generic_val_integer(completed) },
+ { "rejected", tr_JSON_generic_val_integer(rejected) }
+});
+
+function f_OGS_UEInfo_metrics_get_ue_by_imsi(JSON_generic_val json, charstring imsi)
+return JSON_generic_val {
+ var universal charstring exp_supi := "imsi-" & imsi;
+ if (not ischosen(json.JSON_array)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("json is not an array: ", json));
+ }
+ for (var integer i := 0; i < lengthof(json.JSON_array); i := i + 1) {
+ if (not ischosen(json.JSON_array[i].JSON_object)) {
+ continue;
+ }
+ var JSON_generic_val json_supi := f_JSON_Generic_val_object_get_val(json.JSON_array[i], "supi");
+ var universal charstring supi := json_supi.JSON_string;
+ if (not match (supi, exp_supi)) {
+ continue;
+ }
+ return json.JSON_array[i];
+ }
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("IMSI ", imsi, " not found in: ", json));
+ return json;
+}
+
+type component OGS_UEInfo_CT extends http_CT {
+ var float g_tout_http := 5.0;
+};
+
+function f_OGS_UEInfo_init(charstring http_host, integer http_port := c_OGS_UEInfo_default_http_port)
+runs on OGS_UEInfo_CT {
+ var HTTP_Adapter_Params http_adapter_pars := {
+ http_host := http_host,
+ http_port := http_port,
+ use_ssl := false
+ };
+ f_http_init(http_adapter_pars);
+}
+
+private function f_OGS_UEInfo_get_metrics_raw(integer page_size := 10000)
+runs on OGS_UEInfo_CT return charstring
+{
+ var HTTPMessage http_resp;
+ /* page=-1 needed to avoid paging... */
+ f_http_tx_request(url := "/ue-info?page=-1", method := "GET", tout := g_tout_http);
+ http_resp := f_http_rx_response(tr_HTTP_Resp(200), tout := g_tout_http);
+ return http_resp.response.body;
+}
+
+function f_OGS_UEInfo_get_metrics()
+runs on OGS_UEInfo_CT return JSON_generic_val {
+ var JSON_generic_val pdu;
+ var charstring raw := f_OGS_UEInfo_get_metrics_raw();
+ var integer rc := f_dec_JSON(char2oct(raw), pdu); // TODO: check rc
+ return f_JSON_Generic_val_object_get_val(pdu, "items");
+}
+
+function f_OGS_UEInfo_get_ue_handover(charstring imsi)
+runs on OGS_UEInfo_CT return JSON_generic_val {
+ var JSON_generic_val json;
+ json := f_OGS_UEInfo_get_metrics();
+ json := f_OGS_UEInfo_metrics_get_ue_by_imsi(json, imsi);
+ json := f_JSON_Generic_val_object_get_val(json, "handover");
+ return json;
+}
+
+
+}
diff --git a/5gc/gen_links.sh b/5gc/gen_links.sh
index 9d72550..8907a30 100755
--- a/5gc/gen_links.sh
+++ b/5gc/gen_links.sh
@@ -22,6 +22,21 @@
FILES="GTPU_EncDec.cc GTPU_Types.ttcn "
gen_links $DIR $FILES

+# Needed by HTTP_Adapter (OGS_UEInfo.ttcn metrics):
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Abstract_Socket/src
+FILES="Abstract_Socket.cc Abstract_Socket.hh "
+gen_links $DIR $FILES
+
+# Needed by HTTP_Adapter (OGS_UEInfo.ttcn metrics):
+DIR=$BASEDIR/titan.TestPorts.HTTPmsg/src
+FILES="HTTPmsg_MessageLen.ttcn HTTPmsg_MessageLen_Function.cc HTTPmsg_PT.cc HTTPmsg_PT.hh HTTPmsg_PortType.ttcn HTTPmsg_Types.ttcn "
+gen_links $DIR $FILES
+
+# Needed by OGS_UEInfo.ttcn metrics:
+DIR=$BASEDIR/titan.ProtocolModules.JSON_v07_2006/src
+FILES="JSON_Generic_Null_Def.asn JSON_Generic.ttcn"
+gen_links $DIR $FILES
+
DIR=$BASEDIR/osmo-uecups/ttcn3
FILES="UECUPS_CodecPort.ttcn UECUPS_CodecPort_CtrlFunct.ttcn UECUPS_CodecPort_CtrlFunctDef.cc UECUPS_Types.ttcn "
gen_links $DIR $FILES
@@ -89,6 +104,8 @@
FILES+="NG_NAS_Osmo_Types.ttcn NG_NAS_Osmo_Templates.ttcn NG_NAS_Functions.ttcn "
FILES+="NG_CryptoFunctionDefs.cc NG_CryptoFunctions.ttcn "
FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn GTPv1U_Emulation.ttcnpp "
+FILES+="HTTP_Adapter.ttcn "
+FILES+="JSON_Generic_Templates.ttcn "
gen_links $DIR $FILES

gen_links_finish
diff --git a/5gc/regen_makefile.sh b/5gc/regen_makefile.sh
index e3ff277..7f96ebb 100755
--- a/5gc/regen_makefile.sh
+++ b/5gc/regen_makefile.sh
@@ -7,6 +7,7 @@
*.c
*.ttcn
*.ttcnpp
+ Abstract_Socket.cc
IPL4asp_PT.cc
IPL4asp_discovery.cc
Native_FunctionDefs.cc
@@ -21,6 +22,8 @@
TCCInterface.cc
GTPU_EncDec.cc
GTPv1U_CodecPort_CtrlFunctDef.cc
+ HTTPmsg_MessageLen_Function.cc
+ HTTPmsg_PT.cc
UECUPS_CodecPort_CtrlFunctDef.cc
"

diff --git a/library/JSON_Generic_Templates.ttcn b/library/JSON_Generic_Templates.ttcn
new file mode 100644
index 0000000..0ba8ebd
--- /dev/null
+++ b/library/JSON_Generic_Templates.ttcn
@@ -0,0 +1,32 @@
+module JSON_Generic_Templates {
+
+import from JSON_Generic_Null_Def all;
+import from JSON_Generic all;
+
+import from Misc_Helpers all;
+
+template (present) JSON_generic_val
+tr_JSON_generic_val_object(template (present) JSON_Generic.JSON_generic_val.JSON_object json_obj := ?) := {
+ JSON_object := json_obj
+}
+
+template (present) JSON_generic_val
+tr_JSON_generic_val_integer(template (present) integer val := ?) := {
+ JSON_integer := val
+}
+
+function f_JSON_Generic_val_object_get_val(JSON_generic_val json, universal charstring key)
+return JSON_generic_val {
+ if (not ischosen(json.JSON_object)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("json is not an object: ", json));
+ }
+ for (var integer i := 0; i < lengthof(json.JSON_object); i := i + 1) {
+ if (json.JSON_object[i].key == key) {
+ return json.JSON_object[i].val;
+ }
+ }
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("json has no key ", key, ": ", json));
+ return json;
+}
+
+}

To view, visit change 43794. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I8cd11f24791dd86530b6ce5007b01b47e24fdaf8
Gerrit-Change-Number: 43794
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: osmith <osmith@sysmocom.de>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>