internet: (merge !129) Reduced event generation for Ipv4L3Protocol multicast de-duplication

This commit is contained in:
Jared Dulmage
2019-11-29 23:38:12 +01:00
committed by Tommaso Pecorella
parent 3b2ac47f2d
commit 204bb0d30e
3 changed files with 190 additions and 33 deletions

View File

@@ -80,6 +80,12 @@ Ipv4L3Protocol::GetTypeId (void)
TimeValue (MilliSeconds (1)),
MakeTimeAccessor (&Ipv4L3Protocol::m_expire),
MakeTimeChecker ())
.AddAttribute ("PurgeExpiredPeriod",
"Time between purges of expired duplicate packet entries, "
"0 means never purge",
TimeValue (Seconds (1)),
MakeTimeAccessor (&Ipv4L3Protocol::m_purge),
MakeTimeChecker (Seconds (0)))
.AddTraceSource ("Tx",
"Send ipv4 packet to outgoing interface.",
MakeTraceSourceAccessor (&Ipv4L3Protocol::m_txTrace),
@@ -329,12 +335,9 @@ Ipv4L3Protocol::DoDispose (void)
m_fragments.clear ();
m_fragmentsTimers.clear ();
for (auto dup: m_dups)
if (m_cleanDpd.IsRunning ())
{
if (dup.second.IsRunning ())
{
dup.second.Cancel ();
}
m_cleanDpd.Cancel ();
}
m_dups.clear ();
@@ -1763,14 +1766,21 @@ Ipv4L3Protocol::UpdateDuplicate (Ptr<const Packet> p, const Ipv4Header &header)
bytes[8] = 0; // TTL
bytes[10] = bytes[11] = 0; // Header checksum
if (header.GetSerializedSize () > 20) // assume options should be 0'd
std::fill_n (bytes.begin () + 20, header.GetSerializedSize () - 20, 0);
{
std::fill_n (bytes.begin () + 20, header.GetSerializedSize () - 20, 0);
}
// concat hash onto ID
hash |= (uint64_t)Hash32 (bytes);
}
// set cleanup job for new duplicate entries
if (!m_cleanDpd.IsRunning () && m_purge.IsStrictlyPositive ())
{
m_cleanDpd = Simulator::Schedule (m_expire, &Ipv4L3Protocol::RemoveDuplicates, this);
}
// assume this is a new entry
bool isDup = false;
DupTuple_t key {hash, proto, src, dst};
NS_LOG_DEBUG ("Packet " << p->GetUid () << " key = (" <<
std::hex << std::get<0> (key) << ", " <<
@@ -1779,29 +1789,49 @@ Ipv4L3Protocol::UpdateDuplicate (Ptr<const Packet> p, const Ipv4Header &header)
std::get<3> (key) << ")");
// place a new entry, on collision the existing entry iterator is returned
auto iter = m_dups.emplace_hint (m_dups.end (), key, EventId ());
// cancel un-expired event
if (iter->second.IsRunning ())
{
iter->second.Cancel ();
isDup = true; // flag this was a duplicate
}
DupMap_t::iterator iter;
bool inserted, isDup;
std::tie (iter, inserted) = m_dups.emplace (key, Seconds (0));
isDup = !inserted && iter->second > Simulator::Now ();
// set the expiration event
iter->second = Simulator::Schedule (m_expire, &Ipv4L3Protocol::RemoveDuplicate, this, iter);
iter->second = Simulator::Now () + m_expire;
return isDup;
}
void
Ipv4L3Protocol::RemoveDuplicate (DupMap_t::const_iterator iter)
Ipv4L3Protocol::RemoveDuplicates (void)
{
NS_LOG_FUNCTION (this);
NS_LOG_LOGIC ("Remove key = (" <<
std::hex << std::get<0> (iter->first) << ", " <<
std::dec << +std::get<1> (iter->first) << ", " <<
std::get<2> (iter->first) << ", " <<
std::get<3> (iter->first) << ")");
m_dups.erase (iter);
DupMap_t::size_type n = 0;
Time expire = Simulator::Now ();
auto iter = m_dups.cbegin ();
while (iter != m_dups.cend ())
{
if (iter->second < expire)
{
NS_LOG_LOGIC ("Remove key = (" <<
std::hex << std::get<0> (iter->first) << ", " <<
std::dec << +std::get<1> (iter->first) << ", " <<
std::get<2> (iter->first) << ", " <<
std::get<3> (iter->first) << ")");
iter = m_dups.erase (iter);
++n;
}
else
{
++iter;
}
}
NS_LOG_DEBUG ("Purged " << n << " expired duplicate entries out of " << (n + m_dups.size ()));
// keep cleaning up if necessary
if (!m_dups.empty () && m_purge.IsStrictlyPositive ())
{
m_cleanDpd = Simulator::Schedule (m_purge, &Ipv4L3Protocol::RemoveDuplicates, this);
}
}

View File

@@ -560,8 +560,8 @@ private:
/// IETF RFC 6621, Section 6.2 de-duplication w/o IPSec
/// RFC 6621 recommended duplicate packet tuple: {IPV hash, IP protocol, IP source address, IP destination address}
typedef std::tuple <uint64_t, uint8_t, Ipv4Address, Ipv4Address> DupTuple_t;
/// Maps packet duplicate tuple to expiration event
typedef std::map<DupTuple_t, EventId> DupMap_t;
/// Maps packet duplicate tuple to expiration time
typedef std::map<DupTuple_t, Time> DupMap_t;
/**
* Registers duplicate entry, return false if new
@@ -574,12 +574,13 @@ private:
* Remove duplicate packet entry
* \param [in] iter Iterator into duplicate map to remove
*/
void RemoveDuplicate (DupMap_t::const_iterator iter);
bool m_enableDpd; //!< Enable multicast duplicate packet detection
DupMap_t m_dups; //!< map of packet duplicate tuples to expiry event
Time m_expire; //!< duplicate entry expiration delay
void RemoveDuplicates (void);
bool m_enableDpd; //!< Enable multicast duplicate packet detection
DupMap_t m_dups; //!< map of packet duplicate tuples to expiry event
Time m_expire; //!< duplicate entry expiration delay
Time m_purge; //!< time between purging expired duplicate entries
EventId m_cleanDpd; //!< event to cleanup expired duplicate entries
};
} // Namespace ns3

View File

