parse_request_rspec.cc 25.4 KB
Newer Older
1 2
/*
 * EMULAB-COPYRIGHT
3
 * Copyright (c) 2008, 2009 University of Utah and the Flux Group.
4 5 6 7 8 9 10
 * All rights reserved.
 */

/*
 * XML Parser for RSpec ptop files
 */

11
static const char rcsid[] = "$Id: parse_request_rspec.cc,v 1.16 2009-10-21 20:49:26 tarunp Exp $";
12 13 14 15 16 17 18 19

#ifdef WITH_XML

#include "parse_request_rspec.h"
#include "xmlhelpers.h"
#include "parse_error_handler.h"

#include <fstream>
20
#include <sstream>
21
#include <sys/time.h>
22 23 24 25 26 27 28 29

#include "anneal.h"
#include "vclass.h"

#define XMLDEBUG(x) (cerr << x)
#define ISSWITCH(n) (n->types.find("switch") != n->types.end())

#ifdef TBROOT
30
	#define SCHEMA_LOCATION TBROOT"/lib/assign/request.xsd"
31
#else
32
	#define SCHEMA_LOCATION "request.xsd"
33 34 35 36 37 38 39 40 41 42
#endif
/*
 * XXX: Do I have to release lists when done with them?
 */

/*
 * XXX: Global: This is really bad!
 */
extern name_pvertex_map pname2vertex;

43
/* --- Have to include the vnode data structures as well --- */
44 45 46 47 48 49 50
extern name_vvertex_map vname2vertex;
extern name_name_map fixed_nodes;
extern name_name_map node_hints;
extern name_count_map vtypes;
extern name_list_map vclasses;
extern vvertex_vector virtual_nodes;
extern name_vclass_map vclass_map;
51
/* --- end of vtop stuff --- */
52 53 54 55

DOMElement* request_root = NULL;
DOMDocument* doc = NULL;

56 57
int rspec_version = -1;

58 59 60 61 62 63 64
int bind_ptop_subnodes(tb_pgraph &pg);
int bind_vtop_subnodes(tb_vgraph &vg);

/*
 * These are not meant to be used outside of this file, so they are only
 * declared in here
 */
65 66 67 68 69 70 71
bool populate_nodes_rspec(DOMElement *root, 
						  tb_vgraph &vg, 
		                  map< pair<string, string>,
		                       pair<string, string> >* fixed_interfaces);
bool populate_links_rspec(DOMElement *root, tb_vgraph &vg, 
						  map< pair<string, string>, 
							   pair<string, string> >* fixed_interfaces);
72
bool populate_vclasses_rspec (DOMElement *root, tb_vgraph &vg);
73 74
string generate_virtual_node_id (string virtual_id);
string generate_virtual_interface_id(string node_name, int interface_number);
75 76 77
DOMElement* appendChildTagWithData (DOMElement* parent, 
									const char*tag_name, 
		                            const char* child_value);
78

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
bool hasComponentSpec (DOMElement* element);

void populate_policies(DOMElement *root);

int parse_fds_xml (const DOMElement* tag, node_fd_set *fd_set);

