internet: (Merge !102) Add RFC6621 IPv4 layer de-duplication

This commit is contained in:
Jared Dulmage
2019-10-26 13:16:55 +02:00
committed by Tommaso Pecorella
parent ad3324e2dd
commit 60dc6f91b9
4 changed files with 635 additions and 2 deletions

View File

@@ -27,6 +27,8 @@
#include "ns3/socket.h"
#include "ns3/net-device.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"
#include "ns3/boolean.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/object-vector.h"
#include "ns3/ipv4-header.h"
@@ -69,6 +71,15 @@ Ipv4L3Protocol::GetTypeId (void)
TimeValue (Seconds (30)),
MakeTimeAccessor (&Ipv4L3Protocol::m_fragmentExpirationTimeout),
MakeTimeChecker ())
.AddAttribute ("EnableRFC6621",
"Enable RFC 6621 packet de-duplication",
BooleanValue (false),
MakeBooleanAccessor (&Ipv4L3Protocol::m_enableRfc6621),
MakeBooleanChecker ())
.AddAttribute ("DuplicateExpire", "Expiration delay for duplicate cache entries",
TimeValue (MilliSeconds (1)),
MakeTimeAccessor (&Ipv4L3Protocol::m_expire),
MakeTimeChecker ())
.AddTraceSource ("Tx",
"Send ipv4 packet to outgoing interface.",
MakeTraceSourceAccessor (&Ipv4L3Protocol::m_txTrace),
@@ -318,6 +329,15 @@ Ipv4L3Protocol::DoDispose (void)
m_fragments.clear ();
m_fragmentsTimers.clear ();
for (auto dup: m_dups)
{
if (dup.second.IsRunning ())
{
dup.second.Cancel ();
}
}
m_dups.clear ();
Object::DoDispose ();
}
@@ -506,7 +526,7 @@ Ipv4L3Protocol::IsDestinationAddress (Ipv4Address address, uint32_t iif) const
#endif
if (true)
{
NS_LOG_LOGIC ("For me (Ipv4Addr multicast address");
NS_LOG_LOGIC ("For me (Ipv4Addr multicast address)");
return true;
}
}
@@ -629,6 +649,13 @@ Ipv4L3Protocol::Receive ( Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t p
socket->ForwardUp (packet, ipHeader, ipv4Interface);
}
if (m_enableRfc6621 && ipHeader.GetDestination ().IsMulticast () && UpdateDuplicate (packet, ipHeader))
{
NS_LOG_LOGIC ("Dropping received packet -- duplicate.");
m_dropTrace (ipHeader, packet, DROP_DUPLICATE, m_node->GetObject<Ipv4> (), interface);
return;
}
NS_ASSERT_MSG (m_routingProtocol != 0, "Need a routing protocol object to process packets");
if (!m_routingProtocol->RouteInput (packet, ipHeader, device,
MakeCallback (&Ipv4L3Protocol::IpForward, this),
@@ -1697,4 +1724,85 @@ Ipv4L3Protocol::HandleFragmentsTimeout (std::pair<uint64_t, uint32_t> key, Ipv4H
m_fragments.erase (key);
m_fragmentsTimers.erase (key);
}
bool
Ipv4L3Protocol::UpdateDuplicate (Ptr<const Packet> p, const Ipv4Header &header)
{
NS_LOG_FUNCTION (this << p << header);
// \todo RFC 6621 mandates SHA-1 hash. For now ns3 hash should be fine.
uint8_t proto = header.GetProtocol ();
Ipv4Address src = header.GetSource ();
Ipv4Address dst = header.GetDestination ();
uint64_t id = header.GetIdentification ();
// concat hash value onto id
uint64_t hash = id << 32;
if (header.GetFragmentOffset () || !header.IsLastFragment ())
{
// use I-DPD (RFC 6621, Sec 6.2.1)
hash |= header.GetFragmentOffset ();
}
else
{
// use H-DPD (RFC 6621, Sec 6.2.2)
// serialize packet
Ptr<Packet> pkt = p->Copy ();
pkt->AddHeader (header);
std::ostringstream oss (std::ios_base::binary);
pkt->CopyData (&oss, pkt->GetSize ());
std::string bytes = oss.str ();
NS_ASSERT_MSG (bytes.size () >= 20, "Degenerate header serialization");
// zero out mutable fields
bytes[1] = 0; // DSCP / ECN
bytes[6] = bytes[7] = 0; // Flags / Fragment offset
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);
// concat hash onto ID
hash |= (uint64_t)Hash32 (bytes);
}
// 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) << ", " <<
std::dec << +std::get<1> (key) << ", " <<
std::get<2> (key) << ", " <<
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
}
// set the expiration event
iter->second = Simulator::Schedule (m_expire, &Ipv4L3Protocol::RemoveDuplicate, this, iter);
return isDup;
}
void
Ipv4L3Protocol::RemoveDuplicate (DupMap_t::const_iterator iter)
{
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);
}
} // namespace ns3

View File

@@ -101,7 +101,8 @@ public:
DROP_BAD_CHECKSUM, /**< Bad checksum */
DROP_INTERFACE_DOWN, /**< Interface is down so can not send packet */
DROP_ROUTE_ERROR, /**< Route error */
DROP_FRAGMENT_TIMEOUT /**< Fragment timeout exceeded */
DROP_FRAGMENT_TIMEOUT, /**< Fragment timeout exceeded */
DROP_DUPLICATE /**< Duplicate packet received */
};
/**
@@ -556,6 +557,29 @@ private:
Time m_fragmentExpirationTimeout; //!< Expiration timeout
MapFragmentsTimers_t m_fragmentsTimers; //!< Expiration events.
/// 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;
/**
* Registers duplicate entry, return false if new
* \param [in] p Possibly duplicate packet.
* \param [in] header Packet \p p header.
* \return True if this packet is a duplicate
*/
bool UpdateDuplicate (Ptr<const Packet> p, const Ipv4Header &header);
/**
* Remove duplicate packet entry
* \param [in] iter Iterator into duplicate map to remove
*/
void RemoveDuplicate (DupMap_t::const_iterator iter);
bool m_enableRfc6621; //!< Enable RFC 6621 de-duplication
DupMap_t m_dups; //!< map of packet duplicate tuples to expiry event
Time m_expire; //!< duplicate entry expiration delay
};
} // Namespace ns3

View File

@@ -0,0 +1,500 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2013 Universita' di Firenze
* Copyright (c) 2019 WPL, Inc. : RFC 6621 mutlicast packet de-duplication
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
* Modified (2019): Jared Dulmage <jared.dulmage@wpli.net>
* Tests dissemination of multicast packets across a mesh
* network to all nodes over multiple hops. Tests check
* the number of received packets and dropped packets
* with RFC 6621 de-duplication enabled or disabled.
*/
#include "ns3/test.h"
#include "ns3/simulator.h"
#include "ns3/simple-channel.h"
#include "ns3/simple-net-device.h"
#include "ns3/socket.h"
#include "ns3/boolean.h"
#include "ns3/double.h"
#include "ns3/string.h"
#include "ns3/config.h"
#include "ns3/names.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/inet-socket-address.h"
#include "ns3/random-variable-stream.h"
#include "ns3/ipv4-l3-protocol.h"
#include "ns3/ipv4-static-routing.h"
#include "ns3/udp-socket-factory.h"
#include "ns3/udp-socket.h"
#include "ns3/internet-stack-helper.h"
#include "ns3/ipv4-list-routing-helper.h"
#include "ns3/ipv4-static-routing-helper.h"
#include "ns3/ipv4-address-helper.h"
#include "ns3/simple-net-device-helper.h"
#include "ns3/packet-sink-helper.h"
#include "ns3/traffic-control-layer.h"
#include <string>
#include <limits>
#include <functional>
using namespace ns3;
/**
* \ingroup internet-test
* \ingroup tests
*
* \brief IPv4 Deduplication Test
*
* Tests topology:
*
* /---- B ----\
* A ---- | ---- D ---- E
* \---- C ----/
*
* This test case counts the number of packets received
* and dropped at each node across the topology. Every
* node is configured to forward the multicast packet
* which originates at node A.
*
* With RFC 6621 de-duplication enabled, one 1 packet
* is received while some number of duplicate relayed
* packets are dropped by RFC 6621 at each node.
*
* When RFC6621 is disabled, the original packet has TTL = 4.
* Multiple packets are received at each node and several packets
* are dropped due to TTL expiry at each node.
*/
class Ipv4DeduplicationTest : public TestCase
{
/**
* \brief Send data.
* \param socket The sending socket.
* \param to Destination address.
*/
void DoSendData (Ptr<Socket> socket, std::string to);
/**
* \brief Send data.
* \param socket The sending socket.
* \param packet The packet to send.
* \param to Destination address.
*/
void DoSendPacket (Ptr<Socket> socket, Ptr<Packet> packet, std::string to);
/**
* \brief Send data.
* \param socket The sending socket.
* \param to Destination address.
*/
void SendData (Ptr<Socket> socket, std::string to);
/**
* \brief Send data.
* \param socket The sending socket.
* \param packet The packet to send.
* \param to Destination address.
*/
void SendPacket (Ptr<Socket> socket, Ptr<Packet> packet, std::string to);
/**
* \brief Check packet receptions
* \param name Node name
*/
void CheckPackets (const std::string &name);
/**
* \brief Check packet drops
* \param name Node name
*/
void CheckDrops (const std::string &name);
static const Time DELAY;
static std::string MakeName (bool enable, Time expire);
enum MODE {ENABLED = 0,
DISABLED,
DEGENERATE}; // enabled, but expiration time too low
MODE m_mode;
Time m_expire;
std::map<std::string, uint32_t> m_packetCountMap;
std::map<std::string, uint32_t> m_dropCountMap;
public:
virtual void DoRun (void);
Ipv4DeduplicationTest (bool enable, Time expire = Seconds (1));
/**
* \brief Receive data.
* \param [in] socket The receive socket.
*/
void ReceivePkt (Ptr<Socket> socket);
/**
* \brief Register dropped packet.
* \param [in] ipHeader IP header
* \param [in] packet Packet that was dropped
* \param [in] reason Reason for dropping packet
* \param [in] ipv4 Ipv4 instance
* \param [in] interface Interface number
*/
void DropPkt (const Ipv4Header &ipHeader,
Ptr<const Packet> packet, Ipv4L3Protocol::DropReason reason,
Ptr<Ipv4> ipv4, uint32_t interface);
};
const Time
Ipv4DeduplicationTest::DELAY = MilliSeconds (1);
Ipv4DeduplicationTest::Ipv4DeduplicationTest (bool enable, Time expire)
: TestCase (MakeName (enable, expire))
, m_mode (ENABLED)
, m_expire (expire)
{
if (!enable)
{
m_mode = DISABLED;
}
else if (m_expire < DELAY)
{
m_mode = DEGENERATE;
}
}
void Ipv4DeduplicationTest::ReceivePkt (Ptr<Socket> socket)
{
uint32_t availableData;
availableData = socket->GetRxAvailable ();
Ptr<Packet> packet = socket->Recv (std::numeric_limits<uint32_t>::max (), 0);
NS_ASSERT (availableData == packet->GetSize ());
auto node = socket->GetNode ();
std::string name = Names::FindName (node);
m_packetCountMap.insert ({name, 0}); // only inserts when not there
++m_packetCountMap[name];
}
void
Ipv4DeduplicationTest::DropPkt (const Ipv4Header &ipHeader,
Ptr<const Packet> packet, Ipv4L3Protocol::DropReason reason,
Ptr<Ipv4> ipv4, uint32_t interface)
{
switch (m_mode)
{
case ENABLED:
NS_TEST_EXPECT_MSG_EQ (reason, Ipv4L3Protocol::DROP_DUPLICATE, "Wrong reason for drop");
break;
case DISABLED:
NS_TEST_EXPECT_MSG_EQ (reason, Ipv4L3Protocol::DROP_TTL_EXPIRED, "Wrong reason for drop");
break;
case DEGENERATE:
// reason can be either
break;
};
auto node = ipv4->GetNetDevice (interface)->GetNode ();
std::string name = Names::FindName (node);
m_dropCountMap.insert ({name, 0});
++m_dropCountMap[name];
}
void
Ipv4DeduplicationTest::DoSendData (Ptr<Socket> socket, std::string to)
{
SendPacket (socket, Create<Packet> (123), to);
}
void
Ipv4DeduplicationTest::DoSendPacket (Ptr<Socket> socket, Ptr<Packet> packet, std::string to)
{
Address realTo = InetSocketAddress (Ipv4Address (to.c_str ()), 1234);
NS_TEST_EXPECT_MSG_EQ (socket->SendTo (packet, 0, realTo), 123, "100");
}
void
Ipv4DeduplicationTest::SendData (Ptr<Socket> socket, std::string to)
{
DoSendData(socket, to);
}
void
Ipv4DeduplicationTest::SendPacket (Ptr<Socket> socket, Ptr<Packet> packet, std::string to)
{
Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), MilliSeconds (50),
&Ipv4DeduplicationTest::DoSendPacket, this, socket, packet, to);
}
std::string
Ipv4DeduplicationTest::MakeName (bool enabled, Time expire)
{
std::ostringstream oss;
oss << "IP v4 RFC 6621 De-duplication: ";
if (!enabled)
{
oss << "disabled";
}
else if (expire > DELAY)
{
oss << "enabled";
}
else
{
oss << "degenerate";
}
oss << ", expire = " << expire.ToDouble (Time::MS) << "ms";
return oss.str ();
}
void
Ipv4DeduplicationTest::DoRun (void)
{
// multicast target
const std::string targetAddr = "239.192.100.1";
Config::SetDefault ("ns3::Ipv4L3Protocol::EnableRFC6621", BooleanValue (m_mode != DISABLED));
Config::SetDefault ("ns3::Ipv4L3Protocol::DuplicateExpire", TimeValue (m_expire));
// Create topology
// Create nodes
auto nodes = NodeContainer ();
nodes.Create (5);
// Name nodes
Names::Add ("A", nodes.Get (0));
Names::Add ("B", nodes.Get (1));
Names::Add ("C", nodes.Get (2));
Names::Add ("D", nodes.Get (3));
Names::Add ("E", nodes.Get (4));
SimpleNetDeviceHelper simplenet;
auto devices = simplenet.Install (nodes);
// name devices
Names::Add ("A/dev", devices.Get (0));
Names::Add ("B/dev", devices.Get (1));
Names::Add ("C/dev", devices.Get (2));
Names::Add ("D/dev", devices.Get (3));
Names::Add ("E/dev", devices.Get (4));
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 " << Names::FindName (*iter) << " does not have Ipv4 aggregate");
auto routing = staticRouting.GetStaticRouting (ipv4);
routing->AddHostRouteTo (targetAddr.c_str (), ipv4->GetInterfaceForDevice (*diter), 0);
++diter;
}
// set the topology, by default fully-connected
auto channel = devices.Get (0)->GetChannel ();
auto simplechannel = channel->GetObject <SimpleChannel> ();
// ensure some time progress between re-transmissions
simplechannel->SetAttribute ("Delay", TimeValue (DELAY));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("A/dev"), Names::Find <SimpleNetDevice> ("D/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("D/dev"), Names::Find <SimpleNetDevice> ("A/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("A/dev"), Names::Find <SimpleNetDevice> ("E/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("E/dev"), Names::Find <SimpleNetDevice> ("A/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("B/dev"), Names::Find <SimpleNetDevice> ("E/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("E/dev"), Names::Find <SimpleNetDevice> ("B/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("C/dev"), Names::Find <SimpleNetDevice> ("E/dev"));
simplechannel->BlackList (Names::Find <SimpleNetDevice> ("E/dev"), Names::Find <SimpleNetDevice> ("C/dev"));
// Create the UDP sockets
std::list<Ptr<Socket> > sockets;
for (auto end = nodes.End (),
iter = nodes.Begin (); iter != end; ++iter)
{
auto SocketFactory = (*iter)->GetObject<UdpSocketFactory> ();
auto socket = SocketFactory->CreateSocket ();
socket->SetAllowBroadcast (true);
NS_TEST_EXPECT_MSG_EQ (socket->Bind (InetSocketAddress (Ipv4Address::GetAny (), 1234)), 0,
"Could not bind socket for node " << Names::FindName (*iter));
socket->SetRecvCallback (MakeCallback (&Ipv4DeduplicationTest::ReceivePkt, this));
sockets.push_back (socket);
}
// connect up drop traces
Config::ConnectWithoutContext ("/NodeList/*/$ns3::Ipv4L3Protocol/Drop",
MakeCallback (&Ipv4DeduplicationTest::DropPkt, this));
// 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 ------------
// Broadcast 1 packet
SendData (txSocket, targetAddr);
Simulator::Run ();
Simulator::Destroy ();
for (auto end = nodes.End (),
iter = nodes.Begin (); iter != end; ++iter)
{
std::string name = Names::FindName (*iter);
CheckPackets (name);
CheckDrops (name);
}
m_packetCountMap.clear ();
sockets.clear ();
Names::Clear ();
}
// NOTE:
// The de-duplicate disabled received packets and drops can be
// computed by forming the connectivity matrix C with 1's in
// coordinates (row, column) where row and column nodes are connected.
// Reception of packets with TTL n are v_(n-1) = v_n * C where
// v_TTL = [1 0 0 0 0] (corresponding to nodes [A B C D E]).
// The number of drops for each node is v_0 and the number of received
// packets at each node is sum (v_TTL-1, ..., v_0).
void
Ipv4DeduplicationTest::CheckPackets (const std::string &name)
{
// a priori determined packet receptions based on initial TTL of 4, disabled de-dup
std::map <std::string, uint32_t> packets = {
{"A", 14}, {"B", 16}, {"C", 16}, {"D", 16}, {"E", 4}
};
// a priori determined packet receptions based on initial TTL of 4, degenerate de-dup
// There are TTL (4) rounds of packets. Each round a node will register a
// received packet if another connected node transmits. A misses the 1st round
// since it is the only one transmitting. D is not connected to A in 1st round
// either. E only hears a packet in the 3rd and 4th rounds.
std::map <std::string, uint32_t> degenerates = {
{"A", 3}, {"B", 4}, {"C", 4}, {"D", 3}, {"E", 2}
};
NS_TEST_ASSERT_MSG_NE ((m_packetCountMap.find (name) == m_packetCountMap.end ()), true,
"No packets received for node " << name);
switch (m_mode)
{
case ENABLED:
NS_TEST_EXPECT_MSG_EQ (m_packetCountMap[name], 1, "Wrong number of packets received for node " << name);
break;
case DISABLED:
NS_TEST_EXPECT_MSG_EQ (m_packetCountMap[name], packets[name], "Wrong number of packets received for node " << name);
break;
case DEGENERATE:
NS_TEST_EXPECT_MSG_EQ (m_packetCountMap[name], degenerates[name], "Wrong number of packets received for node " << name);
break;
};
}
void
Ipv4DeduplicationTest::CheckDrops (const std::string &name)
{
std::map <std::string, uint32_t> drops;
switch (m_mode)
{
case ENABLED:
// a priori determined packet drops based on initial TTL of 4, enabled de-dup;
// A hears from B & C
// D hears from B, C, AND E
// B (C) hears from A, C (B), D, and A again
drops = {{"A", 1}, {"B", 3}, {"C", 3}, {"D", 2}, {"E", 0}};
break;
case DISABLED:
// a priori determined packet drops based on initial TTL of 4, disabled de-dup
drops = {{"A", 10}, {"B", 9}, {"C", 9}, {"D", 12}, {"E", 2}};
break;
case DEGENERATE:
// a priori determined packet drops based on initial TTL of 4, degenerate de-dup
// There are TTL (4) rounds of transmissions. Since all transmitters are
// synchronized, multiple packets are received each round when there are
// multiple transmitters. Only 1 packet per round is delivered, others are
// dropped. So this can be computed via "disabled" procedure described
// in check packets, but with only a 1 for each node in each round when packets
// are received. Drops are the sum of receptions using these indicator receive vectors
// subtracting 1 for each node (for the delivered packet) and adding 1
// at all nodes for TTL expiry.
drops = {{"A", 4}, {"B", 5}, {"C", 5}, {"D", 5}, {"E", 1}};
break;
}
if (drops[name])
{
NS_TEST_ASSERT_MSG_NE ((m_dropCountMap.find (name) == m_dropCountMap.end ()), true, "No drops for node " << name);
NS_TEST_EXPECT_MSG_EQ (m_dropCountMap[name], drops[name], "Wrong number of drops for node " << name);
}
else
{
NS_TEST_EXPECT_MSG_EQ ((m_dropCountMap.find (name) == m_dropCountMap.end ()), true, "Non-0 drops for node " << name);
}
}
/**
* \ingroup internet-test
* \ingroup tests
*
* \brief IPv4 Deduplication TestSuite
*/
class Ipv4DeduplicationTestSuite : public TestSuite
{
public:
Ipv4DeduplicationTestSuite ();
private:
};
Ipv4DeduplicationTestSuite::Ipv4DeduplicationTestSuite ()
: TestSuite ("ipv4-deduplication", UNIT)
{
AddTestCase (new Ipv4DeduplicationTest (true), TestCase::QUICK);
AddTestCase (new Ipv4DeduplicationTest (false), TestCase::QUICK);
// degenerate case is enabled RFC but with too short an expiry
AddTestCase (new Ipv4DeduplicationTest (true, MicroSeconds (50)), TestCase::QUICK);
}
static Ipv4DeduplicationTestSuite g_ipv4DeduplicationTestSuite; //!< Static variable for test initialization

View File

@@ -297,6 +297,7 @@ def build(bld):
'test/ipv4-rip-test.cc',
'test/tcp-close-test.cc',
'test/icmp-test.cc',
'test/ipv4-deduplication-test.cc',
]
privateheaders = bld(features='ns3privateheader')
privateheaders.module = 'internet'