A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
arp-cache.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2006 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "ns3/assert.h"
21 #include "ns3/packet.h"
22 #include "ns3/simulator.h"
23 #include "ns3/uinteger.h"
24 #include "ns3/log.h"
25 #include "ns3/node.h"
26 #include "ns3/trace-source-accessor.h"
27 
28 #include "arp-cache.h"
29 #include "arp-header.h"
30 #include "ipv4-interface.h"
31 
32 NS_LOG_COMPONENT_DEFINE ("ArpCache");
33 
34 namespace ns3 {
35 
37 
38 TypeId
40 {
41  static TypeId tid = TypeId ("ns3::ArpCache")
42  .SetParent<Object> ()
43  .AddAttribute ("AliveTimeout",
44  "When this timeout expires, the matching cache entry needs refreshing",
45  TimeValue (Seconds (120)),
46  MakeTimeAccessor (&ArpCache::m_aliveTimeout),
47  MakeTimeChecker ())
48  .AddAttribute ("DeadTimeout",
49  "When this timeout expires, a new attempt to resolve the matching entry is made",
50  TimeValue (Seconds (100)),
51  MakeTimeAccessor (&ArpCache::m_deadTimeout),
52  MakeTimeChecker ())
53  .AddAttribute ("WaitReplyTimeout",
54  "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",
55  TimeValue (Seconds (1)),
56  MakeTimeAccessor (&ArpCache::m_waitReplyTimeout),
57  MakeTimeChecker ())
58  .AddAttribute ("MaxRetries",
59  "Number of retransmissions of ArpRequest before marking dead",
60  UintegerValue (3),
61  MakeUintegerAccessor (&ArpCache::m_maxRetries),
62  MakeUintegerChecker<uint32_t> ())
63  .AddAttribute ("PendingQueueSize",
64  "The size of the queue for packets pending an arp reply.",
65  UintegerValue (3),
66  MakeUintegerAccessor (&ArpCache::m_pendingQueueSize),
67  MakeUintegerChecker<uint32_t> ())
68  .AddTraceSource ("Drop",
69  "Packet dropped due to ArpCache entry in WaitReply expiring.",
71  ;
72  return tid;
73 }
74 
76  : m_device (0),
77  m_interface (0)
78 {
79  NS_LOG_FUNCTION (this);
80 }
81 
83 {
84  NS_LOG_FUNCTION (this);
85 }
86 
87 void
89 {
90  NS_LOG_FUNCTION (this);
91  Flush ();
92  m_device = 0;
93  m_interface = 0;
95  {
97  }
99 }
100 
101 void
103 {
104  NS_LOG_FUNCTION (this << device << interface);
105  m_device = device;
106  m_interface = interface;
107 }
108 
111 {
112  return m_device;
113 }
114 
117 {
118  return m_interface;
119 }
120 
121 void
123 {
124  NS_LOG_FUNCTION (this << aliveTimeout);
125  m_aliveTimeout = aliveTimeout;
126 }
127 void
129 {
130  NS_LOG_FUNCTION (this << deadTimeout);
131  m_deadTimeout = deadTimeout;
132 }
133 void
135 {
136  NS_LOG_FUNCTION (this << waitReplyTimeout);
137  m_waitReplyTimeout = waitReplyTimeout;
138 }
139 
140 Time
142 {
143  return m_aliveTimeout;
144 }
145 Time
147 {
148  return m_deadTimeout;
149 }
150 Time
152 {
153  return m_waitReplyTimeout;
154 }
155 
156 void
158  Ipv4Address> arpRequestCallback)
159 {
160  NS_LOG_FUNCTION (this);
161  m_arpRequestCallback = arpRequestCallback;
162 }
163 
164 void
166 {
167  NS_LOG_FUNCTION (this);
168  if (!m_waitReplyTimer.IsRunning ())
169  {
170  NS_LOG_LOGIC ("Starting WaitReplyTimer at " << Simulator::Now () << " for " <<
174  }
175 }
176 
177 void
179 {
180  NS_LOG_FUNCTION (this);
181  ArpCache::Entry* entry;
182  bool restartWaitReplyTimer = false;
183  for (CacheI i = m_arpCache.begin (); i != m_arpCache.end (); i++)
184  {
185  entry = (*i).second;
186  if (entry != 0 && entry->IsWaitReply ())
187  {
188  if (entry->GetRetries () < m_maxRetries)
189  {
190  NS_LOG_LOGIC ("node="<< m_device->GetNode ()->GetId () <<
191  ", ArpWaitTimeout for " << entry->GetIpv4Address () <<
192  " expired -- retransmitting arp request since retries = " <<
193  entry->GetRetries ());
194  m_arpRequestCallback (this, entry->GetIpv4Address ());
195  restartWaitReplyTimer = true;
196  entry->IncrementRetries ();
197  }
198  else
199  {
200  NS_LOG_LOGIC ("node="<<m_device->GetNode ()->GetId () <<
201  ", wait reply for " << entry->GetIpv4Address () <<
202  " expired -- drop since max retries exceeded: " <<
203  entry->GetRetries ());
204  entry->MarkDead ();
205  entry->ClearRetries ();
206  Ptr<Packet> pending = entry->DequeuePending ();
207  while (pending != 0)
208  {
209  m_dropTrace (pending);
210  pending = entry->DequeuePending ();
211  }
212  }
213  }
214 
215  }
216  if (restartWaitReplyTimer)
217  {
218  NS_LOG_LOGIC ("Restarting WaitReplyTimer at " << Simulator::Now ().GetSeconds ());
221  }
222 }
223 
224 void
226 {
227  NS_LOG_FUNCTION (this);
228  for (CacheI i = m_arpCache.begin (); i != m_arpCache.end (); i++)
229  {
230  delete (*i).second;
231  }
232  m_arpCache.erase (m_arpCache.begin (), m_arpCache.end ());
234  {
235  NS_LOG_LOGIC ("Stopping WaitReplyTimer at " << Simulator::Now ().GetSeconds () << " due to ArpCache flush");
237  }
238 }
239 
242 {
243  if (m_arpCache.find (to) != m_arpCache.end ())
244  {
245  ArpCache::Entry *entry = m_arpCache[to];
246  return entry;
247  }
248  return 0;
249 }
250 
253 {
254  NS_LOG_FUNCTION (this << to);
255  NS_ASSERT (m_arpCache.find (to) == m_arpCache.end ());
256 
257  ArpCache::Entry *entry = new ArpCache::Entry (this);
258  m_arpCache[to] = entry;
259  entry->SetIpv4Address (to);
260  return entry;
261 }
262 
264  : m_arp (arp),
265  m_state (ALIVE),
266  m_retries (0)
267 {
268  NS_LOG_FUNCTION (this << arp);
269 }
270 
271 
272 bool
274 {
275  return (m_state == DEAD) ? true : false;
276 }
277 bool
279 {
280  return (m_state == ALIVE) ? true : false;
281 }
282 bool
284 {
285  return (m_state == WAIT_REPLY) ? true : false;
286 }
287 
288 
289 void
291 {
292  NS_LOG_FUNCTION (this);
293  m_state = DEAD;
294  ClearRetries ();
295  UpdateSeen ();
296 }
297 void
299 {
300  NS_LOG_FUNCTION (this << macAddress);
301  NS_ASSERT (m_state == WAIT_REPLY);
302  m_macAddress = macAddress;
303  m_state = ALIVE;
304  ClearRetries ();
305  UpdateSeen ();
306 }
307 
308 bool
310 {
311  NS_LOG_FUNCTION (this << waiting);
312  NS_ASSERT (m_state == WAIT_REPLY);
313  /* We are already waiting for an answer so
314  * we dump the previously waiting packet and
315  * replace it with this one.
316  */
317  if (m_pending.size () >= m_arp->m_pendingQueueSize)
318  {
319  return false;
320  }
321  m_pending.push_back (waiting);
322  return true;
323 }
324 void
326 {
327  NS_LOG_FUNCTION (this << waiting);
328  NS_ASSERT (m_state == ALIVE || m_state == DEAD);
329  NS_ASSERT (m_pending.empty ());
330  m_state = WAIT_REPLY;
331  m_pending.push_back (waiting);
332  UpdateSeen ();
333  m_arp->StartWaitReplyTimer ();
334 }
335 
336 Address
338 {
339  NS_ASSERT (m_state == ALIVE);
340  return m_macAddress;
341 }
344 {
345  return m_ipv4Address;
346 }
347 void
349 {
350  NS_LOG_FUNCTION (this << destination);
351  m_ipv4Address = destination;
352 }
353 Time
355 {
356  switch (m_state) {
358  return m_arp->GetWaitReplyTimeout ();
360  return m_arp->GetDeadTimeout ();
362  return m_arp->GetAliveTimeout ();
363  default:
364  NS_ASSERT (false);
365  return Seconds (0);
366  /* NOTREACHED */
367  }
368 }
369 bool
371 {
372  Time timeout = GetTimeout ();
373  Time delta = Simulator::Now () - m_lastSeen;
374  NS_LOG_DEBUG ("delta=" << delta.GetSeconds () << "s");
375  if (delta > timeout)
376  {
377  return true;
378  }
379  return false;
380 }
383 {
384  NS_LOG_FUNCTION (this);
385  if (m_pending.empty ())
386  {
387  return 0;
388  }
389  else
390  {
391  Ptr<Packet> p = m_pending.front ();
392  m_pending.pop_front ();
393  return p;
394  }
395 }
396 void
398 {
399  NS_LOG_FUNCTION (this << m_macAddress << m_ipv4Address);
400  m_lastSeen = Simulator::Now ();
401 }
402 uint32_t
404 {
405  return m_retries;
406 }
407 void
409 {
410  NS_LOG_FUNCTION (this);
411  m_retries++;
412  UpdateSeen ();
413 }
414 void
416 {
417  NS_LOG_FUNCTION (this);
418  m_retries = 0;
419 }
420 
421 } // namespace ns3
422