Index: fedd/federation/emulab_access.py
===================================================================
--- fedd/federation/emulab_access.py	(revision 8cab4c2ac9081127246fc22ca388f2d95738148a)
+++ fedd/federation/emulab_access.py	(revision 6527d607cd9b5804caf07156b1fed31996f9ad62)
@@ -771,4 +771,7 @@
 			    (info.node[e.name].pname, self.domain),),
 			    e.localname)
+			add_new(("%s%s" % 
+			    (info.node[e.name].lname, self.domain),),
+			    e.localname)
 			e.status = info.node[e.name].status
 			os = info.node[e.name].getOS()
@@ -780,4 +783,13 @@
 		    add_new(('testop1', 'testop2'), e.operation)
 		    i += 1
+
+	for s in t.substrates:
+	    if s.name in info.subs:
+		sub = info.subs[s.name]
+		if sub.cap is not None:
+		    s.capacity = topdl.Capacity(sub.cap, 'max')
+		if sub.delay is not None:
+		    s.delay = topdl.Latency(sub.delay, 'max')
+	# XXX interfaces
 
 
Index: fedd/federation/xmlrpc_emulab_segment.py
===================================================================
--- fedd/federation/xmlrpc_emulab_segment.py	(revision 8cab4c2ac9081127246fc22ca388f2d95738148a)
+++ fedd/federation/xmlrpc_emulab_segment.py	(revision 6527d607cd9b5804caf07156b1fed31996f9ad62)
@@ -19,8 +19,9 @@
 class xmlrpc_emulab_segment:
     class node_info:
-	def __init__(self, name, pname, status=None, osname=None, 
+	def __init__(self, name, pname, lname=None, status=None, osname=None, 
 		osversion=None, image=None):
 	    self.name = name
 	    self.pname = pname
+	    self.lname = lname
 	    self.status = status
 	    self.osname = osname
@@ -36,4 +37,24 @@
 	    return rv
 
+    class lan_info:
+	def __init__(self, name, cap=None, delay=None):
+	    self.name = name
+	    self.cap = cap
+	    self.delay = delay
+	def __repr__(self):
+	    return "%s %s %s" % (self.name, self.cap, self.delay)
+
+    class interface_info:
+	def __init__(self, name, node, sub, cap=None, delay=None):
+	    self.name = name
+	    self.node = node
+	    self.sub = sub
+	    self.cap = cap
+	    self.delay = delay
+	def __repr__(self):
+	    return "%s %s %s %s %s" % (self.name, self.node, self.sub, 
+		    self.cap, self.delay)
+
+
     def __init__(self, boss, ops, cert):
 	self.ctxt = fedd_ssl_context(my_cert=cert)
@@ -53,6 +74,10 @@
 	self.debug = getattr(self, 'debug', False)
 	self.node = { }
+	self.subs = { }
+	self.interfaces = { }
 	self.status = [ ]
 	self.node_info = xmlrpc_emulab_segment.node_info
+	self.lan_info = xmlrpc_emulab_segment.lan_info
+	self.interface_info = xmlrpc_emulab_segment.interface_info
 
     def emulab_call(self, method, params):
@@ -236,9 +261,53 @@
 	return oses
 
-    def get_mapping(self, pid, eid):
-	"""
-	Get the physical to virtual mapping from the expinfo command and save
-	it in the self.map member.
-	"""
+    def get_links(self, pid, eid):
+	params = {
+		'proj': pid,
+		'exp': eid,
+		'aspect': 'links'
+		}
+	code, links = self.emulab_call('experiment.info', params)
+	if code ==0:
+	    lans = { }
+	    # Links contains per-interface information about all the LANs in
+	    # the emulab experiment.  First construct the LANs, then look for
+	    # overrides.
+	    for i in links.values():
+		if i['name'] not in lans:
+		    lans[i['name']] = { 'cap': None, 'delay': None };
+		cap = max(i['bandwidth'], i['r_bandwidth'])
+		delay = max(i['delay'], i['r_delay'])
+		if delay == 0.0: delay = None
+		if lans[i['name']]['cap'] is None or \
+			cap > lans[i['name']]['cap']:
+		    lans[i['name']]['cap'] = cap
+
+		if (lans[i['name']]['delay'] is None and delay is not None) or \
+			delay > lans[i['name']]['delay']:
+		    lans[i['name']]['delay'] = delay
+
+	    for s, info in lans.items():
+		self.subs[s] = self.lan_info(s, info['cap'], info['delay'])
+
+	    # XXX: should deal better with r_delay != delay, etc
+	    for i in links.values():
+		li = self.subs[i['name']]
+		cap = max(i['bandwidth'], i['r_bandwidth'])
+		delay = max(i['delay'], i['r_delay'])
+		if delay == 0.0: delay = None
+		if cap != li.cap or delay != li.delay:
+		    node, dummy = i['member'].split(':', 1)
+		    self.interfaces[i['member']] = \
+			    self.interface_info(i['member'], node, i['name'], 
+				    cap, delay)
+
+	    if self.log:
+		self.log.info("Link mapping complete")
+	    return True
+	else:
+	    raise service_error(service_error.internal, 
+		    "Cannot get link mapping of segment:%s/%s" % (pid, eid))
+
+    def get_nodes(self, pid, eid):
 
 	ev_active = ('ISUP', 'ALWAYSUP' )
@@ -248,5 +317,51 @@
 	ev_terminating = ( 'SHUTDOWN' )
 
-
+	osidmap = self.get_osid_map()
+
+	params = {
+		'proj': pid,
+		'exp': eid,
+		'aspect': 'mapping'
+		}
+	code, nodes = self.emulab_call('experiment.info', params)
+	if code ==0:
+	    for k, v in nodes.items():
+		if v.get('erole', False) and 'pnode' in v:
+		    st = v.get('status', 'up')
+		    ev = v.get('eventstatus', 'ISUP')
+		    os = v.get('osid', None)
+		    lname = "%s.%s.%s" % (k, eid, pid)
+
+		    if st == 'up':
+			if ev in ev_active: st = 'active'
+			elif ev in ev_starting: st = 'starting'
+			elif ev in ev_terminating: st = 'terminating'
+			else: st = 'failed'
+		    else: st = 'failed'
+
+		    if os and os in osidmap:
+		       osname = osidmap[os].get('OS', None)
+		       osversion = osidmap[os].get('version', None)
+		       osimage = "%s/%s" % \
+			       ( osidmap[os].get('pid', ''), 
+				       osidmap[os].get('imageid', ''))
+		    else:
+			osname = osversion = osimage = None
+
+		    self.node[k] = self.node_info(k, v['pnode'], lname,
+			    st, osname, osversion, osimage)
+	    if self.log:
+		self.log.info("Node mapping complete")
+	    return True
+	else:
+	    raise service_error(service_error.internal,
+		    "Cannot get node mapping of segment:%s/%s" % (pid, eid))
+
+    def get_mapping(self, pid, eid):
+	"""
+	Get the physical to virtual mapping from the expinfo command and save
+	it in the self.map member.
+	"""
+	
 	if self.debug:
 	    if self.log:
@@ -256,44 +371,8 @@
 	    if self.log:
 		self.log.info("[get_mapping] Generating mapping")
-
-	    osidmap = self.get_osid_map()
-
-	    params = {
-		    'proj': pid,
-		    'exp': eid,
-		    'aspect': 'mapping'
-		    }
-	    code, nodes = self.emulab_call('experiment.info', params)
-	    if code ==0:
-		for k, v in nodes.items():
-		    if v.get('erole', False) and 'pnode' in v:
-			st = v.get('status', 'up')
-			ev = v.get('eventstatus', 'ISUP')
-			os = v.get('osid', None)
-
-			if st == 'up':
-			    if ev in ev_active: st = 'active'
-			    elif ev in ev_starting: st = 'starting'
-			    elif ev in ev_terminating: st = 'terminating'
-			    else: st = 'failed'
-			else: st = 'failed'
-
-			if os and os in osidmap:
-			   osname = osidmap[os].get('OS', None)
-			   osversion = osidmap[os].get('version', None)
-			   osimage = "%s/%s" % \
-				   ( osidmap[os].get('pid', ''), 
-					   osidmap[os].get('imageid', ''))
-			else:
-			    osname = osversion = osimage = None
-
-			self.node[k] = self.node_info(k, v['pnode'], st,
-				osname, osversion, osimage)
-		if self.log:
-		    self.log.info("Mapping complete")
-		return True
-	    else:
-		raise service_error(service_error.internal,
-			"Cannot get node mapping of segment:%s/%s" % (pid, eid))
+	    self.get_nodes(pid, eid)
+	    self.get_links(pid, eid)
+	    return True
+
     def get_initial_image(self, node, top):
 	for e in top.elements:
