Linux/Ns-3/Dce cross experiments
[nepi.git] / src / nepi / resources / linux / ns3 / tun_tap_fd_link.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2014 INRIA
4 #
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.
9 #
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.
14 #
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/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 from nepi.execution.resource import ResourceState, clsinit_copy, \
21         ResourceManager
22 from nepi.resources.linux.application import LinuxApplication
23
24 import base64
25 import fcntl
26 import os
27 import socket
28 import struct
29
30 @clsinit_copy
31 class LinuxTunTapFdLink(LinuxApplication):
32     """ Interconnects a TAP or TUN Linux device to a FdNetDevice
33     """
34     _rtype = "linux::ns3::TunTapFdLink"
35
36     def __init__(self, ec, guid):
37         super(LinuxTunTapFdLink, self).__init__(ec, guid)
38         self._tap = None
39         self._fdnetdevice = None
40         self._fd = None
41         self._fd_node = None
42         self.send_address = None
43
44     @property
45     def fdnetdevice(self):
46         if not self._fdnetdevice:
47             from nepi.resources.ns3.ns3fdnetdevice import NS3BaseFdNetDevice
48             devices = self.get_connected(NS3BaseFdNetDevice.get_rtype())
49             if not devices or len(devices) != 1: 
50                 msg = "linux::ns3::TunTapFdLink must be connected to exactly one FdNetDevice"
51                 self.error(msg)
52                 raise RuntimeError, msg
53
54             self._fdnetdevice = devices[0]
55         
56             simu = self._fdnetdevice.simulation
57             from nepi.resources.linux.node import LinuxNode
58             nodes = simu.get_connected(LinuxNode.get_rtype())
59             self._fd_node = nodes[0]
60         
61         return self._fdnetdevice
62
63     @property
64     def fdnode(self):
65         return self._fd_node
66
67     @property
68     def tap(self):
69         if not self._tap:
70             from nepi.resources.linux.tap import LinuxTap
71             devices = self.get_connected(LinuxTap.get_rtype())
72             if not devices or len(devices) != 1: 
73                 msg = "linux::ns3::TunTapLink must be connected to exactly one LinuxTap"
74                 self.error(msg)
75                 raise RuntimeError, msg
76
77             self._tap = devices[0]
78         
79         return self._tap
80
81     @property
82     def tapnode(self):
83         return self.tap.node
84
85     @property
86     def node(self):
87         return self.tapnode
88
89     def upload_sources(self):
90         scripts = []
91
92         # vif-passfd python script
93         linux_passfd = os.path.join(os.path.dirname(__file__),
94                 "..",
95                 "scripts",
96                 "linux-passfd.py")
97
98         scripts.append(linux_passfd)
99         
100         # Upload scripts
101         scripts = ";".join(scripts)
102
103         self.node.upload(scripts,
104                 os.path.join(self.node.src_dir),
105                 overwrite = False)
106
107     def upload_start_command(self):
108         if self.tapnode.get("hostname") != \
109                 self.fdnode.get("hostname"):
110             msg = "Tap and FdNetDevice are not in the same host"
111             self.error(msg)
112             raise RuntimeError, msg
113
114         self.send_address = self.fdnetdevice.recv_fd()
115         self.set("command", self._start_command)
116
117         command = self.get("command")
118
119         shfile = os.path.join(self.app_home, "start.sh")
120         self.node.run_and_wait(command, self.run_home,
121                 shfile=shfile,
122                 wait_run=False,
123                 overwrite=True)
124         
125     def do_deploy(self):
126         if self.tap.state < ResourceState.READY or \
127                 self.fdnetdevice.state < ResourceState.READY:
128             self.ec.schedule(self.reschedule_delay, self.deploy)
129         else:
130             self.do_discover()
131             self.do_provision()
132
133             self.set_ready()
134
135     def do_start(self):
136         if self.state == ResourceState.READY:
137             command = self.get("command")
138             self.info("Starting command '%s'" % command)
139
140             self.set_started()
141         else:
142             msg = " Failed to execute command '%s'" % command
143             self.error(msg, out, err)
144             raise RuntimeError, msg
145
146     @property
147     def _start_command(self):
148         vif_name = self.ec.get(self.tap.guid, "deviceName")
149         vif_type = self.tap.vif_type_flag
150         pi = self.ec.get(self.tap.guid, "pi")
151         address = base64.b64encode(self.send_address)
152
153         command = []
154         # Use pl-vif-passfd.py to send fd from TAP to FdNetDevice
155         command.append("PYTHONPATH=$PYTHONPATH:${SRC}")
156         command.append("python ${SRC}/linux-passfd.py")
157         command.append("-a %s" % address)
158         command.append("-N %s " % vif_name)
159         command.append("-t %s " % vif_type)
160         if pi:
161             command.append("-p")
162
163         command = " ".join(command)
164         command = self.replace_paths(command)
165
166         return command
167