[PATCH v2 1/3] TestMulticast.py: Adding test for multicast tools
by Radek Pazdera
From: Radek Pazdera <rpazdera(a)redhat.com>
This test integratest multicast test tools into LNST
and makes it possible to run and evaluate them from
the recipes.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
Tests/TestMulticast.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 128 insertions(+), 0 deletions(-)
create mode 100644 Tests/TestMulticast.py
diff --git a/Tests/TestMulticast.py b/Tests/TestMulticast.py
new file mode 100644
index 0000000..c757bca
--- /dev/null
+++ b/Tests/TestMulticast.py
@@ -0,0 +1,128 @@
+"""
+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 Common.TestsCommon import TestGeneric
+from NetTest.NetTestCommand import CommandException
+from 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.
+
+ """
+
+ _tools_location = "test_tools/multicast/"
+ _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._tools_location + 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"] = self._remove_mask(self.get_opt("source"))
+
+ 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))
+
+ exec_cmd("cd " + self._tools_location + " && make")
+
+ cmd = self._compose_cmd()
+ data_stdout = exec_cmd(cmd, die_on_err=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):
+ return self.set_fail("Conditions not met!", res)
+
+ return self.set_pass(res)
--
1.7.7.6
11 years, 11 months
[lnst] SshUtils: Fix hanging slaves when using -e option
by Jiří Pírko
commit 7b9d4e51f4c4b309328e5a62a96be8dd8698af11
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 5 17:17:40 2012 +0200
SshUtils: Fix hanging slaves when using -e option
This patch fixes problem with haning processes on slave machines,
after remote test execution using the -e option of nettestctl.py.
The problem is, when `ssh' is killed on the client side, the
corresponding remote `sshd' is terminated, but it doesn't signal
bash with SIGHUP if there's no tty allocated. Which (in this case
leaves two processes hanging on the slave machine (/bin/sh and
./nettestslave.py).
The solution here is passing -t agrument to `ssh', which results
in forced allocation of pseudo-tty. There's one issue with this
solution: when the remotely executed command finishes, `ssh'
terminates the connection which reults in printing "Connection
closed by remote host" even if everything was ok (return code 0).
So I also had to remove the error check associated with this
message. But I tested this and it still works fine, because
if the connection is closed by error, `ssh' exits with 255,
LNST can recognize that and still report it as an error.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Common/SshUtils.py | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
---
diff --git a/Common/SshUtils.py b/Common/SshUtils.py
index 109af71..e306976 100644
--- a/Common/SshUtils.py
+++ b/Common/SshUtils.py
@@ -142,7 +142,8 @@ def _remote_login(session, username, password, prompt, timeout=10):
msg = "Got username prompt after password prompt"
raise LoginAuthenticationError(msg, text)
elif match == 3: # "Connection closed"
- raise LoginError("Client said 'connection closed'", text)
+ logging.log(logging.INFO, "Remote command execution successful")
+ break
elif match == 4: # "Connection refused"
raise LoginError("Client said 'connection refused'", text)
elif match == 5: # "Please wait"
@@ -183,7 +184,7 @@ def remote_login(host, port, username, password, prompt, linesep="\n",
command = ""
else:
command = "-C '%s'" % (command)
- cmd = ("ssh -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o UserKnownHostsFile=/dev/null "
+ cmd = ("ssh -t -o ServerAliveInterval=5 -o ServerAliveCountMax=2 -o UserKnownHostsFile=/dev/null "
"-p %s %s@%s %s" % #-o PreferredAuthentications=password
(port, username, host, command))
11 years, 11 months
[lnst] multicast: Adding example recipe
by Jiří Pírko
commit 274ce419a3471c824428ea7c5204e65074af6f8a
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 5 14:56:40 2012 +0200
multicast: Adding example recipe
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
example_recipes/rpazdera-multicast.xml | 38 ++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)
---
diff --git a/example_recipes/rpazdera-multicast.xml b/example_recipes/rpazdera-multicast.xml
new file mode 100644
index 0000000..9a90168
--- /dev/null
+++ b/example_recipes/rpazdera-multicast.xml
@@ -0,0 +1,38 @@
+<!-- Example test scenario using multicast test tools -->
+<nettestrecipe>
+ <machines>
+ <machine id="1">
+ <netmachineconfig>
+ <info hostname="10.34.1.120" rootpass="redhat" />
+ <netdevice id="1" type="eth" phys_id="1" hwaddr="52:54:00:2E:D5:A8"/>
+ <netdevice id="2" type="eth" phys_id="2" hwaddr="52:54:00:90:23:0B"/>
+ </netmachineconfig>
+ <netconfig>
+ <netdevice id="1" type="eth" phys_id="1">
+ <addresses>
+ <address value="192.168.122.237/24" />
+ </addresses>
+ </netdevice>
+ <netdevice id="2" type="eth" phys_id="2" />
+ </netconfig>
+ </machine>
+ <machine id="2">
+ <netmachineconfig>
+ <info hostname="10.34.1.171" rootpass="redhat" />
+ <netdevice id="1" type="eth" phys_id="1" hwaddr="52:54:00:12:DF:5A"/>
+ </netmachineconfig>
+ <netconfig>
+ <netdevice id="1" type="eth" phys_id="1">
+ <addresses>
+ <address value="192.168.122.179/24" />
+ </addresses>
+ </netdevice>
+ </netconfig>
+ </machine>
+ </machines>
+
+ <command_sequence source="cmd_sequences/multicast/if.xml" />
+ <command_sequence source="cmd_sequences/multicast/ttl.xml" />
+ <command_sequence source="cmd_sequences/multicast/loop.xml" />
+ <command_sequence source="cmd_sequences/multicast/simple.xml" />
+</nettestrecipe>
11 years, 11 months
[lnst] multicast: Adding new folder for test tools
by Jiří Pírko
commit 1b1a3a5c5860071b3fcf729ae379df0df628e871
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 5 14:56:39 2012 +0200
multicast: Adding new folder for test tools
The `test_tools/' directory is a place for storing
various non-python tools that will later be used for
testing, such as programs in C, shell scripts etc.
This commit also adds first test tools - a set of
utilities, test setups and cases for validating
implementation of multicast/igmp in kernel.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
example_recipes/cmd_sequences/multicast/if.xml | 77 ++++++++
example_recipes/cmd_sequences/multicast/loop.xml | 70 +++++++
example_recipes/cmd_sequences/multicast/simple.xml | 33 ++++
example_recipes/cmd_sequences/multicast/ttl.xml | 112 ++++++++++++
test_tools/multicast/Makefile | 21 ++
test_tools/multicast/client/send_simple.c | 59 ++++++
test_tools/multicast/multicast_utils.h | 192 ++++++++++++++++++++
test_tools/multicast/offline/sockopt_if.c | 70 +++++++
test_tools/multicast/offline/sockopt_loop.c | 52 ++++++
test_tools/multicast/offline/sockopt_ttl.c | 79 ++++++++
test_tools/multicast/parameters.h | 152 ++++++++++++++++
test_tools/multicast/server/recv_simple.c | 50 +++++
test_tools/multicast/sockopt_utils.h | 175 ++++++++++++++++++
13 files changed, 1142 insertions(+), 0 deletions(-)
---
diff --git a/example_recipes/cmd_sequences/multicast/if.xml b/example_recipes/cmd_sequences/multicast/if.xml
new file mode 100644
index 0000000..c7fec3f
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/if.xml
@@ -0,0 +1,77 @@
+<!-- Offline IP_MULTICAST_IF test -->
+<!-- Requires: 2 hosts
+ - [1] with one interface
+ - [2] with one interface
+ - -->
+
+<command_sequence>
+ <!-- IP_MULTICAST_IF sockopt conformance test -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_if" />
+
+ <!-- This condition doesn't pass yet because of a
+ bug in the syscal. #803202 on RedHat Bugzilla -->
+ <!-- <option name="condition" value="status == 'pass'" /> -->
+ </options>
+ </command>
+
+ <!-- IP_MULTICAST_IF correct interfaces set -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="0" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_IF incorrect interfaces set -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="interface" value="127.0.0.1" />
+
+ <option name="condition" value="packets_received == 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/example_recipes/cmd_sequences/multicast/loop.xml b/example_recipes/cmd_sequences/multicast/loop.xml
new file mode 100644
index 0000000..7b155e1
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/loop.xml
@@ -0,0 +1,70 @@
+<!-- Offline IP_MULTICAST_LOOP test -->
+<!-- Requires: 1 hosts with at least two interfaces -->
+
+<command_sequence>
+ <!-- IP_MULTICAST_LOOP sockopt conformance test -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_loop" />
+ <option name="condition" value="status == 'pass'" />
+ </options>
+ </command>
+
+ <!-- IP_MULTICAST_LOOP enabled -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="loop" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_LOOP disabled -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="loop" value="0" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received == 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/example_recipes/cmd_sequences/multicast/simple.xml b/example_recipes/cmd_sequences/multicast/simple.xml
new file mode 100644
index 0000000..236558b
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/simple.xml
@@ -0,0 +1,33 @@
+<!-- Requires: 2 hosts with at least one interface -->
+<!-- ['machines'][2]['netconfig'][1]['addresses'][0] -->
+
+<command_sequence>
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <!-- <option name="interface" value="192.168.122.179" /> -->
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/example_recipes/cmd_sequences/multicast/ttl.xml b/example_recipes/cmd_sequences/multicast/ttl.xml
new file mode 100644
index 0000000..ae55228
--- /dev/null
+++ b/example_recipes/cmd_sequences/multicast/ttl.xml
@@ -0,0 +1,112 @@
+<!-- Offline IP_MULTICAST_TTL test -->
+<!-- Requires: 2 hosts
+ - [1] with one interface
+ - [2] with one interface
+ - -->
+
+<command_sequence>
+ <!-- IP_MULTICAST_TTL sockopt conformance test -->
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="sockopt_ttl" />
+ <option name="condition" value="status == 'pass'" />
+ </options>
+ </command>
+
+ <!-- IP_MULTICAST_TTL = 0, looped on one host -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="0" />
+ <option name="loop" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_TTL = 0 between 2 hosts -->
+ <!-- KNOWN BUG: according to the specs, packets
+ with TTL=0 should not leave the host.
+
+ Well it does, it's an intentional hack for some
+ apps [1].
+
+ http://www.spinics.net/lists/netdev/msg183704.html
+ -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+ <command type="exec" machine_id="2" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="0" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+
+ <!-- IP_MULTICAST_TTL = 1 between 2 hosts -->
+ <command type="exec" machine_id="1" value="sleep 1" />
+
+ <command type="test" value="Multicast" machine_id="1" timeout="30" bg_id="1">
+ <options>
+ <option name="setup" value="send_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option name="delay" value="0.1" />
+ <option name="ttl" value="1" />
+ <option type="recipe_eval" name="interface" value="['machines'][1]['netconfig'][1]['addresses'][0]" />
+ </options>
+ </command>
+
+ <command type="test" value="Multicast" machine_id="2" timeout="30">
+ <options>
+ <option name="setup" value="recv_simple" />
+ <option name="address" value="238.0.0.1" />
+ <option name="port" value="1337" />
+ <option name="duration" value="10" />
+ <option type="recipe_eval" name="interface" value="['machines'][2]['netconfig'][1]['addresses'][0]" />
+
+ <option name="condition" value="packets_received > 0" />
+ </options>
+ </command>
+
+ <command type="wait" machine_id="1" value="1" />
+</command_sequence>
diff --git a/test_tools/multicast/Makefile b/test_tools/multicast/Makefile
new file mode 100644
index 0000000..47af8f5
--- /dev/null
+++ b/test_tools/multicast/Makefile
@@ -0,0 +1,21 @@
+CC=gcc
+TOOLS_DIR=.
+CFLAGS=-Wall -Wextra -I$(TOOLS_DIR)
+
+SENDERS=send_simple
+RECEIVERS=recv_simple
+OFFLINE=sockopt_loop sockopt_ttl sockopt_if
+
+all: $(SENDERS) $(RECEIVERS) $(OFFLINE)
+
+$(SENDERS):
+ $(CC) $(CFLAGS) -o $@ client/$@.c
+
+$(RECEIVERS):
+ $(CC) $(CFLAGS) -o $@ server/$@.c
+
+$(OFFLINE):
+ $(CC) $(CFLAGS) -o $@ offline/$@.c
+
+clean:
+ rm -f $(SENDERS) $(RECEIVERS) $(OFFLINE)
diff --git a/test_tools/multicast/client/send_simple.c b/test_tools/multicast/client/send_simple.c
new file mode 100644
index 0000000..2651c36
--- /dev/null
+++ b/test_tools/multicast/client/send_simple.c
@@ -0,0 +1,59 @@
+/*
+ * send_simple.c - simple sender setup for multicast tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define SEND
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_out_socket(¶ms);
+
+ /* Sockopts setup */
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ &(params.loop), sizeof(params.loop)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &(params.ttl), sizeof(params.ttl)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF,
+ &(params.interface), sizeof(params.interface)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ int num_sent = 0;
+ num_sent = send_data(sockfd, params.multiaddr, params.port,
+ params.duration, params.delay);
+
+ printf("packets_sent=%d\n", num_sent);
+
+ return EXIT_SUCCESS;
+}
diff --git a/test_tools/multicast/multicast_utils.h b/test_tools/multicast/multicast_utils.h
new file mode 100644
index 0000000..25d0c38
--- /dev/null
+++ b/test_tools/multicast/multicast_utils.h
@@ -0,0 +1,192 @@
+/*
+ * multicast_utils.h - common tools for kernel multicast tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __MULTICAST_UTILS_H__
+#define __MULTICAST_UTILS_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+
+#include <signal.h>
+#include <time.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#if !defined(SEND) && !defined(RECEIVE)
+#error "At least one of SEND/RECEIVE macros must be defined!"
+#endif
+
+#include "parameters.h"
+
+#define MESSAGE "Hello world!"
+
+int __verbosity = 0;
+
+/* Verbose print */
+#define printv(args...) \
+ if (__verbosity > 0) \
+ { \
+ printf(args); \
+ fflush(stdout); \
+ }
+
+/** Initiailze socket for receiving multicast data */
+int init_in_socket(struct in_addr multiaddr, short port)
+{
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ perror("socket()");
+ exit(EXIT_FAILURE);
+ }
+
+ struct sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr = multiaddr;
+ memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
+
+ if (bind(sockfd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
+ perror("bind()");
+ exit(EXIT_FAILURE);
+ }
+
+ return sockfd;
+}
+
+/** Initialize socket for sending multicast data */
+int init_out_socket()
+{
+ int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ perror("socket()");
+ exit(EXIT_FAILURE);
+ }
+
+ return sockfd;
+}
+
+/** Close a socket */
+void free_socket(int sockfd)
+{
+ close(sockfd);
+}
+
+/** Wait for data up to `duration' seconds */
+int wait_for_data(int sockfd, int duration, int packet_limit)
+{
+ const char message[] = MESSAGE;
+ char buffer[] = MESSAGE;
+ memset(buffer, 0, sizeof(buffer));
+
+ int num_received = 0;
+
+ fd_set receive_fd_set;
+ struct timeval timeout;
+
+ time_t deadline = time(NULL) + duration;
+
+ printv("Receiving\n");
+
+ while (1) {
+ FD_ZERO(&receive_fd_set);
+ FD_SET(sockfd, &receive_fd_set);
+
+ if (duration == 0) {
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ } else {
+ time_t now = time(NULL);
+ if ((deadline - now) <= 0)
+ break;
+
+ timeout.tv_sec = deadline - now;
+ timeout.tv_usec = 0;
+ }
+
+
+ if (select(sockfd + 1, &receive_fd_set, NULL, NULL, &timeout) > 0) {
+ recv(sockfd, buffer, sizeof(buffer), 0);
+ if (strncmp(message, buffer, sizeof(buffer)) == 0) {
+ num_received++;
+
+ printv(".");
+ if (!(num_received % 10))
+ printv("\n");
+
+ if (packet_limit > 0 && num_received > packet_limit)
+ break;
+ }
+ }
+ }
+
+ printv("\n");
+
+ return num_received;
+}
+
+/** Send data for specified amount of time */
+int send_data(int sockfd, struct in_addr multiaddr, short port,
+ int duration, double delay)
+{
+ const char message[] = MESSAGE;
+ int i = 0;
+
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr = multiaddr;
+ addr.sin_port = htons(port);
+ memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
+
+ struct timespec delay_value;
+ delay_value.tv_sec = 0;
+ delay_value.tv_nsec = delay * 999999999;
+
+ printv("Sending...\n");
+
+ time_t started_at = time(NULL);
+ while (duration == 0 || (time(NULL) - started_at) < duration) {
+ i++;
+ sendto(sockfd, message, strlen(message), 0,
+ (struct sockaddr*) &addr, sizeof(addr));
+
+ printv(".");
+ if (!(i % 10))
+ printv("\n");
+
+ nanosleep(&delay_value, NULL);
+ }
+
+ printv("\n");
+
+ return i;
+}
+
+#endif
diff --git a/test_tools/multicast/offline/sockopt_if.c b/test_tools/multicast/offline/sockopt_if.c
new file mode 100644
index 0000000..ff5bd51
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_if.c
@@ -0,0 +1,70 @@
+/*
+ * sockopt_if.c - IP_MULTICAST_IF socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_if()
+{
+ struct in_addr address;
+ size_t size = sizeof(address);
+
+ address.s_addr = INADDR_ANY;
+ test_getsockopt("IP_MULTICAST_IF default value",
+ IP_MULTICAST_IF, &address, size);
+
+ inet_pton(AF_INET, "127.0.0.1", &address);
+ test_sockopt_value("IP_MULTICAST_IF set to 127.0.0.1",
+ IP_MULTICAST_IF, &address, size);
+
+ struct ip_mreqn mreqn;
+ mreqn.imr_multiaddr.s_addr = 0xdeadbeef;
+ mreqn.imr_address.s_addr = INADDR_ANY;
+ mreqn.imr_ifindex = 0;
+
+ test_sockopt_value("IP_MULTICAST_IF set to INADDR_ANY",
+ IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
+
+ mreqn.imr_address.s_addr = 0x0100007f;
+ test_sockopt_value("IP_MULTICAST_IF set to 127.0.0.1",
+ IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
+
+
+ /* Errors */
+ test_setsockopt_error("IP_MULTICAST_IF bad optlen",
+ IP_MULTICAST_IF, &address, 3, EINVAL);
+
+ inet_pton(AF_INET, "238.0.10.0", &address);
+ test_setsockopt_error("IP_MULTICAST_IF address 238.0.10.0",
+ IP_MULTICAST_IF, &address,
+ sizeof(address), EADDRNOTAVAIL);
+}
+
+int main()
+{
+ initialize();
+
+ test_if();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/offline/sockopt_loop.c b/test_tools/multicast/offline/sockopt_loop.c
new file mode 100644
index 0000000..fdf7478
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_loop.c
@@ -0,0 +1,52 @@
+/*
+ * sockopt_loop.c - IP_MULTICAST_LOOP socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_loop()
+{
+ int value;
+ size_t size = sizeof(value);
+
+ value = 1;
+ test_getsockopt("IP_MULTICAST_LOOP default value",
+ IP_MULTICAST_LOOP, &value, size);
+
+ value = 0;
+ test_sockopt_value("IP_MULTICAST_LOOP set to zero",
+ IP_MULTICAST_LOOP, &value, size);
+
+ /* Errors */
+ test_setsockopt_error("IP_MULTICAST_LOOP bad optlen",
+ IP_MULTICAST_LOOP, &value, 0, EINVAL);
+}
+
+int main()
+{
+ initialize();
+
+ test_loop();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/offline/sockopt_ttl.c b/test_tools/multicast/offline/sockopt_ttl.c
new file mode 100644
index 0000000..293bbe5
--- /dev/null
+++ b/test_tools/multicast/offline/sockopt_ttl.c
@@ -0,0 +1,79 @@
+/*
+ * sockopt_ttl.c - IP_MULTICAST_TTL socket option test
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "sockopt_utils.h"
+
+
+void test_ttl()
+{
+ int value;
+ size_t size = sizeof(value);
+
+ value = 1;
+ test_getsockopt("IP_MULTICAST_TTL default value",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 0;
+ test_sockopt_value("IP_MULTICAST_TTL set to zero",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 64;
+ test_sockopt_value("IP_MULTICAST_TTL set to 64",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 255;
+ test_sockopt_value("IP_MULTICAST_TTL set to 255",
+ IP_MULTICAST_TTL, &value, size);
+
+
+ /*
+ * Special case:
+ * For some reason kernel accepts
+ * TTL = -1 and takes it as if it were 1
+ */
+ value = -1;
+ test_setsockopt("IP_MULTICAST_TTL set to -1",
+ IP_MULTICAST_TTL, &value, size);
+
+ value = 1;
+ test_getsockopt("IP_MULTICAST_TTL set to 1",
+ IP_MULTICAST_TTL, &value, size);
+
+
+ /* Errors */
+ value = 500;
+ test_setsockopt_error("IP_MULTICAST_TTL set to 500",
+ IP_MULTICAST_TTL, &value, size, EINVAL);
+
+ test_setsockopt_error("IP_MULTICAST_TTL bad optlen",
+ IP_MULTICAST_TTL, &value, 0, EINVAL);
+}
+
+int main()
+{
+ initialize();
+
+ test_ttl();
+
+ report_and_exit();
+ return 0;
+}
diff --git a/test_tools/multicast/parameters.h b/test_tools/multicast/parameters.h
new file mode 100644
index 0000000..6a313ec
--- /dev/null
+++ b/test_tools/multicast/parameters.h
@@ -0,0 +1,152 @@
+/*
+ * parameters.h - common code for parsing sender/receiver parameters
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <signal.h>
+#include <time.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+extern int __verbosity;
+
+/** Structure that carries test parameters */
+struct parameters
+{
+ int duration; /* seconds */
+
+ struct in_addr multiaddr;
+ short port;
+ struct in_addr interface;
+
+#ifdef RECEIVE
+ struct in_addr sourceaddr;
+#endif
+
+#ifdef SEND
+ double delay;
+ int ttl;
+ int loop;
+#endif
+};
+
+/** Initialize parameters struct with default values. */
+void default_parameters(struct parameters* params)
+{
+ params->duration = 10;
+ params->port = 0;
+ memset(¶ms->multiaddr, 0, sizeof(struct in_addr));
+ memset(¶ms->interface, 0, sizeof(struct in_addr));
+#ifdef RECEIVE
+ memset(¶ms->sourceaddr, 0, sizeof(struct in_addr));
+#endif
+
+#ifdef SEND
+ params->delay = 0.1;
+ params->ttl = 1;
+ params->loop = 1;
+#endif
+}
+
+/** Generic function for parsing arguments */
+void parse_args(int argc, char** argv, struct parameters* args)
+{
+#ifdef SEND
+ static const char* opts = "d:a:p:i:f:l:t:v";
+#endif
+
+#ifdef RECEIVE
+ static const char* opts = "d:a:p:s:i:v";
+#endif
+
+ static struct option long_options[] =
+ {
+ {"duration", required_argument, NULL, 'd'},
+ {"multicast_address", required_argument, NULL, 'a'},
+ {"port", required_argument, NULL, 'p'},
+ {"interface", required_argument, NULL, 'i'},
+ {"verbose", no_argument, NULL, 'v'},
+#ifdef RECEIVE
+ {"source_address", required_argument, NULL, 's'},
+#endif
+
+#ifdef SEND
+ {"delay", required_argument, NULL, 'f'},
+ {"ttl", required_argument, NULL, 't'},
+ {"loop", required_argument, NULL, 'l'},
+#endif
+ {0, 0, NULL, 0}
+ };
+
+ default_parameters(args);
+
+ int opt;
+ int option_index = 0;
+ while((opt = getopt_long(argc, argv, opts, long_options,
+ &option_index)) != -1) {
+ switch (opt) {
+ case 'd':
+ args->duration = atoi(optarg);
+ break;
+ case 'a':
+ inet_pton(AF_INET, optarg, &(args->multiaddr));
+ break;
+ case 'p':
+ args->port = atoi(optarg);
+ break;
+ case 'i':
+ inet_pton(AF_INET, optarg, &(args->interface));
+ break;
+ case 'v':
+ __verbosity = 1;
+ break;
+#ifdef RECEIVE
+ case 's':
+ inet_pton(AF_INET, optarg, &(args->sourceaddr));
+ break;
+#endif
+
+#ifdef SEND
+ case 'f':
+ args->delay = atof(optarg);
+ break;
+ case 't':
+ args->ttl = atoi(optarg);
+ break;
+ case 'l':
+ args->loop = atoi(optarg);
+ break;
+#endif
+ default: /* '?' */
+ printf("%s: invalid test options\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
diff --git a/test_tools/multicast/server/recv_simple.c b/test_tools/multicast/server/recv_simple.c
new file mode 100644
index 0000000..c4d045c
--- /dev/null
+++ b/test_tools/multicast/server/recv_simple.c
@@ -0,0 +1,50 @@
+/*
+ * recv_simple.c - simple receiver setup for multicast tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define RECEIVE
+#include "multicast_utils.h"
+
+int main(int argc, char** argv)
+{
+ struct parameters params;
+ parse_args(argc, argv, ¶ms);
+
+ int sockfd = init_in_socket(params.multiaddr, params.port);
+
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = params.multiaddr;
+ mreq.imr_interface = params.interface;
+
+ int num_recv = 0;
+
+ if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ &(mreq), sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return EXIT_FAILURE;
+ }
+
+ num_recv = wait_for_data(sockfd, params.duration, 0);
+
+ printf("packets_received=%d\n", num_recv);
+
+ return EXIT_SUCCESS;
+}
diff --git a/test_tools/multicast/sockopt_utils.h b/test_tools/multicast/sockopt_utils.h
new file mode 100644
index 0000000..6486f71
--- /dev/null
+++ b/test_tools/multicast/sockopt_utils.h
@@ -0,0 +1,175 @@
+/*
+ * sockopt_utils.h - common tools for writing sockopt conformance tests
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Radek Pazdera (rpazdera(a)redhat.com)
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __SOCKOPT_UTILS_H__
+#define __SOCKOPT_UTILS_H__
+
+#define __SUCCESS_CODE 0
+#define __FAILURE_CODE 1
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int __test_status = 1;
+int __sockfd;
+
+void fail()
+{
+ __test_status = 0;
+}
+
+void report_and_exit()
+{
+ close(__sockfd);
+
+ if (__test_status) {
+ printf("status=pass\n");
+ exit(__SUCCESS_CODE);
+ } else {
+ printf("status=fail\n");
+ exit(__FAILURE_CODE);
+ }
+}
+
+void error_exit(char* what)
+{
+ int code = errno;
+ printf("error_message=%s %s\n", what, strerror(code));
+ fail();
+ report_and_exit();
+}
+
+void initialize()
+{
+ __sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (__sockfd < 0)
+ error_exit("socket()");
+}
+
+void test_getsockopt(char* test_name, int optname, void *expected_optval,
+ socklen_t expected_optlen)
+{
+ int status;
+ socklen_t size = expected_optlen;
+ void* value = malloc(size);
+
+ if (value == NULL)
+ error_exit("malloc()");
+
+ memset(value, 0, size);
+
+ status = getsockopt(__sockfd, IPPROTO_IP, optname, value, &size);
+ if (status < 0)
+ error_exit("getsockopt()");
+
+ if (expected_optlen != size) {
+ printf("%s=fail: size of the returned struct differ\n", test_name);
+ fail();
+ } else {
+ socklen_t i;
+ for (i = 0; i < size; i++)
+ if (((char*) value)[i] != ((char*) expected_optval)[i])
+ {
+ free(value);
+ printf("%s=fail: received value of the option "
+ "differs from expected one\n", test_name);
+ fail();
+ return;
+ }
+
+ printf("%s=pass\n", test_name);
+ }
+
+ free(value);
+}
+
+
+void test_setsockopt(char* test_name, int optname, void *optval,
+ socklen_t optlen)
+{
+ int status;
+
+ status = setsockopt(__sockfd, IPPROTO_IP, optname, optval, optlen);
+ if (status < 0)
+ error_exit("setsockopt()");
+
+ printf("%s=pass\n", test_name);
+}
+
+void test_sockopt_value(char* test_name, int optname,
+ void *optval, socklen_t optlen)
+{
+ test_setsockopt(test_name, optname, optval, optlen);
+ test_getsockopt(test_name, optname, optval, optlen);
+}
+
+void test_setsockopt_error(char* test_name, int optname, void *optval,
+ socklen_t optlen, int expected_errorcode)
+{
+ int status;
+
+ status = setsockopt(__sockfd, IPPROTO_IP, optname, optval, optlen);
+ if (status < 0) {
+ if (errno != expected_errorcode) {
+ printf("%s=fail: error codes don't "
+ "match (expected %d, got %d)\n", test_name,
+ expected_errorcode, errno);
+ fail();
+ } else {
+ printf("%s=pass\n", test_name);
+ }
+ } else {
+ printf("%s=fail: no error occured\n", test_name);
+ fail();
+ }
+}
+
+void test_getsockopt_error(char* test_name, int optname, void *optval,
+ socklen_t optlen, int expected_errorcode)
+{
+ int status;
+ socklen_t size = optlen;
+
+ status = getsockopt(__sockfd, IPPROTO_IP, optname, optval, &size);
+ if (status < 0) {
+ if (errno != expected_errorcode) {
+ printf("%s=fail: error codes don't "
+ "match (expected %d, got %d)\n", test_name,
+ expected_errorcode, errno);
+ fail();
+ } else {
+ printf("%s=pass\n", test_name);
+ }
+ } else {
+ printf("%s=fail: no error occured\n", test_name);
+ fail();
+ }
+}
+
+#endif
11 years, 11 months
[lnst] TestMulticast.py: Adding test for multicast tools
by Jiří Pírko
commit a75f9d32f3da1939ac823f268bed2c7f386a534d
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Thu Apr 5 14:56:38 2012 +0200
TestMulticast.py: Adding test for multicast tools
This test integratest multicast test tools into LNST
and makes it possible to run and evaluate them from
the recipes.
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Tests/TestMulticast.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 128 insertions(+), 0 deletions(-)
---
diff --git a/Tests/TestMulticast.py b/Tests/TestMulticast.py
new file mode 100644
index 0000000..c757bca
--- /dev/null
+++ b/Tests/TestMulticast.py
@@ -0,0 +1,128 @@
+"""
+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 Common.TestsCommon import TestGeneric
+from NetTest.NetTestCommand import CommandException
+from 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.
+
+ """
+
+ _tools_location = "test_tools/multicast/"
+ _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._tools_location + 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"] = self._remove_mask(self.get_opt("source"))
+
+ 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))
+
+ exec_cmd("cd " + self._tools_location + " && make")
+
+ cmd = self._compose_cmd()
+ data_stdout = exec_cmd(cmd, die_on_err=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):
+ return self.set_fail("Conditions not met!", res)
+
+ return self.set_pass(res)
11 years, 11 months
[PATCH 0/3] Multicast Tests with LNST
by Radek Pazdera
From: Radek Pazdera <rpazdera(a)redhat.com>
Hi,
I'm trying to implement a set of automatic tests for multicast
implementation in kernel using LNST. The thing is, there is only
a little documentation for the interface at the moment, so some of
the features that need test coverage are not implemented Python's
socket module. That's why I need C for writing tests.
I figured that this might be useful also in other areas of network
stack testing and added a few new things into LNST. I'm sending it
here for review.
I created a directory called `test_tools'. That should be a place for
storing non-python tools and utilities for testing, that can be used
from LNST tests. I placed there a first set of tools for multicast.
The communication between the C and LNST is achieved through a test
called `TestMulticast'. This test takes arguments from the XML recipe
file and executes the selected test setup from multicast tools. It also
collects and evaluates results when the test ends.
Additionaly, I added a couple of example command sequences to
`example_recipes/cmd_sequences/multicast'.
These should serve as a-sort-of building blocks for creating test
recipes. Then if you'd like to run tests for IGMPv2 for instance you
can only create netconfigs, include several test cases and run it as
one big recipe.
Example of these tests in practice is in the `rpazdera-multicast.xml'
recipe I added to `example_recipes' directory.
Is this solution acceptable for you to include it into LNST?
Thank you,
Radek Pazdera
Radek Pazdera (3):
TestMulticast.py: Adding test for multicast tools
multicast: Adding new folder for test tools
multicast: Adding example recipe
Tests/TestMulticast.py | 129 +++++++++++++
example_recipes/cmd_sequences/multicast/if.xml | 77 ++++++++
example_recipes/cmd_sequences/multicast/loop.xml | 70 +++++++
example_recipes/cmd_sequences/multicast/simple.xml | 33 ++++
example_recipes/cmd_sequences/multicast/ttl.xml | 112 ++++++++++++
example_recipes/rpazdera-multicast.xml | 39 ++++
test_tools/multicast/Makefile | 22 +++
test_tools/multicast/client/send_simple.c | 59 ++++++
test_tools/multicast/multicast_utils.h | 192 ++++++++++++++++++++
test_tools/multicast/offline/sockopt_if.c | 70 +++++++
test_tools/multicast/offline/sockopt_loop.c | 52 ++++++
test_tools/multicast/offline/sockopt_ttl.c | 79 ++++++++
test_tools/multicast/parameters.h | 152 ++++++++++++++++
test_tools/multicast/server/recv_simple.c | 50 +++++
test_tools/multicast/sockopt_utils.h | 176 ++++++++++++++++++
15 files changed, 1312 insertions(+), 0 deletions(-)
create mode 100644 Tests/TestMulticast.py
create mode 100644 example_recipes/cmd_sequences/multicast/if.xml
create mode 100644 example_recipes/cmd_sequences/multicast/loop.xml
create mode 100644 example_recipes/cmd_sequences/multicast/simple.xml
create mode 100644 example_recipes/cmd_sequences/multicast/ttl.xml
create mode 100644 example_recipes/rpazdera-multicast.xml
create mode 100644 test_tools/multicast/Makefile
create mode 100644 test_tools/multicast/client/send_simple.c
create mode 100644 test_tools/multicast/multicast_utils.h
create mode 100644 test_tools/multicast/offline/sockopt_if.c
create mode 100644 test_tools/multicast/offline/sockopt_loop.c
create mode 100644 test_tools/multicast/offline/sockopt_ttl.c
create mode 100644 test_tools/multicast/parameters.h
create mode 100644 test_tools/multicast/server/recv_simple.c
create mode 100644 test_tools/multicast/sockopt_utils.h
--
1.7.7.6
11 years, 12 months
[PATCH] SlaveUtils: Changed nettestslave.py exec command
by Radek Pazdera
Hi,
I ran into a minor issue, while I was working with LNST. If you execute
nettestctl.py with the -e option that automatically starts the slaves,
they are run from the directory that is default after logging with
ssh (usually user's home dir). This makes it hard to use paths relative
to the install_path in the tests.
I changed the command so nettestslave.py gets executed from the install
directory, where it resides, so relative paths are valid.
--
Radek Pazdera
Changed the way nettestslave.py is executed so the
cwd is the root of lnst install, not where ssh logs
to by default (which is usually root home dir).
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
---
Common/SlaveUtils.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Common/SlaveUtils.py b/Common/SlaveUtils.py
index d8db772..6cb7cc0 100644
--- a/Common/SlaveUtils.py
+++ b/Common/SlaveUtils.py
@@ -37,6 +37,6 @@ def prepare_client_session(host, port, login,
passwd=None, command=None,
if prompt is None:
prompt = "Started"
- command = "/%s/%s/%s" % (install_path, test_dir, command)
+ command = "cd /%s/%s/ && ./%s" % (install_path, test_dir, command)
return wait_for_login(host, port, login, passwd, prompt,
command=command, timeout=10)
\ No newline at end of file
--
1.7.7.6
11 years, 12 months
[lnst] SlaveUtils: Changed nettestslave.py exec command
by Jiří Pírko
commit 0c21e17ac5d1e2f8f1995b31c1f2e1ac6056662b
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Mon Apr 2 11:25:21 2012 +0200
SlaveUtils: Changed nettestslave.py exec command
Changed the way nettestslave.py is executed so the
cwd is the root of lnst install, not where ssh logs
to by default (which is usually root home dir).
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Common/SlaveUtils.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/Common/SlaveUtils.py b/Common/SlaveUtils.py
index d8db772..e7fdf3d 100644
--- a/Common/SlaveUtils.py
+++ b/Common/SlaveUtils.py
@@ -37,6 +37,6 @@ def prepare_client_session(host, port, login, passwd=None, command=None,
if prompt is None:
prompt = "Started"
- command = "/%s/%s/%s" % (install_path, test_dir, command)
+ command = "cd /%s/%s/ && ./%s" % (install_path, test_dir, command)
return wait_for_login(host, port, login, passwd, prompt,
command=command, timeout=10)
\ No newline at end of file
11 years, 12 months