All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] test-runner: introduce network namespaces
@ 2020-11-17 20:53 James Prestwood
  2020-11-17 20:53 ` [PATCH 2/4] auto-t: update utilities to use namespaces James Prestwood
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: James Prestwood @ 2020-11-17 20:53 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 12391 bytes --]

Our simulated environment was really only meant to test air-to-air
communication by using mac80211_hwsim. Protocols like DHCP use IP
communication which starts to fall apart when using hwsim radios.
Mainly unicast sockets do not work since there is no underlying
network infrastructure.

In order to simulate a more realistic environment network namespaces
are introduced in this patch. This allows wireless phy's to be added
to a network namespace and unique IWD instances manage those phys.
This is done automatically when 'NameSpaces' entries are configured
in hw.conf:

[SETUP]
num_radios=2

[NameSpaces]
ns0=rad1,...

This will create a namespace named ns0, and add rad1 to that
namespace. rad1 will not appear as a phy in what's being called the
'root' namespace (the default namespace).

As far as a test is concerned you can create a new IWD() class and
pass the namespace in. This will start a new IWD instance in that
namespace:

ns0 = ctx.get_namespace('ns0')
wd_ns0 = IWD(start_iwd=True, namespace=ns0)

'wd_ns0' can now be used to interact with IWD in that namespace, just
like any other IWD class object.
---
 tools/test-runner | 298 ++++++++++++++++++++++++++++++----------------
 1 file changed, 196 insertions(+), 102 deletions(-)

diff --git a/tools/test-runner b/tools/test-runner
index 803d4da5..3a9cfce2 100755
--- a/tools/test-runner
+++ b/tools/test-runner
@@ -126,6 +126,9 @@ dev_table = [
 	DevInfo('/proc/self/fd/2', '/dev/stderr')
 ]
 
+# Partial DBus config. The remainder (<listen>) will be filled in for each
+# namespace that is created so each individual dbus-daemon has its own socket
+# and address.
 dbus_config = '''
 <!DOCTYPE busconfig PUBLIC \
 "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN" \
@@ -133,7 +136,6 @@ dbus_config = '''
 busconfig.dtd\">
 <busconfig>
 <type>system</type>
-<listen>unix:path=/run/dbus/system_bus_socket</listen>
 <limit name=\"reply_timeout\">2147483647</limit>
 <auth>ANONYMOUS</auth>
 <allow_anonymous/>
@@ -151,7 +153,6 @@ busconfig.dtd\">
 <allow send_destination=\"*\" eavesdrop=\"true\"/>
 <allow eavesdrop=\"true\"/>
 </policy>
-</busconfig>
 '''
 class Process:
 	'''
@@ -162,7 +163,7 @@ class Process:
 		test exits.
 	'''
 	def __init__(self, args, wait=False, multi_test=False, env=None, ctx=None, check=False,
-				outfile=None):
+				outfile=None, namespace=None):
 		self.args = args
 		self.wait = wait
 		self.name = args[0]
@@ -172,6 +173,10 @@ class Process:
 		self.ret = None
 		self.ctx = ctx
 
+		if namespace:
+			self.args = ['ip', 'netns', 'exec', namespace]
+			self.args.extend(args)
+
 		if ctx:
 			set_stdout = False
 
@@ -209,7 +214,6 @@ class Process:
 					self.stdout = sys.__stdout__
 					self.stderr = sys.__stderr__
 
-
 		self.pid = subprocess.Popen(self.args, stdout=self.stdout, \
 							stderr=self.stderr, env=env, \
 							cwd=os.getcwd())
@@ -233,9 +237,8 @@ class Process:
 
 	def __del__(self):
 		print("Del process %s" % self.args)
-		if self.ctx and self.ctx.args.log:
-			self.stdout.close()
-			self.stderr.close()
+		self.stdout = None
+		self.stderr = None
 
 	def kill(self, force=False):
 		print("Killing process %s" % self.args)
@@ -469,12 +472,172 @@ class Hostapd:
 		self.instances = None
 		self.process.kill()
 
-class TestContext:
+dbus_count = 0
+
+class Namespace:
+	dbus_address = None
+	processes = []
+	radios = []
+
+	def __init__(self, args, name, radios):
+		self.name = name
+		self.radios = radios
+		self.args = args
+
+		Process(['ip', 'netns', 'add', name], wait=True)
+		for r in radios:
+			Process(['iw', 'phy', r.name, 'set', 'netns', 'name', name], wait=True)
+
+		self.start_dbus(multi_test=False)
+
+	def reset(self):
+		self.radios = []
+		self._bus = None
+
+		if self.name == "root":
+			self._bus = dbus.bus.BusConnection(address_or_type=self.dbus_address)
+
+		for p in [p for p in self.processes if p.multi_test is False]:
+			print("Killing process %s" % p.name)
+			self.stop_process(p)
+
+	def __del__(self):
+		print("Removing namespace %s" % self.name)
+		self.reset()
+
+		Process(['ip', 'netns', 'del', self.name], wait=True)
+
+	def get_bus(self):
+		return self._bus
+
+	def start_process(self, args, env=None, **kwargs):
+		# Special case for 'root' namespace (aka TestContext)
+		if self.name == "root":
+			ns = None
+		else:
+			ns = self.name
+
+		if not env:
+			env = os.environ.copy()
+
+		# In case this process needs DBus...
+		env['DBUS_SYSTEM_BUS_ADDRESS'] = self.dbus_address
+
+		p = Process(args, ctx=self, namespace=ns, env=env, **kwargs)
+
+		if not kwargs.get('wait', False):
+			self.processes.append(p)
+
+		return p
+
+	def stop_process(self, p, force=False):
+		p.kill(force)
+		self.processes.remove(p)
+
+	def is_process_running(self, process):
+		for p in self.processes:
+			if p.name == process:
+				return True
+		return False
+
+	def start_dbus(self, multi_test=True):
+		global dbus_count
+
+		self.dbus_address = 'unix:path=/tmp/dbus%d' % dbus_count
+		dbus_cfg = '/tmp/dbus%d.conf' % dbus_count
+		dbus_count += 1
+
+		with open(dbus_cfg, 'w+') as f:
+			f.write(dbus_config)
+			f.write('<listen>%s</listen>\n' % self.dbus_address)
+			f.write('</busconfig>\n')
+
+		p = self.start_process(['dbus-daemon', '--config-file=%s' % dbus_cfg],
+					wait=False, multi_test=multi_test)
+
+		p.wait_for_socket(self.dbus_address.split('=')[1], wait=5)
+
+		self._bus = dbus.bus.BusConnection(address_or_type=self.dbus_address)
+
+	def start_iwd(self, config_dir = '/tmp'):
+		args = []
+		iwd_radios = ','.join([r.name for r in self.radios if r.use == 'iwd'])
+
+		if self.args.valgrind:
+			args.extend(['valgrind', '--leak-check=full', '--track-origins=yes',
+						'--log-file=/tmp/valgrind.log'])
+
+		args.extend(['iwd', '-p', iwd_radios])
+
+		if self.is_verbose(args[0]):
+			args.append('-d')
+
+		env = os.environ.copy()
+
+		env['CONFIGURATION_DIRECTORY'] = config_dir
+		env['STATE_DIRECTORY'] = '/tmp/iwd'
+
+		if self.is_verbose('iwd-dhcp'):
+			env['IWD_DHCP_DEBUG'] = '1'
+
+		if self.is_verbose('iwd-tls'):
+			env['IWD_TLS_DEBUG'] = '1'
+
+		if self.is_verbose('iwd-genl'):
+			env['IWD_GENL_DEBUG'] = '1'
+
+		pid = self.start_process(args, env=env)
+		return pid
+
+	def is_verbose(self, process):
+		process = os.path.basename(process)
+
+		if self.args is None:
+			return False
+
+		# every process is verbose when logging is enabled
+		if self.args.log:
+			return True
+
+		if process in self.args.verbose:
+			return True
+
+		# Special case here to enable verbose output with valgrind running
+		if process == 'valgrind' and 'iwd' in self.args.verbose:
+			return True
+
+		# Handle any glob matches
+		for item in self.args.verbose:
+			if process in glob(item):
+				return True
+
+		return False
+
+	def __str__(self):
+		ret = 'Namespace: %s\n' % self.name
+		ret += 'Processes:\n'
+		for p in self.processes:
+			ret += '\t%s\n' % str(p.args)
+
+		ret += 'Radios:\n'
+		if len(self.radios) > 0:
+			for r in self.radios:
+				ret += '\t%s\n' % str(r)
+		else:
+			ret += '\tNo Radios\n'
+
+		ret += 'DBus Address: %s\n' % self.dbus_address
+		ret += '===================================================\n\n'
+
+		return ret
+
+class TestContext(Namespace):
 	'''
 		Contains all information for a given set of tests being run
 		such as processes, radios, interfaces and test results.
 	'''
 	def __init__(self, args):
+		self.name = "root"
 		self.processes = []
 		self.args = args
 		self.hw_config = None
@@ -484,31 +647,15 @@ class TestContext:
 		self.cur_iface_id = 0
 		self.radios = []
 		self.loopback_started = False
-		self.iwd_extra_options = None
 		self.results = {}
 		self.mainloop = GLib.MainLoop()
-
-	def start_process(self, args, **kwargs):
-		p = Process(args, ctx=self, **kwargs)
-
-		if not kwargs.get('wait', False):
-			self.processes.append(p)
-
-		return p
-
-	def start_dbus(self):
-		with open('/usr/share/dbus-1/system.conf', 'w+') as f:
-			f.write(dbus_config)
-
-		os.mkdir('/run/dbus', 755)
-
-		self.start_process(['dbus-daemon', '--system', '--nosyslog'], multi_test=True)
+		self.namespaces = []
 
 	def start_dbus_monitor(self):
 		if not self.is_verbose('dbus-monitor'):
 			return
 
-		self.start_process(['dbus-monitor', '--system'])
+		self.start_process(['dbus-monitor', '--address', self.dbus_address])
 
 	def start_haveged(self):
 		self.start_process(['haveged'], multi_test=True)
@@ -561,38 +708,6 @@ class TestContext:
 		else:
 			self.create_radios()
 
-	def start_iwd(self, config_dir = '/tmp'):
-		args = []
-		iwd_radios = ','.join([r.name for r in self.radios if r.use == 'iwd'])
-
-		if self.args.valgrind:
-			args.extend(['valgrind', '--leak-check=full', '--track-origins=yes',
-						'--log-file=/tmp/valgrind.log'])
-
-		args.extend(['iwd', '-p', iwd_radios])
-
-		if self.is_verbose(args[0]):
-			args.append('-d')
-
-		if self.iwd_extra_options:
-			args.append(self.iwd_extra_options)
-
-		env = os.environ.copy()
-		env['CONFIGURATION_DIRECTORY'] = config_dir
-		env['STATE_DIRECTORY'] = '/tmp/iwd'
-
-		if self.is_verbose('iwd-dhcp'):
-			env['IWD_DHCP_DEBUG'] = '1'
-
-		if self.is_verbose('iwd-tls'):
-			env['IWD_TLS_DEBUG'] = '1'
-
-		if self.is_verbose('iwd-genl'):
-			env['IWD_GENL_DEBUG'] = '1'
-
-		pid = self.start_process(args, env=env)
-		return pid
-
 	def start_hostapd(self):
 		if not 'HOSTAPD' in self.hw_config:
 			return
@@ -677,66 +792,39 @@ class TestContext:
 
 		print("Ofono started")
 
-	def is_verbose(self, process):
-		process = os.path.basename(process)
+	def create_namespaces(self):
+		if not self.hw_config.has_section('NameSpaces'):
+			return
 
-		if self.args is None:
-			return False
+		for key, value in self.hw_config.items('NameSpaces'):
+			radio_names = value.split(',')
+			# Gather up radio objects for this namespace
+			radios = [rad for rad in self.radios if rad.name in radio_names]
 
-		# every process is verbose when logging is enabled
-		if self.args.log:
-			return True
+			# Remove radios from 'root' namespace
+			self.radios = list(set(self.radios) - set(radios))
 
-		if process in self.args.verbose:
-			return True
+			self.namespaces.append(Namespace(self.args, key, radios))
 
-		# Special case here to enable verbose output with valgrind running
-		if process == 'valgrind' and 'iwd' in self.args.verbose:
-			return True
-
-		# Handle any glob matches
-		for item in self.args.verbose:
-			if process in glob(item):
-				return True
-
-		return False
+	def get_namespace(self, ns):
+		for n in self.namespaces:
+			if n.name == ns:
+				return n
 
-	def stop_process(self, p, force=False):
-		p.kill(force)
-		self.processes.remove(p)
+		return None
 
 	def stop_test_processes(self):
-		self.radios = []
+		self.namespaces = []
 		self.hostapd = None
 		self.wpas_interfaces = None
-		self.iwd_extra_options = None
 
-		for p in [p for p in self.processes if p.multi_test is False]:
-			print("Killing process %s" % p.name)
-			self.stop_process(p)
-
-	def is_process_running(self, process):
-		for p in self.processes:
-			if p.name == process:
-				return True
-		return False
+		self.reset()
 
 	def __str__(self):
 		ret = 'Arguments:\n'
 		for arg in vars(self.args):
 			ret += '\t --%s %s\n' % (arg, str(getattr(self.args, arg)))
 
-		ret += 'Processes:\n'
-		for p in self.processes:
-			ret += '\t%s\n' % str(p.args)
-
-		ret += 'Radios:\n'
-		if len(self.radios) > 0:
-			for r in self.radios:
-				ret += '\t%s\n' % str(r)
-		else:
-			ret += '\tNo Radios\n'
-
 		ret += 'Hostapd:\n'
 		if self.hostapd:
 			for h in self.hostapd.instances:
@@ -744,6 +832,11 @@ class TestContext:
 		else:
 			ret += '\tNo Hostapd instances\n'
 
+		ret += super().__str__()
+
+		for n in self.namespaces:
+			ret += n.__str__()
+
 		return ret
 
 def prepare_sandbox():
@@ -921,6 +1014,7 @@ def pre_test(ctx, test):
 
 	ctx.start_dbus_monitor()
 	ctx.start_radios()
+	ctx.create_namespaces()
 	ctx.start_hostapd()
 	ctx.start_wpas_interfaces()
 	ctx.start_ofono()
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] auto-t: update utilities to use namespaces
  2020-11-17 20:53 [PATCH 1/4] test-runner: introduce network namespaces James Prestwood
@ 2020-11-17 20:53 ` James Prestwood
  2020-11-17 20:53 ` [PATCH 3/4] auto-t: add test_ip_connected to testutil James Prestwood
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: James Prestwood @ 2020-11-17 20:53 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 9247 bytes --]

---
 autotests/util/ead.py   |  2 +-
 autotests/util/hwsim.py | 10 ++++-----
 autotests/util/iwd.py   | 49 +++++++++++++++++++++++------------------
 autotests/util/ofono.py |  5 +++--
 4 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/autotests/util/ead.py b/autotests/util/ead.py
index 356b0b9b..3a613bbe 100644
--- a/autotests/util/ead.py
+++ b/autotests/util/ead.py
@@ -75,7 +75,7 @@ class AdapterList(collections.Mapping):
             del self._dict[path]
 
 class EAD(iwd.AsyncOpAbstract):
-    _bus = dbus.SystemBus()
+    _bus = ctx.get_bus()
 
     _object_manager_if = None
     _adapters = None
diff --git a/autotests/util/hwsim.py b/autotests/util/hwsim.py
index 4f41952f..415bfc90 100755
--- a/autotests/util/hwsim.py
+++ b/autotests/util/hwsim.py
@@ -7,6 +7,7 @@ from abc import ABCMeta, abstractmethod
 from enum import Enum
 
 import iwd
+from config import ctx
 
 HWSIM_SERVICE =                 'net.connman.hwsim'
 HWSIM_RULE_MANAGER_INTERFACE =  'net.connman.hwsim.RuleManager'
@@ -20,9 +21,8 @@ HWSIM_AGENT_MANAGER_PATH =      '/'
 class HwsimDBusAbstract(iwd.AsyncOpAbstract):
     __metaclass__ = ABCMeta
 
-    _bus = dbus.SystemBus()
-
-    def __init__(self, object_path, properties = None):
+    def __init__(self, object_path, properties = None, namespace=ctx):
+        self._bus = namespace.get_bus()
         self._object_path = object_path
         proxy = self._bus.get_object(HWSIM_SERVICE, self._object_path)
         self._iface = dbus.Interface(proxy, self._iface_name)
@@ -256,9 +256,9 @@ class RadioList(collections.Mapping):
         return obj
 
 class Hwsim(iwd.AsyncOpAbstract):
-    _bus = dbus.SystemBus()
+    def __init__(self, namespace=ctx):
+        self._bus = namespace.get_bus()
 
-    def __init__(self):
         self._rule_manager_if = dbus.Interface(
                 self._bus.get_object(HWSIM_SERVICE, '/'),
                 HWSIM_RULE_MANAGER_INTERFACE)
diff --git a/autotests/util/iwd.py b/autotests/util/iwd.py
index af3ecd05..bb4ecefa 100755
--- a/autotests/util/iwd.py
+++ b/autotests/util/iwd.py
@@ -122,9 +122,9 @@ class AsyncOpAbstract(object):
 class IWDDBusAbstract(AsyncOpAbstract):
     __metaclass__ = ABCMeta
 
-    _bus = dbus.SystemBus()
+    def __init__(self, object_path = None, properties = None, service=IWD_SERVICE, namespace=ctx):
+        self._bus = namespace.get_bus()
 
-    def __init__(self, object_path = None, properties = None, service=IWD_SERVICE):
         self._object_path = object_path
         proxy = self._bus.get_object(service, self._object_path)
         self._iface = dbus.Interface(proxy, self._iface_name)
@@ -190,7 +190,7 @@ class SignalAgent(dbus.service.Object):
     def __init__(self, passphrase = None):
         self._path = '/test/agent/' + str(int(round(time.time() * 1000)))
 
-        dbus.service.Object.__init__(self, dbus.SystemBus(), self._path)
+        dbus.service.Object.__init__(self, ctx.get_bus(), self._path)
 
     @property
     def path(self):
@@ -391,7 +391,7 @@ class Device(IWDDBusAbstract):
         '''
         ordered_networks = []
         for bus_obj in self._station.GetOrderedNetworks():
-            ordered_network = OrderedNetwork(bus_obj)
+            ordered_network = OrderedNetwork(bus_obj, self._bus)
             ordered_networks.append(ordered_network)
 
         if len(ordered_networks) > 0:
@@ -407,7 +407,7 @@ class Device(IWDDBusAbstract):
         IWD._wait_for_object_condition(self, condition)
 
         for bus_obj in self._station.GetOrderedNetworks():
-            ordered_network = OrderedNetwork(bus_obj)
+            ordered_network = OrderedNetwork(bus_obj, self._bus)
             ordered_networks.append(ordered_network)
 
         if len(ordered_networks) > 0:
@@ -643,9 +643,8 @@ class KnownNetwork(IWDDBusAbstract):
 class OrderedNetwork(object):
     '''Represents a network found in the scan'''
 
-    _bus = dbus.SystemBus()
-
-    def __init__(self, o_n_tuple):
+    def __init__(self, o_n_tuple, bus):
+        self._bus = bus
         self._network_object = Network(o_n_tuple[0])
         self._network_proxy = dbus.Interface(self._bus.get_object(IWD_SERVICE,
                                         o_n_tuple[0]),
@@ -707,7 +706,7 @@ agent_count = 0
 
 class PSKAgent(dbus.service.Object):
 
-    def __init__(self, passphrases=[], users=[]):
+    def __init__(self, passphrases=[], users=[], namespace=ctx):
         global agent_count
 
         if type(passphrases) != list:
@@ -720,7 +719,7 @@ class PSKAgent(dbus.service.Object):
 
         agent_count += 1
 
-        dbus.service.Object.__init__(self, dbus.SystemBus(), self._path)
+        dbus.service.Object.__init__(self, namespace.get_bus(), self._path)
 
     @property
     def path(self):
@@ -882,6 +881,7 @@ class DeviceList(collections.Mapping):
     def __init__(self, iwd):
         self._dict = {}
         self._p2p_dict = {}
+        self._namespace = iwd.namespace
 
         iwd._object_manager.connect_to_signal("InterfacesAdded",
                                                self._interfaces_added_handler)
@@ -893,9 +893,11 @@ class DeviceList(collections.Mapping):
         for path in objects:
             for interface in objects[path]:
                 if interface == IWD_DEVICE_INTERFACE:
-                    self._dict[path] = Device(path, objects[path][interface])
+                    self._dict[path] = Device(path, objects[path][interface],
+                                                namespace=self._namespace)
                 elif interface == IWD_P2P_INTERFACE:
-                    self._p2p_dict[path] = P2PDevice(path, objects[path][interface])
+                    self._p2p_dict[path] = P2PDevice(path, objects[path][interface],
+                                                namespace=self._namespace)
 
     def __getitem__(self, key):
         return self._dict.__getitem__(key)
@@ -911,9 +913,11 @@ class DeviceList(collections.Mapping):
 
     def _interfaces_added_handler(self, path, interfaces):
         if IWD_DEVICE_INTERFACE in interfaces:
-            self._dict[path] = Device(path, interfaces[IWD_DEVICE_INTERFACE])
+            self._dict[path] = Device(path, interfaces[IWD_DEVICE_INTERFACE],
+                                            namespace=self._namespace)
         elif IWD_P2P_INTERFACE in interfaces:
-            self._p2p_dict[path] = P2PDevice(path, interfaces[IWD_P2P_INTERFACE])
+            self._p2p_dict[path] = P2PDevice(path, interfaces[IWD_P2P_INTERFACE],
+                                            namespace=self._namespace)
 
     def _interfaces_removed_handler(self, path, interfaces):
         if IWD_DEVICE_INTERFACE in interfaces:
@@ -932,8 +936,6 @@ class IWD(AsyncOpAbstract):
         some tests do require starting IWD using this constructor (by passing
         start_iwd_daemon=True)
     '''
-    _bus = dbus.SystemBus()
-
     _object_manager_if = None
     _agent_manager_if = None
     _iwd_proc = None
@@ -941,19 +943,22 @@ class IWD(AsyncOpAbstract):
     _default_instance = None
     psk_agent = None
 
-    def __init__(self, start_iwd_daemon = False, iwd_config_dir = '/tmp'):
-        if start_iwd_daemon and ctx.is_process_running('iwd'):
-            raise Exception("IWD requested to start but is already running")
+    def __init__(self, start_iwd_daemon = False, iwd_config_dir = '/tmp', namespace=ctx):
+        self.namespace = namespace
+        self._bus = namespace.get_bus()
 
         if start_iwd_daemon:
-            self._iwd_proc = ctx.start_iwd(iwd_config_dir)
+            if self.namespace.is_process_running('iwd'):
+                raise Exception("IWD requested to start but is already running")
+
+            self._iwd_proc = self.namespace.start_iwd(iwd_config_dir)
 
         tries = 0
         while not self._bus.name_has_owner(IWD_SERVICE):
             if not ctx.args.gdb:
                 if tries > 200:
                     if start_iwd_daemon:
-                        ctx.stop_process(self._iwd_proc)
+                        self.namespace.stop_process(self._iwd_proc)
                         self._iwd_proc = None
                     raise TimeoutError('IWD has failed to start')
                 tries += 1
@@ -978,7 +983,7 @@ class IWD(AsyncOpAbstract):
         self._devices = None
 
         if self._iwd_proc is not None:
-            ctx.stop_process(self._iwd_proc)
+            self.namespace.stop_process(self._iwd_proc)
             self._iwd_proc = None
 
     @property
diff --git a/autotests/util/ofono.py b/autotests/util/ofono.py
index f1ed14ee..584a656a 100644
--- a/autotests/util/ofono.py
+++ b/autotests/util/ofono.py
@@ -1,12 +1,13 @@
 import dbus
 import time
 from gi.repository import GLib
+from config import ctx
 
 SIM_AUTH_IFACE = 'org.ofono.SimAuthentication'
 
 class Ofono(dbus.service.Object):
-    def __init__(self):
-        self._bus = dbus.SystemBus()
+    def __init__(self, namespace=ctx):
+        self._bus = namespace.get_bus()
 
         tries = 0
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] auto-t: add test_ip_connected to testutil
  2020-11-17 20:53 [PATCH 1/4] test-runner: introduce network namespaces James Prestwood
  2020-11-17 20:53 ` [PATCH 2/4] auto-t: update utilities to use namespaces James Prestwood
