Beispiel #1
0
    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
Beispiel #2
0
    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()