rspec_parser.cc 11.9 KB
Newer Older
1 2
/*
 * Copyright (c) 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 28 29 30
 */

/*
 * Header for RSPEC parser files
 */

# ifdef WITH_XML

#include "rspec_parser.h"
31
#include "xmlhelpers.h"
32 33

#include <string>
34
#include <vector>
35 36 37
#include "xstr.h"
#include <xercesc/dom/DOM.hpp>

38 39 40 41
using namespace rspec_emulab_extension;

rspec_parser :: rspec_parser (int type)
{
42 43
  this->emulabExtensions = new emulab_extensions_parser(type);
  this->rspecType = type; 
44 45 46 47
}

rspec_parser :: ~rspec_parser ()
{
48
  delete this->emulabExtensions;
49 50
}

51 52
struct link_interface rspec_parser :: getIface (const DOMElement* tag)
{
53 54 55 56 57 58 59 60
  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;
61 62
}

63 64
// Returns the component_id. Sets an out parameter to true if an ID is present
string rspec_parser :: readPhysicalId (const DOMElement* tag, 
65
				       bool& hasComponentId)
66
{
67
  return (this->getAttribute(tag, "component_id", hasComponentId));
68 69
}

70 71 72 73 74 75 76
// Returns the component name
string rspec_parser::readComponentName (const DOMElement* tag, 
					bool& hasComponentName) 
{
  return (this->getAttribute(tag, "component_name", hasComponentName));
}

77 78
// Returns the client_id Sets an out parameter to true if an ID is present
string rspec_parser :: readVirtualId (const DOMElement* tag, bool& hasClientId)
79
{
80
  return (this->getAttribute(tag, "client_id", hasClientId));
81 82
}

83
// Returns the CMID and sets an out parameter to true if an ID is present
84
string rspec_parser :: readComponentManagerId (const DOMElement* tag, 
85
					       bool& hasCmId)
86
{
87
  return (this->getAttribute(tag, "component_manager_id", hasCmId));
88 89 90
}

string rspec_parser::readVirtualizationType (const DOMElement* tag, 
91
					     bool& hasVirtualizationType)
92
{
93 94
  return(this->getAttribute(tag, "virtualization_type",
			    hasVirtualizationType));
95 96
}

97 98
// 

99 100
// Returns true if the latitude and longitude tags are present
// Absence of the country tag will be caught by the schema validator
101
vector<string> rspec_parser :: readLocation (const DOMElement* tag,
102
					     int& rvLength)
103
{
104 105 106 107 108 109 110 111 112 113 114 115 116
  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;
117 118 119 120
}

// Returns a list of node_type elements
// The out parameter contains the number of elements found
121
vector<struct node_type> rspec_parser::readNodeTypes (const DOMElement* node,
122 123
						      int& typeCount,
						      int unlimitedSlots)
124
{
125
  bool isSwitch = false;
126 127
  DOMNodeList* nodeTypes = node->getElementsByTagName(XStr("node_type").x());
  vector<struct node_type> types;
128
  for (unsigned int i = 0; i < nodeTypes->getLength(); i++) {
129 130 131 132 133
    DOMElement *tag = dynamic_cast<DOMElement*>(nodeTypes->item(i));
    
    string typeName = XStr(tag->getAttribute(XStr("type_name").x())).c();
    if (typeName == "switch") {
      isSwitch = true;
134
    }
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    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);
  }
150 151
  typeCount = nodeTypes->getLength();
  return types;
152 153
}

154 155
// Returns any fixed interfaces which are found
map< pair<string, string>, pair<string, string> >
156 157
rspec_parser::readInterfacesOnNode  (const DOMElement* node, 
				     bool& allUnique)
158
{
159 160 161
  DOMNodeList* ifaces = node->getElementsByTagName(XStr("interface").x());
  map< pair<string, string>, pair<string, string> > fixedInterfaces;
  allUnique = true;
162
  for (unsigned int i = 0; i < ifaces->getLength(); i++)
163 164 165 166 167 168
    {
      DOMElement* iface = dynamic_cast<DOMElement*>(ifaces->item(i));
      bool hasAttr;
      string nodeId = "";
      string ifaceId = "";
      if (this->rspecType == RSPEC_TYPE_ADVT) {
169 170
        nodeId = this->readPhysicalId (node, hasAttr);
        ifaceId = XStr(iface->getAttribute(XStr("component_id").x())).c();
171 172
      }
      else { //(this->rspecType == RSPEC_TYPE_REQ)
173 174 175 176 177 178 179 180 181 182 183 184
        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)));
        }
185 186
      }
      allUnique &= ((this->ifacesSeen).insert
187
                    (pair<string, string>(nodeId, ifaceId))).second;
188 189
    }
  return (fixedInterfaces);
190 191
}

192
// Returns a link_characteristics element
193
// count should be 1 on success.
194 195
struct link_characteristics 
rspec_parser :: readLinkCharacteristics (const DOMElement* link,
196 197 198
                                         int& count,
                                         int defaultBandwidth,
                                         int unlimitedBandwidth)
199
{
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
  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;
  
217
  count = 1;
218 219
  struct link_characteristics rv = {bandwidth, latency, packetLoss};
  return rv;
220 221
}

222 223
vector<struct link_interface> 
rspec_parser :: readLinkInterface (const DOMElement* link, int& ifaceCount)
224
{
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  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);
  }
249
	
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
  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;
265 266
}

267
vector<struct link_type> rspec_parser::readLinkTypes (const DOMElement* link,
268
						      int& typeCount)
269
{
270 271
  DOMNodeList* linkTypes = link->getElementsByTagName(XStr("link_type").x());
  vector<struct link_type> types;
272
  for (unsigned int i = 0; i < linkTypes->getLength(); i++)  {
273 274 275 276 277 278 279 280 281 282
    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;
283 284
}

285 286 287 288 289
map<string, string> rspec_parser::getShortNames(void)
{
  return (this->shortNames);
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
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)
314
{
315
  count = (tag->getElementsByTagName(XStr("subnode_of").x()))->getLength();
316
  return (this->readChild(tag, "subnode_of", isSubnode));
317 318 319 320
}

string rspec_parser :: readExclusive (const DOMElement* tag, bool& isExclusive)
{
321 322 323 324
  if (this->hasChild(tag, "exclusive")) {
    return (this->readChild(tag, "exclusive", isExclusive));
  }
  return (this->getAttribute(tag, "exclusive", isExclusive));
325 326 327 328
}

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

332 333 334 335 336 337
vector<struct type_limit> 
rspec_parser::readTypeLimits (const DOMElement* tag, int& count) 
{
  count = 0;
  return vector<struct type_limit>();
}
338

339 340 341 342 343 344 345
vector<struct fd> 
rspec_parser::readFeaturesDesires (const DOMElement* tag, int& count) 
{
  count = 0;
  return vector<struct fd>();
}

346 347 348 349 350 351 352
vector<struct policy>
rspec_parser::readPolicies (const DOMElement* tag, int& count)
{
  count = 0;
  return vector<struct policy>();
}

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
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;
}

386 387 388 389
bool rspec_parser::readMultiplexOk (const DOMElement* tag)
{
  return false;
}
390 391 392 393 394 395 396 397 398 399 400 401 402 403

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

404
#endif