parse_request_rspec.cc 24.9 KB
Newer Older
1
/*
Robert Ricci's avatar
Robert Ricci committed
2
 * Copyright (c) 2008-2010 University of Utah and the Flux Group.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 
 * {{{EMULAB-LICENSE
 * 
 * This file is part of the Emulab network testbed software.
 * 
 * This file is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * }}}
22 23 24 25 26 27
 */

/*
 * XML Parser for RSpec ptop files
 */

28
static const char rcsid[] = "$Id: parse_request_rspec.cc,v 1.16 2009-10-21 20:49:26 tarunp Exp $";
29 30 31 32 33 34

#ifdef WITH_XML

#include "parse_request_rspec.h"
#include "xmlhelpers.h"
#include "parse_error_handler.h"
35 36
#include "rspec_parser_v1.h"
#include "rspec_parser_v2.h"
37
#include "emulab_extensions_parser.h"
38 39

#include <fstream>
40
#include <sstream>
41
#include <sys/time.h>
42 43 44 45 46 47 48 49

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

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

#ifdef TBROOT
50 51
	#define SCHEMA_LOCATION TBROOT"/lib/assign/rspec-request.xsd"
#else	
52
	#define SCHEMA_LOCATION "request.xsd"
53
#endif
54 55 56

using namespace rspec_emulab_extension;

57 58 59 60 61 62 63 64 65
/*
 * XXX: Do I have to release lists when done with them?
 */

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

66
/* --- Have to include the vnode data structures as well --- */
67 68 69 70 71 72 73
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;
74
/* --- end of vtop stuff --- */
75 76 77 78

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

79 80
map<string, string>* vIfacesMap = new map<string, string>();

81 82
int rspec_version = -1;

83 84 85
int bind_ptop_subnodes(tb_pgraph &pg);
int bind_vtop_subnodes(tb_vgraph &vg);

86 87
static rspec_parser* rspecParser;

88
/*
89
 * These are not meant to be used outside of this file,so they are only
90 91
 * declared in here
 */
92 93 94 95 96 97 98 99
static bool populate_nodes(DOMElement *root, 
			   tb_vgraph &vg, 
			   map< pair<string, string>,
			   pair<string, string> >* fixed_interfaces);
static bool populate_links(DOMElement *root, 
			   tb_vgraph &vg, 
			   map< pair<string, string>, 
			   pair<string, string> >* fixed_interfaces);
100
static bool populate_vclasses (DOMElement* root, tb_vgraph& vg);
101

102
DOMElement* appendChildTagWithData (DOMElement* parent, 
103 104
				    const char* tag_name, 
				    const char* child_value);
105 106
string generate_virtualNodeId (string virtual_id);
string generate_virtualIfaceId(string node_name, int interface_number);
107

