A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
ndisc-cache.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2007-2009 Strasbourg University
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
7 */
8
9#include "ndisc-cache.h"
10
11#include "icmpv6-l4-protocol.h"
12#include "ipv6-interface.h"
13#include "ipv6-l3-protocol.h"
14
15#include "ns3/log.h"
16#include "ns3/names.h"
17#include "ns3/node.h"
18#include "ns3/uinteger.h"
19
20namespace ns3
21{
22
23NS_LOG_COMPONENT_DEFINE("NdiscCache");
24
26
27TypeId
29{
30 static TypeId tid = TypeId("ns3::NdiscCache")
32 .SetGroupName("Internet")
33 .AddAttribute("UnresolvedQueueSize",
34 "Size of the queue for packets pending an NA reply.",
38 return tid;
39}
40
45
51
52void
54{
55 NS_LOG_FUNCTION(this);
56 Flush();
57 m_device = nullptr;
58 m_interface = nullptr;
59 m_icmpv6 = nullptr;
61}
62
63void
65 Ptr<Ipv6Interface> interface,
67{
68 NS_LOG_FUNCTION(this << device << interface);
69 m_device = device;
70 m_interface = interface;
71 m_icmpv6 = icmpv6;
72}
73
76{
77 NS_LOG_FUNCTION(this);
78 return m_interface;
79}
80
83{
84 NS_LOG_FUNCTION(this);
85 return m_device;
86}
87
90{
91 NS_LOG_FUNCTION(this << dst);
92
93 if (m_ndCache.find(dst) != m_ndCache.end())
94 {
95 NdiscCache::Entry* entry = m_ndCache[dst];
96 NS_LOG_LOGIC("Found an entry: " << *entry);
97
98 return entry;
99 }
100 NS_LOG_LOGIC("Nothing found");
101 return nullptr;
102}
103
104std::list<NdiscCache::Entry*>
106{
107 NS_LOG_FUNCTION(this << dst);
108
109 std::list<NdiscCache::Entry*> entryList;
110 for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
111 {
112 NdiscCache::Entry* entry = (*i).second;
113 if (entry->GetMacAddress() == dst)
114 {
115 NS_LOG_LOGIC("Found an entry:" << (*entry));
116 entryList.push_back(entry);
117 }
118 }
119 return entryList;
120}
121
124{
125 NS_LOG_FUNCTION(this << to);
126 NS_ASSERT(m_ndCache.find(to) == m_ndCache.end());
127
128 auto entry = new NdiscCache::Entry(this);
129 entry->SetIpv6Address(to);
130 m_ndCache[to] = entry;
131 return entry;
132}
133
134void
136{
137 NS_LOG_FUNCTION(this << entry);
138
139 for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
140 {
141 if ((*i).second == entry)
142 {
143 m_ndCache.erase(i);
144 entry->ClearWaitingPacket();
145 delete entry;
146 return;
147 }
148 }
149}
150
151void
153{
154 NS_LOG_FUNCTION(this);
155
156 for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
157 {
158 delete (*i).second; /* delete the pointer NdiscCache::Entry */
159 }
160
161 m_ndCache.erase(m_ndCache.begin(), m_ndCache.end());
162}
163
164void
166{
167 NS_LOG_FUNCTION(this << unresQlen);
168 m_unresQlen = unresQlen;
169}
170
173{
174 NS_LOG_FUNCTION(this);
175 return m_unresQlen;
176}
177
178void
180{
181 NS_LOG_FUNCTION(this << stream);
182 std::ostream* os = stream->GetStream();
183
184 for (auto i = m_ndCache.begin(); i != m_ndCache.end(); i++)
185 {
186 *os << i->first << " dev ";
187 std::string found = Names::FindName(m_device);
188 if (!Names::FindName(m_device).empty())
189 {
190 *os << found;
191 }
192 else
193 {
194 *os << static_cast<int>(m_device->GetIfIndex());
195 }
196
197 *os << " lladdr " << i->second->GetMacAddress();
198
199 if (i->second->IsReachable())
200 {
201 *os << " REACHABLE\n";
202 }
203 else if (i->second->IsDelay())
204 {
205 *os << " DELAY\n";
206 }
207 else if (i->second->IsIncomplete())
208 {
209 *os << " INCOMPLETE\n";
210 }
211 else if (i->second->IsProbe())
212 {
213 *os << " PROBE\n";
214 }
215 else if (i->second->IsStale())
216 {
217 *os << " STALE\n";
218 }
219 else if (i->second->IsPermanent())
220 {
221 *os << " PERMANENT\n";
222 }
223 else if (i->second->IsAutoGenerated())
224 {
225 *os << " STATIC_AUTOGENERATED\n";
226 }
227 else
228 {
229 NS_FATAL_ERROR("Test for possibly unreachable code-- please file a bug report, with a "
230 "test case, if this is ever hit");
231 }
232 }
233}
234
236 : m_ndCache(nd),
237 m_waiting(),
238 m_router(false),
239 m_nudTimer(Timer::CANCEL_ON_DESTROY),
240 m_lastReachabilityConfirmation(Seconds(0.0)),
241 m_nsRetransmit(0)
242{
243 NS_LOG_FUNCTION(this);
244}
245
246void
248{
249 NS_LOG_FUNCTION(this << router);
250 m_router = router;
251}
252
253bool
255{
256 NS_LOG_FUNCTION(this);
257 return m_router;
258}
259
260void
262{
263 NS_LOG_FUNCTION(this << p.second << p.first);
264
265 if (m_waiting.size() >= m_ndCache->GetUnresQlen())
266 {
267 /* we store only m_unresQlen packet => first packet in first packet remove */
268 /** \todo report packet as 'dropped' */
269 m_waiting.pop_front();
270 }
271 m_waiting.push_back(p);
272}
273
274void
276{
277 NS_LOG_FUNCTION(this);
278 /** \todo report packets as 'dropped' */
279 m_waiting.clear();
280}
281
282void
284{
285 NS_LOG_FUNCTION(this);
286 this->MarkStale();
287}
288
289void
291{
292 NS_LOG_FUNCTION(this);
293 Ipv6Address addr;
294
295 /* determine source address */
296 if (m_ipv6Address.IsLinkLocal())
297 {
298 addr = m_ndCache->GetInterface()->GetLinkLocalAddress().GetAddress();
299 }
300 else if (!m_ipv6Address.IsAny())
301 {
302 addr = m_ndCache->GetInterface()->GetAddressMatchingDestination(m_ipv6Address).GetAddress();
303
304 if (addr.IsAny()) /* maybe address has expired */
305 {
306 /* delete the entry */
307 m_ndCache->Remove(this);
308 return;
309 }
310 }
311
312 if (m_nsRetransmit < m_ndCache->m_icmpv6->GetMaxMulticastSolicit())
313 {
314 m_nsRetransmit++;
315
316 m_ndCache->m_icmpv6->SendNS(addr,
318 m_ipv6Address,
319 m_ndCache->GetDevice()->GetAddress());
320 /* arm the timer again */
321 StartRetransmitTimer();
322 }
323 else
324 {
325 Ipv6PayloadHeaderPair malformedPacket = m_waiting.front();
326 if (!malformedPacket.first)
327 {
328 malformedPacket.first = Create<Packet>();
329 }
330 else
331 {
332 malformedPacket.first->AddHeader(malformedPacket.second);
333 }
334
335 m_ndCache->m_icmpv6->SendErrorDestinationUnreachable(malformedPacket.first,
336 addr,
338
339 /* delete the entry */
340 m_ndCache->Remove(this);
341 }
342}
343
344void
346{
347 NS_LOG_FUNCTION(this);
348 Ipv6Address addr;
349
350 this->MarkProbe();
351
352 if (m_ipv6Address.IsLinkLocal())
353 {
354 addr = m_ndCache->GetInterface()->GetLinkLocalAddress().GetAddress();
355 }
356 else if (!m_ipv6Address.IsAny())
357 {
358 addr = m_ndCache->GetInterface()->GetAddressMatchingDestination(m_ipv6Address).GetAddress();
359 if (addr.IsAny()) /* maybe address has expired */
360 {
361 /* delete the entry */
362 m_ndCache->Remove(this);
363 return;
364 }
365 }
366 else
367 {
368 /* should not happen */
369 return;
370 }
371
372 Ipv6PayloadHeaderPair p = m_ndCache->m_icmpv6->ForgeNS(addr,
373 m_ipv6Address,
374 m_ipv6Address,
375 m_ndCache->GetDevice()->GetAddress());
376 p.first->AddHeader(p.second);
377 m_ndCache->GetDevice()->Send(p.first, this->GetMacAddress(), Ipv6L3Protocol::PROT_NUMBER);
378
379 m_nsRetransmit = 1;
380 StartProbeTimer();
381}
382
383void
385{
386 NS_LOG_FUNCTION(this);
387
388 if (m_nsRetransmit < m_ndCache->m_icmpv6->GetMaxUnicastSolicit())
389 {
390 m_nsRetransmit++;
391
392 Ipv6Address addr;
393
394 if (m_ipv6Address.IsLinkLocal())
395 {
396 addr = m_ndCache->GetInterface()->GetLinkLocalAddress().GetAddress();
397 }
398 else if (!m_ipv6Address.IsAny())
399 {
400 addr = m_ndCache->GetInterface()
401 ->GetAddressMatchingDestination(m_ipv6Address)
402 .GetAddress();
403 if (addr.IsAny()) /* maybe address has expired */
404 {
405 /* delete the entry */
406 m_ndCache->Remove(this);
407 return;
408 }
409 }
410 else
411 {
412 /* should not happen */
413 return;
414 }
415
416 /* icmpv6->SendNS (m_ndCache->GetInterface ()->GetLinkLocalAddress (), m_ipv6Address,
417 * m_ipv6Address, m_ndCache->GetDevice ()->GetAddress ()); */
419 m_ndCache->m_icmpv6->ForgeNS(addr,
420 m_ipv6Address,
421 m_ipv6Address,
422 m_ndCache->GetDevice()->GetAddress());
423 p.first->AddHeader(p.second);
424 m_ndCache->GetDevice()->Send(p.first, this->GetMacAddress(), Ipv6L3Protocol::PROT_NUMBER);
425
426 /* arm the timer again */
427 StartProbeTimer();
428 }
429 else
430 {
431 /* delete the entry */
432 m_ndCache->Remove(this);
433 }
434}
435
436void
438{
439 NS_LOG_FUNCTION(this << ipv6Address);
440 m_ipv6Address = ipv6Address;
441}
442
445{
446 NS_LOG_FUNCTION(this);
447 return m_ipv6Address;
448}
449
450Time
452{
453 NS_LOG_FUNCTION(this);
454 return m_lastReachabilityConfirmation;
455}
456
457void
459{
460 NS_LOG_FUNCTION(this);
461 if (m_nudTimer.IsRunning())
462 {
463 m_nudTimer.Cancel();
464 }
465
466 m_lastReachabilityConfirmation = Simulator::Now();
467 m_nudTimer.SetFunction(&NdiscCache::Entry::FunctionReachableTimeout, this);
468 m_nudTimer.SetDelay(m_ndCache->m_icmpv6->GetReachableTime());
469 m_nudTimer.Schedule();
470}
471
472void
474{
475 NS_LOG_FUNCTION(this);
476
477 if (m_state == REACHABLE)
478 {
479 m_lastReachabilityConfirmation = Simulator::Now();
480 if (m_nudTimer.IsRunning())
481 {
482 m_nudTimer.Cancel();
483 }
484 m_nudTimer.Schedule();
485 }
486}
487
488void
490{
491 NS_LOG_FUNCTION(this);
492 if (m_nudTimer.IsRunning())
493 {
494 m_nudTimer.Cancel();
495 }
496
497 m_nudTimer.SetFunction(&NdiscCache::Entry::FunctionProbeTimeout, this);
498 m_nudTimer.SetDelay(m_ndCache->m_icmpv6->GetRetransmissionTime());
499 m_nudTimer.Schedule();
500}
501
502void
504{
505 NS_LOG_FUNCTION(this);
506 if (m_nudTimer.IsRunning())
507 {
508 m_nudTimer.Cancel();
509 }
510
511 m_nudTimer.SetFunction(&NdiscCache::Entry::FunctionDelayTimeout, this);
512 m_nudTimer.SetDelay(m_ndCache->m_icmpv6->GetDelayFirstProbe());
513 m_nudTimer.Schedule();
514}
515
516void
518{
519 NS_LOG_FUNCTION(this);
520 if (m_nudTimer.IsRunning())
521 {
522 m_nudTimer.Cancel();
523 }
524
525 m_nudTimer.SetFunction(&NdiscCache::Entry::FunctionRetransmitTimeout, this);
526 m_nudTimer.SetDelay(m_ndCache->m_icmpv6->GetRetransmissionTime());
527 m_nudTimer.Schedule();
528}
529
530void
532{
533 NS_LOG_FUNCTION(this);
534 m_nudTimer.Cancel();
535 m_nsRetransmit = 0;
536}
537
538void
540{
541 NS_LOG_FUNCTION(this << p.second << p.first);
542 m_state = INCOMPLETE;
543
544 if (p.first)
545 {
546 m_waiting.push_back(p);
547 }
548}
549
550std::list<NdiscCache::Ipv6PayloadHeaderPair>
552{
553 NS_LOG_FUNCTION(this << mac);
554 m_state = REACHABLE;
555 m_macAddress = mac;
556 return m_waiting;
557}
558
559void
561{
562 NS_LOG_FUNCTION(this);
563 m_state = PROBE;
564}
565
566void
568{
569 NS_LOG_FUNCTION(this);
570 m_state = STALE;
571}
572
573void
575{
576 NS_LOG_FUNCTION(this);
577 m_state = REACHABLE;
578}
579
580std::list<NdiscCache::Ipv6PayloadHeaderPair>
582{
583 NS_LOG_FUNCTION(this << mac);
584 m_state = STALE;
585 m_macAddress = mac;
586 return m_waiting;
587}
588
589void
591{
592 NS_LOG_FUNCTION(this);
593 m_state = DELAY;
594}
595
596void
598{
599 NS_LOG_FUNCTION(this);
600 StopNudTimer();
601 m_state = PERMANENT;
602}
603
604void
606{
607 NS_LOG_FUNCTION(this);
608 StopNudTimer();
609 m_state = STATIC_AUTOGENERATED;
610}
611
612bool
614{
615 NS_LOG_FUNCTION(this);
616 return (m_state == STALE);
617}
618
619bool
621{
622 NS_LOG_FUNCTION(this);
623 return (m_state == REACHABLE);
624}
625
626bool
628{
629 NS_LOG_FUNCTION(this);
630 return (m_state == DELAY);
631}
632
633bool
635{
636 NS_LOG_FUNCTION(this);
637 return (m_state == INCOMPLETE);
638}
639
640bool
642{
643 NS_LOG_FUNCTION(this);
644 return (m_state == PROBE);
645}
646
647bool
649{
650 NS_LOG_FUNCTION(this);
651 return (m_state == PERMANENT);
652}
653
654bool
656{
657 NS_LOG_FUNCTION(this);
658 return (m_state == STATIC_AUTOGENERATED);
659}
660
663{
664 NS_LOG_FUNCTION(this);
665 return m_macAddress;
666}
667
668void
670{
671 NS_LOG_FUNCTION(this << mac << int(m_state));
672 m_macAddress = mac;
673}
674
675void
676NdiscCache::Entry::Print(std::ostream& os) const
677{
678 os << m_ipv6Address << " lladdr " << m_macAddress << " state ";
679 switch (m_state)
680 {
681 case INCOMPLETE:
682 os << "INCOMPLETE";
683 break;
684 case REACHABLE:
685 os << "REACHABLE";
686 break;
687 case STALE:
688 os << "STALE";
689 break;
690 case DELAY:
691 os << "DELAY";
692 break;
693 case PROBE:
694 os << "PROBE";
695 break;
696 case PERMANENT:
697 os << "PERMANENT";
698 break;
699 case STATIC_AUTOGENERATED:
700 os << "STATIC_AUTOGENERATED";
701 break;
702 }
703}
704
705void
707{
708 NS_LOG_FUNCTION(this);
709 for (auto i = m_ndCache.begin(); i != m_ndCache.end();)
710 {
711 if (i->second->IsAutoGenerated())
712 {
713 i->second->ClearWaitingPacket();
714 delete i->second;
715 m_ndCache.erase(i++);
716 continue;
717 }
718 i++;
719 }
720}
721
722std::ostream&
723operator<<(std::ostream& os, const NdiscCache::Entry& entry)
724{
725 entry.Print(os);
726 return os;
727}
728
729} /* namespace ns3 */
a polymophic address class
Definition address.h:90
Describes an IPv6 address.
static Ipv6Address MakeSolicitedAddress(Ipv6Address addr)
Make the solicited IPv6 address.
bool IsAny() const
If the IPv6 address is the "Any" address.
static const uint16_t PROT_NUMBER
The protocol number for IPv6 (0x86DD).
static std::string FindName(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and,...
Definition names.cc:818
A record that holds information about a NdiscCache entry.
void MarkProbe()
Changes the state to this entry to PROBE.
bool IsPermanent() const
Is the entry PERMANENT.
void MarkPermanent()
Change the state to this entry to PERMANENT.
void ClearWaitingPacket()
Clear the waiting packet list.
void StartProbeTimer()
Start probe timer.
void MarkReachable()
Changes the state to this entry to REACHABLE.
void StartReachableTimer()
Start the reachable timer.
void Print(std::ostream &os) const
Print this entry to the given output stream.
void UpdateReachableTimer()
Update the reachable timer.
void FunctionProbeTimeout()
Function called when probe timer timeout.
void MarkStale()
Changes the state to this entry to STALE.
Address GetMacAddress() const
Get the MAC address of this entry.
Ipv6Address GetIpv6Address() const
Get the IPv6 address.
void StartDelayTimer()
Start delay timer.
void MarkAutoGenerated()
Changes the state of this entry to auto-generated.
bool IsIncomplete() const
Is the entry INCOMPLETE.
void FunctionDelayTimeout()
Function called when delay timer timeout.
bool IsDelay() const
Is the entry DELAY.
void StartRetransmitTimer()
Start retransmit timer.
void SetIpv6Address(Ipv6Address ipv6Address)
Set the IPv6 address.
void MarkIncomplete(Ipv6PayloadHeaderPair p)
Changes the state to this entry to INCOMPLETE.
bool IsStale() const
Is the entry STALE.
void SetMacAddress(Address mac)
Set the MAC address of this entry.
bool IsProbe() const
Is the entry PROBE.
Time GetLastReachabilityConfirmation() const
Get the time of last reachability confirmation.
void FunctionRetransmitTimeout()
Function called when retransmit timer timeout.
void MarkDelay()
Change the state to this entry to DELAY.
Entry(NdiscCache *nd)
Constructor.
bool IsRouter() const
If the entry is a host or a router.
void SetRouter(bool router)
Set the node type.
void FunctionReachableTimeout()
Function called when reachable timer timeout.
bool IsAutoGenerated() const
Is the entry STATIC_AUTOGENERATED.
void AddWaitingPacket(Ipv6PayloadHeaderPair p)
Add a packet (or replace old value) in the queue.
bool IsReachable() const
Is the entry REACHABLE.
void StopNudTimer()
Stop NUD timer and reset the NUD retransmission counter.
IPv6 Neighbor Discovery cache.
Definition ndisc-cache.h:38
void SetDevice(Ptr< NetDevice > device, Ptr< Ipv6Interface > interface, Ptr< Icmpv6L4Protocol > icmpv6)
Set the device and interface.
std::pair< Ptr< Packet >, Ipv6Header > Ipv6PayloadHeaderPair
Pair of a packet and an Ipv4 header.
virtual NdiscCache::Entry * Add(Ipv6Address to)
Add an entry.
void Flush()
Flush the cache.
Ptr< Ipv6Interface > m_interface
the interface.
void Remove(NdiscCache::Entry *entry)
Delete an entry.
NdiscCache()
Constructor.
void PrintNdiscCache(Ptr< OutputStreamWrapper > stream)
Print the NDISC cache entries.
~NdiscCache() override
Destructor.
Ptr< NetDevice > m_device
The NetDevice.
uint32_t GetUnresQlen()
Get the max number of waiting packet.
virtual NdiscCache::Entry * Lookup(Ipv6Address dst)
Lookup in the cache.
void RemoveAutoGeneratedEntries()
Clear the NDISC cache of all Auto-Generated entries.
void DoDispose() override
Dispose this object.
Ptr< NetDevice > GetDevice() const
Get the NetDevice associated with this cache.
static const uint32_t DEFAULT_UNRES_QLEN
Default value for unres qlen.
Definition ndisc-cache.h:51
static TypeId GetTypeId()
Get the type ID.
Cache m_ndCache
A list of Entry.
std::list< NdiscCache::Entry * > LookupInverse(Address dst)
Lookup in the cache for a MAC address.
void SetUnresQlen(uint32_t unresQlen)
Set the max number of waiting packet.
Ptr< Icmpv6L4Protocol > m_icmpv6
the icmpv6 L4 protocol for this cache.
Ptr< Ipv6Interface > GetInterface() const
Get the Ipv6Interface associated with this cache.
uint32_t m_unresQlen
Max number of packet stored in m_waiting.
A base class which provides memory management and object aggregation.
Definition object.h:78
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
A simple virtual Timer class.
Definition timer.h:67
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition angles.cc:148
#define DELAY(time)
Gets the delay between a given time and the current time.