int parse_vtop_rspec(tb_vgraph &vg, char *filename) {
    /* 
     * Fire up the XML parser
     */
    XMLPlatformUtils::Initialize();
    
    XercesDOMParser *parser = new XercesDOMParser;
    
    /*
     * Enable some of the features we'll be using: validation, namespaces, etc.
     */
    parser->setValidationScheme(XercesDOMParser::Val_Always);
    parser->setDoNamespaces(true);
    parser->setDoSchema(true);
    parser->setValidationSchemaFullChecking(true);
        
    /*
     * Must validate against the ptop schema
     */
104 105 106 107 108 109
	/* This is a problem
	 * We can only know the schema location if we know the rspec version
	 * But we only know the rspec version after it has been validated
	 * And we can only validate it if we know the schema location.
	 * Whoops!
	 */
110 111
    parser -> setExternalSchemaLocation
			("http://www.protogeni.net/resources/rspec/0.1 " SCHEMA_LOCATION);
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
    
    /*
     * Just use a custom error handler - must admin it's not clear to me why
     * we are supposed to use a SAX error handler for this, but this is what
     * the docs say....
     */    
    ParseErrorHandler* errHandler = new ParseErrorHandler();
    parser->setErrorHandler(errHandler);
    
    /*
     * Do the actual parse
     */
    parser->parse(filename);
    //XMLDEBUG("XML parse completed" << endl);
	    
    /* 
     * If there are any errors, do not go any further
     */
    if (errHandler->sawError()) {
131 132
        cerr << "There were " << parser -> getErrorCount () 
			 << " errors in your file. " << endl;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
        exit(EXIT_FATAL);
    }
    else {
        /*
        * Get the root of the document - we're going to be using the same root
        * for all subsequent calls
        */
        doc = parser->getDocument();
        request_root = doc->getDocumentElement();
        
        bool is_physical;
        XStr type (request_root->getAttribute(XStr("type").x()));
		if (strcmp(type.c(), "request") != 0)
		{
			cerr << "Error: RSpec type must be \"request\"" << endl;
			exit (EXIT_FATAL);
		}
        
151
        // NOTE: Not sure about datetimes. They are strings for now
152 153 154
        XStr generated (request_root->getAttribute(XStr("generated").x()));
        XStr valid_until(request_root->getAttribute(XStr("valid_until").x()));
        
155
		map< pair<string, string>, pair<string, string> > fixed_interfaces;
156 157
        
		/*
158 159 160 161
        * These three calls do the real work of populating the assign data
        * structures
        */
        XMLDEBUG("starting node population" << endl);
162
        if (!populate_nodes_rspec(request_root,vg, &fixed_interfaces)) {
163 164
			cerr << "Error reading nodes from virtual topology " 
				 << filename << endl;
165
			exit(EXIT_FATAL);
166 167
        }
        XMLDEBUG("finishing node population" << endl);
168
        
169
        XMLDEBUG("starting link population" << endl);
170
        if (!populate_links_rspec(request_root,vg, &fixed_interfaces)) {
171 172
			cerr << "Error reading links from virtual topology " 
				 << filename << endl;
173
			exit(EXIT_FATAL);
174 175
        }
        XMLDEBUG("finishing link population" << endl);
176
		
177 178 179 180 181 182 183 184 185 186 187 188 189
        /* TODO: We need to do something about policies at some point. */
		//populate_policies(root);
        
        cerr << "RSpec parsing finished" << endl; 
    }
    
    /*
    * All done, clean up memory
    */
//     XMLPlatformUtils::Terminate();
    return 0;
}