108
int parse_request(tb_vgraph &vg, char const * filename) {
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
  /* 
   * Fire up the XML domParser
   */
  XMLPlatformUtils::Initialize();
  
  XercesDOMParser *domParser = new XercesDOMParser;
  
  /*
   * Enable some of the features we'll be using: validation, namespaces, etc.
   */
  domParser->setValidationScheme(XercesDOMParser::Val_Always);
  domParser->setDoNamespaces(true);
  domParser->setDoSchema(true);
  domParser->setValidationSchemaFullChecking(true);
  //domParser->setExternalSchemaLocation("http://www.protogeni.net/resources/rspec/2 http://www.protogeni.net/resources/rspec/2/request.xsd");
  
  /*
   * 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();
  domParser->setErrorHandler(errHandler);
  
  /*
   * Do the actual parse
   */
  domParser->parse(filename);
  XMLDEBUG("XML parse completed" << endl);
  
  /* 
   * If there are any errors, do not go any further
   */
  if (errHandler->sawError()) {
143
    cout << "*** There were " << domParser -> getErrorCount () 
144
	 << " errors in " << filename << endl;
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
151
     */
152 153
    doc = domParser->getDocument();
    request_root = doc->getDocumentElement();
154
    
155 156
    string type = XStr (request_root->getAttribute(XStr("type").x())).c();
    if (type != "request") {
157
      cout << "*** RSpec type must be \"request\" in " << filename
158
	   << " (found " << type << ")" << endl;
159 160
      exit (EXIT_FATAL);
    } 
161
    
162 163 164 165 166 167 168 169 170 171 172
    // Initialize the rspec parser with the correct object depending
    // on the version of the rspec.
    int rspecVersion = rspec_parser_helper::getRspecVersion(request_root);
    switch (rspecVersion) {
    case 1:
      rspecParser = new rspec_parser_v1(RSPEC_TYPE_REQ);
      break;
    case 2:
      rspecParser = new rspec_parser_v2(RSPEC_TYPE_REQ);
      break;
    default:
173
      cout << "*** Unsupported rspec ver. " << rspecVersion
174 175 176 177 178
	   << " ... Aborting " << endl;
      exit(EXIT_FATAL);
    }
    XMLDEBUG("Found rspec ver. " << rspecVersion << endl);
    
179 180
    // Set global variable for annotating
    rspec_version = rspecVersion;
181
    map< pair<string, string>, pair<string, string> > fixed_interfaces;
182

183
    /*
184 185
     * These three calls do the real work of populating the assign data
     * structures
186
     */
187 188
    XMLDEBUG("starting vclass population" << endl);
    if (!populate_vclasses (request_root, vg)) {
189
      cout << "*** Error reading vclasses from virtual topology "
190 191 192 193
	   << filename << endl;
      exit(EXIT_FATAL);
    }
    XMLDEBUG("finishing vclass population" << endl);
194 195
    XMLDEBUG("starting node population" << endl);
    if (!populate_nodes(request_root,vg, &fixed_interfaces)) {
196
      cout << "*** Error reading nodes from virtual topology " 
197 198
	   << filename << endl;
      exit(EXIT_FATAL);
199
    }
200 201 202 203
    XMLDEBUG("finishing node population" << endl);
    
    XMLDEBUG("starting link population" << endl);
    if (!populate_links(request_root,vg, &fixed_interfaces)) {
204
      cout << "*** Error reading links from virtual topology " 
205 206
	   << filename << endl;
      exit(EXIT_FATAL);
207
    }
208
    XMLDEBUG("finishing link population" << endl);
209
    
210 211 212
    /* TODO: We need to do something about policies at some point. */
    //populate_policies(root);
    
213
    XMLDEBUG("RSpec parsing finished" << endl); 
214 215 216 217 218
  }
  
  /*
   * All done, clean up memory
   */
219
//     XMLPlatformUtils::Terminate();
220
  delete rspecParser;
221
  return 0;
222 223
}

224
bool populate_node(DOMElement* elt, 
225 226
		   tb_vgraph &vg, map< pair<string,string>, 
		   pair<string,string> >* fixed_interfaces) 
227
{	
228
  static bool displayedWarning = false;
229 230 231 232 233 234 235
  bool hasVirtualId;
  string virtualId = rspecParser->readVirtualId(elt, hasVirtualId);
  
  bool hasComponentId;
  bool hasCMId;
  string componentId = rspecParser->readPhysicalId(elt, hasComponentId);
  string cmId = rspecParser->readComponentManagerId(elt, hasCMId);
236

237 238
  // If a node has a component_uuid, it is a fixed node
  if (hasComponentId) {
239
    if(hasCMId) {
240
      fixed_nodes [virtualId] = componentId;	
241 242 243
    }
    else {
      cout << "WARNING: Fixed virtual node " << virtualId 
244 245 246
	   << " has a componentId specified "
	   << "but no component manager " << endl
	   << "The componentId will be ignored." << endl;
247
    }
248 249 250
  }
  
  if (!hasVirtualId) {
251
    cout << "*** Every node must have a virtual_id" << endl;
252 253 254 255 256 257
    return false;
  }
  
  bool allUnique;
  map< pair<string, string>, pair<string, string> > fixedIfacesOnNode;
  // XXX: This should not have to be called manually
258
  fixedIfacesOnNode = rspecParser->readInterfacesOnNode(elt, allUnique);
259
  if (!allUnique) {
260
    cout << "*** The node-interface pairs in " << virtualId 
261 262 263 264 265 266
	 << " were not unique."	<< endl;
    return false;
  }
  fixed_interfaces->insert(fixedIfacesOnNode.begin(),fixedIfacesOnNode.end());
  
  /* Deal with the location tag */
267 268 269 270
  if (!displayedWarning) {
    cout << "WARNING: Country information will be ignored" << endl;
    displayedWarning = true;
  }
271 272 273 274 275 276 277 278 279
  
  /*
   * Add on types
   */
  tb_vclass *vclass = NULL;
  
  int typeCount;
  vector<struct node_type> types = rspecParser->readNodeTypes(elt, typeCount);
  bool no_type = (typeCount == 0);
280 281
  string typeName = rspecParser->convertType("pc");
  int typeSlots = 1;
282 283
  bool isStatic = false;
  bool isUnlimited = false;
284
  if (typeCount > 1) {
285
    cout << "*** Too many node types (" << typeCount << ") on " 
286
	 << virtualId << " (allowed 1) ... Aborting " << endl;
287
    return false;
288
  }
289 290 291 292 293 294 295
  else if (typeCount == 1) {
    typeName = types[0].typeName;
    typeSlots = types[0].typeSlots;
    isStatic = types[0].isStatic;
    
    isUnlimited = (typeSlots == 1000);
  }
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
  
  /*
   * 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"!
   */
  const char* typeName_c = typeName.c_str();
  if (ptypes.find(typeName_c) == ptypes.end()) {
    ptypes[typeName_c] = new tb_ptype(typeName_c);
  }
  ptypes[typeName_c]->add_slots(typeSlots);
  
  name_vclass_map::iterator dit = vclass_map.find(fstring(typeName.c_str()));
  if (dit != vclass_map.end()) {
    no_type = true;
    vclass = (*dit).second;
  } 
  else {
    vclass = NULL;
    if (vtypes.find(typeName_c) == vtypes.end()) {
      vtypes[typeName_c] = typeSlots;
    } 
    else {
      vtypes[typeName_c] += typeSlots;
    }
  }
322 323

  // Read emulab extensions
324 325
  
  bool isSubnode;
326 327 328 329
  int subnodeCnt;
  string subnodeOf = rspecParser->readSubnodeOf(elt, isSubnode, subnodeCnt);
  if (isSubnode) {
    if (subnodeCnt > 1) {
330
      cout << "*** To many \"subnode\" relations found in " 
331 332 333 334
	   << virtualId << ". Allowed 1 ... " << endl;
      return false;
    }
  }
335
  
336 337 338 339
  bool disallow_trivial_mix = rspecParser->readDisallowTrivialMix(elt);
 
  bool hasNodeHint = false;
  string nodeHint = rspecParser->readHintTo(elt, hasNodeHint);
340 341
  
  tb_vnode *v = NULL;
342
  if (no_type) {
343 344
    // If they gave no type, just assume it's a PC for
    // now. This is not really a good assumption.
345 346
    XMLDEBUG("WARNING: No type information found on node. " 
             << "Defaulting to " << typeName.c_str() << endl);
347
  }
348
  v = new tb_vnode(virtualId.c_str(), typeName.c_str(), typeSlots);
349 350
  
  // Construct the vertex
351 352 353 354
  if (disallow_trivial_mix) {
    v -> disallow_trivial_mix = true;
  }
  if (isSubnode) {
355
    v -> subnode_of_name = subnodeOf.c_str();
356 357 358 359
  }
  if (hasNodeHint) {
    node_hints[virtualId] = nodeHint;
  }
360 361 362
  
  bool hasExclusive;
  string exclusive = rspecParser->readExclusive(elt, hasExclusive);
363

364 365 366 367 368 369 370 371 372 373 374 375 376 377
  if (hasExclusive) {
    fstring desirename("shared");
    
    if (exclusive == "false" || exclusive == "0") {
      tb_node_featuredesire node_fd( desirename, 1.0,
				     true,featuredesire::FD_TYPE_NORMAL);
      node_fd.add_desire_user( 1.0 );
      v->desires.push_front( node_fd );
    } 
    else if(exclusive != "true" && exclusive != "1"){
      static int syntax_error;
      
      if( !syntax_error ) {
	syntax_error = 1;
378 379 380
	cout << "WARNING: unrecognised exclusive "
	  "attribute \"" << exclusive << "\"; " <<
	  "Assuming exclusive=\"true\"\n";
381 382 383
      }
    }
  }
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412

  int fdsCount;
  vector<struct fd> fds = rspecParser->readFeaturesDesires(elt, fdsCount);
  for (int i = 0; i < fdsCount; i++) {
    struct fd desire = fds[i];
    featuredesire::fd_type fd_type;
    switch(desire.op.type) {
    case LOCAL_OPERATOR:
      fd_type = featuredesire::FD_TYPE_LOCAL_ADDITIVE;
      break;
    case GLOBAL_OPERATOR:
      if (desire.op.op == "OnceOnly") {
	fd_type = featuredesire::FD_TYPE_GLOBAL_ONE_IS_OKAY;
      }
      else {
	fd_type = featuredesire::FD_TYPE_GLOBAL_MORE_THAN_ONE;
      }
      break;
    default:
      fd_type = featuredesire::FD_TYPE_NORMAL;
      break;
    }
    tb_node_featuredesire node_fd (XStr(desire.fd_name.c_str()).f(),
				   desire.fd_weight,
				   desire.violatable,
				   fd_type);
    node_fd.add_desire_user(desire.fd_weight);
    (v->desires).push_front(node_fd);
  }
413 414 415 416 417 418 419 420 421 422
  
  v->vclass = vclass;
  vvertex vv = add_vertex(vg);
  vname2vertex[virtualId.c_str()] = vv;
  virtual_nodes.push_back(vv);
  put(vvertex_pmap,vv,v);
  
  // If a component manager has been specified, then the node must be 
  // managed by that CM. We implement this as a desire.
  if (hasCMId) {
423 424
    tb_node_featuredesire node_fd (XStr(cmId.c_str()).f(), 1.0,
				   true, featuredesire::FD_TYPE_NORMAL);
425
    node_fd.add_desire_user(0.9);
426 427 428 429 430
    (v->desires).push_front(node_fd);
  }
  
  v -> desires.sort();
  return true;
431 432 433 434 435
}

