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
271  InternetStackHelper internet;
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  serverSix->SetAttribute("ForceEtherType", BooleanValue(true));
293  serverNode->AddDevice(serverSix);
294  serverSix->SetNetDevice(serverDev);
295 
296  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6>();
297  ipv6->AddInterface(serverDev);
298  uint32_t netdev_idx = ipv6->AddInterface(serverSix);
299  Ipv6InterfaceAddress ipv6Addr =
300  Ipv6InterfaceAddress(Ipv6Address("2001:0100::1"), Ipv6Prefix(64));
301  ipv6->AddAddress(netdev_idx, ipv6Addr);
302  ipv6->SetUp(netdev_idx);
303  }
304  StartServer(serverNode);
305 
306  // Sender Node
307  Ptr<Node> clientNode = CreateObject<Node>();
308  internet.Install(clientNode);
309  Ptr<SimpleNetDevice> clientDev;
310  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel>();
311  {
312  Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol>();
313  icmpv6l4->SetAttribute("DAD", BooleanValue(false));
314 
315  clientDev = CreateObject<SimpleNetDevice>();
316  clientDev->SetAddress(Mac48Address::ConvertFrom(Mac48Address::Allocate()));
317  clientDev->SetMtu(150);
318  clientDev->SetReceiveErrorModel(clientDevErrorModel);
319  clientDevErrorModel->Disable();
320  clientNode->AddDevice(clientDev);
321 
322  Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice>();
323  clientSix->SetAttribute("ForceEtherType", BooleanValue(true));
324  clientNode->AddDevice(clientSix);
325  clientSix->SetNetDevice(clientDev);
326 
327  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6>();
328  ipv6->AddInterface(clientDev);
329  uint32_t netdev_idx = ipv6->AddInterface(clientSix);
330  Ipv6InterfaceAddress ipv6Addr =
331  Ipv6InterfaceAddress(Ipv6Address("2001:0100::2"), Ipv6Prefix(64));
332  ipv6->AddAddress(netdev_idx, ipv6Addr);
333  ipv6->SetUp(netdev_idx);
334  }
335  StartClient(clientNode);
336 
337  // link the two nodes
338  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel>();
339  serverDev->SetChannel(channel);
340  clientDev->SetChannel(channel);
341 
342  // some small packets, some rather big ones
343  uint32_t packetSizes[5] = {200, 300, 400, 500, 600};
344 
345  // using the alphabet
346  uint8_t fillData[78];
347  for (uint32_t k = 48; k <= 125; k++)
348  {
349  fillData[k - 48] = k;
350  }
351 
352  // First test: normal channel, no errors, no delays
353  for (int i = 0; i < 5; i++)
354  {
355  uint32_t packetSize = packetSizes[i];
356 
357  SetFill(fillData, 78, packetSize);
358 
359  m_receivedPacketServer = Create<Packet>();
360  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
361  Seconds(0),
363  this);
364  Simulator::Run();
365 
366  uint8_t recvBuffer[65000];
367 
368  uint16_t recvSize = m_receivedPacketServer->GetSize();
369 
370  NS_TEST_EXPECT_MSG_EQ(recvSize,
371  packetSizes[i],
372  "Packet size not correct: recvSize: "
373  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
374 
375  m_receivedPacketServer->CopyData(recvBuffer, 65000);
377  0,
378  "Packet content differs");
379  }
380 
381  // Second test: normal channel, no errors, delays each 2 packets.
382  // Each other fragment will arrive out-of-order.
383  // The packets should be received correctly since reassembly will reorder the fragments.
384  channel->SetJumpingMode(true);
385  for (int i = 0; i < 5; i++)
386  {
387  uint32_t packetSize = packetSizes[i];
388 
389  SetFill(fillData, 78, packetSize);
390 
391  m_receivedPacketServer = Create<Packet>();
392  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
393  Seconds(0),
395  this);
396  Simulator::Run();
397 
398  uint8_t recvBuffer[65000];
399 
400  uint16_t recvSize = m_receivedPacketServer->GetSize();
401 
402  NS_TEST_EXPECT_MSG_EQ(recvSize,
403  packetSizes[i],
404  "Packet size not correct: recvSize: "
405  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
406 
407  m_receivedPacketServer->CopyData(recvBuffer, 65000);
409  0,
410  "Packet content differs");
411  }
412  channel->SetJumpingMode(false);
413 
414  // Third test: normal channel, some packets are duplicate.
415  // The duplicate fragments should be discarded, so no error should be fired.
416  channel->SetDuplicateMode(true);
417  for (int i = 1; i < 5; i++)
418  {
419  uint32_t packetSize = packetSizes[i];
420 
421  SetFill(fillData, 78, packetSize);
422 
423  // reset the model, we want to receive the very first fragment.
424  serverDevErrorModel->Reset();
425 
426  m_receivedPacketServer = Create<Packet>();
427  m_icmpType = 0;
428  m_icmpCode = 0;
429  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
430  Seconds(0),
432  this);
433  Simulator::Run();
434 
435  uint8_t recvBuffer[65000];
436 
437  uint16_t recvSize = m_receivedPacketServer->GetSize();
438 
439  NS_TEST_EXPECT_MSG_EQ(recvSize,
440  packetSizes[i],
441  "Packet size not correct: recvSize: "
442  << recvSize << " packetSizes[" << i << "]: " << packetSizes[i]);
443 
444  m_receivedPacketServer->CopyData(recvBuffer, 65000);
446  0,
447  "Packet content differs");
448  }
449  channel->SetDuplicateMode(false);
450 
451  // Fourth test: normal channel, some errors, no delays.
452  // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the
453  // server. Client -> Server : errors enabled Server -> Client : errors disabled
454  clientDevErrorModel->Disable();
455  serverDevErrorModel->Enable();
456  for (int i = 1; i < 5; i++)
457  {
458  uint32_t packetSize = packetSizes[i];
459 
460  SetFill(fillData, 78, packetSize);
461 
462  // reset the model, we want to receive the very first fragment.
463  serverDevErrorModel->Reset();
464 
465  m_receivedPacketServer = Create<Packet>();
466  m_icmpType = 0;
467  m_icmpCode = 0;
468  Simulator::ScheduleWithContext(m_socketClient->GetNode()->GetId(),
469  Seconds(0),
471  this);
472  Simulator::Run();
473 
474  uint16_t recvSize = m_receivedPacketServer->GetSize();
475 
476  NS_TEST_EXPECT_MSG_EQ((recvSize == 0), true, "Server got a packet, something wrong");
477  // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6.
478  }
479 
480  Simulator::Destroy();
481 }
482 
489 {
490  public:
492 
493  private:
494 };
495 
497  : TestSuite("sixlowpan-fragmentation", UNIT)
498 {
499  AddTestCase(new SixlowpanFragmentationTest(), TestCase::QUICK);
500 }
501 
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:100
AttributeValue implementation for Boolean.
Definition: boolean.h:37
AttributeValue implementation for Callback.
Definition: callback.h:809
An implementation of the ICMPv6 protocol.
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:200
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 RemoveAllByteTags()
Remove all byte tags stored in this packet.
Definition: packet.cc:393
void RemoveAllPacketTags()
Remove all packet tags.
Definition: packet.cc:1009
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:126
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:305
A suite of tests to run.
Definition: test.h:1256
a unique identifier for an interface.
Definition: type-id.h:60
#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:1336
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:707
channel
Definition: third.py:81
static SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
Static variable for test initialization.
static const uint32_t packetSize
Packet size generated at the AP.