parse_advertisement_rspec.cc 21.3 KB
Newer Older
1 2
/*
 * EMULAB-COPYRIGHT
Robert Ricci's avatar
Robert Ricci committed
3
 * Copyright (c) 2008-2010 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_advertisement_rspec.cc,v 1.7 2009-10-21 20:49:26 tarunp Exp $";
12 13 14 15 16 17

#ifdef WITH_XML

#include "parse_advertisement_rspec.h"
#include "xmlhelpers.h"
#include "parse_error_handler.h"
18
#include "rspec_parser_helper.h"
19
#include "rspec_parser_v1.h"
20
#include "rspec_parser_v2.h"
21 22 23

#include <fstream>
#include <map>
24
#include <set>
25 26 27 28 29 30 31 32

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

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

#ifdef TBROOT
33
	#define SCHEMA_LOCATION TBROOT"/lib/assign/ad.xsd"
34
#else
35
	#define SCHEMA_LOCATION "ad.xsd"
36
#endif
37 38 39

using namespace rspec_emulab_extension;
 
40 41 42 43 44 45 46 47 48
/*
 * XXX: Do I have to release lists when done with them?
 */

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

49
/* ------------------- Have to include the vnode data structures as well-----*/
50 51 52 53 54 55 56
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;
57
/* -------------------------- end of vtop stuff------------------ */
58

59 60
// This is a hash map of the entire physical topology 
// because it takes far too long for it to search the XML DOM tree.
61 62 63
map<string,DOMElement*>* advertisement_elements= new map<string,DOMElement*>();

map<string, string>* pIfacesMap = new map<string, string>();
64
map<string, string> shortNodeNames;
65

66
DOMElement* advt_root = NULL;
67 68 69 70 71 72 73 74

/*
 * TODO: This should be moved out of parse_top.cc, where it currently
 * resides.
 */
int bind_ptop_subnodes(tb_pgraph &pg);
int bind_vtop_subnodes(tb_vgraph &vg);

75
static rspec_parser* rspecParser;
76

77 78 79 80
/*
 * These are not meant to be used outside of this file, so they are only
 * declared in here
 */
81
static bool populate_nodes(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
82
			   set<string> &unavailable);
83
static bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
84 85 86
			   set<string> &unavailable);
static bool populate_type_limits(DOMElement *root,tb_pgraph &pg,tb_sgraph &sg);
static bool populate_policies (DOMElement*root, tb_pgraph &pg, tb_sgraph &sg);
87

88
int parse_advertisement(tb_pgraph &pg, tb_sgraph &sg, char *filename) {
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  /* 
   * Fire up the XML parser
   */
  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);
  
  /*
   * 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
   */
115
  XMLDEBUG("Begin XML parse" << endl);
116
  domParser->parse(filename);
117
  XMLDEBUG("XML parse completed" << endl);
118 119 120 121 122
  
  /* 
   * If there are any errors, do not go any further
   */
  if (errHandler->sawError()) {
123
    cout << "*** There were " << domParser -> getErrorCount () 
124
	 << " errors in " << filename << endl;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    exit(EXIT_FATAL);
  }
  else {
    /*
     * Get the root of the document - we're going to be using the same root
        * for all subsequent calls
        */
    DOMDocument* doc = domParser->getDocument();
    advt_root = doc->getDocumentElement();
    set<string> unavailable; // this should really be an unordered_set,
    // but that's not very portable yet
    
    int rspecVersion = rspec_parser_helper::getRspecVersion(advt_root);
    switch (rspecVersion) {
    case 1:
      rspecParser = new rspec_parser_v1(RSPEC_TYPE_ADVT);
      break;
    case 2:
      rspecParser = new rspec_parser_v2(RSPEC_TYPE_ADVT);
      break;
    default:
146
      cout << "*** Unsupported rspec ver. " << rspecVersion
147 148 149 150
	   << " ... Aborting " << endl;
      exit(EXIT_FATAL);
    }
    XMLDEBUG("Found rspec ver. " << rspecVersion << endl);
151
    
152 153
    string type = XStr(advt_root->getAttribute(XStr("type").x())).c();
    if (type != "advertisement") {
154
      cout << "*** Rspec type must be \"advertisement\" in " << filename
155 156
	   << " (found " << type << ")" << endl;
      exit(EXIT_FATAL);
157
    }
158 159
    
    /*
160 161
     * These three calls do the real work of populating the assign data
     * structures
162
     */
163
    XMLDEBUG("Starting node population" << endl);
164
    if (!populate_nodes(advt_root,pg,sg,unavailable)) {
165
      cout << "*** Error reading nodes from physical topology "
166 167
	   << filename << endl;
      exit(EXIT_FATAL);
168
    }
169 170
    XMLDEBUG("Finishing node population" << endl);
    XMLDEBUG("Starting link population" << endl);
171
    if (!populate_links(advt_root,pg,sg,unavailable)) {
172
      cout << "*** Error reading links from physical topology "
173 174
	   << filename << endl;
      exit(EXIT_FATAL);
175
    }
176 177
    XMLDEBUG("Finishing link population" << endl);
    XMLDEBUG("Setting type limits" << endl);
178
    if (!populate_type_limits(advt_root, pg, sg)) {
179
      cout << "*** Error setting type limits " << filename << endl;
180 181
      exit(EXIT_FATAL);
    }
182 183 184 185 186 187 188 189
    XMLDEBUG("Finishing setting type limits" << endl);
    XMLDEBUG("Starting policy population" << endl);
    if (!populate_policies(advt_root, pg, sg)) {
      cout << "*** Error setting policies " << filename << endl;
      exit(EXIT_FATAL);
    }
    XMLDEBUG("Finishing setting policies" << endl);
    
190
    XMLDEBUG("RSpec parsing finished" << endl); 
191 192 193 194 195 196
  }
  
  /*
   * All done, clean up memory
   */
  //     XMLPlatformUtils::Terminate();
197
  delete rspecParser;
198
  return 0;
199 200 201 202 203
}

/*
 * Pull nodes from the document, and populate assign's own data structures
 */
204 205
bool populate_nodes(DOMElement *root, 
		    tb_pgraph &pg, tb_sgraph &sg, set<string> &unavailable) {
206
  static bool displayedWarning = false;
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
  bool is_ok = true;
  pair<map<string, DOMElement*>::iterator, bool> insert_ret;
  /*
   * 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);
  
  int availableCount = 0;
  for (size_t i = 0; i < nodeCount; i++) {
    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);
    
    bool hasComponentId;
    bool hasCMId;
    string componentId = rspecParser->readPhysicalId(elt, hasComponentId);
    string componentManagerId = rspecParser->readComponentManagerId(elt,hasCMId);
227

228 229 230 231 232
    bool hasComponentName;
    string componentName 
      = rspecParser->readComponentName (elt, hasComponentName);
    shortNodeNames.insert(pair<string,string>(componentId, componentName));

233 234 235 236 237
    if (!hasComponentId || !hasCMId) {
      is_ok = false;
      continue;
    }
    
238
   // Maintain a list of componentId's seen so far to ensure no duplicates
239 240
    insert_ret = advertisement_elements->insert
      (pair<string, DOMElement*>(componentId, elt));
241
    if (insert_ret.second == false) {
242
      cout << "*** " << componentId << " already exists" << endl;
243 244
      is_ok = false;
    }
245 246 247 248
    
    // XXX: This should not have to be called manually
    bool allUnique;
    rspecParser->readInterfacesOnNode(elt, allUnique);
249 250

    // XXX: We don't ever do anything with this, so I am commenting it out
251 252 253 254
    if (!displayedWarning) {
      cout << "WARNING: Country information will be ignored" << endl;
      displayedWarning = true;
    }
255 256 257 258
    
    pvertex pv;
    
    tb_pnode *p;
259
    /*
260
     * TODO: These three steps shouldn't be 'manual'
261
     */
262 263 264 265 266 267 268 269 270 271 272
    pv = add_vertex(pg);
    // XXX: This is wrong!
    p = new tb_pnode(componentId);
    // XXX: Global
    put(pvertex_pmap,pv,p);
    /*
     * XXX: This shouldn't be "manual"
     */
    pname2vertex[componentId.c_str()] = pv;
    
    int typeCount;
273
    vector<struct node_type>types = rspecParser->readNodeTypes(elt, typeCount);
274 275
    for (int i = 0; i < typeCount; i++) {
      node_type type = types[i];
276
      string typeName = type.typeName;
277 278
      int typeSlots = type.typeSlots;
      bool isStatic = type.isStatic;
279

280 281 282 283 284 285 286 287 288 289 290 291 292 293
      // Add the type into assign's data structures
      if (ptypes.find(typeName) == ptypes.end()) {
	ptypes[typeName] = new tb_ptype(typeName);
      }
      ptypes[typeName]->add_slots(typeSlots);
      tb_ptype *ptype = ptypes[typeName];
      
      /*
       * For the moment, we treat switches specially - when we get the
       * "forwarding" code working correctly, this special treatment
       * will go away.
       * TODO: This should not be in the parser, it should be somewhere
       * else!
       */
294
      if (typeName == "switch") {
295 296 297 298 299 300 301 302 303 304
	p->is_switch = true;
	p->types["switch"] = new tb_pnode::type_record(1,false,ptype);
	svertex sv = add_vertex(sg);
	tb_switch *s = new tb_switch();
	put(svertex_pmap,sv,s);
	s->mate = pv;
	p->sgraph_switch = sv;
	p->switches.insert(pv);
      } 
      else {
305
	p->types[typeName.c_str()]
306 307
	  = new tb_pnode::type_record(typeSlots,isStatic,ptype);
      }
308
      p->type_list.push_back(p->types[typeName.c_str()]);
309 310 311 312 313 314 315
    }
    
    bool hasExclusive;
    string exclusive = rspecParser->readExclusive(elt, hasExclusive);
    
    if (hasExclusive) {
      fstring feature ("shared");
316
      if (exclusive == "false" || exclusive == "0") {
317 318 319 320
	p->features.push_front
	  (tb_node_featuredesire(feature, 1.0, true,
				 featuredesire::FD_TYPE_NORMAL));
      }
321 322 323 324 325 326 327 328
      else if (exclusive != "true" && exclusive != "1") {
	static int syntax_error;
	if ( !syntax_error ) { 
	  syntax_error = 1;
	  cout << "WARNING: unrecognized exclusive attribute \""
	       << exclusive << "\"; Asuming exclusive = \"true\"" << endl;
	}
      }
329 330 331 332
    }
    
    // Add the component_manager_uuid as a feature.
    // We need to do this to handle external references
333 334 335
    tb_node_featuredesire node_fd (XStr(componentManagerId.c_str()).f(), 
				   0.9);//, false, featuredesire::FD_TYPE_NORMAL);
    (p->features).push_front(node_fd);
336

337 338 339 340 341 342 343 344 345 346 347 348 349
    // This has to be at the end becuase if we don't populate
    // at least the interfaces, we get all kinds of crappy errors
    bool isAvailable;
    string available = rspecParser->readAvailable(elt, isAvailable);
    if (available == "false") {
      unavailable.insert(componentId);
      continue;
    }
    ++availableCount;

    bool isSubnode = false;
    int subnodeCnt;
    string subnodeOf = rspecParser->readSubnodeOf (elt, isSubnode, subnodeCnt);
350
    if (isSubnode) {
351
      if (subnodeCnt > 1) {
352
	cout << "*** Too many \"subnode\" relations found in "
353
	     << componentId << "Allowed 1 ... " << endl;
354 355
	is_ok = false;
	continue;
356
      }
357 358 359 360 361
      else { 
	// Just store the name for now, we'll do late binding to
	// an actual pnode later
	p->subnode_of_name = XStr(subnodeOf.c_str()).f();
      }
362
    }
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

    // Deal with features
    int fdsCount;
    vector<struct fd> fds = rspecParser->readFeaturesDesires(elt, fdsCount);
    for (int i = 0; i < fdsCount; i++) {
      struct fd feature = fds[i];
      featuredesire::fd_type fd_type;
      switch(feature.op.type) {
      case LOCAL_OPERATOR:
	fd_type = featuredesire::FD_TYPE_LOCAL_ADDITIVE;
	break;
      case GLOBAL_OPERATOR:
	if (feature.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(feature.fd_name.c_str()).f(),
				     feature.fd_weight,
				     feature.violatable,
				     fd_type);
      (p->features).push_front(node_fd);
    }
392
    
393 394 395 396 397 398 399 400 401 402 403
    // Read extensions for emulab-specific flags
    bool hasTrivialBw;
    int trivialBw = rspecParser->readTrivialBandwidth(elt, hasTrivialBw);
    if (hasTrivialBw) {
      p->trivial_bw = trivialBw;
    }

    if (rspecParser->readUnique(elt)) {
      p->unique = true;
    }

404
    /*
405
     * XXX: Is this really necessary?
406
     */
407 408 409 410 411 412 413 414 415 416 417 418 419
    p->features.sort();
  }
  
  /*
   * This post-pass binds subnodes to their parents
   */
  bind_ptop_subnodes(pg);
  XMLDEBUG ("Found " << availableCount << " available nodes" << endl);
  /*
   * Indicate no errors
   */
  
  return is_ok;
420 421 422 423 424
}

/*
 * Pull the links from the ptop file, and populate assign's own data sturctures
 */
425
bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
426
			  set<string> &unavailable) {
427
    
428 429
  bool is_ok = true;
  pair<map<string, DOMElement*>::iterator, bool> insert_ret;
430 431 432 433

  // It should be safe to read it now because all the short interface names
  // have been populated once all the nodes have been read.
  map<string, string> shortNames = rspecParser->getShortNames();
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
  
  /*
   * TODO: Support the "PENALIZE_BANDWIDTH" option?
   * TODO: Support the "FIX_PLINK_ENDPOINTS" and "FIX_PLINKS_DEFAULT"?
   */
  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);
    
    bool hasComponentId;
    bool hasCMId;
    string componentId = rspecParser->readPhysicalId(elt, hasComponentId);
    string cmId = rspecParser->readComponentManagerId(elt, hasCMId);
    
    if (!hasComponentId || !hasCMId) {
454
      cout << "*** Require component ID and component manager ID" << endl;
455 456 457 458 459 460 461
      is_ok = false;
    }
    else {
      insert_ret = 
	advertisement_elements->insert(pair<string, DOMElement*>
				       (componentId, elt));
      if (insert_ret.second == false) {
462
	cout << "*** " << componentId << " already exists" << endl;
463 464 465
	is_ok = false;
      }
    }
466

467
    /*
468 469
     * Get source and destination interfaces - we use knowledge of the
     * schema that there is awlays exactly one source and one destination
470
     */
471 472 473 474 475 476 477
    int ifaceCount = 0;
    vector<struct link_interface> interfaces 
      = rspecParser->readLinkInterface(elt, ifaceCount);
    
    // Error handling
    switch (ifaceCount) {
    case RSPEC_ERROR_UNSEEN_NODEIFACE_SRC:
478
      cout << "*** Unseen node-interface pair on the source interface ref"
479 480 481 482 483
	   << endl;
      is_ok = false;
      continue;
      
    case RSPEC_ERROR_UNSEEN_NODEIFACE_DST:
484
      cout << "*** Unseen node-interface pair on the destination interface ref"
485 486 487 488 489
	   << endl;
      is_ok = false;
      continue;
    }
    
490
    if (ifaceCount != 2) {
491
      cout << "*** Incorrect number of interfaces found on link " 
492 493 494 495 496 497
	   << componentId << ". Expected 2 (found " 
	   << ifaceCount << ")" << endl;
      is_ok = false;
      continue;
    }

498 499 500 501
    string src_node = interfaces[0].physicalNodeId;
    string src_iface = interfaces[0].physicalIfaceId;
    string dst_node = interfaces[1].physicalNodeId;
    string dst_iface = interfaces[1].physicalIfaceId;
502

503
    if (src_node == "" || src_iface == "") {
504
      cout << "*** Physical link " << componentId 
505 506 507 508 509 510
	   << " must have a component id and component interface id "
	   << " specified for the source node" << endl;
      is_ok = false;
      continue;
    }
    if (dst_node == "" || dst_iface == "") {
511
      cout << "*** Physical link " << componentId 
512 513 514 515 516
	   << " must have a component id and component interface id"
	   << " specified for the destination node" << endl;
      is_ok = false;
      continue;
    }
517

518 519 520
    pIfacesMap->insert(pair<string, string>(src_iface, src_node));
    pIfacesMap->insert(pair<string, string>(dst_iface, dst_node));

521 522 523 524 525
    if( unavailable.count( src_node ) || 
	unavailable.count( dst_node ) )
      //one or both of the endpoints are unavailable; silently
      //ignore the link
      continue;
526

527 528 529 530 531 532
    /*
     * Get standard link characteristics
     */
    int count;
    link_characteristics characteristics
      = rspecParser->readLinkCharacteristics (elt, count);
533 534 535 536 537 538 539 540 541 542 543 544

    if (count == RSPEC_ASYMMETRIC_LINK) {
      cout << "*** Disallowed asymmetric link found on " << componentId
           << ". Links must be symmetric" << endl;
      is_ok = false;
    }
    else if (count > 2) {
      cout << "*** Too many link properties found on " << componentId
           << ". Max. allowed: 2" << endl;
      is_ok = false;
    }

545 546
    int bandwidth = characteristics.bandwidth;
    int latency = characteristics.latency;
547
    double packetLoss = characteristics.packetLoss;
548
      
549 550 551 552 553 554 555 556 557 558 559 560 561 562
    /*
     * Find the nodes in the existing data structures
     */
    pvertex src_vertex = pname2vertex[src_node.c_str()];
    pvertex dst_vertex = pname2vertex[dst_node.c_str()];
    tb_pnode *src_pnode = get(pvertex_pmap,src_vertex);
    tb_pnode *dst_pnode = get(pvertex_pmap,dst_vertex);
    
    /*
     * Start getting link types - we know there is at least one, and we
     * need it for the constructor
     */
    int typeCount;
    vector<link_type> types = rspecParser->readLinkTypes(elt, typeCount);
563
    string str_first_type = types[0].typeName;
564 565 566 567 568 569 570 571 572 573 574 575 576

    /* Create srcmac and dstmacs which are needed by the code which 
     * parsers assign's output
     */

    string srcMac = "(null)", dstMac = "(null)";
    if (shortNames[src_iface] != "(null)") {
      srcMac = shortNodeNames[src_node] + "/" + shortNames[src_iface];
    }
    if (shortNames[dst_iface] != "(null)") {
      dstMac = shortNodeNames[dst_node] + "/" + shortNames[dst_iface];
    }
      
577 578 579 580 581 582 583 584 585
    /*
     * Create the actual link object
     */
    pedge phys_edge = (add_edge(src_vertex,dst_vertex,pg)).first;
    // XXX: Link type!?
    // XXX: Don't want to use (null) src and dest macs, but would break
    // other stuff if I remove them... bummer!
    tb_plink *phys_link =
      new tb_plink(componentId.c_str(), 
586
		   tb_plink::PLINK_NORMAL, str_first_type.c_str(),
587 588
                   src_pnode->name, srcMac.c_str(), shortNames[src_iface],
                   dst_pnode->name, dstMac.c_str(), shortNames[dst_iface]);
589 590 591 592
    
    phys_link->delay_info.bandwidth = bandwidth;
    phys_link->delay_info.delay = latency;
    phys_link->delay_info.loss = packetLoss;
593
		
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
    // XXX: Should not be manual
    put(pedge_pmap, phys_edge, phys_link);
    
    
    // ******************************************
    // XXX: This is weird. It has to be clarified
    // ******************************************
#ifdef PENALIZE_BANDWIDTH
    float penalty = 1.0
      phys_link -> penalty = penalty;
#endif
    
    // XXX: Likewise, should happen automatically, but the current tb_plink
    // strucutre doesn't actually have pointers to the physnode endpoints
    src_pnode->total_interfaces++;
    dst_pnode->total_interfaces++;
610 611
    src_pnode->link_counts[str_first_type.c_str()]++;
    dst_pnode->link_counts[str_first_type.c_str()]++;
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
    
    /*
     * Add in the rest of the link types we found
     */
    for (int i = 1; i < typeCount; i++) {
      const char *str_type_name = types[i].typeName.c_str();
      ////XMLDEBUG("  Link has type " << type_name << endl);
      // XXX: Should not be manual
      phys_link->types.insert(str_type_name);
      src_pnode->link_counts[str_type_name]++;
      dst_pnode->link_counts[str_type_name]++;
    }
    
    if (ISSWITCH(src_pnode) && ISSWITCH(dst_pnode)) {
      svertex src_switch = get(pvertex_pmap,src_vertex)->sgraph_switch;
      svertex dst_switch = get(pvertex_pmap,dst_vertex)->sgraph_switch;
      sedge swedge = add_edge(src_switch,dst_switch,sg).first;
      tb_slink *sl = new tb_slink();
      put(sedge_pmap,swedge,sl);
      sl->mate = phys_edge;
      phys_link->is_type = tb_plink::PLINK_INTERSWITCH;
    }
    
    else if (ISSWITCH(src_pnode) && ! ISSWITCH(dst_pnode)) {
      dst_pnode->switches.insert(src_vertex);
637
#ifdef PER_VNODE_TT
638
      dst_pnode->total_bandwidth += bandwidth;
639
#endif
640 641 642 643
    }
    
    else if (ISSWITCH(dst_pnode) && ! ISSWITCH(src_pnode)) {
	src_pnode->switches.insert(dst_vertex);
644
#ifdef PER_VNODE_TT
645
	src_pnode->total_bandwidth += bandwidth;
646 647 648 649 650 651
#endif
    } else {
        // Neither is a switch - a direct node->node link
#ifdef PER_VNODE_TT
      dst_pnode->total_bandwidth += bandwidth;
      src_pnode->total_bandwidth += bandwidth;
652
#endif
653 654 655 656 657 658 659 660 661 662 663 664 665 666
    }
    
  }
  return is_ok;
}

bool populate_type_limits(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg)
{
  int count;
  vector<struct type_limit> rv = rspecParser->readTypeLimits(root, count);
  XMLDEBUG ("Found " << count << " type limits" << endl);
  for (int i = 0; i < count; i++) {
    fstring type = XStr(rv[i].typeClass.c_str()).f();
    int max = rv[i].typeCount;
667

668 669
    if (ptypes.find(type) == ptypes.end()) {
      ptypes[type] = new tb_ptype(type);
670
    }
671 672 673
    ptypes[type]->set_max_users(max);
  }  
  return true;
674 675
}

676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
bool populate_policies (DOMElement* root, tb_pgraph &pg, tb_sgraph &sg)
{
  int count;
  bool is_ok = true;
  vector<struct policy> policies = rspecParser->readPolicies(root, count);
  XMLDEBUG ("Found " << count << " policies" << endl);
  for (int i = 0; i < count; i++) {
    struct policy policy = policies[i];
    string name = policy.name;
    string limit = policy.limit;
    tb_featuredesire *fd 
      = tb_featuredesire::get_featuredesire_by_name(((fstring)XStr(name).c()));
    if (fd == NULL) {
      cerr << "*** Desire " << name << " not found" << endl;
      is_ok &= false;
    }
    else {
      if (limit == "disallow") {
	fd->disallow_desire();
      }
      else {
	fd->limit_desire(rspec_parser_helper::stringToNum(limit));
      }
    }
  }
  return is_ok;
}   

704
#endif