A Discrete-Event Network Simulator
API
ipv6-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 */
25#include "ns3/arp-l3-protocol.h"
26#include "ns3/boolean.h"
27#include "ns3/config.h"
28#include "ns3/error-channel.h"
29#include "ns3/icmpv4-l4-protocol.h"
30#include "ns3/icmpv6-l4-protocol.h"
31#include "ns3/inet-socket-address.h"
32#include "ns3/inet6-socket-address.h"
33#include "ns3/internet-stack-helper.h"
34#include "ns3/ipv4-l3-protocol.h"
35#include "ns3/ipv4-list-routing.h"
36#include "ns3/ipv4-raw-socket-factory.h"
37#include "ns3/ipv4-static-routing.h"
38#include "ns3/ipv6-l3-protocol.h"
39#include "ns3/ipv6-list-routing.h"
40#include "ns3/ipv6-raw-socket-factory.h"
41#include "ns3/ipv6-static-routing.h"
42#include "ns3/log.h"
43#include "ns3/node.h"
44#include "ns3/simple-net-device.h"
45#include "ns3/simulator.h"
46#include "ns3/socket-factory.h"
47#include "ns3/socket.h"
48#include "ns3/test.h"
49#include "ns3/traffic-control-layer.h"
50#include "ns3/udp-l4-protocol.h"
51#include "ns3/udp-socket-factory.h"
52#include "ns3/udp-socket.h"
53#include "ns3/uinteger.h"
54
55#ifdef __WIN32__
56#include "ns3/win32-internet.h"
57#else
58#include <netinet/in.h>
59#endif
60
61#include <limits>
62#include <string>
63
64using namespace ns3;
65
66class UdpSocketImpl;
67
74class IPv6TestTag : public Tag
75{
76 private:
77 uint64_t token;
78 public:
84 {
85 static TypeId tid =
86 TypeId("ns3::IPv6TestTag").SetParent<Tag>().AddConstructor<IPv6TestTag>();
87 return tid;
88 }
89
90 TypeId GetInstanceTypeId() const override
91 {
92 return GetTypeId();
93 }
94
95 uint32_t GetSerializedSize() const override
96 {
97 return sizeof(token);
98 }
99
100 void Serialize(TagBuffer buffer) const override
101 {
102 buffer.WriteU64(token);
103 }
104
105 void Deserialize(TagBuffer buffer) override
106 {
107 token = buffer.ReadU64();
108 }
109
110 void Print(std::ostream& os) const override
111 {
112 os << "token=" << token;
113 }
114
119 void SetToken(uint64_t token)
120 {
121 this->token = token;
122 }
123
128 uint64_t GetToken()
129 {
130 return token;
131 }
132};
133
141{
145
149 uint8_t* m_data;
151 uint8_t m_icmpType;
152 uint8_t m_icmpCode;
153
154 public:
155 void DoRun() override;
157 ~Ipv6FragmentationTest() override;
158
159 // server part
160
165 void StartServer(Ptr<Node> ServerNode);
170 void HandleReadServer(Ptr<Socket> socket);
171
172 // client part
173
178 void StartClient(Ptr<Node> ClientNode);
183 void HandleReadClient(Ptr<Socket> socket);
192 void HandleReadIcmpClient(Ipv6Address icmpSource,
193 uint8_t icmpTtl,
194 uint8_t icmpType,
195 uint8_t icmpCode,
196 uint32_t icmpInfo);
197
204 void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
205
211
220 void HandleServerRx(Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
221
230 void HandleClientTx(Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
231};
232
234 : TestCase("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
235{
236 m_socketServer = nullptr;
237 m_data = nullptr;
238 m_dataSize = 0;
239 m_size = 0;
240 m_icmpType = 0;
241 m_icmpCode = 0;
242}
243
245{
246 if (m_data)
247 {
248 delete[] m_data;
249 }
250 m_data = nullptr;
251 m_dataSize = 0;
252}
253
254void
256{
257 if (!m_socketServer)
258 {
259 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
260 m_socketServer = Socket::CreateSocket(ServerNode, tid);
262 m_socketServer->Bind(local);
263 Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketServer);
264 }
265
267}
268
269void
271{
272 Ptr<Packet> packet;
273 Address from;
274 while ((packet = socket->RecvFrom(from)))
275 {
276 if (Inet6SocketAddress::IsMatchingType(from))
277 {
278 m_receivedPacketServer = packet->Copy();
279 }
280 }
281}
282
283void
285{
286 if (!m_socketClient)
287 {
288 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
289 m_socketClient = Socket::CreateSocket(ClientNode, tid);
290 m_socketClient->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 9));
293 m_socketClient->SetAttribute("IcmpCallback6", cbValue);
294 }
295
297}
298
299void
301{
302 Ptr<Packet> packet;
303 Address from;
304 while ((packet = socket->RecvFrom(from)))
305 {
306 if (Inet6SocketAddress::IsMatchingType(from))
307 {
308 m_receivedPacketClient = packet->Copy();
309 }
310 }
311}
312
313void
315 uint8_t icmpTtl,
316 uint8_t icmpType,
317 uint8_t icmpCode,
318 uint32_t icmpInfo)
319{
320 m_icmpType = icmpType;
321 m_icmpCode = icmpCode;
322}
323
324void
325Ipv6FragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
326{
327 if (dataSize != m_dataSize)
328 {
329 delete[] m_data;
330 m_data = new uint8_t[dataSize];
331 m_dataSize = dataSize;
332 }
333
334 if (fillSize >= dataSize)
335 {
336 memcpy(m_data, fill, dataSize);
337 return;
338 }
339
340 uint32_t filled = 0;
341 while (filled + fillSize < dataSize)
342 {
343 memcpy(&m_data[filled], fill, fillSize);
344 filled += fillSize;
345 }
346
347 memcpy(&m_data[filled], fill, dataSize - filled);
348
349 m_size = dataSize;
350}
351
354{
355 Ptr<Packet> p;
356 if (m_dataSize)
357 {
358 p = Create<Packet>(m_data, m_dataSize);
359 }
360 else
361 {
362 p = Create<Packet>(m_size);
363 }
364 IPv6TestTag tag;
365 tag.SetToken(42);
366 p->AddPacketTag(tag);
367 p->AddByteTag(tag);
368
370
371 return p;
372}
373
374void
376{
378 ipv6->GetMtu(interface),
379 "Received packet size > MTU: packetSizes: " << packet->GetSize());
380}
381
382void
384{
386 packet->GetSize(),
387 ipv6->GetMtu(interface),
388 "Transmitted packet size > MTU: packetSizes: " << packet->GetSize());
389}
390
391void
393{
394 // Create topology
395
396 InternetStackHelper internet;
397 internet.SetIpv4StackInstall(false);
398
399 // Receiver Node
400 Ptr<Node> serverNode = CreateObject<Node>();
401 internet.Install(serverNode);
402 Ptr<SimpleNetDevice> serverDev;
403 Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel>();
404 {
405 serverDev = CreateObject<SimpleNetDevice>();
406 serverDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
407 serverDev->SetMtu(1500);
408 serverDev->SetReceiveErrorModel(serverDevErrorModel);
409 serverDevErrorModel->Disable();
410 serverNode->AddDevice(serverDev);
411 Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6>();
412 uint32_t netdev_idx = ipv6->AddInterface(serverDev);
413 Ipv6InterfaceAddress ipv6Addr =
415 ipv6->AddAddress(netdev_idx, ipv6Addr);
416 ipv6->SetUp(netdev_idx);
417 ipv6->TraceConnectWithoutContext(
418 "Rx",
420 }
421 StartServer(serverNode);
422
423 // Sender Node
424 Ptr<Node> clientNode = CreateObject<Node>();
425 internet.Install(clientNode);
426 Ptr<SimpleNetDevice> clientDev;
427 Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel>();
428 {
429 clientDev = CreateObject<SimpleNetDevice>();
430 clientDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
431 clientDev->SetMtu(1500);
432 clientDev->SetReceiveErrorModel(clientDevErrorModel);
433 clientDevErrorModel->Disable();
434 clientNode->AddDevice(clientDev);
435 Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6>();
436 uint32_t netdev_idx = ipv6->AddInterface(clientDev);
437 Ipv6InterfaceAddress ipv6Addr =
439 ipv6->AddAddress(netdev_idx, ipv6Addr);
440 ipv6->SetUp(netdev_idx);
441 ipv6->TraceConnectWithoutContext(
442 "Tx",
444 }
445 StartClient(clientNode);
446
447 // link the two nodes
448 Ptr<ErrorChannel> channel = CreateObject<ErrorChannel>();
449 serverDev->SetChannel(channel);
450 clientDev->SetChannel(channel);
451 channel->SetJumpingTime(Seconds(0.5));
452
453 // some small packets, some rather big ones
454 uint32_t packetSizes[5] = {1500, 2000, 5000, 10000, 65000};
455
456 // using the alphabet
457 uint8_t fillData[78];
458 for (uint32_t k = 48; k <= 125; k++)
459 {
460 fillData[k - 48] = k;
461 }
462
463 // First test: normal channel, no errors, no delays
464 for (int i = 0; i < 5; i++)
465 {
466 uint32_t packetSize = packetSizes[i];
467
468 SetFill(fillData, 78, packetSize);
469
470 m_receivedPacketServer = Create<Packet>();
471 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
472 Seconds(0),
474 this);
475 Simulator::Run();
476
477 uint8_t recvBuffer[65000];
478
479 uint16_t recvSize = m_receivedPacketServer->GetSize();
480
481 NS_TEST_EXPECT_MSG_EQ(recvSize,
482 packetSizes[i],
483 "Packet size not correct: recvSize: "
484 << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
485
486 m_receivedPacketServer->CopyData(recvBuffer, 65000);
488 0,
489 "Packet content differs");
490 }
491
492 // Second test: normal channel, no errors, delays each 2 packets.
493 // Each other fragment will arrive out-of-order.
494 // The packets should be received correctly since reassembly will reorder the fragments.
495 channel->SetJumpingMode(true);
496 for (int i = 0; i < 5; i++)
497 {
498 uint32_t packetSize = packetSizes[i];
499
500 SetFill(fillData, 78, packetSize);
501
502 m_receivedPacketServer = Create<Packet>();
503 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
504 Seconds(0),
506 this);
507 Simulator::Run();
508
509 uint8_t recvBuffer[65000];
510
511 uint16_t recvSize = m_receivedPacketServer->GetSize();
512
513 NS_TEST_EXPECT_MSG_EQ(recvSize,
514 packetSizes[i],
515 "Packet size not correct: recvSize: "
516 << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
517
518 m_receivedPacketServer->CopyData(recvBuffer, 65000);
520 0,
521 "Packet content differs");
522 }
523 channel->SetJumpingMode(false);
524
525 // Third test: normal channel, some errors, no delays.
526 // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
527 // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
528 // to the sender (if the first fragment has been received).
529 // In this test case the first fragment is received, so we do expect an ICMP.
530 // Client -> Server : errors enabled
531 // Server -> Client : errors disabled (we want to have back the ICMP)
532 clientDevErrorModel->Disable();
533 serverDevErrorModel->Enable();
534 for (int i = 1; i < 5; i++)
535 {
536 uint32_t packetSize = packetSizes[i];
537
538 SetFill(fillData, 78, packetSize);
539
540 // reset the model, we want to receive the very first fragment.
541 serverDevErrorModel->Reset();
542
543 m_receivedPacketServer = Create<Packet>();
544 m_icmpType = 0;
545 m_icmpCode = 0;
546 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
547 Seconds(0),
549 this);
550 Simulator::Run();
551
552 uint16_t recvSize = m_receivedPacketServer->GetSize();
553
554 NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
555 NS_TEST_EXPECT_MSG_EQ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED) &&
556 (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
557 true,
558 "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType)
559 << int(m_icmpCode));
560 }
561
562 // Fourth test: normal channel, no errors, no delays.
563 // We check tags
564 clientDevErrorModel->Disable();
565 serverDevErrorModel->Disable();
566 for (int i = 0; i < 5; i++)
567 {
568 uint32_t packetSize = packetSizes[i];
569
570 SetFill(fillData, 78, packetSize);
571
572 m_receivedPacketServer = Create<Packet>();
573 Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
574 Seconds(0),
576 this);
577 Simulator::Run();
578
579 IPv6TestTag packetTag;
580 bool found = m_receivedPacketServer->PeekPacketTag(packetTag);
581
582 NS_TEST_EXPECT_MSG_EQ(found, true, "PacketTag not found");
583 NS_TEST_EXPECT_MSG_EQ(packetTag.GetToken(), 42, "PacketTag value not correct");
584
586
587 uint32_t end = 0;
588 uint32_t tagStart = 0;
589 uint32_t tagEnd = 0;
590 while (iter.HasNext())
591 {
592 ByteTagIterator::Item item = iter.Next();
594 "ns3::IPv6TestTag",
595 "ByteTag name not correct");
596 tagStart = item.GetStart();
597 tagEnd = item.GetEnd();
598 if (end == 0)
599 {
600 NS_TEST_EXPECT_MSG_EQ(tagStart, 0, "First ByteTag Start not correct");
601 }
602 if (end != 0)
603 {
604 NS_TEST_EXPECT_MSG_EQ(tagStart, end, "ByteTag End not correct");
605 }
606 end = tagEnd;
607 IPv6TestTag* byteTag = dynamic_cast<IPv6TestTag*>(item.GetTypeId().GetConstructor()());
608 NS_TEST_EXPECT_MSG_NE(byteTag, 0, "ByteTag not found");
609 item.GetTag(*byteTag);
610 NS_TEST_EXPECT_MSG_EQ(byteTag->GetToken(), 42, "ByteTag value not correct");
611 delete byteTag;
612 }
614 }
615
616 Simulator::Destroy();
617}
618
626{
627 public:
629 : TestSuite("ipv6-fragmentation", UNIT)
630 {
631 AddTestCase(new Ipv6FragmentationTest, TestCase::QUICK);
632 }
633};
634
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()
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: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 Inet6 address class.
aggregate IP/TCP/UDP functionality to existing Nodes.
void SetIpv4StackInstall(bool enable)
Enable/disable IPv4 stack install.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
Describes an IPv6 address.
Definition: ipv6-address.h:50
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:82
IPv6 address associated with an interface.
Describes an IPv6 prefix.
Definition: ipv6-address.h:456
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:138
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
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 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.
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
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
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.
#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:830
#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 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:691
channel
Definition: third.py:81
static const uint32_t packetSize
Packet size generated at the AP.