A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
arp-l3-protocol.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006 INRIA
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18 */
19#include "arp-l3-protocol.h"
20
21#include "arp-cache.h"
22#include "arp-header.h"
23#include "arp-queue-disc-item.h"
24#include "ipv4-interface.h"
25#include "ipv4-l3-protocol.h"
26
27#include "ns3/log.h"
28#include "ns3/net-device.h"
29#include "ns3/node.h"
30#include "ns3/object-vector.h"
31#include "ns3/packet.h"
32#include "ns3/pointer.h"
33#include "ns3/string.h"
34#include "ns3/trace-source-accessor.h"
35#include "ns3/traffic-control-layer.h"
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("ArpL3Protocol");
41
42const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
43
44NS_OBJECT_ENSURE_REGISTERED(ArpL3Protocol);
45
46TypeId
48{
49 static TypeId tid =
50 TypeId("ns3::ArpL3Protocol")
52 .AddConstructor<ArpL3Protocol>()
53 .SetGroupName("Internet")
54 .AddAttribute("CacheList",
55 "The list of ARP caches",
58 MakeObjectVectorChecker<ArpCache>())
59 .AddAttribute("RequestJitter",
60 "The jitter in ms a node is allowed to wait "
61 "before sending an ARP request. Some jitter aims "
62 "to prevent collisions. By default, the model "
63 "will wait for a duration in ms defined by "
64 "a uniform random-variable between 0 and RequestJitter",
65 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=10.0]"),
67 MakePointerChecker<RandomVariableStream>())
68 .AddTraceSource("Drop",
69 "Packet dropped because not enough room "
70 "in pending queue for a specific cache entry.",
72 "ns3::Packet::TracedCallback");
73 return tid;
74}
75
77 : m_tc(nullptr)
78{
79 NS_LOG_FUNCTION(this);
80}
81
83{
84 NS_LOG_FUNCTION(this);
85}
86
87int64_t
89{
90 NS_LOG_FUNCTION(this << stream);
92 return 1;
93}
94
95void
97{
98 NS_LOG_FUNCTION(this << node);
99 m_node = node;
100}
101
102void
104{
105 NS_LOG_FUNCTION(this << tc);
106 m_tc = tc;
107}
108
109/*
110 * This method is called by AggregateObject and completes the aggregation
111 * by setting the node in the ipv4 stack
112 */
113void
115{
116 NS_LOG_FUNCTION(this);
117 if (!m_node)
118 {
119 Ptr<Node> node = this->GetObject<Node>();
120 // verify that it's a valid node and that
121 // the node was not set before
122 if (node)
123 {
124 this->SetNode(node);
125 }
126 }
128}
129
130void
132{
133 NS_LOG_FUNCTION(this);
134 for (auto i = m_cacheList.begin(); i != m_cacheList.end(); ++i)
135 {
136 Ptr<ArpCache> cache = *i;
137 cache->Dispose();
138 }
139 m_cacheList.clear();
140 m_node = nullptr;
141 m_tc = nullptr;
143}
144
147{
148 NS_LOG_FUNCTION(this << device << interface);
150 Ptr<ArpCache> cache = CreateObject<ArpCache>();
151 cache->SetDevice(device, interface);
152 NS_ASSERT(device->IsBroadcast());
153 device->AddLinkChangeCallback(MakeCallback(&ArpCache::Flush, cache));
154 cache->SetArpRequestCallback(MakeCallback(&ArpL3Protocol::SendArpRequest, this));
155 m_cacheList.push_back(cache);
156 return cache;
157}
158
161{
162 NS_LOG_FUNCTION(this << device);
163 for (auto i = m_cacheList.begin(); i != m_cacheList.end(); i++)
164 {
165 if ((*i)->GetDevice() == device)
166 {
167 return *i;
168 }
169 }
170 NS_ASSERT(false);
171 // quiet compiler
172 return nullptr;
173}
174
175void
178 uint16_t protocol,
179 const Address& from,
180 const Address& to,
181 NetDevice::PacketType packetType)
182{
183 NS_LOG_FUNCTION(this << device << p->GetSize() << protocol << from << to << packetType);
184
185 Ptr<Packet> packet = p->Copy();
186
187 NS_LOG_LOGIC("ARP: received packet of size " << packet->GetSize());
188
189 Ptr<ArpCache> cache = FindCache(device);
190
191 //
192 // If we're connected to a real world network, then some of the fields sizes
193 // in an ARP packet can vary in ways not seen in simulations. We need to be
194 // able to detect ARP packets with headers we don't recognize and not process
195 // them instead of crashing. The ArpHeader will return 0 if it can't deal
196 // with the received header.
197 //
198 ArpHeader arp;
199 uint32_t size = packet->RemoveHeader(arp);
200 if (size == 0)
201 {
202 NS_LOG_LOGIC("ARP: Cannot remove ARP header");
203 return;
204 }
205 NS_LOG_LOGIC("ARP: received " << (arp.IsRequest() ? "request" : "reply")
206 << " node=" << m_node->GetId() << ", got "
207 << (arp.IsRequest() ? "request" : "reply") << " from "
208 << arp.GetSourceIpv4Address() << " for address "
209 << arp.GetDestinationIpv4Address() << "; we have addresses: ");
210 for (uint32_t i = 0; i < cache->GetInterface()->GetNAddresses(); i++)
211 {
212 NS_LOG_LOGIC(cache->GetInterface()->GetAddress(i).GetLocal() << ", ");
213 }
214
215 /**
216 * \internal
217 * Note: we do not update the ARP cache when we receive an ARP request
218 * from an unknown node. See \bugid{107}
219 */
220 bool found = false;
221 for (uint32_t i = 0; i < cache->GetInterface()->GetNAddresses(); i++)
222 {
223 if (arp.IsRequest() &&
224 arp.GetDestinationIpv4Address() == cache->GetInterface()->GetAddress(i).GetLocal())
225 {
226 found = true;
227 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got request from "
228 << arp.GetSourceIpv4Address() << " -- send reply");
229 SendArpReply(cache,
233 break;
234 }
235 else if (arp.IsReply() &&
237 cache->GetInterface()->GetAddress(i).GetLocal() &&
238 arp.GetDestinationHardwareAddress() == device->GetAddress())
239 {
240 found = true;
242 ArpCache::Entry* entry = cache->Lookup(from);
243 if (entry != nullptr)
244 {
245 if (entry->IsWaitReply())
246 {
247 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply from "
248 << arp.GetSourceIpv4Address()
249 << " for waiting entry -- flush");
250 Address from_mac = arp.GetSourceHardwareAddress();
251 entry->MarkAlive(from_mac);
253 while (pending.first)
254 {
255 cache->GetInterface()->Send(pending.first,
256 pending.second,
258 pending = entry->DequeuePending();
259 }
260 }
261 else
262 {
263 // ignore this reply which might well be an attempt
264 // at poisening my arp cache.
265 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply from "
266 << arp.GetSourceIpv4Address()
267 << " for non-waiting entry -- drop");
268 m_dropTrace(packet);
269 }
270 }
271 else
272 {
273 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply for unknown entry -- drop");
274 m_dropTrace(packet);
275 }
276 break;
277 }
278 }
279 if (!found)
280 {
281 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got request from "
282 << arp.GetSourceIpv4Address() << " for unknown address "
283 << arp.GetDestinationIpv4Address() << " -- drop");
284 }
285}
286
287bool
289 const Ipv4Header& ipHeader,
290 Ipv4Address destination,
291 Ptr<NetDevice> device,
292 Ptr<ArpCache> cache,
293 Address* hardwareDestination)
294{
295 NS_LOG_FUNCTION(this << packet << destination << device << cache << hardwareDestination);
296 ArpCache::Entry* entry = cache->Lookup(destination);
297 if (entry != nullptr)
298 {
299 if (entry->IsExpired())
300 {
301 if (entry->IsDead())
302 {
303 NS_LOG_LOGIC("node=" << m_node->GetId() << ", dead entry for " << destination
304 << " expired -- send arp request");
305 entry->MarkWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader));
308 this,
309 cache,
310 destination);
311 }
312 else if (entry->IsAlive())
313 {
314 NS_LOG_LOGIC("node=" << m_node->GetId() << ", alive entry for " << destination
315 << " expired -- send arp request");
316 entry->MarkWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader));
319 this,
320 cache,
321 destination);
322 }
323 else
324 {
325 NS_FATAL_ERROR("Test for possibly unreachable code-- please file a bug report, "
326 "with a test case, if this is ever hit");
327 }
328 }
329 else
330 {
331 if (entry->IsDead())
332 {
333 NS_LOG_LOGIC("node=" << m_node->GetId() << ", dead entry for " << destination
334 << " valid -- drop");
335 // add the Ipv4 header for tracing purposes
336 packet->AddHeader(ipHeader);
337 m_dropTrace(packet);
338 }
339 else if (entry->IsAlive())
340 {
341 NS_LOG_LOGIC("node=" << m_node->GetId() << ", alive entry for " << destination
342 << " valid -- send");
343 *hardwareDestination = entry->GetMacAddress();
344 return true;
345 }
346 else if (entry->IsWaitReply())
347 {
348 NS_LOG_LOGIC("node=" << m_node->GetId() << ", wait reply for " << destination
349 << " valid -- drop previous");
350 if (!entry->UpdateWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader)))
351 {
352 // add the Ipv4 header for tracing purposes
353 packet->AddHeader(ipHeader);
354 m_dropTrace(packet);
355 }
356 }
357 else if (entry->IsPermanent() || entry->IsAutoGenerated())
358 {
359 NS_LOG_LOGIC("node=" << m_node->GetId() << ", permanent for " << destination
360 << "valid -- send");
361 *hardwareDestination = entry->GetMacAddress();
362 return true;
363 }
364 else
365 {
366 NS_LOG_LOGIC("Test for possibly unreachable code-- please file a bug report, with "
367 "a test case, if this is ever hit");
368 }
369 }
370 }
371 else
372 {
373 // This is our first attempt to transmit data to this destination.
374 NS_LOG_LOGIC("node=" << m_node->GetId() << ", no entry for " << destination
375 << " -- send arp request");
376 entry = cache->Add(destination);
377 entry->MarkWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader));
380 this,
381 cache,
382 destination);
383 }
384 return false;
385}
386
387void
389{
390 NS_LOG_FUNCTION(this << cache << to);
391 ArpHeader arp;
392 // need to pick a source address; use routing implementation to select
394 Ptr<NetDevice> device = cache->GetDevice();
395 NS_ASSERT(device);
396 Ptr<Packet> packet = Create<Packet>();
397 Ipv4Address source = ipv4->SelectSourceAddress(device, to, Ipv4InterfaceAddress::GLOBAL);
398 NS_LOG_LOGIC("ARP: sending request from node "
399 << m_node->GetId() << " || src: " << device->GetAddress() << " / " << source
400 << " || dst: " << device->GetBroadcast() << " / " << to);
401 arp.SetRequest(device->GetAddress(), source, device->GetBroadcast(), to);
403 m_tc->Send(device, Create<ArpQueueDiscItem>(packet, device->GetBroadcast(), PROT_NUMBER, arp));
404}
405
406void
408 Ipv4Address myIp,
409 Ipv4Address toIp,
410 Address toMac)
411{
412 NS_LOG_FUNCTION(this << cache << myIp << toIp << toMac);
413 ArpHeader arp;
414 NS_LOG_LOGIC("ARP: sending reply from node "
415 << m_node->GetId() << "|| src: " << cache->GetDevice()->GetAddress() << " / "
416 << myIp << " || dst: " << toMac << " / " << toIp);
417 arp.SetReply(cache->GetDevice()->GetAddress(), myIp, toMac, toIp);
418 Ptr<Packet> packet = Create<Packet>();
420 m_tc->Send(cache->GetDevice(), Create<ArpQueueDiscItem>(packet, toMac, PROT_NUMBER, arp));
421}
422
423} // namespace ns3
a polymophic address class
Definition: address.h:101
A record that that holds information about an ArpCache entry.
Definition: arp-cache.h:184
bool IsDead()
Definition: arp-cache.cc:390
bool IsAlive()
Definition: arp-cache.cc:397
bool UpdateWaitReply(Ipv4PayloadHeaderPair waiting)
Definition: arp-cache.cc:468
Address GetMacAddress() const
Definition: arp-cache.cc:499
bool IsExpired() const
Definition: arp-cache.cc:547
bool IsWaitReply()
Definition: arp-cache.cc:404
void MarkAlive(Address macAddress)
Definition: arp-cache.cc:435
bool IsAutoGenerated()
Definition: arp-cache.cc:418
void MarkWaitReply(Ipv4PayloadHeaderPair waiting)
Definition: arp-cache.cc:485
Ipv4PayloadHeaderPair DequeuePending()
Definition: arp-cache.cc:557
bool IsPermanent()
Definition: arp-cache.cc:411
void Flush()
Clear the ArpCache of all entries.
Definition: arp-cache.cc:245
std::pair< Ptr< Packet >, Ipv4Header > Ipv4PayloadHeaderPair
Pair of a packet and an Ipv4 header.
Definition: arp-cache.h:178
The packet header for an ARP packet.
Definition: arp-header.h:36
void SetReply(Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress)
Set the ARP reply parameters.
Definition: arp-header.cc:49
bool IsReply() const
Check if the ARP is a reply.
Definition: arp-header.cc:71
bool IsRequest() const
Check if the ARP is a request.
Definition: arp-header.cc:64
Address GetDestinationHardwareAddress() const
Returns the destination hardware address.
Definition: arp-header.cc:85
Ipv4Address GetDestinationIpv4Address() const
Returns the destination IP address.
Definition: arp-header.cc:99
void SetRequest(Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress)
Set the ARP request parameters.
Definition: arp-header.cc:34
Ipv4Address GetSourceIpv4Address() const
Returns the source IP address.
Definition: arp-header.cc:92
Address GetSourceHardwareAddress() const
Returns the source hardware address.
Definition: arp-header.cc:78
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Ptr< RandomVariableStream > m_requestJitter
jitter to de-sync ARP requests
bool Lookup(Ptr< Packet > p, const Ipv4Header &ipHeader, Ipv4Address destination, Ptr< NetDevice > device, Ptr< ArpCache > cache, Address *hardwareDestination)
Perform an ARP lookup.
void Receive(Ptr< NetDevice > device, Ptr< const Packet > p, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
Receive a packet.
void SendArpReply(Ptr< const ArpCache > cache, Ipv4Address myIp, Ipv4Address toIp, Address toMac)
Send an ARP reply to an host.
Ptr< TrafficControlLayer > m_tc
The associated TrafficControlLayer.
CacheList m_cacheList
ARP cache container.
Ptr< ArpCache > FindCache(Ptr< NetDevice > device)
Finds the cache associated with a NetDevice.
void SendArpRequest(Ptr< const ArpCache > cache, Ipv4Address to)
Send an ARP request to an host.
void SetNode(Ptr< Node > node)
Set the node the ARP L3 protocol is associated with.
void DoDispose() override
Destructor implementation.
static const uint16_t PROT_NUMBER
ARP protocol number (0x0806)
void SetTrafficControl(Ptr< TrafficControlLayer > tc)
Set the TrafficControlLayer.
Ptr< ArpCache > CreateCache(Ptr< NetDevice > device, Ptr< Ipv4Interface > interface)
Create an ARP cache for the device/interface.
Ptr< Node > m_node
node the ARP L3 protocol is associated with
void NotifyNewAggregate() override
Notify all Objects aggregated to this one of a new Object being aggregated.
TracedCallback< Ptr< const Packet > > m_dropTrace
trace for packets dropped by ARP
~ArpL3Protocol() override
static TypeId GetTypeId()
Get the type ID.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
static Ipv4Address GetBroadcast()
Packet header for IPv4.
Definition: ipv4-header.h:34
Implement the IPv4 layer.
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:300
uint32_t GetId() const
Definition: node.cc:117
A base class which provides memory management and object aggregation.
Definition: object.h:89
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:423
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:522
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:444
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
virtual double GetValue()=0
Get the next random value drawn from the distribution.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
Hold variables of type string.
Definition: string.h:56
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
ObjectPtrContainerValue ObjectVectorValue
ObjectVectorValue is an alias for ObjectPtrContainerValue.
Definition: object-vector.h:40
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-vector.h:76
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:259
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:46
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:706