@ 2020-11-17 20:53 ` James Prestwood
  2020-11-17 20:53 ` [PATCH 4/4] auto-t: add namespaces to testAP James Prestwood
  2020-11-18 17:01 ` [PATCH 1/4] test-runner: introduce network namespaces Denis Kenzior
  3 siblings, 0 replies; 5+ messages in thread
From: James Prestwood @ 2020-11-17 20:53 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 916 bytes --]

Used to check IP connectivity between namespaces. The input
should be two tuples containing the IP and namespace to ping
from/to.
---
 autotests/util/testutil.py | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/autotests/util/testutil.py b/autotests/util/testutil.py
index faa81f65..94f8ef32 100644
--- a/autotests/util/testutil.py
+++ b/autotests/util/testutil.py
@@ -152,3 +152,13 @@ def test_ip_address_match(intf, ip):
 
     if ip != addr:
         raise Exception('IP for %s did not match %s (was %s)' % (intf, ip, addr))
+
+def test_ip_connected(tup0, tup1):
+    ip0, ns0 = tup0
+    ip1, ns1 = tup1
+
+    try:
+        ns0.start_process(['ping', '-c', '5', '-i', '0.2', ip1], check=True)
+        ns1.start_process(['ping', '-c', '5', '-i', '0.2', ip0], check=True)
+    except:
+        raise Exception('Could not ping between %s and %s' % (ip0, ip1))
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/4] auto-t: add namespaces to testAP
  2020-11-17 20:53 [PATCH 1/4] test-runner: introduce network namespaces James Prestwood
  2020-11-17 20:53 ` [PATCH 2/4] auto-t: update utilities to use namespaces James Prestwood
  2020-11-17 20:53 ` [PATCH 3/4] auto-t: add test_ip_connected to testutil James Prestwood
@ 2020-11-17 20:53 ` James Prestwood
  2020-11-18 17:01 ` [PATCH 1/4] test-runner: introduce network namespaces Denis Kenzior
  3 siblings, 0 replies; 5+ messages in thread
From: James Prestwood @ 2020-11-17 20:53 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1920 bytes --]

---
 autotests/testAP/dhcp_config_test.py | 19 +++++++++++++++----
 autotests/testAP/hw.conf             |  6 +++++-
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/autotests/testAP/dhcp_config_test.py b/autotests/testAP/dhcp_config_test.py
index a278c3b7..975cab4d 100644
--- a/autotests/testAP/dhcp_config_test.py
+++ b/autotests/testAP/dhcp_config_test.py
@@ -16,7 +16,15 @@ class Test(unittest.TestCase):
         # this range.
         wd = IWD(True, '/tmp/dhcp')
 
-        dev1, dev2 = wd.list_devices(2)
+        ns0 = ctx.get_namespace('ns0')
+
+        wd_ns0 = IWD(True, '/tmp/dhcp', namespace=ns0)
+
+        dev1 = wd_ns0.list_devices(1)[0]
+        dev2, dev3, dev4, dev5 = wd.list_devices(4)
+        dev3.disconnect()
+        dev4.disconnect()
+        dev5.disconnect()
 
         dev1.start_ap('APConfig')
 
@@ -51,11 +59,14 @@ class Test(unittest.TestCase):
             wd.wait_for_object_condition(dev2, condition)
 
             testutil.test_iface_operstate(dev2.name)
-            testutil.test_ifaces_connected(dev1.name, dev2.name, group=False)
-
-            testutil.test_ip_address_match(dev1.name, "192.168.1.1")
+            #
+            # TODO: cannot yet check the AP interface IP since its in a
+            #       different namespace.
+            #
             testutil.test_ip_address_match(dev2.name, "192.168.1.3")
 
+            testutil.test_ip_connected(('192.168.1.3', ctx), ('192.168.1.1', ns0))
+
             wd.unregister_psk_agent(psk_agent)
 
             dev2.disconnect()
diff --git a/autotests/testAP/hw.conf b/autotests/testAP/hw.conf
index bac128b2..c9c0c7ca 100644
--- a/autotests/testAP/hw.conf
+++ b/autotests/testAP/hw.conf
@@ -1,6 +1,10 @@
 [SETUP]
-num_radios=5
+num_radios=6
 start_iwd=0
+hwsim_medium=no
 
 [HOSTAPD]
 rad0=psk-ccmp.conf
+
+[NameSpaces]
+ns0=rad5
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/4] test-runner: introduce network namespaces
  2020-11-17 20:53 [PATCH 1/4] test-runner: introduce network namespaces James Prestwood
                   ` (2 preceding siblings ...)
  2020-11-17 20:53 ` [PATCH 4/4] auto-t: add namespaces to testAP James Prestwood
@ 2020-11-18 17:01 ` Denis Kenzior
  3 siblings, 0 replies; 5+ messages in thread
