Linux/Ns-3/Dce cross experiments
[nepi.git] / src / nepi / resources / linux / ns3 / 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.attribute import Attribute, Flags, Types
21 from nepi.execution.resource import ResourceManager, ResourceState, \
22         clsinit_copy
23
24 import os
25 import socket
26 import struct
27 import fcntl
28
29 @clsinit_copy
30 class TapFdLink(ResourceManager):
31     """ Interconnects a TAP or TUN Linux device to a FdNetDevice
32     """
33     _rtype = "linux::ns3::TapFdLink"
34
35     def __init__(self, ec, guid):
36         super(TapFdLink, self).__init__(ec, guid)
37         self._tap = None
38         self._fdnetdevice = None
39         self._fd = None
40
41     @property
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"
48                 self.error(msg)
49                 raise RuntimeError, msg
50
51             self._fdnetdevice = devices[0]
52         
53         return self._fdnetdevice
54
55     @property
56     def fdnode(self):
57         return self.fdnetdevice.node
58
59     @property
60     def tap(self):
61         if not self._tap:
62             from nepi.resources.linux.tap import LinuxTap
63             devices = self.get_connected(LinuxTap.get_rtype())
64             if not devices or len(devices) != 1: 
65                 msg = "TapFdLink must be connected to exactly one LinuxTap"
66                 self.error(msg)
67                 raise RuntimeError, msg
68
69             self._tap = devices[0]
70         
71         return self._tap
72
73     @property
74     def tapnode(self):
75         return self.tap.node
76
77     def do_provision(self):
78         tap = self.tap
79         fdnetdevice = self.fdnetdevice
80
81         vif_name = self.ec.get(tap.guid, "deviceName")
82         vif_type = tap.vif_type_flag
83         pi = self.ec.get(tap.guid, "pi")
84
85         self._fd = self.open_tap(vif_name, vif_type, pi)
86
87         fdnetdevice.send_fd(self._fd)
88
89         super(TapFdLink, self).do_provision()
90
91     def do_deploy(self):
92         if self.tap.state < ResourceState.READY or \
93                 self.fdnetdevice.state < ResourceState.READY:
94             self.ec.schedule(self.reschedule_delay, self.deploy)
95         else:
96             self.do_discover()
97             self.do_provision()
98
99             super(TapFdLink, self).do_deploy()
100
101     def open_tap(self, vif_name, vif_type, pi):
102         IFF_NO_PI = 0x1000
103         TUNSETIFF = 0x400454ca
104
105         flags = 0
106         flags |= vif_type
107
108         if not pi:
109             flags |= IFF_NO_PI
110
111         fd = os.open("/dev/net/tun", os.O_RDWR)
112
113         err = fcntl.ioctl(fd, TUNSETIFF, struct.pack("16sH", vif_name, flags))
114         if err < 0:
115             os.close(fd)
116             raise RuntimeError("Could not configure device %s" % vif_name)
117
118         return fd
119