From: Ondrej Lichtner <olichtne(a)redhat.com>
Implements TestModule classes for the IperfClient and IperfServer that
can be used to measure network performance. Class parameters map
directly to command line arguments of the iperf3 utility, the PASS/FAIL
of the client or server jobs indicates whether or not the throughput
measurement was succesful, no check for 0 or baseline is made by the
TestModules.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Tests/Iperf.py | 147 +++++++++++++++++++++++++++++++++++++++++
lnst/Tests/__init__.py | 1 +
2 files changed, 148 insertions(+)
create mode 100644 lnst/Tests/Iperf.py
diff --git a/lnst/Tests/Iperf.py b/lnst/Tests/Iperf.py
new file mode 100644
index 0000000..ec85f3b
--- /dev/null
+++ b/lnst/Tests/Iperf.py
@@ -0,0 +1,147 @@
+import logging
+import errno
+import re
+import signal
+import time
+import subprocess
+import json
+from lnst.Common.TestModule import BaseTestModule, TestModuleError
+from lnst.Common.Parameters import IntParam, IpParam, StrParam, Param, BoolParam
+from lnst.Common.Parameters import HostnameParam
+from lnst.Common.Utils import is_installed
+
+class IperfBase(BaseTestModule):
+ def run(self):
+ self._res_data = {}
+ if not is_installed("iperf3"):
+ self._res_data["msg"] = "Iperf is not installed on this
machine!"
+ logging.error(self._res_data["msg"])
+ return False
+
+ cmd = self._compose_cmd()
+
+ logging.debug("compiled command: %s" % cmd)
+ logging.debug("running as {} ...".format(self._role))
+
+ server = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, close_fds=True)
+
+ try:
+ stdout, stderr = server.communicate()
+ except KeyboardInterrupt:
+ pass
+
+ try:
+ self._res_data["data"] = json.loads(stdout)
+ except:
+ self._res_data["data"] = stdout
+
+ self._res_data["stderr"] = stderr
+
+ if stderr != "":
+ self._res_data["msg"] = "errors reported by iperf"
+ logging.error(self._res_data["msg"])
+ logging.error(self._res_data["stderr"])
+ return False
+
+ if server.returncode > 0:
+ self._res_data["msg"] = "{} returncode = {}".format(
+ self._role, server.returncode)
+ logging.error(self._res_data["msg"])
+ return False
+
+ return True
+
+class IperfServer(IperfBase):
+ bind = HostnameParam()
+ port = IntParam()
+ cpu_bind = IntParam()
+ opts = StrParam()
+ oneoff = BoolParam(default=False)
+
+ _role = "server"
+ def _compose_cmd(self):
+ bind = ""
+ port = ""
+
+ if "bind" in self.params:
+ bind = "-B {}".format(self.params.bind)
+
+ if "port" in self.params:
+ port = "-p {}".format(self.params.port)
+
+ if "cpu_bind" in self.params:
+ cpu = "-A {:d}".format(self.params.cpu_bind)
+ else:
+ cpu = ""
+
+ if "oneoff" in self.params and self.params.oneoff:
+ oneoff = "-1"
+
+ cmd = "iperf3 -s {bind} -J {port} {cpu} {oneoff} {opts}".format(
+ bind=bind, port=port, cpu=cpu, oneoff=oneoff,
+ opts=self.params.opts if "opts" in self.params else
"")
+
+ return cmd
+
+
+class IperfClient(IperfBase):
+ server = HostnameParam(mandatory=True)
+ duration = IntParam(default=10)
+ udp = BoolParam(default=False)
+ sctp = BoolParam(default=False)
+ port = IntParam()
+ blksize = IntParam()
+ mss = IntParam()
+ cpu_bind = IntParam()
+ parallel = IntParam()
+ opts = StrParam()
+
+ _role = "client"
+
+ def __init__(self, **kwargs):
+ super(IperfClient, self).__init__(**kwargs)
+
+ if self.params.udp and self.params.sctp:
+ raise TestModuleError("Parameters udp and sctp are mutually
exclusive!")
+
+ def _compose_cmd(self):
+ port = ""
+
+ if "port" in self.params:
+ port = "-p {:d}".format(self.params.port)
+
+ if "blksize" in self.params:
+ blksize = "-l {:d}".format(self.params.blksize)
+ else:
+ blksize = ""
+
+ if "mss" in self.params:
+ mss = "-M {:d}".format(self.params.mss)
+ else:
+ mss = ""
+
+ if "cpu_bind" in self.params:
+ cpu = "-A {:d}".format(self.params.cpu_bind)
+ else:
+ cpu = ""
+
+ if "parallel" in self.params:
+ parallel = "-P {:d}".format(self.params.parallel)
+
+ if self.params.udp:
+ test = "--udp"
+ elif self.params.sctp:
+ test = "--sctp"
+ else:
+ test = ""
+
+ cmd = ("iperf3 -c {server} -J -t {duration}"
+ " {cpu} {test} {mss} {blksize} {parallel}"
+ " {opts}".format(
+ server=self.params.server, duration=self.params.duration,
+ cpu=cpu, test=test, mss=mss, blksize=blksize,
+ parallel=parallel,
+ opts=self.params.opts if "opts" in self.params else
""))
+
+ return cmd
diff --git a/lnst/Tests/__init__.py b/lnst/Tests/__init__.py
index 69b757a..bca4893 100644
--- a/lnst/Tests/__init__.py
+++ b/lnst/Tests/__init__.py
@@ -13,5 +13,6 @@ olichtne(a)redhat.com (Ondrej Lichtner)
"""
from lnst.Tests.IcmpPing import IcmpPing
+from lnst.Tests.Iperf import IperfClient, IperfServer
#TODO add support for test classes from lnst-ctl.conf
--
2.17.0