diff --git a/examples/ipv6/CMakeLists.txt b/examples/ipv6/CMakeLists.txt index d9aed784b..5776bc96f 100644 --- a/examples/ipv6/CMakeLists.txt +++ b/examples/ipv6/CMakeLists.txt @@ -71,3 +71,13 @@ set(libraries_to_link ${liblr-wpan} ${libinternet} ${libsixlowpan} build_example( "${name}" "${source_files}" "${header_files}" "${libraries_to_link}" ) + +set(name fragmentation-ipv6-PMTU) +set(source_files ${name}.cc) +set(header_files) +set(libraries_to_link ${libcsma} ${libinternet} ${libinternet-apps} + ${libpoint-to-point} +) +build_example( + "${name}" "${source_files}" "${header_files}" "${libraries_to_link}" +) diff --git a/examples/ipv6/fragmentation-ipv6-PMTU.cc b/examples/ipv6/fragmentation-ipv6-PMTU.cc new file mode 100644 index 000000000..dd014edf9 --- /dev/null +++ b/examples/ipv6/fragmentation-ipv6-PMTU.cc @@ -0,0 +1,160 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008-2009 Strasbourg University + * Copyright (c) 2013 Universita' di Firenze + * Copyright (c) 2022 Jadavpur University + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: David Gross + * Sebastien Vincent + * Modified by Akash Mondal + */ + +// Network topology +// // +// // Src n0 r1 n1 r2 n2 +// // | _ | _ | +// // =========|_|============|_|========= +// // MTU 5000 2000 1500 +// // +// // - Tracing of queues and packet receptions to file "fragmentation-ipv6-PMTU.tr" + +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/csma-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/internet-apps-module.h" +#include "ns3/ipv6-static-routing-helper.h" + +#include "ns3/ipv6-routing-table-entry.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("FragmentationIpv6PmtuExample"); + +int +main (int argc, char **argv) +{ + bool verbose = false; + + CommandLine cmd (__FILE__); + cmd.AddValue ("verbose", "turn on log components", verbose); + cmd.Parse (argc, argv); + + if (verbose) + { + LogComponentEnable ("Ipv6L3Protocol", LOG_LEVEL_ALL); + LogComponentEnable ("Icmpv6L4Protocol", LOG_LEVEL_ALL); + LogComponentEnable ("Ipv6StaticRouting", LOG_LEVEL_ALL); + LogComponentEnable ("Ipv6Interface", LOG_LEVEL_ALL); + LogComponentEnable ("Ping6Application", LOG_LEVEL_ALL); + } + + NS_LOG_INFO ("Create nodes."); + Ptr n0 = CreateObject (); + Ptr r1 = CreateObject (); + Ptr n1 = CreateObject (); + Ptr r2 = CreateObject (); + Ptr n2 = CreateObject (); + + NodeContainer net1 (n0, r1); + NodeContainer net2 (r1, n1, r2); + NodeContainer net3 (r2, n2); + NodeContainer all (n0, r1, n1, r2, n2); + + NS_LOG_INFO ("Create IPv6 Internet Stack"); + InternetStackHelper internetv6; + internetv6.Install (all); + + NS_LOG_INFO ("Create channels."); + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", DataRateValue (5000000)); + csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + csma.SetDeviceAttribute ("Mtu", UintegerValue (2000)); + NetDeviceContainer d2 = csma.Install (net2); // CSMA Network with MTU 2000 + + csma.SetDeviceAttribute ("Mtu", UintegerValue (5000)); + NetDeviceContainer d1 = csma.Install (net1); // CSMA Network with MTU 5000 + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", DataRateValue (5000000)); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + pointToPoint.SetDeviceAttribute ("Mtu", UintegerValue (1500)); + NetDeviceContainer d3 = pointToPoint.Install (net3); // P2P Network with MTU 1500 + + NS_LOG_INFO ("Create networks and assign IPv6 Addresses."); + Ipv6AddressHelper ipv6; + + ipv6.SetBase (Ipv6Address ("2001:1::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer i1 = ipv6.Assign (d1); + i1.SetForwarding (1, true); + i1.SetDefaultRouteInAllNodes (1); + + ipv6.SetBase (Ipv6Address ("2001:2::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer i2 = ipv6.Assign (d2); + i2.SetForwarding (0, true); + i2.SetDefaultRouteInAllNodes (0); + i2.SetForwarding (1, true); + i2.SetDefaultRouteInAllNodes (0); + i2.SetForwarding (2, true); + i2.SetDefaultRouteInAllNodes (2); + + ipv6.SetBase (Ipv6Address ("2001:3::"), Ipv6Prefix (64)); + Ipv6InterfaceContainer i3 = ipv6.Assign (d3); + i3.SetForwarding (0, true); + i3.SetDefaultRouteInAllNodes (0); + + Ipv6StaticRoutingHelper routingHelper; + Ptr routingStream = Create (&std::cout); + routingHelper.PrintRoutingTableAt (Seconds (0), r1, routingStream); + + /* Create a Ping6 application to send ICMPv6 echo request from r to n2 */ + uint32_t packetSize = 1600; // Packet should fragment as intermediate link MTU is 1500 + uint32_t maxPacketCount = 5; + Time interPacketInterval = Seconds (1.0); + Ping6Helper ping6; + + ping6.SetLocal (i2.GetAddress (1, 1)); + ping6.SetRemote (i3.GetAddress (1, 1)); + + ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); + ping6.SetAttribute ("Interval", TimeValue (interPacketInterval)); + ping6.SetAttribute ("PacketSize", UintegerValue (packetSize)); + ApplicationContainer apps = ping6.Install (n1); + apps.Start (Seconds (2.0)); + apps.Stop (Seconds (10.0)); + + /* Create a Ping6 application to send ICMPv6 echo request from n0 to n2 */ + packetSize = 4000; + ping6.SetAttribute ("PacketSize", UintegerValue (packetSize)); + + ping6.SetLocal (i1.GetAddress (0, 1)); + ping6.SetRemote (i3.GetAddress (1, 1)); + apps = ping6.Install (n0); + apps.Start (Seconds (11.0)); + apps.Stop (Seconds (20.0)); + + AsciiTraceHelper ascii; + csma.EnableAsciiAll (ascii.CreateFileStream ("fragmentation-ipv6-PMTU.tr")); + csma.EnablePcapAll (std::string ("fragmentation-ipv6-PMTU"), true); + pointToPoint.EnablePcapAll (std::string ("fragmentation-ipv6-PMTU"), true); + + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} diff --git a/examples/ipv6/wscript b/examples/ipv6/wscript index ce9551d6d..ac1403074 100644 --- a/examples/ipv6/wscript +++ b/examples/ipv6/wscript @@ -28,3 +28,5 @@ def build(bld): obj = bld.create_ns3_program('wsn-ping6', ['lr-wpan', 'internet', 'sixlowpan', 'mobility', 'internet-apps']) obj.source = 'wsn-ping6.cc' + obj = bld.create_ns3_program('fragmentation-ipv6-PMTU', ['csma', 'internet', 'internet-apps', 'point-to-point']) + obj.source = 'fragmentation-ipv6-PMTU.cc' diff --git a/src/internet/model/ipv6-l3-protocol.cc b/src/internet/model/ipv6-l3-protocol.cc index 4cfc2d011..10a517fec 100644 --- a/src/internet/model/ipv6-l3-protocol.cc +++ b/src/internet/model/ipv6-l3-protocol.cc @@ -1116,35 +1116,42 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6 // Check packet size std::list fragments; + // Check if this is the source of the packet + bool fromMe = false; + for (uint32_t i = 0; i < GetNInterfaces (); i++ ) + { + for (uint32_t j = 0; j < GetNAddresses (i); j++ ) + { + if (GetAddress (i,j).GetAddress () == ipHeader.GetSource ()) + { + fromMe = true; + break; + } + } + } + + size_t targetMtu = 0; + // Check if we have a Path MTU stored. If so, use it. Else, use the link MTU. - size_t targetMtu = (size_t)(m_pmtuCache->GetPmtu (ipHeader.GetDestination())); + // Note: PMTU must not be cached in intermediate nodes, and must be checked only by the source node + if (fromMe) + { + targetMtu = (size_t)(m_pmtuCache->GetPmtu (ipHeader.GetDestination ())); + } if (targetMtu == 0) { targetMtu = dev->GetMtu (); } - if (packet->GetSize () > targetMtu + 40) /* 40 => size of IPv6 header */ + if (packet->GetSize () + ipHeader.GetSerializedSize () > targetMtu) { // Router => drop - - bool fromMe = false; - for (uint32_t i=0; i icmpv6 = GetIcmpv6 (); if ( icmpv6 ) { - packet->AddHeader(ipHeader); + packet->AddHeader (ipHeader); icmpv6->SendErrorTooBig (packet, ipHeader.GetSource (), dev->GetMtu ()); } return; diff --git a/src/internet/model/ipv6.h b/src/internet/model/ipv6.h index 415e84867..fa1efab7d 100644 --- a/src/internet/model/ipv6.h +++ b/src/internet/model/ipv6.h @@ -365,7 +365,9 @@ public: /** * \brief Higher-level layers call this method to send a packet - * down the stack to the MAC and PHY layers. + * down the stack to the MAC and PHY layers. All PMTU values are + * stored at this level, so packet size calculations should be + * done mathematically at higher levels. * * \param packet packet to send * \param source source address of packet diff --git a/src/internet/test/ipv6-fragmentation-test.cc b/src/internet/test/ipv6-fragmentation-test.cc index 4083af50c..a879e6207 100644 --- a/src/internet/test/ipv6-fragmentation-test.cc +++ b/src/internet/test/ipv6-fragmentation-test.cc @@ -176,6 +176,26 @@ public: * \returns The sent packet. */ Ptr SendClient (void); + + /** + * \brief Handle Server's incoming packets. + * Ensure no packet greater than MTU is received + * + * \param packet the packet. + * \param ipv6 the Ipv6 protocol. + * \param interface the IP-level interface index. + */ + void HandleServerRx (Ptr packet, Ptr ipv6, uint32_t interface); + + /** + * \brief Handle Client's transmitting packets. + * Ensure no packet greater than MTU is transmitted + * + * \param packet the packet. + * \param ipv6 the Ipv6 protocol. + * \param interface the IP-level interface index. + */ + void HandleClientTx (Ptr packet, Ptr ipv6, uint32_t interface); }; @@ -320,6 +340,16 @@ Ptr Ipv6FragmentationTest::SendClient (void) return p; } +void Ipv6FragmentationTest::HandleServerRx (Ptr packet, Ptr ipv6, uint32_t interface) +{ + NS_TEST_EXPECT_MSG_LT_OR_EQ (packet->GetSize (), ipv6->GetMtu (interface), "Received packet size > MTU: packetSizes: " << packet->GetSize ()); +} + +void Ipv6FragmentationTest::HandleClientTx (Ptr packet, Ptr ipv6, uint32_t interface) +{ + NS_TEST_EXPECT_MSG_LT_OR_EQ (packet->GetSize (), ipv6->GetMtu (interface), "Transmitted packet size > MTU: packetSizes: " << packet->GetSize ()); +} + void Ipv6FragmentationTest::DoRun (void) { @@ -345,6 +375,7 @@ Ipv6FragmentationTest::DoRun (void) Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::1"), Ipv6Prefix (32)); ipv6->AddAddress (netdev_idx, ipv6Addr); ipv6->SetUp (netdev_idx); + ipv6->TraceConnectWithoutContext ("Rx", MakeCallback (&Ipv6FragmentationTest::HandleServerRx, this)); } StartServer (serverNode); @@ -365,6 +396,7 @@ Ipv6FragmentationTest::DoRun (void) Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::2"), Ipv6Prefix (32)); ipv6->AddAddress (netdev_idx, ipv6Addr); ipv6->SetUp (netdev_idx); + ipv6->TraceConnectWithoutContext ("Tx", MakeCallback (&Ipv6FragmentationTest::HandleClientTx, this)); } StartClient (clientNode); @@ -376,7 +408,7 @@ Ipv6FragmentationTest::DoRun (void) // some small packets, some rather big ones - uint32_t packetSizes[5] = {2000, 2500, 5000, 10000, 65000}; + uint32_t packetSizes[5] = {1500, 2000, 5000, 10000, 65000}; // using the alphabet uint8_t fillData[78];