From c505d0f175a08073733ac8ff79dfa694de6e07f3 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Sun, 14 Jul 2013 19:24:24 -0700 Subject: [PATCH 1/1] 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.43.0