1c261d1fa84c9d0626d49b9bda92c716c1d98483
[nepi.git] / examples / roads09.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, ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP
9 import os
10 import shutil
11 import tempfile
12 import time
13 import sys
14 import random
15
16 def pl_auth():
17     user = os.environ.get('PL_USER')
18     pwd = os.environ.get('PL_PASS')
19      
20     if user and pwd:
21         return (user,pwd)
22     else:
23         return None
24
25 class Roads09Ns3PLExample(object):
26     testbed_id = "planetlab"
27     testbed_version = "01"
28     slicename = "inria_nepi"
29     plchost = "nepiplc.pl.sophia.inria.fr"
30     
31     host1 = "nepi1.pl.sophia.inria.fr"
32     host2 = "nepi2.pl.sophia.inria.fr"
33     host3 = "nepi3.pl.sophia.inria.fr"
34     host4 = "nepi5.pl.sophia.inria.fr"
35     
36     def __init__(self):
37         #usage = "usage: %prog -m movie -u user"
38         #parser = OptionParser(usage=usage)
39         #parser.add_option("-u", "--user", dest="user", help="Valid linux system user (not root).", type="str")
40         #parser.add_option("-m", "--movie", dest="movie", help="Path to movie file to play", type="str")
41         #(options, args) = parser.parse_args()
42         #if not options.movie:
43         #    parser.error("Missing 'movie' option.")
44         #if options.user == 'root':
45         #    parser.error("Missing or invalid 'user' option.")
46
47         #self.user = options.user if options.user else os.getlogin()
48         #self.movie =  options.movie
49         
50         if not pl_auth():
51             print "Example requires PlanetLab authentication info (PL_USER and PL_PASS environment variables)"
52             sys.exit(1)
53         
54         self.root_dir = tempfile.mkdtemp()
55
56
57     def make_experiment_desc(self):
58         testbed_id = self.testbed_id
59         testbed_version = self.testbed_version
60         slicename = self.slicename
61         plchost = self.plchost
62         pl_ssh_key = os.environ.get(
63             "PL_SSH_KEY",
64             "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
65         pl_user, pl_pwd = pl_auth()
66
67         exp_desc = ExperimentDescription()
68         pl_provider = FactoriesProvider(testbed_id, testbed_version)
69         pl_desc = exp_desc.add_testbed_description(pl_provider)
70         pl_desc.set_attribute_value("homeDirectory", self.root_dir)
71         pl_desc.set_attribute_value("slice", slicename)
72         pl_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
73         pl_desc.set_attribute_value("authUser", pl_user)
74         pl_desc.set_attribute_value("authPass", pl_pwd)
75         pl_desc.set_attribute_value("plcHost", plchost)
76         
77         return pl_desc, exp_desc
78
79     def make_ns_in_pl(self, pl, exp, node1, iface1, root):
80         ns3_testbed_id = "ns3"
81         ns3_testbed_version = "3_9_RC3"
82         
83         # Add NS3 support in node1
84         plnepi = pl.create("NepiDependency")
85         plns3 = pl.create("NS3Dependency")
86         plnepi.connector("node").connect(node1.connector("deps"))
87         plns3.connector("node").connect(node1.connector("deps"))
88
89         # Create NS3 testbed running in node1
90         ns3_provider = FactoriesProvider(ns3_testbed_id, ns3_testbed_version)
91         ns3_desc = exp.add_testbed_description(ns3_provider)
92         ns3_desc.set_attribute_value("rootDirectory", root)
93         ns3_desc.set_attribute_value("SimulatorImplementationType", "ns3::RealtimeSimulatorImpl")
94         ns3_desc.set_attribute_value("ChecksumEnabled", True)
95         ns3_desc.set_attribute_value(DC.DEPLOYMENT_HOST, "{#[%s].addr[0].[Address]#}" % (
96             iface1.get_attribute_value("label"),))
97         ns3_desc.set_attribute_value(DC.DEPLOYMENT_USER, 
98             pl.get_attribute_value("slice"))
99         ns3_desc.set_attribute_value(DC.DEPLOYMENT_KEY, 
100             pl.get_attribute_value("sliceSSHKey"))
101         ns3_desc.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
102         ns3_desc.set_attribute_value(DC.DEPLOYMENT_COMMUNICATION, DC.ACCESS_SSH)
103         ns3_desc.set_attribute_value(DC.DEPLOYMENT_ENVIRONMENT_SETUP,
104             "{#[%s].[%s]#}" % (
105                 node1.get_attribute_value("label"),
106                 ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,))
107         ns3_desc.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
108         
109         return ns3_desc
110     
111     
112
113     def add_ns3_fdnd(self, node, ns3_desc):
114         fdnd = ns3_desc.create("ns3::FileDescriptorNetDevice")
115         node.connector("devs").connect(fdnd.connector("node"))
116         fdnd.enable_trace("FileDescriptorPcapTrace")
117         return fdnd
118
119     def add_ns3_node(self, ns3_desc):
120         node = ns3_desc.create("ns3::Node")
121         ipv4 = ns3_desc.create("ns3::Ipv4L3Protocol")
122         arp  = ns3_desc.create("ns3::ArpL3Protocol")
123         icmp = ns3_desc.create("ns3::Icmpv4L4Protocol")
124         udp = ns3_desc.create("ns3::UdpL4Protocol")
125         node.connector("protos").connect(ipv4.connector("node"))
126         node.connector("protos").connect(arp.connector("node"))
127         node.connector("protos").connect(icmp.connector("node"))
128         node.connector("protos").connect(udp.connector("node"))
129         return node
130
131     def add_ns3_wifi(self, node, ns3_desc, access_point = False, ip = None, prefix = 24):
132         wifi = ns3_desc.create("ns3::WifiNetDevice")
133         node.connector("devs").connect(wifi.connector("node"))
134
135         phy = ns3_desc.create("ns3::YansWifiPhy")
136         error = ns3_desc.create("ns3::NistErrorRateModel")
137         manager = ns3_desc.create("ns3::ArfWifiManager")
138         if access_point:
139             mac = ns3_desc.create("ns3::QapWifiMac")
140         else:
141             mac = ns3_desc.create("ns3::QstaWifiMac")
142
143         phy.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a")
144         mac.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a")
145         phy.connector("err").connect(error.connector("phy"))
146         wifi.connector("phy").connect(phy.connector("dev"))
147         wifi.connector("mac").connect(mac.connector("dev"))
148         wifi.connector("manager").connect(manager.connector("dev"))
149         
150         if ip:
151             self.add_ip_address(wifi, ip, prefix)
152
153         phy.enable_trace("YansWifiPhyPcapTrace")
154         return wifi, phy
155
156     def add_ns3_random_mobility(self, node, ns3_desc, x, y, z, speed, 
157             bounds_width, bounds_height):
158         position = "%f:%f:%f" % (x, y, z)
159         bounds = "0|%f|0|%f" % (bounds_width, bounds_height) 
160         speed = "Constant:%f" % speed
161         mobility = ns3_desc.create("ns3::RandomDirection2dMobilityModel")
162         mobility.set_attribute_value("Position", position)
163         mobility.set_attribute_value("Bounds", bounds)
164         mobility.set_attribute_value("Speed", speed)
165         mobility.set_attribute_value("Pause",  "Constant:1")
166         node.connector("mobility").connect(mobility.connector("node"))
167         return mobility
168
169     def add_ns3_constant_mobility(self, node, ns3_desc, x, y, z):
170         mobility = ns3_desc.create("ns3::ConstantPositionMobilityModel") 
171         position = "%f:%f:%f" % (x, y, z)
172         mobility.set_attribute_value("Position", position)
173         node.connector("mobility").connect(mobility.connector("node"))
174         return mobility
175
176     def add_ns3_wifi_channel(self, ns3_desc):
177         channel = ns3_desc.create("ns3::YansWifiChannel")
178         delay = ns3_desc.create("ns3::ConstantSpeedPropagationDelayModel")
179         loss  = ns3_desc.create("ns3::LogDistancePropagationLossModel")
180         channel.connector("delay").connect(delay.connector("chan"))
181         channel.connector("loss").connect(loss.connector("prev"))
182         return channel
183
184     def add_ip_address(self, iface, address, prefix = 24):
185         ip = iface.add_address()
186         ip.set_attribute_value("Address", address)
187         ip.set_attribute_value("Broadcast", True)
188         ip.set_attribute_value("NetPrefix", prefix)
189         return ip
190
191     def add_route(self, nodes, destination, netprefix, nexthop):
192         for node in nodes:
193             route = node.add_route()
194             route.set_attribute_value("Destination", destination)
195             route.set_attribute_value("NetPrefix", netprefix)
196             route.set_attribute_value("NextHop", nexthop)
197
198     def make_pl_router(self, pl, hostname, label, ip, inet = None):
199         pl1 = pl.create("Node")
200         pl1.set_attribute_value("hostname", hostname)
201         pl1.set_attribute_value("label", label)
202         pl1.set_attribute_value("emulation", True)
203         pl1if = pl.create("NodeInterface")
204         pl1if.set_attribute_value("label", label+"if")
205         pl1tap = pl.create("TapInterface")
206         pl1tap.enable_trace("packets") # for error output
207         pl1tap.set_attribute_value("label", label+"tap")
208         pl1tap.set_attribute_value("snat", False)
209         inet = inet or pl.create("Internet")
210         pl1.connector("devs").connect(pl1if.connector("node"))
211         pl1.connector("devs").connect(pl1tap.connector("node"))
212         pl1if.connector("inet").connect(inet.connector("devs"))
213         
214         pl1tapip = pl1tap.add_address()
215         pl1tapip.set_attribute_value("Address", ip)
216         pl1tapip.set_attribute_value("NetPrefix", 24)
217         pl1tapip.set_attribute_value("Broadcast", False)
218         
219         return pl1, pl1if, pl1tap, pl1tapip, inet
220     
221     def make_mesh(self, pl, exp, inet):
222         scale = 1.0
223         walkdistance = 1.0
224         walkspeed = 0.1
225     
226         # Router 1 & NS3 host in PL
227         pl1, pl1if, pl1tap, pl1tapip, inet = self.make_pl_router(pl, 
228             self.host1, "mesh_pl1", "192.168.2.2", inet)
229
230         # Add NS3 support in pl1
231         ns3 = self.make_ns_in_pl(pl, exp, pl1, pl1if, "tb-ns3-roads09-1")
232         
233         # Add WiFi channel
234         chan = self.add_ns3_wifi_channel(ns3)
235         
236         # Add APs
237         ap1 = self.add_ns3_node(ns3)
238         ap2 = self.add_ns3_node(ns3)
239         ap3 = self.add_ns3_node(ns3)
240         ap4 = self.add_ns3_node(ns3)
241         ap1wifi, ap1phy = self.add_ns3_wifi(ap1, ns3, False, "192.168.2.3", 26)
242         ap2wifi, ap2phy = self.add_ns3_wifi(ap2, ns3, True, "192.168.2.4", 26)
243         ap3wifi, ap3phy = self.add_ns3_wifi(ap3, ns3, False, "192.168.2.5", 26)
244         ap4wifi, ap4phy = self.add_ns3_wifi(ap4, ns3, False, "192.168.2.6", 26)
245         self.add_ns3_constant_mobility(ap1, ns3, -scale, -scale, 0.0)
246         self.add_ns3_constant_mobility(ap2, ns3, +scale, -scale, 0.0)
247         self.add_ns3_constant_mobility(ap3, ns3, -scale, +scale, 0.0)
248         self.add_ns3_constant_mobility(ap4, ns3, +scale, +scale, 0.0)
249         
250         # Add WiFi nodes
251         wnode1 = self.add_ns3_node(ns3)        
252         wnode2 = self.add_ns3_node(ns3)        
253         wnode3 = self.add_ns3_node(ns3)        
254         wnode4 = self.add_ns3_node(ns3)        
255         wnode5 = self.add_ns3_node(ns3)        
256         wnode1wifi, wnode1phy = self.add_ns3_wifi(wnode1, ns3, False, "192.168.2.7", 26)
257         wnode2wifi, wnode2phy = self.add_ns3_wifi(wnode2, ns3, False, "192.168.2.8", 26)
258         wnode3wifi, wnode3phy = self.add_ns3_wifi(wnode3, ns3, False, "192.168.2.9", 26)
259         wnode4wifi, wnode4phy = self.add_ns3_wifi(wnode4, ns3, False, "192.168.2.10", 26)
260         wnode5wifi, wnode5phy = self.add_ns3_wifi(wnode5, ns3, False, "192.168.2.11", 26)
261         self.add_ns3_random_mobility(wnode1, ns3, -2*scale, -2*scale, 0.0, 
262             walkspeed, walkdistance, walkdistance)
263         self.add_ns3_random_mobility(wnode2, ns3, -2*scale, +scale, 0.0, 
264             walkspeed, walkdistance, walkdistance)
265         self.add_ns3_random_mobility(wnode3, ns3, -scale, +2*scale, 0.0, 
266             walkspeed, walkdistance, walkdistance)
267         self.add_ns3_random_mobility(wnode4, ns3, +scale, +2*scale, 0.0, 
268             walkspeed, walkdistance, walkdistance)
269         self.add_ns3_random_mobility(wnode5, ns3, +2*scale, +2*scale, 0.0, 
270             walkspeed, walkdistance, walkdistance)
271         
272         # Connect all WiFi phys to the channel
273         ap1phy.connector("chan").connect(chan.connector("phys"))
274         ap2phy.connector("chan").connect(chan.connector("phys"))
275         ap3phy.connector("chan").connect(chan.connector("phys"))
276         ap4phy.connector("chan").connect(chan.connector("phys"))
277         wnode1phy.connector("chan").connect(chan.connector("phys"))
278         wnode2phy.connector("chan").connect(chan.connector("phys"))
279         wnode3phy.connector("chan").connect(chan.connector("phys"))
280         wnode4phy.connector("chan").connect(chan.connector("phys"))
281         wnode5phy.connector("chan").connect(chan.connector("phys"))
282         
283         # Add inet connection to AP
284         ap2fdnd = self.add_ns3_fdnd(ap2, ns3)
285         ap2fdndip = self.add_ip_address(ap2fdnd, "192.168.2.20")
286         ap2fdndip.set_attribute_value("NetPrefix", 32) # p2p
287         pl1tap.connector("fd->").connect(ap2fdnd.connector("->fd"))
288         pl1tap.set_attribute_value("pointopoint", "192.168.2.20")
289         r = ap2.add_route()
290         r.set_attribute_value("Destination", "192.168.2.2")
291         r.set_attribute_value("NetPrefix", 32)
292         r.set_attribute_value("NextHop", "192.168.2.20")
293         
294         # return mesh router
295         return (
296             pl1, pl1if, pl1tap, pl1tapip, 
297             (wnode1, wnode2, wnode3, wnode4, wnode5),
298             (wnode1wifi, wnode2wifi, wnode3wifi, wnode4wifi, wnode5wifi),
299             (ap1, ap2, ap3, ap4),
300             (ap1wifi, ap2wifi, ap3wifi, ap4wifi),
301             ns3,
302             inet,
303         )
304     
305     def make_wifi_hotspot(self, pl, exp, inet):
306         scale = 1.0
307         walkdistance = 1.0
308         walkspeed = 0.1
309     
310         # Router 1 & NS3 host in PL
311         pl1, pl1if, pl1tap, pl1tapip, inet = self.make_pl_router(pl, 
312             self.host2, "hs_pl1", "192.168.2.65", inet)
313
314         # Add NS3 support in pl1
315         ns3 = self.make_ns_in_pl(pl, exp, pl1, pl1if, "tb-ns3-roads09-2")
316         
317         # Add WiFi channel
318         chan = self.add_ns3_wifi_channel(ns3)
319         
320         # Add APs
321         ap1 = self.add_ns3_node(ns3)
322         ap1wifi, ap1phy = self.add_ns3_wifi(ap1, ns3, True, "192.168.2.66", 26)
323         self.add_ns3_constant_mobility(ap1, ns3, 0.0, 0.0, 0.0)
324         
325         # Add WiFi nodes
326         wnode1 = self.add_ns3_node(ns3)
327         wnode2 = self.add_ns3_node(ns3)
328         wnode3 = self.add_ns3_node(ns3)
329         wnode4 = self.add_ns3_node(ns3)
330         wnode1wifi, wnode1phy = self.add_ns3_wifi(wnode1, ns3, False, "192.168.2.67", 26)
331         wnode2wifi, wnode2phy = self.add_ns3_wifi(wnode2, ns3, False, "192.168.2.68", 26)
332         wnode3wifi, wnode3phy = self.add_ns3_wifi(wnode3, ns3, False, "192.168.2.69", 26)
333         wnode4wifi, wnode4phy = self.add_ns3_wifi(wnode4, ns3, False, "192.168.2.70", 26)
334         self.add_ns3_random_mobility(wnode1, ns3, +scale, -2*scale, 0.0, 
335             walkspeed, walkdistance, walkdistance)
336         self.add_ns3_random_mobility(wnode2, ns3, -scale, -2*scale, 0.0, 
337             walkspeed, walkdistance, walkdistance)
338         self.add_ns3_random_mobility(wnode3, ns3, -2*scale, +scale, 0.0, 
339             walkspeed, walkdistance, walkdistance)
340         self.add_ns3_random_mobility(wnode4, ns3, -2*scale, +2*scale, 0.0, 
341             walkspeed, walkdistance, walkdistance)
342         
343         # Connect all WiFi phys to the channel
344         ap1phy.connector("chan").connect(chan.connector("phys"))
345         wnode1phy.connector("chan").connect(chan.connector("phys"))
346         wnode2phy.connector("chan").connect(chan.connector("phys"))
347         wnode3phy.connector("chan").connect(chan.connector("phys"))
348         wnode4phy.connector("chan").connect(chan.connector("phys"))
349         
350         # Add inet connection to AP2
351         ap1fdnd = self.add_ns3_fdnd(ap1, ns3)
352         ap1fdndip = self.add_ip_address(ap1fdnd, "192.168.2.80")
353         ap1fdndip.set_attribute_value("NetPrefix", 32) # p2p
354         pl1tap.connector("fd->").connect(ap1fdnd.connector("->fd"))
355         pl1tap.set_attribute_value("pointopoint", "192.168.2.80")
356         r = ap1.add_route()
357         r.set_attribute_value("Destination", "192.168.2.65")
358         r.set_attribute_value("NetPrefix", 32)
359         r.set_attribute_value("NextHop", "192.168.2.80")
360         
361         # return mesh router
362         return (
363             pl1, pl1if, pl1tap, pl1tapip,
364             (wnode1, wnode2, wnode3, wnode4),
365             (wnode1wifi, wnode2wifi, wnode3wifi, wnode4wifi),
366             ap1, ap1wifi,
367             ns3,
368             inet,
369         )
370     
371     def run(self):
372         pl, exp = self.make_experiment_desc()
373     
374         pl1, pl1if, pl1tap, pl1tapip, \
375             mesh_nodes, mesh_node_ifs, \
376             mesh_aps, mesh_ap_ifs, \
377             mesh_ns, \
378             inet = self.make_mesh(pl, exp, None)
379         pl2, pl2if, pl2tap, pl2tapip, \
380             hs_nodes, hs_node_ifs, \
381             hs_ap, hs_apif, \
382             hs_ns, \
383             inet = self.make_wifi_hotspot(pl, exp, inet)
384         
385         # Connect the routers
386         pl1etap = pl.create("TapInterface")
387         pl1etap.enable_trace("packets") # for error output
388         pl1etap.set_attribute_value("label", "pl1etap")
389         pl1etapip = pl1etap.add_address()
390         pl1etapip.set_attribute_value("Address", "192.168.2.1")
391         pl1etapip.set_attribute_value("NetPrefix", 24)
392         pl1etapip.set_attribute_value("Broadcast", False)
393
394         pl2etap = pl.create("TapInterface")
395         pl2etap.enable_trace("packets") # for error output
396         pl2etap.set_attribute_value("label", "pl2etap")
397         pl2etapip = pl2etap.add_address()
398         pl2etapip.set_attribute_value("Address", "192.168.2.81")
399         pl2etapip.set_attribute_value("NetPrefix", 24)
400         pl2etapip.set_attribute_value("Broadcast", False)
401         
402         pl1etap.connector("node").connect(pl1.connector("devs"))
403         pl2etap.connector("node").connect(pl2.connector("devs"))
404         pl1etap.connector("udp").connect(pl2etap.connector("udp"))
405         pl1etap.set_attribute_value("pointopoint", "192.168.2.81")
406         pl2etap.set_attribute_value("pointopoint", "192.168.2.1")
407         
408         # Connect the networks
409         
410         # apn -> ap2 (n != 2)
411         for ap in mesh_aps[:1] + mesh_aps[2:]:
412             r = ap.add_route()
413             r.set_attribute_value("Destination", "192.168.2.64")
414             r.set_attribute_value("NetPrefix", 26)
415             r.set_attribute_value("NextHop", 
416                 mesh_ap_ifs[1].addresses[0].get_attribute_value("Address") )
417
418         for wn in mesh_nodes:
419             apif = mesh_ap_ifs[ random.randint(0,len(mesh_aps)-1) ]
420             r = wn.add_route()
421             r.set_attribute_value("Destination", "192.168.2.64")
422             r.set_attribute_value("NetPrefix", 26)
423             r.set_attribute_value("NextHop", 
424                 apif.addresses[0].get_attribute_value("Address"))
425
426         r = mesh_aps[1].add_route()
427         r.set_attribute_value("Destination", "192.168.2.64")
428         r.set_attribute_value("NetPrefix", 26)
429         r.set_attribute_value("NextHop", "192.168.2.2")
430         
431         r = pl1.add_route()
432         r.set_attribute_value("Destination", "192.168.2.64")
433         r.set_attribute_value("NetPrefix", 26)
434         r.set_attribute_value("NextHop", "192.168.2.81")
435
436         r = pl2.add_route()
437         r.set_attribute_value("Destination", "192.168.2.64")
438         r.set_attribute_value("NetPrefix", 26)
439         r.set_attribute_value("NextHop", "192.168.2.80")
440
441         for wn in hs_nodes:
442             r = wn.add_route()
443             r.set_attribute_value("Destination", "192.168.2.0")
444             r.set_attribute_value("NetPrefix", 26)
445             r.set_attribute_value("NextHop", "192.168.2.66")
446
447         r = hs_ap.add_route()
448         r.set_attribute_value("Destination", "192.168.2.0")
449         r.set_attribute_value("NetPrefix", 26)
450         r.set_attribute_value("NextHop", "192.168.2.65")
451         
452         r = pl2.add_route()
453         r.set_attribute_value("Destination", "192.168.2.0")
454         r.set_attribute_value("NetPrefix", 26)
455         r.set_attribute_value("NextHop", "192.168.2.1")
456
457         r = pl1.add_route()
458         r.set_attribute_value("Destination", "192.168.2.0")
459         r.set_attribute_value("NetPrefix", 26)
460         r.set_attribute_value("NextHop", "192.168.2.20")
461
462         # Add pinger app inside the mesh
463         hs_node_ifs[0].set_attribute_value("label", "hotspot_node_1if")
464         mesh_node_ifs[0].set_attribute_value("label", "mesh_node_1if")
465         ping = mesh_ns.create("ns3::V4Ping")
466         ping.set_attribute_value("Remote", "192.168.2.67") #"{#[hotspot_node_1if].addr[0].[Address]#}")
467         ping.set_attribute_value("StartTime", "0s")
468         ping.set_attribute_value("StopTime", "10s")
469         ping.connector("node").connect(mesh_aps[0].connector("apps"))
470
471         xml = exp.to_xml()
472         
473         print xml
474
475         try:
476             controller = ExperimentController(xml, self.root_dir)
477             controller.start()
478             
479             while not controller.is_finished(ping.guid):
480                 time.sleep(0.5)
481             
482             taptrace = controller.trace(pl.guid, pl1tap.guid, "packets")
483                 
484         finally:
485             controller.stop()
486             controller.shutdown()
487         
488         print "Pakcets at router:"
489         print taptrace
490
491     def clean(self):
492         shutil.rmtree(self.root_dir)
493
494 if __name__ == '__main__':
495     example = Roads09Ns3PLExample()
496     example.run()
497     example.clean()
498