diff --git a/src/nix-vector-routing/model/nix-vector-routing.cc b/src/nix-vector-routing/model/nix-vector-routing.cc index c88ab5576..dc150d54f 100644 --- a/src/nix-vector-routing/model/nix-vector-routing.cc +++ b/src/nix-vector-routing/model/nix-vector-routing.cc @@ -41,8 +41,22 @@ NS_LOG_COMPONENT_DEFINE ("NixVectorRouting"); NS_OBJECT_TEMPLATE_CLASS_DEFINE (NixVectorRouting, Ipv4RoutingProtocol); NS_OBJECT_TEMPLATE_CLASS_DEFINE (NixVectorRouting, Ipv6RoutingProtocol); +#ifdef NS3_MTP +template +std::atomic NixVectorRouting::g_isCacheDirty (false); + +template +std::atomic NixVectorRouting::g_cacheFlushing (false); + +template +std::atomic NixVectorRouting::g_isMapBuilt (false); + +template +std::atomic NixVectorRouting::g_mapBuilding (false); +#else template bool NixVectorRouting::g_isCacheDirty = false; +#endif // Epoch starts from one to make it easier to spot an uninitialized NixVector during debug. template @@ -162,6 +176,9 @@ NixVectorRouting::FlushGlobalNixRoutingCache (void) const // IP address to node mapping is potentially invalid so clear it. // Will be repopulated in lazy evaluation when mapping is needed. g_ipAddressToNodeMap.clear (); +#ifdef NS3_MTP + g_isMapBuilt.store (false, std::memory_order_release); +#endif } template @@ -500,10 +517,27 @@ NixVectorRouting::GetNodeByIp (IpAddress dest) const NS_LOG_FUNCTION (this << dest); // Populate lookup table if is empty. +#ifdef NS3_MTP + if (!g_isMapBuilt.load (std::memory_order_acquire)) + { + if (g_mapBuilding.exchange (true, std::memory_order_relaxed)) + { + while (!g_isMapBuilt.load (std::memory_order_acquire)) + ; + } + else + { + BuildIpAddressToNodeMap (); + g_isMapBuilt.store (true, std::memory_order_release); + g_mapBuilding.store (false, std::memory_order_release); + } + } +#else if ( g_ipAddressToNodeMap.empty () ) { BuildIpAddressToNodeMap (); } +#endif Ptr destNode; @@ -527,10 +561,27 @@ Ptr::IpInterface> NixVectorRouting::GetInterfaceByNetDevice (Ptr netDevice) const { // Populate lookup table if is empty. +#ifdef NS3_MTP + if (!g_isMapBuilt.load (std::memory_order_acquire)) + { + if (g_mapBuilding.exchange (true, std::memory_order_relaxed)) + { + while (!g_isMapBuilt.load (std::memory_order_acquire)) + ; + } + else + { + BuildIpAddressToNodeMap (); + g_isMapBuilt.store (true, std::memory_order_release); + g_mapBuilding.store (false, std::memory_order_release); + } + } +#else if ( g_netdeviceToIpInterfaceMap.empty () ) { BuildIpAddressToNodeMap (); } +#endif Ptr ipInterface; @@ -1039,37 +1090,61 @@ template void NixVectorRouting::NotifyInterfaceUp (uint32_t i) { +#ifdef NS3_MTP + g_isCacheDirty.store (true, std::memory_order_release); +#else g_isCacheDirty = true; +#endif } template void NixVectorRouting::NotifyInterfaceDown (uint32_t i) { +#ifdef NS3_MTP + g_isCacheDirty.store (true, std::memory_order_release); +#else g_isCacheDirty = true; +#endif } template void NixVectorRouting::NotifyAddAddress (uint32_t interface, IpInterfaceAddress address) { +#ifdef NS3_MTP + g_isCacheDirty.store (true, std::memory_order_release); +#else g_isCacheDirty = true; +#endif } template void NixVectorRouting::NotifyRemoveAddress (uint32_t interface, IpInterfaceAddress address) { +#ifdef NS3_MTP + g_isCacheDirty.store (true, std::memory_order_release); +#else g_isCacheDirty = true; +#endif } template void NixVectorRouting::NotifyAddRoute (IpAddress dst, Ipv6Prefix mask, IpAddress nextHop, uint32_t interface, IpAddress prefixToUse) { +#ifdef NS3_MTP + g_isCacheDirty.store (true, std::memory_order_release); +#else g_isCacheDirty = true; +#endif } template void NixVectorRouting::NotifyRemoveRoute (IpAddress dst, Ipv6Prefix mask, IpAddress nextHop, uint32_t interface, IpAddress prefixToUse) { +#ifdef NS3_MTP + g_isCacheDirty.store (true, std::memory_order_release); +#else g_isCacheDirty = true; +#endif } template @@ -1365,12 +1440,29 @@ template void NixVectorRouting::CheckCacheStateAndFlush (void) const { +#ifdef NS3_MTP + if (g_isCacheDirty.load (std::memory_order_acquire)) + { + if (g_cacheFlushing.exchange (true, std::memory_order_relaxed)) + { + while (g_isCacheDirty.load (std::memory_order_acquire)) + ; + } + else + { + FlushGlobalNixRoutingCache (); + g_isCacheDirty.store (false, std::memory_order_release); + g_cacheFlushing.store (false, std::memory_order_release); + } + } +#else if (g_isCacheDirty) { FlushGlobalNixRoutingCache (); g_epoch++; g_isCacheDirty = false; } +#endif } /* Public template function declarations */ diff --git a/src/nix-vector-routing/model/nix-vector-routing.h b/src/nix-vector-routing/model/nix-vector-routing.h index 26f3010a4..cdcdc0889 100644 --- a/src/nix-vector-routing/model/nix-vector-routing.h +++ b/src/nix-vector-routing/model/nix-vector-routing.h @@ -42,6 +42,7 @@ #include "ns3/ipv4-l3-protocol.h" #include "ns3/ipv6-l3-protocol.h" +#include #include #include @@ -446,7 +447,14 @@ private: * Flag to mark when caches are dirty and need to be flushed. * Used for lazy cleanup of caches when there are many topology changes. */ +#ifdef NS3_MTP + static std::atomic g_isCacheDirty; + static std::atomic g_cacheFlushing; + static std::atomic g_isMapBuilt; + static std::atomic g_mapBuilding; +#else static bool g_isCacheDirty; +#endif /** * Nix Epoch, incremented each time a flush is perfomed.