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 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8#include "arp-l3-protocol.h"
9
10#include "arp-cache.h"
11#include "arp-header.h"
12#include "arp-queue-disc-item.h"
13#include "ipv4-interface.h"
14#include "ipv4-l3-protocol.h"
15
16#include "ns3/log.h"
17#include "ns3/net-device.h"
18#include "ns3/node.h"
19#include "ns3/object-vector.h"
20#include "ns3/packet.h"
21#include "ns3/pointer.h"
22#include "ns3/string.h"
23#include "ns3/trace-source-accessor.h"
24#include "ns3/traffic-control-layer.h"
25
26namespace ns3
27{
28
29NS_LOG_COMPONENT_DEFINE("ArpL3Protocol");
30
31const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
32
33NS_OBJECT_ENSURE_REGISTERED(ArpL3Protocol);
34
35TypeId
37{
38 static TypeId tid =
39 TypeId("ns3::ArpL3Protocol")
41 .AddConstructor<ArpL3Protocol>()
42 .SetGroupName("Internet")
43 .AddAttribute("CacheList",
44 "The list of ARP caches",
48 .AddAttribute("RequestJitter",
49 "The jitter in ms a node is allowed to wait "
50 "before sending an ARP request. Some jitter aims "
51 "to prevent collisions. By default, the model "
52 "will wait for a duration in ms defined by "
53 "a uniform random-variable between 0 and RequestJitter",
54 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=10.0]"),
57 .AddTraceSource("Drop",
58 "Packet dropped because not enough room "
59 "in pending queue for a specific cache entry.",
61 "ns3::Packet::TracedCallback");
62 return tid;
63}
64
66 : m_tc(nullptr)
67{
68 NS_LOG_FUNCTION(this);
69}
70
75
76int64_t
78{
79 NS_LOG_FUNCTION(this << stream);
81 return 1;
82}
83
84void
86{
87 NS_LOG_FUNCTION(this << node);
88 m_node = node;
89}
90
91void
97
98/*
99 * This method is called by AggregateObject and completes the aggregation
100 * by setting the node in the ipv4 stack
101 */
102void
104{
105 NS_LOG_FUNCTION(this);
106 if (!m_node)
107 {
108 Ptr<Node> node = this->GetObject<Node>();
109 // verify that it's a valid node and that
110 // the node was not set before
111 if (node)
112 {
113 this->SetNode(node);
114 }
115 }
117}
118
119void
121{
122 NS_LOG_FUNCTION(this);
123 for (auto i = m_cacheList.begin(); i != m_cacheList.end(); ++i)
124 {
125 Ptr<ArpCache> cache = *i;
126 cache->Dispose();
127 }
128 m_cacheList.clear();
129 m_node = nullptr;
130 m_tc = nullptr;
132}
133
136{
137 NS_LOG_FUNCTION(this << device << interface);
140 cache->SetDevice(device, interface);
141 NS_ASSERT(device->IsBroadcast());
142 device->AddLinkChangeCallback(MakeCallback(&ArpCache::Flush, cache));
143 cache->SetArpRequestCallback(MakeCallback(&ArpL3Protocol::SendArpRequest, this));
144 m_cacheList.push_back(cache);
145 return cache;
146}
147
150{
151 NS_LOG_FUNCTION(this << device);
152 for (auto i = m_cacheList.begin(); i != m_cacheList.end(); i++)
153 {
154 if ((*i)->GetDevice() == device)
155 {
156 return *i;
157 }
158 }
159 NS_ASSERT(false);
160 // quiet compiler
161 return nullptr;
162}
163
164void
167 uint16_t protocol,
168 const Address& from,
169 const Address& to,
170 NetDevice::PacketType packetType)
171{
172 NS_LOG_FUNCTION(this << device << p->GetSize() << protocol << from << to << packetType);
173
174 Ptr<Packet> packet = p->Copy();
175
176 NS_LOG_LOGIC("ARP: received packet of size " << packet->GetSize());
177
178 Ptr<ArpCache> cache = FindCache(device);
179
180 //
181 // If we're connected to a real world network, then some of the fields sizes
182 // in an ARP packet can vary in ways not seen in simulations. We need to be
183 // able to detect ARP packets with headers we don't recognize and not process
184 // them instead of crashing. The ArpHeader will return 0 if it can't deal
185 // with the received header.
186 //
187 ArpHeader arp;
188 uint32_t size = packet->RemoveHeader(arp);
189 if (size == 0)
190 {
191 NS_LOG_LOGIC("ARP: Cannot remove ARP header");
192 return;
193 }
194 NS_LOG_LOGIC("ARP: received " << (arp.IsRequest() ? "request" : "reply")
195 << " node=" << m_node->GetId() << ", got "
196 << (arp.IsRequest() ? "request" : "reply") << " from "
197 << arp.GetSourceIpv4Address() << " for address "
198 << arp.GetDestinationIpv4Address() << "; we have addresses: ");
199 for (uint32_t i = 0; i < cache->GetInterface()->GetNAddresses(); i++)
200 {
201 NS_LOG_LOGIC(cache->GetInterface()->GetAddress(i).GetLocal() << ", ");
202 }
203
204 /**
205 * @internal
206 * Note: we do not update the ARP cache when we receive an ARP request
207 * from an unknown node. See \bugid{107}
208 */
209 bool found = false;
210 for (uint32_t i = 0; i < cache->GetInterface()->GetNAddresses(); i++)
211 {
212 if (arp.IsRequest() &&
213 arp.GetDestinationIpv4Address() == cache->GetInterface()->GetAddress(i).GetLocal())
214 {
215 found = true;
216 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got request from "
217 << arp.GetSourceIpv4Address() << " -- send reply");
218 SendArpReply(cache,
222 break;
223 }
224 else if (arp.IsReply() &&
226 cache->GetInterface()->GetAddress(i).GetLocal() &&
227 arp.GetDestinationHardwareAddress() == device->GetAddress())
228 {
229 found = true;
231 ArpCache::Entry* entry = cache->Lookup(from);
232 if (entry != nullptr)
233 {
234 if (entry->IsWaitReply())
235 {
236 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply from "
237 << arp.GetSourceIpv4Address()
238 << " for waiting entry -- flush");
239 Address from_mac = arp.GetSourceHardwareAddress();
240 entry->MarkAlive(from_mac);
242 while (pending.first)
243 {
244 cache->GetInterface()->Send(pending.first,
245 pending.second,
247 pending = entry->DequeuePending();
248 }
249 }
250 else
251 {
252 // ignore this reply which might well be an attempt
253 // at poisoning my arp cache.
254 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply from "
255 << arp.GetSourceIpv4Address()
256 << " for non-waiting entry -- drop");
257 m_dropTrace(packet);
258 }
259 }
260 else
261 {
262 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got reply for unknown entry -- drop");
263 m_dropTrace(packet);
264 }
265 break;
266 }
267 }
268 if (!found)
269 {
270 NS_LOG_LOGIC("node=" << m_node->GetId() << ", got request from "
271 << arp.GetSourceIpv4Address() << " for unknown address "
272 << arp.GetDestinationIpv4Address() << " -- drop");
273 }
274}
275
276bool
278 const Ipv4Header& ipHeader,
279 Ipv4Address destination,
280 Ptr<NetDevice> device,
281 Ptr<ArpCache> cache,
282 Address* hardwareDestination)
283{
284 NS_LOG_FUNCTION(this << packet << destination << device << cache << hardwareDestination);
285 ArpCache::Entry* entry = cache->Lookup(destination);
286 if (entry != nullptr)
287 {
288 if (entry->IsExpired())
289 {
290 if (entry->IsDead())
291 {
292 NS_LOG_LOGIC("node=" << m_node->GetId() << ", dead entry for " << destination
293 << " expired -- send arp request");
294 entry->MarkWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader));
297 this,
298 cache,
299 destination);
300 }
301 else if (entry->IsAlive())
302 {
303 NS_LOG_LOGIC("node=" << m_node->GetId() << ", alive entry for " << destination
304 << " expired -- send arp request");
305 entry->MarkWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader));
308 this,
309 cache,
310 destination);
311 }
312 else
313 {
314 NS_FATAL_ERROR("Test for possibly unreachable code-- please file a bug report, "
315 "with a test case, if this is ever hit");
316 }
317 }
318 else
319 {
320 if (entry->IsDead())
321 {
322 NS_LOG_LOGIC("node=" << m_node->GetId() << ", dead entry for " << destination
323 << " valid -- drop");
324 // add the Ipv4 header for tracing purposes
325 packet->AddHeader(ipHeader);
326 m_dropTrace(packet);
327 }
328 else if (entry->IsAlive())
329 {
330 NS_LOG_LOGIC("node=" << m_node->GetId() << ", alive entry for " << destination
331 << " valid -- send");
332 *hardwareDestination = entry->GetMacAddress();
333 return true;
334 }
335 else if (entry->IsWaitReply())
336 {
337 NS_LOG_LOGIC("node=" << m_node->GetId() << ", wait reply for " << destination
338 << " valid -- drop previous");
339 if (!entry->UpdateWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader)))
340 {
341 // add the Ipv4 header for tracing purposes
342 packet->AddHeader(ipHeader);
343 m_dropTrace(packet);
344 }
345 }
346 else if (entry->IsPermanent() || entry->IsAutoGenerated())
347 {
348 NS_LOG_LOGIC("node=" << m_node->GetId() << ", permanent for " << destination
349 << "valid -- send");
350 *hardwareDestination = entry->GetMacAddress();
351 return true;
352 }
353 else
354 {
355 NS_LOG_LOGIC("Test for possibly unreachable code-- please file a bug report, with "
356 "a test case, if this is ever hit");
357 }
358 }
359 }
360 else
361 {
362 // This is our first attempt to transmit data to this destination.
363 NS_LOG_LOGIC("node=" << m_node->GetId() << ", no entry for " << destination
364 << " -- send arp request");
365 entry = cache->Add(destination);
366 entry->MarkWaitReply(ArpCache::Ipv4PayloadHeaderPair(packet, ipHeader));
369 this,
370 cache,
371 destination);
372 }
373 return false;
374}
375
376void
378{
379 NS_LOG_FUNCTION(this << cache << to);
380 ArpHeader arp;
381 // need to pick a source address; use routing implementation to select
383 Ptr<NetDevice> device = cache->GetDevice();
384 NS_ASSERT(device);
385 Ptr<Packet> packet = Create<Packet>();
386 Ipv4Address source = ipv4->SelectSourceAddress(device, to, Ipv4InterfaceAddress::GLOBAL);
387 NS_LOG_LOGIC("ARP: sending request from node "
388 << m_node->GetId() << " || src: " << device->GetAddress() << " / " << source
389 << " || dst: " << device->GetBroadcast() << " / " << to);
390 arp.SetRequest(device->GetAddress(), source, device->GetBroadcast(), to);
392 m_tc->Send(device, Create<ArpQueueDiscItem>(packet, device->GetBroadcast(), PROT_NUMBER, arp));
393}
394
395void
397 Ipv4Address myIp,
398 Ipv4Address toIp,
399 Address toMac)
400{
401 NS_LOG_FUNCTION(this << cache << myIp << toIp << toMac);
402 ArpHeader arp;
403 NS_LOG_LOGIC("ARP: sending reply from node "
404 << m_node->GetId() << "|| src: " << cache->GetDevice()->GetAddress() << " / "
405 << myIp << " || dst: " << toMac << " / " << toIp);
406 arp.SetReply(cache->GetDevice()->GetAddress(), myIp, toMac, toIp);
407 Ptr<Packet> packet = Create<Packet>();
409 m_tc->Send(cache->GetDevice(), Create<ArpQueueDiscItem>(packet, toMac, PROT_NUMBER, arp));
410}
411
412} // namespace ns3
a polymophic address class
Definition address.h:90
A record that that holds information about an ArpCache entry.
Definition arp-cache.h:173
bool IsDead()
Definition arp-cache.cc:379
bool IsAlive()
Definition arp-cache.cc:386
bool UpdateWaitReply(Ipv4PayloadHeaderPair waiting)
Definition arp-cache.cc:457
Address GetMacAddress() const
Definition arp-cache.cc:488
bool IsExpired() const
Definition arp-cache.cc:535
bool IsWaitReply()
Definition arp-cache.cc:393
void MarkAlive(Address macAddress)
Definition arp-cache.cc:424
bool IsAutoGenerated()
Definition arp-cache.cc:407
void MarkWaitReply(Ipv4PayloadHeaderPair waiting)
Definition arp-cache.cc:474
Ipv4PayloadHeaderPair DequeuePending()
Definition arp-cache.cc:545
bool IsPermanent()
Definition arp-cache.cc:400
void Flush()
Clear the ArpCache of all entries.
Definition arp-cache.cc:234
std::pair< Ptr< Packet >, Ipv4Header > Ipv4PayloadHeaderPair
Pair of a packet and an Ipv4 header.
Definition arp-cache.h:167
The packet header for an ARP packet.
Definition arp-header.h:23
void SetReply(Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress)
Set the ARP reply parameters.
Definition arp-header.cc:39
bool IsReply() const
Check if the ARP is a reply.
Definition arp-header.cc:78
bool IsRequest() const
Check if the ARP is a request.
Definition arp-header.cc:71
Address GetDestinationHardwareAddress() const
Returns the destination hardware address.
Definition arp-header.cc:99
Ipv4Address GetDestinationIpv4Address() const
Returns the destination IP address.
void SetRequest(Address sourceHardwareAddress, Ipv4Address sourceProtocolAddress, Address destinationHardwareAddress, Ipv4Address destinationProtocolAddress)
Set the ARP request parameters.
Definition arp-header.cc:23
Ipv4Address GetSourceIpv4Address() const
Returns the source IP address.
Address GetSourceHardwareAddress() const
Returns the source hardware address.
Definition arp-header.cc:92
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
static TypeId GetTypeId()
Get the type ID.
Ipv4 addresses are stored in host order in this class.
static Ipv4Address GetBroadcast()
Packet header for IPv4.
Definition ipv4-header.h:23
Implement the IPv4 layer.
PacketType
Packet types are used as they are in Linux.
Definition net-device.h:289
uint32_t GetId() const
Definition node.cc:106
A base class which provides memory management and object aggregation.
Definition object.h:78
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition object.cc:412
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
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:560
Hold variables of type string.
Definition string.h:45
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#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 > MakeObjectVectorChecker()
ObjectPtrContainerValue ObjectVectorValue
ObjectVectorValue is an alias for ObjectPtrContainerValue.
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
#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 ",...
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:619
#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 MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1356
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:684