@@ -31,6 +31,7 @@
#include "ns3/socket.h"
#include "ns3/boolean.h"
#include "ns3/double.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"
#include "ns3/config.h"
@@ -49,6 +50,7 @@
#include "ns3/ipv4-static-routing-helper.h"
#include "ns3/ipv4-address-helper.h"
#include "ns3/simple-net-device-helper.h"
#include "ns3/on-off-helper.h"
#include "ns3/traffic-control-layer.h"
@@ -356,6 +358,11 @@ Ipv4DeduplicationTest::DoRun (void)
socket->SetAllowBroadcast (true);
NS_TEST_EXPECT_MSG_EQ (socket->Bind (InetSocketAddress (Ipv4Address::GetAny (), 1234)), 0,
"Could not bind socket for node " << Names::FindName (*iter));
auto udpSocket = socket->GetObject<UdpSocket> ();
udpSocket->MulticastJoinGroup (0, Ipv4Address (targetAddr.c_str ())); // future proof?
udpSocket->SetAttribute ("IpMulticastTtl", StringValue ("4"));
socket->SetRecvCallback (MakeCallback (&Ipv4DeduplicationTest::ReceivePkt, this));
sockets.push_back (socket);
}
@@ -366,9 +373,6 @@ Ipv4DeduplicationTest::DoRun (void)
// start TX from A
auto txSocket = sockets.front ();
auto udpSocket = txSocket->GetObject<UdpSocket> ();
udpSocket->MulticastJoinGroup (0, Ipv4Address (targetAddr.c_str ())); // future proof?
udpSocket->SetAttribute ("IpMulticastTtl", StringValue ("4"));
// ------ Now the tests ------------
@@ -497,3 +501,125 @@ Ipv4DeduplicationTestSuite::Ipv4DeduplicationTestSuite ()
static Ipv4DeduplicationTestSuite g_ipv4DeduplicationTestSuite; //!< Static variable for test initialization
/**
* \ingroup internet-test
* \ingroup tests
*
* \brief IPv4 Deduplication Performance Test
*
* This test case sets up a fully connected network of
* 10 nodes. Each node transmits 2 packets / second
* for about 20 seconds. Packets are relayed from
* every receiver. The test outputs the number of
* events that have been processed during the course
* of the simulation. Test runtime is also a metric.
*
* The de-duplication cache entry expiration algorithm
* has evolved from an event-per-expiry (EPE) algorithm to
* a periodic event, batch purge (PBP) algorithm. The
* current metrics are taken from tests on the development
* box. Periodic batch purge period defaults to 1s.
*
* Events Runtime
* EVE 656140 29s
* PBP 337420 29s
*
*/
class Ipv4DeduplicationPerformanceTest : public TestCase
{
public:
Ipv4DeduplicationPerformanceTest (void);
virtual void DoRun (void);
};
Ipv4DeduplicationPerformanceTest::Ipv4DeduplicationPerformanceTest ()
: TestCase ("Ipv4Deduplication performance test")
{}
void
Ipv4DeduplicationPerformanceTest::DoRun (void)
{
// multicast target
const std::string targetAddr = "239.192.100.1";
Config::SetDefault ("ns3::Ipv4L3Protocol::EnableDuplicatePacketDetection", BooleanValue (true));
Config::SetDefault ("ns3::Ipv4L3Protocol::DuplicateExpire", TimeValue (Time ("10s")));
// Create nodes
auto nodes = NodeContainer ();
nodes.Create (20);
SimpleNetDeviceHelper simplenet;
auto devices = simplenet.Install (nodes);
Ipv4ListRoutingHelper listRouting;
Ipv4StaticRoutingHelper staticRouting;
listRouting.Add (staticRouting, 0);
InternetStackHelper internet;
internet.SetIpv6StackInstall (false);
internet.SetIpv4ArpJitter (true);
internet.SetRoutingHelper (listRouting);
internet.Install (nodes);
Ipv4AddressHelper ipv4address;
ipv4address.SetBase ("10.0.0.0", "255.255.255.0");
ipv4address.Assign (devices);
// add static routes for each node / device
auto diter = devices.Begin ();
for (auto end = nodes.End (),
iter = nodes.Begin (); iter != end; ++iter)
{
// route for forwarding
staticRouting.AddMulticastRoute (*iter, Ipv4Address::GetAny (), targetAddr.c_str (), *diter, NetDeviceContainer (*diter));
// route for host
// Use host routing entry according to note in Ipv4StaticRouting::RouteOutput:
//// Note: Multicast routes for outbound packets are stored in the
//// normal unicast table. An implication of this is that it is not
//// possible to source multicast datagrams on multiple interfaces.
//// This is a well-known property of sockets implementation on
//// many Unix variants.
//// So, we just log it and fall through to LookupStatic ()
auto ipv4 = (*iter)->GetObject <Ipv4> ();
NS_ASSERT_MSG ((bool) ipv4, "Node " << (*iter)->GetId () << " does not have Ipv4 aggregate");
auto routing = staticRouting.GetStaticRouting (ipv4);
routing->AddHostRouteTo (targetAddr.c_str (), ipv4->GetInterfaceForDevice (*diter), 0);
++diter;
}
// Create application
OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (targetAddr.c_str (), 1234));
onoff.SetConstantRate (DataRate ("8kbps")); // 2 packets / second for default 512B packets
onoff.SetAttribute ("MaxBytes", UintegerValue (512 * 40)); // 20 seconds worth of packets
auto apps = onoff.Install (nodes);
apps.StartWithJitter (Seconds (4), CreateObjectWithAttributes <UniformRandomVariable> ("Max", DoubleValue (4)));
Simulator::Run ();
NS_LOG_UNCOND ("Executed " << Simulator::GetEventCount () << " events");
Simulator::Destroy ();
}
/**
* \ingroup internet-test
* \ingroup tests
*
* \brief IPv4 Deduplication Performance TestSuite
*/
class Ipv4DeduplicationPerformanceTestSuite : public TestSuite
{
public:
Ipv4DeduplicationPerformanceTestSuite ();
};
Ipv4DeduplicationPerformanceTestSuite::Ipv4DeduplicationPerformanceTestSuite ()
: TestSuite ("ipv4-deduplication-performance", PERFORMANCE)
{
AddTestCase (new Ipv4DeduplicationPerformanceTest, TestCase::EXTENSIVE);
}
static Ipv4DeduplicationPerformanceTestSuite g_ipv4DeduplicationPerformanceTestSuite; //!< Static variable for test initialization