190 191 192 193
bool populate_node(DOMElement* elt, tb_vgraph &vg, map< pair<string,string>, pair<string,string> >* fixed_interfaces) 
{	
	string str_virtual_uuid = string("");
	if (elt->hasAttribute(XStr("virtual_id").x()))
194 195
		str_virtual_uuid = 
				string (XStr(elt->getAttribute(XStr("virtual_id").x())).c());
196
			
197 198
	XStr virtualization_type
			             (elt->getAttribute(XStr("virtualization_type").x()));
199
	bool available = hasChildTag (elt, "available");
200
        
201 202 203 204 205
	string str_aggregate_uuid = string("");
	string str_component_name = string("");
	string str_component_uuid = string("");
	string str_component_manager_uuid = string("");
	string str_sliver_uuid = string("");
206 207 208 209 210 211 212 213
	
	component_spec componentSpec = parse_component_spec(elt);
	str_component_manager_uuid = string(componentSpec.component_manager_uuid);
	str_component_name = string(componentSpec.component_name);
	str_component_uuid = string(componentSpec.component_uuid);
	str_sliver_uuid = string(componentSpec.sliver_uuid);
	// If a node has a component_uuid, it is a fixed node
	if (str_component_uuid != "")
214
		fixed_nodes [str_virtual_uuid] = str_component_uuid;	
215
		
216 217 218 219 220 221 222 223 224 225 226
	if (str_virtual_uuid == "")
	{
		cerr << "ERROR: Every node must have a virtual_id" << endl;
		return false;
	}

	DOMNodeList *interfaces = elt->getElementsByTagName(XStr("interface").x());
	string *str_interface_virtual_ids = new string [interfaces->getLength()];
	string *str_interface_component_ids = new string [interfaces->getLength()];
	for (int index = 0; index < interfaces->getLength(); ++index)
	{
227 228 229 230 231
		DOMElement* interface = 
				            dynamic_cast<DOMElement*>(interfaces->item(index));
		str_interface_virtual_ids[index] = 
									string(XStr(interface->getAttribute(
						                        XStr("virtual_id").x())).c());
232
		if (interface->hasAttribute(XStr("component_id").x()))
233
		{
234 235 236
			string component_id = 
					               string(XStr(interface->getAttribute
											(XStr("component_id").x())).c());
237
			string component_uuid = str_component_uuid;
238 239 240 241 242 243 244 245
			pair< map< pair<string,string>,pair<string,string> > :: iterator,
				  bool > rv 
					= fixed_interfaces->insert(
								make_pair(
									make_pair(str_virtual_uuid,
							                 str_interface_virtual_ids[index]),
									make_pair(str_component_uuid,
											  component_id)));
246
			if (rv.second == false) 
247
			{
248 249 250
				cerr << "The node-interface pair (" << str_virtual_uuid << ","
						<< str_interface_virtual_ids[index] 
						<< ") was not unique.";
251
				return false;
252
			}
253
		}
254
	}
255

256 257 258 259 260 261 262 263
	/* Deal with the location tag */
	string country = string("");
	string latitude = string ("");
	string longitude = string("");
	if (hasChildTag(elt, "location"))
	{
		country = string(XStr(elt->getAttribute (XStr("country").x())).c());
		if (elt->hasAttribute (XStr("latitude").x()))
264 265
			latitude =
					string(XStr(elt->getAttribute(XStr("latitude").x())).c());
266
		if (elt->hasAttribute (XStr("longitude").x()))
267 268
			longitude =
					string(XStr(elt->getAttribute(XStr("longitude").x())).c());
269
	}
270 271

		/*
272
	* Add on types
273
		*/
274 275 276
	int type_slots = 1;
	tb_vclass *vclass = NULL;
	const char* str_type_name;
277
		// XXX: This a ghastly hack. Find a way around it ASAP.
278 279 280 281
	string s_type_name = string("");
	DOMNodeList *types = elt->getElementsByTagName(XStr("node_type").x());
	int num_types = types->getLength();
	bool no_type = !num_types;
282

283 284 285 286
	for (int i = 0; i < num_types; i++) 
	{
		DOMElement *node_type = dynamic_cast<DOMElement*>(types->item(i));
		XStr node_type_name (node_type->getAttribute(XStr("type_name").x()));
287
			
288 289 290 291 292 293 294 295 296
		XStr type_slots_str (node_type->getAttribute(XStr("type_slots").x()));
		int node_type_slots = 1;
		bool is_unlimited = false;
		if (strcmp(type_slots_str.c(), "unlimited") == 0)
			is_unlimited = true;
		else
			type_slots = node_type_slots = type_slots_str.i();

		bool is_static = node_type->hasAttribute(XStr("static").x());
297 298
			
			/*
299 300 301
		* Make a tb_ptype structure for this guy - or just add this node to
		* it if it already exists
		* XXX: This should not be "manual"!
302
			*/
303 304 305 306 307 308 309
		str_type_name = node_type_name.c();
		s_type_name = string (str_type_name);
		if (ptypes.find(str_type_name) == ptypes.end()) {
			ptypes[str_type_name] = new tb_ptype(str_type_name);
		}
		ptypes[str_type_name]->add_slots(node_type_slots);
		tb_ptype *ptype = ptypes[str_type_name];
310
			
311 312 313 314 315 316 317 318 319
		name_vclass_map::iterator dit = vclass_map.find(node_type_name.f());
		if (dit != vclass_map.end()) {
			no_type = true;
			vclass = (*dit).second;
		} 
		else {
			vclass = NULL;
			if (vtypes.find(str_type_name) == vtypes.end()) {
				vtypes[str_type_name] = node_type_slots;
320 321
			} 
			else {
322
				vtypes[str_type_name] += node_type_slots;
323 324
			}
		}
325
	}
326

327
		/*
328
	* Finally, pull out any special node flags
329 330 331 332 333 334 335
		*/
// 		int trivial_bw = 0;
// 		if (hasChildTag(elt,"trivial_bw")) {
// 			trivial_bw = XStr(getChildValue(elt,"trivial_bw")).i();
// 			////XMLDEBUG("  Trivial bandwidth: " << trivial_bw << endl);
// 		}
// 		p->trivial_bw = trivial_bw;
336 337 338 339
	string str_subnode_of_name = "";
	if (hasChildTag (elt, "subnode_of"))
		str_subnode_of_name = string(XStr(getChildValue (elt, "subnode_of")).c());
	
340 341 342 343 344 345 346 347 348 349 350 351
// 		if (hasChildTag(elt,"unique")) {
// 			p->unique = true;
// 			////XMLDEBUG("  Unique" << endl);
// 		}
	
		// We might add hint_to to Geni later, but I am not sure that will ever happen. 
		// Am leaving this here for the moment anyway - TP
// 		XStr node_hint_to(elt->getAttribute(XStr("hint_to").x()));

// 		XStr *subnode_of_name = NULL;
// 		if (hasChildTag (elt, "subnode_of"))
// 			subnode_of_name = new XStr(getChildValue (elt, "subnode_of"));
352
	// 
353 354 355
// 		bool is_unique = hasChildTag (elt, "unique");
// 		bool is_disallow_trivial_mix = hasChildTag (elt, "disallow_trivial_mix");

356 357
	// A bunch of defaults for stuff that assign wants and Protogeni doesn't
	// The code to read the values from the request is still there 
358 359
	bool is_unique = false;
	bool is_disallow_trivial_mix = false;
360
	//-------------------------------------------------------------------------
361
		
362 363 364 365 366 367
	tb_vnode *v = NULL;
	if (no_type)
		// If they gave no type, just assume it's a PC for
		// now. This is not really a good assumption.
		v = new tb_vnode(str_virtual_uuid.c_str(), "pc", type_slots);
	else
368 369
		v = new tb_vnode(str_virtual_uuid.c_str(), 
						 s_type_name.c_str(), type_slots);
370 371
		
		// Construct the vertex
372
	v -> disallow_trivial_mix = is_disallow_trivial_mix;
373 374
	if (str_subnode_of_name != "")
		v -> subnode_of_name = str_subnode_of_name.c_str();
375
		
376 377 378 379
	if( elt->hasAttribute( XStr( "exclusive" ).x() ) ) {
		XStr exclusive( elt->getAttribute( XStr(
						"exclusive" ).x() ) );
		fstring desirename( "shared" );
380

381
		if( !strcmp( exclusive, "false" ) || !strcmp( exclusive, "0" ) ) {
382
			tb_node_featuredesire node_fd( desirename, 1.0,
383
										true,featuredesire::FD_TYPE_NORMAL);
384 385
			node_fd.add_desire_user( 1.0 );
			v->desires.push_front( node_fd );
386
		} else if( strcmp( exclusive, "true" ) && strcmp( exclusive, "1" ) ) {
387 388 389
			static int syntax_error;

			if( !syntax_error ) {
390 391 392 393
				syntax_error = 1;
				cout << "Warning: unrecognised exclusive "
						"attribute \"" << exclusive << "\"; will "
						"assume exclusive=\"true\"\n";
394
			}
395
		}
396
	}
397
		
398 399 400 401 402
	v->vclass = vclass;
	vvertex vv = add_vertex(vg);
	vname2vertex[str_virtual_uuid.c_str()] = vv;
	virtual_nodes.push_back(vv);
	put(vvertex_pmap,vv,v);
403
		
404 405 406 407 408 409 410 411 412 413 414 415
// 	parse_fds_vnode_xml (elt, &(v -> desires));
	
	if (str_component_manager_uuid != "") 
	{
		tb_node_featuredesire node_fd (
								XStr(str_component_manager_uuid.c_str()).f(), 
								1.0, true, featuredesire::FD_TYPE_NORMAL);
		node_fd.add_desire_user(0);
		(v->desires).push_front(node_fd);
	}
	
 	v -> desires.sort();
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
	return true;
}

