internet: fix errors in IPv6 Path MTU discovery.
This commit is contained in:
committed by
Tommaso Pecorella
parent
9342082c53
commit
bd7a35f821
@@ -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}"
|
||||
)
|
||||
|
||||
160
examples/ipv6/fragmentation-ipv6-PMTU.cc
Normal file
160
examples/ipv6/fragmentation-ipv6-PMTU.cc
Normal 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.");
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user