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/packet.h"
21 #include "ns3/log.h"
22 #include "ns3/node.h"
23 #include "ns3/net-device.h"
24 #include "ns3/object-vector.h"
25 #include "ns3/trace-source-accessor.h"
26 #include "ns3/pointer.h"
27 #include "ns3/string.h"
28 
29 #include "ipv4-l3-protocol.h"
30 #include "arp-l3-protocol.h"
31 #include "arp-header.h"
32 #include "arp-cache.h"
33 #include "arp-queue-disc-item.h"
34 #include "ipv4-interface.h"
35 #include "ns3/traffic-control-layer.h"
36 
37 namespace ns3 {
38 
39 NS_LOG_COMPONENT_DEFINE ("ArpL3Protocol");
40 
41 const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
42 
43 NS_OBJECT_ENSURE_REGISTERED (ArpL3Protocol);
44 
45 TypeId
GetTypeId(void)46 ArpL3Protocol::GetTypeId (void)
47 {
48   static TypeId tid = TypeId ("ns3::ArpL3Protocol")
49     .SetParent<Object> ()
50     .AddConstructor<ArpL3Protocol> ()
51     .SetGroupName ("Internet")
52     .AddAttribute ("CacheList",
53                    "The list of ARP caches",
54                    ObjectVectorValue (),
55                    MakeObjectVectorAccessor (&ArpL3Protocol::m_cacheList),
56                    MakeObjectVectorChecker<ArpCache> ())
57     .AddAttribute ("RequestJitter",
58                    "The jitter in ms a node is allowed to wait "
59                    "before sending an ARP request.  Some jitter aims "
60                    "to prevent collisions. By default, the model "
61                    "will wait for a duration in ms defined by "
62                    "a uniform random-variable between 0 and RequestJitter",
63                    StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=10.0]"),
64                    MakePointerAccessor (&ArpL3Protocol::m_requestJitter),
65                    MakePointerChecker<RandomVariableStream> ())
66     .AddTraceSource ("Drop",
67                      "Packet dropped because not enough room "
68                      "in pending queue for a specific cache entry.",
69                      MakeTraceSourceAccessor (&ArpL3Protocol::m_dropTrace),
70                      "ns3::Packet::TracedCallback")
71   ;
72   return tid;
73 }
74 
ArpL3Protocol()75 ArpL3Protocol::ArpL3Protocol ()
76   : m_tc (0)
77 {
78   NS_LOG_FUNCTION (this);
79 }
80 
~ArpL3Protocol()81 ArpL3Protocol::~ArpL3Protocol ()
82 {
83   NS_LOG_FUNCTION (this);
84 }
85 
86 int64_t
AssignStreams(int64_t stream)87 ArpL3Protocol::AssignStreams (int64_t stream)
88 {
89   NS_LOG_FUNCTION (this << stream);
90   m_requestJitter->SetStream (stream);
91   return 1;
92 }
93 
94 void
SetNode(Ptr<Node> node)95 ArpL3Protocol::SetNode (Ptr<Node> node)
96 {
97   NS_LOG_FUNCTION (this << node);
98   m_node = node;
99 }
100 
101 void
SetTrafficControl(Ptr<TrafficControlLayer> tc)102 ArpL3Protocol::SetTrafficControl (Ptr<TrafficControlLayer> tc)
103 {
104   NS_LOG_FUNCTION (this << tc);
105   m_tc = tc;
106 }
107 
108 /*
109  * This method is called by AggregateObject and completes the aggregation
110  * by setting the node in the ipv4 stack
111  */
112 void
NotifyNewAggregate()113 ArpL3Protocol::NotifyNewAggregate ()
114 {
115   NS_LOG_FUNCTION (this);
116   if (m_node == 0)
117     {
118       Ptr<Node>node = this->GetObject<Node> ();
119       //verify that it's a valid node and that
120       //the node was not set before
121       if (node != 0)
122         {
123           this->SetNode (node);
124         }
125     }
126   Object::NotifyNewAggregate ();
127 }
128 
129 void
DoDispose(void)130 ArpL3Protocol::DoDispose (void)
131 {
132   NS_LOG_FUNCTION (this);
133   for (CacheList::iterator i = m_cacheList.begin (); i != m_cacheList.end (); ++i)
134     {
135       Ptr<ArpCache> cache = *i;
136       cache->Dispose ();
137     }
138   m_cacheList.clear ();
139   m_node = 0;
140   m_tc = 0;
141   Object::DoDispose ();
142 }
143 
144 Ptr<ArpCache>
CreateCache(Ptr<NetDevice> device,Ptr<Ipv4Interface> interface)145 ArpL3Protocol::CreateCache (Ptr<NetDevice> device, Ptr<Ipv4Interface> interface)
146 {
147   NS_LOG_FUNCTION (this << device << interface);
148   Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
149   Ptr<ArpCache> cache = CreateObject<ArpCache> ();
150   cache->SetDevice (device, interface);
151   NS_ASSERT (device->IsBroadcast ());
152   device->AddLinkChangeCallback (MakeCallback (&ArpCache::Flush, cache));
153   cache->SetArpRequestCallback (MakeCallback (&ArpL3Protocol::SendArpRequest, this));
154   m_cacheList.push_back (cache);
155   return cache;
156 }
157 
158 Ptr<ArpCache>
FindCache(Ptr<NetDevice> device)159 ArpL3Protocol::FindCache (Ptr<NetDevice> device)
160 {
161   NS_LOG_FUNCTION (this << device);
162   for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
163     {
164       if ((*i)->GetDevice () == device)
165         {
166           return *i;
167         }
168     }
169   NS_ASSERT (false);
170   // quiet compiler
171   return 0;
172 }
173 
174 void
Receive(Ptr<NetDevice> device,Ptr<const Packet> p,uint16_t protocol,const Address & from,const Address & to,NetDevice::PacketType packetType)175 ArpL3Protocol::Receive (Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from,
176                         const Address &to, NetDevice::PacketType packetType)
177 {
178   NS_LOG_FUNCTION (this << device << p->GetSize () << protocol << from << to << packetType);
179 
180   Ptr<Packet> packet = p->Copy ();
181 
182   NS_LOG_LOGIC ("ARP: received packet of size "<< packet->GetSize ());
183 
184   Ptr<ArpCache> cache = FindCache (device);
185 
186   //
187   // If we're connected to a real world network, then some of the fields sizes
188   // in an ARP packet can vary in ways not seen in simulations.  We need to be
189   // able to detect ARP packets with headers we don't recongnize and not process
190   // them instead of crashing.  The ArpHeader will return 0 if it can't deal
191   // with the received header.
192   //
193   ArpHeader arp;
194   uint32_t size = packet->RemoveHeader (arp);
195   if (size == 0)
196     {
197       NS_LOG_LOGIC ("ARP: Cannot remove ARP header");
198       return;
199     }
200   NS_LOG_LOGIC ("ARP: received " << (arp.IsRequest () ? "request" : "reply") <<
201                 " node=" << m_node->GetId () <<
202                 ", got " <<
203                 (arp.IsRequest () ? "request" : "reply") <<
204                 " from " << arp.GetSourceIpv4Address () <<
205                 " for address " << arp.GetDestinationIpv4Address () <<
206                 "; we have addresses: ");
207   for (uint32_t i = 0; i < cache->GetInterface ()->GetNAddresses (); i++)
208     {
209       NS_LOG_LOGIC (cache->GetInterface ()->GetAddress (i).GetLocal () << ", ");
210     }
211 
212   /**
213    * \internal
214    * Note: we do not update the ARP cache when we receive an ARP request
215    *  from an unknown node. See \bugid{107}
216    */
217   bool found = false;
218   for (uint32_t i = 0; i < cache->GetInterface ()->GetNAddresses (); i++)
219     {
220       if (arp.IsRequest () && arp.GetDestinationIpv4Address () ==
221           cache->GetInterface ()->GetAddress (i).GetLocal ())
222         {
223           found = true;
224           NS_LOG_LOGIC ("node="<<m_node->GetId () <<", got request from " <<
225                         arp.GetSourceIpv4Address () << " -- send reply");
226           SendArpReply (cache, arp.GetDestinationIpv4Address (), arp.GetSourceIpv4Address (),
227                         arp.GetSourceHardwareAddress ());
228           break;
229         }
230       else if (arp.IsReply () &&
231                arp.GetDestinationIpv4Address () == cache->GetInterface ()->GetAddress (i).GetLocal () &&
232                arp.GetDestinationHardwareAddress () == device->GetAddress ())
233         {
234           found = true;
235           Ipv4Address from = arp.GetSourceIpv4Address ();
236           ArpCache::Entry *entry = cache->Lookup (from);
237           if (entry != 0)
238             {
239               if (entry->IsWaitReply ())
240                 {
241                   NS_LOG_LOGIC ("node="<< m_node->GetId () <<
242                                 ", got reply from " << arp.GetSourceIpv4Address ()
243                                        << " for waiting entry -- flush");
244                   Address from_mac = arp.GetSourceHardwareAddress ();
245                   entry->MarkAlive (from_mac);
246                   ArpCache::Ipv4PayloadHeaderPair pending = entry->DequeuePending ();
247                   while (pending.first != 0)
248                     {
249                       cache->GetInterface ()->Send (pending.first, pending.second,
250                                                     arp.GetSourceIpv4Address ());
251                       pending = entry->DequeuePending ();
252                     }
253                 }
254               else
255                 {
256                   // ignore this reply which might well be an attempt
257                   // at poisening my arp cache.
258                   NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply from " <<
259                                 arp.GetSourceIpv4Address () <<
260                                 " for non-waiting entry -- drop");
261                   m_dropTrace (packet);
262                 }
263             }
264           else
265             {
266               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got reply for unknown entry -- drop");
267               m_dropTrace (packet);
268             }
269           break;
270         }
271     }
272   if (found == false)
273     {
274       NS_LOG_LOGIC ("node="<<m_node->GetId ()<<", got request from " <<
275                     arp.GetSourceIpv4Address () << " for unknown address " <<
276                     arp.GetDestinationIpv4Address () << " -- drop");
277     }
278 }
279 
280 bool
Lookup(Ptr<Packet> packet,const Ipv4Header & ipHeader,Ipv4Address destination,Ptr<NetDevice> device,Ptr<ArpCache> cache,Address * hardwareDestination)281 ArpL3Protocol::Lookup (Ptr<Packet> packet, const Ipv4Header & ipHeader, Ipv4Address destination,
282                        Ptr<NetDevice> device,
283                        Ptr<ArpCache> cache,
284                        Address *hardwareDestination)
285 {
286   NS_LOG_FUNCTION (this << packet << destination << device << cache << hardwareDestination);
287   ArpCache::Entry *entry = cache->Lookup (destination);
288   if (entry != 0)
289     {
290       if (entry->IsExpired ())
291         {
292           if (entry->IsDead ())
293             {
294               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
295                             ", dead entry for " << destination << " expired -- send arp request");
296               entry->MarkWaitReply (ArpCache::Ipv4PayloadHeaderPair (packet, ipHeader));
297               Simulator::Schedule (Time (MilliSeconds (m_requestJitter->GetValue ())), &ArpL3Protocol::SendArpRequest, this, cache, destination);
298             }
299           else if (entry->IsAlive ())
300             {
301               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
302                             ", alive entry for " << destination << " expired -- send arp request");
303               entry->MarkWaitReply (ArpCache::Ipv4PayloadHeaderPair (packet, ipHeader));
304               Simulator::Schedule (Time (MilliSeconds (m_requestJitter->GetValue ())), &ArpL3Protocol::SendArpRequest, this, cache, destination);
305             }
306           else
307             {
308               NS_FATAL_ERROR ("Test for possibly unreachable code-- please file a bug report, with a test case, if this is ever hit");
309             }
310         }
311       else
312         {
313           if (entry->IsDead ())
314             {
315               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
316                             ", dead entry for " << destination << " valid -- drop");
317               // add the Ipv4 header for tracing purposes
318               packet->AddHeader (ipHeader);
319               m_dropTrace (packet);
320             }
321           else if (entry->IsAlive ())
322             {
323               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
324                             ", alive entry for " << destination << " valid -- send");
325               *hardwareDestination = entry->GetMacAddress ();
326               return true;
327             }
328           else if (entry->IsWaitReply ())
329             {
330               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
331                             ", wait reply for " << destination << " valid -- drop previous");
332               if (!entry->UpdateWaitReply (ArpCache::Ipv4PayloadHeaderPair (packet, ipHeader)))
333                 {
334                   // add the Ipv4 header for tracing purposes
335                   packet->AddHeader (ipHeader);
336                   m_dropTrace (packet);
337                 }
338             }
339           else if (entry-> IsPermanent ())
340             {
341               NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
342                             ", permanent for " << destination << "valid -- send");
343               *hardwareDestination = entry->GetMacAddress ();
344               return true;
345             }
346           else
347             {
348               NS_LOG_LOGIC ("Test for possibly unreachable code-- please file a bug report, with a test case, if this is ever hit");
349             }
350         }
351     }
352   else
353     {
354       // This is our first attempt to transmit data to this destination.
355       NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
356                     ", no entry for " << destination << " -- send arp request");
357       entry = cache->Add (destination);
358       entry->MarkWaitReply (ArpCache::Ipv4PayloadHeaderPair (packet, ipHeader));
359       Simulator::Schedule (Time (MilliSeconds (m_requestJitter->GetValue ())), &ArpL3Protocol::SendArpRequest, this, cache, destination);
360     }
361   return false;
362 }
363 
364 void
SendArpRequest(Ptr<const ArpCache> cache,Ipv4Address to)365 ArpL3Protocol::SendArpRequest (Ptr<const ArpCache> cache, Ipv4Address to)
366 {
367   NS_LOG_FUNCTION (this << cache << to);
368   ArpHeader arp;
369   // need to pick a source address; use routing implementation to select
370   Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
371   Ptr<NetDevice> device = cache->GetDevice ();
372   NS_ASSERT (device != 0);
373   Ptr<Packet> packet = Create<Packet> ();
374   Ipv4Address source = ipv4->SelectSourceAddress (device,  to, Ipv4InterfaceAddress::GLOBAL);
375   NS_LOG_LOGIC ("ARP: sending request from node "<<m_node->GetId ()<<
376                 " || src: " << device->GetAddress () << " / " << source <<
377                 " || dst: " << device->GetBroadcast () << " / " << to);
378   arp.SetRequest (device->GetAddress (), source, device->GetBroadcast (), to);
379   NS_ASSERT (m_tc != 0);
380   m_tc->Send (device, Create<ArpQueueDiscItem> (packet, device->GetBroadcast (), PROT_NUMBER, arp));
381 }
382 
383 void
SendArpReply(Ptr<const ArpCache> cache,Ipv4Address myIp,Ipv4Address toIp,Address toMac)384 ArpL3Protocol::SendArpReply (Ptr<const ArpCache> cache, Ipv4Address myIp, Ipv4Address toIp, Address toMac)
385 {
386   NS_LOG_FUNCTION (this << cache << myIp << toIp << toMac);
387   ArpHeader arp;
388   NS_LOG_LOGIC ("ARP: sending reply from node "<<m_node->GetId ()<<
389                 "|| src: " << cache->GetDevice ()->GetAddress () <<
390                 " / " << myIp <<
391                 " || dst: " << toMac << " / " << toIp);
392   arp.SetReply (cache->GetDevice ()->GetAddress (), myIp, toMac, toIp);
393   Ptr<Packet> packet = Create<Packet> ();
394   NS_ASSERT (m_tc != 0);
395   m_tc->Send (cache->GetDevice (), Create<ArpQueueDiscItem> (packet, toMac, PROT_NUMBER, arp));
396 }
397 
398 } // namespace ns3
399