Index: fedd/federation/dragon_access.py
===================================================================
--- fedd/federation/dragon_access.py	(revision 68bb551148f95486a80ce8bc60ac008308ff2079)
+++ fedd/federation/dragon_access.py	(revision fde165ce8c0772dfc75eae2e4d368e5263c414c9)
@@ -504,5 +504,5 @@
 	    if not ep:
 		raise service_error(service_error.req, 
-			"Missing DRAGON endpoint foe %s" % s.name)
+			"Missing DRAGON endpoint for %s" % s.id)
 	    v = s.get_attribute('vlans')
 	    vlans = None
@@ -669,5 +669,6 @@
 	    return gri, vlan_no
 	else:
-	    raise service_error(service_error.federant, "Cannot make reservation")
+	    raise service_error(service_error.federant, 
+		    "Cannot make reservation")
 
     def stop_segment(self, repo, gri, log=None):
Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 68bb551148f95486a80ce8bc60ac008308ff2079)
+++ fedd/federation/emulab_access.py	(revision fde165ce8c0772dfc75eae2e4d368e5263c414c9)
@@ -69,4 +69,5 @@
 	self.ssh_privkey_file = config.get("access","ssh_privkey_file")
 	self.create_debug = config.getboolean("access", "create_debug")
+	self.cleanup = not config.getboolean("access", "leave_tmpfiles")
 	self.access_type = config.get("access", "type")
 
@@ -915,4 +916,30 @@
 
     def generate_ns2(self, topo, expfn, softdir, master):
+	def dragon_commands(e):
+	    s = ""
+	    if isinstance(e, topdl.Computer):
+		for i in e.interface:
+		    vlan = i.get_attribute('dragon_vlan')
+		    if vlan:
+			type = i.get_attribute('dragon_type')
+			ip = i.get_attribute('ip4_address')
+			if type == 'link':
+			    s = ("tb-allow-external $%s dragonportal " + \
+				    "ip %s vlan %s\n") % \
+				    (topdl.to_tcl_name(e.name[0]), ip, vlan)
+			elif type == 'lan':
+			    s = ("tb-allow-external $%s dragonportal " + \
+				    "ip %s vlan %s usurp %s\n") % \
+				    (topdl.to_tcl_name(e.name[0]), ip, vlan,
+					i.substrate[0])
+			else:
+			    raise service_error(service_error_internal,
+				    "Unknown DRAGON type %s" % type)
+	    return s
+
+	def not_dragon(e):
+	    return all([not i.get_attribute('dragon_vlan') \
+		    for i in e.interface])
+
 	t = topo.clone()
 
@@ -925,7 +952,9 @@
 	    if isinstance(e, topdl.Computer):
 		e.interface = [i for i in e.interface \
-			if not i.get_attribute('portal')]
-	t.substrates = [ s for s in t.substrates \
-		if not s.get_attribute('portal')]
+			if not i.get_attribute('portal') or \
+			    i.get_attribute('dragon_vlan')]
+	t.substrates = [ s.clone() for s in t.substrates ]
+	#t.substrates = [ s for s in t.substrates \
+	#	if not s.get_attribute('portal')]
 	t.incorporate_elements()
 
@@ -941,7 +970,13 @@
 	else:cmdname = 'SlaveConnectorCmd'
 
+	if self.attrs.has_key('dragon'):
+	    add_filter = not_dragon
+	    filters.append(dragon_commands)
+	else:
+	    add_filter = None
+
 	if self.attrs.has_key(cmdname):
 	    filters.append(topdl.generate_portal_command_filter(
-		self.attrs.get(cmdname)))
+		self.attrs.get(cmdname), add_filter=add_filter))
 
 	if self.attrs.has_key('connectorImage'):
@@ -1086,12 +1121,15 @@
 	    err = e
 
-	self.log.debug("[StartSegment]: removing %s" % tmpdir)
         # Walk up tmpdir, deleting as we go
-        for path, dirs, files in os.walk(tmpdir, topdown=False):
-            for f in files:
-                os.remove(os.path.join(path, f))
-            for d in dirs:
-                os.rmdir(os.path.join(path, d))
-        os.rmdir(tmpdir)
+	if self.cleanup:
+	    self.log.debug("[StartSegment]: removing %s" % tmpdir)
+	    for path, dirs, files in os.walk(tmpdir, topdown=False):
+		for f in files:
+		    os.remove(os.path.join(path, f))
+		for d in dirs:
+		    os.rmdir(os.path.join(path, d))
+	    os.rmdir(tmpdir)
+	else:
+	    self.log.debug("[StartSegment]: not removing %s" % tmpdir)
 
 	if rv:
Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision 68bb551148f95486a80ce8bc60ac008308ff2079)
+++ fedd/federation/experiment_control.py	(revision fde165ce8c0772dfc75eae2e4d368e5263c414c9)
@@ -233,4 +233,6 @@
 
         self.debug = config.getboolean("experiment_control", "create_debug")
+	self.cleanup = not config.getboolean("experiment_control", 
+		"leave_tmpfiles")
         self.state_filename = config.get("experiment_control", 
                 "experiment_state")
