A Discrete-Event Network Simulator
API
sixlowpan-fragmentation-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 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  */
19 #include "ns3/boolean.h"
20 #include "ns3/config.h"
21 #include "ns3/error-channel.h"
22 #include "ns3/icmpv6-l4-protocol.h"
23 #include "ns3/inet-socket-address.h"
24 #include "ns3/internet-stack-helper.h"
25 #include "ns3/ipv6-raw-socket-factory.h"
26 #include "ns3/log.h"
27 #include "ns3/node.h"
28 #include "ns3/simple-net-device.h"
29 #include "ns3/simulator.h"
30 #include "ns3/sixlowpan-net-device.h"
31 #include "ns3/socket-factory.h"
32 #include "ns3/socket.h"
33 #include "ns3/test.h"
34 #include "ns3/udp-socket-factory.h"
35 #include "ns3/udp-socket.h"
36 #include "ns3/uinteger.h"
37 
38 #ifdef __WIN32__
39 #include "ns3/win32-internet.h"
40 #else
41 #include <netinet/in.h>
42 #endif
43 
44 #include <limits>
45 #include <string>
46 
47 using namespace ns3;
48 
55 {
59 
62  uint32_t m_dataSize;
63  uint8_t* m_data;
64  uint32_t m_size;
65  uint8_t m_icmpType;
66  uint8_t m_icmpCode;
67 
68  public:
69  void DoRun() override;
71  ~SixlowpanFragmentationTest() override;
72 
73  // server part
74 
79  void StartServer(Ptr<Node> serverNode);
84  void HandleReadServer(Ptr<Socket> socket);
85 
86  // client part
87 
92  void StartClient(Ptr<Node> clientNode);
97  void HandleReadClient(Ptr<Socket> socket);
106  void HandleReadIcmpClient(Ipv6Address icmpSource,
107  uint8_t icmpTtl,
108  uint8_t icmpType,
109  uint8_t icmpCode,
110  uint32_t icmpInfo);
117  void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
122  Ptr<Packet> SendClient();
123 };
124 
126  : TestCase("Verify the 6LoWPAN protocol fragmentation and reassembly")
127 {
128  m_socketServer = nullptr;
129  m_data = nullptr;
130  m_dataSize = 0;
131  m_size = 0;
132  m_icmpType = 0;
133  m_icmpCode = 0;
134 }
135 
137 {
138  if (m_data)
139  {
140  delete[] m_data;
141  }
142  m_data = nullptr;
143  m_dataSize = 0;
144 }
145 
146 void
148 {
149  if (!m_socketServer)
150  {
151  TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
152  m_socketServer = Socket::CreateSocket(serverNode, tid);
153  Inet6SocketAddress local = Inet6SocketAddress(Ipv6Address("2001:0100::1"), 9);
154  m_socketServer->Bind(local);
155  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket>(m_socketServer);
156  }
157 
160 }
161 
162 void
164 {
165  Ptr<Packet> packet;
166  Address from;
167  while ((packet = socket->RecvFrom(from)))
168  {
169  if (Inet6SocketAddress::IsMatchingType(from))
170  {
171  packet->RemoveAllPacketTags();
172  packet->RemoveAllByteTags();
173 
174  m_receivedPacketServer = packet->Copy();
175  }
176  }
177 }
178 
179 void
181 {
182  if (!m_socketClient)
183  {
184  TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
185  m_socketClient = Socket::CreateSocket(clientNode, tid);
186  m_socketClient->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 9));
188  CallbackValue cbValue =
190  m_socketClient->SetAttribute("IcmpCallback6", cbValue);
191  }
192 
195 }
196 
197 void
199 {
200  Ptr<Packet> packet;
201  Address from;
202  while ((packet = socket->RecvFrom(from)))
203  {
204  if (Inet6SocketAddress::IsMatchingType(from))
205  {
206  m_receivedPacketClient = packet->Copy();
207  }
208  }
209 }
210 
211 void
213  uint8_t icmpTtl,
214  uint8_t icmpType,
215  uint8_t icmpCode,
216  uint32_t icmpInfo)
217 {
218  m_icmpType = icmpType;
219  m_icmpCode = icmpCode;
220 }
221 
222 void
223 SixlowpanFragmentationTest::SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize)
224 {
225  if (dataSize != m_dataSize)
226  {
227  delete[] m_data;
228  m_data = new uint8_t[dataSize];
229  m_dataSize = dataSize;
230  }
231 
232  if (fillSize >= dataSize)
233  {
234  memcpy(m_data, fill, dataSize);
235  return;
236  }
237 
238  uint32_t filled = 0;
239  while (filled + fillSize < dataSize)
240  {
241  memcpy(&m_data[filled], fill, fillSize);
242  filled += fillSize;
243  }
244 
245  memcpy(&m_data[filled], fill, dataSize - filled);
246 
247  m_size = dataSize;
248 }
249 
252 {
253  Ptr<Packet> p;
254  if (m_dataSize)
255  {
256  p = Create<Packet>(m_data, m_dataSize);
257  }
258  else
259  {
260  p = Create<Packet>(m_size);
261  }
262  m_socketClient->Send(p);
263 
264  return p;
265 }
266 
267 void
269 {
270  // Create topology
272  internet.SetIpv4StackInstall(false);
273  Packet::EnablePrinting();
274 
275  // Receiver Node
276  Ptr<Node> serverNode = CreateObject<Node>();
277  internet.Install(serverNode);
278  Ptr<SimpleNetDevice> serverDev;
279  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel>();
280  {
281  Ptr<Icmpv6L4Protocol> icmpv6l4 = serverNode->GetObject<Icmpv6L4Protocol>();
282  icmpv6l4->SetAttribute("DAD", BooleanValue(false));
283 
284  serverDev = CreateObject<SimpleNetDevice>();
285  serverDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
286  serverDev->SetMtu(1500);
287  serverDev->SetReceiveErrorModel(serverDevErrorModel);
288  serverDevErrorModel->Disable();
289  serverNode->AddDevice(serverDev);
290 
291  Ptr<SixLowPanNetDevice> serverSix = CreateObject<SixLowPanNetDevice>();
292  serverNode->AddDevice(serverSix);
293  serverSix->SetNetDevice(serverDev);
294 
295  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6>();
296  ipv6->AddInterface(serverDev);
297  uint32_t netdev_idx = ipv6->AddInterface(serverSix);
298  Ipv6InterfaceAddress ipv6Addr =
299  Ipv6InterfaceAddress(Ipv6Address("2001:0100::1"), Ipv6Prefix(64));
300  ipv6->AddAddress(netdev_idx, ipv6Addr);
301  ipv6->SetUp(netdev_idx);
302  }
303  StartServer(serverNode);
304 
305  // Sender Node
306  Ptr<Node> clientNode = CreateObject<Node>();
307  internet.Install(clientNode);
308  Ptr<SimpleNetDevice> clientDev;
309  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel>();
310  {
311  Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol>();
312  icmpv6l4->SetAttribute("DAD", BooleanValue(false));
313 
314  clientDev = CreateObject<SimpleNetDevice>();
315  clientDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
316  clientDev->SetMtu(150);
317  clientDev->SetReceiveErrorModel(clientDevErrorModel);
318  clientDevErrorModel->Disable();
319  clientNode->AddDevice(clientDev);
320 
321  Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice>();
322  clientNode->AddDevice(clientSix);
323  clientSix->SetNetDevice(clientDev);
324 
325  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6>();
326  ipv6->AddInterface(clientDev);
327  uint32_t netdev_idx = ipv6->AddInterface(clientSix);
328  Ipv6InterfaceAddress ipv6Addr =
329  Ipv6InterfaceAddress(Ipv6Address("2001:0100::2"), Ipv6Prefix(64));
330  ipv6->AddAddress(netdev_idx, ipv6Addr);
331  ipv6->SetUp(netdev_idx);
332  }
333  StartClient(clientNode);
334 
335  // link the two nodes
336  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel>();
337  serverDev->SetChannel(channel);
338  clientDev->SetChannel(channel);
339 
340  // some small packets, some rather big ones
341  uint32_t packetSizes[5] = {200, 300, 400, 500, 600};
342 
343  // using the alphabet
344  uint8_t fillData[78];
345  for (uint32_t k = 48; k <= 125; k++)
346  {
347  fillData[k - 48] = k;
348  }
349 
350  // First test: normal channel, no errors, no delays
351  for (int i = 0; i < 5; i++)
352  {
353  uint32_t packetSize = packetSizes[i];
354 
355  SetFill(fillData, 78, packetSize);
356 
357  m_receivedPacketServer = Create<Packet>();
358  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
359  Seconds(0),
361  this);
362  Simulator::Run();
363 
364  uint8_t recvBuffer[65000];
365 
366  uint16_t recvSize = m_receivedPacketServer->GetSize();
367 
368  NS_TEST_EXPECT_MSG_EQ(recvSize,
369  packetSizes[i],
370  "Packet size not correct: recvSize: "
371  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
372 
373  m_receivedPacketServer->CopyData(recvBuffer, 65000);
375  0,
376  "Packet content differs");
377  }
378 
379  // Second test: normal channel, no errors, delays each 2 packets.
380  // Each other fragment will arrive out-of-order.
381  // The packets should be received correctly since reassembly will reorder the fragments.
382  channel->SetJumpingMode(true);
383  for (int i = 0; i < 5; i++)
384  {
385  uint32_t packetSize = packetSizes[i];
386 
387  SetFill(fillData, 78, packetSize);
388 
389  m_receivedPacketServer = Create<Packet>();
390  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
391  Seconds(0),
393  this);
394  Simulator::Run();
395 
396  uint8_t recvBuffer[65000];
397 
398  uint16_t recvSize = m_receivedPacketServer->GetSize();
399 
400  NS_TEST_EXPECT_MSG_EQ(recvSize,
401  packetSizes[i],
402  "Packet size not correct: recvSize: "
403  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
404 
405  m_receivedPacketServer->CopyData(recvBuffer, 65000);
407  0,
408  "Packet content differs");
409  }
410  channel->SetJumpingMode(false);
411 
412  // Third test: normal channel, some packets are duplicate.
413  // The duplicate fragments should be discarded, so no error should be fired.
414  channel->SetDuplicateMode(true);
415  for (int i = 1; i < 5; i++)
416  {
417  uint32_t packetSize = packetSizes[i];
418 
419  SetFill(fillData, 78, packetSize);
420 
421  // reset the model, we want to receive the very first fragment.
422  serverDevErrorModel->Reset();
423 
424  m_receivedPacketServer = Create<Packet>();
425  m_icmpType = 0;
426  m_icmpCode = 0;
427  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
428  Seconds(0),
430  this);
431  Simulator::Run();
432 
433  uint8_t recvBuffer[65000];
434 
435  uint16_t recvSize = m_receivedPacketServer->GetSize();
436 
437  NS_TEST_EXPECT_MSG_EQ(recvSize,
438  packetSizes[i],
439  "Packet size not correct: recvSize: "
440  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
441 
442  m_receivedPacketServer->CopyData(recvBuffer, 65000);
444  0,
445  "Packet content differs");
446  }
447  channel->SetDuplicateMode(false);
448 
449  // Fourth test: normal channel, some errors, no delays.
450  // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the
451  // server. Client -> Server : errors enabled Server -> Client : errors disabled
452  clientDevErrorModel->Disable();
453  serverDevErrorModel->Enable();
454  for (int i = 1; i < 5; i++)
455  {
456  uint32_t packetSize = packetSizes[i];
457 
458  SetFill(fillData, 78, packetSize);
459 
460  // reset the model, we want to receive the very first fragment.
461  serverDevErrorModel->Reset();
462 
463  m_receivedPacketServer = Create<Packet>();
464  m_icmpType = 0;
465  m_icmpCode = 0;
466  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
467  Seconds(0),
469  this);
470  Simulator::Run();
471 
472  uint16_t recvSize = m_receivedPacketServer->GetSize();
473 
474  NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
475  // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6.
476  }
477 
478  Simulator::Destroy();
479 }
480 
487 {
488  public:
490 
491  private:
492 };
493 
495  : TestSuite("sixlowpan-fragmentation", UNIT)
496 {
497  AddTestCase(new SixlowpanFragmentationTest(), TestCase::QUICK);
498 }
499 
Ptr< Packet > m_sentPacketClient
Packet sent by client.
void StartClient(Ptr< Node > clientNode)
Start the client node.
void StartServer(Ptr< Node > serverNode)
Start the server node.
Ptr< Socket > m_socketServer
Socket on the server.
Ptr< Socket > m_socketClient
Socket on the client.
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
Set the packet optional content.
void HandleReadIcmpClient(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Handles incoming ICMP packets in the client.
Ptr< Packet > m_receivedPacketServer
packet received by the server.
void HandleReadServer(Ptr< Socket > socket)
Handles incoming packets in the server.
uint32_t m_dataSize
Size of the data (if any).
void HandleReadClient(Ptr< Socket > socket)
Handles incoming packets in the client.
Ptr< Packet > SendClient()
Send a packet to the server.
uint32_t m_size
Size of the packet if no data has been provided.
void DoRun() override
Implementation to actually run this TestCase.
Ptr< Packet > m_receivedPacketClient
Packet received by the client.
uint8_t * m_data
Data to be carried in the packet.
a polymophic address class
Definition: address.h:101
An implementation of the ICMPv6 protocol.
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 RemoveAllByteTags()
Remove all byte tags stored in this packet.
Definition: packet.cc:393
void RemoveAllPacketTags()
Remove all packet tags.
Definition: packet.cc:990
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.
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
a unique identifier for an interface.
Definition: type-id.h:59
#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
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 SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
Static variable for test initialization.
static const uint32_t packetSize
Packet size generated at the AP.