A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ipv4-global-routing.cc
Go to the documentation of this file.
1 // -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*-
2 //
3 // Copyright (c) 2008 University of Washington
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 
19 #include <vector>
20 #include <iomanip>
21 #include "ns3/names.h"
22 #include "ns3/log.h"
23 #include "ns3/simulator.h"
24 #include "ns3/object.h"
25 #include "ns3/packet.h"
26 #include "ns3/net-device.h"
27 #include "ns3/ipv4-route.h"
28 #include "ns3/ipv4-routing-table-entry.h"
29 #include "ns3/boolean.h"
30 #include "ipv4-global-routing.h"
31 #include "global-route-manager.h"
32 
33 NS_LOG_COMPONENT_DEFINE ("Ipv4GlobalRouting");
34 
35 namespace ns3 {
36 
37 NS_OBJECT_ENSURE_REGISTERED (Ipv4GlobalRouting);
38 
39 TypeId
41 {
42  static TypeId tid = TypeId ("ns3::Ipv4GlobalRouting")
43  .SetParent<Object> ()
44  .AddAttribute ("RandomEcmpRouting",
45  "Set to true if packets are randomly routed among ECMP; set to false for using only one route consistently",
46  BooleanValue (false),
47  MakeBooleanAccessor (&Ipv4GlobalRouting::m_randomEcmpRouting),
48  MakeBooleanChecker ())
49  .AddAttribute ("RespondToInterfaceEvents",
50  "Set to true if you want to dynamically recompute the global routes upon Interface notification events (up/down, or add/remove address)",
51  BooleanValue (false),
52  MakeBooleanAccessor (&Ipv4GlobalRouting::m_respondToInterfaceEvents),
53  MakeBooleanChecker ())
54  ;
55  return tid;
56 }
57 
59  : m_randomEcmpRouting (false),
60  m_respondToInterfaceEvents (false)
61 {
63 
64  m_rand = CreateObject<UniformRandomVariable> ();
65 }
66 
68 {
70 }
71 
72 void
74  Ipv4Address nextHop,
75  uint32_t interface)
76 {
77  NS_LOG_FUNCTION (dest << nextHop << interface);
79  *route = Ipv4RoutingTableEntry::CreateHostRouteTo (dest, nextHop, interface);
80  m_hostRoutes.push_back (route);
81 }
82 
83 void
85  uint32_t interface)
86 {
87  NS_LOG_FUNCTION (dest << interface);
89  *route = Ipv4RoutingTableEntry::CreateHostRouteTo (dest, interface);
90  m_hostRoutes.push_back (route);
91 }
92 
93 void
95  Ipv4Mask networkMask,
96  Ipv4Address nextHop,
97  uint32_t interface)
98 {
99  NS_LOG_FUNCTION (network << networkMask << nextHop << interface);
102  networkMask,
103  nextHop,
104  interface);
105  m_networkRoutes.push_back (route);
106 }
107 
108 void
110  Ipv4Mask networkMask,
111  uint32_t interface)
112 {
113  NS_LOG_FUNCTION (network << networkMask << interface);
116  networkMask,
117  interface);
118  m_networkRoutes.push_back (route);
119 }
120 
121 void
123  Ipv4Mask networkMask,
124  Ipv4Address nextHop,
125  uint32_t interface)
126 {
127  NS_LOG_FUNCTION (network << networkMask << nextHop);
130  networkMask,
131  nextHop,
132  interface);
133  m_ASexternalRoutes.push_back (route);
134 }
135 
136 
139 {
141  NS_LOG_LOGIC ("Looking for route for destination " << dest);
142  Ptr<Ipv4Route> rtentry = 0;
143  // store all available routes that bring packets to their destination
144  typedef std::vector<Ipv4RoutingTableEntry*> RouteVec_t;
145  RouteVec_t allRoutes;
146 
147  NS_LOG_LOGIC ("Number of m_hostRoutes = " << m_hostRoutes.size ());
148  for (HostRoutesCI i = m_hostRoutes.begin ();
149  i != m_hostRoutes.end ();
150  i++)
151  {
152  NS_ASSERT ((*i)->IsHost ());
153  if ((*i)->GetDest ().IsEqual (dest))
154  {
155  if (oif != 0)
156  {
157  if (oif != m_ipv4->GetNetDevice ((*i)->GetInterface ()))
158  {
159  NS_LOG_LOGIC ("Not on requested interface, skipping");
160  continue;
161  }
162  }
163  allRoutes.push_back (*i);
164  NS_LOG_LOGIC (allRoutes.size () << "Found global host route" << *i);
165  }
166  }
167  if (allRoutes.size () == 0) // if no host route is found
168  {
169  NS_LOG_LOGIC ("Number of m_networkRoutes" << m_networkRoutes.size ());
170  for (NetworkRoutesI j = m_networkRoutes.begin ();
171  j != m_networkRoutes.end ();
172  j++)
173  {
174  Ipv4Mask mask = (*j)->GetDestNetworkMask ();
175  Ipv4Address entry = (*j)->GetDestNetwork ();
176  if (mask.IsMatch (dest, entry))
177  {
178  if (oif != 0)
179  {
180  if (oif != m_ipv4->GetNetDevice ((*j)->GetInterface ()))
181  {
182  NS_LOG_LOGIC ("Not on requested interface, skipping");
183  continue;
184  }
185  }
186  allRoutes.push_back (*j);
187  NS_LOG_LOGIC (allRoutes.size () << "Found global network route" << *j);
188  }
189  }
190  }
191  if (allRoutes.size () == 0) // consider external if no host/network found
192  {
193  for (ASExternalRoutesI k = m_ASexternalRoutes.begin ();
194  k != m_ASexternalRoutes.end ();
195  k++)
196  {
197  Ipv4Mask mask = (*k)->GetDestNetworkMask ();
198  Ipv4Address entry = (*k)->GetDestNetwork ();
199  if (mask.IsMatch (dest, entry))
200  {
201  NS_LOG_LOGIC ("Found external route" << *k);
202  if (oif != 0)
203  {
204  if (oif != m_ipv4->GetNetDevice ((*k)->GetInterface ()))
205  {
206  NS_LOG_LOGIC ("Not on requested interface, skipping");
207  continue;
208  }
209  }
210  allRoutes.push_back (*k);
211  break;
212  }
213  }
214  }
215  if (allRoutes.size () > 0 ) // if route(s) is found
216  {
217  // pick up one of the routes uniformly at random if random
218  // ECMP routing is enabled, or always select the first route
219  // consistently if random ECMP routing is disabled
220  uint32_t selectIndex;
222  {
223  selectIndex = m_rand->GetInteger (0, allRoutes.size ()-1);
224  }
225  else
226  {
227  selectIndex = 0;
228  }
229  Ipv4RoutingTableEntry* route = allRoutes.at (selectIndex);
230  // create a Ipv4Route object from the selected routing table entry
231  rtentry = Create<Ipv4Route> ();
232  rtentry->SetDestination (route->GetDest ());
233  // XXX handle multi-address case
234  rtentry->SetSource (m_ipv4->GetAddress (route->GetInterface (), 0).GetLocal ());
235  rtentry->SetGateway (route->GetGateway ());
236  uint32_t interfaceIdx = route->GetInterface ();
237  rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
238  return rtentry;
239  }
240  else
241  {
242  return 0;
243  }
244 }
245 
246 uint32_t
248 {
250  uint32_t n = 0;
251  n += m_hostRoutes.size ();
252  n += m_networkRoutes.size ();
253  n += m_ASexternalRoutes.size ();
254  return n;
255 }
256 
258 Ipv4GlobalRouting::GetRoute (uint32_t index) const
259 {
260  NS_LOG_FUNCTION (index);
261  if (index < m_hostRoutes.size ())
262  {
263  uint32_t tmp = 0;
264  for (HostRoutesCI i = m_hostRoutes.begin ();
265  i != m_hostRoutes.end ();
266  i++)
267  {
268  if (tmp == index)
269  {
270  return *i;
271  }
272  tmp++;
273  }
274  }
275  index -= m_hostRoutes.size ();
276  uint32_t tmp = 0;
277  if (index < m_networkRoutes.size ())
278  {
279  for (NetworkRoutesCI j = m_networkRoutes.begin ();
280  j != m_networkRoutes.end ();
281  j++)
282  {
283  if (tmp == index)
284  {
285  return *j;
286  }
287  tmp++;
288  }
289  }
290  index -= m_networkRoutes.size ();
291  tmp = 0;
292  for (ASExternalRoutesCI k = m_ASexternalRoutes.begin ();
293  k != m_ASexternalRoutes.end ();
294  k++)
295  {
296  if (tmp == index)
297  {
298  return *k;
299  }
300  tmp++;
301  }
302  NS_ASSERT (false);
303  // quiet compiler.
304  return 0;
305 }
306 void
308 {
309  NS_LOG_FUNCTION (index);
310  if (index < m_hostRoutes.size ())
311  {
312  uint32_t tmp = 0;
313  for (HostRoutesI i = m_hostRoutes.begin ();
314  i != m_hostRoutes.end ();
315  i++)
316  {
317  if (tmp == index)
318  {
319  NS_LOG_LOGIC ("Removing route " << index << "; size = " << m_hostRoutes.size ());
320  delete *i;
321  m_hostRoutes.erase (i);
322  NS_LOG_LOGIC ("Done removing host route " << index << "; host route remaining size = " << m_hostRoutes.size ());
323  return;
324  }
325  tmp++;
326  }
327  }
328  index -= m_hostRoutes.size ();
329  uint32_t tmp = 0;
330  for (NetworkRoutesI j = m_networkRoutes.begin ();
331  j != m_networkRoutes.end ();
332  j++)
333  {
334  if (tmp == index)
335  {
336  NS_LOG_LOGIC ("Removing route " << index << "; size = " << m_networkRoutes.size ());
337  delete *j;
338  m_networkRoutes.erase (j);
339  NS_LOG_LOGIC ("Done removing network route " << index << "; network route remaining size = " << m_networkRoutes.size ());
340  return;
341  }
342  tmp++;
343  }
344  index -= m_networkRoutes.size ();
345  tmp = 0;
346  for (ASExternalRoutesI k = m_ASexternalRoutes.begin ();
347  k != m_ASexternalRoutes.end ();
348  k++)
349  {
350  if (tmp == index)
351  {
352  NS_LOG_LOGIC ("Removing route " << index << "; size = " << m_ASexternalRoutes.size ());
353  delete *k;
354  m_ASexternalRoutes.erase (k);
355  NS_LOG_LOGIC ("Done removing network route " << index << "; network route remaining size = " << m_networkRoutes.size ());
356  return;
357  }
358  tmp++;
359  }
360  NS_ASSERT (false);
361 }
362 
363 int64_t
365 {
366  NS_LOG_FUNCTION (this << stream);
367  m_rand->SetStream (stream);
368  return 1;
369 }
370 
371 void
373 {
375  for (HostRoutesI i = m_hostRoutes.begin ();
376  i != m_hostRoutes.end ();
377  i = m_hostRoutes.erase (i))
378  {
379  delete (*i);
380  }
381  for (NetworkRoutesI j = m_networkRoutes.begin ();
382  j != m_networkRoutes.end ();
383  j = m_networkRoutes.erase (j))
384  {
385  delete (*j);
386  }
387  for (ASExternalRoutesI l = m_ASexternalRoutes.begin ();
388  l != m_ASexternalRoutes.end ();
389  l = m_ASexternalRoutes.erase (l))
390  {
391  delete (*l);
392  }
393 
395 }
396 
397 // Formatted like output of "route -n" command
398 void
400 {
401  std::ostream* os = stream->GetStream ();
402  if (GetNRoutes () > 0)
403  {
404  *os << "Destination Gateway Genmask Flags Metric Ref Use Iface" << std::endl;
405  for (uint32_t j = 0; j < GetNRoutes (); j++)
406  {
407  std::ostringstream dest, gw, mask, flags;
408  Ipv4RoutingTableEntry route = GetRoute (j);
409  dest << route.GetDest ();
410  *os << std::setiosflags (std::ios::left) << std::setw (16) << dest.str ();
411  gw << route.GetGateway ();
412  *os << std::setiosflags (std::ios::left) << std::setw (16) << gw.str ();
413  mask << route.GetDestNetworkMask ();
414  *os << std::setiosflags (std::ios::left) << std::setw (16) << mask.str ();
415  flags << "U";
416  if (route.IsHost ())
417  {
418  flags << "H";
419  }
420  else if (route.IsGateway ())
421  {
422  flags << "G";
423  }
424  *os << std::setiosflags (std::ios::left) << std::setw (6) << flags.str ();
425  // Metric not implemented
426  *os << "-" << " ";
427  // Ref ct not implemented
428  *os << "-" << " ";
429  // Use not implemented
430  *os << "-" << " ";
431  if (Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ())) != "")
432  {
433  *os << Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ()));
434  }
435  else
436  {
437  *os << route.GetInterface ();
438  }
439  *os << std::endl;
440  }
441  }
442 }
443 
446 {
447 
448 //
449 // First, see if this is a multicast packet we have a route for. If we
450 // have a route, then send the packet down each of the specified interfaces.
451 //
452  if (header.GetDestination ().IsMulticast ())
453  {
454  NS_LOG_LOGIC ("Multicast destination-- returning false");
455  return 0; // Let other routing protocols try to handle this
456  }
457 //
458 // See if this is a unicast packet we have a route for.
459 //
460  NS_LOG_LOGIC ("Unicast destination- looking up");
461  Ptr<Ipv4Route> rtentry = LookupGlobal (header.GetDestination (), oif);
462  if (rtentry)
463  {
464  sockerr = Socket::ERROR_NOTERROR;
465  }
466  else
467  {
468  sockerr = Socket::ERROR_NOROUTETOHOST;
469  }
470  return rtentry;
471 }
472 
473 bool
476 {
477 
478  NS_LOG_FUNCTION (this << p << header << header.GetSource () << header.GetDestination () << idev);
479  // Check if input device supports IP
480  NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
481  uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
482 
483  if (header.GetDestination ().IsMulticast ())
484  {
485  NS_LOG_LOGIC ("Multicast destination-- returning false");
486  return false; // Let other routing protocols try to handle this
487  }
488 
489  if (header.GetDestination ().IsBroadcast ())
490  {
491  NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
492  // TODO: Local Deliver for broadcast
493  // TODO: Forward broadcast
494  }
495 
496  // TODO: Configurable option to enable RFC 1222 Strong End System Model
497  // Right now, we will be permissive and allow a source to send us
498  // a packet to one of our other interface addresses; that is, the
499  // destination unicast address does not match one of the iif addresses,
500  // but we check our other interfaces. This could be an option
501  // (to remove the outer loop immediately below and just check iif).
502  for (uint32_t j = 0; j < m_ipv4->GetNInterfaces (); j++)
503  {
504  for (uint32_t i = 0; i < m_ipv4->GetNAddresses (j); i++)
505  {
506  Ipv4InterfaceAddress iaddr = m_ipv4->GetAddress (j, i);
507  Ipv4Address addr = iaddr.GetLocal ();
508  if (addr.IsEqual (header.GetDestination ()))
509  {
510  if (j == iif)
511  {
512  NS_LOG_LOGIC ("For me (destination " << addr << " match)");
513  }
514  else
515  {
516  NS_LOG_LOGIC ("For me (destination " << addr << " match) on another interface " << header.GetDestination ());
517  }
518  lcb (p, header, iif);
519  return true;
520  }
521  if (header.GetDestination ().IsEqual (iaddr.GetBroadcast ()))
522  {
523  NS_LOG_LOGIC ("For me (interface broadcast address)");
524  lcb (p, header, iif);
525  return true;
526  }
527  NS_LOG_LOGIC ("Address "<< addr << " not a match");
528  }
529  }
530  // Check if input device supports IP forwarding
531  if (m_ipv4->IsForwarding (iif) == false)
532  {
533  NS_LOG_LOGIC ("Forwarding disabled for this interface");
534  ecb (p, header, Socket::ERROR_NOROUTETOHOST);
535  return false;
536  }
537  // Next, try to find a route
538  NS_LOG_LOGIC ("Unicast destination- looking up global route");
539  Ptr<Ipv4Route> rtentry = LookupGlobal (header.GetDestination ());
540  if (rtentry != 0)
541  {
542  NS_LOG_LOGIC ("Found unicast destination- calling unicast callback");
543  ucb (rtentry, p, header);
544  return true;
545  }
546  else
547  {
548  NS_LOG_LOGIC ("Did not find unicast destination- returning false");
549  return false; // Let other routing protocols try to handle this
550  // route request.
551  }
552 }
553 void
555 {
556  NS_LOG_FUNCTION (this << i);
557  if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0) // avoid startup events
558  {
562  }
563 }
564 
565 void
567 {
568  NS_LOG_FUNCTION (this << i);
569  if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0) // avoid startup events
570  {
574  }
575 }
576 
577 void
579 {
580  NS_LOG_FUNCTION (this << interface << address);
581  if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0) // avoid startup events
582  {
586  }
587 }
588 
589 void
591 {
592  NS_LOG_FUNCTION (this << interface << address);
593  if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0) // avoid startup events
594  {
598  }
599 }
600 
601 void
603 {
604  NS_LOG_FUNCTION (this << ipv4);
605  NS_ASSERT (m_ipv4 == 0 && ipv4 != 0);
606  m_ipv4 = ipv4;
607 }
608 
609 
610 } // namespace ns3