Index: fedd/deter/topdl.py
===================================================================
--- fedd/deter/topdl.py	(revision 94a6661c11a455b028b72f90dbdd891354e59775)
+++ fedd/deter/topdl.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
@@ -250,4 +250,15 @@
 	return rv
 
+    def __getstate__(self):
+	d = self.__dict__.copy()
+	del d['interfaces']
+	return d
+
+    def __setstate__(self, d):
+	# Import everything from the pickle dict (except what we excluded in
+	# __getstate__)
+	self.__dict__.update(d)
+	self.interfaces = []
+
 class CPU(base):
     def __init__(self, type, attribute=[]):
@@ -417,4 +428,15 @@
 		    for a in self.attribute], "")
 	return rv
+
+    def __getstate__(self):
+	d = self.__dict__.copy()
+	del d['subs']
+	return d
+
+    def __setstate__(self, d):
+	# Import everything from the pickle dict (except what we excluded in
+	# __getstate__)
+	self.__dict__.update(d)
+	self.subs = []
 
 
@@ -813,4 +835,10 @@
 	return rv
 
+    def __setstate__(self, d):
+	# Import everything from the pickle dict and call incorporate to
+	# connect them.
+	self.__dict__.update(d)
+	self.incorporate_elements()
+
 
 def topology_from_xml(string=None, file=None, filename=None, top="topology"):
@@ -891,5 +919,5 @@
 	xp.ParseFile(file)
     elif string:
-	xp.Parse(string, isfinal=True)
+	xp.Parse(string, True)
     else:
 	return None
