2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2014 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
20 from nepi.execution.attribute import Attribute, Flags, Types
21 from nepi.execution.resource import ResourceManager, ResourceState, \
30 class PlanetlabTunTapFdLink(ResourceManager):
31 """ Interconnects a TAP or TUN Linux device to a FdNetDevice
33 _rtype = "planetlab::ns3::TunTapFdLink"
35 def __init__(self, ec, guid):
36 super(PlanetlabTunTapFdLink, self).__init__(ec, guid)
38 self._fdnetdevice = None
39 self._fd_sock_address = None
42 def fdnetdevice(self):
43 if not self._fdnetdevice:
44 from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice
45 devices = self.get_connected(NS3BaseFdNetDevice.get_rtype())
46 if not devices or len(devices) != 1:
47 msg = "TapFdLink must be connected to exactly one FdNetDevices"
49 raise RuntimeError, msg
51 self._fdnetdevice = devices[0]
53 return self._fdnetdevice
58 from nepi.resources.planetlab.tap import PlanetlabTap
59 devices = self.get_connected(PlanetlabTap.get_rtype())
61 if not devices or len(devices) != 1:
62 msg = "TapFdLink must be connected to exactly one PlanetlabTap"
64 raise RuntimeError, msg
66 self._tap = devices[0]
71 def fd_sock_address(self):
72 return self._fd_sock_address
78 def upload_sources(self):
81 # vif-passfd python script
82 pl_vif_passfd = os.path.join(os.path.dirname(__file__), "scripts",
85 scripts.append(pl_vif_passfd)
88 scripts = ";".join(scripts)
90 self.node.upload(scripts,
91 os.path.join(self.node.src_dir),
94 def upload_start_command(self):
95 if self.tap.node.get("hostname") != \
96 self.fdnetdevice.node.get("hostname"):
97 msg = "Tap and FdNetDevice are not in the same host"
99 raise RuntimeError, msg
101 self._fd_sock_address = self.fdnetdevice.recv_fd()
102 self.set("command", self._start_command)
104 command = self.get("command")
105 env = self.get("env")
107 # We want to make sure the ccnd is running
108 # before the experiment starts.
109 # Run the command as a bash script in background,
110 # in the host ( but wait until the command has
111 # finished to continue )
112 env = self.replace_paths(env)
113 command = self.replace_paths(command)
115 shfile = os.path.join(self.app_home, "start.sh")
116 self.node.run_and_wait(command, self.run_home,
121 if self.tap.state < ResourceState.READY or \
122 self.fdnetdevice.state < ResourceState.READY:
123 self.ec.schedule(self.reschedule_delay, self.deploy)
128 super(PlanetlabTunTapFdLink, self).do_deploy()
131 if self.state == ResourceState.READY:
132 command = self.get("command")
133 self.info("Starting command '%s'" % command)
137 msg = " Failed to execute command '%s'" % command
138 self.error(msg, out, err)
139 raise RuntimeError, msg
142 def _start_command(self):
144 # Use pl-vif-passfd.py to send fd from TAP to FdNetDevice
145 command.append("sudo -S")
146 command.append("PYTHONPATH=$PYTHONPATH:${SRC}")
147 command.append("python ${SRC}/pl-vif-passfd")
148 command.append("-a %s" % self.fd_sock_address)
149 command.append("-S %s " % self.tap.sock_name)
151 command = " ".join(command)
152 command = self.replace_paths(command)