Bug 1721 - Path MTU isn't handled properly
authorTommaso Pecorella <tommaso.pecorella@unifi.it>
Mon, 12 Aug 2013 06:51:18 +0200
changeset 10127 f4cee68de571
parent 10126 9af31e6577bb
child 10128 f30c35341c5a
Bug 1721 - Path MTU isn't handled properly
CHANGES.html
RELEASE_NOTES
examples/ipv6/fragmentation-ipv6-two-MTU.cc
examples/ipv6/wscript
src/internet/model/icmpv6-l4-protocol.cc
src/internet/model/ipv6-l3-protocol.cc
src/internet/model/ipv6-l3-protocol.h
src/internet/model/ipv6-pmtu-cache.cc
src/internet/model/ipv6-pmtu-cache.h
src/internet/model/ipv6.cc
src/internet/model/ipv6.h
src/internet/wscript
--- a/CHANGES.html	Sun Aug 11 20:53:01 2013 -0700
+++ b/CHANGES.html	Mon Aug 12 06:51:18 2013 +0200
@@ -69,6 +69,8 @@
       an Autoconfigured address.</li>
   <li>Mac64Address support has been extended. It can now be used with 
       IPv6 to make an Autoconfigured address.</li>
+  <li>IPv6 can now detect and use Path-MTU. See 
+      examples/ipv6/fragmentation-ipv6-two-MTU.cc for an example.</li>
 </ul>
 
 <h2>Changes to existing API:</h2>
--- a/RELEASE_NOTES	Sun Aug 11 20:53:01 2013 -0700
+++ b/RELEASE_NOTES	Mon Aug 12 06:51:18 2013 +0200
@@ -39,6 +39,8 @@
    - 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 @@
 - 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/ipv6/fragmentation-ipv6-two-MTU.cc	Mon Aug 12 06:51:18 2013 +0200
@@ -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 <gdavid.devel@gmail.com>
+ *         Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
+ * Modified by Tommaso Pecorella <tommaso.pecorella@unifi.it>
+ */
+
+// 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 <fstream>
+#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<Node>& n, uint32_t interface, Ipv6Address address)
+  {
+    Ptr<Ipv6> ipv6 = n->GetObject<Ipv6> ();
+    ipv6->AddAddress (interface, address);
+  }
+
+  /**
+   * \brief Print the routing table.
+   * \param n the node
+   */
+  inline void PrintRoutingTable (Ptr<Node>& n)
+  {
+    Ptr<Ipv6StaticRouting> routing = 0;
+    Ipv6StaticRoutingHelper routingHelper;
+    Ptr<Ipv6> ipv6 = n->GetObject<Ipv6> ();
+    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<Node> n0 = CreateObject<Node> ();
+  Ptr<Node> r = CreateObject<Node> ();
+  Ptr<Node> n1 = CreateObject<Node> ();
+
+  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.");
+}
+
--- a/examples/ipv6/wscript	Sun Aug 11 20:53:01 2013 -0700
+++ b/examples/ipv6/wscript	Mon Aug 12 06:51:18 2013 +0200
@@ -18,6 +18,9 @@
     
     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'
--- a/src/internet/model/icmpv6-l4-protocol.cc	Sun Aug 11 20:53:01 2013 -0700
+++ b/src/internet/model/icmpv6-l4-protocol.cc	Mon Aug 12 06:51:18 2013 +0200
@@ -835,6 +835,10 @@
   origPkt->RemoveHeader (ipHeader);
   uint8_t payload[8];
   origPkt->CopyData (payload, 8);
+
+  Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol> ();
+  ipv6->SetPmtu(ipHeader.GetDestinationAddress(), tooBig.GetMtu ());
+
   Forward (src, tooBig, tooBig.GetMtu (), ipHeader, payload);
 }
 
--- a/src/internet/model/ipv6-l3-protocol.cc	Sun Aug 11 20:53:01 2013 -0700
+++ b/src/internet/model/ipv6-l3-protocol.cc	Mon Aug 12 06:51:18 2013 +0200
@@ -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 @@
   : m_nInterfaces (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
+  m_pmtuCache = CreateObject<Ipv6PmtuCache> ();
 }
 
 Ipv6L3Protocol::~Ipv6L3Protocol ()
@@ -131,6 +135,7 @@
 
   m_node = 0;
   m_routingProtocol = 0;
+  m_pmtuCache = 0;
   Object::DoDispose ();
 }
 
@@ -449,10 +454,24 @@
 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<Ipv6Interface> 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 @@
   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 @@
   // Check packet size
   std::list<Ptr<Packet> > 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 @@
       // To get specific method GetFragments from Ipv6ExtensionFragmentation
       Ipv6ExtensionFragment *ipv6Fragment = dynamic_cast<Ipv6ExtensionFragment *> (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 ()))
