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 "loopback-net-device.h"
24 
25 #include "ns3/abort.h"
26 #include "ns3/assert.h"
27 #include "ns3/bridge-net-device.h"
28 #include "ns3/channel.h"
29 #include "ns3/ipv4.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 (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin();
197  i != lsa.m_linkRecords.end();
198  i++)
199  {
200  GlobalRoutingLinkRecord* pSrc = *i;
202 
203  pDst->SetLinkType(pSrc->GetLinkType());
204  pDst->SetLinkId(pSrc->GetLinkId());
205  pDst->SetLinkData(pSrc->GetLinkData());
206  pDst->SetMetric(pSrc->GetMetric());
207 
208  m_linkRecords.push_back(pDst);
209  pDst = nullptr;
210  }
211 
213 }
214 
216 {
217  NS_LOG_FUNCTION(this);
219 }
220 
221 void
223 {
224  NS_LOG_FUNCTION(this);
225  for (ListOfLinkRecords_t::iterator i = m_linkRecords.begin(); i != m_linkRecords.end(); i++)
226  {
227  NS_LOG_LOGIC("Free link record");
228 
229  GlobalRoutingLinkRecord* p = *i;
230  delete p;
231  p = nullptr;
232 
233  *i = nullptr;
234  }
235  NS_LOG_LOGIC("Clear list");
236  m_linkRecords.clear();
237 }
238 
239 uint32_t
241 {
242  NS_LOG_FUNCTION(this << lr);
243  m_linkRecords.push_back(lr);
244  return m_linkRecords.size();
245 }
246 
247 uint32_t
249 {
250  NS_LOG_FUNCTION(this);
251  return m_linkRecords.size();
252 }
253 
256 {
257  NS_LOG_FUNCTION(this << n);
258  uint32_t j = 0;
259  for (ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin(); i != m_linkRecords.end();
260  i++, j++)
261  {
262  if (j == n)
263  {
264  return *i;
265  }
266  }
267  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index");
268  return nullptr;
269 }
270 
271 bool
273 {
274  NS_LOG_FUNCTION(this);
275  return m_linkRecords.empty();
276 }
277 
280 {
281  NS_LOG_FUNCTION(this);
282  return m_lsType;
283 }
284 
285 void
287 {
288  NS_LOG_FUNCTION(this << typ);
289  m_lsType = typ;
290 }
291 
294 {
295  NS_LOG_FUNCTION(this);
296  return m_linkStateId;
297 }
298 
299 void
301 {
302  NS_LOG_FUNCTION(this << addr);
303  m_linkStateId = addr;
304 }
305 
308 {
309  NS_LOG_FUNCTION(this);
310  return m_advertisingRtr;
311 }
312 
313 void
315 {
316  NS_LOG_FUNCTION(this << addr);
317  m_advertisingRtr = addr;
318 }
319 
320 void
322 {
323  NS_LOG_FUNCTION(this << mask);
325 }
326 
327 Ipv4Mask
329 {
330  NS_LOG_FUNCTION(this);
332 }
333 
336 {
337  NS_LOG_FUNCTION(this);
338  return m_status;
339 }
340 
341 uint32_t
343 {
344  NS_LOG_FUNCTION(this << addr);
345  m_attachedRouters.push_back(addr);
346  return m_attachedRouters.size();
347 }
348 
349 uint32_t
351 {
352  NS_LOG_FUNCTION(this);
353  return m_attachedRouters.size();
354 }
355 
358 {
359  NS_LOG_FUNCTION(this << n);
360  uint32_t j = 0;
361  for (ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin();
362  i != m_attachedRouters.end();
363  i++, j++)
364  {
365  if (j == n)
366  {
367  return *i;
368  }
369  }
370  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
371  return Ipv4Address("0.0.0.0");
372 }
373 
374 void
376 {
377  NS_LOG_FUNCTION(this << status);
378  m_status = status;
379 }
380 
381 Ptr<Node>
383 {
384  NS_LOG_FUNCTION(this);
386 }
387 
388 void
390 {
391  NS_LOG_FUNCTION(this << node);
392  m_node_id = node->GetId();
393 }
394 
395 void
396 GlobalRoutingLSA::Print(std::ostream& os) const
397 {
398  NS_LOG_FUNCTION(this << &os);
399  os << std::endl;
400  os << "========== Global Routing LSA ==========" << std::endl;
401  os << "m_lsType = " << m_lsType;
403  {
404  os << " (GlobalRoutingLSA::RouterLSA)";
405  }
407  {
408  os << " (GlobalRoutingLSA::NetworkLSA)";
409  }
411  {
412  os << " (GlobalRoutingLSA::ASExternalLSA)";
413  }
414  else
415  {
416  os << "(Unknown LSType)";
417  }
418  os << std::endl;
419 
420  os << "m_linkStateId = " << m_linkStateId << " (Router ID)" << std::endl;
421  os << "m_advertisingRtr = " << m_advertisingRtr << " (Router ID)" << std::endl;
422 
424  {
425  for (ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin();
426  i != m_linkRecords.end();
427  i++)
428  {
429  GlobalRoutingLinkRecord* p = *i;
430 
431  os << "---------- RouterLSA Link Record ----------" << std::endl;
432  os << "m_linkType = " << p->m_linkType;
434  {
435  os << " (GlobalRoutingLinkRecord::PointToPoint)" << std::endl;
436  os << "m_linkId = " << p->m_linkId << std::endl;
437  os << "m_linkData = " << p->m_linkData << std::endl;
438  os << "m_metric = " << p->m_metric << std::endl;
439  }
441  {
442  os << " (GlobalRoutingLinkRecord::TransitNetwork)" << std::endl;
443  os << "m_linkId = " << p->m_linkId << " (Designated router for network)"
444  << std::endl;
445  os << "m_linkData = " << p->m_linkData << " (This router's IP address)"
446  << std::endl;
447  os << "m_metric = " << p->m_metric << std::endl;
448  }
450  {
451  os << " (GlobalRoutingLinkRecord::StubNetwork)" << std::endl;
452  os << "m_linkId = " << p->m_linkId << " (Network number of attached network)"
453  << std::endl;
454  os << "m_linkData = " << p->m_linkData << " (Network mask of attached network)"
455  << std::endl;
456  os << "m_metric = " << p->m_metric << std::endl;
457  }
458  else
459  {
460  os << " (Unknown LinkType)" << std::endl;
461  os << "m_linkId = " << p->m_linkId << std::endl;
462  os << "m_linkData = " << p->m_linkData << std::endl;
463  os << "m_metric = " << p->m_metric << std::endl;
464  }
465  os << "---------- End RouterLSA Link Record ----------" << std::endl;
466  }
467  }
469  {
470  os << "---------- NetworkLSA Link Record ----------" << std::endl;
471  os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask << std::endl;
472  for (ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin();
473  i != m_attachedRouters.end();
474  i++)
475  {
476  Ipv4Address p = *i;
477  os << "attachedRouter = " << p << std::endl;
478  }
479  os << "---------- End NetworkLSA Link Record ----------" << std::endl;
480  }
482  {
483  os << "---------- ASExternalLSA Link Record --------" << std::endl;
484  os << "m_linkStateId = " << m_linkStateId << std::endl;
485  os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask << std::endl;
486  }
487  else
488  {
489  NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
490  }
491  os << "========== End Global Routing LSA ==========" << std::endl;
492 }
493 
494 std::ostream&
495 operator<<(std::ostream& os, GlobalRoutingLSA& lsa)
496 {
497  lsa.Print(os);
498  return os;
499 }
500 
501 // ---------------------------------------------------------------------------
502 //
503 // GlobalRouter Implementation
504 //
505 // ---------------------------------------------------------------------------
506 
507 NS_OBJECT_ENSURE_REGISTERED(GlobalRouter);
508 
509 TypeId
511 {
512  static TypeId tid = TypeId("ns3::GlobalRouter").SetParent<Object>().SetGroupName("Internet");
513  return tid;
514 }
515 
517  : m_LSAs()
518 {
519  NS_LOG_FUNCTION(this);
521 }
522 
524 {
525  NS_LOG_FUNCTION(this);
526  ClearLSAs();
527 }
528 
529 void
531 {
532  NS_LOG_FUNCTION(this << routing);
533  m_routingProtocol = routing;
534 }
535 
538 {
539  NS_LOG_FUNCTION(this);
540  return m_routingProtocol;
541 }
542 
543 void
545 {
546  NS_LOG_FUNCTION(this);
547  m_routingProtocol = nullptr;
548  for (InjectedRoutesI k = m_injectedRoutes.begin(); k != m_injectedRoutes.end();
549  k = m_injectedRoutes.erase(k))
550  {
551  delete (*k);
552  }
554 }
555 
556 void
558 {
559  NS_LOG_FUNCTION(this);
560  for (ListOfLSAs_t::iterator i = m_LSAs.begin(); i != m_LSAs.end(); i++)
561  {
562  NS_LOG_LOGIC("Free LSA");
563 
564  GlobalRoutingLSA* p = *i;
565  delete p;
566  p = nullptr;
567 
568  *i = nullptr;
569  }
570  NS_LOG_LOGIC("Clear list of LSAs");
571  m_LSAs.clear();
572 }
573 
576 {
577  NS_LOG_FUNCTION(this);
578  return m_routerId;
579 }
580 
581 //
582 // DiscoverLSAs is called on all nodes in the system that have a GlobalRouter
583 // interface aggregated. We need to go out and discover any adjacent routers
584 // and build the Link State Advertisements that reflect them and their associated
585 // networks.
586 //
587 uint32_t
589 {
590  NS_LOG_FUNCTION(this);
591  Ptr<Node> node = GetObject<Node>();
592  NS_ABORT_MSG_UNLESS(node,
593  "GlobalRouter::DiscoverLSAs (): GetObject for <Node> interface failed");
594  NS_LOG_LOGIC("For node " << node->GetId());
595 
596  ClearLSAs();
597 
598  //
599  // While building the Router-LSA, keep a list of those NetDevices for
600  // which the current node is the designated router and we will later build
601  // a NetworkLSA for.
602  //
604 
605  //
606  // We're aggregated to a node. We need to ask the node for a pointer to its
607  // Ipv4 interface. This is where the information regarding the attached
608  // interfaces lives. If we're a router, we had better have an Ipv4 interface.
609  //
610  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4>();
611  NS_ABORT_MSG_UNLESS(ipv4Local,
612  "GlobalRouter::DiscoverLSAs (): GetObject for <Ipv4> interface failed");
613 
614  //
615  // Every router node originates a Router-LSA
616  //
619  pLSA->SetLinkStateId(m_routerId);
622  pLSA->SetNode(node);
623 
624  //
625  // Ask the node for the number of net devices attached. This isn't necessarily
626  // equal to the number of links to adjacent nodes (other routers) as the number
627  // of devices may include those for stub networks (e.g., ethernets, etc.) and
628  // bridge devices also take up an "extra" net device.
629  //
630  uint32_t numDevices = node->GetNDevices();
631 
632  //
633  // Iterate through the devices on the node and walk the channel to see what's
634  // on the other side of the standalone devices..
635  //
636  for (uint32_t i = 0; i < numDevices; ++i)
637  {
638  Ptr<NetDevice> ndLocal = node->GetDevice(i);
639 
640  if (DynamicCast<LoopbackNetDevice>(ndLocal))
641  {
642  continue;
643  }
644 
645  //
646  // There is an assumption that bridge ports must never have an IP address
647  // associated with them. This turns out to be a very convenient place to
648  // check and make sure that this is the case.
649  //
650  if (NetDeviceIsBridged(ndLocal))
651  {
652  int32_t ifIndex = ipv4Local->GetInterfaceForDevice(ndLocal);
654  ifIndex != -1,
655  "GlobalRouter::DiscoverLSAs(): Bridge ports must not have an IPv4 interface index");
656  }
657 
658  //
659  // Check to see if the net device we just got has a corresponding IP
660  // interface (could be a pure L2 NetDevice) -- for example a net device
661  // associated with a bridge. We are only going to involve devices with
662  // IP addresses in routing.
663  //
664  int32_t interfaceNumber = ipv4Local->GetInterfaceForDevice(ndLocal);
665  if (interfaceNumber == -1 ||
666  !(ipv4Local->IsUp(interfaceNumber) && ipv4Local->IsForwarding(interfaceNumber)))
667  {
668  NS_LOG_LOGIC("Net device "
669  << ndLocal
670  << "has no IP interface or is not enabled for forwarding, skipping");
671  continue;
672  }
673 
674  //
675  // We have a net device that we need to check out. If it supports
676  // broadcast and is not a point-point link, then it will be either a stub
677  // network or a transit network depending on the number of routers on
678  // the segment. We add the appropriate link record to the LSA.
679  //
680  // If the device is a point to point link, we treat it separately. In
681  // that case, there may be zero, one, or two link records added.
682  //
683 
684  if (ndLocal->IsBroadcast() && !ndLocal->IsPointToPoint())
685  {
686  NS_LOG_LOGIC("Broadcast link");
687  ProcessBroadcastLink(ndLocal, pLSA, c);
688  }
689  else if (ndLocal->IsPointToPoint())
690  {
691  NS_LOG_LOGIC("Point=to-point link");
692  ProcessPointToPointLink(ndLocal, pLSA);
693  }
694  else
695  {
696  NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
697  }
698  }
699 
700  NS_LOG_LOGIC("========== LSA for node " << node->GetId() << " ==========");
701  NS_LOG_LOGIC(*pLSA);
702  m_LSAs.push_back(pLSA);
703  pLSA = nullptr;
704 
705  //
706  // Now, determine whether we need to build a NetworkLSA. This is the case if
707  // we found at least one designated router.
708  //
709  uint32_t nDesignatedRouters = c.GetN();
710  if (nDesignatedRouters > 0)
711  {
712  NS_LOG_LOGIC("Build Network LSAs");
713  BuildNetworkLSAs(c);
714  }
715 
716  //
717  // Build injected route LSAs as external routes
718  // RFC 2328, section 12.4.4
719  //
720  for (InjectedRoutesCI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
721  {
724  pLSA->SetLinkStateId((*i)->GetDestNetwork());
726  pLSA->SetNetworkLSANetworkMask((*i)->GetDestNetworkMask());
728  m_LSAs.push_back(pLSA);
729  }
730  return m_LSAs.size();
731 }
732 
733 void
735 {
736  NS_LOG_FUNCTION(this << nd << pLSA << &c);
737 
738  if (nd->IsBridge())
739  {
740  ProcessBridgedBroadcastLink(nd, pLSA, c);
741  }
742  else
743  {
744  ProcessSingleBroadcastLink(nd, pLSA, c);
745  }
746 }
747 
748 void
750  GlobalRoutingLSA* pLSA,
752 {
753  NS_LOG_FUNCTION(this << nd << pLSA << &c);
754 
756  NS_ABORT_MSG_IF(plr == nullptr,
757  "GlobalRouter::ProcessSingleBroadcastLink(): Can't alloc link record");
758 
759  //
760  // We have some preliminaries to do to get enough information to proceed.
761  // This information we need comes from the internet stack, so notice that
762  // there is an implied assumption that global routing is only going to
763  // work with devices attached to the internet stack (have an ipv4 interface
764  // associated to them.
765  //
766  Ptr<Node> node = nd->GetNode();
767 
768  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4>();
770  ipv4Local,
771  "GlobalRouter::ProcessSingleBroadcastLink (): GetObject for <Ipv4> interface failed");
772 
773  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice(nd);
775  interfaceLocal == -1,
776  "GlobalRouter::ProcessSingleBroadcastLink(): No interface index associated with device");
777 
778  if (ipv4Local->GetNAddresses(interfaceLocal) > 1)
779  {
780  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
781  }
782  Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
783  Ipv4Mask maskLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetMask();
784  NS_LOG_LOGIC("Working with local address " << addrLocal);
785  uint16_t metricLocal = ipv4Local->GetMetric(interfaceLocal);
786 
787  //
788  // Check to see if the net device is connected to a channel/network that has
789  // another router on it. If there is no other router on the link (but us) then
790  // this is a stub network. If we find another router, then what we have here
791  // is a transit network.
792  //
794  if (AnotherRouterOnLink(nd) == false)
795  {
796  //
797  // This is a net device connected to a stub network
798  //
799  NS_LOG_LOGIC("Router-LSA Stub Network");
801 
802  //
803  // According to OSPF, the Link ID is the IP network number of
804  // the attached network.
805  //
806  plr->SetLinkId(addrLocal.CombineMask(maskLocal));
807 
808  //
809  // and the Link Data is the network mask; converted to Ipv4Address
810  //
811  Ipv4Address maskLocalAddr;
812  maskLocalAddr.Set(maskLocal.Get());
813  plr->SetLinkData(maskLocalAddr);
814  plr->SetMetric(metricLocal);
815  pLSA->AddLinkRecord(plr);
816  plr = nullptr;
817  }
818  else
819  {
820  //
821  // We have multiple routers on a broadcast interface, so this is
822  // a transit network.
823  //
824  NS_LOG_LOGIC("Router-LSA Transit Network");
826 
827  //
828  // By definition, the router with the lowest IP address is the
829  // designated router for the network. OSPF says that the Link ID
830  // gets the IP interface address of the designated router in this
831  // case.
832  //
834  Ipv4Address desigRtr;
835  desigRtr = FindDesignatedRouterForLink(nd);
836 
837  //
838  // Let's double-check that any designated router we find out on our
839  // network is really on our network.
840  //
841  if (desigRtr != "255.255.255.255")
842  {
843  Ipv4Address networkHere = addrLocal.CombineMask(maskLocal);
844  Ipv4Address networkThere = desigRtr.CombineMask(maskLocal);
846  networkHere == networkThere,
847  "GlobalRouter::ProcessSingleBroadcastLink(): Network number confusion ("
848  << addrLocal << "/" << maskLocal.GetPrefixLength() << ", " << desigRtr << "/"
849  << maskLocal.GetPrefixLength() << ")");
850  }
851  if (desigRtr == addrLocal)
852  {
853  c.Add(nd);
854  NS_LOG_LOGIC("Node " << node->GetId() << " elected a designated router");
855  }
856  plr->SetLinkId(desigRtr);
857 
858  //
859  // OSPF says that the Link Data is this router's own IP address.
860  //
861  plr->SetLinkData(addrLocal);
862  plr->SetMetric(metricLocal);
863  pLSA->AddLinkRecord(plr);
864  plr = nullptr;
865  }
866 }
867 
868 void
870  GlobalRoutingLSA* pLSA,
872 {
873  NS_LOG_FUNCTION(this << nd << pLSA << &c);
874  NS_ASSERT_MSG(nd->IsBridge(),
875  "GlobalRouter::ProcessBridgedBroadcastLink(): Called with non-bridge net device");
876 
877 #if 0
878  //
879  // It is possible to admit the possibility that a bridge device on a node
880  // can also participate in routing. This would surprise people who don't
881  // come from Microsoft-land where they do use such a construct. Based on
882  // the principle of least-surprise, we will leave the relatively simple
883  // code in place to do this, but not enable it until someone really wants
884  // the capability. Even then, we will not enable this code as a default
885  // but rather something you will have to go and turn on.
886  //
887 
888  Ptr<BridgeNetDevice> bnd = nd->GetObject<BridgeNetDevice> ();
889  NS_ABORT_MSG_UNLESS (bnd, "GlobalRouter::DiscoverLSAs (): GetObject for <BridgeNetDevice> failed");
890 
891  //
892  // We have some preliminaries to do to get enough information to proceed.
893  // This information we need comes from the internet stack, so notice that
894  // there is an implied assumption that global routing is only going to
895  // work with devices attached to the internet stack (have an ipv4 interface
896  // associated to them.
897  //
898  Ptr<Node> node = nd->GetNode ();
899  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4> ();
900  NS_ABORT_MSG_UNLESS (ipv4Local, "GlobalRouter::ProcessBridgedBroadcastLink (): GetObject for <Ipv4> interface failed");
901 
902  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice (nd);
903  NS_ABORT_MSG_IF (interfaceLocal == -1, "GlobalRouter::ProcessBridgedBroadcastLink(): No interface index associated with device");
904 
905  if (ipv4Local->GetNAddresses (interfaceLocal) > 1)
906  {
907  NS_LOG_WARN ("Warning, interface has multiple IP addresses; using only the primary one");
908  }
909  Ipv4Address addrLocal = ipv4Local->GetAddress (interfaceLocal, 0).GetLocal ();
910  Ipv4Mask maskLocal = ipv4Local->GetAddress (interfaceLocal, 0).GetMask ();
911  NS_LOG_LOGIC ("Working with local address " << addrLocal);
912  uint16_t metricLocal = ipv4Local->GetMetric (interfaceLocal);
913 
914  //
915  // We need to handle a bridge on the router. This means that we have been
916  // given a net device that is a BridgeNetDevice. It has an associated Ipv4
917  // interface index and address. Some number of other net devices live "under"
918  // the bridge device as so-called bridge ports. In a nutshell, what we have
919  // to do is to repeat what is done for a single broadcast link on all of
920  // those net devices living under the bridge (trolls?)
921  //
922 
923  bool areTransitNetwork = false;
924  Ipv4Address desigRtr ("255.255.255.255");
925 
926  for (uint32_t i = 0; i < bnd->GetNBridgePorts (); ++i)
927  {
928  Ptr<NetDevice> ndTemp = bnd->GetBridgePort (i);
929 
930  //
931  // We have to decide if we are a transit network. This is characterized
932  // by the presence of another router on the network segment. If we find
933  // another router on any of our bridged links, we are a transit network.
934  //
936  if (AnotherRouterOnLink (ndTemp))
937  {
938  areTransitNetwork = true;
939 
940  //
941  // If we're going to be a transit network, then we have got to elect
942  // a designated router for the whole bridge. This means finding the
943  // router with the lowest IP address on the whole bridge. We ask
944  // for the lowest address on each segment and pick the lowest of them
945  // all.
946  //
948  Ipv4Address desigRtrTemp = FindDesignatedRouterForLink (ndTemp);
949 
950  //
951  // Let's double-check that any designated router we find out on our
952  // network is really on our network.
953  //
954  if (desigRtrTemp != "255.255.255.255")
955  {
956  Ipv4Address networkHere = addrLocal.CombineMask (maskLocal);
957  Ipv4Address networkThere = desigRtrTemp.CombineMask (maskLocal);
958  NS_ABORT_MSG_UNLESS (networkHere == networkThere,
959  "GlobalRouter::ProcessSingleBroadcastLink(): Network number confusion (" <<
960  addrLocal << "/" << maskLocal.GetPrefixLength () << ", " <<
961  desigRtrTemp << "/" << maskLocal.GetPrefixLength () << ")");
962  }
963  if (desigRtrTemp < desigRtr)
964  {
965  desigRtr = desigRtrTemp;
966  }
967  }
968  }
969  //
970  // That's all the information we need to put it all together, just like we did
971  // in the case of a single broadcast link.
972  //
973 
975  NS_ABORT_MSG_IF (plr == 0, "GlobalRouter::ProcessBridgedBroadcastLink(): Can't alloc link record");
976 
977  if (areTransitNetwork == false)
978  {
979  //
980  // This is a net device connected to a bridge of stub networks
981  //
982  NS_LOG_LOGIC ("Router-LSA Stub Network");
984 
985  //
986  // According to OSPF, the Link ID is the IP network number of
987  // the attached network.
988  //
989  plr->SetLinkId (addrLocal.CombineMask (maskLocal));
990 
991  //
992  // and the Link Data is the network mask; converted to Ipv4Address
993  //
994  Ipv4Address maskLocalAddr;
995  maskLocalAddr.Set (maskLocal.Get ());
996  plr->SetLinkData (maskLocalAddr);
997  plr->SetMetric (metricLocal);
998  pLSA->AddLinkRecord (plr);
999  plr = 0;
1000  }
1001  else
1002  {
1003  //
1004  // We have multiple routers on a bridged broadcast interface, so this is
1005  // a transit network.
1006  //
1007  NS_LOG_LOGIC ("Router-LSA Transit Network");
1009 
1010  //
1011  // By definition, the router with the lowest IP address is the
1012  // designated router for the network. OSPF says that the Link ID
1013  // gets the IP interface address of the designated router in this
1014  // case.
1015  //
1016  if (desigRtr == addrLocal)
1017  {
1018  c.Add (nd);
1019  NS_LOG_LOGIC ("Node " << node->GetId () << " elected a designated router");
1020  }
1021  plr->SetLinkId (desigRtr);
1022 
1023  //
1024  // OSPF says that the Link Data is this router's own IP address.
1025  //
1026  plr->SetLinkData (addrLocal);
1027  plr->SetMetric (metricLocal);
1028  pLSA->AddLinkRecord (plr);
1029  plr = 0;
1030  }
1031 #endif
1032 }
1033 
1034 void
1036 {
1037  NS_LOG_FUNCTION(this << ndLocal << pLSA);
1038 
1039  //
1040  // We have some preliminaries to do to get enough information to proceed.
1041  // This information we need comes from the internet stack, so notice that
1042  // there is an implied assumption that global routing is only going to
1043  // work with devices attached to the internet stack (have an ipv4 interface
1044  // associated to them.
1045  //
1046  Ptr<Node> nodeLocal = ndLocal->GetNode();
1047 
1048  Ptr<Ipv4> ipv4Local = nodeLocal->GetObject<Ipv4>();
1050  ipv4Local,
1051  "GlobalRouter::ProcessPointToPointLink (): GetObject for <Ipv4> interface failed");
1052 
1053  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice(ndLocal);
1055  interfaceLocal == -1,
1056  "GlobalRouter::ProcessPointToPointLink (): No interface index associated with device");
1057 
1058  if (ipv4Local->GetNAddresses(interfaceLocal) > 1)
1059  {
1060  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
1061  }
1062  Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
1063  NS_LOG_LOGIC("Working with local address " << addrLocal);
1064  uint16_t metricLocal = ipv4Local->GetMetric(interfaceLocal);
1065 
1066  //
1067  // Now, we're going to walk over to the remote net device on the other end of
1068  // the point-to-point channel we know we have. This is where our adjacent
1069  // router (to use OSPF lingo) is running.
1070  //
1071  Ptr<Channel> ch = ndLocal->GetChannel();
1072 
1073  //
1074  // Get the net device on the other side of the point-to-point channel.
1075  //
1076  Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
1077 
1078  //
1079  // The adjacent net device is aggregated to a node. We need to ask that net
1080  // device for its node, then ask that node for its Ipv4 interface. Note a
1081  // requirement that nodes on either side of a point-to-point link must have
1082  // internet stacks; and an assumption that point-to-point links are incompatible
1083  // with bridging.
1084  //
1085  Ptr<Node> nodeRemote = ndRemote->GetNode();
1086  Ptr<Ipv4> ipv4Remote = nodeRemote->GetObject<Ipv4>();
1088  ipv4Remote,
1089  "GlobalRouter::ProcessPointToPointLink(): GetObject for remote <Ipv4> failed");
1090 
1091  //
1092  // Further note the requirement that nodes on either side of a point-to-point
1093  // link must participate in global routing and therefore have a GlobalRouter
1094  // interface aggregated.
1095  //
1096  Ptr<GlobalRouter> rtrRemote = nodeRemote->GetObject<GlobalRouter>();
1097  if (!rtrRemote)
1098  {
1099  // This case is possible if the remote does not participate in global routing
1100  return;
1101  }
1102  //
1103  // We're going to need the remote router ID, so we might as well get it now.
1104  //
1105  Ipv4Address rtrIdRemote = rtrRemote->GetRouterId();
1106  NS_LOG_LOGIC("Working with remote router " << rtrIdRemote);
1107 
1108  //
1109  // Now, just like we did above, we need to get the IP interface index for the
1110  // net device on the other end of the point-to-point channel.
1111  //
1112  int32_t interfaceRemote = ipv4Remote->GetInterfaceForDevice(ndRemote);
1113  NS_ABORT_MSG_IF(interfaceRemote == -1,
1114  "GlobalRouter::ProcessPointToPointLinks(): No interface index associated with "
1115  "remote device");
1116 
1117  //
1118  // Now that we have the Ipv4 interface, we can get the (remote) address and
1119  // mask we need.
1120  //
1121  if (ipv4Remote->GetNAddresses(interfaceRemote) > 1)
1122  {
1123  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
1124  }
1125  Ipv4Address addrRemote = ipv4Remote->GetAddress(interfaceRemote, 0).GetLocal();
1126  Ipv4Mask maskRemote = ipv4Remote->GetAddress(interfaceRemote, 0).GetMask();
1127  NS_LOG_LOGIC("Working with remote address " << addrRemote);
1128 
1129  //
1130  // Now we can fill out the link records for this link. There are always two
1131  // link records; the first is a point-to-point record describing the link and
1132  // the second is a stub network record with the network number.
1133  //
1135  if (ipv4Remote->IsUp(interfaceRemote))
1136  {
1137  NS_LOG_LOGIC("Remote side interface " << interfaceRemote << " is up-- add a type 1 link");
1138 
1139  plr = new GlobalRoutingLinkRecord;
1140  NS_ABORT_MSG_IF(plr == nullptr,
1141  "GlobalRouter::ProcessPointToPointLink(): Can't alloc link record");
1143  plr->SetLinkId(rtrIdRemote);
1144  plr->SetLinkData(addrLocal);
1145  plr->SetMetric(metricLocal);
1146  pLSA->AddLinkRecord(plr);
1147  plr = nullptr;
1148  }
1149 
1150  // Regardless of state of peer, add a type 3 link (RFC 2328: 12.4.1.1)
1151  plr = new GlobalRoutingLinkRecord;
1152  NS_ABORT_MSG_IF(plr == nullptr,
1153  "GlobalRouter::ProcessPointToPointLink(): Can't alloc link record");
1155  plr->SetLinkId(addrRemote);
1156  plr->SetLinkData(Ipv4Address(maskRemote.Get())); // Frown
1157  plr->SetMetric(metricLocal);
1158  pLSA->AddLinkRecord(plr);
1159  plr = nullptr;
1160 }
1161 
1162 void
1164 {
1165  NS_LOG_FUNCTION(this << &c);
1166 
1167  uint32_t nDesignatedRouters = c.GetN();
1168  NS_LOG_DEBUG("Number of designated routers: " << nDesignatedRouters);
1169 
1170  for (uint32_t i = 0; i < nDesignatedRouters; ++i)
1171  {
1172  //
1173  // Build one NetworkLSA for each net device talking to a network that we are the
1174  // designated router for. These devices are in the provided container.
1175  //
1176  Ptr<NetDevice> ndLocal = c.Get(i);
1177  Ptr<Node> node = ndLocal->GetNode();
1178 
1179  Ptr<Ipv4> ipv4Local = node->GetObject<Ipv4>();
1181  ipv4Local,
1182  "GlobalRouter::ProcessPointToPointLink (): GetObject for <Ipv4> interface failed");
1183 
1184  int32_t interfaceLocal = ipv4Local->GetInterfaceForDevice(ndLocal);
1186  interfaceLocal == -1,
1187  "GlobalRouter::BuildNetworkLSAs (): No interface index associated with device");
1188 
1189  if (ipv4Local->GetNAddresses(interfaceLocal) > 1)
1190  {
1191  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the primary one");
1192  }
1193  Ipv4Address addrLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetLocal();
1194  Ipv4Mask maskLocal = ipv4Local->GetAddress(interfaceLocal, 0).GetMask();
1195 
1196  GlobalRoutingLSA* pLSA = new GlobalRoutingLSA;
1197  NS_ABORT_MSG_IF(pLSA == nullptr,
1198  "GlobalRouter::BuildNetworkLSAs(): Can't alloc link record");
1199 
1201  pLSA->SetLinkStateId(addrLocal);
1203  pLSA->SetNetworkLSANetworkMask(maskLocal);
1205  pLSA->SetNode(node);
1206 
1207  //
1208  // Build a list of AttachedRouters by walking the devices in the channel
1209  // and, if we find a node with a GlobalRouter interface and an IPv4
1210  // interface associated with that device, we call it an attached router.
1211  //
1213  Ptr<Channel> ch = ndLocal->GetChannel();
1214  std::size_t nDevices = ch->GetNDevices();
1215  NS_ASSERT(nDevices);
1217  NS_LOG_LOGIC("Found " << deviceList.GetN() << " non-bridged devices on channel");
1218 
1219  for (uint32_t i = 0; i < deviceList.GetN(); i++)
1220  {
1221  Ptr<NetDevice> tempNd = deviceList.Get(i);
1222  NS_ASSERT(tempNd);
1223  if (tempNd == ndLocal)
1224  {
1225  NS_LOG_LOGIC("Adding " << addrLocal << " to Network LSA");
1226  pLSA->AddAttachedRouter(addrLocal);
1227  continue;
1228  }
1229  Ptr<Node> tempNode = tempNd->GetNode();
1230 
1231  // Does the node in question have a GlobalRouter interface? If not it can
1232  // hardly be considered an attached router.
1233  //
1234  Ptr<GlobalRouter> rtr = tempNode->GetObject<GlobalRouter>();
1235  if (!rtr)
1236  {
1237  NS_LOG_LOGIC("Node " << tempNode->GetId()
1238  << " does not have GlobalRouter interface--skipping");
1239  continue;
1240  }
1241 
1242  //
1243  // Does the attached node have an ipv4 interface for the device we're probing?
1244  // If not, it can't play router.
1245  //
1246  Ptr<Ipv4> tempIpv4 = tempNode->GetObject<Ipv4>();
1247  int32_t tempInterface = tempIpv4->GetInterfaceForDevice(tempNd);
1248 
1249  if (tempInterface != -1)
1250  {
1251  Ptr<Ipv4> tempIpv4 = tempNode->GetObject<Ipv4>();
1252  NS_ASSERT(tempIpv4);
1253  if (!tempIpv4->IsUp(tempInterface))
1254  {
1255  NS_LOG_LOGIC("Remote side interface " << tempInterface << " not up");
1256  }
1257  else
1258  {
1259  if (tempIpv4->GetNAddresses(tempInterface) > 1)
1260  {
1261  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the "
1262  "primary one");
1263  }
1264  Ipv4Address tempAddr = tempIpv4->GetAddress(tempInterface, 0).GetLocal();
1265  NS_LOG_LOGIC("Adding " << tempAddr << " to Network LSA");
1266  pLSA->AddAttachedRouter(tempAddr);
1267  }
1268  }
1269  else
1270  {
1271  NS_LOG_LOGIC("Node " << tempNode->GetId() << " device " << tempNd
1272  << " does not have IPv4 interface; skipping");
1273  }
1274  }
1275  m_LSAs.push_back(pLSA);
1276  NS_LOG_LOGIC("========== LSA for node " << node->GetId() << " ==========");
1277  NS_LOG_LOGIC(*pLSA);
1278  pLSA = nullptr;
1279  }
1280 }
1281 
1284 {
1285  NS_LOG_FUNCTION(this << ch);
1287 
1288  for (std::size_t i = 0; i < ch->GetNDevices(); i++)
1289  {
1290  Ptr<NetDevice> nd = ch->GetDevice(i);
1291  NS_LOG_LOGIC("checking to see if the device " << nd << " is bridged");
1293  if (bnd && BridgeHasAlreadyBeenVisited(bnd) == false)
1294  {
1295  NS_LOG_LOGIC("Device is bridged by BridgeNetDevice "
1296  << bnd << " with " << bnd->GetNBridgePorts() << " ports");
1297  MarkBridgeAsVisited(bnd);
1298  // Find all channels bridged together, and recursively call
1299  // on all other channels
1300  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); j++)
1301  {
1302  Ptr<NetDevice> bridgedDevice = bnd->GetBridgePort(j);
1303  if (bridgedDevice->GetChannel() == ch)
1304  {
1305  NS_LOG_LOGIC("Skipping my own device/channel");
1306  continue;
1307  }
1308  NS_LOG_LOGIC("Calling on channel " << bridgedDevice->GetChannel());
1309  c.Add(FindAllNonBridgedDevicesOnLink(bridgedDevice->GetChannel()));
1310  }
1311  }
1312  else
1313  {
1314  NS_LOG_LOGIC("Device is not bridged; adding");
1315  c.Add(nd);
1316  }
1317  }
1318  NS_LOG_LOGIC("Found " << c.GetN() << " devices");
1319  return c;
1320 }
1321 
1322 //
1323 // Given a local net device, we need to walk the channel to which the net device is
1324 // attached and look for nodes with GlobalRouter interfaces on them (one of them
1325 // will be us). Of these, the router with the lowest IP address on the net device
1326 // connecting to the channel becomes the designated router for the link.
1327 //
1330 {
1331  NS_LOG_FUNCTION(this << ndLocal);
1332 
1333  Ptr<Channel> ch = ndLocal->GetChannel();
1334  uint32_t nDevices = ch->GetNDevices();
1335  NS_ASSERT(nDevices);
1336 
1337  NS_LOG_LOGIC("Looking for designated router off of net device " << ndLocal << " on node "
1338  << ndLocal->GetNode()->GetId());
1339 
1340  Ipv4Address desigRtr("255.255.255.255");
1341 
1342  //
1343  // Look through all of the devices on the channel to which the net device
1344  // in question is attached.
1345  //
1346  for (uint32_t i = 0; i < nDevices; i++)
1347  {
1348  Ptr<NetDevice> ndOther = ch->GetDevice(i);
1349  NS_ASSERT(ndOther);
1350 
1351  Ptr<Node> nodeOther = ndOther->GetNode();
1352 
1353  NS_LOG_LOGIC("Examine channel device " << i << " on node " << nodeOther->GetId());
1354 
1355  //
1356  // For all other net devices, we need to check and see if a router
1357  // is present. If the net device on the other side is a bridged
1358  // device, we need to consider all of the other devices on the
1359  // bridge as well (all of the bridge ports.
1360  //
1361  NS_LOG_LOGIC("checking to see if the device is bridged");
1363  if (bnd)
1364  {
1365  NS_LOG_LOGIC("Device is bridged by BridgeNetDevice " << bnd);
1366 
1367  //
1368  // When enumerating a bridge, don't count the netdevice we came in on
1369  //
1370  if (ndLocal == ndOther)
1371  {
1372  NS_LOG_LOGIC("Skip -- it is where we came from.");
1373  continue;
1374  }
1375 
1376  //
1377  // It is possible that the bridge net device is sitting under a
1378  // router, so we have to check for the presence of that router
1379  // before we run off and follow all the links
1380  //
1381  // We require a designated router to have a GlobalRouter interface and
1382  // an internet stack that includes the Ipv4 interface. If it doesn't
1383  // it can't play router.
1384  //
1385  NS_LOG_LOGIC("Checking for router on bridge net device " << bnd);
1386  Ptr<GlobalRouter> rtr = nodeOther->GetObject<GlobalRouter>();
1387  Ptr<Ipv4> ipv4 = nodeOther->GetObject<Ipv4>();
1388  if (rtr && ipv4)
1389  {
1390  int32_t interfaceOther = ipv4->GetInterfaceForDevice(bnd);
1391  if (interfaceOther != -1)
1392  {
1393  NS_LOG_LOGIC("Found router on bridge net device " << bnd);
1394  if (!ipv4->IsUp(interfaceOther))
1395  {
1396  NS_LOG_LOGIC("Remote side interface " << interfaceOther << " not up");
1397  continue;
1398  }
1399  if (ipv4->GetNAddresses(interfaceOther) > 1)
1400  {
1401  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the "
1402  "primary one");
1403  }
1404  Ipv4Address addrOther = ipv4->GetAddress(interfaceOther, 0).GetLocal();
1405  desigRtr = addrOther < desigRtr ? addrOther : desigRtr;
1406  NS_LOG_LOGIC("designated router now " << desigRtr);
1407  }
1408  }
1409 
1410  //
1411  // Check if we have seen this bridge net device already while
1412  // recursively enumerating an L2 broadcast domain. If it is new
1413  // to us, go ahead and process it. If we have already processed it,
1414  // move to the next
1415  //
1416  if (BridgeHasAlreadyBeenVisited(bnd))
1417  {
1418  NS_ABORT_MSG("ERROR: L2 forwarding loop detected!");
1419  }
1420 
1421  MarkBridgeAsVisited(bnd);
1422 
1423  NS_LOG_LOGIC("Looking through bridge ports of bridge net device " << bnd);
1424  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
1425  {
1426  Ptr<NetDevice> ndBridged = bnd->GetBridgePort(j);
1427  NS_LOG_LOGIC("Examining bridge port " << j << " device " << ndBridged);
1428  if (ndBridged == ndOther)
1429  {
1430  NS_LOG_LOGIC("That bridge port is me, don't walk backward");
1431  continue;
1432  }
1433 
1434  NS_LOG_LOGIC("Recursively looking for routers down bridge port " << ndBridged);
1435  Ipv4Address addrOther = FindDesignatedRouterForLink(ndBridged);
1436  desigRtr = addrOther < desigRtr ? addrOther : desigRtr;
1437  NS_LOG_LOGIC("designated router now " << desigRtr);
1438  }
1439  }
1440  else
1441  {
1442  NS_LOG_LOGIC("This device is not bridged");
1443  Ptr<Node> nodeOther = ndOther->GetNode();
1444  NS_ASSERT(nodeOther);
1445 
1446  //
1447  // We require a designated router to have a GlobalRouter interface and
1448  // an internet stack that includes the Ipv4 interface. If it doesn't
1449  //
1450  Ptr<GlobalRouter> rtr = nodeOther->GetObject<GlobalRouter>();
1451  Ptr<Ipv4> ipv4 = nodeOther->GetObject<Ipv4>();
1452  if (rtr && ipv4)
1453  {
1454  int32_t interfaceOther = ipv4->GetInterfaceForDevice(ndOther);
1455  if (interfaceOther != -1)
1456  {
1457  if (!ipv4->IsUp(interfaceOther))
1458  {
1459  NS_LOG_LOGIC("Remote side interface " << interfaceOther << " not up");
1460  continue;
1461  }
1462  NS_LOG_LOGIC("Found router on net device " << ndOther);
1463  if (ipv4->GetNAddresses(interfaceOther) > 1)
1464  {
1465  NS_LOG_WARN("Warning, interface has multiple IP addresses; using only the "
1466  "primary one");
1467  }
1468  Ipv4Address addrOther = ipv4->GetAddress(interfaceOther, 0).GetLocal();
1469  desigRtr = addrOther < desigRtr ? addrOther : desigRtr;
1470  NS_LOG_LOGIC("designated router now " << desigRtr);
1471  }
1472  }
1473  }
1474  }
1475  return desigRtr;
1476 }
1477 
1478 //
1479 // Given a node and an attached net device, take a look off in the channel to
1480 // which the net device is attached and look for a node on the other side
1481 // that has a GlobalRouter interface aggregated. Life gets more complicated
1482 // when there is a bridged net device on the other side.
1483 //
1484 bool
1486 {
1487  NS_LOG_FUNCTION(this << nd);
1488 
1489  Ptr<Channel> ch = nd->GetChannel();
1490  if (!ch)
1491  {
1492  // It may be that this net device is a stub device, without a channel
1493  return false;
1494  }
1495  uint32_t nDevices = ch->GetNDevices();
1496  NS_ASSERT(nDevices);
1497 
1498  NS_LOG_LOGIC("Looking for routers off of net device " << nd << " on node "
1499  << nd->GetNode()->GetId());
1500 
1501  //
1502  // Look through all of the devices on the channel to which the net device
1503  // in question is attached.
1504  //
1505  for (uint32_t i = 0; i < nDevices; i++)
1506  {
1507  Ptr<NetDevice> ndOther = ch->GetDevice(i);
1508  NS_ASSERT(ndOther);
1509 
1510  NS_LOG_LOGIC("Examine channel device " << i << " on node " << ndOther->GetNode()->GetId());
1511 
1512  //
1513  // Ignore the net device itself.
1514  //
1515  if (ndOther == nd)
1516  {
1517  NS_LOG_LOGIC("Myself, skip");
1518  continue;
1519  }
1520 
1521  //
1522  // For all other net devices, we need to check and see if a router
1523  // is present. If the net device on the other side is a bridged
1524  // device, we need to consider all of the other devices on the
1525  // bridge.
1526  //
1527  NS_LOG_LOGIC("checking to see if device is bridged");
1529  if (bnd)
1530  {
1531  NS_LOG_LOGIC("Device is bridged by net device " << bnd);
1532 
1533  //
1534  // Check if we have seen this bridge net device already while
1535  // recursively enumerating an L2 broadcast domain. If it is new
1536  // to us, go ahead and process it. If we have already processed it,
1537  // move to the next
1538  //
1539  if (BridgeHasAlreadyBeenVisited(bnd))
1540  {
1541  NS_ABORT_MSG("ERROR: L2 forwarding loop detected!");
1542  }
1543 
1544  MarkBridgeAsVisited(bnd);
1545 
1546  NS_LOG_LOGIC("Looking through bridge ports of bridge net device " << bnd);
1547  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
1548  {
1549  Ptr<NetDevice> ndBridged = bnd->GetBridgePort(j);
1550  NS_LOG_LOGIC("Examining bridge port " << j << " device " << ndBridged);
1551  if (ndBridged == ndOther)
1552  {
1553  NS_LOG_LOGIC("That bridge port is me, skip");
1554  continue;
1555  }
1556 
1557  NS_LOG_LOGIC("Recursively looking for routers on bridge port " << ndBridged);
1558  if (AnotherRouterOnLink(ndBridged))
1559  {
1560  NS_LOG_LOGIC("Found routers on bridge port, return true");
1561  return true;
1562  }
1563  }
1564  NS_LOG_LOGIC("No routers on bridged net device, return false");
1565  return false;
1566  }
1567 
1568  NS_LOG_LOGIC("This device is not bridged");
1569  Ptr<Node> nodeTemp = ndOther->GetNode();
1570  NS_ASSERT(nodeTemp);
1571 
1572  Ptr<GlobalRouter> rtr = nodeTemp->GetObject<GlobalRouter>();
1573  if (rtr)
1574  {
1575  NS_LOG_LOGIC("Found GlobalRouter interface, return true");
1576  return true;
1577  }
1578  else
1579  {
1580  NS_LOG_LOGIC("No GlobalRouter interface on device, continue search");
1581  }
1582  }
1583  NS_LOG_LOGIC("No routers found, return false");
1584  return false;
1585 }
1586 
1587 uint32_t
1589 {
1590  NS_LOG_FUNCTION(this);
1591  return m_LSAs.size();
1592 }
1593 
1594 //
1595 // Get the nth link state advertisement from this router.
1596 //
1597 bool
1599 {
1600  NS_LOG_FUNCTION(this << n << &lsa);
1601  NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA");
1602  //
1603  // All of the work was done in GetNumLSAs. All we have to do here is to
1604  // walk the list of link state advertisements created there and return the
1605  // one the client is interested in.
1606  //
1607  ListOfLSAs_t::const_iterator i = m_LSAs.begin();
1608  uint32_t j = 0;
1609 
1610  for (; i != m_LSAs.end(); i++, j++)
1611  {
1612  if (j == n)
1613  {
1614  GlobalRoutingLSA* p = *i;
1615  lsa = *p;
1616  return true;
1617  }
1618  }
1619 
1620  return false;
1621 }
1622 
1623 void
1625 {
1626  NS_LOG_FUNCTION(this << network << networkMask);
1628  //
1629  // Interface number does not matter here, using 1.
1630  //
1631  *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo(network, networkMask, 1);
1632  m_injectedRoutes.push_back(route);
1633 }
1634 
1637 {
1638  NS_LOG_FUNCTION(this << index);
1639  if (index < m_injectedRoutes.size())
1640  {
1641  uint32_t tmp = 0;
1642  for (InjectedRoutesCI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
1643  {
1644  if (tmp == index)
1645  {
1646  return *i;
1647  }
1648  tmp++;
1649  }
1650  }
1651  NS_ASSERT(false);
1652  // quiet compiler.
1653  return nullptr;
1654 }
1655 
1656 uint32_t
1658 {
1659  NS_LOG_FUNCTION(this);
1660  return m_injectedRoutes.size();
1661 }
1662 
1663 void
1665 {
1666  NS_LOG_FUNCTION(this << index);
1667  NS_ASSERT(index < m_injectedRoutes.size());
1668  uint32_t tmp = 0;
1669  for (InjectedRoutesI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
1670  {
1671  if (tmp == index)
1672  {
1673  NS_LOG_LOGIC("Removing route " << index << "; size = " << m_injectedRoutes.size());
1674  delete *i;
1675  m_injectedRoutes.erase(i);
1676  return;
1677  }
1678  tmp++;
1679  }
1680 }
1681 
1682 bool
1684 {
1685  NS_LOG_FUNCTION(this << network << networkMask);
1686  for (InjectedRoutesI i = m_injectedRoutes.begin(); i != m_injectedRoutes.end(); i++)
1687  {
1688  if ((*i)->GetDestNetwork() == network && (*i)->GetDestNetworkMask() == networkMask)
1689  {
1690  NS_LOG_LOGIC("Withdrawing route to network/mask " << network << "/" << networkMask);
1691  delete *i;
1692  m_injectedRoutes.erase(i);
1693  return true;
1694  }
1695  }
1696  return false;
1697 }
1698 
1699 //
1700 // Link through the given channel and find the net device that's on the
1701 // other end. This only makes sense with a point-to-point channel.
1702 //
1705 {
1706  NS_LOG_FUNCTION(this << nd << ch);
1707  NS_ASSERT_MSG(ch->GetNDevices() == 2,
1708  "GlobalRouter::GetAdjacent (): Channel with other than two devices");
1709  //
1710  // This is a point to point channel with two endpoints. Get both of them.
1711  //
1712  Ptr<NetDevice> nd1 = ch->GetDevice(0);
1713  Ptr<NetDevice> nd2 = ch->GetDevice(1);
1714  //
1715  // One of the endpoints is going to be "us" -- that is the net device attached
1716  // to the node on which we're running -- i.e., "nd". The other endpoint (the
1717  // one to which we are connected via the channel) is the adjacent router.
1718  //
1719  if (nd1 == nd)
1720  {
1721  return nd2;
1722  }
1723  else if (nd2 == nd)
1724  {
1725  return nd1;
1726  }
1727  else
1728  {
1729  NS_ASSERT_MSG(false, "GlobalRouter::GetAdjacent (): Wrong or confused channel?");
1730  return nullptr;
1731  }
1732 }
1733 
1734 //
1735 // Decide whether or not a given net device is being bridged by a BridgeNetDevice.
1736 //
1739 {
1740  NS_LOG_FUNCTION(this << nd);
1741 
1742  Ptr<Node> node = nd->GetNode();
1743  uint32_t nDevices = node->GetNDevices();
1744 
1745  //
1746  // There is no bit on a net device that says it is being bridged, so we have
1747  // to look for bridges on the node to which the device is attached. If we
1748  // find a bridge, we need to look through its bridge ports (the devices it
1749  // bridges) to see if we find the device in question.
1750  //
1751  for (uint32_t i = 0; i < nDevices; ++i)
1752  {
1753  Ptr<NetDevice> ndTest = node->GetDevice(i);
1754  NS_LOG_LOGIC("Examine device " << i << " " << ndTest);
1755 
1756  if (ndTest->IsBridge())
1757  {
1758  NS_LOG_LOGIC("device " << i << " is a bridge net device");
1759  Ptr<BridgeNetDevice> bnd = ndTest->GetObject<BridgeNetDevice>();
1761  bnd,
1762  "GlobalRouter::DiscoverLSAs (): GetObject for <BridgeNetDevice> failed");
1763 
1764  for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
1765  {
1766  NS_LOG_LOGIC("Examine bridge port " << j << " " << bnd->GetBridgePort(j));
1767  if (bnd->GetBridgePort(j) == nd)
1768  {
1769  NS_LOG_LOGIC("Net device " << nd << " is bridged by " << bnd);
1770  return bnd;
1771  }
1772  }
1773  }
1774  }
1775  NS_LOG_LOGIC("Net device " << nd << " is not bridged");
1776  return nullptr;
1777 }
1778 
1779 //
1780 // Start a new enumeration of an L2 broadcast domain by clearing m_bridgesVisited
1781 //
1782 void
1784 {
1785  m_bridgesVisited.clear();
1786 }
1787 
1788 //
1789 // Check if we have already visited a given bridge net device by searching m_bridgesVisited
1790 //
1791 bool
1793 {
1794  std::vector<Ptr<BridgeNetDevice>>::iterator iter;
1795  for (iter = m_bridgesVisited.begin(); iter != m_bridgesVisited.end(); ++iter)
1796  {
1797  if (bridgeNetDevice == *iter)
1798  {
1799  NS_LOG_LOGIC("Bridge " << bridgeNetDevice << " has been visited.");
1800  return true;
1801  }
1802  }
1803  return false;
1804 }
1805 
1806 //
1807 // Remember that we visited a bridge net device by adding it to m_bridgesVisited
1808 //
1809 void
1811 {
1812  NS_LOG_FUNCTION(this << bridgeNetDevice);
1813  m_bridgesVisited.push_back(bridgeNetDevice);
1814 }
1815 
1816 } // 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.
std::list< Ipv4RoutingTableEntry * >::iterator InjectedRoutesI
Iterator to container of Ipv4RoutingTableEntry.
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.
std::list< Ipv4RoutingTableEntry * >::const_iterator InjectedRoutesCI
Const Iterator to container of Ipv4RoutingTableEntry.
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:43
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:79
virtual int32_t GetInterfaceForDevice(Ptr< const NetDevice > device) const =0
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:258
uint16_t GetPrefixLength() const
uint32_t Get() const
Get the host-order 32-bit IP mask.
Definition: ipv4-address.cc:91
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:353
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
#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:129