From 6efce7a9345cf04d5a622193489faaa1ab5313e7 Mon Sep 17 00:00:00 2001 From: Aditya Date: Mon, 23 Jun 2025 23:20:40 +0530 Subject: [PATCH] internet: (fixes #809) Solves IPv4,6 Raw Socket Fragmentation Issue --- CHANGES.md | 2 + RELEASE_NOTES.md | 1 + src/internet-apps/test/ping-test.cc | 59 ++++---- src/internet/model/ipv4-l3-protocol.cc | 15 +- src/internet/model/ipv6-l3-protocol.cc | 14 +- src/internet/test/ipv4-raw-test.cc | 188 ++++++++++++++++++++++- src/internet/test/ipv6-raw-test.cc | 197 ++++++++++++++++++++++++- 7 files changed, 434 insertions(+), 42 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d16802c78..1a630af7c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 07142db63..1689224e8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -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 diff --git a/src/internet-apps/test/ping-test.cc b/src/internet-apps/test/ping-test.cc index 7935d7cee..124752904 100644 --- a/src/internet-apps/test/ping-test.cc +++ b/src/internet-apps/test/ping-test.cc @@ -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 diff --git a/src/internet/model/ipv4-l3-protocol.cc b/src/internet/model/ipv4-l3-protocol.cc index a645145a2..07e6cd6e2 100644 --- a/src/internet/model/ipv4-l3-protocol.cc +++ b/src/internet/model/ipv4-l3-protocol.cc @@ -631,13 +631,6 @@ Ipv4L3Protocol::Receive(Ptr device, } } - for (auto i = m_sockets.begin(); i != m_sockets.end(); ++i) - { - NS_LOG_LOGIC("Forwarding to raw socket"); - Ptr 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 packet, const Ipv4Header& ip, uin m_localDeliverTrace(ipHeader, p, iif); + Ptr ipv4Interface = GetInterface(iif); + + for (auto& socket : m_sockets) + { + NS_LOG_INFO("Delivering to raw socket " << socket); + socket->ForwardUp(p, ipHeader, ipv4Interface); + } + Ptr protocol = GetProtocol(ipHeader.GetProtocol(), iif); if (protocol) { diff --git a/src/internet/model/ipv6-l3-protocol.cc b/src/internet/model/ipv6-l3-protocol.cc index 466686840..1c0d89068 100644 --- a/src/internet/model/ipv6-l3-protocol.cc +++ b/src/internet/model/ipv6-l3-protocol.cc @@ -1048,13 +1048,6 @@ Ipv6L3Protocol::Receive(Ptr device, } } - /* forward up to IPv6 raw sockets */ - for (auto it = m_sockets.begin(); it != m_sockets.end(); ++it) - { - Ptr socket = *it; - socket->ForwardUp(packet, hdr, device); - } - Ptr ipv6ExtensionDemux = m_node->GetObject(); Ptr ipv6Extension = nullptr; uint8_t nextHeader = hdr.GetNextHeader(); @@ -1442,6 +1435,7 @@ Ipv6L3Protocol::LocalDeliver(Ptr packet, const Ipv6Header& ip, uin bool isDropped = false; bool stopProcessing = false; DropReason dropReason; + Ptr 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 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)); diff --git a/src/internet/test/ipv4-raw-test.cc b/src/internet/test/ipv4-raw-test.cc index 9f9fc8bb8..e578a70e7 100644 --- a/src/internet/test/ipv4-raw-test.cc +++ b/src/internet/test/ipv4-raw-test.cc @@ -5,21 +5,26 @@ * * Author: Hajime Tazaki */ -/** +/* * 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 s, uint32_t sz); + + /** + * @brief Receive callback + * @param s The receiving socket. + */ + void RxCallback(Ptr s); + + /** + * @brief Packet dropped callback at Phy Rx. + * @param p Dropped packet. + */ + void PhyRxDropCallback(Ptr 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 s) +{ + Ptr 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 p) +{ + ++m_droppedFragments; +} + +void +Ipv4RawFragmentationTest::SendPacket(Ptr socket, uint32_t size) +{ + Address realTo = InetSocketAddress(Ipv4Address("10.0.1.1"), 0); + Ptr p = Create(size); + socket->SendTo(p, 0, realTo); + NS_LOG_DEBUG("Sender sent " << p->GetSize() << " bytes to 10.0.1.1"); +} + +void +Ipv4RawFragmentationTest::DoRun() +{ + Ptr rxNode = CreateObject(); + Ptr txNode = CreateObject(); + + 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; + uint32_t netdev_idx; + Ipv4InterfaceAddress ipv4Addr; + + ipv4 = rxNode->GetObject(); + 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(); + 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 rxSocketFactory = rxNode->GetObject(); + Ptr rxSocket = rxSocketFactory->CreateSocket(); + rxSocket->Bind(InetSocketAddress(Ipv4Address::GetAny(), 0)); + rxSocket->SetRecvCallback(MakeCallback(&Ipv4RawFragmentationTest::RxCallback, this)); + + Ptr txSocketFactory = txNode->GetObject(); + Ptr txSocket = txSocketFactory->CreateSocket(); + + // Contains both Fragmentable and Non-fragmentable payload sizes + std::vector 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 fragmentablePayloadSizes = {5000, 10000, 20000, 40000, 60000}; + + for (auto sentPayloadSize : fragmentablePayloadSizes) + { + m_rxCount = 0; + m_droppedFragments = 0; + Ptr errModel = CreateObject(); + 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); } }; diff --git a/src/internet/test/ipv6-raw-test.cc b/src/internet/test/ipv6-raw-test.cc index e317a5813..60479730c 100644 --- a/src/internet/test/ipv6-raw-test.cc +++ b/src/internet/test/ipv6-raw-test.cc @@ -5,11 +5,12 @@ * * Author: Hajime Tazaki */ -/** +/* * 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, Ipv6Address dst, uint32_t size); + + /** + * @brief Receive a packet + * @param socket Socket that received a packet + */ + void RxCallback(Ptr socket); + + /** + * @brief Packet dropped callback at Phy Rx. + * @param p Dropped packet. + */ + void PhyRxDropCallback(Ptr 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) +{ + Ptr p = socket->Recv(std::numeric_limits::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 sock, Ipv6Address dst, uint32_t size) +{ + Ptr p = Create(size); + sock->SendTo(p, 0, Inet6SocketAddress(dst, 0)); + NS_LOG_DEBUG("Sender sent " << p->GetSize() << " bytes to " << dst); +} + +void +Ipv6RawFragmentationTest::PhyRxDropCallback(Ptr /*p*/) +{ + ++m_droppedFragments; +} + +void +Ipv6RawFragmentationTest::DoRun() +{ + Ptr rxNode = CreateObject(); + Ptr txNode = CreateObject(); + + SimpleNetDeviceHelper helper; + helper.SetNetDevicePointToPointMode(true); + + Ptr rxDev = DynamicCast(helper.Install(rxNode).Get(0)); + Ptr txDev = DynamicCast(helper.Install(txNode).Get(0)); + + txDev->SetMtu(1280); // Minimum MTU allowed for IPv6 + + rxDev->TraceConnectWithoutContext( + "PhyRxDrop", + MakeCallback(&Ipv6RawFragmentationTest::PhyRxDropCallback, this)); + + Ptr ch = CreateObject(); + rxDev->SetChannel(ch); + txDev->SetChannel(ch); + + InternetStackHelper stack; + stack.SetIpv4StackInstall(false); + stack.Install(NodeContainer(rxNode, txNode)); + + rxNode->GetObject()->SetAttribute("DAD", BooleanValue(false)); + txNode->GetObject()->SetAttribute("DAD", BooleanValue(false)); + + Ptr ipv6Rx = rxNode->GetObject(); + Ptr ipv6Tx = txNode->GetObject(); + + 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 rxSock = rxNode->GetObject()->CreateSocket(); + rxSock->SetAttribute("Protocol", UintegerValue(proto)); + rxSock->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 0)); + rxSock->SetRecvCallback(MakeCallback(&Ipv6RawFragmentationTest::RxCallback, this)); + + Ptr txSock = txNode->GetObject()->CreateSocket(); + txSock->SetAttribute("Protocol", UintegerValue(proto)); + + std::vector 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 fragmentablePayloadSizes = {5000, 10000, 20000, 40000, 60000}; + + for (auto sentPayloadSize : fragmentablePayloadSizes) + { + m_rxCount = 0; + m_droppedFragments = 0; + + Ptr errModel = CreateObject(); + 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); } };