src/internet/model/ipv6-l3-protocol.cc
changeset 10127 f4cee68de571
parent 9955 d97de2f9fbe5
child 10158 971f362648c3
--- 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 ()))