Commit abf45b15 authored by Tarun Prabhu's avatar Tarun Prabhu

Massive commit of all the work to get assign to read XML. Fingers crossed...

parent 085a8fe6
......@@ -8,6 +8,7 @@ TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ..
SUBDIR = assign
MAKEFILE_IN = @srcdir@/GNUmakefile.in
HAVE_XERCES = @HAVE_XERCES@
include $(OBJDIR)/Makeconf
......@@ -22,7 +23,7 @@ all: assign
include $(TESTBED_SRCDIR)/GNUmakerules
OBJS=parse_top.o parse_ptop.o assign.o pclass.o vclass.o config.o score.o \
OBJS=parse_top.o parse_ptop.o assign.o pclass.o vclass.o score.o \
parser.o solution.o anneal.o featuredesire.o neighborhood.o fstring.o
LIBS+= -lm
LDFLAGS+= -pipe -O3
......@@ -30,6 +31,12 @@ CXXFLAGS = -pipe -I/usr/local/include -ftemplate-depth-40
# For OSX w/ fink
CXXFLAGS += -I/sw/include
ifeq ($(HAVE_XERCES),yes)
CXXFLAGS += -DWITH_XML
LIBS += -L/usr/local/lib -lxerces-c
OBJS += parse_ptop_xml.o parse_vtop_xml.o parse_policy_xml.o parse_error_handler.o xmlhelpers.o parse_advertisement_rspec.o parse_request_rspec.o annotate_rspec.o annotate_vtop.o annotate.o
endif
# Pick either this
CXXFLAGS += -O3
# or this
......@@ -65,6 +72,8 @@ CXXFLAGS += -DFIX_PLINK_ENDPOINTS
CXXFLAGS += -DTRIVIAL_LINK_BW
# Use the old acceptance criteria, which gives special treatment to violations
CXXFLAGS += -DSPECIAL_VIOLATION_TREATMENT
# Pass the Emulab installation root directory
CXXFLAGS += -DTBROOT='"$(TBROOT)"'
# If you're looking to turn on or off USE_OPTIMAL, its now a cmdline
# option. Use OP={0,1} on the command line at run time... :)
......@@ -73,7 +82,7 @@ DEPLIBS=$(OBJS)
assign: ${MAKEFILE_IN} ${DEPLIBS} ${OBJS}
${CXX} -o assign ${LIBS} $(OBJS) ${LDFLAGS}
install: $(INSTALL_LIBEXECDIR)/assign
clean:
......@@ -83,25 +92,69 @@ clean:
# All this crap generated with 'g++ -MM' - don't want to do all the makefile goo
# to make this automatic, since none of it ever changes
#
anneal.o: anneal.cc anneal.h port.h delay.h physical.h common.h \
config.h featuredesire.h pclass.h virtual.h maps.h score.h solution.h \
vclass.h ${MAKEFILE_IN}
assign.o: assign.cc port.h common.h config.h delay.h physical.h \
featuredesire.h virtual.h vclass.h pclass.h score.h solution.h maps.h \
anneal.h ${MAKEFILE_IN}
config.o: config.cc config.h ${MAKEFILE_IN}
featuredesire.o: featuredesire.cc featuredesire.h common.h config.h \
${MAKEFILE_IN}
parse_ptop.o: parse_ptop.cc port.h delay.h physical.h common.h \
config.h featuredesire.h parser.h ${MAKEFILE_IN}
parse_top.o: parse_top.cc port.h common.h config.h vclass.h delay.h \
physical.h featuredesire.h virtual.h parser.h anneal.h pclass.h ${MAKEFILE_IN}
parser.o: parser.cc parser.h port.h ${MAKEFILE_IN}
pclass.o: pclass.cc port.h common.h config.h delay.h physical.h \
featuredesire.h virtual.h pclass.h ${MAKEFILE_IN}
score.o: score.cc port.h common.h config.h vclass.h delay.h physical.h \
featuredesire.h virtual.h pclass.h score.h /usr/include/math.h ${MAKEFILE_IN}
anneal.o: anneal.cc anneal.h port.h delay.h physical.h common.h fstring.h \
featuredesire.h forwarding.h pclass.h virtual.h maps.h score.h \
solution.h vclass.h neighborhood.h
assign.o: assign.cc port.h common.h fstring.h delay.h physical.h \
featuredesire.h forwarding.h virtual.h vclass.h pclass.h score.h \
solution.h maps.h anneal.h config.h parse_advertisement_rspec.h parse_ptop_xml.h xmlhelpers.h \
xstr.h parse_request_rspec.h parse_vtop_xml.h
annotate.o: annotate.cc annotate.h
annotate_rspec.o: annotate.cc annotate.h annotate_rspec.cc annotate_rspec.h \
xmlhelpers.h xstr.h
annotate_vtop.o: annotate.cc annotate.h annotate_vtop.cc annotate_vtop.h \
xmlhelpers.h xstr.h
config.o: config.cc config.h common.h port.h fstring.h score.h physical.h \
delay.h featuredesire.h forwarding.h virtual.h anneal.h pclass.h
featuredesire.o: featuredesire.cc featuredesire.h common.h port.h \
fstring.h score.h physical.h delay.h forwarding.h virtual.h
forwarding.o: forwarding.cc forwarding.h port.h fstring.h physical.h \
common.h delay.h featuredesire.h
fstring.o: fstring.cc fstring.h port.h
fstringtest.o: fstringtest.cc fstring.h port.h
neighborhood.o: neighborhood.cc neighborhood.h port.h common.h fstring.h \
physical.h delay.h featuredesire.h forwarding.h vclass.h virtual.h \
pclass.h
parse_error_handler.o: parse_error_handler.cc parse_error_handler.h \
xmlhelpers.h featuredesire.h common.h port.h fstring.h xstr.h
parse_policy_xml.o: parse_policy_xml.cc parse_policy_xml.h physical.h \
common.h port.h fstring.h delay.h featuredesire.h forwarding.h \
xmlhelpers.h xstr.h parse_error_handler.h
parse_ptop.o: parse_ptop.cc port.h delay.h physical.h common.h fstring.h \
featuredesire.h forwarding.h parser.h
parse_ptop_xml.o: parse_ptop_xml.cc parse_ptop_xml.h physical.h common.h \
port.h fstring.h delay.h featuredesire.h forwarding.h xmlhelpers.h \
xstr.h parse_error_handler.h
parser.o: parser.cc parser.h port.h
parse_advertisement_rspec.o: parse_advertisement_rspec.cc parse_advertisement_rspec.h \
common.h port.h fstring.h delay.h featuredesire.h forwarding.h \
xmlhelpers.h xstr.h parse_error_handler.h anneal.h
parse_request_rspec.o: parse_request_rspec.cc parse_request_rspec.h \
common.h port.h fstring.h delay.h featuredesire.h forwarding.h \
virtual.h xmlhelpers.h xstr.h parse_error_handler.h anneal.h \
vclass.h
parse_top.o: parse_top.cc port.h common.h fstring.h vclass.h delay.h \
physical.h featuredesire.h forwarding.h virtual.h parser.h anneal.h \
pclass.h
parse_top_xml.o: parse_top_xml.cc port.h common.h fstring.h vclass.h \
delay.h physical.h featuredesire.h forwarding.h virtual.h parser.h \
anneal.h pclass.h parse_top_xml.h xmlhelpers.h xstr.h \
parse_error_handler.h
parse_vtop_rspec.o: parse_vtop_rspec.cc parse_vtop_rspec.h \
common.h port.h fstring.h delay.h featuredesire.h forwarding.h \
virtual.h xmlhelpers.h xstr.h parse_error_handler.h anneal.h \
vclass.h
parse_vtop_xml.o: parse_vtop_xml.cc port.h common.h fstring.h vclass.h \
delay.h physical.h featuredesire.h forwarding.h virtual.h parser.h \
anneal.h pclass.h parse_vtop_xml.h xmlhelpers.h xstr.h \
parse_error_handler.h
pclass.o: pclass.cc port.h common.h fstring.h delay.h physical.h \
featuredesire.h forwarding.h virtual.h pclass.h
score.o: score.cc port.h common.h fstring.h vclass.h delay.h physical.h \
featuredesire.h forwarding.h virtual.h pclass.h score.h
solution.o: solution.cc solution.h port.h delay.h physical.h common.h \
config.h featuredesire.h virtual.h maps.h vclass.h ${MAKEFILE_IN}
vclass.o: vclass.cc port.h common.h config.h vclass.h delay.h \
physical.h featuredesire.h virtual.h ${MAKEFILE_IN}
fstring.h featuredesire.h forwarding.h virtual.h maps.h vclass.h
vclass.o: vclass.cc port.h common.h fstring.h vclass.h delay.h physical.h \
featuredesire.h forwarding.h virtual.h
xmlhelpers.o: xmlhelpers.cc xmlhelpers.h featuredesire.h common.h port.h \
fstring.h xstr.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003-2006 University of Utah and the Flux Group.
* Copyright (c) 2003-2009 University of Utah and the Flux Group.
* All rights reserved.
*/
static const char rcsid[] = "$Id: anneal.cc,v 1.46 2009-05-20 18:06:07 tarunp Exp $";
#include "anneal.h"
#include "virtual.h"
......@@ -48,6 +50,35 @@ name_name_map node_hints;
extern FILE *scoresout, *tempout, *deltaout;
#endif
/*
* Parameters used to control annealing
*/
int init_temp = 10;
int temp_prob = 130;
#ifdef LOW_TEMP_STOP
float temp_stop = .005;
#else
float temp_stop = 2;
#endif
int CYCLES = 20;
// The following are basically arbitrary constants
// Initial acceptance ratio for melting
float X0 = .95;
#ifdef LOCAL_DERIVATIVE
float epsilon = 0.0001;
#else
float epsilon = 0.01;
#endif
float delta = 2;
// Number of runs to spend melting
int melt_trans = 1000;
int min_neighborhood_size = 1000;
float temp_rate = 0.9;
// Determines whether to accept a change of score difference 'change' at
// temperature 'temperature'.
inline bool accept(double change, double temperature) {
......@@ -171,8 +202,9 @@ void smart_unmap_part2() {
double temp;
/* When this is finished the state will reflect the best solution found. */
void anneal(bool scoring_selftest, double scale_neighborhood,
double *initial_temperature, double use_connected_pnode_find)
void anneal(bool scoring_selftest, bool check_fixed_nodes,
double scale_neighborhood, double *initial_temperature,
double use_connected_pnode_find)
{
cout << "Annealing." << endl;
......@@ -187,15 +219,10 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
double scorediff;
int nnodes = num_vertices(VG);
int npnodes = num_vertices(PG);
//int npnodes = num_vertices(PG);
int npclasses = pclasses.size();
float cycles = CYCLES*(float)(nnodes + num_edges(VG) + PHYSICAL(npnodes));
float optimal = OPTIMAL_SCORE(num_edges(VG),nnodes);
#ifdef STATS
cout << "STATS_OPTIMAL = " << optimal << endl;
#endif
int mintrans = (int)cycles;
int trans;
......@@ -214,7 +241,7 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
vvertex_int_priority_queue unassigned_nodes;
#ifdef VERBOSE
cout << "Initialized to cycles="<<cycles<<" optimal="<<optimal<<" mintrans="
cout << "Initialized to cycles="<<cycles<<" mintrans="
<< mintrans<<" naccepts="<<naccepts<< endl;
#endif
......@@ -258,8 +285,8 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
// For now, if we find more than one match, we pick the first. It's
// possible that picking some other type would give us a better
// score, but let's noty worry about that
if (vn->vclass->has_type((*i)->ptype->name())) {
vn->type = (*i)->ptype->name();
if (vn->vclass->has_type((*i)->get_ptype()->name())) {
vn->type = (*i)->get_ptype()->name();
break;
}
}
......@@ -275,7 +302,17 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
<< vn->type << "\n";
}
}
if (add_node(vv,pv,false,true,false) == 1) {
/*
* Normally, we want to bypass some checks in add_node for fixed nodes -
* but not always (usually for testing purposes).
*/
bool skip_checks = true;
if (check_fixed_nodes) {
skip_checks = false;
}
if (add_node(vv,pv,false,skip_checks,false) == 1) {
cout << "*** Fixed node: Could not map " << vn->name <<
" to " << pn->name << endl;
fix_failed++;
......@@ -417,7 +454,6 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
// Crap added by ricci
#ifdef MELT
bool melting;
double meltstart;
#endif
int nincreases, ndecreases;
double avgincrease;
......@@ -601,9 +637,9 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
if (vn->vclass != NULL) {
vn->type = vn->vclass->choose_type();
#ifdef SCORE_DEBUG
cerr << "vclass " << vn->vclass->name << ": choose type for " <<
cerr << "vclass " << vn->vclass->get_name() << ": choose type for " <<
vn->name << " = " << vn->type << " dominant = " <<
vn->vclass->dominant << endl;
vn->vclass->get_dominant() << endl;
#endif
}
......@@ -746,13 +782,7 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
* this transition
*/
bool accepttrans = false;
if (newscore < optimal) {
// If this score is smaller than the one we think is optimal, of course we
// take it!
accepttrans = true;
RDEBUG(cout << "accept: optimal (" << newscore << "," << optimal
<< ")" << endl;)
} else if (melting) {
if (melting) {
// When melting, we take everything!
accepttrans = true;
RDEBUG(cout << "accept: melting" << endl;)
......@@ -870,10 +900,10 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
#endif // SCORE_DEBUG
tie(vit,veit) = vertices(VG);
for (;vit!=veit;++vit) {
tb_vnode *vn = get(vvertex_pmap,*vit);
if (vn->assigned) {
best_solution.set_assignment(*vit,vn->assignment);
best_solution.set_vtype_assignment(*vit,vn->type);
tb_vnode *vnode = get(vvertex_pmap,*vit);
if (vnode->assigned) {
best_solution.set_assignment(*vit,vnode->assignment);
best_solution.set_vtype_assignment(*vit,vnode->type);
} else {
best_solution.clear_assignment(*vit);
}
......@@ -882,14 +912,14 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
//abstypes[*vit] = get(vvertex_pmap,*vit)->type;
}
vedge_iterator eit, eeit;
tie(eit, eeit) = edges(VG);
for (;eit!=eeit;++eit) {
tb_vlink *vlink = get(vedge_pmap, *eit);
vedge_iterator edge_it, edge_it_end;
tie(edge_it, edge_it_end) = edges(VG);
for (;edge_it!=edge_it_end;++edge_it) {
tb_vlink *vlink = get(vedge_pmap, *edge_it);
if (vlink->link_info.type_used != tb_link_info::LINK_UNMAPPED) {
best_solution.set_link_assignment(*eit,vlink->link_info);
best_solution.set_link_assignment(*edge_it,vlink->link_info);
} else {
best_solution.clear_link_assignment(*eit);
best_solution.clear_link_assignment(*edge_it);
}
}
......@@ -900,10 +930,6 @@ void anneal(bool scoring_selftest, double scale_neighborhood,
cerr << "New best recorded" << endl;
#endif
}
if (newscore < optimal) {
cout << "OPTIMAL ( " << optimal << ")" << endl;
goto DONE;
}
// Accept change
} else { // !acceptrans
// Reject change, go back to the state we were in before
......
......@@ -58,6 +58,25 @@ using namespace __gnu_cxx;
#define PHYSICAL(x) 0
#endif
/*
* Parameters used to control annealing
*/
extern int init_temp;
extern int temp_prob;
extern float temp_stop;
extern int CYCLES;
// Initial acceptance ratio for melting
extern float X0;
extern float epsilon;
extern float delta;
// Number of runs to spend melting
extern int melt_trans;
extern int min_neighborhood_size;
extern float temp_rate;
/*
* Globals - XXX made non-global!
*/
......@@ -80,8 +99,9 @@ inline bool accept(double change, double temperature);
tb_pnode *find_pnode(tb_vnode *vn);
/* The big guy! */
void anneal(bool scoring_selftest, double scale_neighborhood,
double *initial_temperature, double use_connected_pnode_find);
void anneal(bool scoring_selftest, bool check_fixed_nodes,
double scale_neighborhood, double *initial_temperature,
double use_connected_pnode_find);
typedef hash_map<fstring,fstring> name_name_map;
typedef slist<fstring> name_slist;
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2008 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* Implements the annotate methods which are independent of the type of file being annotated.
*/
static const char rcsid[] = "$Id: annotate.cc,v 1.2 2009-05-20 18:06:07 tarunp Exp $";
#ifdef WITH_XML
#include "annotate.h"
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMWriter.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
XERCES_CPP_NAMESPACE_USE
using namespace std;
void annotate::write_annotated_file (const char* filename)
{
// Get the current implementation
DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(NULL);
// Construct the DOMWriter
DOMWriter* writer = ((DOMImplementationLS*)impl)->createDOMWriter();
// Make the output look pretty
if (writer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
writer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
// Set the byte-order-mark feature
if (writer->canSetFeature(XMLUni::fgDOMWRTBOM, true))
writer->setFeature(XMLUni::fgDOMWRTBOM, true);
// Construct the LocalFileFormatTarget
XMLFormatTarget *outputFile = new xercesc::LocalFileFormatTarget(filename);
// Serialize a DOMNode to the local file "<some-file-name>.xml"
writer->writeNode(outputFile, *dynamic_cast<DOMNode*>(this->virtual_root));
// Flush the buffer to ensure all contents are written
outputFile->flush();
// Release the memory
writer->release();
}
#endif
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2008 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* Base class for the annotater.
*/
/* This is ugly, but we only really need this file if we are building with XML support */
#ifdef WITH_XML
#ifndef __ANNOTATE_H
#define __ANNOTATE_H
#include <utility>
#include <string>
#include <list>
#include <map>
#include <xercesc/dom/DOM.hpp>
class annotate
{
protected:
//xercesc::DOMDocument* doc;
xercesc::DOMElement* virtual_root;
std::map<std::string, xercesc::DOMElement*> *physical_elements;
public:
// Annotates nodes and direct links in the rspec
virtual void annotate_element(const char* v_name, const char* p_name) = 0;
// Annotates intraswitch and interswitch links in the rspec
virtual void annotate_element(const char* v_name, std::list<const char*>* links) = 0;
// Creates a hop from a switch till the next end point. Adds the hop to the vlink and returns the hop element that was created
virtual xercesc::DOMElement* create_component_hop (const xercesc::DOMElement* plink, xercesc::DOMElement* vlink, int endpoint_interface, const xercesc::DOMElement* prev_component_hop) = 0;
// Finds the next link in the path returned by assign
virtual xercesc::DOMElement* find_next_link_in_path (xercesc::DOMElement *prev, std::list<const char*>* links) = 0;
// Writes the annotated xml to disk
void write_annotated_file(const char* filename);
};
#endif // for __ANNOTATE_H
#endif // for WITH_XML
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2003-2009 University of Utah and the Flux Group.
* All rights reserved.
*/
static const char rcsid[] = "$Id: annotate_rspec.cc,v 1.2 2009-05-20 18:06:07 tarunp Exp $";
#ifdef WITH_XML
#include "annotate.h"
#include "annotate_rspec.h"
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/dom/DOM.hpp>
#include "xstr.h"
#include "xmlhelpers.h"
#include <iostream>
#include <utility>
#include <list>
#include <string>
#define XMLDEBUG(x) (cerr << x);
extern DOMDocument* doc;
extern DOMElement* request_root;
extern map<string, DOMElement*>* advertisement_elements;
XERCES_CPP_NAMESPACE_USE
using namespace std;
annotate_rspec :: annotate_rspec ()
{
// this->doc = doc;
this->virtual_root = request_root;
this->physical_elements = advertisement_elements;
}
// This will get called when a node or a direct link needs to be annotated
void annotate_rspec::annotate_element (const char* v_name, const char* p_name)
{
DOMElement* vnode = getElementByAttributeValue(this->virtual_root, "node", "virtual_id", v_name);
// If a vnode by that name was found, then go ahead. If not, that element should be a link
// We are not terribly concerned about having to scan the entire physical topology twice
// because direct links are never really going to happen
if (vnode != NULL)
{
DOMElement* pnode = (this->physical_elements->find(p_name))->second;
copy_component_spec(pnode, vnode);
}
else
{
DOMElement* vlink = getElementByAttributeValue(this->virtual_root, "link", "virtual_id", v_name);
DOMElement* plink = (this->physical_elements->find(p_name))->second;
annotate_interface (plink, vlink, 0);
annotate_interface (plink, vlink, 1);
create_component_hop(plink, vlink, BOTH, NULL);
}
}
// This is called when an intraswitch or interswitch link has to be annotated
void annotate_rspec::annotate_element (const char* v_name, list<const char*>* links)
{
// These are the paths from the source to the first switch
// and from the last switch to the destination
const char* psrc_name = links->front();
const char* pdst_name = links->back();
DOMElement* p_src_switch_link = (this->physical_elements->find(psrc_name))->second;
DOMElement* p_switch_dst_link = (this->physical_elements->find(pdst_name))->second;
// Remove these links from the list
// If it is an intra-switch link, the list should now be empty.
links->pop_front();
links->pop_back();
DOMElement* vlink = getElementByAttributeValue (this->virtual_root, "link", "virtual_id", v_name);
annotate_interface(p_src_switch_link, vlink, 0);
annotate_interface(p_switch_dst_link, vlink, 1);
DOMElement* prev_component_hop = create_component_hop (p_src_switch_link, vlink, SOURCE, NULL);
for (DOMElement *prev_link_in_path = p_src_switch_link; !links->empty(); )
{
DOMElement* p_switch_switch_link = find_next_link_in_path (prev_link_in_path, links);
prev_component_hop = create_component_hop (p_switch_switch_link, vlink, NEITHER, prev_component_hop);
prev_link_in_path = p_switch_switch_link;
}
create_component_hop (p_switch_dst_link, vlink, DESTINATION, prev_component_hop);
}
// Creates a hop from a switch till the next end point. Adds the hop to the vlink and returns the hop element that was created
DOMElement* annotate_rspec::create_component_hop (const DOMElement* plink, DOMElement* vlink, int endpoint_interface, const DOMElement* prev_component_hop)
{
// Create a single_hop_link element
DOMElement* component_hop = doc->createElement(XStr("component_hop").x());
copy_component_spec(plink, component_hop);
DOMElement* component_hop_interface = doc->createElement(XStr("interface").x());
// We assume the first interface is the source and the second is the destination
DOMNodeList* pinterfaces = plink->getElementsByTagName(XStr("interface").x());
DOMElement* plink_src_iface = dynamic_cast<DOMElement*>(pinterfaces->item(0));
DOMElement* plink_dst_iface = dynamic_cast<DOMElement*>(pinterfaces->item(1));
DOMNodeList* vinterfaces = vlink->getElementsByTagName(XStr("interface").x());
DOMElement* vlink_src_iface = dynamic_cast<DOMElement*>(vinterfaces->item(0));
DOMElement* vlink_dst_iface = dynamic_cast<DOMElement*>(vinterfaces->item(1));
// If the previous component hop is not specified (NULL),
// then the link is either direct or the direction is guaranteed to be from the node to the switch
DOMElement* plink_src_iface_clone = dynamic_cast<DOMElement*>(doc->importNode(dynamic_cast<DOMNode*>(plink_src_iface), true));
DOMElement* plink_dst_iface_clone = dynamic_cast<DOMElement*>(doc->importNode(dynamic_cast<DOMNode*>(plink_dst_iface), true));
// If the previous component is specified,
// the link specification could be the opposite of what we need
if (prev_component_hop != NULL)
{
// Find the destination of the previous component hop
DOMElement* prev_hop_dst_iface = dynamic_cast<DOMElement*>((prev_component_hop->getElementsByTagName(XStr("interface").x()))->item(1));
XStr prev_hop_dst_uuid (prev_hop_dst_iface->getAttribute(XStr("component_node_uuid").x()));
// We need to do this because in advertisements, all links are from nodes to switches
// and we need to reverse this order for the last hop of a multi-hop path
// This is slightly more expensive, but definitely more robust than checking based on whether a destination interface was specified
if (strcmp(prev_hop_dst_uuid.c(), XStr(plink_dst_iface->getAttribute(XStr("component_node_uuid").x())).c()) == 0)
{
plink_src_iface_clone = dynamic_cast<DOMElement*>(doc->importNode(dynamic_cast<DOMNode*>(plink_dst_iface), true));
plink_dst_iface_clone = dynamic_cast<DOMElement*>(doc->importNode(dynamic_cast<DOMNode*>(plink_src_iface), true));
}
}
// If the source interface is an end point
if (endpoint_interface == SOURCE || endpoint_interface == BOTH)
set_interface_as_link_endpoint(plink_src_iface_clone, XStr(vlink_src_iface->getAttribute(XStr("virtual_node_id").x())).c());
// If the destination interface is an end point
if (endpoint_interface == DESTINATION || endpoint_interface == BOTH)
set_interface_as_link_endpoint(plink_dst_iface_clone, XStr(vlink_dst_iface->getAttribute(XStr("virtual_node_id").x())).c());
// Add interface specifications to the link in the single hop element
component_hop->appendChild(plink_src_iface_clone);
component_hop->appendChild(plink_dst_iface_clone);
vlink->appendChild(component_hop);
return (component_hop);
}
// Annotates the interface element on a link and updates the node which is the end point of the link as well
void annotate_rspec::annotate_interface (const DOMElement* plink, DOMElement* vlink, int interface_number)
{
DOMNodeList* vinterfaces = vlink->getElementsByTagName(XStr("interface").x());
DOMElement* vlink_iface = dynamic_cast<DOMElement*>(vinterfaces->item(interface_number));
// Get the virtual_id on the end points of the interface
XStr vlink_iface_virtual_id (vlink_iface->getAttribute(XStr("virtual_node_id").x()));
DOMElement* vnode = getElementByAttributeValue(this->virtual_root, "node", "virtual_id", vlink_iface_virtual_id.c());
XStr node_component_uuid (vnode->getAttribute(XStr("component_uuid").x()));
DOMElement* p_iface = getElementByAttributeValue(plink, "interface", "component_node_uuid", node_component_uuid.c());
vlink_iface->setAttribute(XStr("component_node_uuid").x(), p_iface->getAttribute(XStr("component_node_uuid").x()));
vlink_iface->setAttribute(XStr("component_interface_name").x(), p_iface->getAttribute(XStr("component_interface_name").x()));
XStr component_interface_name (vlink_iface->getAttribute(XStr("component_interface_name").x()));
XStr virtual_interface_name (vlink_iface->getAttribute(XStr("virtual_interface_name").x()));
// Get the interface for the node and update
DOMElement* vnode_iface_decl = getElementByAttributeValue(vnode, "interface", "virtual_id", virtual_interface_name.c());
vnode_iface_decl->setAttribute (XStr("component_name").x(), component_interface_name.x());
}
// Copies the component spec from the source to the destination
void annotate_rspec::copy_component_spec(const DOMElement* src, DOMElement* dst)
{
if (src->hasAttribute (XStr("component_name").x()))
dst->setAttribute (XStr("component_name").x(), XStr(src->getAttribute(XStr("component_name").x())).x());
dst->setAttribute (XStr("component_uuid").x(), XStr(src->getAttribute(XStr("component_uuid").x())).x());
dst->setAttribute (XStr("component_manager_uuid").x(), XStr(src->getAttribute(XStr("component_manager_uuid").x())).x());
}
// If the interface belongs to an end point of the link, and additional virtual_id attribute has to be added to it
void annotate_rspec::set_interface_as_link_endpoint (DOMElement* interface, const char* virtual_id)
{
interface->setAttribute(XStr("virtual_id").x(), XStr(virtual_id).x());
}
// Finds the next link in the path returned by assign
// Assign sometimes reverses the links on the path from the source to the destination,
// so you need to look at the entire path to find the next link
DOMElement* annotate_rspec::find_next_link_in_path (DOMElement *prev, list<const char*>* links)
{
list<const char*>::iterator it;
DOMElement* link = NULL;
for (it = links->begin(); it != links->end(); ++it)
{
link = (this->physical_elements->find(*it))->second;
XStr link_src(getNthInterface(link,0)->getAttribute(XStr("component_node_uuid").x()));
XStr link_dst(getNthInterface(link,1)->getAttribute(XStr("component_node_uuid").x()));
XStr prev_dst(getNthInterface(prev,1)->getAttribute(XStr("component_node_uuid").x()));
if (strcmp(link_src.c(), prev_dst.c()) == 0 || strcmp(link_dst.c(), prev_dst.c()) == 0)
{
links->remove(*it);
break;
}
}
return link;
}
#endif
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2008 University of Utah and the Flux Group.
* All rights reserved.
*/
/*
* Base class for the annotater.
*/
/* This is ugly, but we only really need this file if we are building with XML support */
#ifdef WITH_XML
#ifndef __ANNOTATE_RSPEC_H
#define __ANNOTATE_RSPEC_H
#include "annotate.h"
#include <list>
#include <map>
#include <utility>
#include <string>
#include <xercesc/dom/DOM.hpp>
class annotate_rspec : public annotate
{
private:
// Enumeration of which interface in a hop is an interface to a link end point
enum endpoint_interface_enum { NEITHER, SOURCE, DESTINATION, BOTH };
public:
annotate_rspec ();
~annotate_rspec () { ; }
// Annotates nodes and direct links in the rspec