From 8a72586835c8852fb3cded82ee3432e07754dce7 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 26 Oct 2018 15:54:28 +0200 Subject: [PATCH] Introduce iperf3 testing infrastructure Change-Id: I6ff6bef14feb535d98ca41b9788700d699e1ef1e --- src/osmo_gsm_tester/iperf3.py | 107 ++++++++++++++++++++++++++++++++++ src/osmo_gsm_tester/suite.py | 8 ++- suites/gprs/iperf3.py | 74 +++++++++++++++++++++++ suites/gprs/suite.conf | 2 +- 4 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 src/osmo_gsm_tester/iperf3.py create mode 100755 suites/gprs/iperf3.py diff --git a/src/osmo_gsm_tester/iperf3.py b/src/osmo_gsm_tester/iperf3.py new file mode 100644 index 00000000..8141fea9 --- /dev/null +++ b/src/osmo_gsm_tester/iperf3.py @@ -0,0 +1,107 @@ +# osmo_gsm_tester: specifics for running an iperf3 client and server +# +# Copyright (C) 2018 by sysmocom - s.f.m.c. GmbH +# +# Author: Pau Espin Pedrol +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import json + +from . import log, util, process, pcap_recorder + +DEFAULT_SRV_PORT = 5003 + +class IPerf3Server(log.Origin): + + def __init__(self, suite_run, ip_address): + super().__init__(log.C_RUN, 'iperf3-srv_%s' % ip_address.get('addr')) + self.run_dir = None + self.config_file = None + self.process = None + self.suite_run = suite_run + self.ip_address = ip_address + self._port = DEFAULT_SRV_PORT + + def start(self): + self.log('Starting iperf3-srv') + self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name())) + + pcap_recorder.PcapRecorder(self.suite_run, self.run_dir.new_dir('pcap'), None, + 'host %s and port not 22' % self.addr()) + + self.log_file = self.run_dir.new_file('iperf3_srv.json') + self.process = process.Process(self.name(), self.run_dir, + ('iperf3', '-s', '-B', self.addr(), + '-p', str(self._port), '-J', + '--logfile', os.path.abspath(self.log_file)), + env={}) + self.suite_run.remember_to_stop(self.process) + self.process.launch() + + def stop(self): + self.suite_run.stop_process(self.process) + + def get_results(self): + with open(self.log_file) as f: + data = json.load(f) + return data + + def addr(self): + return self.ip_address.get('addr') + + def port(self): + return self._port + + def running(self): + return not self.process.terminated() + + def create_client(self): + return IPerf3Client(self.suite_run, self) + +class IPerf3Client(log.Origin): + + def __init__(self, suite_run, iperf3srv): + super().__init__(log.C_RUN, 'iperf3-cli_%s' % iperf3srv.addr()) + self.run_dir = None + self.config_file = None + self.process = None + self.server = iperf3srv + self.suite_run = suite_run + + def run_test(self, netns=None): + self.log('Starting iperf3-client connecting to %s:%d' % (self.server.addr(), self.server.port())) + self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name())) + + pcap_recorder.PcapRecorder(self.suite_run, self.run_dir.new_dir('pcap'), None, + 'host %s and port not 22' % self.server.addr(), netns) + + self.log_file = self.run_dir.new_file('iperf3_cli.json') + popen_args = ('iperf3', '-c', self.server.addr(), + '-p', str(self.server.port()), '-J', + '--logfile', os.path.abspath(self.log_file)) + if netns: + self.process = process.NetNSProcess(self.name(), self.run_dir, netns, popen_args, env={}) + else: + self.process = process.Process(self.name(), self.run_dir, popen_args, env={}) + process.run_proc_sync(self.process) + return self.get_results() + + def get_results(self): + with open(self.log_file) as f: + data = json.load(f) + return data + +# vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py index 67ddefdc..e5ac9a82 100644 --- a/src/osmo_gsm_tester/suite.py +++ b/src/osmo_gsm_tester/suite.py @@ -23,7 +23,7 @@ import time import pprint from . import config, log, util, resource, test from .event_loop import MainLoop -from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, modem, esme, osmocon, ms_driver +from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, modem, esme, osmocon, ms_driver, iperf3 class Timeout(Exception): pass @@ -349,6 +349,12 @@ class SuiteRun(log.Origin): self.register_for_cleanup(osmocon_obj) return osmocon_obj + def iperf3srv(self, ip_address=None): + if ip_address is None: + ip_address = self.ip_address() + iperf3srv_obj = iperf3.IPerf3Server(self, ip_address) + return iperf3srv_obj + def msisdn(self): msisdn = self.resources_pool.next_msisdn(self) self.log('using MSISDN', msisdn) diff --git a/suites/gprs/iperf3.py b/suites/gprs/iperf3.py new file mode 100755 index 00000000..a1dd62c4 --- /dev/null +++ b/suites/gprs/iperf3.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +def print_results(cli_res, srv_res): + cli_sent = cli_res['end']['sum_sent'] + cli_recv = cli_res['end']['sum_received'] + print("RESULT client:") + print("\tSEND: %d KB, %d kbps, %d seconds (%d retrans)" % (cli_sent['bytes']/1000, cli_sent['bits_per_second']/1000, cli_sent['seconds'], cli_sent['retransmits'])) + print("\tRECV: %d KB, %d kbps, %d seconds" % (cli_recv['bytes']/1000, cli_recv['bits_per_second']/1000, cli_recv['seconds'])) + print("RESULT server:") + print("\tSEND: %d KB, %d kbps, %d seconds" % (cli_sent['bytes']/1000, cli_sent['bits_per_second']/1000, cli_sent['seconds'])) + print("\tRECV: %d KB, %d kbps, %d seconds" % (cli_recv['bytes']/1000, cli_recv['bits_per_second']/1000, cli_recv['seconds'])) + +hlr = suite.hlr() +bts = suite.bts() +pcu = bts.pcu() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +ggsn = suite.ggsn() +sgsn = suite.sgsn(hlr, ggsn) +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +ms = suite.modem() +iperf3srv = suite.iperf3srv() +iperf3cli = iperf3srv.create_client() + +bsc.bts_add(bts) +sgsn.bts_add(bts) + +print('start iperfv3 server...') +iperf3srv.start() + +print('start network...') +hlr.start() +stp.start() +ggsn.start() +sgsn.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() + +bts.start() +wait(bsc.bts_is_connected, bts) +print('Waiting for bts to be ready...') +wait(bts.ready_for_pcu) +pcu.start() + +hlr.subscriber_add(ms) + +ms.connect(msc.mcc_mnc()) +ms.attach() + +ms.log_info() + +print('waiting for modems to attach...') +wait(ms.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms) + +print('waiting for modems to attach to data services...') +wait(ms.is_attached) + +# We need to use inet46 since ofono qmi only uses ipv4v6 eua (OS#2713) +ctx_id_v4 = ms.activate_context(apn='inet46', protocol=ms.CTX_PROT_IPv4) +print("Setting up data plan for %r" % repr(ctx_id_v4)) +ms.setup_context_data_plane(ctx_id_v4) + +print("Running iperf3 client to %s through %r" % (iperf3srv.addr(),repr(ctx_id_v4))) +res = iperf3cli.run_test(ms.netns()) +iperf3srv.stop() +print_results(res, iperf3srv.get_results()) + +ms.deactivate_context(ctx_id_v4) diff --git a/suites/gprs/suite.conf b/suites/gprs/suite.conf index 1590b7da..a24bc5d0 100644 --- a/suites/gprs/suite.conf +++ b/suites/gprs/suite.conf @@ -1,6 +1,6 @@ resources: ip_address: - - times: 8 # msc, bsc, hlr, stp, mgw*2, sgsn, ggsn + - times: 9 # msc, bsc, hlr, stp, mgw*2, sgsn, ggsn, iperf3srv bts: - times: 1 modem: