A Discrete-Event Network Simulator
API
ipv4-fragmentation-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 Universita' di Firenze, Italy
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
18 */
23#include "ns3/arp-l3-protocol.h"
24#include "ns3/boolean.h"
25#include "ns3/config.h"
26#include "ns3/error-channel.h"
27#include "ns3/icmpv4-l4-protocol.h"
28#include "ns3/inet-socket-address.h"
29#include "ns3/internet-stack-helper.h"
30#include "ns3/ipv4-l3-protocol.h"
31#include "ns3/ipv4-list-routing.h"
32#include "ns3/ipv4-raw-socket-factory.h"
33#include "ns3/ipv4-static-routing.h"
34#include "ns3/log.h"
35#include "ns3/node.h"
36#include "ns3/simple-net-device-helper.h"
37#include "ns3/simple-net-device.h"
38#include "ns3/simulator.h"
39#include "ns3/socket-factory.h"
40#include "ns3/socket.h"
41#include "ns3/test.h"
42#include "ns3/udp-l4-protocol.h"
43#include "ns3/udp-socket-factory.h"
44#include "ns3/udp-socket.h"
45#include "ns3/uinteger.h"
46
47#ifdef __WIN32__
48#include "ns3/win32-internet.h"
49#else
50#include <netinet/in.h>
51#endif
52
53#include <limits>
54#include <string>
55
56using namespace ns3;
57
58class UdpSocketImpl;
59
66class IPv4TestTag : public Tag
67{
68 private:
69 uint64_t token;
70 public:
76 {
77 static TypeId tid =
78 TypeId("ns3::IPv4TestTag").SetParent<Tag>().AddConstructor<IPv4TestTag>();
79 return tid;
80 }
81
82 TypeId GetInstanceTypeId() const override
83 {
84 return GetTypeId();
85 }
86
87 uint32_t GetSerializedSize() const override
88 {
89 return sizeof(token);
90 }
91
92 void Serialize(TagBuffer buffer) const override
93 {
94 buffer.WriteU64(token);
95 }
96
97 void Deserialize(TagBuffer buffer) override
98 {
99 token = buffer.ReadU64();
100 }
101
102 void Print(std::ostream& os) const override
103 {
104 os << "token=" << token;
105 }
106
111 void SetToken(uint64_t token)
112 {
113 this->token = token;
114 }
115
120 uint64_t GetToken()
121 {
122 return token;
123 }
124};
125
133{
137
141 uint8_t* m_data;
143 uint8_t m_icmpType;
145
146 public:
147 void DoRun() override;
152 Ipv4FragmentationTest(bool broadcast);
153 ~Ipv4FragmentationTest() override;
154
155 // server part
156
161 void StartServer(Ptr<Node> ServerNode);
166 void HandleReadServer(Ptr<Socket> socket);
167
168 // client part
169
174 void StartClient(Ptr<Node> ClientNode);
179 void HandleReadClient(Ptr<Socket> socket);
188 void HandleReadIcmpClient(Ipv4Address icmpSource,
189 uint8_t icmpTtl,
190 uint8_t icmpType,
191 uint8_t icmpCode,
192 uint32_t icmpInfo);
193
200 void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
201
207};
208
210 : TestCase(std::string("Verify the IPv4 layer 3 protocol fragmentation and reassembly: ") +
211 (broadcast ? "broadcast" : "unicast"))
212{
213 m_socketServer = nullptr;
214 m_data = nullptr;
215 m_dataSize = 0;
216 m_size = 0;
217 m_icmpType = 0;
218 m_broadcast = broadcast;
219}
220
222{
223 if (m_data)
224 {
225 delete[] m_data;
226 }
227 m_data = nullptr;
228 m_dataSize = 0;
229}
230
231void
233{
234 if (!m_socketServer)
235 {
236 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
237 m_socketServer = Socket::CreateSocket(ServerNode, tid);
238 InetSocketAddress local = InetSocketAddress(Ipv4Address::GetAny(), 9);
239 m_socketServer->Bind(local);
240 Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketServer);
241 if (udpSocket)
242 {
243 // equivalent to setsockopt (MCAST_JOIN_GROUP)
244 udpSocket->MulticastJoinGroup(0, Ipv4Address("10.0.0.1"));
245 }
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_receivedPacketServer = packet->Copy();
261 }
262 }
263}
264
265void
267{
268 if (!m_socketClient)
269 {
270 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
271 m_socketClient = Socket::CreateSocket(ClientNode, tid);
275 m_socketClient->SetAttribute("IcmpCallback", cbValue);
277 }
278
280}
281
282void
284{
285 Ptr<Packet> packet;
286 Address from;
287 while ((packet = socket->RecvFrom(from)))
288 {
289 if (InetSocketAddress::IsMatchingType(from))
290 {
291 m_receivedPacketClient = packet->Copy();
292 }
293 }
294}
295
296void
298 uint8_t icmpTtl,
299 uint8_t icmpType,
300 uint8_t icmpCode,
301 uint32_t icmpInfo)
302{
303 m_icmpType = icmpType;
304}
305
306void
307Ipv4FragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
308{
309 if (dataSize != m_dataSize)
310 {
311 delete[] m_data;
312 m_data = new uint8_t[dataSize];
313 m_dataSize = dataSize;
314 }
315
316 if (fillSize >= dataSize)
317 {
318 memcpy(m_data, fill, dataSize);
319 return;
320 }
321
322 uint32_t filled = 0;
323 while (filled + fillSize < dataSize)
324 {
325 memcpy(&m_data[filled], fill, fillSize);
326 filled += fillSize;
327 }
328
329 memcpy(&m_data[filled], fill, dataSize - filled);
330
331 m_size = dataSize;
332}
333
336{
337 Ptr<Packet> p;
338 if (m_dataSize)
339 {
340 p = Create<Packet>(m_data, m_dataSize);
341 }
342 else
343 {
344 p = Create<Packet>(m_size);
345 }
346 IPv4TestTag tag;
347 tag.SetToken(42);
348 p->AddPacketTag(tag);
349 p->AddByteTag(tag);
350
351 if (m_broadcast)
352 {
355 InetSocketAddress saddress = InetSocketAddress::ConvertFrom(address);
356 saddress.SetIpv4(Ipv4Address::GetBroadcast());
357 m_socketClient->SendTo(p, 0, saddress);
358 }
359 else
360 {
362 }
363
364 return p;
365}
366
367void
369{
370 // set the arp cache to something quite high
371 // we shouldn't need because the NetDevice used doesn't need arp, but still
372 Config::SetDefault("ns3::ArpCache::PendingQueueSize", UintegerValue(100));
373
374 // Create topology
375
376 // Receiver Node
377 Ptr<Node> serverNode = CreateObject<Node>();
378 // Sender Node
379 Ptr<Node> clientNode = CreateObject<Node>();
380
381 NodeContainer nodes(serverNode, clientNode);
382
383 Ptr<ErrorChannel> channel = CreateObject<ErrorChannel>();
384 channel->SetJumpingTime(Seconds(0.5));
385
386 SimpleNetDeviceHelper helperChannel;
387 helperChannel.SetNetDevicePointToPointMode(true);
388 NetDeviceContainer net = helperChannel.Install(nodes, channel);
389
390 InternetStackHelper internet;
391 internet.Install(nodes);
392
393 Ptr<Ipv4> ipv4;
394 uint32_t netdev_idx;
395 Ipv4InterfaceAddress ipv4Addr;
396
397 // Receiver Node
398 ipv4 = serverNode->GetObject<Ipv4>();
399 netdev_idx = ipv4->AddInterface(net.Get(0));
400 ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.0.1"), Ipv4Mask(0xffff0000U));
401 ipv4->AddAddress(netdev_idx, ipv4Addr);
402 ipv4->SetUp(netdev_idx);
403 Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel>();
404 Ptr<SimpleNetDevice> serverDev = DynamicCast<SimpleNetDevice>(net.Get(0));
405 serverDevErrorModel->Disable();
406 serverDev->SetMtu(1500);
407 serverDev->SetReceiveErrorModel(serverDevErrorModel);
408 StartServer(serverNode);
409
410 // Sender Node
411 ipv4 = clientNode->GetObject<Ipv4>();
412 netdev_idx = ipv4->AddInterface(net.Get(1));
413 ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.0.2"), Ipv4Mask(0xffff0000U));
414 ipv4->AddAddress(netdev_idx, ipv4Addr);
415 ipv4->SetUp(netdev_idx);
416 Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel>();
417 Ptr<SimpleNetDevice> clientDev = DynamicCast<SimpleNetDevice>(net.Get(1));
418 clientDevErrorModel->Disable();
419 clientDev->SetMtu(1500);
420 clientDev->SetReceiveErrorModel(clientDevErrorModel);
421 StartClient(clientNode);
422
423 // some small packets, some rather big ones
424 uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
425
426 // using the alphabet
427 uint8_t fillData[78];
428 for (uint32_t k = 48; k <= 125; k++)
429 {
430 fillData[k - 48] = k;
431 }
432
433 // First test: normal channel, no errors, no delays
434 for (int i = 0; i < 5; i++)
435 {
436 uint32_t packetSize = packetSizes[i];
437
438 SetFill(fillData, 78, packetSize);
439
440 m_receivedPacketServer = Create<Packet>();
441 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
442 Seconds(0),
444 this);
445 Simulator::Run();
446
447 uint8_t recvBuffer[65000];
448
449 uint16_t recvSize = m_receivedPacketServer->GetSize();
450
451 NS_TEST_EXPECT_MSG_EQ(recvSize, packetSizes[i], "Packet size not correct");
452
453 m_receivedPacketServer->CopyData(recvBuffer, 65000);
455 0,
456 "Packet content differs");
457 }
458
459 // Second test: normal channel, no errors, delays each 2 packets.
460 // Each other fragment will arrive out-of-order.
461 // The packets should be received correctly since reassembly will reorder the fragments.
462 channel->SetJumpingMode(true);
463 for (int i = 0; i < 5; i++)
464 {
465 uint32_t packetSize = packetSizes[i];
466
467 SetFill(fillData, 78, packetSize);
468
469 m_receivedPacketServer = Create<Packet>();
470 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
471 Seconds(0),
473 this);
474 Simulator::Run();
475
476 uint8_t recvBuffer[65000];
477
478 uint16_t recvSize = m_receivedPacketServer->GetSize();
479
480 NS_TEST_EXPECT_MSG_EQ(recvSize, packetSizes[i], "Packet size not correct");
481
482 m_receivedPacketServer->CopyData(recvBuffer, 65000);
484 0,
485 "Packet content differs");
486 }
487 channel->SetJumpingMode(false);
488
489 // Third test: normal channel, some errors, no delays.
490 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
491 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
492 // to the sender (if the first fragment has been received).
493 // In this test case the first fragment is received, so we do expect an ICMP.
494 // Client -> Server : errors enabled
495 // Server -> Client : errors disabled (we want to have back the ICMP)
496 clientDevErrorModel->Disable();
497 serverDevErrorModel->Enable();
498 for (int i = 1; i < 5; i++)
499 {
500 uint32_t packetSize = packetSizes[i];
501
502 SetFill(fillData, 78, packetSize);
503
504 // reset the model, we want to receive the very first fragment.
505 serverDevErrorModel->Reset();
506
507 m_receivedPacketServer = Create<Packet>();
508 m_icmpType = 0;
509 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
510 Seconds(0),
512 this);
513 Simulator::Run();
514
515 uint16_t recvSize = m_receivedPacketServer->GetSize();
516
517 NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
519 true,
520 "Client did not receive ICMP::TIME_EXCEEDED");
521 }
522
523 // Fourth test: normal channel, no errors, no delays.
524 // We check tags
525 clientDevErrorModel->Disable();
526 serverDevErrorModel->Disable();
527 for (int i = 0; i < 5; i++)
528 {
529 uint32_t packetSize = packetSizes[i];
530
531 SetFill(fillData, 78, packetSize);
532
533 m_receivedPacketServer = Create<Packet>();
534 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
535 Seconds(0),
537 this);
538 Simulator::Run();
539
540 IPv4TestTag packetTag;
541 bool found = m_receivedPacketServer->PeekPacketTag(packetTag);
542
543 NS_TEST_EXPECT_MSG_EQ(found, true, "PacketTag not found");
544 NS_TEST_EXPECT_MSG_EQ(packetTag.GetToken(), 42, "PacketTag value not correct");
545
547
548 uint32_t end = 0;
549 uint32_t tagStart = 0;
550 uint32_t tagEnd = 0;
551 while (iter.HasNext())
552 {
553 ByteTagIterator::Item item = iter.Next();
555 "ns3::IPv4TestTag",
556 "ByteTag name not correct");
557 tagStart = item.GetStart();
558 tagEnd = item.GetEnd();
559 if (end == 0)
560 {
561 NS_TEST_EXPECT_MSG_EQ(tagStart, 0, "First ByteTag Start not correct");
562 }
563 if (end != 0)
564 {
565 NS_TEST_EXPECT_MSG_EQ(tagStart, end, "ByteTag End not correct");
566 }
567 end = tagEnd;
568 IPv4TestTag* byteTag = dynamic_cast<IPv4TestTag*>(item.GetTypeId().GetConstructor()());
569 NS_TEST_EXPECT_MSG_NE(byteTag, 0, "ByteTag not found");
570 item.GetTag(*byteTag);
571 NS_TEST_EXPECT_MSG_EQ(byteTag->GetToken(), 42, "ByteTag value not correct");
572 delete byteTag;
573 }
575 }
576
577 Simulator::Destroy();
578}
579
587{
588 public:
590};
591
593 : TestSuite("ipv4-fragmentation", UNIT)
594{
595 AddTestCase(new Ipv4FragmentationTest(false), TestCase::QUICK);
596 AddTestCase(new Ipv4FragmentationTest(true), TestCase::QUICK);
597}
598
Tag used in IPv4 Fragmentation Test.
uint64_t GetToken()
Get the token.
static TypeId GetTypeId()
Get the type ID.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
uint32_t GetSerializedSize() const override
void SetToken(uint64_t token)
Set the token.
void Deserialize(TagBuffer buffer) override
uint64_t token
Token carried by the tag.
void Serialize(TagBuffer buffer) const override
void Print(std::ostream &os) const override
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()
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.
void HandleReadClient(Ptr< Socket > socket)
Handle incoming packets.
Ipv4FragmentationTest(bool broadcast)
Constructor.
void DoRun() override
Implementation to actually run this TestCase.
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:92
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:64
uint32_t GetEnd() const
The index is an offset from the start of the packet.
Definition: packet.cc:48
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:54
uint32_t GetStart() const
The index is an offset from the start of the packet.
Definition: packet.cc:42
TypeId GetTypeId() const
Definition: packet.cc:36
Iterator over the set of byte tags in a packet.
Definition: packet.h:57
bool HasNext() const
Definition: packet.cc:72
AttributeValue implementation for Callback.
Definition: callback.h:793
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:43
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:79
a class to store IPv4 address information on an interface
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:258
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() const
Definition: node.cc:117
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:258
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:400
Ptr< Packet > Copy() const
performs a COW copy of the packet.
Definition: packet.cc:131
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:979
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:934
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:1002
ByteTagIterator GetByteTagIterator() const
Returns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:956
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 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:126
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
virtual Ptr< Node > GetNode() const =0
Return the node this socket is associated with.
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:104
uint64_t ReadU64()
Definition: tag-buffer.cc:139
tag a set of bytes in a packet
Definition: tag.h:39
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:60
Callback< ObjectBase * > GetConstructor() const
Get the constructor callback.
Definition: type-id.cc:1088
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
std::string GetName() const
Get the name.
Definition: type-id.cc:995
A sockets interface to UDP.
Hold an unsigned integer type.
Definition: uinteger.h:45
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
#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:666
#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:251
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
static Ipv4FragmentationTestSuite g_ipv4fragmentationTestSuite
Static variable for test initialization.
NodeContainer nodes
address
Definition: first.py:40
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:691
STL namespace.
channel
Definition: third.py:81
static const uint32_t packetSize
Packet size generated at the AP.