Added routes to OMF nodes
authorAlina Quereilhac <alina.quereilhac@inria.fr>
Tue, 9 Oct 2012 15:10:45 +0000 (17:10 +0200)
committerAlina Quereilhac <alina.quereilhac@inria.fr>
Tue, 9 Oct 2012 15:10:45 +0000 (17:10 +0200)
16 files changed:
examples/omf-plexuslab-vlc.py [new file with mode: 0644]
examples/omf-plexuslab-xeyes.py [new file with mode: 0644]
examples/omf_vlc.py [deleted file]
src/nepi/core/design.py
src/nepi/core/execute.py
src/nepi/core/testbed_impl.py
src/nepi/testbeds/netns/metadata.py
src/nepi/testbeds/ns3/factories_metadata.py
src/nepi/testbeds/omf/execute.py
src/nepi/testbeds/omf/metadata.py
src/nepi/testbeds/omf/omf_api.py
src/nepi/testbeds/planetlab/interfaces.py
src/nepi/testbeds/planetlab/node.py
src/nepi/util/parser/_xml.py
src/nepi/util/parser/base.py
src/nepi/util/proxy.py

diff --git a/examples/omf-plexuslab-vlc.py b/examples/omf-plexuslab-vlc.py
new file mode 100644 (file)
index 0000000..3ffabe4
--- /dev/null
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Experiment Topology:
+#
+#  n1 --- n2
+#  0.1   0.2 
+#    
+
+from nepi.core.design import ExperimentDescription, FactoriesProvider
+from nepi.core.execute import ExperimentController
+import getpass
+import logging
+import tempfile
+import time
+
+logging.basicConfig(level=logging.DEBUG)
+
+root_dir = tempfile.mkdtemp()
+
+exp_desc = ExperimentDescription()
+
+testbed_id = "omf"
+omf_provider = FactoriesProvider(testbed_id)
+omf_desc = exp_desc.add_testbed_description(omf_provider)
+omf_desc.set_attribute_value("homeDirectory", root_dir)
+omf_desc.set_attribute_value("enableDebug", True)
+omf_desc.set_attribute_value("xmppSlice", "default_slice")
+omf_desc.set_attribute_value("xmppHost", "xmpp-plexus.onelab.eu")
+omf_desc.set_attribute_value("xmppPort", 5222)
+omf_desc.set_attribute_value("xmppPassword", "1234")
+
+# Add node1
+node1 = omf_desc.create("Node")
+node1.set_attribute_value("hostname", "omf.plexus.wlab17")
+
+# Add configuration for interface 1
+iface1 = omf_desc.create("WifiInterface")
+iface1.set_attribute_value("alias", "w0")
+iface1.set_attribute_value("mode", "adhoc")
+iface1.set_attribute_value("channel", "6")
+iface1.set_attribute_value("type", "g")
+iface1.set_attribute_value("essid", "cvlcmode")
+iface1.set_attribute_value("ip", "192.168.0.17")
+node1.connector("devs").connect(iface1.connector("node"))
+
+# Add multicast route to node 1
+route1 = node1.add_route()
+route1.set_attribute_value("Destination", "224.0.0.0")
+route1.set_attribute_value("NetPrefix", 4)
+route1.set_attribute_value("Device", "wlan0")
+
+# Add node2
+node2 = omf_desc.create("Node")
+node2.set_attribute_value("hostname", "omf.plexus.wlab37")
+
+# Add configuration for interface 2
+iface2 = omf_desc.create("WifiInterface")
+iface2.set_attribute_value("alias", "w0")
+iface2.set_attribute_value("mode", "adhoc")
+iface2.set_attribute_value("channel", "6")
+iface2.set_attribute_value("type", "g")
+iface2.set_attribute_value("essid", "cvlcmode")
+iface2.set_attribute_value("ip", "192.168.0.37")
+node2.connector("devs").connect(iface2.connector("node"))
+
+# Add multicast route to node 2
+route2 = node2.add_route()
+route2.set_attribute_value("Destination", "224.0.0.0")
+route2.set_attribute_value("NetPrefix", 4)
+route2.set_attribute_value("Device", "wlan0")
+
+# Add a channel... this could be ommited
+channel = omf_desc.create("Channel")
+channel.set_attribute_value("mode", "adhoc")
+channel.set_attribute_value("channel", "6")
+channel.set_attribute_value("type", "g")
+channel.set_attribute_value("essid", "cvlcmode")
+channel.connector("devs").connect(iface1.connector("chan"))
+channel.connector("devs").connect(iface2.connector("chan"))
+
+# Add a vlc server to stream a video using multicast
+app1 = omf_desc.create("OmfApplication")
+app1.set_attribute_value("appId", "Vlc#1")
+app1.set_attribute_value("arguments", "/opt/bbb_240p_mpeg4_lq.ts --sout '#rtp{dst=239.255.0.1,port=1234,mux=ts}' vlc://quit")
+app1.set_attribute_value("path", "/opt/vlc-1.1.13/cvlc")
+app1.set_attribute_value("env", "DISPLAY=localhost:10.0 XAUTHORITY=/root/.Xauthority")
+app1.connector("node").connect(node1.connector("apps"))
+
+# Add a vlc client to receive the video stream
+app2 = omf_desc.create("OmfApplication")
+app2.set_attribute_value("appId", "Vlc#2")
+app2.set_attribute_value("arguments", "rtp://239.255.0.1:1234")
+app2.set_attribute_value("path", "/opt/vlc-1.1.13/cvlc")
+# To see the stream to a ssh -X connection, the DISPLAY variable must be set to the value of the node.
+# Also don't forget to execute in 'xhost + localhost' in the node
+app2.set_attribute_value("env", "DISPLAY=localhost:10.0 XAUTHORITY=/root/.Xauthority")
+app2.connector("node").connect(node2.connector("apps"))
+
+xml = exp_desc.to_xml()
+
+controller = ExperimentController(xml, root_dir)
+controller.start()
+#while not (controller.is_finished(app1.guid) and \
+#        controller.is_finished(app2.guid)):
+#    time.sleep(0.5)
+
+time.sleep(30)
+
+controller.set(iface2.guid, "channel", "1")
+
+time.sleep(15)
+
+controller.stop()
+controller.shutdown()
+
diff --git a/examples/omf-plexuslab-xeyes.py b/examples/omf-plexuslab-xeyes.py
new file mode 100644 (file)
index 0000000..7e83943
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Experiment Topology:
+#
+#  n1 --- n2
+#  0.1   0.2 
+#    
+
+from nepi.core.design import ExperimentDescription, FactoriesProvider
+from nepi.core.execute import ExperimentController
+import getpass
+import logging
+import tempfile
+import time
+
+logging.basicConfig(level=logging.DEBUG)
+
+root_dir = tempfile.mkdtemp()
+
+exp_desc = ExperimentDescription()
+
+testbed_id = "omf"
+omf_provider = FactoriesProvider(testbed_id)
+omf_desc = exp_desc.add_testbed_description(omf_provider)
+omf_desc.set_attribute_value("homeDirectory", root_dir)
+omf_desc.set_attribute_value("enableDebug", True)
+omf_desc.set_attribute_value("xmppSlice", "default_slice")
+omf_desc.set_attribute_value("xmppHost", "xmpp-plexus.onelab.eu")
+omf_desc.set_attribute_value("xmppPort", 5222)
+omf_desc.set_attribute_value("xmppPassword", "1234")
+
+node1 = omf_desc.create("Node")
+node1.set_attribute_value("hostname", "omf.plexus.wlab17")
+
+app1 = omf_desc.create("OmfApplication")
+app1.set_attribute_value("appId", "xeyes#1")
+app1.set_attribute_value("path", "/usr/bin/xeyes")
+app1.set_attribute_value("env", "DISPLAY=localhost:10.0 XAUTHORITY=/root/.Xauthority")
+app1.connector("node").connect(node1.connector("apps"))
+
+xml = exp_desc.to_xml()
+
+controller = ExperimentController(xml, root_dir)
+controller.start()
+
+time.sleep(30)
+
+controller.stop()
+controller.shutdown()
+
diff --git a/examples/omf_vlc.py b/examples/omf_vlc.py
deleted file mode 100644 (file)
index 1f92319..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-#
-# Experiment Topology:
-#
-#  n1 --- n2
-#  0.1   0.2 
-#    
-
-from nepi.core.design import ExperimentDescription, FactoriesProvider
-from nepi.core.execute import ExperimentController
-import getpass
-import tempfile
-import time
-
-root_dir = tempfile.mkdtemp()
-
-exp_desc = ExperimentDescription()
-
-testbed_id = "omf"
-omf_provider = FactoriesProvider(testbed_id)
-omf_desc = exp_desc.add_testbed_description(omf_provider)
-omf_desc.set_attribute_value("homeDirectory", root_dir)
-omf_desc.set_attribute_value("enableDebug", True)
-omf_desc.set_attribute_value("xmppSlice", "default_slice")
-omf_desc.set_attribute_value("xmppHost", "xmpp-omf.onelab.eu")
-omf_desc.set_attribute_value("xmppPort", 5222)
-omf_desc.set_attribute_value("xmppPassword", "1234")
-
-node1 = omf_desc.create("Node")
-node1.set_attribute_value("hostname", "omf.my.wlab18")
-node2 = omf_desc.create("Node")
-node2.set_attribute_value("hostname", "omf.my.wlab49")
-
-iface12 = omf_desc.create("WifiInterface")
-iface12.set_attribute_value("mode", "adhoc")
-iface12.set_attribute_value("channel", "6")
-iface12.set_attribute_value("type", "g")
-iface12.set_attribute_value("essid", "cvlcmode")
-iface12.set_attribute_value("ip", "192.168.0.18")
-node1.connector("devs").connect(iface12.connector("node"))
-
-iface21 = omf_desc.create("WifiInterface")
-iface21.set_attribute_value("mode", "adhoc")
-iface21.set_attribute_value("channel", "6")
-iface21.set_attribute_value("type", "g")
-iface21.set_attribute_value("essid", "cvlcmode")
-iface21.set_attribute_value("ip", "192.168.0.49")
-node2.connector("devs").connect(iface21.connector("node"))
-
-channel = omf_desc.create("Channel")
-channel.set_attribute_value("mode", "adhoc")
-channel.set_attribute_value("channel", "6")
-channel.set_attribute_value("type", "g")
-channel.set_attribute_value("essid", "cvlcmode")
-channel.connector("devs").connect(iface12.connector("chan"))
-channel.connector("devs").connect(iface21.connector("chan"))
-
-app2 = omf_desc.create("OmfApplication")
-app2.set_attribute_value("appId", "Vlc#2")
-app2.set_attribute_value("arguments", "rtp://239.255.0.1:1234")
-app2.set_attribute_value("path", "/opt/vlc-1.1.13/vlc")
-app2.connector("node").connect(node2.connector("apps"))
-
-app1 = omf_desc.create("OmfApplication")
-app1.set_attribute_value("appId", "Vlc#1")
-app1.set_attribute_value("arguments", "/opt/10-by-p0d.avi --sout '#duplicate{dst=display,dst=rtp{mux=ts,dst=239.255.0.1,port=1234}}'")
-app1.set_attribute_value("path", "/opt/vlc-1.1.13/vlc")
-app1.connector("node").connect(node1.connector("apps"))
-
-xml = exp_desc.to_xml()
-
-controller = ExperimentController(xml, root_dir)
-controller.start()
-#while not (controller.is_finished(app1.guid) and \
-#        controller.is_finished(app2.guid)):
-#    time.sleep(0.5)
-
-time.sleep(20)
-
-controller.set(iface21.guid, "channel", "1")
-
-time.sleep(15)
-
-controller.stop()
-controller.shutdown()
-
index e630012..7ad5509 100644 (file)
@@ -157,6 +157,12 @@ class Route(AttributesMap):
                 value = 0,
                 flags = Attribute.NoDefaultValue,
                 validation_function = validation.is_integer)
+        self.add_attribute(name = "Device",
+                help = "Device name", 
+                type = Attribute.STRING,
+                value = None,
+                flags = Attribute.NoDefaultValue,
+                validation_function = validation.is_string)
 
 class Box(AttributesMap, Taggable):
     def __init__(self, guid, factory, testbed_guid, container = None):
index 9f034cb..5e0c5ea 100644 (file)
@@ -83,7 +83,8 @@ class TestbedController(object):
         """Instructs the addition of an address"""
         raise NotImplementedError
 
-    def defer_add_route(self, guid, destination, netprefix, nexthop, metric = 0):
+    def defer_add_route(self, guid, destination, netprefix, nexthop, 
+            metric = 0, device = None):
         """Instructs the addition of a route"""
         raise NotImplementedError
 
@@ -1017,8 +1018,10 @@ class ExperimentController(object):
                         testbed.defer_add_address(guid, address, netprefix, 
                                 broadcast)
                 # routes
-                for (destination, netprefix, nexthop, metric) in data.get_route_data(guid):
-                    testbed.defer_add_route(guid, destination, netprefix, nexthop, metric)
+                for (destination, netprefix, nexthop, metric, device) in \
+                        data.get_route_data(guid):
+                    testbed.defer_add_route(guid, destination, netprefix, nexthop, 
+                            metric, device)
                 # store connections data
                 for (connector_type_name, other_guid, other_connector_type_name) \
                         in data.get_connection_data(guid):
index ade1ccc..d27588d 100644 (file)
@@ -150,12 +150,14 @@ class TestbedController(execute.TestbedController):
             self._add_address[guid] = list()
         self._add_address[guid].append((address, netprefix, broadcast))
 
-    def defer_add_route(self, guid, destination, netprefix, nexthop, metric = 0):
+    def defer_add_route(self, guid, destination, netprefix, nexthop, 
+            metric = 0, device = None):
         self._validate_guid(guid)
         self._validate_allow_routes(guid)
         if not guid in self._add_route:
             self._add_route[guid] = list()
-        self._add_route[guid].append((destination, netprefix, nexthop, metric)) 
+        self._add_route[guid].append((destination, netprefix, nexthop, 
+            metric, device)) 
 
     def do_setup(self):
         self._root_directory = self._attributes.\
index 472062c..36e914a 100644 (file)
@@ -245,7 +245,7 @@ def configure_node(testbed_instance, guid):
         return
     routes = testbed_instance._add_route[guid]
     for route in routes:
-        (destination, netprefix, nexthop, metric) = route
+        (destination, netprefix, nexthop, metric, device) = route
         element.add_route(prefix = destination, prefix_len = netprefix,
             nexthop = nexthop, metric = metric)
 
index 201c932..a7921a8 100644 (file)
@@ -477,7 +477,7 @@ def configure_node(testbed_instance, guid):
     ns3 = testbed_instance.ns3
     routes = testbed_instance._add_route[guid]
     for route in routes:
-        (destination, netprefix, nexthop, metric) = route
+        (destination, netprefix, nexthop, metric, device) = route
         address = ns3.Ipv4Address(destination)
         if nexthop:
             nexthop_address = ns3.Ipv4Address(nexthop)
@@ -497,7 +497,7 @@ def configure_node(testbed_instance, guid):
                     break
             if ifindex < 0:
                 # Check previous ptp routes
-                for chaindest, chainprefix, chainhop, metric in routes:
+                for chaindest, chainprefix, chainhop, metric, device in routes:
                     if chaindest == nexthop and chainprefix == 32:
                         chainhop_address = ns3.Ipv4Address(chainhop)
                         for ifidx in xrange(nifaces):
index db2e810..9736955 100644 (file)
@@ -34,7 +34,8 @@ class TestbedController(testbed_impl.TestbedController):
         port = self._attributes.get_attribute_value("xmppPort")
         password = self._attributes.get_attribute_value("xmppPassword")
 
-        self._api = OmfAPI(slice, host, port, password)
+        xmpp_root = self._attributes.get_attribute_value("xmppRoot")
+        self._api = OmfAPI(slice, host, port, password, xmpp_root)
  
         super(TestbedController, self).do_setup()
 
index 4b1734f..faca73f 100644 (file)
@@ -1,12 +1,13 @@
 # -*- coding: utf-8 -*-
 
 import functools
+import random
 import weakref
 
 from constants import TESTBED_ID, TESTBED_VERSION
 from nepi.core import metadata
 from nepi.core.attributes import Attribute
-from nepi.util import tags, validation
+from nepi.util import tags, validation, ipaddr2
 from nepi.util.constants import ApplicationStatus as AS, \
         FactoryCategories as FC, DeploymentConfiguration as DC
 
@@ -22,6 +23,10 @@ class OmfResource(object):
     def tc(self):
         return self._tc and self._tc()
 
+    @property
+    def guid(self):
+        return self._guid
+
     def configure(self):
         pass
 
@@ -45,6 +50,26 @@ class OmfNode(OmfResource):
         self.hostname = self.tc._get_parameters(guid)['hostname']
         self.tc.api.enroll_host(self.hostname)
 
