ec.register_connection(ovs, node)
return ovs
-def add_port(ec, port_name, ovs):
+def add_port(ec, port_name, network, ovs):
port = ec.register_resource("OVSPort")
ec.set(port, "port_name", port_name)
+ ec.set(port, "network", network)
ec.register_connection(port, ovs)
return port
ec.register_connection(tap, node)
return tap
-def add_tunnel(ec, network, port0, tap):
- tunnel = ec.register_resource("OVSTunnel")
- ec.set(tunnel, "network", network)
+def add_tunnel(ec, port0, tap):
+ tunnel = ec.register_resource("LinuxUdpTunnel")
ec.register_connection(port0, tunnel)
ec.register_connection(tunnel, tap)
return tunnel
host1 = "planetlab2.ionio.gr"
host2 = "iraplab2.iralab.uni-karlsruhe.de"
-ip_controller = "xxx.yyy.zzz.ttt"
+ip_controller = "1.1.1.1"
#XXX : Depends on the Vsys_tag of your slice
network = "192.168.3.0"
ovs2 = add_ovs(ec, "nepi_bridge_2", "192.168.3.2/24", ip_controller, "6633", s2_node)
# Add ports on ovs
-port1 = add_port(ec, "nepi_port1", ovs1)
-port3 = add_port(ec, "nepi_port3", ovs1)
-port2 = add_port(ec, "nepi_port2", ovs2)
-port4 = add_port(ec, "nepi_port4", ovs2)
+port1 = add_port(ec, "nepi_port1", network, ovs1)
+port3 = add_port(ec, "nepi_port3", network, ovs1)
+port2 = add_port(ec, "nepi_port2", network, ovs2)
+port4 = add_port(ec, "nepi_port4", network, ovs2)
h1_node = add_node(ec, host1, slicename, pl_user, pl_password)
h2_node = add_node(ec, host2, slicename, pl_user, pl_password)
tap2 = add_tap(ec, "192.168.3.4", 24, "192.168.3.2", h2_node)
# Connect the nodes
-tunnel1 = add_tunnel(ec, network, port1, tap1)
-tunnel2 = add_tunnel(ec, network, port2, tap2)
-tunnel3 = add_tunnel(ec, network, port3, port4)
+tunnel1 = add_tunnel(ec, port1, tap1)
+tunnel2 = add_tunnel(ec, port2, tap2)
+tunnel3 = add_tunnel(ec, port3, port4)
# Add ping commands
app1 = add_app(ec, "ping -c5 192.168.3.2", s1_node)
ec.register_connection(ovs, node)
return ovs
-def add_port(ec, port_name, ovs):
+def add_port(ec, port_name, network, ovs):
port = ec.register_resource("OVSPort")
ec.set(port, "port_name", port_name)
+ ec.set(port, "network", network)
ec.register_connection(port, ovs)
return port
ec.register_connection(tap, node)
return tap
-def add_tunnel(ec, network, port0, tap):
- tunnel = ec.register_resource("OVSTunnel")
- ec.set(tunnel, "network", network)
+def add_tunnel(ec, port0, tap):
+ tunnel = ec.register_resource("LinuxUdpTunnel")
ec.register_connection(port0, tunnel)
ec.register_connection(tunnel, tap)
return tunnel
#XXX : Need to put 6 working nodes or to let Nepi find for you
switch1 = "planetlab2.virtues.fi"
switch2 = "planetlab2.upc.es"
-switch3 = "planetlab2.cs.aueb.gr"
+switch3 = "planetlab1.informatik.uni-erlangen.de"
host1 = "planetlab2.ionio.gr"
host2 = "iraplab2.iralab.uni-karlsruhe.de"
host3 = "planetlab2.diku.dk"
ovs3 = add_ovs(ec, "nepi_bridge_3", "192.168.3.6/24", ip_controller, "6633", s3_node)
# Add ports on ovs
-port1 = add_port(ec, "nepi_port1", ovs1)
-port4 = add_port(ec, "nepi_port4", ovs1)
-port7 = add_port(ec, "nepi_port7", ovs1)
-port2 = add_port(ec, "nepi_port2", ovs2)
-port5 = add_port(ec, "nepi_port5", ovs2)
-port3 = add_port(ec, "nepi_port3", ovs3)
-port6 = add_port(ec, "nepi_port6", ovs3)
+port1 = add_port(ec, "nepi_port1", network, ovs1)
+port4 = add_port(ec, "nepi_port4", network, ovs1)
+port7 = add_port(ec, "nepi_port7", network, ovs1)
+port2 = add_port(ec, "nepi_port2", network, ovs2)
+port5 = add_port(ec, "nepi_port5", network, ovs2)
+port3 = add_port(ec, "nepi_port3", network, ovs3)
+port6 = add_port(ec, "nepi_port6", network, ovs3)
h1_node = add_node(ec, host1, slicename, pl_user, pl_password)
h2_node = add_node(ec, host2, slicename, pl_user, pl_password)
tap3 = add_tap(ec, "192.168.3.5", 24, "192.168.3.6", h3_node)
# Connect the nodes
-tunnel1 = add_tunnel(ec, network, port1, tap1)
-tunnel2 = add_tunnel(ec, network, port2, tap2)
-tunnel3 = add_tunnel(ec, network, port3, tap3)
-tunnel4 = add_tunnel(ec, network, port4, port5)
-tunnel5 = add_tunnel(ec, network, port7, port6)
+tunnel1 = add_tunnel(ec, port1, tap1)
+tunnel2 = add_tunnel(ec, port2, tap2)
+tunnel3 = add_tunnel(ec, port3, tap3)
+tunnel4 = add_tunnel(ec, port4, port5)
+tunnel5 = add_tunnel(ec, port7, port6)
#tunnel6 = add_tunnel(ec, network, port8, port9)
# Add ping commands
ec.register_connection(ovs, node)
return ovs
-def add_port(ec, port_name, ovs):
+def add_port(ec, port_name, network, ovs):
port = ec.register_resource("OVSPort")
ec.set(port, "port_name", port_name)
+ ec.set(port, "network", network)
ec.register_connection(port, ovs)
return port
ec.register_connection(tap, node)
return tap
-def add_tunnel(ec, network, port0, tap):
- tunnel = ec.register_resource("OVSTunnel")
- ec.set(tunnel, "network", network)
+def add_tunnel(ec, port0, tap):
+ tunnel = ec.register_resource("LinuxUdpTunnel")
ec.register_connection(port0, tunnel)
ec.register_connection(tunnel, tap)
return tunnel
#XXX : Need to put 6 working nodes or to let Nepi find for you
switch1 = "planetlab2.virtues.fi"
switch2 = "planetlab2.upc.es"
-switch3 = "planetlab2.cs.aueb.gr"
+switch3 = "planetlab1.informatik.uni-erlangen.de"
host1 = "planetlab2.ionio.gr"
host2 = "iraplab2.iralab.uni-karlsruhe.de"
host3 = "planetlab2.diku.dk"
ovs3 = add_ovs(ec, "nepi_bridge_3", "192.168.3.6/24", ip_controller, "6633", s3_node)
# Add ports on ovs
-port1 = add_port(ec, "nepi_port1", ovs1)
-port4 = add_port(ec, "nepi_port4", ovs1)
-port7 = add_port(ec, "nepi_port7", ovs1)
-port2 = add_port(ec, "nepi_port2", ovs2)
-port5 = add_port(ec, "nepi_port5", ovs2)
-port8 = add_port(ec, "nepi_port8", ovs2)
-port3 = add_port(ec, "nepi_port3", ovs3)
-port6 = add_port(ec, "nepi_port6", ovs3)
-port9 = add_port(ec, "nepi_port9", ovs3)
+port1 = add_port(ec, "nepi_port1", network, ovs1)
+port4 = add_port(ec, "nepi_port4", network, ovs1)
+port7 = add_port(ec, "nepi_port7", network, ovs1)
+port2 = add_port(ec, "nepi_port2", network, ovs2)
+port5 = add_port(ec, "nepi_port5", network, ovs2)
+port8 = add_port(ec, "nepi_port8", network, ovs2)
+port3 = add_port(ec, "nepi_port3", network, ovs3)
+port6 = add_port(ec, "nepi_port6", network, ovs3)
+port9 = add_port(ec, "nepi_port9", network, ovs3)
h1_node = add_node(ec, host1, slicename, pl_user, pl_password)
h2_node = add_node(ec, host2, slicename, pl_user, pl_password)
tap3 = add_tap(ec, "192.168.3.5", 24, "192.168.3.6", h3_node)
# Connect the nodes
-tunnel1 = add_tunnel(ec, network, port1, tap1)
-tunnel2 = add_tunnel(ec, network, port2, tap2)
-tunnel3 = add_tunnel(ec, network, port3, tap3)
-tunnel4 = add_tunnel(ec, network, port4, port5)
-tunnel5 = add_tunnel(ec, network, port7, port6)
-tunnel6 = add_tunnel(ec, network, port8, port9)
+tunnel1 = add_tunnel(ec, port1, tap1)
+tunnel2 = add_tunnel(ec, port2, tap2)
+tunnel3 = add_tunnel(ec, port3, tap3)
+tunnel4 = add_tunnel(ec, port4, port5)
+tunnel5 = add_tunnel(ec, port7, port6)
+tunnel6 = add_tunnel(ec, port8, port9)
# Add ping commands
app1 = add_app(ec, "ping -c5 192.168.3.4", s1_node)
return True
- ## XXX: NOT REALLY WORKING YET!
+ def initiate_udp_connection(self, remote_endpoint, connection_app_home,
+ connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
+ port = self.udp_connect(remote_endpoint, connection_app_home,
+ connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)
+ return port
+
def udp_connect(self, remote_endpoint, connection_app_home,
connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
udp_connect_command = self._udp_connect_command(
cipher, cipher_key, bwlimit, txqueuelen)
# upload command to connect.sh script
- shfile = os.path.join(connection_app_home, "udp-connect.sh")
+ shfile = os.path.join(self.app_home, "udp-connect.sh")
self.node.upload_command(udp_connect_command,
shfile = shfile,
overwrite = False)
# invoke connect script
cmd = "bash %s" % shfile
- (out, err), proc = self.node.run(cmd, connection_run_home)
+ (out, err), proc = self.node.run(cmd, self.run_home)
# check if execution errors occurred
msg = "Failed to connect endpoints "
raise RuntimeError, msg
# Wait for pid file to be generated
- pid, ppid = self.node.wait_pid(connection_run_home)
+ self._pid, self._ppid = self.node.wait_pid(self.run_home)
# If the process is not running, check for error information
# on the remote machine
- if not pid or not ppid:
- (out, err), proc = self.node.check_errors(connection_run_home)
+ if not self._pid or not self._ppid:
+ (out, err), proc = self.node.check_errors(self.run_home)
# Out is what was written in the stderr file
if err:
msg = " Failed to start command '%s' " % command
self.error(msg, out, err)
raise RuntimeError, msg
- return pid, ppid
+ port = self.wait_local_port()
+
+ return port
def _udp_connect_command(self, remote_endpoint, connection_run_home,
cipher, cipher_key, bwlimit, txqueuelen):
remote_ip = remote_endpoint.node.get("ip")
- local_port_file = os.path.join(connection_run_home,
+ local_port_file = os.path.join(self.run_home,
"local_port")
- remote_port_file = os.path.join(connection_run_home,
+ remote_port_file = os.path.join(self.run_home,
"remote_port")
- ret_file = os.path.join(connection_run_home,
+ ret_file = os.path.join(self.run_home,
"ret_file")
# Generate UDP connect command
return command
+ def establish_udp_connection(self, remote_endpoint, port):
+ # upload remote port number to file
+ rem_port = "%s\n" % port
+ self.node.upload(rem_port,
+ os.path.join(self.run_home, "remote_port"),
+ text = True,
+ overwrite = False)
+
+ def verify_connection(self):
+ self.wait_result()
+
+ def terminate_connection(self):
+ if self._pid and self._ppid:
+ (out, err), proc = self.node.kill(self._pid, self._ppid,
+ sudo = True)
+
+ # check if execution errors occurred
+ if proc.poll() and err:
+ msg = " Failed to Kill the Tap"
+ self.error(msg, out, err)
+ raise RuntimeError, msg
+
+ def check_status(self):
+ return self.node.status(self._pid, self._ppid)
+
+ def wait_local_port(self):
+ """ Waits until the local_port file for the endpoint is generated,
+ and returns the port number
+
+ """
+ return self.wait_file("local_port")
+
+ def wait_result(self):
+ """ Waits until the return code file for the endpoint is generated
+
+ """
+ return self.wait_file("ret_file")
+
+ def wait_file(self, filename):
+ """ Waits until file on endpoint is generated """
+ result = None
+ delay = 1.0
+
+ for i in xrange(20):
+ (out, err), proc = self.node.check_output(
+ self.run_home, filename)
+ if out:
+ result = out.strip()
+ break
+ else:
+ time.sleep(delay)
+ delay = delay * 1.5
+ else:
+ msg = "Couldn't retrieve %s" % filename
+ self.error(msg, out, err)
+ raise RuntimeError, msg
+
+ return result
+
@property
def _start_command(self):
command = []
self.endpoint1.node.mkdir(self.run_home(self.endpoint1))
self.endpoint2.node.mkdir(self.run_home(self.endpoint2))
+ self.debug("Initiate the connection")
# Start 2 step connection
# Initiate connection from endpoint 1 to endpoint 2
data1 = self.initiate_connection(self.endpoint1, self.endpoint2)
# Initiate connection from endpoint 2 to endpoint 1
data2 = self.initiate_connection(self.endpoint2, self.endpoint1)
+ self.debug("Establish the connection")
# Establish connection from endpoint 1 to endpoint 2
self.establish_connection(self.endpoint1, self.endpoint2, data2)
# Establish connection from endpoint 2 to endpoint 1
self.establish_connection(self.endpoint2, self.endpoint1, data1)
+ self.debug("Verify the connection")
# check if connection was successful on both sides
self.verify_connection(self.endpoint1, self.endpoint2)
self.verify_connection(self.endpoint2, self.endpoint1)
def do_stop(self):
""" Stops application execution
"""
+
if self.state == ResourceState.STARTED:
self.info("Stopping tunnel")
connected = []
for guid in self.connections:
rm = self.ec.get_resource(guid)
- if hasattr(rm, "udp_connect"):
+ if hasattr(rm, "initiate_udp_connection"):
connected.append(rm)
return connected
cipher_key = self.get("cipherKey")
bwlimit = self.get("bwLimit")
txqueuelen = self.get("txQueueLen")
-
- # Return the command to execute to initiate the connection to the
- # other endpoint
connection_app_home = self.app_home(endpoint)
connection_run_home = self.run_home(endpoint)
- pid, ppid = endpoint.udp_connect(
+
+ port = endpoint.initiate_udp_connection(
remote_endpoint,
connection_app_home,
connection_run_home,
cipher, cipher_key, bwlimit, txqueuelen)
- port = self.wait_local_port(endpoint)
-
- self._pids[endpoint] = (pid, ppid)
-
return port
def establish_connection(self, endpoint, remote_endpoint, port):
- self.upload_remote_port(endpoint, port)
+ endpoint.establish_udp_connection(remote_endpoint, port)
def verify_connection(self, endpoint, remote_endpoint):
- self.wait_result(endpoint)
+ endpoint.verify_connection()
def terminate_connection(self, endpoint, remote_endpoint):
- pid, ppid = self._pids[endpoint]
-
- if pid and ppid:
- (out, err), proc = endpoint.node.kill(pid, ppid,
- sudo = True)
-
- # check if execution errors occurred
- if proc.poll() and err:
- msg = " Failed to STOP tunnel"
- self.error(msg, out, err)
- raise RuntimeError, msg
+ endpoint.terminate_connection()
def check_state_connection(self):
# Make sure the process is still running in background
# No execution errors occurred. Make sure the background
# process with the recorded pid is still running.
- pid1, ppid1 = self._pids[self.endpoint1]
- pid2, ppid2 = self._pids[self.endpoint2]
- status1 = self.endpoint1.node.status(pid1, ppid1)
- status2 = self.endpoint2.node.status(pid2, ppid2)
+ status1 = self.endpoint1.check_status()
+ status2 = self.endpoint2.check_status()
if status1 == ProcStatus.FINISHED and \
status2 == ProcStatus.FINISHED:
return result
- def upload_remote_port(self, endpoint, port):
- # upload remote port number to file
- port = "%s\n" % port
- endpoint.node.upload(port,
- os.path.join(self.run_home(endpoint), "remote_port"),
- text = True,
- overwrite = False)
-
"""
from nepi.resources.planetlab.openvswitch.ovsport import OVSPort
- rm = self.get_connected(OVSPort.get_rtype())
+ rms = self.get_connected(OVSPort.get_rtype())
- if rm[0].state < ResourceState.RELEASED:
- self.ec.schedule(reschedule_delay, self.release)
- return
+ for rm in rms :
+ if rm.state < ResourceState.RELEASED:
+ self.ec.schedule(reschedule_delay, self.release)
+ return
cmd = "sliver-ovs del-bridge %s" % self.get('bridge_name')
(out, err), proc = self.node.run(cmd, self.ovs_checks,
from nepi.resources.planetlab.node import PlanetlabNode
from nepi.resources.linux.application import LinuxApplication
+import os
+
reschedule_delay = "0.5s"
@clsinit_copy
_help = "Runs an OpenVSwitch on a PlanetLab host"
_backend = "planetlab"
- _authorized_connections = ["OVSSwitch", "OVSTunnel"]
+ _authorized_connections = ["OVSSwitch", "LinuxUdpTunnel", "LinuxTunnel"]
@classmethod
def _register_attributes(cls):
"""
port_name = Attribute("port_name", "Name of the port",
flags = Flags.Design)
+ endpoint_ip = Attribute("endpoint_ip", "IP of the endpoint. This is the attribute "
+ "you should use to establish a tunnel or a remote "
+ "connection between endpoint",
+ flags = Flags.Design)
+ network = Attribute("network", "Network used by the port",
+ flags = Flags.Design)
cls._register_attribute(port_name)
+ cls._register_attribute(endpoint_ip)
+ cls._register_attribute(network)
def __init__(self, ec, guid):
"""
"""
super(OVSPort, self).__init__(ec, guid)
+
+
self._port_number = None
- self.port_info = []
+ # in case of connection by tunnel
+ self._remote_ip = None
def log_message(self, msg):
return " guid %d - OVSPort - %s " % (self.guid, msg)
if ovsswitch: return ovsswitch[0]
return None
+ @property
+ def remote_ip(self):
+ return self._remote_ip
+
@property
def port_number(self):
return self._port_number
self.info("Created the port %s on switch %s" % (self.get('port_name'),
self.ovsswitch.get('bridge_name')))
- def get_local_end(self):
+ def initiate_udp_connection(self, remote_endpoint, connection_app_home,
+ connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
""" Get the local_endpoint of the port
"""
+ self._remote_ip = remote_endpoint.node.get("ip")
+
msg = "Discovering the number of the port %s" % self.get('port_name')
- self.debug(msg)
+ self.info(msg)
command = "sliver-ovs get-local-endpoint %s" % self.get('port_name')
out = err = ""
self.info("The number of the %s is %s" % (self.get('port_name'),
self.port_number))
-
- def set_port_info(self):
- """ Set all the information about the port inside a list
- """
- info = []
- info.append(self.node.get('hostname'))
+ if remote_endpoint.is_rm_instance("PlanetlabTap"):
+ self._vroute = self.ec.register_resource("PlanetlabVroute")
+ self.ec.set(self._vroute, "action", "add")
+ self.ec.set(self._vroute, "network", self.get("network"))
+
+ print "Vroute Guid :" + str(self._vroute)
+
+ self.ec.register_connection(self._vroute, remote_endpoint.guid)
+ self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
+
+ # For debugging
+ msg = "Route for the tap configured"
+ self.debug(msg)
+
+ return self.port_number
+
- #Return the ip of the node
- import socket
- ip = socket.gethostbyname(self.node.get('hostname'))
- info.append(ip)
+ def establish_udp_connection(self,remote_endpoint, port):
+ establish_connection_command = self._establish_connection_command(port)
- info.append(self.get('port_name'))
- info.append(self.ovsswitch.get('virtual_ip_pref'))
- info.append(self.port_number)
- return info
+ # upload command to connect.sh script
+ shfile = os.path.join(self.app_home, "sw-connect.sh")
+ self.node.upload_command(establish_connection_command,
+ shfile = shfile,
+ overwrite = False)
- def switch_connect_command(self, local_port_name,
- remote_ip, remote_port_num):
+ # invoke connect script
+ cmd = "bash %s" % shfile
+ (out, err), proc = self.node.run(cmd, self.run_home,
+ sudo = True,
+ stdout = "sw_stdout",
+ stderr = "sw_stderr")
+
+ # check if execution errors occurred
+ msg = "Failed to connect endpoints "
+ if proc.poll():
+ self.error(msg, out, err)
+ raise RuntimeError, msg
+
+ # Wait for pid file to be generated
+ self._pid, self._ppid = self.node.wait_pid(self.run_home)
+
+ # If the process is not running, check for error information
+ # on the remote machine
+ if not self._pid or not self._ppid:
+ (out, err), proc = self.node.check_errors(self.run_home)
+ # Out is what was written in the stderr file
+ if err:
+ msg = " Failed to start command '%s' " % command
+ self.error(msg, out, err)
+ raise RuntimeError, msg
+
+ # For debugging
+ msg = "Connection on port configured"
+ self.debug(msg)
+
+
+ def _establish_connection_command(self, port):
""" Script to create the connection from a switch to a
remote endpoint
"""
+ local_port_name = self.get('port_name')
command = ["sliver-ovs"]
command.append("set-remote-endpoint ")
command.append("%s " % local_port_name)
- command.append("%s " % remote_ip)
- command.append("%s " % remote_port_num)
+ command.append("%s " % self.remote_ip)
+ command.append("%s " % port)
command = " ".join(command)
command = self.replace_paths(command)
return command
+ def verify_connection(self):
+ self.ovsswitch.ovs_status()
+
+ def terminate_connection(self):
+ return True
+
+ def check_status(self):
+ return self.node.status(self._pid, self._ppid)
+
def do_deploy(self):
""" Deploy the OVS port after the OVS Switch
"""
self.do_provision()
self.create_port()
- self.get_local_end()
+ end_ip = self.ovsswitch.get('virtual_ip_pref').split('/')
+ self.set("endpoint_ip", end_ip[0])
#Check the status of the OVS Switch
self.ovsswitch.ovs_status()
- # Save all the information inside a list
- self.port_info = self.set_port_info()
-
super(OVSPort, self).do_deploy()
def do_release(self):
""" Delete the port on the OVSwitch. It needs to wait for the tunnel
to be released.
"""
+ from nepi.resources.linux.udptunnel import LinuxUdpTunnel
+ rm = self.get_connected(LinuxUdpTunnel.get_rtype())
- from nepi.resources.planetlab.openvswitch.tunnel import OVSTunnel
- rm = self.get_connected(OVSTunnel.get_rtype())
-
- if rm and rm[0].state < ResourceState.RELEASED:
+ if rm and rm[0].state < ResourceState.STOPPED:
self.ec.schedule(reschedule_delay, self.release)
return
+++ /dev/null
-#
-# NEPI, a framework to manage network experiments
-# Copyright (C) 2013 INRIA
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
-# Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
-# Julien Tribino <julien.tribino@inria.fr>
-
-
-from nepi.execution.attribute import Attribute, Flags, Types
-from nepi.execution.resource import ResourceManager, ResourceFactory, clsinit_copy, \
- ResourceState
-from nepi.resources.linux.application import LinuxApplication
-from nepi.resources.planetlab.node import PlanetlabNode
-from nepi.resources.planetlab.openvswitch.ovs import OVSSwitch
-from nepi.util.timefuncs import tnow, tdiffsec
-from nepi.resources.planetlab.vroute import PlanetlabVroute
-from nepi.resources.planetlab.tap import PlanetlabTap
-
-import os
-import time
-import socket
-
-reschedule_delay = "0.5s"
-
-@clsinit_copy
-class OVSTunnel(LinuxApplication):
- """
- .. class:: Class Args :
-
- :param ec: The Experiment controller
- :type ec: ExperimentController
- :param guid: guid of the RM
- :type guid: int
- :param creds: Credentials to communicate with the rm
- :type creds: dict
-
- """
-
- _rtype = "OVSTunnel"
- _authorized_connections = ["OVSPort", "PlanetlabTap"]
-
- @classmethod
- def _register_attributes(cls):
- """ Register the attributes of OVSTunnel RM
-
- """
- network = Attribute("network", "IPv4 Network Address",
- flags = Flags.Design)
-
- cipher = Attribute("cipher",
- "Cipher to encript communication. "
- "One of PLAIN, AES, Blowfish, DES, DES3. ",
- default = None,
- allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"],
- type = Types.Enumerate,
- flags = Flags.Design)
-
- cipher_key = Attribute("cipherKey",
- "Specify a symmetric encryption key with which to protect "
- "packets across the tunnel. python-crypto must be installed "
- "on the system." ,
- flags = Flags.Design)
-
- txqueuelen = Attribute("txQueueLen",
- "Specifies the interface's transmission queue length. "
- "Defaults to 1000. ",
- type = Types.Integer,
- flags = Flags.Design)
-
- bwlimit = Attribute("bwLimit",
- "Specifies the interface's emulated bandwidth in bytes "
- "per second.",
- type = Types.Integer,
- flags = Flags.Design)
-
- cls._register_attribute(network)
- cls._register_attribute(cipher)
- cls._register_attribute(cipher_key)
- cls._register_attribute(txqueuelen)
- cls._register_attribute(bwlimit)
-
- def __init__(self, ec, guid):
- """
- :param ec: The Experiment controller
- :type ec: ExperimentController
- :param guid: guid of the RM
- :type guid: int
-
- """
- super(OVSTunnel, self).__init__(ec, guid)
- self._home = "tunnel-%s" % self.guid
- self.port_info_tunl = []
- self._pid = None
- self._ppid = None
- self._vroute = None
- self._node_endpoint1 = None
- self._node_endpoint2 = None
-
- def log_message(self, msg):
- return " guid %d - Tunnel - %s " % (self.guid, msg)
-
- def app_home(self, node):
- return os.path.join(node.exp_home, self._home)
-
- def run_home(self, node):
- return os.path.join(self.app_home(node), self.ec.run_id)
-
- @property
- def tap(self):
- """ Return the Tap RM if it exists """
- rclass = ResourceFactory.get_resource_type(PlanetlabTap.get_rtype())
- for guid in self.connections:
- rm = self.ec.get_resource(guid)
- if isinstance(rm, rclass):
- return rm
-
- @property
- def ovsswitch(self):
- """ Return the 1st switch """
- for guid in self.connections:
- rm_port = self.ec.get_resource(guid)
- if hasattr(rm_port, "create_port"):
- rm_list = rm_port.get_connected(OVSSwitch.get_rtype())
- if rm_list:
- return rm_list[0]
-
- @property
- def check_switch_host_link(self):
- """ Check if the links are between switches
- or switch-host. Return False for the latter.
- """
- if self.tap :
- return True
- return False
-
-
- def endpoints(self):
- """ Return the list with the two connected elements.
- Either Switch-Switch or Switch-Host
- """
- connected = [1, 1]
- position = 0
- for guid in self.connections:
- rm = self.ec.get_resource(guid)
- if hasattr(rm, "create_port"):
- connected[position] = rm
- position += 1
- elif hasattr(rm, "udp_connect"):
- connected[1] = rm
- return connected
-
- def get_node(self, endpoint):
- """ Get the nodes of the endpoint
- """
- rm = []
- if hasattr(endpoint, "create_port"):
- rm_list = endpoint.get_connected(OVSSwitch.get_rtype())
- if rm_list:
- rm = rm_list[0].get_connected(PlanetlabNode.get_rtype())
- else:
- rm = endpoint.get_connected(PlanetlabNode.get_rtype())
-
- if rm :
- return rm[0]
-
- @property
- def endpoint1(self):
- """ Return the first endpoint : Always a Switch
- """
- endpoint = self.endpoints()
- return endpoint[0]
-
- @property
- def endpoint2(self):
- """ Return the second endpoint : Either a Switch or a TAP
- """
- endpoint = self.endpoints()
- return endpoint[1]
-
- def get_port_info(self, endpoint1, endpoint2):
- #TODO : Need to change it. Really bad to have method that return different type of things !!!!!
- """ Retrieve the port_info list for each port
-
- """
- if self.check_switch_host_link :
- host0, ip0, pname0, virt_ip0, pnumber0 = endpoint1.port_info
- return pnumber0
-
- host0, ip0, pname0, virt_ip0, pnumber0 = endpoint1.port_info
- host1, ip1, pname1, virt_ip1, pnumber1 = endpoint2.port_info
-
- return pname0, ip1, pnumber1
-
- def wait_local_port(self, node_endpoint):
- """ Waits until the if_name file for the command is generated,
- and returns the if_name for the device """
-
- local_port = None
- delay = 1.0
-
- #TODO : Need to change it with reschedule to avoid the problem
- # of the order of connection
- for i in xrange(10):
- (out, err), proc = node_endpoint.check_output(self.run_home(node_endpoint), 'local_port')
- if out:
- local_port = int(out)
- break
- else:
- time.sleep(delay)
- delay = delay * 1.5
- else:
- msg = "Couldn't retrieve local_port"
- self.error(msg, out, err)
- raise RuntimeError, msg
-
- return local_port
-
- def connection(self, local_endpoint, rm_endpoint):
- """ Create the connect command for each case :
- - Host - Switch,
- - Switch - Switch,
- - Switch - Host
- """
- local_node = self.get_node(local_endpoint)
- local_node.mkdir(self.run_home(local_node))
-
- rm_node = self.get_node(rm_endpoint)
- rm_node.mkdir(self.run_home(rm_node))
-
- # Host to switch
- if self.check_switch_host_link and local_endpoint == self.endpoint2 :
- # Collect info from rem_endpoint
- remote_ip = socket.gethostbyname(rm_node.get("hostname"))
-
- # Collect info from endpoint
- connection_run_home = self.run_home(local_node)
- connection_app_home = self.app_home(local_node)
- cipher = self.get("cipher")
- cipher_key = self.get("cipherKey")
- bwlimit = self.get("bwLimit")
- txqueuelen = self.get("txQueueLen")
-
-
- # Upload the remote port in a file
- rem_port = str(self.get_port_info(rm_endpoint,local_endpoint))
- rem_port_file = os.path.join(self.run_home(local_node), "remote_port")
- local_node.upload(rem_port, rem_port_file,
- text = True,
- overwrite = False)
-
- self._pid, self._ppid = local_endpoint.udp_connect(
- rm_node, connection_run_home, connection_app_home,
- cipher, cipher_key, bwlimit, txqueuelen)
-
-
-# connect_command = local_endpoint.udp_connect_command(
-# remote_ip, local_port_file, rem_port_file,
-# ret_file, cipher, cipher_key, bwlimit, txqueuelen)
-
-# self.connection_command(connect_command, local_node, rm_node)
-
-# # Wait for pid file to be generated
-# self._pid, self._ppid = local_node.wait_pid(self.run_home(local_node))
-
- if not self._pid or not self._ppid:
- (out, err), proc = local_node.check_errors(self.run_home(local_node))
- # Out is what was written in the stderr file
- if err:
- msg = " Failed to start connection of the OVS Tunnel "
- self.error(msg, out, err)
- raise RuntimeError, msg
- return
-
- # Switch to Host
- if self.check_switch_host_link and local_endpoint == self.endpoint1:
- local_port_name = local_endpoint.get('port_name')
- remote_port_num = self.wait_local_port(rm_node)
- remote_ip = socket.gethostbyname(rm_node.get("hostname"))
-
- # Switch to Switch
- if not self.check_switch_host_link :
- local_port_name, remote_ip, remote_port_num = self.get_port_info(local_endpoint, rm_endpoint)
-
- connect_command = local_endpoint.switch_connect_command(
- local_port_name, remote_ip, remote_port_num)
-
- self.connection_command(connect_command, local_node, rm_node)
-
- def connection_command(self, command, node_endpoint, rm_node_endpoint):
- """ Execute the connection command on the node and check if the processus is
- correctly running on the node.
- """
- shfile = os.path.join(self.app_home(node_endpoint), "sw_connect.sh")
- node_endpoint.upload(command,
- shfile,
- text = True,
- overwrite = False)
-
- # Invoke connect script
- out = err= ''
- cmd = "bash %s" % shfile
- (out, err), proc = node_endpoint.run(cmd, self.run_home(node_endpoint),
- sudo = True,
- stdout = "sw_stdout",
- stderr = "sw_stderr")
-
- # Check if execution errors occured
-
- if proc.poll():
- msg = "Failed to connect endpoints"
- self.error(msg, out, err)
- raise RuntimeError, msg
-
- # For debugging
- msg = "Connection on port configured"
- self.debug(msg)
-
- def do_provision(self):
- """ Provision the tunnel
- """
-
- #TODO : The order of the connection is important for now !
- # Need to change the code of wait local port
- self.connection(self.endpoint2, self.endpoint1)
- self.connection(self.endpoint1, self.endpoint2)
-
- def configure_route(self):
- """ Configure the route for the tap device
-
- .. note : In case of a conection between a switch and a host, a route
- was missing on the node with the Tap Device. This method create
- the missing route.
- """
-
- if self.check_switch_host_link:
- self._vroute = self.ec.register_resource("PlanetlabVroute")
- self.ec.set(self._vroute, "action", "add")
- self.ec.set(self._vroute, "network", self.get("network"))
-
- self.ec.register_connection(self._vroute, self.tap.guid)
- self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
-
- def do_deploy(self):
- """ Deploy the tunnel after the endpoint get ready
- """
- if (not self.endpoint1 or self.endpoint1.state < ResourceState.READY) or \
- (not self.endpoint2 or self.endpoint2.state < ResourceState.READY):
- self.ec.schedule(reschedule_delay, self.deploy)
- return
-
- self.do_discover()
- self.do_provision()
- self.configure_route()
-
- # Cannot call the deploy of the linux application
- # because of a log error.
- # Need to investigate if it is right that the tunnel
- # inherits from the linux application
- # super(OVSTunnel, self).do_deploy()
- self.set_ready()
-
- def do_release(self):
- """ Release the tunnel by releasing the Tap Device if exists
- """
- if self.check_switch_host_link:
- # TODO: Make more generic Release method of PLTAP
- tap_node = self.get_node(self.endpoint2)
- if self._pid and self._ppid:
- (out, err), proc = tap_node.kill(self._pid,
- self._ppid, sudo = True)
-
- if err or proc.poll():
- msg = " Failed to delete TAP device"
- self.error(msg, out, err)
-
- super(OVSTunnel, self).do_release()
-
return True
+
+ def initiate_udp_connection(self, remote_endpoint, connection_app_home,
+ connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
+ port = self.udp_connect(remote_endpoint, connection_app_home,
+ connection_run_home, cipher, cipher_key, bwlimit, txqueuelen)
+ return port
+
+
def udp_connect(self, remote_endpoint, connection_app_home,
connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
udp_connect_command = self._udp_connect_command(
cipher, cipher_key, bwlimit, txqueuelen)
# upload command to connect.sh script
- shfile = os.path.join(connection_app_home, "udp-connect.sh")
+ shfile = os.path.join(self.app_home, "udp-connect.sh")
self.node.upload_command(udp_connect_command,
shfile = shfile,
overwrite = False)
# invoke connect script
cmd = "bash %s" % shfile
- (out, err), proc = self.node.run(cmd, connection_run_home)
+ (out, err), proc = self.node.run(cmd, self.run_home)
# check if execution errors occurred
msg = "Failed to connect endpoints "
raise RuntimeError, msg
# Wait for pid file to be generated
- pid, ppid = self.node.wait_pid(connection_run_home)
+ self._pid, self._ppid = self.node.wait_pid(self.run_home)
# If the process is not running, check for error information
# on the remote machine
- if not pid or not ppid:
- (out, err), proc = self.node.check_errors(connection_run_home)
+ if not self._pid or not self._ppid:
+ (out, err), proc = self.node.check_errors(self.run_home)
# Out is what was written in the stderr file
if err:
msg = " Failed to start command '%s' " % command
self.error(msg, out, err)
raise RuntimeError, msg
- return pid, ppid
+ port = self.wait_local_port()
+
+ return port
def _udp_connect_command(self, remote_endpoint, connection_run_home,
cipher, cipher_key, bwlimit, txqueuelen):
remote_ip = remote_endpoint.node.get("ip")
- local_port_file = os.path.join(connection_run_home,
+ local_port_file = os.path.join(self.run_home,
"local_port")
- remote_port_file = os.path.join(connection_run_home,
+ remote_port_file = os.path.join(self.run_home,
"remote_port")
- ret_file = os.path.join(connection_run_home,
+ ret_file = os.path.join(self.run_home,
"ret_file")
# Generate UDP connect command
return command
+ def establish_udp_connection(self, remote_endpoint, port):
+ # upload remote port number to file
+ rem_port = "%s\n" % port
+ self.node.upload(rem_port,
+ os.path.join(self.run_home, "remote_port"),
+ text = True,
+ overwrite = False)
+
+ def verify_connection(self):
+ self.wait_result()
+
+ def terminate_connection(self):
+ if self._pid and self._ppid:
+ (out, err), proc = self.node.kill(self._pid, self._ppid,
+ sudo = True)
+
+ # check if execution errors occurred
+ if proc.poll() and err:
+ msg = " Failed to Kill the Tap"
+ self.error(msg, out, err)
+ raise RuntimeError, msg
+
+ def check_status(self):
+ return self.node.status(self._pid, self._ppid)
+
+ def wait_local_port(self):
+ """ Waits until the local_port file for the endpoint is generated,
+ and returns the port number
+
+ """
+ return self.wait_file("local_port")
+
+ def wait_result(self):
+ """ Waits until the return code file for the endpoint is generated
+
+ """
+ return self.wait_file("ret_file")
+
+ def wait_file(self, filename):
+ """ Waits until file on endpoint is generated """
+ result = None
+ delay = 1.0
+
+ for i in xrange(20):
+ (out, err), proc = self.node.check_output(
+ self.run_home, filename)
+ if out:
+ result = out.strip()
+ break
+ else:
+ time.sleep(delay)
+ delay = delay * 1.5
+ else:
+ msg = "Couldn't retrieve %s" % filename
+ self.error(msg, out, err)
+ raise RuntimeError, msg
+
+ return result
+
+
+
def _gre_connect_command(self, remote_endpoint, connection_run_home):
# Set the remote endpoint
self.set("pointopoint", remote_endpoint.get("endpoint_ip"))
return command
+
@property
def _start_command(self):
if self.gre_enabled:
ec.shutdown()
- def ztest_tap_udp_tunnel(self):
+ def test_tap_udp_tunnel(self):
self.t_tap_udp_tunnel(self.user1, self.host1, self.identity,
self.user2, self.host2, self.identity)
- def test_tun_udp_tunnel(self):
+ def ztest_tun_udp_tunnel(self):
self.t_tun_udp_tunnel(self.user1, self.host1, self.identity,
self.user2, self.host2, self.identity)
self.host1 = "planetlab1.informatik.uni-erlangen.de"
self.host2 = "planck227ple.test.ibbt.be"
self.user = "inria_nepi"
- self.identity = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
+ #self.identity = "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'])
+ self.identity = "%s/.ssh/id_rsa" % (os.environ['HOME'])
#self.netblock = "192.168.1"
self.netblock = "192.168.3"