A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
nix-vector-routing.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 The Georgia Institute of Technology
3 * Copyright (c) 2021 NITK Surathkal
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * This file is adapted from the old ipv4-nix-vector-routing.cc.
8 *
9 * Authors: Josh Pelkey <jpelkey@gatech.edu>
10 *
11 * Modified by: Ameya Deshpande <ameyanrd@outlook.com>
12 */
13
14#include "nix-vector-routing.h"
15
16#include "ns3/abort.h"
17#include "ns3/ipv4-list-routing.h"
18#include "ns3/log.h"
19#include "ns3/loopback-net-device.h"
20#include "ns3/names.h"
21
22#include <iomanip>
23#include <queue>
24
25namespace ns3
26{
27
28NS_LOG_COMPONENT_DEFINE("NixVectorRouting");
29
30NS_OBJECT_TEMPLATE_CLASS_DEFINE(NixVectorRouting, Ipv4RoutingProtocol);
31NS_OBJECT_TEMPLATE_CLASS_DEFINE(NixVectorRouting, Ipv6RoutingProtocol);
32
33template <typename T>
35
36// Epoch starts from one to make it easier to spot an uninitialized NixVector during debug.
37template <typename T>
39
40template <typename T>
42
43template <typename T>
46
47template <typename T>
48TypeId
50{
51 std::string name;
52 if constexpr (std::is_same_v<T, Ipv4RoutingProtocol>)
53 {
54 name = "Ipv4";
55 }
56 else
57 {
58 name = "Ipv6";
59 }
60 static TypeId tid = TypeId("ns3::" + name + "NixVectorRouting")
61 .SetParent<T>()
62 .SetGroupName("NixVectorRouting")
64 return tid;
65}
66
67template <typename T>
69 : m_totalNeighbors(0)
70{
72}
73
74template <typename T>
79
80template <typename T>
81void
83{
84 NS_ASSERT(ipv4);
85 NS_ASSERT(!m_ip);
86 NS_LOG_DEBUG("Created Ipv4NixVectorProtocol");
87
88 m_ip = ipv4;
89}
90
91template <typename T>
92void
94{
95 NS_ASSERT(ipv6);
96 NS_ASSERT(!m_ip);
97 NS_LOG_DEBUG("Created Ipv6NixVectorProtocol");
98
99 m_ip = ipv6;
100}
101
102template <typename T>
103void
105{
106 NS_LOG_FUNCTION(this);
107
108 for (uint32_t i = 0; i < m_ip->GetNInterfaces(); i++)
109 {
110 m_ip->SetForwarding(i, true);
111 }
112
113 T::DoInitialize();
114}
115
116template <typename T>
117void
119{
121
122 m_node = nullptr;
123 m_ip = nullptr;
124
125 T::DoDispose();
126}
127
128template <typename T>
129void
131{
133
134 m_node = node;
135}
136
137template <typename T>
138void
140{
142
143 for (auto i = NodeList::Begin(); i != NodeList::End(); i++)
144 {
145 Ptr<Node> node = *i;
146 Ptr<NixVectorRouting<T>> rp = node->GetObject<NixVectorRouting>();
147 if (!rp)
148 {
149 continue;
150 }
151 NS_LOG_LOGIC("Flushing Nix caches.");
152 rp->FlushNixCache();
153 rp->FlushIpRouteCache();
154 rp->m_totalNeighbors = 0;
155 }
156
157 // IP address to node mapping is potentially invalid so clear it.
158 // Will be repopulated in lazy evaluation when mapping is needed.
159 g_ipAddressToNodeMap.clear();
160}
161
162template <typename T>
163void
165{
167 m_nixCache.clear();
168}
169
170template <typename T>
171void
173{
175 m_ipRouteCache.clear();
176}
177
178template <typename T>
181{
182 NS_LOG_FUNCTION(this << source << dest << oif);
183
185 nixVector->SetEpoch(g_epoch);
186
187 // not in cache, must build the nix vector
188 // First, we have to figure out the nodes
189 // associated with these IPs
190 Ptr<Node> destNode = GetNodeByIp(dest);
191 if (!destNode)
192 {
193 NS_LOG_ERROR("No routing path exists");
194 return nullptr;
195 }
196
197 // if source == dest, then we have a special case
198 /// @internal
199 /// Do not process packets to self (see \bugid{1308})
200 if (source == destNode)
201 {
202 NS_LOG_DEBUG("Do not process packets to self");
203 return nullptr;
204 }
205 else
206 {
207 // otherwise proceed as normal
208 // and build the nix vector
209 std::vector<Ptr<Node>> parentVector;
210
212 {
213 if (BuildNixVector(parentVector, source->GetId(), destNode->GetId(), nixVector))
214 {
215 return nixVector;
216 }
217 else
218 {
219 NS_LOG_ERROR("No routing path exists");
220 return nullptr;
221 }
222 }
223 else
224 {
225 NS_LOG_ERROR("No routing path exists");
226 return nullptr;
227 }
228 }
229}
230
231template <typename T>
234{
235 NS_LOG_FUNCTION(this << address);
236
237 CheckCacheStateAndFlush();
238
239 auto iter = m_nixCache.find(address);
240 if (iter != m_nixCache.end())
241 {
242 NS_LOG_LOGIC("Found Nix-vector in cache.");
243 foundInCache = true;
244 return iter->second;
245 }
246
247 // not in cache
248 foundInCache = false;
249 return nullptr;
250}
251
252template <typename T>
255{
256 NS_LOG_FUNCTION(this << address);
257
258 CheckCacheStateAndFlush();
259
260 auto iter = m_ipRouteCache.find(address);
261 if (iter != m_ipRouteCache.end())
262 {
263 NS_LOG_LOGIC("Found IpRoute in cache.");
264 return iter->second;
265 }
266
267 // not in cache
268 return nullptr;
269}
270
271template <typename T>
272bool
277{
279
280 if (source == dest)
281 {
282 return true;
283 }
284
285 if (!parentVector.at(dest))
286 {
287 return false;
288 }
289
291
292 uint32_t numberOfDevices = parentNode->GetNDevices();
293 uint32_t destId = 0;
295
296 // scan through the net devices on the T node
297 // and then look at the nodes adjacent to them
298 for (uint32_t i = 0; i < numberOfDevices; i++)
299 {
300 // Get a net device from the node
301 // as well as the channel, and figure
302 // out the adjacent net devices
304 if (localNetDevice->IsBridge())
305 {
306 continue;
307 }
308 Ptr<Channel> channel = localNetDevice->GetChannel();
309 if (!channel)
310 {
311 continue;
312 }
313
314 // this function takes in the local net dev, and channel, and
315 // writes to the netDeviceContainer the adjacent net devs
317 GetAdjacentNetDevices(localNetDevice, channel, netDeviceContainer);
318
319 // Finally we can get the adjacent nodes
320 // and scan through them. If we find the
321 // node that matches "dest" then we can add
322 // the index to the nix vector.
323 // the index corresponds to the neighbor index
324 uint32_t offset = 0;
325 for (auto iter = netDeviceContainer.Begin(); iter != netDeviceContainer.End(); iter++)
326 {
327 Ptr<Node> remoteNode = (*iter)->GetNode();
328
329 if (remoteNode->GetId() == dest)
330 {
331 destId = totalNeighbors + offset;
332 }
333 offset += 1;
334 }
335
337 }
338 NS_LOG_LOGIC("Adding Nix: " << destId << " with " << nixVector->BitCount(totalNeighbors)
339 << " bits, for node " << parentNode->GetId());
340 nixVector->AddNeighborIndex(destId, nixVector->BitCount(totalNeighbors));
341
342 // recurse through T vector, grabbing the path
343 // and building the nix vector
344 BuildNixVector(parentVector, source, (parentVector.at(dest))->GetId(), nixVector);
345 return true;
346}
347
348template <typename T>
349void
351 Ptr<Channel> channel,
353{
354 NS_LOG_FUNCTION(this << netDevice << channel);
355
356 Ptr<IpInterface> netDeviceInterface = GetInterfaceByNetDevice(netDevice);
357 if (!netDeviceInterface || !netDeviceInterface->IsUp())
358 {
359 NS_LOG_LOGIC("IpInterface either doesn't exist or is down");
360 return;
361 }
362
364
365 for (std::size_t i = 0; i < channel->GetNDevices(); i++)
366 {
367 Ptr<NetDevice> remoteDevice = channel->GetDevice(i);
368 if (remoteDevice != netDevice)
369 {
370 // Compare if the remoteDevice shares a common subnet with remoteDevice
371 Ptr<IpInterface> remoteDeviceInterface = GetInterfaceByNetDevice(remoteDevice);
373 {
374 NS_LOG_LOGIC("IpInterface either doesn't exist or is down");
375 continue;
376 }
377
379 bool commonSubnetFound = false;
380
381 for (uint32_t j = 0; j < netDeviceAddresses; ++j)
382 {
384 if constexpr (!IsIpv4)
385 {
387 {
388 continue;
389 }
390 }
391 for (uint32_t k = 0; k < remoteDeviceAddresses; ++k)
392 {
394 if constexpr (!IsIpv4)
395 {
397 {
398 continue;
399 }
400 }
401 if (netDeviceIfAddr.IsInSameSubnet(remoteDeviceIfAddr.GetAddress()))
402 {
403 commonSubnetFound = true;
404 break;
405 }
406 }
407
409 {
410 break;
411 }
412 }
413
415 {
416 continue;
417 }
418
419 Ptr<BridgeNetDevice> bd = NetDeviceIsBridged(remoteDevice);
420 // we have a bridged device, we need to add all
421 // bridged devices
422 if (bd)
423 {
424 NS_LOG_LOGIC("Looking through bridge ports of bridge net device " << bd);
425 for (uint32_t j = 0; j < bd->GetNBridgePorts(); ++j)
426 {
427 Ptr<NetDevice> ndBridged = bd->GetBridgePort(j);
428 if (ndBridged == remoteDevice)
429 {
430 NS_LOG_LOGIC("That bridge port is me, don't walk backward");
431 continue;
432 }
433 Ptr<Channel> chBridged = ndBridged->GetChannel();
434 if (!chBridged)
435 {
436 continue;
437 }
438 GetAdjacentNetDevices(ndBridged, chBridged, netDeviceContainer);
439 }
440 }
441 else
442 {
443 netDeviceContainer.Add(channel->GetDevice(i));
444 }
445 }
446 }
447}
448
449template <typename T>
450void
452{
454
455 for (auto it = NodeList::Begin(); it != NodeList::End(); ++it)
456 {
457 Ptr<Node> node = *it;
458 Ptr<IpL3Protocol> ip = node->GetObject<IpL3Protocol>();
459
460 if (ip)
461 {
462 uint32_t numberOfDevices = node->GetNDevices();
463
465 {
466 Ptr<NetDevice> device = node->GetDevice(deviceId);
467
468 // If this is not a loopback device add the IP address to the map
470 {
471 int32_t interfaceIndex = (ip)->GetInterfaceForDevice(node->GetDevice(deviceId));
472 if (interfaceIndex != -1)
473 {
474 g_netdeviceToIpInterfaceMap[device] = (ip)->GetInterface(interfaceIndex);
475
478 addressIndex++)
479 {
481 ip->GetAddress(interfaceIndex, addressIndex);
482 IpAddress addr = ifAddr.GetAddress();
483
485 g_ipAddressToNodeMap.count(addr),
486 "Duplicate IP address ("
487 << addr
488 << ") found during NIX Vector map construction for node "
489 << node->GetId());
490
491 NS_LOG_LOGIC("Adding IP address "
492 << addr << " for node " << node->GetId()
493 << " to NIX Vector IP address to node map");
494 g_ipAddressToNodeMap[addr] = node;
495 }
496 }
497 }
498 }
499 }
500 }
501}
502
503template <typename T>
506{
507 NS_LOG_FUNCTION(this << dest);
508
509 // Populate lookup table if is empty.
510 if (g_ipAddressToNodeMap.empty())
511 {
512 BuildIpAddressToNodeMap();
513 }
514
516
517 auto iter = g_ipAddressToNodeMap.find(dest);
518
519 if (iter == g_ipAddressToNodeMap.end())
520 {
521 NS_LOG_ERROR("Couldn't find dest node given the IP" << dest);
522 destNode = nullptr;
523 }
524 else
525 {
526 destNode = iter->second;
527 }
528
529 return destNode;
530}
531
532template <typename T>
535{
536 // Populate lookup table if is empty.
537 if (g_netdeviceToIpInterfaceMap.empty())
538 {
539 BuildIpAddressToNodeMap();
540 }
541
543
544 auto iter = g_netdeviceToIpInterfaceMap.find(netDevice);
545
546 if (iter == g_netdeviceToIpInterfaceMap.end())
547 {
548 NS_LOG_ERROR("Couldn't find IpInterface node given the NetDevice" << netDevice);
549 ipInterface = nullptr;
550 }
551 else
552 {
553 ipInterface = iter->second;
554 }
555
556 return ipInterface;
557}
558
559template <typename T>
562{
563 NS_LOG_FUNCTION(this << node);
564
565 uint32_t numberOfDevices = node->GetNDevices();
567
568 // scan through the net devices on the T node
569 // and then look at the nodes adjacent to them
570 for (uint32_t i = 0; i < numberOfDevices; i++)
571 {
572 // Get a net device from the node
573 // as well as the channel, and figure
574 // out the adjacent net devices
575 Ptr<NetDevice> localNetDevice = node->GetDevice(i);
576 Ptr<Channel> channel = localNetDevice->GetChannel();
577 if (!channel)
578 {
579 continue;
580 }
581
582 // this function takes in the local net dev, and channel, and
583 // writes to the netDeviceContainer the adjacent net devs
585 GetAdjacentNetDevices(localNetDevice, channel, netDeviceContainer);
586
588 }
589
590 return totalNeighbors;
591}
592
593template <typename T>
596{
597 NS_LOG_FUNCTION(this << nd);
598
599 Ptr<Node> node = nd->GetNode();
600 uint32_t nDevices = node->GetNDevices();
601
602 //
603 // There is no bit on a net device that says it is being bridged, so we have
604 // to look for bridges on the node to which the device is attached. If we
605 // find a bridge, we need to look through its bridge ports (the devices it
606 // bridges) to see if we find the device in question.
607 //
608 for (uint32_t i = 0; i < nDevices; ++i)
609 {
610 Ptr<NetDevice> ndTest = node->GetDevice(i);
611 NS_LOG_LOGIC("Examine device " << i << " " << ndTest);
612
613 if (ndTest->IsBridge())
614 {
615 NS_LOG_LOGIC("device " << i << " is a bridge net device");
618 bnd,
619 "NixVectorRouting::NetDeviceIsBridged (): GetObject for <BridgeNetDevice> failed");
620
621 for (uint32_t j = 0; j < bnd->GetNBridgePorts(); ++j)
622 {
623 NS_LOG_LOGIC("Examine bridge port " << j << " " << bnd->GetBridgePort(j));
624 if (bnd->GetBridgePort(j) == nd)
625 {
626 NS_LOG_LOGIC("Net device " << nd << " is bridged by " << bnd);
627 return bnd;
628 }
629 }
630 }
631 }
632 NS_LOG_LOGIC("Net device " << nd << " is not bridged");
633 return nullptr;
634}
635
636template <typename T>
640 IpAddress& gatewayIp) const
641{
642 NS_LOG_FUNCTION(this << node << nodeIndex << gatewayIp);
643
644 uint32_t numberOfDevices = node->GetNDevices();
645 uint32_t index = 0;
647
648 // scan through the net devices on the parent node
649 // and then look at the nodes adjacent to them
650 for (uint32_t i = 0; i < numberOfDevices; i++)
651 {
652 // Get a net device from the node
653 // as well as the channel, and figure
654 // out the adjacent net devices
655 Ptr<NetDevice> localNetDevice = node->GetDevice(i);
656 Ptr<Channel> channel = localNetDevice->GetChannel();
657 if (!channel)
658 {
659 continue;
660 }
661
662 // this function takes in the local net dev, and channel, and
663 // writes to the netDeviceContainer the adjacent net devs
665 GetAdjacentNetDevices(localNetDevice, channel, netDeviceContainer);
666
667 // check how many neighbors we have
669 {
670 // found the proper net device
671 index = i;
673 Ptr<IpInterface> gatewayInterface = GetInterfaceByNetDevice(gatewayDevice);
675 gatewayIp = ifAddr.GetAddress();
676 break;
677 }
679 }
680
681 return index;
682}
683
684template <typename T>
687 const IpHeader& header,
688 Ptr<NetDevice> oif,
690{
691 NS_LOG_FUNCTION(this << header << oif);
692
696
697 CheckCacheStateAndFlush();
698
699 IpAddress destAddress = header.GetDestination();
700
701 NS_LOG_DEBUG("Dest IP from header: " << destAddress);
702
703 if (destAddress.IsLocalhost())
704 {
706 rtentry->SetSource(IpAddress::GetLoopback());
707 rtentry->SetDestination(destAddress);
708 rtentry->SetGateway(IpAddress::GetZero());
709 for (uint32_t i = 0; i < m_ip->GetNInterfaces(); i++)
710 {
712 DynamicCast<LoopbackNetDevice>(m_ip->GetNetDevice(i));
713 if (loNetDevice)
714 {
715 rtentry->SetOutputDevice(loNetDevice);
716 break;
717 }
718 }
719 return rtentry;
720 }
721
722 if constexpr (!IsIpv4)
723 {
724 /* when sending on link-local multicast, there have to be interface specified */
725 if (destAddress.IsLinkLocalMulticast())
726 {
728 oif,
729 "Try to send on link-local multicast address, and no interface index is given!");
731 rtentry->SetSource(
732 m_ip->SourceAddressSelection(m_ip->GetInterfaceForDevice(oif), destAddress));
733 rtentry->SetDestination(destAddress);
734 rtentry->SetGateway(Ipv6Address::GetZero());
735 rtentry->SetOutputDevice(oif);
736 return rtentry;
737 }
738 }
739 // Check the Nix cache
740 bool foundInCache = false;
741 nixVectorInCache = GetNixVectorInCache(destAddress, foundInCache);
742
743 // not in cache
744 if (!foundInCache)
745 {
746 NS_LOG_LOGIC("Nix-vector not in cache, build: ");
747 // Build the nix-vector, given this node and the
748 // dest IP address
749 nixVectorInCache = GetNixVector(m_node, destAddress, oif);
751 {
752 // cache it
753 m_nixCache.insert(typename NixMap_t::value_type(destAddress, nixVectorInCache));
754 }
755 }
756
757 // path exists
759 {
760 NS_LOG_LOGIC("Nix-vector contents: " << *nixVectorInCache);
761
762 // create a new nix vector to be used,
763 // we want to keep the cached version clean
765
766 // Get the interface number that we go out of, by extracting
767 // from the nix-vector
768 if (m_totalNeighbors == 0)
769 {
770 m_totalNeighbors = FindTotalNeighbors(m_node);
771 }
772
773 // Get the interface number that we go out of, by extracting
774 // from the nix-vector
775 uint32_t numberOfBits = nixVectorForPacket->BitCount(m_totalNeighbors);
776 uint32_t nodeIndex = nixVectorForPacket->ExtractNeighborIndex(numberOfBits);
777
778 // Search here in a cache for this node index
779 // and look for a IpRoute
780 rtentry = GetIpRouteInCache(destAddress);
781
782 if (!rtentry || !(rtentry->GetOutputDevice() == oif))
783 {
784 // not in cache or a different specified output
785 // device is to be used
786
787 // first, make sure we erase existing (incorrect)
788 // rtentry from the map
789 if (rtentry)
790 {
791 m_ipRouteCache.erase(destAddress);
792 }
793
794 NS_LOG_LOGIC("IpRoute not in cache, build: ");
796 uint32_t index = FindNetDeviceForNixIndex(m_node, nodeIndex, gatewayIp);
798
799 if (!oif)
800 {
801 interfaceIndex = (m_ip)->GetInterfaceForDevice(m_node->GetDevice(index));
802 }
803 else
804 {
805 interfaceIndex = (m_ip)->GetInterfaceForDevice(oif);
806 }
807
808 NS_ASSERT_MSG(interfaceIndex != -1, "Interface index not found for device");
809
810 IpAddress sourceIPAddr = m_ip->SourceAddressSelection(interfaceIndex, destAddress);
811
812 // start filling in the IpRoute info
814 rtentry->SetSource(sourceIPAddr);
815
816 rtentry->SetGateway(gatewayIp);
817 rtentry->SetDestination(destAddress);
818
819 if (!oif)
820 {
821 rtentry->SetOutputDevice(m_ip->GetNetDevice(interfaceIndex));
822 }
823 else
824 {
825 rtentry->SetOutputDevice(oif);
826 }
827
829
830 // add rtentry to cache
831 m_ipRouteCache.insert(typename IpRouteMap_t::value_type(destAddress, rtentry));
832 }
833
834 NS_LOG_LOGIC("Nix-vector contents: " << *nixVectorInCache << " : Remaining bits: "
835 << nixVectorForPacket->GetRemainingBits());
836
837 // Add nix-vector in the packet class
838 // make sure the packet exists first
839 if (p)
840 {
841 NS_LOG_LOGIC("Adding Nix-vector to packet: " << *nixVectorForPacket);
842 p->SetNixVector(nixVectorForPacket);
843 }
844 }
845 else // path doesn't exist
846 {
847 NS_LOG_ERROR("No path to the dest: " << destAddress);
849 }
850
851 return rtentry;
852}
853
854template <typename T>
855bool
857 const IpHeader& header,
862 const ErrorCallback& ecb)
863{
864 NS_LOG_FUNCTION(this << p << header << header.GetSource() << header.GetDestination() << idev);
865
866 CheckCacheStateAndFlush();
867
868 NS_ASSERT(m_ip);
869 // Check if input device supports IP
870 NS_ASSERT(m_ip->GetInterfaceForDevice(idev) >= 0);
871 uint32_t iif = m_ip->GetInterfaceForDevice(idev);
872 // Check if input device supports IP
873 NS_ASSERT(iif >= 0);
874
875 IpAddress destAddress = header.GetDestination();
876
877 if constexpr (IsIpv4)
878 {
879 // Local delivery
880 if (m_ip->IsDestinationAddress(destAddress, iif))
881 {
882 if (!lcb.IsNull())
883 {
884 NS_LOG_LOGIC("Local delivery to " << destAddress);
885 p->SetNixVector(nullptr);
886 lcb(p, header, iif);
887 return true;
888 }
889 else
890 {
891 // The local delivery callback is null. This may be a multicast
892 // or broadcast packet, so return false so that another
893 // multicast routing protocol can handle it. It should be possible
894 // to extend this to explicitly check whether it is a unicast
895 // packet, and invoke the error callback if so
896 return false;
897 }
898 }
899 }
900 else
901 {
902 if (destAddress.IsMulticast())
903 {
904 NS_LOG_LOGIC("Multicast route not supported by Nix-Vector routing " << destAddress);
905 return false; // Let other routing protocols try to handle this
906 }
907
908 // Check if input device supports IP forwarding
909 if (m_ip->IsForwarding(iif) == false)
910 {
911 NS_LOG_LOGIC("Forwarding disabled for this interface");
912 if (!ecb.IsNull())
913 {
915 }
916 return true;
917 }
918 }
919
921
922 // Get the nix-vector from the packet
923 Ptr<NixVector> nixVector = p->GetNixVector();
924
925 // If nixVector isn't in packet, something went wrong
927
928 if (nixVector->GetEpoch() != g_epoch)
929 {
930 NS_LOG_LOGIC("NixVector epoch mismatch (" << nixVector->GetEpoch() << " Vs " << g_epoch
931 << ") - rebuilding it");
932 nixVector = GetNixVector(m_node, destAddress, nullptr);
933 p->SetNixVector(nixVector);
934 }
935
936 // Get the interface number that we go out of, by extracting
937 // from the nix-vector
938 if (m_totalNeighbors == 0)
939 {
940 m_totalNeighbors = FindTotalNeighbors(m_node);
941 }
942 uint32_t numberOfBits = nixVector->BitCount(m_totalNeighbors);
943 uint32_t nodeIndex = nixVector->ExtractNeighborIndex(numberOfBits);
944
945 rtentry = GetIpRouteInCache(destAddress);
946 // not in cache
947 if (!rtentry)
948 {
949 NS_LOG_LOGIC("IpRoute not in cache, build: ");
951 uint32_t index = FindNetDeviceForNixIndex(m_node, nodeIndex, gatewayIp);
952 uint32_t interfaceIndex = (m_ip)->GetInterfaceForDevice(m_node->GetDevice(index));
953 IpInterfaceAddress ifAddr = m_ip->GetAddress(interfaceIndex, 0);
954
955 // start filling in the IpRoute info
957 rtentry->SetSource(ifAddr.GetAddress());
958
959 rtentry->SetGateway(gatewayIp);
960 rtentry->SetDestination(destAddress);
961 rtentry->SetOutputDevice(m_ip->GetNetDevice(interfaceIndex));
962
963 // add rtentry to cache
964 m_ipRouteCache.insert(typename IpRouteMap_t::value_type(destAddress, rtentry));
965 }
966
967 NS_LOG_LOGIC("At Node " << m_node->GetId() << ", Extracting " << numberOfBits
968 << " bits from Nix-vector: " << nixVector << " : " << *nixVector);
969
970 // call the unicast callback
971 // local deliver is handled by Ipv4StaticRoutingImpl
972 // so this code is never even called if the packet is
973 // destined for this node.
974 if constexpr (IsIpv4)
975 {
976 ucb(rtentry, p, header);
977 }
978 else
979 {
980 ucb(idev, rtentry, p, header);
981 }
982
983 return true;
984}
985
986template <typename T>
987void
989{
991
992 CheckCacheStateAndFlush();
993
994 std::ostream* os = stream->GetStream();
995 // Copy the current ostream state
996 std::ios oldState(nullptr);
997 oldState.copyfmt(*os);
998
999 *os << std::resetiosflags(std::ios::adjustfield) << std::setiosflags(std::ios::left);
1000
1001 *os << "Node: " << m_node->GetId() << ", Time: " << Now().As(unit)
1002 << ", Local time: " << m_node->GetLocalTime().As(unit) << ", Nix Routing" << std::endl;
1003
1004 *os << "NixCache:" << std::endl;
1005 if (m_nixCache.size() > 0)
1006 {
1007 *os << std::setw(30) << "Destination";
1008 *os << "NixVector" << std::endl;
1009 for (auto it = m_nixCache.begin(); it != m_nixCache.end(); it++)
1010 {
1011 std::ostringstream dest;
1012 dest << it->first;
1013 *os << std::setw(30) << dest.str();
1014 if (it->second)
1015 {
1016 *os << *(it->second) << std::endl;
1017 }
1018 else
1019 {
1020 *os << "-" << std::endl;
1021 }
1022 }
1023 }
1024
1025 *os << "IpRouteCache:" << std::endl;
1026 if (m_ipRouteCache.size() > 0)
1027 {
1028 *os << std::setw(30) << "Destination";
1029 *os << std::setw(30) << "Gateway";
1030 *os << std::setw(30) << "Source";
1031 *os << "OutputDevice" << std::endl;
1032 for (auto it = m_ipRouteCache.begin(); it != m_ipRouteCache.end(); it++)
1033 {
1034 std::ostringstream dest;
1035 std::ostringstream gw;
1036 std::ostringstream src;
1037 dest << it->second->GetDestination();
1038 *os << std::setw(30) << dest.str();
1039 gw << it->second->GetGateway();
1040 *os << std::setw(30) << gw.str();
1041 src << it->second->GetSource();
1042 *os << std::setw(30) << src.str();
1043 *os << " ";
1044 if (Names::FindName(it->second->GetOutputDevice()) != "")
1045 {
1046 *os << Names::FindName(it->second->GetOutputDevice());
1047 }
1048 else
1049 {
1050 *os << it->second->GetOutputDevice()->GetIfIndex();
1051 }
1052 *os << std::endl;
1053 }
1054 }
1055 *os << std::endl;
1056 // Restore the previous ostream state
1057 (*os).copyfmt(oldState);
1058}
1059
1060// virtual functions from Ipv4RoutingProtocol
1061template <typename T>
1062void
1064{
1065 g_isCacheDirty = true;
1066}
1067
1068template <typename T>
1069void
1071{
1072 g_isCacheDirty = true;
1073}
1074
1075template <typename T>
1076void
1078{
1079 g_isCacheDirty = true;
1080}
1081
1082template <typename T>
1083void
1085{
1086 g_isCacheDirty = true;
1087}
1088
1089template <typename T>
1090void
1092 Ipv6Prefix mask,
1093 IpAddress nextHop,
1094 uint32_t interface,
1096{
1097 g_isCacheDirty = true;
1098}
1099
1100template <typename T>
1101void
1103 Ipv6Prefix mask,
1104 IpAddress nextHop,
1105 uint32_t interface,
1107{
1108 g_isCacheDirty = true;
1109}
1110
1111template <typename T>
1112bool
1116 std::vector<Ptr<Node>>& parentVector,
1117 Ptr<NetDevice> oif) const
1118{
1119 NS_LOG_FUNCTION(this << numberOfNodes << source << dest << parentVector << oif);
1120
1121 NS_LOG_LOGIC("Going from Node " << source->GetId() << " to Node " << dest->GetId());
1122 std::queue<Ptr<Node>> greyNodeList; // discovered nodes with unexplored children
1123
1124 // reset the parent vector
1125 parentVector.assign(numberOfNodes, nullptr); // initialize to 0
1126
1127 // Add the source node to the queue, set its parent to itself
1128 greyNodeList.push(source);
1129 parentVector.at(source->GetId()) = source;
1130
1131 // BFS loop
1132 while (!greyNodeList.empty())
1133 {
1135 Ptr<IpL3Protocol> ip = currNode->GetObject<IpL3Protocol>();
1136
1137 if (currNode == dest)
1138 {
1139 NS_LOG_LOGIC("Made it to Node " << currNode->GetId());
1140 return true;
1141 }
1142
1143 // if this is the first iteration of the loop and a
1144 // specific output interface was given, make sure
1145 // we go this way
1146 if (currNode == source && oif)
1147 {
1148 // make sure that we can go this way
1149 if (ip)
1150 {
1151 uint32_t interfaceIndex = (ip)->GetInterfaceForDevice(oif);
1152 if (!(ip->IsUp(interfaceIndex)))
1153 {
1154 NS_LOG_LOGIC("IpInterface is down");
1155 return false;
1156 }
1157 }
1158 if (!(oif->IsLinkUp()))
1159 {
1160 NS_LOG_LOGIC("Link is down.");
1161 return false;
1162 }
1163 Ptr<Channel> channel = oif->GetChannel();
1164 if (!channel)
1165 {
1166 return false;
1167 }
1168
1169 // this function takes in the local net dev, and channel, and
1170 // writes to the netDeviceContainer the adjacent net devs
1172 GetAdjacentNetDevices(oif, channel, netDeviceContainer);
1173
1174 // Finally we can get the adjacent nodes
1175 // and scan through them. We push them
1176 // to the greyNode queue, if they aren't
1177 // already there.
1178 for (auto iter = netDeviceContainer.Begin(); iter != netDeviceContainer.End(); iter++)
1179 {
1180 Ptr<Node> remoteNode = (*iter)->GetNode();
1181 Ptr<IpInterface> remoteIpInterface = GetInterfaceByNetDevice(*iter);
1182 if (!remoteIpInterface || !(remoteIpInterface->IsUp()))
1183 {
1184 NS_LOG_LOGIC("IpInterface either doesn't exist or is down");
1185 continue;
1186 }
1187
1188 // check to see if this node has been pushed before
1189 // by checking to see if it has a parent
1190 // if it doesn't (null or 0), then set its parent and
1191 // push to the queue
1192 if (!parentVector.at(remoteNode->GetId()))
1193 {
1194 parentVector.at(remoteNode->GetId()) = currNode;
1195 greyNodeList.push(remoteNode);
1196 }
1197 }
1198 }
1199 else
1200 {
1201 // Iterate over the current node's adjacent vertices
1202 // and push them into the queue
1203 for (uint32_t i = 0; i < (currNode->GetNDevices()); i++)
1204 {
1205 // Get a net device from the node
1206 // as well as the channel, and figure
1207 // out the adjacent net device
1209
1210 // make sure that we can go this way
1211 if (ip)
1212 {
1213 uint32_t interfaceIndex = (ip)->GetInterfaceForDevice(currNode->GetDevice(i));
1214 if (!(ip->IsUp(interfaceIndex)))
1215 {
1216 NS_LOG_LOGIC("IpInterface is down");
1217 continue;
1218 }
1219 }
1220 if (!(localNetDevice->IsLinkUp()))
1221 {
1222 NS_LOG_LOGIC("Link is down.");
1223 continue;
1224 }
1225 Ptr<Channel> channel = localNetDevice->GetChannel();
1226 if (!channel)
1227 {
1228 continue;
1229 }
1230
1231 // this function takes in the local net dev, and channel, and
1232 // writes to the netDeviceContainer the adjacent net devs
1234 GetAdjacentNetDevices(localNetDevice, channel, netDeviceContainer);
1235
1236 // Finally we can get the adjacent nodes
1237 // and scan through them. We push them
1238 // to the greyNode queue, if they aren't
1239 // already there.
1240 for (auto iter = netDeviceContainer.Begin(); iter != netDeviceContainer.End();
1241 iter++)
1242 {
1243 Ptr<Node> remoteNode = (*iter)->GetNode();
1244 Ptr<IpInterface> remoteIpInterface = GetInterfaceByNetDevice(*iter);
1245 if (!remoteIpInterface || !(remoteIpInterface->IsUp()))
1246 {
1247 NS_LOG_LOGIC("IpInterface either doesn't exist or is down");
1248 continue;
1249 }
1250
1251 // check to see if this node has been pushed before
1252 // by checking to see if it has a parent
1253 // if it doesn't (null or 0), then set its parent and
1254 // push to the queue
1255 if (!parentVector.at(remoteNode->GetId()))
1256 {
1257 parentVector.at(remoteNode->GetId()) = currNode;
1258 greyNodeList.push(remoteNode);
1259 }
1260 }
1261 }
1262 }
1263
1264 // Pop off the head grey node. We have all its children.
1265 // It is now black.
1266 greyNodeList.pop();
1267 }
1268
1269 // Didn't find the dest...
1270 return false;
1271}
1272
1273template <typename T>
1274void
1278 Time::Unit unit) const
1279{
1280 NS_LOG_FUNCTION(this << source << dest);
1281
1285
1286 CheckCacheStateAndFlush();
1287
1288 Ptr<Node> destNode = GetNodeByIp(dest);
1289 if (!destNode)
1290 {
1291 NS_LOG_ERROR("No routing path exists");
1292 return;
1293 }
1294
1295 std::ostream* os = stream->GetStream();
1296 // Copy the current ostream state
1297 std::ios oldState(nullptr);
1298 oldState.copyfmt(*os);
1299
1300 *os << std::resetiosflags(std::ios::adjustfield) << std::setiosflags(std::ios::left);
1301 *os << "Time: " << Now().As(unit) << ", Nix Routing" << std::endl;
1302 *os << "Route path from ";
1303 *os << "Node " << source->GetId() << " to Node " << destNode->GetId() << ", ";
1304 *os << "Nix Vector: ";
1305
1306 // Check the Nix cache
1307 bool foundInCache = true;
1308 nixVectorInCache = GetNixVectorInCache(dest, foundInCache);
1309
1310 // not in cache
1311 if (!foundInCache)
1312 {
1313 NS_LOG_LOGIC("Nix-vector not in cache, build: ");
1314 // Build the nix-vector, given the source node and the
1315 // dest IP address
1316 nixVectorInCache = GetNixVector(source, dest, nullptr);
1317 }
1318
1320 {
1323
1324 if (nixVectorInCache)
1325 {
1326 // Make a NixVector copy to work with. This is because
1327 // we don't want to extract the bits from nixVectorInCache
1328 // which is stored in the m_nixCache.
1329 nixVector = nixVectorInCache->Copy();
1330
1331 *os << *nixVector;
1332 }
1333 *os << std::endl;
1334
1335 if (source == destNode)
1336 {
1337 std::ostringstream addr;
1338 std::ostringstream node;
1339 addr << dest;
1340 node << "(Node " << destNode->GetId() << ")";
1341 *os << std::setw(25) << addr.str();
1342 *os << std::setw(10) << node.str();
1343 *os << "----> ";
1344 *os << std::setw(25) << addr.str();
1345 *os << node.str() << std::endl;
1346 }
1347
1348 while (curr != destNode)
1349 {
1350 totalNeighbors = FindTotalNeighbors(curr);
1351 // Get the number of bits required
1352 // to represent all the neighbors
1354 // Get the nixIndex
1355 uint32_t nixIndex = nixVector->ExtractNeighborIndex(numberOfBits);
1356 // gatewayIP is the IP of next
1357 // node on channel found from nixIndex
1359 // Get the Net Device index from the nixIndex
1360 uint32_t netDeviceIndex = FindNetDeviceForNixIndex(curr, nixIndex, gatewayIp);
1361 // Get the interfaceIndex with the help of netDeviceIndex.
1362 // It will be used to get the IP address on interfaceIndex
1363 // interface of 'curr' node.
1364 Ptr<IpL3Protocol> ip = curr->GetObject<IpL3Protocol>();
1366 uint32_t interfaceIndex = ip->GetInterfaceForDevice(outDevice);
1368 if (curr == source)
1369 {
1370 sourceIPAddr = ip->SourceAddressSelection(interfaceIndex, dest);
1371 }
1372 else
1373 {
1374 // We use the first address because it's indifferent which one
1375 // we use to identify intermediate routers
1376 sourceIPAddr = ip->GetAddress(interfaceIndex, 0).GetAddress();
1377 }
1378
1379 std::ostringstream currAddr;
1380 std::ostringstream currNode;
1381 std::ostringstream nextAddr;
1382 std::ostringstream nextNode;
1384 currNode << "(Node " << curr->GetId() << ")";
1385 *os << std::setw(25) << currAddr.str();
1386 *os << std::setw(10) << currNode.str();
1387 // Replace curr with the next node
1388 curr = GetNodeByIp(gatewayIp);
1389 nextAddr << ((curr == destNode) ? dest : gatewayIp);
1390 nextNode << "(Node " << curr->GetId() << ")";
1391 *os << "----> ";
1392 *os << std::setw(25) << nextAddr.str();
1393 *os << nextNode.str() << std::endl;
1394 }
1395 *os << std::endl;
1396 }
1397 else
1398 {
1399 *os << ")" << std::endl;
1400 // No Route exists
1401 *os << "There does not exist a path from Node " << source->GetId() << " to Node "
1402 << destNode->GetId() << "." << std::endl;
1403 }
1404 // Restore the previous ostream state
1405 (*os).copyfmt(oldState);
1406}
1407
1408template <typename T>
1409void
1411{
1412 if (g_isCacheDirty)
1413 {
1414 FlushGlobalNixRoutingCache();
1415 g_epoch++;
1416 g_isCacheDirty = false;
1417 }
1418}
1419
1420/* Public template function declarations */
1427 IpAddress dest,
1429 Time::Unit unit) const;
1432 IpAddress dest,
1434 Time::Unit unit) const;
1435
1436} // namespace ns3
a virtual net device that bridges multiple LAN segments
Callback template class.
Definition callback.h:422
static Ipv6Address GetZero()
Get the 0 (::) Ipv6Address.
@ LINKLOCAL
Link-local address (fe80::/64)
Describes an IPv6 prefix.
static std::string FindName(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and,...
Definition names.cc:818
holds a vector of ns3::NetDevice pointers
Nix-vector routing protocol.
void PrintRoutingPath(Ptr< Node > source, IpAddress dest, Ptr< OutputStreamWrapper > stream, Time::Unit unit) const
Print the Routing Path according to Nix Routing.
void BuildIpAddressToNodeMap() const
Build map from IP Address to Node for faster lookup.
Ptr< IpRoute > GetIpRouteInCache(IpAddress address)
Checks the cache based on dest IP for the IpRoute.
virtual void NotifyRemoveRoute(IpAddress dst, Ipv6Prefix mask, IpAddress nextHop, uint32_t interface, IpAddress prefixToUse=IpAddress::GetZero())
Notify route removing.
virtual void NotifyAddRoute(IpAddress dst, Ipv6Prefix mask, IpAddress nextHop, uint32_t interface, IpAddress prefixToUse=IpAddress::GetZero())
Notify a new route.
typename std::conditional_t< IsIpv4, Ipv4InterfaceAddress, Ipv6InterfaceAddress > IpInterfaceAddress
Alias for Ipv4InterfaceAddress and Ipv6InterfaceAddress classes.
bool BFS(uint32_t numberOfNodes, Ptr< Node > source, Ptr< Node > dest, std::vector< Ptr< Node > > &parentVector, Ptr< NetDevice > oif) const
Breadth first search algorithm.
static uint32_t g_epoch
Nix Epoch, incremented each time a flush is performed.
virtual void NotifyInterfaceUp(uint32_t interface)
void GetAdjacentNetDevices(Ptr< NetDevice > netDevice, Ptr< Channel > channel, NetDeviceContainer &netDeviceContainer) const
Given a net-device returns all the adjacent net-devices, essentially getting the neighbors on that ch...
std::conditional_t< IsIpv4, UnicastForwardCallbackv4, UnicastForwardCallbackv6 > UnicastForwardCallback
Callback for unicast packets to be forwarded.
virtual void NotifyInterfaceDown(uint32_t interface)
typename std::conditional_t< IsIpv4, Ipv4Address, Ipv6Address > IpAddress
Alias for Ipv4Address and Ipv6Address classes.
static IpAddressToNodeMap g_ipAddressToNodeMap
Address to node map.
void FlushGlobalNixRoutingCache() const
Called when run-time link topology change occurs which iterates through the node list and flushes any...
virtual void SetIpv6(Ptr< Ip > ipv6)
Typically, invoked directly or indirectly from ns3::Ipv6::SetRoutingProtocol.
virtual Ptr< IpRoute > RouteOutput(Ptr< Packet > p, const IpHeader &header, Ptr< NetDevice > oif, Socket::SocketErrno &sockerr)
Query routing cache for an existing route, for an outbound packet.
virtual void SetIpv4(Ptr< Ip > ipv4)
Typically, invoked directly or indirectly from ns3::Ipv4::SetRoutingProtocol.
Ptr< IpInterface > GetInterfaceByNetDevice(Ptr< NetDevice > netDevice) const
Iterates through the node list and finds the one corresponding to the given IpAddress.
uint32_t FindTotalNeighbors(Ptr< Node > node) const
Simply iterates through the nodes net-devices and determines how many neighbors the node has.
virtual void NotifyAddAddress(uint32_t interface, IpInterfaceAddress address)
std::conditional_t< IsIpv4, MulticastForwardCallbackv4, MulticastForwardCallbackv6 > MulticastForwardCallback
Callback for multicast packets to be forwarded.
void FlushIpRouteCache() const
Flushes the cache which stores the Ip route based on the destination IP.
virtual bool RouteInput(Ptr< const Packet > p, const IpHeader &header, Ptr< const NetDevice > idev, const UnicastForwardCallback &ucb, const MulticastForwardCallback &mcb, const LocalDeliverCallback &lcb, const ErrorCallback &ecb)
Route an input packet (to be forwarded or locally delivered)
Ptr< NixVector > GetNixVector(Ptr< Node > source, IpAddress dest, Ptr< NetDevice > oif) const
Takes in the source node and dest IP and calls GetNodeByIp, BFS, accounting for any output interface ...
typename std::conditional_t< IsIpv4, Ipv4Header, Ipv6Header > IpHeader
Alias for Ipv4Header and Ipv6Header classes.
bool BuildNixVector(const std::vector< Ptr< Node > > &parentVector, uint32_t source, uint32_t dest, Ptr< NixVector > nixVector) const
Recurses the T vector, created by BFS and actually builds the nixvector.
Ptr< NixVector > GetNixVectorInCache(const IpAddress &address, bool &foundInCache) const
Checks the cache based on dest IP for the nix-vector.
uint32_t FindNetDeviceForNixIndex(Ptr< Node > node, uint32_t nodeIndex, IpAddress &gatewayIp) const
Nix index is with respect to the neighbors.
static NetDeviceToIpInterfaceMap g_netdeviceToIpInterfaceMap
NetDevice pointer to IpInterface pointer map.
void SetNode(Ptr< Node > node)
Set the Node pointer of the node for which this routing protocol is to be placed.
virtual void PrintRoutingTable(Ptr< OutputStreamWrapper > stream, Time::Unit unit=Time::S) const
Print the Routing Table entries.
typename std::conditional_t< IsIpv4, Ipv4L3Protocol, Ipv6L3Protocol > IpL3Protocol
Alias for Ipv4L3Protocol and Ipv4L3Protocol classes.
virtual void NotifyRemoveAddress(uint32_t interface, IpInterfaceAddress address)
static TypeId GetTypeId()
The Interface ID of the Global Router interface.
static bool g_isCacheDirty
Flag to mark when caches are dirty and need to be flushed.
void CheckCacheStateAndFlush() const
Flushes routing caches if required.
std::unordered_map< IpAddress, ns3::Ptr< ns3::Node >, IpAddressHash > IpAddressToNodeMap
Mapping of IP address to ns-3 node.
std::unordered_map< Ptr< NetDevice >, Ptr< IpInterface > > NetDeviceToIpInterfaceMap
Mapping of Ptr<NetDevice> to Ptr<IpInterface>.
Ptr< BridgeNetDevice > NetDeviceIsBridged(Ptr< NetDevice > nd) const
Determine if the NetDevice is bridged.
void FlushNixCache() const
Flushes the cache which stores nix-vector based on destination IP.
Ptr< Node > GetNodeByIp(IpAddress dest) const
Iterates through the node list and finds the one corresponding to the given IpAddress.
static Iterator Begin()
Definition node-list.cc:226
static uint32_t GetNNodes()
Definition node-list.cc:247
static Iterator End()
Definition node-list.cc:233
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:66
SocketErrno
Enumeration of the possible errors returned by a socket.
Definition socket.h:73
@ ERROR_NOROUTETOHOST
Definition socket.h:84
@ ERROR_NOTERROR
Definition socket.h:74
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
Unit
The unit to use to interpret a number representing time.
Definition nstime.h:100
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition abort.h:133
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:243
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_TEMPLATE_CLASS_DEFINE(type, param)
Explicitly instantiate a template class with one template parameter and register the resulting instan...
Definition object-base.h:67
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition simulator.cc:294
Every class exported by the ns3 library is enclosed in the ns3 namespace.