--- a/src/internet/model/ipv6-l3-protocol.h	Sun Aug 11 20:53:01 2013 -0700
+++ b/src/internet/model/ipv6-l3-protocol.h	Mon Aug 12 06:51:18 2013 +0200
@@ -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
 {
@@ -278,6 +279,13 @@
   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
    */
@@ -485,6 +493,18 @@
   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
    */
@@ -507,6 +527,16 @@
   bool m_ipForward;
 
   /**
+   * \brief MTU Discover (i.e. Path MTU) state.
+   */
+  bool m_mtuDiscover;
+
+  /**
+   * \brief Path MTU Cache.
+   */
+  Ptr<Ipv6PmtuCache> m_pmtuCache;
+
+  /**
    * \brief List of transport protocol.
    */
   L4List_t m_protocols;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/model/ipv6-pmtu-cache.cc	Mon Aug 12 06:51:18 2013 +0200
@@ -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 <tommaso.pecorella@unifi.it>
+ */
+
+#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<Object> ()
+    .AddAttribute ("CacheExpiryTime",
+                   "Validity time for a Path MTU entry. Default is 10 minutes, minimum is 5 minutes.",
+                   TimeValue (Seconds (60 * 10)),
+                   MakeTimeAccessor (&Ipv6PmtuCache::m_validityTime),
+                   MakeTimeChecker (Time (Seconds (60 * 5))))
+  ;
+  return tid;
+}
+
+Ipv6PmtuCache::Ipv6PmtuCache ()
+{
+}
+
+Ipv6PmtuCache::~Ipv6PmtuCache ()
+{
+}
+
+void Ipv6PmtuCache::DoDispose ()
+{
+  for (pathMtuTimerIter iter = m_pathMtuTimer.begin (); iter != m_pathMtuTimer.end (); iter++)
+    {
+      iter->second.Cancel ();
+    }
+  m_pathMtuTimer.clear ();
+  m_pathMtu.clear ();
+}
+
+uint32_t Ipv6PmtuCache::GetPmtu (Ipv6Address dst)
+{
+  NS_LOG_FUNCTION (this << dst);
+
+  if (m_pathMtu.find (dst) != m_pathMtu.end ())
+    {
+      return m_pathMtu[dst];
+    }
+  return 0;
+}
+
+void Ipv6PmtuCache::SetPmtu (Ipv6Address dst, uint32_t pmtu)
+{
+  NS_LOG_FUNCTION (this << dst << pmtu);
+
+  m_pathMtu[dst] = pmtu;
+  if (m_pathMtuTimer.find (dst) != m_pathMtuTimer.end ())
+    {
+      m_pathMtuTimer[dst].Cancel ();
+    }
+  EventId pMtuTimer;
+  pMtuTimer = Simulator::Schedule (m_validityTime, &Ipv6PmtuCache::ClearPmtu, this, dst);
+  m_pathMtuTimer[dst] = pMtuTimer;
+}
+
+Time Ipv6PmtuCache::GetPmtuValidityTime () const
+{
+  NS_LOG_FUNCTION (this);
+  return m_validityTime;
+}
+
+bool Ipv6PmtuCache::SetPmtuValidityTime (Time validity)
+{
+  NS_LOG_FUNCTION (this << validity);
+
+  if (validity > Seconds (60 * 5))
+    {
+      m_validityTime = validity;
+      return true;
+    }
+
+  NS_LOG_LOGIC ("rejecting a PMTU validity timer lesser than 5 minutes");
+  return false;
+}
+
+void Ipv6PmtuCache::ClearPmtu (Ipv6Address dst)
+{
+  NS_LOG_FUNCTION (this << dst);
+
+  m_pathMtu.erase (dst);
+  m_pathMtuTimer.erase (dst);
+}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/internet/model/ipv6-pmtu-cache.h	Mon Aug 12 06:51:18 2013 +0200
@@ -0,0 +1,122 @@
+/* -*- 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 <tommaso.pecorella@unifi.it>
+ */
+
+#ifndef IPV6_PMTU_CACHE_H
+#define IPV6_PMTU_CACHE_H
+
+#include <map>
+
+#include "ns3/core-module.h"
+#include "ns3/ipv6-address.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup ipv6
+ * \brief This class implements the Path MTU cache, as defined by RFC 1981.
+ *
+ * The Path MTU is stored according to the destination address, and it is
+ * cleared upon expiration (default validity time is 10 minutes).
+ *
+ * The "infinite lifetime" PMTU entry type is not implemented, since it is
+ * useful only in an very limited number of cases. See the RFC for further
+ * details.
+ */
+
+class Ipv6PmtuCache : public Object
+{
+public:
+  class Entry;
+
+  /**
+   * \brief Get the type ID
+   * \return type ID
+   */
+  static TypeId GetTypeId ();
+
+  /**
+   * \brief Constructor.
+   */
+  Ipv6PmtuCache ();
+
+  /**
+   * \brief Destructor.
+   */
+  ~Ipv6PmtuCache ();
+
+  /**
+   * \brief Dispose object.
+   */
+  virtual void DoDispose ();
+
+  /**
+   * \brief Gets the known Path MTU for the specific destination
+   * \param dst the destination
+   * \return the Path MTU (zero if unknown)
+   */
+  uint32_t GetPmtu (Ipv6Address dst);
+
+  /**
+   * \brief Sets the Path MTU for the specific destination
+   * \param dst the destination
+   * \param pmtu the Path MTU
+   */
+  void SetPmtu (Ipv6Address dst, uint32_t pmtu);
+
+  /**
+   * \brief Gets the Path MTU validity time
+   * \return the Path MTU validity time
+   */
+  Time GetPmtuValidityTime () const;
+
+  /**
+   * \brief Sets the Path MTU validity time (minimum is 5 minutes)
+   * \param validity the Path MTU validity time
+   * \return true if the change was successful
+   */
+  bool SetPmtuValidityTime (Time validity);
+
+private:
+  /**
+   * \brief Clears the Path MTU for the specific destination
+   * \param dst the destination
+   */
+  void ClearPmtu (Ipv6Address dst);
+
+  /**
+   * \brief Path MTU table
+   */
+  std::map<Ipv6Address, uint32_t> m_pathMtu;
+
+  typedef std::map<Ipv6Address, EventId> ::iterator pathMtuTimerIter;
+  /**
+   * \brief Path MTU Expiration table
+   */
+  std::map<Ipv6Address, EventId> m_pathMtuTimer;
+
+  /**
+   * \brief Path MTU entry validity time
+   */
+  Time m_validityTime;
+};
+
+}
+
+#endif /* IPV6_PMTU_CACHE_H */
--- a/src/internet/model/ipv6.cc	Sun Aug 11 20:53:01 2013 -0700
+++ b/src/internet/model/ipv6.cc	Mon Aug 12 06:51:18 2013 +0200
@@ -40,13 +40,11 @@
                    MakeBooleanAccessor (&Ipv6::SetIpForward,
                                         &Ipv6::GetIpForward),
                    MakeBooleanChecker ())
