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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
7 */
8/**
9 * This is the test code for ipv4-l3protocol.cc (only the fragmentation and reassembly part).
10 */
11
12#include "ns3/arp-l3-protocol.h"
13#include "ns3/boolean.h"
14#include "ns3/config.h"
15#include "ns3/error-channel.h"
16#include "ns3/icmpv4-l4-protocol.h"
17#include "ns3/inet-socket-address.h"
18#include "ns3/internet-stack-helper.h"
19#include "ns3/ipv4-l3-protocol.h"
20#include "ns3/ipv4-list-routing.h"
21#include "ns3/ipv4-raw-socket-factory.h"
22#include "ns3/ipv4-static-routing.h"
23#include "ns3/log.h"
24#include "ns3/node.h"
25#include "ns3/simple-net-device-helper.h"
26#include "ns3/simple-net-device.h"
27#include "ns3/simulator.h"
28#include "ns3/socket-factory.h"
29#include "ns3/socket.h"
30#include "ns3/test.h"
31#include "ns3/udp-l4-protocol.h"
32#include "ns3/udp-socket-factory.h"
33#include "ns3/udp-socket.h"
34#include "ns3/uinteger.h"
35
36#ifdef __WIN32__
37#include "ns3/win32-internet.h"
38#else
39#include <netinet/in.h>
40#endif
41
42#include <limits>
43#include <string>
44
45using namespace ns3;
46
47class UdpSocketImpl;
48
49/**
50 * \ingroup internet-test
51 *
52 * \brief Tag used in IPv4 Fragmentation Test
53 */
54class IPv4TestTag : public Tag
55{
56 private:
57 uint64_t token; //!< Token carried by the tag.
58 public:
59 /**
60 * \brief Get the type ID.
61 * \return the object TypeId
62 */
64 {
65 static TypeId tid =
66 TypeId("ns3::IPv4TestTag").SetParent<Tag>().AddConstructor<IPv4TestTag>();
67 return tid;
68 }
69
70 TypeId GetInstanceTypeId() const override
71 {
72 return GetTypeId();
73 }
74
75 uint32_t GetSerializedSize() const override
76 {
77 return sizeof(token);
78 }
79
80 void Serialize(TagBuffer buffer) const override
81 {
82 buffer.WriteU64(token);
83 }
84
85 void Deserialize(TagBuffer buffer) override
86 {
87 token = buffer.ReadU64();
88 }
89
90 void Print(std::ostream& os) const override
91 {
92 os << "token=" << token;
93 }
94
95 /**
96 * \brief Set the token.
97 * \param token The token.
98 */
99 void SetToken(uint64_t token)
100 {
101 this->token = token;
102 }
103
104 /**
105 * \brief Get the token.
106 * \returns The token.
107 */
108 uint64_t GetToken() const
109 {
110 return token;
111 }
112};
113
114/**
115 * \ingroup internet-test
116 *
117 * \brief IPv4 Fragmentation Test
118 */
120{
121 Ptr<Packet> m_sentPacketClient; //!< Packet sent by client.
122 Ptr<Packet> m_receivedPacketClient; //!< Packet received by client.
123 Ptr<Packet> m_receivedPacketServer; //!< Packet received by server.
124
125 Ptr<Socket> m_socketServer; //!< Server socket.
126 Ptr<Socket> m_socketClient; //!< Client socket.
127 uint32_t m_dataSize; //!< Data size.
128 uint8_t* m_data; //!< Data.
129 uint32_t m_size; //!< packet size.
130 uint8_t m_icmpType; //!< ICMP type.
131 bool m_broadcast; //!< broadcast packets
132
133 public:
134 void DoRun() override;
135 /**
136 * Constructor
137 * \param broadcast send broadcast packets (true) or unicast packets (false)
138 */
139 Ipv4FragmentationTest(bool broadcast);
140 ~Ipv4FragmentationTest() override;
141
142 // server part
143
144 /**
145 * \brief Start the server.
146 * \param ServerNode The server.
147 */
148 void StartServer(Ptr<Node> ServerNode);
149 /**
150 * \brief Handle incoming packets.
151 * \param socket The receiving socket.
152 */
153 void HandleReadServer(Ptr<Socket> socket);
154
155 // client part
156
157 /**
158 * \brief Start the client.
159 * \param ClientNode The client.
160 */
161 void StartClient(Ptr<Node> ClientNode);
162 /**
163 * \brief Handle incoming packets.
164 * \param socket The receiving socket.
165 */
166 void HandleReadClient(Ptr<Socket> socket);
167 /**
168 * \brief Handle incoming ICMP packets.
169 * \param icmpSource The ICMP sender.
170 * \param icmpTtl The ICMP TTL.
171 * \param icmpType The ICMP Type.
172 * \param icmpCode The ICMP Code.
173 * \param icmpInfo The ICMP Info.
174 */
175 void HandleReadIcmpClient(Ipv4Address icmpSource,
176 uint8_t icmpTtl,
177 uint8_t icmpType,
178 uint8_t icmpCode,
179 uint32_t icmpInfo);
180
181 /**
182 * \brief Set the packet fill.
183 * \param fill The fill.
184 * \param fillSize The fill size.
185 * \param dataSize The packet size.
186 */
187 void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
188
189 /**
190 * \brief Send a packet.
191 * \returns The sent packet.
192 */
194};
195
197 : TestCase(std::string("Verify the IPv4 layer 3 protocol fragmentation and reassembly: ") +
198 (broadcast ? "broadcast" : "unicast"))
199{
200 m_socketServer = nullptr;
201 m_data = nullptr;
202 m_dataSize = 0;
203 m_size = 0;
204 m_icmpType = 0;
205 m_broadcast = broadcast;
206}
207
209{
210 if (m_data)
211 {
212 delete[] m_data;
213 }
214 m_data = nullptr;
215 m_dataSize = 0;
216}
217
218void
220{
221 if (!m_socketServer)
222 {
223 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
224 m_socketServer = Socket::CreateSocket(ServerNode, tid);
226 m_socketServer->Bind(local);
228 if (udpSocket)
229 {
230 // equivalent to setsockopt (MCAST_JOIN_GROUP)
231 udpSocket->MulticastJoinGroup(0, Ipv4Address("10.0.0.1"));
232 }
233 }
234
236}
237
238void
240{
241 Ptr<Packet> packet;
242 Address from;
243 while ((packet = socket->RecvFrom(from)))
244 {
246 {
247 m_receivedPacketServer = packet->Copy();
248 }
249 }
250}
251
252void
268
269void
271{
272 Ptr<Packet> packet;
273 Address from;
274 while ((packet = socket->RecvFrom(from)))
275 {
277 {
278 m_receivedPacketClient = packet->Copy();
279 }
280 }
281}
282
283void
285 uint8_t icmpTtl,
286 uint8_t icmpType,
287 uint8_t icmpCode,
288 uint32_t icmpInfo)
289{
290 m_icmpType = icmpType;
291}
292
293void
294Ipv4FragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
295{
296 if (dataSize != m_dataSize)
297 {
298 delete[] m_data;
299 m_data = new uint8_t[dataSize];
300 m_dataSize = dataSize;
301 }
302
303 if (fillSize >= dataSize)
304 {
305 memcpy(m_data, fill, dataSize);
306 return;
307 }
308
309 uint32_t filled = 0;
310 while (filled + fillSize < dataSize)
311 {
312 memcpy(&m_data[filled], fill, fillSize);
313 filled += fillSize;
314 }
315
316 memcpy(&m_data[filled], fill, dataSize - filled);
317
318 m_size = dataSize;
319}
320
323{
324 Ptr<Packet> p;
325 if (m_dataSize)
326 {
328 }
329 else
330 {
332 }
333 IPv4TestTag tag;
334 tag.SetToken(42);
335 p->AddPacketTag(tag);
336 p->AddByteTag(tag);
337
338 if (m_broadcast)
339 {
340 Address address;
341 m_socketClient->GetPeerName(address);
344 m_socketClient->SendTo(p, 0, saddress);
345 }
346 else
347 {
349 }
350
351 return p;
352}
353
354void
356{
357 // set the arp cache to something quite high
358 // we shouldn't need because the NetDevice used doesn't need arp, but still
359 Config::SetDefault("ns3::ArpCache::PendingQueueSize", UintegerValue(100));
360
361 // Create topology
362
363 // Receiver Node
364 Ptr<Node> serverNode = CreateObject<Node>();
365 // Sender Node
366 Ptr<Node> clientNode = CreateObject<Node>();
367
368 NodeContainer nodes(serverNode, clientNode);
369
371 channel->SetJumpingTime(Seconds(0.5));
372
373 SimpleNetDeviceHelper helperChannel;
374 helperChannel.SetNetDevicePointToPointMode(true);
375 NetDeviceContainer net = helperChannel.Install(nodes, channel);
376
377 InternetStackHelper internet;
378 internet.Install(nodes);
379
380 Ptr<Ipv4> ipv4;
381 uint32_t netdev_idx;
382 Ipv4InterfaceAddress ipv4Addr;
383
384 // Receiver Node
385 ipv4 = serverNode->GetObject<Ipv4>();
386 netdev_idx = ipv4->AddInterface(net.Get(0));
387 ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.0.1"), Ipv4Mask(0xffff0000U));
388 ipv4->AddAddress(netdev_idx, ipv4Addr);
389 ipv4->SetUp(netdev_idx);
392 serverDevErrorModel->Disable();
393 serverDev->SetMtu(1500);
394 serverDev->SetReceiveErrorModel(serverDevErrorModel);
395 StartServer(serverNode);
396
397 // Sender Node
398 ipv4 = clientNode->GetObject<Ipv4>();
399 netdev_idx = ipv4->AddInterface(net.Get(1));
400 ipv4Addr = Ipv4InterfaceAddress(Ipv4Address("10.0.0.2"), Ipv4Mask(0xffff0000U));
401 ipv4->AddAddress(netdev_idx, ipv4Addr);
402 ipv4->SetUp(netdev_idx);
405 clientDevErrorModel->Disable();
406 clientDev->SetMtu(1500);
407 clientDev->SetReceiveErrorModel(clientDevErrorModel);
408 StartClient(clientNode);
409
410 // some small packets, some rather big ones
411 uint32_t packetSizes[5] = {1000, 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
429 Seconds(0),
431 this);
433
434 uint8_t recvBuffer[65000];
435
436 uint16_t recvSize = m_receivedPacketServer->GetSize();
437
438 NS_TEST_EXPECT_MSG_EQ(recvSize, packetSizes[i], "Packet size not correct");
439
440 m_receivedPacketServer->CopyData(recvBuffer, 65000);
442 0,
443 "Packet content differs");
444 }
445
446 // Second test: normal channel, no errors, delays each 2 packets.
447 // Each other fragment will arrive out-of-order.
448 // The packets should be received correctly since reassembly will reorder the fragments.
449 channel->SetJumpingMode(true);
450 for (int i = 0; i < 5; i++)
451 {
452 uint32_t packetSize = packetSizes[i];
453
454 SetFill(fillData, 78, packetSize);
455
458 Seconds(0),
460 this);
462
463 uint8_t recvBuffer[65000];
464
465 uint16_t recvSize = m_receivedPacketServer->GetSize();
466
467 NS_TEST_EXPECT_MSG_EQ(recvSize, packetSizes[i], "Packet size not correct");
468
469 m_receivedPacketServer->CopyData(recvBuffer, 65000);
471 0,
472 "Packet content differs");
473 }
474 channel->SetJumpingMode(false);
475
476 // Third test: normal channel, some errors, no delays.
477 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
478 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
479 // to the sender (if the first fragment has been received).
480 // In this test case the first fragment is received, so we do expect an ICMP.
481 // Client -> Server : errors enabled
482 // Server -> Client : errors disabled (we want to have back the ICMP)
483 clientDevErrorModel->Disable();
484 serverDevErrorModel->Enable();
485 for (int i = 1; i < 5; i++)
486 {
487 uint32_t packetSize = packetSizes[i];
488
489 SetFill(fillData, 78, packetSize);
490
491 // reset the model, we want to receive the very first fragment.
492 serverDevErrorModel->Reset();
493
495 m_icmpType = 0;
497 Seconds(0),
499 this);
501
502 uint16_t recvSize = m_receivedPacketServer->GetSize();
503
504 NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
506 true,
507 "Client did not receive ICMP::TIME_EXCEEDED");
508 }
509
510 // Fourth test: normal channel, no errors, no delays.
511 // We check tags
512 clientDevErrorModel->Disable();
513 serverDevErrorModel->Disable();
514 for (int i = 0; i < 5; i++)
515 {
516 uint32_t packetSize = packetSizes[i];
517
518 SetFill(fillData, 78, packetSize);
519
522 Seconds(0),
524 this);
526
527 IPv4TestTag packetTag;
528 bool found = m_receivedPacketServer->PeekPacketTag(packetTag);
529
530 NS_TEST_EXPECT_MSG_EQ(found, true, "PacketTag not found");
531 NS_TEST_EXPECT_MSG_EQ(packetTag.GetToken(), 42, "PacketTag value not correct");
532
534
535 uint32_t end = 0;
536 uint32_t tagStart = 0;
537 uint32_t tagEnd = 0;
538 while (iter.HasNext())
539 {
540 ByteTagIterator::Item item = iter.Next();
542 "ns3::IPv4TestTag",
543 "ByteTag name not correct");
544 tagStart = item.GetStart();
545 tagEnd = item.GetEnd();
546 if (end == 0)
547 {
548 NS_TEST_EXPECT_MSG_EQ(tagStart, 0, "First ByteTag Start not correct");
549 }
550 if (end != 0)
551 {
552 NS_TEST_EXPECT_MSG_EQ(tagStart, end, "ByteTag End not correct");
553 }
554 end = tagEnd;
555 IPv4TestTag* byteTag = dynamic_cast<IPv4TestTag*>(item.GetTypeId().GetConstructor()());
556 NS_TEST_EXPECT_MSG_NE(byteTag, 0, "ByteTag not found");
557 item.GetTag(*byteTag);
558 NS_TEST_EXPECT_MSG_EQ(byteTag->GetToken(), 42, "ByteTag value not correct");
559 delete byteTag;
560 }
562 }
563
565}
566
567/**
568 * \ingroup internet-test
569 *
570 * \brief IPv4 Fragmentation TestSuite
571 */
573{
574 public:
576};
577
579 : TestSuite("ipv4-fragmentation", Type::UNIT)
580{
581 AddTestCase(new Ipv4FragmentationTest(false), TestCase::Duration::QUICK);
582 AddTestCase(new Ipv4FragmentationTest(true), TestCase::Duration::QUICK);
583}
584
586 g_ipv4fragmentationTestSuite; //!< Static variable for test initialization
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:90
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition packet.h:52
uint32_t GetEnd() const
The index is an offset from the start of the packet.
Definition packet.cc:37
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition packet.cc:43
uint32_t GetStart() const
The index is an offset from the start of the packet.
Definition packet.cc:31
TypeId GetTypeId() const
Definition packet.cc:25
Iterator over the set of byte tags in a packet.
Definition packet.h:45
bool HasNext() const
Definition packet.cc:61
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.
static Ipv4Address GetBroadcast()
static Ipv4Address GetAny()
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
a class to store IPv4 address information on an interface
a class to represent an Ipv4 address mask
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:106
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition packet.h:850
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition packet.cc:389
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition packet.cc:972
ByteTagIterator GetByteTagIterator() const
Returns an iterator over the set of byte tags included in this packet.
Definition packet.cc:926
Smart pointer class similar to boost::intrusive_ptr.
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:131
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition simulator.h:577
static void Run()
Run the simulation.
Definition simulator.cc:167
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:117
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:61
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:41
void WriteU64(uint64_t v)
Definition tag-buffer.cc:93
uint64_t ReadU64()
tag a set of bytes in a packet
Definition tag.h:28
encapsulates test code
Definition test.h:1050
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:292
A suite of tests to run.
Definition test.h:1267
Type
Type of test.
Definition test.h:1274
a unique identifier for an interface.
Definition type-id.h:48
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:872
Callback< ObjectBase * > GetConstructor() const
Get the constructor callback.
Definition type-id.cc:1154
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
std::string GetName() const
Get the name.
Definition type-id.cc:1061
A sockets interface to UDP.
Hold an unsigned integer type.
Definition uinteger.h:34
void SetDefault(std::string name, const AttributeValue &value)
Definition config.cc:883
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
#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:656
#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:241
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
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:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
STL namespace.
static const uint32_t packetSize
Packet size generated at the AP.