Commit 34d18441 authored by Tarun Prabhu's avatar Tarun Prabhu

Add extension and vclass support. It should be working correctly now. There's...

Add extension and vclass support. It should be working correctly now. There's a lot of ugliness w.r.t. hardware types and sliver types, while dealing with switches, nodes and vclasses. I have tried to hide most of it in rspec_parser_v2.cc and rspec_parser_helper.cc.
parent 742f3035
......@@ -84,21 +84,20 @@ struct property emulab_extensions_parser::readProperty (const DOMElement* tag)
struct hardness emulab_extensions_parser::readHardness (const DOMElement* tag)
{
struct hardness hardnessObject;
if (this->hasChild(tag, "hard")) {
// XXX: This is a temporary fix. We will need to deal with hard
// vclasses correctly at some point
string strWeight = this->getAttribute(tag, "weight");
if (strWeight == "hard") {
hardnessObject.type = HARD_VCLASS;
}
else /* (this->hasChildTag(tag, "soft")) */ {
hardnessObject.weight
= rspec_parser_helper::stringToNum (this->readChild(tag, "weight"));
else {
hardnessObject.type = SOFT_VCLASS;
hardnessObject.weight = rspec_parser_helper::stringToNum(strWeight);
}
return hardnessObject;
}
vector<struct vclass>
emulab_extensions_parser::readAllVClasses (const DOMElement* elem)
emulab_extensions_parser::readVClasses (const DOMElement* elem)
{
DOMNodeList* vclassNodes
= elem->getElementsByTagName(XStr("emulab:vclass").x());
......@@ -113,10 +112,31 @@ emulab_extensions_parser::readAllVClasses (const DOMElement* elem)
struct vclass emulab_extensions_parser::readVClass (const DOMElement* tag)
{
vector<string> physTypes;
DOMNodeList* physNodes
= tag->getElementsByTagName(XStr("emulab:physical_type").x());
for (int i = 0; i < physNodes->getLength(); i++) {
DOMElement* physNode = dynamic_cast<DOMElement*>(physNodes->item(i));
// XXX: This is nasty because the type name that we give assign
// has to be the concatation of the hardware type and sliver type
// It's not clear which is the best place to do this
// i.e. whether to generate this concatenated type here in the parser
// (in which case any time the formula to convert the single type to
// a hardware type and sliver type changes, it will have to be updated
// both here and in libvtop) or to do it just once in libvtop in which
// case the reverse holds true i.e. when we change the way we concatenate
// the types and present it to assign, we will have to change the code
// in libvtop
string physNodeName = this->getAttribute(physNode, "name");
cerr << "Converted vclass name to "
<< rspec_parser_helper::convertType(physNodeName) << endl;
physTypes.push_back(rspec_parser_helper::convertType(physNodeName));
}
struct vclass vclassObject = {
this->getAttribute(tag, "name"),
rspec_parser_helper::convertType(this->getAttribute(tag, "name")),
this->readHardness(tag),
this->readChild(tag, "physical_type")
physTypes
};
return vclassObject;
}
......@@ -163,4 +183,72 @@ emulab_extensions_parser::readTypeLimits (const DOMElement* tag, int& count)
return rv;
}
string emulab_extensions_parser::readSubnodeOf (const DOMElement* tag,
bool& isSubnode)
{
string rv = "";
DOMNodeList* subnodes
= tag->getElementsByTagName(XStr("emulab:subnode_of").x());
isSubnode = (subnodes->getLength() > 0);
if (isSubnode) {
DOMElement* subnode = dynamic_cast<DOMElement*>(subnodes->item(0));
rv = this->getAttribute(subnode, "parent");
}
return rv;
}
bool emulab_extensions_parser::readDisallowTrivialMix (const DOMElement* tag)
{
DOMNodeList* trivialMix
= tag->getElementsByTagName(XStr("emulab:disallow_trivial_mix").x());
return (trivialMix->getLength() > 0);
}
bool emulab_extensions_parser::readUnique (const DOMElement* tag)
{
DOMNodeList* uniques = tag->getElementsByTagName(XStr("emulab:unique").x());
return (uniques->getLength() > 0);
}
int emulab_extensions_parser::readTrivialBandwidth(const DOMElement* tag,
bool& hasTrivialBw)
{
int trivialBw = 0;
DOMNodeList* bws
= tag->getElementsByTagName(XStr("emulab:trivial_bandwidth").x());
hasTrivialBw = (bws->getLength() > 0);
if (hasTrivialBw) {
trivialBw =(int)this->stringToNum(this->getAttribute
(dynamic_cast<DOMElement*>(bws->item(0)),
"value"));
}
return trivialBw;
}
string emulab_extensions_parser::readHintTo (const DOMElement* tag,
bool& hasHint)
{
string hint = "";
DOMNodeList* hints = tag->getElementsByTagName(XStr("emulab:hint_to").x());
hasHint = (hints->getLength() > 0);
if (hasHint) {
hint = this->getAttribute(dynamic_cast<DOMElement*>(hints->item(0)),
"value");
}
return hint;
}
bool emulab_extensions_parser::readNoDelay (const DOMElement* tag)
{
DOMNodeList* nodelays= tag->getElementsByTagName(XStr("emulab:nodelay").x());
return (nodelays->getLength() > 0);
}
bool emulab_extensions_parser::readTrivialOk (const DOMElement* tag)
{
DOMNodeList* trivial_oks
= tag->getElementsByTagName(XStr("emulab:trivial_ok").x());
return (trivial_oks->getLength() > 0);
}
#endif // WITH_XML
......@@ -61,7 +61,7 @@ namespace rspec_emulab_extension {
struct vclass {
std::string name;
struct hardness type;
std::string physicalType;
std::vector<std::string> physicalTypes;
};
struct property {
......@@ -96,14 +96,21 @@ namespace rspec_emulab_extension {
std::vector<struct property> readProperties
(const xercesc::DOMElement* elem);
struct property readProperty (const xercesc::DOMElement* tag);
std::vector<struct vclass> readAllVClasses (const xercesc::DOMElement*);
std::vector<struct vclass> readVClasses (const xercesc::DOMElement*);
struct vclass readVClass (const xercesc::DOMElement* tag);
std::string readAssignedTo (const xercesc::DOMElement* tag);
std::string readHintTo (const xercesc::DOMElement* tag);
std::string readTypeSlots (const xercesc::DOMElement* tag);
bool readStaticType (const xercesc::DOMElement* tag);
std::vector<struct type_limit> readTypeLimits(const xercesc::DOMElement* tag,
std::vector<struct type_limit> readTypeLimits(const xercesc::DOMElement*,
int& count);
std::string readSubnodeOf (const xercesc::DOMElement* tag, bool&);
virtual bool readDisallowTrivialMix (const xercesc::DOMElement* tag);
virtual bool readUnique (const xercesc::DOMElement* tag);
virtual int readTrivialBandwidth (const xercesc::DOMElement* tag, bool&);
virtual std::string readHintTo (const xercesc::DOMElement* tag, bool&);
virtual bool readNoDelay (const xercesc::DOMElement* tag);
virtual bool readTrivialOk (const xercesc::DOMElement* tag);
};
} // namespace rspec_emulab_extension
......
......@@ -139,7 +139,7 @@ int parse_advertisement(tb_pgraph &pg, tb_sgraph &sg, char *filename) {
rspecParser = new rspec_parser_v2(RSPEC_TYPE_ADVT);
break;
default:
cerr << "ERROR: Unsupported rspec ver. " << rspecVersion
cerr << "*** Unsupported rspec ver. " << rspecVersion
<< " ... Aborting " << endl;
exit(EXIT_FATAL);
}
......@@ -162,21 +162,21 @@ int parse_advertisement(tb_pgraph &pg, tb_sgraph &sg, char *filename) {
*/
XMLDEBUG("starting node population" << endl);
if (!populate_nodes(advt_root,pg,sg,unavailable)) {
cerr << "Error reading nodes from physical topology "
cerr << "*** Error reading nodes from physical topology "
<< filename << endl;
exit(EXIT_FATAL);
}
XMLDEBUG("finishing node population" << endl);
XMLDEBUG("starting link population" << endl);
if (!populate_links(advt_root,pg,sg,unavailable)) {
cerr << "Error reading links from physical topology "
cerr << "*** Error reading links from physical topology "
<< filename << endl;
exit(EXIT_FATAL);
}
XMLDEBUG("finishing link population" << endl);
XMLDEBUG("setting type limits" << endl);
if (!populate_type_limits(advt_root, pg, sg)) {
cerr << "Error setting type limits " << filename << endl;
cerr << "*** Error setting type limits " << filename << endl;
exit(EXIT_FATAL);
}
XMLDEBUG("finishing setting type limits" << endl);
......@@ -219,7 +219,7 @@ bool populate_nodes(DOMElement *root,
bool hasCMId;
string componentId = rspecParser->readPhysicalId(elt, hasComponentId);
string componentManagerId = rspecParser->readComponentManagerId(elt,hasCMId);
if (!hasComponentId || !hasCMId) {
is_ok = false;
continue;
......@@ -228,28 +228,29 @@ bool populate_nodes(DOMElement *root,
// Maintain a list of componentId's seen so far to ensure no duplicates
insert_ret = advertisement_elements->insert
(pair<string, DOMElement*>(componentId, elt));
if (insert_ret.second == false)
{
cerr << componentId << " already exists" << endl;
is_ok = false;
}
if (insert_ret.second == false) {
cerr << "*** " << componentId << " already exists" << endl;
is_ok = false;
}
// XXX: This should not have to be called manually
bool allUnique;
rspecParser->readInterfacesOnNode(elt, allUnique);
// XXX: We don't ever do anything with this, so I am commenting it out
/* Deal with the location tag */
int locationDataCount;
vector<string> locationData
= rspecParser->readLocation(elt, locationDataCount);
string country = locationData[0];
string latitude = "";
string longitude = "";
if (locationDataCount == 3) {
latitude = locationData[1];
longitude = locationData[2];
}
// /* Deal with the location tag */
// int locationDataCount;
// vector<string> locationData
// = rspecParser->readLocation(elt, locationDataCount);
// string country = locationData[0];
// string latitude = "";
// string longitude = "";
// if (locationDataCount == 3) {
// latitude = locationData[1];
// longitude = locationData[2];
// }
pvertex pv;
......@@ -268,13 +269,14 @@ bool populate_nodes(DOMElement *root,
pname2vertex[componentId.c_str()] = pv;
int typeCount;
vector<struct node_type> types = rspecParser->readNodeTypes(elt, typeCount);
vector<struct node_type>types = rspecParser->readNodeTypes(elt, typeCount);
bool switchAdded = false;
for (int i = 0; i < typeCount; i++) {
node_type type = types[i];
const char* typeName = type.typeName.c_str();
int typeSlots = type.typeSlots;
bool isStatic = type.isStatic;
// Add the type into assign's data structures
if (ptypes.find(typeName) == ptypes.end()) {
ptypes[typeName] = new tb_ptype(typeName);
......@@ -290,6 +292,7 @@ bool populate_nodes(DOMElement *root,
* else!
*/
if (strcmp(typeName, "switch") == 0) {
// if (rspecParser->checkIsSwitch(componentId) && !switchAdded) {
p->is_switch = true;
p->types["switch"] = new tb_pnode::type_record(1,false,ptype);
svertex sv = add_vertex(sg);
......@@ -324,13 +327,26 @@ bool populate_nodes(DOMElement *root,
(tb_node_featuredesire(XStr(componentManagerId.c_str()).f(),
1.0, false, featuredesire::FD_TYPE_NORMAL));
bool isSubnode;
string subnodeOf = rspecParser->readSubnodeOf (elt, isSubnode);
// 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);
if (isSubnode) {
if (!p->subnode_of_name.empty()){
if (subnodeCnt > 1) {
cerr << "*** Too many \"subnode\" relations found in "
<< componentId << "Allowed 1 ... " << endl;
is_ok = false;
continue;
}
}
else {
// Just store the name for now, we'll do late binding to
// an actual pnode later
......@@ -338,16 +354,6 @@ bool populate_nodes(DOMElement *root,
}
}
// 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;
// Deal with features
int fdsCount;
vector<struct fd> fds = rspecParser->readFeaturesDesires(elt, fdsCount);
......@@ -377,6 +383,17 @@ bool populate_nodes(DOMElement *root,
(p->features).push_front(node_fd);
}
// 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;
}
/*
* XXX: Is this really necessary?
*/
......@@ -423,8 +440,7 @@ bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
string cmId = rspecParser->readComponentManagerId(elt, hasCMId);
if (!hasComponentId || !hasCMId) {
cerr << "All elements must have a component_uuid/component_urn "
<< "and a component_manager_uuid/component_manager_urn" << endl;
cerr << "*** Require component ID and component manager ID" << endl;
is_ok = false;
}
else {
......@@ -432,11 +448,11 @@ bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
advertisement_elements->insert(pair<string, DOMElement*>
(componentId, elt));
if (insert_ret.second == false) {
cerr << componentId << " already exists" << endl;
cerr << "*** " << componentId << " already exists" << endl;
is_ok = false;
}
}
/*
* Get source and destination interfaces - we use knowledge of the
* schema that there is awlays exactly one source and one destination
......@@ -447,26 +463,27 @@ bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
// Error handling
switch (ifaceCount) {
case RSPEC_ERROR_BAD_IFACE_COUNT:
cerr << "Incorrect number of interfaces found on link "
<< componentId << ". Expected 2 (found "
<< ifaceCount << ")" << endl;
is_ok = false;
continue;
case RSPEC_ERROR_UNSEEN_NODEIFACE_SRC:
cerr << "Unseen node-interface pair on the source interface ref"
cerr << "*** Unseen node-interface pair on the source interface ref"
<< endl;
is_ok = false;
continue;
case RSPEC_ERROR_UNSEEN_NODEIFACE_DST:
cerr << "Unseen node-interface pair on the destination interface ref"
cerr << "*** Unseen node-interface pair on the destination interface ref"
<< endl;
is_ok = false;
continue;
}
if (ifaceCount != 2) {
cerr << "*** Incorrect number of interfaces found on link "
<< componentId << ". Expected 2 (found "
<< ifaceCount << ")" << endl;
is_ok = false;
continue;
}
/* NOTE: In a request, we assume that each link has only two interfaces
* Although the order is immaterial, assign expects a source first
* and a destination second and we assume the same
......@@ -477,26 +494,26 @@ bool populate_links(DOMElement *root, tb_pgraph &pg, tb_sgraph &sg,
string dst_iface = interfaces[1].physicalIfaceId;
if (src_node == "" || src_iface == "") {
cerr << "Physical link " << componentId
cerr << "*** Physical link " << componentId
<< " must have a component id and component interface id "
<< " specified for the source node" << endl;
is_ok = false;
continue;
}
if (dst_node == "" || dst_iface == "") {
cerr << "Physical link " << componentId
cerr << "*** Physical link " << componentId
<< " must have a component id and component interface id"
<< " specified for the destination node" << endl;
is_ok = false;
continue;
}
if( unavailable.count( src_node ) ||
unavailable.count( dst_node ) )
//one or both of the endpoints are unavailable; silently
//ignore the link
continue;
/*
* Get standard link characteristics
*/
......
......@@ -17,6 +17,7 @@ static const char rcsid[] = "$Id: parse_request_rspec.cc,v 1.16 2009-10-21 20:49
#include "parse_error_handler.h"
#include "rspec_parser_v1.h"
#include "rspec_parser_v2.h"
#include "emulab_extensions_parser.h"
#include <fstream>
#include <sstream>
......@@ -33,6 +34,9 @@ static const char rcsid[] = "$Id: parse_request_rspec.cc,v 1.16 2009-10-21 20:49
#else
#define SCHEMA_LOCATION "request.xsd"
#endif
using namespace rspec_emulab_extension;
/*
* XXX: Do I have to release lists when done with them?
*/
......@@ -74,6 +78,7 @@ static bool populate_links(DOMElement *root,
tb_vgraph &vg,
map< pair<string, string>,
pair<string, string> >* fixed_interfaces);
static bool populate_vclasses (DOMElement* root, tb_vgraph& vg);
DOMElement* appendChildTagWithData (DOMElement* parent,
const char* tag_name,
......@@ -116,7 +121,7 @@ int parse_request(tb_vgraph &vg, char *filename) {
* If there are any errors, do not go any further
*/
if (errHandler->sawError()) {
cerr << "There were " << domParser -> getErrorCount ()
cerr << "*** There were " << domParser -> getErrorCount ()
<< " errors in your file. " << endl;
exit(EXIT_FATAL);
}
......@@ -131,7 +136,7 @@ int parse_request(tb_vgraph &vg, char *filename) {
bool is_physical;
XStr type (request_root->getAttribute(XStr("type").x()));
if (strcmp(type.c(), "request") != 0) {
cerr << "Error: RSpec type must be \"request\"" << endl;
cerr << "*** RSpec type must be \"request\"" << endl;
exit (EXIT_FATAL);
}
......@@ -150,7 +155,7 @@ int parse_request(tb_vgraph &vg, char *filename) {
rspecParser = new rspec_parser_v2(RSPEC_TYPE_REQ);
break;
default:
cerr << "ERROR: Unsupported rspec ver. " << rspecVersion
cerr << "*** Unsupported rspec ver. " << rspecVersion
<< " ... Aborting " << endl;
exit(EXIT_FATAL);
}
......@@ -162,9 +167,16 @@ int parse_request(tb_vgraph &vg, char *filename) {
* These three calls do the real work of populating the assign data
* structures
*/
XMLDEBUG("starting vclass population" << endl);
if (!populate_vclasses (request_root, vg)) {
cerr << "*** Error reading vclasses from virtual topology "
<< filename << endl;
exit(EXIT_FATAL);
}
XMLDEBUG("finishing vclass population" << endl);
XMLDEBUG("starting node population" << endl);
if (!populate_nodes(request_root,vg, &fixed_interfaces)) {
cerr << "Error reading nodes from virtual topology "
cerr << "*** Error reading nodes from virtual topology "
<< filename << endl;
exit(EXIT_FATAL);
}
......@@ -172,7 +184,7 @@ int parse_request(tb_vgraph &vg, char *filename) {
XMLDEBUG("starting link population" << endl);
if (!populate_links(request_root,vg, &fixed_interfaces)) {
cerr << "Error reading links from virtual topology "
cerr << "*** Error reading links from virtual topology "
<< filename << endl;
exit(EXIT_FATAL);
}
......@@ -216,16 +228,16 @@ bool populate_node(DOMElement* elt,
}
if (!hasVirtualId) {
cerr << "ERROR: Every node must have a virtual_id" << endl;
cerr << "*** Every node must have a virtual_id" << endl;
return false;
}
bool allUnique;
map< pair<string, string>, pair<string, string> > fixedIfacesOnNode;
fixedIfacesOnNode = rspecParser->readInterfacesOnNode(elt, allUnique);
// XXX: This should not have to be called manually
fixedIfacesOnNode = rspecParser->readInterfacesOnNode(elt, allUnique);
if (!allUnique) {
cerr << "The node-interface pairs in " << virtualId
cerr << "*** The node-interface pairs in " << virtualId
<< " were not unique." << endl;
return false;
}
......@@ -243,9 +255,9 @@ bool populate_node(DOMElement* elt,
vector<struct node_type> types = rspecParser->readNodeTypes(elt, typeCount);
bool no_type = (typeCount == 0);
if (typeCount > 1) {
cerr << "ERROR: Too many node types (" << typeCount << ") on "
cerr << "*** Too many node types (" << typeCount << ") on "
<< virtualId << " (allowed 1) ... Aborting " << endl;
exit(EXIT_FAILURE);
return false;
}
string typeName = types[0].typeName;
......@@ -254,6 +266,8 @@ bool populate_node(DOMElement* elt,
bool isUnlimited = (typeSlots == 1000);
cerr << "Found req type " << typeName << endl;
/*
* Make a tb_ptype structure for this guy - or just add this node to
* it if it already exists
......@@ -280,15 +294,24 @@ bool populate_node(DOMElement* elt,
vtypes[typeName_c] += typeSlots;
}
}
// Read emulab extensions
bool isSubnode;
string subnodeOf = rspecParser->readSubnodeOf(elt, isSubnode);
int subnodeCnt;
string subnodeOf = rspecParser->readSubnodeOf(elt, isSubnode, subnodeCnt);
if (isSubnode) {
if (subnodeCnt > 1) {
cerr << "*** To many \"subnode\" relations found in "
<< virtualId << ". Allowed 1 ... " << endl;
return false;
}
}
// A bunch of defaults for stuff that assign wants and Protogeni doesn't
// The code to read the values from the request is still there
bool is_unique = false;
bool is_disallow_trivial_mix = false;
//-------------------------------------------------------------------------
bool disallow_trivial_mix = rspecParser->readDisallowTrivialMix(elt);
bool hasNodeHint = false;
string nodeHint = rspecParser->readHintTo(elt, hasNodeHint);
tb_vnode *v = NULL;
if (no_type)
......@@ -300,13 +323,19 @@ bool populate_node(DOMElement* elt,
typeName.c_str(), typeSlots);
// Construct the vertex
v -> disallow_trivial_mix = is_disallow_trivial_mix;
if (isSubnode)
if (disallow_trivial_mix) {
v -> disallow_trivial_mix = true;
}
if (isSubnode) {
v -> subnode_of_name = subnodeOf.c_str();
}
if (hasNodeHint) {
node_hints[virtualId] = nodeHint;
}
bool hasExclusive;
string exclusive = rspecParser->readExclusive(elt, hasExclusive);
if (hasExclusive) {
fstring desirename("shared");
......@@ -327,6 +356,35 @@ bool populate_node(DOMElement* elt,
}
}
}
int fdsCount;
vector<struct fd> fds = rspecParser->readFeaturesDesires(elt, fdsCount);
for (int i = 0; i < fdsCount; i++) {
struct fd desire = fds[i];
featuredesire::fd_type fd_type;
switch(desire.op.type) {
case LOCAL_OPERATOR:
fd_type = featuredesire::FD_TYPE_LOCAL_ADDITIVE;
break;
case GLOBAL_OPERATOR:
if (desire.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(desire.fd_name.c_str()).f(),
desire.fd_weight,
desire.violatable,
fd_type);
node_fd.add_desire_user(desire.fd_weight);
(v->desires).push_front(node_fd);
}
v->vclass = vclass;
vvertex vv = add_vertex(vg);
......@@ -399,24 +457,30 @@ bool populate_link (DOMElement* elt,
*/
int count;
vector<struct link_type> linkTypes = rspecParser->readLinkTypes(elt, count);
string linkType = "ethernet";
if (count > 1) {
cerr << "ERROR: Too many link types specified (" << count
cerr << "*** Too many link types specified (" << count
<< ") on " << virtualId << ". Allowed 1 ... Aborting" << endl;
exit(EXIT_FAILURE);
return false;
}
else if (count == 1){
linkType = linkTypes[0].typeName;
}
string linkType = linkTypes[0].typeName;
if (linkType == "")
linkType = "ethernet";
/*
* Get standard link characteristics
*/
struct link_characteristics characteristics
= rspecParser->readLinkCharacteristics(elt, count);
if (count != 1) {
cerr << "*** Incorrect number of link properties specified ("
<< count << " on " << virtualId <<". Allowed 1 " << endl;
return false;
}
int bandwidth = characteristics.bandwidth;
int latency = characteristics.latency;
double packetLoss = characteristics.packetLoss;
struct link_interface src;
struct link_interface dst;
......@@ -488,18 +552,14 @@ bool populate_link (DOMElement* elt,
DOMElement* src_interface_ref
= doc->createElement(XStr("interface_ref").x());
src_interface_ref->setAttribute(XStr("virtualIfaceId").x(),
src_interface_ref->setAttribute(XStr("clientId").x(),
virtualIfaceId);
src_interface_ref->setAttribute(XStr("virtualNodeId").x(),
virtualNodeId);
link->appendChild(src_interface_ref);
DOMElement* dst_interface_ref
= doc->createElement(XStr("interface_ref").x());
dst_interface_ref->setAttribute(XStr("virtualIfaceId").x(),
dst_interface_ref->setAttribute(XStr("clientId").x(),
XStr(str_lan_interface_id.c_str()).x());
dst_interface_ref->setAttribute(XStr("virtualNodeId").x(),
XStr(str_lan_id.c_str()).x());
link->appendChild(dst_interface_ref);
// Adding attributes to ensure that the element is handled
......@@ -522,34 +582,35 @@ bool populate_link (DOMElement* elt,
dst = interfaces[1];
}
else {
cerr << "ERROR: Too few interfaces found (" << ifaceCount << ")"
cerr << "*** Too few interfaces found (" << ifaceCount << ")"
<< " on " << virtualId << " at least 2 required ... Aborting"
<< endl;
exit(EXIT_FAILURE);
return false;
}
string srcNode = src.virtualNodeId;
string srcIface = src.virtualIfaceId;
string dstNode = dst.virtualNodeId;
string dstIface = dst.virtualIfaceId;
if (srcNode == "" || srcIface == "") {
cerr << "No source node found on interface for link "
cerr << "*** No source node found on interface for link "
<< virtualId << endl;
return false;
}
if (dstNode == "" || dstIface == "") {
cerr << "No destination node found on interface for link "
cerr << "*** No destination node found on interface for link "
<< virtualId << endl;