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
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 {
169 if (Inet6SocketAddress::IsMatchingType(from))
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);
186 m_socketClient->Bind(Inet6SocketAddress(Ipv6Address::GetAny(), 9));
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 {
204 if (Inet6SocketAddress::IsMatchingType(from))
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);
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:92
AttributeValue implementation for Boolean.
Definition: boolean.h:37
AttributeValue implementation for Callback.
Definition: callback.h:793
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:258
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.
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.
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
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
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:1338
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:691
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.