Merge with head
[nepi.git] / examples / wireless_overlay.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from nepi.core.design import ExperimentDescription, FactoriesProvider
5 from nepi.core.execute import ExperimentController
6 from optparse import OptionParser, SUPPRESS_HELP
7 from nepi.util import proxy
8 from nepi.util.constants import DeploymentConfiguration as DC
9 import os
10 import shutil
11 import tempfile
12 import time
13 import math
14
15 """
16   -----------------------------------------------------------------------
17   |    NETNS                                                            |                                    
18   |                                                                     |
19   |    +-----+     +-----+    +-----+    +-----+          +------+      |
20   |    |node1|     |node2|    |node3|    |node4 |         |server|      |
21   |    +-----+     +-----+    +-----+    +-----+          +------+      |
22   |     65/30       69/30      33/30      37/30            226/30       |
23   |    -------     -------    -------    -------          --------      |
24   |       |           |          |          |                |          |
25   |---------------------------------------------------------------------|
26   |       |           |          |          |                |          | 
27   |    -------     -------    -------    -------             |          |
28   |     66/30       30/30     34/30       38/30              |          |
29   |    +-----+     +-----+    +-----+    +-----+             |          |
30   |    |sta0 |     |sta1 |    |sta2 |    |sta3 |             |          |
31   |    +-----+     +-----+    +-----+    +-----+             |          |
32   |     34/27       35/27      36/27      37/27              |          |
33   |    -------     --------    -------   -------             |          |
34   |     ((*))       ((*))       ((*))     ((*))              |          |
35   |                                                          |          |
36   |                                                          |          |
37   |                       ((*))                              |          |
38   |                     --------                             |          |
39   |                       33/27                              |          |
40   |                     +------+                             |          |
41   |                     |  AP  |  225/30 |--------------------          |
42   |                     +------+                                        |
43   |                                                                     |
44   |     NS-3                                                            |
45   -----------------------------------------------------------------------
46
47 """
48
49 class WirelessOverlay(object):
50     def __init__(self):
51         usage = "usage: %prog -n number_sta -m movie -u user"
52         parser = OptionParser(usage=usage)
53         parser.add_option("-u", "--user", dest="user", help="Valid linux system user (not root).", type="str")
54         parser.add_option("-m", "--movie", dest="movie", help="Path to movie file to play", type="str")
55         parser.add_option("-n", "--nsta", dest="nsta", help="Number of wifi stations", type="int")
56         parser.add_option("-a", "--base_addr", dest="base_addr", help="Base address segment for the experiment", type="str")
57         (options, args) = parser.parse_args()
58         #if not options.movie:
59         #    parser.error("Missing 'movie' option.")
60         if options.user == 'root':
61             parser.error("Missing or invalid 'user' option.")
62         if options.user == 'root':
63             parser.error("Missing or invalid 'user' option.")
64         if options.nsta and options.nsta > 8:
65             parser.error("Try a number of stations under 9.")
66
67         self.user = options.user if options.user else os.getlogin()
68         #self.movie = options.movie
69         self.nsta = options.nsta if options.nsta else 2
70         base = options.base_addr if options.base_addr else "192.168.4"
71         self.base_addr = base + ".%d"
72         self.root_dir = tempfile.mkdtemp()
73
74     def add_netns_tap(self, netns_desc, node):
75         tap = netns_desc.create("TapNodeInterface")
76         tap.set_attribute_value("up", True)
77         node.connector("devs").connect(tap.connector("node"))
78         return tap
79
80     def add_ns3_fdnd(self, ns3_desc, node):
81         fdnd = ns3_desc.create("ns3::FdNetDevice")
82         node.connector("devs").connect(fdnd.connector("node"))
83         fdnd.enable_trace("FdPcapTrace")
84         return fdnd
85
86     def add_ns3_node(self, ns3_desc):
87         node = ns3_desc.create("ns3::Node")
88         ipv4 = ns3_desc.create("ns3::Ipv4L3Protocol")
89         arp  = ns3_desc.create("ns3::ArpL3Protocol")
90         icmp = ns3_desc.create("ns3::Icmpv4L4Protocol")
91         udp = ns3_desc.create("ns3::UdpL4Protocol")
92         node.connector("protos").connect(ipv4.connector("node"))
93         node.connector("protos").connect(arp.connector("node"))
94         node.connector("protos").connect(icmp.connector("node"))
95         node.connector("protos").connect(udp.connector("node"))
96         return node
97
98     def add_ns3_wifi(self, ns3_desc, node, access_point = False):
99         wifi = ns3_desc.create("ns3::WifiNetDevice")
100         node.connector("devs").connect(wifi.connector("node"))
101
102         phy = ns3_desc.create("ns3::YansWifiPhy")
103         error = ns3_desc.create("ns3::NistErrorRateModel")
104         manager = ns3_desc.create("ns3::ArfWifiManager")
105         if access_point:
106             mac = ns3_desc.create("ns3::ApWifiMac")
107         else:
108             mac = ns3_desc.create("ns3::StaWifiMac")
109
110         phy.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a")
111         mac.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a")
112         phy.connector("err").connect(error.connector("phy"))
113         wifi.connector("phy").connect(phy.connector("dev"))
114         wifi.connector("mac").connect(mac.connector("dev"))
115         wifi.connector("manager").connect(manager.connector("dev"))
116
117         phy.enable_trace("YansWifiPhyPcapTrace")
118         return wifi, phy
119
120     def add_ns3_constant_mobility(self, ns3_desc, node, x, y, z):
121         mobility = ns3_desc.create("ns3::ConstantPositionMobilityModel") 
122         position = "%d:%d:%d" % (x, y, z)
123         mobility.set_attribute_value("Position", position)
124         node.connector("mobility").connect(mobility.connector("node"))
125         return mobility
126
127     def add_ns3_wifi_channel(self, ns3_desc):
128         channel = ns3_desc.create("ns3::YansWifiChannel")
129         delay = ns3_desc.create("ns3::ConstantSpeedPropagationDelayModel")
130         loss  = ns3_desc.create("ns3::LogDistancePropagationLossModel")
131         channel.connector("delay").connect(delay.connector("chan"))
132         channel.connector("loss").connect(loss.connector("prev"))
133         return channel
134
135     def add_ip_address(self, iface, address, netprefix):
136         ip = iface.add_address()
137         ip.set_attribute_value("Address", address)
138         ip.set_attribute_value("NetPrefix", netprefix)
139
140     def add_route(self, node, destination, netprefix, nexthop):
141         route = node.add_route()
142         route.set_attribute_value("Destination", destination)
143         route.set_attribute_value("NetPrefix", netprefix)
144         route.set_attribute_value("NextHop", nexthop)
145
146     def run(self):
147         exp_desc = ExperimentDescription()
148
149         ## NS3 ##
150
151         ns3_provider = FactoriesProvider("ns3")
152         ns3_desc = exp_desc.add_testbed_description(ns3_provider)
153         ns3_desc.set_attribute_value("homeDirectory", self.root_dir)
154         ns3_desc.set_attribute_value("SimulatorImplementationType", "ns3::RealtimeSimulatorImpl")
155         ns3_desc.set_attribute_value("ChecksumEnabled", True)
156         
157         ## NS3 wifi network 32/27
158         r = 50
159         wifi_chan = self.add_ns3_wifi_channel(ns3_desc)
160         
161         # AP node
162         ap = self.add_ns3_node(ns3_desc)
163         self.add_ns3_constant_mobility(ns3_desc, ap, r, r, 0)
164
165         wifi_ap, phy_ap = self.add_ns3_wifi(ns3_desc, ap, access_point = True)
166         self.add_ip_address(wifi_ap, (self.base_addr%33), 27)
167         phy_ap.connector("chan").connect(wifi_chan.connector("phys"))
168         
169         sta_nodes = []
170         
171         # STA nodes
172         for i in xrange(0, self.nsta):
173             stai = self.add_ns3_node(ns3_desc)
174             angi = (360/self.nsta)*i
175             xi = r*math.cos(angi)
176             yi = r*math.sin(angi)
177             self.add_ns3_constant_mobility(ns3_desc, stai, xi, yi, 0)
178             wifi, phy= self.add_ns3_wifi(ns3_desc, stai, access_point = False)
179             wifi_addr = self.base_addr%(34 + i)
180             self.add_ip_address(wifi, wifi_addr, 27)
181             phy.connector("chan").connect(wifi_chan.connector("phys"))
182             sta_nodes.append((stai, wifi_addr))
183
184         ## NETNS ##
185
186         netns_provider = FactoriesProvider("netns")
187         netns_desc = exp_desc.add_testbed_description(netns_provider)
188         netns_desc.set_attribute_value("homeDirectory", self.root_dir)
189         netns_desc.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
190         netns_root_dir = os.path.join(self.root_dir, "netns_instance")
191         os.mkdir(netns_root_dir)
192         netns_desc.set_attribute_value(DC.ROOT_DIRECTORY, netns_root_dir)
193         netns_desc.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
194         netns_desc.set_attribute_value(DC.USE_SUDO, True)
195
196         server = netns_desc.create("Node")
197         server.set_attribute_value("forward_X11", True)
198
199         command = "xterm" 
200         app = netns_desc.create("Application")
201         app.set_attribute_value("command", command)
202         app.set_attribute_value("user", self.user)
203         app.connector("node").connect(server.connector("apps"))
204
205         # INTERCONNECTION NETNS/NS3
206
207         tap = self.add_netns_tap(netns_desc, server)
208         fdnd_ap = self.add_ns3_fdnd(ns3_desc, ap)
209         fdnd_ap.connector("->fd").connect(tap.connector("fd->"))
210         ## net NS3::fdnd/NETNS::tap 224/30
211         self.add_ip_address(fdnd_ap, (self.base_addr%225), 30)
212         self.add_ip_address(tap, (self.base_addr%226), 30)
213
214         # ROUTES
215         self.add_route(server, (self.base_addr%32), 27, (self.base_addr%225))
216
217         i = 0
218         for (stai, wifi_addr) in sta_nodes:
219             # fdnd - netns tap
220             nodei = netns_desc.create("Node")
221             nodei.set_attribute_value("forward_X11", True)
222             tapi = self.add_netns_tap(netns_desc, nodei)
223             fdndi = self.add_ns3_fdnd(ns3_desc, stai)
224             fdndi.connector("->fd").connect(tapi.connector("fd->"))
225             
226             ## net NS3::fdnd/NETNS::tap subnets of 64/27
227             net = 64 + i
228             self.add_ip_address(tapi, (self.base_addr%(net + 1)), 30)
229             self.add_ip_address(fdndi, (self.base_addr%(net + 2)), 30)
230             
231             print i, " ", stai, " ", net
232             # routes
233             self.add_route(nodei, (self.base_addr%32), 27, (self.base_addr%(net+2)))
234             self.add_route(nodei, (self.base_addr%224), 30, (self.base_addr%(net+2)))
235             self.add_route(stai, (self.base_addr%224), 30, (self.base_addr%33))
236             
237             self.add_route(ap, (self.base_addr%net), 30, wifi_addr)
238             self.add_route(server, (self.base_addr%net), 30, (self.base_addr%225))
239             i += 4
240
241
242         xml = exp_desc.to_xml()
243         controller = ExperimentController(xml, self.root_dir)
244         controller.start()
245         while not controller.is_finished(app.guid):
246             time.sleep(0.5)
247         time.sleep(0.1)
248         controller.stop()
249         controller.shutdown()
250
251     def clean(self):
252         shutil.rmtree(self.root_dir)
253
254 if __name__ == '__main__':
255     example = WirelessOverlay()
256     example.run()
257     example.clean()
258