A Discrete-Event Network Simulator
API
ipv6-fragmentation-test.cc
Go to the documentation of this file.
1/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2011 Universita' di Firenze, Italy
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19 */
26#include "ns3/test.h"
27#include "ns3/config.h"
28#include "ns3/uinteger.h"
29#include "ns3/socket-factory.h"
30#include "ns3/ipv4-raw-socket-factory.h"
31#include "ns3/ipv6-raw-socket-factory.h"
32#include "ns3/udp-socket-factory.h"
33#include "ns3/simulator.h"
34#include "ns3/simple-net-device.h"
35#include "ns3/socket.h"
36#include "ns3/udp-socket.h"
37
38#include "ns3/log.h"
39#include "ns3/node.h"
40#include "ns3/inet-socket-address.h"
41#include "ns3/boolean.h"
42
43#include "ns3/ipv6-static-routing.h"
44#include "ns3/ipv6-list-routing.h"
45#include "ns3/inet6-socket-address.h"
46#
47#include "ns3/arp-l3-protocol.h"
48#include "ns3/ipv4-l3-protocol.h"
49#include "ns3/icmpv4-l4-protocol.h"
50#include "ns3/ipv4-list-routing.h"
51#include "ns3/ipv4-static-routing.h"
52#include "ns3/udp-l4-protocol.h"
53
54#include "ns3/ipv6-l3-protocol.h"
55#include "ns3/icmpv6-l4-protocol.h"
56#include "ns3/traffic-control-layer.h"
57#include "ns3/internet-stack-helper.h"
58#include "ns3/error-channel.h"
59
60#include <string>
61#include <limits>
62#include <netinet/in.h>
63
64using namespace ns3;
65
66class UdpSocketImpl;
67
74class IPv6TestTag : public Tag {
75private:
76 uint64_t token;
77public:
82 static TypeId GetTypeId () {
83 static TypeId tid = TypeId ("ns3::IPv6TestTag").SetParent<Tag> ().AddConstructor<IPv6TestTag> ();
84 return tid;
85 }
86 virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
87 virtual uint32_t GetSerializedSize () const { return sizeof (token); }
88 virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
89 virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
90 virtual void Print (std::ostream &os) const { os << "token=" << token; }
95 void SetToken (uint64_t token) { this->token = token; }
100 uint64_t GetToken () { return token; }
101};
102
103
111{
115
116
120 uint8_t *m_data;
122 uint8_t m_icmpType;
123 uint8_t m_icmpCode;
124
125public:
126 virtual void DoRun (void);
129
130 // server part
131
136 void StartServer (Ptr<Node> ServerNode);
141 void HandleReadServer (Ptr<Socket> socket);
142
143 // client part
144
149 void StartClient (Ptr<Node> ClientNode);
154 void HandleReadClient (Ptr<Socket> socket);
163 void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
164 uint8_t icmpCode, uint32_t icmpInfo);
165
172 void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
173
178 Ptr<Packet> SendClient (void);
179
188 void HandleServerRx (Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
189
198 void HandleClientTx (Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
199};
200
201
203 : TestCase ("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
204{
205 m_socketServer = 0;
206 m_data = 0;
207 m_dataSize = 0;
208 m_size = 0;
209 m_icmpType = 0;
210 m_icmpCode = 0;
211}
212
214{
215 if ( m_data )
216 {
217 delete[] m_data;
218 }
219 m_data = 0;
220 m_dataSize = 0;
221}
222
223
224void
226{
227
228 if (m_socketServer == 0)
229 {
230 TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
231 m_socketServer = Socket::CreateSocket (ServerNode, tid);
232 Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001::1"), 9);
233 m_socketServer->Bind (local);
234 Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
235 }
236
238}
239
240void
242{
243 Ptr<Packet> packet;
244 Address from;
245 while ((packet = socket->RecvFrom (from)))
246 {
247 if (Inet6SocketAddress::IsMatchingType (from))
248 {
249 m_receivedPacketServer = packet->Copy ();
250 }
251 }
252}
253
254void
256{
257
258 if (m_socketClient == 0)
259 {
260 TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
261 m_socketClient = Socket::CreateSocket (ClientNode, tid);
262 m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
265 m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
266 }
267
269}
270
271void
273{
274 Ptr<Packet> packet;
275 Address from;
276 while ((packet = socket->RecvFrom (from)))
277 {
278 if (Inet6SocketAddress::IsMatchingType (from))
279 {
280 m_receivedPacketClient = packet->Copy ();
281 }
282 }
283}
284
285void
287 uint8_t icmpTtl, uint8_t icmpType,
288 uint8_t icmpCode, uint32_t icmpInfo)
289{
290 m_icmpType = icmpType;
291 m_icmpCode = icmpCode;
292}
293
294void
295Ipv6FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
296{
297 if (dataSize != m_dataSize)
298 {
299 delete [] m_data;
300 m_data = new uint8_t [dataSize];
301 m_dataSize = dataSize;
302 }
303
304 if (fillSize >= dataSize)
305 {
306 memcpy (m_data, fill, dataSize);
307 return;
308 }
309
310 uint32_t filled = 0;
311 while (filled + fillSize < dataSize)
312 {
313 memcpy (&m_data[filled], fill, fillSize);
314 filled += fillSize;
315 }
316
317 memcpy (&m_data[filled], fill, dataSize - filled);
318
319 m_size = dataSize;
320}
321
323{
324 Ptr<Packet> p;
325 if (m_dataSize)
326 {
327 p = Create<Packet> (m_data, m_dataSize);
328 }
329 else
330 {
331 p = Create<Packet> (m_size);
332 }
333 IPv6TestTag tag;
334 tag.SetToken (42);
335 p->AddPacketTag (tag);
336 p->AddByteTag (tag);
337
338 m_socketClient->Send (p);
339
340 return p;
341}
342
344{
345 NS_TEST_EXPECT_MSG_LT_OR_EQ (packet->GetSize (), ipv6->GetMtu (interface), "Received packet size > MTU: packetSizes: " << packet->GetSize ());
346}
347
349{
350 NS_TEST_EXPECT_MSG_LT_OR_EQ (packet->GetSize (), ipv6->GetMtu (interface), "Transmitted packet size > MTU: packetSizes: " << packet->GetSize ());
351}
352
353void
355{
356 // Create topology
357
358 InternetStackHelper internet;
359 internet.SetIpv4StackInstall (false);
360
361 // Receiver Node
362 Ptr<Node> serverNode = CreateObject<Node> ();
363 internet.Install (serverNode);
364 Ptr<SimpleNetDevice> serverDev;
365 Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
366 {
367 serverDev = CreateObject<SimpleNetDevice> ();
368 serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
369 serverDev->SetMtu (1500);
370 serverDev->SetReceiveErrorModel (serverDevErrorModel);
371 serverDevErrorModel->Disable ();
372 serverNode->AddDevice (serverDev);
373 Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
374 uint32_t netdev_idx = ipv6->AddInterface (serverDev);
376 ipv6->AddAddress (netdev_idx, ipv6Addr);
377 ipv6->SetUp (netdev_idx);
378 ipv6->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv6FragmentationTest::HandleServerRx, this));
379 }
380 StartServer (serverNode);
381
382 // Sender Node
383 Ptr<Node> clientNode = CreateObject<Node> ();
384 internet.Install (clientNode);
385 Ptr<SimpleNetDevice> clientDev;
386 Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
387 {
388 clientDev = CreateObject<SimpleNetDevice> ();
389 clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
390 clientDev->SetMtu (1500);
391 clientDev->SetReceiveErrorModel (clientDevErrorModel);
392 clientDevErrorModel->Disable ();
393 clientNode->AddDevice (clientDev);
394 Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
395 uint32_t netdev_idx = ipv6->AddInterface (clientDev);
397 ipv6->AddAddress (netdev_idx, ipv6Addr);
398 ipv6->SetUp (netdev_idx);
399 ipv6->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv6FragmentationTest::HandleClientTx, this));
400 }
401 StartClient (clientNode);
402
403 // link the two nodes
404 Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
405 serverDev->SetChannel (channel);
406 clientDev->SetChannel (channel);
407 channel->SetJumpingTime (Seconds (0.5));
408
409
410 // some small packets, some rather big ones
411 uint32_t packetSizes[5] = {1500, 2000, 5000, 10000, 65000};
412
413 // using the alphabet
414 uint8_t fillData[78];
415 for ( uint32_t k = 48; k <= 125; k++ )
416 {
417 fillData[k - 48] = k;
418 }
419
420 // First test: normal channel, no errors, no delays
421 for ( int i = 0; i < 5; i++)
422 {
423 uint32_t packetSize = packetSizes[i];
424
425 SetFill (fillData, 78, packetSize);
426
427 m_receivedPacketServer = Create<Packet> ();
428 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
430 Simulator::Run ();
431
432 uint8_t recvBuffer[65000];
433
434 uint16_t recvSize = m_receivedPacketServer->GetSize ();
435
436 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
437 "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
438
439 m_receivedPacketServer->CopyData (recvBuffer, 65000);
441 0, "Packet content differs");
442 }
443
444 // Second test: normal channel, no errors, delays each 2 packets.
445 // Each other fragment will arrive out-of-order.
446 // The packets should be received correctly since reassembly will reorder the fragments.
447 channel->SetJumpingMode (true);
448 for ( int i = 0; i < 5; i++)
449 {
450 uint32_t packetSize = packetSizes[i];
451
452 SetFill (fillData, 78, packetSize);
453
454 m_receivedPacketServer = Create<Packet> ();
455 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
457 Simulator::Run ();
458
459 uint8_t recvBuffer[65000];
460
461 uint16_t recvSize = m_receivedPacketServer->GetSize ();
462
463 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
464 "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
465
466 m_receivedPacketServer->CopyData (recvBuffer, 65000);
468 0, "Packet content differs");
469 }
470 channel->SetJumpingMode (false);
471
472 // Third test: normal channel, some errors, no delays.
473 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
474 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
475 // to the sender (if the first fragment has been received).
476 // In this test case the first fragment is received, so we do expect an ICMP.
477 // Client -> Server : errors enabled
478 // Server -> Client : errors disabled (we want to have back the ICMP)
479 clientDevErrorModel->Disable ();
480 serverDevErrorModel->Enable ();
481 for ( int i = 1; i < 5; i++)
482 {
483 uint32_t packetSize = packetSizes[i];
484
485 SetFill (fillData, 78, packetSize);
486
487 // reset the model, we want to receive the very first fragment.
488 serverDevErrorModel->Reset ();
489
490 m_receivedPacketServer = Create<Packet> ();
491 m_icmpType = 0;
492 m_icmpCode = 0;
493 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
495 Simulator::Run ();
496
497 uint16_t recvSize = m_receivedPacketServer->GetSize ();
498
499 NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
500 NS_TEST_EXPECT_MSG_EQ ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED)
501 && (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
502 true, "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType) << int(m_icmpCode) );
503 }
504
505 // Fourth test: normal channel, no errors, no delays.
506 // We check tags
507 clientDevErrorModel->Disable ();
508 serverDevErrorModel->Disable ();
509 for (int i= 0; i<5; i++)
510 {
511 uint32_t packetSize = packetSizes[i];
512
513 SetFill (fillData, 78, packetSize);
514
515 m_receivedPacketServer = Create<Packet> ();
516 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
518 Simulator::Run ();
519
520 IPv6TestTag packetTag;
521 bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
522
523 NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
524 NS_TEST_EXPECT_MSG_EQ (packetTag.GetToken (), 42, "PacketTag value not correct");
525
527
528 uint32_t end = 0;
529 uint32_t tagStart = 0;
530 uint32_t tagEnd = 0;
531 while (iter.HasNext ())
532 {
533 ByteTagIterator::Item item = iter.Next ();
534 NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv6TestTag", "ByteTag name not correct");
535 tagStart = item.GetStart ();
536 tagEnd = item.GetEnd ();
537 if (end == 0)
538 {
539 NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
540 }
541 if (end != 0)
542 {
543 NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
544 }
545 end = tagEnd;
546 IPv6TestTag *byteTag = dynamic_cast<IPv6TestTag *> (item.GetTypeId ().GetConstructor () ());
547 NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
548 item.GetTag (*byteTag);
549 NS_TEST_EXPECT_MSG_EQ (byteTag->GetToken (), 42, "ByteTag value not correct");
550 delete byteTag;
551 }
553 }
554
555 Simulator::Destroy ();
556}
557
558
566{
567public:
568 Ipv6FragmentationTestSuite () : TestSuite ("ipv6-fragmentation", UNIT)
569 {
570 AddTestCase (new Ipv6FragmentationTest, TestCase::QUICK);
571 }
572};
573
575
Tag used in IPv6 Fragmentation Test.
virtual void Print(std::ostream &os) const
static TypeId GetTypeId()
Get the type ID.
virtual void Serialize(TagBuffer buffer) const
virtual TypeId GetInstanceTypeId() const
Get the most derived TypeId for this Object.
virtual void Deserialize(TagBuffer buffer)
uint64_t GetToken()
Get the token.
virtual uint32_t GetSerializedSize() const
uint64_t token
Token carried by the tag.
void SetToken(uint64_t token)
Set the token.
IPv6 Fragmentation Test.
void HandleReadServer(Ptr< Socket > socket)
Handle incoming packets.
Ptr< Socket > m_socketClient
Client socket.
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
Set the packet fill.
void HandleReadIcmpClient(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Handle incoming ICMP packets.
Ptr< Socket > m_socketServer
Server socket.
virtual void DoRun(void)
Implementation to actually run this TestCase.
void StartServer(Ptr< Node > ServerNode)
Start the server.
Ptr< Packet > m_receivedPacketServer
Packet received by server.
Ptr< Packet > m_sentPacketClient
Packet sent by client.
Ptr< Packet > SendClient(void)
Send a packet.
void HandleReadClient(Ptr< Socket > socket)
Handle incoming packets.
void HandleServerRx(Ptr< const Packet > packet, Ptr< Ipv6 > ipv6, uint32_t interface)
Handle Server's incoming packets.
void HandleClientTx(Ptr< const Packet > packet, Ptr< Ipv6 > ipv6, uint32_t interface)
Handle Client's transmitting packets.
Ptr< Packet > m_receivedPacketClient
Packet received by client.
void StartClient(Ptr< Node > ClientNode)
Start the client.
IPv6 Fragmentation TestSuite.
a polymophic address class
Definition: address.h:91
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:62
uint32_t GetEnd(void) const
The index is an offset from the start of the packet.
Definition: packet.cc:44
TypeId GetTypeId(void) const
Definition: packet.cc:34
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:49
uint32_t GetStart(void) const
The index is an offset from the start of the packet.
Definition: packet.cc:39
Iterator over the set of byte tags in a packet.
Definition: packet.h:55
bool HasNext(void) const
Definition: packet.cc:65
Item Next(void)
Definition: packet.cc:70
AttributeValue implementation for Callback.
Definition: callback.h:1944
An Inet6 address class.
aggregate IP/TCP/UDP functionality to existing Nodes.
void SetIpv4StackInstall(bool enable)
Enable/disable IPv4 stack install.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
Describes an IPv6 address.
Definition: ipv6-address.h:50
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:82
IPv6 address associated with an interface.
Describes an IPv6 prefix.
Definition: ipv6-address.h:456
uint32_t GetId(void) const
Definition: node.cc:109
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:130
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:256
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
ByteTagIterator GetByteTagIterator(void) const
Returns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:933
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:956
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:912
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:978
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
virtual Ptr< Node > GetNode(void) const =0
Return the node this socket is associated with.
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
read and write tag data
Definition: tag-buffer.h:52
void WriteU64(uint64_t v)
Definition: tag-buffer.cc:102
uint64_t ReadU64(void)
Definition: tag-buffer.cc:134
tag a set of bytes in a packet
Definition: tag.h:37
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1197
a unique identifier for an interface.
Definition: type-id.h:59
Callback< ObjectBase * > GetConstructor(void) const
Get the constructor callback.
Definition: type-id.cc:1060
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
std::string GetName(void) const
Get the name.
Definition: type-id.cc:976
A sockets interface to UDP.
#define NS_TEST_EXPECT_MSG_LT_OR_EQ(actual, limit, msg)
Test that an actual value is less than or equal to a limit and report if not.
Definition: test.h:785
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition: test.h:636
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:240
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
static Ipv6FragmentationTestSuite g_ipv6fragmentationTestSuite
Static variable for test initialization.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
channel
Definition: third.py:92
static const uint32_t packetSize
Packet size generated at the AP.