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