[lnst: 9/11] NetTestSlave: add methods {create, deconfigure}_if_pair
by Jiří Pírko
commit aaf369d3aa5f2376a62b289c9c396f68510d18e8
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:34 2014 +0200
NetTestSlave: add methods {create, deconfigure}_if_pair
These two new methods are used to create paired interfaces, such as
veth. Since these devices are created together LNST representation of
the devices needs to reflect that. After device creation the method also
takes care of moving the devices to the correct network namespaces.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Slave/InterfaceManager.py | 36 ++++++++++++++++
lnst/Slave/NetTestSlave.py | 89 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+), 0 deletions(-)
---
diff --git a/lnst/Slave/InterfaceManager.py b/lnst/Slave/InterfaceManager.py
index 3695fe2..e30b52a 100644
--- a/lnst/Slave/InterfaceManager.py
+++ b/lnst/Slave/InterfaceManager.py
@@ -156,6 +156,24 @@ class InterfaceManager(object):
self._tmp_mapping[if_id] = device
return config["name"]
+ def create_device_pair(self, if_id1, config1, if_id2, config2):
+ name1, name2 = self.assign_name(config1)
+ config1["name"] = name1
+ config2["name"] = name2
+ config1["peer_name"] = name2
+ config2["peer_name"] = name1
+
+ device1 = Device(self)
+ device2 = Device(self)
+
+ device1.set_configuration(config1)
+ device2.set_configuration(config2)
+ device1.create()
+
+ self._tmp_mapping[if_id1] = device1
+ self._tmp_mapping[if_id2] = device2
+ return name1, name2
+
def _is_name_used(self, name):
for device in self._devices.itervalues():
if name == device.get_name():
@@ -168,6 +186,16 @@ class InterfaceManager(object):
index += 1
return prefix + str(index)
+ def _assign_name_pair(self, prefix):
+ index1 = 0
+ index2 = 0
+ while (self._is_name_used(prefix + str(index1))):
+ index1 += 1
+ index2 = index1 + 1
+ while (self._is_name_used(prefix + str(index2))):
+ index2 += 1
+ return prefix + str(index1), prefix + str(index2)
+
def assign_name(self, config):
if "name" in config:
return config["name"]
@@ -193,6 +221,10 @@ class InterfaceManager(object):
vlan_tci = get_option(config, "vlan_tci")
prefix = "%s.%s_" % (netdev_name, vlan_tci)
return self._assign_name_generic(prefix)
+ elif dev_type == "veth":
+ return self._assign_name_pair("veth")
+ else:
+ return self._assign_name_generic("dev")
class Device(object):
def __init__(self, if_manager):
@@ -306,6 +338,10 @@ class Device(object):
def get_configuration(self):
return self._conf
+ def del_configuration(self):
+ self._conf = None
+ self._conf_dict = None
+
def clear_configuration(self):
if self._master["primary"]:
primary_id = self._master["primary"]
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index ca714e2..d2f7834 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -166,6 +166,95 @@ class SlaveMethods:
dev.configure()
return dev_name
+ def create_if_pair(self, if_id1, config1, if_id2, config2):
+ dev_names = self._if_manager.create_device_pair(if_id1, config1,
+ if_id2, config2)
+ dev1 = self._if_manager.get_mapped_device(if_id1)
+ dev2 = self._if_manager.get_mapped_device(if_id2)
+
+ while dev1.get_if_index() == None and dev2.get_if_index() == None:
+ msgs = self._server_handler.get_messages_from_con('netlink')
+ for msg in msgs:
+ self._if_manager.handle_netlink_msgs(msg[1]["data"])
+
+ if config1["netns"] != None:
+ hwaddr = dev1.get_hwaddr()
+ self.set_if_netns(if_id1, config1["netns"])
+
+ msg = {"type": "command", "method_name": "map_if_by_hwaddr",
+ "args": [if_id1, hwaddr]}
+ self._server_handler.send_data_to_netns(config1["netns"], msg)
+ result = self._slave_server.wait_for_result(config1["netns"])
+ if len(result["result"]) != 1:
+ raise Exception("Mapping failed.")
+
+ msg = {"type": "command", "method_name": "configure_interface",
+ "args": [if_id1, config1]}
+ self._server_handler.send_data_to_netns(config1["netns"], msg)
+ result = self._slave_server.wait_for_result(config1["netns"])
+ if result["result"] != True:
+ raise Exception("Configuration failed.")
+ else:
+ dev1.configure()
+ if config2["netns"] != None:
+ hwaddr = dev2.get_hwaddr()
+ self.set_if_netns(if_id2, config2["netns"])
+
+ msg = {"type": "command", "method_name": "map_if_by_hwaddr",
+ "args": [if_id2, hwaddr]}
+ self._server_handler.send_data_to_netns(config2["netns"], msg)
+ result = self._slave_server.wait_for_result(config2["netns"])
+ if len(result["result"]) != 1:
+ raise Exception("Mapping failed.")
+
+ msg = {"type": "command", "method_name": "configure_interface",
+ "args": [if_id2, config2]}
+ self._server_handler.send_data_to_netns(config2["netns"], msg)
+ result = self._slave_server.wait_for_result(config2["netns"])
+ if result["result"] != True:
+ raise Exception("Configuration failed.")
+ else:
+ dev2.configure()
+ return dev_names
+
+ def deconfigure_if_pair(self, if_id1, if_id2):
+ dev1 = self._if_manager.get_mapped_device(if_id1)
+ dev2 = self._if_manager.get_mapped_device(if_id2)
+
+ if dev1.get_netns() == None:
+ dev1.deconfigure()
+ else:
+ netns = dev1.get_netns()
+
+ msg = {"type": "command", "method_name": "deconfigure_interface",
+ "args": [if_id1]}
+ self._server_handler.send_data_to_netns(netns, msg)
+ result = self._slave_server.wait_for_result(netns)
+ if result["result"] != True:
+ raise Exception("Deconfiguration failed.")
+
+ self.return_if_netns(if_id1)
+
+ if dev2.get_netns() == None:
+ dev2.deconfigure()
+ else:
+ netns = dev2.get_netns()
+
+ msg = {"type": "command", "method_name": "deconfigure_interface",
+ "args": [if_id2]}
+ self._server_handler.send_data_to_netns(netns, msg)
+ result = self._slave_server.wait_for_result(netns)
+ if result["result"] != True:
+ raise Exception("Deconfiguration failed.")
+
+ self.return_if_netns(if_id2)
+
+ dev1.destroy()
+ dev2.destroy()
+ dev1.del_configuration()
+ dev2.del_configuration()
+ return True
+
def deconfigure_interface(self, if_id):
device = self._if_manager.get_mapped_device(if_id)
device.clear_configuration()
9 years, 8 months
[lnst: 8/11] *ConfigDevice: add VEth classes
by Jiří Pírko
commit 960c68c59a52c9672dcf53e303a557cf5a818835
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:33 2014 +0200
*ConfigDevice: add VEth classes
This patch adds the classes NetConfigDeviceVEth and NmConfigDeviceVEth.
That represent configuration of veth type devices. Since NM doesn't
support veth devices, the NmConfigDeviceVEth class just to defines the
is_nm_managed method.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Slave/NetConfigDevice.py | 22 +++++++++++++++++++++-
lnst/Slave/NmConfigDevice.py | 9 ++++++++-
2 files changed, 29 insertions(+), 2 deletions(-)
---
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py
index d64c471..2a15a82 100644
--- a/lnst/Slave/NetConfigDevice.py
+++ b/lnst/Slave/NetConfigDevice.py
@@ -394,6 +394,25 @@ class NetConfigDeviceOvsBridge(NetConfigDeviceGeneric):
self._del_ports()
+class NetConfigDeviceVEth(NetConfigDeviceGeneric):
+ _modulename = ""
+ _moduleload = False
+
+ def create(self):
+ conf = self._dev_config
+ exec_cmd("ip link add %s type veth peer name %s" % (conf["name"],
+ conf["peer_name"]))
+
+ def destroy(self):
+ conf = self._dev_config
+ exec_cmd("ip link del %s" % conf["name"])
+
+ def configure(self):
+ #no configuration options supported at the moment
+ return True
+
+ def deconfigure(self):
+ return True
type_class_mapping = {
"eth": NetConfigDeviceEth,
@@ -402,7 +421,8 @@ type_class_mapping = {
"macvlan": NetConfigDeviceMacvlan,
"vlan": NetConfigDeviceVlan,
"team": NetConfigDeviceTeam,
- "ovs_bridge": NetConfigDeviceOvsBridge
+ "ovs_bridge": NetConfigDeviceOvsBridge,
+ "veth": NetConfigDeviceVEth
}
def NetConfigDevice(dev_config, if_manager):
diff --git a/lnst/Slave/NmConfigDevice.py b/lnst/Slave/NmConfigDevice.py
index 718bd9f..37251e9 100644
--- a/lnst/Slave/NmConfigDevice.py
+++ b/lnst/Slave/NmConfigDevice.py
@@ -805,6 +805,12 @@ class NmConfigDeviceOvsBridge(NmConfigDeviceGeneric):
return managed
+class NmConfigDeviceVEth(NmConfigDeviceGeneric):
+ #Not supported by NetworkManager
+ @classmethod
+ def is_nm_managed(cls, dev_config, if_manager):
+ return False
+
type_class_mapping = {
"eth": NmConfigDeviceEth,
"bond": NmConfigDeviceBond,
@@ -812,7 +818,8 @@ type_class_mapping = {
"macvlan": NmConfigDeviceMacvlan,
"vlan": NmConfigDeviceVlan,
"team": NmConfigDeviceTeam,
- "ovs_bridge": NmConfigDeviceOvsBridge
+ "ovs_bridge": NmConfigDeviceOvsBridge,
+ "veth": NmConfigDeviceVEth
}
def is_nm_managed(dev_config, if_manager):
9 years, 8 months
[lnst: 7/11] *ConfigDevice: split device creation and configuration
by Jiří Pírko
commit 2599992e2798423fe80540e779f132818278914e
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:32 2014 +0200
*ConfigDevice: split device creation and configuration
This patch splits the device creation (destruction) part of configure
(deconfigure) method of ConfigDevice objects into it's own separate
method create (destroy). This split is usefull mostly for configuring
veth devices, however to keep the code consistent I changed all other
device types as well.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Slave/InterfaceManager.py | 18 +++++++++++-
lnst/Slave/NetConfigDevice.py | 58 +++++++++++++++++++++++++--------------
lnst/Slave/NetTestSlave.py | 5 +++-
lnst/Slave/NmConfigDevice.py | 6 ++++
4 files changed, 64 insertions(+), 23 deletions(-)
---
diff --git a/lnst/Slave/InterfaceManager.py b/lnst/Slave/InterfaceManager.py
index 16eba2d..3695fe2 100644
--- a/lnst/Slave/InterfaceManager.py
+++ b/lnst/Slave/InterfaceManager.py
@@ -151,7 +151,7 @@ class InterfaceManager(object):
device = Device(self)
device.set_configuration(config)
- device.configure()
+ device.create()
self._tmp_mapping[if_id] = device
return config["name"]
@@ -198,6 +198,7 @@ class Device(object):
def __init__(self, if_manager):
self._initialized = False
self._configured = False
+ self._created = False
self._if_index = None
self._hwaddr = None
@@ -320,6 +321,7 @@ class Device(object):
if self._conf != None:
self.down()
self.deconfigure()
+ self.destroy()
self._conf = None
self._conf_dict = None
@@ -354,6 +356,20 @@ class Device(object):
if if_index in self._slaves:
self._slaves.remove(if_index)
+ def create(self):
+ if self._conf != None and not self._created:
+ self._conf.create()
+ self._created = True
+ return True
+ return False
+
+ def destroy(self):
+ if self._conf != None and self._created:
+ self._conf.destroy()
+ self._created = False
+ return True
+ return False
+
def configure(self):
if self._conf != None and not self._configured:
self._conf.configure()
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py
index 86744db..d64c471 100644
--- a/lnst/Slave/NetConfigDevice.py
+++ b/lnst/Slave/NetConfigDevice.py
@@ -50,6 +50,12 @@ class NetConfigDeviceGeneric(object):
def slave_del(self, slave_id):
pass
+ def create(self):
+ pass
+
+ def destroy(self):
+ pass
+
def up(self):
config = self._dev_config
if "addresses" in config:
@@ -120,14 +126,18 @@ class NetConfigDeviceBond(NetConfigDeviceGeneric):
exec_cmd('echo "%s%s" > %s/slaves' % (mark, slave_name,
self._get_bond_dir()))
- def configure(self):
+ def create(self):
self._add_rm_bond("+")
+
+ def destroy(self):
+ self._add_rm_bond("-")
+
+ def configure(self):
self._setup_options()
self._add_rm_slaves("+")
def deconfigure(self):
self._add_rm_slaves("-")
- self._add_rm_bond("-")
class NetConfigDeviceBridge(NetConfigDeviceGeneric):
_modulename = "bridge"
@@ -144,13 +154,17 @@ class NetConfigDeviceBridge(NetConfigDeviceGeneric):
for slave_id in get_slaves(self._dev_config):
self._add_rm_port(prefix, slave_id)
- def configure(self):
+ def create(self):
self._add_rm_bridge("add")
+
+ def destroy(self):
+ self._add_rm_bridge("del")
+
+ def configure(self):
self._add_rm_ports("add")
def deconfigure(self):
self._add_rm_ports("del")
- self._add_rm_bridge("del")
def slave_add(self, slave_id):
self._add_rm_port("add", slave_id)
@@ -161,7 +175,7 @@ class NetConfigDeviceBridge(NetConfigDeviceGeneric):
class NetConfigDeviceMacvlan(NetConfigDeviceGeneric):
_modulename = "macvlan"
- def configure(self):
+ def create(self):
config = self._dev_config;
realdev_id = config["slaves"][0]
realdev_name = self._if_manager.get_mapped_device(realdev_id).get_name()
@@ -175,7 +189,7 @@ class NetConfigDeviceMacvlan(NetConfigDeviceGeneric):
exec_cmd("ip link add link %s %s%s type macvlan"
% (realdev_name, dev_name, hwaddr))
- def deconfigure(self):
+ def destroy(self):
dev_name = self._dev_config["name"]
exec_cmd("ip link del %s" % dev_name)
@@ -198,7 +212,7 @@ class NetConfigDeviceVlan(NetConfigDeviceGeneric):
vlan_tci = int(get_option(config, "vlan_tci"))
return dev_name, realdev_name, vlan_tci
- def configure(self):
+ def create(self):
dev_name, realdev_name, vlan_tci = self._get_vlan_info()
if self._check_ip_link_add():
exec_cmd("ip link add link %s %s type vlan id %d"
@@ -210,7 +224,7 @@ class NetConfigDeviceVlan(NetConfigDeviceGeneric):
raise Exception("Bad vlan device name")
exec_cmd("vconfig add %s %d" % (realdev_name, vlan_tci))
- def deconfigure(self):
+ def destroy(self):
dev_name = self._get_vlan_info()[0]
if self._check_ip_link_add():
exec_cmd("ip link del %s" % dev_name)
@@ -252,9 +266,7 @@ class NetConfigDeviceTeam(NetConfigDeviceGeneric):
port_dev = self._if_manager.get_mapped_device(slave_id)
port_dev.up()
- def configure(self):
- self._ports_down()
-
+ def create(self):
teamd_config = get_option(self._dev_config, "teamd_config")
teamd_config = prepare_json_str(teamd_config)
@@ -263,6 +275,13 @@ class NetConfigDeviceTeam(NetConfigDeviceGeneric):
dbus_option = " -D" if self._should_enable_dbus() else ""
exec_cmd("teamd -r -d -c \"%s\" -t %s %s" % (teamd_config, dev_name, dbus_option))
+ def destroy(self):
+ dev_name = self._dev_config["name"]
+ exec_cmd("teamd -k -t %s" % dev_name)
+
+ def configure(self):
+ self._ports_down()
+
for slave_id in get_slaves(self._dev_config):
self.slave_add(slave_id)
self._ports_up()
@@ -271,10 +290,6 @@ class NetConfigDeviceTeam(NetConfigDeviceGeneric):
for slave_id in get_slaves(self._dev_config):
self.slave_del(slave_id)
- dev_name = self._dev_config["name"]
-
- exec_cmd("teamd -k -t %s" % dev_name)
-
def slave_add(self, slave_id):
dev_name = self._dev_config["name"]
port_dev = self._if_manager.get_mapped_device(slave_id)
@@ -359,25 +374,26 @@ class NetConfigDeviceOvsBridge(NetConfigDeviceGeneric):
for bond_id, bond in bonds.iteritems():
exec_cmd("ovs-vsctl del-port %s %s" % (br_name, bond_id))
- def configure(self):
+ def create(self):
dev_cfg = self._dev_config
-
br_name = dev_cfg["name"]
exec_cmd("ovs-vsctl add-br %s" % br_name)
+ def destroy(self):
+ dev_cfg = self._dev_config
+ br_name = dev_cfg["name"]
+ exec_cmd("ovs-vsctl del-br %s" % br_name)
+
+ def configure(self):
self._add_ports()
self._add_bonds()
def deconfigure(self):
- dev_cfg = self._dev_config
-
self._del_bonds()
self._del_ports()
- br_name = dev_cfg["name"]
- exec_cmd("ovs-vsctl del-br %s" % br_name)
type_class_mapping = {
"eth": NetConfigDeviceEth,
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index d331818..ca714e2 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -161,7 +161,10 @@ class SlaveMethods:
return True
def create_soft_interface(self, if_id, config):
- return self._if_manager.create_device_from_config(if_id, config)
+ dev_name = self._if_manager.create_device_from_config(if_id, config)
+ dev = self._if_manager.get_mapped_device(if_id)
+ dev.configure()
+ return dev_name
def deconfigure_interface(self, if_id):
device = self._if_manager.get_mapped_device(if_id)
diff --git a/lnst/Slave/NmConfigDevice.py b/lnst/Slave/NmConfigDevice.py
index e07c0ba..718bd9f 100644
--- a/lnst/Slave/NmConfigDevice.py
+++ b/lnst/Slave/NmConfigDevice.py
@@ -105,6 +105,12 @@ class NmConfigDeviceGeneric(object):
def deconfigure(self):
pass
+ def create(self):
+ pass
+
+ def destroy(self):
+ pass
+
def slave_add(self, slave_id):
pass
9 years, 8 months
[lnst: 6/11] NetTestSlave: make return_if_netns method recursive
by Jiří Pírko
commit eeaafdf71ce2b3b57d76558281fa27a97c9375b2
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:31 2014 +0200
NetTestSlave: make return_if_netns method recursive
This patch makes the 'return_if_netns' slave method recursive - the
controller always calls it in the root namespace which will reroute the
method to the specific namespace that the device was moved into. In
addition the InterfaceManager class will not remove Device objects if
they're moved to a namespace (_netns attribute != None) or if they have
a configuration object associated with them. This works around a bug on
older kernels that generate RTM_DELLINK messages for slave devices when
removing the master device (e.g. bridge).
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/Machine.py | 3 +--
lnst/Slave/InterfaceManager.py | 3 +--
lnst/Slave/NetTestSlave.py | 20 ++++++++++++++++----
3 files changed, 18 insertions(+), 8 deletions(-)
---
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index 94d4fbd..7bacad1 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -621,8 +621,7 @@ class Interface(object):
if self._netns != None:
self._machine._rpc_call_to_netns(self._netns,
"deconfigure_interface", self.get_id())
- self._machine._rpc_call_to_netns(self._netns,
- "return_if_netns", self.get_id())
+ self._machine._rpc_call_to("return_if_netns", self.get_id())
else:
self._machine._rpc_call("deconfigure_interface", self.get_id())
self._configured = False
diff --git a/lnst/Slave/InterfaceManager.py b/lnst/Slave/InterfaceManager.py
index 78cc46b..16eba2d 100644
--- a/lnst/Slave/InterfaceManager.py
+++ b/lnst/Slave/InterfaceManager.py
@@ -101,7 +101,7 @@ class InterfaceManager(object):
elif msg['header']['type'] == RTM_DELLINK:
if msg['index'] in self._devices:
dev = self._devices[msg['index']]
- if dev.get_netns() != None:
+ if dev.get_netns() == None and dev.get_conf_dict() == None:
dev.del_link()
del self._devices[msg['index']]
else:
@@ -230,7 +230,6 @@ class Device(object):
self._state = nl_msg.get_attr("IFLA_OPERSTATE")
self._ip = None #TODO
self.set_master(nl_msg.get_attr("IFLA_MASTER"), primary=True)
- self._netns = None
link = nl_msg.get_attr("IFLA_LINK")
if link != None:
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index e7d620c..d331818 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -468,10 +468,22 @@ class SlaveMethods:
def return_if_netns(self, if_id):
device = self._if_manager.get_mapped_device(if_id)
- dev_name = device.get_name()
- ppid = os.getppid()
- exec_cmd("ip link set %s netns %d" % (dev_name, ppid))
- return True
+ if device.get_netns() == None:
+ dev_name = device.get_name()
+ ppid = os.getppid()
+ exec_cmd("ip link set %s netns %d" % (dev_name, ppid))
+ return True
+ else:
+ netns = device.get_netns()
+ msg = {"type": "command", "method_name": "return_if_netns",
+ "args": [if_id]}
+ self._server_handler.send_data_to_netns(netns, msg)
+ result = self._slave_server.wait_for_result(netns)
+ if result["result"] != True:
+ raise Exception("Return from netns failed.")
+
+ device.set_netns(None)
+ return True
class ServerHandler(object):
def __init__(self, addr):
9 years, 8 months
[lnst: 5/11] NetTestSlave: extend communication options between namespaces
by Jiří Pírko
commit 3152c9a6ac0ca9b90cccdede8b369d7fd927a9bd
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:30 2014 +0200
NetTestSlave: extend communication options between namespaces
The ServerHandler class now supports retrieving messages from a
specified connection. And the NetTestSlave class now supports waiting
for a response from a specified connection using the ServerHandler
method.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Slave/NetTestSlave.py | 27 +++++++++++++++++++++++++--
1 files changed, 25 insertions(+), 2 deletions(-)
---
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index 8db7b8f..e7d620c 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -46,13 +46,14 @@ class SlaveMethods:
Exported xmlrpc methods
'''
def __init__(self, command_context, log_ctl, if_manager, net_namespaces,
- server_handler):
+ server_handler, slave_server):
self._packet_captures = {}
self._if_manager = if_manager
self._command_context = command_context
self._log_ctl = log_ctl
self._net_namespaces = net_namespaces
self._server_handler = server_handler
+ self._slave_server = slave_server
self._capture_files = {}
self._copy_targets = {}
@@ -541,6 +542,14 @@ class ServerHandler(object):
self._c_socket = None
return messages
+ def get_messages_from_con(self, con_id):
+ if self._connection_handler.get_connection(con_id) != None:
+ return self._connection_handler.check_connections_by_id([con_id])
+ elif self._netns_con_handler.get_connection(con_id) != None:
+ return self._netns_con_handler.check_connections_by_id([con_id])
+ else:
+ raise Exception("Unknown connection id '%s'." % con_id)
+
def send_data_to_ctl(self, data):
if self._c_socket != None:
if self._netns != None:
@@ -598,7 +607,7 @@ class NetTestSlave:
self._methods = SlaveMethods(self._cmd_context, log_ctl,
self._if_manager, self._net_namespaces,
- self._server_handler)
+ self._server_handler, self)
self.register_die_signal(signal.SIGHUP)
self.register_die_signal(signal.SIGINT)
@@ -630,6 +639,20 @@ class NetTestSlave:
self._methods.machine_cleanup()
+ def wait_for_result(self, id):
+ result = None
+ while result == None:
+ msgs = self._server_handler.get_messages_from_con(id)
+ for msg in msgs:
+ if msg[1]["type"] == "result":
+ result = msg[1]
+ elif msg[1]["type"] == "from_netns" and\
+ msg[1]["data"]["type"] == "result":
+ result = msg[1]["data"]
+ else:
+ self._process_msg(msg[1])
+ return result
+
def _process_msg(self, msg):
if msg["type"] == "command":
method = getattr(self._methods, msg["method_name"], None)
9 years, 8 months
[lnst: 4/11] RecipeParser: support parsing veth interfaces
by Jiří Pírko
commit 4b98ac1eb328eecf4ed951223d52e61ba06bc9b3
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:29 2014 +0200
RecipeParser: support parsing veth interfaces
The _process_interface method now returns a list of parsed interfaces.
This is because when parsing the veth_pair tag the method parses both
child veth tags and returns 2 interfaces at once. Both interfaces
contain a reference (by id) to their peer.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Controller/RecipeParser.py | 16 +++++++++++++---
1 files changed, 13 insertions(+), 3 deletions(-)
---
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
index 76da1c6..3960c97 100644
--- a/lnst/Controller/RecipeParser.py
+++ b/lnst/Controller/RecipeParser.py
@@ -66,7 +66,7 @@ class RecipeParser(XmlParser):
machine["interfaces"] = XmlCollection(interfaces_tag)
for interface_tag in interfaces_tag:
interface = self._process_interface(interface_tag)
- machine["interfaces"].append(interface)
+ machine["interfaces"].extend(interface)
return machine
@@ -83,9 +83,19 @@ class RecipeParser(XmlParser):
def _process_interface(self, iface_tag):
iface = XmlData(iface_tag)
- iface["id"] = self._get_attribute(iface_tag, "id")
iface["type"] = iface_tag.tag
+ if iface["type"] == "veth_pair":
+ iface = self._process_interface(iface_tag[0])[0]
+ iface2 = self._process_interface(iface_tag[1])[0]
+
+ iface["peer"] = iface2["id"]
+ iface2["peer"] = iface["id"]
+
+ return [iface, iface2]
+
+ iface["id"] = self._get_attribute(iface_tag, "id")
+
iface["netns"] = None
if self._has_attribute(iface_tag, "netns"):
iface["netns"] = self._get_attribute(iface_tag, "netns")
@@ -222,7 +232,7 @@ class RecipeParser(XmlParser):
bond_slaves.append(slave_id)
- return iface
+ return [iface]
def _proces_options(self, opts_tag):
options = XmlCollection(opts_tag)
9 years, 8 months
[lnst: 3/11] schema-recipe: add support for veth interfaces
by Jiří Pírko
commit 71aee0f2c91200bf9f25af25e33340a052a367ca
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:28 2014 +0200
schema-recipe: add support for veth interfaces
This patch adds recipe XML support for veth interfaces. Since veth
devices are created in pairs, XML specification reflects this by
encapsulating two <veth> tags in a single <veth_pair> tag. Both of these
tags are mandatory. At the moment there are no <options> supported - you
can specify them, but they will be ignored.
Example interface specification would look something like this:
<interfaces>
<eth id="out_if" label="tnet"/>
<veth_pair>
<veth id="testifc1" netns="xyz">
<addresses>
<address value="192.168.200.2/24"/>
</addresses>
</veth>
<veth id="testifc2"/>
</veth_pair>
<bridge id="br">
<slaves>
<slave id="out_if"/>
<slave id="testifc2"/>
</slaves>
</bridge>
</interfaces>
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
schema-recipe.rng | 36 ++++++++++++++++++++++++++++++++++++
1 files changed, 36 insertions(+), 0 deletions(-)
---
diff --git a/schema-recipe.rng b/schema-recipe.rng
index 6795f72..f13f36a 100644
--- a/schema-recipe.rng
+++ b/schema-recipe.rng
@@ -135,6 +135,7 @@
<ref name="macvlan"/>
<ref name="team"/>
<ref name="ovs_bridge"/>
+ <ref name="veth_pair"/>
</choice>
</zeroOrMore>
</element>
@@ -328,6 +329,41 @@
</interleave>
</define>
+ <define name="veth_pair">
+ <element name="veth_pair">
+ <optional>
+ <ref name="define"/>
+ </optional>
+ <ref name="veth"/>
+ <optional>
+ <ref name="define"/>
+ </optional>
+ <ref name="veth"/>
+ </element>
+ </define>
+
+ <define name="veth">
+ <element name="veth">
+ <attribute name="id"/>
+ <optional>
+ <attribute name="netns"/>
+ </optional>
+ <interleave>
+ <optional>
+ <ref name="define"/>
+ </optional>
+
+ <zeroOrMore>
+ <ref name="options"/>
+ </zeroOrMore>
+
+ <optional>
+ <ref name="addresses"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
<define name="options">
<element name="options">
<interleave>
9 years, 8 months
[lnst: 2/11] ConnectionHandler: check specific connections
by Jiří Pírko
commit 5dfba356b1d9ea21bd9c0691ce421946723165dc
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:27 2014 +0200
ConnectionHandler: check specific connections
This patch extends the ConnectionHandler class with functionality to
check specific connections for new messages instead of always checking
all of them.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Common/ConnectionHandler.py | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
---
diff --git a/lnst/Common/ConnectionHandler.py b/lnst/Common/ConnectionHandler.py
index 042e78a..e8a6976 100644
--- a/lnst/Common/ConnectionHandler.py
+++ b/lnst/Common/ConnectionHandler.py
@@ -70,9 +70,15 @@ class ConnectionHandler(object):
self._connections = {}
def check_connections(self):
+ return self.check_connections_by_id(self._connections.keys())
+
+ def check_connections_by_id(self, connection_ids):
+ connections = []
+ for con_id in connection_ids:
+ connections.append(self._connections[con_id])
requests = []
try:
- rl, wl, xl = select.select(self._connections.values(), [], [], 0)
+ rl, wl, xl = select.select(connections, [], [], 0)
except select.error:
return []
for f in rl:
9 years, 8 months
[lnst: 1/11] NetTestSlave: remount sysfs in new net namespace
by Jiří Pírko
commit 179dd0a46fd68b86bd5f7f21d761709802d70711
Author: Ondrej Lichtner <olichtne(a)redhat.com>
Date: Thu Aug 21 14:25:26 2014 +0200
NetTestSlave: remount sysfs in new net namespace
Creating a new network namespace does not change the contents of the
sysfs filesystem which makes it unusable for network configuration
purposes. This patch fixes that by creating a new mount namespace and
remounting the sysfs filesystem.
This also means that we don't need to use iproute2 to create Bonding
interfaces anymore.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Slave/NetConfigDevice.py | 28 +++++-----------------------
lnst/Slave/NetTestSlave.py | 14 +++++++++++++-
2 files changed, 18 insertions(+), 24 deletions(-)
---
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py
index 338df67..86744db 100644
--- a/lnst/Slave/NetConfigDevice.py
+++ b/lnst/Slave/NetConfigDevice.py
@@ -14,8 +14,6 @@ jpirko(a)redhat.com (Jiri Pirko)
import logging
import re
import sys
-from platform import release
-from distutils.version import LooseVersion
from lnst.Common.ExecCmd import exec_cmd
from lnst.Slave.NetConfigCommon import get_slaves, get_option, get_slave_option
from lnst.Common.Utils import kmod_in_use, bool_it
@@ -88,16 +86,9 @@ class NetConfigDeviceBond(NetConfigDeviceGeneric):
_moduleparams = "max_bonds=0"
def _add_rm_bond(self, mark):
- #3.10 works on rhel7, I didn't test which oldest version works...
- if LooseVersion(release()) > LooseVersion('3.10'):
- if mark == "+":
- exec_cmd('ip link add %s type bond' % self._dev_config["name"])
- elif mark == "-":
- exec_cmd('ip link del %s' % self._dev_config["name"])
- else:
- bond_masters = "/sys/class/net/bonding_masters"
- exec_cmd('echo "%s%s" > %s' % (mark, self._dev_config["name"],
- bond_masters))
+ bond_masters = "/sys/class/net/bonding_masters"
+ exec_cmd('echo "%s%s" > %s' % (mark, self._dev_config["name"],
+ bond_masters))
def _get_bond_dir(self):
return "/sys/class/net/%s/bonding" % self._dev_config["name"]
@@ -123,20 +114,11 @@ class NetConfigDeviceBond(NetConfigDeviceGeneric):
slave_dev = self._if_manager.get_mapped_device(slave_id)
slave_conf = slave_dev.get_conf_dict()
slave_name = slave_dev.get_name()
- bond_name = self._dev_config["name"]
if mark == "+":
slave_dev.down()
- #3.10 works on rhel7, I didn't test which oldest version works...
- if LooseVersion(release()) > LooseVersion('3.10'):
- if mark == "+":
- exec_cmd('ip link set %s master %s' % (slave_name,
- bond_name))
- elif mark == "-":
- exec_cmd('ip link set %s nomaster' % (slave_name))
- else:
- exec_cmd('echo "%s%s" > %s/slaves' % (mark, slave_name,
- self._get_bond_dir()))
+ exec_cmd('echo "%s%s" > %s/slaves' % (mark, slave_name,
+ self._get_bond_dir()))
def configure(self):
self._add_rm_bond("+")
diff --git a/lnst/Slave/NetTestSlave.py b/lnst/Slave/NetTestSlave.py
index 780cd9a..8db7b8f 100644
--- a/lnst/Slave/NetTestSlave.py
+++ b/lnst/Slave/NetTestSlave.py
@@ -402,9 +402,21 @@ class SlaveMethods:
elif pid == 0:
#create new network namespace
libc_name = ctypes.util.find_library("c")
- CLONE_NEWNET = 0x40000000 #from sched.h
+ #from sched.h
+ CLONE_NEWNET = 0x40000000
+ CLONE_NEWNS = 0x00020000
+ #based on ipnetns.c from the iproute2 project
+ MNT_DETACH = 0x00000002
+ MS_SLAVE = 1<<19
+ MS_REC = 16384
+
libc = ctypes.CDLL(libc_name)
libc.unshare(CLONE_NEWNET)
+ #based on ipnetns.c from the iproute2 project
+ libc.unshare(CLONE_NEWNS)
+ libc.mount("", "/", "none", MS_SLAVE | MS_REC, 0)
+ libc.umount2("/sys", MNT_DETACH)
+ libc.mount(netns, "/sys", "sysfs", 0, 0)
#set ctl socket to pipe to main netns
self._server_handler.close_s_sock()
9 years, 8 months
[lnst] (11 commits) ...From: Ondrej Lichtner <olichtne@redhat.com>
by Jiří Pírko
Summary of changes:
179dd0a... NetTestSlave: remount sysfs in new net namespace
5dfba35... ConnectionHandler: check specific connections
71aee0f... schema-recipe: add support for veth interfaces
4b98ac1... RecipeParser: support parsing veth interfaces
3152c9a... NetTestSlave: extend communication options between namespac
eeaafdf... NetTestSlave: make return_if_netns method recursive
2599992... *ConfigDevice: split device creation and configuration
960c68c... *ConfigDevice: add VEth classes
aaf369d... NetTestSlave: add methods {create, deconfigure}_if_pair
5d4d155... Machine: Interface class veth support
0aad5c4... From: Ondrej Lichtner <olichtne(a)redhat.com>
9 years, 8 months