--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/test/ipv6-fragmentation-test.cc Wed Mar 21 18:51:55 2012 +0100
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Universita' di Firenze, Italy
+ *
+ * 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 <[email protected]>
+ */
+/**
+ * This is the test code for ipv6-l3protocol.cc (only the fragmentation and reassembly part).
+ */
+#define NS3_LOG_ENABLE 1
+
+#include "ns3/test.h"
+#include "ns3/config.h"
+#include "ns3/uinteger.h"
+#include "ns3/socket-factory.h"
+#include "ns3/ipv4-raw-socket-factory.h"
+#include "ns3/ipv6-raw-socket-factory.h"
+#include "ns3/udp-socket-factory.h"
+#include "ns3/simulator.h"
+#include "error-channel.h"
+#include "error-net-device.h"
+#include "ns3/drop-tail-queue.h"
+#include "ns3/socket.h"
+#include "ns3/udp-socket.h"
+
+#include "ns3/log.h"
+#include "ns3/node.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/boolean.h"
+
+#include "ns3/ipv6-static-routing.h"
+#include "ns3/ipv6-list-routing.h"
+#include "ns3/inet6-socket-address.h"
+#
+#include "ns3/arp-l3-protocol.h"
+#include "ns3/ipv4-l3-protocol.h"
+#include "ns3/icmpv4-l4-protocol.h"
+#include "ns3/ipv4-list-routing.h"
+#include "ns3/ipv4-static-routing.h"
+#include "ns3/udp-l4-protocol.h"
+
+#include "ns3/ipv6-l3-protocol.h"
+#include "ns3/icmpv6-l4-protocol.h"
+
+#include <string>
+#include <limits>
+#include <netinet/in.h>
+
+namespace ns3 {
+
+class UdpSocketImpl;
+
+static void
+AddInternetStack (Ptr<Node> node)
+{
+ //IPV6
+ Ptr<Ipv6L3Protocol> ipv6 = CreateObject<Ipv6L3Protocol> ();
+
+ //Routing for Ipv6
+ Ptr<Ipv6ListRouting> ipv6Routing = CreateObject<Ipv6ListRouting> ();
+ ipv6->SetRoutingProtocol (ipv6Routing);
+ Ptr<Ipv6StaticRouting> ipv6staticRouting = CreateObject<Ipv6StaticRouting> ();
+ ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0);
+ node->AggregateObject (ipv6);
+
+ //ICMPv6
+ Ptr<Icmpv6L4Protocol> icmp6 = CreateObject<Icmpv6L4Protocol> ();
+ node->AggregateObject (icmp6);
+
+ //Ipv6 Extensions
+ ipv6->RegisterExtensions ();
+ ipv6->RegisterOptions ();
+
+ //UDP
+ Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
+ node->AggregateObject (udp);
+}
+
+
+class Ipv6FragmentationTest : public TestCase
+{
+ Ptr<Packet> m_sentPacketClient;
+ Ptr<Packet> m_receivedPacketClient;
+ Ptr<Packet> m_receivedPacketServer;
+
+
+ Ptr<Socket> m_socketServer;
+ Ptr<Socket> m_socketClient;
+ uint32_t m_dataSize;
+ uint8_t *m_data;
+ uint32_t m_size;
+ uint8_t m_icmpType;
+ uint8_t m_icmpCode;
+
+public:
+ virtual void DoRun (void);
+ Ipv6FragmentationTest ();
+ ~Ipv6FragmentationTest ();
+
+ // server part
+ void StartServer (Ptr<Node> ServerNode);
+ void HandleReadServer (Ptr<Socket> socket);
+
+ // client part
+ void StartClient (Ptr<Node> ClientNode);
+ void HandleReadClient (Ptr<Socket> socket);
+ void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
+ uint8_t icmpCode,uint32_t icmpInfo);
+
+ void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
+ Ptr<Packet> SendClient (void);
+
+};
+
+
+Ipv6FragmentationTest::Ipv6FragmentationTest ()
+ : TestCase ("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
+{
+ m_socketServer = 0;
+ m_data = 0;
+ m_dataSize = 0;
+}
+
+Ipv6FragmentationTest::~Ipv6FragmentationTest ()
+{
+ if ( m_data )
+ {
+ delete[] m_data;
+ }
+ m_data = 0;
+ m_dataSize = 0;
+}
+
+
+void
+Ipv6FragmentationTest::StartServer (Ptr<Node> ServerNode)
+{
+
+ if (m_socketServer == 0)
+ {
+ TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
+ m_socketServer = Socket::CreateSocket (ServerNode, tid);
+ Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001::1"), 9);
+ m_socketServer->Bind (local);
+ Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
+ }
+
+ m_socketServer->SetRecvCallback (MakeCallback (&Ipv6FragmentationTest::HandleReadServer, this));
+}
+
+void
+Ipv6FragmentationTest::HandleReadServer (Ptr<Socket> socket)
+{
+ Ptr<Packet> packet;
+ Address from;
+ while ((packet = socket->RecvFrom (from)))
+ {
+ if (Inet6SocketAddress::IsMatchingType (from))
+ {
+ packet->RemoveAllPacketTags ();
+ packet->RemoveAllByteTags ();
+
+ m_receivedPacketServer = packet->Copy ();
+ }
+ }
+}
+
+void
+Ipv6FragmentationTest::StartClient (Ptr<Node> ClientNode)
+{
+
+ if (m_socketClient == 0)
+ {
+ TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
+ m_socketClient = Socket::CreateSocket (ClientNode, tid);
+ m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
+ m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001::1"), 9));
+ CallbackValue cbValue = MakeCallback (&Ipv6FragmentationTest::HandleReadIcmpClient, this);
+ m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
+ }
+
+ m_socketClient->SetRecvCallback (MakeCallback (&Ipv6FragmentationTest::HandleReadClient, this));
+}
+
+void
+Ipv6FragmentationTest::HandleReadClient (Ptr<Socket> socket)
+{
+ Ptr<Packet> packet;
+ Address from;
+ while ((packet = socket->RecvFrom (from)))
+ {
+ if (Inet6SocketAddress::IsMatchingType (from))
+ {
+ m_receivedPacketClient = packet->Copy ();
+ }
+ }
+}
+
+void
+Ipv6FragmentationTest::HandleReadIcmpClient (Ipv6Address icmpSource,
+ uint8_t icmpTtl, uint8_t icmpType,
+ uint8_t icmpCode, uint32_t icmpInfo)
+{
+ m_icmpType = icmpType;
+ m_icmpCode = icmpCode;
+}
+
+void
+Ipv6FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
+{
+ if (dataSize != m_dataSize)
+ {
+ delete [] m_data;
+ m_data = new uint8_t [dataSize];
+ m_dataSize = dataSize;
+ }
+
+ if (fillSize >= dataSize)
+ {
+ memcpy (m_data, fill, dataSize);
+ return;
+ }
+
+ uint32_t filled = 0;
+ while (filled + fillSize < dataSize)
+ {
+ memcpy (&m_data[filled], fill, fillSize);
+ filled += fillSize;
+ }
+
+ memcpy (&m_data[filled], fill, dataSize - filled);
+
+ m_size = dataSize;
+}
+
+Ptr<Packet> Ipv6FragmentationTest::SendClient (void)
+{
+ Ptr<Packet> p;
+ if (m_dataSize)
+ {
+ p = Create<Packet> (m_data, m_dataSize);
+ }
+ else
+ {
+ p = Create<Packet> (m_size);
+ }
+ m_socketClient->Send (p);
+
+ return p;
+}
+
+void
+Ipv6FragmentationTest::DoRun (void)
+{
+ // set the arp cache to something quite high
+ // we shouldn't need because the NetDevice used doesn't need arp, but still
+ // Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
+// LogComponentEnable ("ErrorNetDevice", LOG_LEVEL_ALL);
+// LogComponentEnableAll(LOG_LEVEL_ALL);
+// Create topology
+
+ // Receiver Node
+ Ptr<Node> serverNode = CreateObject<Node> ();
+ AddInternetStack (serverNode);
+ Ptr<ErrorNetDevice> serverDev;
+ Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
+ {
+ serverDev = CreateObject<ErrorNetDevice> ();
+ serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
+ serverDev->SetMtu (1500);
+ serverDev->SetReceiveErrorModel (serverDevErrorModel);
+ serverDevErrorModel->Disable ();
+ serverNode->AddDevice (serverDev);
+ Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
+ uint32_t netdev_idx = ipv6->AddInterface (serverDev);
+ Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::1"), Ipv6Prefix (32));
+ ipv6->AddAddress (netdev_idx, ipv6Addr);
+ ipv6->SetUp (netdev_idx);
+ }
+ StartServer (serverNode);
+
+ // Sender Node
+ Ptr<Node> clientNode = CreateObject<Node> ();
+ AddInternetStack (clientNode);
+ Ptr<ErrorNetDevice> clientDev;
+ Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
+ {
+ clientDev = CreateObject<ErrorNetDevice> ();
+ clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
+ clientDev->SetMtu (1000);
+ clientDev->SetReceiveErrorModel (clientDevErrorModel);
+ clientDevErrorModel->Disable ();
+ clientNode->AddDevice (clientDev);
+ Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
+ uint32_t netdev_idx = ipv6->AddInterface (clientDev);
+ Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::2"), Ipv6Prefix (32));
+ ipv6->AddAddress (netdev_idx, ipv6Addr);
+ ipv6->SetUp (netdev_idx);
+ }
+ StartClient (clientNode);
+
+ // link the two nodes
+ Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
+ serverDev->SetChannel (channel);
+ clientDev->SetChannel (channel);
+ channel->SetJumpingTime (Seconds (0.5));
+
+
+ // some small packets, some rather big ones
+ uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
+
+ // using the alphabet
+ uint8_t fillData[78];
+ for ( uint32_t k = 48; k <= 125; k++ )
+ {
+ fillData[k - 48] = k;
+ }
+
+ // First test: normal channel, no errors, no delays
+ for ( int i = 0; i < 5; i++)
+ {
+ uint32_t packetSize = packetSizes[i];
+
+ SetFill (fillData, 78, packetSize);
+
+ m_receivedPacketServer = Create<Packet> ();
+ Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
+ &Ipv6FragmentationTest::SendClient, this);
+ Simulator::Run ();
+
+ uint8_t recvBuffer[65000];
+
+ uint16_t recvSize = m_receivedPacketServer->GetSize ();
+
+ NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
+ "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
+
+ m_receivedPacketServer->CopyData (recvBuffer, 65000);
+ NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
+ 0, "Packet content differs");
+ }
+
+ // Second test: normal channel, no errors, delays each 2 packets.
+ // Each other fragment will arrive out-of-order.
+ // The packets should be received correctly since reassembly will reorder the fragments.
+ channel->SetJumpingMode (true);
+ for ( int i = 0; i < 5; i++)
+ {
+ uint32_t packetSize = packetSizes[i];
+
+ SetFill (fillData, 78, packetSize);
+
+ m_receivedPacketServer = Create<Packet> ();
+ Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
+ &Ipv6FragmentationTest::SendClient, this);
+ Simulator::Run ();
+
+ uint8_t recvBuffer[65000];
+
+ uint16_t recvSize = m_receivedPacketServer->GetSize ();
+
+ NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
+ "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
+
+ m_receivedPacketServer->CopyData (recvBuffer, 65000);
+ NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
+ 0, "Packet content differs");
+ }
+ channel->SetJumpingMode (false);
+
+ // Third test: normal channel, some errors, no delays.
+ // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
+ // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
+ // to the sender (if the first fragment has been received).
+ // In this test case the first fragment is received, so we do expect an ICMP.
+ // Client -> Server : errors enabled
+ // Server -> Client : errors disabled (we want to have back the ICMP)
+ clientDevErrorModel->Disable ();
+ serverDevErrorModel->Enable ();
+ for ( int i = 1; i < 5; i++)
+ {
+ uint32_t packetSize = packetSizes[i];
+
+ SetFill (fillData, 78, packetSize);
+
+ // reset the model, we want to receive the very first fragment.
+ serverDevErrorModel->Reset ();
+
+ m_receivedPacketServer = Create<Packet> ();
+ m_icmpType = 0;
+ m_icmpCode = 0;
+ Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
+ &Ipv6FragmentationTest::SendClient, this);
+ Simulator::Run ();
+
+ uint16_t recvSize = m_receivedPacketServer->GetSize ();
+
+ NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
+ NS_TEST_EXPECT_MSG_EQ ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED)
+ && (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
+ true, "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType) << int(m_icmpCode) );
+ }
+
+
+ Simulator::Destroy ();
+}
+//-----------------------------------------------------------------------------
+class Ipv6FragmentationTestSuite : public TestSuite
+{
+public:
+ Ipv6FragmentationTestSuite () : TestSuite ("ipv6-fragmentation", UNIT)
+ {
+ AddTestCase (new Ipv6FragmentationTest);
+ }
+} g_ipv6fragmentationTestSuite;
+
+}; // namespace ns3