aboutsummaryrefslogtreecommitdiff
path: root/rumba
diff options
context:
space:
mode:
Diffstat (limited to 'rumba')
-rw-r--r--rumba/model.py35
-rw-r--r--rumba/prototypes/irati.py186
-rw-r--r--rumba/prototypes/irati_templates.py338
-rw-r--r--rumba/testbeds/qemu.py108
4 files changed, 619 insertions, 48 deletions
diff --git a/rumba/model.py b/rumba/model.py
index 5ec36cc..5f4f162 100644
--- a/rumba/model.py
+++ b/rumba/model.py
@@ -317,8 +317,8 @@ class Experiment:
# Generate missing information
self.generate()
- @staticmethod
- def from_config_file(testbed, filename='demo.conf'):
+ @classmethod
+ def from_config_file(cls, testbed, filename='demo.conf'):
"""
:type testbed: Testbed
:rtype: Experiment
@@ -345,7 +345,8 @@ class Experiment:
if line.startswith('#') or line == "":
continue
- m = re.match(r'\s*eth\s+([\w-]+)\s+(\d+)([GMK])bps\s+(\w.*)$', line)
+ m = re.match(r'\s*eth\s+([\w-]+)\s+(\d+)([GMK])bps\s+(\w.*)$',
+ line)
if m:
shim = m.group(1)
speed = int(m.group(2))
@@ -365,7 +366,10 @@ class Experiment:
shims[shim] = {'name': shim, 'speed': speed, 'type': 'eth'}
for vm in vm_list:
- nodes.setdefault(vm, {'name': vm, 'difs': [], 'dif_registrations': {}, 'registrations': {}})
+ nodes.setdefault(vm, {'name': vm,
+ 'difs': [],
+ 'dif_registrations': {},
+ 'registrations': {}})
nodes[vm]['difs'].append(shim)
continue
@@ -380,16 +384,21 @@ class Experiment:
% (line_cnt, dif))
continue
- difs.setdefault(dif, {'name': dif}) # Other dict contents might be policies.
+ difs.setdefault(dif, {'name': dif})
if vm in nodes and dif in nodes[vm]['dif_registrations']:
- print('Error: Line %d: vm %s in dif %s already specified'
- % (line_cnt, vm, dif))
+ print(
+ 'Error: Line %d: vm %s in dif %s already specified'
+ % (line_cnt, vm, dif))
continue
- nodes.setdefault(vm, {'name': vm, 'difs': [], 'dif_registrations': {}, 'registrations': {}})
+ nodes.setdefault(vm, {'name': vm,
+ 'difs': [],
+ 'dif_registrations': {},
+ 'registrations': {}})
nodes[vm]['difs'].append(dif)
- nodes[vm]['dif_registrations'][dif] = dif_list # It is not defined yet, per check above.
+ nodes[vm]['dif_registrations'][dif] = dif_list
+ # It is not defined yet, per check above.
continue
@@ -401,7 +410,8 @@ class Experiment:
parsed_difs = {}
for shim_name, shim in shims.items():
- parsed_difs[shim_name] = (ShimEthDIF(shim_name, link_speed=shim['speed']))
+ parsed_difs[shim_name] = (ShimEthDIF(shim_name,
+ link_speed=shim['speed']))
for dif_name, dif in difs.items():
parsed_difs[dif_name] = (NormalDIF(dif_name))
@@ -411,10 +421,11 @@ class Experiment:
name = node_data['name']
difs = [parsed_difs[x] for x in node_data['difs']]
dif_registrations = {parsed_difs[x]: [parsed_difs[y] for y in l]
- for x, l in node_data['dif_registrations'].items()}
+ for x, l
+ in node_data['dif_registrations'].items()}
parsed_nodes.append(Node(name, difs, dif_registrations))
- return Experiment(testbed=testbed, nodes=parsed_nodes)
+ return cls(testbed=testbed, nodes=parsed_nodes)
def __repr__(self):
s = ""
diff --git a/rumba/prototypes/irati.py b/rumba/prototypes/irati.py
index e8766da..e06610d 100644
--- a/rumba/prototypes/irati.py
+++ b/rumba/prototypes/irati.py
@@ -2,6 +2,7 @@
# Commands to setup and instruct IRATI
#
# Vincenzo Maffione <v.maffione@nextworks.it>
+# Marco Capitani <m.capitani@nextworks.it>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -17,9 +18,12 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
+import copy
+import json
import rumba.ssh_support as ssh
import rumba.model as mod
+import rumba.prototypes.irati_templates as irati_templates
# An experiment over the IRATI implementation
class Experiment(mod.Experiment):
@@ -46,3 +50,185 @@ class Experiment(mod.Experiment):
print("Setting up IRATI on the nodes...")
self.setup()
print("[IRATI experiment] end")
+
+
+class ConfBuilder(object):
+
+ def __init__(self, experiment):
+ self.write_conf(experiment)
+
+ @staticmethod
+ def write_conf(experiment):
+ """
+ :type experiment: Experiment
+ :param experiment: the experiment to be configured
+ """
+ # Constants and initializations
+ ipcmconfs = dict()
+ difconfs = dict()
+ ipcp2shim_map = {}
+ node2id_map = {}
+ manager = False
+ mgmt_dif_name = 'NMS'
+
+ # TODO ask: what are these, and how are they represented in experiment?
+ # Are these bindings or registration (in node)?
+ # In gen.py these are given on a per-dif basis...
+ app_mappings = []
+
+ # If some app directives were specified, use those to build da.map.
+ # Otherwise, assume the standard applications are to be mapped in
+ # the DIF with the highest rank.
+ if len(app_mappings) == 0:
+ if len(experiment.dif_ordering) > 0:
+ for adm in \
+ irati_templates.da_map_base["applicationToDIFMappings"]:
+ adm["difName"] = "%s" % (experiment.dif_ordering[-1],)
+ # else:
+ # irati_templates.da_map_base["applicationToDIFMappings"] = []
+ # for apm in app_mappings:
+ # irati_templates.da_map_base["applicationToDIFMappings"]\
+ # .append({
+ # "encodedAppName": apm['name'],
+ # "difName": "%s.DIF" % (apm['dif'])
+ # })
+
+ # TODO ask: I guess this will need to be added,
+ # and in that case we should add it to the qemu plugin too...
+ # Where should we take it in input?
+
+ if manager:
+ # Add MAD/Manager configuration
+ irati_templates.ipcmconf_base["addons"] = {
+ "mad": {
+ "managerAppName": "",
+ "NMSDIFs": [{"DIF": "%s" % mgmt_dif_name}],
+ "managerConnections": [{
+ "managerAppName": "manager-1--",
+ "DIF": "%s" % mgmt_dif_name
+ }]
+ }
+ }
+
+ node_number = 1
+ for node in experiment.nodes: # type: mod.Node
+ node2id_map[node.name] = node_number
+ node_number += 1
+ ipcmconfs[node.name] = copy.deepcopy(irati_templates.ipcmconf_base)
+ if manager:
+ ipcmconfs[node.name]["addons"]["mad"]["managerAppName"] \
+ = "%s.mad-1--" % (node.name,)
+
+ for dif in experiment.dif_ordering: # type: mod.DIF
+ if isinstance(dif, mod.ShimEthDIF):
+ ipcp2shim_map.update({ipcp.name: dif for ipcp in dif.ipcps})
+ elif isinstance(dif, mod.NormalDIF):
+ difconfs[dif.name] = dict()
+ for node in dif.members:
+ difconfs[dif.name][node.name] = copy.deepcopy(
+ irati_templates.normal_dif_base
+ )
+
+ for node in experiment.nodes: # type: mod.Node
+ ipcmconf = ipcmconfs[node.name]
+
+ for ipcp in node.ipcps: # type: mod.ShimEthIPCP
+ if isinstance(ipcp, mod.ShimEthIPCP):
+ node_name, port_id = ipcp.ifname.split('.')
+ shim = ipcp2shim_map[ipcp.name] # type: mod.ShimEthDIF
+ ipcmconf["ipcProcessesToCreate"].append({
+ "apName": "eth.%d.IPCP" % int(port_id),
+ "apInstance": "1",
+ "difName": shim.name
+ })
+
+ template_file_name = 'shimeth.%s.%s.dif' \
+ % (node_name, shim.name)
+ ipcmconf["difConfigurations"].append({
+ "name": shim.name,
+ "template": template_file_name
+ })
+
+ fout = open(template_file_name, 'w')
+ fout.write(json.dumps(
+ {"difType": "shim-eth-vlan",
+ "configParameters": {
+ "interface-name": "ifc%d" % (int(port_id),)
+ }
+ },
+ indent=4, sort_keys=True))
+ fout.close()
+
+ # Run over dif_ordering array, to make sure each IPCM config has
+ # the correct ordering for the ipcProcessesToCreate list of operations.
+ # If we iterated over the difs map, the order would be randomic, and so
+ # some IPCP registrations in lower DIFs may fail.
+ # This would happen because at the moment of registration,
+ # it may be that the IPCP of the lower DIF has not been created yet.
+ shims = ipcp2shim_map.values()
+ for dif in experiment.dif_ordering: # type: mod.NormalDIF
+
+ if dif in shims:
+ # Shims are managed separately, in the previous loop
+ continue
+
+ for node in dif.members: # type: mod.Node
+ node_name = node.name
+ ipcmconf = ipcmconfs[node_name]
+
+ normal_ipcp = {"apName": "%s.%s.IPCP" % (dif.name, node_name),
+ "apInstance": "1",
+ "difName": "%s" % (dif.name,),
+ "difsToRegisterAt": []}
+
+ for lower_dif in node.dif_registrations[dif]: # type: mod.DIF
+ normal_ipcp["difsToRegisterAt"].append(lower_dif.name)
+
+ ipcmconf["ipcProcessesToCreate"].append(normal_ipcp)
+
+ ipcmconf["difConfigurations"].append({
+ "name": "%s" % (dif.name,),
+ "template": "normal.%s.%s.dif" % (node_name, dif.name,)
+ })
+
+ # Fill in the map of IPCP addresses.
+ # This could be moved at difconfs
+ for other_node in dif.members: # type: mod.Node
+ difconfs[dif.name][other_node.name] \
+ ["knownIPCProcessAddresses"].append({
+ "apName": "%s.%s.IPCP" % (dif.name, node_name),
+ "apInstance": "1",
+ "address": 16 + node2id_map[node_name]})
+ for path, ps in dif.policies.items():
+ # if policy['nodes'] == [] or vmname in policy['nodes']:
+ # TODO: policies can be applied per-node
+ # (and not just per-dif) in rumba? With what syntax?
+ irati_templates.translate_policy(
+ difconfs[dif.name][node_name], path, ps, parms=[])
+
+ # Dump the DIF Allocator map
+ with open('da.map', 'w') as da_map_file:
+ json.dump(irati_templates.da_map_base,
+ da_map_file,
+ indent=4,
+ sort_keys=True)
+
+ for node in experiment.nodes:
+ # Dump the IPCM configuration files
+ with open('%s.ipcm.conf' % (node.name,), 'w') as node_file:
+ json.dump(ipcmconfs[node.name],
+ node_file,
+ indent=4,
+ sort_keys=True)
+
+ for dif in experiment.dif_ordering: # type: mod.DIF
+ dif_conf = difconfs.get(dif.name, None)
+ if dif_conf:
+ # Dump the normal DIF configuration files
+ for node in dif.members:
+ with open('normal.%s.%s.dif' % (node.name, dif.name), 'w') \
+ as dif_conf_file:
+ json.dump(dif_conf[node.name],
+ dif_conf_file,
+ indent=4,
+ sort_keys=True)
diff --git a/rumba/prototypes/irati_templates.py b/rumba/prototypes/irati_templates.py
new file mode 100644
index 0000000..0f3ef05
--- /dev/null
+++ b/rumba/prototypes/irati_templates.py
@@ -0,0 +1,338 @@
+# Environment setup for VMs. Standard linux approach
+env_dict = {'installpath': '/usr', 'varpath': ''}
+
+# Template for a IPCM configuration file
+ipcmconf_base = {
+ "configFileVersion": "1.4.1",
+ "localConfiguration": {
+ "installationPath": "%(installpath)s/bin" % env_dict,
+ "libraryPath": "%(installpath)s/lib" % env_dict,
+ "logPath": "%(varpath)s/var/log" % env_dict,
+ "consoleSocket": "%(varpath)s/var/run/ipcm-console.sock" % env_dict,
+ "pluginsPaths": [
+ "%(installpath)s/lib/rinad/ipcp" % env_dict,
+ "/lib/modules/4.1.33-irati/extra"
+ ]
+ },
+
+ "ipcProcessesToCreate": [],
+ "difConfigurations": [],
+}
+
+
+da_map_base = {
+ "applicationToDIFMappings": [
+ {
+ "encodedAppName": "rina.apps.echotime.server-1--",
+ "difName": "n.DIF"
+ },
+ {
+ "encodedAppName": "traffic.generator.server-1--",
+ "difName": "n.DIF"
+ }
+ ],
+}
+
+
+# Template for a normal DIF configuration file
+normal_dif_base = {
+ "difType" : "normal-ipc",
+ "dataTransferConstants" : {
+ "addressLength" : 2,
+ "cepIdLength" : 2,
+ "lengthLength" : 2,
+ "portIdLength" : 2,
+ "qosIdLength" : 2,
+ "rateLength" : 4,
+ "frameLength" : 4,
+ "sequenceNumberLength" : 4,
+ "ctrlSequenceNumberLength" : 4,
+ "maxPduSize" : 10000,
+ "maxPduLifetime" : 60000
+ },
+
+ "qosCubes" : [ {
+ "name" : "unreliablewithflowcontrol",
+ "id" : 1,
+ "partialDelivery" : False,
+ "orderedDelivery" : True,
+ "efcpPolicies" : {
+ "dtpPolicySet" : {
+ "name" : "default",
+ "version" : "0"
+ },
+ "initialATimer" : 0,
+ "dtcpPresent" : True,
+ "dtcpConfiguration" : {
+ "dtcpPolicySet" : {
+ "name" : "default",
+ "version" : "0"
+ },
+ "rtxControl" : False,
+ "flowControl" : True,
+ "flowControlConfig" : {
+ "rateBased" : False,
+ "windowBased" : True,
+ "windowBasedConfig" : {
+ "maxClosedWindowQueueLength" : 10,
+ "initialCredit" : 200
+ }
+ }
+ }
+ }
+ }, {
+ "name" : "reliablewithflowcontrol",
+ "id" : 2,
+ "partialDelivery" : False,
+ "orderedDelivery" : True,
+ "maxAllowableGap": 0,
+ "efcpPolicies" : {
+ "dtpPolicySet" : {
+ "name" : "default",
+ "version" : "0"
+ },
+ "initialATimer" : 0,
+ "dtcpPresent" : True,
+ "dtcpConfiguration" : {
+ "dtcpPolicySet" : {
+ "name" : "default",
+ "version" : "0"
+ },
+ "rtxControl" : True,
+ "rtxControlConfig" : {
+ "dataRxmsNmax" : 5,
+ "initialRtxTime" : 1000
+ },
+ "flowControl" : True,
+ "flowControlConfig" : {
+ "rateBased" : False,
+ "windowBased" : True,
+ "windowBasedConfig" : {
+ "maxClosedWindowQueueLength" : 10,
+ "initialCredit" : 200
+ }
+ }
+ }
+ }
+ } ],
+
+ "knownIPCProcessAddresses": [],
+
+ "addressPrefixes" : [ {
+ "addressPrefix" : 0,
+ "organization" : "N.Bourbaki"
+ }, {
+ "addressPrefix" : 16,
+ "organization" : "IRATI"
+ } ],
+
+ "rmtConfiguration" : {
+ "pffConfiguration" : {
+ "policySet" : {
+ "name" : "default",
+ "version" : "0"
+ }
+ },
+ "policySet" : {
+ "name" : "default",
+ "version" : "1"
+ }
+ },
+
+ "enrollmentTaskConfiguration" : {
+ "policySet" : {
+ "name" : "default",
+ "version" : "1",
+ "parameters" : [ {
+ "name" : "enrollTimeoutInMs",
+ "value" : "10000"
+ }, {
+ "name" : "watchdogPeriodInMs",
+ "value" : "30000"
+ }, {
+ "name" : "declaredDeadIntervalInMs",
+ "value" : "120000"
+ }, {
+ "name" : "neighborsEnrollerPeriodInMs",
+ "value" : "0"
+ }, {
+ "name" : "maxEnrollmentRetries",
+ "value" : "0"
+ } ]
+ }
+ },
+
+ "flowAllocatorConfiguration" : {
+ "policySet" : {
+ "name" : "default",
+ "version" : "1"
+ }
+ },
+
+ "namespaceManagerConfiguration" : {
+ "policySet" : {
+ "name" : "default",
+ "version" : "1"
+ }
+ },
+
+ "securityManagerConfiguration" : {
+ "policySet" : {
+ "name" : "default",
+ "version" : "1"
+ }
+ },
+
+ "resourceAllocatorConfiguration" : {
+ "pduftgConfiguration" : {
+ "policySet" : {
+ "name" : "default",
+ "version" : "0"
+ }
+ }
+ },
+
+ "routingConfiguration" : {
+ "policySet" : {
+ "name" : "link-state",
+ "version" : "1",
+ "parameters" : [ {
+ "name" : "objectMaximumAge",
+ "value" : "10000"
+ },{
+ "name" : "waitUntilReadCDAP",
+ "value" : "5001"
+ },{
+ "name" : "waitUntilError",
+ "value" : "5001"
+ },{
+ "name" : "waitUntilPDUFTComputation",
+ "value" : "103"
+ },{
+ "name" : "waitUntilFSODBPropagation",
+ "value" : "101"
+ },{
+ "name" : "waitUntilAgeIncrement",
+ "value" : "997"
+ },{
+ "name" : "routingAlgorithm",
+ "value" : "Dijkstra"
+ }]
+ }
+ }
+}
+
+
+def ps_set(d, k, v, parms):
+ if k not in d:
+ d[k] = {'name': '', 'version': '1'}
+
+ if d[k]["name"] == v and "parameters" in d[k]:
+ cur_names = [p["name"] for p in d[k]["parameters"]]
+ for p in parms:
+ name, value = p.split('=')
+ if name in cur_names:
+ for i in range(len(d[k]["parameters"])):
+ if d[k]["parameters"][i]["name"] == name:
+ d[k]["parameters"][i]["value"] = value
+ break
+ else:
+ d[k]["parameters"].append({ 'name': name, 'value': value })
+
+ elif len(parms) > 0:
+ d[k]["parameters"] = [ { 'name': p.split('=')[0], 'value': p.split('=')[1]} for p in parms ]
+
+ d[k]["name"] = v
+
+
+def dtp_ps_set(d, v, parms):
+ for i in range(len(d["qosCubes"])):
+ ps_set(d["qosCubes"][i]["efcpPolicies"], "dtpPolicySet", v, parms)
+
+
+def dtcp_ps_set(d, v, parms):
+ for i in range(len(d["qosCubes"])):
+ ps_set(d["qosCubes"][i]["efcpPolicies"]["dtcpConfiguration"], "dtcpPolicySet", v, parms)
+
+
+policy_translator = {
+ 'rmt.pff': lambda d, v, p: ps_set(d["rmtConfiguration"]["pffConfiguration"],
+ "policySet", v, p),
+ 'rmt': lambda d, v, p: ps_set(d["rmtConfiguration"], "policySet", v, p),
+ 'enrollment-task': lambda d, v, p: ps_set(d["enrollmentTaskConfiguration"],
+ "policySet", v, p),
+ 'flow-allocator': lambda d, v, p: ps_set(d["flowAllocatorConfiguration"],
+ "policySet", v, p),
+ 'namespace-manager': lambda d, v, p: ps_set(
+ d["namespaceManagerConfiguration"], "policySet", v, p),
+ 'security-manager': lambda d, v, p: ps_set(
+ d["securityManagerConfiguration"], "policySet", v, p),
+ 'routing': lambda d, v, p: ps_set(d["routingConfiguration"], "policySet", v, p),
+ 'resource-allocator.pduftg': lambda d, v, p: ps_set(
+ d["resourceAllocatorConfiguration"], "policySet", v, p),
+ 'efcp.*.dtcp': None,
+ 'efcp.*.dtp': None,
+}
+
+
+def is_security_path(path):
+ sp = path.split('.')
+ return (len(sp) == 3) and (sp[0] == 'security-manager') \
+ and (sp[1] in ['auth', 'encrypt', 'ttl', 'errorcheck'])
+
+
+# Do we know this path ?
+def policy_path_valid(path):
+ if path in policy_translator:
+ return True
+
+ # Try to validate security configuration
+ if is_security_path(path):
+ return True
+
+ return False
+
+
+def translate_security_path(d, path, ps, parms):
+ u1, component, profile = path.split('.')
+ if "authSDUProtProfiles" not in d["securityManagerConfiguration"]:
+ d["securityManagerConfiguration"]["authSDUProtProfiles"] = {}
+ d = d["securityManagerConfiguration"]["authSDUProtProfiles"]
+
+ tr = {'auth': 'authPolicy', 'encrypt': 'encryptPolicy',
+ 'ttl': 'TTLPolicy', 'errorcheck': 'ErrorCheckPolicy'}
+
+ if profile == 'default':
+ if profile not in d:
+ d["default"] = {}
+
+ ps_set(d["default"], tr[component], ps, parms)
+
+ else: # profile is the name of a DIF
+ if "specific" not in d:
+ d["specific"] = []
+ j = -1
+ for i in range(len(d["specific"])):
+ if d["specific"][i]["underlyingDIF"] == profile + ".DIF":
+ j = i
+ break
+
+ if j == -1: # We need to create an entry for the new DIF
+ d["specific"].append({"underlyingDIF" : profile + ".DIF"})
+
+ ps_set(d["specific"][j], tr[component], ps, parms)
+
+
+def translate_policy(difconf, path, ps, parms):
+ if path =='efcp.*.dtcp':
+ dtcp_ps_set(difconf, ps, parms)
+
+ elif path == 'efcp.*.dtp':
+ dtp_ps_set(difconf, ps, parms)
+
+ elif is_security_path(path):
+ translate_security_path(difconf, path, ps, parms)
+
+ else:
+ policy_translator[path](difconf, ps, parms)
+
diff --git a/rumba/testbeds/qemu.py b/rumba/testbeds/qemu.py
index 3573554..7255b3c 100644
--- a/rumba/testbeds/qemu.py
+++ b/rumba/testbeds/qemu.py
@@ -2,6 +2,7 @@
# QEMU testbed for Rumba
#
# Vincenzo Maffione <v.maffione@nextworks.it>
+# Marco Capitani <m.capitani@nextworks.it>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -26,7 +27,8 @@ import rumba.model as mod
class Testbed(mod.Testbed):
- def __init__(self, exp_name, username, bzimage, initramfs, proj_name="ARCFIRE", password="",
+ def __init__(self, exp_name, bzimage, initramfs, proj_name="ARCFIRE",
+ password="root", username="root",
use_vhost=True, qemu_logs_dir=None):
mod.Testbed.__init__(self, exp_name, username, password, proj_name)
self.vms = {}
@@ -34,15 +36,18 @@ class Testbed(mod.Testbed):
self.bzimage = bzimage
self.initramfs = initramfs
self.vhost = use_vhost
- self.qemu_logs_dir = os.getcwd() if qemu_logs_dir is None else qemu_logs_dir
+ self.qemu_logs_dir = os.getcwd() if qemu_logs_dir is None \
+ else qemu_logs_dir
self.boot_processes = []
@staticmethod
- def _run_command_chain(commands, results_queue, error_queue, ignore_errors=False):
+ def _run_command_chain(commands, results_queue,
+ error_queue, ignore_errors=False):
"""
Runs (sequentially) the command list.
- On error, breaks and dumps it in error_queue, and interrupts as soon as it is non-empty.
+ On error, breaks and dumps it in error_queue, and interrupts
+ as soon as it is non-empty (unless ignore errors is True).
:type commands: list
:type results_queue: Queue
@@ -88,11 +93,12 @@ class Testbed(mod.Testbed):
e_queue = multiprocessing.Queue()
print(experiment.dif_ordering)
for shim in experiment.dif_ordering:
- command_list = []
if not isinstance(shim, mod.ShimEthDIF):
# Nothing to do here
continue
self.shims.append(shim)
+ ipcps = shim.ipcps
+ command_list = []
command_list += ('sudo brctl addbr %(br)s\n'
'sudo ip link set %(br)s up'
% {'br': shim.name}
@@ -113,23 +119,39 @@ class Testbed(mod.Testbed):
speed = '%dmbit' % shim.link_speed
# Rate limit the traffic transmitted on the TAP interface
- command_list += ('sudo tc qdisc add dev %(tap)s handle 1: root '
- 'htb default 11\n'
- 'sudo tc class add dev %(tap)s parent 1: classid '
- '1:1 htb rate 10gbit\n'
- 'sudo tc class add dev %(tap)s parent 1:1 classid '
- '1:11 htb rate %(speed)s'
- % {'tap': tap_id, 'speed': speed}
- ).split('\n')
-
- vm['ports'].append({'tap_id': tap_id, 'shim': shim, 'port_id': port_id})
+ command_list += (
+ 'sudo tc qdisc add dev %(tap)s handle 1: root '
+ 'htb default 11\n'
+ 'sudo tc class add dev %(tap)s parent 1: classid '
+ '1:1 htb rate 10gbit\n'
+ 'sudo tc class add dev %(tap)s parent 1:1 classid '
+ '1:11 htb rate %(speed)s'
+ % {'tap': tap_id, 'speed': speed}
+ ).split('\n')
+
+ vm['ports'].append({'tap_id': tap_id,
+ 'shim': shim,
+ 'port_id': port_id})
+ ipcp_set = [x for x in ipcps if x in node.ipcps]
+ if len(ipcp_set) > 1:
+ raise Exception("Error: more than one ipcp in common "
+ "between shim dif %s and node %s"
+ % (shim.name, node.name))
+ ipcp = ipcp_set[0] # type: mod.ShimEthIPCP
+ assert ipcp.name == '%s.%s' % (shim.name, node.name), \
+ 'Incorrect Shim Ipcp found: expected %s.%s, found %s' \
+ % (shim.name, node.name, ipcp.name)
+ ipcp.ifname = tap_id
# TODO deal with Ip address (shim UDP DIF).
# Avoid stacking processes if one failed before.
if not e_queue.empty():
break
# Launch commands asynchronously
- process = multiprocessing.Process(target=self._run_command_chain, args=(command_list, r_queue, e_queue))
+ process = multiprocessing.Process(target=self._run_command_chain,
+ args=(command_list,
+ r_queue,
+ e_queue))
shim_processes.append(process)
process.start()
@@ -149,7 +171,8 @@ class Testbed(mod.Testbed):
result = r_queue.get(timeout=1)
if result == "Command chain ran correctly.":
over_processes += 1
- print('DEBUG: %s of %s processes completed.' % (over_processes, total_processes))
+ print('DEBUG: %s of %s processes completed.'
+ % (over_processes, total_processes))
except:
max_waiting_time -= 1
@@ -199,7 +222,6 @@ class Testbed(mod.Testbed):
'-device %(frontend)s,mac=%(mac)s,netdev=mgmt '
'-netdev user,id=mgmt,%(hostfwdstr)s '
'-vga std '
- '-pidfile rina-%(id)s.pid '
'-serial file:%(vmname)s.log '
% vars_dict
)
@@ -211,23 +233,29 @@ class Testbed(mod.Testbed):
mac = '00:0a:0a:0a:%02x:%02x' % (vmid, port['port_id'])
port['mac'] = mac
- command += ('-device %(frontend)s,mac=%(mac)s,netdev=data%(idx)s '
- '-netdev tap,ifname=%(tap)s,id=data%(idx)s,script=no,'
- 'downscript=no%(vhost)s '
- % {'mac': mac, 'tap': tap_id, 'idx': port['port_id'],
- 'frontend': vm_frontend, 'vhost': ',vhost=on' if self.vhost else ''}
- )
+ command += (
+ '-device %(frontend)s,mac=%(mac)s,netdev=data%(idx)s '
+ '-netdev tap,ifname=%(tap)s,id=data%(idx)s,script=no,'
+ 'downscript=no%(vhost)s '
+ % {'mac': mac, 'tap': tap_id, 'idx': port['port_id'],
+ 'frontend': vm_frontend,
+ 'vhost': ',vhost=on' if self.vhost else ''}
+ )
booting_budget -= 1
if booting_budget <= 0:
- print('Sleeping %s secs waiting for the VMs to boot' % boot_backoff)
+
+ print('Sleeping %s secs waiting '
+ 'for the VMs to boot' % boot_backoff)
+
time.sleep(boot_backoff)
booting_budget = boot_batch_size
- with open('%s/qemu_out_%s' % (self.qemu_logs_dir, vmid), 'w') as out_file:
+ with open('%s/qemu_out_%s' % (self.qemu_logs_dir, vmid), 'w')\
+ as out_file:
print('DEBUG: executing >> %s' % command)
- self.boot_processes.append(subprocess.Popen(command.split(), stdout=out_file))
- pass
+ self.boot_processes.append(subprocess.Popen(command.split(),
+ stdout=out_file))
vmid += 1
@@ -267,9 +295,10 @@ class Testbed(mod.Testbed):
'sudo ip tuntap del mode tap name %(tap)s'
% {'tap': tap, 'br': shim.name}
).split('\n')
- process = multiprocessing.Process(target=self._run_command_chain,
- args=(commands, results_queue, error_queue),
- kwargs={'ignore_errors': True})
+ process = multiprocessing.Process(
+ target=self._run_command_chain,
+ args=(commands, results_queue, error_queue),
+ kwargs={'ignore_errors': True})
port_processes.append(process)
process.start()
@@ -280,14 +309,17 @@ class Testbed(mod.Testbed):
while max_waiting_time > 0 and over_processes < total_processes:
# Check for errors
if not error_queue.empty():
- print('Failure while shutting down: %s' % str(error_queue.get()))
+ print(
+ 'Failure while shutting down: %s' % str(error_queue.get())
+ )
over_processes += 1
try:
# Check for results
result = results_queue.get(timeout=1)
if result == "Command chain ran correctly.":
over_processes += 1
- print('DEBUG: %s of %s tear-down port processes completed.' % (over_processes, total_processes))
+ print('DEBUG: %s of %s tear-down port processes completed.'
+ % (over_processes, total_processes))
except:
max_waiting_time -= 1
@@ -302,7 +334,9 @@ class Testbed(mod.Testbed):
% {'br': shim.name}
).split('\n')
process = multiprocessing.Process(target=self._run_command_chain,
- args=(commands, results_queue, error_queue),
+ args=(commands,
+ results_queue,
+ error_queue),
kwargs={'ignore_errors': True})
shim_processes.append(process)
process.start()
@@ -314,13 +348,15 @@ class Testbed(mod.Testbed):
while max_waiting_time > 0 and over_processes < total_processes:
# Check for errors
if not error_queue.empty():
- print('Failure while shutting down: %s' % str(error_queue.get()))
+ print('Failure while shutting down: %s'
+ % str(error_queue.get()))
over_processes += 1
try:
# Check for results
result = results_queue.get(timeout=1)
if result == "Command chain ran correctly.":
over_processes += 1
- print('DEBUG: %s of %s tear-down shim processes completed.' % (over_processes, total_processes))
+ print('DEBUG: %s of %s tear-down shim processes completed.'
+ % (over_processes, total_processes))
except:
max_waiting_time -= 1