aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-03-01 21:21:59 +0100
committerHarald Welte <laforge@osmocom.org>2022-01-27 10:52:47 +0100
commit36fbac125bc191cdef1ff63c05cd4c752708b56f (patch)
tree09031cd375beb827deb43d71913935c4f7234631
parentc3c6ee6c63c714c48e60ac678b80ae0b4afedbdc (diff)
WIP: DIAMETER performance testinglaforge/s6a
-rw-r--r--diameter/DIAMETER_Tests.cfg19
-rw-r--r--diameter/DIAMETER_Tests.default12
-rw-r--r--diameter/DIAMETER_Tests.ttcn180
-rwxr-xr-xdiameter/gen_links.sh43
-rwxr-xr-xdiameter/regen_makefile.sh9
-rw-r--r--diameter/sctptest.c220
6 files changed, 483 insertions, 0 deletions
diff --git a/diameter/DIAMETER_Tests.cfg b/diameter/DIAMETER_Tests.cfg
new file mode 100644
index 00000000..a55c10e1
--- /dev/null
+++ b/diameter/DIAMETER_Tests.cfg
@@ -0,0 +1,19 @@
+[ORDERED_INCLUDE]
+# Common configuration, shared between test suites
+"../Common.cfg"
+# testsuite specific configuration, not expected to change
+"./DIAMETER_Tests.default"
+
+# Local configuration below
+
+[LOGGING]
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+#DIAMETER_Tests.mp_client := { "192.168.100.1", 62324, "", -1}
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+DIAMETER_Tests.control
diff --git a/diameter/DIAMETER_Tests.default b/diameter/DIAMETER_Tests.default
new file mode 100644
index 00000000..0b0bd1ce
--- /dev/null
+++ b/diameter/DIAMETER_Tests.default
@@ -0,0 +1,12 @@
+[LOGGING]
+FileMask := ERROR | WARNING | PARALLEL | TESTCASE | USER;
+
+[TESTPORT_PARAMETERS]
+DIA_SERVER.DIAMETER.noDelay := "YES"
+DIA_CLIENT.DIAMETER.noDelay := "YES"
+
+[MODULE_PARAMETERS]
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
diff --git a/diameter/DIAMETER_Tests.ttcn b/diameter/DIAMETER_Tests.ttcn
new file mode 100644
index 00000000..0633ab71
--- /dev/null
+++ b/diameter/DIAMETER_Tests.ttcn
@@ -0,0 +1,180 @@
+module DIAMETER_Tests {
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from IPL4asp_Types all;
+
+import from DIAMETER_Types all;
+import from DIAMETER_Templates all;
+import from DIAMETER_CodecPort all;
+import from DIAMETER_CodecPort_CtrlFunct all;
+import from DIAMETER_Emulation all;
+
+modulepar {
+ DIAMETER_conn_parameters mp_server := {
+ remote_ip := "",
+ remote_sctp_port := -1,
+ local_ip := "127.0.0.1",
+ local_sctp_port := 8888
+ };
+ DIAMETER_conn_parameters mp_client := {
+ remote_ip := "127.0.0.1",
+ remote_sctp_port := 8888,
+ local_ip := "",
+ local_sctp_port := -1
+ };
+}
+
+type component DIAMETER_RAW_CT {
+ port DIAMETER_CODEC_PT DIAMETER;
+ var integer g_diameter_conn_id;
+ var integer msg_count_intended := 100000;
+ var integer msg_count_actual := 0;
+}
+
+private template (value) SctpTuple ts_SCTP(template (omit) integer ppid := omit) := {
+ sinfo_stream := omit,
+ sinfo_ppid := ppid,
+ remSocks := omit,
+ assocId := omit
+};
+
+private template PortEvent tr_SctpAssocChange := {
+ sctpEvent := {
+ sctpAssocChange := ?
+ }
+}
+private template PortEvent tr_SctpPeerAddrChange := {
+ sctpEvent := {
+ sctpPeerAddrChange := ?
+ }
+}
+
+function f_init(DIAMETER_conn_parameters p) runs on DIAMETER_RAW_CT {
+ var Result res;
+
+ map(self:DIAMETER, system:DIAMETER_CODEC_PT);
+
+ if (p.remote_sctp_port == -1) {
+ res := DIAMETER_CodecPort_CtrlFunct.f_IPL4_listen(DIAMETER, p.local_ip, p.local_sctp_port, { sctp := valueof(ts_SCTP) });
+ } else {
+ res := DIAMETER_CodecPort_CtrlFunct.f_IPL4_connect(DIAMETER, p.remote_ip, p.remote_sctp_port,
+ p.local_ip, p.local_sctp_port, -1, { sctp := valueof(ts_SCTP) });
+ }
+
+ if (not ispresent(res.connId)) {
+ setverdict(fail, "Could not connect DIAMETER socket, check your configuration");
+ mtc.stop;
+ }
+ g_diameter_conn_id := res.connId;
+}
+
+
+function tr_DIAMETER_RecvFrom_R(template PDU_DIAMETER msg)
+runs on DIAMETER_RAW_CT return template DIAMETER_RecvFrom {
+ var template DIAMETER_RecvFrom mrf := {
+ connId := g_diameter_conn_id,
+ remName := ?,
+ remPort := ?,
+ locName := ?,
+ locPort := ?,
+ msg := msg
+ }
+ return mrf;
+}
+
+function f_rcv_main() runs on DIAMETER_RAW_CT {
+ var template IMSI imsi_t;
+ var hexstring imsi;
+ var DIAMETER_RecvFrom mrf;
+ var PortEvent port_evt;
+
+ alt {
+ [] DIAMETER.receive(PortEvent:{connOpened := ?}) -> value port_evt {
+ g_diameter_conn_id := port_evt.connOpened.connId;
+ }
+ [] DIAMETER.receive(PortEvent:?) { }
+ /* handle CER/CEA handshake */
+ [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(tr_DIAMETER_R(cmd_code := Capabilities_Exchange))) -> value mrf {
+ var template (value) PDU_DIAMETER resp;
+ resp := ts_DIA_CEA(mrf.msg.hop_by_hop_id, mrf.msg.end_to_end_id);
+ DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, resp));
+ }
+
+ /* DIAMETER from remote peer */
+ [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(?)) -> value mrf {
+ msg_count_actual := msg_count_actual + 1;
+ //imsi_t := f_DIAMETER_get_imsi(mrf.msg);
+ }
+ [] DIAMETER.receive(tr_SctpAssocChange) { }
+ [] DIAMETER.receive(tr_SctpPeerAddrChange) { }
+ }
+}
+
+
+function f_server_main(DIAMETER_conn_parameters p) runs on DIAMETER_RAW_CT {
+ f_init(p);
+ while (true) {
+ f_rcv_main();
+ }
+}
+
+function f_client_main(DIAMETER_conn_parameters p) runs on DIAMETER_RAW_CT {
+ var integer i;
+ var hexstring imsi := f_rnd_hexstring(16);
+
+ f_init(p);
+
+ f_sleep(1.0);
+ log("START_XMIT");
+ for (i := 0; i < msg_count_intended; i := i+1) {
+ var template (value) PDU_DIAMETER msg;
+ msg := ts_DIA_AIR(int2oct(i, 4), int2oct(100000+i, 4), char2oct("session_id"),
+ "dest_realm", imsi);
+ DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, msg));
+ msg_count_actual := msg_count_actual + 1;
+ }
+ log("Transmitted ", msg_count_actual, " messages");
+}
+
+
+const integer NR_PAIRS := 1
+
+type component Test_CT {
+ var DIAMETER_RAW_CT vc_server[NR_PAIRS];
+ var DIAMETER_RAW_CT vc_client[NR_PAIRS];
+};
+
+
+
+testcase TC_flood() runs on Test_CT {
+ var integer i;
+
+ for (i := 0; i < sizeof(vc_server); i:=i+1) {
+ var DIAMETER_conn_parameters p_server := mp_server;
+ p_server.local_sctp_port := p_server.local_sctp_port + i;
+ log("Starting server ", i);
+ vc_server[i] := DIAMETER_RAW_CT.create("DIA_SERVER");
+ vc_server[i].start(f_server_main(p_server));
+ }
+
+ for (i := 0; i < sizeof(vc_client); i:=i+1) {
+ var DIAMETER_conn_parameters p_client := mp_client;
+ p_client.remote_sctp_port := p_client.remote_sctp_port + i;
+ log("Starting client ", i);
+ vc_client[i] := DIAMETER_RAW_CT.create("DIA_CLIENT");
+ vc_client[i].start(f_client_main(p_client));
+ }
+
+ for (i := 0; i < lengthof(vc_client); i:=i+1) {
+ vc_client[i].done;
+ }
+ f_sleep(1.0);
+}
+
+
+
+
+
+
+}
diff --git a/diameter/gen_links.sh b/diameter/gen_links.sh
new file mode 100755
index 00000000..cc5304fd
--- /dev/null
+++ b/diameter/gen_links.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+BASEDIR=../deps
+
+. ../gen_links.sh.inc
+
+DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
+FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h"
+FILES+=" TCCEncoding_Functions.ttcn TCCEncoding.cc " # GSM 7-bit coding
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+# Required by MGCP and IPA
+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
+
+DIR=$BASEDIR/titan.TestPorts.TELNETasp/src
+FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn"
+gen_links $DIR $FILES
+
+#DIR=$BASEDIR/titan.ProtocolModules.GTPv2_v13.7.0/src
+#FILES="GTPv2_Types.ttcn"
+#gen_links $DIR $FILES
+
+#DIR=$BASEDIR/titan.ProtocolModules.GTP_v13.5.0/src
+#FILES="GTPC_EncDec.cc GTPC_Types.ttcn GTPU_EncDec.cc GTPU_Types.ttcn"
+#gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.DIAMETER_ProtocolModule_Generator/src
+FILES="DIAMETER_EncDec.cc"
+gen_links $DIR $FILES
+
+DIR=../library
+FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc "
+FILES+="DNS_Helpers.ttcn "
+FILES+="DIAMETER_Types.ttcn DIAMETER_CodecPort.ttcn DIAMETER_CodecPort_CtrlFunct.ttcn DIAMETER_CodecPort_CtrlFunctDef.cc DIAMETER_Emulation.ttcn DIAMETER_Templates.ttcn "
+gen_links $DIR $FILES
+
+ignore_pp_results
diff --git a/diameter/regen_makefile.sh b/diameter/regen_makefile.sh
new file mode 100755
index 00000000..77b25254
--- /dev/null
+++ b/diameter/regen_makefile.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+FILES="*.ttcn IPL4asp_PT.cc IPL4asp_discovery.cc Native_FunctionDefs.cc TCCConversion.cc TCCEncoding.cc TCCInterface.cc TELNETasp_PT.cc DIAMETER_EncDec.cc DIAMETER_CodecPort_CtrlFunctDef.cc "
+
+export CPPFLAGS_TTCN3=""
+
+../regen-makefile.sh DIAMETER_Tests.ttcn $FILES
+
+sed -i -e 's/^LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lfftranscode -lgnutls/' Makefile
diff --git a/diameter/sctptest.c b/diameter/sctptest.c
new file mode 100644
index 00000000..2e56c1ae
--- /dev/null
+++ b/diameter/sctptest.c
@@ -0,0 +1,220 @@
+/*
+ * Simple SCTP test program, original version by Daniel Mack
+ * at https://gist.github.com/zonque/7d03568eab14a2bb57cb
+ *
+ * Modified in 2020 by Harald Welte <laforge@gnumonks.org> for
+ * - DATA chunk rate testing.
+ * - initial support for userspace SCTP stack testing
+ *
+ * Compile:
+ *
+ * gcc sctptest.c -o server -lsctp -Wall
+ * ln -s server client
+ *
+ * Invoke:
+ *
+ * ./client
+ * ./server
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#define HAVE_KERNEL_SCTP
+
+#ifdef HAVE_KERNEL_SCTP
+#include <netinet/sctp.h>
+#define ext_socket socket
+#define ext_bind bind
+#define ext_setsockopt setsockopt
+#define ext_listen listen
+#define ext_accept accept
+#define ext_close close
+#define ext_connect connect
+#else
+/* sctplib + socketapi */
+#include <ext_socket.h>
+#include <sctp.h>
+#endif
+
+#define MY_PORT_NUM 62324
+
+/* compute differece between two timespec */
+static void timespec_diff(const struct timespec *start, const struct timespec *stop,
+ struct timespec *result)
+{
+ if ((stop->tv_nsec - start->tv_nsec) < 0) {
+ result->tv_sec = stop->tv_sec - start->tv_sec - 1;
+ result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
+ } else {
+ result->tv_sec = stop->tv_sec - start->tv_sec;
+ result->tv_nsec = stop->tv_nsec - start->tv_nsec;
+ }
+}
+
+static void die(const char *s) {
+ perror(s);
+ exit(1);
+}
+
+static void server(int argc, char **argv)
+{
+ struct sockaddr_in servaddr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_ANY),
+ .sin_port = htons(MY_PORT_NUM),
+ };
+ struct sctp_initmsg initmsg = {
+ .sinit_num_ostreams = 5,
+ .sinit_max_instreams = 5,
+ .sinit_max_attempts = 4,
+ };
+ struct sctp_sndrcvinfo sndrcvinfo;
+ int listen_fd, conn_fd, flags, ret, in;
+
+ listen_fd = ext_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
+ if (listen_fd < 0)
+ die("socket");
+
+ ret = ext_bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
+ if (ret < 0)
+ die("bind");
+
+ ret = ext_setsockopt(listen_fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
+ if (ret < 0)
+ die("setsockopt");
+
+ ret = ext_listen(listen_fd, initmsg.sinit_max_instreams);
+ if (ret < 0)
+ die("listen");
+
+ for (;;) {
+ char buffer[1024];
+ unsigned int num_chunks_rcvd;
+
+ printf("Waiting for connection\n");
+ fflush(stdout);
+
+ conn_fd = ext_accept(listen_fd, (struct sockaddr *) NULL, NULL);
+ if(conn_fd < 0)
+ die("accept()");
+
+ printf("New client connected\n");
+ fflush(stdout);
+ num_chunks_rcvd = 0;
+
+ while (1) {
+ in = sctp_recvmsg(conn_fd, buffer, sizeof(buffer), NULL, 0, &sndrcvinfo, &flags);
+ if (in <= 0)
+ break;
+ num_chunks_rcvd++;
+ }
+
+ printf("Server: Received %u chunks, closing\n", num_chunks_rcvd);
+ fflush(stdout);
+
+ ext_close(conn_fd);
+ }
+}
+
+static void client(int argc, char **argv) {
+ struct sockaddr_in servaddr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(MY_PORT_NUM),
+ .sin_addr.s_addr = inet_addr("127.0.0.1"),
+ };
+ struct timespec ts_start, ts_stop, ts_diff;
+ uint8_t *payload;
+ unsigned int num_chunks = 10000;
+ unsigned int chunksize = 150;
+ int nodelay = 0;
+ int conn_fd, ret;
+
+ while (1) {
+ int option_index = 0, c;
+ const struct option long_options[] = {
+ { "num-chunks", 1, 0, 'n' },
+ { "chunk-size", 1, 0, 's' },
+ { "sctp-nodelay", 0, 0, 'd' },
+ { 0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "n:s:d", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'n':
+ num_chunks = atoi(optarg);
+ break;
+ case 's':
+ chunksize = atoi(optarg);
+ break;
+ case 'd':
+ nodelay = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ printf("About to send %u chunks of each %u bytes\n", num_chunks, chunksize);
+
+ payload = malloc(chunksize);
+ if (!payload)
+ die("malloc()");
+
+ conn_fd = ext_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
+ if (conn_fd < 0)
+ die("socket()");
+
+ ret = ext_setsockopt(conn_fd, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay));
+ if (ret < 0)
+ die("setsockopt(SCTP_NODELAY)");
+
+ ret = ext_connect(conn_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
+ if (ret < 0)
+ die("connect()");
+
+ ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts_start);
+ if (ret < 0)
+ die("clock_gettime()");
+
+ for (int i = 0; i < num_chunks; i++) {
+ ret = sctp_sendmsg(conn_fd, payload, chunksize, NULL, 0, 0, 0, 0, 0, 0 );
+ if (ret < 0)
+ die("sctp_sendmsg");
+ }
+
+ ret = clock_gettime(CLOCK_MONOTONIC_RAW, &ts_stop);
+ if (ret < 0)
+ die("clock_gettime()");
+ timespec_diff(&ts_start, &ts_stop, &ts_diff);
+ float diff_f = (float)ts_diff.tv_sec + (float)ts_diff.tv_nsec/1000000000.0;
+ printf("%u DATA chunks of %u bytes each in %5.2f seconds: %5.2f DATA chunks per second\n",
+ num_chunks, chunksize, diff_f, (float)num_chunks/diff_f);
+
+ close(conn_fd);
+
+}
+
+int main(int argc, char **argv) {
+
+ if (strstr(basename(argv[0]), "server"))
+ server(argc, argv);
+ else
+ client(argc, argv);
+
+ return 0;
+}