@@ -816,46 +818,55 @@
                     "Access denied by %s (%s)" % (tb, uri))
 
-        e = r['emulab']
-        p = e['project']
-        tbparam[tb] = { 
-                "boss": e['boss'],
-                "host": e['ops'],
-                "domain": e['domain'],
-                "fs": e['fileServer'],
-                "eventserver": e['eventServer'],
-                "project": unpack_id(p['name']),
-                "emulab" : e,
-                "allocID" : r['allocID'],
-                }
-        # Make the testbed name be the label the user applied
-        p['testbed'] = {'localname': tb }
-
-        for u in p['user']:
-            role = u.get('role', None)
-            if role == 'experimentCreation':
-                tbparam[tb]['user'] = unpack_id(u['userID'])
-                break
-        else:
-            raise service_error(service_error.internal, 
-                    "No createExperimentUser from %s" %tb)
-
-        # Add attributes to barameter space.  We don't allow attributes to
-        # overlay any parameters already installed.
-        for a in e['fedAttr']:
-            try:
-                if a['attribute'] and isinstance(a['attribute'], basestring)\
-                        and not tbparam[tb].has_key(a['attribute'].lower()):
-                    tbparam[tb][a['attribute'].lower()] = a['value']
-            except KeyError:
-                self.log.error("Bad attribute in response: %s" % a)
+	if r.has_key('emulab'):
+	    e = r['emulab']
+	    p = e['project']
+	    tbparam[tb] = { 
+		    "boss": e['boss'],
+		    "host": e['ops'],
+		    "domain": e['domain'],
+		    "fs": e['fileServer'],
+		    "eventserver": e['eventServer'],
+		    "project": unpack_id(p['name']),
+		    "emulab" : e,
+		    "allocID" : r['allocID'],
+		    "uri": uri,
+		    }
+	    # Make the testbed name be the label the user applied
+	    p['testbed'] = {'localname': tb }
+
+	    for u in p['user']:
+		role = u.get('role', None)
+		if role == 'experimentCreation':
+		    tbparam[tb]['user'] = unpack_id(u['userID'])
+		    break
+	    else:
+		raise service_error(service_error.internal, 
+			"No createExperimentUser from %s" %tb)
+	    # Add attributes to parameter space.  We don't allow attributes to
+	    # overlay any parameters already installed.
+	    for a in e['fedAttr']:
+		try:
+		    if a['attribute'] and \
+			    isinstance(a['attribute'], basestring)\
+			    and not tbparam[tb].has_key(a['attribute'].lower()):
+			tbparam[tb][a['attribute'].lower()] = a['value']
+		except KeyError:
+		    self.log.error("Bad attribute in response: %s" % a)
+	else:
+	    tbparam[tb] = { 
+		"allocID" : r['allocID'],
+		"uri": uri,
+	    }
+
         
-    def release_access(self, tb, aid):
+    def release_access(self, tb, aid, uri=None):
         """
         Release access to testbed through fedd
         """
 
-        uri = self.tbmap.get(tb, None)
+	if not uri:
+	    uri = self.tbmap.get(tb, None)
         if not uri:
-            raise service_error(serice_error.server_config, 
+            raise service_error(service_error.server_config, 
                     "Unknown testbed: %s" % tb)
 
@@ -905,4 +916,5 @@
 	    self.testbed = testbed
 	    self.log_collector = log_collector
+	    self.response = None
 
 	def __call__(self, uri, aid, topo, master, attrs=None):
@@ -927,4 +939,5 @@
 			for line in  lval.splitlines(True):
 			    self.log_collector.write(line)
+		    self.response = r
 		else:
 		    raise service_error(service_error.internal, 
@@ -966,4 +979,13 @@
             tbparams, topo, tmpdir, alloc_log=None, log_collector=None, 
 	    attrs=None):
+	def get_vlan(r):
+	    if r.has_key('StartSegmentResponseBody'):
+		srb = r['StartSegmentResponseBody']
+		if srb.has_key('fedAttr'):
+		    for k, v in [ (a['attribute'], a['value']) \
+			    for a in srb['fedAttr']]:
+			if k == 'vlan': return v
+	    return None
+
         started = { }           # Testbeds where a sub-experiment started 
                                 # successfully
@@ -972,4 +994,9 @@
         fail_soft = False
 
+	slaves = [ k for k in allocated.keys() \
+		if k != master and not topo[k].get_attribute('transit')]
+	transit = [ k for k in allocated.keys() \
+		if topo[k].get_attribute('transit')]
+
         log = alloc_log or self.log
 
@@ -977,13 +1004,6 @@
         threads = [ ]
 
-        for tb in [ k for k in allocated.keys() if k != master]:
-            # Create and start a thread to start the segment, and save it to
-            # get the return value later
-            thread_pool.wait_for_slot()
-	    uri = self.tbmap.get(tb, None)
-	    if not uri:
-		raise service_error(service_error.internal, 
-			"Unknown testbed %s !?" % tb)
-
+	for tb in transit:
+	    uri = tbparams[tb]['uri']
 	    if tbparams[tb].has_key('allocID') and \
 		    tbparams[tb]['allocID'].has_key('fedid'):
@@ -993,24 +1013,86 @@
 			"No alloc id for testbed %s !?" % tb)
 