/*
 * Pull nodes from the document, and populate assign's own data structures
 */
436
bool populate_nodes(DOMElement *root, 
437 438
                    tb_vgraph &vg, map< pair<string, string>, 
                    pair<string, string> >* fixed_interfaces) {
439 440 441 442 443
  bool is_ok = true;
  /*
   * Get a list of all nodes in this document
   */
  DOMNodeList *nodes = root->getElementsByTagName(XStr("node").x());
444 445
  int nodeCount = nodes->getLength();
  XMLDEBUG("Found " << nodeCount << " nodes in rspec" << endl);
446
  
447
  for (unsigned i = 0; i < nodeCount; i++)  {
448 449 450 451 452 453 454 455 456 457
    DOMNode *node = nodes->item(i);
    // This should not be able to fail, because all elements in
    // this list came from the getElementsByTagName() call
    DOMElement *elt = dynamic_cast<DOMElement*>(node);
    is_ok &= populate_node(elt, vg, fixed_interfaces);
  }
  
  /*
   * This post-pass binds subnodes to their parents
   */
458
  bind_vtop_subnodes(vg);
459 460 461 462
  
  /*
   * Indicate errors, if any
   */
463
  return is_ok;
464 465
}

466 467 468
bool populate_link (DOMElement* elt, 
		    tb_vgraph &vg, map< pair<string,string>, 
		    pair<string,string> >* fixed_interfaces) 
