A Discrete-Event Network Simulator
API
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 
37 namespace ns3
38 {
39 
40 NS_LOG_COMPONENT_DEFINE("ArpL3Protocol");
41 
42 const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
43 
44 NS_OBJECT_ENSURE_REGISTERED(ArpL3Protocol);
45 
46 TypeId
48 {
49  static TypeId tid =
50  TypeId("ns3::ArpL3Protocol")
51  .SetParent<Object>()
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 
87 int64_t
89 {
90  NS_LOG_FUNCTION(this << stream);
91  m_requestJitter->SetStream(stream);
92  return 1;
93 }
94 
95 void
97 {
98  NS_LOG_FUNCTION(this << node);
99  m_node = node;
100 }
101 
102 void
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  */
113 void
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 
130 void
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 
175 void
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 
220  bool found = false;
221  for (uint32_t i = 0; i < cache->GetInterface()->GetNAddresses(); i++)
222  {
223  if (arp.IsRequest() &&
225  {
226  found = true;
227  NS_LOG_LOGIC("node=" << m_node->GetId() << ", got request from "
228  << arp.GetSourceIpv4Address() << " -- send reply");
229  SendArpReply(cache,
231  arp.GetSourceIpv4Address(),
233  break;
234  }
235  else if (arp.IsReply() &&
237  cache->GetInterface()->GetAddress(i).GetLocal() &&
238  arp.GetDestinationHardwareAddress() == device->GetAddress())
239  {
240  found = true;
241  Ipv4Address from = arp.GetSourceIpv4Address();
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,
257  arp.GetSourceIpv4Address());
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 
287 bool
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 
387 void
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);
402  NS_ASSERT(m_tc);
403  m_tc->Send(device, Create<ArpQueueDiscItem>(packet, device->GetBroadcast(), PROT_NUMBER, arp));
404 }
405 
406 void
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>();
419  NS_ASSERT(m_tc);
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
ArpCache::Entry * Add(Ipv4Address to)
Add an Ipv4Address to this ARP cache.
Definition: arp-cache.cc:352
Ptr< Ipv4Interface > GetInterface() const
Returns the Ipv4Interface that this ARP cache is associated with.
Definition: arp-cache.cc:128
ArpCache::Entry * Lookup(Ipv4Address destination)
Do lookup in the ARP cache against an IP address.
Definition: arp-cache.cc:340
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
Ipv4Address GetLocal() const
Get the local address.
Ipv4InterfaceAddress GetAddress(uint32_t index) const
void Send(Ptr< Packet > p, const Ipv4Header &hdr, Ipv4Address dest)
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:331
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
void Dispose()
Dispose of this Object.
Definition: object.cc:219
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
Ptr< Packet > Copy() const
performs a COW copy of the packet.
Definition: packet.cc:131
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
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
#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
#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:1338
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:839
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:704
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Definition: pointer.h:227
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