-            t  = self.pooled_thread(\
-                    target=self.start_segment(log=log, debug=self.debug,
-			testbed=tb, cert_file=self.cert_file,
-			cert_pwd=self.cert_pwd,
-			trusted_certs=self.trusted_certs,
-			caller=self.call_StartSegment,
-			log_collector=log_collector), 
-                    args=(uri, aid, topo[tb], False, attrs), name=tb,
-                    pdata=thread_pool, trace_file=self.trace_file)
-            threads.append(t)
-            t.start()
-
-        # Wait until all finish (keep pinging the log, though)
-	mins = 0
-	while not thread_pool.wait_for_all_done(60.0):
-	    mins += 1
-	    alloc_log.info("Waiting for sub threads (it has been %d mins)" \
-		    % mins)
-
-	thread_pool.clear()
+	    m = re.search('(\d+)', tb)
+	    if m:
+		to_repl = "unassigned%s" % m.group(1)
+	    else:
+		raise service_error(service_error.internal, 
+			"Bad dynamic allocation name")
+		break
+
+	    ss = self.start_segment(log=log, debug=self.debug, 
+		testbed=master, cert_file=self.cert_file, 
+		cert_pwd=self.cert_pwd, 
+		trusted_certs=self.trusted_certs,
+		caller=self.call_StartSegment,
+		log_collector=log_collector)
+	    t = self.pooled_thread(
+		    target=ss,
+		    args =(uri, aid, topo[tb], False, attrs),
+		    name=tb, pdata=thread_pool, trace_file=self.trace_file)
+	    threads.append(t)
+	    t.start()
+	    # Wait until the this transit node finishes (keep pinging the log,
+	    # though)
+
+	    mins = 0
+	    while not thread_pool.wait_for_all_done(60.0):
+		mins += 1
+		alloc_log.info("Waiting for master (it has been %d mins)" \
+			% mins)
+
+	    if t.rv:
+		vlan = get_vlan(ss.response)
+		if vlan is not None:
+		    for k, t in topo.items():
+			for e in t.elements:
+			    for i in e.interface:
+				vl = i.get_attribute('dragon_vlan')
+				if vl is not None and vl == to_repl:
+				    i.set_attribute('dragon_vlan', vlan)
+	    else:
+		break
+	    thread_pool.clear()
+
+
+        failed = [ t.getName() for t in threads if not t.rv ]
+
+	if len(failed) == 0:
+	    for tb in slaves:
+		# Create and start a thread to start the segment, and save it
+		# to get the return value later
+		thread_pool.wait_for_slot()
+		uri = self.tbmap.get(tb, None)
+		if not uri:
+		    raise service_error(service_error.internal, 
+			    "Unknown testbed %s !?" % tb)
+
+		if tbparams[tb].has_key('allocID') and \
+			tbparams[tb]['allocID'].has_key('fedid'):
+		    aid = tbparams[tb]['allocID']['fedid']
+		else:
+		    raise service_error(service_error.internal, 
+			    "No alloc id for testbed %s !?" % tb)
+
+		t  = self.pooled_thread(\
+			target=self.start_segment(log=log, debug=self.debug,
+			    testbed=tb, cert_file=self.cert_file,
+			    cert_pwd=self.cert_pwd,
+			    trusted_certs=self.trusted_certs,
+			    caller=self.call_StartSegment,
+			    log_collector=log_collector), 
+			args=(uri, aid, topo[tb], False, attrs), name=tb,
+			pdata=thread_pool, trace_file=self.trace_file)
+		threads.append(t)
+		t.start()
+
+	    # Wait until all finish (keep pinging the log, though)
+	    mins = 0
+	    while not thread_pool.wait_for_all_done(60.0):
+		mins += 1
+		alloc_log.info("Waiting for sub threads (it has been %d mins)" \
+			% mins)
+
+	    thread_pool.clear()
 
         # If none failed, start the master
@@ -1074,5 +1156,6 @@
                 # release the allocations
                 for tb in tbparams.keys():
-                    self.release_access(tb, tbparams[tb]['allocID'])
+                    self.release_access(tb, tbparams[tb]['allocID'],
+			    tbparams[tb].get('uri', None))
                 # Remove the placeholder
                 self.state_lock.acquire()
@@ -1086,13 +1169,16 @@
             log.info("[start_segment]: Experiment %s active" % eid)
 
-        log.debug("[start_experiment]: removing %s" % tmpdir)
 
         # Walk up tmpdir, deleting as we go
-        for path, dirs, files in os.walk(tmpdir, topdown=False):
-            for f in files:
-                os.remove(os.path.join(path, f))
-            for d in dirs:
-                os.rmdir(os.path.join(path, d))
-        os.rmdir(tmpdir)
+	if self.cleanup:
+	    log.debug("[start_experiment]: removing %s" % tmpdir)
+	    for path, dirs, files in os.walk(tmpdir, topdown=False):
+		for f in files:
+		    os.remove(os.path.join(path, f))
+		for d in dirs:
+		    os.rmdir(os.path.join(path, d))
+	    os.rmdir(tmpdir)
+	else:
+	    log.debug("[start_experiment]: not removing %s" % tmpdir)
 
         # Insert the experiment into our state and update the disk copy
@@ -1190,7 +1276,9 @@
     def allocate_ips_to_topo(self, top):
 	"""
-	Add an ip4_address attribute to all the hosts in teh topology, based on
+	Add an ip4_address attribute to all the hosts in the topology, based on
 	the shared substrates on which they sit.  An /etc/hosts file is also
-	created and returned as a list of hostfiles entries.
+	created and returned as a list of hostfiles entries.  We also return
+	the allocator, because we may need to allocate IPs to portals
+	(specifically DRAGON portals).
 	"""
 	subs = sorted(top.substrates, 
@@ -1230,5 +1318,5 @@
 		ifs[hname] += 1
 		base += 1
-	return hosts
+	return hosts, ips
 
     def get_access_to_testbeds(self, testbeds, user, access_user, 
@@ -1283,5 +1371,5 @@
 
     def new_portal_node(self, st, dt, tbparams, master, eid, myname, desthost,
-	    portal_type, portal_subst, subst=None, addr=None):
+	    portal_type, iface_desc=()):
 	sproject = tbparams[st].get('project', 'project')
 	dproject = tbparams[dt].get('project', 'project')
@@ -1298,26 +1386,16 @@
 	    active = ("%s" %(st > dt))
 
-	ifaces = [
-	    topdl.Interface(
-		substrate=portal_subst,
-		attribute=[
-		    topdl.Attribute(attribute='portal',
-			value='true')
-		    ]
-		),
-	    ]
-	if subst and addr:
-	    ifaces.append(
-		    topdl.Interface(
-			substrate=subst,
-			attribute=[ 
-			    topdl.Attribute(
-				attribute='ip4_address', 
-				value=addr,
-			    )
+	ifaces = [ ]
+	for sub, attrs in iface_desc:
+	    inf = topdl.Interface(
+		    substrate=sub,
+		    attribute=[
+			topdl.Attribute(
+			    attribute=n,
+			    value = v)
+			for n, v in attrs
 			]
-			))
-
-
+		    )
+	    ifaces.append(inf)
 	return topdl.Computer(
 		name=myname,
@@ -1340,5 +1418,5 @@
 			    ('active', "%s" % active),
 			    ('portal_type', portal_type), 
-			    ('startup', 'sudo -H /usr/local/federation/bin/fed-tun.pl -f /proj/%s/exp/%s/tmp/%s.%s.%s%s.gw.conf >& /tmp/bridge.log' % (sproject, eid, myname.lower(), eid.lower(), sproject.lower(), sdomain.lower())))
+			    ('startup', 'sudo -H /usr/local/federation/bin/fed-tun.pl >& /tmp/bridge.log'))
 		    ],
 		interface=ifaces,
@@ -1375,5 +1453,201 @@
 	return (tsubstrate, segment_element)
 
