A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
global-route-manager-impl.cc
Go to the documentation of this file.
1/*
2 * Copyright 2007 University of Washington
3 * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Authors: Tom Henderson (tomhend@u.washington.edu)
8 *
9 * Kunihiro Ishigura, Toshiaki Takada (GNU Zebra) are attributed authors
10 * of the quagga 0.99.7/src/ospfd/ospf_spf.c code which was ported here
11 */
12
14
15#include "candidate-queue.h"
17#include "ipv4-global-routing.h"
18#include "ipv4-l3-protocol.h"
19#include "ipv4.h"
20
21#include "ns3/assert.h"
22#include "ns3/fatal-error.h"
23#include "ns3/log.h"
24#include "ns3/node-list.h"
25#include "ns3/simulator.h"
26
27#include <algorithm>
28#include <iomanip>
29#include <iostream>
30#include <queue>
31#include <utility>
32#include <vector>
33
34namespace ns3
35{
36
37NS_LOG_COMPONENT_DEFINE("GlobalRouteManagerImpl");
38
39/**
40 * @brief Stream insertion operator.
41 *
42 * @param os the reference to the output stream
43 * @param exit the exit node
44 * @returns the reference to the output stream
45 */
46std::ostream&
47operator<<(std::ostream& os, const SPFVertex::NodeExit_t& exit)
48{
49 os << "(" << exit.first << " ," << exit.second << ")";
50 return os;
51}
52
53std::ostream&
54operator<<(std::ostream& os, const SPFVertex::ListOfSPFVertex_t& vs)
55{
56 os << "{";
57 for (auto iter = vs.begin(); iter != vs.end();)
58 {
59 os << (*iter)->m_vertexId;
60 if (++iter != vs.end())
61 {
62 os << ", ";
63 }
64 else
65 {
66 break;
67 }
68 }
69 os << "}";
70 return os;
71}
72
73// ---------------------------------------------------------------------------
74//
75// SPFVertex Implementation
76//
77// ---------------------------------------------------------------------------
78
81 m_vertexId("255.255.255.255"),
82 m_lsa(nullptr),
85 m_nextHop("0.0.0.0"),
86 m_parents(),
87 m_children(),
89{
90 NS_LOG_FUNCTION(this);
91}
92
94 : m_vertexId(lsa->GetLinkStateId()),
95 m_lsa(lsa),
98 m_nextHop("0.0.0.0"),
99 m_parents(),
100 m_children(),
101 m_vertexProcessed(false)
102{
103 NS_LOG_FUNCTION(this << lsa);
104
106 {
107 NS_LOG_LOGIC("Setting m_vertexType to VertexRouter");
109 m_node = lsa->GetNode();
110 }
111 else if (lsa->GetLSType() == GlobalRoutingLSA::NetworkLSA)
112 {
113 NS_LOG_LOGIC("Setting m_vertexType to VertexNetwork");
115 }
116}
117
119{
120 NS_LOG_FUNCTION(this);
121
122 NS_LOG_LOGIC("Children vertices - " << m_children);
123 NS_LOG_LOGIC("Parent vertices - " << m_parents);
124
125 // find this node from all its parents and remove the entry of this node
126 // from all its parents
127 for (auto piter = m_parents.begin(); piter != m_parents.end(); piter++)
128 {
129 // remove the current vertex from its parent's children list. Check
130 // if the size of the list is reduced, or the child<->parent relation
131 // is not bidirectional
132 uint32_t orgCount = (*piter)->m_children.size();
133 (*piter)->m_children.remove(this);
134 uint32_t newCount = (*piter)->m_children.size();
135
136 NS_ASSERT_MSG(orgCount > newCount,
137 "Unable to find the current vertex from its parents --- impossible!");
138 }
139
140 // delete children
141 while (!m_children.empty())
142 {
143 // pop out children one by one. Some children may disappear
144 // when deleting some other children in the list. As a result,
145 // it is necessary to use pop to walk through all children, instead
146 // of using iterator.
147 //
148 // Note that m_children.pop_front () is not necessary as this
149 // p is removed from the children list when p is deleted
150 SPFVertex* p = m_children.front();
151 // 'p' == 0, this child is already deleted by its other parent
152 if (p == nullptr)
153 {
154 continue;
155 }
156 NS_LOG_LOGIC("Parent vertex-" << m_vertexId << " deleting its child vertex-"
157 << p->GetVertexId());
158 delete p;
159 p = nullptr;
160 }
161 m_children.clear();
162 // delete parents
163 m_parents.clear();
164 // delete root exit direction
165 m_ecmpRootExits.clear();
166
167 NS_LOG_LOGIC("Vertex-" << m_vertexId << " completed deleted");
168}
169
170void
172{
173 NS_LOG_FUNCTION(this << type);
174 m_vertexType = type;
175}
176
179{
180 NS_LOG_FUNCTION(this);
181 return m_vertexType;
182}
183
184void
186{
187 NS_LOG_FUNCTION(this << id);
188 m_vertexId = id;
189}
190
193{
194 NS_LOG_FUNCTION(this);
195 return m_vertexId;
196}
197
198void
200{
201 NS_LOG_FUNCTION(this << lsa);
202 m_lsa = lsa;
203}
204
207{
208 NS_LOG_FUNCTION(this);
209 return m_lsa;
210}
211
212void
214{
215 NS_LOG_FUNCTION(this << distance);
216 m_distanceFromRoot = distance;
217}
218
225
226void
228{
229 NS_LOG_FUNCTION(this << parent);
230
231 // always maintain only one parent when using setter/getter methods
232 m_parents.clear();
233 m_parents.push_back(parent);
234}
235
238{
239 NS_LOG_FUNCTION(this << i);
240
241 // If the index i is out-of-range, return 0 and do nothing
242 if (m_parents.size() <= i)
243 {
244 NS_LOG_LOGIC("Index to SPFVertex's parent is out-of-range.");
245 return nullptr;
246 }
247 auto iter = m_parents.begin();
248 while (i-- > 0)
249 {
250 iter++;
251 }
252 return *iter;
253}
254
255void
257{
258 NS_LOG_FUNCTION(this << v);
259
260 NS_LOG_LOGIC("Before merge, list of parents = " << m_parents);
261 // combine the two lists first, and then remove any duplicated after
262 m_parents.insert(m_parents.end(), v->m_parents.begin(), v->m_parents.end());
263 // remove duplication
264 m_parents.sort();
265 m_parents.unique();
266 NS_LOG_LOGIC("After merge, list of parents = " << m_parents);
267}
268
269void
271{
272 NS_LOG_FUNCTION(this << nextHop << id);
273
274 // always maintain only one root's exit
275 m_ecmpRootExits.clear();
276 m_ecmpRootExits.emplace_back(nextHop, id);
277 // update the following in order to be backward compatible with
278 // GetNextHop and GetOutgoingInterface methods
279 m_nextHop = nextHop;
280 m_rootOif = id;
281}
282
283void
285{
286 NS_LOG_FUNCTION(this << exit);
287 SetRootExitDirection(exit.first, exit.second);
288}
289
292{
293 NS_LOG_FUNCTION(this << i);
294
296 "Index out-of-range when accessing SPFVertex::m_ecmpRootExits!");
297 auto iter = m_ecmpRootExits.begin();
298 while (i-- > 0)
299 {
300 iter++;
301 }
302
303 return *iter;
304}
305
308{
309 NS_LOG_FUNCTION(this);
310
311 NS_ASSERT_MSG(m_ecmpRootExits.size() <= 1,
312 "Assumed there is at most one exit from the root to this vertex");
313 return GetRootExitDirection(0);
314}
315
316void
318{
319 NS_LOG_FUNCTION(this << vertex);
320
321 // obtain the external list of exit directions
322 //
323 // Append the external list into 'this' and remove duplication afterward
324 const ListOfNodeExit_t& extList = vertex->m_ecmpRootExits;
325 m_ecmpRootExits.insert(m_ecmpRootExits.end(), extList.begin(), extList.end());
326 m_ecmpRootExits.sort();
327 m_ecmpRootExits.unique();
328}
329
330void
332{
333 NS_LOG_FUNCTION(this << vertex);
334
335 // discard all exit direction currently associated with this vertex,
336 // and copy all the exit directions from the given vertex
337 if (!m_ecmpRootExits.empty())
338 {
339 NS_LOG_WARN("x root exit directions in this vertex are going to be discarded");
340 }
341 m_ecmpRootExits.clear();
342 m_ecmpRootExits.insert(m_ecmpRootExits.end(),
343 vertex->m_ecmpRootExits.begin(),
344 vertex->m_ecmpRootExits.end());
345}
346
349{
350 NS_LOG_FUNCTION(this);
351 return m_ecmpRootExits.size();
352}
353
356{
357 NS_LOG_FUNCTION(this);
358 return m_children.size();
359}
360
363{
364 NS_LOG_FUNCTION(this << n);
365 uint32_t j = 0;
366
367 for (auto i = m_children.begin(); i != m_children.end(); i++, j++)
368 {
369 if (j == n)
370 {
371 return *i;
372 }
373 }
374 NS_ASSERT_MSG(false, "Index <n> out of range.");
375 return nullptr;
376}
377
380{
381 NS_LOG_FUNCTION(this << child);
382 m_children.push_back(child);
383 return m_children.size();
384}
385
386void
388{
389 NS_LOG_FUNCTION(this << value);
390 m_vertexProcessed = value;
391}
392
393bool
395{
396 NS_LOG_FUNCTION(this);
397 return m_vertexProcessed;
398}
399
400void
402{
403 NS_LOG_FUNCTION(this);
404 for (uint32_t i = 0; i < this->GetNChildren(); i++)
405 {
406 this->GetChild(i)->ClearVertexProcessed();
407 }
408 this->SetVertexProcessed(false);
409}
410
413{
414 return m_node;
415}
416
417// ---------------------------------------------------------------------------
418//
419// GlobalRouteManagerLSDB Implementation
420//
421// ---------------------------------------------------------------------------
422
429
431{
432 NS_LOG_FUNCTION(this);
433 for (auto i = m_database.begin(); i != m_database.end(); i++)
434 {
435 NS_LOG_LOGIC("free LSA");
436 GlobalRoutingLSA* temp = i->second;
437 delete temp;
438 }
439 for (uint32_t j = 0; j < m_extdatabase.size(); j++)
440 {
441 NS_LOG_LOGIC("free ASexternalLSA");
442 GlobalRoutingLSA* temp = m_extdatabase.at(j);
443 delete temp;
444 }
445 NS_LOG_LOGIC("clear map");
446 m_database.clear();
447}
448
449void
451{
452 NS_LOG_FUNCTION(this);
453 for (auto i = m_database.begin(); i != m_database.end(); i++)
454 {
455 GlobalRoutingLSA* temp = i->second;
457 }
458}
459
460void
462{
463 NS_LOG_FUNCTION(this << addr << lsa);
465 {
466 m_extdatabase.push_back(lsa);
467 }
468 else
469 {
470 m_database.insert(LSDBPair_t(addr, lsa));
471 }
472}
473
476{
477 NS_LOG_FUNCTION(this << index);
478 return m_extdatabase.at(index);
479}
480
483{
484 NS_LOG_FUNCTION(this);
485 return m_extdatabase.size();
486}
487
490{
491 NS_LOG_FUNCTION(this << addr);
492 //
493 // Look up an LSA by its address.
494 //
495 for (auto i = m_database.begin(); i != m_database.end(); i++)
496 {
497 if (i->first == addr)
498 {
499 return i->second;
500 }
501 }
502 return nullptr;
503}
504
507{
508 NS_LOG_FUNCTION(this << addr);
509 //
510 // Look up an LSA by its address.
511 //
512 for (auto i = m_database.begin(); i != m_database.end(); i++)
513 {
514 GlobalRoutingLSA* temp = i->second;
515 // Iterate among temp's Link Records
516 for (uint32_t j = 0; j < temp->GetNLinkRecords(); j++)
517 {
520 lr->GetLinkData() == addr)
521 {
522 return temp;
523 }
524 }
525 }
526 return nullptr;
527}
528
529// ---------------------------------------------------------------------------
530//
531// GlobalRouteManagerImpl Implementation
532//
533// ---------------------------------------------------------------------------
534
541
543{
544 NS_LOG_FUNCTION(this);
545 if (m_lsdb)
546 {
547 delete m_lsdb;
548 }
549}
550
551void
553{
554 NS_LOG_FUNCTION(this << lsdb);
555 if (m_lsdb)
556 {
557 delete m_lsdb;
558 }
559 m_lsdb = lsdb;
560}
561
562void
564{
565 NS_LOG_FUNCTION(this);
566 for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
567 {
568 Ptr<Node> node = *i;
569 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
570 if (!router)
571 {
572 continue;
573 }
574 Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol();
575 uint32_t j = 0;
576 uint32_t nRoutes = gr->GetNRoutes();
577 NS_LOG_LOGIC("Deleting " << gr->GetNRoutes() << " routes from node " << node->GetId());
578 // Each time we delete route 0, the route index shifts downward
579 // We can delete all routes if we delete the route numbered 0
580 // nRoutes times
581 for (j = 0; j < nRoutes; j++)
582 {
583 NS_LOG_LOGIC("Deleting global route " << j << " from node " << node->GetId());
584 gr->RemoveRoute(0);
585 }
586 NS_LOG_LOGIC("Deleted " << j << " global routes from node " << node->GetId());
587 }
588 if (m_lsdb)
589 {
590 NS_LOG_LOGIC("Deleting LSDB, creating new one");
591 delete m_lsdb;
593 }
594}
595
596//
597// In order to build the routing database, we need to walk the list of nodes
598// in the system and look for those that support the GlobalRouter interface.
599// These routers will export a number of Link State Advertisements (LSAs)
600// that describe the links and networks that are "adjacent" (i.e., that are
601// on the other side of a point-to-point link). We take these LSAs and put
602// add them to the Link State DataBase (LSDB) from which the routes will
603// ultimately be computed.
604//
605void
607{
608 NS_LOG_FUNCTION(this);
609 //
610 // Walk the list of nodes looking for the GlobalRouter Interface. Nodes with
611 // global router interfaces are, not too surprisingly, our routers.
612 //
613 for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
614 {
615 Ptr<Node> node = *i;
616
617 Ptr<GlobalRouter> rtr = node->GetObject<GlobalRouter>();
618 //
619 // Ignore nodes that aren't participating in routing.
620 //
621 if (!rtr)
622 {
623 continue;
624 }
625 //
626 // You must call DiscoverLSAs () before trying to use any routing info or to
627 // update LSAs. DiscoverLSAs () drives the process of discovering routes in
628 // the GlobalRouter. Afterward, you may use GetNumLSAs (), which is a very
629 // computationally inexpensive call. If you call GetNumLSAs () before calling
630 // DiscoverLSAs () will get zero as the number since no routes have been
631 // found.
632 //
633 Ptr<Ipv4GlobalRouting> grouting = rtr->GetRoutingProtocol();
634 uint32_t numLSAs = rtr->DiscoverLSAs();
635 NS_LOG_LOGIC("Found " << numLSAs << " LSAs");
636
637 for (uint32_t j = 0; j < numLSAs; ++j)
638 {
639 auto lsa = new GlobalRoutingLSA();
640 //
641 // This is the call to actually fetch a Link State Advertisement from the
642 // router.
643 //
644 rtr->GetLSA(j, *lsa);
645 NS_LOG_LOGIC(*lsa);
646 //
647 // Write the newly discovered link state advertisement to the database.
648 //
649 m_lsdb->Insert(lsa->GetLinkStateId(), lsa);
650 }
651 }
652}
653
654//
655// For each node that is a global router (which is determined by the presence
656// of an aggregated GlobalRouter interface), run the Dijkstra SPF calculation
657// on the database rooted at that router, and populate the node forwarding
658// tables.
659//
660// This function parallels RFC2328, Section 16.1.1, and quagga ospfd
661//
662// This calculation yields the set of intra-area routes associated
663// with an area (called hereafter Area A). A router calculates the
664// shortest-path tree using itself as the root. The formation
665// of the shortest path tree is done here in two stages. In the
666// first stage, only links between routers and transit networks are
667// considered. Using the Dijkstra algorithm, a tree is formed from
668// this subset of the link state database. In the second stage,
669// leaves are added to the tree by considering the links to stub
670// networks.
671//
672// The area's link state database is represented as a directed graph.
673// The graph's vertices are routers, transit networks and stub networks.
674//
675// The first stage of the procedure (i.e., the Dijkstra algorithm)
676// can now be summarized as follows. At each iteration of the
677// algorithm, there is a list of candidate vertices. Paths from
678// the root to these vertices have been found, but not necessarily
679// the shortest ones. However, the paths to the candidate vertex
680// that is closest to the root are guaranteed to be shortest; this
681// vertex is added to the shortest-path tree, removed from the
682// candidate list, and its adjacent vertices are examined for
683// possible addition to/modification of the candidate list. The
684// algorithm then iterates again. It terminates when the candidate
685// list becomes empty.
686//
687void
689{
690 NS_LOG_FUNCTION(this);
691 //
692 // Walk the list of nodes in the system.
693 //
694 NS_LOG_INFO("About to start SPF calculation");
695 for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
696 {
697 Ptr<Node> node = *i;
698 //
699 // Look for the GlobalRouter interface that indicates that the node is
700 // participating in routing.
701 //
702 Ptr<GlobalRouter> rtr = node->GetObject<GlobalRouter>();
703
704 uint32_t systemId = Simulator::GetSystemId();
705 // Ignore nodes that are not assigned to our systemId (distributed sim)
706 if (node->GetSystemId() != systemId)
707 {
708 continue;
709 }
710
711 //
712 // if the node has a global router interface, then run the global routing
713 // algorithms.
714 //
715 if (rtr && rtr->GetNumLSAs())
716 {
717 SPFCalculate(rtr->GetRouterId());
718 }
719 }
720 NS_LOG_INFO("Finished SPF calculation");
721}
722
723//
724// This method is derived from quagga ospf_spf_next (). See RFC2328 Section
725// 16.1 (2) for further details.
726//
727// We're passed a parameter <v> that is a vertex which is already in the SPF
728// tree. A vertex represents a router node. We also get a reference to the
729// SPF candidate queue, which is a priority queue containing the shortest paths
730// to the networks we know about.
731//
732// We examine the links in v's LSA and update the list of candidates with any
733// vertices not already on the list. If a lower-cost path is found to a
734// vertex already on the candidate list, store the new (lower) cost.
735//
736void
738{
739 NS_LOG_FUNCTION(this << v << &candidate);
740
741 SPFVertex* w = nullptr;
742 GlobalRoutingLSA* w_lsa = nullptr;
743 GlobalRoutingLinkRecord* l = nullptr;
744 uint32_t distance = 0;
745 uint32_t numRecordsInVertex = 0;
746 //
747 // V points to a Router-LSA or Network-LSA
748 // Loop over the links in router LSA or attached routers in Network LSA
749 //
750 if (v->GetVertexType() == SPFVertex::VertexRouter)
751 {
752 numRecordsInVertex = v->GetLSA()->GetNLinkRecords();
753 }
754 if (v->GetVertexType() == SPFVertex::VertexNetwork)
755 {
756 numRecordsInVertex = v->GetLSA()->GetNAttachedRouters();
757 }
758
759 // Loop over the links in V's LSA
760 for (uint32_t i = 0; i < numRecordsInVertex; i++)
761 {
762 // Get w_lsa: In case of V is Router-LSA
763 if (v->GetVertexType() == SPFVertex::VertexRouter)
764 {
765 NS_LOG_LOGIC("Examining link " << i << " of " << v->GetVertexId() << "'s "
766 << v->GetLSA()->GetNLinkRecords() << " link records");
767 //
768 // (a) If this is a link to a stub network, examine the next link in V's LSA.
769 // Links to stub networks will be considered in the second stage of the
770 // shortest path calculation.
771 //
772 l = v->GetLSA()->GetLinkRecord(i);
773 NS_ASSERT(l != nullptr);
775 {
776 NS_LOG_LOGIC("Found a Stub record to " << l->GetLinkId());
777 continue;
778 }
779 //
780 // (b) Otherwise, W is a transit vertex (router or transit network). Look up
781 // the vertex W's LSA (router-LSA or network-LSA) in Area A's link state
782 // database.
783 //
785 {
786 //
787 // Lookup the link state advertisement of the new link -- we call it <w> in
788 // the link state database.
789 //
790 w_lsa = m_lsdb->GetLSA(l->GetLinkId());
791 NS_ASSERT(w_lsa);
792 NS_LOG_LOGIC("Found a P2P record from " << v->GetVertexId() << " to "
793 << w_lsa->GetLinkStateId());
794 }
796 {
797 w_lsa = m_lsdb->GetLSA(l->GetLinkId());
798 NS_ASSERT(w_lsa);
799 NS_LOG_LOGIC("Found a Transit record from " << v->GetVertexId() << " to "
800 << w_lsa->GetLinkStateId());
801 }
802 else
803 {
804 NS_ASSERT_MSG(0, "illegal Link Type");
805 }
806 }
807 // Get w_lsa: In case of V is Network-LSA
808 if (v->GetVertexType() == SPFVertex::VertexNetwork)
809 {
810 w_lsa = m_lsdb->GetLSAByLinkData(v->GetLSA()->GetAttachedRouter(i));
811 if (!w_lsa)
812 {
813 continue;
814 }
815 NS_LOG_LOGIC("Found a Network LSA from " << v->GetVertexId() << " to "
816 << w_lsa->GetLinkStateId());
817 }
818
819 // Note: w_lsa at this point may be either RouterLSA or NetworkLSA
820 //
821 // (c) If vertex W is already on the shortest-path tree, examine the next
822 // link in the LSA.
823 //
824 // If the link is to a router that is already in the shortest path first tree
825 // then we have it covered -- ignore it.
826 //
828 {
829 NS_LOG_LOGIC("Skipping -> LSA " << w_lsa->GetLinkStateId() << " already in SPF tree");
830 continue;
831 }
832 //
833 // (d) Calculate the link state cost D of the resulting path from the root to
834 // vertex W. D is equal to the sum of the link state cost of the (already
835 // calculated) shortest path to vertex V and the advertised cost of the link
836 // between vertices V and W.
837 //
838 if (v->GetLSA()->GetLSType() == GlobalRoutingLSA::RouterLSA)
839 {
840 NS_ASSERT(l != nullptr);
841 distance = v->GetDistanceFromRoot() + l->GetMetric();
842 }
843 else
844 {
845 distance = v->GetDistanceFromRoot();
846 }
847
848 NS_LOG_LOGIC("Considering w_lsa " << w_lsa->GetLinkStateId());
849
850 // Is there already vertex w in candidate list?
852 {
853 // Calculate nexthop to w
854 // We need to figure out how to actually get to the new router represented
855 // by <w>. This will (among other things) find the next hop address to send
856 // packets destined for this network to, and also find the outbound interface
857 // used to forward the packets.
858
859 // prepare vertex w
860 w = new SPFVertex(w_lsa);
861 if (SPFNexthopCalculation(v, w, l, distance))
862 {
864 //
865 // Push this new vertex onto the priority queue (ordered by distance from the
866 // root node).
867 //
868 candidate.Push(w);
869 NS_LOG_LOGIC("Pushing " << w->GetVertexId()
870 << ", parent vertexId: " << v->GetVertexId()
871 << ", distance: " << w->GetDistanceFromRoot());
872 }
873 else
874 {
875 NS_ASSERT_MSG(0, "SPFNexthopCalculation never return false, but it does now!");
876 }
877 }
879 {
880 //
881 // We have already considered the link represented by <w>. What wse have to
882 // do now is to decide if this new router represents a route with a shorter
883 // distance metric.
884 //
885 // So, locate the vertex in the candidate queue and take a look at the
886 // distance.
887
888 /* (quagga-0.98.6) W is already on the candidate list; call it cw.
889 * Compare the previously calculated cost (cw->distance)
890 * with the cost we just determined (w->distance) to see
891 * if we've found a shorter path.
892 */
893 SPFVertex* cw;
894 cw = candidate.Find(w_lsa->GetLinkStateId());
895 if (cw->GetDistanceFromRoot() < distance)
896 {
897 //
898 // This is not a shorter path, so don't do anything.
899 //
900 continue;
901 }
902 else if (cw->GetDistanceFromRoot() == distance)
903 {
904 //
905 // This path is one with an equal cost.
906 //
907 NS_LOG_LOGIC("Equal cost multiple paths found.");
908
909 // At this point, there are two instances 'w' and 'cw' of the
910 // same vertex, the vertex that is currently being considered
911 // for adding into the shortest path tree. 'w' is the instance
912 // as seen from the root via vertex 'v', and 'cw' is the instance
913 // as seen from the root via some other vertices other than 'v'.
914 // These two instances are being merged in the following code.
915 // In particular, the parent nodes, the next hops, and the root's
916 // output interfaces of the two instances are being merged.
917 //
918 // Note that this is functionally equivalent to calling
919 // ospf_nexthop_merge (cw->nexthop, w->nexthop) in quagga-0.98.6
920 // (ospf_spf.c::859), although the detail implementation
921 // is very different from quagga (blame ns3::GlobalRouteManagerImpl)
922
923 // prepare vertex w
924 w = new SPFVertex(w_lsa);
925 SPFNexthopCalculation(v, w, l, distance);
927 cw->MergeParent(w);
928 // SPFVertexAddParent (w) is necessary as the destructor of
929 // SPFVertex checks if the vertex and its parent is linked
930 // bidirectionally
932 delete w;
933 }
934 else // cw->GetDistanceFromRoot () > w->GetDistanceFromRoot ()
935 {
936 //
937 // this path represents a new, lower-cost path to <w> (the vertex we found in
938 // the current link record of the link state advertisement of the current root
939 // (vertex <v>)
940 //
941 // N.B. the nexthop_calculation is conditional, if it finds a valid nexthop
942 // it will call spf_add_parents, which will flush the old parents
943 //
944 if (SPFNexthopCalculation(v, cw, l, distance))
945 {
946 //
947 // If we've changed the cost to get to the vertex represented by <w>, we
948 // must reorder the priority queue keyed to that cost.
949 //
950 candidate.Reorder();
951 }
952 }
953 }
954 }
955}
956
957//
958// This method is derived from quagga ospf_nexthop_calculation() 16.1.1.
959//
960// Calculate nexthop from root through V (parent) to vertex W (destination)
961// with given distance from root->W.
962//
963// As appropriate, set w's parent, distance, and nexthop information
964//
965// For now, this is greatly simplified from the quagga code
966//
967int
969 SPFVertex* w,
971 uint32_t distance)
972{
973 NS_LOG_FUNCTION(this << v << w << l << distance);
974 //
975 // If w is a NetworkVertex, l should be null
976 /*
977 if (w->GetVertexType () == SPFVertex::VertexNetwork && l)
978 {
979 NS_ASSERT_MSG (0, "Error: SPFNexthopCalculation parameter problem");
980 }
981 */
982
983 //
984 // The vertex m_spfroot is a distinguished vertex representing the node at
985 // the root of the calculations. That is, it is the node for which we are
986 // calculating the routes.
987 //
988 // There are two distinct cases for calculating the next hop information.
989 // First, if we're considering a hop from the root to an "adjacent" network
990 // (one that is on the other side of a point-to-point link connected to the
991 // root), then we need to store the information needed to forward down that
992 // link. The second case is if the network is not directly adjacent. In that
993 // case we need to use the forwarding information from the vertex on the path
994 // to the destination that is directly adjacent [node 1] in both cases of the
995 // diagram below.
996 //
997 // (1) [root] -> [point-to-point] -> [node 1]
998 // (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2]
999 //
1000 // We call the propagation of next hop information down vertices of a path
1001 // "inheriting" the next hop information.
1002 //
1003 // The point-to-point link information is only useful in this calculation when
1004 // we are examining the root node.
1005 //
1006 if (v == m_spfroot)
1007 {
1008 //
1009 // In this case <v> is the root node, which means it is the starting point
1010 // for the packets forwarded by that node. This also means that the next hop
1011 // address of packets headed for some arbitrary off-network destination must
1012 // be the destination at the other end of one of the links off of the root
1013 // node if this root node is a router. We then need to see if this node <w>
1014 // is a router.
1015 //
1017 {
1018 //
1019 // In the case of point-to-point links, the link data field (m_linkData) of a
1020 // Global Router Link Record contains the local IP address. If we look at the
1021 // link record describing the link from the perspective of <w> (the remote
1022 // node from the viewpoint of <v>) back to the root node, we can discover the
1023 // IP address of the router to which <v> is adjacent. This is a distinguished
1024 // address -- the next hop address to get from <v> to <w> and all networks
1025 // accessed through that path.
1026 //
1027 // SPFGetNextLink () is a little odd. used in this way it is just going to
1028 // return the link record describing the link from <w> to <v>. Think of it as
1029 // SPFGetLink.
1030 //
1031 NS_ASSERT(l);
1032 GlobalRoutingLinkRecord* linkRemote = nullptr;
1033 linkRemote = SPFGetNextLink(w, v, linkRemote);
1034 //
1035 // At this point, <l> is the Global Router Link Record describing the point-
1036 // to point link from <v> to <w> from the perspective of <v>; and <linkRemote>
1037 // is the Global Router Link Record describing that same link from the
1038 // perspective of <w> (back to <v>). Now we can just copy the next hop
1039 // address from the m_linkData member variable.
1040 //
1041 // The next hop member variable we put in <w> has the sense "in order to get
1042 // from the root node to the host represented by vertex <w>, you have to send
1043 // the packet to the next hop address specified in w->m_nextHop.
1044 //
1045 Ipv4Address nextHop = linkRemote->GetLinkData();
1046 //
1047 // Now find the outgoing interface corresponding to the point to point link
1048 // from the perspective of <v> -- remember that <l> is the link "from"
1049 // <v> "to" <w>.
1050 //
1052
1053 w->SetRootExitDirection(nextHop, outIf);
1054 w->SetDistanceFromRoot(distance);
1055 w->SetParent(v);
1056 NS_LOG_LOGIC("Next hop from " << v->GetVertexId() << " to " << w->GetVertexId()
1057 << " goes through next hop " << nextHop
1058 << " via outgoing interface " << outIf
1059 << " with distance " << distance);
1060 }
1061 else
1062 {
1064 // W is a directly connected network; no next hop is required
1065 GlobalRoutingLSA* w_lsa = w->GetLSA();
1067 // Find outgoing interface ID for this network
1068 uint32_t outIf =
1070 // Set the next hop to 0.0.0.0 meaning "not exist"
1072 w->SetRootExitDirection(nextHop, outIf);
1073 w->SetDistanceFromRoot(distance);
1074 w->SetParent(v);
1075 NS_LOG_LOGIC("Next hop from " << v->GetVertexId() << " to network " << w->GetVertexId()
1076 << " via outgoing interface " << outIf
1077 << " with distance " << distance);
1078 return 1;
1079 }
1080 }
1081 else if (v->GetVertexType() == SPFVertex::VertexNetwork)
1082 {
1083 // See if any of v's parents are the root
1084 if (v->GetParent() == m_spfroot)
1085 {
1086 // 16.1.1 para 5. ...the parent vertex is a network that
1087 // directly connects the calculating router to the destination
1088 // router. The list of next hops is then determined by
1089 // examining the destination's router-LSA...
1091 GlobalRoutingLinkRecord* linkRemote = nullptr;
1092 while ((linkRemote = SPFGetNextLink(w, v, linkRemote)))
1093 {
1094 /* ...For each link in the router-LSA that points back to the
1095 * parent network, the link's Link Data field provides the IP
1096 * address of a next hop router. The outgoing interface to
1097 * use can then be derived from the next hop IP address (or
1098 * it can be inherited from the parent network).
1099 */
1100 Ipv4Address nextHop = linkRemote->GetLinkData();
1101 uint32_t outIf = v->GetRootExitDirection().second;
1102 w->SetRootExitDirection(nextHop, outIf);
1103 NS_LOG_LOGIC("Next hop from " << v->GetVertexId() << " to " << w->GetVertexId()
1104 << " goes through next hop " << nextHop
1105 << " via outgoing interface " << outIf);
1106 }
1107 }
1108 else
1109 {
1111 }
1112 }
1113 else
1114 {
1115 //
1116 // If we're calculating the next hop information from a node (v) that is
1117 // *not* the root, then we need to "inherit" the information needed to
1118 // forward the packet from the vertex closer to the root. That is, we'll
1119 // still send packets to the next hop address of the router adjacent to the
1120 // root on the path toward <w>.
1121 //
1122 // Above, when we were considering the root node, we calculated the next hop
1123 // address and outgoing interface required to get off of the root network.
1124 // At this point, we are further away from the root network along one of the
1125 // (shortest) paths. So the next hop and outgoing interface remain the same
1126 // (are inherited).
1127 //
1129 }
1130 //
1131 // In all cases, we need valid values for the distance metric and a parent.
1132 //
1133 w->SetDistanceFromRoot(distance);
1134 w->SetParent(v);
1135
1136 return 1;
1137}
1138
1139//
1140// This method is derived from quagga ospf_get_next_link ()
1141//
1142// First search the Global Router Link Records of vertex <v> for one
1143// representing a point-to point link to vertex <w>.
1144//
1145// What is done depends on prev_link. Contrary to appearances, prev_link just
1146// acts as a flag here. If prev_link is NULL, we return the first Global
1147// Router Link Record we find that describes a point-to-point link from <v>
1148// to <w>. If prev_link is not NULL, we return a Global Router Link Record
1149// representing a possible *second* link from <v> to <w>.
1150//
1153 SPFVertex* w,
1154 GlobalRoutingLinkRecord* prev_link)
1155{
1156 NS_LOG_FUNCTION(this << v << w << prev_link);
1157
1158 bool skip = true;
1159 bool found_prev_link = false;
1161 //
1162 // If prev_link is 0, we are really looking for the first link, not the next
1163 // link.
1164 //
1165 if (prev_link == nullptr)
1166 {
1167 skip = false;
1168 found_prev_link = true;
1169 }
1170 //
1171 // Iterate through the Global Router Link Records advertised by the vertex
1172 // <v> looking for records representing the point-to-point links off of this
1173 // vertex.
1174 //
1175 for (uint32_t i = 0; i < v->GetLSA()->GetNLinkRecords(); ++i)
1176 {
1177 l = v->GetLSA()->GetLinkRecord(i);
1178 //
1179 // The link ID of a link record representing a point-to-point link is set to
1180 // the router ID of the neighboring router -- the router to which the link
1181 // connects from the perspective of <v> in this case. The vertex ID is also
1182 // set to the router ID (using the link state advertisement of a router node).
1183 // We're just checking to see if the link <l> is actually the link from <v> to
1184 // <w>.
1185 //
1186 if (l->GetLinkId() == w->GetVertexId())
1187 {
1188 if (!found_prev_link)
1189 {
1190 NS_LOG_LOGIC("Skipping links before prev_link found");
1191 found_prev_link = true;
1192 continue;
1193 }
1194
1195 NS_LOG_LOGIC("Found matching link l: linkId = " << l->GetLinkId()
1196 << " linkData = " << l->GetLinkData());
1197 //
1198 // If skip is false, don't (not too surprisingly) skip the link found -- it's
1199 // the one we're interested in. That's either because we didn't pass in a
1200 // previous link, and we're interested in the first one, or because we've
1201 // skipped a previous link and moved forward to the next (which is then the
1202 // one we want).
1203 //
1204 if (!skip)
1205 {
1206 NS_LOG_LOGIC("Returning the found link");
1207 return l;
1208 }
1209 else
1210 {
1211 //
1212 // Skip is true and we've found a link from <v> to <w>. We want the next one.
1213 // Setting skip to false gets us the next point-to-point global router link
1214 // record in the LSA from <v>.
1215 //
1216 NS_LOG_LOGIC("Skipping the found link");
1217 skip = false;
1218 continue;
1219 }
1220 }
1221 }
1222 return nullptr;
1223}
1224
1225//
1226// Used for unit tests.
1227//
1228void
1234
1235//
1236// Used to test if a node is a stub, from an OSPF sense.
1237// If there is only one link of type 1 or 2, then a default route
1238// can safely be added to the next-hop router and SPF does not need
1239// to be run
1240//
1241bool
1243{
1244 NS_LOG_FUNCTION(this << root);
1245 GlobalRoutingLSA* rlsa = m_lsdb->GetLSA(root);
1246 Ipv4Address myRouterId = rlsa->GetLinkStateId();
1247 int transits = 0;
1248 GlobalRoutingLinkRecord* transitLink = nullptr;
1249 for (uint32_t i = 0; i < rlsa->GetNLinkRecords(); i++)
1250 {
1254 {
1255 transits++;
1256 transitLink = l;
1257 }
1258 }
1259 if (transits == 0)
1260 {
1261 // This router is not connected to any router. Probably, global
1262 // routing should not be called for this node, but we can just raise
1263 // a warning here and return true.
1264 NS_LOG_WARN("all nodes should have at least one transit link:" << root);
1265 return true;
1266 }
1267 if (transits == 1)
1268 {
1270 {
1271 // Install default route to next hop router
1272 // What is the next hop? We need to check all neighbors on the link.
1273 // If there is a single router that has two transit links, then
1274 // that is the default next hop. If there are more than one
1275 // routers on link with multiple transit links, return false.
1276 // Not yet implemented, so simply return false
1277 NS_LOG_LOGIC("TBD: Would have inserted default for transit");
1278 return false;
1279 }
1280 else if (transitLink->GetLinkType() == GlobalRoutingLinkRecord::PointToPoint)
1281 {
1282 // Install default route to next hop
1283 // The link record LinkID is the router ID of the peer.
1284 // The Link Data is the local IP interface address
1285 GlobalRoutingLSA* w_lsa = m_lsdb->GetLSA(transitLink->GetLinkId());
1286 uint32_t nLinkRecords = w_lsa->GetNLinkRecords();
1287 for (uint32_t j = 0; j < nLinkRecords; ++j)
1288 {
1289 //
1290 // We are only concerned about point-to-point links
1291 //
1292 GlobalRoutingLinkRecord* lr = w_lsa->GetLinkRecord(j);
1294 {
1295 continue;
1296 }
1297 // Find the link record that corresponds to our routerId
1298 if (lr->GetLinkId() == myRouterId)
1299 {
1300 // Next hop is stored in the LinkID field of lr
1301 Ptr<GlobalRouter> router = rlsa->GetNode()->GetObject<GlobalRouter>();
1302 NS_ASSERT(router);
1303 Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol();
1304 NS_ASSERT(gr);
1305 gr->AddNetworkRouteTo(Ipv4Address("0.0.0.0"),
1306 Ipv4Mask("0.0.0.0"),
1307 lr->GetLinkData(),
1308 FindOutgoingInterfaceId(transitLink->GetLinkData()));
1309 NS_LOG_LOGIC("Inserting default route for node "
1310 << myRouterId << " to next hop " << lr->GetLinkData()
1311 << " via interface "
1312 << FindOutgoingInterfaceId(transitLink->GetLinkData()));
1313 return true;
1314 }
1315 }
1316 }
1317 }
1318 return false;
1319}
1320
1321// quagga ospf_spf_calculate
1322void
1324{
1325 NS_LOG_FUNCTION(this << root);
1326
1327 SPFVertex* v;
1328 //
1329 // Initialize the Link State Database.
1330 //
1331 m_lsdb->Initialize();
1332 //
1333 // The candidate queue is a priority queue of SPFVertex objects, with the top
1334 // of the queue being the closest vertex in terms of distance from the root
1335 // of the tree. Initially, this queue is empty.
1336 //
1337 CandidateQueue candidate;
1338 NS_ASSERT(candidate.Size() == 0);
1339 //
1340 // Initialize the shortest-path tree to only contain the router doing the
1341 // calculation. Each router (and corresponding network) is a vertex in the
1342 // shortest path first (SPF) tree.
1343 //
1344 v = new SPFVertex(m_lsdb->GetLSA(root));
1345 //
1346 // This vertex is the root of the SPF tree and it is distance 0 from the root.
1347 // We also mark this vertex as being in the SPF tree.
1348 //
1349 m_spfroot = v;
1350 v->SetDistanceFromRoot(0);
1351 v->GetLSA()->SetStatus(GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
1352 NS_LOG_LOGIC("Starting SPFCalculate for node " << root);
1353
1354 //
1355 // Optimize SPF calculation, for ns-3.
1356 // We do not need to calculate SPF for every node in the network if this
1357 // node has only one interface through which another router can be
1358 // reached. Instead, short-circuit this computation and just install
1359 // a default route in the CheckForStubNode() method.
1360 //
1361 if (NodeList::GetNNodes() > 0 && CheckForStubNode(root))
1362 {
1363 NS_LOG_LOGIC("SPFCalculate truncated for stub node " << root);
1364 delete m_spfroot;
1365 return;
1366 }
1367
1368 for (;;)
1369 {
1370 //
1371 // The operations we need to do are given in the OSPF RFC which we reference
1372 // as we go along.
1373 //
1374 // RFC2328 16.1. (2).
1375 //
1376 // We examine the Global Router Link Records in the Link State
1377 // Advertisements of the current vertex. If there are any point-to-point
1378 // links to unexplored adjacent vertices we add them to the tree and update
1379 // the distance and next hop information on how to get there. We also add
1380 // the new vertices to the candidate queue (the priority queue ordered by
1381 // shortest path). If the new vertices represent shorter paths, we use them
1382 // and update the path cost.
1383 //
1384 SPFNext(v, candidate);
1385 //
1386 // RFC2328 16.1. (3).
1387 //
1388 // If at this step the candidate list is empty, the shortest-path tree (of
1389 // transit vertices) has been completely built and this stage of the
1390 // procedure terminates.
1391 //
1392 if (candidate.Size() == 0)
1393 {
1394 break;
1395 }
1396 //
1397 // Choose the vertex belonging to the candidate list that is closest to the
1398 // root, and add it to the shortest-path tree (removing it from the candidate
1399 // list in the process).
1400 //
1401 // Recall that in the previous step, we created SPFVertex structures for each
1402 // of the routers found in the Global Router Link Records and added tehm to
1403 // the candidate list.
1404 //
1405 NS_LOG_LOGIC(candidate);
1406 v = candidate.Pop();
1407 NS_LOG_LOGIC("Popped vertex " << v->GetVertexId());
1408 //
1409 // Update the status field of the vertex to indicate that it is in the SPF
1410 // tree.
1411 //
1412 v->GetLSA()->SetStatus(GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
1413 //
1414 // The current vertex has a parent pointer. By calling this rather oddly
1415 // named method (blame quagga) we add the current vertex to the list of
1416 // children of that parent vertex. In the next hop calculation called during
1417 // SPFNext, the parent pointer was set but the vertex has been orphaned up
1418 // to now.
1419 //
1421 //
1422 // Note that when there is a choice of vertices closest to the root, network
1423 // vertices must be chosen before router vertices in order to necessarily
1424 // find all equal-cost paths.
1425 //
1426 // RFC2328 16.1. (4).
1427 //
1428 // This is the method that actually adds the routes. It'll walk the list
1429 // of nodes in the system, looking for the node corresponding to the router
1430 // ID of the root of the tree -- that is the router we're building the routes
1431 // for. It looks for the Ipv4 interface of that node and remembers it. So
1432 // we are only actually adding routes to that one node at the root of the SPF
1433 // tree.
1434 //
1435 // We're going to pop of a pointer to every vertex in the tree except the
1436 // root in order of distance from the root. For each of the vertices, we call
1437 // SPFIntraAddRouter (). Down in SPFIntraAddRouter, we look at all of the
1438 // point-to-point Global Router Link Records (the links to nodes adjacent to
1439 // the node represented by the vertex). We add a route to the IP address
1440 // specified by the m_linkData field of each of those link records. This will
1441 // be the *local* IP address associated with the interface attached to the
1442 // link. We use the outbound interface and next hop information present in
1443 // the vertex <v> which have possibly been inherited from the root.
1444 //
1445 // To summarize, we're going to look at the node represented by <v> and loop
1446 // through its point-to-point links, adding a *host* route to the local IP
1447 // address (at the <v> side) for each of those links.
1448 //
1449 if (v->GetVertexType() == SPFVertex::VertexRouter)
1450 {
1452 }
1453 else if (v->GetVertexType() == SPFVertex::VertexNetwork)
1454 {
1456 }
1457 else
1458 {
1459 NS_ASSERT_MSG(0, "illegal SPFVertex type");
1460 }
1461 //
1462 // RFC2328 16.1. (5).
1463 //
1464 // Iterate the algorithm by returning to Step 2 until there are no more
1465 // candidate vertices.
1466 }
1467
1468 // Second stage of SPF calculation procedure
1470 for (uint32_t i = 0; i < m_lsdb->GetNumExtLSAs(); i++)
1471 {
1472 m_spfroot->ClearVertexProcessed();
1473 GlobalRoutingLSA* extlsa = m_lsdb->GetExtLSA(i);
1474 NS_LOG_LOGIC("Processing External LSA with id " << extlsa->GetLinkStateId());
1476 }
1477
1478 //
1479 // We're all done setting the routing information for the node at the root of
1480 // the SPF tree. Delete all of the vertices and corresponding resources. Go
1481 // possibly do it again for the next router.
1482 //
1483 delete m_spfroot;
1484 m_spfroot = nullptr;
1485}
1486
1487void
1489{
1490 NS_LOG_FUNCTION(this << v << extlsa);
1491 NS_LOG_LOGIC("Processing external for destination "
1492 << extlsa->GetLinkStateId() << ", for router " << v->GetVertexId()
1493 << ", advertised by " << extlsa->GetAdvertisingRouter());
1494 if (v->GetVertexType() == SPFVertex::VertexRouter)
1495 {
1496 GlobalRoutingLSA* rlsa = v->GetLSA();
1497 NS_LOG_LOGIC("Processing router LSA with id " << rlsa->GetLinkStateId());
1498 if ((rlsa->GetLinkStateId()) == (extlsa->GetAdvertisingRouter()))
1499 {
1500 NS_LOG_LOGIC("Found advertising router to destination");
1501 SPFAddASExternal(extlsa, v);
1502 }
1503 }
1504 for (uint32_t i = 0; i < v->GetNChildren(); i++)
1505 {
1506 if (!v->GetChild(i)->IsVertexProcessed())
1507 {
1508 NS_LOG_LOGIC("Vertex's child " << i << " not yet processed, processing...");
1509 ProcessASExternals(v->GetChild(i), extlsa);
1510 v->GetChild(i)->SetVertexProcessed(true);
1511 }
1512 }
1513}
1514
1515//
1516// Adding external routes to routing table - modeled after
1517// SPFAddIntraAddStub()
1518//
1519
1520void
1522{
1523 NS_LOG_FUNCTION(this << extlsa << v);
1524
1525 NS_ASSERT_MSG(m_spfroot, "GlobalRouteManagerImpl::SPFAddASExternal (): Root pointer not set");
1526 // Two cases to consider: We are advertising the external ourselves
1527 // => No need to add anything
1528 // OR find best path to the advertising router
1529 if (v->GetVertexId() == m_spfroot->GetVertexId())
1530 {
1531 NS_LOG_LOGIC("External is on local host: " << v->GetVertexId() << "; returning");
1532 return;
1533 }
1534 NS_LOG_LOGIC("External is on remote host: " << extlsa->GetAdvertisingRouter()
1535 << "; installing");
1536
1537 Ipv4Address routerId = m_spfroot->GetVertexId();
1538
1539 NS_LOG_LOGIC("Vertex ID = " << routerId);
1540 //
1541 // The node we need to add routes to is the node corresponding to the root vertex.
1542 // This is the node for which we are building the routing table.
1543 //
1544 Ptr<Node> node = m_spfroot->GetNode();
1545
1546 if (!node)
1547 {
1548 NS_FATAL_ERROR("SPFAddASExternal():Can't find root node " << routerId);
1549 return;
1550 }
1551 //
1552 // The router ID is accessible through the GlobalRouter interface, so we need
1553 // to QI for that interface. If there's no GlobalRouter interface, the node
1554 // in question cannot be the router we want, so we continue.
1555 //
1556 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
1557 NS_ASSERT_MSG(router, "No GlobalRouter interface on SPF root node " << node->GetId());
1558 //
1559 // If the router ID of the current node is equal to the router ID of the
1560 // root of the SPF tree, then this node is the one for which we need to
1561 // write the routing tables.
1562 //
1563 if (router->GetRouterId() == routerId)
1564 {
1565 NS_LOG_LOGIC("Setting routes for node " << node->GetId());
1566 //
1567 // Routing information is updated using the Ipv4 interface. We need to QI
1568 // for that interface. If the node is acting as an IP version 4 router, it
1569 // should absolutely have an Ipv4 interface.
1570 //
1571 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
1572 NS_ASSERT_MSG(ipv4,
1573 "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
1574 "QI for <Ipv4> interface failed");
1575 //
1576 // Get the Global Router Link State Advertisement from the vertex we're
1577 // adding the routes to. The LSA will have a number of attached Global Router
1578 // Link Records corresponding to links off of that vertex / node. We're going
1579 // to be interested in the records corresponding to point-to-point links.
1580 //
1581 NS_ASSERT_MSG(v->GetLSA(),
1582 "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
1583 "Expected valid LSA in SPFVertex* v");
1584 Ipv4Mask tempmask = extlsa->GetNetworkLSANetworkMask();
1585 Ipv4Address tempip = extlsa->GetLinkStateId();
1586 tempip = tempip.CombineMask(tempmask);
1587
1588 //
1589 // Here's why we did all of that work. We're going to add a host route to the
1590 // host address found in the m_linkData field of the point-to-point link
1591 // record. In the case of a point-to-point link, this is the local IP address
1592 // of the node connected to the link. Each of these point-to-point links
1593 // will correspond to a local interface that has an IP address to which
1594 // the node at the root of the SPF tree can send packets. The vertex <v>
1595 // (corresponding to the node that has these links and interfaces) has
1596 // an m_nextHop address precalculated for us that is the address to which the
1597 // root node should send packets to be forwarded to these IP addresses.
1598 // Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
1599 // which the packets should be send for forwarding.
1600 //
1601 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
1602
1603 NS_ASSERT_MSG(router, "No GlobalRouter interface on node " << node->GetId());
1604
1605 Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol();
1606 NS_ASSERT(gr);
1607 // walk through all next-hop-IPs and out-going-interfaces for reaching
1608 // the stub network gateway 'v' from the root node
1609 for (uint32_t i = 0; i < v->GetNRootExitDirections(); i++)
1610 {
1611 SPFVertex::NodeExit_t exit = v->GetRootExitDirection(i);
1612 Ipv4Address nextHop = exit.first;
1613 int32_t outIf = exit.second;
1614 if (outIf >= 0)
1615 {
1616 gr->AddASExternalRouteTo(tempip, tempmask, nextHop, outIf);
1617 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
1618 << " add external network route to " << tempip
1619 << " using next hop " << nextHop << " via interface "
1620 << outIf);
1621 }
1622 else
1623 {
1624 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
1625 << " NOT able to add network route to " << tempip
1626 << " using next hop " << nextHop
1627 << " since outgoing interface id is negative");
1628 }
1629 }
1630 return;
1631 }
1632 // This should never happen. The RouterId and vertexId should match
1633 NS_FATAL_ERROR("SPFIntraAddRouter(): routerId and vertex ID do not match");
1634}
1635
1636// Processing logic from RFC 2328, page 166 and quagga ospf_spf_process_stubs ()
1637// stub link records will exist for point-to-point interfaces and for
1638// broadcast interfaces for which no neighboring router can be found
1639void
1641{
1642 NS_LOG_FUNCTION(this << v);
1643 NS_LOG_LOGIC("Processing stubs for " << v->GetVertexId());
1644 if (v->GetVertexType() == SPFVertex::VertexRouter)
1645 {
1646 GlobalRoutingLSA* rlsa = v->GetLSA();
1647 NS_LOG_LOGIC("Processing router LSA with id " << rlsa->GetLinkStateId());
1648 for (uint32_t i = 0; i < rlsa->GetNLinkRecords(); i++)
1649 {
1650 NS_LOG_LOGIC("Examining link " << i << " of " << v->GetVertexId() << "'s "
1651 << v->GetLSA()->GetNLinkRecords() << " link records");
1652 GlobalRoutingLinkRecord* l = v->GetLSA()->GetLinkRecord(i);
1654 {
1655 NS_LOG_LOGIC("Found a Stub record to " << l->GetLinkId());
1656 SPFIntraAddStub(l, v);
1657 continue;
1658 }
1659 }
1660 }
1661 for (uint32_t i = 0; i < v->GetNChildren(); i++)
1662 {
1663 if (!v->GetChild(i)->IsVertexProcessed())
1664 {
1665 SPFProcessStubs(v->GetChild(i));
1666 v->GetChild(i)->SetVertexProcessed(true);
1667 }
1668 }
1669}
1670
1671// RFC2328 16.1. second stage.
1672void
1674{
1675 NS_LOG_FUNCTION(this << l << v);
1676
1677 NS_ASSERT_MSG(m_spfroot, "GlobalRouteManagerImpl::SPFIntraAddStub (): Root pointer not set");
1678
1679 // XXX simplified logic for the moment. There are two cases to consider:
1680 // 1) the stub network is on this router; do nothing for now
1681 // (already handled above)
1682 // 2) the stub network is on a remote router, so I should use the
1683 // same next hop that I use to get to vertex v
1684 if (v->GetVertexId() == m_spfroot->GetVertexId())
1685 {
1686 NS_LOG_LOGIC("Stub is on local host: " << v->GetVertexId() << "; returning");
1687 return;
1688 }
1689 NS_LOG_LOGIC("Stub is on remote host: " << v->GetVertexId() << "; installing");
1690 //
1691 // The root of the Shortest Path First tree is the router to which we are
1692 // going to write the actual routing table entries. The vertex corresponding
1693 // to this router has a vertex ID which is the router ID of that node. We're
1694 // going to use this ID to discover which node it is that we're actually going
1695 // to update.
1696 //
1697 Ipv4Address routerId = m_spfroot->GetVertexId();
1698
1699 NS_LOG_LOGIC("Vertex ID = " << routerId);
1700 //
1701 // The node we need to add routes to is the node corresponding to the root vertex.
1702 // This is the node for which we are building the routing table.
1703 //
1704 Ptr<Node> node = m_spfroot->GetNode();
1705 if (!node)
1706 {
1707 NS_LOG_ERROR("SPFIntraAddStub():Can't find root node " << routerId);
1708 return;
1709 }
1710 //
1711 // The router ID is accessible through the GlobalRouter interface, so we need
1712 // to QI for that interface. If there's no GlobalRouter interface, the node
1713 // in question cannot be the router we want, so we continue.
1714 //
1715 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
1716 NS_ASSERT_MSG(router, "No GlobalRouter interface on node " << node->GetId());
1717 //
1718 // If the router ID of the current node is equal to the router ID of the
1719 // root of the SPF tree, then this node is the one for which we need to
1720 // write the routing tables.
1721 //
1722 if (routerId == router->GetRouterId())
1723 {
1724 NS_LOG_LOGIC("Setting routes for node " << node->GetId());
1725 //
1726 // Routing information is updated using the Ipv4 interface. We need to QI
1727 // for that interface. If the node is acting as an IP version 4 router, it
1728 // should absolutely have an Ipv4 interface.
1729 //
1730 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
1731 NS_ASSERT_MSG(ipv4,
1732 "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
1733 "QI for <Ipv4> interface failed");
1734 //
1735 // Get the Global Router Link State Advertisement from the vertex we're
1736 // adding the routes to. The LSA will have a number of attached Global Router
1737 // Link Records corresponding to links off of that vertex / node. We're going
1738 // to be interested in the records corresponding to point-to-point links.
1739 //
1740 NS_ASSERT_MSG(v->GetLSA(),
1741 "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
1742 "Expected valid LSA in SPFVertex* v");
1743 Ipv4Mask tempmask(l->GetLinkData().Get());
1744 Ipv4Address tempip = l->GetLinkId();
1745 tempip = tempip.CombineMask(tempmask);
1746 //
1747 // Here's why we did all of that work. We're going to add a host route to the
1748 // host address found in the m_linkData field of the point-to-point link
1749 // record. In the case of a point-to-point link, this is the local IP address
1750 // of the node connected to the link. Each of these point-to-point links
1751 // will correspond to a local interface that has an IP address to which
1752 // the node at the root of the SPF tree can send packets. The vertex <v>
1753 // (corresponding to the node that has these links and interfaces) has
1754 // an m_nextHop address precalculated for us that is the address to which the
1755 // root node should send packets to be forwarded to these IP addresses.
1756 // Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
1757 // which the packets should be send for forwarding.
1758 //
1759
1760 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
1761
1762 Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol();
1763 NS_ASSERT(gr);
1764 // walk through all next-hop-IPs and out-going-interfaces for reaching
1765 // the stub network gateway 'v' from the root node
1766 for (uint32_t i = 0; i < v->GetNRootExitDirections(); i++)
1767 {
1768 SPFVertex::NodeExit_t exit = v->GetRootExitDirection(i);
1769 Ipv4Address nextHop = exit.first;
1770 int32_t outIf = exit.second;
1771 if (outIf >= 0)
1772 {
1773 gr->AddNetworkRouteTo(tempip, tempmask, nextHop, outIf);
1774 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
1775 << " add network route to " << tempip << " using next hop "
1776 << nextHop << " via interface " << outIf);
1777 }
1778 else
1779 {
1780 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
1781 << " NOT able to add network route to " << tempip
1782 << " using next hop " << nextHop
1783 << " since outgoing interface id is negative");
1784 }
1785 }
1786 return;
1787 }
1788 // This should never happen. The RouterId and vertex Id should match
1789 NS_LOG_ERROR("SPFIntraAddStub(): routerId and vertex ID do not match");
1790}
1791
1792//
1793// Return the interface number corresponding to a given IP address and mask
1794// This is a wrapper around GetInterfaceForPrefix(), but we first
1795// have to find the right node pointer to pass to that function.
1796// If no such interface is found, return -1 (note: unit test framework
1797// for routing assumes -1 to be a legal return value)
1798//
1799int32_t
1801{
1802 NS_LOG_FUNCTION(this << a << amask);
1803 //
1804 // We have an IP address <a> and a vertex ID of the root of the SPF tree.
1805 // The question is what interface index does this address correspond to.
1806 // The answer is a little complicated since we have to find a pointer to
1807 // the node corresponding to the vertex ID, find the Ipv4 interface on that
1808 // node in order to iterate the interfaces and find the one corresponding to
1809 // the address in question.
1810 //
1811 Ipv4Address routerId = m_spfroot->GetVertexId();
1812 //
1813 // The node we need to add routes to is the node corresponding to the root vertex.
1814 // This is the node for which we are building the routing table.
1815 //
1816 Ptr<Node> node = m_spfroot->GetNode();
1817 if (!node)
1818 {
1819 //
1820 // Couldn't find it.
1821 //
1822 NS_LOG_LOGIC("FindOutgoingInterfaceId():Can't find root node " << routerId);
1823 return -1;
1824 }
1825
1826 Ptr<GlobalRouter> rtr = node->GetObject<GlobalRouter>();
1827 NS_ASSERT_MSG(rtr, "No GlobalRouter interface on node " << node->GetId());
1828 //
1829 // If the node doesn't have a GlobalRouter interface it can't be the one
1830 // we're interested in.
1831 //
1832
1833 if (rtr->GetRouterId() == routerId)
1834 {
1835 //
1836 // This is the node we're building the routing table for. We're going to need
1837 // the Ipv4 interface to look for the ipv4 interface index. Since this node
1838 // is participating in routing IP version 4 packets, it certainly must have
1839 // an Ipv4 interface.
1840 //
1841 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
1842 NS_ASSERT_MSG(ipv4,
1843 "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
1844 "GetObject for <Ipv4> interface failed");
1845 //
1846 // Look through the interfaces on this node for one that has the IP address
1847 // we're looking for. If we find one, return the corresponding interface
1848 // index, or -1 if not found.
1849 //
1850 int32_t interface = ipv4->GetInterfaceForPrefix(a, amask);
1851
1852#if 0
1853 if (interface < 0)
1854 {
1855 NS_FATAL_ERROR ("GlobalRouteManagerImpl::FindOutgoingInterfaceId(): "
1856 "Expected an interface associated with address a:" << a);
1857 }
1858#endif
1859 return interface;
1860 }
1861 // This should never happen. The RouterId and vertex Id should match
1862 NS_FATAL_ERROR("SPFIntraAddRouter(): routerId and vertex ID do not match");
1863 return -1;
1864}
1865
1866//
1867// This method is derived from quagga ospf_intra_add_router ()
1868//
1869// This is where we are actually going to add the host routes to the routing
1870// tables of the individual nodes.
1871//
1872// The vertex passed as a parameter has just been added to the SPF tree.
1873// This vertex must have a valid m_root_oid, corresponding to the outgoing
1874// interface on the root router of the tree that is the first hop on the path
1875// to the vertex. The vertex must also have a next hop address, corresponding
1876// to the next hop on the path to the vertex. The vertex has an m_lsa field
1877// that has some number of link records. For each point to point link record,
1878// the m_linkData is the local IP address of the link. This corresponds to
1879// a destination IP address, reachable from the root, to which we add a host
1880// route.
1881//
1882void
1884{
1885 NS_LOG_FUNCTION(this << v);
1886
1887 NS_ASSERT_MSG(m_spfroot, "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set");
1888 //
1889 // The root of the Shortest Path First tree is the router to which we are
1890 // going to write the actual routing table entries. The vertex corresponding
1891 // to this router has a vertex ID which is the router ID of that node. We're
1892 // going to use this ID to discover which node it is that we're actually going
1893 // to update.
1894 //
1895 Ipv4Address routerId = m_spfroot->GetVertexId();
1896
1897 NS_LOG_LOGIC("Vertex ID = " << routerId);
1898 //
1899 // The node we need to add routes to is the node corresponding to the root vertex.
1900 // This is the node for which we are building the routing table.
1901 //
1902 Ptr<Node> node = m_spfroot->GetNode();
1903 if (!node)
1904 {
1905 NS_LOG_ERROR("SPFIntraAddRouter():Can't find root node " << routerId);
1906 return;
1907 }
1908
1909 //
1910 // The router ID is accessible through the GlobalRouter interface, so we need
1911 // to GetObject for that interface. If there's no GlobalRouter interface,
1912 // the node in question cannot be the router we want, so we continue.
1913 //
1914 Ptr<GlobalRouter> rtr = node->GetObject<GlobalRouter>();
1915 NS_ASSERT_MSG(rtr, "No GlobalRouter interface on node " << node->GetId());
1916 //
1917 // If the router ID of the current node is equal to the router ID of the
1918 // root of the SPF tree, then this node is the one for which we need to
1919 // write the routing tables.
1920 //
1921
1922 if (rtr->GetRouterId() == routerId)
1923 {
1924 NS_LOG_LOGIC("Setting routes for node " << node->GetId());
1925 //
1926 // Routing information is updated using the Ipv4 interface. We need to
1927 // GetObject for that interface. If the node is acting as an IP version 4
1928 // router, it should absolutely have an Ipv4 interface.
1929 //
1930 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
1931 NS_ASSERT_MSG(ipv4,
1932 "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
1933 "GetObject for <Ipv4> interface failed");
1934 //
1935 // Get the Global Router Link State Advertisement from the vertex we're
1936 // adding the routes to. The LSA will have a number of attached Global Router
1937 // Link Records corresponding to links off of that vertex / node. We're going
1938 // to be interested in the records corresponding to point-to-point links.
1939 //
1940 GlobalRoutingLSA* lsa = v->GetLSA();
1941 NS_ASSERT_MSG(lsa,
1942 "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
1943 "Expected valid LSA in SPFVertex* v");
1944
1945 uint32_t nLinkRecords = lsa->GetNLinkRecords();
1946 //
1947 // Iterate through the link records on the vertex to which we're going to add
1948 // routes. To make sure we're being clear, we're going to add routing table
1949 // entries to the tables on the node corresponding to the root of the SPF tree.
1950 // These entries will have routes to the IP addresses we find from looking at
1951 // the local side of the point-to-point links found on the node described by
1952 // the vertex <v>.
1953 //
1954 NS_LOG_LOGIC(" Node " << node->GetId() << " found " << nLinkRecords
1955 << " link records in LSA " << lsa << "with LinkStateId "
1956 << lsa->GetLinkStateId());
1957 for (uint32_t j = 0; j < nLinkRecords; ++j)
1958 {
1959 //
1960 // We are only concerned about point-to-point links
1961 //
1964 {
1965 continue;
1966 }
1967 //
1968 // Here's why we did all of that work. We're going to add a host route to the
1969 // host address found in the m_linkData field of the point-to-point link
1970 // record. In the case of a point-to-point link, this is the local IP address
1971 // of the node connected to the link. Each of these point-to-point links
1972 // will correspond to a local interface that has an IP address to which
1973 // the node at the root of the SPF tree can send packets. The vertex <v>
1974 // (corresponding to the node that has these links and interfaces) has
1975 // an m_nextHop address precalculated for us that is the address to which the
1976 // root node should send packets to be forwarded to these IP addresses.
1977 // Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
1978 // which the packets should be send for forwarding.
1979 //
1980 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
1981 if (!router)
1982 {
1983 continue;
1984 }
1985 Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol();
1986 NS_ASSERT(gr);
1987 // walk through all available exit directions due to ECMP,
1988 // and add host route for each of the exit direction toward
1989 // the vertex 'v'
1990 for (uint32_t i = 0; i < v->GetNRootExitDirections(); i++)
1991 {
1992 SPFVertex::NodeExit_t exit = v->GetRootExitDirection(i);
1993 Ipv4Address nextHop = exit.first;
1994 int32_t outIf = exit.second;
1995 if (outIf >= 0)
1996 {
1997 gr->AddHostRouteTo(lr->GetLinkData(), nextHop, outIf);
1998 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
1999 << " adding host route to " << lr->GetLinkData()
2000 << " using next hop " << nextHop
2001 << " and outgoing interface " << outIf);
2002 }
2003 else
2004 {
2005 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
2006 << " NOT able to add host route to " << lr->GetLinkData()
2007 << " using next hop " << nextHop
2008 << " since outgoing interface id is negative " << outIf);
2009 }
2010 }
2011 }
2012 //
2013 // Done adding the routes for the selected node.
2014 //
2015 return;
2016 }
2017 // This should never happen. The RouterId and vertex Id should match
2018 NS_FATAL_ERROR("SPFIntraAddRouter(): routerId and vertex ID do not match");
2019}
2020
2021void
2023{
2024 NS_LOG_FUNCTION(this << v);
2025
2026 NS_ASSERT_MSG(m_spfroot, "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set");
2027 //
2028 // The root of the Shortest Path First tree is the router to which we are
2029 // going to write the actual routing table entries. The vertex corresponding
2030 // to this router has a vertex ID which is the router ID of that node. We're
2031 // going to use this ID to discover which node it is that we're actually going
2032 // to update.
2033 //
2034 Ipv4Address routerId = m_spfroot->GetVertexId();
2035
2036 NS_LOG_LOGIC("Vertex ID = " << routerId);
2037 //
2038 // The node we need to add routes to is the node corresponding to the root vertex.
2039 // This is the node for which we are building the routing table.
2040 //
2041 Ptr<Node> node = m_spfroot->GetNode();
2042 if (!node)
2043 {
2044 NS_LOG_ERROR("SPFIntraAddTransit():Can't find root node " << routerId);
2045 return;
2046 }
2047
2048 //
2049 // The router ID is accessible through the GlobalRouter interface, so we need
2050 // to GetObject for that interface. If there's no GlobalRouter interface,
2051 // the node in question cannot be the router we want, so we continue.
2052 //
2053 Ptr<GlobalRouter> rtr = node->GetObject<GlobalRouter>();
2054 NS_ASSERT_MSG(rtr, "No GlobalRouter interface on node " << node->GetId());
2055 //
2056 // If the router ID of the current node is equal to the router ID of the
2057 // root of the SPF tree, then this node is the one for which we need to
2058 // write the routing tables.
2059 //
2060
2061 if (rtr->GetRouterId() == routerId)
2062 {
2063 NS_LOG_LOGIC("setting routes for node " << node->GetId());
2064 //
2065 // Routing information is updated using the Ipv4 interface. We need to
2066 // GetObject for that interface. If the node is acting as an IP version 4
2067 // router, it should absolutely have an Ipv4 interface.
2068 //
2069 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
2070 NS_ASSERT_MSG(ipv4,
2071 "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
2072 "GetObject for <Ipv4> interface failed");
2073 //
2074 // Get the Global Router Link State Advertisement from the vertex we're
2075 // adding the routes to. The LSA will have a number of attached Global Router
2076 // Link Records corresponding to links off of that vertex / node. We're going
2077 // to be interested in the records corresponding to point-to-point links.
2078 //
2079 GlobalRoutingLSA* lsa = v->GetLSA();
2080 NS_ASSERT_MSG(lsa,
2081 "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
2082 "Expected valid LSA in SPFVertex* v");
2083 Ipv4Mask tempmask = lsa->GetNetworkLSANetworkMask();
2084 Ipv4Address tempip = lsa->GetLinkStateId();
2085 tempip = tempip.CombineMask(tempmask);
2086 Ptr<GlobalRouter> router = node->GetObject<GlobalRouter>();
2087 Ptr<Ipv4GlobalRouting> gr = router->GetRoutingProtocol();
2088 NS_ASSERT(gr);
2089 // walk through all available exit directions due to ECMP,
2090 // and add host route for each of the exit direction toward
2091 // the vertex 'v'
2092 for (uint32_t i = 0; i < v->GetNRootExitDirections(); i++)
2093 {
2094 SPFVertex::NodeExit_t exit = v->GetRootExitDirection(i);
2095 Ipv4Address nextHop = exit.first;
2096 int32_t outIf = exit.second;
2097
2098 if (outIf >= 0)
2099 {
2100 gr->AddNetworkRouteTo(tempip, tempmask, nextHop, outIf);
2101 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
2102 << " add network route to " << tempip << " using next hop "
2103 << nextHop << " via interface " << outIf);
2104 }
2105 else
2106 {
2107 NS_LOG_LOGIC("(Route " << i << ") Node " << node->GetId()
2108 << " NOT able to add network route to " << tempip
2109 << " using next hop " << nextHop
2110 << " since outgoing interface id is negative " << outIf);
2111 }
2112 }
2113 //
2114 // done adding routes for the root node.
2115 //
2116 return;
2117 }
2118 // This should never happen. The RouterId and vertex Id should match
2119 NS_FATAL_ERROR("SPFIntraAddTransit(): routerId and vertex ID do not match");
2120}
2121
2122// Derived from quagga ospf_vertex_add_parents ()
2123//
2124// This is a somewhat oddly named method (blame quagga). Although you might
2125// expect it to add a parent *to* something, it actually adds a vertex
2126// to the list of children *in* each of its parents.
2127//
2128// Given a pointer to a vertex, it links back to the vertex's parent that it
2129// already has set and adds itself to that vertex's list of children.
2130//
2131void
2133{
2134 NS_LOG_FUNCTION(this << v);
2135
2136 for (uint32_t i = 0;;)
2137 {
2138 SPFVertex* parent;
2139 // check if all parents of vertex v
2140 if ((parent = v->GetParent(i++)) == nullptr)
2141 {
2142 break;
2143 }
2144 parent->AddChild(v);
2145 }
2146}
2147
2150{
2151 // iterate through the list of nodes
2152 for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
2153 {
2154 Ptr<Node> node = *i;
2155 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
2156
2157 if (!ipv4)
2158 {
2159 continue;
2160 }
2161
2162 int32_t interface = ipv4->GetInterfaceForAddress(address);
2163 if (interface >= 0) // Address found on this node
2164 {
2165 return node;
2166 }
2167 }
2168 return nullptr; // If no node with the given IP address was found
2169}
2170
2171void
2173 Ptr<Node> dest,
2175 bool nodeIdLookup,
2176 Time::Unit unit)
2177{
2178 // Get any Ip of destination other than the loopbackIp
2179 Ptr<Ipv4> ipv4 = dest->GetObject<Ipv4>();
2180 NS_ASSERT_MSG(ipv4, "Ipv4 not found on destination node " << dest->GetId());
2181
2182 uint32_t numInterfaces = ipv4->GetNInterfaces();
2183
2184 for (uint32_t i = 0; i < numInterfaces; i++)
2185 {
2186 uint32_t numAddresses = ipv4->GetNAddresses(i);
2187 for (uint32_t j = 0; j < numAddresses; j++)
2188 {
2189 Ipv4InterfaceAddress addr = ipv4->GetAddress(i, j);
2190 if (addr.GetLocal() != Ipv4Address::GetLoopback())
2191 {
2192 Ipv4Address destinationAddr;
2193 destinationAddr = addr.GetLocal();
2194 PrintRoute(sourceNode, destinationAddr, stream, nodeIdLookup, unit);
2195 return;
2196 }
2197 }
2198 }
2199 // If no IP address is associated with the destination node, abort the program
2200 NS_ABORT_MSG("No IP address associated with destination Node");
2201}
2202
2205{
2206 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
2207 auto globalRouting = DynamicCast<Ipv4GlobalRouting>(ipv4->GetRoutingProtocol());
2208
2209 if (globalRouting)
2210 {
2211 return globalRouting;
2212 }
2213
2214 auto list = DynamicCast<Ipv4ListRouting>(ipv4->GetRoutingProtocol());
2215 if (!list)
2216 {
2217 return nullptr;
2218 }
2219
2220 for (uint32_t i = 0; i < list->GetNRoutingProtocols(); i++)
2221 {
2222 int16_t priority = 0;
2223 globalRouting = DynamicCast<Ipv4GlobalRouting>(list->GetRoutingProtocol(i, priority));
2224 if (globalRouting)
2225 {
2226 return globalRouting;
2227 }
2228 }
2229
2230 return nullptr;
2231}
2232
2233bool
2235{
2236 for (uint32_t i = 0; i < ipv4->GetNInterfaces(); i++)
2237 {
2238 for (uint32_t j = 0; j < ipv4->GetNAddresses(i); j++)
2239 {
2240 auto addr = ipv4->GetAddress(i, j);
2241 if (dest == addr.GetLocal())
2242 {
2243 return true;
2244 }
2245 }
2246 }
2247
2248 return false;
2249}
2250
2251bool
2253{
2254 uint32_t numInter = ipv4->GetNInterfaces();
2255 if (numInter == 0)
2256 {
2257 NS_ABORT_MSG("No interfaces associated with source Node");
2258 return false;
2259 }
2260
2261 for (uint32_t i = 0; i < numInter; i++)
2262 {
2263 if (ipv4->GetNAddresses(i) > 0)
2264 {
2265 return true;
2266 }
2267 }
2268
2269 NS_ABORT_MSG("No IP address associated with source Node");
2270 return false;
2271}
2272
2273bool
2275{
2276 bool found = false;
2277 uint32_t numInterfaces = ipv4CurrentNode->GetNInterfaces();
2278 for (uint32_t i = 0; i < numInterfaces; i++)
2279 {
2280 uint32_t numAddresses = ipv4CurrentNode->GetNAddresses(i);
2281 for (uint32_t j = 0; j < numAddresses; j++)
2282 {
2283 Ipv4InterfaceAddress senderAddr = ipv4CurrentNode->GetAddress(i, j);
2284 Ipv4Mask mask = senderAddr.GetMask();
2285
2286 // Check if the destination is within the same subnet
2287 if (mask.IsMatch(dest, senderAddr.GetLocal()))
2288 {
2289 // next hop will be the destNode
2290 return true;
2291 }
2292 }
2293 }
2294 return found;
2295}
2296
2297void
2299 Ipv4Address dest,
2301 bool nodeIdLookup,
2302 Time::Unit unit)
2303{
2304 NS_LOG_FUNCTION(this << sourceNode << dest);
2305
2306 Ptr<Node> destNode = GetNodeByIp(dest);
2307 // check that given ipv4address exists
2308 if (!destNode)
2309 {
2310 NS_ABORT_MSG("Destination node not found for IP address: " << dest);
2311 return;
2312 }
2313
2314 NS_ABORT_MSG_IF(!sourceNode, "No Source Node Provided");
2315 Ptr<Ipv4> ipv4 = sourceNode->GetObject<Ipv4>();
2316 // check for ipv4 stack
2317 NS_ABORT_MSG_IF(!ipv4, "No Ipv4 object found on source node " << sourceNode->GetId());
2318
2319 // check if source has ipv4 address assigned to it
2321 {
2322 NS_ABORT_MSG("No IP address associated with source Node");
2323 return;
2324 }
2325
2326 auto globalRouting = GetGlobalRoutingForNode(sourceNode);
2327
2328 // Final check: If still nullptr, GlobalRouting wasn't found anywhere
2329 if (!globalRouting)
2330 {
2331 NS_ABORT_MSG("No global routing protocol found on source node " << sourceNode->GetId());
2332 return;
2333 }
2334
2335 // Set up the output stream
2336 std::ostream* os = stream->GetStream();
2337 uint32_t hopsRemaining = 64;
2338 uint32_t currHop = 1;
2339 // Print the maxHop. This is similar to TraceRoute
2340 *os << ", " << hopsRemaining << " hops Max." << std::endl;
2341
2342 // first check if it is local delivery to one of the nodes on the source node itself
2343 if (IsLocalDelivery(ipv4, dest))
2344 {
2345 NS_LOG_DEBUG("PrintRoute: Source and Destination are on the same Node "
2346 << sourceNode->GetId());
2347 *os << "Source and Destination are on the same Node";
2348 *os << std::endl << std::endl;
2349 return;
2350 }
2351
2352 // check if routes exist
2353 if (!globalRouting->LookupGlobal(dest))
2354 {
2355 *os << "There is no path from Node " << sourceNode->GetId() << " to Node "
2356 << destNode->GetId() << "." << std::endl
2357 << std::endl;
2358 return;
2359 }
2360
2361 // we start searching for gateways
2362 Ptr<Node> currentNode = sourceNode;
2363 Ipv4Address currentNodeIp;
2364 std::list<Ptr<Node>> visitedNodes;
2365 visitedNodes.push_back(currentNode);
2366 while (currentNode != destNode)
2367 {
2368 if (!hopsRemaining)
2369 {
2370 NS_LOG_WARN("Max Hop Limit reached");
2371 return;
2372 }
2373
2374 Ptr<Ipv4> ipv4CurrentNode = currentNode->GetObject<Ipv4>();
2375 auto router = GetGlobalRoutingForNode(currentNode);
2376
2377 Ptr<Ipv4Route> gateway = router->LookupGlobal(dest);
2378 // check if the gateway exists
2379 if (!gateway)
2380 {
2381 NS_LOG_WARN("No next hop found");
2382 return;
2383 }
2384
2385 Ipv4Address gatewayAddress = gateway->GetGateway();
2386
2387 // check if the currentNode and the destination belong to the same network. Routing tables
2388 // will have a routing table entry with 0.0.0.0 as Gateway
2389 if (gatewayAddress == Ipv4Address::GetZero())
2390 {
2391 // check if gateway is on the same subnet as the destination if it is not and still null
2392 // then there is no next jump
2393 bool found = IsOnSameSubnet(ipv4CurrentNode, dest);
2394 if (!found)
2395 {
2396 *os << "Error: Did not find any addresses for " << dest << " From "
2397 << currentNode->GetId() << std::endl;
2398 return;
2399 }
2400 else
2401 {
2402 currentNode = destNode;
2403 break;
2404 }
2405 }
2406
2407 Ptr<Node> nextNode = GetNodeByIp(gatewayAddress);
2408
2409 if (nextNode == currentNode)
2410 {
2411 *os << "Invalid route: Next hop points back to the current node (Node "
2412 << currentNode->GetId() << ").\n";
2413 NS_LOG_WARN("Invalid route: Next hop points back to the current node.");
2414 return;
2415 }
2416
2417 // check for loops
2418 if (std::find(visitedNodes.begin(), visitedNodes.end(), nextNode) != visitedNodes.end())
2419 {
2420 *os << "Loop detected! Node " << nextNode->GetId() << " revisited.\n\n";
2421 NS_LOG_WARN("Routing Loop detected");
2422 return;
2423 }
2424 visitedNodes.push_back(nextNode);
2425
2426 Ptr<NetDevice> outdevice = gateway->GetOutputDevice();
2427 Ptr<Ipv4L3Protocol> ipv4 = currentNode->GetObject<Ipv4L3Protocol>();
2428 uint32_t interfaceIndex = ipv4CurrentNode->GetInterfaceForDevice(outdevice);
2429 currentNodeIp = ipv4->SourceAddressSelection(interfaceIndex, gatewayAddress);
2430
2431 // print this iteration
2432 std::ostringstream addr;
2433 std::ostringstream node;
2434 if (nextNode != destNode)
2435 {
2436 node << "(Node " << nextNode->GetId() << ")";
2437 addr << gatewayAddress;
2438 *os << std::right << std::setw(2) << currHop++ << " " << addr.str();
2439 if (nodeIdLookup)
2440 {
2441 *os << " " << node.str();
2442 }
2443 *os << std::endl;
2444 }
2445 // if the next node is the destination node, then print the Destination IP instead of the
2446 // ingress IP of the destination.
2447 else
2448 {
2449 node << "(Node " << destNode->GetId() << ")";
2450 addr << dest;
2451 *os << std::right << std::setw(2) << currHop++ << " " << addr.str();
2452 if (nodeIdLookup)
2453 {
2454 *os << " " << node.str();
2455 }
2456 *os << std::endl;
2457 }
2458 currentNode = nextNode;
2459 currentNodeIp = gatewayAddress;
2460 hopsRemaining--;
2461 }
2462 *os << std::endl;
2463}
2464
2465} // namespace ns3
uint32_t v
A Candidate Queue used in routing calculations.
SPFVertex * Pop()
Pop the Shortest Path First Vertex pointer at the top of the queue.
uint32_t Size() const
Return the number of Shortest Path First Vertex pointers presently stored in the Candidate Queue.
void Push(SPFVertex *vNew)
Push a Shortest Path First Vertex pointer onto the queue according to the priority scheme.
void Reorder()
Reorders the Candidate Queue according to the priority scheme.
SPFVertex * Find(const Ipv4Address addr) const
Searches the Candidate Queue for a Shortest Path First Vertex pointer that points to a vertex having ...
void SPFCalculate(Ipv4Address root)
Calculate the shortest path first (SPF) tree.
void SPFAddASExternal(GlobalRoutingLSA *extlsa, SPFVertex *v)
Add an external route to the routing tables.
bool IsLocalDelivery(Ptr< Ipv4 > ipv4, Ipv4Address dest)
Is used by PrintRoute() to check if the destination is on the source node itself.
void ProcessASExternals(SPFVertex *v, GlobalRoutingLSA *extlsa)
Process Autonomous Systems (AS) External LSA.
bool ValidateSourceNodeHasIpAddress(Ptr< Ipv4 > ipv4)
Is used by PrintRoute() to check if the source node has an ipv4 address.
virtual void InitializeRoutes()
Compute routes using a Dijkstra SPF computation and populate per-node forwarding tables.
void SPFProcessStubs(SPFVertex *v)
Process Stub nodes.
virtual void BuildGlobalRoutingDatabase()
Build the routing database by gathering Link State Advertisements from each node exporting a GlobalRo...
GlobalRoutingLinkRecord * SPFGetNextLink(SPFVertex *v, SPFVertex *w, GlobalRoutingLinkRecord *prev_link)
Search for a link between two vertices.
int32_t FindOutgoingInterfaceId(Ipv4Address a, Ipv4Mask amask=Ipv4Mask("255.255.255.255"))
Return the interface number corresponding to a given IP address and mask.
void PrintRoute(Ptr< Node > sourceNode, Ptr< Node > dest, Ptr< OutputStreamWrapper > stream, bool nodeIdLookup, Time::Unit unit)
prints the path from this node to the destination node at a particular time.
virtual void DeleteGlobalRoutes()
Delete all static routes on all nodes that have a GlobalRouterInterface.
GlobalRouteManagerLSDB * m_lsdb
the Link State DataBase (LSDB) of the Global Route Manager
bool CheckForStubNode(Ipv4Address root)
Test if a node is a stub, from an OSPF sense.
void DebugUseLsdb(GlobalRouteManagerLSDB *lsdb)
Debugging routine; allow client code to supply a pre-built LSDB.
bool IsOnSameSubnet(Ptr< Ipv4 > ipv4CurrentNode, Ipv4Address dest)
Is used by PrintRoute() to check if the destination is on the same subnet as the source node.
void SPFNext(SPFVertex *v, CandidateQueue &candidate)
Examine the links in v's LSA and update the list of candidates with any vertices not already on the l...
void DebugSPFCalculate(Ipv4Address root)
Debugging routine; call the core SPF from the unit tests.
void SPFIntraAddTransit(SPFVertex *v)
Add a transit to the routing tables.
Ptr< Node > GetNodeByIp(const Ipv4Address &source)
given IP it iterates through the node list to find the node associated with the ip
int SPFNexthopCalculation(SPFVertex *v, SPFVertex *w, GlobalRoutingLinkRecord *l, uint32_t distance)
Calculate nexthop from root through V (parent) to vertex W (destination) with given distance from roo...
void SPFIntraAddStub(GlobalRoutingLinkRecord *l, SPFVertex *v)
Add a stub to the routing tables.
Ptr< Ipv4GlobalRouting > GetGlobalRoutingForNode(Ptr< Node > node)
Is used by PrintRoute() to get the global routing protocol associated with it or returns nullptr if n...
void SPFIntraAddRouter(SPFVertex *v)
Add a host route to the routing tables.
void SPFVertexAddParent(SPFVertex *v)
Adds a vertex to the list of children in each of its parents.
The Link State DataBase (LSDB) of the Global Route Manager.
void Initialize()
Set all LSA flags to an initialized state, for SPF computation.
std::pair< Ipv4Address, GlobalRoutingLSA * > LSDBPair_t
pair of IPv4 addresses / Link State Advertisements
~GlobalRouteManagerLSDB()
Destroy an empty Global Router Manager Link State Database.
uint32_t GetNumExtLSAs() const
Get the number of External Link State Advertisements.
GlobalRoutingLSA * GetLSA(Ipv4Address addr) const
Look up the Link State Advertisement associated with the given link state ID (address).
std::vector< GlobalRoutingLSA * > m_extdatabase
database of External Link State Advertisements
void Insert(Ipv4Address addr, GlobalRoutingLSA *lsa)
Insert an IP address / Link State Advertisement pair into the Link State Database.
LSDBMap_t m_database
database of IPv4 addresses / Link State Advertisements
GlobalRoutingLSA * GetExtLSA(uint32_t index) const
Look up the External Link State Advertisement associated with the given index.
GlobalRouteManagerLSDB()
Construct an empty Global Router Manager Link State Database.
GlobalRoutingLSA * GetLSAByLinkData(Ipv4Address addr) const
Look up the Link State Advertisement associated with the given link state ID (address).
An interface aggregated to a node to provide global routing info.
a Link State Advertisement (LSA) for a router, used in global routing.
Ipv4Address GetAdvertisingRouter() const
Get the Advertising Router as defined by the OSPF spec.
void SetStatus(SPFStatus status)
Set the SPF status of the advertisement.
@ LSA_SPF_NOT_EXPLORED
New vertex not yet considered.
@ LSA_SPF_IN_SPFTREE
Vertex is in the SPF tree.
@ LSA_SPF_CANDIDATE
Vertex is in the SPF candidate queue.
Ptr< Node > GetNode() const
Get the Node pointer of the node that originated this LSA.
SPFStatus GetStatus() const
Get the SPF status of the advertisement.
Ipv4Mask GetNetworkLSANetworkMask() const
For a Network LSA, get the Network Mask field that precedes the list of attached routers.
LSType GetLSType() const
Return the LSType field of the LSA.
uint32_t GetNLinkRecords() const
Return the number of Global Routing Link Records in the LSA.
GlobalRoutingLinkRecord * GetLinkRecord(uint32_t n) const
Return a pointer to the specified Global Routing Link Record.
Ipv4Address GetLinkStateId() const
Get the Link State ID as defined by the OSPF spec.
Ipv4 addresses are stored in host order in this class.
static Ipv4Address GetLoopback()
static Ipv4Address GetZero()
Ipv4Address CombineMask(const Ipv4Mask &mask) const
Combine this address with a network mask.
uint32_t Get() const
Get the host-order 32-bit IP address.
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
a class to store IPv4 address information on an interface
Ipv4Mask GetMask() const
Get the network mask.
Ipv4Address GetLocal() const
Get the local address.
Implement the IPv4 layer.
a class to represent an Ipv4 address mask
bool IsMatch(Ipv4Address a, Ipv4Address b) const
static Iterator Begin()
Definition node-list.cc:226
static uint32_t GetNNodes()
Definition node-list.cc:247
static Iterator End()
Definition node-list.cc:233
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:518
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
Vertex used in shortest path first (SPF) computations.
Ipv4Address GetVertexId() const
Get the Vertex ID field of a SPFVertex object.
std::pair< Ipv4Address, int32_t > NodeExit_t
IPv4 / interface container for exit nodes.
GlobalRoutingLSA * GetLSA() const
Get the Global Router Link State Advertisement returned by the Global Router represented by this SPFV...
Ipv4Address m_nextHop
next hop
void SetVertexId(Ipv4Address id)
Set the Vertex ID field of a SPFVertex object.
Ptr< Node > GetNode() const
Get the node pointer corresponding to this Vertex.
void MergeParent(const SPFVertex *v)
Merge the Parent list from the v into this vertex.
VertexType
Enumeration of the possible types of SPFVertex objects.
@ VertexNetwork
Vertex representing a network in the topology.
@ VertexRouter
Vertex representing a router in the topology.
@ VertexUnknown
Uninitialized Link Record.
void InheritAllRootExitDirections(const SPFVertex *vertex)
Inherit all root exit directions from a given vertex to 'this' vertex.
void SetDistanceFromRoot(uint32_t distance)
Set the distance from the root vertex to "this" SPFVertex object.
SPFVertex * GetChild(uint32_t n) const
Get a borrowed SPFVertex pointer to the specified child of "this" SPFVertex.
VertexType GetVertexType() const
Get the Vertex Type field of a SPFVertex object.
bool IsVertexProcessed() const
Check the value of the VertexProcessed flag.
void SetParent(SPFVertex *parent)
Set the pointer to the SPFVector that is the parent of "this" SPFVertex.
void MergeRootExitDirections(const SPFVertex *vertex)
Merge into 'this' vertex the list of exit directions from another vertex.
std::list< SPFVertex * > ListOfSPFVertex_t
container of SPFVertex items
Ptr< Node > m_node
node pointer corresponding to the this Vertex
uint32_t GetDistanceFromRoot() const
Get the distance from the root vertex to "this" SPFVertex object.
GlobalRoutingLSA * m_lsa
Link State Advertisement.
~SPFVertex()
Destroy an SPFVertex (Shortest Path First Vertex).
void SetRootExitDirection(Ipv4Address nextHop, int32_t id=SPF_INFINITY)
Set the IP address and outgoing interface index that should be used to begin forwarding packets from ...
void SetVertexProcessed(bool value)
Set the value of the VertexProcessed flag.
std::list< NodeExit_t > ListOfNodeExit_t
container of Exit nodes
void SetVertexType(VertexType type)
Set the Vertex Type field of a SPFVertex object.
void SetLSA(GlobalRoutingLSA *lsa)
Set the Global Router Link State Advertisement returned by the Global Router represented by this SPFV...
uint32_t GetNRootExitDirections() const
Get the number of exit directions from root for reaching 'this' vertex.
int32_t m_rootOif
root Output Interface
uint32_t m_distanceFromRoot
Distance from root node.
void ClearVertexProcessed()
Clear the value of the VertexProcessed flag.
bool m_vertexProcessed
Flag to note whether vertex has been processed in stage two of SPF computation.
uint32_t GetNChildren() const
Get the number of children of "this" SPFVertex.
Ipv4Address m_vertexId
Vertex ID.
uint32_t AddChild(SPFVertex *child)
Get a borrowed SPFVertex pointer to the specified child of "this" SPFVertex.
NodeExit_t GetRootExitDirection() const
Obtain a pair indicating the exit direction from the root.
ListOfNodeExit_t m_ecmpRootExits
store the multiple root's exits for supporting ECMP
SPFVertex * GetParent(uint32_t i=0) const
Get a pointer to the SPFVector that is the parent of "this" SPFVertex.
ListOfSPFVertex_t m_children
Children list.
VertexType m_vertexType
Vertex type.
ListOfSPFVertex_t m_parents
parent list
SPFVertex()
Construct an empty ("uninitialized") SPFVertex (Shortest Path First Vertex).
static uint32_t GetSystemId()
Get the system id of this simulator.
Definition simulator.cc:313
Unit
The unit to use to interpret a number representing time.
Definition nstime.h:102
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:246
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:253
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:605
const uint32_t SPF_INFINITY
"infinite" distance between nodes
#define list