rspec_parser_v2.cc 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2010 University of Utah and the Flux Group.
 * All rights reserved.
 */

/*
 * XML parser for RSPEC version 2.0
 */

#ifdef WITH_XML

13
#include "common.h"
14 15 16
#include "rspec_parser_v2.h"
#include "rspec_parser.h"

17
#include <cstdlib>
18 19 20 21 22 23 24 25 26
#include <string>
#include <vector>
#include <xercesc/dom/DOM.hpp>

#include "xstr.h"

XERCES_CPP_NAMESPACE_USE

using namespace std;
27
using namespace rspec_emulab_extension;
28

29 30
vector<struct link_interface> 
rspec_parser_v2::readLinkInterface (const DOMElement* link, int& ifaceCount)
31
{
32
  vector<struct link_interface> rv;
33 34 35 36 37 38 39
  // We can't use getElementsByTagName here because
  // that returns all interface_refs in all descendants of link
  // which would include any component hops
  // as would be present in a partially-mapped rspec.
  vector<DOMElement*> interfaceRefs 
    = this->getChildrenByName(link, "interface_ref");
  ifaceCount = interfaceRefs.size();
40
  
41
  for (int i = 0; i < ifaceCount; i += 2) {
42
    DOMElement* ref = interfaceRefs[i];
43 44 45 46
    string sourceId = this->getAttribute(ref, "component_id");
    if (this->rspecType == RSPEC_TYPE_REQ) {
      sourceId = this->getAttribute(ref, "client_id");
    }
47
    if ((this->ifacesSeen).find(sourceId) == (this->ifacesSeen).end()) {
48
      cerr << "*** Could not find source interface " << sourceId << endl;
49
      exit(EXIT_FATAL);
50
    }
51 52 53

    string destId = "";
    if ((i+1) < ifaceCount) {
54
      DOMElement* nextRef = interfaceRefs[i+1];
55 56 57 58 59
      destId = this->getAttribute(nextRef, "component_id");
      if (this->rspecType == RSPEC_TYPE_REQ) {
	destId = this->getAttribute(nextRef, "client_id");
      }
      if ((this->ifacesSeen).find(destId) == (this->ifacesSeen).end()) {
60
	cerr << "*** Could not find destination interface " << destId << endl;
61
	exit(EXIT_FATAL);
62
      }
63
    }
64

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    struct link_interface srcIface, dstIface;
    if (this->rspecType == RSPEC_TYPE_ADVT) {
      srcIface.physicalNodeId = this->ifacesSeen[sourceId];
      srcIface.physicalIfaceId = sourceId;
      dstIface.physicalNodeId = this->ifacesSeen[destId];
      dstIface.physicalIfaceId = destId;
    }
    else { // if (this->rspecType == RSPEC_TYPE_REQ)
      srcIface.virtualNodeId = this->ifacesSeen[sourceId];
      srcIface.virtualIfaceId = sourceId;
      dstIface.virtualNodeId = this->ifacesSeen[destId];
      dstIface.virtualIfaceId = destId;
    }
    
    rv.push_back(srcIface);
    rv.push_back(dstIface);
  }
  return rv;
83 84
}

85 86 87 88
// Since this parser is meant to be used by assign,
// and assign doesn't allow for asymmetric properties on a single link,
// this only returns the specified values when there is only one link property
// 
89
// Returns a link_characteristics element
90 91 92 93 94
struct link_characteristics 
rspec_parser_v2 :: readLinkCharacteristics (const DOMElement* link,
					    int& count,
					    int defaultBandwidth,
					    int unlimitedBandwidth)
95
{
96
  DOMNodeList* properties = link->getElementsByTagName(XStr("property").x());
97
  
98
  string strBw = "", strLat = "", strLoss = "";
99
  bool hasBandwidth, hasLatency, hasPacketLoss;
100 101
  count = properties->getLength();

102 103 104 105 106
  // Read only from the first property and ignore the rest
  DOMElement* property = dynamic_cast<DOMElement*>(properties->item(0));
  strBw = this->getAttribute(property, "capacity", hasBandwidth);
  strLat = this->getAttribute(property, "latency", hasLatency);
  strLoss = this->getAttribute(property, "packet_loss", hasPacketLoss);
107

108 109 110 111 112 113 114 115 116 117 118 119 120 121
  int bandwidth = 0, latency = 0;
  float packetLoss = 0.0;
  if (!hasBandwidth)
    bandwidth = defaultBandwidth;
  else if(strBw == "unlimited")
    bandwidth = unlimitedBandwidth;
  else
    bandwidth = atoi(strBw.c_str());
  
  latency = hasLatency ? atoi(strLat.c_str()) : 0 ;
  packetLoss = hasPacketLoss ? atof(strLoss.c_str()) : 0.0;
  
  struct link_characteristics rv = {bandwidth, latency, packetLoss};
  return rv;
122 123
}

124 125 126 127
vector<struct node_type> 
rspec_parser_v2::readNodeTypes (const DOMElement* node,
				int& typeCount,
				int unlimitedSlots)
128
{
129 130 131 132 133
  string defHw = "pc";
  string defSl = "raw-pc";
  bool isSwitch = false;

  vector<struct node_type> types;
134 135 136 137 138 139 140 141 142 143 144
  DOMNodeList* sliverTypes 
    = node->getElementsByTagName(XStr("sliver_type").x());
  DOMNodeList* hardwareTypes 
    = node->getElementsByTagName(XStr("hardware_type").x());

  if (hardwareTypes->getLength() == 0) {
    // If there are no sliver types, return an empty vector
    if (sliverTypes->getLength() == 0) {
      typeCount = 0;
      return vector<struct node_type>();
    }
145

146 147
    for (int j = 0; j < sliverTypes->getLength(); j++) {
      DOMElement* slNode = dynamic_cast<DOMElement*>(sliverTypes->item(j));
148
      string slTypeName = this->getAttribute(slNode, "name");
149
      string typeName = this->convertType(defHw, slTypeName);
150 151 152 153 154 155
      struct node_type type = {typeName, 1, false};
      types.push_back(type);
    }
  }
  
  for (int i = 0; i < hardwareTypes->getLength(); i++) {
156 157
    DOMElement* hardwareNode 
      = dynamic_cast<DOMElement*>(hardwareTypes->item(i));
158 159
    
    string hwTypeName = this->getAttribute (hardwareNode, "name");
160

161 162 163 164 165
    string slot = (this->emulabExtensions)->readTypeSlots(hardwareNode);
    // Default number of slots
    if (slot == "") {
      slot = "unlimited";
    }
166 167
    int typeSlots 
      = (slot == "unlimited") ? unlimitedSlots : (int)stringToNum(slot);
168
    bool isStatic = (this->emulabExtensions)->readStaticType(hardwareNode);
169 170 171 172 173 174 175 176 177 178 179 180 181

    // XXX: If the node is a switch, add it to the list of switches
    // Since switches are treated specially in assign 
    // and it's such a hardcoded &#$*% mess, if a hardware type is "switch"
    // only switch is returned and the sliver types are ignored
    // If someone wants a switch with sliver type openvz or something like that
    // they are out of luck
    if (hwTypeName == "switch") {
      isSwitch = true;
      struct node_type type = {"switch", typeSlots, isStatic};
      types.push_back(type);
      continue;
    }
182 183
    
    if (sliverTypes->getLength() == 0) {
184
      string typeName = this->convertType(hwTypeName, defSl);
185 186 187 188 189 190 191
      struct node_type type = {typeName, typeSlots, isStatic};
      types.push_back(type);
    }

    for (int j = 0; j < sliverTypes->getLength(); j++) {
      DOMElement* slNode = dynamic_cast<DOMElement*>(sliverTypes->item(j));
      string slTypeName = this->getAttribute(slNode, "name");
192
      string typeName = this->convertType(hwTypeName, slTypeName);
193 194 195 196 197
      
      struct node_type type = {typeName, typeSlots, isStatic};
      types.push_back(type);
    }
  }
198 199 200 201 202

  if (isSwitch) {
    this->addSwitch(node);
  }

203 204
  typeCount = types.size();
  return types;
205 206 207
}

map< pair<string, string>, pair<string, string> >
208 209 210 211 212 213 214 215 216 217 218 219 220 221
rspec_parser_v2::readInterfacesOnNode  (const DOMElement* node, 
					bool& allUnique)
{
  DOMNodeList* ifaces = node->getElementsByTagName(XStr("interface").x());
  map< pair<string, string>, pair<string, string> > fixedInterfaces;
  allUnique = true;
  for (int i = 0; i < ifaces->getLength(); i++) {
    DOMElement* iface = dynamic_cast<DOMElement*>(ifaces->item(i));
    bool hasAttr;
    string nodeId = "";
    string ifaceId = "";
    if (this->rspecType == RSPEC_TYPE_ADVT) {
      nodeId = this->readPhysicalId (node, hasAttr);
      ifaceId = XStr(iface->getAttribute(XStr("component_id").x())).c();
222 223 224 225 226 227
      bool hasShortName = false;
      string shortName 
	= (this->emulabExtensions)->readShortInterfaceName(iface,hasShortName);
      if (hasShortName) {
	(this->shortNames).insert(pair<string,string>(ifaceId, shortName));
      }
228 229 230 231
    }
    else { //(this->rspecType == RSPEC_TYPE_REQ)
      nodeId = this->readVirtualId (node, hasAttr);
      ifaceId = XStr(iface->getAttribute(XStr("client_id").x())).c();
232 233 234 235
      bool isFixed = false;
      string fixedTo
	= (this->emulabExtensions)->readFixedInterface(iface, isFixed);
      if (isFixed) {
236 237
	fixedInterfaces.insert (make_pair 
				(make_pair(nodeId,ifaceId),
238
				 make_pair("", fixedTo)));
239 240 241 242 243 244 245 246 247 248
      }
    }
    allUnique &= ((this->ifacesSeen).insert	
		  (pair<string, string> (ifaceId, nodeId))).second;
  }
  return (fixedInterfaces);
}

// Reads the available tag. In v2, it is mandatory
string rspec_parser_v2::readAvailable (const DOMElement* node, bool& hasTag) 
249
{
250 251 252 253 254 255 256
  DOMNodeList* tags = node->getElementsByTagName(XStr("available").x());
  hasTag = (tags->getLength() > 0);
  if (hasTag) {
    DOMElement* availableNode = dynamic_cast<DOMElement*>(tags->item(0));
    return (this->getAttribute(availableNode, "now"));
  }
  return "";
257 258
}

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
vector<struct link_type> 
rspec_parser_v2::readLinkTypes (const DOMElement* link, int& typeCount)
{
  DOMNodeList* linkTypes = link->getElementsByTagName(XStr("link_type").x());
  vector<struct link_type> types;
  for (int i = 0; i < linkTypes->getLength(); i++) {
    DOMElement* tag = dynamic_cast<DOMElement*>(linkTypes->item(i));
    string name = this->getAttribute(tag, "name");

    struct link_type type = {name, name};
    types.push_back(type);
  }
  typeCount = types.size();
  return types;
}

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
string rspec_parser_v2::readSubnodeOf (const DOMElement* node,
				       bool& isSubnode,
				       int& count)
{
  int cnt = 0;
  string parent = "";
  DOMNodeList* relations = node->getElementsByTagName(XStr("relations").x());
  for (int i = 0, cnt = 0; i < relations->getLength(); i++) {
    DOMElement* relation = dynamic_cast<DOMElement*>(relations->item(0));
    string type = this->getAttribute(node, "type");
    if (type == "parent") {
      bool hasSubnode = false;
      parent = (this->emulabExtensions)->readSubnodeOf(relation, hasSubnode);
      if (hasSubnode) {
	isSubnode = true;
	++cnt;
      }
    }
  }
  count = cnt;
  if (count == 1) {
    return parent;
  }
  return "";
}

vector<struct vclass>
rspec_parser_v2::readVClasses(const DOMElement* tag) 
{
  return ((this->emulabExtensions)->readVClasses(tag));
}

307 308 309 310 311
vector<struct type_limit>
rspec_parser_v2::readTypeLimits (const DOMElement* tag, int& count)
{
  return ((this->emulabExtensions)->readTypeLimits(tag, count));
}
312

313 314 315 316 317 318
vector<struct fd>
rspec_parser_v2::readFeaturesDesires (const DOMElement* tag, int& count)
{
  return ((this->emulabExtensions)->readFeaturesDesires(tag, count));
}

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
bool rspec_parser_v2::readDisallowTrivialMix (const DOMElement* tag)
{
  return ((this->emulabExtensions)->readDisallowTrivialMix(tag));
}

bool rspec_parser_v2::readUnique (const DOMElement* tag)
{
  return ((this->emulabExtensions)->readUnique(tag));
}

int rspec_parser_v2::readTrivialBandwidth (const DOMElement* tag,
					   bool& hasTrivialBw)
{
  return ((this->emulabExtensions)->readTrivialBandwidth(tag, hasTrivialBw));
}

string rspec_parser_v2::readHintTo (const DOMElement* tag, bool& hasHintTo)
{
  return ((this->emulabExtensions)->readHintTo(tag, hasHintTo));
}

bool rspec_parser_v2::readNoDelay (const DOMElement* tag)
{
  return ((this->emulabExtensions)->readNoDelay(tag));
}

bool rspec_parser_v2::readTrivialOk (const DOMElement* tag)
{
  return ((this->emulabExtensions)->readTrivialOk(tag));
}

350 351 352 353 354 355 356 357 358 359 360
bool rspec_parser_v2::readMultiplexOk (const DOMElement* tag)
{
  return ((this->emulabExtensions)->readMultiplexOk(tag));
}

vector<struct policy> 
rspec_parser_v2::readPolicies (const DOMElement* tag, int& count) 
{
  return ((this->emulabExtensions)->readPolicies(tag, count));
}

361 362 363 364 365 366 367 368 369 370 371
string rspec_parser_v2::convertType (const string hwType, const string slType) 
{
  return rspec_parser_helper::convertType(hwType, slType);
}

string rspec_parser_v2::convertType (const string type)
{
  return rspec_parser_helper::convertType(type);
}


372
#endif // #ifdef WITH_XML