-#if 0
-    .AddAttribute ("MtuDiscover", "If enabled, every outgoing IPv6 packet will have the DF flag set.",
-                   BooleanValue (false),
-                   MakeBooleanAccessor (&UdpSocket::SetMtuDiscover,
-                                        &UdpSocket::GetMtuDiscover),
+    .AddAttribute ("MtuDiscover", "If disabled, every interface will have its MTU set to 1280 bytes.",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&Ipv6::SetMtuDiscover,
+                                        &Ipv6::GetMtuDiscover),
                    MakeBooleanChecker ())
-#endif
   ;
   return tid;
 }
--- a/src/internet/model/ipv6.h	Sun Aug 11 20:53:01 2013 -0700
+++ b/src/internet/model/ipv6.h	Mon Aug 12 06:51:18 2013 +0200
@@ -253,6 +253,13 @@
   virtual uint16_t GetMtu (uint32_t interface) const = 0;
 
   /**
+   * \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) = 0;
+
+  /**
    * \brief If the specified interface index is in "up" state.
    * \param interface Interface number of IPv6 interface
    * \returns true if the underlying interface is in the "up" state,
@@ -320,6 +327,18 @@
    * \return forwarding state (enabled or not)
    */
   virtual bool GetIpForward (void) const = 0;
+
+  /**
+   * \brief Set IPv6 MTU discover state.
+   * \param mtuDiscover IPv6 MTU discover enabled or not
+   */
+  virtual void SetMtuDiscover (bool mtuDiscover) = 0;
+
+  /**
+   * \brief Get IPv6 MTU discover state.
+   * \return MTU discover state (enabled or not)
+   */
+  virtual bool GetMtuDiscover (void) const = 0;
 };
 
 } // namespace ns3 
--- a/src/internet/wscript	Sun Aug 11 20:53:01 2013 -0700
+++ b/src/internet/wscript	Mon Aug 12 06:51:18 2013 +0200
@@ -191,6 +191,7 @@
         'model/ipv6-address-generator.cc',
         'model/ipv4-packet-probe.cc',
         'model/ipv6-packet-probe.cc',
+        'model/ipv6-pmtu-cache.cc',
         ]
 
     internet_test = bld.create_ns3_module_test_library('internet')
@@ -304,6 +305,7 @@
         'model/rtt-estimator.h',
         'model/ipv4-packet-probe.h',
         'model/ipv6-packet-probe.h',
+        'model/ipv6-pmtu-cache.h',
        ]
 
     if bld.env['NSC_ENABLED']: