1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Universita' di Firenze, Italy
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19  */
20 /**
21  * \file
22  *
23  * This is the test code for ipv6-l3protocol.cc (only the fragmentation and reassembly part).
24  */
25 
26 #include "ns3/test.h"
27 #include "ns3/config.h"
28 #include "ns3/uinteger.h"
29 #include "ns3/socket-factory.h"
30 #include "ns3/ipv4-raw-socket-factory.h"
31 #include "ns3/ipv6-raw-socket-factory.h"
32 #include "ns3/udp-socket-factory.h"
33 #include "ns3/simulator.h"
34 #include "ns3/simple-net-device.h"
35 #include "ns3/socket.h"
36 #include "ns3/udp-socket.h"
37 
38 #include "ns3/log.h"
39 #include "ns3/node.h"
40 #include "ns3/inet-socket-address.h"
41 #include "ns3/boolean.h"
42 
43 #include "ns3/ipv6-static-routing.h"
44 #include "ns3/ipv6-list-routing.h"
45 #include "ns3/inet6-socket-address.h"
46 #
47 #include "ns3/arp-l3-protocol.h"
48 #include "ns3/ipv4-l3-protocol.h"
49 #include "ns3/icmpv4-l4-protocol.h"
50 #include "ns3/ipv4-list-routing.h"
51 #include "ns3/ipv4-static-routing.h"
52 #include "ns3/udp-l4-protocol.h"
53 
54 #include "ns3/ipv6-l3-protocol.h"
55 #include "ns3/icmpv6-l4-protocol.h"
56 #include "ns3/traffic-control-layer.h"
57 #include "ns3/internet-stack-helper.h"
58 #include "ns3/error-channel.h"
59 
60 #include <string>
61 #include <limits>
62 #include <netinet/in.h>
63 
64 using namespace ns3;
65 
66 class UdpSocketImpl;
67 
68 /**
69  * \ingroup internet-test
70  * \ingroup tests
71  *
72  * \brief Tag used in IPv6 Fragmentation Test
73  */
74 class IPv6TestTag : public Tag {
75 private:
76   uint64_t token; //!< Token carried by the tag.
77 public:
78   /**
79    * \brief Get the type ID.
80    * \return the object TypeId
81    */
GetTypeId()82   static TypeId GetTypeId () {
83     static TypeId tid = TypeId ("ns3::IPv6TestTag").SetParent<Tag> ().AddConstructor<IPv6TestTag> ();
84     return tid;
85   }
GetInstanceTypeId() const86   virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
GetSerializedSize() const87   virtual uint32_t GetSerializedSize () const { return sizeof (token); }
Serialize(TagBuffer buffer) const88   virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
Deserialize(TagBuffer buffer)89   virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
Print(std::ostream & os) const90   virtual void Print (std::ostream &os) const { os << "token=" << token; }
91   /**
92    * \brief Set the token.
93    * \param token The token.
94    */
SetToken(uint64_t token)95   void SetToken (uint64_t token) { this->token = token; }
96   /**
97    * \brief Get the token.
98    * \returns The token.
99    */
GetToken()100   uint64_t GetToken () { return token; }
101 };
102 
103 
104 /**
105  * \ingroup internet-test
106  * \ingroup tests
107  *
108  * \brief IPv6 Fragmentation Test
109  */
110 class Ipv6FragmentationTest : public TestCase
111 {
112   Ptr<Packet> m_sentPacketClient;      //!< Packet sent by client.
113   Ptr<Packet> m_receivedPacketClient;  //!< Packet received by client.
114   Ptr<Packet> m_receivedPacketServer;  //!< Packet received by server.
115 
116 
117   Ptr<Socket> m_socketServer;   //!< Server socket.
118   Ptr<Socket> m_socketClient;   //!< Client socket.
119   uint32_t m_dataSize;    //!< Data size.
120   uint8_t *m_data;        //!< Data.
121   uint32_t m_size;        //!< packet size.
122   uint8_t m_icmpType;     //!< ICMP type.
123   uint8_t m_icmpCode;     //!< ICMP code.
124 
125 public:
126   virtual void DoRun (void);
127   Ipv6FragmentationTest ();
128   ~Ipv6FragmentationTest ();
129 
130   // server part
131 
132   /**
133    * \brief Start the server.
134    * \param ServerNode The server.
135    */
136   void StartServer (Ptr<Node> ServerNode);
137   /**
138    * \brief Handle incoming packets.
139    * \param socket The receiving socket.
140    */
141   void HandleReadServer (Ptr<Socket> socket);
142 
143   // client part
144 
145   /**
146    * \brief Start the client.
147    * \param ClientNode The client.
148    */
149   void StartClient (Ptr<Node> ClientNode);
150   /**
151    * \brief Handle incoming packets.
152    * \param socket The receiving socket.
153    */
154   void HandleReadClient (Ptr<Socket> socket);
155   /**
156    * \brief Handle incoming ICMP packets.
157    * \param icmpSource The ICMP sender.
158    * \param icmpTtl The ICMP TTL.
159    * \param icmpType The ICMP Type.
160    * \param icmpCode The ICMP Code.
161    * \param icmpInfo The ICMP Info.
162    */
163   void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
164                              uint8_t icmpCode, uint32_t icmpInfo);
165 
166   /**
167    * \brief Set the packet fill.
168    * \param fill The fill.
169    * \param fillSize The fill size.
170    * \param dataSize The packet size.
171    */
172   void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
173 
174   /**
175    * \brief Send a packet.
176    * \returns The sent packet.
177    */
178   Ptr<Packet> SendClient (void);
179 };
180 
181 
Ipv6FragmentationTest()182 Ipv6FragmentationTest::Ipv6FragmentationTest ()
183   : TestCase ("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
184 {
185   m_socketServer = 0;
186   m_data = 0;
187   m_dataSize = 0;
188   m_size = 0;
189   m_icmpType = 0;
190   m_icmpCode = 0;
191 }
192 
~Ipv6FragmentationTest()193 Ipv6FragmentationTest::~Ipv6FragmentationTest ()
194 {
195   if ( m_data )
196     {
197       delete[] m_data;
198     }
199   m_data = 0;
200   m_dataSize = 0;
201 }
202 
203 
204 void
StartServer(Ptr<Node> ServerNode)205 Ipv6FragmentationTest::StartServer (Ptr<Node> ServerNode)
206 {
207 
208   if (m_socketServer == 0)
209     {
210       TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
211       m_socketServer = Socket::CreateSocket (ServerNode, tid);
212       Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001::1"), 9);
213       m_socketServer->Bind (local);
214       Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
215     }
216 
217   m_socketServer->SetRecvCallback (MakeCallback (&Ipv6FragmentationTest::HandleReadServer, this));
218 }
219 
220 void
HandleReadServer(Ptr<Socket> socket)221 Ipv6FragmentationTest::HandleReadServer (Ptr<Socket> socket)
222 {
223   Ptr<Packet> packet;
224   Address from;
225   while ((packet = socket->RecvFrom (from)))
226     {
227       if (Inet6SocketAddress::IsMatchingType (from))
228         {
229           m_receivedPacketServer = packet->Copy ();
230         }
231     }
232 }
233 
234 void
StartClient(Ptr<Node> ClientNode)235 Ipv6FragmentationTest::StartClient (Ptr<Node> ClientNode)
236 {
237 
238   if (m_socketClient == 0)
239     {
240       TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
241       m_socketClient = Socket::CreateSocket (ClientNode, tid);
242       m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
243       m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001::1"), 9));
244       CallbackValue cbValue = MakeCallback (&Ipv6FragmentationTest::HandleReadIcmpClient, this);
245       m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
246     }
247 
248   m_socketClient->SetRecvCallback (MakeCallback (&Ipv6FragmentationTest::HandleReadClient, this));
249 }
250 
251 void
HandleReadClient(Ptr<Socket> socket)252 Ipv6FragmentationTest::HandleReadClient (Ptr<Socket> socket)
253 {
254   Ptr<Packet> packet;
255   Address from;
256   while ((packet = socket->RecvFrom (from)))
257     {
258       if (Inet6SocketAddress::IsMatchingType (from))
259         {
260           m_receivedPacketClient = packet->Copy ();
261         }
262     }
263 }
264 
265 void
HandleReadIcmpClient(Ipv6Address icmpSource,uint8_t icmpTtl,uint8_t icmpType,uint8_t icmpCode,uint32_t icmpInfo)266 Ipv6FragmentationTest::HandleReadIcmpClient (Ipv6Address icmpSource,
267                                              uint8_t icmpTtl, uint8_t icmpType,
268                                              uint8_t icmpCode, uint32_t icmpInfo)
269 {
270   m_icmpType = icmpType;
271   m_icmpCode = icmpCode;
272 }
273 
274 void
SetFill(uint8_t * fill,uint32_t fillSize,uint32_t dataSize)275 Ipv6FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
276 {
277   if (dataSize != m_dataSize)
278     {
279       delete [] m_data;
280       m_data = new uint8_t [dataSize];
281       m_dataSize = dataSize;
282     }
283 
284   if (fillSize >= dataSize)
285     {
286       memcpy (m_data, fill, dataSize);
287       return;
288     }
289 
290   uint32_t filled = 0;
291   while (filled + fillSize < dataSize)
292     {
293       memcpy (&m_data[filled], fill, fillSize);
294       filled += fillSize;
295     }
296 
297   memcpy (&m_data[filled], fill, dataSize - filled);
298 
299   m_size = dataSize;
300 }
301 
SendClient(void)302 Ptr<Packet> Ipv6FragmentationTest::SendClient (void)
303 {
304   Ptr<Packet> p;
305   if (m_dataSize)
306     {
307       p = Create<Packet> (m_data, m_dataSize);
308     }
309   else
310     {
311       p = Create<Packet> (m_size);
312     }
313   IPv6TestTag tag;
314   tag.SetToken (42);
315   p->AddPacketTag (tag);
316   p->AddByteTag (tag);
317 
318   m_socketClient->Send (p);
319 
320   return p;
321 }
322 
323 void
DoRun(void)324 Ipv6FragmentationTest::DoRun (void)
325 {
326   // Create topology
327 
328   InternetStackHelper internet;
329   internet.SetIpv4StackInstall (false);
330 
331   // Receiver Node
332   Ptr<Node> serverNode = CreateObject<Node> ();
333   internet.Install (serverNode);
334   Ptr<SimpleNetDevice> serverDev;
335   Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
336   {
337     serverDev = CreateObject<SimpleNetDevice> ();
338     serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
339     serverDev->SetMtu (1500);
340     serverDev->SetReceiveErrorModel (serverDevErrorModel);
341     serverDevErrorModel->Disable ();
342     serverNode->AddDevice (serverDev);
343     Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
344     uint32_t netdev_idx = ipv6->AddInterface (serverDev);
345     Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::1"), Ipv6Prefix (32));
346     ipv6->AddAddress (netdev_idx, ipv6Addr);
347     ipv6->SetUp (netdev_idx);
348   }
349   StartServer (serverNode);
350 
351   // Sender Node
352   Ptr<Node> clientNode = CreateObject<Node> ();
353   internet.Install (clientNode);
354   Ptr<SimpleNetDevice> clientDev;
355   Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
356   {
357     clientDev = CreateObject<SimpleNetDevice> ();
358     clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
359     clientDev->SetMtu (1500);
360     clientDev->SetReceiveErrorModel (clientDevErrorModel);
361     clientDevErrorModel->Disable ();
362     clientNode->AddDevice (clientDev);
363     Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
364     uint32_t netdev_idx = ipv6->AddInterface (clientDev);
365     Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::2"), Ipv6Prefix (32));
366     ipv6->AddAddress (netdev_idx, ipv6Addr);
367     ipv6->SetUp (netdev_idx);
368   }
369   StartClient (clientNode);
370 
371   // link the two nodes
372   Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
373   serverDev->SetChannel (channel);
374   clientDev->SetChannel (channel);
375   channel->SetJumpingTime (Seconds (0.5));
376 
377 
378   // some small packets, some rather big ones
379   uint32_t packetSizes[5] = {2000, 2500, 5000, 10000, 65000};
380 
381   // using the alphabet
382   uint8_t fillData[78];
383   for ( uint32_t k = 48; k <= 125; k++ )
384     {
385       fillData[k - 48] = k;
386     }
387 
388   // First test: normal channel, no errors, no delays
389   for ( int i = 0; i < 5; i++)
390     {
391       uint32_t packetSize = packetSizes[i];
392 
393       SetFill (fillData, 78, packetSize);
394 
395       m_receivedPacketServer = Create<Packet> ();
396       Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
397                                       &Ipv6FragmentationTest::SendClient, this);
398       Simulator::Run ();
399 
400       uint8_t recvBuffer[65000];
401 
402       uint16_t recvSize = m_receivedPacketServer->GetSize ();
403 
404       NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
405                              "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
406 
407       m_receivedPacketServer->CopyData (recvBuffer, 65000);
408       NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
409                              0, "Packet content differs");
410     }
411 
412   // Second test: normal channel, no errors, delays each 2 packets.
413   // Each other fragment will arrive out-of-order.
414   // The packets should be received correctly since reassembly will reorder the fragments.
415   channel->SetJumpingMode (true);
416   for ( int i = 0; i < 5; i++)
417     {
418       uint32_t packetSize = packetSizes[i];
419 
420       SetFill (fillData, 78, packetSize);
421 
422       m_receivedPacketServer = Create<Packet> ();
423       Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
424                                       &Ipv6FragmentationTest::SendClient, this);
425       Simulator::Run ();
426 
427       uint8_t recvBuffer[65000];
428 
429       uint16_t recvSize = m_receivedPacketServer->GetSize ();
430 
431       NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
432                              "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
433 
434       m_receivedPacketServer->CopyData (recvBuffer, 65000);
435       NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
436                              0, "Packet content differs");
437     }
438   channel->SetJumpingMode (false);
439 
440   // Third test: normal channel, some errors, no delays.
441   // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
442   // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
443   // to the sender (if the first fragment has been received).
444   // In this test case the first fragment is received, so we do expect an ICMP.
445   // Client -> Server : errors enabled
446   // Server -> Client : errors disabled (we want to have back the ICMP)
447   clientDevErrorModel->Disable ();
448   serverDevErrorModel->Enable ();
449   for ( int i = 1; i < 5; i++)
450     {
451       uint32_t packetSize = packetSizes[i];
452 
453       SetFill (fillData, 78, packetSize);
454 
455       // reset the model, we want to receive the very first fragment.
456       serverDevErrorModel->Reset ();
457 
458       m_receivedPacketServer = Create<Packet> ();
459       m_icmpType = 0;
460       m_icmpCode = 0;
461       Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
462                                       &Ipv6FragmentationTest::SendClient, this);
463       Simulator::Run ();
464 
465       uint16_t recvSize = m_receivedPacketServer->GetSize ();
466 
467       NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
468       NS_TEST_EXPECT_MSG_EQ ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED)
469                              && (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
470                              true, "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType) << int(m_icmpCode) );
471     }
472 
473   // Fourth test: normal channel, no errors, no delays.
474   // We check tags
475   clientDevErrorModel->Disable ();
476   serverDevErrorModel->Disable ();
477   for (int i= 0; i<5; i++)
478     {
479       uint32_t packetSize = packetSizes[i];
480 
481       SetFill (fillData, 78, packetSize);
482 
483       m_receivedPacketServer = Create<Packet> ();
484       Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
485                                       &Ipv6FragmentationTest::SendClient, this);
486       Simulator::Run ();
487 
488       IPv6TestTag packetTag;
489       bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
490 
491       NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
492       NS_TEST_EXPECT_MSG_EQ (packetTag.GetToken (), 42, "PacketTag value not correct");
493 
494       ByteTagIterator iter = m_receivedPacketServer->GetByteTagIterator ();
495 
496       uint32_t end = 0;
497       uint32_t tagStart = 0;
498       uint32_t tagEnd = 0;
499       while (iter.HasNext ())
500         {
501           ByteTagIterator::Item item = iter.Next ();
502           NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv6TestTag", "ByteTag name not correct");
503           tagStart = item.GetStart ();
504           tagEnd = item.GetEnd ();
505           if (end == 0)
506             {
507               NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
508             }
509           if (end != 0)
510             {
511               NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
512             }
513           end = tagEnd;
514           IPv6TestTag *byteTag = dynamic_cast<IPv6TestTag *> (item.GetTypeId ().GetConstructor () ());
515           NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
516           item.GetTag (*byteTag);
517           NS_TEST_EXPECT_MSG_EQ (byteTag->GetToken (), 42, "ByteTag value not correct");
518           delete byteTag;
519         }
520       NS_TEST_EXPECT_MSG_EQ (end, m_receivedPacketServer->GetSize (), "trivial");
521     }
522 
523   Simulator::Destroy ();
524 }
525 
526 
527 /**
528  * \ingroup internet-test
529  * \ingroup tests
530  *
531  * \brief IPv6 Fragmentation TestSuite
532  */
533 class Ipv6FragmentationTestSuite : public TestSuite
534 {
535 public:
Ipv6FragmentationTestSuite()536   Ipv6FragmentationTestSuite () : TestSuite ("ipv6-fragmentation", UNIT)
537   {
538     AddTestCase (new Ipv6FragmentationTest, TestCase::QUICK);
539   }
540 };
541 
542 static Ipv6FragmentationTestSuite g_ipv6fragmentationTestSuite; //!< Static variable for test initialization
543 
544