From 17e7d24deb4190ee1cc022f94f773b7329785064 Mon Sep 17 00:00:00 2001
From: Tommaso Pecorella
Date: Mon, 12 Aug 2013 06:51:18 +0200
Subject: [PATCH] Bug 1721 - Path MTU isn't handled properly
---
CHANGES.html | 2 +
RELEASE_NOTES | 3 +
examples/ipv6/fragmentation-ipv6-two-MTU.cc | 169 ++++++++++++++++++++
examples/ipv6/wscript | 3 +
src/internet/model/icmpv6-l4-protocol.cc | 4 +
src/internet/model/ipv6-l3-protocol.cc | 42 ++++-
src/internet/model/ipv6-l3-protocol.h | 30 ++++
src/internet/model/ipv6-pmtu-cache.cc | 115 +++++++++++++
src/internet/model/ipv6-pmtu-cache.h | 122 ++++++++++++++
src/internet/model/ipv6.cc | 10 +-
src/internet/model/ipv6.h | 19 +++
src/internet/wscript | 2 +
12 files changed, 513 insertions(+), 8 deletions(-)
create mode 100644 examples/ipv6/fragmentation-ipv6-two-MTU.cc
create mode 100644 src/internet/model/ipv6-pmtu-cache.cc
create mode 100644 src/internet/model/ipv6-pmtu-cache.h
diff --git a/CHANGES.html b/CHANGES.html
index e1d17779b..58b766810 100644
--- a/CHANGES.html
+++ b/CHANGES.html
@@ -69,6 +69,8 @@ us a note on ns-developers mailing list.
an Autoconfigured address.
Mac64Address support has been extended. It can now be used with
IPv6 to make an Autoconfigured address.
+ IPv6 can now detect and use Path-MTU. See
+ examples/ipv6/fragmentation-ipv6-two-MTU.cc for an example.
Changes to existing API:
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 9603f2f34..7e3525720 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -39,6 +39,8 @@ New user-visible features
- PHY support for UE measurements (RSRP and RSRQ)
- RRC support for UE measurements (configuration, execution, reporting)
- Automatic Handover trigger based on RRC UE measurement reports
+- IPv6 can now detect and use Path-MTU. See
+ examples/ipv6/fragmentation-ipv6-two-MTU.cc for an example.
Bugs fixed
----------
@@ -63,6 +65,7 @@ Bugs fixed
- Bug 1712 - The IP (v4 and v6) forwarding needs a test
- Bug 1718 - Ipv4StaticRouting log component is misspelled
- Bug 1720 - IPv6 Fragmentation cause crashes
+- Bug 1721 - Path MTU isn't handled properly
- Bug 1727 - Ping6 should use a proper source address
- Bug 1731 - lte-phy-error-model passes unexpectedly
- Bug 1742 - IPv6 HbH and Dst Extension Header size is not correctly calculated
diff --git a/examples/ipv6/fragmentation-ipv6-two-MTU.cc b/examples/ipv6/fragmentation-ipv6-two-MTU.cc
new file mode 100644
index 000000000..fe7cf0e70
--- /dev/null
+++ b/examples/ipv6/fragmentation-ipv6-two-MTU.cc
@@ -0,0 +1,169 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008-2009 Strasbourg University
+ * Copyright (c) 2013 Universita' di Firenze
+ *
+ * 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 Tommaso Pecorella
+ */
+
+// Network topology
+// //
+// // Src n0 r n1 Dst
+// // | _ |
+// // MTU ====|_|==== MTU
+// // 5000 router 1500
+// //
+// // - Tracing of queues and packet receptions to file "fragmentation-ipv6-two-mtu.tr"
+
+#include
+#include "ns3/core-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/csma-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/ipv6-static-routing-helper.h"
+
+#include "ns3/ipv6-routing-table-entry.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("FragmentationIpv6TwoMtuExample");
+
+/**
+ * \class StackHelper
+ * \brief Helper to set or get some IPv6 information about nodes.
+ */
+class StackHelper
+{
+public:
+ /**
+ * \brief Add an address to a IPv6 node.
+ * \param n node
+ * \param interface interface index
+ * \param address IPv6 address to add
+ */
+ inline void AddAddress (Ptr& n, uint32_t interface, Ipv6Address address)
+ {
+ Ptr ipv6 = n->GetObject ();
+ ipv6->AddAddress (interface, address);
+ }
+
+ /**
+ * \brief Print the routing table.
+ * \param n the node
+ */
+ inline void PrintRoutingTable (Ptr& n)
+ {
+ Ptr routing = 0;
+ Ipv6StaticRoutingHelper routingHelper;
+ Ptr ipv6 = n->GetObject ();
+ uint32_t nbRoutes = 0;
+ Ipv6RoutingTableEntry route;
+
+ routing = routingHelper.GetStaticRouting (ipv6);
+
+ std::cout << "Routing table of " << n << " : " << std::endl;
+ std::cout << "Destination\t\t\t\t" << "Gateway\t\t\t\t\t" << "Interface\t" << "Prefix to use" << std::endl;
+
+ nbRoutes = routing->GetNRoutes ();
+ for (uint32_t i = 0; i < nbRoutes; i++)
+ {
+ route = routing->GetRoute (i);
+ std::cout << route.GetDest () << "\t"
+ << route.GetGateway () << "\t"
+ << route.GetInterface () << "\t"
+ << route.GetPrefixToUse () << "\t"
+ << std::endl;
+ }
+ }
+};
+
+int main (int argc, char** argv)
+{
+#if 0
+ 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);
+#endif
+
+ CommandLine cmd;
+ cmd.Parse (argc, argv);
+
+ StackHelper stackHelper;
+
+ NS_LOG_INFO ("Create nodes.");
+ Ptr n0 = CreateObject ();
+ Ptr r = CreateObject ();
+ Ptr n1 = CreateObject ();
+
+ NodeContainer net1 (n0, r);
+ NodeContainer net2 (r, n1);
+ NodeContainer all (n0, r, n1);
+
+ 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)));
+ NetDeviceContainer d2 = csma.Install (net2);
+ csma.SetDeviceAttribute ("Mtu", UintegerValue (5000));
+ NetDeviceContainer d1 = csma.Install (net1);
+
+ 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);
+
+ stackHelper.PrintRoutingTable (n0);
+
+ /* Create a Ping6 application to send ICMPv6 echo request from n0 to n1 via r */
+ uint32_t packetSize = 4096;
+ uint32_t maxPacketCount = 5;
+ Time interPacketInterval = Seconds (1.0);
+ Ping6Helper ping6;
+
+ ping6.SetLocal (i1.GetAddress (0, 1));
+ ping6.SetRemote (i2.GetAddress (1, 1));
+
+ ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
+ ping6.SetAttribute ("Interval", TimeValue (interPacketInterval));
+ ping6.SetAttribute ("PacketSize", UintegerValue (packetSize));
+ ApplicationContainer apps = ping6.Install (net1.Get (0));
+ apps.Start (Seconds (2.0));
+ apps.Stop (Seconds (20.0));
+
+ AsciiTraceHelper ascii;
+ csma.EnableAsciiAll (ascii.CreateFileStream ("fragmentation-ipv6-two-mtu.tr"));
+ csma.EnablePcapAll (std::string ("fragmentation-ipv6-two-mtu"), 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 5c3b86be9..609f3b637 100644
--- a/examples/ipv6/wscript
+++ b/examples/ipv6/wscript
@@ -18,6 +18,9 @@ def build(bld):
obj = bld.create_ns3_program('fragmentation-ipv6', ['csma', 'internet'])
obj.source = 'fragmentation-ipv6.cc'
+
+ obj = bld.create_ns3_program('fragmentation-ipv6-two-MTU', ['csma', 'internet'])
+ obj.source = 'fragmentation-ipv6-two-MTU.cc'
obj = bld.create_ns3_program('loose-routing-ipv6', ['csma', 'internet'])
obj.source = 'loose-routing-ipv6.cc'
diff --git a/src/internet/model/icmpv6-l4-protocol.cc b/src/internet/model/icmpv6-l4-protocol.cc
index 827b37cb2..3ec0fe413 100644
--- a/src/internet/model/icmpv6-l4-protocol.cc
+++ b/src/internet/model/icmpv6-l4-protocol.cc
@@ -835,6 +835,10 @@ void Icmpv6L4Protocol::HandlePacketTooBig (Ptr p, Ipv6Address const &src
origPkt->RemoveHeader (ipHeader);
uint8_t payload[8];
origPkt->CopyData (payload, 8);
+
+ Ptr ipv6 = m_node->GetObject ();
+ ipv6->SetPmtu(ipHeader.GetDestinationAddress(), tooBig.GetMtu ());
+
Forward (src, tooBig, tooBig.GetMtu (), ipHeader, payload);
}
diff --git a/src/internet/model/ipv6-l3-protocol.cc b/src/internet/model/ipv6-l3-protocol.cc
index 0ef79e0ac..7ac57c146 100644
--- a/src/internet/model/ipv6-l3-protocol.cc
+++ b/src/internet/model/ipv6-l3-protocol.cc
@@ -44,6 +44,9 @@
#include "icmpv6-l4-protocol.h"
#include "ndisc-cache.h"
+// Minimum IPv6 MTU, as defined by RFC 2460
+#define IPV6_MIN_MTU 1280
+
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (Ipv6L3Protocol);
@@ -88,6 +91,7 @@ Ipv6L3Protocol::Ipv6L3Protocol ()
: m_nInterfaces (0)
{
NS_LOG_FUNCTION_NOARGS ();
+ m_pmtuCache = CreateObject ();
}
Ipv6L3Protocol::~Ipv6L3Protocol ()
@@ -131,6 +135,7 @@ void Ipv6L3Protocol::DoDispose ()
m_node = 0;
m_routingProtocol = 0;
+ m_pmtuCache = 0;
Object::DoDispose ();
}
@@ -449,10 +454,24 @@ uint16_t Ipv6L3Protocol::GetMetric (uint32_t i) const
uint16_t Ipv6L3Protocol::GetMtu (uint32_t i) const
{
NS_LOG_FUNCTION (this << i);
+
+ // RFC 1981, if PMTU is disabled, return the minimum MTU
+ if (!m_mtuDiscover)
+ {
+ return IPV6_MIN_MTU;
+ }
+
Ptr interface = GetInterface (i);
return interface->GetDevice ()->GetMtu ();
}
+void Ipv6L3Protocol::SetPmtu (Ipv6Address dst, uint32_t pmtu)
+{
+ NS_LOG_FUNCTION (this << dst << int(pmtu));
+ m_pmtuCache->SetPmtu (dst, pmtu);
+}
+
+
bool Ipv6L3Protocol::IsUp (uint32_t i) const
{
NS_LOG_FUNCTION (this << i);
@@ -556,6 +575,18 @@ bool Ipv6L3Protocol::GetIpForward () const
return m_ipForward;
}
+void Ipv6L3Protocol::SetMtuDiscover (bool mtuDiscover)
+{
+ NS_LOG_FUNCTION (this << int(mtuDiscover));
+ m_mtuDiscover = mtuDiscover;
+}
+
+bool Ipv6L3Protocol::GetMtuDiscover () const
+{
+ NS_LOG_FUNCTION (this);
+ return m_mtuDiscover;
+}
+
void Ipv6L3Protocol::SetSendIcmpv6Redirect (bool sendIcmpv6Redirect)
{
NS_LOG_FUNCTION (this << sendIcmpv6Redirect);
@@ -848,7 +879,14 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6
// Check packet size
std::list > fragments;
- if (packet->GetSize () > (size_t)(dev->GetMtu () + 40)) /* 40 => size of IPv6 header */
+ // 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.GetDestinationAddress()));
+ if (targetMtu == 0)
+ {
+ targetMtu = dev->GetMtu ();
+ }
+
+ if (packet->GetSize () > targetMtu + 40) /* 40 => size of IPv6 header */
{
// Router => drop
@@ -882,7 +920,7 @@ void Ipv6L3Protocol::SendRealOut (Ptr route, Ptr packet, Ipv6
// To get specific method GetFragments from Ipv6ExtensionFragmentation
Ipv6ExtensionFragment *ipv6Fragment = dynamic_cast (PeekPointer (ipv6ExtensionDemux->GetExtension (Ipv6Header::IPV6_EXT_FRAGMENTATION)));
NS_ASSERT (ipv6Fragment != 0);
- ipv6Fragment->GetFragments (packet, outInterface->GetDevice ()->GetMtu (), fragments);
+ ipv6Fragment->GetFragments (packet, targetMtu, fragments);
}
if (!route->GetGateway ().IsEqual (Ipv6Address::GetAny ()))
diff --git a/src/internet/model/ipv6-l3-protocol.h b/src/internet/model/ipv6-l3-protocol.h
index 116d27a6b..e6118e103 100644
--- a/src/internet/model/ipv6-l3-protocol.h
+++ b/src/internet/model/ipv6-l3-protocol.h
@@ -28,6 +28,7 @@
#include "ns3/ipv6.h"
#include "ns3/ipv6-address.h"
#include "ns3/ipv6-header.h"
+#include "ns3/ipv6-pmtu-cache.h"
namespace ns3
{
@@ -277,6 +278,13 @@ public:
*/
uint16_t GetMtu (uint32_t i) const;
+ /**
+ * \brief Set the Path MTU for the specified IPv6 destination address.
+ * \param dst Ipv6 destination address
+ * \param pmtu the Path MTU
+ */
+ virtual void SetPmtu (Ipv6Address dst, uint32_t pmtu);
+
/**
* \brief Is specified interface up ?
* \param i interface index
@@ -484,6 +492,18 @@ private:
*/
virtual bool GetIpForward () const;
+ /**
+ * \brief Set IPv6 MTU discover state.
+ * \param mtuDiscover IPv6 MTU discover enabled or not
+ */
+ virtual void SetMtuDiscover (bool mtuDiscover);
+
+ /**
+ * \brief Get IPv6 MTU discover state.
+ * \return MTU discover state (enabled or not)
+ */
+ virtual bool GetMtuDiscover (void) const;
+
/**
* \brief Set the ICMPv6 Redirect sending state.
* \param sendIcmpv6Redirect ICMPv6 Redirect sending enabled or not
@@ -506,6 +526,16 @@ private:
*/
bool m_ipForward;
+ /**
+ * \brief MTU Discover (i.e. Path MTU) state.
+ */
+ bool m_mtuDiscover;
+
+ /**
+ * \brief Path MTU Cache.
+ */
+ Ptr m_pmtuCache;
+
/**
* \brief List of transport protocol.
*/
diff --git a/src/internet/model/ipv6-pmtu-cache.cc b/src/internet/model/ipv6-pmtu-cache.cc
new file mode 100644
index 000000000..33197e091
--- /dev/null
+++ b/src/internet/model/ipv6-pmtu-cache.cc
@@ -0,0 +1,115 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 Universita' di Firenze
+ *
+ * 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: Tommaso Pecorella
+ */
+
+#include "ipv6-pmtu-cache.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("Ipv6PmtuCache");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (Ipv6PmtuCache);
+
+TypeId Ipv6PmtuCache::GetTypeId ()
+{
+ static TypeId tid = TypeId ("ns3::Ipv6PmtuCache")
+ .SetParent