revised patch to fix bug 253
authorTom Henderson <tomh@tomh.org>
Wed, 30 Jul 2008 06:30:42 -0700
changeset 3499 a18520551cdf
parent 3493 53ec8893863d
child 3500 8a4b1d0ae55c
revised patch to fix bug 253
src/internet-stack/arp-cache.cc
src/internet-stack/arp-cache.h
src/internet-stack/arp-l3-protocol.cc
src/internet-stack/arp-l3-protocol.h
--- a/src/internet-stack/arp-cache.cc	Tue Jul 29 15:36:41 2008 -0400
+++ b/src/internet-stack/arp-cache.cc	Wed Jul 30 06:30:42 2008 -0700
@@ -22,6 +22,8 @@
 #include "ns3/simulator.h"
 #include "ns3/uinteger.h"
 #include "ns3/log.h"
+#include "ns3/node.h"
+#include "ns3/trace-source-accessor.h"
 
 #include "arp-cache.h"
 #include "arp-header.h"
@@ -47,15 +49,23 @@
                    MakeTimeAccessor (&ArpCache::m_deadTimeout),
                    MakeTimeChecker ())
     .AddAttribute ("WaitReplyTimeout",
-                   "When this timeout expires, the matching cache entry is marked dead",
+                   "When this timeout expires, the cache entries will be scanned and entries in WaitReply state will resend ArpRequest unless MaxRetries has been exceeded, in which case the entry is marked dead",           
                    TimeValue (Seconds (1)),
                    MakeTimeAccessor (&ArpCache::m_waitReplyTimeout),
                    MakeTimeChecker ())
+    .AddAttribute ("MaxRetries",                   
+                   "Number of retransmissions of ArpRequest before marking dead",                  
+                   UintegerValue (3),
+                   MakeUintegerAccessor (&ArpCache::m_maxRetries),
+                   MakeUintegerChecker<uint32_t> ())
     .AddAttribute ("PendingQueueSize",
                    "The size of the queue for packets pending an arp reply.",
                    UintegerValue (3),
                    MakeUintegerAccessor (&ArpCache::m_pendingQueueSize),
                    MakeUintegerChecker<uint32_t> ())
+    .AddTraceSource ("Drop",                     
+                     "Packet dropped due to ArpCache entry in WaitReply expiring.",
+                     MakeTraceSourceAccessor (&ArpCache::m_dropTrace))
     ;
   return tid;
 }
@@ -79,6 +89,10 @@
   Flush ();
   m_device = 0;
   m_interface = 0;
+  if (!m_waitReplyTimer.IsRunning ())
+    {
+      Simulator::Remove (m_waitReplyTimer);
+    }
   Object::DoDispose ();
 }
 
@@ -143,6 +157,73 @@
 }
 
 void 
+ArpCache::SetArpRequestCallback (Callback<void, Ptr<const ArpCache>,
+                             Ipv4Address> arpRequestCallback)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_arpRequestCallback = arpRequestCallback;
+}
+
+void 
+ArpCache::StartWaitReplyTimer (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  if (!m_waitReplyTimer.IsRunning ())
+    {
+      NS_LOG_LOGIC ("Starting WaitReplyTimer at " << Simulator::Now ().GetSeconds ());
+      m_waitReplyTimer = Simulator::Schedule (m_waitReplyTimeout, 
+        &ArpCache::HandleWaitReplyTimeout, this);
+    }
+}
+
+void
+ArpCache::HandleWaitReplyTimeout (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  ArpCache::Entry* entry;
+  bool restartWaitReplyTimer = false;
+  for (CacheI i = m_arpCache.begin (); i != m_arpCache.end (); i++) 
+    {
+      entry = (*i).second;
+      if (entry != 0 && entry->IsWaitReply () && entry->IsExpired ())
+          {
+          if (entry->GetRetries () < m_maxRetries)
+            {
+              NS_LOG_LOGIC ("node="<< m_device->GetNode ()->GetId () <<
+                ", ArpWaitTimeout for " << entry->GetIpv4Address () <<
+                " expired -- retransmitting arp request since retries = " << 
+                entry->GetRetries ());
+              m_arpRequestCallback (this, entry->GetIpv4Address ());
+              restartWaitReplyTimer = true;
+              entry->IncrementRetries ();
+            }
+          else
+            {
+              NS_LOG_LOGIC ("node="<<m_device->GetNode ()->GetId () <<
+                ", wait reply for " << entry->GetIpv4Address () << 
+                " expired -- drop since max retries exceeded: " << 
+                 entry->GetRetries ());
+              entry->MarkDead ();
+              entry->ClearRetries ();
+              Ptr<Packet> pending = entry->DequeuePending();
+              while (pending != 0)
+                {
+                  m_dropTrace (pending);
+                  pending = entry->DequeuePending();
+                }
+            }
+       }
+
+    }
+  if (restartWaitReplyTimer)
+    {
+      NS_LOG_LOGIC ("Restarting WaitReplyTimer at " << Simulator::Now ().GetSeconds ());
+      m_waitReplyTimer = Simulator::Schedule (m_waitReplyTimeout, 
+        &ArpCache::HandleWaitReplyTimeout, this);
+    }
+}
+
+void 
 ArpCache::Flush (void)
 {
   NS_LOG_FUNCTION_NOARGS ();
@@ -173,12 +254,14 @@
 
   ArpCache::Entry *entry = new ArpCache::Entry (this);
   m_arpCache[to] = entry;  
+  entry->SetIpv4Address (to);
   return entry;
 }
 
 ArpCache::Entry::Entry (ArpCache *arp)
   : m_arp (arp),
-    m_state (ALIVE)
+    m_state (ALIVE),
+    m_retries (0)
 {
   NS_LOG_FUNCTION_NOARGS ();
 }
@@ -209,6 +292,7 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
   m_state = DEAD;
+  ClearRetries ();
   UpdateSeen ();
 }
 void
@@ -218,6 +302,7 @@
   NS_ASSERT (m_state == WAIT_REPLY);
   m_macAddress = macAddress;
   m_state = ALIVE;
+  ClearRetries ();
   UpdateSeen ();
 }
 
@@ -246,15 +331,29 @@
   m_state = WAIT_REPLY;
   m_pending.push_back (waiting);
   UpdateSeen ();
+  m_arp->StartWaitReplyTimer ();
 }
 
 Address
-ArpCache::Entry::GetMacAddress (void)
+ArpCache::Entry::GetMacAddress (void) const
 {
   NS_LOG_FUNCTION_NOARGS ();
   NS_ASSERT (m_state == ALIVE);
   return m_macAddress;
 }
+Ipv4Address 
+ArpCache::Entry::GetIpv4Address (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_ipv4Address;
+}
+void 
+ArpCache::Entry::SetIpv4Address (Ipv4Address destination)
+{
+  NS_LOG_FUNCTION (this << destination);
+  m_ipv4Address = destination;
+}
+
 bool 
 ArpCache::Entry::IsExpired (void)
 {
@@ -307,6 +406,25 @@
   NS_LOG_FUNCTION_NOARGS ();
   m_lastSeen = Simulator::Now ();
 }
+uint32_t
+ArpCache::Entry::GetRetries (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_retries;
+}
+void
+ArpCache::Entry::IncrementRetries (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_retries++;
+  UpdateSeen ();
+}
+void
+ArpCache::Entry::ClearRetries (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  m_retries = 0;
+}
 
 } // namespace ns3
 
--- a/src/internet-stack/arp-cache.h	Tue Jul 29 15:36:41 2008 -0400
+++ b/src/internet-stack/arp-cache.h	Wed Jul 30 06:30:42 2008 -0700
@@ -22,6 +22,8 @@
 
 #include <stdint.h>
 #include <list>
+#include "ns3/simulator.h"
+#include "ns3/callback.h"
 #include "ns3/packet.h"
 #include "ns3/nstime.h"
 #include "ns3/net-device.h"
@@ -29,6 +31,7 @@
 #include "ns3/address.h"
 #include "ns3/ptr.h"
 #include "ns3/object.h"
+#include "ns3/traced-callback.h"
 #include "sgi-hashmap.h"
 
 namespace ns3 {
@@ -72,7 +75,22 @@
   Time GetWaitReplyTimeout (void) const;
 
   /**
-   * \brief Do lookup in the ARP chache against an IP address
+   * This callback is set when the ArpCache is set up and allows
+   * the cache to generate an Arp request when the WaitReply
+   * time expires and a retransmission must be sent
+   *
+   * \param arpRequestCallback Callback for transmitting an Arp request.
+   */
+  void SetArpRequestCallback (Callback<void, Ptr<const ArpCache>, 
+                             Ipv4Address> arpRequestCallback);
+  /**
+   * This method will schedule a timeout at WaitReplyTimeout interval
+   * in the future, unless a timer is already running for the cache,
+   * in which case this method does nothing.
+   */
+  void StartWaitReplyTimer (void);
+  /**
+   * \brief Do lookup in the ARP cache against an IP address
    * \param destination The destination IPv4 address to lookup the MAC address
    * of
    * \return An ArpCache::Entry with info about layer 2
@@ -131,7 +149,15 @@
     /**
      * \return The MacAddress of this entry
      */
-    Address GetMacAddress (void);
+    Address GetMacAddress (void) const;
+    /**
+     * \return The Ipv4Address for this entry
+     */
+    Ipv4Address GetIpv4Address (void) const;
+    /**
+     * \param The Ipv4Address for this entry
+     */
+    void SetIpv4Address (Ipv4Address destination);
     /**
      * \return True if this entry has timedout; false otherwise.
      */
@@ -142,6 +168,20 @@
      *            packets are pending.
      */
     Ptr<Packet> DequeuePending (void);
+    /**
+     * \returns number of retries that have been sent for an ArpRequest
+     *  in WaitReply state.
+     */
+    uint32_t GetRetries (void) const;
+    /**
+     * \brief Increment the counter of number of retries for an entry
+     */
+    void IncrementRetries (void);
+    /**
+     * \brief Zero the counter of number of retries for an entry
+     */
+    void ClearRetries (void);
+
   private:
     enum ArpCacheEntryState_e {
       ALIVE,
@@ -154,7 +194,9 @@
     ArpCacheEntryState_e m_state;
     Time m_lastSeen;
     Address m_macAddress;
+    Ipv4Address m_ipv4Address;
     std::list<Ptr<Packet> > m_pending;
+    uint32_t m_retries;
   };
 
 private:
@@ -168,8 +210,18 @@
   Time m_aliveTimeout;
   Time m_deadTimeout;
   Time m_waitReplyTimeout;
+  EventId m_waitReplyTimer;
+  Callback<void, Ptr<const ArpCache>, Ipv4Address> m_arpRequestCallback;
+  uint32_t m_maxRetries;
+  /**
+   * This function is an event handler for the event that the
+   * ArpCache wants to check whether it must retry any Arp requests.
+   * If there are no Arp requests pending, this event is not scheduled.
+   */
+  void HandleWaitReplyTimeout (void);
   uint32_t m_pendingQueueSize;
   Cache m_arpCache;
+  TracedCallback<Ptr<const Packet> > m_dropTrace;
 };
 
 
--- a/src/internet-stack/arp-l3-protocol.cc	Tue Jul 29 15:36:41 2008 -0400
+++ b/src/internet-stack/arp-l3-protocol.cc	Wed Jul 30 06:30:42 2008 -0700
@@ -95,6 +95,7 @@
   cache->SetDevice (device, interface);
   NS_ASSERT (device->IsBroadcast ());
   device->SetLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
+  cache->SetArpRequestCallback (MakeCallback (&ArpL3Protocol::SendArpRequest, this));
   m_cacheList.push_back (cache);
   return cache;
 }
@@ -218,16 +219,7 @@
             } 
           else if (entry->IsWaitReply ()) 
             {
-              NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
-                        ", wait reply for " << destination << " expired -- drop");
-              entry->MarkDead ();
-              Ptr<Packet> pending = entry->DequeuePending();
-              while (pending != 0)
-                {
-                  m_dropTrace (pending);
-                  pending = entry->DequeuePending();
-                }
-              m_dropTrace (packet);
+              NS_FATAL_ERROR ("Test for possibly unreachable code-- please file a bug report if this is ever hit");
             }
         } 
       else 
--- a/src/internet-stack/arp-l3-protocol.h	Tue Jul 29 15:36:41 2008 -0400
+++ b/src/internet-stack/arp-l3-protocol.h	Wed Jul 30 06:30:42 2008 -0700
@@ -52,7 +52,7 @@
   Ptr<ArpCache> CreateCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface);
 
   /**
-   * \brief Recieve a packet
+   * \brief Receive a packet
    */
   void Receive(Ptr<NetDevice> device, Ptr<Packet> p, uint16_t protocol, const Address &from, const Address &to,
                NetDevice::PacketType packetType);