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
55{
59
63 uint8_t* m_data;
65 uint8_t m_icmpType;
66 uint8_t m_icmpCode;
67
68 public:
69 void DoRun() 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);
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 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>();
361 Seconds(0),
363 this);
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>();
393 Seconds(0),
395 this);
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;
430 Seconds(0),
432 this);
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;
469 Seconds(0),
471 this);
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
481}
482
489{
490 public:
492
493 private:
494};
495
497 : TestSuite("sixlowpan-fragmentation", UNIT)
498{
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:804
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:200
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:78
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:140
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition: simulator.h:587
static void Run()
Run the simulation.
Definition: simulator.cc:176
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:126
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:1060
@ QUICK
Fast test.
Definition: test.h:1065
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
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:840
#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:702
static SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
Static variable for test initialization.
static const uint32_t packetSize
Packet size generated at the AP.