From: Denis Kenzior @ 2020-11-18 17:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1458 bytes --]

Hi James,

On 11/17/20 2:53 PM, James Prestwood wrote:
> Our simulated environment was really only meant to test air-to-air
> communication by using mac80211_hwsim. Protocols like DHCP use IP
> communication which starts to fall apart when using hwsim radios.
> Mainly unicast sockets do not work since there is no underlying
> network infrastructure.
> 
> In order to simulate a more realistic environment network namespaces
> are introduced in this patch. This allows wireless phy's to be added
> to a network namespace and unique IWD instances manage those phys.
> This is done automatically when 'NameSpaces' entries are configured
> in hw.conf:
> 
> [SETUP]
> num_radios=2
> 
> [NameSpaces]
> ns0=rad1,...
> 
> This will create a namespace named ns0, and add rad1 to that
> namespace. rad1 will not appear as a phy in what's being called the
> 'root' namespace (the default namespace).
> 
> As far as a test is concerned you can create a new IWD() class and
> pass the namespace in. This will start a new IWD instance in that
> namespace:
> 
> ns0 = ctx.get_namespace('ns0')
> wd_ns0 = IWD(start_iwd=True, namespace=ns0)
> 
> 'wd_ns0' can now be used to interact with IWD in that namespace, just
> like any other IWD class object.
> ---
>   tools/test-runner | 298 ++++++++++++++++++++++++++++++----------------
>   1 file changed, 196 insertions(+), 102 deletions(-)
> 

All applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-11-18 17:01 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-17 20:53 [PATCH 1/4] test-runner: introduce network namespaces James Prestwood
2020-11-17 20:53 ` [PATCH 2/4] auto-t: update utilities to use namespaces James Prestwood
2020-11-17 20:53 ` [PATCH 3/4] auto-t: add test_ip_connected to testutil James Prestwood
2020-11-17 20:53 ` [PATCH 4/4] auto-t: add namespaces to testAP James Prestwood
2020-11-18 17:01 ` [PATCH 1/4] test-runner: introduce network namespaces Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.