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 
64 using namespace ns3;
65 
66 class UdpSocketImpl;
67 
73 class IPv6TestTag : public Tag
74 {
75  private:
76  uint64_t token;
77  public:
82  static TypeId GetTypeId()
83  {
84  static TypeId tid =
85  TypeId("ns3::IPv6TestTag").SetParent<Tag>().AddConstructor<IPv6TestTag>();
86  return tid;
87  }
88 
89  TypeId GetInstanceTypeId() const override
90  {
91  return GetTypeId();
92  }
93 
94  uint32_t GetSerializedSize() const override
95  {
96  return sizeof(token);
97  }
98 
99  void Serialize(TagBuffer buffer) const override
100  {
101  buffer.WriteU64(token);
102  }
103 
104  void Deserialize(TagBuffer buffer) override
105  {
106  token = buffer.ReadU64();
107  }
108 
109  void Print(std::ostream& os) const override
110  {
111  os << "token=" << token;
112  }
113 
118  void SetToken(uint64_t token)
119  {
120  this->token = token;
121  }
122 
127  uint64_t GetToken() const
128  {
129  return token;
130  }
131 };
132 
139 {
143 
146  uint32_t m_dataSize;
147  uint8_t* m_data;
148  uint32_t m_size;
149  uint8_t m_icmpType;
150  uint8_t m_icmpCode;
151 
152  public:
153  void DoRun() override;
155  ~Ipv6FragmentationTest() override;
156 
157  // server part
158 
163  void StartServer(Ptr<Node> ServerNode);
168  void HandleReadServer(Ptr<Socket> socket);
169 
170  // client part
171 
176  void StartClient(Ptr<Node> ClientNode);
181  void HandleReadClient(Ptr<Socket> socket);
190  void HandleReadIcmpClient(Ipv6Address icmpSource,
191  uint8_t icmpTtl,
192  uint8_t icmpType,
193  uint8_t icmpCode,
194  uint32_t icmpInfo);
195 
202  void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
203 
208  Ptr<Packet> SendClient();
209 
218  void HandleServerRx(Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
219 
228  void HandleClientTx(Ptr<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
229 };
230 
232  : TestCase("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
233 {
234  m_socketServer = nullptr;
235  m_data = nullptr;
236  m_dataSize = 0;
237  m_size = 0;
238  m_icmpType = 0;
239  m_icmpCode = 0;
240 }
241 
243 {
244  if (m_data)
245  {
246  delete[] m_data;
247  }
248  m_data = nullptr;
249  m_dataSize = 0;
250 }
251 
252 void
254 {
255  if (!m_socketServer)
256  {
257  TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
258  m_socketServer = Socket::CreateSocket(ServerNode, tid);
259  Inet6SocketAddress local = Inet6SocketAddress(Ipv6Address("2001::1"), 9);
260  m_socketServer->Bind(local);
261  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketServer);
262  }
263 
265 }
266 
267 void
269 {
270  Ptr<Packet> packet;
271  Address from;
272  while ((packet = socket->RecvFrom(from)))
273  {
274  if (Inet6SocketAddress::IsMatchingType(from))
275  {
276  m_receivedPacketServer = packet->Copy();
277  }
278  }
279 }
280 
281 void
283 {
284  if (!m_socketClient)
285  {
286  TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
287  m_socketClient = Socket::CreateSocket(ClientNode, tid);
288  m_socketClient->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 9));
291  m_socketClient->SetAttribute("IcmpCallback6", cbValue);
292  }
293 
295 }
296 
297 void
299 {
300  Ptr<Packet> packet;
301  Address from;
302  while ((packet = socket->RecvFrom(from)))
303  {
304  if (Inet6SocketAddress::IsMatchingType(from))
305  {
306  m_receivedPacketClient = packet->Copy();
307  }
308  }
309 }
310 
311 void
313  uint8_t icmpTtl,
314  uint8_t icmpType,
315  uint8_t icmpCode,
316  uint32_t icmpInfo)
317 {
318  m_icmpType = icmpType;
319  m_icmpCode = icmpCode;
320 }
321 
322 void
323 Ipv6FragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
324 {
325  if (dataSize != m_dataSize)
326  {
327  delete[] m_data;
328  m_data = new uint8_t[dataSize];
329  m_dataSize = dataSize;
330  }
331 
332  if (fillSize >= dataSize)
333  {
334  memcpy(m_data, fill, dataSize);
335  return;
336  }
337 
338  uint32_t filled = 0;
339  while (filled + fillSize < dataSize)
340  {
341  memcpy(&m_data[filled], fill, fillSize);
342  filled += fillSize;
343  }
344 
345  memcpy(&m_data[filled], fill, dataSize - filled);
346 
347  m_size = dataSize;
348 }
349 
352 {
353  Ptr<Packet> p;
354  if (m_dataSize)
355  {
356  p = Create<Packet>(m_data, m_dataSize);
357  }
358  else
359  {
360  p = Create<Packet>(m_size);
361  }
362  IPv6TestTag tag;
363  tag.SetToken(42);
364  p->AddPacketTag(tag);
365  p->AddByteTag(tag);
366 
367  m_socketClient->Send(p);
368 
369  return p;
370 }
371 
372 void
374 {
376  ipv6->GetMtu(interface),
377  "Received packet size > MTU: packetSizes: " << packet->GetSize());
378 }
379 
380 void
382 {
384  packet->GetSize(),
385  ipv6->GetMtu(interface),
386  "Transmitted packet size > MTU: packetSizes: " << packet->GetSize());
387 }
388 
389 void
391 {
392  // Create topology
393 
395  internet.SetIpv4StackInstall(false);
396 
397  // Receiver Node
398  Ptr<Node> serverNode = CreateObject<Node>();
399  internet.Install(serverNode);
400  Ptr<SimpleNetDevice> serverDev;
401  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel>();
402  {
403  serverDev = CreateObject<SimpleNetDevice>();
404  serverDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
405  serverDev->SetMtu(1500);
406  serverDev->SetReceiveErrorModel(serverDevErrorModel);
407  serverDevErrorModel->Disable();
408  serverNode->AddDevice(serverDev);
409  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6>();
410  uint32_t netdev_idx = ipv6->AddInterface(serverDev);
411  Ipv6InterfaceAddress ipv6Addr =
413  ipv6->AddAddress(netdev_idx, ipv6Addr);
414  ipv6->SetUp(netdev_idx);
415  ipv6->TraceConnectWithoutContext(
416  "Rx",
418  }
419  StartServer(serverNode);
420 
421  // Sender Node
422  Ptr<Node> clientNode = CreateObject<Node>();
423  internet.Install(clientNode);
424  Ptr<SimpleNetDevice> clientDev;
425  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel>();
426  {
427  clientDev = CreateObject<SimpleNetDevice>();
428  clientDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
429  clientDev->SetMtu(1500);
430  clientDev->SetReceiveErrorModel(clientDevErrorModel);
431  clientDevErrorModel->Disable();
432  clientNode->AddDevice(clientDev);
433  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6>();
434  uint32_t netdev_idx = ipv6->AddInterface(clientDev);
435  Ipv6InterfaceAddress ipv6Addr =
437  ipv6->AddAddress(netdev_idx, ipv6Addr);
438  ipv6->SetUp(netdev_idx);
439  ipv6->TraceConnectWithoutContext(
440  "Tx",
442  }
443  StartClient(clientNode);
444 
445  // link the two nodes
446  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel>();
447  serverDev->SetChannel(channel);
448  clientDev->SetChannel(channel);
449  channel->SetJumpingTime(Seconds(0.5));
450 
451  // some small packets, some rather big ones
452  uint32_t packetSizes[5] = {1500, 2000, 5000, 10000, 65000};
453 
454  // using the alphabet
455  uint8_t fillData[78];
456  for (uint32_t k = 48; k <= 125; k++)
457  {
458  fillData[k - 48] = k;
459  }
460 
461  // First test: normal channel, no errors, no delays
462  for (int i = 0; i < 5; i++)
463  {
464  uint32_t packetSize = packetSizes[i];
465 
466  SetFill(fillData, 78, packetSize);
467 
468  m_receivedPacketServer = Create<Packet>();
469  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
470  Seconds(0),
472  this);
473  Simulator::Run();
474 
475  uint8_t recvBuffer[65000];
476 
477  uint16_t recvSize = m_receivedPacketServer->GetSize();
478 
479  NS_TEST_EXPECT_MSG_EQ(recvSize,
480  packetSizes[i],
481  "Packet size not correct: recvSize: "
482  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
483 
484  m_receivedPacketServer->CopyData(recvBuffer, 65000);
486  0,
487  "Packet content differs");
488  }
489 
490  // Second test: normal channel, no errors, delays each 2 packets.
491  // Each other fragment will arrive out-of-order.
492  // The packets should be received correctly since reassembly will reorder the fragments.
493  channel->SetJumpingMode(true);
494  for (int i = 0; i < 5; i++)
495  {
496  uint32_t packetSize = packetSizes[i];
497 
498  SetFill(fillData, 78, packetSize);
499 
500  m_receivedPacketServer = Create<Packet>();
501  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
502  Seconds(0),
504  this);
505  Simulator::Run();
506 
507  uint8_t recvBuffer[65000];
508 
509  uint16_t recvSize = m_receivedPacketServer->GetSize();
510 
511  NS_TEST_EXPECT_MSG_EQ(recvSize,
512  packetSizes[i],
513  "Packet size not correct: recvSize: "
514  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
515 
516  m_receivedPacketServer->CopyData(recvBuffer, 65000);
518  0,
519  "Packet content differs");
520  }
521  channel->SetJumpingMode(false);
522 
523  // Third test: normal channel, some errors, no delays.
524  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
525  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
526  // to the sender (if the first fragment has been received).
527  // In this test case the first fragment is received, so we do expect an ICMP.
528  // Client -> Server : errors enabled
529  // Server -> Client : errors disabled (we want to have back the ICMP)
530  clientDevErrorModel->Disable();
531  serverDevErrorModel->Enable();
532  for (int i = 1; i < 5; i++)
533  {
534  uint32_t packetSize = packetSizes[i];
535 
536  SetFill(fillData, 78, packetSize);
537 
538  // reset the model, we want to receive the very first fragment.
539  serverDevErrorModel->Reset();
540 
541  m_receivedPacketServer = Create<Packet>();
542  m_icmpType = 0;
543  m_icmpCode = 0;
544  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
545  Seconds(0),
547  this);
548  Simulator::Run();
549 
550  uint16_t recvSize = m_receivedPacketServer->GetSize();
551 
552  NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
553  NS_TEST_EXPECT_MSG_EQ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED) &&
554  (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
555  true,
556  "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType)
557  << int(m_icmpCode));
558  }
559 
560  // Fourth test: normal channel, no errors, no delays.
561  // We check tags
562  clientDevErrorModel->Disable();
563  serverDevErrorModel->Disable();
564  for (int i = 0; i < 5; i++)
565  {
566  uint32_t packetSize = packetSizes[i];
567 
568  SetFill(fillData, 78, packetSize);
569 
570  m_receivedPacketServer = Create<Packet>();
571  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
572  Seconds(0),
574  this);
575  Simulator::Run();
576 
577  IPv6TestTag packetTag;
578  bool found = m_receivedPacketServer->PeekPacketTag(packetTag);
579 
580  NS_TEST_EXPECT_MSG_EQ(found, true, "PacketTag not found");
581  NS_TEST_EXPECT_MSG_EQ(packetTag.GetToken(), 42, "PacketTag value not correct");
582 
584 
585  uint32_t end = 0;
586  uint32_t tagStart = 0;
587  uint32_t tagEnd = 0;
588  while (iter.HasNext())
589  {
590  ByteTagIterator::Item item = iter.Next();
592  "ns3::IPv6TestTag",
593  "ByteTag name not correct");
594  tagStart = item.GetStart();
595  tagEnd = item.GetEnd();
596  if (end == 0)
597  {
598  NS_TEST_EXPECT_MSG_EQ(tagStart, 0, "First ByteTag Start not correct");
599  }
600  if (end != 0)
601  {
602  NS_TEST_EXPECT_MSG_EQ(tagStart, end, "ByteTag End not correct");
603  }
604  end = tagEnd;
605  IPv6TestTag* byteTag = dynamic_cast<IPv6TestTag*>(item.GetTypeId().GetConstructor()());
606  NS_TEST_EXPECT_MSG_NE(byteTag, 0, "ByteTag not found");
607  item.GetTag(*byteTag);
608  NS_TEST_EXPECT_MSG_EQ(byteTag->GetToken(), 42, "ByteTag value not correct");
609  delete byteTag;
610  }
612  }
613 
614  Simulator::Destroy();
615 }
616 
623 {
624  public:
626  : TestSuite("ipv6-fragmentation", UNIT)
627  {
628  AddTestCase(new Ipv6FragmentationTest, TestCase::QUICK);
629  }
630 };
631 
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:101
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
An Inet6 address class.
aggregate IP/TCP/UDP functionality to existing Nodes.
Describes an IPv6 address.
Definition: ipv6-address.h:49
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:455
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:204
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:861
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:960
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:915
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:983
ByteTagIterator GetByteTagIterator() const
Returns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:937
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
void SetRecvCallback(Callback< void, Ptr< Socket >> receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
virtual Ptr< Node > GetNode() const =0
Return the node this socket is associated with.
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
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.
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:301
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:59
Callback< ObjectBase * > GetConstructor() const
Get the constructor callback.
Definition: type-id.cc:1084
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
std::string GetName() const
Get the name.
Definition: type-id.cc:991
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:1326
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:704
channel
Definition: third.py:88
static const uint32_t packetSize
Packet size generated at the AP.