A Discrete-Event Network Simulator
API
global-router-interface.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2007 University of Washington
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Tom Henderson (tomhend@u.washington.edu)
18  */
19 
21 
22 #include "ipv4-global-routing.h"
23 #include "ipv4.h"
24 #include "loopback-net-device.h"
25 
26 #include "ns3/abort.h"
27 #include "ns3/assert.h"
28 #include "ns3/bridge-net-device.h"
29 #include "ns3/channel.h"
30 #include "ns3/log.h"
31 #include "ns3/net-device.h"
32 #include "ns3/node-list.h"
33 #include "ns3/node.h"
34 
35 #include <vector>
36 
37 namespace ns3
38 {
39 
40 NS_LOG_COMPONENT_DEFINE("GlobalRouter");
41 
42 // ---------------------------------------------------------------------------
43 //
44 // GlobalRoutingLinkRecord Implementation
45 //
46 // ---------------------------------------------------------------------------
47 
49  : m_linkId("0.0.0.0"),
50  m_linkData("0.0.0.0"),
51  m_linkType(Unknown),
52  m_metric(0)
53 {
54  NS_LOG_FUNCTION(this);
55 }
56 
58  Ipv4Address linkId,
59  Ipv4Address linkData,
60  uint16_t metric)
61  : m_linkId(linkId),
62  m_linkData(linkData),
63  m_linkType(linkType),
64  m_metric(metric)
65 {
66  NS_LOG_FUNCTION(this << linkType << linkId << linkData << metric);
67 }
68 
70 {
71  NS_LOG_FUNCTION(this);
72 }
73 
76 {
77  NS_LOG_FUNCTION(this);
78  return m_linkId;
79 }
80 
81 void
83 {
84  NS_LOG_FUNCTION(this << addr);
85  m_linkId = addr;
86 }
87 
90 {
91  NS_LOG_FUNCTION(this);
92  return m_linkData;
93 }
94 
95 void
97 {
98  NS_LOG_FUNCTION(this << addr);
99  m_linkData = addr;
100 }
101 
104 {
105  NS_LOG_FUNCTION(this);
106  return m_linkType;
107 }
108 
109 void
111 {
112  NS_LOG_FUNCTION(this << linkType);
113  m_linkType = linkType;
114 }
115 
116 uint16_t
118 {
119  NS_LOG_FUNCTION(this);
120  return m_metric;
121 }
122 
123 void
125 {
126  NS_LOG_FUNCTION(this << metric);
127  m_metric = metric;
128 }
129 
130 // ---------------------------------------------------------------------------
131 //
132 // GlobalRoutingLSA Implementation
133 //
134 // ---------------------------------------------------------------------------
135 
137  : m_lsType(GlobalRoutingLSA::Unknown),
138  m_linkStateId("0.0.0.0"),
139  m_advertisingRtr("0.0.0.0"),
140  m_linkRecords(),
141  m_networkLSANetworkMask("0.0.0.0"),
142  m_attachedRouters(),
143  m_status(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED),
144  m_node_id(0)
145 {
146  NS_LOG_FUNCTION(this);
147 }
148 
150  Ipv4Address linkStateId,
151  Ipv4Address advertisingRtr)
152  : m_lsType(GlobalRoutingLSA::Unknown),
153  m_linkStateId(linkStateId),
154  m_advertisingRtr(advertisingRtr),
155  m_linkRecords(),
156  m_networkLSANetworkMask("0.0.0.0"),
157  m_attachedRouters(),
158  m_status(status),
159  m_node_id(0)
160 {
161  NS_LOG_FUNCTION(this << status << linkStateId << advertisingRtr);
162 }
163 
165  : m_lsType(lsa.m_lsType),
166  m_linkStateId(lsa.m_linkStateId),
167  m_advertisingRtr(lsa.m_advertisingRtr),
168  m_networkLSANetworkMask(lsa.m_networkLSANetworkMask),
169  m_status(lsa.m_status),
170  m_node_id(lsa.m_node_id)
171 {
172  NS_LOG_FUNCTION(this << &lsa);
173  NS_ASSERT_MSG(IsEmpty(), "GlobalRoutingLSA::GlobalRoutingLSA (): Non-empty LSA in constructor");
174  CopyLinkRecords(lsa);
175 }
176 
179 {
180  NS_LOG_FUNCTION(this << &lsa);
181  m_lsType = lsa.m_lsType;
185  m_node_id = lsa.m_node_id;
186 
188  CopyLinkRecords(lsa);
189  return *this;
190 }
191 
192 void
194 {
195  NS_LOG_FUNCTION(this << &lsa);
196  for (auto i = lsa.m_linkRecords.begin(); i != lsa.m_linkRecords.end(); i++)
197  {
198  GlobalRoutingLinkRecord* pSrc = *i;
199  auto pDst = new GlobalRoutingLinkRecord;
200 
201  pDst->SetLinkType(pSrc->GetLinkType());
202  pDst->SetLinkId(pSrc->GetLinkId());
203  pDst->SetLinkData(pSrc->GetLinkData());
204  pDst->SetMetric(pSrc->GetMetric());
205 
206  m_linkRecords.push_back(pDst);
207  pDst = nullptr;
208  }
209 
211 }
212 
214 {
215  NS_LOG_FUNCTION(this);
217 }
218 
219 void
221 {
222  NS_LOG_FUNCTION(this);
223  for (auto i = m_linkRecords.begin(); i != m_linkRecords.end(); i++)
224  {
225  NS_LOG_LOGIC("Free link record");
226 
227  GlobalRoutingLinkRecord* p = *i;
228  delete p;
229  p = nullptr;
230 
231  *i = nullptr;
232  }
233  NS_LOG_LOGIC("Clear list");
234  m_linkRecords.clear();
235 }
236 
237 uint32_t
239 {
240  NS_LOG_FUNCTION(this << lr);
241  m_linkRecords.push_back(lr);
242  return m_linkRecords.size();
243 }
244 
245 uint32_t
247 {
248  NS_LOG_FUNCTION(this);
249  return m_linkRecords.size();
250 }
251 
254 {
255  NS_LOG_FUNCTION(this << n);
256  uint32_t j = 0;
257  for (auto i = m_linkRecords.begin(); i != m_linkRecords.end(); i++, j++)
258  {
259  if (j == n)
260  {
261  return *i;
262  }
263  }
264  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index");
265  return nullptr;
266 }
267 
268 bool
270 {
271  NS_LOG_FUNCTION(this);
272  return m_linkRecords.empty();
273 }
274 
277 {
278  NS_LOG_FUNCTION(this);
279  return m_lsType;
280 }
281 
282 void
284 {
285  NS_LOG_FUNCTION(this << typ);
286  m_lsType = typ;
287 }
288 
291 {
292  NS_LOG_FUNCTION(this);
293  return m_linkStateId;
294 }
295 
296 void
298 {
299  NS_LOG_FUNCTION(this << addr);
300  m_linkStateId = addr;
301 }
302 
305 {
306  NS_LOG_FUNCTION(this);
307  return m_advertisingRtr;
308 }
309 
310 void
312 {
313  NS_LOG_FUNCTION(this << addr);
314  m_advertisingRtr = addr;
315 }
316 
317 void
319 {
320  NS_LOG_FUNCTION(this << mask);
322 }
323 
324 Ipv4Mask
326 {
327  NS_LOG_FUNCTION(this);
329 }
330 
333 {
334  NS_LOG_FUNCTION(this);
335  return m_status;
336 }
337 
338 uint32_t
340 {
341  NS_LOG_FUNCTION(this << addr);
342  m_attachedRouters.push_back(addr);
343  return m_attachedRouters.size();
344 }
345 
346 uint32_t
348 {
349  NS_LOG_FUNCTION(this);
350  return m_attachedRouters.size();
351 }
352 
355 {
356  NS_LOG_FUNCTION(this << n);
357  uint32_t j = 0;
358  for (auto i = m_attachedRouters.begin(); i != m_attachedRouters.end(); i++, j++)
359  {
360  if (j == n)
361  {
362  return *i;
363  }
364  }
365  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
366  return Ipv4Address("0.0.0.0");
367 }
368 
369 void
371 {
372  NS_LOG_FUNCTION(this << status);
373  m_status = status;
374 }
375 
376 Ptr<Node>
378 {
379  NS_LOG_FUNCTION(this);
381 }
382 
383 void
385 {
386  NS_LOG_FUNCTION(this << node);
387  m_node_id = node->GetId();
388 }
389 
390 void
391 GlobalRoutingLSA::Print(std::ostream& os) const
392 {
393  NS_LOG_FUNCTION(this << &os);
394  os << std::endl;
395  os << "========== Global Routing LSA ==========" << std::endl;
396  os << "m_lsType = " << m_lsType;
398  {
399  os << " (GlobalRoutingLSA::RouterLSA)";
400  }
402  {
403  os << " (GlobalRoutingLSA::NetworkLSA)";
404  }
406  {
407  os << " (GlobalRoutingLSA::ASExternalLSA)";
408  }
409  else
410  {
411  os << "(Unknown LSType)";
412  }
413  os << std::endl;
414 
415  os << "m_linkStateId = " << m_linkStateId << " (Router ID)" << std::endl;
416  os << "m_advertisingRtr = " << m_advertisingRtr << " (Router ID)" << std::endl;
417 
419  {
420  for (auto i = m_linkRecords.begin(); i != m_linkRecords.end(); i++)
421  {
422  GlobalRoutingLinkRecord* p = *i;
423 
424  os << "---------- RouterLSA Link Record ----------" << std::endl;
425  os << "m_linkType = " << p->m_linkType;
427  {
428  os << " (GlobalRoutingLinkRecord::PointToPoint)" << std::endl;
429  os << "m_linkId = " << p->m_linkId << std::endl;
430  os << "m_linkData = " << p->m_linkData << std::endl;
431  os << "m_metric = " << p->m_metric << std::endl;
432  }
434  {
435  os << " (GlobalRoutingLinkRecord::TransitNetwork)" << std::endl;
436  os << "m_linkId = " << p->m_linkId << " (Designated router for network)"
437  << std::endl;
438  os << "m_linkData = " << p->m_linkData << " (This router's IP address)"
439  << std::endl;
440  os << "m_metric = " << p->m_metric << std::endl;
441  }
443  {
444  os << " (GlobalRoutingLinkRecord::StubNetwork)" << std::endl;
445  os << "m_linkId = " << p->m_linkId << " (Network number of attached network)"
446  << std::endl;
447  os << "m_linkData = " << p->m_linkData << " (Network mask of attached network)"
448  << std::endl;
449  os << "m_metric = " << p->m_metric << std::endl;
450  }
451  else
452  {
453  os << " (Unknown LinkType)" << std::endl;
454  os << "m_linkId = " << p->m_linkId << std::endl;
455  os << "m_linkData = " << p->m_linkData << std::endl;
456  os << "m_metric = " << p->m_metric << std::endl;
457  }
458  os << "---------- End RouterLSA Link Record ----------" << std::endl;
459  }
460  }
462  {
463  os << "---------- NetworkLSA Link Record ----------" << std::endl;
464  os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask << std::endl;
465  for (auto i = m_attachedRouters.begin(); i != m_attachedRouters.end(); i++)
466  {
467  Ipv4Address p = *i;
468  os << "attachedRouter = " << p << std::endl;
469  }
470  os << "---------- End NetworkLSA Link Record ----------" << std::endl;
471  }
473  {
474  os << "---------- ASExternalLSA Link Record --------" << std::endl;
475  os << "m_linkStateId = " << m_linkStateId << std::endl;
476  os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask << std::endl;
477  }
478  else
479  {
480  NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
481  }
482  os << "========== End Global Routing LSA ==========" << std::endl;
483 }
484 
485 std::ostream&
486 operator<<(std::ostream& os, GlobalRoutingLSA& lsa)
487 {
488  lsa.Print(os);
489  return os;
490 }
491 
492 // ---------------------------------------------------------------------------
493 //
494 // GlobalRouter Implementation
495 //
496 // ---------------------------------------------------------------------------
497 
498 NS_OBJECT_ENSURE_REGISTERED(GlobalRouter);
499 
500 TypeId
502 {
503  static TypeId tid = TypeId("ns3::GlobalRouter").SetParent<Object>().SetGroupName("Internet");
504  return tid;
505 }
506 
508  : m_LSAs()
509 {
510  NS_LOG_FUNCTION(this);
512 }
513 
515 {
516  NS_LOG_FUNCTION(this);
517  ClearLSAs();
518 }
519 
520 void
522 {
523  NS_LOG_FUNCTION(this << routing);
524  m_routingProtocol = routing;
525 }
526 
529 {
530  NS_LOG_FUNCTION(this);
531  return m_routingProtocol;
532 }
533 
534 void
536 {
537  NS_LOG_FUNCTION(this);
538  m_routingProtocol = nullptr;
539  for (auto k = m_injectedRoutes.begin(); k != m_injectedRoutes.end();
540  k = m_injectedRoutes.erase(k))
541  {
542  delete (*k);
543  }
545 }
546 
547 void
549 {
550  NS_LOG_FUNCTION(this);
551  for (auto i = m_LSAs.begin(); i != m_LSAs.end(); i++)
552  {
553  NS_LOG_LOGIC("Free LSA");
554 
555  GlobalRoutingLSA* p = *i;
556  delete p;
557  p = nullptr;
558 
559  *i = nullptr;
560  }
561  NS_LOG_LOGIC("Clear list of LSAs");
562  m_LSAs.clear();
563 }
564 
567 {
568  NS_LOG_FUNCTION(this);
569  return m_routerId;
570 }
571 
572 //
573 // DiscoverLSAs is called on all nodes in the system that have a GlobalRouter
574 // interface aggregated. We need to go out and discover any adjacent routers
575 // and build the Link State Advertisements that reflect them and their associated
576 // networks.
577 //
578 uint32_t
580 {
581  NS_LOG_FUNCTION(this);
582  Ptr<Node> node = GetObject<Node>();
583  NS_ABORT_MSG_UNLESS(node,
584  "GlobalRouter::DiscoverLSAs (): GetObject for <Node> interface failed");
585  NS_LOG_LOGIC("For node " << node->GetId());
586 
587  ClearLSAs();
588 
589  //
590  // While building the Router-LSA, keep a list of those NetDevices for
591  // which the current node is the designated router and we will later build
592  // a NetworkLSA for.
593  //
595 
596  //
597  // We're aggregated to a node. We need to ask the node for a pointer to its
598  // Ipv4 interface. This is where the information regarding the attached
599  // interfaces lives. If we're a router, we had better have an Ipv4 interface.
600  //
601  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4>();
602  NS_ABORT_MSG_UNLESS(ipv4Local,
603  "GlobalRouter::DiscoverLSAs (): GetObject for <Ipv4> interface failed");
604 
605  //
606  // Every router node originates a Router-LSA
607  //
608  auto pLSA = new GlobalRoutingLSA;
610  pLSA->SetLinkStateId(m_routerId);
611  pLSA->SetAdvertisingRouter(m_routerId);
613  pLSA->SetNode(node);
614 
615  //
616  // Ask the node for the number of net devices attached. This isn't necessarily
617  // equal to the number of links to adjacent nodes (other routers) as the number
618  // of devices may include those for stub networks (e.g., ethernets, etc.) and
619  // bridge devices also take up an "extra" net device.
620  //
621  uint32_t numDevices = node->GetNDevices();
622 
623  //
624  // Iterate through the devices on the node and walk the channel to see what's
625  // on the other side of the standalone devices..
626  //
627  for (uint32_t i = 0; i < numDevices; ++i)
628  {
629  Ptr<NetDevice> ndLocal = node->GetDevice(i);
630 
631  if (DynamicCast<LoopbackNetDevice>(ndLocal))
632  {
633  continue;
634  }
635 
636  //
637  // There is an assumption that bridge ports must never have an IP address
638  // associated with them. This turns out to be a very convenient place to
639  // check and make sure that this is the case.
640  //
641  if (NetDeviceIsBridged(ndLocal))
642  {
643  int32_t ifIndex = ipv4Local->GetInterfaceForDevice(ndLocal);
645  ifIndex != -1,
646  "GlobalRouter::DiscoverLSAs(): Bridge ports must not have an IPv4 interface index");
647  }
648 
649  //
650  // Check to see if the net device we just got has a corresponding IP
651  // interface (could be a pure L2 NetDevice) -- for example a net device
652  // associated with a bridge. We are only going to involve devices with
653  // IP addresses in routing.
654  //
655  int32_t interfaceNumber = ipv4Local->GetInterfaceForDevice(ndLocal);
656  if (interfaceNumber == -1 ||
657  !(ipv4Local->IsUp(interfaceNumber) && ipv4Local->IsForwarding(interfaceNumber)))
658  {
659  NS_LOG_LOGIC("Net device "
660  << ndLocal
661  << "has no IP interface or is not enabled for forwarding, skipping");
662  continue;
663  }
664 
665  //
666  // We have a net device that we need to check out. If it supports
667  // broadcast and is not a point-point link, then it will be either a stub
668  // network or a transit network depending on the number of routers on
669  // the segment. We add the appropriate link record to the LSA.
670  //
671  // If the device is a point to point link, we treat it separately. In
672  // that case, there may be zero, one, or two link records added.
673  //
674 
675  if (ndLocal->IsBroadcast() && !ndLocal->IsPointToPoint())
676  {
677  NS_LOG_LOGIC("Broadcast link");
678  ProcessBroadcastLink(ndLocal, pLSA, c);
679  }
680  else if (ndLocal->IsPointToPoint())
681  {
682  NS_LOG_LOGIC("Point=to-point link");
683  ProcessPointToPointLink(ndLocal, pLSA);
684  }
685  else
686  {
687  NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
688  }
689  }
690 
691  NS_LOG_LOGIC("========== LSA for node " << node->GetId() << " ==========");
692  NS_LOG_LOGIC(*pLSA);
693  m_LSAs.push_back(pLSA);
694  pLSA = nullptr;
695 
696  //
697  // Now, determine whether we need to build a NetworkLSA. This is the case if
698  // we found at least one designated router.
699  //
700  uint32_t nDesignatedRouters = c.GetN();
701  if (nDesignatedRouters > 0)
702  {
703  NS_LOG_LOGIC("Build Network LSAs");
704  BuildNetworkLSAs(c);
705  }
706 
707  //
708  // Build injected route LSAs as external routes
709  // RFC 2328, section 12.4.4
710  //
711  for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
712  {
713  auto pLSA = new GlobalRoutingLSA;
715  pLSA->SetLinkStateId((*i)->GetDestNetwork());
716  pLSA->SetAdvertisingRouter(m_routerId);
717  pLSA->SetNetworkLSANetworkMask((*i)->GetDestNetworkMask());
719  m_LSAs.push_back(pLSA);
720  }
721  return m_LSAs.size();
722 }
723 
724 void
726 {
727  NS_LOG_FUNCTION(this << nd << pLSA << &c);
728 
729  if (nd->IsBridge())
730  {
731  ProcessBridgedBroadcastLink(nd, pLSA, c);
732  }
733  else
734  {
735  ProcessSingleBroadcastLink(nd, pLSA, c);
736  }
737 }
738 
739 void
741  GlobalRoutingLSA* pLSA,
743 {
744  NS_LOG_FUNCTION(this << nd << pLSA << &c);
745 
746  auto plr = new GlobalRoutingLinkRecord;
747  NS_ABORT_MSG_IF(plr == nullptr,
748  "GlobalRouter::ProcessSingleBroadcastLink(): Can't alloc link record");
749 
750  //
751  // We have some preliminaries to do to get enough information to proceed.
752  // This information we need comes from the internet stack, so notice that
753  // there is an implied assumption that global routing is only going to
754  // work with devices attached to the internet stack (have an ipv4 interface
755  // associated to them.
756  //
757  Ptr<Node> node = nd->GetNode();
758 
759  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4>();
761  ipv4Local,
762  "GlobalRouter::ProcessSingleBroadcastLink (): GetObject for <Ipv4> interface failed");
763 
764  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice(nd);
766  interfaceLocal == -1,
767  "GlobalRouter::ProcessSingleBroadcastLink(): No interface index associated with device");
768 
769  if (ipv4Local->GetNAddresses(interfaceLocal) > 1)
770  {
771  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
772  }
773  Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
774  Ipv4Mask maskLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetMask();
775  NS_LOG_LOGIC("Working with local address " << addrLocal);
776  uint16_t metricLocal = ipv4Local->GetMetric(interfaceLocal);
777 
778  //
779  // Check to see if the net device is connected to a channel/network that has
780  // another router on it. If there is no other router on the link (but us) then
781  // this is a stub network. If we find another router, then what we have here
782  // is a transit network.
783  //
785  if (!AnotherRouterOnLink(nd))
786  {
787  //
788  // This is a net device connected to a stub network
789  //
790  NS_LOG_LOGIC("Router-LSA Stub Network");
791  plr->SetLinkType(GlobalRoutingLinkRecord::StubNetwork);
792 
793  //
794  // According to OSPF, the Link ID is the IP network number of
795  // the attached network.
796  //
797  plr->SetLinkId(addrLocal.CombineMask(maskLocal));
798 
799  //
800  // and the Link Data is the network mask; converted to Ipv4Address
801  //
802  Ipv4Address maskLocalAddr;
803  maskLocalAddr.Set(maskLocal.Get());
804  plr->SetLinkData(maskLocalAddr);
805  plr->SetMetric(metricLocal);
806  pLSA->AddLinkRecord(plr);
807  plr = nullptr;
808  }
809  else
810  {
811  //
812  // We have multiple routers on a broadcast interface, so this is
813  // a transit network.
814  //
815  NS_LOG_LOGIC("Router-LSA Transit Network");
816  plr->SetLinkType(GlobalRoutingLinkRecord::TransitNetwork);
817 
818  //
819  // By definition, the router with the lowest IP address is the
820  // designated router for the network. OSPF says that the Link ID
821  // gets the IP interface address of the designated router in this
822  // case.
823  //
825  Ipv4Address designatedRtr;
826  designatedRtr = FindDesignatedRouterForLink(nd);
827 
828  //
829  // Let's double-check that any designated router we find out on our
830  // network is really on our network.
831  //
832  if (designatedRtr != "255.255.255.255")
833  {
834  Ipv4Address networkHere = addrLocal.CombineMask(maskLocal);
835  Ipv4Address networkThere = designatedRtr.CombineMask(maskLocal);
837  networkHere == networkThere,
838  "GlobalRouter::ProcessSingleBroadcastLink(): Network number confusion ("
839  << addrLocal << "/" << maskLocal.GetPrefixLength() << ", " << designatedRtr
840  << "/" << maskLocal.GetPrefixLength() << ")");
841  }
842  if (designatedRtr == addrLocal)
843  {
844  c.Add(nd);
845  NS_LOG_LOGIC("Node " << node->GetId() << " elected a designated router");
846  }
847  plr->SetLinkId(designatedRtr);
848 
849  //
850  // OSPF says that the Link Data is this router's own IP address.
851  //
852  plr->SetLinkData(addrLocal);
853  plr->SetMetric(metricLocal);
854  pLSA->AddLinkRecord(plr);
855  plr = nullptr;
856  }
857 }
858 
859 void
861  GlobalRoutingLSA* pLSA,
863 {
864  NS_LOG_FUNCTION(this << nd << pLSA << &c);
865  NS_ASSERT_MSG(nd->IsBridge(),
866  "GlobalRouter::ProcessBridgedBroadcastLink(): Called with non-bridge net device");
867 
868 #if 0
869  //
870  // It is possible to admit the possibility that a bridge device on a node
871  // can also participate in routing. This would surprise people who don't
872  // come from Microsoft-land where they do use such a construct. Based on
873  // the principle of least-surprise, we will leave the relatively simple
874  // code in place to do this, but not enable it until someone really wants
875  // the capability. Even then, we will not enable this code as a default
876  // but rather something you will have to go and turn on.
877  //
878 
879  Ptr<BridgeNetDevice> bnd = nd->GetObject<BridgeNetDevice> ();
880  NS_ABORT_MSG_UNLESS (bnd, "GlobalRouter::DiscoverLSAs (): GetObject for <BridgeNetDevice> failed");
881 
882  //
883  // We have some preliminaries to do to get enough information to proceed.
884  // This information we need comes from the internet stack, so notice that
885  // there is an implied assumption that global routing is only going to
886  // work with devices attached to the internet stack (have an ipv4 interface
887  // associated to them.
888  //
889  Ptr<Node> node = nd->GetNode ();
890  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4> ();
891  NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::ProcessBridgedBroadcastLink (): GetObject for <Ipv4> interface failed");
892 
893  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice (nd);
894  NS_ABORT_MSG_IF (interfaceLocal == -1, "GlobalRouter::ProcessBridgedBroadcastLink(): No interface index associated with device");
895 
896  if (ipv4Local->GetNAddresses (interfaceLocal) > 1)
897  {
898  NS_LOG_WARN ("Warning, interface has multiple IP addresses; using only the primary one");
899  }
900  Ipv4Address addrLocal = ipv4Local->GetAddress (interfaceLocal, 0).GetLocal ();
901  Ipv4Mask maskLocal = ipv4Local->GetAddress (interfaceLocal, 0).GetMask ();
902  NS_LOG_LOGIC ("Working with local address " << addrLocal);
903  uint16_t metricLocal = ipv4Local->GetMetric (interfaceLocal);
904 
905  //
906  // We need to handle a bridge on the router. This means that we have been
907  // given a net device that is a BridgeNetDevice. It has an associated Ipv4
908  // interface index and address. Some number of other net devices live "under"
909  // the bridge device as so-called bridge ports. In a nutshell, what we have
910  // to do is to repeat what is done for a single broadcast link on all of
911  // those net devices living under the bridge (trolls?)
912  //
913 
914  bool areTransitNetwork = false;
915  Ipv4Address designatedRtr ("255.255.255.255");
916 
917  for (uint32_t i = 0; i < bnd->GetNBridgePorts (); ++i)
918  {
919  Ptr<NetDevice> ndTemp = bnd->GetBridgePort (i);
920 
921  //
922  // We have to decide if we are a transit network. This is characterized
923  // by the presence of another router on the network segment. If we find
924  // another router on any of our bridged links, we are a transit network.
925  //
927  if (AnotherRouterOnLink (ndTemp))
928  {
929  areTransitNetwork = true;
930 
931  //
932  // If we're going to be a transit network, then we have got to elect
933  // a designated router for the whole bridge. This means finding the
934  // router with the lowest IP address on the whole bridge. We ask
935  // for the lowest address on each segment and pick the lowest of them
936  // all.
937  //
939  Ipv4Address designatedRtrTemp = FindDesignatedRouterForLink (ndTemp);
940 
941  //
942  // Let's double-check that any designated router we find out on our
943  // network is really on our network.
944  //
945  if (designatedRtrTemp != "255.255.255.255")
946  {
947  Ipv4Address networkHere = addrLocal.CombineMask (maskLocal);
948  Ipv4Address networkThere = designatedRtrTemp.CombineMask (maskLocal);
949  NS_ABORT_MSG_UNLESS (networkHere == networkThere,
950  "GlobalRouter::ProcessSingleBroadcastLink(): Network number confusion (" <<
951  addrLocal << "/" << maskLocal.GetPrefixLength () << ", " <<
952  designatedRtrTemp << "/" << maskLocal.GetPrefixLength () << ")");
953  }
954  if (designatedRtrTemp < designatedRtr)
955  {
956  designatedRtr = designatedRtrTemp;
957  }
958  }
959  }
960  //
961  // That's all the information we need to put it all together, just like we did
962  // in the case of a single broadcast link.
963  //
964 
966  NS_ABORT_MSG_IF (plr == 0, "GlobalRouter::ProcessBridgedBroadcastLink(): Can't alloc link record");
967 
968  if (areTransitNetwork == false)
969  {
970  //
971  // This is a net device connected to a bridge of stub networks
972  //
973  NS_LOG_LOGIC ("Router-LSA Stub Network");
975 
976  //
977  // According to OSPF, the Link ID is the IP network number of
978  // the attached network.
979  //
980  plr->SetLinkId (addrLocal.CombineMask (maskLocal));
981 
982  //
983  // and the Link Data is the network mask; converted to Ipv4Address
984  //
985  Ipv4Address maskLocalAddr;
986  maskLocalAddr.Set (maskLocal.Get ());
987  plr->SetLinkData (maskLocalAddr);
988  plr->SetMetric (metricLocal);
989  pLSA->AddLinkRecord (plr);
990  plr = 0;
991  }
992  else
993  {
994  //
995  // We have multiple routers on a bridged broadcast interface, so this is
996  // a transit network.
997  //
998  NS_LOG_LOGIC ("Router-LSA Transit Network");
1000 
1001  //
1002  // By definition, the router with the lowest IP address is the
1003  // designated router for the network. OSPF says that the Link ID
1004  // gets the IP interface address of the designated router in this
1005  // case.
1006  //
1007  if (designatedRtr == addrLocal)
1008  {
1009  c.Add (nd);
1010  NS_LOG_LOGIC ("Node " << node->GetId () << " elected a designated router");
1011  }
1012  plr->SetLinkId (designatedRtr);
1013 
1014  //
1015  // OSPF says that the Link Data is this router's own IP address.
1016  //
1017  plr->SetLinkData (addrLocal);
1018  plr->SetMetric (metricLocal);
1019  pLSA->AddLinkRecord (plr);
1020  plr = 0;
1021  }
1022 #endif
1023 }
1024 
1025 void
1027 {
1028  NS_LOG_FUNCTION(this << ndLocal << pLSA);
1029 
1030  //
1031  // We have some preliminaries to do to get enough information to proceed.
1032  // This information we need comes from the internet stack, so notice that
1033  // there is an implied assumption that global routing is only going to
1034  // work with devices attached to the internet stack (have an ipv4 interface
1035  // associated to them.
1036  //
1037  Ptr<Node> nodeLocal = ndLocal->GetNode();
1038 
1039  Ptr<Ipv4> ipv4Local = nodeLocal->GetObject<Ipv4>();
1041  ipv4Local,
1042  "GlobalRouter::ProcessPointToPointLink (): GetObject for <Ipv4> interface failed");
1043 
1044  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice(ndLocal);
1046  interfaceLocal == -1,
1047  "GlobalRouter::ProcessPointToPointLink (): No interface index associated with device");
1048 
1049  if (ipv4Local->GetNAddresses(interfaceLocal) > 1)
1050  {
1051  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
1052  }
1053  Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
1054  NS_LOG_LOGIC("Working with local address " << addrLocal);
1055  uint16_t metricLocal = ipv4Local->GetMetric(interfaceLocal);
1056 
1057  //
1058  // Now, we're going to walk over to the remote net device on the other end of
1059  // the point-to-point channel we know we have. This is where our adjacent
1060  // router (to use OSPF lingo) is running.
1061  //
1062  Ptr<Channel> ch = ndLocal->GetChannel();
1063 
1064  //
1065  // Get the net device on the other side of the point-to-point channel.
1066  //
1067  Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
1068 
1069  //
1070  // The adjacent net device is aggregated to a node. We need to ask that net
1071  // device for its node, then ask that node for its Ipv4 interface. Note a
1072  // requirement that nodes on either side of a point-to-point link must have
1073  // internet stacks; and an assumption that point-to-point links are incompatible
1074  // with bridging.
1075  //
1076  Ptr<Node> nodeRemote = ndRemote->GetNode();
1077  Ptr<Ipv4> ipv4Remote = nodeRemote->GetObject<Ipv4>();
1079  ipv4Remote,
1080  "GlobalRouter::ProcessPointToPointLink(): GetObject for remote <Ipv4> failed");
1081 
1082  //
1083  // Further note the requirement that nodes on either side of a point-to-point
1084  // link must participate in global routing and therefore have a GlobalRouter
1085  // interface aggregated.
1086  //
1087  Ptr<GlobalRouter> rtrRemote = nodeRemote->GetObject<GlobalRouter>();
1088  if (!rtrRemote)
1089  {
1090  // This case is possible if the remote does not participate in global routing
1091  return;
1092  }
1093  //
1094  // We're going to need the remote router ID, so we might as well get it now.
1095  //
1096  Ipv4Address rtrIdRemote = rtrRemote->GetRouterId();
1097  NS_LOG_LOGIC("Working with remote router " << rtrIdRemote);
1098 
1099  //
1100  // Now, just like we did above, we need to get the IP interface index for the
1101  // net device on the other end of the point-to-point channel.
1102  //
1103  int32_t interfaceRemote = ipv4Remote->GetInterfaceForDevice(ndRemote);
1104  NS_ABORT_MSG_IF(interfaceRemote == -1,
1105  "GlobalRouter::ProcessPointToPointLinks(): No interface index associated with "
1106  "remote device");
1107 
1108  //
1109  // Now that we have the Ipv4 interface, we can get the (remote) address and
1110  // mask we need.
1111  //
1112  if (ipv4Remote->GetNAddresses(interfaceRemote) > 1)
1113  {
1114  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
1115  }
1116  Ipv4Address addrRemote = ipv4Remote->GetAddress(interfaceRemote, 0).GetLocal();
1117  Ipv4Mask maskRemote = ipv4Remote->GetAddress(interfaceRemote, 0).GetMask();
1118  NS_LOG_LOGIC("Working with remote address " << addrRemote);
1119 
1120  //
1121  // Now we can fill out the link records for this link. There are always two
1122  // link records; the first is a point-to-point record describing the link and
1123  // the second is a stub network record with the network number.
1124  //
1126  if (ipv4Remote->IsUp(interfaceRemote))
1127  {
1128  NS_LOG_LOGIC("Remote side interface " << interfaceRemote << " is up-- add a type 1 link");
1129 
1130  plr = new GlobalRoutingLinkRecord;
1131  NS_ABORT_MSG_IF(plr == nullptr,
1132  "GlobalRouter::ProcessPointToPointLink(): Can't alloc link record");
1134  plr->SetLinkId(rtrIdRemote);
1135  plr->SetLinkData(addrLocal);
1136  plr->SetMetric(metricLocal);
1137  pLSA->AddLinkRecord(plr);
1138  plr = nullptr;
1139  }
1140 
1141  // Regardless of state of peer, add a type 3 link (RFC 2328: 12.4.1.1)
1142  plr = new GlobalRoutingLinkRecord;
1143  NS_ABORT_MSG_IF(plr == nullptr,
1144  "GlobalRouter::ProcessPointToPointLink(): Can't alloc link record");
1146  plr->SetLinkId(addrRemote);
1147  plr->SetLinkData(Ipv4Address(maskRemote.Get())); // Frown
1148  plr->SetMetric(metricLocal);
1149  pLSA->AddLinkRecord(plr);
1150  plr = nullptr;
1151 }
1152 
1153 void
1155 {
1156  NS_LOG_FUNCTION(this << &c);
1157 
1158  uint32_t nDesignatedRouters = c.GetN();
1159  NS_LOG_DEBUG("Number of designated routers: " << nDesignatedRouters);
1160 
1161  for (uint32_t i = 0; i < nDesignatedRouters; ++i)
1162  {
1163  //
1164  // Build one NetworkLSA for each net device talking to a network that we are the
1165  // designated router for. These devices are in the provided container.
1166  //
1167  Ptr<NetDevice> ndLocal = c.Get(i);
1168  Ptr<Node> node = ndLocal->GetNode();
1169 
1170  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4>();
1172  ipv4Local,
1173  "GlobalRouter::ProcessPointToPointLink (): GetObject for <Ipv4> interface failed");
1174 
1175  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice(ndLocal);
1177  interfaceLocal == -1,
1178  "GlobalRouter::BuildNetworkLSAs (): No interface index associated with device");
1179 
1180  if (ipv4Local->GetNAddresses(interfaceLocal) > 1)
1181  {
1182  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
1183  }
1184  Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
1185  Ipv4Mask maskLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetMask();
1186 
1187  auto pLSA = new GlobalRoutingLSA;
1188  NS_ABORT_MSG_IF(pLSA == nullptr,
1189  "GlobalRouter::BuildNetworkLSAs(): Can't alloc link record");
1190 
1191  pLSA->SetLSType(GlobalRoutingLSA::NetworkLSA);
1192  pLSA->SetLinkStateId(addrLocal);
1193  pLSA->SetAdvertisingRouter(m_routerId);
1194  pLSA->SetNetworkLSANetworkMask(maskLocal);
1195  pLSA->SetStatus(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
1196  pLSA->SetNode(node);
1197 
1198  //
1199  // Build a list of AttachedRouters by walking the devices in the channel
1200  // and, if we find a node with a GlobalRouter interface and an IPv4
1201  // interface associated with that device, we call it an attached router.
1202  //
1204  Ptr<Channel> ch = ndLocal->GetChannel();
1205  std::size_t nDevices = ch->GetNDevices();
1206  NS_ASSERT(nDevices);
1208  NS_LOG_LOGIC("Found " << deviceList.GetN() << " non-bridged devices on channel");
1209 
1210  for (uint32_t i = 0; i < deviceList.GetN(); i++)
1211  {
1212  Ptr<NetDevice> tempNd = deviceList.Get(i);
1213  NS_ASSERT(tempNd);
1214  if (tempNd == ndLocal)
1215  {
1216  NS_LOG_LOGIC("Adding " << addrLocal << " to Network LSA");
1217  pLSA->AddAttachedRouter(addrLocal);
1218  continue;
1219  }
1220  Ptr<Node> tempNode = tempNd->GetNode();
1221 
1222  // Does the node in question have a GlobalRouter interface? If not it can
1223  // hardly be considered an attached router.
1224  //
1225  Ptr<GlobalRouter> rtr = tempNode->GetObject<GlobalRouter>();
1226  if (!rtr)
1227  {
1228  NS_LOG_LOGIC("Node " << tempNode->GetId()
1229  << " does not have GlobalRouter interface--skipping");
1230  continue;
1231  }
1232 
1233  //
1234  // Does the attached node have an ipv4 interface for the device we're probing?
1235  // If not, it can't play router.
1236  //
1237  Ptr<Ipv4> tempIpv4 = tempNode->GetObject<Ipv4>();
1238  int32_t tempInterface = tempIpv4->GetInterfaceForDevice(tempNd);
1239 
1240  if (tempInterface != -1)
1241  {
1242  Ptr<Ipv4> tempIpv4 = tempNode->GetObject<Ipv4>();
1243  NS_ASSERT(tempIpv4);
1244  if (!tempIpv4->IsUp(tempInterface))
1245  {
1246  NS_LOG_LOGIC("Remote side interface " << tempInterface << " not up");
1247  }
1248  else
1249  {
1250  if (tempIpv4->GetNAddresses(tempInterface) > 1)
1251  {
1252  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the "
1253  "primary one");
1254  }
1255  Ipv4Address tempAddr = tempIpv4->GetAddress(tempInterface, 0).GetLocal();
1256  NS_LOG_LOGIC("Adding " << tempAddr << " to Network LSA");
1257  pLSA->AddAttachedRouter(tempAddr);
1258  }
1259  }
1260  else
1261  {
1262  NS_LOG_LOGIC("Node " << tempNode->GetId() << " device " << tempNd
1263  << " does not have IPv4 interface; skipping");
1264  }
1265  }
1266  m_LSAs.push_back(pLSA);
1267  NS_LOG_LOGIC("========== LSA for node " << node->GetId() << " ==========");
1268  NS_LOG_LOGIC(*pLSA);
1269  pLSA = nullptr;
1270  }
1271 }
1272 
1275 {
1276  NS_LOG_FUNCTION(this << ch);
1278 
1279  for (std::size_t i = 0; i < ch->GetNDevices(); i++)
1280  {
1281  Ptr<NetDevice> nd = ch->GetDevice(i);
1282  NS_LOG_LOGIC("checking to see if the device " << nd << " is bridged");
1284  if (bnd && !BridgeHasAlreadyBeenVisited(bnd))
1285  {
1286  NS_LOG_LOGIC("Device is bridged by BridgeNetDevice "
1287  << bnd << " with " << bnd->GetNBridgePorts() << " ports");
1288  MarkBridgeAsVisited(bnd);
1289  // Find all channels bridged together, and recursively call
1290  // on all other channels
1291  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); j++)
1292  {
1293  Ptr<NetDevice> bridgedDevice = bnd->GetBridgePort(j);
1294  if (bridgedDevice->GetChannel() == ch)
1295  {
1296  NS_LOG_LOGIC("Skipping my own device/channel");
1297  continue;
1298  }
1299  NS_LOG_LOGIC("Calling on channel " << bridgedDevice->GetChannel());
1300  c.Add(FindAllNonBridgedDevicesOnLink(bridgedDevice->GetChannel()));
1301  }
1302  }
1303  else
1304  {
1305  NS_LOG_LOGIC("Device is not bridged; adding");
1306  c.Add(nd);
1307  }
1308  }
1309  NS_LOG_LOGIC("Found " << c.GetN() << " devices");
1310  return c;
1311 }
1312 
1313 //
1314 // Given a local net device, we need to walk the channel to which the net device is
1315 // attached and look for nodes with GlobalRouter interfaces on them (one of them
1316 // will be us). Of these, the router with the lowest IP address on the net device
1317 // connecting to the channel becomes the designated router for the link.
1318 //
1321 {
1322  NS_LOG_FUNCTION(this << ndLocal);
1323 
1324  Ptr<Channel> ch = ndLocal->GetChannel();
1325  uint32_t nDevices = ch->GetNDevices();
1326  NS_ASSERT(nDevices);
1327 
1328  NS_LOG_LOGIC("Looking for designated router off of net device " << ndLocal << " on node "
1329  << ndLocal->GetNode()->GetId());
1330 
1331  Ipv4Address designatedRtr("255.255.255.255");
1332 
1333  //
1334  // Look through all of the devices on the channel to which the net device
1335  // in question is attached.
1336  //
1337  for (uint32_t i = 0; i < nDevices; i++)
1338  {
1339  Ptr<NetDevice> ndOther = ch->GetDevice(i);
1340  NS_ASSERT(ndOther);
1341 
1342  Ptr<Node> nodeOther = ndOther->GetNode();
1343 
1344  NS_LOG_LOGIC("Examine channel device " << i << " on node " << nodeOther->GetId());
1345 
1346  //
1347  // For all other net devices, we need to check and see if a router
1348  // is present. If the net device on the other side is a bridged
1349  // device, we need to consider all of the other devices on the
1350  // bridge as well (all of the bridge ports.
1351  //
1352  NS_LOG_LOGIC("checking to see if the device is bridged");
1354  if (bnd)
1355  {
1356  NS_LOG_LOGIC("Device is bridged by BridgeNetDevice " << bnd);
1357 
1358  //
1359  // When enumerating a bridge, don't count the netdevice we came in on
1360  //
1361  if (ndLocal == ndOther)
1362  {
1363  NS_LOG_LOGIC("Skip -- it is where we came from.");
1364  continue;
1365  }
1366 
1367  //
1368  // It is possible that the bridge net device is sitting under a
1369  // router, so we have to check for the presence of that router
1370  // before we run off and follow all the links
1371  //
1372  // We require a designated router to have a GlobalRouter interface and
1373  // an internet stack that includes the Ipv4 interface. If it doesn't
1374  // it can't play router.
1375  //
1376  NS_LOG_LOGIC("Checking for router on bridge net device " << bnd);
1377  Ptr<GlobalRouter> rtr = nodeOther->GetObject<GlobalRouter>();
1378  Ptr<Ipv4> ipv4 = nodeOther->GetObject<Ipv4>();
1379  if (rtr && ipv4)
1380  {
1381  int32_t interfaceOther = ipv4->GetInterfaceForDevice(bnd);
1382  if (interfaceOther != -1)
1383  {
1384  NS_LOG_LOGIC("Found router on bridge net device " << bnd);
1385  if (!ipv4->IsUp(interfaceOther))
1386  {
1387  NS_LOG_LOGIC("Remote side interface " << interfaceOther << " not up");
1388  continue;
1389  }
1390  if (ipv4->GetNAddresses(interfaceOther) > 1)
1391  {
1392  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the "
1393  "primary one");
1394  }
1395  Ipv4Address addrOther = ipv4->GetAddress(interfaceOther, 0).GetLocal();
1396  designatedRtr = addrOther < designatedRtr ? addrOther : designatedRtr;
1397  NS_LOG_LOGIC("designated router now " << designatedRtr);
1398  }
1399  }
1400 
1401  //
1402  // Check if we have seen this bridge net device already while
1403  // recursively enumerating an L2 broadcast domain. If it is new
1404  // to us, go ahead and process it. If we have already processed it,
1405  // move to the next
1406  //
1407  if (BridgeHasAlreadyBeenVisited(bnd))
1408  {
1409  NS_ABORT_MSG("ERROR: L2 forwarding loop detected!");
1410  }
1411 
1412  MarkBridgeAsVisited(bnd);
1413 
1414  NS_LOG_LOGIC("Looking through bridge ports of bridge net device " << bnd);
1415  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
1416  {
1417  Ptr<NetDevice> ndBridged = bnd->GetBridgePort(j);
1418  NS_LOG_LOGIC("Examining bridge port " << j << " device " << ndBridged);
1419  if (ndBridged == ndOther)
1420  {
1421  NS_LOG_LOGIC("That bridge port is me, don't walk backward");
1422  continue;
1423  }
1424 
1425  NS_LOG_LOGIC("Recursively looking for routers down bridge port " << ndBridged);
1426  Ipv4Address addrOther = FindDesignatedRouterForLink(ndBridged);
1427  designatedRtr = addrOther < designatedRtr ? addrOther : designatedRtr;
1428  NS_LOG_LOGIC("designated router now " << designatedRtr);
1429  }
1430  }
1431  else
1432  {
1433  NS_LOG_LOGIC("This device is not bridged");
1434  Ptr<Node> nodeOther = ndOther->GetNode();
1435  NS_ASSERT(nodeOther);
1436 
1437  //
1438  // We require a designated router to have a GlobalRouter interface and
1439  // an internet stack that includes the Ipv4 interface. If it doesn't
1440  //
1441  Ptr<GlobalRouter> rtr = nodeOther->GetObject<GlobalRouter>();
1442  Ptr<Ipv4> ipv4 = nodeOther->GetObject<Ipv4>();
1443  if (rtr && ipv4)
1444  {
1445  int32_t interfaceOther = ipv4->GetInterfaceForDevice(ndOther);
1446  if (interfaceOther != -1)
1447  {
1448  if (!ipv4->IsUp(interfaceOther))
1449  {
1450  NS_LOG_LOGIC("Remote side interface " << interfaceOther << " not up");
1451  continue;
1452  }
1453  NS_LOG_LOGIC("Found router on net device " << ndOther);
1454  if (ipv4->GetNAddresses(interfaceOther) > 1)
1455  {
1456  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the "
1457  "primary one");
1458  }
1459  Ipv4Address addrOther = ipv4->GetAddress(interfaceOther, 0).GetLocal();
1460  designatedRtr = addrOther < designatedRtr ? addrOther : designatedRtr;
1461  NS_LOG_LOGIC("designated router now " << designatedRtr);
1462  }
1463  }
1464  }
1465  }
1466  return designatedRtr;
1467 }
1468 
1469 //
1470 // Given a node and an attached net device, take a look off in the channel to
1471 // which the net device is attached and look for a node on the other side
1472 // that has a GlobalRouter interface aggregated. Life gets more complicated
1473 // when there is a bridged net device on the other side.
1474 //
1475 bool
1477 {
1478  NS_LOG_FUNCTION(this << nd);
1479 
1480  Ptr<Channel> ch = nd->GetChannel();
1481  if (!ch)
1482  {
1483  // It may be that this net device is a stub device, without a channel
1484  return false;
1485  }
1486  uint32_t nDevices = ch->GetNDevices();
1487  NS_ASSERT(nDevices);
1488 
1489  NS_LOG_LOGIC("Looking for routers off of net device " << nd << " on node "
1490  << nd->GetNode()->GetId());
1491 
1492  //
1493  // Look through all of the devices on the channel to which the net device
1494  // in question is attached.
1495  //
1496  for (uint32_t i = 0; i < nDevices; i++)
1497  {
1498  Ptr<NetDevice> ndOther = ch->GetDevice(i);
1499  NS_ASSERT(ndOther);
1500 
1501  NS_LOG_LOGIC("Examine channel device " << i << " on node " << ndOther->GetNode()->GetId());
1502 
1503  //
1504  // Ignore the net device itself.
1505  //
1506  if (ndOther == nd)
1507  {
1508  NS_LOG_LOGIC("Myself, skip");
1509  continue;
1510  }
1511 
1512  //
1513  // For all other net devices, we need to check and see if a router
1514  // is present. If the net device on the other side is a bridged
1515  // device, we need to consider all of the other devices on the
1516  // bridge.
1517  //
1518  NS_LOG_LOGIC("checking to see if device is bridged");
1520  if (bnd)
1521  {
1522  NS_LOG_LOGIC("Device is bridged by net device " << bnd);
1523 
1524  //
1525  // Check if we have seen this bridge net device already while
1526  // recursively enumerating an L2 broadcast domain. If it is new
1527  // to us, go ahead and process it. If we have already processed it,
1528  // move to the next
1529  //
1530  if (BridgeHasAlreadyBeenVisited(bnd))
1531  {
1532  NS_ABORT_MSG("ERROR: L2 forwarding loop detected!");
1533  }
1534 
1535  MarkBridgeAsVisited(bnd);
1536 
1537  NS_LOG_LOGIC("Looking through bridge ports of bridge net device " << bnd);
1538  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
1539  {
1540  Ptr<NetDevice> ndBridged = bnd->GetBridgePort(j);
1541  NS_LOG_LOGIC("Examining bridge port " << j << " device " << ndBridged);
1542  if (ndBridged == ndOther)
1543  {
1544  NS_LOG_LOGIC("That bridge port is me, skip");
1545  continue;
1546  }
1547 
1548  NS_LOG_LOGIC("Recursively looking for routers on bridge port " << ndBridged);
1549  if (AnotherRouterOnLink(ndBridged))
1550  {
1551  NS_LOG_LOGIC("Found routers on bridge port, return true");
1552  return true;
1553  }
1554  }
1555  NS_LOG_LOGIC("No routers on bridged net device, return false");
1556  return false;
1557  }
1558 
1559  NS_LOG_LOGIC("This device is not bridged");
1560  Ptr<Node> nodeTemp = ndOther->GetNode();
1561  NS_ASSERT(nodeTemp);
1562 
1563  Ptr<GlobalRouter> rtr = nodeTemp->GetObject<GlobalRouter>();
1564  if (rtr)
1565  {
1566  NS_LOG_LOGIC("Found GlobalRouter interface, return true");
1567  return true;
1568  }
1569  else
1570  {
1571  NS_LOG_LOGIC("No GlobalRouter interface on device, continue search");
1572  }
1573  }
1574  NS_LOG_LOGIC("No routers found, return false");
1575  return false;
1576 }
1577 
1578 uint32_t
1580 {
1581  NS_LOG_FUNCTION(this);
1582  return m_LSAs.size();
1583 }
1584 
1585 //
1586 // Get the nth link state advertisement from this router.
1587 //
1588 bool
1590 {
1591  NS_LOG_FUNCTION(this << n << &lsa);
1592  NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA");
1593  //
1594  // All of the work was done in GetNumLSAs. All we have to do here is to
1595  // walk the list of link state advertisements created there and return the
1596  // one the client is interested in.
1597  //
1598  auto i = m_LSAs.begin();
1599  uint32_t j = 0;
1600 
1601  for (; i != m_LSAs.end(); i++, j++)
1602  {
1603  if (j == n)
1604  {
1605  GlobalRoutingLSA* p = *i;
1606  lsa = *p;
1607  return true;
1608  }
1609  }
1610 
1611  return false;
1612 }
1613 
1614 void
1616 {
1617  NS_LOG_FUNCTION(this << network << networkMask);
1618  auto route = new Ipv4RoutingTableEntry();
1619  //
1620  // Interface number does not matter here, using 1.
1621  //
1622  *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, 1);
1623  m_injectedRoutes.push_back(route);
1624 }
1625 
1628 {
1629  NS_LOG_FUNCTION(this << index);
1630  if (index < m_injectedRoutes.size())
1631  {
1632  uint32_t tmp = 0;
1633  for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
1634  {
1635  if (tmp == index)
1636  {
1637  return *i;
1638  }
1639  tmp++;
1640  }
1641  }
1642  NS_ASSERT(false);
1643  // quiet compiler.
1644  return nullptr;
1645 }
1646 
1647 uint32_t
1649 {
1650  NS_LOG_FUNCTION(this);
1651  return m_injectedRoutes.size();
1652 }
1653 
1654 void
1656 {
1657  NS_LOG_FUNCTION(this << index);
1658  NS_ASSERT(index < m_injectedRoutes.size());
1659  uint32_t tmp = 0;
1660  for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
1661  {
1662  if (tmp == index)
1663  {
1664  NS_LOG_LOGIC("Removing route " << index << "; size = " << m_injectedRoutes.size());
1665  delete *i;
1666  m_injectedRoutes.erase(i);
1667  return;
1668  }
1669  tmp++;
1670  }
1671 }
1672 
1673 bool
1675 {
1676  NS_LOG_FUNCTION(this << network << networkMask);
1677  for (auto i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
1678  {
1679  if ((*i)->GetDestNetwork() == network && (*i)->GetDestNetworkMask() == networkMask)
1680  {
1681  NS_LOG_LOGIC("Withdrawing route to network/mask " << network << "/" << networkMask);
1682  delete *i;
1683  m_injectedRoutes.erase(i);
1684  return true;
1685  }
1686  }
1687  return false;
1688 }
1689 
1690 //
1691 // Link through the given channel and find the net device that's on the
1692 // other end. This only makes sense with a point-to-point channel.
1693 //
1696 {
1697  NS_LOG_FUNCTION(this << nd << ch);
1698  NS_ASSERT_MSG(ch->GetNDevices() == 2,
1699  "GlobalRouter::GetAdjacent (): Channel with other than two devices");
1700  //
1701  // This is a point to point channel with two endpoints. Get both of them.
1702  //
1703  Ptr<NetDevice> nd1 = ch->GetDevice(0);
1704  Ptr<NetDevice> nd2 = ch->GetDevice(1);
1705  //
1706  // One of the endpoints is going to be "us" -- that is the net device attached
1707  // to the node on which we're running -- i.e., "nd". The other endpoint (the
1708  // one to which we are connected via the channel) is the adjacent router.
1709  //
1710  if (nd1 == nd)
1711  {
1712  return nd2;
1713  }
1714  else if (nd2 == nd)
1715  {
1716  return nd1;
1717  }
1718  else
1719  {
1720  NS_ASSERT_MSG(false, "GlobalRouter::GetAdjacent (): Wrong or confused channel?");
1721  return nullptr;
1722  }
1723 }
1724 
1725 //
1726 // Decide whether or not a given net device is being bridged by a BridgeNetDevice.
1727 //
1730 {
1731  NS_LOG_FUNCTION(this << nd);
1732 
1733  Ptr<Node> node = nd->GetNode();
1734  uint32_t nDevices = node->GetNDevices();
1735 
1736  //
1737  // There is no bit on a net device that says it is being bridged, so we have
1738  // to look for bridges on the node to which the device is attached. If we
1739  // find a bridge, we need to look through its bridge ports (the devices it
1740  // bridges) to see if we find the device in question.
1741  //
1742  for (uint32_t i = 0; i < nDevices; ++i)
1743  {
1744  Ptr<NetDevice> ndTest = node->GetDevice(i);
1745  NS_LOG_LOGIC("Examine device " << i << " " << ndTest);
1746 
1747  if (ndTest->IsBridge())
1748  {
1749  NS_LOG_LOGIC("device " << i << " is a bridge net device");
1750  Ptr<BridgeNetDevice> bnd = ndTest->GetObject<BridgeNetDevice>();
1752  bnd,
1753  "GlobalRouter::DiscoverLSAs (): GetObject for <BridgeNetDevice> failed");
1754 
1755  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
1756  {
1757  NS_LOG_LOGIC("Examine bridge port " << j << " " << bnd->GetBridgePort(j));
1758  if (bnd->GetBridgePort(j) == nd)
1759  {
1760  NS_LOG_LOGIC("Net device " << nd << " is bridged by " << bnd);
1761  return bnd;
1762  }
1763  }
1764  }
1765  }
1766  NS_LOG_LOGIC("Net device " << nd << " is not bridged");
1767  return nullptr;
1768 }
1769 
1770 //
1771 // Start a new enumeration of an L2 broadcast domain by clearing m_bridgesVisited
1772 //
1773 void
1775 {
1776  m_bridgesVisited.clear();
1777 }
1778 
1779 //
1780 // Check if we have already visited a given bridge net device by searching m_bridgesVisited
1781 //
1782 bool
1784 {
1785  for (auto iter = m_bridgesVisited.begin(); iter != m_bridgesVisited.end(); ++iter)
1786  {
1787  if (bridgeNetDevice == *iter)
1788  {
1789  NS_LOG_LOGIC("Bridge " << bridgeNetDevice << " has been visited.");
1790  return true;
1791  }
1792  }
1793  return false;
1794 }
1795 
1796 //
1797 // Remember that we visited a bridge net device by adding it to m_bridgesVisited
1798 //
1799 void
1801 {
1802  NS_LOG_FUNCTION(this << bridgeNetDevice);
1803  m_bridgesVisited.push_back(bridgeNetDevice);
1804 }
1805 
1806 } // namespace ns3
a virtual net device that bridges multiple LAN segments
virtual Ptr< NetDevice > GetDevice(std::size_t i) const =0
virtual std::size_t GetNDevices() const =0
static uint32_t AllocateRouterId()
Allocate a 32-bit router ID from monotonically increasing counter.
An interface aggregated to a node to provide global routing info.
Ipv4Address FindDesignatedRouterForLink(Ptr< NetDevice > ndLocal) const
Finds a designated router.
void MarkBridgeAsVisited(Ptr< BridgeNetDevice > device) const
When recursively checking for devices on the link, mark a given device as having been visited.
Ptr< Ipv4GlobalRouting > m_routingProtocol
the Ipv4GlobalRouting in use
bool GetLSA(uint32_t n, GlobalRoutingLSA &lsa) const
Get a Global Routing Link State Advertisements that this router has said that it can export.
void ProcessSingleBroadcastLink(Ptr< NetDevice > nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c)
Process a single broadcast link.
bool WithdrawRoute(Ipv4Address network, Ipv4Mask networkMask)
Withdraw a route from the global unicast routing table.
NetDeviceContainer FindAllNonBridgedDevicesOnLink(Ptr< Channel > ch) const
Return a container of all non-bridged NetDevices on a link.
bool BridgeHasAlreadyBeenVisited(Ptr< BridgeNetDevice > device) const
When recursively checking for devices on the link, check whether a given device has already been visi...
InjectedRoutes m_injectedRoutes
Routes we are exporting.
void ClearBridgesVisited() const
Clear the list of bridges visited on the link.
void InjectRoute(Ipv4Address network, Ipv4Mask networkMask)
Inject a route to be circulated to other routers as an external route.
Ptr< BridgeNetDevice > NetDeviceIsBridged(Ptr< NetDevice > nd) const
Decide whether or not a given net device is being bridged by a BridgeNetDevice.
Ipv4Address GetRouterId() const
Get the Router ID associated with this Global Router.
uint32_t GetNumLSAs() const
Get the Number of Global Routing Link State Advertisements that this router can export.
ListOfLSAs_t m_LSAs
database of GlobalRoutingLSAs
void ProcessBridgedBroadcastLink(Ptr< NetDevice > nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c)
Process a bridged broadcast link.
GlobalRouter()
Create a Global Router class.
Ipv4RoutingTableEntry * GetInjectedRoute(uint32_t i)
Return the injected route indexed by i.
void ClearLSAs()
Clear list of LSAs.
static TypeId GetTypeId()
Get the type ID.
Ptr< Ipv4GlobalRouting > GetRoutingProtocol()
Get the specific Global Routing Protocol used.
Ipv4Address m_routerId
router ID (its IPv4 address)
void RemoveInjectedRoute(uint32_t i)
Withdraw a route from the global unicast routing table.
bool AnotherRouterOnLink(Ptr< NetDevice > nd) const
Checks for the presence of another router on the NetDevice.
void SetRoutingProtocol(Ptr< Ipv4GlobalRouting > routing)
Set the specific Global Routing Protocol to be used.
Ptr< NetDevice > GetAdjacent(Ptr< NetDevice > nd, Ptr< Channel > ch) const
Link through the given channel and find the net device that's on the other end.
std::vector< Ptr< BridgeNetDevice > > m_bridgesVisited
Container of bridges visited.
void ProcessPointToPointLink(Ptr< NetDevice > ndLocal, GlobalRoutingLSA *pLSA)
Process a point to point link.
uint32_t DiscoverLSAs()
Walk the connected channels, discover the adjacent routers and build the associated number of Global ...
void DoDispose() override
Destructor implementation.
void ProcessBroadcastLink(Ptr< NetDevice > nd, GlobalRoutingLSA *pLSA, NetDeviceContainer &c)
Process a generic broadcast link.
uint32_t GetNInjectedRoutes()
Get the number of injected routes that have been added to the routing table.
void BuildNetworkLSAs(NetDeviceContainer c)
Build one NetworkLSA for each net device talking to a network that we are the designated router for.
a Link State Advertisement (LSA) for a router, used in global routing.
Ipv4Address GetAdvertisingRouter() const
Get the Advertising Router as defined by the OSPF spec.
void SetStatus(SPFStatus status)
Set the SPF status of the advertisement.
void Print(std::ostream &os) const
Print the contents of the Global Routing Link State Advertisement and any Global Routing Link Records...
SPFStatus
Enumeration of the possible values of the status flag in the Routing Link State Advertisements.
@ LSA_SPF_NOT_EXPLORED
New vertex not yet considered.
uint32_t GetNAttachedRouters() const
Return the number of attached routers listed in the NetworkLSA.
Ptr< Node > GetNode() const
Get the Node pointer of the node that originated this LSA.
uint32_t AddLinkRecord(GlobalRoutingLinkRecord *lr)
Add a given Global Routing Link Record to the LSA.
LSType
corresponds to LS type field of RFC 2328 OSPF LSA header
SPFStatus GetStatus() const
Get the SPF status of the advertisement.
Ipv4Address m_linkStateId
The Link State ID is defined by the OSPF spec.
bool IsEmpty() const
Check to see if the list of Global Routing Link Records present in the Global Routing Link State Adve...
Ipv4Mask GetNetworkLSANetworkMask() const
For a Network LSA, get the Network Mask field that precedes the list of attached routers.
GlobalRoutingLSA()
Create a blank Global Routing Link State Advertisement.
ListOfLinkRecords_t m_linkRecords
Each Link State Advertisement contains a number of Link Records that describe the kinds of links that...
Ipv4Address GetAttachedRouter(uint32_t n) const
Return an Ipv4Address corresponding to the specified attached router.
void SetNode(Ptr< Node > node)
Set the Node pointer of the node that originated this LSA.
LSType GetLSType() const
Return the LSType field of the LSA.
uint32_t AddAttachedRouter(Ipv4Address addr)
Add an attached router to the list in the NetworkLSA.
uint32_t GetNLinkRecords() const
Return the number of Global Routing Link Records in the LSA.
~GlobalRoutingLSA()
Destroy an existing Global Routing Link State Advertisement.
Ipv4Address m_advertisingRtr
The Advertising Router is defined by the OSPF spec.
void SetLSType(LSType typ)
Set the LS type field of the LSA.
void ClearLinkRecords()
Release all of the Global Routing Link Records present in the Global Routing Link State Advertisement...
void SetAdvertisingRouter(Ipv4Address rtr)
Set the Advertising Router as defined by the OSPF spec.
SPFStatus m_status
This is a tristate flag used internally in the SPF computation to mark if an SPFVertex (a data struct...
LSType m_lsType
The type of the LSA.
ListOfAttachedRouters_t m_attachedRouters
Each Network LSA contains a list of attached routers.
GlobalRoutingLinkRecord * GetLinkRecord(uint32_t n) const
Return a pointer to the specified Global Routing Link Record.
void SetNetworkLSANetworkMask(Ipv4Mask mask)
For a Network LSA, set the Network Mask field that precedes the list of attached routers.
Ipv4Mask m_networkLSANetworkMask
Each Network LSA contains the network mask of the attached network.
void CopyLinkRecords(const GlobalRoutingLSA &lsa)
Copy any Global Routing Link Records in a given Global Routing Link State Advertisement to the curren...
void SetLinkStateId(Ipv4Address addr)
Set the Link State ID is defined by the OSPF spec.
GlobalRoutingLSA & operator=(const GlobalRoutingLSA &lsa)
Assignment operator for a Global Routing Link State Advertisement.
Ipv4Address GetLinkStateId() const
Get the Link State ID as defined by the OSPF spec.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
void Set(uint32_t address)
input address is in host order.
Ipv4Address CombineMask(const Ipv4Mask &mask) const
Combine this address with a network mask.
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:80
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:257
uint16_t GetPrefixLength() const
uint32_t Get() const
Get the host-order 32-bit IP mask.
Definition: ipv4-address.cc:84
A record of an IPv4 routing table entry for Ipv4GlobalRouting and Ipv4StaticRouting.
static Ipv4RoutingTableEntry CreateNetworkRouteTo(Ipv4Address network, Ipv4Mask networkMask, Ipv4Address nextHop, uint32_t interface)
holds a vector of ns3::NetDevice pointers
uint32_t GetN() const
Get the number of Ptr<NetDevice> stored in this container.
void Add(NetDeviceContainer other)
Append the contents of another NetDeviceContainer to the end of this container.
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
uint32_t GetNDevices() const
Definition: node.cc:162
uint32_t GetId() const
Definition: node.cc:117
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition: node.cc:152
static Ptr< Node > GetNode(uint32_t n)
Definition: node-list.cc:251
A base class which provides memory management and object aggregation.
Definition: object.h:89
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#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:86
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:261
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159