Index: fedd/fedd_create.py
===================================================================
--- fedd/fedd_create.py	(revision ba07149039647bdd0a7aaaa0c83f4d0ee65abc4c)
+++ fedd/fedd_create.py	(revision c259a77478513f42034b6a889604796363902099)
@@ -17,5 +17,6 @@
 from federation.client_lib import client_opts, exit_with_fault, RPCException, \
 	wrangle_standard_options, do_rpc, get_experiment_names, save_certfile,\
-	get_abac_certs, log_authentication
+	get_abac_certs, log_authentication, parse_service,\
+	service_dict_to_line, ns_service_re, extract_services_from_xml
 from federation.util import abac_split_cert, abac_context_to_creds
 
@@ -58,35 +59,4 @@
 	self.set_defaults(delegate=True)
 
-def parse_service(svc):
-    """
-    Pasre a service entry into a hash representing a service entry in a
-    message.  The format is:
-	svc_name:exporter(s):importer(s):attr=val,attr=val
-    The svc_name is teh service name, exporter is the exporting testbeds
-    (comma-separated) importer is the importing testbeds (if any) and the rest
-    are attr=val pairs that will become attributes of the service.  These
-    include parameters and other such stuff.
-    """
-
-    terms = svc.split(':')
-    svcd = { }
-    if len(terms) < 2 or len(terms[0]) == 0 or len(terms[1]) == 0:
-	sys.exit("Bad service description '%s': Not enough terms" % svc)
-    
-    svcd['name'] = terms[0]
-    svcd['export'] = terms[1].split(",")
-    if len(terms) > 2 and len(terms[2]) > 0:
-	svcd['import'] = terms[2].split(",")
-    if len(terms) > 3 and len(terms[3]) > 0:
-	svcd['fedAttr'] = [ ]
-	for t in terms[3].split(";"):
-	    i = t.find("=")
-	    if i != -1 :
-		svcd['fedAttr'].append(
-			{'attribute': t[0:i], 'value': t[i+1:]})
-	    else:
-		sys.exit("Bad service attribute '%s': no equals sign" % t)
-    return svcd
-
 def project_export_service(master, project):
     """
@@ -156,5 +126,4 @@
 
 # Main line
-service_re = re.compile('^\\s*#\\s*SERVICE:\\s*([\\S]+)')
 parser = fedd_create_opts()
 (opts, args) = parser.parse_args()
@@ -173,4 +142,6 @@
     try:
 	top = topdl.topology_from_xml(filename=opts.file, top='experiment')
+	# Pull any service descriptions from the file as well
+	svcs = extract_services_from_xml(filename=opts.file)
     except EnvironmentError:
 	# Can't read the file, fail now
@@ -186,6 +157,6 @@
 	    # Parse all the strings that we can pull out of the file using the
 	    # service_re.
-	    svcs.extend([parse_service(service_re.match(l).group(1)) \
-		    for l in lines if service_re.match(l)])
+	    svcs.extend([parse_service(ns_service_re.match(l).group(1)) \
+		    for l in lines if ns_service_re.match(l)])
 	except EnvironmentError:
 	    sys.exit("Cannot read description file (%s)" %opts.file)
Index: fedd/fedd_ns2topdl.py
===================================================================
--- fedd/fedd_ns2topdl.py	(revision ba07149039647bdd0a7aaaa0c83f4d0ee65abc4c)
+++ fedd/fedd_ns2topdl.py	(revision c259a77478513f42034b6a889604796363902099)
@@ -8,5 +8,6 @@
 from federation.remote_service import service_caller
 from federation.client_lib import client_opts, exit_with_fault, RPCException, \
-	wrangle_standard_options, do_rpc, get_experiment_names, save_certfile
+	wrangle_standard_options, do_rpc, get_experiment_names, save_certfile,\
+	ns_service_re
 
 class ns_topdl_opts(client_opts):
@@ -26,8 +27,12 @@
 except RuntimeError, e:
     sys.exit("%s" %e)
-
+svcs = []
+contents = ''
 if opts.file:
     try:
-	contents = "".join([l for l in open(opts.file, "r")])
+	for l in open(opts.file, 'r'):
+	    contents += l
+	    if  ns_service_re.match(l):
+		svcs.append('SERVICE: %s' % ns_service_re.match(l).group(1))
     except EnvironmentError, e:
 	sys.exit("Can't read %s: %s" % (opts.file, e))
@@ -62,7 +67,13 @@
     sys.exit("Bad response. %s" % e.message)
 
+if len(svcs) > 0 :
+    comments = '<!--\n%s\n-->' % '\n'.join(svcs)
+else:
+    comments = ''
+
 if opts.outfile:
     try:
 	f = open(opts.outfile, "w")
+	print >>f, comments
 	print >>f, topdl.topology_to_xml(top, top="experiment")
 	f.close()
@@ -70,4 +81,5 @@
 	sys.exit("Can't write to %s: %s" % (opts.outfile, e))
 else:
+    print comments
     print topdl.topology_to_xml(top, top="experiment")
 proof = proof.from_dict(resp_dict.get('proof', {}))
Index: fedd/federation/client_lib.py
===================================================================
--- fedd/federation/client_lib.py	(revision ba07149039647bdd0a7aaaa0c83f4d0ee65abc4c)
+++ fedd/federation/client_lib.py	(revision c259a77478513f42034b6a889604796363902099)
@@ -4,9 +4,10 @@
 import pwd
 import os
+import re
 import os.path
+import xml.parsers.expat
 
 from string import join
 from datetime import datetime
-
 
 from deter import fedid
@@ -137,4 +138,87 @@
     return rv
 
+ns_service_re = re.compile('^\\s*#\\s*SERVICE:\\s*([\\S]+)')
+xml_service_re = re.compile('SERVICE:\\s*([\\S]+)\\s*$')
+
+def parse_service(svc):
+    """
+    Pasre a service entry into a hash representing a service entry in a
+    message.  The format is:
+	svc_name:exporter(s):importer(s):attr=val,attr=val
+    The svc_name is the service name, exporter is the exporting testbeds
+    (comma-separated) importer is the importing testbeds (if any) and the rest
+    are attr=val pairs that will become attributes of the service.  These
+    include parameters and other such stuff.
+    """
+
+    terms = svc.split(':')
+    svcd = { }
+    if len(terms) < 2 or len(terms[0]) == 0 or len(terms[1]) == 0:
+	sys.exit("Bad service description '%s': Not enough terms" % svc)
+
+    svcd['name'] = terms[0]
+    svcd['export'] = terms[1].split(",")
+    if len(terms) > 2 and len(terms[2]) > 0:
+	svcd['import'] = terms[2].split(",")
+    if len(terms) > 3 and len(terms[3]) > 0:
+	svcd['fedAttr'] = [ ]
+	for t in terms[3].split(";"):
+	    i = t.find("=")
+	    if i != -1 :
+		svcd['fedAttr'].append(
+			{'attribute': t[0:i], 'value': t[i+1:]})
+	    else:
+		sys.exit("Bad service attribute '%s': no equals sign" % t)
+    return svcd
+
+def service_dict_to_line(d):
+    """
+    Convert a dict containing a service description into a colon separated
+    service description suitable for inclusion in a file or command line.
+    """
+
+    return 'SERVICE: %s' % (
+	    ':'.join([
+		d.get('name', ''),
+		','.join(d.get('export','')),
+		','.join(d.get('import','')),
+		','.join([
+		    '='.join((dd.get('attribute', ''), dd.get('value',''))) \
+			for dd in d.get('fedAttr', [])
+		])
+	    ]))
+
+def extract_services_from_xml(string=None, file=None, filename=None):
+    class parser:
+	def __init__(self):
+	    self.svcs = []
+	def comment_handler(self, data):
+	    for l in data.split('\n'):
+		if xml_service_re.match(l):
+		    self.svcs.append(
+			    parse_service(xml_service_re.match(l).group(1)))
+
+    p = parser()
+    xp = xml.parsers.expat.ParserCreate()
+
+    xp.CommentHandler = p.comment_handler
+
+    num_set = len([ x for x in (string, filename, file)\
+	    if x is not None ])
+
+    if num_set != 1:
+	raise RuntimeError("Exactly one one of file, filename and string " + \
+		"must be set")
+    elif filename:
+	f = open(filename, "r")
+	xp.ParseFile(f)
+	f.close()
+    elif file:
+	xp.ParseFile(file)
+    elif string:
+	xp.Parse(string, True)
+
+    return p.svcs
+
 def wrangle_standard_options(opts):
     """