Index: fedd/federation/benito_access.py
===================================================================
--- fedd/federation/benito_access.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
+++ fedd/federation/benito_access.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
@@ -0,0 +1,96 @@
+#!/usr/local/bin/python
+
+import os,sys
+import stat # for chmod constants
+import re
+import random
+import string
+import copy
+import pickle
+import logging
+import subprocess
+import traceback
+
+from threading import *
+from M2Crypto.SSL import SSLError
+
+from emulab_access import access as emulab_access
+
+from util import *
+from deter import fedid, generate_fedid
+from authorizer import authorizer, abac_authorizer
+from service_error import service_error
+from remote_service import xmlrpc_handler, soap_handler, service_caller
+from proof import proof as access_proof
+
+import httplib
+import tempfile
+from urlparse import urlparse
+
+from deter import topdl
+import list_log
+import benito_segment
+
+
+# Make log messages disappear if noone configures a fedd logger
+class nullHandler(logging.Handler):
+    def emit(self, record): pass
+
+fl = logging.getLogger("fedd.access")
+fl.addHandler(nullHandler())
+
+class access(emulab_access):
+    """
+    The implementation of access control based on mapping users to projects.
+
+    Users can be mapped to existing projects or have projects created
+    dynamically.  This implements both direct requests and proxies.
+    """
+
+    max_name_len = 19
+
+    def __init__(self, config=None, auth=None):
+        """
+        Initializer.  Pulls parameters out of the ConfigParser's access section.
+        """
+	emulab_access.__init__(self, config, auth)
+
+	# Segment creation is where most of the differences are.
+	self.start_segment = benito_segment.start_segment
+	self.stop_segment = benito_segment.stop_segment
+	self.info_segment = benito_segment.info_segment
+
+    # These are subroutines for StartSegment
+    def generate_ns2(self, topo, expfn, softdir, connInfo):
+	"""
+	Benito is expecting a topdl file, so this routine is misnamed.  It does
+	clean up the topdl, removing elements benito doesn't understand and
+	writing out the file.
+	"""
+	# Main line of generate_ns2
+	t = topo.clone()
+
+	# Weed out the things we aren't going to instantiate: Segments, portal
+	# substrates, and portal interfaces.  (The copy in the for loop allows
+	# us to delete from e.elements in side the for loop).  While we're
+	# touching all the elements, we also adjust paths from the original
+	# testbed to local testbed paths 
+	for e in [e for e in t.elements]:
+	    if isinstance(e, topdl.Segment):
+		t.elements.remove(e)
+	    # Fix software paths
+	    for s in getattr(e, 'software', []):
+		s.location = re.sub("^.*/", softdir, s.location)
+
+	t.substrates = [ s.clone() for s in t.substrates ]
+	t.incorporate_elements()
+
+	# Convert to ns and write it out
+	expfile = topdl.topology_to_xml(t, top='experiment')
+	try:
+	    f = open(expfn, "w")
+	    print >>f, expfile
+	    f.close()
+	except EnvironmentError:
+	    raise service_error(service_error.internal,
+		    "Cannot write experiment file %s: %s" % (expfn,e))
Index: fedd/federation/benito_segment.py
===================================================================
--- fedd/federation/benito_segment.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
+++ fedd/federation/benito_segment.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
@@ -0,0 +1,195 @@
+#!/usr/local/bin/python
+
+import sys, os
+import re
+import os.path
+
+import tempfile
+import subprocess
+import logging 
+import time
+import signal
+
+import util
+
+from deter import topdl
+
+from ssh_emulab_segment import ssh_emulab_segment
+from xmlrpc_emulab_segment import xmlrpc_emulab_segment
+
+
+class start_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None,
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+	self.start_mixed = '/share/benito/start_mixed %s %s %s'
+	self.start_qemu =  '/share/benito/start_qemu %s %s %s'
+
+    def get_mapping(self, pid, eid):
+	"""
+	Benito's info reporting is not sufficient to support this yet
+	"""
+	pass
+
+    def set_up_experiment_filespace(self, user, host, pid, eid, tmpdir):
+	"""
+	Send all the software and configuration files into the experiment's
+	file space.  To reduce the number of ssh connections, we script many
+	changes and execute the script.
+	"""
+	# Configuration directories on the remote machine
+	proj_dir = "/proj/%s/exp/%s/tmp" % (pid, eid)
+	softdir = "/proj/%s/software/%s" % (pid, eid)
+	# Local software dir
+	lsoftdir = "%s/software" % tmpdir
+
+	# Open up a temporary file to contain a script for setting up the
+	# filespace for the new experiment.
+	self.log.info("[start_segment]: creating script file")
+	try:
+	    sf, scriptname = tempfile.mkstemp()
+	    scriptfile = os.fdopen(sf, 'w')
+	except EnvironmentError:
+	    return False
+
+	scriptbase = os.path.basename(scriptname)
+
+	# Script the filesystem changes
+	print >>scriptfile, "/bin/rm -rf %s" % proj_dir
+	# Clear and create the software directory
+	print >>scriptfile, "/bin/rm -rf %s/*" % softdir
+	print >>scriptfile, 'mkdir -p %s' % proj_dir
+	if os.path.isdir(lsoftdir):
+	    print >>scriptfile, 'mkdir -p %s' % softdir
+	print >>scriptfile, "rm -f %s" % scriptbase
+	scriptfile.close()
+
+	# Move the script to the remote machine
+	# XXX: could collide tempfile names on the remote host
+	if self.scp_file(scriptname, user, host, scriptbase):
+	    os.remove(scriptname)
+	else:
+	    return False
+
+	# Execute the script (and the script's last line deletes it)
+	if not self.ssh_cmd(user, host, "sh -x %s" % scriptbase):
+	    return False
+
+	for f in os.listdir(tmpdir):
+	    if not os.path.isdir("%s/%s" % (tmpdir, f)):
+		if not self.scp_file("%s/%s" % (tmpdir, f), user, host,
+			"%s/%s" % (proj_dir, f)):
+		    return False
+	if os.path.isdir(lsoftdir):
+	    for f in os.listdir(lsoftdir):
+		if not os.path.isdir("%s/%s" % (lsoftdir, f)):
+		    if not self.scp_file("%s/%s" % (lsoftdir, f), 
+			    user, host, "%s/%s" % (softdir, f)):
+			return False
+	return True
+
+
+    def __call__(self, parent, eid, pid, user, tclfile, tmpdir, timeout=0, 
+	    gid=None):
+	"""
+	Start a sub-experiment on a federant.
+
+	Get the current state, and terminate the experiment if it exists. The
+	group membership of the experiment is difficult to determine or change,
+	so start with a clean slate.  Create a new one and ship data
+	and configs and start the experiment.  There are small ordering
+	differences based on the initial state of the sub-experiment.
+	"""
+
+	# benito listens to the filename extension.  tclfile here is really
+	# topdl, but we'll move it to a different filename.
+	if tclfile.endswith('.tcl'):
+	    topdlfile = os.path.join(tmpdir, 'experiment.xml')
+	    os.rename(tclfile, topdlfile)
+	else:
+	    topdlfile = tclfile
+
+
+	state = self.get_state(pid, eid)
+
+	if state != 'none':
+	    self.terminate_exp(pid, eid)
+
+	top = topdl.topology_from_xml(filename=topdlfile, top='experiment')
+	embedded = False
+	for e in top.elements:
+	    if isinstance(e, topdl.Computer) and \
+		    e.get_attribute('partition') is not None:
+		embedded = True
+		break
+	# on the for
+	else:
+	    embedded = False
+
+	if embedded:
+	    cmd = self.start_mixed  %  (pid, eid, topdlfile)
+	else:
+	    cmd = self.start_qemu % (pid, eid, topdlfile, 20)
+
+	if not self.ssh_cmd(user, self.ops, cmd):
+	    self.log.error("Cannot create benito experiment")
+	    return False
+
+	if not self.swap_exp(pid, eid, 'in'):
+	    self.log.error("swap in failed")
+	    return False
+	# Everything has gone OK.
+	self.get_mapping(pid,eid)
+	return True
+
+class stop_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+
+    def __call__(self, parent, user, pid, eid, gid=None, terminate=False):
+	"""
+	Stop a sub experiment by calling swapexp on the federant
+	"""
+
+	self.log.info("[stop_segment]: Stopping %s" % eid)
+	rv = False
+	try:
+	    # Clean out tar files: we've gone over quota in the past
+	    self.ssh_cmd(user, self.ops, 
+		    "rm -rf /proj/%s/software/%s" % (pid, eid))
+	    rv = self.swap_exp(pid, eid, 'out')
+	    if terminate:
+		rv = self.terminate_exp(pid, eid)
+	except self.cmd_timeout:
+	    rv = False
+	return rv
+
+class info_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+
+    def get_mapping(self, pid, eid):
+	"""
+	Benito's info reporting is not sufficient to support this yet
+	"""
+	pass
+
+    def __call__(self, parent, user, pid, eid):
+	self.log.info("[info_segment]: Getting info from %s" % eid)
+	self.get_mapping(pid,eid)
+	return True
+
+class operation_segment(ssh_emulab_segment, xmlrpc_emulab_segment):
+    def __init__(self, log=None, keyfile=None, debug=False, boss=None, 
+	    ops=None, cert=None):
+	ssh_emulab_segment.__init__(self, log=log, keyfile=keyfile, debug=debug)
+	xmlrpc_emulab_segment.__init__(self, boss=boss, ops=ops, cert=cert)
+
+    def __call__(self, parent, op, targets, param, top):
+	self.status.append('operations not yet supported')
+	return True
Index: fedd/federation/deter_impl.py
===================================================================
--- fedd/federation/deter_impl.py	(revision 94a6661c11a455b028b72f90dbdd891354e59775)
+++ fedd/federation/deter_impl.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
@@ -7,4 +7,5 @@
 import protogeni_access
 import deter_internal_access