+    def configure(self):
+        routes = self.tc._add_route.get(self.guid, [])
+        iface_guids = self.tc.get_connected(self.guid, "devs", "node")
+       
+        for route in routes:
+            (destination, netprefix, nexthop, metric, device) = route
+            netmask = ipaddr2.ipv4_mask2dot(netprefix)
+
+            # Validate that the interface is associated to the node
+            for iface_guid in iface_guids:
+                iface = self.tc.elements.get(iface_guid)
+                if iface.devname == device:
+                    self.tc.api.execute(self.hostname, 
+                        "Id#%s" % str(random.getrandbits(128)), 
+                        "add -net %s netmask %s dev %s" % (destination, netmask, iface.devname), 
+                        "/sbin/route", # path
+                        None, # env
+                     )
+                    break
+
 ## APPLICATION ################################################################
 
 class OmfApplication(OmfResource):
@@ -84,6 +109,8 @@ class OmfApplication(OmfResource):
 ## WIFIIFACE ########################################################
 
 class OmfWifiInterface(OmfResource):
+    alias2name = dict({'w0':'wlan0', 'w1':'wlan1'})
+
     def __init__(self, guid, tc):
         super(OmfWifiInterface, self).__init__(guid, tc)
         node_guids = tc.get_connected(guid, "node", "devs")
@@ -91,19 +118,24 @@ class OmfWifiInterface(OmfResource):
             raise RuntimeError("Can't instantiate interface %d outside node" % guid)
 
         self._node_guid = node_guids[0] 
+        self.alias = None
         self.mode = None
         self.type = None
         self.essid = None
         self.channel = None
         self.ip = None
+        self.devname = None
 
     def __setattr__(self, name, value):
+        if name == "alias":
+            self.devname = self.alias2name.get(value)
+
         if name in ["ip", "mode", "type", "essid", "channel"]:
             node = self.tc.elements.get(self._node_guid)    
-            attribute = "net/w0/%s" % name
+            attribute = "net/%s/%s" % (self.alias, name)
             self._tc().api.configure(node.hostname, attribute, value)
-        else:
-            super(OmfWifiInterface, self).__setattr__(name, value)
+        
+        super(OmfWifiInterface, self).__setattr__(name, value)
 
 # Factories
 NODE = "Node"
@@ -138,7 +170,7 @@ def status(testbed_instance, guid):
 
 def configure(testbed_instance, guid):
     element = testbed_instance.elements.get(guid)
-    return element.status()
+    return element.configure()
 
 ### Factory information ###
 
@@ -258,9 +290,14 @@ attributes = dict({
                 "flags": Attribute.NoDefaultValue, 
                 "validation_function": validation.is_ip4_address
             }),
-
-
-
+    "alias": dict({
+                "name": "alias",
+                "help": "Alias for device (e.g. w0, w1, etc)",
+                "type": Attribute.STRING,
+                "value": "w0",
+                "flags": Attribute.NoDefaultValue, 
+                "validation_function": validation.is_string
+            }),
     })
 
 traces = dict()