/*
 * Pull nodes from the document, and populate assign's own data structures
 */
bool populate_nodes_rspec(DOMElement *root, tb_vgraph &vg, map< pair<string, string>, pair<string, string> >* fixed_interfaces) {
	bool is_ok = true;
    /*
     * Get a list of all nodes in this document
     */
    DOMNodeList *nodes = root->getElementsByTagName(XStr("node").x());
    int nodeCount = nodes->getLength();
    XMLDEBUG("Found " << nodeCount << " nodes in rspec" << endl);
	clock_t times [nodeCount];

    for (size_t i = 0; i < nodeCount; i++) 
	{
		DOMNode *node = nodes->item(i);
435
		// This should not be able to fail, because all elements in
436 437 438
		// this list came from the getElementsByTagName() call
		DOMElement *elt = dynamic_cast<DOMElement*>(node);
		is_ok &= populate_node(elt, vg, fixed_interfaces);
439 440 441 442 443 444 445 446 447 448 449 450 451
    }
   		 
    /*
     * This post-pass binds subnodes to their parents
     */
    bind_vtop_subnodes(vg);
    
    /*
     * Indicate errors, if any
     */
    return is_ok;
}

452 453 454 455
bool populate_link (DOMElement* elt, tb_vgraph &vg, map< pair<string,string>, pair<string,string> >* fixed_interfaces) 
{
	string str_virtual_id = string("");
	if (elt->hasAttribute(XStr("virtual_id").x()))
456 457
		str_virtual_id = string
				        (XStr(elt->getAttribute(XStr("virtual_id").x())).c());
458
		
459 460
	string str_virtualization_type = string("");
	if (elt->hasAttribute(XStr("virtualization_type").x()))
461 462 463
		str_virtualization_type = string
								(XStr(elt->getAttribute
				                  (XStr("virtualization_type").x())).c());
464
		
465
	/*
466 467 468
	* Get the link type - we know there is at least one, and we
	* need it for the constructor
	* Note: Changed from element to attribute
469
	*/
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
	string str_link_type(XStr(elt->getAttribute(XStr("link_type").x())).c());
	if (str_link_type == "")
		str_link_type = "ethernet";

		/*
	* Get standard link characteristics
		*/
	bool bandwidth_specified = hasChildTag(elt, "bandwidth");
	XStr bandwidth( bandwidth_specified ? 
						getChildValue(elt,"bandwidth") : 
						XStr( "100000" ).x() );
	bool latency_specified = hasChildTag(elt, "latency");
	XStr latency( latency_specified ?
			      			getChildValue(elt,"latency") :
							XStr( "0" ).x() );
	bool packet_loss_specified = hasChildTag(elt, "packet_loss");
	XStr packet_loss( packet_loss_specified ?
				  			getChildValue(elt,"packet_loss") :
							XStr( "0" ).x() );
489
		
490 491 492 493
	string src_node;
	string src_iface;
	string dst_node;
	string dst_iface;
494
		
495 496
	DOMNodeList *interfaces = 
			             elt->getElementsByTagName(XStr("interface_ref").x());
497 498
	interface_spec source;
	interface_spec dest;
499
		
500 501 502 503 504
	/* NOTE: In a request, we assume that each link has only two interfaces.
	 * Although the order is immaterial, assign expects a source first 
	 * and then destination and we assume the same ordering.
	 * If more than two interfaces are provided, the link must be a lan 
	 */
505 506 507 508 509 510 511 512 513 514 515
	if (interfaces->getLength() != 2)
	{
		string str_lan_id = generate_virtual_node_id(str_virtual_id);
		
		// NOTE: This is an attribute which is not in the rspec
		// it has been added to easily identify lan_links during annotation
		elt->setAttribute(XStr("is_lan").x(), XStr("true").x());
			
		// Create the lan node
		DOMElement* lan_node = doc->createElement(XStr("node").x());
		request_root->appendChild(lan_node);
516 517
		lan_node->setAttribute(XStr("virtualization_type").x(),
							   XStr("raw").x());
518
		lan_node->setAttribute(XStr("exclusive").x(), XStr("1").x());
519 520
		lan_node->setAttribute(XStr("virtual_id").x(),
							   XStr(str_lan_id.c_str()).x());
521 522 523 524 525 526 527 528 529 530
			
		// Create node type for the lan
		DOMElement* lan_node_type = doc->createElement(XStr("node_type").x());
		lan_node_type->setAttribute(XStr("type_name").x(), XStr("lan").x());
		lan_node_type->setAttribute(XStr("type_slots").x(), XStr("1").x());
		lan_node->appendChild(lan_node_type);
		
		// NOTE: This is an attribute which is not in the rspec
		// but which has been added to distinguish the element
		// from those explicitly specified by the user during annotation
531 532
		lan_node->setAttribute(XStr("generated_by_assign").x(),
							   XStr("true").x());
533 534 535 536 537 538 539 540
			
		// We need to store the dynamically created links in a list
		// and add them to the virtual graph later because the sanity checks
		// will fail if they are added before the lan node is added.
		list<DOMElement*> links;
		list<DOMElement*>::iterator it = links.begin();
		for (int i = 0; i < interfaces->getLength(); ++i)
		{
541 542 543 544 545 546
			DOMElement* interface =
					           dynamic_cast<DOMElement*>(interfaces->item(i));
			XStr virtual_interface_id
				(interface->getAttribute(XStr("virtual_interface_id").x()));
			XStr virtual_node_id
					(interface->getAttribute(XStr("virtual_node_id").x()));
547
				
548 549 550 551
			string str_lan_interface_id = 
					generate_virtual_interface_id(str_lan_id, i);
			DOMElement* lan_interface = 
					               doc->createElement(XStr("interface").x());
552
			lan_node->appendChild(lan_interface);
553 554
			lan_interface->setAttribute(XStr("virtual_id").x(),
									XStr(str_lan_interface_id.c_str()).x());
555
				
556 557 558
			interface_spec interface_ref =
					       parse_interface_rspec_xml(
					           dynamic_cast<DOMElement*>(interfaces->item(i)));
559 560
			DOMElement* link = doc->createElement(XStr("link").x());
			request_root->appendChild(link);
561 562 563 564
			link->setAttribute(
							XStr("virtual_id").x(), 
								 XStr(interface_ref.virtual_node_id 
										 + string(":") + str_lan_id).x());
565 566 567 568
			appendChildTagWithData(link, "bandwidth", bandwidth.c());
			appendChildTagWithData(link, "latency", latency.c());
			appendChildTagWithData(link, "packet_loss", packet_loss.c());
				
569 570
			DOMElement* src_interface_ref = 
					           doc->createElement(XStr("interface_ref").x());
571
			src_interface_ref->setAttribute(XStr("virtual_interface_id").x(),
572 573 574
					                           virtual_interface_id.x());
			src_interface_ref->setAttribute(XStr("virtual_node_id").x(),
											virtual_node_id.x());
575 576
			link->appendChild(src_interface_ref);
				
577 578 579 580 581 582 583
			DOMElement* dst_interface_ref = 
					       doc->createElement(XStr("interface_ref").x());
			dst_interface_ref->setAttribute(
									XStr("virtual_interface_id").x(),
									XStr(str_lan_interface_id.c_str()).x());
			dst_interface_ref->setAttribute(XStr("virtual_node_id").x(),
											XStr(str_lan_id.c_str()).x());
584 585 586 587
			link->appendChild(dst_interface_ref);
			
			// Adding attributes to ensure that the element is handled
			// correctly during annotation.
588 589 590 591
			link->setAttribute(XStr("generated_by_assign").x(),
							   XStr("true").x());
			link->setAttribute(XStr("lan_link").x(),
							   XStr(str_virtual_id.c_str()).x());
592 593 594 595 596 597 598 599 600 601 602
			
			links.insert(it, link);
		}
			
		populate_node(lan_node, vg, fixed_interfaces);
		for (it = links.begin(); it != links.end(); ++it)
			populate_link(*it, vg, fixed_interfaces);
		return true;
	}
	else 
	{
603 604 605 606
		source = parse_interface_rspec_xml(
							dynamic_cast<DOMElement*>(interfaces->item(0)));
		dest = 	parse_interface_rspec_xml(
				            dynamic_cast<DOMElement*>(interfaces->item(1)));
607 608 609 610 611 612 613 614
	}

	src_node = source.virtual_node_id;
	src_iface = source.virtual_interface_id;
	dst_node = dest.virtual_node_id;
	dst_iface = dest.virtual_interface_id;
	if (src_node.compare("") == 0 || src_iface.compare("") == 0)
	{
615 616
		cerr << "No source node found on interface for link " 
				<< str_virtual_id << endl;
617 618 619 620
		return false;
	}
	if (dst_node.compare("") == 0 || dst_iface.compare("") == 0)
	{
621 622
		cerr << "No destination node found on interface for link " 
				<< str_virtual_id << endl;
623 624 625 626
		return false;
	}
        
	if (vname2vertex.find(src_node.c_str()) == vname2vertex.end()) {
627 628
		cerr << "Bad link " << str_virtual_id 
				<< ", non-existent source node " << src_node << endl;
629 630 631
		return false;
	}
	if (vname2vertex.find(dst_node.c_str()) == vname2vertex.end()) {
632 633
		cerr << "Bad link " << str_virtual_id 
				<< ", non-existent destination node " << dst_node << endl;
634 635 636 637 638 639 640 641
		return false;
	}
		
	vvertex v_src_vertex = vname2vertex[src_node.c_str()];
	vvertex v_dst_vertex = vname2vertex[dst_node.c_str()];
	tb_vnode *src_vnode = get(vvertex_pmap,v_src_vertex);
	tb_vnode *dst_vnode = get(vvertex_pmap,v_dst_vertex);

Tarun Prabhu's avatar
Tarun Prabhu committed
642 643 644 645
  // If the virtualization type on the string is missing or "raw", then
  // we leave the emulated flag off - we want the whole physical
  // interface. If anything else, we assume that it's some kind of
  // virtualized link and the emulated flag should be set.
646 647 648 649 650 651
	bool emulated = true;
	if (str_virtualization_type.compare("raw") == 0 ||
                str_virtualization_type.compare("") == 0) {
            emulated = false;
            cerr << "Set emulated=false" << endl;
        }
652 653 654
		
// 		bool allow_delayed = !hasChildTag (elt, "nodelay");
		
655 656 657
	// This section has a whole bunch of defaults for tags that 
	// were used in the old text format but are not in Protogeni. 
	// We will eventually decide whether or not we want them.
658
	bool allow_delayed = true;
659
		//bool allow_trivial = false;
660
	bool allow_trivial = true;
661
		
662
	map< pair<string,string>, pair<string,string> >::iterator it;
663
		
664 665
	bool fix_src_iface = false;
	fstring fixed_src_iface = "";
666 667
	it = fixed_interfaces->find(pair<string,string>(src_node.c_str(),
								 src_iface.c_str()));
668 669
	if (it != fixed_interfaces->end())
	{
670 671 672
		cerr << "Found fixed source interface (" << (it->second).first << ","
				<< (it->second).second << ") on (" << (it->first).first << ","
				<< (it->first).second << ")" << endl;
673 674 675
		fix_src_iface = true;
		fixed_src_iface = (it->second).second;
	}
676 677
			
		
678 679 680 681 682
	bool fix_dst_iface = false;
	fstring fixed_dst_iface = "";
	it = fixed_interfaces->find(make_pair(dst_node, src_iface));
	if (it != fixed_interfaces->end())
	{
683 684 685
		cerr << "Found fixed destination interface (" << (it->second).first 
				<< "," << (it->second).second << ") on (" << (it->first).first
				<< "," << (it->first).second << ")" << endl;
686 687 688
		fix_dst_iface = true;
		fixed_dst_iface = (it->second).second;
	}
689 690

/*		bool allow_trivial = false;
691 692 693 694 695 696
#ifdef ALLOW_TRIVIAL_DEFAULT
	allow_trivial = true;
#else
	allow_trivial = false;
#endif	
	allow_trivial = hasChildTag(elt, "trivial_ok");*/
697
		
698 699 700
	if (emulated) 
	{
		if (!allow_trivial) 
701
		{
702 703
			src_vnode->total_bandwidth += bandwidth.i();
			dst_vnode->total_bandwidth += bandwidth.i();
704
		}
705 706 707 708 709 710 711 712
	} 
	else 
	{
		src_vnode->num_links++;
		dst_vnode->num_links++;
		src_vnode->link_counts[str_link_type.c_str()]++;
		dst_vnode->link_counts[str_link_type.c_str()]++;
	}
713 714

		/*
715
	* Create the actual link object
716
		*/
717
	vedge virt_edge = (add_edge(v_src_vertex,v_dst_vertex,vg)).first;
718
		
719
	tb_vlink *virt_link = new tb_vlink();
720
		
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
	virt_link-> name = str_virtual_id;
	virt_link-> type = fstring(str_link_type.c_str());

	virt_link-> fix_src_iface = fix_src_iface;
	virt_link-> src_iface = (fixed_src_iface);//.f();

	virt_link-> fix_dst_iface = fix_dst_iface;
	virt_link-> dst_iface = (fixed_dst_iface);//.f();

	virt_link-> emulated = emulated;
	virt_link-> allow_delayed = allow_delayed;
	virt_link-> allow_trivial = allow_trivial;
	virt_link-> no_connection = true;
	virt_link->delay_info.bandwidth = bandwidth.i();
	virt_link->delay_info.delay = latency.i();
	virt_link->delay_info.loss = packet_loss.d();
	virt_link->src = v_src_vertex;
	virt_link->dst = v_dst_vertex;
739 740
	
		// XXX: Should not be manual
741 742 743 744
	put(vedge_pmap, virt_edge, virt_link);
	
	return true;
}
745

