A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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
47using namespace ns3;
48
49/**
50 * \ingroup sixlowpan-tests
51 *
52 * \brief 6LoWPAN Fragmentation Test
53 */
55{
56 Ptr<Packet> m_sentPacketClient; //!< Packet sent by client.
57 Ptr<Packet> m_receivedPacketClient; //!< Packet received by the client.
58 Ptr<Packet> m_receivedPacketServer; //!< packet received by the server.
59
60 Ptr<Socket> m_socketServer; //!< Socket on the server.
61 Ptr<Socket> m_socketClient; //!< Socket on the client.
62 uint32_t m_dataSize; //!< Size of the data (if any).
63 uint8_t* m_data; //!< Data to be carried in the packet
64 uint32_t m_size; //!< Size of the packet if no data has been provided.
65 uint8_t m_icmpType; //!< ICMP type.
66 uint8_t m_icmpCode; //!< ICMP code.
67
68 public:
69 void DoRun() override;
72
73 // server part
74
75 /**
76 * Start the server node.
77 * \param serverNode The server node.
78 */
79 void StartServer(Ptr<Node> serverNode);
80 /**
81 * Handles incoming packets in the server.
82 * \param socket The receiving socket.
83 */
84 void HandleReadServer(Ptr<Socket> socket);
85
86 // client part
87
88 /**
89 * Start the client node.
90 * \param clientNode The client node.
91 */
92 void StartClient(Ptr<Node> clientNode);
93 /**
94 * Handles incoming packets in the client.
95 * \param socket The receiving socket.
96 */
97 void HandleReadClient(Ptr<Socket> socket);
98 /**
99 * Handles incoming ICMP packets in the client.
100 * \param icmpSource ICMP sender address.
101 * \param icmpTtl ICMP TTL.
102 * \param icmpType ICMP type.
103 * \param icmpCode ICMP code.
104 * \param icmpInfo ICMP info.
105 */
106 void HandleReadIcmpClient(Ipv6Address icmpSource,
107 uint8_t icmpTtl,
108 uint8_t icmpType,
109 uint8_t icmpCode,
110 uint32_t icmpInfo);
111 /**
112 * Set the packet optional content.
113 * \param fill Pointer to an array of data.
114 * \param fillSize Size of the array of data.
115 * \param dataSize Size of the packet - if fillSize is less than dataSize, the data is repeated.
116 */
117 void SetFill(uint8_t* fill, uint32_t fillSize, uint32_t dataSize);
118 /**
119 * Send a packet to the server.
120 * \returns The packet sent.
121 */
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
146void
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
162void
164{
165 Ptr<Packet> packet;
166 Address from;
167 while ((packet = socket->RecvFrom(from)))
168 {
170 {
171 packet->RemoveAllPacketTags();
172 packet->RemoveAllByteTags();
173
174 m_receivedPacketServer = packet->Copy();
175 }
176 }
177}
178
179void
181{
182 if (!m_socketClient)
183 {
184 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
185 m_socketClient = Socket::CreateSocket(clientNode, tid);
188 CallbackValue cbValue =
190 m_socketClient->SetAttribute("IcmpCallback6", cbValue);
191 }
192
195}
196
197void
199{
200 Ptr<Packet> packet;
201 Address from;
202 while ((packet = socket->RecvFrom(from)))
203 {
205 {
206 m_receivedPacketClient = packet->Copy();
207 }
208 }
209}
210
211void
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
222void
223SixlowpanFragmentationTest::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 }
263
264 return p;
265}
266
267void
269{
270 // Create topology
271 InternetStackHelper internet;
272 internet.SetIpv4StackInstall(false);
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>();
359 Seconds(0),
361 this);
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>();
391 Seconds(0),
393 this);
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;
428 Seconds(0),
430 this);
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;
467 Seconds(0),
469 this);
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
479}
480
481/**
482 * \ingroup sixlowpan-tests
483 *
484 * \brief 6LoWPAN Fragmentation TestSuite
485 */
487{
488 public:
490
491 private:
492};
493
495 : TestSuite("sixlowpan-fragmentation", Type::UNIT)
496{
497 AddTestCase(new SixlowpanFragmentationTest(), TestCase::Duration::QUICK);
498}
499
501 g_sixlowpanFragmentationTestSuite; //!< Static variable for test initialization
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
AttributeValue implementation for Boolean.
Definition: boolean.h:37
AttributeValue implementation for Callback.
Definition: callback.h:808
An implementation of the ICMPv6 protocol.
An Inet6 address class.
static bool IsMatchingType(const Address &addr)
If the address match.
aggregate IP/TCP/UDP functionality to existing Nodes.
Describes an IPv6 address.
Definition: ipv6-address.h:49
static Ipv6Address GetAny()
Get the "any" (::) Ipv6Address.
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
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address Allocate()
Allocate a new Mac48Address.
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:211
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
static void EnablePrinting()
Enable printing packets metadata.
Definition: packet.cc:596
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition: simulator.h:588
static void Run()
Run the simulation.
Definition: simulator.cc:178
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
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:128
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition: socket.cc:72
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.
encapsulates test code
Definition: test.h:1061
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:301
A suite of tests to run.
Definition: test.h:1268
Type
Type of test.
Definition: test.h:1275
a unique identifier for an interface.
Definition: type-id.h:59
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:836
#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:252
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
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:706
static SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
Static variable for test initialization.
static const uint32_t packetSize
Packet size generated at the AP.