In order to be loaded properly, each test module was required to use
'Test' prefix in its name. However, in recipes, the prefix was never
used.
This was justified when the modules were mixed with other code. However,
this hasn't been the case for quite a while now. The modules are kept in
their own directory, so requiring a prefix is not necessary any more.
This patch removes the prefixes from module names.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
lnst/Common/NetTestCommand.py | 2 +-
lnst/Common/ResourceCache.py | 2 +-
lnst/Controller/NetTestController.py | 2 +-
test_modules/DummyFailing.py | 19 ++++
test_modules/Icmp6Ping.py | 70 +++++++++++++++
test_modules/IcmpPing.py | 68 ++++++++++++++
test_modules/Iperf.py | 154 +++++++++++++++++++++++++++++++
test_modules/Multicast.py | 132 +++++++++++++++++++++++++++
test_modules/NetCat.py | 69 ++++++++++++++
test_modules/PacketAssert.py | 169 +++++++++++++++++++++++++++++++++++
test_modules/PktCounter.py | 72 +++++++++++++++
test_modules/PktgenTx.py | 93 +++++++++++++++++++
test_modules/TestDummyFailing.py | 19 ----
test_modules/TestIcmp6Ping.py | 70 ---------------
test_modules/TestIcmpPing.py | 68 --------------
test_modules/TestIperf.py | 154 -------------------------------
test_modules/TestMulticast.py | 132 ---------------------------
test_modules/TestNetCat.py | 69 --------------
test_modules/TestPacketAssert.py | 169 -----------------------------------
test_modules/TestPktCounter.py | 72 ---------------
test_modules/TestPktgenTx.py | 93 -------------------
21 files changed, 849 insertions(+), 849 deletions(-)
create mode 100644 test_modules/DummyFailing.py
create mode 100644 test_modules/Icmp6Ping.py
create mode 100644 test_modules/IcmpPing.py
create mode 100644 test_modules/Iperf.py
create mode 100644 test_modules/Multicast.py
create mode 100644 test_modules/NetCat.py
create mode 100644 test_modules/PacketAssert.py
create mode 100644 test_modules/PktCounter.py
create mode 100644 test_modules/PktgenTx.py
delete mode 100644 test_modules/TestDummyFailing.py
delete mode 100644 test_modules/TestIcmp6Ping.py
delete mode 100644 test_modules/TestIcmpPing.py
delete mode 100644 test_modules/TestIperf.py
delete mode 100644 test_modules/TestMulticast.py
delete mode 100644 test_modules/TestNetCat.py
delete mode 100644 test_modules/TestPacketAssert.py
delete mode 100644 test_modules/TestPktCounter.py
delete mode 100644 test_modules/TestPktgenTx.py
diff --git a/lnst/Common/NetTestCommand.py b/lnst/Common/NetTestCommand.py
index 9e1708d..abd7400 100644
--- a/lnst/Common/NetTestCommand.py
+++ b/lnst/Common/NetTestCommand.py
@@ -243,7 +243,7 @@ def NetTestCommandTest(command, resource_table):
raise Exception(msg)
module_path = resource_table["module"][test_name]
- module_name = "Test%s" % test_name
+ module_name = test_name
module = imp.load_source(module_name, module_path)
test_class = getattr(module, module_name)
diff --git a/lnst/Common/ResourceCache.py b/lnst/Common/ResourceCache.py
index a4ab955..8719b09 100644
--- a/lnst/Common/ResourceCache.py
+++ b/lnst/Common/ResourceCache.py
@@ -102,7 +102,7 @@ class ResourceCache(object):
entry_path = "%s/%s" % (entry_dir, os.path.basename(filepath))
if entry_type == "module":
- filename = "Test%s.py" % entry_name
+ filename = "%s.py" % entry_name
shutil.move(entry_path, "%s/%s" % (entry_dir, filename))
elif entry_type == "tools":
filename = entry_name
diff --git a/lnst/Controller/NetTestController.py b/lnst/Controller/NetTestController.py
index 85253ed..e55c36d 100644
--- a/lnst/Controller/NetTestController.py
+++ b/lnst/Controller/NetTestController.py
@@ -663,7 +663,7 @@ class NetTestController:
for f in files:
test_path = os.path.abspath("%s/%s" % (dir_name, f))
if os.path.isfile(test_path):
- match = re.match("Test(.+)\.py$", f)
+ match = re.match("(.+)\.py$", f)
if match:
test_name = match.group(1)
test_hash = md5sum(test_path)
diff --git a/test_modules/DummyFailing.py b/test_modules/DummyFailing.py
new file mode 100644
index 0000000..fed9fe4
--- /dev/null
+++ b/test_modules/DummyFailing.py
@@ -0,0 +1,19 @@
+"""
+This module defines dummy failing test
+
+Copyright 2011 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jpirko(a)redhat.com (Jiri Pirko)
+"""
+
+import logging
+from lnst.Common.TestsCommon import TestGeneric
+
+class DummyFailing(TestGeneric):
+ def run(self):
+ res_data = {"msg": "what else did you expect?"}
+ return self.set_fail(res_data)
diff --git a/test_modules/Icmp6Ping.py b/test_modules/Icmp6Ping.py
new file mode 100644
index 0000000..3c5c994
--- /dev/null
+++ b/test_modules/Icmp6Ping.py
@@ -0,0 +1,70 @@
+__author__ = """
+jpirko(a)redhat.com (Jiri Pirko)
+jmalanik(a)redhat.com (Jan Malanik)
+jtluka(a)redhat.com (Jan Tluka)
+"""
+
+
+import logging
+import re
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.ExecCmd import exec_cmd
+
+
+class Icmp6Ping(TestGeneric):
+ def compose_cmd(self):
+ addr = self.get_mopt("addr", opt_type="addr")
+ cmd = "ping6 %s" % addr
+
+ iface = self.get_opt("iface")
+ if iface:
+ cmd += " -I %s" % iface
+
+ count = self.get_opt("count")
+ if count:
+ cmd += " -c %s" % count
+
+ interval = self.get_opt("interval")
+ if interval:
+ cmd += " -i %s" % interval
+
+ return cmd
+
+ def run(self):
+ cmd = self.compose_cmd()
+ logging.debug("%s" % cmd)
+
+ limit_rate = self.get_opt("limit_rate ", default=80)
+ data_stdout = exec_cmd(cmd, die_on_err=False)[0]
+
+ stat_pttr1 = r'(\d+) packets transmitted, (\d+) received'
+ stat_pttr2 = r'rtt min/avg/max/mdev =
(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
+
+ match = re.search(stat_pttr1, data_stdout)
+ if not match:
+ res_data = {"msg": "expected pattern not found"}
+ return self.set_fail(res_data)
+
+ trans_pkts, recv_pkts = match.groups()
+ rate = int(round((float(recv_pkts) / float(trans_pkts)) * 100))
+ logging.debug("Transmitted \"%s\", received \"%s\",
" \
+ "rate \"%d%%\", limit_rate \"%d%%\"" \
+ % (trans_pkts, recv_pkts, rate, limit_rate ))
+
+ res_data = {"rate": rate,
+ "limit_rate": limit_rate}
+
+ match = re.search(stat_pttr2, data_stdout)
+ if match:
+ tmin, tavg, tmax, tmdev = [float(x) for x in match.groups()]
+ logging .debug("rtt min \"%.3f\", avg \"%.3f\", max
\"%.3f\", "
+ "mdev \"%.3f\"" % (tmin, tavg, tmax, tmdev))
+
+ res_data["rtt_min"] = tmin
+ res_data["rtt_max"] = tmax
+
+ if rate < limit_rate :
+ res_data["msg"] = "rate is lower that limit"
+ return self.set_fail(res_data)
+
+ return self.set_pass(res_data)
diff --git a/test_modules/IcmpPing.py b/test_modules/IcmpPing.py
new file mode 100644
index 0000000..6f7380c
--- /dev/null
+++ b/test_modules/IcmpPing.py
@@ -0,0 +1,68 @@
+"""
+This module defines icmp ping test
+
+Copyright 2011 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jpirko(a)redhat.com (Jiri Pirko)
+"""
+
+import logging
+import re
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.ExecCmd import exec_cmd
+
+class IcmpPing(TestGeneric):
+ def _compose_cmd(self):
+ addr = self.get_mopt("addr", opt_type="addr")
+ cmd = "ping %s" % addr
+ count = self.get_opt("count")
+ if count:
+ cmd += " -c %s" % count
+ interval = self.get_opt("interval")
+ if interval:
+ cmd += " -i %s" % interval
+ iface = self.get_opt("iface")
+ if iface:
+ cmd += " -I %s" % iface
+ return cmd
+
+ def run(self):
+ cmd = self._compose_cmd()
+ limit_rate = self.get_opt("limit_rate", default=80)
+
+ data_stdout = exec_cmd(cmd, die_on_err=False)[0]
+ stat_pttr1 = r'(\d+) packets transmitted, (\d+) received'
+ stat_pttr2 = r'rtt min/avg/max/mdev =
(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
+
+ match = re.search(stat_pttr1, data_stdout)
+ if not match:
+ res_data = {"msg": "expected pattern not found"}
+ return self.set_fail(res_data)
+
+ trans_pkts, recv_pkts = match.groups()
+ rate = int(round((float(recv_pkts) / float(trans_pkts)) * 100))
+ logging.debug("Transmitted \"%s\", received \"%s\",
"
+ "rate \"%d%%\", limit_rate \"%d%%\""
+ % (trans_pkts, recv_pkts, rate, limit_rate))
+
+ res_data = {"rate": rate,
+ "limit_rate": limit_rate}
+
+ match = re.search(stat_pttr2, data_stdout)
+ if match:
+ tmin, tavg, tmax, tmdev = [float(x) for x in match.groups()]
+ logging.debug("rtt min \"%.3f\", avg \"%.3f\", max
\"%.3f\", "
+ "mdev \"%.3f\"" % (tmin, tavg, tmax, tmdev))
+
+ res_data["rtt_min"] = tmin
+ res_data["rtt_max"] = tmax
+
+ if rate < limit_rate:
+ res_data["msg"] = "rate is lower that limit"
+ return self.set_fail(res_data)
+
+ return self.set_pass(res_data)
diff --git a/test_modules/Iperf.py b/test_modules/Iperf.py
new file mode 100644
index 0000000..2982cff
--- /dev/null
+++ b/test_modules/Iperf.py
@@ -0,0 +1,154 @@
+"""
+This module defines iperf test
+"""
+
+__author__ = """
+jtluka(a)redhat.com (Jan Tluka)
+"""
+
+import logging
+import time
+import errno
+import re
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.ExecCmd import exec_cmd
+from lnst.Common.ShellProcess import ShellProcess
+
+class Iperf(TestGeneric):
+ def _compose_iperf_cmd(self, role):
+ iperf_options = self.get_opt("iperf_opts")
+ if iperf_options is None:
+ iperf_options = ""
+
+ cmd = ""
+ if role == "client":
+ iperf_server = self.get_mopt("iperf_server",
opt_type="addr")
+ cmd = "iperf --%s %s -t %s %s" % (role, iperf_server,
self.duration, iperf_options)
+ elif role == "server":
+ bind = self.get_opt("bind", opt_type="addr")
+ if bind != None:
+ cmd = "iperf --%s -B %s %s" % (role, bind, iperf_options)
+ else:
+ cmd = "iperf --%s %s" % (role, iperf_options)
+
+ return cmd
+
+ def _rate_over_threshold(self, rate):
+ # convert rate to the same unit as threshold unit
+ pattern = "(\d*(\.\d*){0,1})\s*([ kMGT])bits\/sec"
+
+ # parse threshold value
+ r1 = re.match(pattern, self.threshold)
+ thr_units = r1.group(3)
+
+ # parse measured rate value
+ r2 = re.match(pattern, rate)
+ rate_units = r2.group(3)
+
+ thr_val = float(r1.group(1))
+
+ rate_val = float(r2.group(1))
+
+ # do the conversion of rate units
+ if thr_units != rate_units:
+ # remove any k,M,G,T from measured rate
+ if rate_units == 'k':
+ rate_val *= 1000
+ elif rate_units == 'M':
+ rate_val *= 1000*1000
+ elif rate_val == 'G':
+ rate_val *= 1000*1000*1000
+
+ # divide by k or M or G if present
+ if thr_units == 'k':
+ rate_val /= 1000
+ elif thr_units == 'M':
+ rate_val /= 1000*1000
+ elif thr_units == 'G':
+ rate_val /= 1000*1000*1000
+
+ if rate_val < thr_val:
+ logging.info("measured rate is below threshold! " \
+ "(measured: %s < threshold: %s)" % \
+ (rate, self.threshold))
+ return False
+
+ return True
+
+ def run_client(self, cmd):
+ client = ShellProcess(cmd)
+ try:
+ client.wait()
+ except OSError as e:
+ # we got interrupted, let's gather data
+ if e.errno == errno.EINTR:
+ client.kill()
+
+ output = client.read_nonblocking()
+
+ if re.search("connect failed:", output):
+ logging.info("Iperf connection failed!")
+ return (False, "Iperf connection failed!")
+
+ m = re.search("\[[^0-9]*[0-9]*\]\s*0.0-\s*\d*\.\d sec\s*\d*(\.\d*){0,1}\s*[
kGMT]Bytes\s*(\d*(\.\d*){0,1}\s*[ kGMT]bits\/sec)", output)
+ if m is None:
+ logging.info("Could not get performance throughput!")
+ return (False, "Could not get performance throughput!")
+
+ rate = m.group(2)
+ if self.threshold is not None:
+ # check if expected threshold is reached
+ result = self._rate_over_threshold(rate)
+ if result:
+ return (True, "Measured rate (%s) is over threshold (%s)." %
+ (rate, self.threshold))
+ else:
+ return (False, "Measured rate (%s) is below threshold (%s)!" %
+ (rate, self.threshold))
+ else:
+ return True, "Measured rate: %s" % rate
+
+ def run_server(self, cmd):
+ server = ShellProcess(cmd)
+
+ if not self._keep_server_running:
+ time.sleep(float(self.duration))
+ server.read_nonblocking()
+ server.kill()
+ else:
+ try:
+ server.wait()
+ except OSError as e:
+ if e.errno == errno.EINTR:
+ server.kill()
+
+ server.read_nonblocking()
+
+ def run(self):
+ self._keep_server_running = True
+
+ self.duration = self.get_opt("duration")
+ if self.duration is None:
+ self.duration = 60 # for client purposes
+ else:
+ self._keep_server_running = False # for server purposes
+
+ self.threshold = self.get_opt("threshold")
+
+ role = self.get_mopt("role")
+ cmd = self._compose_iperf_cmd(role)
+ logging.debug("compiled command: %s" % cmd)
+
+ if role == "server":
+ logging.debug("running as server ...")
+ self.run_server(cmd)
+
+ return self.set_pass()
+ elif role == "client":
+ logging.debug("running as client ...")
+ (rv, message) = self.run_client(cmd)
+ res_data = {"msg": message}
+ if rv == False:
+ return self.set_fail(res_data)
+
+ return self.set_pass(res_data)
diff --git a/test_modules/Multicast.py b/test_modules/Multicast.py
new file mode 100644
index 0000000..4865957
--- /dev/null
+++ b/test_modules/Multicast.py
@@ -0,0 +1,132 @@
+"""
+Wrapper for executing the multicast test tools in LNST
+
+Copyright 2012 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+rpazdera(a)redhat.com (Radek Pazdera)
+"""
+
+import logging
+import re
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.NetTestCommand import CommandException
+from lnst.Common.ExecCmd import exec_cmd
+
+class Multicast(TestGeneric):
+ """ Wrapper for executing the multicast test tools in LNST
+
+ Running this test executes specified test setup from
+ multicast tools and evaluates the results. The behavior
+ is defined entirely by behavior of the selected setup.
+
+ """
+
+ _conditions = {}
+
+ @staticmethod
+ def _remove_mask(address_in_string):
+ """ Remove mask suffix from the IP address """
+ if address_in_string != None:
+ return address_in_string.split('/')[0]
+ else:
+ return address_in_string
+
+ def _compose_cmd(self):
+ """ Setup a command from the recipe options """
+ cmd = ""
+ opts = {}
+
+ setup = self.get_mopt("setup")
+ opts["multicast_address"] =
self._remove_mask(self.get_opt("address"))
+ opts["port"] = self.get_opt("port")
+ opts["interface"] =
self._remove_mask(self.get_opt("interface"))
+ opts["duration"] = self.get_opt("duration")
+
+ # sender-specific
+ opts["loop"] = self.get_opt("loop")
+ opts["ttl"] = self.get_opt("ttl")
+ opts["delay"] = self.get_opt("delay")
+
+ # receiver-specific
+ opts["source_address"] =
self._remove_mask(self.get_opt("source"))
+
+ # igmp-specific
+ opts["query_type"] = self.get_opt("query_type")
+ opts["dest_address"] = self.get_opt("dest_address")
+ opts["max_resp_time"] = self.get_opt("max_resp_time")
+
+ cmd = "./{0} ".format(setup)
+
+ for optname, optval in opts.iteritems():
+ if optval != None:
+ cmd += "--{0} \"{1}\" ".format(optname, optval)
+
+ return cmd
+
+ def _evaluate_result(self, name, value):
+ """ Check if the result meets required conditions
"""
+ if name in self._conditions:
+ try:
+ float(value)
+ except ValueError:
+ value = '"' + value + '"'
+
+ result = eval(value + self._conditions[name])
+ logging.info("Condition evaluated {2}: {0}{1}".format(name,
+ self._conditions[name], str(result)))
+
+ return result
+ else:
+ return True
+
+ def _prepare_conditions(self):
+ """ Search for var names in conditions """
+ varname_r = r"[a-zA-Z_][a-zA-Z0-9_]*"
+
+ conds = self.get_multi_opt("condition")
+ logging.debug(conds)
+ for cond in conds:
+ if cond == None:
+ continue
+ logging.debug(cond)
+ match = re.match(varname_r, cond)
+ if match:
+ name = match.group(0)
+ self._conditions[name] = cond.replace(name, "")
+ else:
+ raise CommandException(self)
+
+
+ def run(self):
+ self._prepare_conditions()
+
+ setup_name = self.get_mopt("setup")
+ logging.info("Started Multicast test setup {0}".format(setup_name))
+
+ cmd = self._compose_cmd()
+ data_stdout = self.exec_from("multicast", cmd, die_on_err=False,
+ log_outputs=False)[0]
+
+ res = {}
+
+ # line format matches name=value pairs with optional
+ # double quotes around the value
+ line_format_r = r"([a-zA-Z0-9_ ]+)=\"?([a-zA-Z0-9_ ]*)\"?"
+
+ for line in data_stdout.split("\n"):
+ match = re.search(line_format_r, line)
+ if match:
+ name = match.group(1).strip()
+ value = match.group(2).strip()
+
+ res[name] = value
+ logging.info("Test result: {0} = {1}".format(name, value))
+ if not self._evaluate_result(name, value):
+ res["msg"] = "Conditions not met!"
+ return self.set_fail(res)
+
+ return self.set_pass(res)
diff --git a/test_modules/NetCat.py b/test_modules/NetCat.py
new file mode 100644
index 0000000..ffa4c9f
--- /dev/null
+++ b/test_modules/NetCat.py
@@ -0,0 +1,69 @@
+"""
+This module defines netcat stream test
+
+Copyright 2011 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jtluka(a)redhat.com (Jan Tluka)
+"""
+
+import re
+import time
+import logging
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.ShellProcess import ShellProcess
+
+class NetCat(TestGeneric):
+ def _get_stream(self):
+ return self.get_opt("stream", default="tcp")
+
+ def _compose_nc_cmd(self):
+ cmd = "yes | nc -v"
+
+ if self._get_stream() == "udp":
+ cmd += " -u"
+
+ ipv = self.get_opt("ipv") # IP protocol version - 4 or 6
+ if ipv:
+ cmd += " -%s" % ipv
+
+ addr = self.get_mopt("addr", opt_type="addr")
+ port = self.get_mopt("port")
+ cmd += " %s %s" % (addr, port)
+
+ return cmd
+
+ def _compose_tcpdump_cmd(self):
+ cmd = ("tcpdump -c 10 -i any %s port %s and host %s" %
+ (self._get_stream(),
+ self.get_mopt("port"),
+ self.get_mopt("addr", opt_type="addr")))
+ return cmd
+
+ def run(self):
+ nc = ShellProcess(self._compose_nc_cmd())
+
+ # check whether anything is being sent over the line
+ td = ShellProcess(self._compose_tcpdump_cmd())
+
+ try:
+ td.read_until_output_matches("10 packets captured", timeout=5)
+ except ShellProcess.ProcessTerminatedError:
+ res_data = {"msg": "tcpdump process died unexpectedly!"}
+ return self.set_fail(res_data)
+ except ShellProcess.ProcessTimeoutError:
+ res_data = {"msg": "No stream detected!"}
+ return self.set_fail(res_data)
+
+ td.kill()
+
+ duration = self.get_opt("duration", default=30)
+ time.sleep(duration)
+
+ nc.kill()
+
+ logging.info("nc stream with duration of %s secs" % duration)
+ return self.set_pass()
diff --git a/test_modules/PacketAssert.py b/test_modules/PacketAssert.py
new file mode 100644
index 0000000..c716c66
--- /dev/null
+++ b/test_modules/PacketAssert.py
@@ -0,0 +1,169 @@
+"""
+Test if packets were transfered through some interface correctly.
+This test is using tcpdump.
+
+Copyright 2012 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+rpazdera(a)redhat.com (Radek Pazdera)
+"""
+
+import logging
+import subprocess
+import re
+import signal
+from lnst.Common.TestsCommon import TestGeneric
+
+class PacketAssert(TestGeneric):
+ """ Assert for number of incomming/outgoing packets
+ Capturing backend of this class is provided by
+ tcpdump(8).
+ """
+
+ _cmd = ""
+ _tcpdump = None
+ _grep_filters = []
+
+ _min_cond = 1
+ _max_cond = None
+
+ _num_recv = 0
+
+ def _set_interrupt_handler(self):
+ signal.signal(signal.SIGINT, self._interrupt_handler)
+ signal.signal(signal.SIGTERM, self._interrupt_handler)
+
+ def _interrupt_handler(self, signum, frame):
+ """ Kill tcpdump when interrupted """
+ self._tcpdump.terminate()
+
+ tcpdump_output = self._tcpdump.stdout
+ while True:
+ try:
+ next_line = tcpdump_output.readline()
+ except IOError: # Interrupted system call
+ break
+
+ if next_line == "":
+ break
+
+ next_line = next_line.strip("\n")
+
+ if re.match("[0-9]+\:[0-9]+\:[0-9\.]+", next_line) and\
+ self.line != "":
+ self._process_captured_line(self.line)
+ self.line = next_line
+ else:
+ self.line += next_line
+ if self.line != "":
+ self._process_captured_line(self.line)
+
+
+ def _prepare_grep_filters(self):
+ """ Parse `grep_for' test options """
+ filters = self.get_multi_opt("grep_for")
+
+ for filt in filters:
+ if filt != None:
+ self._grep_filters.append(filt)
+
+ def _prepare_conditions(self):
+ """ Parse `min' and `max' """
+ min_packets = self.get_opt("min")
+ max_packets = self.get_opt("max")
+
+ if min_packets != None:
+ self._min_cond = int(min_packets)
+
+ if max_packets != None:
+ self._max_cond = int(max_packets)
+
+ def _compose_cmd(self):
+ """ Create a command from the recipe options """
+ cmd = ""
+
+ interface = self.get_mopt("interface")
+ pcap_filter = self.get_opt("filter")
+ if not pcap_filter:
+ pcap_filter = ""
+
+ cmd = "tcpdump -p -nn -i %s \"%s\"" % (interface,
pcap_filter)
+ self._cmd = cmd
+
+ def _execute_tcpdump(self):
+ """ Start tcpdump in the background """
+ cmd = self._cmd
+ proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ self._tcpdump = proc
+
+ def _process_captured_line(self, line):
+ """ Apply filters and see if the packet passed them
"""
+ if len(self._grep_filters):
+ for filt in self._grep_filters:
+ if not re.search(filt, line):
+ return
+
+ self._num_recv += 1
+
+ def _evaluate_results(self):
+ """ Compare results with the conditions """
+ num = self._num_recv
+ if num >= self._min_cond:
+ if self._max_cond != None:
+ return num <= self._max_cond
+ return True
+ return False
+
+ def run(self):
+ self._set_interrupt_handler()
+
+ self._prepare_grep_filters()
+ self._prepare_conditions()
+ self._compose_cmd()
+ self._execute_tcpdump()
+
+ logging.info("Capturing started")
+
+ self.line = ""
+ tcpdump_output = self._tcpdump.stdout
+ while True:
+ if self._tcpdump.poll() != None:
+ if self._tcpdump.returncode > 0:
+ raise Exception("tcpdump terminated with error")
+ else:
+ break
+
+ try:
+ next_line = tcpdump_output.readline()
+ except IOError: # Interrupted system call
+ continue
+
+ if next_line == "":
+ continue
+
+ next_line = next_line.strip("\n")
+
+ if re.match("[0-9]+\:[0-9]+\:[0-9\.]+", next_line) and\
+ self.line != "":
+ self._process_captured_line(self.line)
+ self.line = next_line
+ else:
+ self.line += next_line
+
+ if self.line != "":
+ self._process_captured_line(self.line)
+
+ logging.info("Capturing finished. Received %d packets",
self._num_recv)
+ res = {"received": self._num_recv,
+ "min": self._min_cond,
+ "max": self._max_cond}
+
+ if self._evaluate_results():
+ return self.set_pass(res)
+
+ res["msg"] = "PacketAssert failed!"
+ return self.set_fail(res)
diff --git a/test_modules/PktCounter.py b/test_modules/PktCounter.py
new file mode 100644
index 0000000..bb0325b
--- /dev/null
+++ b/test_modules/PktCounter.py
@@ -0,0 +1,72 @@
+"""
+This module defines packet counter implemented by iptables
+
+Copyright 2011 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jpirko(a)redhat.com (Jiri Pirko)
+"""
+
+import logging
+import re
+import os
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.ExecCmd import exec_cmd, ExecCmdFail
+
+def get_pkt_count(indev_name, dport, proto):
+ if indev_name:
+ p_indev_name = indev_name
+ else:
+ p_indev_name = "\*"
+ if proto:
+ p_proto = proto
+ if dport:
+ p_protodport = "%s dpt:%s" % (proto, dport)
+ else:
+ p_protodport = ""
+ else:
+ p_proto = "all"
+ p_protodport = ""
+ pttr =
(r'\s*(\d+)\s+\d+\s+%s\s+\-\-\s+%s\s+\*\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*%s'
+ % (p_proto, p_indev_name, p_protodport))
+ data_stdout = exec_cmd("iptables -L -v -x -n")[0]
+ match = re.search(pttr, data_stdout)
+ if not match:
+ return None
+ return match.groups()[0]
+
+class PktCounter(TestGeneric):
+ def run(self):
+ indev_name = self.get_opt("input_netdev_name")
+ dport = self.get_opt("dport")
+ proto = self.get_opt("proto")
+ params = ""
+ if indev_name:
+ params += " -i %s" % indev_name
+
+ if proto:
+ params += " -p %s" % proto
+
+ if dport:
+ params += " --dport %s" % dport
+
+ '''
+ Remove all same already existing rules
+ '''
+ while True:
+ if get_pkt_count(indev_name, dport, proto) == None:
+ break
+ exec_cmd("iptables -D INPUT%s" % params)
+
+ exec_cmd("iptables -I INPUT%s" % params)
+
+ self.wait_on_interrupt()
+
+ count = get_pkt_count(indev_name, dport, proto)
+
+ exec_cmd("iptables -D INPUT%s" % params)
+
+ return self.set_pass(res_data={"pkt_count": count})
diff --git a/test_modules/PktgenTx.py b/test_modules/PktgenTx.py
new file mode 100644
index 0000000..cf35b5f
--- /dev/null
+++ b/test_modules/PktgenTx.py
@@ -0,0 +1,93 @@
+"""
+This module defines pktgen test, Tx side
+
+Copyright 2011 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jpirko(a)redhat.com (Jiri Pirko)
+"""
+
+import logging
+import re
+import os
+from lnst.Common.TestsCommon import TestGeneric
+from lnst.Common.ExecCmd import exec_cmd, ExecCmdFail
+
+class Pktgen:
+ def __init__(self, dev):
+ self._dev = dev
+
+ def set(self, val):
+ exec_cmd("echo \"%s\" > %s" % (val, self._dev))
+
+class PktgenWorkers:
+ def __init__(self):
+ self._current = 0
+ self._cpunum = int(os.sysconf('SC_NPROCESSORS_ONLN'))
+ self._wrkrs = {}
+
+ def _init_current_wrkr(self):
+ num = self._current
+ wrkr = Pktgen("/proc/net/pktgen/kpktgend_%d" % (num))
+ wrkr.set("rem_device_all")
+ wrkr.set("max_before_softirq 5000")
+ self._wrkrs[num] = wrkr
+
+ def _get_wrkr(self):
+ num = self._current
+ if not num in self._wrkrs:
+ self._init_current_wrkr()
+ wrkr = self._wrkrs[num]
+ num += 1
+ if num == self._cpunum:
+ num = 0
+ self._current = num
+ return wrkr
+
+ def add_device(self, dev_name):
+ wrkr = self._get_wrkr()
+ wrkr.set("add_device %s" % dev_name)
+
+def pktget_options_merge(pktgen_options, default_pktgen_options):
+ opts = [re.split('\s+', opt) for opt in pktgen_options]
+ def_opts = [re.split('\s+', opt) for opt in default_pktgen_options]
+ res = []
+ for def_opt in def_opts:
+ if not def_opt[0] in [opt[0] for opt in opts]:
+ res.append(def_opt)
+ res = res + opts
+ return [" ".join(opt) for opt in res]
+
+class PktgenTx(TestGeneric):
+ def run(self):
+ dev_names = self.get_multi_mopt("netdev_name")
+ pktgen_options = self.get_multi_mopt("pktgen_option")
+
+ default_pktgen_options = [
+ "count 10000000",
+ "clone_skb 100000",
+ "pkt_size 60",
+ ]
+ pktgen_options = pktget_options_merge(pktgen_options,
+ default_pktgen_options)
+
+ exec_cmd("modprobe pktgen")
+
+ pgctl = Pktgen("/proc/net/pktgen/pgctrl")
+ pgwrkr = PktgenWorkers()
+
+ try:
+ for dev_name in dev_names:
+ pgwrkr.add_device(dev_name)
+ pg = Pktgen("/proc/net/pktgen/%s" % dev_name)
+ for pktgen_option in pktgen_options:
+ pg.set(pktgen_option)
+ pgctl.set("start")
+ except ExecCmdFail:
+ res_data = {"msg": "pktgen failed"}
+ return self.set_fail(res_data)
+
+ return self.set_pass()
diff --git a/test_modules/TestDummyFailing.py b/test_modules/TestDummyFailing.py
deleted file mode 100644
index 4ea342d..0000000
--- a/test_modules/TestDummyFailing.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""
-This module defines dummy failing test
-
-Copyright 2011 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-jpirko(a)redhat.com (Jiri Pirko)
-"""
-
-import logging
-from lnst.Common.TestsCommon import TestGeneric
-
-class TestDummyFailing(TestGeneric):
- def run(self):
- res_data = {"msg": "what else did you expect?"}
- return self.set_fail(res_data)
diff --git a/test_modules/TestIcmp6Ping.py b/test_modules/TestIcmp6Ping.py
deleted file mode 100644
index 83550c5..0000000
--- a/test_modules/TestIcmp6Ping.py
+++ /dev/null
@@ -1,70 +0,0 @@
-__author__ = """
-jpirko(a)redhat.com (Jiri Pirko)
-jmalanik(a)redhat.com (Jan Malanik)
-jtluka(a)redhat.com (Jan Tluka)
-"""
-
-
-import logging
-import re
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.ExecCmd import exec_cmd
-
-
-class TestIcmp6Ping(TestGeneric):
- def compose_cmd(self):
- addr = self.get_mopt("addr", opt_type="addr")
- cmd = "ping6 %s" % addr
-
- iface = self.get_opt("iface")
- if iface:
- cmd += " -I %s" % iface
-
- count = self.get_opt("count")
- if count:
- cmd += " -c %s" % count
-
- interval = self.get_opt("interval")
- if interval:
- cmd += " -i %s" % interval
-
- return cmd
-
- def run(self):
- cmd = self.compose_cmd()
- logging.debug("%s" % cmd)
-
- limit_rate = self.get_opt("limit_rate ", default=80)
- data_stdout = exec_cmd(cmd, die_on_err=False)[0]
-
- stat_pttr1 = r'(\d+) packets transmitted, (\d+) received'
- stat_pttr2 = r'rtt min/avg/max/mdev =
(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
-
- match = re.search(stat_pttr1, data_stdout)
- if not match:
- res_data = {"msg": "expected pattern not found"}
- return self.set_fail(res_data)
-
- trans_pkts, recv_pkts = match.groups()
- rate = int(round((float(recv_pkts) / float(trans_pkts)) * 100))
- logging.debug("Transmitted \"%s\", received \"%s\",
" \
- "rate \"%d%%\", limit_rate \"%d%%\"" \
- % (trans_pkts, recv_pkts, rate, limit_rate ))
-
- res_data = {"rate": rate,
- "limit_rate": limit_rate}
-
- match = re.search(stat_pttr2, data_stdout)
- if match:
- tmin, tavg, tmax, tmdev = [float(x) for x in match.groups()]
- logging .debug("rtt min \"%.3f\", avg \"%.3f\", max
\"%.3f\", "
- "mdev \"%.3f\"" % (tmin, tavg, tmax, tmdev))
-
- res_data["rtt_min"] = tmin
- res_data["rtt_max"] = tmax
-
- if rate < limit_rate :
- res_data["msg"] = "rate is lower that limit"
- return self.set_fail(res_data)
-
- return self.set_pass(res_data)
diff --git a/test_modules/TestIcmpPing.py b/test_modules/TestIcmpPing.py
deleted file mode 100644
index 6920056..0000000
--- a/test_modules/TestIcmpPing.py
+++ /dev/null
@@ -1,68 +0,0 @@
-"""
-This module defines icmp ping test
-
-Copyright 2011 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-jpirko(a)redhat.com (Jiri Pirko)
-"""
-
-import logging
-import re
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.ExecCmd import exec_cmd
-
-class TestIcmpPing(TestGeneric):
- def _compose_cmd(self):
- addr = self.get_mopt("addr", opt_type="addr")
- cmd = "ping %s" % addr
- count = self.get_opt("count")
- if count:
- cmd += " -c %s" % count
- interval = self.get_opt("interval")
- if interval:
- cmd += " -i %s" % interval
- iface = self.get_opt("iface")
- if iface:
- cmd += " -I %s" % iface
- return cmd
-
- def run(self):
- cmd = self._compose_cmd()
- limit_rate = self.get_opt("limit_rate", default=80)
-
- data_stdout = exec_cmd(cmd, die_on_err=False)[0]
- stat_pttr1 = r'(\d+) packets transmitted, (\d+) received'
- stat_pttr2 = r'rtt min/avg/max/mdev =
(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+)/(\d+\.\d+) ms'
-
- match = re.search(stat_pttr1, data_stdout)
- if not match:
- res_data = {"msg": "expected pattern not found"}
- return self.set_fail(res_data)
-
- trans_pkts, recv_pkts = match.groups()
- rate = int(round((float(recv_pkts) / float(trans_pkts)) * 100))
- logging.debug("Transmitted \"%s\", received \"%s\",
"
- "rate \"%d%%\", limit_rate \"%d%%\""
- % (trans_pkts, recv_pkts, rate, limit_rate))
-
- res_data = {"rate": rate,
- "limit_rate": limit_rate}
-
- match = re.search(stat_pttr2, data_stdout)
- if match:
- tmin, tavg, tmax, tmdev = [float(x) for x in match.groups()]
- logging.debug("rtt min \"%.3f\", avg \"%.3f\", max
\"%.3f\", "
- "mdev \"%.3f\"" % (tmin, tavg, tmax, tmdev))
-
- res_data["rtt_min"] = tmin
- res_data["rtt_max"] = tmax
-
- if rate < limit_rate:
- res_data["msg"] = "rate is lower that limit"
- return self.set_fail(res_data)
-
- return self.set_pass(res_data)
diff --git a/test_modules/TestIperf.py b/test_modules/TestIperf.py
deleted file mode 100644
index a58104d..0000000
--- a/test_modules/TestIperf.py
+++ /dev/null
@@ -1,154 +0,0 @@
-"""
-This module defines iperf test
-"""
-
-__author__ = """
-jtluka(a)redhat.com (Jan Tluka)
-"""
-
-import logging
-import time
-import errno
-import re
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.ExecCmd import exec_cmd
-from lnst.Common.ShellProcess import ShellProcess
-
-class TestIperf(TestGeneric):
- def _compose_iperf_cmd(self, role):
- iperf_options = self.get_opt("iperf_opts")
- if iperf_options is None:
- iperf_options = ""
-
- cmd = ""
- if role == "client":
- iperf_server = self.get_mopt("iperf_server",
opt_type="addr")
- cmd = "iperf --%s %s -t %s %s" % (role, iperf_server,
self.duration, iperf_options)
- elif role == "server":
- bind = self.get_opt("bind", opt_type="addr")
- if bind != None:
- cmd = "iperf --%s -B %s %s" % (role, bind, iperf_options)
- else:
- cmd = "iperf --%s %s" % (role, iperf_options)
-
- return cmd
-
- def _rate_over_threshold(self, rate):
- # convert rate to the same unit as threshold unit
- pattern = "(\d*(\.\d*){0,1})\s*([ kMGT])bits\/sec"
-
- # parse threshold value
- r1 = re.match(pattern, self.threshold)
- thr_units = r1.group(3)
-
- # parse measured rate value
- r2 = re.match(pattern, rate)
- rate_units = r2.group(3)
-
- thr_val = float(r1.group(1))
-
- rate_val = float(r2.group(1))
-
- # do the conversion of rate units
- if thr_units != rate_units:
- # remove any k,M,G,T from measured rate
- if rate_units == 'k':
- rate_val *= 1000
- elif rate_units == 'M':
- rate_val *= 1000*1000
- elif rate_val == 'G':
- rate_val *= 1000*1000*1000
-
- # divide by k or M or G if present
- if thr_units == 'k':
- rate_val /= 1000
- elif thr_units == 'M':
- rate_val /= 1000*1000
- elif thr_units == 'G':
- rate_val /= 1000*1000*1000
-
- if rate_val < thr_val:
- logging.info("measured rate is below threshold! " \
- "(measured: %s < threshold: %s)" % \
- (rate, self.threshold))
- return False
-
- return True
-
- def run_client(self, cmd):
- client = ShellProcess(cmd)
- try:
- client.wait()
- except OSError as e:
- # we got interrupted, let's gather data
- if e.errno == errno.EINTR:
- client.kill()
-
- output = client.read_nonblocking()
-
- if re.search("connect failed:", output):
- logging.info("Iperf connection failed!")
- return (False, "Iperf connection failed!")
-
- m = re.search("\[[^0-9]*[0-9]*\]\s*0.0-\s*\d*\.\d sec\s*\d*(\.\d*){0,1}\s*[
kGMT]Bytes\s*(\d*(\.\d*){0,1}\s*[ kGMT]bits\/sec)", output)
- if m is None:
- logging.info("Could not get performance throughput!")
- return (False, "Could not get performance throughput!")
-
- rate = m.group(2)
- if self.threshold is not None:
- # check if expected threshold is reached
- result = self._rate_over_threshold(rate)
- if result:
- return (True, "Measured rate (%s) is over threshold (%s)." %
- (rate, self.threshold))
- else:
- return (False, "Measured rate (%s) is below threshold (%s)!" %
- (rate, self.threshold))
- else:
- return True, "Measured rate: %s" % rate
-
- def run_server(self, cmd):
- server = ShellProcess(cmd)
-
- if not self._keep_server_running:
- time.sleep(float(self.duration))
- server.read_nonblocking()
- server.kill()
- else:
- try:
- server.wait()
- except OSError as e:
- if e.errno == errno.EINTR:
- server.kill()
-
- server.read_nonblocking()
-
- def run(self):
- self._keep_server_running = True
-
- self.duration = self.get_opt("duration")
- if self.duration is None:
- self.duration = 60 # for client purposes
- else:
- self._keep_server_running = False # for server purposes
-
- self.threshold = self.get_opt("threshold")
-
- role = self.get_mopt("role")
- cmd = self._compose_iperf_cmd(role)
- logging.debug("compiled command: %s" % cmd)
-
- if role == "server":
- logging.debug("running as server ...")
- self.run_server(cmd)
-
- return self.set_pass()
- elif role == "client":
- logging.debug("running as client ...")
- (rv, message) = self.run_client(cmd)
- res_data = {"msg": message}
- if rv == False:
- return self.set_fail(res_data)
-
- return self.set_pass(res_data)
diff --git a/test_modules/TestMulticast.py b/test_modules/TestMulticast.py
deleted file mode 100644
index cb5a60e..0000000
--- a/test_modules/TestMulticast.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-Wrapper for executing the multicast test tools in LNST
-
-Copyright 2012 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-rpazdera(a)redhat.com (Radek Pazdera)
-"""
-
-import logging
-import re
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.NetTestCommand import CommandException
-from lnst.Common.ExecCmd import exec_cmd
-
-class TestMulticast(TestGeneric):
- """ Wrapper for executing the multicast test tools in LNST
-
- Running this test executes specified test setup from
- multicast tools and evaluates the results. The behavior
- is defined entirely by behavior of the selected setup.
-
- """
-
- _conditions = {}
-
- @staticmethod
- def _remove_mask(address_in_string):
- """ Remove mask suffix from the IP address """
- if address_in_string != None:
- return address_in_string.split('/')[0]
- else:
- return address_in_string
-
- def _compose_cmd(self):
- """ Setup a command from the recipe options """
- cmd = ""
- opts = {}
-
- setup = self.get_mopt("setup")
- opts["multicast_address"] =
self._remove_mask(self.get_opt("address"))
- opts["port"] = self.get_opt("port")
- opts["interface"] =
self._remove_mask(self.get_opt("interface"))
- opts["duration"] = self.get_opt("duration")
-
- # sender-specific
- opts["loop"] = self.get_opt("loop")
- opts["ttl"] = self.get_opt("ttl")
- opts["delay"] = self.get_opt("delay")
-
- # receiver-specific
- opts["source_address"] =
self._remove_mask(self.get_opt("source"))
-
- # igmp-specific
- opts["query_type"] = self.get_opt("query_type")
- opts["dest_address"] = self.get_opt("dest_address")
- opts["max_resp_time"] = self.get_opt("max_resp_time")
-
- cmd = "./{0} ".format(setup)
-
- for optname, optval in opts.iteritems():
- if optval != None:
- cmd += "--{0} \"{1}\" ".format(optname, optval)
-
- return cmd
-
- def _evaluate_result(self, name, value):
- """ Check if the result meets required conditions
"""
- if name in self._conditions:
- try:
- float(value)
- except ValueError:
- value = '"' + value + '"'
-
- result = eval(value + self._conditions[name])
- logging.info("Condition evaluated {2}: {0}{1}".format(name,
- self._conditions[name], str(result)))
-
- return result
- else:
- return True
-
- def _prepare_conditions(self):
- """ Search for var names in conditions """
- varname_r = r"[a-zA-Z_][a-zA-Z0-9_]*"
-
- conds = self.get_multi_opt("condition")
- logging.debug(conds)
- for cond in conds:
- if cond == None:
- continue
- logging.debug(cond)
- match = re.match(varname_r, cond)
- if match:
- name = match.group(0)
- self._conditions[name] = cond.replace(name, "")
- else:
- raise CommandException(self)
-
-
- def run(self):
- self._prepare_conditions()
-
- setup_name = self.get_mopt("setup")
- logging.info("Started Multicast test setup {0}".format(setup_name))
-
- cmd = self._compose_cmd()
- data_stdout = self.exec_from("multicast", cmd, die_on_err=False,
- log_outputs=False)[0]
-
- res = {}
-
- # line format matches name=value pairs with optional
- # double quotes around the value
- line_format_r = r"([a-zA-Z0-9_ ]+)=\"?([a-zA-Z0-9_ ]*)\"?"
-
- for line in data_stdout.split("\n"):
- match = re.search(line_format_r, line)
- if match:
- name = match.group(1).strip()
- value = match.group(2).strip()
-
- res[name] = value
- logging.info("Test result: {0} = {1}".format(name, value))
- if not self._evaluate_result(name, value):
- res["msg"] = "Conditions not met!"
- return self.set_fail(res)
-
- return self.set_pass(res)
diff --git a/test_modules/TestNetCat.py b/test_modules/TestNetCat.py
deleted file mode 100644
index 89c7e4b..0000000
--- a/test_modules/TestNetCat.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""
-This module defines netcat stream test
-
-Copyright 2011 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-jtluka(a)redhat.com (Jan Tluka)
-"""
-
-import re
-import time
-import logging
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.ShellProcess import ShellProcess
-
-class TestNetCat(TestGeneric):
- def _get_stream(self):
- return self.get_opt("stream", default="tcp")
-
- def _compose_nc_cmd(self):
- cmd = "yes | nc -v"
-
- if self._get_stream() == "udp":
- cmd += " -u"
-
- ipv = self.get_opt("ipv") # IP protocol version - 4 or 6
- if ipv:
- cmd += " -%s" % ipv
-
- addr = self.get_mopt("addr", opt_type="addr")
- port = self.get_mopt("port")
- cmd += " %s %s" % (addr, port)
-
- return cmd
-
- def _compose_tcpdump_cmd(self):
- cmd = ("tcpdump -c 10 -i any %s port %s and host %s" %
- (self._get_stream(),
- self.get_mopt("port"),
- self.get_mopt("addr", opt_type="addr")))
- return cmd
-
- def run(self):
- nc = ShellProcess(self._compose_nc_cmd())
-
- # check whether anything is being sent over the line
- td = ShellProcess(self._compose_tcpdump_cmd())
-
- try:
- td.read_until_output_matches("10 packets captured", timeout=5)
- except ShellProcess.ProcessTerminatedError:
- res_data = {"msg": "tcpdump process died unexpectedly!"}
- return self.set_fail(res_data)
- except ShellProcess.ProcessTimeoutError:
- res_data = {"msg": "No stream detected!"}
- return self.set_fail(res_data)
-
- td.kill()
-
- duration = self.get_opt("duration", default=30)
- time.sleep(duration)
-
- nc.kill()
-
- logging.info("nc stream with duration of %s secs" % duration)
- return self.set_pass()
diff --git a/test_modules/TestPacketAssert.py b/test_modules/TestPacketAssert.py
deleted file mode 100644
index d8a73e3..0000000
--- a/test_modules/TestPacketAssert.py
+++ /dev/null
@@ -1,169 +0,0 @@
-"""
-Test if packets were transfered through some interface correctly.
-This test is using tcpdump.
-
-Copyright 2012 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-rpazdera(a)redhat.com (Radek Pazdera)
-"""
-
-import logging
-import subprocess
-import re
-import signal
-from lnst.Common.TestsCommon import TestGeneric
-
-class TestPacketAssert(TestGeneric):
- """ Assert for number of incomming/outgoing packets
- Capturing backend of this class is provided by
- tcpdump(8).
- """
-
- _cmd = ""
- _tcpdump = None
- _grep_filters = []
-
- _min_cond = 1
- _max_cond = None
-
- _num_recv = 0
-
- def _set_interrupt_handler(self):
- signal.signal(signal.SIGINT, self._interrupt_handler)
- signal.signal(signal.SIGTERM, self._interrupt_handler)
-
- def _interrupt_handler(self, signum, frame):
- """ Kill tcpdump when interrupted """
- self._tcpdump.terminate()
-
- tcpdump_output = self._tcpdump.stdout
- while True:
- try:
- next_line = tcpdump_output.readline()
- except IOError: # Interrupted system call
- break
-
- if next_line == "":
- break
-
- next_line = next_line.strip("\n")
-
- if re.match("[0-9]+\:[0-9]+\:[0-9\.]+", next_line) and\
- self.line != "":
- self._process_captured_line(self.line)
- self.line = next_line
- else:
- self.line += next_line
- if self.line != "":
- self._process_captured_line(self.line)
-
-
- def _prepare_grep_filters(self):
- """ Parse `grep_for' test options """
- filters = self.get_multi_opt("grep_for")
-
- for filt in filters:
- if filt != None:
- self._grep_filters.append(filt)
-
- def _prepare_conditions(self):
- """ Parse `min' and `max' """
- min_packets = self.get_opt("min")
- max_packets = self.get_opt("max")
-
- if min_packets != None:
- self._min_cond = int(min_packets)
-
- if max_packets != None:
- self._max_cond = int(max_packets)
-
- def _compose_cmd(self):
- """ Create a command from the recipe options """
- cmd = ""
-
- interface = self.get_mopt("interface")
- pcap_filter = self.get_opt("filter")
- if not pcap_filter:
- pcap_filter = ""
-
- cmd = "tcpdump -p -nn -i %s \"%s\"" % (interface,
pcap_filter)
- self._cmd = cmd
-
- def _execute_tcpdump(self):
- """ Start tcpdump in the background """
- cmd = self._cmd
- proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- self._tcpdump = proc
-
- def _process_captured_line(self, line):
- """ Apply filters and see if the packet passed them
"""
- if len(self._grep_filters):
- for filt in self._grep_filters:
- if not re.search(filt, line):
- return
-
- self._num_recv += 1
-
- def _evaluate_results(self):
- """ Compare results with the conditions """
- num = self._num_recv
- if num >= self._min_cond:
- if self._max_cond != None:
- return num <= self._max_cond
- return True
- return False
-
- def run(self):
- self._set_interrupt_handler()
-
- self._prepare_grep_filters()
- self._prepare_conditions()
- self._compose_cmd()
- self._execute_tcpdump()
-
- logging.info("Capturing started")
-
- self.line = ""
- tcpdump_output = self._tcpdump.stdout
- while True:
- if self._tcpdump.poll() != None:
- if self._tcpdump.returncode > 0:
- raise Exception("tcpdump terminated with error")
- else:
- break
-
- try:
- next_line = tcpdump_output.readline()
- except IOError: # Interrupted system call
- continue
-
- if next_line == "":
- continue
-
- next_line = next_line.strip("\n")
-
- if re.match("[0-9]+\:[0-9]+\:[0-9\.]+", next_line) and\
- self.line != "":
- self._process_captured_line(self.line)
- self.line = next_line
- else:
- self.line += next_line
-
- if self.line != "":
- self._process_captured_line(self.line)
-
- logging.info("Capturing finished. Received %d packets",
self._num_recv)
- res = {"received": self._num_recv,
- "min": self._min_cond,
- "max": self._max_cond}
-
- if self._evaluate_results():
- return self.set_pass(res)
-
- res["msg"] = "PacketAssert failed!"
- return self.set_fail(res)
diff --git a/test_modules/TestPktCounter.py b/test_modules/TestPktCounter.py
deleted file mode 100644
index 7eec92c..0000000
--- a/test_modules/TestPktCounter.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""
-This module defines packet counter implemented by iptables
-
-Copyright 2011 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-jpirko(a)redhat.com (Jiri Pirko)
-"""
-
-import logging
-import re
-import os
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.ExecCmd import exec_cmd, ExecCmdFail
-
-def get_pkt_count(indev_name, dport, proto):
- if indev_name:
- p_indev_name = indev_name
- else:
- p_indev_name = "\*"
- if proto:
- p_proto = proto
- if dport:
- p_protodport = "%s dpt:%s" % (proto, dport)
- else:
- p_protodport = ""
- else:
- p_proto = "all"
- p_protodport = ""
- pttr =
(r'\s*(\d+)\s+\d+\s+%s\s+\-\-\s+%s\s+\*\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*%s'
- % (p_proto, p_indev_name, p_protodport))
- data_stdout = exec_cmd("iptables -L -v -x -n")[0]
- match = re.search(pttr, data_stdout)
- if not match:
- return None
- return match.groups()[0]
-
-class TestPktCounter(TestGeneric):
- def run(self):
- indev_name = self.get_opt("input_netdev_name")
- dport = self.get_opt("dport")
- proto = self.get_opt("proto")
- params = ""
- if indev_name:
- params += " -i %s" % indev_name
-
- if proto:
- params += " -p %s" % proto
-
- if dport:
- params += " --dport %s" % dport
-
- '''
- Remove all same already existing rules
- '''
- while True:
- if get_pkt_count(indev_name, dport, proto) == None:
- break
- exec_cmd("iptables -D INPUT%s" % params)
-
- exec_cmd("iptables -I INPUT%s" % params)
-
- self.wait_on_interrupt()
-
- count = get_pkt_count(indev_name, dport, proto)
-
- exec_cmd("iptables -D INPUT%s" % params)
-
- return self.set_pass(res_data={"pkt_count": count})
diff --git a/test_modules/TestPktgenTx.py b/test_modules/TestPktgenTx.py
deleted file mode 100644
index 684640f..0000000
--- a/test_modules/TestPktgenTx.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""
-This module defines pktgen test, Tx side
-
-Copyright 2011 Red Hat, Inc.
-Licensed under the GNU General Public License, version 2 as
-published by the Free Software Foundation; see COPYING for details.
-"""
-
-__author__ = """
-jpirko(a)redhat.com (Jiri Pirko)
-"""
-
-import logging
-import re
-import os
-from lnst.Common.TestsCommon import TestGeneric
-from lnst.Common.ExecCmd import exec_cmd, ExecCmdFail
-
-class Pktgen:
- def __init__(self, dev):
- self._dev = dev
-
- def set(self, val):
- exec_cmd("echo \"%s\" > %s" % (val, self._dev))
-
-class PktgenWorkers:
- def __init__(self):
- self._current = 0
- self._cpunum = int(os.sysconf('SC_NPROCESSORS_ONLN'))
- self._wrkrs = {}
-
- def _init_current_wrkr(self):
- num = self._current
- wrkr = Pktgen("/proc/net/pktgen/kpktgend_%d" % (num))
- wrkr.set("rem_device_all")
- wrkr.set("max_before_softirq 5000")
- self._wrkrs[num] = wrkr
-
- def _get_wrkr(self):
- num = self._current
- if not num in self._wrkrs:
- self._init_current_wrkr()
- wrkr = self._wrkrs[num]
- num += 1
- if num == self._cpunum:
- num = 0
- self._current = num
- return wrkr
-
- def add_device(self, dev_name):
- wrkr = self._get_wrkr()
- wrkr.set("add_device %s" % dev_name)
-
-def pktget_options_merge(pktgen_options, default_pktgen_options):
- opts = [re.split('\s+', opt) for opt in pktgen_options]
- def_opts = [re.split('\s+', opt) for opt in default_pktgen_options]
- res = []
- for def_opt in def_opts:
- if not def_opt[0] in [opt[0] for opt in opts]:
- res.append(def_opt)
- res = res + opts
- return [" ".join(opt) for opt in res]
-
-class TestPktgenTx(TestGeneric):
- def run(self):
- dev_names = self.get_multi_mopt("netdev_name")
- pktgen_options = self.get_multi_mopt("pktgen_option")
-
- default_pktgen_options = [
- "count 10000000",
- "clone_skb 100000",
- "pkt_size 60",
- ]
- pktgen_options = pktget_options_merge(pktgen_options,
- default_pktgen_options)
-
- exec_cmd("modprobe pktgen")
-
- pgctl = Pktgen("/proc/net/pktgen/pgctrl")
- pgwrkr = PktgenWorkers()
-
- try:
- for dev_name in dev_names:
- pgwrkr.add_device(dev_name)
- pg = Pktgen("/proc/net/pktgen/%s" % dev_name)
- for pktgen_option in pktgen_options:
- pg.set(pktgen_option)
- pgctl.set("start")
- except ExecCmdFail:
- res_data = {"msg": "pktgen failed"}
- return self.set_fail(res_data)
-
- return self.set_pass()
--
1.8.3.1