A Discrete-Event Network Simulator
API
ipv4-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 */
24#include "ns3/test.h"
25#include "ns3/config.h"
26#include "ns3/uinteger.h"
27#include "ns3/socket-factory.h"
28#include "ns3/ipv4-raw-socket-factory.h"
29#include "ns3/udp-socket-factory.h"
30#include "ns3/simulator.h"
31#include "ns3/simple-net-device.h"
32#include "ns3/simple-net-device-helper.h"
33#include "ns3/socket.h"
34#include "ns3/udp-socket.h"
35
36#include "ns3/log.h"
37#include "ns3/node.h"
38#include "ns3/inet-socket-address.h"
39#include "ns3/boolean.h"
40
41#include "ns3/arp-l3-protocol.h"
42#include "ns3/ipv4-l3-protocol.h"
43#include "ns3/icmpv4-l4-protocol.h"
44#include "ns3/ipv4-list-routing.h"
45#include "ns3/ipv4-static-routing.h"
46#include "ns3/udp-l4-protocol.h"
47#include "ns3/internet-stack-helper.h"
48#include "ns3/error-channel.h"
49
50#include <string>
51#include <limits>
52#include <netinet/in.h>
53
54using namespace ns3;
55
56class UdpSocketImpl;
57
64class IPv4TestTag : public Tag {
65private:
66 uint64_t token;
67public:
72 static TypeId GetTypeId () {
73 static TypeId tid = TypeId ("ns3::IPv4TestTag").SetParent<Tag> ().AddConstructor<IPv4TestTag> ();
74 return tid;
75 }
76 virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
77 virtual uint32_t GetSerializedSize () const { return sizeof (token); }
78 virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
79 virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
80 virtual void Print (std::ostream &os) const { os << "token=" << token; }
85 void SetToken (uint64_t token) { this->token = token; }
90 uint64_t GetToken () { return token; }
91};
92
100{
104
105
109 uint8_t *m_data;
111 uint8_t m_icmpType;
113
114public:
115 virtual void DoRun (void);
120 Ipv4FragmentationTest (bool broadcast);
122
123 // server part
124
129 void StartServer (Ptr<Node> ServerNode);
134 void HandleReadServer (Ptr<Socket> socket);
135
136 // client part
137
142 void StartClient (Ptr<Node> ClientNode);
147 void HandleReadClient (Ptr<Socket> socket);
156 void HandleReadIcmpClient (Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
157 uint8_t icmpCode, uint32_t icmpInfo);
158
165 void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
166
171 Ptr<Packet> SendClient (void);
172
173};
174
176 : TestCase (std::string ("Verify the IPv4 layer 3 protocol fragmentation and reassembly: ") +
177 (broadcast? "broadcast": "unicast"))
178{
179 m_socketServer = 0;
180 m_data = 0;
181 m_dataSize = 0;
182 m_size = 0;
183 m_icmpType = 0;
184 m_broadcast = broadcast;
185}
186
188{
189 if ( m_data )
190 {
191 delete[] m_data;
192 }
193 m_data = 0;
194 m_dataSize = 0;
195}
196
197
198void
200{
201
202 if (m_socketServer == 0)
203 {
204 TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
205 m_socketServer = Socket::CreateSocket (ServerNode, tid);
206 InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 9);
207 m_socketServer->Bind (local);
208 Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
209 if (udpSocket)
210 {
211 // equivalent to setsockopt (MCAST_JOIN_GROUP)
212 udpSocket->MulticastJoinGroup (0, Ipv4Address ("10.0.0.1"));
213 }
214 }
215
217}
218
219void
221{
222 Ptr<Packet> packet;
223 Address from;
224 while ((packet = socket->RecvFrom (from)))
225 {
226 if (InetSocketAddress::IsMatchingType (from))
227 {
228 m_receivedPacketServer = packet->Copy();
229 }
230 }
231}
232
233void
235{
236
237 if (m_socketClient == 0)
238 {
239 TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
240 m_socketClient = Socket::CreateSocket (ClientNode, tid);
244 m_socketClient->SetAttribute ("IcmpCallback", cbValue);
246 }
247
249}
250
251void
253{
254 Ptr<Packet> packet;
255 Address from;
256 while ((packet = socket->RecvFrom (from)))
257 {
258 if (InetSocketAddress::IsMatchingType (from))
259 {
260 m_receivedPacketClient = packet->Copy();
261 }
262 }
263}
264
265void
267 uint8_t icmpTtl, uint8_t icmpType,
268 uint8_t icmpCode, uint32_t icmpInfo)
269{
270 m_icmpType = icmpType;
271}
272
273void
274Ipv4FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
275{
276 if (dataSize != m_dataSize)
277 {
278 delete [] m_data;
279 m_data = new uint8_t [dataSize];
280 m_dataSize = dataSize;
281 }
282
283 if (fillSize >= dataSize)
284 {
285 memcpy (m_data, fill, dataSize);
286 return;
287 }
288
289 uint32_t filled = 0;
290 while (filled + fillSize < dataSize)
291 {
292 memcpy (&m_data[filled], fill, fillSize);
293 filled += fillSize;
294 }
295
296 memcpy(&m_data[filled], fill, dataSize - filled);
297
298 m_size = dataSize;
299}
300
302{
303 Ptr<Packet> p;
304 if (m_dataSize)
305 {
306 p = Create<Packet> (m_data, m_dataSize);
307 }
308 else
309 {
310 p = Create<Packet> (m_size);
311 }
312 IPv4TestTag tag;
313 tag.SetToken (42);
314 p->AddPacketTag (tag);
315 p->AddByteTag (tag);
316
317 if (m_broadcast)
318 {
321 InetSocketAddress saddress = InetSocketAddress::ConvertFrom (address);
322 saddress.SetIpv4 (Ipv4Address::GetBroadcast ());
323 m_socketClient->SendTo (p, 0, saddress);
324 }
325 else
326 {
327 m_socketClient->Send (p);
328 }
329
330 return p;
331}
332
333void
335{
336 // set the arp cache to something quite high
337 // we shouldn't need because the NetDevice used doesn't need arp, but still
338 Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
339
340 // Create topology
341
342 // Receiver Node
343 Ptr<Node> serverNode = CreateObject<Node> ();
344 // Sender Node
345 Ptr<Node> clientNode = CreateObject<Node> ();
346
347 NodeContainer nodes (serverNode, clientNode);
348
349 Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
350 channel->SetJumpingTime (Seconds (0.5));
351
352 SimpleNetDeviceHelper helperChannel;
353 helperChannel.SetNetDevicePointToPointMode (true);
354 NetDeviceContainer net = helperChannel.Install (nodes, channel);
355
356 InternetStackHelper internet;
357 internet.Install (nodes);
358
359 Ptr<Ipv4> ipv4;
360 uint32_t netdev_idx;
361 Ipv4InterfaceAddress ipv4Addr;
362
363 // Receiver Node
364 ipv4 = serverNode->GetObject<Ipv4> ();
365 netdev_idx = ipv4->AddInterface (net.Get (0));
366 ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
367 ipv4->AddAddress (netdev_idx, ipv4Addr);
368 ipv4->SetUp (netdev_idx);
369 Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
370 Ptr<SimpleNetDevice> serverDev = DynamicCast<SimpleNetDevice> (net.Get (0));
371 serverDevErrorModel->Disable ();
372 serverDev->SetMtu(1500);
373 serverDev->SetReceiveErrorModel (serverDevErrorModel);
374 StartServer (serverNode);
375
376 // Sender Node
377 ipv4 = clientNode->GetObject<Ipv4> ();
378 netdev_idx = ipv4->AddInterface (net.Get (1));
379 ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
380 ipv4->AddAddress (netdev_idx, ipv4Addr);
381 ipv4->SetUp (netdev_idx);
382 Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
383 Ptr<SimpleNetDevice> clientDev = DynamicCast<SimpleNetDevice> (net.Get (1));
384 clientDevErrorModel->Disable ();
385 clientDev->SetMtu(1500);
386 clientDev->SetReceiveErrorModel (clientDevErrorModel);
387 StartClient (clientNode);
388
389 // some small packets, some rather big ones
390 uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
391
392 // using the alphabet
393 uint8_t fillData[78];
394 for ( uint32_t k=48; k<=125; k++ )
395 {
396 fillData[k-48] = k;
397 }
398
399 // First test: normal channel, no errors, no delays
400 for( int i= 0; i<5; i++)
401 {
402 uint32_t packetSize = packetSizes[i];
403
404 SetFill (fillData, 78, packetSize);
405
406 m_receivedPacketServer = Create<Packet> ();
407 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
409 Simulator::Run ();
410
411 uint8_t recvBuffer[65000];
412
413 uint16_t recvSize = m_receivedPacketServer->GetSize ();
414
415 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
416
417 m_receivedPacketServer->CopyData(recvBuffer, 65000);
419 0, "Packet content differs");
420 }
421
422 // Second test: normal channel, no errors, delays each 2 packets.
423 // Each other fragment will arrive out-of-order.
424 // The packets should be received correctly since reassembly will reorder the fragments.
425 channel->SetJumpingMode(true);
426 for( int i= 0; i<5; i++)
427 {
428 uint32_t packetSize = packetSizes[i];
429
430 SetFill (fillData, 78, packetSize);
431
432 m_receivedPacketServer = Create<Packet> ();
433 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
435 Simulator::Run ();
436
437 uint8_t recvBuffer[65000];
438
439 uint16_t recvSize = m_receivedPacketServer->GetSize ();
440
441 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
442
443 m_receivedPacketServer->CopyData(recvBuffer, 65000);
445 0, "Packet content differs");
446 }
447 channel->SetJumpingMode(false);
448
449 // Third test: normal channel, some errors, no delays.
450 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
451 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
452 // to the sender (if the first fragment has been received).
453 // In this test case the first fragment is received, so we do expect an ICMP.
454 // Client -> Server : errors enabled
455 // Server -> Client : errors disabled (we want to have back the ICMP)
456 clientDevErrorModel->Disable();
457 serverDevErrorModel->Enable();
458 for( int i= 1; i<5; i++)
459 {
460 uint32_t packetSize = packetSizes[i];
461
462 SetFill (fillData, 78, packetSize);
463
464 // reset the model, we want to receive the very first fragment.
465 serverDevErrorModel->Reset();
466
467 m_receivedPacketServer = Create<Packet> ();
468 m_icmpType = 0;
469 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
471 Simulator::Run ();
472
473 uint16_t recvSize = m_receivedPacketServer->GetSize ();
474
475 NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
476 NS_TEST_EXPECT_MSG_EQ ((m_icmpType == 11), true, "Client did not receive ICMP::TIME_EXCEEDED");
477 }
478
479 // Fourth test: normal channel, no errors, no delays.
480 // We check tags
481 clientDevErrorModel->Disable ();
482 serverDevErrorModel->Disable ();
483 for (int i= 0; i<5; i++)
484 {
485 uint32_t packetSize = packetSizes[i];
486
487 SetFill (fillData, 78, packetSize);
488
489 m_receivedPacketServer = Create<Packet> ();
490 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
492 Simulator::Run ();
493
494 IPv4TestTag packetTag;
495 bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
496
497 NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
498 NS_TEST_EXPECT_MSG_EQ (packetTag.GetToken (), 42, "PacketTag value not correct");
499
501
502 uint32_t end = 0;
503 uint32_t tagStart = 0;
504 uint32_t tagEnd = 0;
505 while (iter.HasNext ())
506 {
507 ByteTagIterator::Item item = iter.Next ();
508 NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv4TestTag", "ByteTag name not correct");
509 tagStart = item.GetStart ();
510 tagEnd = item.GetEnd ();
511 if (end == 0)
512 {
513 NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
514 }
515 if (end != 0)
516 {
517 NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
518 }
519 end = tagEnd;
520 IPv4TestTag *byteTag = dynamic_cast<IPv4TestTag *> (item.GetTypeId ().GetConstructor () ());
521 NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
522 item.GetTag (*byteTag);
523 NS_TEST_EXPECT_MSG_EQ (byteTag->GetToken (), 42, "ByteTag value not correct");
524 delete byteTag;
525 }
527 }
528
529
530 Simulator::Destroy ();
531}
532
533
541{
542public:
544};
545
547 : TestSuite ("ipv4-fragmentation", UNIT)
548{
549 AddTestCase (new Ipv4FragmentationTest(false), TestCase::QUICK);
550 AddTestCase (new Ipv4FragmentationTest(true), TestCase::QUICK);
551}
552
Tag used in IPv4 Fragmentation Test.
uint64_t GetToken()
Get the token.
static TypeId GetTypeId()
Get the type ID.
virtual TypeId GetInstanceTypeId() const
Get the most derived TypeId for this Object.
virtual uint32_t GetSerializedSize() const
void SetToken(uint64_t token)
Set the token.
uint64_t token
Token carried by the tag.
virtual void Print(std::ostream &os) const
virtual void Deserialize(TagBuffer buffer)
virtual void Serialize(TagBuffer buffer) const
IPv4 Fragmentation Test.
Ptr< Packet > m_receivedPacketClient
Packet received by client.
Ptr< Packet > m_receivedPacketServer
Packet received by server.
Ptr< Packet > m_sentPacketClient
Packet sent by client.
Ptr< Packet > SendClient(void)
Send a packet.
Ptr< Socket > m_socketServer
Server socket.
void StartClient(Ptr< Node > ClientNode)
Start the client.
Ptr< Socket > m_socketClient
Client socket.
void StartServer(Ptr< Node > ServerNode)
Start the server.
void HandleReadIcmpClient(Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Handle incoming ICMP packets.
virtual void DoRun(void)
Implementation to actually run this TestCase.
void HandleReadClient(Ptr< Socket > socket)
Handle incoming packets.
Ipv4FragmentationTest(bool broadcast)
Constructor.
void HandleReadServer(Ptr< Socket > socket)
Handle incoming packets.
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
Set the packet fill.
bool m_broadcast
broadcast packets
IPv4 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 Inet address class
void SetIpv4(Ipv4Address address)
aggregate IP/TCP/UDP functionality to existing Nodes.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:77
a class to store IPv4 address information on an interface
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:256
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
keep track of a set of node pointers.
uint32_t GetId(void) const
Definition: node.cc:109
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
build a set of SimpleNetDevice objects
void SetNetDevicePointToPointMode(bool pointToPointMode)
SimpleNetDevice is Broadcast capable and ARP needing.
NetDeviceContainer Install(Ptr< Node > node) const
This method creates an ns3::SimpleChannel with the attributes configured by SimpleNetDeviceHelper::Se...
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 bool SetAllowBroadcast(bool allowBroadcast)=0
Configure whether broadcast datagram transmissions are allowed.
virtual int GetPeerName(Address &address) const =0
Get the peer address of a connected socket.
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.
virtual int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress)=0
Send data to a specified peer.
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
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.
Hold an unsigned integer type.
Definition: uinteger.h:44
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:849
#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 Ipv4FragmentationTestSuite g_ipv4fragmentationTestSuite
Static variable for test initialization.
address
Definition: first.py:44
nodes
Definition: first.py:32
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
STL namespace.
channel
Definition: third.py:92
static const uint32_t packetSize
Pcket size generated at the AP.