WIP: DIAMETER performance testing
Change-Id: I7e6e4fdf3252b0a05f13eb85c8a84cc3c32b550e
This commit is contained in:
parent
c3c6ee6c63
commit
36fbac125b
|
@ -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
|
|
@ -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]
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue