Commit af0400c1 authored by Jonathon Duerig's avatar Jonathon Duerig

The design of distributed-dijkstra is now much more modular with explicit...

The design of distributed-dijkstra is now much more modular with explicit options for no compression etc. There remains a possibly serious bug in the checker which I am investigating.
parent 7fcb28aa
......@@ -7,92 +7,31 @@
*/
#include "lib.h"
#include "bitmath.h"
#include "dijkstra.h"
#include "Compressor.h"
using namespace std;
Compressor::Compressor()
: graph(NULL)
, ipMap(NULL)
{
}
Compressor::~Compressor()
{
}
void Compressor::compress(SingleSource const & newGraph,
HostHostToIpMap const & newIp)
{
graph = &newGraph;
ipMap = &newIp;
root_10.reset();
root_172_16.reset();
root_192_168.reset();
const int Compressor::shift[PRIVATE_SUBNET_COUNT] = {IP_SIZE - 8,
IP_SIZE - 12,
IP_SIZE - 16};
set<string> implicitIp;
HostEntry::const_iterator implicitPos;
HostEntry::const_iterator implicitLimit;
implicitPos = (*ipMap)[graph->getSource()].begin();
implicitLimit = (*ipMap)[graph->getSource()].end();
for ( ; implicitPos != implicitLimit; ++implicitPos)
{
implicitIp.insert(implicitPos->second.second);
}
for (int i = 0; i < graph->getVertexCount(); ++i)
{
int dest = i;
if (dest != graph->getSource())
{
HostEntry::const_iterator pos;
HostEntry::const_iterator limit;
pos = (*ipMap)[dest].begin();
limit = (*ipMap)[dest].end();
for ( ; pos != limit; ++pos)
{
if (implicitIp.find(pos->second.first) == implicitIp.end())
{
IPAddress destIp = stringToIP(pos->second.first);
add(dest, destIp);
}
}
}
}
root_10.printRoutes(INT_MAX, *ipMap, graph->getSource(), ip_10);
root_172_16.printRoutes(INT_MAX, *ipMap, graph->getSource(),
ip_172_16);
root_192_168.printRoutes(INT_MAX, *ipMap, graph->getSource(),
ip_192_168);
}
const IPAddress Compressor::prefix[PRIVATE_SUBNET_COUNT] = {10,
(172 << 8) + 16,
(192 << 8) + 168};
void Compressor::add(int dest, IPAddress destIp)
Compressor::PRIVATE_SUBNET Compressor::whichSubnet(IPAddress destIp)
{
int firstHop = graph->getFirstHop(dest);
HostEntry::const_iterator pos;
pos = (*ipMap)[graph->getSource()].find(firstHop);
if (pos != (*ipMap)[graph->getSource()].end())
#ifdef ROCKETFUEL_TEST
return SUB_10;
#else
for (PRIVATE_SUBNET i = PRIVATE_SUBNET_MIN; i < PRIVATE_SUBNET_COUNT;
i = static_cast<PRIVATE_SUBNET>(i + PRIVATE_SUBNET_UNIT))
{
if ((destIp >> shift_10) == ip_10)
if ((destIp >> shift[i]) == prefix[i])
{
root_10.addRoute(destIp, firstHop, IP_SIZE - shift_10);
}
else if ((destIp >> shift_172_16) == ip_172_16)
{
root_172_16.addRoute(destIp, firstHop, IP_SIZE - shift_172_16);
}
else if ((destIp >> shift_192_168) == ip_192_168)
{
root_192_168.addRoute(destIp, firstHop, IP_SIZE - shift_192_168);
}
else
{
// TODO: Figure out what cost means
printRouteToIp(pos->second.first, pos->second.second,
ipToString(destIp), 1);
return i;
}
}
return PRIVATE_SUBNET_INVALID;
#endif
}
......@@ -6,51 +6,67 @@
* All rights reserved.
*/
// This is a function-object which carries out route compression. This
// relies on the helper class IpTree. See that class for details of
// the algorithm. Of note is that there are three bitspaces which can
// be compressed: 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16. These
// must be individually compressed because otherwise a subnet might
// cover a real internet address. Any ip address not in one of these
// blocks is not compressed and a single route is printed to that
// address.
// This is a parent class for a group of functors. Which functor is
// actually called is dependant upon command-line arguments and is set
// in the 'processArgs()' function in 'dijkstra.cc'. Each of these
// functors prints out all the routes for a particular source using
// the graph and IP map given. The different types of functors use
// different techniques to compress the routing table as it is
// printed. See 'NoneCompressor.h', 'VoteCompressor.h', and
// 'OptimalCompressor.h' for details on the particulars.
#ifndef COMPRESSOR_H_DISTRIBUTED_DIJKSTRA_1
#define COMPRESSOR_H_DISTRIBUTED_DIJKSTRA_2
#define COMPRESSOR_H_DISTRIBUTED_DIJKSTRA_1
#include "dijkstra.h"
#include "bitmath.h"
#include "SingleSource.h"
#include "IpTree.h"
class Compressor
{
private:
static const int shift_10 = IP_SIZE - 8;
static const IPAddress ip_10 = 10;
protected:
// These constants are used to distinguish between the three
// non-routable prefixes that can be used to build a private
// network.
enum PRIVATE_SUBNET
{
PRIVATE_SUBNET_MIN = 0,
PRIVATE_SUBNET_UNIT = 1,
PRIVATE_SUBNET_MAX = 2,
PRIVATE_SUBNET_COUNT = 3,
PRIVATE_SUBNET_INVALID = 3,
SUB_10 = 0,
SUB_172_16 = 1,
SUB_192_168 = 2
};
static const int shift[PRIVATE_SUBNET_COUNT];// = {IP_SIZE - 8,
// IP_SIZE - 12,
// IP_SIZE - 16};
static const IPAddress prefix[PRIVATE_SUBNET_COUNT];// = {10,
// (172 << 8) + 16,
// (192 << 8) + 168};
static const int shift_172_16 = IP_SIZE - 12;
static const IPAddress ip_172_16 = (172 << 8) + 16;
static PRIVATE_SUBNET whichSubnet(IPAddress destIp);
static const int shift_192_168 = IP_SIZE - 16;
static const IPAddress ip_192_168 = (192 << 8) + 168;
// static const int shift_10 = IP_SIZE - 8;
// static const IPAddress ip_10 = 10;
//
// static const int shift_172_16 = IP_SIZE - 12;
// static const IPAddress ip_172_16 = (172 << 8) + 16;
//
// static const int shift_192_168 = IP_SIZE - 16;
// static const IPAddress ip_192_168 = (192 << 8) + 168;
public:
Compressor();
~Compressor();
Compressor() {}
virtual ~Compressor() {}
// Run the algorithm. Note that no state is kept between invocations.
void compress(SingleSource const & newGraph,
HostHostToIpMap const & newIp);
private:
void add(int dest, IPAddress destIp);
virtual void printRoutes(SingleSource const & graph,
HostHostToIpMap const & ip)=0;
private:
Compressor(Compressor const &);
Compressor & operator=(Compressor const &) { return *this; }
private:
IpTree root_10;
IpTree root_172_16;
IpTree root_192_168;
SingleSource const * graph;
HostHostToIpMap const * ipMap;
};
#endif
......@@ -17,10 +17,17 @@ all: dijkstra
include $(TESTBED_SRCDIR)/GNUmakerules
dijkstra-debug: dijkstra.o bitmath.o Compressor.o IpTree.o SingleSource.o \
bitmath.h Exception.h SingleSource.h IpTree.h dijkstra.h \
Compressor.h lib.h
$(CXX) $(CXXFLAGS) -static dijkstra.o bitmath.o Compressor.o IpTree.o SingleSource.o $(LIBS) -o $@
dijkstra-debug: Compressor.o TreeCompressor.o dijkstra.o \
NoneCompressor.o VoteIpTree.o SingleSource.o \
OptimalIpTree.o bitmath.o \
Compressor.h OptimalIpTree.h VoteIpTree.h \
Exception.h SetIterator.h bitmath.h \
IpTree.h SingleSource.h dijkstra.h \
NoneCompressor.h TreeCompressor.h lib.h
$(CXX) $(CXXFLAGS) -static Compressor.o TreeCompressor.o dijkstra.o \
NoneCompressor.o VoteIpTree.o SingleSource.o \
OptimalIpTree.o bitmath.o $(LIBS) -o $@
client: all
client-install: client
......
......@@ -6,51 +6,38 @@
* All rights reserved.
*/
// IpTree is a sparse binary tree into which IP addresses are
// inserted. Each IP address inserted into the tree has an associated
// 'first hop' number. Each node knows which firstHop numbers it has
// encountered and how many of each there are.
#ifndef IP_TREE_H_DISTRIBUTED_DIJKSTRA_1
#define IP_TREE_H_DISTRIBUTED_DIJKSTRA_1
class IpTree
{
public:
IpTree();
~IpTree();
IpTree() {}
virtual ~IpTree() {}
// return a new default-constructed IpTree of the same type as the
// current object is.
virtual std::auto_ptr<IpTree> exemplar(void) const=0;
// Reset the state of the tree. Remove any state and put it back
// to how it was just after construction.
void reset(void);
virtual void reset(void)=0;
// Fill the tree with an IP address. The recursively added address
// is limited by depth.
void addRoute(IPAddress ip, int newFirstHop, int depth = 0);
// Print a route based on the most popular first hop this object
// has encountered. The object knows how many of each first hop
// has visited it. The one which has visited it the most often is
// the first hop which is selected. A route based on that first
// hop is then printed. Note that if the parent's most popular
// first hop is the same as the current first hop, no route need
// be printed. The left/right branch selection of the path from
// the root to this host represents the prefix. The depth
// represents the netmask size.
void printRoutes(int parentFirstHop, HostHostToIpMap const & ip,
int source, IPAddress subnet);
// Which of the first hops in m_childHops have we encountered the
// most?
std::map<int,int>::iterator findMostPos(void);
void addRoute(IPAddress ip, int newFirstHop)
{
addRoute(ip, newFirstHop, 0);
}
virtual void addRoute(IPAddress ip, int newFirstHop, int depth)=0;
// Print out the routes for this subtree
virtual void printRoutes(HostHostToIpMap const & ip, int source,
IPAddress subnet)=0;
private:
IpTree(IpTree const &);
IpTree & operator=(IpTree const &) { return *this; }
private:
std::auto_ptr<IpTree> m_child[2];
int m_firstHop;
std::map<int, int> m_childHops;
int m_depth;
};
#endif
// NoneCompressor.cc
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2004 University of Utah and the Flux Group.
* All rights reserved.
*/
#include "lib.h"
#include "NoneCompressor.h"
using namespace std;
NoneCompressor::NoneCompressor()
{
}
NoneCompressor::~NoneCompressor()
{
}
void NoneCompressor::printRoutes(SingleSource const & graph,
HostHostToIpMap const & ip)
{
printRoutesFromHost(graph.getSource(), graph, ip);
}
void NoneCompressor::printRoutesFromHost(int source,
SingleSource const & graph,
HostHostToIpMap const & ip)
{
for (int i = 0; i < graph.getVertexCount(); ++i)
{
if (i != source)
{
printRoutesToHost(source, i, graph, ip);
}
}
}
void NoneCompressor::printRoutesToHost(int source, int dest,
SingleSource const & graph,
HostHostToIpMap const & ip)
{
string sourceIp;
string firstHopIp;
calculateSourceInfo(source, dest, graph, ip, sourceIp, firstHopIp);
multimap< int, pair<string, string> >::const_iterator pos;
pos = ip[dest].begin();
multimap< int, pair<string, string> >::const_iterator limit;
limit = ip[dest].end();
string previous;
for ( ; pos != limit; ++pos)
{
string const & destIp = pos->second.first;
if (destIp != previous)
{
printRouteToIp(sourceIp, firstHopIp, destIp,
graph.getDistance(dest));
previous = destIp;
}
}
}
void NoneCompressor::calculateSourceInfo(int source, int dest,
SingleSource const & graph,
HostHostToIpMap const & ip,
string & outSourceIp,
string & outFirstHopIp)
{
multimap< int, pair<string, string> >::const_iterator sourcePos;
sourcePos = ip[source].find(graph.getFirstHop(dest));
if (sourcePos == ip[source].end())
{
throw RouteNotFoundException(source, dest, graph.getFirstHop(dest));
}
outSourceIp = sourcePos->second.first;
outFirstHopIp = sourcePos->second.second;
}
// NoneCompressor.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2004 University of Utah and the Flux Group.
* All rights reserved.
*/
// This function-object carries out route compression. Actually, the
// point of this object is to represent no-compression. This object
// simply prints out the routes generated without trying to compress
// anything. This is used if the user doesn't want any route
// compression or while testing a route-compression method.
#ifndef NONE_COMPRESSOR_H_DISTRIBUTED_DIJKSTRA_1
#define NONE_COMPRESSOR_H_DISTRIBUTED_DIJKSTRA_1
#include "Compressor.h"
class NoneCompressor : public Compressor
{
public:
NoneCompressor();
virtual ~NoneCompressor();
virtual void printRoutes(SingleSource const & graph,
HostHostToIpMap const & ip);
private:
// Print all routes from a particular host to every destination.
void printRoutesFromHost(int source, SingleSource const & graph,
HostHostToIpMap const & ip);
// Print all routes from a particular host to a particular host
void printRoutesToHost(int source, int dest, SingleSource const & graph,
HostHostToIpMap const & ip);
// Calculate the source ip address and the first hop ip address
// between a particular pair of hosts.
void calculateSourceInfo(int source, int dest,
SingleSource const & graph,
HostHostToIpMap const & ip,
std::string & OutSourceIp,
std::string & OutFirstHopIp);
private:
NoneCompressor(NoneCompressor const &);
NoneCompressor & operator=(NoneCompressor const &) { return *this; }
};
#endif
// OptimalIpTree.cc
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2004 University of Utah and the Flux Group.
* All rights reserved.
*/
#include "lib.h"
#include "OptimalIpTree.h"
#include "SetIterator.h"
#include "dijkstra.h"
using namespace std;
void OptimalIpTree::IntersectionOrUnion(set<int> const & left,
set<int> const & right,
set<int> & result)
{
assert(&left != &result && &right != &result);
result.clear();
bool useIntersection = false;
SetIterator pos(left, right);
for ( ; pos.valid() && !useIntersection; pos.increment())
{
if (pos.getSet() == SetIterator::BOTH_SETS)
{
useIntersection = true;
}
}
if (useIntersection)
{
Intersection(left, right, result);
}
else
{
Union(left, right, result);
}
}
void OptimalIpTree::Intersection(set<int> const & left,
set<int> const & right,
set<int> & result)
{
assert(result.empty());
assert(&left != &result && &right != &result);
SetIterator pos(left, right);
for ( ; pos.valid(); pos.increment())
{
if (pos.getSet() == SetIterator::BOTH_SETS)
{
result.insert(pos.getValue());
}
}
}
void OptimalIpTree::Union(set<int> const & left,
set<int> const & right,
set<int> & result)
{
assert(result.empty());
assert(&left != &result && &right != &result);
SetIterator pos(left, right);
for ( ; pos.valid(); pos.increment())
{
result.insert(pos.getValue());
}
}
OptimalIpTree::OptimalIpTree()
: m_depth(0)
{
}
OptimalIpTree::~OptimalIpTree()
{
}
OptimalIpTree::OptimalIpTree(OptimalIpTree const & right)
{
m_depth = right.m_depth;
m_firstHops = right.m_firstHops;
if (right.m_children[0].get() == NULL)
{
m_children[0].reset(NULL);
}
else
{
m_children[0].reset(new OptimalIpTree(*(right.m_children[0])));
}
if (right.m_children[1].get() == NULL)
{
m_children[1].reset(NULL);
}
else
{
m_children[1].reset(new OptimalIpTree(*(right.m_children[1])));
}
}
OptimalIpTree & OptimalIpTree::operator=(OptimalIpTree const & right)
{
OptimalIpTree swapper(right);
m_firstHops.swap(swapper.m_firstHops);
swap(m_depth, swapper.m_depth);
swap(m_children[0], swapper.m_children[0]);
swap(m_children[1], swapper.m_children[1]);
return *this;
}
auto_ptr<IpTree> OptimalIpTree::exemplar(void) const
{
return auto_ptr<IpTree>(new OptimalIpTree());
}
void OptimalIpTree::reset(void)
{
m_depth = 0;
m_firstHops.clear();
m_children[0].reset(NULL);
m_children[1].reset(NULL);
}
void OptimalIpTree::addRoute(IPAddress ip, int newFirstHop, int depth)
{
m_depth = depth;
if (depth < IP_SIZE)
{
IPAddress bit = (ip >> (IP_SIZE - depth - 1)) & 0x01;
if (m_children[bit].get() == NULL)
{
m_children[bit].reset(new OptimalIpTree());
}
m_children[bit]->addRoute(ip, newFirstHop, depth + 1);
}
else
{
m_firstHops.clear();
m_firstHops.insert(newFirstHop);
}
}
void OptimalIpTree::joinSets(void)
{
if (m_children[0].get() != NULL && m_children[1].get() != NULL)
{
m_children[0]->joinSets();
m_children[1]->joinSets();
IntersectionOrUnion(m_children[0]->m_firstHops,
m_children[1]->m_firstHops,
m_firstHops);
}
else if (m_children[0].get() != NULL)
{
m_children[0]->joinSets();
m_firstHops = m_children[0]->m_firstHops;
}
else if (m_children[1].get() != NULL)
{
m_children[1]->joinSets();
m_firstHops = m_children[1]->m_firstHops;
}
// If both are NULL, we are a leaf, and do nothing.
}
void OptimalIpTree::printRoutes(HostHostToIpMap const & ip, int source,
IPAddress subnet)
{
if (m_children[0].get() != NULL || m_children[1].get() != NULL)
{
joinSets();
assert(!(m_firstHops.empty()));
HostEntry::const_iterator pos;
pos = ip[source].find(*(m_firstHops.begin()));
if (pos != ip[source].end())
{
printRouteToSubnet(pos->second.first, pos->second.second,
ipToString(subnet << (IP_SIZE - m_depth)),
m_depth, 1);
}
printRoutes(*(m_firstHops.begin()), ip, source, subnet);
}
}
void OptimalIpTree::printRoutes(int firstHop, HostHostToIpMap const & ip,
int source, IPAddress subnet)
{
assert(!(m_firstHops.empty()));
if (m_firstHops.count(firstHop) == 0)
{
firstHop = *(m_firstHops.begin());
HostEntry::const_iterator pos = ip[source].find(firstHop);
if (pos != ip[source].end())
{
printRouteToSubnet(pos->second.first, pos->second.second,
ipToString(subnet << (IP_SIZE - m_depth)),
m_depth, 1);
// TODO: replace hardcoded '1' with cost metric
}
}
if (m_children[0].get() != NULL)
{
m_children[0]->printRoutes(firstHop, ip, source, subnet << 1);
}
if (m_children[1].get() != NULL)
{
m_children[1]->printRoutes(firstHop, ip, source, (subnet << 1) + 1);
}
}
int OptimalIpTree::size(void)
{
int result = 1;
if (m_children[0].get() != NULL)
{
result += m_children[0]->size();
}
if (m_children[1].get() != NULL)
{
result += m_children[1]->size();
}
return result;
}
// OptimalIpTree.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2004 University of Utah and the Flux Group.
* All rights reserved.
*/
// This algorithm comes from the paper 'Constructing Optimal IP
// Routing Tables' by Richard P. Draves, Christopher King, Srinivasan
// Venkatachary, and Brian D. Zill. It was published by the IEEE.
#ifndef OPTIMAL_IP_TREE_H_DISTRIBUTED_DIJKSTRA_1
#define OPTIMAL_IP_TREE_H_DISTRIBUTED_DIJKSTRA_1
#include "bitmath.h"
#include "IpTree.h"
class OptimalIpTree : public IpTree
{
public: