parse_advertisement_rspec.cc 22 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_advertisement_rspec.cc,v 1.7 2009-10-21 20:49:26 tarunp Exp $";
29 30 31 32 33 34

#ifdef WITH_XML

#include "parse_advertisement_rspec.h"
#include "xmlhelpers.h"
#include "parse_error_handler.h"
35
#include "rspec_parser_helper.h"
36
#include "rspec_parser_v1.h"
37
#include "rspec_parser_v2.h"
38 39 40

#include <fstream>
#include <map>
41
#include <set>
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
	#define SCHEMA_LOCATION TBROOT"/lib/assign/ad.xsd"
51
#else
52
	#define SCHEMA_LOCATION "ad.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
// This is a hash map of the entire physical topology 
// because it takes far too long for it to search the XML DOM tree.
78 79 80
map<string,DOMElement*>* advertisement_elements= new map<string,DOMElement*>();

map<string, string>* pIfacesMap = new map<string, string>();
81
map<string, string> shortNodeNames;
82

83
DOMElement* advt_root = NULL;
84 85 86 87 88 89 90 91

/*
 * 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);

92
static rspec_parser* rspecParser;
93

94 95 96 97
/*
 * These are not meant to be used outside of this file, so they are only
 * declared in here
 */
98
static bool populate_nodes(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
99
			   set<string> &unavailable);
100
static bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
101 102 103
			   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);
104

105
int parse_advertisement(tb_pgraph &pg, tb_sgraph &sg, char *filename) {
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
  /* 
   * 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
   */
132
  XMLDEBUG("Begin XML parse" << endl);
133
  domParser->parse(filename);
134
  XMLDEBUG("XML parse completed" << endl);
135 136 137 138 139
  
  /* 
   * If there are any errors, do not go any further
   */
  if (errHandler->sawError()) {
140
    cout << "*** There were " << domParser -> getErrorCount () 
141
	 << " errors in " << filename << endl;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    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:
163
      cout << "*** Unsupported rspec ver. " << rspecVersion
164 165 166 167
	   << " ... Aborting " << endl;
      exit(EXIT_FATAL);
    }
    XMLDEBUG("Found rspec ver. " << rspecVersion << endl);
168
    
169 170
    string type = XStr(advt_root->getAttribute(XStr("type").x())).c();
    if (type != "advertisement") {
171
      cout << "*** Rspec type must be \"advertisement\" in " << filename
172 173
	   << " (found " << type << ")" << endl;
      exit(EXIT_FATAL);
174
    }
175 176
    
    /*
177 178
     * These three calls do the real work of populating the assign data
     * structures
179
     */
180
    XMLDEBUG("Starting node population" << endl);
181
    if (!populate_nodes(advt_root,pg,sg,unavailable)) {
182
      cout << "*** Error reading nodes from physical topology "
183 184
	   << filename << endl;
      exit(EXIT_FATAL);
185
    }
186 187
    XMLDEBUG("Finishing node population" << endl);
    XMLDEBUG("Starting link population" << endl);
188
    if (!populate_links(advt_root,pg,sg,unavailable)) {
189
      cout << "*** Error reading links from physical topology "
190 191
	   << filename << endl;
      exit(EXIT_FATAL);
192
    }
193 194
    XMLDEBUG("Finishing link population" << endl);
    XMLDEBUG("Setting type limits" << endl);
195
    if (!populate_type_limits(advt_root, pg, sg)) {
196
      cout << "*** Error setting type limits " << filename << endl;
197 198
      exit(EXIT_FATAL);
    }
199 200 201 202 203 204 205 206
    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);
    
207
    XMLDEBUG("RSpec parsing finished" << endl); 
208 209 210 211 212 213
  }
  
  /*
   * All done, clean up memory
   */
  //     XMLPlatformUtils::Terminate();
214
  delete rspecParser;
215
  return 0;
216 217 218 219 220
}

/*
 * Pull nodes from the document, and populate assign's own data structures
 */
221 222
bool populate_nodes(DOMElement *root, 
		    tb_pgraph &pg, tb_sgraph &sg, set<string> &unavailable) {
223
  static bool displayedWarning = false;
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
  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);
244

245 246 247 248 249
    bool hasComponentName;
    string componentName 
      = rspecParser->readComponentName (elt, hasComponentName);
    shortNodeNames.insert(pair<string,string>(componentId, componentName));

250 251 252 253 254
    if (!hasComponentId || !hasCMId) {
      is_ok = false;
      continue;
    }
    
255
   // Maintain a list of componentId's seen so far to ensure no duplicates
256 257
    insert_ret = advertisement_elements->insert
      (pair<string, DOMElement*>(componentId, elt));
258
    if (insert_ret.second == false) {
259
      cout << "*** " << componentId << " already exists" << endl;
260 261
      is_ok = false;
    }
262 263 264 265
    
    // XXX: This should not have to be called manually
    bool allUnique;
    rspecParser->readInterfacesOnNode(elt, allUnique);
266 267

    // XXX: We don't ever do anything with this, so I am commenting it out
268 269 270 271
    if (!displayedWarning) {
      cout << "WARNING: Country information will be ignored" << endl;
      displayedWarning = true;
    }
272 273 274 275
    
    pvertex pv;
    
    tb_pnode *p;
276
    /*
277
     * TODO: These three steps shouldn't be 'manual'
278
     */
279 280 281 282 283 284 285 286 287 288 289
    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;
290
    vector<struct node_type>types = rspecParser->readNodeTypes(elt, typeCount);
291 292
    for (int i = 0; i < typeCount; i++) {
      node_type type = types[i];
293
      string typeName = type.typeName;
294 295
      int typeSlots = type.typeSlots;
      bool isStatic = type.isStatic;
296

297 298 299 300 301 302 303 304 305 306 307 308 309 310
      // 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!
       */
311
      if (typeName == "switch") {
312 313 314 315 316 317 318 319 320 321
	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 {
322
	p->types[typeName.c_str()]
323 324
	  = new tb_pnode::type_record(typeSlots,isStatic,ptype);
      }
325
      p->type_list.push_back(p->types[typeName.c_str()]);
326 327 328 329 330 331 332
    }
    
    bool hasExclusive;
    string exclusive = rspecParser->readExclusive(elt, hasExclusive);
    
    if (hasExclusive) {
      fstring feature ("shared");
333
      if (exclusive == "false" || exclusive == "0") {
334 335 336 337
	p->features.push_front
	  (tb_node_featuredesire(feature, 1.0, true,
				 featuredesire::FD_TYPE_NORMAL));
      }
338 339 340 341 342 343 344 345
      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;
	}
      }
346 347 348 349
    }
    
    // Add the component_manager_uuid as a feature.
    // We need to do this to handle external references
350 351 352
    tb_node_featuredesire node_fd (XStr(componentManagerId.c_str()).f(), 
				   0.9);//, false, featuredesire::FD_TYPE_NORMAL);
    (p->features).push_front(node_fd);
353

354 355 356 357 358 359 360 361 362 363 364 365 366
    // 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);
367
    if (isSubnode) {
368
      if (subnodeCnt > 1) {
369
	cout << "*** Too many \"subnode\" relations found in "
370
	     << componentId << "Allowed 1 ... " << endl;
371 372
	is_ok = false;
	continue;
373
      }
374 375 376 377 378
      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();
      }
379
    }
380 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

    // 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);
    }
409
    
410 411 412 413 414 415 416 417 418 419 420
    // 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;
    }

421
    /*
422
     * XXX: Is this really necessary?
423
     */
424 425 426 427 428 429 430 431 432 433 434 435 436
    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;
437 438 439 440 441
}

/*
 * Pull the links from the ptop file, and populate assign's own data sturctures
 */
442
bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
443
			  set<string> &unavailable) {
444
    
445 446
  bool is_ok = true;
  pair<map<string, DOMElement*>::iterator, bool> insert_ret;
447 448 449 450

  // 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();
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
  
  /*
   * 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) {
471
      cout << "*** Require component ID and component manager ID" << endl;
472 473 474 475 476 477 478
      is_ok = false;
    }
    else {
      insert_ret = 
	advertisement_elements->insert(pair<string, DOMElement*>
				       (componentId, elt));
      if (insert_ret.second == false) {
479
	cout << "*** " << componentId << " already exists" << endl;
480 481 482
	is_ok = false;
      }
    }
483

484
    /*
485 486
     * Get source and destination interfaces - we use knowledge of the
     * schema that there is awlays exactly one source and one destination
487
     */
488 489 490 491 492 493 494
    int ifaceCount = 0;
    vector<struct link_interface> interfaces 
      = rspecParser->readLinkInterface(elt, ifaceCount);
    
    // Error handling
    switch (ifaceCount) {
    case RSPEC_ERROR_UNSEEN_NODEIFACE_SRC:
495
      cout << "*** Unseen node-interface pair on the source interface ref"
496 497 498 499 500
	   << endl;
      is_ok = false;
      continue;
      
    case RSPEC_ERROR_UNSEEN_NODEIFACE_DST:
501
      cout << "*** Unseen node-interface pair on the destination interface ref"
502 503 504 505 506
	   << endl;
      is_ok = false;
      continue;
    }
    
507
    if (ifaceCount != 2) {
508
      cout << "*** Incorrect number of interfaces found on link " 
509 510 511 512 513 514
	   << componentId << ". Expected 2 (found " 
	   << ifaceCount << ")" << endl;
      is_ok = false;
      continue;
    }

515 516 517 518
    string src_node = interfaces[0].physicalNodeId;
    string src_iface = interfaces[0].physicalIfaceId;
    string dst_node = interfaces[1].physicalNodeId;
    string dst_iface = interfaces[1].physicalIfaceId;
519

520
    if (src_node == "" || src_iface == "") {
521
      cout << "*** Physical link " << componentId 
522 523 524 525 526 527
	   << " must have a component id and component interface id "
	   << " specified for the source node" << endl;
      is_ok = false;
      continue;
    }
    if (dst_node == "" || dst_iface == "") {
528
      cout << "*** Physical link " << componentId 
529 530 531 532 533
	   << " must have a component id and component interface id"
	   << " specified for the destination node" << endl;
      is_ok = false;
      continue;
    }
534

535 536 537
    pIfacesMap->insert(pair<string, string>(src_iface, src_node));
    pIfacesMap->insert(pair<string, string>(dst_iface, dst_node));

538 539 540 541 542
    if( unavailable.count( src_node ) || 
	unavailable.count( dst_node ) )
      //one or both of the endpoints are unavailable; silently
      //ignore the link
      continue;
543

544 545 546 547 548 549
    /*
     * Get standard link characteristics
     */
    int count;
    link_characteristics characteristics
      = rspecParser->readLinkCharacteristics (elt, count);
550 551 552 553 554 555 556 557 558 559 560 561

    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;
    }

562 563
    int bandwidth = characteristics.bandwidth;
    int latency = characteristics.latency;
564
    double packetLoss = characteristics.packetLoss;
565
      
566 567 568 569 570 571 572 573 574 575 576 577 578 579
    /*
     * 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);
580
    string str_first_type = types[0].typeName;
581 582 583 584 585 586 587 588 589 590 591 592 593

    /* 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];
    }
      
594 595 596 597 598 599 600 601 602
    /*
     * 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(), 
603
		   tb_plink::PLINK_NORMAL, str_first_type.c_str(),
604 605
                   src_pnode->name, srcMac.c_str(), shortNames[src_iface],
                   dst_pnode->name, dstMac.c_str(), shortNames[dst_iface]);
606 607 608 609
    
    phys_link->delay_info.bandwidth = bandwidth;
    phys_link->delay_info.delay = latency;
    phys_link->delay_info.loss = packetLoss;
610
		
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
    // 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++;
627 628
    src_pnode->link_counts[str_first_type.c_str()]++;
    dst_pnode->link_counts[str_first_type.c_str()]++;
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
    
    /*
     * 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);
654
#ifdef PER_VNODE_TT
655
      dst_pnode->total_bandwidth += bandwidth;
656
#endif
657 658 659 660
    }
    
    else if (ISSWITCH(dst_pnode) && ! ISSWITCH(src_pnode)) {
	src_pnode->switches.insert(dst_vertex);
661
#ifdef PER_VNODE_TT
662
	src_pnode->total_bandwidth += bandwidth;
663 664 665 666 667 668
#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;
669
#endif
670 671 672 673 674 675 676 677 678 679 680 681 682 683
    }
    
  }
  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;
684

685 686
    if (ptypes.find(type) == ptypes.end()) {
      ptypes[type] = new tb_ptype(type);
687
    }
688 689 690
    ptypes[type]->set_max_users(max);
  }  
  return true;
691 692
}

693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
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;
}   

721
#endif