internet: (fixes #809) Solves IPv4,6 Raw Socket Fragmentation Issue
This commit is contained in:
@@ -26,6 +26,8 @@ This file is a best-effort approach to solving this issue; we will do our best b
|
||||
|
||||
### Changed behavior
|
||||
|
||||
* (internet) The Ipv[4,6]RawSocket now reflects the Linux implementation, meaning that fragmented packets are reassembled (fragments are not anymore received by the socket), and packets that are simply forwarded are not received by the socket either (fixes #809).
|
||||
|
||||
## Changes from ns-3.44 to ns-3.45
|
||||
|
||||
### New API
|
||||
|
||||
@@ -77,6 +77,7 @@ to work with the release.
|
||||
|
||||
- (bindings) #1187 - Fix library filtering to skip non-ns-3 libraries with "ns3" in their names.
|
||||
- (flow-monitor) #1202 - Create XML file in text mode
|
||||
- (internet) !2486 - Fix #809 - Ping for v4,v6 works now if fragmentation occurs.
|
||||
- (mobility) !2397 - Fix Rectangle::GetClosestSideOrCorner. It could assign the incorrect side when the checked position was outside the rectangle.
|
||||
- (wifi) #2368 - Fix various issues related to Content Channels and RU allocation. Fixes mostly covers cases where OFDMA is used with central 26 tones, where a single user is being assigned the whole PPDU bandwidth or where a RU is larger than 20 MHz.
|
||||
- (wifi) Various fixes to the EMLSR model have been made
|
||||
|
||||
@@ -605,7 +605,7 @@ PingTestSuite::PingTestSuite()
|
||||
testcase2v4->SetSimulatorStopTime(Seconds(5));
|
||||
testcase2v4->CheckReportTransmitted(1);
|
||||
testcase2v4->CheckReportReceived(0);
|
||||
testcase1v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
|
||||
testcase2v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
|
||||
AddTestCase(testcase2v4, TestCase::Duration::QUICK);
|
||||
|
||||
auto testcase2v6 = new PingTestCase(
|
||||
@@ -697,8 +697,8 @@ PingTestSuite::PingTestSuite()
|
||||
// 5. Test for behavior of pinging an unreachable host when the
|
||||
// network does not send an ICMP unreachable message.
|
||||
// Unlimited pings, StopApplication () with no packet in flight
|
||||
// Configuration: Ping::Count = 0, Ping start time = 1s
|
||||
// Ping stop time = 5.5s. Ping to unknown destination.
|
||||
// Configuration: Ping::Count = 5, Ping start time = 1s
|
||||
// Ping stop time = 6.5s. Ping to unknown destination.
|
||||
// Expected behavior: By default, the timeout value is 1 second. Ping
|
||||
// sends first packet at time 1 second, and does not
|
||||
// receive a response. At the timeout (simulation time
|
||||
@@ -900,30 +900,39 @@ PingTestSuite::PingTestSuite()
|
||||
testcase9v6->CheckReportTime(MicroSeconds(3040000));
|
||||
AddTestCase(testcase9v6, TestCase::Duration::QUICK);
|
||||
|
||||
#ifdef NOTYET
|
||||
//
|
||||
// 10. Test for behavior of pinging on a link that causes IPv4 fragmentation
|
||||
// Configuration: Ping::Count = 1, Ping start time = 1s
|
||||
// Ping stop time = 2.5s. Ping to Node 1
|
||||
// Ping size set to 2000 bytes.
|
||||
// Expected behavior: At shortly after time 1 seconds, Ping should
|
||||
// successfully exit by recording the successful
|
||||
// exchange of one echo request and reply.
|
||||
// How validated: PingReport trace is checked for number of packets
|
||||
// transmitted (5) and received (0).
|
||||
// PingReport time is checked for an explicit time
|
||||
// (1.020028s) corresponding to 2000 bytes
|
||||
// The packet loss rate should be checked to be 100 percent
|
||||
PingTestCase* testcase10v4 = new PingTestCase("10. Test for IPv4 fragmentation", USEIPV6_FALSE);
|
||||
// 10. Test for behavior of pinging with a big size that causes fragmentation
|
||||
// Configuration: Ping::Count = 5, Ping::Interval = 1s, Ping start
|
||||
// time = 1s, Ping stop time = 6.5s,
|
||||
// Payload size = 60000B
|
||||
// Expected behavior: Pings are sent at times 1, 2, 3, 4, 5 sec. The
|
||||
// number sent equals number received, which equals 5.
|
||||
// How validated: PingReport trace is checked for number of packets
|
||||
// transmitted and received (5), and number of drops (0).
|
||||
auto testcase10v4 = new PingTestCase("10. 5 pings, heavy payload, no losses, "
|
||||
"StopApplication () with no packets in flight IPv4",
|
||||
USEIPV6_FALSE);
|
||||
testcase10v4->SetStartTime(Seconds(1));
|
||||
testcase10v4->SetStopTime(Seconds(2.5));
|
||||
testcase10v4->SetCount(1);
|
||||
testcase10v4->SetSize(2000);
|
||||
testcase10v4->CheckReportTransmitted(1);
|
||||
testcase10v4->CheckReportReceived(1);
|
||||
testcase10v4->CheckReportTime(MicroSeconds(1020028));
|
||||
testcase10v4->SetStopTime(Seconds(6.5));
|
||||
testcase10v4->SetCount(5);
|
||||
testcase10v4->SetSize(60000);
|
||||
testcase10v4->CheckReportTransmitted(5);
|
||||
testcase10v4->CheckReportReceived(5);
|
||||
testcase10v4->CheckTraceTx(5);
|
||||
testcase10v4->SetDestinationAddress(Ipv4Address("10.0.0.2"));
|
||||
AddTestCase(testcase10v4, TestCase::Duration::QUICK);
|
||||
#endif
|
||||
|
||||
auto testcase10v6 = new PingTestCase("10. 5 pings, heavy payload, no losses, "
|
||||
"StopApplication () with no packets in flight IPv6",
|
||||
USEIPV6_TRUE);
|
||||
testcase10v6->SetStartTime(Seconds(1));
|
||||
testcase10v6->SetStopTime(Seconds(6.5));
|
||||
testcase10v6->SetCount(5);
|
||||
testcase10v6->SetSize(60000);
|
||||
testcase10v6->CheckReportTransmitted(5);
|
||||
testcase10v6->CheckReportReceived(5);
|
||||
testcase10v6->CheckTraceTx(5);
|
||||
testcase10v6->SetDestinationAddress(Ipv6Address("2001:1::200:ff:fe00:2"));
|
||||
AddTestCase(testcase10v6, TestCase::Duration::QUICK);
|
||||
}
|
||||
|
||||
static PingTestSuite pingTestSuite; //!< Static variable for test initialization
|
||||
|
||||
@@ -631,13 +631,6 @@ Ipv4L3Protocol::Receive(Ptr<NetDevice> device,
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = m_sockets.begin(); i != m_sockets.end(); ++i)
|
||||
{
|
||||
NS_LOG_LOGIC("Forwarding to raw socket");
|
||||
Ptr<Ipv4RawSocketImpl> socket = *i;
|
||||
socket->ForwardUp(packet, ipHeader, ipv4Interface);
|
||||
}
|
||||
|
||||
if (m_enableDpd && ipHeader.GetDestination().IsMulticast() && UpdateDuplicate(packet, ipHeader))
|
||||
{
|
||||
NS_LOG_LOGIC("Dropping received packet -- duplicate.");
|
||||
@@ -1095,6 +1088,14 @@ Ipv4L3Protocol::LocalDeliver(Ptr<const Packet> packet, const Ipv4Header& ip, uin
|
||||
|
||||
m_localDeliverTrace(ipHeader, p, iif);
|
||||
|
||||
Ptr<Ipv4Interface> ipv4Interface = GetInterface(iif);
|
||||
|
||||
for (auto& socket : m_sockets)
|
||||
{
|
||||
NS_LOG_INFO("Delivering to raw socket " << socket);
|
||||
socket->ForwardUp(p, ipHeader, ipv4Interface);
|
||||
}
|
||||
|
||||
Ptr<IpL4Protocol> protocol = GetProtocol(ipHeader.GetProtocol(), iif);
|
||||
if (protocol)
|
||||
{
|
||||
|
||||
@@ -1048,13 +1048,6 @@ Ipv6L3Protocol::Receive(Ptr<NetDevice> device,
|
||||
}
|
||||
}
|
||||
|
||||
/* forward up to IPv6 raw sockets */
|
||||
for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it)
|
||||
{
|
||||
Ptr<Ipv6RawSocketImpl> socket = *it;
|
||||
socket->ForwardUp(packet, hdr, device);
|
||||
}
|
||||
|
||||
Ptr<Ipv6ExtensionDemux> ipv6ExtensionDemux = m_node->GetObject<Ipv6ExtensionDemux>();
|
||||
Ptr<Ipv6Extension> ipv6Extension = nullptr;
|
||||
uint8_t nextHeader = hdr.GetNextHeader();
|
||||
@@ -1442,6 +1435,7 @@ Ipv6L3Protocol::LocalDeliver(Ptr<const Packet> packet, const Ipv6Header& ip, uin
|
||||
bool isDropped = false;
|
||||
bool stopProcessing = false;
|
||||
DropReason dropReason;
|
||||
Ptr<NetDevice> device = GetNetDevice(iif);
|
||||
|
||||
// check for a malformed hop-by-hop extension
|
||||
// this is a common case when forging IPv6 raw packets
|
||||
@@ -1534,6 +1528,12 @@ Ipv6L3Protocol::LocalDeliver(Ptr<const Packet> packet, const Ipv6Header& ip, uin
|
||||
|
||||
m_localDeliverTrace(newIpHeader, p, iif);
|
||||
|
||||
for (auto& socket : m_sockets)
|
||||
{
|
||||
NS_LOG_INFO("Delivering to raw socket " << socket);
|
||||
socket->ForwardUp(p, newIpHeader, device);
|
||||
}
|
||||
|
||||
IpL4Protocol::RxStatus status =
|
||||
protocol->Receive(p, newIpHeader, GetInterface(iif));
|
||||
|
||||
|
||||
@@ -5,21 +5,26 @@
|
||||
*
|
||||
* Author: Hajime Tazaki <tazaki@sfc.wide.ad.jp>
|
||||
*/
|
||||
/**
|
||||
/*
|
||||
* This is the test code for ipv4-raw-socket-impl.cc.
|
||||
*/
|
||||
|
||||
#include "ns3/arp-l3-protocol.h"
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/icmpv4-l4-protocol.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
#include "ns3/ipv4-address-helper.h"
|
||||
#include "ns3/ipv4-global-routing-helper.h"
|
||||
#include "ns3/ipv4-l3-protocol.h"
|
||||
#include "ns3/ipv4-list-routing.h"
|
||||
#include "ns3/ipv4-raw-socket-factory.h"
|
||||
#include "ns3/ipv4-static-routing.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/point-to-point-helper.h"
|
||||
#include "ns3/simple-channel.h"
|
||||
#include "ns3/simple-net-device-helper.h"
|
||||
#include "ns3/simple-net-device.h"
|
||||
@@ -27,7 +32,6 @@
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/test.h"
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include "ns3/win32-internet.h"
|
||||
#else
|
||||
@@ -41,6 +45,185 @@
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ipv4-raw-fragmentation-test");
|
||||
|
||||
/**
|
||||
* @ingroup internet-test
|
||||
*
|
||||
* @brief IPv4 Raw Socket Fragmentation Test
|
||||
* Configuration : Two sockets. 1 sender, 1 receiver
|
||||
* Sender socket sends packets in two epochs.
|
||||
* In the first epoch, it sends payload of sizes {500, 1000, 5000, 10000,
|
||||
* 20000, 40000, 60000}.
|
||||
* In the second epoch, it sends payload of sizes {5000, 10000, 20000,
|
||||
* 40000, 60000}. These are payloads of size greater than the MTU of
|
||||
* the link.
|
||||
* In the first epoch, there is no loss model.
|
||||
* In the second epoch, the second fragment of the packet sent is dropped.
|
||||
*
|
||||
* Expected behaviour: In the first epoch: Receiver should receive only 1 packet and the size of
|
||||
* the payload received should be equal to the size of the payload sent.
|
||||
* No packets should have been dropped.
|
||||
* In the second epoch: Receiver should not receive any packet. Only 1 packet
|
||||
* should have been dropped at the physical layer.
|
||||
*/
|
||||
class Ipv4RawFragmentationTest : public TestCase
|
||||
{
|
||||
public:
|
||||
Ipv4RawFragmentationTest();
|
||||
void DoRun() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Send data to the receiver
|
||||
* @param s The sending socket.
|
||||
* @param sz Size of the packet.
|
||||
*/
|
||||
void SendPacket(Ptr<Socket> s, uint32_t sz);
|
||||
|
||||
/**
|
||||
* @brief Receive callback
|
||||
* @param s The receiving socket.
|
||||
*/
|
||||
void RxCallback(Ptr<Socket> s);
|
||||
|
||||
/**
|
||||
* @brief Packet dropped callback at Phy Rx.
|
||||
* @param p Dropped packet.
|
||||
*/
|
||||
void PhyRxDropCallback(Ptr<const Packet> p);
|
||||
|
||||
uint32_t m_rxCount{0}; //!< Received packet count
|
||||
uint32_t m_rxPayloadSize{0}; //!< Received packet size
|
||||
uint32_t m_droppedFragments{0}; //!< Number of dropped fragments
|
||||
};
|
||||
|
||||
Ipv4RawFragmentationTest::Ipv4RawFragmentationTest()
|
||||
: TestCase("IPv4 raw fragmentation, fragment‑loss test")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4RawFragmentationTest::RxCallback(Ptr<Socket> s)
|
||||
{
|
||||
Ptr<Packet> p = s->Recv();
|
||||
Ipv4Header h;
|
||||
if (p->PeekHeader(h))
|
||||
{
|
||||
p->RemoveHeader(h);
|
||||
}
|
||||
m_rxCount++;
|
||||
m_rxPayloadSize = p->GetSize();
|
||||
NS_LOG_DEBUG("Receiver got " << m_rxPayloadSize << " bytes");
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4RawFragmentationTest::PhyRxDropCallback(Ptr<const Packet> p)
|
||||
{
|
||||
++m_droppedFragments;
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4RawFragmentationTest::SendPacket(Ptr<Socket> socket, uint32_t size)
|
||||
{
|
||||
Address realTo = InetSocketAddress(Ipv4Address("10.0.1.1"), 0);
|
||||
Ptr<Packet> p = Create<Packet>(size);
|
||||
socket->SendTo(p, 0, realTo);
|
||||
NS_LOG_DEBUG("Sender sent " << p->GetSize() << " bytes to 10.0.1.1");
|
||||
}
|
||||
|
||||
void
|
||||
Ipv4RawFragmentationTest::DoRun()
|
||||
{
|
||||
Ptr<Node> rxNode = CreateObject<Node>();
|
||||
Ptr<Node> txNode = CreateObject<Node>();
|
||||
|
||||
NodeContainer nodes(rxNode, txNode);
|
||||
|
||||
SimpleNetDeviceHelper helperChannel;
|
||||
helperChannel.SetNetDevicePointToPointMode(true);
|
||||
NetDeviceContainer net = helperChannel.Install(nodes);
|
||||
|
||||
net.Get(1)->SetMtu(1000);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install(nodes);
|
||||
|
||||
Ptr<Ipv4> ipv4;
|
||||
uint32_t netdev_idx;
|
||||
Ipv4InterfaceAddress ipv4Addr;
|
||||
|
||||
ipv4 = rxNode->GetObject<Ipv4>();
|
||||
netdev_idx = ipv4->AddInterface(net.Get(0));
|
||||
ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.1.1"), Ipv4Mask(0xffff0000U));
|
||||
ipv4->AddAddress(netdev_idx, ipv4Addr);
|
||||
ipv4->SetUp(netdev_idx);
|
||||
|
||||
ipv4 = txNode->GetObject<Ipv4>();
|
||||
netdev_idx = ipv4->AddInterface(net.Get(1));
|
||||
ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.1.2"), Ipv4Mask(0xffff0000U));
|
||||
ipv4->AddAddress(netdev_idx, ipv4Addr);
|
||||
ipv4->SetUp(netdev_idx);
|
||||
|
||||
net.Get(0)->TraceConnectWithoutContext(
|
||||
"PhyRxDrop",
|
||||
MakeCallback(&Ipv4RawFragmentationTest::PhyRxDropCallback, this));
|
||||
|
||||
Ptr<SocketFactory> rxSocketFactory = rxNode->GetObject<Ipv4RawSocketFactory>();
|
||||
Ptr<Socket> rxSocket = rxSocketFactory->CreateSocket();
|
||||
rxSocket->Bind(InetSocketAddress(Ipv4Address::GetAny(), 0));
|
||||
rxSocket->SetRecvCallback(MakeCallback(&Ipv4RawFragmentationTest::RxCallback, this));
|
||||
|
||||
Ptr<SocketFactory> txSocketFactory = txNode->GetObject<Ipv4RawSocketFactory>();
|
||||
Ptr<Socket> txSocket = txSocketFactory->CreateSocket();
|
||||
|
||||
// Contains both Fragmentable and Non-fragmentable payload sizes
|
||||
std::vector<uint32_t> payloadSizes = {500, 1000, 5000, 10000, 20000, 40000, 60000};
|
||||
|
||||
for (auto sentPayloadSize : payloadSizes)
|
||||
{
|
||||
m_rxCount = 0;
|
||||
m_droppedFragments = 0;
|
||||
m_rxPayloadSize = 0;
|
||||
Simulator::Schedule(Seconds(1.0),
|
||||
&Ipv4RawFragmentationTest::SendPacket,
|
||||
this,
|
||||
txSocket,
|
||||
sentPayloadSize);
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_rxCount, 1, "Packet should be reassembled and be delivered");
|
||||
NS_TEST_EXPECT_MSG_EQ(m_rxPayloadSize,
|
||||
sentPayloadSize,
|
||||
"Reassembled payload size must match the payload size sent");
|
||||
NS_TEST_EXPECT_MSG_EQ(m_droppedFragments, 0, "No fragment must have been dropped");
|
||||
}
|
||||
|
||||
std::vector<uint32_t> fragmentablePayloadSizes = {5000, 10000, 20000, 40000, 60000};
|
||||
|
||||
for (auto sentPayloadSize : fragmentablePayloadSizes)
|
||||
{
|
||||
m_rxCount = 0;
|
||||
m_droppedFragments = 0;
|
||||
Ptr<ReceiveListErrorModel> errModel = CreateObject<ReceiveListErrorModel>();
|
||||
errModel->SetList({1});
|
||||
|
||||
net.Get(0)->SetAttribute("ReceiveErrorModel", PointerValue(errModel));
|
||||
|
||||
Simulator::Schedule(Seconds(1.0),
|
||||
&Ipv4RawFragmentationTest::SendPacket,
|
||||
this,
|
||||
txSocket,
|
||||
sentPayloadSize);
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_rxCount, 0, "Packet must not have been delivered");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_droppedFragments, 1, "One fragment must have been dropped");
|
||||
}
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup internet-test
|
||||
*
|
||||
@@ -370,6 +553,7 @@ class Ipv4RawTestSuite : public TestSuite
|
||||
: TestSuite("ipv4-raw", Type::UNIT)
|
||||
{
|
||||
AddTestCase(new Ipv4RawSocketImplTest, TestCase::Duration::QUICK);
|
||||
AddTestCase(new Ipv4RawFragmentationTest, TestCase::Duration::QUICK);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
*
|
||||
* Author: Hajime Tazaki <tazaki@sfc.wide.ad.jp>
|
||||
*/
|
||||
/**
|
||||
/*
|
||||
* This is the test code for ipv6-raw-socket-impl.cc.
|
||||
*/
|
||||
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/icmpv6-l4-protocol.h"
|
||||
#include "ns3/inet6-socket-address.h"
|
||||
#include "ns3/internet-stack-helper.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/node-container.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/simple-channel.h"
|
||||
#include "ns3/simple-net-device-helper.h"
|
||||
#include "ns3/simple-net-device.h"
|
||||
@@ -43,6 +45,198 @@
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ipv6-raw-fragmentation-test");
|
||||
|
||||
/**
|
||||
* @ingroup internet-test
|
||||
*
|
||||
* @brief IPv6 Raw Socket Fragmentation Test
|
||||
* Configuration : Two sockets. 1 sender, 1 receiver
|
||||
* Sender socket sends packets in two epochs.
|
||||
* In the first epoch, it sends payload of sizes {500, 1000, 5000, 10000,
|
||||
* 20000, 40000, 60000}.
|
||||
* In the second epoch, it sends payload of sizes {5000, 10000, 20000,
|
||||
* 40000, 60000}. These are payloads of size greater than the MTU of
|
||||
* the link.
|
||||
* In the first epoch, there is no loss model.
|
||||
* In the second epoch, the second fragment of the packet sent is dropped.
|
||||
*
|
||||
* Expected behaviour: In the first epoch: Receiver should receive only 1 packet and the size of
|
||||
* the payload received should be equal to the size of the payload sent.
|
||||
* No packets should have been dropped.
|
||||
* In the second epoch: Receiver should not receive any packet. Only 1 packet
|
||||
* should have been dropped at the physical layer.
|
||||
*/
|
||||
class Ipv6RawFragmentationTest : public TestCase
|
||||
{
|
||||
public:
|
||||
Ipv6RawFragmentationTest();
|
||||
void DoRun() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Send a packet
|
||||
* @param socket The sending socket
|
||||
* @param dst Destination IPv6 address.
|
||||
* @param size Size (bytes) of the payload to send.
|
||||
*/
|
||||
void SendPacket(Ptr<Socket> socket, Ipv6Address dst, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Receive a packet
|
||||
* @param socket Socket that received a packet
|
||||
*/
|
||||
void RxCallback(Ptr<Socket> socket);
|
||||
|
||||
/**
|
||||
* @brief Packet dropped callback at Phy Rx.
|
||||
* @param p Dropped packet.
|
||||
*/
|
||||
void PhyRxDropCallback(Ptr<const Packet> p);
|
||||
|
||||
uint32_t m_rxCount{0}; //!< Total count of packets received.
|
||||
uint32_t m_rxPayloadSize{0}; //!< Size of the last packet received.
|
||||
uint32_t m_droppedFragments{0}; //!< Number of dropped packets
|
||||
};
|
||||
|
||||
Ipv6RawFragmentationTest::Ipv6RawFragmentationTest()
|
||||
: TestCase("ipv6-raw-fragmentation-test")
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ipv6RawFragmentationTest::RxCallback(Ptr<Socket> socket)
|
||||
{
|
||||
Ptr<Packet> p = socket->Recv(std::numeric_limits<uint32_t>::max(), 0);
|
||||
|
||||
Ipv6Header hdr;
|
||||
if (p->PeekHeader(hdr))
|
||||
{
|
||||
p->RemoveHeader(hdr);
|
||||
}
|
||||
|
||||
m_rxPayloadSize = p->GetSize();
|
||||
m_rxCount++;
|
||||
NS_LOG_DEBUG("Receiver got " << m_rxPayloadSize << " bytes");
|
||||
}
|
||||
|
||||
void
|
||||
Ipv6RawFragmentationTest::SendPacket(Ptr<Socket> sock, Ipv6Address dst, uint32_t size)
|
||||
{
|
||||
Ptr<Packet> p = Create<Packet>(size);
|
||||
sock->SendTo(p, 0, Inet6SocketAddress(dst, 0));
|
||||
NS_LOG_DEBUG("Sender sent " << p->GetSize() << " bytes to " << dst);
|
||||
}
|
||||
|
||||
void
|
||||
Ipv6RawFragmentationTest::PhyRxDropCallback(Ptr<const Packet> /*p*/)
|
||||
{
|
||||
++m_droppedFragments;
|
||||
}
|
||||
|
||||
void
|
||||
Ipv6RawFragmentationTest::DoRun()
|
||||
{
|
||||
Ptr<Node> rxNode = CreateObject<Node>();
|
||||
Ptr<Node> txNode = CreateObject<Node>();
|
||||
|
||||
SimpleNetDeviceHelper helper;
|
||||
helper.SetNetDevicePointToPointMode(true);
|
||||
|
||||
Ptr<SimpleNetDevice> rxDev = DynamicCast<SimpleNetDevice>(helper.Install(rxNode).Get(0));
|
||||
Ptr<SimpleNetDevice> txDev = DynamicCast<SimpleNetDevice>(helper.Install(txNode).Get(0));
|
||||
|
||||
txDev->SetMtu(1280); // Minimum MTU allowed for IPv6
|
||||
|
||||
rxDev->TraceConnectWithoutContext(
|
||||
"PhyRxDrop",
|
||||
MakeCallback(&Ipv6RawFragmentationTest::PhyRxDropCallback, this));
|
||||
|
||||
Ptr<SimpleChannel> ch = CreateObject<SimpleChannel>();
|
||||
rxDev->SetChannel(ch);
|
||||
txDev->SetChannel(ch);
|
||||
|
||||
InternetStackHelper stack;
|
||||
stack.SetIpv4StackInstall(false);
|
||||
stack.Install(NodeContainer(rxNode, txNode));
|
||||
|
||||
rxNode->GetObject<Icmpv6L4Protocol>()->SetAttribute("DAD", BooleanValue(false));
|
||||
txNode->GetObject<Icmpv6L4Protocol>()->SetAttribute("DAD", BooleanValue(false));
|
||||
|
||||
Ptr<Ipv6> ipv6Rx = rxNode->GetObject<Ipv6>();
|
||||
Ptr<Ipv6> ipv6Tx = txNode->GetObject<Ipv6>();
|
||||
|
||||
uint32_t ifRx = ipv6Rx->AddInterface(rxDev);
|
||||
ipv6Rx->AddAddress(ifRx, Ipv6InterfaceAddress("2001:db8::1", Ipv6Prefix(64)));
|
||||
ipv6Rx->SetUp(ifRx);
|
||||
|
||||
uint32_t ifTx = ipv6Tx->AddInterface(txDev);
|
||||
ipv6Tx->AddAddress(ifTx, Ipv6InterfaceAddress("2001:db8::2", Ipv6Prefix(64)));
|
||||
ipv6Tx->SetUp(ifTx);
|
||||
|
||||
const uint8_t proto = Ipv6Header::IPV6_ICMPV6;
|
||||
|
||||
Ptr<Socket> rxSock = rxNode->GetObject<Ipv6RawSocketFactory>()->CreateSocket();
|
||||
rxSock->SetAttribute("Protocol", UintegerValue(proto));
|
||||
rxSock->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 0));
|
||||
rxSock->SetRecvCallback(MakeCallback(&Ipv6RawFragmentationTest::RxCallback, this));
|
||||
|
||||
Ptr<Socket> txSock = txNode->GetObject<Ipv6RawSocketFactory>()->CreateSocket();
|
||||
txSock->SetAttribute("Protocol", UintegerValue(proto));
|
||||
|
||||
std::vector<uint32_t> payloadSizes = {500, 1000, 5000, 10000, 20000, 40000, 60000};
|
||||
|
||||
for (auto sentPayloadSize : payloadSizes)
|
||||
{
|
||||
m_rxCount = 0;
|
||||
m_rxPayloadSize = 0;
|
||||
|
||||
Simulator::Schedule(Seconds(0.0),
|
||||
&Ipv6RawFragmentationTest::SendPacket,
|
||||
this,
|
||||
txSock,
|
||||
Ipv6Address("2001:db8::1"),
|
||||
sentPayloadSize);
|
||||
Simulator::Stop(Seconds(1.0));
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_rxPayloadSize,
|
||||
sentPayloadSize,
|
||||
"Reassembled packet size should be the same as the packet size sent");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_rxCount, 1, "Only 1 packet should have been received");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_droppedFragments, 0, "No packets should have been dropped");
|
||||
}
|
||||
|
||||
std::vector<uint32_t> fragmentablePayloadSizes = {5000, 10000, 20000, 40000, 60000};
|
||||
|
||||
for (auto sentPayloadSize : fragmentablePayloadSizes)
|
||||
{
|
||||
m_rxCount = 0;
|
||||
m_droppedFragments = 0;
|
||||
|
||||
Ptr<ReceiveListErrorModel> errModel = CreateObject<ReceiveListErrorModel>();
|
||||
errModel->SetList({1});
|
||||
|
||||
rxDev->SetAttribute("ReceiveErrorModel", PointerValue(errModel));
|
||||
|
||||
Simulator::Schedule(Seconds(0.0),
|
||||
&Ipv6RawFragmentationTest::SendPacket,
|
||||
this,
|
||||
txSock,
|
||||
Ipv6Address("2001:db8::1"),
|
||||
sentPayloadSize);
|
||||
Simulator::Stop(Seconds(1.0));
|
||||
Simulator::Run();
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_rxCount, 0, "No packet should have been received");
|
||||
|
||||
NS_TEST_EXPECT_MSG_EQ(m_droppedFragments, 1, "Exactly 1 packet should have been dropped.");
|
||||
}
|
||||
Simulator::Destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup internet-test
|
||||
*
|
||||
@@ -322,6 +516,7 @@ class Ipv6RawTestSuite : public TestSuite
|
||||
: TestSuite("ipv6-raw", Type::UNIT)
|
||||
{
|
||||
AddTestCase(new Ipv6RawSocketImplTest, TestCase::Duration::QUICK);
|
||||
AddTestCase(new Ipv6RawFragmentationTest, TestCase::Duration::QUICK);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user