internet: fix errors in IPv6 Path MTU discovery.

This commit is contained in:
Akash Mondal
2022-01-26 23:42:10 +00:00
committed by Tommaso Pecorella
parent 9342082c53
commit bd7a35f821
6 changed files with 231 additions and 18 deletions

View File

@@ -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}"
)

View File

@@ -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 <gdavid.devel@gmail.com>
* Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
* Modified by Akash Mondal <a98mondal@gmail.com>
*/
// 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 <fstream>
#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<Node> n0 = CreateObject<Node> ();
Ptr<Node> r1 = CreateObject<Node> ();
Ptr<Node> n1 = CreateObject<Node> ();
Ptr<Node> r2 = CreateObject<Node> ();
Ptr<Node> n2 = CreateObject<Node> ();
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<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> (&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.");
}

View File

@@ -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'

View File

@@ -1116,35 +1116,42 @@ void Ipv6L3Protocol::SendRealOut (Ptr<Ipv6Route> route, Ptr<Packet> packet, Ipv6
// Check packet size
std::list<Ipv6ExtensionFragment::Ipv6PayloadHeaderPair> 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<GetNInterfaces(); i++ )
{
for (uint32_t j=0; j<GetNAddresses(i); j++ )
{
if (GetAddress(i,j).GetAddress() == ipHeader.GetSource())
{
fromMe = true;
break;
}
}
}
if (!fromMe)
{
Ptr<Icmpv6L4Protocol> icmpv6 = GetIcmpv6 ();
if ( icmpv6 )
{
packet->AddHeader(ipHeader);
packet->AddHeader (ipHeader);
icmpv6->SendErrorTooBig (packet, ipHeader.GetSource (), dev->GetMtu ());
}
return;

View File

@@ -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

View File

@@ -176,6 +176,26 @@ public:
* \returns The sent packet.
*/
Ptr<Packet> 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<const Packet> packet, Ptr<Ipv6> 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<const Packet> packet, Ptr<Ipv6> ipv6, uint32_t interface);
};
@@ -320,6 +340,16 @@ Ptr<Packet> Ipv6FragmentationTest::SendClient (void)
return p;
}
void Ipv6FragmentationTest::HandleServerRx (Ptr<const Packet> packet, Ptr<Ipv6> 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<const Packet> packet, Ptr<Ipv6> 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];