@@ -273,6 +310,7 @@ factories_info = dict({
             "help": "OMF Node",
             "category": FC.CATEGORY_NODES,
             "create_function": functools.partial(create, NODE),
+            "configure_function": configure,
             "box_attributes": ["hostname"],
             "connector_types": ["devs", "apps"],
             "tags": [tags.NODE, tags.ALLOW_ROUTES],
@@ -282,7 +320,7 @@ factories_info = dict({
             "category": FC.CATEGORY_DEVICES,
             "create_function": functools.partial(create, WIFIIFACE),
             "configure_function": configure,
-            "box_attributes": ["mode", "type", "channel", "essid", "ip"],
+            "box_attributes": ["mode", "type", "channel", "essid", "ip", "alias"],
             "connector_types": ["node", "chan"],
             "tags": [tags.INTERFACE, tags.HAS_ADDRESSES],
        }),
@@ -343,6 +381,14 @@ testbed_attributes = dict({
                 "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
                 "validation_function": validation.is_string
             }),
+    "xmppRoot": dict({
+                "name": "xmppRoot",
+                "help": "Root node of the xmpp server pubsub tree",
+                "type": Attribute.STRING,
+                "value": "OMF",
+                "flags": Attribute.ExecReadOnly | Attribute.ExecImmutable,
+                "validation_function": validation.is_string
+            }),
     })
 
 supported_recovery_policies = [
index d76fba3..7b54b4c 100644 (file)
@@ -8,7 +8,7 @@ from nepi.testbeds.omf.omf_client import OMFClient
 from nepi.testbeds.omf.omf_messages import MessageHandler
 
 class OmfAPI(object):
-    def __init__(self, slice, host, port, password):
+    def __init__(self, slice, host, port, password, xmpp_root = None):
         date = datetime.datetime.now().strftime("%Y-%m-%dt%H.%M.%S")
         tz = -time.altzone if time.daylight != 0 else -time.timezone
         date += "%+06.2f" % (tz / 3600) # timezone difference is in seconds
@@ -18,6 +18,7 @@ class OmfAPI(object):
         self._port = port
         self._password = password
         self._hostnames = []
+        self._xmpp_root = xmpp_root or "OMF"
 
         self._logger = logging.getLogger("nepi.testbeds.omf")
 
@@ -61,9 +62,9 @@ class OmfAPI(object):
         self._client.create(xmpp_node)
         self._client.subscribe(xmpp_node)
 
-        address = "/%s/OMF/%s/%s" % (self._host, self._slice, self._user)
+        address = "/%s/%s/%s/%s" % (self._host, self._xmpp_root, self._slice, self._user)
         payload = self._message.newexpfunction(self._user, address)
-        slice_sid = "/OMF/%s" % (self._slice)
+        slice_sid = "/%s/%s" % (self._xmpp_root, self._slice)
         self._client.publish(payload, slice_sid)
 
     def _enroll_logger(self):
@@ -78,18 +79,18 @@ class OmfAPI(object):
         self._client.publish(payload, xmpp_node)
 
     def _host_session_id(self, hostname):
-        return "/OMF/%s/%s/%s" % (self._slice, self._user, hostname)
+        return "/%s/%s/%s/%s" % (self._xmpp_root, self._slice, self._user, hostname)
 
     def _host_resource_id(self, hostname):
-        return "/OMF/%s/resources/%s" % (self._slice, hostname)
+        return "/%s/%s/resources/%s" % (self._xmpp_root, self._slice, hostname)
 
     @property
     def _exp_session_id(self):
-        return "/OMF/%s/%s" % (self._slice, self._user)
+        return "/%s/%s/%s" % (self._xmpp_root, self._slice, self._user)
 
     @property
     def _logger_session_id(self):
-        return "/OMF/%s/%s/LOGGER" % (self._slice, self._user)
+        return "/%s/%s/%s/LOGGER" % (self._xmpp_root, self._slice, self._user)
 
     def delete(self, hostname):
         if not hostname in self._hostnames:
index 24937db..f4df82f 100644 (file)
@@ -221,7 +221,7 @@ class TunIface(object):
             if pointopoint:
                 prefix = 32
                 
-            dest, destprefix, nexthop, metric = route
+            dest, destprefix, nexthop, metric, device = route
             
             myNet = ipaddr.IPv4Network("%s/%d" % (addr, prefix))
             gwIp = ipaddr.IPv4Network(nexthop)
index e863f4a..34f6f79 100644 (file)
@@ -672,7 +672,7 @@ class Node(object):
         
         vsys_vnet = ipaddr.IPv4Network(vsys_vnet)
         for route in routes:
-            dest, prefix, nexthop, metric = route
+            dest, prefix, nexthop, metric, device = route
             dest = ipaddr.IPv4Network("%s/%d" % (dest,prefix))
             nexthop = ipaddr.IPAddress(nexthop)
             if dest not in vsys_vnet or nexthop not in vsys_vnet:
@@ -681,7 +681,7 @@ class Node(object):
         return 'vroute'
     
     def format_route(self, route, dev, method, action):
-        dest, prefix, nexthop, metric = route
+        dest, prefix, nexthop, metric, device = route
         if method == 'vroute':
             return (
                 "%s %s%s gw %s %s" % (
index a1a8a59..683e4f5 100644 (file)
@@ -131,7 +131,7 @@ class XmlExperimentParser(ExperimentParser):
 
     def routes_data_to_xml(self, doc, parent_tag, guid, data):
         routes_tag = doc.createElement("routes") 
-        for (destination, netprefix, nexthop, metric) \
+        for (destination, netprefix, nexthop, metric, device) \
                 in data.get_route_data(guid):
             route_tag = doc.createElement("route") 
             routes_tag.appendChild(route_tag)
@@ -139,6 +139,7 @@ class XmlExperimentParser(ExperimentParser):
             route_tag.setAttribute("NetPrefix", xmlencode(netprefix))
             route_tag.setAttribute("NextHop", xmlencode(nexthop))
             route_tag.setAttribute("Metric", xmlencode(metric))
+            route_tag.setAttribute("Device", xmlencode(device))
         if routes_tag.hasChildNodes():
             parent_tag.appendChild(routes_tag)
 
@@ -283,8 +284,9 @@ class XmlExperimentParser(ExperimentParser):
                 nexthop = xmldecode(route_tag.getAttribute("NextHop"))
                 metric = int(route_tag.getAttribute("Metric")) \
                         if route_tag.hasAttribute("Metric") else 0
+                device = xmldecode(route_tag.getAttribute("Device"))
                 data.add_route_data(guid, destination, netprefix, 
-                        nexthop, metric)
+                        nexthop, metric, device)
 
     def connections_data_from_xml(self, tag, guid, data):
         connections_tag_list = tag.getElementsByTagName("connections")
index 6da07db..eeaf594 100644 (file)
@@ -85,7 +85,7 @@ class ExperimentData(object):
             address_data["Broadcast"] = broadcast
         addresses_data.append(address_data)
 
-    def add_route_data(self, guid, destination, netprefix, nexthop, metric):
+    def add_route_data(self, guid, destination, netprefix, nexthop, metric, device):
         data = self.data[guid]
         if not "routes" in data:
             data["routes"] = list()
@@ -94,7 +94,8 @@ class ExperimentData(object):
             "Destination": destination,
             "NetPrefix": netprefix, 
             "NextHop": nexthop, 
-            "Metric": metric
+            "Metric": metric,
+            "Device": device
             })
         routes_data.append(route_data)
 
