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