469
{
470 471 472 473 474 475 476 477 478 479 480 481 482 483
  bool hasVirtualId;
  string virtualId = rspecParser->readVirtualId(elt, hasVirtualId);
  
  bool hasVirtualizationType;
  string virtualizationType 
    = rspecParser->readVirtualizationType(elt, hasVirtualizationType);
  
  /*
   * Get the link type - we know there is at least one, and we
   * need it for the constructor
   * Note: Changed from element to attribute
   */
  int count;
  vector<struct link_type> linkTypes = rspecParser->readLinkTypes(elt, count);
484
  string linkType = "ethernet";
485
  if (count > 1) {
486
    cout << "*** Too many link types specified (" << count 
487
	 << ") on " << virtualId << ". Allowed 1 ... Aborting" << endl;
488 489 490 491
    return false;
  }
  else if (count == 1){
    linkType = linkTypes[0].typeName;
492 493 494 495 496 497 498
  }
  
  /*
   * Get standard link characteristics
   */
  struct link_characteristics characteristics
    = rspecParser->readLinkCharacteristics(elt, count);
499 500 501
  if (count == RSPEC_ASYMMETRIC_LINK) {
    cout << "*** Disallowed asymmetric link specified on " << virtualId 
         <<". Links must be symmetric" << endl;
502 503
    return false;
  }
504
  else if (count > 2) { 
505
    cout << "*** Too many link properties found on " << virtualId
506 507 508 509
         << ". Max. allowed: 2" << endl;
    return false;
  }

510 511 512
  int bandwidth = characteristics.bandwidth;
  int latency = characteristics.latency;
  double packetLoss = characteristics.packetLoss;
513

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
  struct link_interface src;
  struct link_interface dst;
  
  int ifaceCount = 0;
  vector<struct link_interface> interfaces
    = rspecParser->readLinkInterface(elt, ifaceCount);
  
  /* 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 
   */
  if (ifaceCount > 2) {
    string str_lan_id = generate_virtualNodeId(virtualId);
    
    // 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);
    lan_node->setAttribute(XStr("virtualization_type").x(),
			   XStr("raw").x());
    lan_node->setAttribute(XStr("exclusive").x(), XStr("1").x());
    lan_node->setAttribute(XStr("virtual_id").x(),
			   XStr(str_lan_id.c_str()).x());
    
    // 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
    lan_node->setAttribute(XStr("generated_by_assign").x(),
			   XStr("true").x());
    
    // 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 < ifaceCount; ++i) {
      link_interface interface = interfaces[i];
561 562
      string virtualIfaceId = XStr(interface.virtualIfaceId.c_str()).c();
      string virtualNodeId = XStr(interface.virtualNodeId.c_str()).c();
563 564 565 566 567 568 569 570 571 572 573
      
      string str_lan_interface_id = generate_virtualIfaceId(str_lan_id, i);
      DOMElement* lan_interface = doc->createElement(XStr("interface").x());

      lan_node->appendChild(lan_interface);
      lan_interface->setAttribute(XStr("virtual_id").x(),
				  XStr(str_lan_interface_id.c_str()).x());
      
      DOMElement* link = doc->createElement(XStr("link").x());
      request_root->appendChild(link);
      link->setAttribute(XStr("virtual_id").x(), 
574 575
                         XStr(interface.virtualNodeId 
                              + string(":") + str_lan_id).x());
576 577 578 579 580 581 582 583
      appendChildTagWithData(link, "bandwidth",
			     rspecParser->numToString(bandwidth).c_str());
      appendChildTagWithData(link, "latency",
			     rspecParser->numToString(latency).c_str());
      appendChildTagWithData(link, "packet_loss",
			     rspecParser->numToString(packetLoss).c_str());
      
      DOMElement* src_interface_ref 
584
        = doc->createElement(XStr("interface_ref").x());
585
      src_interface_ref->setAttribute(XStr("clientId").x(),
586
                                      XStr(virtualIfaceId.c_str()).x());
587 588 589
      link->appendChild(src_interface_ref);
      
      DOMElement* dst_interface_ref 
590
        = doc->createElement(XStr("interface_ref").x());
591
      dst_interface_ref->setAttribute(XStr("clientId").x(),
592
                                      XStr(str_lan_interface_id.c_str()).x());
593 594 595 596 597
      link->appendChild(dst_interface_ref);
      
      // Adding attributes to ensure that the element is handled
      // correctly during annotation.
      link->setAttribute(XStr("generated_by_assign").x(),
598
                         XStr("true").x());
599
      link->setAttribute(XStr("lan_link").x(),
600
                         XStr(virtualId.c_str()).x());
601 602 603 604 605 606 607 608 609 610 611 612 613 614
      
      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 if (ifaceCount == 2) {
    src = interfaces[0];
    dst = interfaces[1];
  }
  else {
615
    cout << "*** Too few interfaces found (" << ifaceCount << ")" 
616 617
	 << " on " << virtualId << " at least 2 required ... Aborting" 
	 << endl;
618
    return false;
619 620 621 622 623 624
  }
  
  string srcNode = src.virtualNodeId;
  string srcIface = src.virtualIfaceId;
  string dstNode = dst.virtualNodeId;
  string dstIface = dst.virtualIfaceId;
625

626
  if (srcNode == "" || srcIface == "") {
627
    cout << "*** No source node found on interface for link " 
628 629 630 631
	 << virtualId << endl;
    return false;
  }
  if (dstNode == "" || dstIface == "") {
632
    cout << "*** No destination node found on interface for link " 
633
         << virtualId << endl;
634 635 636 637
    return false;
  }
  
  if (vname2vertex.find(srcNode.c_str()) == vname2vertex.end()) {
638
    cout << "*** Bad link " << virtualId 
639
         << ", non-existent source node " << srcNode << endl;
640 641 642
    return false;
  }
  if (vname2vertex.find(dstNode.c_str()) == vname2vertex.end()) {
643
    cout << "*** Bad link " << virtualId 
644
         << ", non-existent destination node " << dstNode << endl;
645 646
    return false;
  }
647 648 649

  vIfacesMap->insert(pair<string, string>(srcIface, srcNode));
  vIfacesMap->insert(pair<string, string>(dstIface, dstNode));
650 651 652 653 654 655
  
  vvertex v_src_vertex = vname2vertex[srcNode.c_str()];
  vvertex v_dst_vertex = vname2vertex[dstNode.c_str()];
  tb_vnode *src_vnode = get(vvertex_pmap,v_src_vertex);
  tb_vnode *dst_vnode = get(vvertex_pmap,v_dst_vertex);
  
656
  // XXX: This is obsolete. We need to fix it ASAP
657
  bool emulated = false;
658 659 660
  emulated = rspecParser->readMultiplexOk(elt);
//   if (virtualizationType == "raw" || virtualizationType == "")
//     emulated = true;
661
  
662 663 664
  // Emulab extensions
  bool allow_delayed = !(rspecParser->readNoDelay(elt));
  bool allow_trivial = rspecParser->readTrivialOk(elt);
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
  
  map< pair<string,string>, pair<string,string> >::iterator it;
  
  bool fix_srcIface = false;
  fstring fixed_srcIface = "";
  it = fixed_interfaces->find(pair<string,string>(srcNode, srcIface));
  if (it != fixed_interfaces->end()) {
    fix_srcIface = true;
    fixed_srcIface = (it->second).second;
  }
  
  
  bool fix_dstIface = false;
  fstring fixed_dstIface = "";
  it = fixed_interfaces->find(make_pair(dstNode, dstIface));
  if (it != fixed_interfaces->end()) {
    fix_dstIface = true;
    fixed_dstIface = (it->second).second;
683

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
  }
  
  if (emulated) {
    if (!allow_trivial) {
      src_vnode->total_bandwidth += bandwidth;
      dst_vnode->total_bandwidth += bandwidth;
    }
  } 
  else {
    src_vnode->num_links++;
    dst_vnode->num_links++;
    src_vnode->link_counts[linkType.c_str()]++;
    dst_vnode->link_counts[linkType.c_str()]++;
  }
  
  vedge virt_edge = (add_edge(v_src_vertex,v_dst_vertex,vg)).first;
  
  tb_vlink *virt_link = new tb_vlink();
  
703 704
  virt_link->name = virtualId;
  virt_link->type = fstring(linkType.c_str());
705

706
  virt_link->fix_src_iface = fix_srcIface;
707
  if (fix_srcIface) {
708
    virt_link->src_iface = (fixed_srcIface);//.f();
709
  }
710
  
711
  virt_link->fix_dst_iface = fix_dstIface;
712
  if (fix_dstIface) {
713
    virt_link->dst_iface = (fixed_dstIface);//.f();
714
  }
715
  
716 717 718
  virt_link->emulated = emulated;
  virt_link->allow_delayed = allow_delayed;
  virt_link->allow_trivial = allow_trivial;
719
  virt_link->no_connection = true;
720 721 722 723 724 725 726 727 728 729
  virt_link->delay_info.bandwidth = bandwidth;
  virt_link->delay_info.delay = latency;
  virt_link->delay_info.loss = packetLoss;
  virt_link->src = v_src_vertex;
  virt_link->dst = v_dst_vertex;
  
  // XXX: Should not be manual
  put(vedge_pmap, virt_edge, virt_link);
  
  return true;
730
}
731

732
/*
733
 * Pull the links from the vtop file, and populate assign's own data sturctures
734
 */
735 736 737 738
bool 
populate_links(DOMElement *root, 
	       tb_vgraph &vg, 
	       map< pair<string, string>, pair<string, string> >*fixed_interfaces) {
739 740 741 742
    
    bool is_ok = true;
    /*
     * TODO: Support the "PENALIZE_BANDWIDTH" option?
743
     * TODO: Support the "FIX_PLINK_ENDPOINTS" and "FIX_PLINKS_DEFAULT"?
744 745 746 747
     */
    DOMNodeList *links = root->getElementsByTagName(XStr("link").x());
    int linkCount = links->getLength();
    XMLDEBUG("Found " << links->getLength()  << " links in rspec" << endl);
748
    for (int i = 0; i < linkCount; i++) {
749 750
        DOMNode *link = links->item(i);
        DOMElement *elt = dynamic_cast<DOMElement*>(link);
751
	is_ok &= populate_link(elt, vg, fixed_interfaces);	
752 753 754 755
    }
    return is_ok;
}

756 757 758 759 760 761 762 763
bool populate_vclass (struct vclass vclass, tb_vgraph& vg)
{
  tb_vclass *v = NULL;
  const char* name = vclass.name.c_str();
  // We don't have support for hard vclasses yet
  if (vclass.type.type == SOFT_VCLASS) {
    v = new tb_vclass (XStr(name).f(), vclass.type.weight);
    if (v == NULL) {
764
      cout << "*** Could not create vclass " << vclass.name << endl;
765 766 767 768 769
      return false;
    }
    vclass_map[name] = v;
  }
  
770
  for (unsigned int i = 0; i < vclass.physicalTypes.size(); i++) {
771 772 773 774 775 776 777 778 779 780 781 782 783 784
    fstring physType = XStr(vclass.physicalTypes[i].c_str()).f();
    v->add_type(physType);
    vclasses[name].push_back(physType);
  }
  return true;
}

/*
 * Populate the vclasses
 */
bool populate_vclasses (DOMElement* root, tb_vgraph& vg)
{
  bool isOk = true;
  vector<struct vclass> vclasses = rspecParser->readVClasses(root);
785
  XMLDEBUG("Found " << vclasses.size() << " vclasses." << endl);
786
  for (unsigned int i = 0; i < vclasses.size(); i++) {
787 788 789 790 791 792
    isOk &= populate_vclass(vclasses[i], vg);
  }
  return isOk;
}
    

793
DOMElement* appendChildTagWithData (DOMElement* parent, 
794 795
				    const char* tag_name, 
				    const char* child_value)
796
{
797 798 799 800
  DOMElement* child = doc->createElement(XStr(tag_name).x());
  child->appendChild(doc->createTextNode(XStr(child_value).x()));
  parent->appendChild(child);
  return child;
801 802
}

803
string generate_virtualNodeId (string virtual_id) 
804
{
805
  ostringstream oss;
806 807 808 809 810
  struct timeval tv;
  struct timezone tz;
  gettimeofday(&tv, &tz);
  oss << virtual_id << tv.tv_sec << tv.tv_usec;
  return oss.str();
811 812
}

813
string generate_virtualIfaceId (string lan_name, int interface_number)
814
{ 
815
  ostringstream oss;
816 817
  oss << lan_name << ":" << interface_number;
  return oss.str();
818 819
}

820
#endif