A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ipv6-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 * \file
10 *
11 * This is the test code for ipv6-l3protocol.cc (only the fragmentation and reassembly part).
12 */
13
14#include "ns3/arp-l3-protocol.h"
15#include "ns3/boolean.h"
16#include "ns3/config.h"
17#include "ns3/error-channel.h"
18#include "ns3/icmpv4-l4-protocol.h"
19#include "ns3/icmpv6-l4-protocol.h"
20#include "ns3/inet-socket-address.h"
21#include "ns3/inet6-socket-address.h"
22#include "ns3/internet-stack-helper.h"
23#include "ns3/ipv4-l3-protocol.h"
24#include "ns3/ipv4-list-routing.h"
25#include "ns3/ipv4-raw-socket-factory.h"
26#include "ns3/ipv4-static-routing.h"
27#include "ns3/ipv6-l3-protocol.h"
28#include "ns3/ipv6-list-routing.h"
29#include "ns3/ipv6-raw-socket-factory.h"
30#include "ns3/ipv6-static-routing.h"
31#include "ns3/log.h"
32#include "ns3/node.h"
33#include "ns3/simple-net-device.h"
34#include "ns3/simulator.h"
35#include "ns3/socket-factory.h"
36#include "ns3/socket.h"
37#include "ns3/test.h"
38#include "ns3/traffic-control-layer.h"
39#include "ns3/udp-l4-protocol.h"
40#include "ns3/udp-socket-factory.h"
41#include "ns3/udp-socket.h"
42#include "ns3/uinteger.h"
43
44#ifdef __WIN32__
45#include "ns3/win32-internet.h"
46#else
47#include <netinet/in.h>
48#endif
49
50#include <limits>
51#include <string>
52
53using namespace ns3;
54
55class UdpSocketImpl;
56
57/**
58 * \ingroup internet-test
59 *
60 * \brief Tag used in IPv6 Fragmentation Test
61 */
62class IPv6TestTag : public Tag
63{
64 private:
65 uint64_t token; //!< Token carried by the tag.
66 public:
67 /**
68 * \brief Get the type ID.
69 * \return the object TypeId
70 */
72 {
73 static TypeId tid =
74 TypeId("ns3::IPv6TestTag").SetParent<Tag>().AddConstructor<IPv6TestTag>();
75 return tid;
76 }
77
78 TypeId GetInstanceTypeId() const override
79 {
80 return GetTypeId();
81 }
82
83 uint32_t GetSerializedSize() const override
84 {
85 return sizeof(token);
86 }
87
88 void Serialize(TagBuffer buffer) const override
89 {
90 buffer.WriteU64(token);
91 }
92
93 void Deserialize(TagBuffer buffer) override
94 {
95 token = buffer.ReadU64();
96 }
97
98 void Print(std::ostream& os) const override
99 {
100 os << "token=" << token;
101 }
102
103 /**
104 * \brief Set the token.
105 * \param token The token.
106 */
107 void SetToken(uint64_t token)
108 {
109 this->token = token;
110 }
111
112 /**
113 * \brief Get the token.
114 * \returns The token.
115 */
116 uint64_t GetToken() const
117 {
118 return token;
119 }
120};
121
122/**
123 * \ingroup internet-test
124 *
125 * \brief IPv6 Fragmentation Test
126 */
128{
129 Ptr<Packet> m_sentPacketClient; //!< Packet sent by client.
130 Ptr<Packet> m_receivedPacketClient; //!< Packet received by client.
131 Ptr<Packet> m_receivedPacketServer; //!< Packet received by server.
132
133 Ptr<Socket> m_socketServer; //!< Server socket.
134 Ptr<Socket> m_socketClient; //!< Client socket.
135 uint32_t m_dataSize; //!< Data size.
136 uint8_t* m_data; //!< Data.
137 uint32_t m_size; //!< packet size.
138 uint8_t m_icmpType; //!< ICMP type.
139 uint8_t m_icmpCode; //!< ICMP code.
140
141 public:
142 void DoRun() override;
144 ~Ipv6FragmentationTest() override;
145
146 // server part
147
148 /**
149 * \brief Start the server.
150 * \param ServerNode The server.
151 */
152 void StartServer(Ptr<Node> ServerNode);
153 /**
154 * \brief Handle incoming packets.
155 * \param socket The receiving socket.
156 */
157 void HandleReadServer(Ptr<Socket> socket);
158
159 // client part
160
161 /**
162 * \brief Start the client.
163 * \param ClientNode The client.
164 */
165 void StartClient(Ptr<Node> ClientNode);
166 /**
167 * \brief Handle incoming packets.
168 * \param socket The receiving socket.
169 */
170 void HandleReadClient(Ptr<Socket> socket);
171 /**
172 * \brief Handle incoming ICMP packets.
173 * \param icmpSource The ICMP sender.
174 * \param icmpTtl The ICMP TTL.
175 * \param icmpType The ICMP Type.
176 * \param icmpCode The ICMP Code.
177 * \param icmpInfo The ICMP Info.
178 */
179 void HandleReadIcmpClient(Ipv6Address icmpSource,
180 uint8_t icmpTtl,
181 uint8_t icmpType,
182 uint8_t icmpCode,
183 uint32_t icmpInfo);
184
185 /**
186 * \brief Set the packet fill.
187 * \param fill The fill.
188 * \param fillSize The fill size.
189 * \param dataSize The packet size.
190 */
191 void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
192
193 /**
194 * \brief Send a packet.
195 * \returns The sent packet.
196 */
198
199 /**
200 * \brief Handle Server's incoming packets.
201 * Ensure no packet greater than MTU is received
202 *
203 * \param packet the packet.
204 * \param ipv6 the Ipv6 protocol.
205 * \param interface the IP-level interface index.
206 */
207 void HandleServerRx(Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
208
209 /**
210 * \brief Handle Client's transmitting packets.
211 * Ensure no packet greater than MTU is transmitted
212 *
213 * \param packet the packet.
214 * \param ipv6 the Ipv6 protocol.
215 * \param interface the IP-level interface index.
216 */
217 void HandleClientTx(Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
218};
219
221 : TestCase("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
222{
223 m_socketServer = nullptr;
224 m_data = nullptr;
225 m_dataSize = 0;
226 m_size = 0;
227 m_icmpType = 0;
228 m_icmpCode = 0;
229}
230
232{
233 if (m_data)
234 {
235 delete[] m_data;
236 }
237 m_data = nullptr;
238 m_dataSize = 0;
239}
240
241void
255
256void
258{
259 Ptr<Packet> packet;
260 Address from;
261 while ((packet = socket->RecvFrom(from)))
262 {
264 {
265 m_receivedPacketServer = packet->Copy();
266 }
267 }
268}
269
270void
285
286void
288{
289 Ptr<Packet> packet;
290 Address from;
291 while ((packet = socket->RecvFrom(from)))
292 {
294 {
295 m_receivedPacketClient = packet->Copy();
296 }
297 }
298}
299
300void
302 uint8_t icmpTtl,
303 uint8_t icmpType,
304 uint8_t icmpCode,
305 uint32_t icmpInfo)
306{
307 m_icmpType = icmpType;
308 m_icmpCode = icmpCode;
309}
310
311void
312Ipv6FragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
313{
314 if (dataSize != m_dataSize)
315 {
316 delete[] m_data;
317 m_data = new uint8_t[dataSize];
318 m_dataSize = dataSize;
319 }
320
321 if (fillSize >= dataSize)
322 {
323 memcpy(m_data, fill, dataSize);
324 return;
325 }
326
327 uint32_t filled = 0;
328 while (filled + fillSize < dataSize)
329 {
330 memcpy(&m_data[filled], fill, fillSize);
331 filled += fillSize;
332 }
333
334 memcpy(&m_data[filled], fill, dataSize - filled);
335
336 m_size = dataSize;
337}
338
341{
342 Ptr<Packet> p;
343 if (m_dataSize)
344 {
346 }
347 else
348 {
350 }
351 IPv6TestTag tag;
352 tag.SetToken(42);
353 p->AddPacketTag(tag);
354 p->AddByteTag(tag);
355
357
358 return p;
359}
360
361void
363{
364 NS_TEST_EXPECT_MSG_LT_OR_EQ(packet->GetSize(),
365 ipv6->GetMtu(interface),
366 "Received packet size > MTU: packetSizes: " << packet->GetSize());
367}
368
369void
371{
373 packet->GetSize(),
374 ipv6->GetMtu(interface),
375 "Transmitted packet size > MTU: packetSizes: " << packet->GetSize());
376}
377
378void
380{
381 // Create topology
382
383 InternetStackHelper internet;
384 internet.SetIpv4StackInstall(false);
385
386 // Receiver Node
387 Ptr<Node> serverNode = CreateObject<Node>();
388 internet.Install(serverNode);
389 Ptr<SimpleNetDevice> serverDev;
391 {
392 serverDev = CreateObject<SimpleNetDevice>();
393 serverDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
394 serverDev->SetMtu(1500);
395 serverDev->SetReceiveErrorModel(serverDevErrorModel);
396 serverDevErrorModel->Disable();
397 serverNode->AddDevice(serverDev);
398 Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6>();
399 uint32_t netdev_idx = ipv6->AddInterface(serverDev);
400 Ipv6InterfaceAddress ipv6Addr =
402 ipv6->AddAddress(netdev_idx, ipv6Addr);
403 ipv6->SetUp(netdev_idx);
404 ipv6->TraceConnectWithoutContext(
405 "Rx",
407 }
408 StartServer(serverNode);
409
410 // Sender Node
411 Ptr<Node> clientNode = CreateObject<Node>();
412 internet.Install(clientNode);
413 Ptr<SimpleNetDevice> clientDev;
415 {
416 clientDev = CreateObject<SimpleNetDevice>();
417 clientDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
418 clientDev->SetMtu(1500);
419 clientDev->SetReceiveErrorModel(clientDevErrorModel);
420 clientDevErrorModel->Disable();
421 clientNode->AddDevice(clientDev);
422 Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6>();
423 uint32_t netdev_idx = ipv6->AddInterface(clientDev);
424 Ipv6InterfaceAddress ipv6Addr =
426 ipv6->AddAddress(netdev_idx, ipv6Addr);
427 ipv6->SetUp(netdev_idx);
428 ipv6->TraceConnectWithoutContext(
429 "Tx",
431 }
432 StartClient(clientNode);
433
434 // link the two nodes
436 serverDev->SetChannel(channel);
437 clientDev->SetChannel(channel);
438 channel->SetJumpingTime(Seconds(0.5));
439
440 // some small packets, some rather big ones
441 uint32_t packetSizes[5] = {1500, 2000, 5000, 10000, 65000};
442
443 // using the alphabet
444 uint8_t fillData[78];
445 for (uint32_t k = 48; k <= 125; k++)
446 {
447 fillData[k - 48] = k;
448 }
449
450 // First test: normal channel, no errors, no delays
451 for (int i = 0; i < 5; i++)
452 {
453 uint32_t packetSize = packetSizes[i];
454
455 SetFill(fillData, 78, packetSize);
456
459 Seconds(0),
461 this);
463
464 uint8_t recvBuffer[65000];
465
466 uint16_t recvSize = m_receivedPacketServer->GetSize();
467
468 NS_TEST_EXPECT_MSG_EQ(recvSize,
469 packetSizes[i],
470 "Packet size not correct: recvSize: "
471 << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
472
473 m_receivedPacketServer->CopyData(recvBuffer, 65000);
475 0,
476 "Packet content differs");
477 }
478
479 // Second test: normal channel, no errors, delays each 2 packets.
480 // Each other fragment will arrive out-of-order.
481 // The packets should be received correctly since reassembly will reorder the fragments.
482 channel->SetJumpingMode(true);
483 for (int i = 0; i < 5; i++)
484 {
485 uint32_t packetSize = packetSizes[i];
486
487 SetFill(fillData, 78, packetSize);
488
491 Seconds(0),
493 this);
495
496 uint8_t recvBuffer[65000];
497
498 uint16_t recvSize = m_receivedPacketServer->GetSize();
499
500 NS_TEST_EXPECT_MSG_EQ(recvSize,
501 packetSizes[i],
502 "Packet size not correct: recvSize: "
503 << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
504
505 m_receivedPacketServer->CopyData(recvBuffer, 65000);
507 0,
508 "Packet content differs");
509 }
510 channel->SetJumpingMode(false);
511
512 // Third test: normal channel, some errors, no delays.
513 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
514 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
515 // to the sender (if the first fragment has been received).
516 // In this test case the first fragment is received, so we do expect an ICMP.
517 // Client -> Server : errors enabled
518 // Server -> Client : errors disabled (we want to have back the ICMP)
519 clientDevErrorModel->Disable();
520 serverDevErrorModel->Enable();
521 for (int i = 1; i < 5; i++)
522 {
523 uint32_t packetSize = packetSizes[i];
524
525 SetFill(fillData, 78, packetSize);
526
527 // reset the model, we want to receive the very first fragment.
528 serverDevErrorModel->Reset();
529
531 m_icmpType = 0;
532 m_icmpCode = 0;
534 Seconds(0),
536 this);
538
539 uint16_t recvSize = m_receivedPacketServer->GetSize();
540
541 NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
544 true,
545 "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType)
546 << int(m_icmpCode));
547 }
548
549 // Fourth test: normal channel, no errors, no delays.
550 // We check tags
551 clientDevErrorModel->Disable();
552 serverDevErrorModel->Disable();
553 for (int i = 0; i < 5; i++)
554 {
555 uint32_t packetSize = packetSizes[i];
556
557 SetFill(fillData, 78, packetSize);
558
561 Seconds(0),
563 this);
565
566 IPv6TestTag packetTag;
567 bool found = m_receivedPacketServer->PeekPacketTag(packetTag);
568
569 NS_TEST_EXPECT_MSG_EQ(found, true, "PacketTag not found");
570 NS_TEST_EXPECT_MSG_EQ(packetTag.GetToken(), 42, "PacketTag value not correct");
571
573
574 uint32_t end = 0;
575 uint32_t tagStart = 0;
576 uint32_t tagEnd = 0;
577 while (iter.HasNext())
578 {
579 ByteTagIterator::Item item = iter.Next();
581 "ns3::IPv6TestTag",
582 "ByteTag name not correct");
583 tagStart = item.GetStart();
584 tagEnd = item.GetEnd();
585 if (end == 0)
586 {
587 NS_TEST_EXPECT_MSG_EQ(tagStart, 0, "First ByteTag Start not correct");
588 }
589 if (end != 0)
590 {
591 NS_TEST_EXPECT_MSG_EQ(tagStart, end, "ByteTag End not correct");
592 }
593 end = tagEnd;
594 IPv6TestTag* byteTag = dynamic_cast<IPv6TestTag*>(item.GetTypeId().GetConstructor()());
595 NS_TEST_EXPECT_MSG_NE(byteTag, 0, "ByteTag not found");
596 item.GetTag(*byteTag);
597 NS_TEST_EXPECT_MSG_EQ(byteTag->GetToken(), 42, "ByteTag value not correct");
598 delete byteTag;
599 }
601 }
602
604}
605
606/**
607 * \ingroup internet-test
608 *
609 * \brief IPv6 Fragmentation TestSuite
610 */
612{
613 public:
615 : TestSuite("ipv6-fragmentation", Type::UNIT)
616 {
617 AddTestCase(new Ipv6FragmentationTest, TestCase::Duration::QUICK);
618 }
619};
620
622 g_ipv6fragmentationTestSuite; //!< Static variable for test initialization
Tag used in IPv6 Fragmentation Test.
void Serialize(TagBuffer buffer) const override
static TypeId GetTypeId()
Get the type ID.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
uint64_t GetToken() const
Get the token.
uint64_t token
Token carried by the tag.
void Print(std::ostream &os) const override
void Deserialize(TagBuffer buffer) override
uint32_t GetSerializedSize() const override
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.
void DoRun() override
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.
void HandleReadClient(Ptr< Socket > socket)
Handle incoming packets.
Ptr< Packet > SendClient()
Send a packet.
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: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 Inet6 address class.
static bool IsMatchingType(const Address &addr)
If the address match.
aggregate IP/TCP/UDP functionality to existing Nodes.
Describes an IPv6 address.
static Ipv6Address GetAny()
Get the "any" (::) Ipv6Address.
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition ipv6.h:71
IPv6 address associated with an interface.
Describes an IPv6 prefix.
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address Allocate()
Allocate a new Mac48Address.
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.
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 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.
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
static constexpr auto UNIT
Definition test.h:1291
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.
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_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:820
#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 Ipv6FragmentationTestSuite g_ipv6fragmentationTestSuite
Static variable for test initialization.
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
static const uint32_t packetSize
Packet size generated at the AP.