A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
65class IPv4TestTag : public Tag
66{
67 private:
68 uint64_t token;
69 public:
75 {
76 static TypeId tid =
77 TypeId("ns3::IPv4TestTag").SetParent<Tag>().AddConstructor<IPv4TestTag>();
78 return tid;
79 }
80
81 TypeId GetInstanceTypeId() const override
82 {
83 return GetTypeId();
84 }
85
86 uint32_t GetSerializedSize() const override
87 {
88 return sizeof(token);
89 }
90
91 void Serialize(TagBuffer buffer) const override
92 {
93 buffer.WriteU64(token);
94 }
95
96 void Deserialize(TagBuffer buffer) override
97 {
98 token = buffer.ReadU64();
99 }
100
101 void Print(std::ostream& os) const override
102 {
103 os << "token=" << token;
104 }
105
110 void SetToken(uint64_t token)
111 {
112 this->token = token;
113 }
114
119 uint64_t GetToken() const
120 {
121 return token;
122 }
123};
124
131{
135
139 uint8_t* m_data;
141 uint8_t m_icmpType;
143
144 public:
145 void DoRun() override;
150 Ipv4FragmentationTest(bool broadcast);
151 ~Ipv4FragmentationTest() override;
152
153 // server part
154
159 void StartServer(Ptr<Node> ServerNode);
164 void HandleReadServer(Ptr<Socket> socket);
165
166 // client part
167
172 void StartClient(Ptr<Node> ClientNode);
177 void HandleReadClient(Ptr<Socket> socket);
186 void HandleReadIcmpClient(Ipv4Address icmpSource,
187 uint8_t icmpTtl,
188 uint8_t icmpType,
189 uint8_t icmpCode,
190 uint32_t icmpInfo);
191
198 void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
199
205};
206
208 : TestCase(std::string("Verify the IPv4 layer 3 protocol fragmentation and reassembly: ") +
209 (broadcast ? "broadcast" : "unicast"))
210{
211 m_socketServer = nullptr;
212 m_data = nullptr;
213 m_dataSize = 0;
214 m_size = 0;
215 m_icmpType = 0;
216 m_broadcast = broadcast;
217}
218
220{
221 if (m_data)
222 {
223 delete[] m_data;
224 }
225 m_data = nullptr;
226 m_dataSize = 0;
227}
228
229void
231{
232 if (!m_socketServer)
233 {
234 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
235 m_socketServer = Socket::CreateSocket(ServerNode, tid);
237 m_socketServer->Bind(local);
238 Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketServer);
239 if (udpSocket)
240 {
241 // equivalent to setsockopt (MCAST_JOIN_GROUP)
242 udpSocket->MulticastJoinGroup(0, Ipv4Address("10.0.0.1"));
243 }
244 }
245
247}
248
249void
251{
252 Ptr<Packet> packet;
253 Address from;
254 while ((packet = socket->RecvFrom(from)))
255 {
257 {
258 m_receivedPacketServer = packet->Copy();
259 }
260 }
261}
262
263void
265{
266 if (!m_socketClient)
267 {
268 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
269 m_socketClient = Socket::CreateSocket(ClientNode, tid);
273 m_socketClient->SetAttribute("IcmpCallback", cbValue);
275 }
276
278}
279
280void
282{
283 Ptr<Packet> packet;
284 Address from;
285 while ((packet = socket->RecvFrom(from)))
286 {
288 {
289 m_receivedPacketClient = packet->Copy();
290 }
291 }
292}
293
294void
296 uint8_t icmpTtl,
297 uint8_t icmpType,
298 uint8_t icmpCode,
299 uint32_t icmpInfo)
300{
301 m_icmpType = icmpType;
302}
303
304void
305Ipv4FragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
306{
307 if (dataSize != m_dataSize)
308 {
309 delete[] m_data;
310 m_data = new uint8_t[dataSize];
311 m_dataSize = dataSize;
312 }
313
314 if (fillSize >= dataSize)
315 {
316 memcpy(m_data, fill, dataSize);
317 return;
318 }
319
320 uint32_t filled = 0;
321 while (filled + fillSize < dataSize)
322 {
323 memcpy(&m_data[filled], fill, fillSize);
324 filled += fillSize;
325 }
326
327 memcpy(&m_data[filled], fill, dataSize - filled);
328
329 m_size = dataSize;
330}
331
334{
335 Ptr<Packet> p;
336 if (m_dataSize)
337 {
338 p = Create<Packet>(m_data, m_dataSize);
339 }
340 else
341 {
342 p = Create<Packet>(m_size);
343 }
344 IPv4TestTag tag;
345 tag.SetToken(42);
346 p->AddPacketTag(tag);
347 p->AddByteTag(tag);
348
349 if (m_broadcast)
350 {
351 Address address;
352 m_socketClient->GetPeerName(address);
355 m_socketClient->SendTo(p, 0, saddress);
356 }
357 else
358 {
360 }
361
362 return p;
363}
364
365void
367{
368 // set the arp cache to something quite high
369 // we shouldn't need because the NetDevice used doesn't need arp, but still
370 Config::SetDefault("ns3::ArpCache::PendingQueueSize", UintegerValue(100));
371
372 // Create topology
373
374 // Receiver Node
375 Ptr<Node> serverNode = CreateObject<Node>();
376 // Sender Node
377 Ptr<Node> clientNode = CreateObject<Node>();
378
379 NodeContainer nodes(serverNode, clientNode);
380
381 Ptr<ErrorChannel> channel = CreateObject<ErrorChannel>();
382 channel->SetJumpingTime(Seconds(0.5));
383
384 SimpleNetDeviceHelper helperChannel;
385 helperChannel.SetNetDevicePointToPointMode(true);
386 NetDeviceContainer net = helperChannel.Install(nodes, channel);
387
388 InternetStackHelper internet;
389 internet.Install(nodes);
390
391 Ptr<Ipv4> ipv4;
392 uint32_t netdev_idx;
393 Ipv4InterfaceAddress ipv4Addr;
394
395 // Receiver Node
396 ipv4 = serverNode->GetObject<Ipv4>();
397 netdev_idx = ipv4->AddInterface(net.Get(0));
398 ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.0.1"), Ipv4Mask(0xffff0000U));
399 ipv4->AddAddress(netdev_idx, ipv4Addr);
400 ipv4->SetUp(netdev_idx);
401 Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel>();
402 Ptr<SimpleNetDevice> serverDev = DynamicCast<SimpleNetDevice>(net.Get(0));
403 serverDevErrorModel->Disable();
404 serverDev->SetMtu(1500);
405 serverDev->SetReceiveErrorModel(serverDevErrorModel);
406 StartServer(serverNode);
407
408 // Sender Node
409 ipv4 = clientNode->GetObject<Ipv4>();
410 netdev_idx = ipv4->AddInterface(net.Get(1));
411 ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.0.2"), Ipv4Mask(0xffff0000U));
412 ipv4->AddAddress(netdev_idx, ipv4Addr);
413 ipv4->SetUp(netdev_idx);
414 Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel>();
415 Ptr<SimpleNetDevice> clientDev = DynamicCast<SimpleNetDevice>(net.Get(1));
416 clientDevErrorModel->Disable();
417 clientDev->SetMtu(1500);
418 clientDev->SetReceiveErrorModel(clientDevErrorModel);
419 StartClient(clientNode);
420
421 // some small packets, some rather big ones
422 uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
423
424 // using the alphabet
425 uint8_t fillData[78];
426 for (uint32_t k = 48; k <= 125; k++)
427 {
428 fillData[k - 48] = k;
429 }
430
431 // First test: normal channel, no errors, no delays
432 for (int i = 0; i < 5; i++)
433 {
434 uint32_t packetSize = packetSizes[i];
435
436 SetFill(fillData, 78, packetSize);
437
438 m_receivedPacketServer = Create<Packet>();
440 Seconds(0),
442 this);
444
445 uint8_t recvBuffer[65000];
446
447 uint16_t recvSize = m_receivedPacketServer->GetSize();
448
449 NS_TEST_EXPECT_MSG_EQ(recvSize, packetSizes[i], "Packet size not correct");
450
451 m_receivedPacketServer->CopyData(recvBuffer, 65000);
453 0,
454 "Packet content differs");
455 }
456
457 // Second test: normal channel, no errors, delays each 2 packets.
458 // Each other fragment will arrive out-of-order.
459 // The packets should be received correctly since reassembly will reorder the fragments.
460 channel->SetJumpingMode(true);
461 for (int i = 0; i < 5; i++)
462 {
463 uint32_t packetSize = packetSizes[i];
464
465 SetFill(fillData, 78, packetSize);
466
467 m_receivedPacketServer = Create<Packet>();
469 Seconds(0),
471 this);
473
474 uint8_t recvBuffer[65000];
475
476 uint16_t recvSize = m_receivedPacketServer->GetSize();
477
478 NS_TEST_EXPECT_MSG_EQ(recvSize, packetSizes[i], "Packet size not correct");
479
480 m_receivedPacketServer->CopyData(recvBuffer, 65000);
482 0,
483 "Packet content differs");
484 }
485 channel->SetJumpingMode(false);
486
487 // Third test: normal channel, some errors, no delays.
488 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
489 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
490 // to the sender (if the first fragment has been received).
491 // In this test case the first fragment is received, so we do expect an ICMP.
492 // Client -> Server : errors enabled
493 // Server -> Client : errors disabled (we want to have back the ICMP)
494 clientDevErrorModel->Disable();
495 serverDevErrorModel->Enable();
496 for (int i = 1; i < 5; i++)
497 {
498 uint32_t packetSize = packetSizes[i];
499
500 SetFill(fillData, 78, packetSize);
501
502 // reset the model, we want to receive the very first fragment.
503 serverDevErrorModel->Reset();
504
505 m_receivedPacketServer = Create<Packet>();
506 m_icmpType = 0;
508 Seconds(0),
510 this);
512
513 uint16_t recvSize = m_receivedPacketServer->GetSize();
514
515 NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
517 true,
518 "Client did not receive ICMP::TIME_EXCEEDED");
519 }
520
521 // Fourth test: normal channel, no errors, no delays.
522 // We check tags
523 clientDevErrorModel->Disable();
524 serverDevErrorModel->Disable();
525 for (int i = 0; i < 5; i++)
526 {
527 uint32_t packetSize = packetSizes[i];
528
529 SetFill(fillData, 78, packetSize);
530
531 m_receivedPacketServer = Create<Packet>();
533 Seconds(0),
535 this);
537
538 IPv4TestTag packetTag;
539 bool found = m_receivedPacketServer->PeekPacketTag(packetTag);
540
541 NS_TEST_EXPECT_MSG_EQ(found, true, "PacketTag not found");
542 NS_TEST_EXPECT_MSG_EQ(packetTag.GetToken(), 42, "PacketTag value not correct");
543
545
546 uint32_t end = 0;
547 uint32_t tagStart = 0;
548 uint32_t tagEnd = 0;
549 while (iter.HasNext())
550 {
551 ByteTagIterator::Item item = iter.Next();
553 "ns3::IPv4TestTag",
554 "ByteTag name not correct");
555 tagStart = item.GetStart();
556 tagEnd = item.GetEnd();
557 if (end == 0)
558 {
559 NS_TEST_EXPECT_MSG_EQ(tagStart, 0, "First ByteTag Start not correct");
560 }
561 if (end != 0)
562 {
563 NS_TEST_EXPECT_MSG_EQ(tagStart, end, "ByteTag End not correct");
564 }
565 end = tagEnd;
566 IPv4TestTag* byteTag = dynamic_cast<IPv4TestTag*>(item.GetTypeId().GetConstructor()());
567 NS_TEST_EXPECT_MSG_NE(byteTag, 0, "ByteTag not found");
568 item.GetTag(*byteTag);
569 NS_TEST_EXPECT_MSG_EQ(byteTag->GetToken(), 42, "ByteTag value not correct");
570 delete byteTag;
571 }
573 }
574
576}
577
584{
585 public:
587};
588
590 : TestSuite("ipv4-fragmentation", UNIT)
591{
594}
595
Tag used in IPv4 Fragmentation Test.
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
uint64_t GetToken() const
Get the token.
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:100
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:63
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:56
bool HasNext() const
Definition: packet.cc:72
AttributeValue implementation for Callback.
Definition: callback.h:804
an Inet address class
void SetIpv4(Ipv4Address address)
static bool IsMatchingType(const Address &address)
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
aggregate IP/TCP/UDP functionality to existing Nodes.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
static Ipv4Address GetBroadcast()
static Ipv4Address GetAny()
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:257
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:200
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:400
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
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
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...
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition: simulator.h:587
static void Run()
Run the simulation.
Definition: simulator.cc:176
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
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
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition: socket.cc:72
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
@ QUICK
Fast test.
Definition: test.h:1065
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:59
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:840
Callback< ObjectBase * > GetConstructor() const
Get the constructor callback.
Definition: type-id.cc:1089
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
std::string GetName() const
Get the name.
Definition: type-id.cc:996
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:1336
static Ipv4FragmentationTestSuite g_ipv4fragmentationTestSuite
Static variable for test initialization.
NodeContainer nodes
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:702
STL namespace.
static const uint32_t packetSize
Packet size generated at the AP.