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