-    def add_portals(self, top, topo, eid, master, tbparams):
+    def new_dragon_topo(self, idx, sub, topo, tbs, tbparams):
+	if sub.capacity is None:
+	    raise service_error(service_error.internal,
+		    "Cannot DRAGON split substrate w/o capacity")
+	segs = [ ]
+	substr = topdl.Substrate(name="dragon%d" % idx, 
+		capacity=sub.capacity.clone(),
+		attribute=[ topdl.Attribute(attribute=n, value=v)
+		    for n, v, in (\
+			    ('vlan', 'unassigned%d' % idx),)])
+	for tb in tbs.keys():
+	    seg = topdl.Segment(
+		    id = tbparams[tb]['allocID'],
+		    type='emulab',
+		    uri = self.tbmap.get(tb, None),
+		    interface=[ 
+			topdl.Interface(
+			    substrate=substr.name),
+			],
+		    attribute=[ topdl.Attribute(
+			attribute='dragon_endpoint', value='true'),
+			]
+		    )
+	    if tbparams[tb].has_key('vlans'):
+		seg.set_attribute('vlans', tbparams[tb]['vlans'])
+	    segs.append(seg)
+
+	topo["dragon%d" %idx] = \
+		topdl.Topology(substrates=[substr], elements=segs,
+			attribute=[
+			    topdl.Attribute(attribute="transit", value='true'),
+			    topdl.Attribute(attribute="dynamic", value='true'),
+			    topdl.Attribute(attribute="testbed", value='dragon'),
+			    ]
+			)
+
+    def create_dragon_substrate(self, sub, topo, tbs, tbparams, master, eid):
+	"""
+	Add attribiutes to the various elements indicating that they are to be
+	dragon connected and create a dragon segment in tops to be
+	instantiated.
+	"""
+
+	def get_substrate_from_topo(name, t):
+	    for s in t.substrates:
+		if s.name == name: return s
+	    else: return None
+
+	dn = len([x for x in topo.keys() if x.startswith('dragon')])
+	elements = [ i.element for i in sub.interfaces ]
+	count = { }
+	for e in elements:
+	    tb = e.get_attribute('testbed')
+	    count[tb] = count.get(tb, 0) + 1
+
+	for tb in tbs.keys():
+	    s = get_substrate_from_topo(sub.name, topo[tb])
+	    if s:
+		for i in s.interfaces:
+		    i.set_attribute('dragon_vlan', 'unassigned%d' % dn)
+		    if count[tb] > 1: i.set_attribute('dragon_type', 'lan')
+		    else: i.set_attribute('dragon_type', 'link')
+	    else:
+		raise service_error(service_error.internal,
+			"No substrate %s in testbed %s" % (sub.name, tb))
+
+	self.new_dragon_topo(dn, sub, topo, tbs, tbparams)
+
+    def insert_internet_portals(self, sub, topo, tbs, tbparams, master, eid,
+	    segment_substrate, portals):
+	# More than one testbed is on this substrate.  Insert
+	# some portals into the subtopologies.  st == source testbed,
+	# dt == destination testbed.
+	for st in tbs.keys():
+	    if not segment_substrate.has_key(st):
+		segment_substrate[st] = { }
+	    if not portals.has_key(st): 
+		portals[st] = { }
+	    for dt in [ t for t in tbs.keys() if t != st]:
+		sproject = tbparams[st].get('project', 'project')
+		dproject = tbparams[dt].get('project', 'project')
+		mproject = tbparams[master].get('project', 'project')
+		sdomain = tbparams[st].get('domain', ".example.com")
+		ddomain = tbparams[dt].get('domain', ".example.com")
+		mdomain = tbparams[master].get('domain', '.example.com')
+		muser = tbparams[master].get('user', 'root')
+		smbshare = tbparams[master].get('smbshare', 'USERS')
+		aid = tbparams[dt]['allocID']['fedid']
+		if st == master or dt == master:
+		    active = ("%s" % (st == master))
+		else:
+		    active = ("%s" %(st > dt))
+		if not segment_substrate[st].has_key(dt):
+		    # Put a substrate and a segment for the connected
+		    # testbed in there.
+		    tsubstrate, segment_element = \
+			    self.new_portal_substrate(st, dt, eid, tbparams)
+		    segment_substrate[st][dt] = tsubstrate
+		    topo[st].substrates.append(tsubstrate)
+		    topo[st].elements.append(segment_element)
+
+		new_portal = False
+		if portals[st].has_key(dt):
+		    # There's a portal set up to go to this destination.
+		    # See if there's room to multiples this connection on
+		    # it.  If so, add an interface to the portal; if not,
+		    # set up to add a portal below.
+		    # [This little festival of braces is just a pop of the
+		    # last element in the list of portals between st and
+		    # dt.]
+		    portal = portals[st][dt][-1]
+		    mux = len([ i for i in portal.interface \
+			    if not i.get_attribute('portal')])
+		    if mux == self.muxmax:
+			new_portal = True
+			portal_type = "experiment"
+			myname = "%stunnel%d" % (dt, len(portals[st][dt]))
+			desthost = "%stunnel%d" % (st, len(portals[st][dt]))
+		    else:
+			new_i = topdl.Interface(
+				substrate=s.name,
+				attribute=[ 
+				    topdl.Attribute(
+					attribute='ip4_address', 
+					value=tbs[dt]
+				    )
+				])
+			portal.interface.append(new_i)
+		else:
+		    # First connection to this testbed, make an empty list
+		    # and set up to add the new portal below
+		    new_portal = True
+		    portals[st][dt] = [ ]
+		    myname = "%stunnel%d" % (dt, len(portals[st][dt]))
+		    desthost = "%stunnel%d" % (st, len(portals[st][dt]))
+
+		    if dt == master or st == master: portal_type = "both"
+		    else: portal_type = "experiment"
+
+		if new_portal:
+		    infs = (
+			    (segment_substrate[st][dt].name, 
+				(('portal', 'true'),)),
+			    (sub.name, 
+				(('ip4_address', tbs[dt]),))
+			)
+		    portal =  self.new_portal_node(st, dt, tbparams, 
+			    master, eid, myname, desthost, portal_type,
+			    infs)
+		    if self.fedkit:
+			self.add_kit(portal, self.fedkit)
+		    if self.gatewaykit: 
+			self.add_kit(portal, self.gatewaykit)
+
+		    topo[st].elements.append(portal)
+		    portals[st][dt].append(portal)
+
+    def add_control_portal(self, st, dt, master, eid, topo, tbparams):
+	# Add to the master testbed
+	tsubstrate, segment_element = \
+		self.new_portal_substrate(st, dt, eid, tbparams)
+	myname = "%stunnel" % dt
+	desthost = "%stunnel" % st
+
+	portal = self.new_portal_node(st, dt, tbparams, master,
+		eid, myname, desthost, "control", 
+		((tsubstrate.name,(('portal','true'),)),))
+	if self.fedkit:
+	    self.add_kit(portal, self.fedkit)
+	if self.gatewaykit: 
+	    self.add_kit(portal, self.gatewaykit)
+
+	topo[st].substrates.append(tsubstrate)
+	topo[st].elements.append(segment_element)
+	topo[st].elements.append(portal)
+
+    def new_dragon_portal(self, st, dt, master, eid, dip, idx, 
+	    substrate, tbparams):
+	# Add to the master testbed
+	myname = "%stunnel" % dt
+	desthost = "%s" % ip_addr(dip)
+
+	portal = self.new_portal_node(st, dt, tbparams, master,
+		eid, myname, desthost, "control", 
+		((substrate.name,(
+		    ('portal','true'),
+		    ('ip4_address', "%s" % ip_addr(dip)),
+		    ('dragon_vlan', 'unassigned%d' % idx),
+		    ('dragon_type', 'link'),)),))
+	if self.fedkit:
+	    self.add_kit(portal, self.fedkit)
+	if self.gatewaykit: 
+	    self.add_kit(portal, self.gatewaykit)
+
+	return portal
+
+    def add_portals(self, top, topo, eid, master, tbparams, ip_allocator):
 	"""
 	For each substrate in the main topology, find those that
@@ -1397,84 +1671,12 @@
 		continue
 
-	    # More than one testbed is on this substrate.  Insert
-	    # some portals into the subtopologies.  st == source testbed,
-	    # dt == destination testbed.
-	    for st in tbs.keys():
-		if not segment_substrate.has_key(st):
-		    segment_substrate[st] = { }
-		if not portals.has_key(st): 
-		    portals[st] = { }
-		for dt in [ t for t in tbs.keys() if t != st]:
-		    sproject = tbparams[st].get('project', 'project')
-		    dproject = tbparams[dt].get('project', 'project')
-		    mproject = tbparams[master].get('project', 'project')
-		    sdomain = tbparams[st].get('domain', ".example.com")
-		    ddomain = tbparams[dt].get('domain', ".example.com")
-		    mdomain = tbparams[master].get('domain', '.example.com')
-		    muser = tbparams[master].get('user', 'root')
-		    smbshare = tbparams[master].get('smbshare', 'USERS')
-		    aid = tbparams[dt]['allocID']['fedid']
-		    if st == master or dt == master:
-			active = ("%s" % (st == master))
-		    else:
-			active = ("%s" %(st > dt))
-		    if not segment_substrate[st].has_key(dt):
-			# Put a substrate and a segment for the connected
-			# testbed in there.
-			tsubstrate, segment_element = \
-				self.new_portal_substrate(st, dt, eid, tbparams)
-			segment_substrate[st][dt] = tsubstrate
-			topo[st].substrates.append(tsubstrate)
-			topo[st].elements.append(segment_element)
-
-		    new_portal = False
-		    if portals[st].has_key(dt):
-			# There's a portal set up to go to this destination.
-			# See if there's room to multiples this connection on
-			# it.  If so, add an interface to the portal; if not,
-			# set up to add a portal below.
-			# [This little festival of braces is just a pop of the
-			# last element in the list of portals between st and
-			# dt.]
-			portal = portals[st][dt][-1]
-			mux = len([ i for i in portal.interface \
-				if not i.get_attribute('portal')])
-			if mux == self.muxmax:
-			    new_portal = True
-			    portal_type = "experiment"
-			    myname = "%stunnel%d" % (dt, len(portals[st][dt]))
-			    desthost = "%stunnel%d" % (st, len(portals[st][dt]))
-			else:
-			    new_i = topdl.Interface(
-				    substrate=s.name,
-				    attribute=[ 
-					topdl.Attribute(
-					    attribute='ip4_address', 
-					    value=tbs[dt]
-					)
-				    ])
-			    portal.interface.append(new_i)
-		    else:
-			# First connection to this testbed, make an empty list
-			# and set up to add the new portal below
-			new_portal = True
-			portals[st][dt] = [ ]
-			myname = "%stunnel%d" % (dt, len(portals[st][dt]))
-			desthost = "%stunnel%d" % (st, len(portals[st][dt]))
-
-			if dt == master or st == master: portal_type = "both"
-			else: portal_type = "experiment"
-
-		    if new_portal:
-			portal =  self.new_portal_node(st, dt, tbparams, 
-				master, eid, myname, desthost, portal_type,
-				segment_substrate[st][dt].name, s.name, tbs[dt])
-			if self.fedkit:
-			    self.add_kit(portal, self.fedkit)
-			if self.gatewaykit: 
-			    self.add_kit(portal, self.gatewaykit)
-
-			topo[st].elements.append(portal)
-			portals[st][dt].append(portal)
+	    # DRAGON will not create multi-site vlans yet
+	    if len(tbs) == 2 and \
+		    all([tbparams[x].has_key('dragon') for x in tbs]):
+		self.create_dragon_substrate(s, topo, tbs, tbparams, 
+			master, eid)
+	    else:
+		self.insert_internet_portals(s, topo, tbs, tbparams, master,
+			eid, segment_substrate, portals)
 
 	# Make sure that all the slaves have a control portal back to the
@@ -1486,39 +1688,83 @@
 		    e.get_attribute('portal_type') == 'both']) == 0:
 
-		# Add to the master testbed
-		tsubstrate, segment_element = \
-			self.new_portal_substrate(master, tb, eid, tbparams)
-		myname = "%stunnel" % tb
-		desthost = "%stunnel" % master
-
-		portal = self.new_portal_node(master, tb, tbparams, master,
-			eid, myname, desthost, "control", tsubstrate.name)
-		if self.fedkit:
-		    self.add_kit(portal, self.fedkit)
-		if self.gatewaykit: 
-		    self.add_kit(portal, self.gatewaykit)
-
-		topo[master].substrates.append(tsubstrate)
-		topo[master].elements.append(segment_element)
-		topo[master].elements.append(portal)
-
-		# And to the other testbed
-
-		tsubstrate, segment_element = \
-			self.new_portal_substrate(tb, master, eid, tbparams)
-		myname = "%stunnel" % master
-		desthost = "%stunnel" % tb
-
-		portal = self.new_portal_node(tb, master, tbparams, master,
-			eid, myname, desthost, "control", tsubstrate.name)
-		if self.fedkit:
-		    self.add_kit(portal, self.fedkit)
-		if self.gatewaykit: 
-		    self.add_kit(portal, self.gatewaykit)
-
-		topo[tb].substrates.append(tsubstrate)
-		topo[tb].elements.append(segment_element)
-		topo[tb].elements.append(portal)
-
+		if tbparams[master].has_key('dragon') \
+			and tbparams[tb].has_key('dragon'):
+
+		    idx = len([x for x in topo.keys() \
+			    if x.startswith('dragon')])
+		    dip, leng = ip_allocator.allocate(4)
+		    dip += 1
+		    csub = topdl.Substrate(
+			    name="dragon-control-%s" % tb,
+			    capacity=topdl.Capacity(100000.0, 'max'),
+			    attribute=[
+				topdl.Attribute(
+				    attribute='portal',
+				    value='true'
+				    )
+				]
+			    )
+		    seg = topdl.Segment(
+			    id= tbparams[master]['allocID'],
+			    type='emulab',
+			    uri = self.tbmap.get(master, None),
+			    interface=[ 
+				topdl.Interface(
+				    substrate=csub.name),
+				],
+			    attribute = [
+				topdl.Attribute(attribute=n, value=v)
+				    for n, v in (\
+					('domain', 
+					    tbparams[master].get('domain',
+						".example.com")),
+					('experiment', "%s/%s" % \
+						(tbparams[master].get(
+						    'project', 
+						    'project'), 
+						    eid)),)
+				],
+			    )
+		    topo[tb].substrates.append(csub)
+		    topo[tb].elements.append(
+			    self.new_dragon_portal(tb, master, master, eid, 
+				dip, idx, csub, tbparams))
+		    topo[tb].elements.append(seg)
+
+		    dip+=1
+		    mcsub = csub.clone()
+		    seg = topdl.Segment(
+			    id= tbparams[tb]['allocID'],
+			    type='emulab',
+			    uri = self.tbmap.get(tb, None),
+			    interface=[ 
+				topdl.Interface(
+				    substrate=csub.name),
+				],
+			    attribute = [
+				topdl.Attribute(attribute=n, value=v)
+				    for n, v in (\
+					('domain', 
+					    tbparams[tb].get('domain',
+						".example.com")),
+					('experiment', "%s/%s" % \
+						(tbparams[tb].get('project', 
+						    'project'), 
+						    eid)),)
+				],
+			    )
+		    topo[master].substrates.append(mcsub)
+		    topo[master].elements.append(
+			    self.new_dragon_portal(master, tb, master, eid, 
+				dip, idx, mcsub, tbparams))
+		    topo[master].elements.append(seg)
+
+		    self.create_dragon_substrate(csub, topo, 
+			    {tb: 1, master:1}, tbparams, master, eid)
+		else:
+		    self.add_control_portal(master, tb, master, eid, topo, 
+			    tbparams)
+		    self.add_control_portal(tb, master, master, eid, topo, 
+			    tbparams)
 
 	# Connect the portal nodes into the topologies and clear out
@@ -1715,5 +1961,5 @@
 	    top = topdl.topology_from_xml(file=split_data, top="experiment")
 
-	    hosts = self.allocate_ips_to_topo(top)
+	    hosts, ip_allocator = self.allocate_ips_to_topo(top)
 	     # Find the testbeds to look up
             testbeds = set([ a.value for e in top.elements \
@@ -1759,5 +2005,20 @@
 		    self.auth.set_attribute(asignee, "%s/%s" % (configpath, f))
 
-	    self.add_portals(top, topo, eid, master, tbparams)
+	    self.add_portals(top, topo, eid, master, tbparams, ip_allocator)
+	    # Now get access to the dynamic testbeds
+	    for k, t in topo.items():
+		if not t.get_attribute('dynamic'):
+		    continue
+		tb = t.get_attribute('testbed')
+		if tb: 
+		    self.get_access(tb, None, user, tbparams, master, 
+			    export_project, access_user)
+		    tbparams[k] = tbparams[tb]
+		    del tbparams[tb]
+		    allocated[k] = 1
+		else:
+		    raise service_error(service_error.internal, 
+			    "Dynamic allocation from no testbed!?")
+
 	    self.wrangle_software(expid, top, topo, tbparams)
 
@@ -1769,8 +2030,10 @@
                 tbparams[k]['federant'] = {\
                         'name': [ { 'localname' : eid} ],\
-                        'emulab': tbparams[k]['emulab'],\
                         'allocID' : tbparams[k]['allocID'],\
                         'master' : k == master,\
                     }
+		if tbparams[k].has_key('emulab'):
+                        tbparams[k]['federant']['emulab'] = \
+				tbparams[k]['emulab']
 
             self.state_lock.acquire()
@@ -2019,7 +2282,8 @@
             if rv.has_key('federant'): del rv['federant']
         else:
-            # remove the allocationID info from each federant
+            # remove the allocationID and uri info from each federant
             for f in rv.get('federant', []):
                 if f.has_key('allocID'): del f['allocID']
+		if f.has_key('uri'): del f['uri']
         return rv
 
@@ -2156,5 +2420,5 @@
             for fed in fed_exp.get('federant', []):
                 try:
-                    tb = fed['emulab']['project']['testbed']['localname']
+                    tb = fed['uri']
                     aid = fed['allocID']
                 except KeyError, e:
Index: fedd/federation/topdl.py
===================================================================
--- fedd/federation/topdl.py	(revision 68bb551148f95486a80ce8bc60ac008308ff2079)
+++ fedd/federation/topdl.py	(revision fde165ce8c0772dfc75eae2e4d368e5263c414c9)
@@ -22,4 +22,14 @@
 	elif getattr(a, '__iter__', None): return a
 	else: return [ a ]
+
+    def remove_attribute(self, key):
+	to_del = None
+	attrs = getattr(self, 'attribute', [])
+	for i, a in enumerate(attrs):
+	    if a.attribute == key:
+		to_del = i
+		break
+	
+	if to_del: del attrs[i]
 
     def get_attribute(self, key):
@@ -384,9 +394,11 @@
 	    return e
 
-    def __init__(self, substrates=[], elements=[]):
+    def __init__(self, substrates=[], elements=[], attribute=[]):
 	self.substrates = [ self.init_class(Substrate, s) \
 		for s in self.make_list(substrates) ]
 	self.elements = [ self.init_element(e) \
 		for e in self.make_list(elements) ]
+	self.attribute = [ self.init_class(Attribute, c) \
+		for c in self.make_list(attribute) ]
 	self.incorporate_elements()
 
@@ -419,5 +431,6 @@
     def clone(self):
 	return Topology(substrates=[s.clone() for s in self.substrates], 
-		elements=[e.clone() for e in self.elements])
+		elements=[e.clone() for e in self.elements],
+		attribute=[a.clone() for a in self.attribute])
 
 
@@ -432,4 +445,6 @@
 	if self.elements:
 	    rv['elements'] = [ s.to_dict() for s in self.elements ]
+	if self.attribute:
+	    rv['attribute'] = [ s.to_dict() for s in self.attribute]
 	return rv
 
@@ -519,6 +534,8 @@
 
 	for k in e.keys():
-	    if isinstance(e[k], (basestring, int, float, long)):
+	    if isinstance(e[k], basestring):
 		rv += "<%s>%s</%s>" % (k, escape(e[k]), k)
+	    elif isinstance(e[k], (int, float, long)):
+		rv += "<%s>%d</%s>" % (k, e[k], k)
 	    elif isinstance(e[k], dict):
 		rv += "<%s>%s</%s>" % (k, dict_to_xml(e[k]), k)
@@ -530,5 +547,8 @@
 			rv += "<%s>%s</%s>" % (k, escape(ee), k)
 	    else:
-		raise ConsistencyError("What is this?? %s %s" % (k, e[k]))
+		try:
+		    rv += "<%s>%s</%s>" % (k, e[k], k)
+		except Exception:
+		    raise ConsistencyError("What is this?? %s %s" % (k, e[k]))
 	if top: rv += "</%s>" % top
 	return rv
@@ -582,10 +602,14 @@
     return t
 
-def generate_portal_command_filter(cmd):
+def generate_portal_command_filter(cmd, add_filter=None):
     def rv(e):
 	s =""
 	if isinstance(e, Computer):
 	    gw = e.get_attribute('portal')
-	    if gw:
+	    if add_filter and callable(add_filter):
+		add = add_filter(e)
+	    else:
+		add = True
+	    if gw and add:
 		s = "%s $%s\n" % (cmd, to_tcl_name(e.name[0]))
 	return s
