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

/*
 * Header for RSPEC parser files
 */

# ifdef WITH_XML

#include "rspec_parser.h"
14
#include "xmlhelpers.h"
15 16

#include <string>
17
#include <vector>
18 19 20
#include "xstr.h"
#include <xercesc/dom/DOM.hpp>

21 22 23 24
using namespace rspec_emulab_extension;

rspec_parser :: rspec_parser (int type)
{
25 26
  this->emulabExtensions = new emulab_extensions_parser(type);
  this->rspecType = type; 
27 28 29 30
}

rspec_parser :: ~rspec_parser ()
{
31
  delete this->emulabExtensions;
32 33
}

34 35
struct link_interface rspec_parser :: getIface (const DOMElement* tag)
{
36 37 38 39 40 41 42 43 44
  bool exists;
  struct link_interface rv = 
    {
      string(XStr(tag->getAttribute(XStr("virtual_node_id").x())).c()),
      string(XStr(tag->getAttribute(XStr("virtual_interface_id").x())).c()),
      string(XStr(tag->getAttribute(XStr("component_node_uuid").x())).c()),
      string(XStr(tag->getAttribute(XStr("component_interface_id").x())).c())
    };
  return rv;
45 46
}

47 48
// Returns the component_id. Sets an out parameter to true if an ID is present
string rspec_parser :: readPhysicalId (const DOMElement* tag, 
49
				       bool& hasComponentId)
50
{
51
  return (this->getAttribute(tag, "component_id", hasComponentId));
52 53
}

54 55 56 57 58 59 60
// Returns the component name
string rspec_parser::readComponentName (const DOMElement* tag, 
					bool& hasComponentName) 
{
  return (this->getAttribute(tag, "component_name", hasComponentName));
}

61 62
// Returns the client_id Sets an out parameter to true if an ID is present
string rspec_parser :: readVirtualId (const DOMElement* tag, bool& hasClientId)
63
{
64
  return (this->getAttribute(tag, "client_id", hasClientId));
65 66
}

67
// Returns the CMID and sets an out parameter to true if an ID is present
68
string rspec_parser :: readComponentManagerId (const DOMElement* tag, 
69
					       bool& hasCmId)
70
{
71
  return (this->getAttribute(tag, "component_manager_id", hasCmId));
72 73 74
}

string rspec_parser::readVirtualizationType (const DOMElement* tag, 
75
					     bool& hasVirtualizationType)
76
{
77 78
  return(this->getAttribute(tag, "virtualization_type",
			    hasVirtualizationType));
79 80
}

81 82
// 

83 84
// Returns true if the latitude and longitude tags are present
// Absence of the country tag will be caught by the schema validator
85
vector<string> rspec_parser :: readLocation (const DOMElement* tag,
86
					     int& rvLength)
87
{
88 89 90 91 92 93 94 95 96 97 98 99 100
  bool hasCountry, hasLatitude, hasLongitude;
  
  string country = this->getAttribute(tag, "country", hasCountry);
  string latitude = this->getAttribute(tag, "latitude", hasLatitude);
  string longitude = this->getAttribute(tag, "longitude", hasLongitude);
  
  rvLength = (hasLatitude && hasLongitude) ? 3 : 1;
  
  vector<string> rv;
  rv.push_back(country);
  rv.push_back(latitude);
  rv.push_back(longitude);
  return rv;
101 102 103 104
}

// Returns a list of node_type elements
// The out parameter contains the number of elements found
105
vector<struct node_type> rspec_parser::readNodeTypes (const DOMElement* node,
106 107
						      int& typeCount,
						      int unlimitedSlots)
108
{
109
  bool isSwitch = false;
110 111
  DOMNodeList* nodeTypes = node->getElementsByTagName(XStr("node_type").x());
  vector<struct node_type> types;
112 113 114 115 116 117
  for (int i = 0; i < nodeTypes->getLength(); i++) {
    DOMElement *tag = dynamic_cast<DOMElement*>(nodeTypes->item(i));
    
    string typeName = XStr(tag->getAttribute(XStr("type_name").x())).c();
    if (typeName == "switch") {
      isSwitch = true;
118
    }
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    int typeSlots;
    string slot = XStr(tag->getAttribute(XStr("type_slots").x())).c();
    if (slot == "unlimited")
      typeSlots = unlimitedSlots;
    else 
      typeSlots = (int)stringToNum(slot);
    
    bool isStatic = tag->hasAttribute(XStr("static").x());
    struct node_type type = {typeName, typeSlots, isStatic};
    types.push_back(type);
  }

  if (isSwitch) {
    this->addSwitch(node);
  }
134 135
  typeCount = nodeTypes->getLength();
  return types;
136 137
}

138 139
// Returns any fixed interfaces which are found
map< pair<string, string>, pair<string, string> >
140 141
rspec_parser::readInterfacesOnNode  (const DOMElement* node, 
				     bool& allUnique)
142
{
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
  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();
      }
      else { //(this->rspecType == RSPEC_TYPE_REQ)
	nodeId = this->readVirtualId (node, hasAttr);
	ifaceId = XStr(iface->getAttribute(XStr("client_id").x())).c();
	if (iface->hasAttribute(XStr("component_id").x())) {
	  bool hasComponentId;
	  string componentNodeId = 
	    this->readPhysicalId (node, hasComponentId);
	  string componentIfaceId = 
	    this->getAttribute(iface, "component_id");
	  fixedInterfaces.insert (make_pair 
				  (make_pair(nodeId,ifaceId),
				   make_pair(componentNodeId,componentIfaceId)));
168
	}
169 170 171 172 173
      }
      allUnique &= ((this->ifacesSeen).insert
		    (pair<string, string>(nodeId, ifaceId))).second;
    }
  return (fixedInterfaces);
174 175
}

176
// Returns a link_characteristics element
177
// count should be 1 on success.
178 179 180 181 182
struct link_characteristics 
rspec_parser :: readLinkCharacteristics (const DOMElement* link,
					 int& count,
					 int defaultBandwidth,
					 int unlimitedBandwidth)
183
{
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  bool hasBandwidth, hasLatency, hasPacketLoss;
  string strBw = this->readChild(link, "bandwidth", hasBandwidth);
  string strLat = this->readChild(link, "latency", hasLatency);
  string strLoss = this->readChild(link, "packet_loss", hasPacketLoss);
  
  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;
  
201
  count = 1;
202 203
  struct link_characteristics rv = {bandwidth, latency, packetLoss};
  return rv;
204 205
}

206 207
vector<struct link_interface> 
rspec_parser :: readLinkInterface (const DOMElement* link, int& ifaceCount)
208
{
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
  DOMNodeList* ifaceRefs =
    link->getElementsByTagName(XStr("interface_ref").x());
  ifaceCount = ifaceRefs->getLength();
  
  if (ifaceCount != 2) {
    ifaceCount = RSPEC_ERROR_BAD_IFACE_COUNT;
    return vector<struct link_interface>();
  }
  
  struct link_interface srcIface 
    = this->getIface(dynamic_cast<DOMElement*>(ifaceRefs->item(0)));
  struct link_interface dstIface
    = this->getIface(dynamic_cast<DOMElement*>(ifaceRefs->item(1)));
  
  pair<string, string> srcNodeIface;
  pair<string, string> dstNodeIface;
  if (this->rspecType == RSPEC_TYPE_ADVT) {
    srcNodeIface = make_pair(srcIface.physicalNodeId, srcIface.physicalIfaceId);
    dstNodeIface = make_pair(dstIface.physicalNodeId, dstIface.physicalIfaceId);
  }
  else {//(this->rspecType == RSPEC_TYPE_REQ)
    srcNodeIface = make_pair(srcIface.virtualNodeId, srcIface.virtualIfaceId);
    dstNodeIface = make_pair(dstIface.virtualNodeId, dstIface.virtualIfaceId);
  }
233
	
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  vector<struct link_interface> rv;
  // Check if the node-interface pair has been seen before.
  // If it hasn't, it is an error
  if ((this->ifacesSeen).find(srcNodeIface) == (this->ifacesSeen).end()) {
    ifaceCount = RSPEC_ERROR_UNSEEN_NODEIFACE_SRC;
    return rv;
  }
  if ((this->ifacesSeen).find(dstNodeIface) == (this->ifacesSeen).end()) {
    ifaceCount = RSPEC_ERROR_UNSEEN_NODEIFACE_DST;
    return rv;
  }
  
  rv.push_back(srcIface);
  rv.push_back(dstIface);
  return rv;
249 250
}

251
vector<struct link_type> rspec_parser::readLinkTypes (const DOMElement* link,
252
						      int& typeCount)
253
{
254 255 256 257 258 259 260 261 262 263 264 265 266
  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 = XStr(tag->getAttribute(XStr("name").x())).c();
    string typeName = XStr(tag->getAttribute(XStr("type_name").x())).c();
    
    struct link_type type = {name, typeName};
    types.push_back(type);
  }
  typeCount = linkTypes->getLength();
  return types;
267 268
}

269 270 271 272 273
map<string, string> rspec_parser::getShortNames(void)
{
  return (this->shortNames);
}

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
bool rspec_parser::checkIsSwitch (string nodeId) 
{
  return (((this->switches).find(nodeId)) != (this->switches).end());
}

void rspec_parser::addSwitch (const DOMElement* node) 
{
  bool dummy;
  string nodeId = this->readPhysicalId(node, dummy);
  if (this->rspecType == RSPEC_TYPE_REQ) {
    nodeId = this->readVirtualId(node, dummy);
  }
  (this->switches).insert(nodeId);
}

vector<struct vclass>
rspec_parser :: readVClasses (const DOMElement* tag)
{
  return vector<struct vclass>();
}

string rspec_parser :: readSubnodeOf (const DOMElement* tag, 
				      bool& isSubnode,
				      int& count)
298
{
299
  count = (tag->getElementsByTagName(XStr("subnode_of").x()))->getLength();
300
  return (this->readChild(tag, "subnode_of", isSubnode));
301 302 303 304
}

string rspec_parser :: readExclusive (const DOMElement* tag, bool& isExclusive)
{
305 306 307 308
  if (this->hasChild(tag, "exclusive")) {
    return (this->readChild(tag, "exclusive", isExclusive));
  }
  return (this->getAttribute(tag, "exclusive", isExclusive));
309 310 311 312
}

string rspec_parser :: readAvailable (const DOMElement* tag, bool& isAvailable)
{
313
  return (this->readChild(tag, "available", isAvailable));
314 315
}

316 317 318 319 320 321
vector<struct type_limit> 
rspec_parser::readTypeLimits (const DOMElement* tag, int& count) 
{
  count = 0;
  return vector<struct type_limit>();
}
322

323 324 325 326 327 328 329
vector<struct fd> 
rspec_parser::readFeaturesDesires (const DOMElement* tag, int& count) 
{
  count = 0;
  return vector<struct fd>();
}

330 331 332 333 334 335 336
vector<struct policy>
rspec_parser::readPolicies (const DOMElement* tag, int& count)
{
  count = 0;
  return vector<struct policy>();
}

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
bool rspec_parser::readDisallowTrivialMix (const DOMElement* tag)
{
  return false;
}

bool rspec_parser::readUnique (const DOMElement* tag)
{
  return false;
}

int rspec_parser::readTrivialBandwidth (const DOMElement* tag,
					 bool& hasTrivialBw)
{
  hasTrivialBw = false;
  return 0;
}

string rspec_parser::readHintTo (const DOMElement* tag, bool& hasHintTo)
{
  hasHintTo = false;
  return "";
}

bool rspec_parser::readNoDelay (const DOMElement* tag)
{
  return false;
}

bool rspec_parser::readTrivialOk (const DOMElement* tag)
{
  return false;
}

370 371 372 373
bool rspec_parser::readMultiplexOk (const DOMElement* tag)
{
  return false;
}
374 375 376 377 378 379 380 381 382 383 384 385 386 387

// In the default case, just return the type as it is. 
// Only in version 2 will we need to do something intelligent(?) with it
string rspec_parser::convertType (const string hwType) {
  return hwType;
}

// Since assign doesn't really know what multiple types mean,
// we will only return the first. Hopefully, this will never ever
// really get used outside of v2.
string rspec_parser::convertType (const string hwType, const string slType) {
  return hwType;
}

388
#endif