f4d6504cb898caa3934fcad341375a88daffd70c
[nepi.git] / examples / ns3 / multi_host / topology.py
1 #!/usr/bin/env python\r
2 #\r
3 #    NEPI, a framework to manage network experiments\r
4 #    Copyright (C) 2015 INRIA\r
5 #\r
6 #    This program is free software: you can redistribute it and/or modify\r
7 #    it under the terms of the GNU General Public License version 2 as\r
8 #    published by the Free Software Foundation;\r
9 #\r
10 #    This program is distributed in the hope that it will be useful,\r
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 #    GNU General Public License for more details.\r
14 #\r
15 #    You should have received a copy of the GNU General Public License\r
16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
17 #\r
18 # Author: Damien Saucez <damien.saucez@inria.fr>\r
19 #         Alina Quereilhac <alina.quereilhac@inria.fr>\r
20 #\r
21 \r
22 from six import PY2, next\r
23 if PY2:\r
24     import ipaddr\r
25 else:\r
26     import ipaddress\r
27 from optparse import OptionParser\r
28 import os\r
29 from random import randint\r
30 \r
31 # list of hosts for running the experiment on\r
32 hostname1 = "onelab4.warsaw.rd.tp.pl"\r
33 hostname2 = "planet2.servers.ua.pt"\r
34 \r
35 def get_options():\r
36     # PlanetLab credentials\r
37     pl_slice = os.environ.get("PL_SLICE")\r
38     pl_user = os.environ.get("PL_USER")\r
39     pl_password = os.environ.get("PL_PASS")\r
40     pl_ssh_key = os.environ.get("PL_SSHKEY")\r
41 \r
42     usage = ("usage: %prog -s <pl-slice> -u <pl-user> -p <pl-password> "\r
43                 "-k <pl-ssh-key> -n <node-count> ")\r
44 \r
45     parser = OptionParser(usage = usage)\r
46     parser.add_option("-s", "--pl-slice", dest="pl_slice",\r
47             help="PlanetLab slicename", default=pl_slice, type="str")\r
48     parser.add_option("-u", "--pl-user", dest="pl_user",\r
49             help="PlanetLab web username", default=pl_user, type="str")\r
50     parser.add_option("-p", "--pl-password", dest="pl_password",\r
51             help="PlanetLab web password", default=pl_password, type="str")\r
52     parser.add_option("-k", "--pl-ssh-key", dest="pl_ssh_key",\r
53             help="Path to private SSH key associated with the PL account",\r
54             default=pl_ssh_key, type="str")\r
55     parser.add_option("-n", "--node-count", dest="node_count",\r
56             help="Number of nodes in the wireless network",\r
57             default = 4, type="int")\r
58 \r
59     (options, args) = parser.parse_args()\r
60 \r
61     return (options.pl_slice, options.pl_user, options.pl_password, \r
62             options.pl_ssh_key, options.node_count)\r
63 \r
64 # == add host and simu =======================================================\r
65 def add_host_simu(ec, hostname, username, pl_user, pl_password, ssh_key):\r
66     host = ec.register_resource("planetlab::Node")\r
67     ec.set(host, "hostname", hostname)\r
68 \r
69     if username:\r
70         ec.set(host, "username", username)\r
71 \r
72     if pl_user:\r
73         ec.set(host, "pluser", pl_user)\r
74 \r
75     if pl_password:\r
76         ec.set(host, "plpassword", pl_password)\r
77 \r
78     if ssh_key:\r
79         ec.set(host, "identity", ssh_key)\r
80 \r
81     ec.set(host, "cleanProcesses", True)\r
82     ec.set(host, "cleanExperiment", True)\r
83 \r
84     simu = ec.register_resource("linux::ns3::Simulation")\r
85     ec.set(simu, "simulatorImplementationType", "ns3::RealtimeSimulatorImpl")\r
86     ec.set(simu, "checksumEnabled", True)\r
87     ec.set(simu, "verbose", True)\r
88     ec.set(simu, "enableDump", True)\r
89     ec.set (simu, "StopTime", "200s")\r
90     ec.register_connection(simu, host)\r
91 \r
92     return host, simu\r
93 \r
94 # == build topology  =========================================================\r
95 \r
96 def add_ns3_wifi_device(ec, ns3_node, ip, prefixlen, ap_mode):\r
97     # create the WiFi network interface\r
98     dev = ec.register_resource("ns3::WifiNetDevice")\r
99 \r
100     # specify the network layer parameters\r
101     ec.set(dev, "ip", ip)\r
102     ec.set(dev, "prefix", prefixlen)\r
103     ec.register_connection(ns3_node, dev)\r
104 \r
105     # specify the MAC layer parameters\r
106     #\r
107     # can be in access point mode or not\r
108     if ap_mode:\r
109         mac = ec.register_resource("ns3::ApWifiMac")\r
110     else:\r
111         mac = ec.register_resource("ns3::StaWifiMac")\r
112 \r
113     # the MAC is IEEE 802.11a\r
114     ec.set(mac, "Standard", "WIFI_PHY_STANDARD_80211a")\r
115     ec.register_connection(dev, mac)\r
116 \r
117     # specify the physical layer parameters\r
118     phy = ec.register_resource("ns3::YansWifiPhy")\r
119     #\r
120     # it physical layer is IEEE802.11a\r
121     ec.set(phy, "Standard", "WIFI_PHY_STANDARD_80211a")\r
122     ec.register_connection(dev, phy)\r
123     #\r
124     # specify an error model for transmissions\r
125     error = ec.register_resource("ns3::NistErrorRateModel")\r
126     ec.register_connection(phy, error)\r
127 \r
128     # specify the Wifi manager to be assocated with the interface\r
129     manager = ec.register_resource("ns3::ArfWifiManager")\r
130     ec.register_connection(dev, manager)\r
131 \r
132     return dev, phy\r
133 \r
134 def add_ns3_wifi_channel(ec):\r
135     channel = ec.register_resource("ns3::YansWifiChannel")\r
136 \r
137     delay = ec.register_resource("ns3::ConstantSpeedPropagationDelayModel")\r
138     ec.register_connection(channel, delay)\r
139 \r
140     loss  = ec.register_resource("ns3::LogDistancePropagationLossModel")\r
141     ec.register_connection(channel, loss)\r
142 \r
143     return channel\r
144 \r
145 # == Add random mobility\r
146 def add_ns3_random_mobility(ec, ns3_node):\r
147     speed =  1\r
148     bounds_width = 100\r
149     bounds_height = 100\r
150     x = randint(0, bounds_width)\r
151     y = randint(0, bounds_height)\r
152     z = 0\r
153 \r
154     position = "%d:%d:%d" % (x, y, z)\r
155     bounds = "0|%d|0|%d" % (bounds_width, bounds_height)\r
156     speed = "ns3::UniformRandomVariable[Min=%d|Max=%s]" % (speed, speed)\r
157     pause = "ns3::ConstantRandomVariable[Constant=1.0]"\r
158 \r
159     mobility = ec.register_resource("ns3::RandomDirection2dMobilityModel")\r
160     ec.set(mobility, "Position", position)\r
161     ec.set(mobility, "Bounds", bounds)\r
162     ec.set(mobility, "Speed", speed)\r
163     ec.set(mobility, "Pause",  pause)\r
164     ec.register_connection(ns3_node, mobility)\r
165 \r
166     return mobility\r
167 \r
168 # == Add constant mobility\r
169 def add_ns3_constant_mobility(ec, ns3_node):\r
170     mobility = ec.register_resource("ns3::ConstantPositionMobilityModel")\r
171     position = "%d:%d:%d" % (0, 50, 0)\r
172     ec.set(mobility, "Position", position)\r
173     ec.register_connection(ns3_node, mobility)\r
174 \r
175     return mobility\r
176 \r
177 # == add ns-3 node\r
178 def add_ns3_node(ec, simu, ip, prefixlen, channel, ap_mode=False):\r
179     ns3_node = ec.register_resource("ns3::Node")\r
180     ec.set(ns3_node, "enableStack", True)\r
181     ec.register_connection(ns3_node, simu)\r
182 \r
183     dev, phy = add_ns3_wifi_device(ec, ns3_node, ip, prefixlen, ap_mode)\r
184     ec.register_connection(channel, phy)\r
185 \r
186     if not ap_mode:\r
187         add_ns3_random_mobility(ec, ns3_node)\r
188     else:\r
189         add_ns3_constant_mobility(ec, ns3_node)\r
190 \r
191     return ns3_node\r
192 \r
193 # == add DCE agent\r
194 def add_dce_agent(ec, ns3_node):\r
195     agent = ec.register_resource("linux::ns3::dce::Application")\r
196     ec.set(agent, "sources", "code/agent.c")\r
197     ec.set(agent, "build", "gcc -fPIC -pie -rdynamic ${SRC}/agent.c -o ${BIN_DCE}/agent")\r
198     ec.set(agent, "binary", "agent")\r
199     ec.set(agent, "stackSize", 1<<20)\r
200     ec.set(agent, "StartTime", "10s")\r
201     ec.set(agent, "StopTime", "200s")\r
202 \r
203     ec.register_connection(agent, ns3_node)\r
204 \r
205     return agent\r
206 \r
207 # == add DCE transmitter\r
208 def add_dce_transmitter(ec, ns3_node, target):\r
209     transmitter = ec.register_resource("linux::ns3::dce::Application")\r
210     ec.set(transmitter, "sources", "code/transmitter.c")\r
211     ec.set(transmitter, "build", "gcc -fPIC -pie -rdynamic ${SRC}/transmitter.c -o ${BIN_DCE}/transmitter")\r
212     ec.set(transmitter, "binary", "transmitter")\r
213     ec.set(transmitter, "arguments", target)\r
214     ec.set(transmitter, "stackSize", 1<<20)\r
215     ec.set(transmitter, "StartTime", "10s")\r
216     ec.set(transmitter, "StopTime", "200s")\r
217     \r
218     ec.register_connection(transmitter, ns3_node)\r
219 \r
220     return transmitter\r
221 \r
222 # == Add ns-3 route\r
223 def add_ns3_route(ec, ns3_node, network, prefixlen, nexthop):\r
224     route = ec.register_resource("ns3::Route")\r
225     ec.set(route, "network", network)\r
226     ec.set(route, "prefix", prefixlen)\r
227     ec.set(route, "nexthop", nexthop)\r
228     ec.register_connection(route, ns3_node)\r
229 \r
230     return route\r
231 \r
232 # = build ns3 topology =======================================================\r
233 def build_ns3_topology(ec, simu, node_count, network, prefixlen, agent_ip):\r
234     channel = add_ns3_wifi_channel(ec)\r
235 \r
236     if PY2:\r
237         net = ipaddr.IPv4Network("%s/%s" % (network, prefixlen)) \r
238         itr = net.iterhosts()\r
239     else:\r
240         net = ipaddress.IPv4Network("%s/%s" % (network, prefixlen)) \r
241         itr = net.hosts()\r
242 \r
243     ap_ip = next(itr).exploded\r
244     ap = add_ns3_node(ec, simu, ap_ip, prefixlen, channel, ap_mode=True)\r
245 \r
246     agent = None\r
247     if ap_ip == agent_ip:\r
248         agent = add_dce_agent(ec, ap)\r
249 \r
250     for i in range(0, node_count):\r
251         ip = itr.next().exploded\r
252         sensor = add_ns3_node(ec, simu, ip, prefixlen, channel, ap_mode=False)\r
253         transmitter = add_dce_transmitter(ec, sensor, ap_ip)\r
254         add_ns3_route(ec, sensor, network="0.0.0.0", prefixlen="0", nexthop=ap_ip)\r
255 \r
256     return ap, agent\r
257 \r
258 \r
259 # == add FdNetDevice =========================================================\r
260 def add_fdnet_device(ec, ap, ip, prefixlen):\r
261     fddev = ec.register_resource("ns3::FdNetDevice")\r
262     ec.set(fddev, "ip", ip)\r
263     ec.set(fddev, "prefix", prefixlen)\r
264     ec.register_connection(ap, fddev)\r
265 \r
266     return fddev\r
267 \r
268 # == connect with UDP tunnel =================================================\r
269 def connect_with_udp_tunnel(ec, fddev1, fddev2):                                                             \r
270     tunnel = ec.register_resource("planetlab::ns3::FdUdpTunnel")\r
271     ec.register_connection(tunnel, fddev1)\r
272     ec.register_connection(tunnel, fddev2)\r
273 \r
274     return tunnel\r
275 \r
276 # == connect with virtual link ===============================================\r
277 def connect_with_virtual_link(ec, tap, fddev):                                                                   \r
278     link = ec.register_resource("planetlab::ns3::TunTapFdLink")                          \r
279     ec.register_connection(link, tap)\r
280     ec.register_connection(link, fddev)\r
281 \r
282     return link\r
283 \r
284 # == Add planet lab route ====================================================\r
285 \r
286 def add_planetlab_route(ec, dev, network, prefixlen, nexthop):\r
287     route = ec.register_resource("planetlab::Vroute")\r
288     ec.set(route, "network", network)\r
289     ec.set(route, "prefix", prefixlen)\r
290     ec.set(route, "nexthop", nexthop)\r
291     ec.register_connection(route, dev)\r
292 \r
293     return route\r
294 \r