LEFT | RIGHT |
(no file at all) | |
| 1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
| 2 /* |
| 3 * Copyright (c) 2013 Universita' di Firenze, Italy |
| 4 * |
| 5 * This program is free software; you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 2 as |
| 7 * published by the Free Software Foundation; |
| 8 * |
| 9 * This program is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. |
| 13 * |
| 14 * You should have received a copy of the GNU General Public License |
| 15 * along with this program; if not, write to the Free Software |
| 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 17 * |
| 18 * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it> |
| 19 */ |
| 20 #define NS3_LOG_ENABLE 1 |
| 21 |
| 22 #include "ns3/test.h" |
| 23 #include "ns3/config.h" |
| 24 #include "ns3/uinteger.h" |
| 25 #include "ns3/socket-factory.h" |
| 26 #include "ns3/ipv6-raw-socket-factory.h" |
| 27 #include "ns3/udp-socket-factory.h" |
| 28 #include "ns3/simulator.h" |
| 29 #include "error-channel-sixlow.h" |
| 30 #include "ns3/simple-net-device.h" |
| 31 #include "ns3/drop-tail-queue.h" |
| 32 #include "ns3/socket.h" |
| 33 #include "ns3/udp-socket.h" |
| 34 |
| 35 #include "ns3/log.h" |
| 36 #include "ns3/node.h" |
| 37 #include "ns3/inet-socket-address.h" |
| 38 #include "ns3/boolean.h" |
| 39 |
| 40 #include "ns3/ipv6-static-routing.h" |
| 41 #include "ns3/ipv6-list-routing.h" |
| 42 #include "ns3/inet6-socket-address.h" |
| 43 #include "ns3/sixlowpan-net-device.h" |
| 44 |
| 45 #include "ns3/udp-l4-protocol.h" |
| 46 |
| 47 #include "ns3/ipv6-l3-protocol.h" |
| 48 #include "ns3/icmpv6-l4-protocol.h" |
| 49 |
| 50 #include <string> |
| 51 #include <limits> |
| 52 #include <netinet/in.h> |
| 53 |
| 54 using namespace ns3; |
| 55 |
| 56 class UdpSocketImpl; |
| 57 |
| 58 static void |
| 59 AddInternetStack (Ptr<Node> node) |
| 60 { |
| 61 //IPV6 |
| 62 Ptr<Ipv6L3Protocol> ipv6 = CreateObject<Ipv6L3Protocol> (); |
| 63 |
| 64 //Routing for Ipv6 |
| 65 Ptr<Ipv6ListRouting> ipv6Routing = CreateObject<Ipv6ListRouting> (); |
| 66 ipv6->SetRoutingProtocol (ipv6Routing); |
| 67 Ptr<Ipv6StaticRouting> ipv6staticRouting = CreateObject<Ipv6StaticRouting> (); |
| 68 ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0); |
| 69 node->AggregateObject (ipv6); |
| 70 |
| 71 //ICMPv6 |
| 72 Ptr<Icmpv6L4Protocol> icmp6 = CreateObject<Icmpv6L4Protocol> (); |
| 73 node->AggregateObject (icmp6); |
| 74 |
| 75 //Ipv6 Extensions |
| 76 ipv6->RegisterExtensions (); |
| 77 ipv6->RegisterOptions (); |
| 78 |
| 79 //UDP |
| 80 Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> (); |
| 81 node->AggregateObject (udp); |
| 82 } |
| 83 |
| 84 |
| 85 class SixlowpanFragmentationTest : public TestCase |
| 86 { |
| 87 Ptr<Packet> m_sentPacketClient; |
| 88 Ptr<Packet> m_receivedPacketClient; |
| 89 Ptr<Packet> m_receivedPacketServer; |
| 90 |
| 91 |
| 92 Ptr<Socket> m_socketServer; |
| 93 Ptr<Socket> m_socketClient; |
| 94 uint32_t m_dataSize; |
| 95 uint8_t *m_data; |
| 96 uint32_t m_size; |
| 97 uint8_t m_icmpType; |
| 98 uint8_t m_icmpCode; |
| 99 |
| 100 public: |
| 101 virtual void DoRun (void); |
| 102 SixlowpanFragmentationTest (); |
| 103 ~SixlowpanFragmentationTest (); |
| 104 |
| 105 // server part |
| 106 void StartServer (Ptr<Node> ServerNode); |
| 107 void HandleReadServer (Ptr<Socket> socket); |
| 108 |
| 109 // client part |
| 110 void StartClient (Ptr<Node> ClientNode); |
| 111 void HandleReadClient (Ptr<Socket> socket); |
| 112 void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t ic
mpType, |
| 113 uint8_t icmpCode,uint32_t icmpInfo); |
| 114 |
| 115 void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize); |
| 116 Ptr<Packet> SendClient (void); |
| 117 |
| 118 }; |
| 119 |
| 120 |
| 121 SixlowpanFragmentationTest::SixlowpanFragmentationTest () |
| 122 : TestCase ("Verify the 6LoWPAN protocol fragmentation and reassembly") |
| 123 { |
| 124 m_socketServer = 0; |
| 125 m_data = 0; |
| 126 m_dataSize = 0; |
| 127 } |
| 128 |
| 129 SixlowpanFragmentationTest::~SixlowpanFragmentationTest () |
| 130 { |
| 131 if ( m_data ) |
| 132 { |
| 133 delete[] m_data; |
| 134 } |
| 135 m_data = 0; |
| 136 m_dataSize = 0; |
| 137 } |
| 138 |
| 139 |
| 140 void |
| 141 SixlowpanFragmentationTest::StartServer (Ptr<Node> ServerNode) |
| 142 { |
| 143 |
| 144 if (m_socketServer == 0) |
| 145 { |
| 146 TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); |
| 147 m_socketServer = Socket::CreateSocket (ServerNode, tid); |
| 148 Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001:0100::1"
), 9); |
| 149 m_socketServer->Bind (local); |
| 150 Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer); |
| 151 } |
| 152 |
| 153 m_socketServer->SetRecvCallback (MakeCallback (&SixlowpanFragmentationTest::Ha
ndleReadServer, this)); |
| 154 } |
| 155 |
| 156 void |
| 157 SixlowpanFragmentationTest::HandleReadServer (Ptr<Socket> socket) |
| 158 { |
| 159 Ptr<Packet> packet; |
| 160 Address from; |
| 161 while ((packet = socket->RecvFrom (from))) |
| 162 { |
| 163 if (Inet6SocketAddress::IsMatchingType (from)) |
| 164 { |
| 165 packet->RemoveAllPacketTags (); |
| 166 packet->RemoveAllByteTags (); |
| 167 |
| 168 m_receivedPacketServer = packet->Copy (); |
| 169 } |
| 170 } |
| 171 } |
| 172 |
| 173 void |
| 174 SixlowpanFragmentationTest::StartClient (Ptr<Node> ClientNode) |
| 175 { |
| 176 |
| 177 if (m_socketClient == 0) |
| 178 { |
| 179 TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); |
| 180 m_socketClient = Socket::CreateSocket (ClientNode, tid); |
| 181 m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9)); |
| 182 m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001:0100::1"),
9)); |
| 183 CallbackValue cbValue = MakeCallback (&SixlowpanFragmentationTest::HandleR
eadIcmpClient, this); |
| 184 m_socketClient->SetAttribute ("IcmpCallback6", cbValue); |
| 185 } |
| 186 |
| 187 m_socketClient->SetRecvCallback (MakeCallback (&SixlowpanFragmentationTest::Ha
ndleReadClient, this)); |
| 188 } |
| 189 |
| 190 void |
| 191 SixlowpanFragmentationTest::HandleReadClient (Ptr<Socket> socket) |
| 192 { |
| 193 Ptr<Packet> packet; |
| 194 Address from; |
| 195 while ((packet = socket->RecvFrom (from))) |
| 196 { |
| 197 if (Inet6SocketAddress::IsMatchingType (from)) |
| 198 { |
| 199 m_receivedPacketClient = packet->Copy (); |
| 200 } |
| 201 } |
| 202 } |
| 203 |
| 204 void |
| 205 SixlowpanFragmentationTest::HandleReadIcmpClient (Ipv6Address icmpSource, |
| 206 uint8_t icmpTtl, uint8_t icmpT
ype, |
| 207 uint8_t icmpCode, uint32_t icm
pInfo) |
| 208 { |
| 209 m_icmpType = icmpType; |
| 210 m_icmpCode = icmpCode; |
| 211 } |
| 212 |
| 213 void |
| 214 SixlowpanFragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t
dataSize) |
| 215 { |
| 216 if (dataSize != m_dataSize) |
| 217 { |
| 218 delete [] m_data; |
| 219 m_data = new uint8_t [dataSize]; |
| 220 m_dataSize = dataSize; |
| 221 } |
| 222 |
| 223 if (fillSize >= dataSize) |
| 224 { |
| 225 memcpy (m_data, fill, dataSize); |
| 226 return; |
| 227 } |
| 228 |
| 229 uint32_t filled = 0; |
| 230 while (filled + fillSize < dataSize) |
| 231 { |
| 232 memcpy (&m_data[filled], fill, fillSize); |
| 233 filled += fillSize; |
| 234 } |
| 235 |
| 236 memcpy (&m_data[filled], fill, dataSize - filled); |
| 237 |
| 238 m_size = dataSize; |
| 239 } |
| 240 |
| 241 Ptr<Packet> SixlowpanFragmentationTest::SendClient (void) |
| 242 { |
| 243 Ptr<Packet> p; |
| 244 if (m_dataSize) |
| 245 { |
| 246 p = Create<Packet> (m_data, m_dataSize); |
| 247 } |
| 248 else |
| 249 { |
| 250 p = Create<Packet> (m_size); |
| 251 } |
| 252 m_socketClient->Send (p); |
| 253 |
| 254 return p; |
| 255 } |
| 256 |
| 257 void |
| 258 SixlowpanFragmentationTest::DoRun (void) |
| 259 { |
| 260 // Create topology |
| 261 |
| 262 // Receiver Node |
| 263 Ptr<Node> serverNode = CreateObject<Node> (); |
| 264 AddInternetStack (serverNode); |
| 265 Ptr<SimpleNetDevice> serverDev; |
| 266 Ptr<BinaryErrorSixlowModel> serverDevErrorModel = CreateObject<BinaryErrorSixl
owModel> (); |
| 267 { |
| 268 serverDev = CreateObject<SimpleNetDevice> (); |
| 269 serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())
); |
| 270 serverDev->SetMtu (1500); |
| 271 serverDev->SetReceiveErrorModel (serverDevErrorModel); |
| 272 serverDevErrorModel->Disable (); |
| 273 serverNode->AddDevice (serverDev); |
| 274 |
| 275 Ptr<SixLowPanNetDevice> serverSix = CreateObject<SixLowPanNetDevice> (); |
| 276 serverSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); |
| 277 serverNode->AddDevice (serverSix); |
| 278 serverSix->SetNetDevice (serverDev); |
| 279 |
| 280 Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> (); |
| 281 ipv6->AddInterface (serverDev); |
| 282 uint32_t netdev_idx = ipv6->AddInterface (serverSix); |
| 283 Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:010
0::1"), Ipv6Prefix (64)); |
| 284 ipv6->AddAddress (netdev_idx, ipv6Addr); |
| 285 ipv6->SetUp (netdev_idx); |
| 286 |
| 287 Ptr<Icmpv6L4Protocol> icmpv6l4 = serverNode->GetObject<Icmpv6L4Protocol> (); |
| 288 icmpv6l4->SetAttribute("DAD", BooleanValue (false)); |
| 289 } |
| 290 StartServer (serverNode); |
| 291 |
| 292 // Sender Node |
| 293 Ptr<Node> clientNode = CreateObject<Node> (); |
| 294 AddInternetStack (clientNode); |
| 295 Ptr<SimpleNetDevice> clientDev; |
| 296 Ptr<BinaryErrorSixlowModel> clientDevErrorModel = CreateObject<BinaryErrorSixl
owModel> (); |
| 297 { |
| 298 clientDev = CreateObject<SimpleNetDevice> (); |
| 299 clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ())
); |
| 300 clientDev->SetMtu (150); |
| 301 clientDev->SetReceiveErrorModel (clientDevErrorModel); |
| 302 clientDevErrorModel->Disable (); |
| 303 clientNode->AddDevice (clientDev); |
| 304 |
| 305 Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice> (); |
| 306 clientSix->SetAttribute ("ForceEtherType", BooleanValue (true) ); |
| 307 serverNode->AddDevice (clientSix); |
| 308 clientSix->SetNetDevice (clientDev); |
| 309 |
| 310 Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> (); |
| 311 ipv6->AddInterface (clientDev); |
| 312 uint32_t netdev_idx = ipv6->AddInterface (clientSix); |
| 313 Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:010
0::2"), Ipv6Prefix (64)); |
| 314 ipv6->AddAddress (netdev_idx, ipv6Addr); |
| 315 ipv6->SetUp (netdev_idx); |
| 316 |
| 317 Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol> (); |
| 318 icmpv6l4->SetAttribute("DAD", BooleanValue (false)); |
| 319 } |
| 320 StartClient (clientNode); |
| 321 |
| 322 // link the two nodes |
| 323 Ptr<ErrorChannelSixlow> channel = CreateObject<ErrorChannelSixlow> (); |
| 324 serverDev->SetChannel (channel); |
| 325 clientDev->SetChannel (channel); |
| 326 |
| 327 |
| 328 // some small packets, some rather big ones |
| 329 uint32_t packetSizes[5] = {200, 300, 400, 500, 600}; |
| 330 |
| 331 // using the alphabet |
| 332 uint8_t fillData[78]; |
| 333 for ( uint32_t k = 48; k <= 125; k++ ) |
| 334 { |
| 335 fillData[k - 48] = k; |
| 336 } |
| 337 |
| 338 // First test: normal channel, no errors, no delays |
| 339 for ( int i = 0; i < 5; i++) |
| 340 { |
| 341 uint32_t packetSize = packetSizes[i]; |
| 342 |
| 343 SetFill (fillData, 78, packetSize); |
| 344 |
| 345 m_receivedPacketServer = Create<Packet> (); |
| 346 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seco
nds (0), |
| 347 &SixlowpanFragmentationTest::SendClient, t
his); |
| 348 Simulator::Run (); |
| 349 |
| 350 uint8_t recvBuffer[65000]; |
| 351 |
| 352 uint16_t recvSize = m_receivedPacketServer->GetSize (); |
| 353 |
| 354 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], |
| 355 "Packet size not correct: recvSize: " << recvSize <
< " packetSizes[" << i << "]: " << packetSizes[i] ); |
| 356 |
| 357 m_receivedPacketServer->CopyData (recvBuffer, 65000); |
| 358 NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer-
>GetSize ()), |
| 359 0, "Packet content differs"); |
| 360 } |
| 361 |
| 362 // Second test: normal channel, no errors, delays each 2 packets. |
| 363 // Each other fragment will arrive out-of-order. |
| 364 // The packets should be received correctly since reassembly will reorder the
fragments. |
| 365 channel->SetJumpingMode (true); |
| 366 for ( int i = 0; i < 5; i++) |
| 367 { |
| 368 uint32_t packetSize = packetSizes[i]; |
| 369 |
| 370 SetFill (fillData, 78, packetSize); |
| 371 |
| 372 m_receivedPacketServer = Create<Packet> (); |
| 373 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seco
nds (0), |
| 374 &SixlowpanFragmentationTest::SendClient, t
his); |
| 375 Simulator::Run (); |
| 376 |
| 377 uint8_t recvBuffer[65000]; |
| 378 |
| 379 uint16_t recvSize = m_receivedPacketServer->GetSize (); |
| 380 |
| 381 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], |
| 382 "Packet size not correct: recvSize: " << recvSize <
< " packetSizes[" << i << "]: " << packetSizes[i] ); |
| 383 |
| 384 m_receivedPacketServer->CopyData (recvBuffer, 65000); |
| 385 NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer-
>GetSize ()), |
| 386 0, "Packet content differs"); |
| 387 } |
| 388 channel->SetJumpingMode (false); |
| 389 |
| 390 |
| 391 // Third test: normal channel, some packets are duplicate. |
| 392 // The duplicate fragments should be discarded, so no error should be fired. |
| 393 channel->SetDuplicateMode (true); |
| 394 for ( int i = 1; i < 5; i++) |
| 395 { |
| 396 uint32_t packetSize = packetSizes[i]; |
| 397 |
| 398 SetFill (fillData, 78, packetSize); |
| 399 |
| 400 // reset the model, we want to receive the very first fragment. |
| 401 serverDevErrorModel->Reset (); |
| 402 |
| 403 m_receivedPacketServer = Create<Packet> (); |
| 404 m_icmpType = 0; |
| 405 m_icmpCode = 0; |
| 406 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seco
nds (0), |
| 407 &SixlowpanFragmentationTest::SendClient, t
his); |
| 408 Simulator::Run (); |
| 409 |
| 410 uint8_t recvBuffer[65000]; |
| 411 |
| 412 uint16_t recvSize = m_receivedPacketServer->GetSize (); |
| 413 |
| 414 NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], |
| 415 "Packet size not correct: recvSize: " << recvSize <
< " packetSizes[" << i << "]: " << packetSizes[i] ); |
| 416 |
| 417 m_receivedPacketServer->CopyData (recvBuffer, 65000); |
| 418 NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer-
>GetSize ()), |
| 419 0, "Packet content differs"); |
| 420 } |
| 421 channel->SetDuplicateMode (false); |
| 422 |
| 423 // Fourth test: normal channel, some errors, no delays. |
| 424 // The reassembly procedure does NOT fire any ICMP, so we do not expect any re
ply from the server. |
| 425 // Client -> Server : errors enabled |
| 426 // Server -> Client : errors disabled |
| 427 clientDevErrorModel->Disable (); |
| 428 serverDevErrorModel->Enable (); |
| 429 for ( int i = 1; i < 5; i++) |
| 430 { |
| 431 uint32_t packetSize = packetSizes[i]; |
| 432 |
| 433 SetFill (fillData, 78, packetSize); |
| 434 |
| 435 // reset the model, we want to receive the very first fragment. |
| 436 serverDevErrorModel->Reset (); |
| 437 |
| 438 m_receivedPacketServer = Create<Packet> (); |
| 439 m_icmpType = 0; |
| 440 m_icmpCode = 0; |
| 441 Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seco
nds (0), |
| 442 &SixlowpanFragmentationTest::SendClient, t
his); |
| 443 Simulator::Run (); |
| 444 |
| 445 uint16_t recvSize = m_receivedPacketServer->GetSize (); |
| 446 |
| 447 NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, someth
ing wrong"); |
| 448 // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6. |
| 449 } |
| 450 |
| 451 |
| 452 |
| 453 Simulator::Destroy (); |
| 454 } |
| 455 //----------------------------------------------------------------------------- |
| 456 class SixlowpanFragmentationTestSuite : public TestSuite |
| 457 { |
| 458 public: |
| 459 SixlowpanFragmentationTestSuite () : TestSuite ("sixlowpan-fragmentation", UNI
T) |
| 460 { |
| 461 AddTestCase (new SixlowpanFragmentationTest, TestCase::QUICK); |
| 462 } |
| 463 } g_sixlowpanFragmentationTestSuite; |
LEFT | RIGHT |