746 747 748 749 750 751 752 753 754
/*
 * Pull the links from the ptop file, and populate assign's own data sturctures
 */
bool populate_links_rspec(DOMElement *root, tb_vgraph &vg, map< pair<string, string>, pair<string, string> >* fixed_interfaces) {
    
    bool is_ok = true;
    
    /*
     * TODO: Support the "PENALIZE_BANDWIDTH" option?
755
     * TODO: Support the "FIX_PLINK_ENDPOINTS" and "FIX_PLINKS_DEFAULT"?
756 757 758 759 760 761 762 763 764
     */
    DOMNodeList *links = root->getElementsByTagName(XStr("link").x());
    int linkCount = links->getLength();
    XMLDEBUG("Found " << links->getLength()  << " links in rspec" << endl);
    for (size_t i = 0; i < linkCount; i++) {
        DOMNode *link = links->item(i);
        DOMElement *elt = dynamic_cast<DOMElement*>(link);
        
		is_ok &= populate_link(elt, vg, fixed_interfaces);	
765 766 767 768
    }
    return is_ok;
}

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
string generate_virtual_node_id (string virtual_id) 
{
	std:ostringstream oss;
	struct timeval tv;
	struct timezone tz;
	gettimeofday(&tv, &tz);
	oss << virtual_id << tv.tv_sec << tv.tv_usec;
	return oss.str();
}

DOMElement* appendChildTagWithData (DOMElement* parent, const char*tag_name, const char* child_value)
{
	DOMElement* child = doc->createElement(XStr(tag_name).x());
	child->appendChild(doc->createTextNode(XStr(child_value).x()));
	parent->appendChild(child);
	return child;
}

string generate_virtual_interface_id (string lan_name, int interface_number)
{
	std:ostringstream oss;
	oss << lan_name << ":" << interface_number;
	return oss.str();
}

794
#endif