diff --git a/SConstruct b/SConstruct index 8d8468c27..9c9a2567c 100644 --- a/SConstruct +++ b/SConstruct @@ -374,15 +374,17 @@ routing.add_sources([ 'routing-environment.cc', 'static-router.cc', 'static-route-manager.cc', + 'static-route-manager-impl.cc', 'candidate-queue.cc', ]) routing.add_headers ([ + 'candidate-queue.h', + 'static-route-manager-impl.h', ]) routing.add_inst_headers([ 'routing-environment.h', 'static-router.h', 'static-route-manager.h', - 'candidate-queue.h', ]) # utils diff --git a/examples/simple-static-routing.cc b/examples/simple-static-routing.cc index 55200e7af..01848c92c 100644 --- a/examples/simple-static-routing.cc +++ b/examples/simple-static-routing.cc @@ -65,6 +65,7 @@ #include "ns3/ipv4-route.h" #include "ns3/p2p-topology.h" #include "ns3/onoff-application.h" +#include "ns3/routing-environment.h" #include "ns3/static-route-manager.h" using namespace ns3; @@ -84,6 +85,7 @@ int main (int argc, char *argv[]) DebugComponentEnable("StaticRouter"); DebugComponentEnable("StaticRouteManager"); #endif + DebugComponentEnable("StaticRouteManager"); // Set up some default values for the simulation. Use the Bind() // technique to tell the system what subclass of Queue to use, @@ -142,9 +144,8 @@ int main (int argc, char *argv[]) if (RoutingEnvironment::StaticRoutingEnabled()) { - Ptr routeManager = Create (); - routeManager->BuildStaticRoutingDatabase (); - routeManager->InitializeRoutes (); + StaticRouteManager::BuildStaticRoutingDatabase (); + StaticRouteManager::InitializeRoutes (); } // Create the OnOff application to send UDP datagrams of size diff --git a/src/routing/candidate-queue.h b/src/routing/candidate-queue.h index 5d8993f2e..27fcd01b4 100644 --- a/src/routing/candidate-queue.h +++ b/src/routing/candidate-queue.h @@ -19,7 +19,7 @@ #include #include -#include "static-route-manager.h" +#include "static-route-manager-impl.h" namespace ns3 { diff --git a/src/routing/static-route-manager-impl.cc b/src/routing/static-route-manager-impl.cc new file mode 100644 index 000000000..52f8d4b32 --- /dev/null +++ b/src/routing/static-route-manager-impl.cc @@ -0,0 +1,1382 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include "ns3/assert.h" +#include "ns3/fatal-error.h" +#include "ns3/debug.h" +#include "ns3/node-list.h" +#include "ns3/ipv4.h" +#include "static-router.h" +#include "static-route-manager-impl.h" +#include "candidate-queue.h" + +NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); + +namespace ns3 { + +// --------------------------------------------------------------------------- +// +// SPFVertex Implementation +// +// --------------------------------------------------------------------------- + +SPFVertex::SPFVertex () : + m_vertexType (VertexUnknown), + m_vertexId ("255.255.255.255"), + m_lsa (0), + m_distanceFromRoot (SPF_INFINITY), + m_rootOif (SPF_INFINITY), + m_nextHop ("0.0.0.0"), + m_parent (0), + m_children () +{ +} + +SPFVertex::SPFVertex (StaticRouterLSA* lsa) : + m_vertexType (VertexRouter), + m_vertexId (lsa->GetLinkStateId ()), + m_lsa (lsa), + m_distanceFromRoot (SPF_INFINITY), + m_rootOif (SPF_INFINITY), + m_nextHop ("0.0.0.0"), + m_parent (0), + m_children () +{ +} + +SPFVertex::~SPFVertex () +{ + for ( ListOfSPFVertex_t::iterator i = m_children.begin (); + i != m_children.end (); + i++) + { + SPFVertex *p = *i; + delete p; + p = 0; + *i = 0; + } + m_children.clear (); +} + + void +SPFVertex::SetVertexType (SPFVertex::VertexType type) +{ + m_vertexType = type; +} + + SPFVertex::VertexType +SPFVertex::GetVertexType (void) const +{ + return m_vertexType; +} + + void +SPFVertex::SetVertexId (Ipv4Address id) +{ + m_vertexId = id; +} + + Ipv4Address +SPFVertex::GetVertexId (void) const +{ + return m_vertexId; +} + + void +SPFVertex::SetLSA (StaticRouterLSA* lsa) +{ + m_lsa = lsa; +} + + StaticRouterLSA* +SPFVertex::GetLSA (void) const +{ + return m_lsa; +} + + void +SPFVertex::SetDistanceFromRoot (uint32_t distance) +{ + m_distanceFromRoot = distance; +} + + uint32_t +SPFVertex::GetDistanceFromRoot (void) const +{ + return m_distanceFromRoot; +} + + void +SPFVertex::SetOutgoingInterfaceId (uint32_t id) +{ + m_rootOif = id; +} + + uint32_t +SPFVertex::GetOutgoingInterfaceId (void) const +{ + return m_rootOif; +} + + void +SPFVertex::SetNextHop (Ipv4Address nextHop) +{ + m_nextHop = nextHop; +} + + Ipv4Address +SPFVertex::GetNextHop (void) const +{ + return m_nextHop; +} + + void +SPFVertex::SetParent (SPFVertex* parent) +{ + m_parent = parent; +} + + SPFVertex* +SPFVertex::GetParent (void) const +{ + return m_parent; +} + + uint32_t +SPFVertex::GetNChildren (void) const +{ + return m_children.size (); +} + + SPFVertex* +SPFVertex::GetChild (uint32_t n) const +{ + uint32_t j = 0; + + for ( ListOfSPFVertex_t::const_iterator i = m_children.begin (); + i != m_children.end (); + i++, j++) + { + if (j == n) + { + return *i; + } + } + NS_ASSERT_MSG(false, "Index out of range."); + return 0; +} + + uint32_t +SPFVertex::AddChild (SPFVertex* child) +{ + m_children.push_back (child); + return m_children.size (); +} + +// --------------------------------------------------------------------------- +// +// StaticRouteManagerLSDB Implementation +// +// --------------------------------------------------------------------------- + +StaticRouteManagerLSDB::StaticRouteManagerLSDB () +: + m_database () +{ + NS_DEBUG ("StaticRouteManagerLSDB::StaticRouteManagerLSDB ()"); +} + +StaticRouteManagerLSDB::~StaticRouteManagerLSDB () +{ + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); + + LSDBMap_t::iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ():free LSA"); + StaticRouterLSA* temp = i->second; + delete temp; + } + NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); + m_database.clear (); +} + + void +StaticRouteManagerLSDB::Initialize () +{ + NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); + + LSDBMap_t::iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + StaticRouterLSA* temp = i->second; + temp->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); + } +} + + void +StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) +{ + NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); + m_database.insert (LSDBPair_t (addr, lsa)); +} + + StaticRouterLSA* +StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const +{ + NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); +// +// Look up an LSA by its address. +// + LSDBMap_t::const_iterator i; + for (i= m_database.begin (); i!= m_database.end (); i++) + { + if (i->first == addr) + { + return i->second; + } + } + return 0; +} + +// --------------------------------------------------------------------------- +// +// StaticRouteManagerImpl Implementation +// +// --------------------------------------------------------------------------- + +StaticRouteManagerImpl::StaticRouteManagerImpl () +: + m_spfroot (0) +{ + NS_DEBUG ("StaticRouteManagerImpl::StaticRoutemanagerImpl ()"); + m_lsdb = new StaticRouteManagerLSDB (); +} + +StaticRouteManagerImpl::~StaticRouteManagerImpl () +{ + NS_DEBUG ("StaticRouteManagerImpl::~StaticRouteManagerImpl ()"); + + if (m_lsdb) + { + delete m_lsdb; + } +} + + void +StaticRouteManagerImpl::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) +{ + NS_DEBUG ("StaticRouteManagerImpl::DebugUseLsdb ()"); + + if (m_lsdb) + { + delete m_lsdb; + } + m_lsdb = lsdb; +} + +// +// In order to build the routing database, we need to walk the list of nodes +// in the system and look for those that support the StaticRouter interface. +// These routers will export a number of Link State Advertisements (LSAs) +// that describe the links and networks that are "adjacent" (i.e., that are +// on the other side of a point-to-point link). We take these LSAs and put +// add them to the Link State DataBase (LSDB) from which the routes will +// ultimately be computed. +// + void +StaticRouteManagerImpl::BuildStaticRoutingDatabase () +{ + NS_DEBUG ("StaticRouteManagerImpl::BuildStaticRoutingDatabase()"); +// +// Walk the list of nodes looking for the StaticRouter Interface. +// + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); +// +// Ignore nodes that aren't participating in routing. +// + if (!rtr) + { + continue; + } +// +// You must call DiscoverLSAs () before trying to use any routing info or to +// update LSAs. DiscoverLSAs () drives the process of discovering routes in +// the StaticRouter. Afterward, you may use GetNumLSAs (), which is a very +// computationally inexpensive call. If you call GetNumLSAs () before calling +// DiscoverLSAs () will get zero as the number since no routes have been +// found. +// + uint32_t numLSAs = rtr->DiscoverLSAs (); + NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); + + for (uint32_t j = 0; j < numLSAs; ++j) + { + StaticRouterLSA* lsa = new StaticRouterLSA (); +// +// This is the call to actually fetch a Link State Advertisement from the +// router. +// + rtr->GetLSA (j, *lsa); + NS_DEBUG ("LSA " << j); + NS_DEBUG (*lsa); +// +// Write the newly discovered link state advertisement to the database. +// + m_lsdb->Insert (lsa->GetLinkStateId (), lsa); + } + } +} + +// +// For each node that is a static router (which is determined by the presence +// of an aggregated StaticRouter interface), run the Dijkstra SPF calculation +// on the database rooted at that router, and populate the node forwarding +// tables. +// +// This function parallels RFC2328, Section 16.1.1, and quagga ospfd +// +// This calculation yields the set of intra-area routes associated +// with an area (called hereafter Area A). A router calculates the +// shortest-path tree using itself as the root. The formation +// of the shortest path tree is done here in two stages. In the +// first stage, only links between routers and transit networks are +// considered. Using the Dijkstra algorithm, a tree is formed from +// this subset of the link state database. In the second stage, +// leaves are added to the tree by considering the links to stub +// networks. +// +// The area's link state database is represented as a directed graph. +// The graph's vertices are routers, transit networks and stub networks. +// +// The first stage of the procedure (i.e., the Dijkstra algorithm) +// can now be summarized as follows. At each iteration of the +// algorithm, there is a list of candidate vertices. Paths from +// the root to these vertices have been found, but not necessarily +// the shortest ones. However, the paths to the candidate vertex +// that is closest to the root are guaranteed to be shortest; this +// vertex is added to the shortest-path tree, removed from the +// candidate list, and its adjacent vertices are examined for +// possible addition to/modification of the candidate list. The +// algorithm then iterates again. It terminates when the candidate +// list becomes empty. +// + void +StaticRouteManagerImpl::InitializeRoutes () +{ + NS_DEBUG ("StaticRouteManagerImpl::InitializeRoutes ()"); +// +// Walk the list of nodes in the system. +// + typedef std::vector < Ptr >::iterator Iterator; + for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) + { + Ptr node = *i; +// +// Look for the StaticRouter interface that indicates that the node is +// participating in routing. +// + Ptr rtr = + node->QueryInterface (StaticRouter::iid); +// +// if the node has a static router interface, then run the static routing +// algorithms. +// + if (rtr && rtr->GetNumLSAs () ) + { + SPFCalculate (rtr->GetRouterId ()); + } + } +} + +// +// This method is derived from quagga ospf_spf_next (). See RFC2328 Section +// 16.1 (2) for further details. +// +// We're passed a parameter that is a vertex which is already in the SPF +// tree. A vertex represents a router node. We also get a reference to the +// SPF candidate queue, which is a priority queue containing the shortest paths +// to the networks we know about. +// +// We examine the links in v's LSA and update the list of candidates with any +// vertices not already on the list. If a lower-cost path is found to a +// vertex already on the candidate list, store the new (lower) cost. +// + void +StaticRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate) +{ + SPFVertex* w = 0; + StaticRouterLSA* w_lsa = 0; + uint32_t distance = 0; + + NS_DEBUG ("StaticRouteManagerImpl::SPFNext ()"); +// +// Always true for now, since all our LSAs are RouterLSAs. +// + if (v->GetVertexType () == SPFVertex::VertexRouter) + { + if (true) + { + NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " << + v->GetLSA ()->GetNLinkRecords () << " link records"); +// +// Walk the list of link records in the link state advertisement associated +// with the "current" router (represented by vertex ). +// + for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) + { +// +// (a) If this is a link to a stub network, examine the next link in V's LSA. +// Links to stub networks will be considered in the second stage of the +// shortest path calculation. +// + StaticRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); + if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) + { + NS_DEBUG ("SPFNext: Found a Stub record to " << + l->GetLinkId ()); + continue; + } +// +// (b) Otherwise, W is a transit vertex (router or transit network). Look up +// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state +// database. +// + if (l->GetLinkType () == StaticRouterLinkRecord::PointToPoint) + { +// +// Lookup the link state advertisement of the new link -- we call it in +// the link state database. +// + w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); + NS_ASSERT (w_lsa); + NS_DEBUG ("SPFNext: Found a P2P record from " << + v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); +// +// (c) If vertex W is already on the shortest-path tree, examine the next +// link in the LSA. +// +// If the link is to a router that is already in the shortest path first tree +// then we have it covered -- ignore it. +// + if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_IN_SPFTREE) + { + NS_DEBUG ("SPFNext: Skipping-> LSA "<< + w_lsa->GetLinkStateId () << " already in SPF tree"); + continue; + } +// +// The link is to a router we haven't dealt with yet. +// +// (d) Calculate the link state cost D of the resulting path from the root to +// vertex W. D is equal to the sum of the link state cost of the (already +// calculated) shortest path to vertex V and the advertised cost of the link +// between vertices V and W. +// + distance = v->GetDistanceFromRoot () + l->GetMetric (); + + NS_DEBUG ("SPFNext: Considering w_lsa " << + w_lsa->GetLinkStateId ()); + + if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_NOT_EXPLORED) + { +// +// If we havent yet considered the link represented by we have to create +// a new SPFVertex to represent it. +// + w = new SPFVertex (w_lsa); +// +// We need to figure out how to actually get to the new router represented +// by . This will (among other things) find the next hop address to send +// packets destined for this network to, and also find the outbound interface +// used to forward the packets. +// + if (SPFNexthopCalculation (v, w, l, distance)) + { + w_lsa->SetStatus ( + StaticRouterLSA::LSA_SPF_CANDIDATE); +// +// Push this new vertex onto the priority queue (ordered by distance from the +// root node). +// + candidate.Push (w); + NS_DEBUG ("SPFNext: Pushing " << + w->GetVertexId () << ", parent vertexId: " << + v->GetVertexId ()); + } + } + } else if (w_lsa->GetStatus () == + StaticRouterLSA::LSA_SPF_CANDIDATE) + { +// +// We have already considered the link represented by . What wse have to +// do now is to decide if this new router represents a route with a shorter +// distance metric. +// +// So, locate the vertex in the candidate queue and take a look at the +// distance. + w = candidate.Find (w_lsa->GetLinkStateId ()); + if (w->GetDistanceFromRoot () < distance) + { +// +// This is not a shorter path, so don't do anything. +// + continue; + } + else if (w->GetDistanceFromRoot () == distance) + { +// +// This path is one with an equal cost. Do nothing for now -- we're not doing +// equal-cost multipath cases yet. +// + } + else + { +// +// this path represents a new, lower-cost path to (the vertex we found in +// the current link record of the link state advertisement of the current root +// (vertex ) +// +// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop +// it will call spf_add_parents, which will flush the old parents +// + if (SPFNexthopCalculation (v, w, l, distance)) + { +// +// If we've changed the cost to get to the vertex represented by , we +// must reorder the priority queue keyed to that cost. +// + candidate.Reorder (); + } + } + } // point-to-point + } // for loop + } + } +} + +// +// This method is derived from quagga ospf_next_hop_calculation() 16.1.1. +// +// Calculate the next hop IP address and the outgoing interface required to +// get packets from the root through (parent) to vertex (destination), +// over a given distance. +// +// For now, this is greatly simplified from the quagga code +// + int +StaticRouteManagerImpl::SPFNexthopCalculation ( + SPFVertex* v, + SPFVertex* w, + StaticRouterLinkRecord* l, + uint32_t distance) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFNexthopCalculation ()"); +// +// The vertex m_spfroot is a distinguished vertex representing the node at +// the root of the calculations. That is, it is the node for which we are +// calculating the routes. +// +// There are two distinct cases for calculating the next hop information. +// First, if we're considering a hop from the root to an "adjacent" network +// (one that is on the other side of a point-to-point link connected to the +// root), then we need to store the information needed to forward down that +// link. The second case is if the network is not directly adjacent. In that +// case we need to use the forwarding information from the vertex on the path +// to the destination that is directly adjacent [node 1] in both cases of the +// diagram below. +// +// (1) [root] -> [point-to-point] -> [node 1] +// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2] +// +// We call the propagation of next hop information down vertices of a path +// "inheriting" the next hop information. +// +// The point-to-point link information is only useful in this calculation when +// we are examining the root node. +// + if (v == m_spfroot) + { +// +// In this case is the root node, which means it is the starting point +// for the packets forwarded by that node. This also means that the next hop +// address of packets headed for some arbitrary off-network destination must +// be the destination at the other end of one of the links off of the root +// node if this root node is a router. We then need to see if this node +// is a router. +// + if (w->GetVertexType () == SPFVertex::VertexRouter) + { +// +// In the case of point-to-point links, the link data field (m_linkData) of a +// Static Router Link Record contains the local IP address. If we look at the +// link record describing the link from the perspecive of (the remote +// node from the viewpoint of ) back to the root node, we can discover the +// IP address of the router to which is adjacent. This is a distinguished +// address -- the next hop address to get from to and all networks +// accessed through that path. +// +// SPFGetNextLink () is a little odd. used in this way it is just going to +// return the link record describing the link from to . Think of it as +// SPFGetLink. +// + StaticRouterLinkRecord *linkRemote = 0; + linkRemote = SPFGetNextLink (w, v, linkRemote); +// +// At this point, is the Static Router Link Record describing the point- +// to point link from to from the perspective of ; and +// is the Static Router Link Record describing that same link from the +// perspective of (back to ). Now we can just copy the next hop +// address from the m_linkData member variable. +// +// The next hop member variable we put in has the sense "in order to get +// from the root node to the host represented by vertex , you have to send +// the packet to the next hop address specified in w->m_nextHop. +// + w->SetNextHop(linkRemote->GetLinkData ()); +// +// Now find the outgoing interface corresponding to the point to point link +// from the perspective of -- remember that is the link "from" +// "to" . +// + w->SetOutgoingInterfaceId ( + FindOutgoingInterfaceId (l->GetLinkData ())); + + NS_DEBUG ("SPFNexthopCalculation: Next hop from " << + v->GetVertexId () << " to " << w->GetVertexId () << + " goes through next hop " << w->GetNextHop () << + " via outgoing interface " << w->GetOutgoingInterfaceId ()); + } + } + else + { +// +// If we're calculating the next hop information from a node (v) that is +// *not* the root, then we need to "inherit" the information needed to +// forward the packet from the vertex closer to the root. That is, we'll +// still send packets to the next hop address of the router adjacent to the +// root on the path toward . +// +// Above, when we were considering the root node, we calculated the next hop +// address and outgoing interface required to get off of the root network. +// At this point, we are further away from the root network along one of the +// (shortest) paths. So the next hop and outoing interface remain the same +// (are inherited). +// + w->SetNextHop (v->GetNextHop ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); + } +// +// In all cases, we need valid values for the distance metric and a parent. +// + w->SetDistanceFromRoot (distance); + w->SetParent (v); + + return 1; +} + +// +// This method is derived from quagga ospf_get_next_link () +// +// First search the Static Router Link Records of vertex for one +// representing a point-to point link to vertex . +// +// What is done depends on prev_link. Contrary to appearances, prev_link just +// acts as a flag here. If prev_link is NULL, we return the first Static +// Router Link Record we find that describes a point-to-point link from +// to . If prev_link is not NULL, we return a Static Router Link Record +// representing a possible *second* link from to . +// +// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for +// any link records after pre_link and not just after the first? +// + StaticRouterLinkRecord* +StaticRouteManagerImpl::SPFGetNextLink ( + SPFVertex* v, + SPFVertex* w, + StaticRouterLinkRecord* prev_link) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFGetNextLink ()"); + + bool skip = true; + StaticRouterLinkRecord* l; +// +// If prev_link is 0, we are really looking for the first link, not the next +// link. +// + if (prev_link == 0) + { + skip = false; + } +// +// Iterate through the Static Router Link Records advertised by the vertex +// looking for records representing the point-to-point links off of this +// vertex. +// + for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) + { + l = v->GetLSA ()->GetLinkRecord (i); + if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) + { + continue; + } +// +// The link ID of a link record representing a point-to-point link is set to +// the router ID of the neighboring router -- the router to which the link +// connects from the perspective of in this case. The vertex ID is also +// set to the router ID (using the link state advertisement of a router node). +// We're just checking to see if the link is actually the link from to +// . +// + if (l->GetLinkId () == w->GetVertexId ()) { + NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << + l->GetLinkId () << " linkData = " << l->GetLinkData ()); +// +// If skip is false, don't (not too surprisingly) skip the link found -- it's +// the one we're interested in. That's either because we didn't pass in a +// previous link, and we're interested in the first one, or because we've +// skipped a previous link and moved forward to the next (which is then the +// one we want). +// + if (skip == false) + { + NS_DEBUG ("SPFGetNextLink: Returning the found link"); + return l; + } + else + { +// +// Skip is true and we've found a link from to . We want the next one. +// Setting skip to false gets us the next point-to-point static router link +// record in the LSA from . +// + NS_DEBUG ("SPFGetNextLink: Skipping the found link"); + skip = false; + continue; + } + } + } + return 0; +} + +// +// Used for unit tests. +// + void +StaticRouteManagerImpl::DebugSPFCalculate (Ipv4Address root) +{ + NS_DEBUG ("StaticRouteManagerImpl::DebugSPFCalculate ()"); + SPFCalculate (root); +} + +// quagga ospf_spf_calculate + void +StaticRouteManagerImpl::SPFCalculate (Ipv4Address root) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFCalculate (): " + "root = " << root); + + SPFVertex *v; +// +// Initialize the Link State Database. +// + m_lsdb->Initialize (); +// +// The candidate queue is a priority queue of SPFVertex objects, with the top +// of the queue being the closest vertex in terms of distance from the root +// of the tree. Initially, this queue is empty. +// + CandidateQueue candidate; + NS_ASSERT(candidate.Size () == 0); +// +// Initialize the shortest-path tree to only contain the router doing the +// calculation. Each router (and corresponding network) is a vertex in the +// shortest path first (SPF) tree. +// + v = new SPFVertex (m_lsdb->GetLSA (root)); +// +// This vertex is the root of the SPF tree and it is distance 0 from the root. +// We also mark this vertex as being in the SPF tree. +// + m_spfroot= v; + v->SetDistanceFromRoot (0); + v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); + + for (;;) + { +// +// The operations we need to do are given in the OSPF RFC which we reference +// as we go along. +// +// RFC2328 16.1. (2). +// +// We examine the Static Router Link Records in the Link State +// Advertisements of the current vertex. If there are any point-to-point +// links to unexplored adjacent vertices we add them to the tree and update +// the distance and next hop information on how to get there. We also add +// the new vertices to the candidate queue (the priority queue ordered by +// shortest path). If the new vertices represent shorter paths, we use them +// and update the path cost. +// + SPFNext (v, candidate); +// +// RFC2328 16.1. (3). +// +// If at this step the candidate list is empty, the shortest-path tree (of +// transit vertices) has been completely built and this stage of the +// procedure terminates. +// + if (candidate.Size () == 0) + { + break; + } +// +// Choose the vertex belonging to the candidate list that is closest to the +// root, and add it to the shortest-path tree (removing it from the candidate +// list in the process). +// +// Recall that in the previous step, we created SPFVertex structures for each +// of the routers found in the Static Router Link Records and added tehm to +// the candidate list. +// + v = candidate.Pop (); + NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ()); +// +// Update the status field of the vertex to indicate that it is in the SPF +// tree. +// + v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); +// +// The current vertex has a parent pointer. By calling this rather oddly +// named method (blame quagga) we add the current vertex to the list of +// children of that parent vertex. In the next hop calculation called during +// SPFNext, the parent pointer was set but the vertex has been orphaned up +// to now. +// + SPFVertexAddParent (v); +// +// Note that when there is a choice of vertices closest to the root, network +// vertices must be chosen before router vertices in order to necessarily +// find all equal-cost paths. We don't do this at this moment, we should add +// the treatment above codes. -- kunihiro. +// +// RFC2328 16.1. (4). +// +// This is the method that actually adds the routes. It'll walk the list +// of nodes in the system, looking for the node corresponding to the router +// ID of the root of the tree -- that is the router we're building the routes +// for. It looks for the Ipv4 interface of that node and remembers it. So +// we are only actually adding routes to that one node at the root of the SPF +// tree. +// +// We're going to pop of a pointer to every vertex in the tree except the +// root in order of distance from the root. For each of the vertices, we call +// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the +// point-to-point Static Router Link Records (the links to nodes adjacent to +// the node represented by the vertex). We add a route to the IP address +// specified by the m_linkData field of each of those link records. This will +// be the *local* IP address associated with the interface attached to the +// link. We use the outbound interface and next hop information present in +// the vertex which have possibly been inherited from the root. +// +// To summarize, we're going to look at the node represented by and loop +// through its point-to-point links, adding a *host* route to the local IP +// address (at the side) for each of those links. +// + SPFIntraAddRouter (v); +// +// RFC2328 16.1. (5). +// +// Iterate the algorithm by returning to Step 2 until there are no more +// candidate vertices. +// + } +// +// Second stage of SPF calculation procedure's +// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); +// +// We're all done setting the routing information for the node at the root of +// the SPF tree. Delete all of the vertices and corresponding resources. Go +// possibly do it again for the next router. +// + delete m_spfroot; + m_spfroot = 0; +} + +// +// BUGBUG FIXME: This should probably be a method on Ipv4 +// +// Return the interface index corresponding to a given IP address +// + uint32_t +StaticRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a) +{ +// +// We have an IP address and a vertex ID of the root of the SPF tree. +// The question is what interface index does this address correspond to. +// The answer is a little complicated since we have to find a pointer to +// the node corresponding to the vertex ID, find the Ipv4 interface on that +// node in order to iterate the interfaces and find the one corresponding to +// the address in question. +// + Ipv4Address routerId = m_spfroot->GetVertexId (); +// +// Walk the list of nodes in the system looking for the one corresponding to +// the node at the root of the SPF tree. This is the node for which we are +// building the routing table. +// + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) + { + Ptr node = *i; + + Ptr rtr = + node->QueryInterface (StaticRouter::iid); +// +// If the node doesn't have a StaticRouter interface it can't be the one +// we're interested in. +// + if (rtr == 0) + { + continue; + } + + if (rtr->GetRouterId () == routerId) + { +// +// This is the node we're building the routing table for. We're going to need +// the Ipv4 interface to look for the ipv4 interface index. Since this node +// is participating in routing IP version 4 packets, it certainly must have +// an Ipv4 interface. +// + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG (ipv4, + "StaticRouteManagerImpl::FindOutgoingInterfaceId (): " + "QI for interface failed"); +// +// Look through the interfaces on this node for one that has the IP address +// we're looking for. If we find one, return the corresponding interface +// index. +// + for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) + { + if (ipv4->GetAddress (i) == a) + { + NS_DEBUG ( + "StaticRouteManagerImpl::FindOutgoingInterfaceId (): " + "Interface match for " << a); + return i; + } + } + } + } +// +// Couldn't find it. +// + return 0; +} + +// +// This method is derived from quagga ospf_intra_add_router () +// +// This is where we are actually going to add the host routes to the routing +// tables of the individual nodes. +// +// The vertex passed as a parameter has just been added to the SPF tree. +// This vertex must have a valid m_root_oid, corresponding to the outgoing +// interface on the root router of the tree that is the first hop on the path +// to the vertex. The vertex must also have a next hop address, corresponding +// to the next hop on the path to the vertex. The vertex has an m_lsa field +// that has some number of link records. For each point to point link record, +// the m_linkData is the local IP address of the link. This corresponds to +// a destination IP address, reachable from the root, to which we add a host +// route. +// + void +StaticRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) +{ + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter ()"); + + NS_ASSERT_MSG (m_spfroot, + "StaticRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set"); +// +// The root of the Shortest Path First tree is the router to which we are +// going to write the actual routing table entries. The vertex corresponding +// to this router has a vertex ID which is the router ID of that node. We're +// going to use this ID to discover which node it is that we're actually going +// to update. +// + Ipv4Address routerId = m_spfroot->GetVertexId (); + + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "Vertex ID = " << routerId); +// +// We need to walk the list of nodes looking for the one that has the router +// ID corresponding to the root vertex. This is the one we're going to write +// the routing information to. +// + std::vector >::iterator i = NodeList::Begin (); + for (; i != NodeList::End (); i++) + { + Ptr node = *i; +// +// The router ID is accessible through the StaticRouter interface, so we need +// to QI for that interface. If there's no StaticRouter interface, the node +// in question cannot be the router we want, so we continue. +// + Ptr rtr = + node->QueryInterface (StaticRouter::iid); + + if (rtr == 0) + { + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "No StaticRouter interface on node " << node->GetId ()); + continue; + } +// +// If the router ID of the current node is equal to the router ID of the +// root of the SPF tree, then this node is the one for which we need to +// write the routing tables. +// + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "Considering router " << rtr->GetRouterId ()); + + if (rtr->GetRouterId () == routerId) + { + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + "setting routes for node " << node->GetId ()); +// +// Routing information is updated using the Ipv4 interface. We need to QI +// for that interface. If the node is acting as an IP version 4 router, it +// should absolutely have an Ipv4 interface. +// + Ptr ipv4 = node->QueryInterface (Ipv4::iid); + NS_ASSERT_MSG (ipv4, + "StaticRouteManagerImpl::SPFIntraAddRouter (): " + "QI for interface failed"); +// +// Get the Static Router Link State Advertisement from the vertex we're +// adding the routes to. The LSA will have a number of attached Static Router +// Link Records corresponding to links off of that vertex / node. We're going +// to be interested in the records corresponding to point-to-point links. +// + StaticRouterLSA *lsa = v->GetLSA (); + NS_ASSERT_MSG (lsa, + "StaticRouteManagerImpl::SPFIntraAddRouter (): " + "Expected valid LSA in SPFVertex* v"); + + uint32_t nLinkRecords = lsa->GetNLinkRecords (); +// +// Iterate through the link records on the vertex to which we're going to add +// routes. To make sure we're being clear, we're going to add routing table +// entries to the tables on the node corresping to the root of the SPF tree. +// These entries will have routes to the IP addresses we find from looking at +// the local side of the point-to-point links found on the node described by +// the vertex . +// + for (uint32_t j = 0; j < nLinkRecords; j += 2) + { +// +// We are only concerned about point-to-point links +// + StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); + if (lr->GetLinkType () != StaticRouterLinkRecord::PointToPoint) + { + continue; + } + + NS_DEBUG ("StaticRouteManagerImpl::SPFIntraAddRouter (): " + " Node " << node->GetId () << + " add route to " << lr->GetLinkData () << + " using next hop " << v->GetNextHop () << + " via interface " << v->GetOutgoingInterfaceId ()); +// +// Here's why we did all of that work. We're going to add a host route to the +// host address found in the m_linkData field of the point-to-point link +// record. In the case of a point-to-point link, this is the local IP address +// of the node connected to the link. Each of these point-to-point links +// will correspond to a local interface that has an IP address to which +// the node at the root of the SPF tree can send packets. The vertex +// (corresponding to the node that has these links and interfaces) has +// an m_nextHop address precalculated for us that is the address to which the +// root node should send packets to be forwarded to these IP addresses. +// Similarly, the vertex has an m_rootOif (outbound interface index) to +// which the packets should be send for forwarding. +// + ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (), + v->GetOutgoingInterfaceId ()); + } +// +// Done adding the routes for the selected node. +// + return; + } + } +} + +// Derived from quagga ospf_vertex_add_parents () +// +// This is a somewhat oddly named method (blame quagga). Although you might +// expect it to add a parent *to* something, it actually adds a vertex +// to the list of children *in* each of its parents. +// +// Given a pointer to a vertex, it links back to the vertex's parent that it +// already has set and adds itself to that vertex's list of children. +// +// For now, only one parent (not doing equal-cost multipath) +// + void +StaticRouteManagerImpl::SPFVertexAddParent (SPFVertex* v) +{ + v->GetParent ()->AddChild (v); +} + +} // namespace ns3 + +#ifdef RUN_SELF_TESTS + +// --------------------------------------------------------------------------- +// +// Unit Tests +// +// --------------------------------------------------------------------------- + +#include "ns3/test.h" + +namespace ns3 { + +class StaticRouterTestNode : public Node +{ +public: + StaticRouterTestNode (); + +private: + virtual void DoAddDevice (Ptr device) const {}; + virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); +}; + +StaticRouterTestNode::StaticRouterTestNode () +{ +// Ptr ipv4 = Create (this); +} + + TraceResolver* +StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) +{ + return 0; +} + +class StaticRouteManagerImplTest : public Test { +public: + StaticRouteManagerImplTest (); + virtual ~StaticRouteManagerImplTest (); + virtual bool RunTests (void); +}; + +StaticRouteManagerImplTest::StaticRouteManagerImplTest () + : Test ("StaticRouteManagerImpl") +{ +} + +StaticRouteManagerImplTest::~StaticRouteManagerImplTest () +{} + + bool +StaticRouteManagerImplTest::RunTests (void) +{ + bool ok = true; + + CandidateQueue candidate; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = new SPFVertex; + v->SetDistanceFromRoot (rand () % 100); + candidate.Push (v); + } + + uint32_t lastDistance = 0; + + for (int i = 0; i < 100; ++i) + { + SPFVertex *v = candidate.Pop (); + if (v->GetDistanceFromRoot () < lastDistance) + { + ok = false; + } + lastDistance = v->GetDistanceFromRoot (); + delete v; + v = 0; + } + + // Build fake link state database; four routers (0-3), 3 point-to-point + // links + // + // n0 + // \ link 0 + // \ link 2 + // n2 -------------------------n3 + // / + // / link 1 + // n1 + // + // link0: 10.1.1.1/30, 10.1.1.2/30 + // link1: 10.1.2.1/30, 10.1.2.2/30 + // link2: 10.1.3.1/30, 10.1.3.2/30 + // + // Router 0 + StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", // router ID 0.0.0.2 + "10.1.1.1", // local ID + 1); // metric + + StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.1.1", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa0 = new StaticRouterLSA (); + lsa0->SetLinkStateId ("0.0.0.0"); + lsa0->SetAdvertisingRouter ("0.0.0.0"); + lsa0->AddLinkRecord (lr0); + lsa0->AddLinkRecord (lr1); + + // Router 1 + StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + + StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa1 = new StaticRouterLSA (); + lsa1->SetLinkStateId ("0.0.0.1"); + lsa1->SetAdvertisingRouter ("0.0.0.1"); + lsa1->AddLinkRecord (lr2); + lsa1->AddLinkRecord (lr3); + + // Router 2 + StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.0", + "10.1.1.2", + 1); + + StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.1.2", + "255.255.255.252", + 1); + + StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.1", + "10.1.2.2", + 1); + + StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.2", + "255.255.255.252", + 1); + + StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.3", + "10.1.3.2", + 1); + + StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.3.2", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa2 = new StaticRouterLSA (); + lsa2->SetLinkStateId ("0.0.0.2"); + lsa2->SetAdvertisingRouter ("0.0.0.2"); + lsa2->AddLinkRecord (lr4); + lsa2->AddLinkRecord (lr5); + lsa2->AddLinkRecord (lr6); + lsa2->AddLinkRecord (lr7); + lsa2->AddLinkRecord (lr8); + lsa2->AddLinkRecord (lr9); + + // Router 3 + StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + + StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord ( + StaticRouterLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + + StaticRouterLSA* lsa3 = new StaticRouterLSA (); + lsa3->SetLinkStateId ("0.0.0.3"); + lsa3->SetAdvertisingRouter ("0.0.0.3"); + lsa3->AddLinkRecord (lr10); + lsa3->AddLinkRecord (lr11); + + // Test the database + StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); + srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0); + srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1); + srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2); + srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3); + NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); + + // XXX next, calculate routes based on the manually created LSDB + StaticRouteManagerImpl* srm = new StaticRouteManagerImpl (); + srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB + // Note-- this will succeed without any nodes in the topology + // because the NodeList is empty + srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 + + // This delete clears the srm, which deletes the LSDB, which clears + // all of the LSAs, which each destroys the attached LinkRecords. + delete srm; + + return ok; +} + +// Instantiate this class for the unit tests +static StaticRouteManagerImplTest g_staticRouteManagerTest; + +} // namespace ns3 + +#endif diff --git a/src/routing/static-route-manager-impl.h b/src/routing/static-route-manager-impl.h new file mode 100644 index 000000000..a4d97db77 --- /dev/null +++ b/src/routing/static-route-manager-impl.h @@ -0,0 +1,677 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef STATIC_ROUTE_MANAGER_IMPL_H +#define STATIC_ROUTE_MANAGER_IMPL_H + +#include +#include +#include +#include +#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" +#include "static-router.h" + +namespace ns3 { + +const uint32_t SPF_INFINITY = 0xffffffff; + +class CandidateQueue; + +/** + * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328, + * Section 16. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is the SPFVertex representing the router that is having + * its routing tables set. The SPFVertex objects representing other routers + * or networks in the simulation are arranged in the SPF tree. It is this + * tree that represents the Shortest Paths to the other networks. + * + * Each SPFVertex has a pointer to the Static Router Link State Advertisement + * (LSA) that its underlying router has exported. Within these LSAs are + * Static Router Link Records that describe the point to point links from the + * underlying router to other nodes (represented by other SPFVertex objects) + * in the simulation topology. The combination of the arrangement of the + * SPFVertex objects in the SPF tree, along with the details of the link + * records that connect them provide the information required to construct the + * required routes. + */ +class SPFVertex +{ +public: +/** + * @enum Enumeration of the possible types of SPFVertex objects. Currently + * we use VertexRouter to identify objects that represent a router in the + * simulation topology, and VertexNetwork to identify objects that represent + * a network. + */ + enum VertexType { + VertexUnknown = 0, /**< Uninitialized Link Record */ + VertexRouter, /**< Vertex representing a router in the topology */ + VertexNetwork /**< Vertex representing a network in the topology */ + }; +/** + * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First + * Vertex). + * + * The Vertex Type is set to VertexUnknown, the Vertex ID is set to + * 255.255.255.255, and the distance from root is set to infinity + * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to + * null as is the parent SPFVertex. The outgoing interface index is set to + * infinity, the next hop address is set to 0.0.0.0 and the list of children + * of the SPFVertex is initialized to empty. + * + * @see VertexType + */ + SPFVertex(); +/** + * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). + * + * The Vertex Type is initialized to VertexRouter and the Vertex ID is found + * from the Link State ID of the Link State Advertisement (LSA) passed as a + * parameter. The Link State ID is set to the Router ID of the advertising + * router. The referenced LSA (m_lsa) is set to the given LSA. Other than + * these members, initialization is as in the default constructor. + * of the SPFVertex is initialized to empty. + * + * @see SPFVertex::SPFVertex () + * @see VertexType + * @see StaticRouterLSA + * @param lsa The Link State Advertisement used for finding initial values. + */ + SPFVertex(StaticRouterLSA* lsa); +/** + * @brief Destroy an SPFVertex (Shortest Path First Vertex). + * + * The children vertices of the SPFVertex are recursively deleted. + * + * @see SPFVertex::SPFVertex () + */ + ~SPFVertex(); +/** + * @brief Get the Vertex Type field of a SPFVertex object. + * + * The Vertex Type describes the kind of simulation object a given SPFVertex + * represents. + * + * @see VertexType + * @returns The VertexType of the current SPFVertex object. + */ + VertexType GetVertexType (void) const; +/** + * @brief Set the Vertex Type field of a SPFVertex object. + * + * The Vertex Type describes the kind of simulation object a given SPFVertex + * represents. + * + * @see VertexType + * @param The new VertexType for the current SPFVertex object. + */ + void SetVertexType (VertexType type); +/** + * @brief Get the Vertex ID field of a SPFVertex object. + * + * The Vertex ID uniquely identifies the simulation object a given SPFVertex + * represents. Typically, this is the Router ID for SPFVertex objects + * representing routers, and comes from the Link State Advertisement of a + * router aggregated to a node in the simulation. These IDs are allocated + * automatically by the routing environment and look like IP addresses + * beginning at 0.0.0.0 and monotonically increasing as new routers are + * instantiated. + * + * @returns The Ipv4Address Vertex ID of the current SPFVertex object. + */ + Ipv4Address GetVertexId (void) const; +/** + * @brief Set the Vertex ID field of a SPFVertex object. + * + * The Vertex ID uniquely identifies the simulation object a given SPFVertex + * represents. Typically, this is the Router ID for SPFVertex objects + * representing routers, and comes from the Link State Advertisement of a + * router aggregated to a node in the simulation. These IDs are allocated + * automatically by the routing environment and look like IP addresses + * beginning at 0.0.0.0 and monotonically increasing as new routers are + * instantiated. + * + * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. + */ + void SetVertexId (Ipv4Address id); +/** + * @brief Get the Static Router Link State Advertisement returned by the + * Static Router represented by this SPFVertex during the route discovery + * process. + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @returns A pointer to the StaticRouterLSA found by the router represented + * by this SPFVertex object. + */ + StaticRouterLSA* GetLSA (void) const; +/** + * @brief Set the Static Router Link State Advertisement returned by the + * Static Router represented by this SPFVertex during the route discovery + * process. + * + * @see SPFVertex::GetLSA () + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouter::DiscoverLSAs () + * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You + * must not delete the LSA after calling this method. + * @param A pointer to the StaticRouterLSA. + */ + void SetLSA (StaticRouterLSA* lsa); +/** + * @brief Get the distance from the root vertex to "this" SPFVertex object. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex to which + * a route is being calculated from the root. The distance from the root that + * we're asking for is the number of hops from the root vertex to the vertex + * in question. + * + * The distance is calculated during route discovery and is stored in a + * member variable. This method simply fetches that value. + * + * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex. + */ + uint32_t GetDistanceFromRoot (void) const; +/** + * @brief Set the distance from the root vertex to "this" SPFVertex object. + * + * Each router in the simulation is associated with an SPFVertex object. When + * calculating routes, each of these routers is, in turn, chosen as the "root" + * of the calculation and routes to all of the other routers are eventually + * saved in the routing tables of each of the chosen nodes. Each of these + * routers in the calculation has an associated SPFVertex. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex to which + * a route is being calculated from the root. The distance from the root that + * we're asking for is the number of hops from the root vertex to the vertex + * in question. + * + * @param distance The distance, in hops, from the root SPFVertex to "this" + * SPFVertex. + */ + void SetDistanceFromRoot (uint32_t distance); +/** + * @brief Get the interface ID that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The outgoing interface that we're asking for is the interface + * index on the root node that should be used to start packets along the + * path to "this" vertex. + * + * When initializing the root SPFVertex, the interface ID is determined by + * examining the Static Router Link Records of the Link State Advertisement + * generated by the root node's StaticRouter. These interfaces are used to + * forward packets off of the root's network down those links. As other + * vertices are discovered which are further away from the root, they will + * be accessible down one of the paths begun by a Static Router Link Record. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to the interface of that + * first hop. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, the root node is asking, "which of my local interfaces + * should I use to get a packet to the network or host represented by 'this' + * SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @returns The interface index to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + uint32_t GetOutgoingInterfaceId (void) const; +/** + * @brief Set the interface ID that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The outgoing interface that we're asking for is the interface + * index on the root node that should be used to start packets along the + * path to "this" vertex. + * + * When initializing the root SPFVertex, the interface ID is determined by + * examining the Static Router Link Records of the Link State Advertisement + * generated by the root node's StaticRouter. These interfaces are used to + * forward packets off of the root's network down those links. As other + * vertices are discovered which are further away from the root, they will + * be accessible down one of the paths begun by a Static Router Link Record. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to the interface of that + * first hop. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, we are letting the root node know which of its local + * interfaces it should use to get a packet to the network or host represented + * by "this" SPFVertex. + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @param id The interface index to use when forwarding packets to the host or + * network represented by "this" SPFVertex. + */ + void SetOutgoingInterfaceId (uint32_t id); +/** + * @brief Get the IP address that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The IP address that we're asking for is the address on the + * remote side of a link off of the root node that should be used as the + * destination for packets along the path to "this" vertex. + * + * When initializing the root SPFVertex, the IP address used when forwarding + * packets is determined by examining the Static Router Link Records of the + * Link State Advertisement generated by the root node's StaticRouter. This + * address is used to forward packets off of the root's network down those + * links. As other vertices / nodes are discovered which are further away + * from the root, they will be accessible down one of the paths via a link + * described by one of these Static Router Link Records. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to a first hop router down + * an interface. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method, the root node is asking, "which router should I send a + * packet to in order to get that packet to the network or host represented + * by 'this' SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @returns The IP address to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + Ipv4Address GetNextHop (void) const; +/** + * @brief Set the IP address that should be used to begin forwarding packets + * from the root SPFVertex to "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set. The "this" SPFVertex is the vertex that + * represents the host or network to which a route is being calculated from + * the root. The IP address that we're asking for is the address on the + * remote side of a link off of the root node that should be used as the + * destination for packets along the path to "this" vertex. + * + * When initializing the root SPFVertex, the IP address used when forwarding + * packets is determined by examining the Static Router Link Records of the + * Link State Advertisement generated by the root node's StaticRouter. This + * address is used to forward packets off of the root's network down those + * links. As other vertices / nodes are discovered which are further away + * from the root, they will be accessible down one of the paths via a link + * described by one of these Static Router Link Records. + * + * To forward packets to these hosts or networks, the root node must begin + * the forwarding process by sending the packets to a first hop router down + * an interface. This means that the first hop address and interface ID must + * be the same for all downstream SPFVertices. We call this "inheriting" + * the interface and next hop. + * + * In this method we are telling the root node which router it should send + * should I send a packet to in order to get that packet to the network or + * host represented by 'this' SPFVertex." + * + * @see StaticRouter + * @see StaticRouterLSA + * @see StaticRouterLinkRecord + * @param nextHop The IP address to use when forwarding packets to the host + * or network represented by "this" SPFVertex. + */ + void SetNextHop (Ipv4Address nextHop); +/** + * @brief Get a pointer to the SPFVector that is the parent of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. + * + * This method returns a pointer to the parent node of "this" SPFVertex + * (both of which reside in that SPF tree). + * + * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex + * in the SPF tree. + */ + SPFVertex* GetParent (void) const; +/** + * @brief Set the pointer to the SPFVector that is the parent of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. + * + * This method sets the parent pointer of "this" SPFVertex (both of which + * reside in that SPF tree). + * + * @param parent A pointer to the SPFVertex that is the parent of "this" + * SPFVertex* in the SPF tree. + */ + void SetParent (SPFVertex* parent); +/** + * @brief Get the number of children of "this" SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method returns the number of children of "this" SPFVertex (which + * reside in the SPF tree). + * + * @returns The number of children of "this" SPFVertex (which reside in the + * SPF tree). + */ + uint32_t GetNChildren (void) const; +/** + * @brief Get a borrowed SPFVertex pointer to the specified child of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method the number of children of "this" SPFVertex (which reside in + * the SPF tree. + * + * @see SPFVertex::GetNChildren + * @param n The index (from 0 to the number of children minus 1) of the + * child SPFVertex to return. + * @warning The pointer returned by GetChild () is a borrowed pointer. You + * do not have any ownership of the underlying object and must not delete + * that object. + * @returns A pointer to the specified child SPFVertex (which resides in the + * SPF tree). + */ + SPFVertex* GetChild (uint32_t n) const; +/** + * @brief Get a borrowed SPFVertex pointer to the specified child of "this" + * SPFVertex. + * + * Each router node in the simulation is associated with an SPFVertex object. + * When calculating routes, each of these routers is, in turn, chosen as the + * "root" of the calculation and routes to all of the other routers are + * eventually saved in the routing tables of each of the chosen nodes. + * + * The "Root" vertex is then the SPFVertex representing the router that is + * having its routing tables set and is the root of the SPF tree. Each vertex + * in the SPF tree can have a number of children that represent host or + * network routes available via that vertex. + * + * This method the number of children of "this" SPFVertex (which reside in + * the SPF tree. + * + * @see SPFVertex::GetNChildren + * @param n The index (from 0 to the number of children minus 1) of the + * child SPFVertex to return. + * @warning Ownership of the pointer added to the children of "this" + * SPFVertex is transferred to the "this" SPFVertex. You must not delete the + * (now) child SPFVertex after calling this method. + * @param child A pointer to the SPFVertex (which resides in the SPF tree) to + * be added to the list of children of "this" SPFVertex. + * @returns The number of children of "this" SPFVertex after the addition of + * the new child. + */ + uint32_t AddChild (SPFVertex* child); + +private: + VertexType m_vertexType; + Ipv4Address m_vertexId; + StaticRouterLSA* m_lsa; + uint32_t m_distanceFromRoot; + uint32_t m_rootOif; + Ipv4Address m_nextHop; + SPFVertex* m_parent; + typedef std::list ListOfSPFVertex_t; + ListOfSPFVertex_t m_children; +/** + * @brief The SPFVertex copy construction is disallowed. There's no need for + * it and a compiler provided shallow copy would be wrong. + */ + SPFVertex (SPFVertex& v); +/** + * @brief The SPFVertex copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be wrong. + */ + SPFVertex& operator= (SPFVertex& v); +}; + +/** + * @brief The Link State DataBase (LSDB) of the Static Route Manager. + * + * Each node in the simulation participating in static routing has a + * StaticRouter interface. The primary job of this interface is to export + * Static Router Link State Advertisements (LSAs). These advertisements in + * turn contain a number of Static Router Link Records that describe the + * point to point links from the underlying node to other nodes (that will + * also export their own LSAs. + * + * This class implements a searchable database of LSAs gathered from every + * router in the simulation. + */ +class StaticRouteManagerLSDB +{ +public: +/** + * @brief Construct an empty Static Router Manager Link State Database. + * + * The database map composing the Link State Database is initialized in + * this constructor. + */ + StaticRouteManagerLSDB (); +/** + * @brief Destroy an empty Static Router Manager Link State Database. + * + * The database map is walked and all of the Link State Advertisements stored + * in the database are freed; then the database map itself is clear ()ed to + * release any remaining resources. + */ + ~StaticRouteManagerLSDB (); +/** + * @brief Insert an IP address / Link State Advertisement pair into the Link + * State Database. + * + * The IPV4 address and the StaticRouterLSA given as parameters are converted + * to an STL pair and are inserted into the database map. + * + * @see StaticRouterLSA + * @see Ipv4Address + * @param addr The IP address associated with the LSA. Typically the Router + * ID. + * @param lsa A pointer to the Link State Advertisement for the router. + */ + void Insert(Ipv4Address addr, StaticRouterLSA* lsa); +/** + * @brief Look up the Link State Advertisement associated with the given + * IP Address. + * + * The database map is searched for the given IPV4 address and corresponding + * StaticRouterLSA is returned. + * + * @see StaticRouterLSA + * @see Ipv4Address + * @param addr The IP address associated with the LSA. Typically the Router + * ID. + * @returns A pointer to the Link State Advertisement for the router specified + * by the IP address addr. + */ + StaticRouterLSA* GetLSA (Ipv4Address addr) const; +/** + * @brief Set all LSA flags to an initialized state, for SPF computation + * + * This function walks the database and resets the status flags of all of the + * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done + * prior to each SPF calculation to reset the state of the SPFVertex structures + * that will reference the LSAs during the calculation. + * + * @see StaticRouterLSA + * @see SPFVertex + */ + void Initialize (); + +private: + typedef std::map LSDBMap_t; + typedef std::pair LSDBPair_t; + + LSDBMap_t m_database; +/** + * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no + * need for it and a compiler provided shallow copy would be hopelessly wrong. + */ + StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); +/** + * @brief The SPFVertex copy assignment operator is disallowed. There's no + * need for it and a compiler provided shallow copy would be wrong. + */ + StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); +}; + +/** + * @brief A global static router + * + * This singleton object can query interface each node in the system + * for a StaticRouter interface. For those nodes, it fetches one or + * more Link State Advertisements and stores them in a local database. + * Then, it can compute shortest paths on a per-node basis to all routers, + * and finally configure each of the node's forwarding tables. + * + * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. + */ +class StaticRouteManagerImpl +{ +public: + StaticRouteManagerImpl (); + virtual ~StaticRouteManagerImpl (); +/** + * @brief Build the routing database by gathering Link State Advertisements + * from each node exporting a StaticRouter interface. + * + */ + virtual void BuildStaticRoutingDatabase(); +/** + * @brief Compute routes using a Dijkstra SPF computation and populate + * per-node forwarding tables + */ + virtual void InitializeRoutes(); +/** + * @brief Debugging routine; allow client code to supply a pre-built LSDB + */ + void DebugUseLsdb (StaticRouteManagerLSDB*); +/** + * @brief Debugging routine; call the core SPF from the unit tests + */ + void DebugSPFCalculate (Ipv4Address root); +private: +/** + * @brief Static Route Manager Implementation copy construction is disallowed. + * There's no need for it and a compiler provided shallow copy would be + * hopelessly wrong. + */ + StaticRouteManagerImpl (StaticRouteManagerImpl& srmi); +/** + * @brief Static Route Manager Implementation assignment operator is + * disallowed. There's no need for it and a compiler provided shallow copy + * would be hopelessly wrong. + */ + StaticRouteManagerImpl& operator= (StaticRouteManagerImpl& srmi); + + SPFVertex* m_spfroot; + StaticRouteManagerLSDB* m_lsdb; + void SPFCalculate (Ipv4Address root); + void SPFNext (SPFVertex*, CandidateQueue&); + int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* l, uint32_t distance); + void SPFVertexAddParent(SPFVertex* v); + StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, + StaticRouterLinkRecord* prev_link); + void SPFIntraAddRouter(SPFVertex* v); + uint32_t FindOutgoingInterfaceId(Ipv4Address a); +}; + +} // namespace ns3 + +#endif /* STATIC_ROUTE_MANAGER_IMPL_H */ diff --git a/src/routing/static-route-manager.cc b/src/routing/static-route-manager.cc index 02948ac9c..09ced494f 100644 --- a/src/routing/static-route-manager.cc +++ b/src/routing/static-route-manager.cc @@ -14,1358 +14,32 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include #include "ns3/assert.h" -#include "ns3/fatal-error.h" #include "ns3/debug.h" -#include "ns3/node-list.h" -#include "ns3/ipv4.h" -#include "static-router.h" +#include "ns3/simulation-singleton.h" #include "static-route-manager.h" -#include "candidate-queue.h" - -NS_DEBUG_COMPONENT_DEFINE ("StaticRouteManager"); +#include "static-route-manager-impl.h" namespace ns3 { -// --------------------------------------------------------------------------- -// -// SPFVertex Implementation -// -// --------------------------------------------------------------------------- - -SPFVertex::SPFVertex () : - m_vertexType (VertexUnknown), - m_vertexId ("255.255.255.255"), - m_lsa (0), - m_distanceFromRoot (SPF_INFINITY), - m_rootOif (SPF_INFINITY), - m_nextHop ("0.0.0.0"), - m_parent (0), - m_children () -{ -} - -SPFVertex::SPFVertex (StaticRouterLSA* lsa) : - m_vertexType (VertexRouter), - m_vertexId (lsa->GetLinkStateId ()), - m_lsa (lsa), - m_distanceFromRoot (SPF_INFINITY), - m_rootOif (SPF_INFINITY), - m_nextHop ("0.0.0.0"), - m_parent (0), - m_children () -{ -} - -SPFVertex::~SPFVertex () -{ - for ( ListOfSPFVertex_t::iterator i = m_children.begin (); - i != m_children.end (); - i++) - { - SPFVertex *p = *i; - delete p; - p = 0; - *i = 0; - } - m_children.clear (); -} - - void -SPFVertex::SetVertexType (SPFVertex::VertexType type) -{ - m_vertexType = type; -} - - SPFVertex::VertexType -SPFVertex::GetVertexType (void) const -{ - return m_vertexType; -} - - void -SPFVertex::SetVertexId (Ipv4Address id) -{ - m_vertexId = id; -} - - Ipv4Address -SPFVertex::GetVertexId (void) const -{ - return m_vertexId; -} - - void -SPFVertex::SetLSA (StaticRouterLSA* lsa) -{ - m_lsa = lsa; -} - - StaticRouterLSA* -SPFVertex::GetLSA (void) const -{ - return m_lsa; -} - - void -SPFVertex::SetDistanceFromRoot (uint32_t distance) -{ - m_distanceFromRoot = distance; -} - - uint32_t -SPFVertex::GetDistanceFromRoot (void) const -{ - return m_distanceFromRoot; -} - - void -SPFVertex::SetOutgoingInterfaceId (uint32_t id) -{ - m_rootOif = id; -} - - uint32_t -SPFVertex::GetOutgoingInterfaceId (void) const -{ - return m_rootOif; -} - - void -SPFVertex::SetNextHop (Ipv4Address nextHop) -{ - m_nextHop = nextHop; -} - - Ipv4Address -SPFVertex::GetNextHop (void) const -{ - return m_nextHop; -} - - void -SPFVertex::SetParent (SPFVertex* parent) -{ - m_parent = parent; -} - - SPFVertex* -SPFVertex::GetParent (void) const -{ - return m_parent; -} - - uint32_t -SPFVertex::GetNChildren (void) const -{ - return m_children.size (); -} - - SPFVertex* -SPFVertex::GetChild (uint32_t n) const -{ - uint32_t j = 0; - - for ( ListOfSPFVertex_t::const_iterator i = m_children.begin (); - i != m_children.end (); - i++, j++) - { - if (j == n) - { - return *i; - } - } - NS_ASSERT_MSG(false, "Index out of range."); - return 0; -} - - uint32_t -SPFVertex::AddChild (SPFVertex* child) -{ - m_children.push_back (child); - return m_children.size (); -} - -// --------------------------------------------------------------------------- -// -// StaticRouteManagerLSDB Implementation -// -// --------------------------------------------------------------------------- - -StaticRouteManagerLSDB::StaticRouteManagerLSDB () -: - m_database () -{ - NS_DEBUG ("StaticRouteManagerLSDB::StaticRouteManagerLSDB ()"); -} - -StaticRouteManagerLSDB::~StaticRouteManagerLSDB () -{ - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ()"); - - LSDBMap_t::iterator i; - for (i= m_database.begin (); i!= m_database.end (); i++) - { - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB ():free LSA"); - StaticRouterLSA* temp = i->second; - delete temp; - } - NS_DEBUG ("StaticRouteManagerLSDB::~StaticRouteManagerLSDB (): clear map"); - m_database.clear (); -} - - void -StaticRouteManagerLSDB::Initialize () -{ - NS_DEBUG ("StaticRouteManagerLSDB::Initialize ()"); - - LSDBMap_t::iterator i; - for (i= m_database.begin (); i!= m_database.end (); i++) - { - StaticRouterLSA* temp = i->second; - temp->SetStatus (StaticRouterLSA::LSA_SPF_NOT_EXPLORED); - } -} - - void -StaticRouteManagerLSDB::Insert (Ipv4Address addr, StaticRouterLSA* lsa) -{ - NS_DEBUG ("StaticRouteManagerLSDB::Insert ()"); - m_database.insert (LSDBPair_t (addr, lsa)); -} - - StaticRouterLSA* -StaticRouteManagerLSDB::GetLSA (Ipv4Address addr) const -{ - NS_DEBUG ("StaticRouteManagerLSDB::GetLSA ()"); -// -// Look up an LSA by its address. -// - LSDBMap_t::const_iterator i; - for (i= m_database.begin (); i!= m_database.end (); i++) - { - if (i->first == addr) - { - return i->second; - } - } - return 0; -} - // --------------------------------------------------------------------------- // // StaticRouteManager Implementation // // --------------------------------------------------------------------------- -StaticRouteManager::StaticRouteManager () -: - m_spfroot (0) -{ - m_lsdb = new StaticRouteManagerLSDB (); -} - -StaticRouteManager::~StaticRouteManager () -{ - NS_DEBUG ("StaticRouteManager::~StaticRouteManager ()"); - - if (m_lsdb) - { - delete m_lsdb; - } -} - - void -StaticRouteManager::DebugUseLsdb (StaticRouteManagerLSDB* lsdb) -{ - if (m_lsdb) - delete m_lsdb; - m_lsdb = lsdb; -} - -// -// In order to build the routing database, we need to walk the list of nodes -// in the system and look for those that support the StaticRouter interface. -// These routers will export a number of Link State Advertisements (LSAs) -// that describe the links and networks that are "adjacent" (i.e., that are -// on the other side of a point-to-point link). We take these LSAs and put -// add them to the Link State DataBase (LSDB) from which the routes will -// ultimately be computed. -// void StaticRouteManager::BuildStaticRoutingDatabase () { - NS_DEBUG ("StaticRouteManager::BuildStaticRoutingDatabase()"); -// -// Walk the list of nodes looking for the StaticRouter Interface. -// - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) - { - Ptr node = *i; - - Ptr rtr = - node->QueryInterface (StaticRouter::iid); -// -// Ignore nodes that aren't participating in routing. -// - if (!rtr) - { - continue; - } -// -// You must call DiscoverLSAs () before trying to use any routing info or to -// update LSAs. DiscoverLSAs () drives the process of discovering routes in -// the StaticRouter. Afterward, you may use GetNumLSAs (), which is a very -// computationally inexpensive call. If you call GetNumLSAs () before calling -// DiscoverLSAs () will get zero as the number since no routes have been -// found. -// - uint32_t numLSAs = rtr->DiscoverLSAs (); - NS_DEBUG ("Discover LSAs: Found " << numLSAs << " LSAs"); - - for (uint32_t j = 0; j < numLSAs; ++j) - { - StaticRouterLSA* lsa = new StaticRouterLSA (); -// -// This is the call to actually fetch a Link State Advertisement from the -// router. -// - rtr->GetLSA (j, *lsa); - NS_DEBUG ("LSA " << j); - NS_DEBUG (*lsa); -// -// Write the newly discovered link state advertisement to the database. -// - m_lsdb->Insert (lsa->GetLinkStateId (), lsa); - } - } + return SimulationSingleton::Get ()-> + BuildStaticRoutingDatabase (); } -// -// For each node that is a static router (which is determined by the presence -// of an aggregated StaticRouter interface), run the Dijkstra SPF calculation -// on the database rooted at that router, and populate the node forwarding -// tables. -// -// This function parallels RFC2328, Section 16.1.1, and quagga ospfd -// -// This calculation yields the set of intra-area routes associated -// with an area (called hereafter Area A). A router calculates the -// shortest-path tree using itself as the root. The formation -// of the shortest path tree is done here in two stages. In the -// first stage, only links between routers and transit networks are -// considered. Using the Dijkstra algorithm, a tree is formed from -// this subset of the link state database. In the second stage, -// leaves are added to the tree by considering the links to stub -// networks. -// -// The area's link state database is represented as a directed graph. -// The graph's vertices are routers, transit networks and stub networks. -// -// The first stage of the procedure (i.e., the Dijkstra algorithm) -// can now be summarized as follows. At each iteration of the -// algorithm, there is a list of candidate vertices. Paths from -// the root to these vertices have been found, but not necessarily -// the shortest ones. However, the paths to the candidate vertex -// that is closest to the root are guaranteed to be shortest; this -// vertex is added to the shortest-path tree, removed from the -// candidate list, and its adjacent vertices are examined for -// possible addition to/modification of the candidate list. The -// algorithm then iterates again. It terminates when the candidate -// list becomes empty. -// void StaticRouteManager::InitializeRoutes () { - NS_DEBUG ("StaticRouteManager::InitializeRoutes ()"); -// -// Walk the list of nodes in the system. -// - typedef std::vector < Ptr >::iterator Iterator; - for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++) - { - Ptr node = *i; -// -// Look for the StaticRouter interface that indicates that the node is -// participating in routing. -// - Ptr rtr = - node->QueryInterface (StaticRouter::iid); -// -// if the node has a static router interface, then run the static routing -// algorithms. -// - if (rtr && rtr->GetNumLSAs () ) - { - SPFCalculate (rtr->GetRouterId ()); - } - } -} - -// -// This method is derived from quagga ospf_spf_next (). See RFC2328 Section -// 16.1 (2) for further details. -// -// We're passed a parameter that is a vertex which is already in the SPF -// tree. A vertex represents a router node. We also get a reference to the -// SPF candidate queue, which is a priority queue containing the shortest paths -// to the networks we know about. -// -// We examine the links in v's LSA and update the list of candidates with any -// vertices not already on the list. If a lower-cost path is found to a -// vertex already on the candidate list, store the new (lower) cost. -// - void -StaticRouteManager::SPFNext (SPFVertex* v, CandidateQueue& candidate) -{ - SPFVertex* w = 0; - StaticRouterLSA* w_lsa = 0; - uint32_t distance = 0; - - NS_DEBUG ("StaticRouteManager::SPFNext ()"); -// -// Always true for now, since all our LSAs are RouterLSAs. -// - if (v->GetVertexType () == SPFVertex::VertexRouter) - { - if (true) - { - NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " << - v->GetLSA ()->GetNLinkRecords () << " link records"); -// -// Walk the list of link records in the link state advertisement associated -// with the "current" router (represented by vertex ). -// - for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) - { -// -// (a) If this is a link to a stub network, examine the next link in V's LSA. -// Links to stub networks will be considered in the second stage of the -// shortest path calculation. -// - StaticRouterLinkRecord *l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () == StaticRouterLinkRecord::StubNetwork) - { - NS_DEBUG ("SPFNext: Found a Stub record to " << - l->GetLinkId ()); - continue; - } -// -// (b) Otherwise, W is a transit vertex (router or transit network). Look up -// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state -// database. -// - if (l->GetLinkType () == StaticRouterLinkRecord::PointToPoint) - { -// -// Lookup the link state advertisement of the new link -- we call it in -// the link state database. -// - w_lsa = m_lsdb->GetLSA (l->GetLinkId ()); - NS_ASSERT (w_lsa); - NS_DEBUG ("SPFNext: Found a P2P record from " << - v->GetVertexId () << " to " << w_lsa->GetLinkStateId ()); -// -// (c) If vertex W is already on the shortest-path tree, examine the next -// link in the LSA. -// -// If the link is to a router that is already in the shortest path first tree -// then we have it covered -- ignore it. -// - if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_IN_SPFTREE) - { - NS_DEBUG ("SPFNext: Skipping-> LSA "<< - w_lsa->GetLinkStateId () << " already in SPF tree"); - continue; - } -// -// The link is to a router we haven't dealt with yet. -// -// (d) Calculate the link state cost D of the resulting path from the root to -// vertex W. D is equal to the sum of the link state cost of the (already -// calculated) shortest path to vertex V and the advertised cost of the link -// between vertices V and W. -// - distance = v->GetDistanceFromRoot () + l->GetMetric (); - - NS_DEBUG ("SPFNext: Considering w_lsa " << - w_lsa->GetLinkStateId ()); - - if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_NOT_EXPLORED) - { -// -// If we havent yet considered the link represented by we have to create -// a new SPFVertex to represent it. -// - w = new SPFVertex (w_lsa); -// -// We need to figure out how to actually get to the new router represented -// by . This will (among other things) find the next hop address to send -// packets destined for this network to, and also find the outbound interface -// used to forward the packets. -// - if (SPFNexthopCalculation (v, w, l, distance)) - { - w_lsa->SetStatus ( - StaticRouterLSA::LSA_SPF_CANDIDATE); -// -// Push this new vertex onto the priority queue (ordered by distance from the -// root node). -// - candidate.Push (w); - NS_DEBUG ("SPFNext: Pushing " << - w->GetVertexId () << ", parent vertexId: " << - v->GetVertexId ()); - } - } - } else if (w_lsa->GetStatus () == - StaticRouterLSA::LSA_SPF_CANDIDATE) - { -// -// We have already considered the link represented by . What wse have to -// do now is to decide if this new router represents a route with a shorter -// distance metric. -// -// So, locate the vertex in the candidate queue and take a look at the -// distance. - w = candidate.Find (w_lsa->GetLinkStateId ()); - if (w->GetDistanceFromRoot () < distance) - { -// -// This is not a shorter path, so don't do anything. -// - continue; - } - else if (w->GetDistanceFromRoot () == distance) - { -// -// This path is one with an equal cost. Do nothing for now -- we're not doing -// equal-cost multipath cases yet. -// - } - else - { -// -// this path represents a new, lower-cost path to (the vertex we found in -// the current link record of the link state advertisement of the current root -// (vertex ) -// -// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop -// it will call spf_add_parents, which will flush the old parents -// - if (SPFNexthopCalculation (v, w, l, distance)) - { -// -// If we've changed the cost to get to the vertex represented by , we -// must reorder the priority queue keyed to that cost. -// - candidate.Reorder (); - } - } - } // point-to-point - } // for loop - } - } -} - -// -// This method is derived from quagga ospf_next_hop_calculation() 16.1.1. -// -// Calculate the next hop IP address and the outgoing interface required to -// get packets from the root through (parent) to vertex (destination), -// over a given distance. -// -// For now, this is greatly simplified from the quagga code -// - int -StaticRouteManager::SPFNexthopCalculation ( - SPFVertex* v, - SPFVertex* w, - StaticRouterLinkRecord* l, - uint32_t distance) -{ - NS_DEBUG ("StaticRouteManager::SPFNexthopCalculation ()"); -// -// The vertex m_spfroot is a distinguished vertex representing the node at -// the root of the calculations. That is, it is the node for which we are -// calculating the routes. -// -// There are two distinct cases for calculating the next hop information. -// First, if we're considering a hop from the root to an "adjacent" network -// (one that is on the other side of a point-to-point link connected to the -// root), then we need to store the information needed to forward down that -// link. The second case is if the network is not directly adjacent. In that -// case we need to use the forwarding information from the vertex on the path -// to the destination that is directly adjacent [node 1] in both cases of the -// diagram below. -// -// (1) [root] -> [point-to-point] -> [node 1] -// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2] -// -// We call the propagation of next hop information down vertices of a path -// "inheriting" the next hop information. -// -// The point-to-point link information is only useful in this calculation when -// we are examining the root node. -// - if (v == m_spfroot) - { -// -// In this case is the root node, which means it is the starting point -// for the packets forwarded by that node. This also means that the next hop -// address of packets headed for some arbitrary off-network destination must -// be the destination at the other end of one of the links off of the root -// node if this root node is a router. We then need to see if this node -// is a router. -// - if (w->GetVertexType () == SPFVertex::VertexRouter) - { -// -// In the case of point-to-point links, the link data field (m_linkData) of a -// Static Router Link Record contains the local IP address. If we look at the -// link record describing the link from the perspecive of (the remote -// node from the viewpoint of ) back to the root node, we can discover the -// IP address of the router to which is adjacent. This is a distinguished -// address -- the next hop address to get from to and all networks -// accessed through that path. -// -// SPFGetNextLink () is a little odd. used in this way it is just going to -// return the link record describing the link from to . Think of it as -// SPFGetLink. -// - StaticRouterLinkRecord *linkRemote = 0; - linkRemote = SPFGetNextLink (w, v, linkRemote); -// -// At this point, is the Static Router Link Record describing the point- -// to point link from to from the perspective of ; and -// is the Static Router Link Record describing that same link from the -// perspective of (back to ). Now we can just copy the next hop -// address from the m_linkData member variable. -// -// The next hop member variable we put in has the sense "in order to get -// from the root node to the host represented by vertex , you have to send -// the packet to the next hop address specified in w->m_nextHop. -// - w->SetNextHop(linkRemote->GetLinkData ()); -// -// Now find the outgoing interface corresponding to the point to point link -// from the perspective of -- remember that is the link "from" -// "to" . -// - w->SetOutgoingInterfaceId ( - FindOutgoingInterfaceId (l->GetLinkData ())); - - NS_DEBUG ("SPFNexthopCalculation: Next hop from " << - v->GetVertexId () << " to " << w->GetVertexId () << - " goes through next hop " << w->GetNextHop () << - " via outgoing interface " << w->GetOutgoingInterfaceId ()); - } - } - else - { -// -// If we're calculating the next hop information from a node (v) that is -// *not* the root, then we need to "inherit" the information needed to -// forward the packet from the vertex closer to the root. That is, we'll -// still send packets to the next hop address of the router adjacent to the -// root on the path toward . -// -// Above, when we were considering the root node, we calculated the next hop -// address and outgoing interface required to get off of the root network. -// At this point, we are further away from the root network along one of the -// (shortest) paths. So the next hop and outoing interface remain the same -// (are inherited). -// - w->SetNextHop (v->GetNextHop ()); - w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); - } -// -// In all cases, we need valid values for the distance metric and a parent. -// - w->SetDistanceFromRoot (distance); - w->SetParent (v); - - return 1; -} - -// -// This method is derived from quagga ospf_get_next_link () -// -// First search the Static Router Link Records of vertex for one -// representing a point-to point link to vertex . -// -// What is done depends on prev_link. Contrary to appearances, prev_link just -// acts as a flag here. If prev_link is NULL, we return the first Static -// Router Link Record we find that describes a point-to-point link from -// to . If prev_link is not NULL, we return a Static Router Link Record -// representing a possible *second* link from to . -// -// BUGBUG FIXME: This seems to be a bug. Shouldn't this function look for -// any link records after pre_link and not just after the first? -// - StaticRouterLinkRecord* -StaticRouteManager::SPFGetNextLink ( - SPFVertex* v, - SPFVertex* w, - StaticRouterLinkRecord* prev_link) -{ - NS_DEBUG ("StaticRouteManager::SPFGetNextLink ()"); - - bool skip = true; - StaticRouterLinkRecord* l; -// -// If prev_link is 0, we are really looking for the first link, not the next -// link. -// - if (prev_link == 0) - { - skip = false; - } -// -// Iterate through the Static Router Link Records advertised by the vertex -// looking for records representing the point-to-point links off of this -// vertex. -// - for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i) - { - l = v->GetLSA ()->GetLinkRecord (i); - if (l->GetLinkType () != StaticRouterLinkRecord::PointToPoint) - { - continue; - } -// -// The link ID of a link record representing a point-to-point link is set to -// the router ID of the neighboring router -- the router to which the link -// connects from the perspective of in this case. The vertex ID is also -// set to the router ID (using the link state advertisement of a router node). -// We're just checking to see if the link is actually the link from to -// . -// - if (l->GetLinkId () == w->GetVertexId ()) { - NS_DEBUG ("SPFGetNextLink: Found matching link l: linkId = " << - l->GetLinkId () << " linkData = " << l->GetLinkData ()); -// -// If skip is false, don't (not too surprisingly) skip the link found -- it's -// the one we're interested in. That's either because we didn't pass in a -// previous link, and we're interested in the first one, or because we've -// skipped a previous link and moved forward to the next (which is then the -// one we want). -// - if (skip == false) - { - NS_DEBUG ("SPFGetNextLink: Returning the found link"); - return l; - } - else - { -// -// Skip is true and we've found a link from to . We want the next one. -// Setting skip to false gets us the next point-to-point static router link -// record in the LSA from . -// - NS_DEBUG ("SPFGetNextLink: Skipping the found link"); - skip = false; - continue; - } - } - } - return 0; -} - -// -// Used for unit tests. -// - void -StaticRouteManager::DebugSPFCalculate (Ipv4Address root) -{ - SPFCalculate (root); -} - -// quagga ospf_spf_calculate - void -StaticRouteManager::SPFCalculate (Ipv4Address root) -{ - NS_DEBUG ("StaticRouteManager::SPFCalculate (): " - "root = " << root); - - SPFVertex *v; -// -// Initialize the Link State Database. -// - m_lsdb->Initialize (); -// -// The candidate queue is a priority queue of SPFVertex objects, with the top -// of the queue being the closest vertex in terms of distance from the root -// of the tree. Initially, this queue is empty. -// - CandidateQueue candidate; - NS_ASSERT(candidate.Size () == 0); -// -// Initialize the shortest-path tree to only contain the router doing the -// calculation. Each router (and corresponding network) is a vertex in the -// shortest path first (SPF) tree. -// - v = new SPFVertex (m_lsdb->GetLSA (root)); -// -// This vertex is the root of the SPF tree and it is distance 0 from the root. -// We also mark this vertex as being in the SPF tree. -// - m_spfroot= v; - v->SetDistanceFromRoot (0); - v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); - - for (;;) - { -// -// The operations we need to do are given in the OSPF RFC which we reference -// as we go along. -// -// RFC2328 16.1. (2). -// -// We examine the Static Router Link Records in the Link State -// Advertisements of the current vertex. If there are any point-to-point -// links to unexplored adjacent vertices we add them to the tree and update -// the distance and next hop information on how to get there. We also add -// the new vertices to the candidate queue (the priority queue ordered by -// shortest path). If the new vertices represent shorter paths, we use them -// and update the path cost. -// - SPFNext (v, candidate); -// -// RFC2328 16.1. (3). -// -// If at this step the candidate list is empty, the shortest-path tree (of -// transit vertices) has been completely built and this stage of the -// procedure terminates. -// - if (candidate.Size () == 0) - { - break; - } -// -// Choose the vertex belonging to the candidate list that is closest to the -// root, and add it to the shortest-path tree (removing it from the candidate -// list in the process). -// -// Recall that in the previous step, we created SPFVertex structures for each -// of the routers found in the Static Router Link Records and added tehm to -// the candidate list. -// - v = candidate.Pop (); - NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ()); -// -// Update the status field of the vertex to indicate that it is in the SPF -// tree. -// - v->GetLSA ()->SetStatus (StaticRouterLSA::LSA_SPF_IN_SPFTREE); -// -// The current vertex has a parent pointer. By calling this rather oddly -// named method (blame quagga) we add the current vertex to the list of -// children of that parent vertex. In the next hop calculation called during -// SPFNext, the parent pointer was set but the vertex has been orphaned up -// to now. -// - SPFVertexAddParent (v); -// -// Note that when there is a choice of vertices closest to the root, network -// vertices must be chosen before router vertices in order to necessarily -// find all equal-cost paths. We don't do this at this moment, we should add -// the treatment above codes. -- kunihiro. -// -// RFC2328 16.1. (4). -// -// This is the method that actually adds the routes. It'll walk the list -// of nodes in the system, looking for the node corresponding to the router -// ID of the root of the tree -- that is the router we're building the routes -// for. It looks for the Ipv4 interface of that node and remembers it. So -// we are only actually adding routes to that one node at the root of the SPF -// tree. -// -// We're going to pop of a pointer to every vertex in the tree except the -// root in order of distance from the root. For each of the vertices, we call -// SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the -// point-to-point Static Router Link Records (the links to nodes adjacent to -// the node represented by the vertex). We add a route to the IP address -// specified by the m_linkData field of each of those link records. This will -// be the *local* IP address associated with the interface attached to the -// link. We use the outbound interface and next hop information present in -// the vertex which have possibly been inherited from the root. -// -// To summarize, we're going to look at the node represented by and loop -// through its point-to-point links, adding a *host* route to the local IP -// address (at the side) for each of those links. -// - SPFIntraAddRouter (v); -// -// RFC2328 16.1. (5). -// -// Iterate the algorithm by returning to Step 2 until there are no more -// candidate vertices. -// - } -// -// Second stage of SPF calculation procedure's -// NOTYET: ospf_spf_process_stubs (area, area->spf, new_table); -// -// We're all done setting the routing information for the node at the root of -// the SPF tree. Delete all of the vertices and corresponding resources. Go -// possibly do it again for the next router. -// - delete m_spfroot; - m_spfroot = 0; -} - -// -// BUGBUG FIXME: This should probably be a method on Ipv4 -// -// Return the interface index corresponding to a given IP address -// - uint32_t -StaticRouteManager::FindOutgoingInterfaceId (Ipv4Address a) -{ -// -// We have an IP address and a vertex ID of the root of the SPF tree. -// The question is what interface index does this address correspond to. -// The answer is a little complicated since we have to find a pointer to -// the node corresponding to the vertex ID, find the Ipv4 interface on that -// node in order to iterate the interfaces and find the one corresponding to -// the address in question. -// - Ipv4Address routerId = m_spfroot->GetVertexId (); -// -// Walk the list of nodes in the system looking for the one corresponding to -// the node at the root of the SPF tree. This is the node for which we are -// building the routing table. -// - std::vector >::iterator i = NodeList::Begin (); - for (; i != NodeList::End (); i++) - { - Ptr node = *i; - - Ptr rtr = - node->QueryInterface (StaticRouter::iid); -// -// If the node doesn't have a StaticRouter interface it can't be the one -// we're interested in. -// - if (rtr == 0) - { - continue; - } - - if (rtr->GetRouterId () == routerId) - { -// -// This is the node we're building the routing table for. We're going to need -// the Ipv4 interface to look for the ipv4 interface index. Since this node -// is participating in routing IP version 4 packets, it certainly must have -// an Ipv4 interface. -// - Ptr ipv4 = node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG (ipv4, - "StaticRouteManager::FindOutgoingInterfaceId (): " - "QI for interface failed"); -// -// Look through the interfaces on this node for one that has the IP address -// we're looking for. If we find one, return the corresponding interface -// index. -// - for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++) - { - if (ipv4->GetAddress (i) == a) - { - NS_DEBUG ("StaticRouteManager::FindOutgoingInterfaceId (): " - "Interface match for " << a); - return i; - } - } - } - } -// -// Couldn't find it. -// - return 0; -} - -// -// This method is derived from quagga ospf_intra_add_router () -// -// This is where we are actually going to add the host routes to the routing -// tables of the individual nodes. -// -// The vertex passed as a parameter has just been added to the SPF tree. -// This vertex must have a valid m_root_oid, corresponding to the outgoing -// interface on the root router of the tree that is the first hop on the path -// to the vertex. The vertex must also have a next hop address, corresponding -// to the next hop on the path to the vertex. The vertex has an m_lsa field -// that has some number of link records. For each point to point link record, -// the m_linkData is the local IP address of the link. This corresponds to -// a destination IP address, reachable from the root, to which we add a host -// route. -// - void -StaticRouteManager::SPFIntraAddRouter (SPFVertex* v) -{ - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ()"); - - NS_ASSERT_MSG (m_spfroot, - "StaticRouteManager::SPFIntraAddRouter (): Root pointer not set"); -// -// The root of the Shortest Path First tree is the router to which we are -// going to write the actual routing table entries. The vertex corresponding -// to this router has a vertex ID which is the router ID of that node. We're -// going to use this ID to discover which node it is that we're actually going -// to update. -// - Ipv4Address routerId = m_spfroot->GetVertexId (); - - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter ():" - "Vertex ID = " << routerId); -// -// We need to walk the list of nodes looking for the one that has the router -// ID corresponding to the root vertex. This is the one we're going to write -// the routing information to. -// - std::vector >::iterator i = NodeList::Begin (); - for (; i != NodeList::End (); i++) - { - Ptr node = *i; -// -// The router ID is accessible through the StaticRouter interface, so we need -// to QI for that interface. If there's no StaticRouter interface, the node -// in question cannot be the router we want, so we continue. -// - Ptr rtr = - node->QueryInterface (StaticRouter::iid); - - if (rtr == 0) - { - continue; - } -// -// If the router ID of the current node is equal to the router ID of the -// root of the SPF tree, then this node is the one for which we need to -// write the routing tables. -// - if (rtr->GetRouterId () == routerId) - { - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " - "setting routes for node " << node->GetId ()); -// -// Routing information is updated using the Ipv4 interface. We need to QI -// for that interface. If the node is acting as an IP version 4 router, it -// should absolutely have an Ipv4 interface. -// - Ptr ipv4 = node->QueryInterface (Ipv4::iid); - NS_ASSERT_MSG (ipv4, - "StaticRouteManager::SPFIntraAddRouter (): " - "QI for interface failed"); -// -// Get the Static Router Link State Advertisement from the vertex we're -// adding the routes to. The LSA will have a number of attached Static Router -// Link Records corresponding to links off of that vertex / node. We're going -// to be interested in the records corresponding to point-to-point links. -// - StaticRouterLSA *lsa = v->GetLSA (); - NS_ASSERT_MSG (lsa, - "StaticRouteManager::SPFIntraAddRouter (): " - "Expected valid LSA in SPFVertex* v"); - - uint32_t nLinkRecords = lsa->GetNLinkRecords (); -// -// Iterate through the link records on the vertex to which we're going to add -// routes. To make sure we're being clear, we're going to add routing table -// entries to the tables on the node corresping to the root of the SPF tree. -// These entries will have routes to the IP addresses we find from looking at -// the local side of the point-to-point links found on the node described by -// the vertex . -// - for (uint32_t j = 0; j < nLinkRecords; j += 2) - { -// -// We are only concerned about point-to-point links -// - StaticRouterLinkRecord *lr = lsa->GetLinkRecord (j); - if (lr->GetLinkType () != StaticRouterLinkRecord::PointToPoint) - { - continue; - } - - NS_DEBUG ("StaticRouteManager::SPFIntraAddRouter (): " - " Node " << node->GetId () << - " add route to " << lr->GetLinkData () << - " using next hop " << v->GetNextHop () << - " via interface " << v->GetOutgoingInterfaceId ()); -// -// Here's why we did all of that work. We're going to add a host route to the -// host address found in the m_linkData field of the point-to-point link -// record. In the case of a point-to-point link, this is the local IP address -// of the node connected to the link. Each of these point-to-point links -// will correspond to a local interface that has an IP address to which -// the node at the root of the SPF tree can send packets. The vertex -// (corresponding to the node that has these links and interfaces) has -// an m_nextHop address precalculated for us that is the address to which the -// root node should send packets to be forwarded to these IP addresses. -// Similarly, the vertex has an m_rootOif (outbound interface index) to -// which the packets should be send for forwarding. -// - ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (), - v->GetOutgoingInterfaceId ()); - } - } -// -// We've found the node and added the routes. Don't need to search forward -// for another node we'll never find. -// - return; - } -} - -// Derived from quagga ospf_vertex_add_parents () -// -// This is a somewhat oddly named method (blame quagga). Although you might -// expect it to add a parent *to* something, it actually adds a vertex -// to the list of children *in* each of its parents. -// -// Given a pointer to a vertex, it links back to the vertex's parent that it -// already has set and adds itself to that vertex's list of children. -// -// For now, only one parent (not doing equal-cost multipath) -// - void -StaticRouteManager::SPFVertexAddParent (SPFVertex* v) -{ - v->GetParent ()->AddChild (v); + return SimulationSingleton::Get ()-> + InitializeRoutes (); } } // namespace ns3 - -#ifdef RUN_SELF_TESTS - -// --------------------------------------------------------------------------- -// -// Unit Tests -// -// --------------------------------------------------------------------------- - -#include "ns3/test.h" - -namespace ns3 { - -class StaticRouterTestNode : public Node -{ -public: - StaticRouterTestNode (); - -private: - virtual void DoAddDevice (Ptr device) const {}; - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); -}; - -StaticRouterTestNode::StaticRouterTestNode () -{ -// Ptr ipv4 = Create (this); -} - - TraceResolver* -StaticRouterTestNode::DoCreateTraceResolver (TraceContext const &context) -{ - return 0; -} - -class StaticRouteManagerTest : public Test { -public: - StaticRouteManagerTest (); - virtual ~StaticRouteManagerTest (); - virtual bool RunTests (void); -}; - -StaticRouteManagerTest::StaticRouteManagerTest () - : Test ("StaticRouteManager") -{ -} - -StaticRouteManagerTest::~StaticRouteManagerTest () -{} - - bool -StaticRouteManagerTest::RunTests (void) -{ - bool ok = true; - - CandidateQueue candidate; - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = new SPFVertex; - v->SetDistanceFromRoot (rand () % 100); - candidate.Push (v); - } - - uint32_t lastDistance = 0; - - for (int i = 0; i < 100; ++i) - { - SPFVertex *v = candidate.Pop (); - if (v->GetDistanceFromRoot () < lastDistance) - { - ok = false; - } - lastDistance = v->GetDistanceFromRoot (); - delete v; - v = 0; - } - - // Build fake link state database; four routers (0-3), 3 point-to-point - // links - // - // n0 - // \ link 0 - // \ link 2 - // n2 -------------------------n3 - // / - // / link 1 - // n1 - // - // link0: 10.1.1.1/30, 10.1.1.2/30 - // link1: 10.1.2.1/30, 10.1.2.2/30 - // link2: 10.1.3.1/30, 10.1.3.2/30 - // - // Router 0 - StaticRouterLinkRecord* lr0 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.2", // router ID 0.0.0.2 - "10.1.1.1", // local ID - 1); // metric - - StaticRouterLinkRecord* lr1 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.1.1", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa0 = new StaticRouterLSA (); - lsa0->SetLinkStateId ("0.0.0.0"); - lsa0->SetAdvertisingRouter ("0.0.0.0"); - lsa0->AddLinkRecord (lr0); - lsa0->AddLinkRecord (lr1); - - // Router 1 - StaticRouterLinkRecord* lr2 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.2", - "10.1.2.1", - 1); - - StaticRouterLinkRecord* lr3 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.2.1", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa1 = new StaticRouterLSA (); - lsa1->SetLinkStateId ("0.0.0.1"); - lsa1->SetAdvertisingRouter ("0.0.0.1"); - lsa1->AddLinkRecord (lr2); - lsa1->AddLinkRecord (lr3); - - // Router 2 - StaticRouterLinkRecord* lr4 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.0", - "10.1.1.2", - 1); - - StaticRouterLinkRecord* lr5 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.1.2", - "255.255.255.252", - 1); - - StaticRouterLinkRecord* lr6 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.1", - "10.1.2.2", - 1); - - StaticRouterLinkRecord* lr7 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.2.2", - "255.255.255.252", - 1); - - StaticRouterLinkRecord* lr8 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.3", - "10.1.3.2", - 1); - - StaticRouterLinkRecord* lr9 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.3.2", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa2 = new StaticRouterLSA (); - lsa2->SetLinkStateId ("0.0.0.2"); - lsa2->SetAdvertisingRouter ("0.0.0.2"); - lsa2->AddLinkRecord (lr4); - lsa2->AddLinkRecord (lr5); - lsa2->AddLinkRecord (lr6); - lsa2->AddLinkRecord (lr7); - lsa2->AddLinkRecord (lr8); - lsa2->AddLinkRecord (lr9); - - // Router 3 - StaticRouterLinkRecord* lr10 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::PointToPoint, - "0.0.0.2", - "10.1.2.1", - 1); - - StaticRouterLinkRecord* lr11 = new StaticRouterLinkRecord ( - StaticRouterLinkRecord::StubNetwork, - "10.1.2.1", - "255.255.255.252", - 1); - - StaticRouterLSA* lsa3 = new StaticRouterLSA (); - lsa3->SetLinkStateId ("0.0.0.3"); - lsa3->SetAdvertisingRouter ("0.0.0.3"); - lsa3->AddLinkRecord (lr10); - lsa3->AddLinkRecord (lr11); - - // Test the database - StaticRouteManagerLSDB* srmlsdb = new StaticRouteManagerLSDB (); - srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0); - srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1); - srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2); - srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3); - NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ())); - - // XXX next, calculate routes based on the manually created LSDB - StaticRouteManager* srm = new StaticRouteManager (); - srm->DebugUseLsdb (srmlsdb); // manually add in an LSDB - // Note-- this will succeed without any nodes in the topology - // because the NodeList is empty - srm->DebugSPFCalculate (lsa0->GetLinkStateId ()); // node n0 - - // This delete clears the srm, which deletes the LSDB, which clears - // all of the LSAs, which each destroys the attached LinkRecords. - delete srm; - - return ok; -} - -// Instantiate this class for the unit tests -static StaticRouteManagerTest g_staticRouteManagerTest; - -} // namespace ns3 - -#endif diff --git a/src/routing/static-route-manager.h b/src/routing/static-route-manager.h index 67e120da4..e8616d573 100644 --- a/src/routing/static-route-manager.h +++ b/src/routing/static-route-manager.h @@ -13,603 +13,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef STATIC_ROUTE_MANAGER_H #define STATIC_ROUTE_MANAGER_H -#include -#include -#include -#include -#include "ns3/object.h" -#include "ns3/ptr.h" -#include "ns3/ipv4-address.h" -#include "static-router.h" - namespace ns3 { -const uint32_t SPF_INFINITY = 0xffffffff; - -class CandidateQueue; - -/** - * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328, - * Section 16. - * - * Each router in the simulation is associated with an SPFVertex object. When - * calculating routes, each of these routers is, in turn, chosen as the "root" - * of the calculation and routes to all of the other routers are eventually - * saved in the routing tables of each of the chosen nodes. Each of these - * routers in the calculation has an associated SPFVertex. - * - * The "Root" vertex is the SPFVertex representing the router that is having - * its routing tables set. The SPFVertex objects representing other routers - * or networks in the simulation are arranged in the SPF tree. It is this - * tree that represents the Shortest Paths to the other networks. - * - * Each SPFVertex has a pointer to the Static Router Link State Advertisement - * (LSA) that its underlying router has exported. Within these LSAs are - * Static Router Link Records that describe the point to point links from the - * underlying router to other nodes (represented by other SPFVertex objects) - * in the simulation topology. The combination of the arrangement of the - * SPFVertex objects in the SPF tree, along with the details of the link - * records that connect them provide the information required to construct the - * required routes. - */ -class SPFVertex -{ -public: -/** - * @enum Enumeration of the possible types of SPFVertex objects. Currently - * we use VertexRouter to identify objects that represent a router in the - * simulation topology, and VertexNetwork to identify objects that represent - * a network. - */ - enum VertexType { - VertexUnknown = 0, /**< Uninitialized Link Record */ - VertexRouter, /**< Vertex representing a router in the topology */ - VertexNetwork /**< Vertex representing a network in the topology */ - }; -/** - * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First - * Vertex). - * - * The Vertex Type is set to VertexUnknown, the Vertex ID is set to - * 255.255.255.255, and the distance from root is set to infinity - * (UINT32_MAX). The referenced Link State Advertisement (LSA) is set to - * null as is the parent SPFVertex. The outgoing interface index is set to - * infinity, the next hop address is set to 0.0.0.0 and the list of children - * of the SPFVertex is initialized to empty. - * - * @see VertexType - */ - SPFVertex(); -/** - * @brief Construct an initialized SPFVertex (Shortest Path First Vertex). - * - * The Vertex Type is initialized to VertexRouter and the Vertex ID is found - * from the Link State ID of the Link State Advertisement (LSA) passed as a - * parameter. The Link State ID is set to the Router ID of the advertising - * router. The referenced LSA (m_lsa) is set to the given LSA. Other than - * these members, initialization is as in the default constructor. - * of the SPFVertex is initialized to empty. - * - * @see SPFVertex::SPFVertex () - * @see VertexType - * @see StaticRouterLSA - * @param lsa The Link State Advertisement used for finding initial values. - */ - SPFVertex(StaticRouterLSA* lsa); -/** - * @brief Destroy an SPFVertex (Shortest Path First Vertex). - * - * The children vertices of the SPFVertex are recursively deleted. - * - * @see SPFVertex::SPFVertex () - */ - ~SPFVertex(); -/** - * @brief Get the Vertex Type field of a SPFVertex object. - * - * The Vertex Type describes the kind of simulation object a given SPFVertex - * represents. - * - * @see VertexType - * @returns The VertexType of the current SPFVertex object. - */ - VertexType GetVertexType (void) const; -/** - * @brief Set the Vertex Type field of a SPFVertex object. - * - * The Vertex Type describes the kind of simulation object a given SPFVertex - * represents. - * - * @see VertexType - * @param The new VertexType for the current SPFVertex object. - */ - void SetVertexType (VertexType type); -/** - * @brief Get the Vertex ID field of a SPFVertex object. - * - * The Vertex ID uniquely identifies the simulation object a given SPFVertex - * represents. Typically, this is the Router ID for SPFVertex objects - * representing routers, and comes from the Link State Advertisement of a - * router aggregated to a node in the simulation. These IDs are allocated - * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increasing as new routers are - * instantiated. - * - * @returns The Ipv4Address Vertex ID of the current SPFVertex object. - */ - Ipv4Address GetVertexId (void) const; -/** - * @brief Set the Vertex ID field of a SPFVertex object. - * - * The Vertex ID uniquely identifies the simulation object a given SPFVertex - * represents. Typically, this is the Router ID for SPFVertex objects - * representing routers, and comes from the Link State Advertisement of a - * router aggregated to a node in the simulation. These IDs are allocated - * automatically by the routing environment and look like IP addresses - * beginning at 0.0.0.0 and monotonically increasing as new routers are - * instantiated. - * - * @param id The new Ipv4Address Vertex ID for the current SPFVertex object. - */ - void SetVertexId (Ipv4Address id); -/** - * @brief Get the Static Router Link State Advertisement returned by the - * Static Router represented by this SPFVertex during the route discovery - * process. - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @returns A pointer to the StaticRouterLSA found by the router represented - * by this SPFVertex object. - */ - StaticRouterLSA* GetLSA (void) const; -/** - * @brief Set the Static Router Link State Advertisement returned by the - * Static Router represented by this SPFVertex during the route discovery - * process. - * - * @see SPFVertex::GetLSA () - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouter::DiscoverLSAs () - * @warning Ownership of the LSA is transferred to the "this" SPFVertex. You - * must not delete the LSA after calling this method. - * @param A pointer to the StaticRouterLSA. - */ - void SetLSA (StaticRouterLSA* lsa); -/** - * @brief Get the distance from the root vertex to "this" SPFVertex object. - * - * Each router in the simulation is associated with an SPFVertex object. When - * calculating routes, each of these routers is, in turn, chosen as the "root" - * of the calculation and routes to all of the other routers are eventually - * saved in the routing tables of each of the chosen nodes. Each of these - * routers in the calculation has an associated SPFVertex. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex to which - * a route is being calculated from the root. The distance from the root that - * we're asking for is the number of hops from the root vertex to the vertex - * in question. - * - * The distance is calculated during route discovery and is stored in a - * member variable. This method simply fetches that value. - * - * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex. - */ - uint32_t GetDistanceFromRoot (void) const; -/** - * @brief Set the distance from the root vertex to "this" SPFVertex object. - * - * Each router in the simulation is associated with an SPFVertex object. When - * calculating routes, each of these routers is, in turn, chosen as the "root" - * of the calculation and routes to all of the other routers are eventually - * saved in the routing tables of each of the chosen nodes. Each of these - * routers in the calculation has an associated SPFVertex. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex to which - * a route is being calculated from the root. The distance from the root that - * we're asking for is the number of hops from the root vertex to the vertex - * in question. - * - * @param distance The distance, in hops, from the root SPFVertex to "this" - * SPFVertex. - */ - void SetDistanceFromRoot (uint32_t distance); -/** - * @brief Get the interface ID that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The outgoing interface that we're asking for is the interface - * index on the root node that should be used to start packets along the - * path to "this" vertex. - * - * When initializing the root SPFVertex, the interface ID is determined by - * examining the Static Router Link Records of the Link State Advertisement - * generated by the root node's StaticRouter. These interfaces are used to - * forward packets off of the root's network down those links. As other - * vertices are discovered which are further away from the root, they will - * be accessible down one of the paths begun by a Static Router Link Record. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to the interface of that - * first hop. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method, the root node is asking, "which of my local interfaces - * should I use to get a packet to the network or host represented by 'this' - * SPFVertex." - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @returns The interface index to use when forwarding packets to the host - * or network represented by "this" SPFVertex. - */ - uint32_t GetOutgoingInterfaceId (void) const; -/** - * @brief Set the interface ID that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The outgoing interface that we're asking for is the interface - * index on the root node that should be used to start packets along the - * path to "this" vertex. - * - * When initializing the root SPFVertex, the interface ID is determined by - * examining the Static Router Link Records of the Link State Advertisement - * generated by the root node's StaticRouter. These interfaces are used to - * forward packets off of the root's network down those links. As other - * vertices are discovered which are further away from the root, they will - * be accessible down one of the paths begun by a Static Router Link Record. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to the interface of that - * first hop. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method, we are letting the root node know which of its local - * interfaces it should use to get a packet to the network or host represented - * by "this" SPFVertex. - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @param id The interface index to use when forwarding packets to the host or - * network represented by "this" SPFVertex. - */ - void SetOutgoingInterfaceId (uint32_t id); -/** - * @brief Get the IP address that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The IP address that we're asking for is the address on the - * remote side of a link off of the root node that should be used as the - * destination for packets along the path to "this" vertex. - * - * When initializing the root SPFVertex, the IP address used when forwarding - * packets is determined by examining the Static Router Link Records of the - * Link State Advertisement generated by the root node's StaticRouter. This - * address is used to forward packets off of the root's network down those - * links. As other vertices / nodes are discovered which are further away - * from the root, they will be accessible down one of the paths via a link - * described by one of these Static Router Link Records. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to a first hop router down - * an interface. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method, the root node is asking, "which router should I send a - * packet to in order to get that packet to the network or host represented - * by 'this' SPFVertex." - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @returns The IP address to use when forwarding packets to the host - * or network represented by "this" SPFVertex. - */ - Ipv4Address GetNextHop (void) const; -/** - * @brief Set the IP address that should be used to begin forwarding packets - * from the root SPFVertex to "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set. The "this" SPFVertex is the vertex that - * represents the host or network to which a route is being calculated from - * the root. The IP address that we're asking for is the address on the - * remote side of a link off of the root node that should be used as the - * destination for packets along the path to "this" vertex. - * - * When initializing the root SPFVertex, the IP address used when forwarding - * packets is determined by examining the Static Router Link Records of the - * Link State Advertisement generated by the root node's StaticRouter. This - * address is used to forward packets off of the root's network down those - * links. As other vertices / nodes are discovered which are further away - * from the root, they will be accessible down one of the paths via a link - * described by one of these Static Router Link Records. - * - * To forward packets to these hosts or networks, the root node must begin - * the forwarding process by sending the packets to a first hop router down - * an interface. This means that the first hop address and interface ID must - * be the same for all downstream SPFVertices. We call this "inheriting" - * the interface and next hop. - * - * In this method we are telling the root node which router it should send - * should I send a packet to in order to get that packet to the network or - * host represented by 'this' SPFVertex." - * - * @see StaticRouter - * @see StaticRouterLSA - * @see StaticRouterLinkRecord - * @param nextHop The IP address to use when forwarding packets to the host - * or network represented by "this" SPFVertex. - */ - void SetNextHop (Ipv4Address nextHop); -/** - * @brief Get a pointer to the SPFVector that is the parent of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. - * - * This method returns a pointer to the parent node of "this" SPFVertex - * (both of which reside in that SPF tree). - * - * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex - * in the SPF tree. - */ - SPFVertex* GetParent (void) const; -/** - * @brief Set the pointer to the SPFVector that is the parent of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. - * - * This method sets the parent pointer of "this" SPFVertex (both of which - * reside in that SPF tree). - * - * @param parent A pointer to the SPFVertex that is the parent of "this" - * SPFVertex* in the SPF tree. - */ - void SetParent (SPFVertex* parent); -/** - * @brief Get the number of children of "this" SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. Each vertex - * in the SPF tree can have a number of children that represent host or - * network routes available via that vertex. - * - * This method returns the number of children of "this" SPFVertex (which - * reside in the SPF tree). - * - * @returns The number of children of "this" SPFVertex (which reside in the - * SPF tree). - */ - uint32_t GetNChildren (void) const; -/** - * @brief Get a borrowed SPFVertex pointer to the specified child of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. Each vertex - * in the SPF tree can have a number of children that represent host or - * network routes available via that vertex. - * - * This method the number of children of "this" SPFVertex (which reside in - * the SPF tree. - * - * @see SPFVertex::GetNChildren - * @param n The index (from 0 to the number of children minus 1) of the - * child SPFVertex to return. - * @warning The pointer returned by GetChild () is a borrowed pointer. You - * do not have any ownership of the underlying object and must not delete - * that object. - * @returns A pointer to the specified child SPFVertex (which resides in the - * SPF tree). - */ - SPFVertex* GetChild (uint32_t n) const; -/** - * @brief Get a borrowed SPFVertex pointer to the specified child of "this" - * SPFVertex. - * - * Each router node in the simulation is associated with an SPFVertex object. - * When calculating routes, each of these routers is, in turn, chosen as the - * "root" of the calculation and routes to all of the other routers are - * eventually saved in the routing tables of each of the chosen nodes. - * - * The "Root" vertex is then the SPFVertex representing the router that is - * having its routing tables set and is the root of the SPF tree. Each vertex - * in the SPF tree can have a number of children that represent host or - * network routes available via that vertex. - * - * This method the number of children of "this" SPFVertex (which reside in - * the SPF tree. - * - * @see SPFVertex::GetNChildren - * @param n The index (from 0 to the number of children minus 1) of the - * child SPFVertex to return. - * @warning Ownership of the pointer added to the children of "this" - * SPFVertex is transferred to the "this" SPFVertex. You must not delete the - * (now) child SPFVertex after calling this method. - * @param child A pointer to the SPFVertex (which resides in the SPF tree) to - * be added to the list of children of "this" SPFVertex. - * @returns The number of children of "this" SPFVertex after the addition of - * the new child. - */ - uint32_t AddChild (SPFVertex* child); - -private: - VertexType m_vertexType; - Ipv4Address m_vertexId; - StaticRouterLSA* m_lsa; - uint32_t m_distanceFromRoot; - uint32_t m_rootOif; - Ipv4Address m_nextHop; - SPFVertex* m_parent; - typedef std::list ListOfSPFVertex_t; - ListOfSPFVertex_t m_children; -/** - * @brief The SPFVertex copy construction is disallowed. There's no need for - * it and a compiler provided shallow copy would be wrong. - */ - SPFVertex (SPFVertex& v); -/** - * @brief The SPFVertex copy assignment operator is disallowed. There's no - * need for it and a compiler provided shallow copy would be wrong. - */ - SPFVertex& operator= (SPFVertex& v); -}; - -/** - * @brief The Link State DataBase (LSDB) of the Static Route Manager. - * - * Each node in the simulation participating in static routing has a - * StaticRouter interface. The primary job of this interface is to export - * Static Router Link State Advertisements (LSAs). These advertisements in - * turn contain a number of Static Router Link Records that describe the - * point to point links from the underlying node to other nodes (that will - * also export their own LSAs. - * - * This class implements a searchable database of LSAs gathered from every - * router in the simulation. - */ -class StaticRouteManagerLSDB -{ -public: -/** - * @brief Construct an empty Static Router Manager Link State Database. - * - * The database map composing the Link State Database is initialized in - * this constructor. - */ - StaticRouteManagerLSDB (); -/** - * @brief Destroy an empty Static Router Manager Link State Database. - * - * The database map is walked and all of the Link State Advertisements stored - * in the database are freed; then the database map itself is clear ()ed to - * release any remaining resources. - */ - ~StaticRouteManagerLSDB (); -/** - * @brief Insert an IP address / Link State Advertisement pair into the Link - * State Database. - * - * The IPV4 address and the StaticRouterLSA given as parameters are converted - * to an STL pair and are inserted into the database map. - * - * @see StaticRouterLSA - * @see Ipv4Address - * @param addr The IP address associated with the LSA. Typically the Router - * ID. - * @param lsa A pointer to the Link State Advertisement for the router. - */ - void Insert(Ipv4Address addr, StaticRouterLSA* lsa); -/** - * @brief Look up the Link State Advertisement associated with the given - * IP Address. - * - * The database map is searched for the given IPV4 address and corresponding - * StaticRouterLSA is returned. - * - * @see StaticRouterLSA - * @see Ipv4Address - * @param addr The IP address associated with the LSA. Typically the Router - * ID. - * @returns A pointer to the Link State Advertisement for the router specified - * by the IP address addr. - */ - StaticRouterLSA* GetLSA (Ipv4Address addr) const; -/** - * @brief Set all LSA flags to an initialized state, for SPF computation - * - * This function walks the database and resets the status flags of all of the - * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED. This is done - * prior to each SPF calculation to reset the state of the SPFVertex structures - * that will reference the LSAs during the calculation. - * - * @see StaticRouterLSA - * @see SPFVertex - */ - void Initialize (); - -private: - typedef std::map LSDBMap_t; - typedef std::pair LSDBPair_t; - - LSDBMap_t m_database; -/** - * @brief StaticRouteManagerLSDB copy construction is disallowed. There's no - * need for it and a compiler provided shallow copy would be hopelessly wrong. - */ - StaticRouteManagerLSDB (StaticRouteManagerLSDB& lsdb); -/** - * @brief The SPFVertex copy assignment operator is disallowed. There's no - * need for it and a compiler provided shallow copy would be wrong. - */ - StaticRouteManagerLSDB& operator= (StaticRouteManagerLSDB& lsdb); -}; - /** * @brief A global static router * @@ -621,35 +30,20 @@ private: * * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd. */ -class StaticRouteManager : public Object +class StaticRouteManager { public: - static const InterfaceId iid; - StaticRouteManager (); /** * @brief Build the routing database by gathering Link State Advertisements * from each node exporting a StaticRouter interface. * */ - virtual void BuildStaticRoutingDatabase(); + static void BuildStaticRoutingDatabase(); /** * @brief Compute routes using a Dijkstra SPF computation and populate * per-node forwarding tables */ - virtual void InitializeRoutes(); -/** - * @brief Debugging routine; allow client code to supply a pre-built LSDB - */ - void DebugUseLsdb (StaticRouteManagerLSDB*); -/** - * @brief Debugging routine; call the core SPF from the unit tests - */ - void DebugSPFCalculate (Ipv4Address root); - - virtual ~StaticRouteManager (); - -protected: - + static void InitializeRoutes(); private: /** * @brief Static Route Manager copy construction is disallowed. There's no @@ -662,18 +56,6 @@ private: * need for it and a compiler provided shallow copy would be hopelessly wrong. */ StaticRouteManager& operator= (StaticRouteManager& srm); - - SPFVertex* m_spfroot; - StaticRouteManagerLSDB* m_lsdb; - void SPFCalculate (Ipv4Address root); - void SPFNext (SPFVertex*, CandidateQueue&); - int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* l, uint32_t distance); - void SPFVertexAddParent(SPFVertex* v); - StaticRouterLinkRecord* SPFGetNextLink(SPFVertex* v, SPFVertex* w, - StaticRouterLinkRecord* prev_link); - void SPFIntraAddRouter(SPFVertex* v); - uint32_t FindOutgoingInterfaceId(Ipv4Address a); }; } // namespace ns3