2 # -*- coding: utf-8 -*-
23 sys.path.append(os.path.abspath("../../src"))
25 from nepi.core.design import ExperimentDescription, FactoriesProvider
26 from nepi.core.execute import ExperimentController
27 from nepi.util import proxy
28 from nepi.util.constants import DeploymentConfiguration as DC, ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP
29 from nepi.testbeds.planetlab import util as plutil
30 from optparse import OptionParser
33 class PlanetLabMulticastOverlay:
34 testbed_id = "planetlab"
35 slicename = "inria_nepi"
36 plchost = "www.planet-lab.eu"
37 plkey = os.environ.get(
39 "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) )
40 pluser = os.environ.get("PL_USER")
41 plpass = os.environ.get("PL_PASS")
45 port_base = 2000 + (os.getpid() % 1000) * 13
48 self.root_dir = tempfile.mkdtemp()
49 self.__class__.port_base = self.__class__.port_base + 100
52 print "\tDISPLAY:", os.environ['DISPLAY']
53 print "\tPLC:", self.plchost
54 print "\tUsername:", self.pluser
55 print "\tslice:", self.slicename
57 api = plutil.getAPI(self.pluser, self.plpass, hostname=self.plchost)
58 self.vnet = plutil.getVnet(api, self.slicename).split('/')[0].strip()
60 print "\tvnet:", self.vnet
64 shutil.rmtree(self.root_dir)
68 shutil.rmtree(self.root_dir)
70 def make_experiment_desc(self):
71 testbed_id = self.testbed_id
72 slicename = self.slicename
73 plchost = self.plchost
74 pl_ssh_key = self.plkey
78 plroot_dir = os.path.join(self.root_dir,"pl")
79 if not os.path.exists(plroot_dir):
80 os.makedirs(plroot_dir)
82 exp_desc = ExperimentDescription()
83 pl_provider = FactoriesProvider(testbed_id)
84 pl_desc = exp_desc.add_testbed_description(pl_provider)
85 pl_desc.set_attribute_value(DC.ROOT_DIRECTORY, plroot_dir )
86 pl_desc.set_attribute_value("homeDirectory", self.root_dir)
87 pl_desc.set_attribute_value("slice", slicename)
88 pl_desc.set_attribute_value("sliceSSHKey", pl_ssh_key)
89 pl_desc.set_attribute_value("authUser", pl_user)
90 pl_desc.set_attribute_value("authPass", pl_pwd)
91 pl_desc.set_attribute_value("plcHost", plchost)
92 pl_desc.set_attribute_value("tapPortBase", self.port_base)
93 pl_desc.set_attribute_value("p2pDeployment", not self.no_p2p_deploy)
94 pl_desc.set_attribute_value("cleanProc", True)
95 pl_desc.set_attribute_value("plLogLevel", "INFO")
97 return pl_desc, exp_desc
99 def make_pl_tapnode(self, pl, ip, inet = None, label = None, hostname = None, routes = None, mcast = False, mcastrouter = False, types = None):
100 if not isinstance(ip, list):
104 node1 = pl.create("Node")
106 node1.set_attribute_value("label", label)
108 node1.set_attribute_value("hostname", hostname)
109 iface1 = pl.create("NodeInterface")
111 iface1.set_attribute_value("label", label+"iface")
113 types = ["TapInterface"] * len(ips)
116 for i,(ip,devtype) in enumerate(zip(ips,types)):
117 _tap1 = pl.create(devtype)
118 _tap1.set_attribute_value("multicast", True)
119 _tap1.enable_trace("pcap") # for error output
121 _tap1.set_attribute_value("label", label+"tap"+(str(i+1) if i else ""))
123 _tap1ip = _tap1.add_address()
124 _tap1ip.set_attribute_value("Address", ip)
125 _tap1ip.set_attribute_value("NetPrefix", 32)
126 _tap1ip.set_attribute_value("Broadcast", False)
128 node1.connector("devs").connect(_tap1.connector("node"))
131 tap1ip.append(_tap1ip)
133 inet = inet or pl.create("Internet")
134 node1.connector("devs").connect(iface1.connector("node"))
135 iface1.connector("inet").connect(inet.connector("devs"))
137 for destip, destprefix, nexthop in routes:
138 r1 = node1.add_route()
139 r1.set_attribute_value("Destination", destip)
140 r1.set_attribute_value("NetPrefix", destprefix)
141 r1.set_attribute_value("NextHop", nexthop)
145 fwd = pl.create("MulticastForwarder")
146 fwd.enable_trace("stderr")
147 fwd.connector("node").connect(node1.connector("apps"))
148 mrt = pl.create("MulticastRouter")
149 mrt.connector("fwd").connect(fwd.connector("router"))
150 mrt.enable_trace("stderr")
152 ann = pl.create("MulticastAnnouncer")
153 ann.enable_trace("stderr")
154 ann.connector("node").connect(node1.connector("apps"))
156 return node1, iface1, tap1, tap1ip, inet
158 def add_vlc_base(self, pl, node):
159 app = pl.create("Application")
160 app.set_attribute_value("rpmFusion", True)
161 app.set_attribute_value("depends", "vlc")
162 app.set_attribute_value("command", "sudo -S dbus-uuidgen --ensure ; vlc --version")
163 app.enable_trace("stdout")
164 app.enable_trace("stderr")
165 node.connector("apps").connect(app.connector("node"))
168 def add_vlc_restreamer(self, pl, node):
169 hostname = node.get_attribute_value("hostname")
170 app = self.add_vlc_base(pl, node)
171 app.set_attribute_value("label","vlc_restreamer_%d" % (node.guid,))
172 app.set_attribute_value("command",
173 "sudo -S dbus-uuidgen --ensure ; "
176 " udp/ts://@239.255.12.42"
177 " --sout '#std{access=http,mux=ts,dst=:8080}'"
178 " ; sleep 5 ; done ")
181 def add_vlc_dumper(self, pl, node, hostname=None, labelprefix = "vlc_dumper", precmd = "sleep 5 ; "):
182 app = self.add_vlc_base(pl, node)
183 mylabel = "%s_%d" % (labelprefix, node.guid,)
185 hostname = node.get_attribute_value("hostname")
186 app.set_attribute_value("label",mylabel)
187 app.set_attribute_value("command",
189 "sudo -S dbus-uuidgen --ensure ; "
190 "cat /dev/null > {#["+mylabel+"].trace[output].[name]#} ; "
191 "while [[ $(stat -c '%s' {#["+mylabel+"].trace[output].[name]#}) == '0' ]] ; do "
193 " http://"+hostname+":8080 vlc://quit"
194 " --sout '#std{access=file,mux=ts,dst={#["+mylabel+"].trace[output].[name]#}}'"
195 " ; sleep 5 ; done ")
196 app.enable_trace("output")
199 def add_vlc_source(self, pl, node, iflabels):
200 app = self.add_vlc_base(pl, node)
201 app.set_attribute_value("label","vlc_source_%d" % (node.guid,))
202 app.set_attribute_value("sources", self.movie_source)
203 app.set_attribute_value("command",
204 "sudo -S dbus-uuidgen --ensure ; "
206 +os.path.basename(self.movie_source)
207 +" --sout '#duplicate{"
209 "dst=std{access=udp,dst=239.255.12.42,mux=ts,ttl=64,miface-addr={#[%s].addr[0].[Address]#}}" % (iflabel,)
210 for iflabel in iflabels
215 def add_net_monitor(self, pl, node):
216 app = pl.create("Application")
217 app.set_attribute_value("label","network_monitor_%d" % (node.guid,))
218 app.set_attribute_value("command",
219 r"""head -n 2 /proc/net/dev ; while true ; do cat /proc/net/dev | sed -r 's/.*/'"$(date -R)"': \0/' | grep eth0 ; sleep 1 ; done""")
220 app.enable_trace("stdout")
221 node.connector("apps").connect(app.connector("node"))
224 def add_ip_address(self, iface, address, netprefix):
225 ip = iface.add_address()
226 ip.set_attribute_value("Address", address)
227 ip.set_attribute_value("NetPrefix", netprefix)
229 def add_route(self, node, destination, netprefix, nexthop):
230 route = node.add_route()
231 route.set_attribute_value("Destination", destination)
232 route.set_attribute_value("NetPrefix", netprefix)
233 route.set_attribute_value("NextHop", nexthop)
235 def make_ns_in_pl(self, pl, exp, node1, iface1, root):
236 ns3_testbed_id = "ns3"
238 # Add NS3 support in node1
239 plnepi = pl.create("NepiDependency")
240 plns3 = pl.create("NS3Dependency")
241 plnepi.connector("node").connect(node1.connector("deps"))
242 plns3.connector("node").connect(node1.connector("deps"))
244 # Create NS3 testbed running in node1
245 ns3_provider = FactoriesProvider(ns3_testbed_id)
246 ns_desc = exp.add_testbed_description(ns3_provider)
247 ns_desc.set_attribute_value("rootDirectory", root)
248 ns_desc.set_attribute_value("SimulatorImplementationType", "ns3::RealtimeSimulatorImpl")
249 ns_desc.set_attribute_value("ChecksumEnabled", True)
250 ns_desc.set_attribute_value(DC.DEPLOYMENT_HOST, "{#[%s].addr[0].[Address]#}" % (
251 iface1.get_attribute_value("label"),))
252 ns_desc.set_attribute_value(DC.DEPLOYMENT_USER,
253 pl.get_attribute_value("slice"))
254 ns_desc.set_attribute_value(DC.DEPLOYMENT_KEY,
255 pl.get_attribute_value("sliceSSHKey"))
256 ns_desc.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
257 ns_desc.set_attribute_value(DC.DEPLOYMENT_COMMUNICATION, DC.ACCESS_SSH)
258 ns_desc.set_attribute_value(DC.DEPLOYMENT_ENVIRONMENT_SETUP,
260 node1.get_attribute_value("label"),
261 ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,))
262 ns_desc.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
266 def add_ip_address(self, iface, address, netprefix, broadcast = False):
267 ip = iface.add_address()
268 ip.set_attribute_value("Address", address)
269 ip.set_attribute_value("NetPrefix", netprefix)
270 ip.set_attribute_value("Broadcast", broadcast)
273 def add_route(self, node, destination, netprefix, nexthop):
274 route = node.add_route()
275 route.set_attribute_value("Destination", destination)
276 route.set_attribute_value("NetPrefix", netprefix)
277 route.set_attribute_value("NextHop", nexthop)
280 def add_ns_fdnd(self, ns_desc, node):
281 fdnd = ns_desc.create("ns3::FdNetDevice")
282 node.connector("devs").connect(fdnd.connector("node"))
283 #fdnd.enable_trace("FdPcapTrace")
286 def add_ns_node(self, ns_desc):
287 node = ns_desc.create("ns3::Node")
288 ipv4 = ns_desc.create("ns3::Ipv4L3Protocol")
289 arp = ns_desc.create("ns3::ArpL3Protocol")
290 icmp = ns_desc.create("ns3::Icmpv4L4Protocol")
291 udp = ns_desc.create("ns3::UdpL4Protocol")
292 node.connector("protos").connect(ipv4.connector("node"))
293 node.connector("protos").connect(arp.connector("node"))
294 node.connector("protos").connect(icmp.connector("node"))
295 node.connector("protos").connect(udp.connector("node"))
298 def add_ns_wifi_dev(self, ns_desc, node, access_point = False):
299 wifi = ns_desc.create("ns3::WifiNetDevice")
300 node.connector("devs").connect(wifi.connector("node"))
302 phy = ns_desc.create("ns3::YansWifiPhy")
303 error = ns_desc.create("ns3::NistErrorRateModel")
304 manager = ns_desc.create("ns3::ArfWifiManager")
306 mac = ns_desc.create("ns3::ApWifiMac")
308 mac = ns_desc.create("ns3::StaWifiMac")
310 phy.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a")
311 mac.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a")
312 phy.connector("err").connect(error.connector("phy"))
313 wifi.connector("phy").connect(phy.connector("dev"))
314 wifi.connector("mac").connect(mac.connector("dev"))
315 wifi.connector("manager").connect(manager.connector("dev"))
317 #phy.enable_trace("YansWifiPhyPcapTrace")
320 def add_ns_constant_mobility(self, ns_desc, node, x, y, z):
321 mobility = ns_desc.create("ns3::ConstantPositionMobilityModel")
322 position = "%d:%d:%d" % (x, y, z)
323 mobility.set_attribute_value("Position", position)
324 node.connector("mobility").connect(mobility.connector("node"))
327 def add_ns_wifi_channel(self, ns_desc):
328 channel = ns_desc.create("ns3::YansWifiChannel")
329 delay = ns_desc.create("ns3::ConstantSpeedPropagationDelayModel")
330 loss = ns_desc.create("ns3::LogDistancePropagationLossModel")
331 channel.connector("delay").connect(delay.connector("chan"))
332 channel.connector("loss").connect(loss.connector("prev"))
335 def make_netns_testbed(self, exp_desc):
336 netns_provider = FactoriesProvider("netns")
337 netns_desc = exp_desc.add_testbed_description(netns_provider)
338 netns_desc.set_attribute_value("homeDirectory", self.root_dir)
339 netns_desc.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON)
340 netns_root_dir = os.path.join(self.root_dir, "netns")
341 os.mkdir(netns_root_dir)
342 netns_desc.set_attribute_value(DC.ROOT_DIRECTORY, netns_root_dir)
343 netns_desc.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL)
344 netns_desc.set_attribute_value(DC.USE_SUDO, True)
347 def add_netns_node(self, netns_desc, forwardX = True, label = None):
348 node = netns_desc.create("Node")
349 node.set_attribute_value("forward_X11", forwardX)
351 node.set_attribute_value("label", label)
354 def add_netns_app(self, netns_desc, command, node):
355 app = netns_desc.create("Application")
356 app.set_attribute_value("command", command)
357 app.set_attribute_value("user", self.user)
358 app.connector("node").connect(node.connector("apps"))
361 def add_pl_netns_connection(self,
363 netns_desc, netns_node, netns_addr, netns_prefix = 30,
365 pl_tap.set_attribute_value("tun_cipher", "PLAIN")
366 pl_tap.set_attribute_value("multicast", True)
367 #pl_tap.enable_trace("pcap")
368 #pl_tap.enable_trace("packets")
369 pl_tapip = pl_tap.addresses[0].get_attribute_value("Address")
370 netns_tap = netns_desc.create("TunNodeInterface")
371 netns_tap.set_attribute_value("up", True)
372 netns_tap.set_attribute_value("mtu", 1448)
373 self.add_ip_address(netns_tap, netns_addr, netns_prefix)
375 netns_tap.set_attribute_value("label", taplabel)
376 netns_node.connector("devs").connect(netns_tap.connector("node"))
377 netns_tunchannel = netns_desc.create("TunChannel")
378 netns_tunchannel.set_attribute_value("tun_cipher", "PLAIN")
379 netns_tunchannel.connector("->fd").connect(netns_tap.connector("fd->"))
380 pl_tap.connector("tcp").connect(netns_tunchannel.connector("tcp"))
382 pl_tap.set_attribute_value("tun_cipher", "PLAIN")
383 pl_tap.set_attribute_value("pointopoint", netns_addr)
385 def add_pl_ns_connection(self, pl_desc, pl_node, pl_addr,
386 ns, ns_node, ns_addr, prefix = 30,
387 fd = False, ptp = False):
388 pl_tap = pl_desc.create("TapInterface")
390 pl_tap.set_attribute_value("tun_cipher", "PLAIN")
391 self.add_ip_address(pl_tap, pl_addr, prefix)
392 pl_node.connector("devs").connect(pl_tap.connector("node"))
393 ns_fdnd = ns.create("ns3::FdNetDevice")
394 ns_node.connector("devs").connect(ns_fdnd.connector("node"))
395 self.add_ip_address(ns_fdnd, ns_addr, prefix)
398 pl_tap.connector("fd->").connect(ns_fdnd.connector("->fd"))
400 tunchannel = ns.create("ns3::Nepi::TunChannel")
401 tunchannel.connector("fd->").connect(ns_fdnd.connector("->fd"))
402 pl_tap.connector("udp").connect(tunchannel.connector("udp"))
405 pl_tap.set_attribute_value("pointopoint", ns_addr)
407 def make_pl_overlay(self, numnodes):
408 ns3_testbed_id = "ns3"
410 pl, exp = self.make_experiment_desc()
412 # We'll make a distribution spanning tree using prefix matching as a distance
413 api = plutil.getAPI(self.pluser, self.plpass, hostname=self.plchost)
414 nodes = plutil.getNodes(api, numnodes, operatingSystem = 'f12')
415 root = min(nodes, key=operator.attrgetter('hostname'))
416 links = list(plutil.getSpanningTree(nodes, root=root))
421 node.childips = set()
423 # Build an explicit tree
424 for slave, master in links:
425 master.children.append(slave)
427 # We have to assign IPs and routes.
428 # The IP will be assigned sequentially, depth-first.
429 # This will result in rather compact routing rules
430 nextip = [128-numnodes]
431 def traverse(traverse, node, parent=None, base=struct.unpack('!L',socket.inet_aton(self.vnet))[0]):
433 raise RuntimeError, "Too many IPs to assign!"
435 node.vif_addr = base | (nextip[0])
436 nips = 1+len(node.children) # one vif per child, plus one for the parent
439 for i in xrange(nips):
440 node.vif_ips.add(node.vif_addr+i)
443 parent.childips.update(node.vif_ips)
445 for i,child in enumerate(node.children):
446 traverse(traverse, child, node, base)
449 parent.childips.update(node.childips)
451 traverse(traverse, root)
453 def printtree(printtree, node, indent=''):
454 print indent, '-', socket.inet_ntoa(struct.pack('!L',node.vif_addr)), '\t', node.country, node.city, node.site, '\t', node.hostname
455 for child in node.children:
456 childips = map(ipaddr.IPAddress, child.childips)
457 childnets = ipaddr.collapse_address_list(childips)
458 cip = ipaddr.IPAddress(child.vif_addr)
459 for cnet in childnets:
460 print indent, '|- R', cnet, '->', cip
461 printtree(printtree, child, indent+' | ')
462 printtree(printtree, root)
464 inet = pl.create("Internet")
469 def maketree(maketree, node, parent=None, parentIp=None):
472 for i,child in enumerate(node.children):
473 childips = map(ipaddr.IPAddress, child.childips)
474 childnets = ipaddr.collapse_address_list(childips)
475 cip = ipaddr.IPAddress(child.vif_addr)
476 pip = ipaddr.IPAddress(node.vif_addr+1+i)
477 for cnet in childnets:
478 routes.append((cnet.ip.exploded, cnet.prefixlen, cip.exploded))
479 ctaps.append( maketree(maketree, child, node, pip) )
481 routes.append((self.vnet,24,parentIp))
488 # NS node, first leaf
489 if not ns_chosen and not node.children:
490 ns_chosen.append(True)
493 ips = [ ipaddr.IPAddress(node.vif_addr+i) for i in xrange(1+len(node.children)) ]
494 node1, iface1, tap1, tap1ip, _ = self.make_pl_tapnode(pl, ips, inet,
495 hostname = node.hostname,
497 mcastrouter = bool(node.children),
500 types = ( [ "TapInterface" ] * len(ips) if parent else [ "TunInterface" ] + [ "TapInterface" ] * (len(ips)-1) )
503 for tap, ctap in zip(tap1[1:], ctaps):
504 tap.connector("udp").connect(ctap.connector("udp"))
507 if not node.children:
508 leaves.append((node, node1))
510 self.add_net_monitor(pl, node1)
511 self.add_vlc_dumper(pl, node1)
512 self.add_vlc_restreamer(pl, node1)
515 # t.get_attribute_value("label")
518 # self.add_vlc_source(pl, node1, taplabels)
521 roottap = maketree(maketree, root)
523 vnet_i = int(ipaddr.IPAddress(self.vnet))
526 pl_ns_root = exp.get_element_by_label("ns_root")
527 pl_ns_root_iface = exp.get_element_by_label("ns_rootiface")
528 ns = self.make_ns_in_pl(pl, exp, pl_ns_root, pl_ns_root_iface, "ns3")
529 wifi_chan = self.add_ns_wifi_channel(ns)
532 ap_node = self.add_ns_node(ns)
533 self.add_ns_constant_mobility(ns, ap_node, 0, 0, 0)
534 ap_wifi, ap_phy = self.add_ns_wifi_dev(ns, ap_node, access_point = True)
535 ap_phy.connector("chan").connect(wifi_chan.connector("phys"))
537 # Net range free for WiFi
538 wifi_net_prefix = 32-int(math.floor(math.log(256-nextip[0]&0xff) / math.log(2)))
539 wifi_net = vnet_i | (256 - (1<<(32-wifi_net_prefix)))
542 pl_addr = str(ipaddr.IPAddress(wifi_net | 1))
543 ns_addr = str(ipaddr.IPAddress(wifi_net | 2))
544 self.add_pl_ns_connection(
545 pl, pl_ns_root, pl_addr,
546 ns, ap_node, ns_addr,
547 fd = True, ptp = True, prefix=30)
551 ap_addr = str(ipaddr.IPAddress(vnet_i | 254))
552 ap_addr_prefix = 32-int(math.ceil(math.log(self.nsta+3) / math.log(2)))
553 self.add_ip_address(ap_wifi, ap_addr, ap_addr_prefix)
556 self.add_route(pl_ns_root,
557 str(ipaddr.IPAddress(wifi_net)), wifi_net_prefix,
560 print "NS-3 AP\t%s/%s <--> PL AP %s" % (ns_addr, 30, pl_addr)
561 print " | (|) %s/%s" % (ap_addr, ap_addr_prefix)
563 print " | R %s/%d --> %s" % (str(ipaddr.IPAddress(wifi_net)), wifi_net_prefix, ns_addr)
565 nextpip = (vnet_i | 255) >> (32-ap_addr_prefix) << (32-ap_addr_prefix)
566 nextdip = vnet_i | 253
567 ap_net = nextpip - (1<<(32-ap_addr_prefix))
570 for i in xrange(self.nsta):
571 stai = self.add_ns_node(ns)
572 angi = (360/self.nsta)*i
573 xi = r*math.cos(angi)
574 yi = r*math.sin(angi)
575 self.add_ns_constant_mobility(ns, stai, xi, yi, 0)
576 wifi, phy = self.add_ns_wifi_dev(ns, stai, access_point = False)
577 phy.connector("chan").connect(wifi_chan.connector("phys"))
579 wifi_addr = str(ipaddr.IPAddress(vnet_i | nextdip))
586 plns_net = str(ipaddr.IPAddress(plns_net_i))
587 pl_addr2 = str(ipaddr.IPAddress(plns_net_i | 1))
588 ns_addr2 = str(ipaddr.IPAddress(plns_net_i | 2))
590 # route from AP (after others)
591 print " | R %s/%s -> %s" % ( plns_net,30,ns_addr2 )
592 self.add_route(ap_node, plns_net, 30, wifi_addr)
594 print " +---\t(|) %16s/%s" % (wifi_addr,ap_addr_prefix)
595 print " | %16s (ns3) <---> (pl) %16s/30" % (ns_addr2, pl_addr2)
596 print " |\t \t\t <-- R %s/24" % (self.vnet, )
597 print " |\t \t R %s/30 -> %s" % (plns_net, pl_addr2)
598 print " |\t \t R %s <-- %s/24" % (ap_addr, plns_net)
600 self.add_ip_address(wifi, wifi_addr, ap_addr_prefix)
601 self.add_route(stai, plns_net, 30, pl_addr2)
602 self.add_route(stai, self.vnet, 24, ap_addr)
604 pl_nodei, _, pl_ifacei, _, _ = self.make_pl_tapnode(pl, [], inet,
605 routes = [(self.vnet, 24, ns_addr2)],
607 label = "ns_plnode_%d" % (i+1,)
610 self.add_pl_ns_connection(
611 pl, pl_nodei, pl_addr2,
615 self.add_vlc_dumper(pl, pl_nodei,
617 labelprefix = "vlc_dumper_ns",
618 precmd = "sleep 15 ; ")
620 # Validate (post-fact to let the user see the diagram above)
621 if nextpip < wifi_net:
622 raise RuntimeError, "Not enough IPs for wifi section"
624 # route back to PL (after others)
625 print " | R %s/%s -> %s" % ( self.vnet,24,pl_addr )
626 self.add_route(ap_node, self.vnet, 24, pl_addr)
630 netns_addr = str(ipaddr.IPAddress(vnet_i | 1))
632 root1 = exp.get_element_by_label("root")
633 netns = self.make_netns_testbed(exp)
634 netns_node = self.add_netns_node(netns)
635 netns_term = self.add_netns_app(netns, "xterm", netns_node)
636 if self.movie_source:
639 +os.path.abspath(self.movie_source)
640 +" --sout '#std{access=udp{ttl=64,miface-addr="+netns_addr+"},dst=239.255.12.42,mux=ts}'"
643 cmd = self.movie_command % {
644 "dst" : "std{access=udp{ttl=64,miface-addr="+netns_addr+"},dst=239.255.12.42,mux=ts}"
646 netns_vlc = self.add_netns_app(netns, cmd, netns_node)
648 # connection PL1/NETNS
649 self.add_pl_netns_connection(
651 netns, netns_node, netns_addr,
653 taplabel="netns_source")
654 self.add_route(netns_node,
656 str(ipaddr.IPAddress(root.vif_addr)) )
658 # pick random hostname to stream from
659 interactive_source_host = random.sample(leaves,1)[0][0].hostname
662 test_dir = "./results"
666 controller = ExperimentController(xml, self.root_dir)
669 # launch vlc client to monitor activity
671 proc = subprocess.Popen([
672 "vlc", "-I", "dummy", "http://%s:8080" % (interactive_source_host,)])
674 print >>sys.stderr, "Close xterm to shut down or Ctrl+C"
676 while not controller.is_finished(netns_term.guid):
678 except KeyboardInterrupt:
681 controller.traces_info()
685 controller.traces_info()
690 os.kill(proc.pid, signal.SIGTERM)
693 traces_info = controller.traces_info()
694 for progress, (testbed_guid, guids) in enumerate(traces_info.iteritems()):
695 for subprogress, (guid, traces) in enumerate(guids.iteritems()):
696 for name, data in traces.iteritems():
697 path = data["filepath"]
698 elem = exp.get_element(guid)
700 label = elem.get_attribute_value("label")
701 if label is not None:
702 path = "%s-%s" % (label,path)
707 print >>sys.stderr, ("%.2f%% Downloading trace" % (progress + (subprogress * 1.0 / len(guids)) * 100.0 / len(traces_info))), path
709 filepath = os.path.join(test_dir, path)
712 trace = controller.trace(guid, name)
714 traceback.print_exc(file=sys.stderr)
717 if not os.path.exists(os.path.dirname(filepath)):
718 os.makedirs(os.path.dirname(filepath))
720 traceback.print_exc(file=sys.stderr)
723 if len(trace) >= 2**20:
724 # Bigger than 1M, compress
725 tracefile = gzip.GzipFile(filepath+".gz", "wb")
727 tracefile = open(filepath,"wb")
729 tracefile.write(trace)
733 traceback.print_exc(file=sys.stderr)
738 traceback.print_exc()
740 controller.shutdown()
742 traceback.print_exc()
745 if __name__ == '__main__':
746 usage = "usage: %prog -m movie -u user"
747 parser = OptionParser(usage=usage)
748 parser.add_option("-u", "--user", dest="user", help="Valid linux system user (not root).", type="str")
749 parser.add_option("-U", "--pluser", dest="pluser", help="PlanetLab PLC username", type="str")
750 parser.add_option("-m", "--movie", dest="movie", help="Path to movie file to play", type="str")
751 parser.add_option("-n", "--nsta", dest="nsta", default=3, help="Number of wifi stations attached to the overlay", type="int")
752 parser.add_option("-N", "--nodes", dest="nodes", default=5, help="Number of overlay nodes", type="int")
753 parser.add_option("-s", "--slicename", dest="slicename", help="PlanetLab slice", type="str")
754 parser.add_option("-H", "--plchost", dest="plchost", help="PlanetLab's PLC hostname", type="str")
755 parser.add_option("-k", "--plkey", dest="plkey", help="Slice SSH key", type="str")
756 parser.add_option("-P", "--no-p2p", dest="nop2p", help="Disable peer-to-peer deployment. Not recommended for first deployment.",
757 action="store_true", default=False)
758 (options, args) = parser.parse_args()
759 if options.user == 'root':
760 parser.error("Missing or invalid 'user' option.")
762 exp = PlanetLabMulticastOverlay()
763 if not options.movie or options.movie.startswith("/dev/"):
765 if not options.movie:
766 options.movie = "/dev/video0"
767 exp.movie_source = None
768 exp.movie_command = (
769 "vlc -I dummy -vvv --color "
770 "v4l:///dev/video0:size=320x240:channel=0:adev=/dev/dsp:audio=0 "
771 "--sout '#transcode{vcodec=mpeg4,acodec=aac,vb=100,ab=16,venc=ffmpeg{keyint=80,hq=rd},deinterlace}:"
775 exp.movie_source = options.movie
776 exp.no_p2p_deploy = options.nop2p
777 exp.nsta = options.nsta
779 exp.user = options.user
781 exp.plchost = options.plchost
782 if options.slicename:
783 exp.slicename = options.slicename
785 exp.plkey = options.plkey
787 exp.pluser = options.pluser
789 exp.plpass = getpass.getpass("Password for %s: " % (exp.pluser,))
791 # Fix some distro's environment to work well with netns
792 if re.match(r"[^:]*:\d+$", os.environ['DISPLAY']):
793 os.environ['DISPLAY'] += '.0'
794 if not os.environ.get('XAUTHORITY'):
795 os.environ['XAUTHORITY'] = os.path.join(os.environ['HOME'], '.Xauthority')
799 exp.make_pl_overlay(options.nodes)