def setUp(self): self.root_dir = tempfile.mkdtemp() self.__class__.port_base = self.__class__.port_base + 100 print "Using:" print "\tDISPLAY:", os.environ['DISPLAY'] print "\tPLC:", self.plchost print "\tUsername:"******"\tslice:", self.slicename api = plutil.getAPI(self.pluser, self.plpass, hostname=self.plchost) self.vnet = plutil.getVnet(api, self.slicename).split('/')[0].strip() print "\tvnet:", self.vnet
def make_pl_overlay(self, numnodes): ns3_testbed_id = "ns3" pl, exp = self.make_experiment_desc() # We'll make a distribution spanning tree using prefix matching as a distance api = plutil.getAPI(self.pluser, self.plpass, hostname=self.plchost) nodes = plutil.getNodes(api, numnodes, operatingSystem = 'f12') root = min(nodes, key=operator.attrgetter('hostname')) links = list(plutil.getSpanningTree(nodes, root=root)) for node in nodes: node.vif_ips = set() node.children = [] node.childips = set() # Build an explicit tree for slave, master in links: master.children.append(slave) # We have to assign IPs and routes. # The IP will be assigned sequentially, depth-first. # This will result in rather compact routing rules nextip = [128-numnodes] def traverse(traverse, node, parent=None, base=struct.unpack('!L',socket.inet_aton(self.vnet))[0]): if nextip[0] >= 254: raise RuntimeError, "Too many IPs to assign!" node.vif_addr = base | (nextip[0]) nips = 1+len(node.children) # one vif per child, plus one for the parent nextip[0] += nips for i in xrange(nips): node.vif_ips.add(node.vif_addr+i) if parent: parent.childips.update(node.vif_ips) for i,child in enumerate(node.children): traverse(traverse, child, node, base) if parent: parent.childips.update(node.childips) traverse(traverse, root) def printtree(printtree, node, indent=''): print indent, '-', socket.inet_ntoa(struct.pack('!L',node.vif_addr)), '\t', node.country, node.city, node.site, '\t', node.hostname for child in node.children: childips = map(ipaddr.IPAddress, child.childips) childnets = ipaddr.collapse_address_list(childips) cip = ipaddr.IPAddress(child.vif_addr) for cnet in childnets: print indent, '|- R', cnet, '->', cip printtree(printtree, child, indent+' | ') printtree(printtree, root) inet = pl.create("Internet") ns_chosen = [] leaves = [] def maketree(maketree, node, parent=None, parentIp=None): routes = [] ctaps = [] for i,child in enumerate(node.children): childips = map(ipaddr.IPAddress, child.childips) childnets = ipaddr.collapse_address_list(childips) cip = ipaddr.IPAddress(child.vif_addr) pip = ipaddr.IPAddress(node.vif_addr+1+i) for cnet in childnets: routes.append((cnet.ip.exploded, cnet.prefixlen, cip.exploded)) ctaps.append( maketree(maketree, child, node, pip) ) if parentIp: routes.append((self.vnet,24,parentIp)) if not parent: label = "root" else: label = None # NS node, first leaf if not ns_chosen and not node.children: ns_chosen.append(True) label = "ns_root" ips = [ ipaddr.IPAddress(node.vif_addr+i) for i in xrange(1+len(node.children)) ] node1, iface1, tap1, tap1ip, _ = self.make_pl_tapnode(pl, ips, inet, hostname = node.hostname, routes = routes, mcastrouter = bool(node.children), mcast = True, label = label, types = ( [ "TapInterface" ] * len(ips) if parent else [ "TunInterface" ] + [ "TapInterface" ] * (len(ips)-1) ) ) for tap, ctap in zip(tap1[1:], ctaps): tap.connector("udp").connect(ctap.connector("udp")) # Store leaves if not node.children: leaves.append((node, node1)) self.add_net_monitor(pl, node1) self.add_vlc_dumper(pl, node1) self.add_vlc_restreamer(pl, node1) #if not parent: # taplabels = [ # t.get_attribute_value("label") # for t in tap1[1:] # ] # self.add_vlc_source(pl, node1, taplabels) return tap1[0] roottap = maketree(maketree, root) vnet_i = int(ipaddr.IPAddress(self.vnet)) ## NS3 ## pl_ns_root = exp.get_element_by_label("ns_root") pl_ns_root_iface = exp.get_element_by_label("ns_rootiface") ns = self.make_ns_in_pl(pl, exp, pl_ns_root, pl_ns_root_iface, "ns3") wifi_chan = self.add_ns_wifi_channel(ns) # AP node ap_node = self.add_ns_node(ns) self.add_ns_constant_mobility(ns, ap_node, 0, 0, 0) ap_wifi, ap_phy = self.add_ns_wifi_dev(ns, ap_node, access_point = True) ap_phy.connector("chan").connect(wifi_chan.connector("phys")) # Net range free for WiFi wifi_net_prefix = 32-int(math.floor(math.log(256-nextip[0]&0xff) / math.log(2))) wifi_net = vnet_i | (256 - (1<<(32-wifi_net_prefix))) # connect AP to PL pl_addr = str(ipaddr.IPAddress(wifi_net | 1)) ns_addr = str(ipaddr.IPAddress(wifi_net | 2)) self.add_pl_ns_connection( pl, pl_ns_root, pl_addr, ns, ap_node, ns_addr, fd = True, ptp = True, prefix=30) # AP ip ap_addr = str(ipaddr.IPAddress(vnet_i | 254)) ap_addr_prefix = 32-int(math.ceil(math.log(self.nsta+3) / math.log(2))) self.add_ip_address(ap_wifi, ap_addr, ap_addr_prefix) # route for PL->wifi self.add_route(pl_ns_root, str(ipaddr.IPAddress(wifi_net)), wifi_net_prefix, ns_addr) print "NS-3 AP\t%s/%s <--> PL AP %s" % (ns_addr, 30, pl_addr) print " | (|) %s/%s" % (ap_addr, ap_addr_prefix) print " |" print " | R %s/%d --> %s" % (str(ipaddr.IPAddress(wifi_net)), wifi_net_prefix, ns_addr) nextpip = (vnet_i | 255) >> (32-ap_addr_prefix) << (32-ap_addr_prefix) nextdip = vnet_i | 253 ap_net = nextpip - (1<<(32-ap_addr_prefix)) r = 50 # STA nodes for i in xrange(self.nsta): stai = self.add_ns_node(ns) angi = (360/self.nsta)*i xi = r*math.cos(angi) yi = r*math.sin(angi) self.add_ns_constant_mobility(ns, stai, xi, yi, 0) wifi, phy = self.add_ns_wifi_dev(ns, stai, access_point = False) phy.connector("chan").connect(wifi_chan.connector("phys")) wifi_addr = str(ipaddr.IPAddress(vnet_i | nextdip)) nextdip -= 1 nextpip -= 4 while nextpip & 3: nextpip -= 1 plns_net_i = nextpip plns_net = str(ipaddr.IPAddress(plns_net_i)) pl_addr2 = str(ipaddr.IPAddress(plns_net_i | 1)) ns_addr2 = str(ipaddr.IPAddress(plns_net_i | 2)) # route from AP (after others) print " | R %s/%s -> %s" % ( plns_net,30,ns_addr2 ) self.add_route(ap_node, plns_net, 30, wifi_addr) print " +---\t(|) %16s/%s" % (wifi_addr,ap_addr_prefix) print " | %16s (ns3) <---> (pl) %16s/30" % (ns_addr2, pl_addr2) print " |\t \t\t <-- R %s/24" % (self.vnet, ) print " |\t \t R %s/30 -> %s" % (plns_net, pl_addr2) print " |\t \t R %s <-- %s/24" % (ap_addr, plns_net) self.add_ip_address(wifi, wifi_addr, ap_addr_prefix) self.add_route(stai, plns_net, 30, pl_addr2) self.add_route(stai, self.vnet, 24, ap_addr) pl_nodei, _, pl_ifacei, _, _ = self.make_pl_tapnode(pl, [], inet, routes = [(self.vnet, 24, ns_addr2)], mcast = False, label = "ns_plnode_%d" % (i+1,) ) self.add_pl_ns_connection( pl, pl_nodei, pl_addr2, ns, stai, ns_addr2, prefix = 30) self.add_vlc_dumper(pl, pl_nodei, hostname = pl_addr, labelprefix = "vlc_dumper_ns", precmd = "sleep 15 ; ") # Validate (post-fact to let the user see the diagram above) if nextpip < wifi_net: raise RuntimeError, "Not enough IPs for wifi section" # route back to PL (after others) print " | R %s/%s -> %s" % ( self.vnet,24,pl_addr ) self.add_route(ap_node, self.vnet, 24, pl_addr) ## NETNS ## netns_addr = str(ipaddr.IPAddress(vnet_i | 1)) root1 = exp.get_element_by_label("root") netns = self.make_netns_testbed(exp) netns_node = self.add_netns_node(netns) netns_term = self.add_netns_app(netns, "xterm", netns_node) if self.movie_source: cmd = ( "vlc -I dummy " +os.path.abspath(self.movie_source) +" --sout '#std{access=udp{ttl=64,miface-addr="+netns_addr+"},dst=239.255.12.42,mux=ts}'" ) else: cmd = self.movie_command % { "dst" : "std{access=udp{ttl=64,miface-addr="+netns_addr+"},dst=239.255.12.42,mux=ts}" } netns_vlc = self.add_netns_app(netns, cmd, netns_node) # connection PL1/NETNS self.add_pl_netns_connection( roottap, netns, netns_node, netns_addr, 24, taplabel="netns_source") self.add_route(netns_node, "0.0.0.0", 0, str(ipaddr.IPAddress(root.vif_addr)) ) # pick random hostname to stream from interactive_source_host = random.sample(leaves,1)[0][0].hostname xml = exp.to_xml() test_dir = "./results" #sys.exit(1) try: controller = ExperimentController(xml, self.root_dir) controller.start() # launch vlc client to monitor activity time.sleep(5) proc = subprocess.Popen([ "vlc", "-I", "dummy", "http://%s:8080" % (interactive_source_host,)]) print >>sys.stderr, "Close xterm to shut down or Ctrl+C" try: while not controller.is_finished(netns_term.guid): time.sleep(5) except KeyboardInterrupt: # ping netns try: controller.traces_info() except: pass try: controller.traces_info() except: pass # kill streamer os.kill(proc.pid, signal.SIGTERM) # download results traces_info = controller.traces_info() for progress, (testbed_guid, guids) in enumerate(traces_info.iteritems()): for subprogress, (guid, traces) in enumerate(guids.iteritems()): for name, data in traces.iteritems(): path = data["filepath"] elem = exp.get_element(guid) if elem is not None: label = elem.get_attribute_value("label") if label is not None: path = "%s-%s" % (label,path) if not path: continue print >>sys.stderr, ("%.2f%% Downloading trace" % (progress + (subprogress * 1.0 / len(guids)) * 100.0 / len(traces_info))), path filepath = os.path.join(test_dir, path) try: trace = controller.trace(guid, name) except: traceback.print_exc(file=sys.stderr) continue try: if not os.path.exists(os.path.dirname(filepath)): os.makedirs(os.path.dirname(filepath)) except: traceback.print_exc(file=sys.stderr) try: if len(trace) >= 2**20: # Bigger than 1M, compress tracefile = gzip.GzipFile(filepath+".gz", "wb") else: tracefile = open(filepath,"wb") try: tracefile.write(trace) finally: tracefile.close() except: traceback.print_exc(file=sys.stderr) finally: try: controller.stop() except: traceback.print_exc() try: controller.shutdown() except: traceback.print_exc()