From c505d0f175a08073733ac8ff79dfa694de6e07f3 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Sun, 14 Jul 2013 19:24:24 -0700 Subject: [PATCH] PlanetlabTap reads STOP from unix socket --- setup.py | 2 +- .../planetlab/scripts/.pl-tap-create.py.swp | Bin 0 -> 20480 bytes .../planetlab/scripts/pl-vif-create.py | 157 ++++++++++++++++++ .../planetlab/scripts/pl-vif-stop.py | 56 +++++++ src/nepi/resources/planetlab/tap.py | 85 ++++++---- src/nepi/resources/planetlab/tun.py | 8 +- test/resources/planetlab/tap.py | 4 +- test/resources/planetlab/tun.py | 2 +- 8 files changed, 277 insertions(+), 37 deletions(-) create mode 100644 src/nepi/resources/planetlab/scripts/.pl-tap-create.py.swp create mode 100644 src/nepi/resources/planetlab/scripts/pl-vif-create.py create mode 100644 src/nepi/resources/planetlab/scripts/pl-vif-stop.py diff --git a/setup.py b/setup.py index 69fc5b27..bebb10aa 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ setup( "nepi.resources.ns3", "nepi.resources.omf", "nepi.resources.planetlab", - "nepi.resources.planetlab", "nepi.util"], package_dir = {"": "src"}, + package_data = {"nepi.resources.planetlab" : [ "scripts/*.py" ]} ) diff --git a/src/nepi/resources/planetlab/scripts/.pl-tap-create.py.swp b/src/nepi/resources/planetlab/scripts/.pl-tap-create.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..9f6e2d644382a158450598c63a39601f8c3d0e22 GIT binary patch literal 20480 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. +# +# Author: Alina Quereilhac + +import base64 +import errno +import vsys +import socket +from optparse import OptionParser, SUPPRESS_HELP + +# TODO: GRE OPTION!! CONFIGURE THE VIF-UP IN GRE MODE!! + +STOP_MSG = "STOP" + +def create_socket(socket_name): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(socket_name) + return sock + +def recv_msg(conn): + msg = [] + chunk = '' + + while '\n' not in chunk: + try: + chunk = conn.recv(1024) + except (OSError, socket.error), e: + if e[0] != errno.EINTR: + raise + # Ignore eintr errors + continue + + if chunk: + msg.append(chunk) + else: + # empty chunk = EOF + break + + msg = ''.join(msg).split('\n')[0] + decoded = base64.b64decode(msg) + return decoded.rstrip() + +def send_reply(conn, reply): + encoded = base64.b64encode(reply) + conn.send("%s\n" % encoded) + +def stop_action(): + return "STOP-ACK" + +def reply_action(msg): + return "Reply to: %s" % msg + +def get_options(): + usage = ("usage: %prog -t -a -n " + "-s -p -f -S ") + + parser = OptionParser(usage = usage) + + parser.add_option("-t", "--vif-type", dest="vif_type", + help = "Virtual interface type. Either IFF_TAP or IFF_TUN. " + "Defaults to IFF_TAP. ", type="str") + + parser.add_option("-a", "--ip4-address", dest="ip4_address", + help = "IPv4 address to assign to interface. It must belong to the " + "network segment owned by the slice, given by the vsys_vnet tag. ", + type="str") + + parser.add_option("-n", "--net-prefix", dest="net_prefix", + help = "IPv4 network prefix for the interface. It must be the one " + "given by the slice's vsys_vnet tag. ", + type="int") + + parser.add_option("-s", "--snat", dest="snat", default = False, + action="store_true", help="Enable SNAT for the interface") + + parser.add_option("-p", "--pointopoint", dest="pointopoint", + help = "Peer end point for the interface ", default = None, + type="str") + + parser.add_option("-f", "--if-name-file", dest="if_name_file", + help = "File to store the interface name assigned by the OS", + default = "if_name", type="str") + + parser.add_option("-S", "--socket-name", dest="socket_name", + help = "Name for the unix socket used to interact with this process", + default = "tap.sock", type="str") + + (options, args) = parser.parse_args() + + vif_type = vsys.IFF_TAP + if options.vif_type and options.vif_type == "IFF_TUN": + vif_type = vsys.IFF_TUN + + return (vif_type, options.ip4_address, options.net_prefix, options.snat, + options.pointopoint, options.if_name_file, options.socket_name) + +if __name__ == '__main__': + + (vif_type, ip4_address, net_prefix, snat, pointopoint, + if_name_file, socket_name) = get_options() + + (fd, if_name) = vsys.fd_tuntap(vif_type) + vsys.vif_up(if_name, ip4_address, net_prefix, snat, pointopoint) + + # Saving interface name to 'if_name_file + f = open(if_name_file, 'w') + f.write(if_name) + f.close() + + # create unix socket to receive instructions + sock = create_socket(socket_name) + sock.listen(0) + + # wait for messages to arrive and process them + stop = False + + while not stop: + conn, addr = sock.accept() + conn.settimeout(5) + + while not stop: + try: + msg = recv_msg(conn) + except socket.timeout, e: + # Ingore time-out + continue + + if not msg: + # Ignore - connection lost + break + + if msg == STOP_MSG: + stop = True + reply = stop_action() + else: + reply = reply_action(msg) + + try: + send_reply(conn, reply) + except socket.error: + break + diff --git a/src/nepi/resources/planetlab/scripts/pl-vif-stop.py b/src/nepi/resources/planetlab/scripts/pl-vif-stop.py new file mode 100644 index 00000000..3176a877 --- /dev/null +++ b/src/nepi/resources/planetlab/scripts/pl-vif-stop.py @@ -0,0 +1,56 @@ +# +# 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 . +# +# Author: Alina Quereilhac + +import base64 +import errno +import vsys +import socket +from optparse import OptionParser, SUPPRESS_HELP + +STOP_MSG = "STOP" + +def get_options(): + usage = ("usage: %prog -S ") + + parser = OptionParser(usage = usage) + + parser.add_option("-S", "--socket-name", dest="socket_name", + help = "Name for the unix socket used to interact with this process", + default = "tap.sock", type="str") + + (options, args) = parser.parse_args() + + return (options.socket_name) + +if __name__ == '__main__': + + (socket_name) = get_options() + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(socket_name) + encoded = base64.b64encode(STOP_MSG) + sock.send("%s\n" % encoded) + reply = sock.recv(1024) + reply = base64.b64decode(reply) + + print reply + + + + diff --git a/src/nepi/resources/planetlab/tap.py b/src/nepi/resources/planetlab/tap.py index ed6c2aae..f4afcf63 100644 --- a/src/nepi/resources/planetlab/tap.py +++ b/src/nepi/resources/planetlab/tap.py @@ -28,7 +28,6 @@ import os import time # TODO: - routes!!! -# - Make base clase 'virtual device' and redefine vif_type # - Instead of doing an infinite loop, open a port for communication allowing # to pass the fd to another process @@ -47,6 +46,7 @@ class PlanetlabTap(LinuxApplication): flags = Flags.ExecReadOnly) prefix4 = Attribute("prefix4", "IPv4 network prefix", + type = Types.Integer, flags = Flags.ExecReadOnly) mtu = Attribute("mtu", "Maximum transmition unit for device", @@ -110,25 +110,41 @@ class PlanetlabTap(LinuxApplication): def upload_start_command(self): # upload tap-creation python script - start_script = self.replace_paths(self._start_script) - self.node.upload(start_script, - os.path.join(self.app_home, "tap_create.py"), - text = True, + pl_tap_create = os.path.join(os.path.dirname(__file__), "scripts", + "pl-tap-create.py") + self.node.upload(pl_tap_create, + os.path.join(self.app_home, "pl-vif-create.py"), overwrite = False) # upload start.sh start_command = self.replace_paths(self._start_command) - + self.info("Uploading command '%s'" % start_command) self.set("command", start_command) + self.node.upload(start_command, os.path.join(self.app_home, "start.sh"), text = True, overwrite = False) + # upload tap-stop python script + pl_tap_stop = os.path.join(os.path.dirname(__file__), "scripts", + "pl-tap-stop.py") + self.node.upload(pl_tap_stop, + os.path.join(self.app_home, "pl-vif-stop.py"), + overwrite = False) + + # upload stop.sh script + stop_command = self.replace_paths(self._stop_command) + self.node.upload(stop_command, + os.path.join(self.app_home, "stop.sh"), + text = True, + overwrite = False) + # We want to make sure the device is up and running - # before the experiment starts. + # before the deploy finishes (so things will be ready + # before other stuff starts running). # Run the command as a bash script in background, # in the host ( but wait until the command has # finished to continue ) @@ -174,8 +190,9 @@ class PlanetlabTap(LinuxApplication): if state == ResourceState.STARTED: self.info("Stopping command '%s'" % command) - command = "rm %s" % os.path.join(self.run_home, "if_stop") - (out, err), proc = self.execute_command(command) + command = "bash %s" % os.path.join(self.app_home, "stop.sh") + (out, err), proc = self.execute_command(command, + blocking = True) self._stop_time = tnow() self._state = ResourceState.STOPPED @@ -223,35 +240,39 @@ class PlanetlabTap(LinuxApplication): @property def _start_command(self): - return "sudo -S python ${APP_HOME}/tap_create.py" + command = ["sudo -S python ${APP_HOME}/pl-vif-create.py"] + + command.append("-t %s" % self.vif_type) + command.append("-a %s" % self.get("ip4")) + command.append("-n %d" % self.get("prefix4")) + command.append("-f %s " % self.if_name_file) + command.append("-S %s " % self.sock_name) + if self.get("snat") == True: + command.append("-s") + if self.get("pointopoint"): + command.append("-p %s" % self.get("pointopoint")) + + return " ".join(command) @property - def _start_script(self): - return ( "import vsys, time, os \n" - "(fd, if_name) = vsys.fd_tuntap(vsys.%(devtype)s)\n" - "vsys.vif_up(if_name, '%(ip)s', %(prefix)s%(snat)s%(pointopoint)s)\n" - "f = open('%(if_name_file)s', 'w')\n" - "f.write(if_name)\n" - "f.close()\n\n" - "f = open('%(if_stop_file)s', 'w')\n" - "f.close()\n\n" - "while os.path.exists('%(if_stop_file)s'):\n" - " time.sleep(2)\n" - ) % ({ - "devtype": self._vif_type, - "ip": self.get("ip4"), - "prefix": self.get("prefix4"), - "snat": ", snat=True" if self.get("snat") else "", - "pointopoint": ", pointopoint=%s" % self.get("pointopoint") \ - if self.get("pointopoint") else "", - "if_name_file": os.path.join(self.run_home, "if_name"), - "if_stop_file": os.path.join(self.run_home, "if_stop"), - }) + def _stop_command(self): + command = ["sudo -S python ${APP_HOME}/pl-vif-stop.py"] + + command.append("-S %s " % self.sock_name) + return " ".join(command) @property - def _vif_type(self): + def vif_type(self): return "IFF_TAP" + @property + def if_name_file(self): + return os.path.join(self.run_home, "if_name") + + @property + def sock_name(self): + return os.path.join(self.run_home, "tap.sock") + def valid_connection(self, guid): # TODO: Validate! return True diff --git a/src/nepi/resources/planetlab/tun.py b/src/nepi/resources/planetlab/tun.py index 2c16cb19..8d66210b 100644 --- a/src/nepi/resources/planetlab/tun.py +++ b/src/nepi/resources/planetlab/tun.py @@ -20,6 +20,8 @@ from nepi.execution.resource import clsinit_copy from nepi.resources.planetlab.tap import PlanetlabTap +import os + @clsinit_copy class PlanetlabTun(PlanetlabTap): _rtype = "PlanetlabTun" @@ -29,7 +31,11 @@ class PlanetlabTun(PlanetlabTap): self._home = "tun-%s" % self.guid @property - def _vif_type(self): + def sock_name(self): + return os.path.join(self.run_home, "tun.sock") + + @property + def vif_type(self): return "IFF_TUN" diff --git a/test/resources/planetlab/tap.py b/test/resources/planetlab/tap.py index c945ae20..f08a54c9 100755 --- a/test/resources/planetlab/tap.py +++ b/test/resources/planetlab/tap.py @@ -44,11 +44,11 @@ class PlanetlabTapTestCase(unittest.TestCase): tap = ec.register_resource("PlanetlabTap") ec.set(tap, "ip4", "192.168.1.1") - ec.set(tap, "prefix4", "24") + ec.set(tap, "prefix4", 24) ec.register_connection(tap, node) app = ec.register_resource("LinuxApplication") - cmd = "ping -c3 192.168.1.1" + cmd = "ping -c3 192.168.1.1" ec.set(app, "command", cmd) ec.register_connection(app, node) diff --git a/test/resources/planetlab/tun.py b/test/resources/planetlab/tun.py index 3d650d6b..8c79ed1d 100755 --- a/test/resources/planetlab/tun.py +++ b/test/resources/planetlab/tun.py @@ -44,7 +44,7 @@ class PlanetlabTunTestCase(unittest.TestCase): tun = ec.register_resource("PlanetlabTun") ec.set(tun, "ip4", "192.168.1.1") - ec.set(tun, "prefix4", "24") + ec.set(tun, "prefix4", 24) ec.register_connection(tun, node) app = ec.register_resource("LinuxApplication") -- 2.47.0