1 #!/usr/bin/env python
\r
3 # NEPI, a framework to manage network experiments
\r
4 # Copyright (C) 2015 INRIA
\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
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
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
18 # Author: Damien Saucez <damien.saucez@inria.fr>
\r
19 # Alina Quereilhac <alina.quereilhac@inria.fr>
\r
22 from six import PY2, next
\r
27 from optparse import OptionParser
\r
29 from random import randint
\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
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
42 usage = ("usage: %prog -s <pl-slice> -u <pl-user> -p <pl-password> "
\r
43 "-k <pl-ssh-key> -n <node-count> ")
\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
59 (options, args) = parser.parse_args()
\r
61 return (options.pl_slice, options.pl_user, options.pl_password,
\r
62 options.pl_ssh_key, options.node_count)
\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
70 ec.set(host, "username", username)
\r
73 ec.set(host, "pluser", pl_user)
\r
76 ec.set(host, "plpassword", pl_password)
\r
79 ec.set(host, "identity", ssh_key)
\r
81 ec.set(host, "cleanProcesses", True)
\r
82 ec.set(host, "cleanExperiment", True)
\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
94 # == build topology =========================================================
\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
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
105 # specify the MAC layer parameters
\r
107 # can be in access point mode or not
\r
109 mac = ec.register_resource("ns3::ApWifiMac")
\r
111 mac = ec.register_resource("ns3::StaWifiMac")
\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
117 # specify the physical layer parameters
\r
118 phy = ec.register_resource("ns3::YansWifiPhy")
\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
124 # specify an error model for transmissions
\r
125 error = ec.register_resource("ns3::NistErrorRateModel")
\r
126 ec.register_connection(phy, error)
\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
134 def add_ns3_wifi_channel(ec):
\r
135 channel = ec.register_resource("ns3::YansWifiChannel")
\r
137 delay = ec.register_resource("ns3::ConstantSpeedPropagationDelayModel")
\r
138 ec.register_connection(channel, delay)
\r
140 loss = ec.register_resource("ns3::LogDistancePropagationLossModel")
\r
141 ec.register_connection(channel, loss)
\r
145 # == Add random mobility
\r
146 def add_ns3_random_mobility(ec, ns3_node):
\r
149 bounds_height = 100
\r
150 x = randint(0, bounds_width)
\r
151 y = randint(0, bounds_height)
\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
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
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
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
183 dev, phy = add_ns3_wifi_device(ec, ns3_node, ip, prefixlen, ap_mode)
\r
184 ec.register_connection(channel, phy)
\r
187 add_ns3_random_mobility(ec, ns3_node)
\r
189 add_ns3_constant_mobility(ec, ns3_node)
\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
203 ec.register_connection(agent, ns3_node)
\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
218 ec.register_connection(transmitter, ns3_node)
\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
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
237 net = ipaddr.IPv4Network("%s/%s" % (network, prefixlen))
\r
238 itr = net.iterhosts()
\r
240 net = ipaddress.IPv4Network("%s/%s" % (network, prefixlen))
\r
243 ap_ip = next(itr).exploded
\r
244 ap = add_ns3_node(ec, simu, ap_ip, prefixlen, channel, ap_mode=True)
\r
247 if ap_ip == agent_ip:
\r
248 agent = add_dce_agent(ec, ap)
\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
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
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
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
284 # == Add planet lab route ====================================================
\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