@@ -183,7 +184,8 @@ class ExperimentData(object):
         return [(data["Destination"],
                  data["NetPrefix"],
                  data["NextHop"],
-                 data["Metric"]) \
+                 data["Metric"],
+                 data["Device"]) \
                          for data in routes_data]
 
 class ExperimentParser(object):
@@ -254,7 +256,9 @@ class ExperimentParser(object):
              netprefix = route.get_attribute_value("NetPrefix")
              nexthop = route.get_attribute_value("NextHop")
              metric = route.get_attribute_value("Metric")
-             data.add_route_data(guid, destination, netprefix, nexthop, metric)
+             device = route.get_attribute_value("Device")
+             data.add_route_data(guid, destination, netprefix, nexthop, 
+                     metric, device)
 
     def from_data(self, experiment_description, data):
         box_guids = list()
@@ -325,13 +329,14 @@ class ExperimentParser(object):
                 addr.set_attribute_value("Broadcast", broadcast)
 
     def routes_from_data(self, box, data):
-         for (destination, netprefix, nexthop, metric) \
+         for (destination, netprefix, nexthop, metric, device) \
                  in data.get_route_data(box.guid):
             addr = box.add_route()
             addr.set_attribute_value("Destination", destination)
             addr.set_attribute_value("NetPrefix", netprefix)
             addr.set_attribute_value("NextHop", nexthop)
             addr.set_attribute_value("Metric", metric)
+            addr.set_attribute_value("Device", device)
 
     def connections_from_data(self, experiment_description, guids, data):
         for guid in guids:
index 9545a5c..04f3655 100644 (file)
@@ -761,8 +761,10 @@ class TestbedControllerServer(BaseServer):
     @Marshalling.handles(ADD_ROUTE)
     @Marshalling.args(int, str, int, str, int)
     @Marshalling.retvoid
-    def defer_add_route(self, guid, destination, netprefix, nexthop, metric):
-        self._testbed.defer_add_route(guid, destination, netprefix, nexthop, metric)
+    def defer_add_route(self, guid, destination, netprefix, nexthop, 
+            metric, device):
+        self._testbed.defer_add_route(guid, destination, netprefix, nexthop, 
+                metric, device)
 
     @Marshalling.handles(DO_SETUP)
     @Marshalling.args()