+import benito_access
 import skeleton_access
 
@@ -86,4 +87,6 @@
 		    self.access = deter_internal_access.access(config,
 			    self.auth)
+		if self.access_type == "benito":
+		    self.access = benito_access.access(config, self.auth)
 		elif self.access_type == "skel":
 		    self.access = skeleton_access.access(config, self.auth)
Index: fedd/federation/experiment_control.py
===================================================================
--- fedd/federation/experiment_control.py	(revision 94a6661c11a455b028b72f90dbdd891354e59775)
+++ fedd/federation/experiment_control.py	(revision 6a50b78172df7385895b43b3da46f5b4447e4d50)
@@ -2038,5 +2038,5 @@
 		try:
 		    vis = self.genviz(
-			    topdl.topology_to_vtopo(self.state[key].topo))
+			    topdl.topology_to_vtopo(self.state[key].top))
 		except service_error, e:
 		    self.state_lock.release()
@@ -2297,5 +2297,5 @@
         if key in self.state:
 	    if force or self.state[key].older_than(self.info_cache_limit):
-		top = self.state[key].top 
+		top = self.state[key].top
 		if top is not None: top = top.clone()
 		d1, info_params, cert, d2 = \
@@ -2368,5 +2368,5 @@
 	    # Copy the topo if we need legacy annotations
 	    if legacy:
-		top = self.state[key].top 
+		top = self.state[key].top
 		if top is not None: top = top.clone()
         self.state_lock.release()
