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 "ns3/node.h"
31 #include "ipv4-global-routing.h"
32 #include "global-route-manager.h"
33 
34 namespace ns3 {
35 
36 NS_LOG_COMPONENT_DEFINE ("Ipv4GlobalRouting");
37 
38 NS_OBJECT_ENSURE_REGISTERED (Ipv4GlobalRouting);
39 
40 TypeId
GetTypeId(void)41 Ipv4GlobalRouting::GetTypeId (void)
42 {
43   static TypeId tid = TypeId ("ns3::Ipv4GlobalRouting")
44     .SetParent<Object> ()
45     .SetGroupName ("Internet")
46     .AddAttribute ("RandomEcmpRouting",
47                    "Set to true if packets are randomly routed among ECMP; set to false for using only one route consistently",
48                    BooleanValue (false),
49                    MakeBooleanAccessor (&Ipv4GlobalRouting::m_randomEcmpRouting),
50                    MakeBooleanChecker ())
51     .AddAttribute ("RespondToInterfaceEvents",
52                    "Set to true if you want to dynamically recompute the global routes upon Interface notification events (up/down, or add/remove address)",
53                    BooleanValue (false),
54                    MakeBooleanAccessor (&Ipv4GlobalRouting::m_respondToInterfaceEvents),
55                    MakeBooleanChecker ())
56   ;
57   return tid;
58 }
59 
Ipv4GlobalRouting()60 Ipv4GlobalRouting::Ipv4GlobalRouting ()
61   : m_randomEcmpRouting (false),
62     m_respondToInterfaceEvents (false)
63 {
64   NS_LOG_FUNCTION (this);
65 
66   m_rand = CreateObject<UniformRandomVariable> ();
67 }
68 
~Ipv4GlobalRouting()69 Ipv4GlobalRouting::~Ipv4GlobalRouting ()
70 {
71   NS_LOG_FUNCTION (this);
72 }
73 
74 void
AddHostRouteTo(Ipv4Address dest,Ipv4Address nextHop,uint32_t interface)75 Ipv4GlobalRouting::AddHostRouteTo (Ipv4Address dest,
76                                    Ipv4Address nextHop,
77                                    uint32_t interface)
78 {
79   NS_LOG_FUNCTION (this << dest << nextHop << interface);
80   Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
81   *route = Ipv4RoutingTableEntry::CreateHostRouteTo (dest, nextHop, interface);
82   m_hostRoutes.push_back (route);
83 }
84 
85 void
AddHostRouteTo(Ipv4Address dest,uint32_t interface)86 Ipv4GlobalRouting::AddHostRouteTo (Ipv4Address dest,
87                                    uint32_t interface)
88 {
89   NS_LOG_FUNCTION (this << dest << interface);
90   Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
91   *route = Ipv4RoutingTableEntry::CreateHostRouteTo (dest, interface);
92   m_hostRoutes.push_back (route);
93 }
94 
95 void
AddNetworkRouteTo(Ipv4Address network,Ipv4Mask networkMask,Ipv4Address nextHop,uint32_t interface)96 Ipv4GlobalRouting::AddNetworkRouteTo (Ipv4Address network,
97                                       Ipv4Mask networkMask,
98                                       Ipv4Address nextHop,
99                                       uint32_t interface)
100 {
101   NS_LOG_FUNCTION (this << network << networkMask << nextHop << interface);
102   Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
103   *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo (network,
104                                                         networkMask,
105                                                         nextHop,
106                                                         interface);
107   m_networkRoutes.push_back (route);
108 }
109 
110 void
AddNetworkRouteTo(Ipv4Address network,Ipv4Mask networkMask,uint32_t interface)111 Ipv4GlobalRouting::AddNetworkRouteTo (Ipv4Address network,
112                                       Ipv4Mask networkMask,
113                                       uint32_t interface)
114 {
115   NS_LOG_FUNCTION (this << network << networkMask << interface);
116   Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
117   *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo (network,
118                                                         networkMask,
119                                                         interface);
120   m_networkRoutes.push_back (route);
121 }
122 
123 void
AddASExternalRouteTo(Ipv4Address network,Ipv4Mask networkMask,Ipv4Address nextHop,uint32_t interface)124 Ipv4GlobalRouting::AddASExternalRouteTo (Ipv4Address network,
125                                          Ipv4Mask networkMask,
126                                          Ipv4Address nextHop,
127                                          uint32_t interface)
128 {
129   NS_LOG_FUNCTION (this << network << networkMask << nextHop << interface);
130   Ipv4RoutingTableEntry *route = new Ipv4RoutingTableEntry ();
131   *route = Ipv4RoutingTableEntry::CreateNetworkRouteTo (network,
132                                                         networkMask,
133                                                         nextHop,
134                                                         interface);
135   m_ASexternalRoutes.push_back (route);
136 }
137 
138 
139 Ptr<Ipv4Route>
LookupGlobal(Ipv4Address dest,Ptr<NetDevice> oif)140 Ipv4GlobalRouting::LookupGlobal (Ipv4Address dest, Ptr<NetDevice> oif)
141 {
142   NS_LOG_FUNCTION (this << dest << oif);
143   NS_LOG_LOGIC ("Looking for route for destination " << dest);
144   Ptr<Ipv4Route> rtentry = 0;
145   // store all available routes that bring packets to their destination
146   typedef std::vector<Ipv4RoutingTableEntry*> RouteVec_t;
147   RouteVec_t allRoutes;
148 
149   NS_LOG_LOGIC ("Number of m_hostRoutes = " << m_hostRoutes.size ());
150   for (HostRoutesCI i = m_hostRoutes.begin ();
151        i != m_hostRoutes.end ();
152        i++)
153     {
154       NS_ASSERT ((*i)->IsHost ());
155       if ((*i)->GetDest () == dest)
156         {
157           if (oif != 0)
158             {
159               if (oif != m_ipv4->GetNetDevice ((*i)->GetInterface ()))
160                 {
161                   NS_LOG_LOGIC ("Not on requested interface, skipping");
162                   continue;
163                 }
164             }
165           allRoutes.push_back (*i);
166           NS_LOG_LOGIC (allRoutes.size () << "Found global host route" << *i);
167         }
168     }
169   if (allRoutes.size () == 0) // if no host route is found
170     {
171       NS_LOG_LOGIC ("Number of m_networkRoutes" << m_networkRoutes.size ());
172       for (NetworkRoutesI j = m_networkRoutes.begin ();
173            j != m_networkRoutes.end ();
174            j++)
175         {
176           Ipv4Mask mask = (*j)->GetDestNetworkMask ();
177           Ipv4Address entry = (*j)->GetDestNetwork ();
178           if (mask.IsMatch (dest, entry))
179             {
180               if (oif != 0)
181                 {
182                   if (oif != m_ipv4->GetNetDevice ((*j)->GetInterface ()))
183                     {
184                       NS_LOG_LOGIC ("Not on requested interface, skipping");
185                       continue;
186                     }
187                 }
188               allRoutes.push_back (*j);
189               NS_LOG_LOGIC (allRoutes.size () << "Found global network route" << *j);
190             }
191         }
192     }
193   if (allRoutes.size () == 0)  // consider external if no host/network found
194     {
195       for (ASExternalRoutesI k = m_ASexternalRoutes.begin ();
196            k != m_ASexternalRoutes.end ();
197            k++)
198         {
199           Ipv4Mask mask = (*k)->GetDestNetworkMask ();
200           Ipv4Address entry = (*k)->GetDestNetwork ();
201           if (mask.IsMatch (dest, entry))
202             {
203               NS_LOG_LOGIC ("Found external route" << *k);
204               if (oif != 0)
205                 {
206                   if (oif != m_ipv4->GetNetDevice ((*k)->GetInterface ()))
207                     {
208                       NS_LOG_LOGIC ("Not on requested interface, skipping");
209                       continue;
210                     }
211                 }
212               allRoutes.push_back (*k);
213               break;
214             }
215         }
216     }
217   if (allRoutes.size () > 0 ) // if route(s) is found
218     {
219       // pick up one of the routes uniformly at random if random
220       // ECMP routing is enabled, or always select the first route
221       // consistently if random ECMP routing is disabled
222       uint32_t selectIndex;
223       if (m_randomEcmpRouting)
224         {
225           selectIndex = m_rand->GetInteger (0, allRoutes.size ()-1);
226         }
227       else
228         {
229           selectIndex = 0;
230         }
231       Ipv4RoutingTableEntry* route = allRoutes.at (selectIndex);
232       // create a Ipv4Route object from the selected routing table entry
233       rtentry = Create<Ipv4Route> ();
234       rtentry->SetDestination (route->GetDest ());
235       /// \todo handle multi-address case
236       rtentry->SetSource (m_ipv4->GetAddress (route->GetInterface (), 0).GetLocal ());
237       rtentry->SetGateway (route->GetGateway ());
238       uint32_t interfaceIdx = route->GetInterface ();
239       rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
240       return rtentry;
241     }
242   else
243     {
244       return 0;
245     }
246 }
247 
248 uint32_t
GetNRoutes(void) const249 Ipv4GlobalRouting::GetNRoutes (void) const
250 {
251   NS_LOG_FUNCTION (this);
252   uint32_t n = 0;
253   n += m_hostRoutes.size ();
254   n += m_networkRoutes.size ();
255   n += m_ASexternalRoutes.size ();
256   return n;
257 }
258 
259 Ipv4RoutingTableEntry *
GetRoute(uint32_t index) const260 Ipv4GlobalRouting::GetRoute (uint32_t index) const
261 {
262   NS_LOG_FUNCTION (this << index);
263   if (index < m_hostRoutes.size ())
264     {
265       uint32_t tmp = 0;
266       for (HostRoutesCI i = m_hostRoutes.begin ();
267            i != m_hostRoutes.end ();
268            i++)
269         {
270           if (tmp  == index)
271             {
272               return *i;
273             }
274           tmp++;
275         }
276     }
277   index -= m_hostRoutes.size ();
278   uint32_t tmp = 0;
279   if (index < m_networkRoutes.size ())
280     {
281       for (NetworkRoutesCI j = m_networkRoutes.begin ();
282            j != m_networkRoutes.end ();
283            j++)
284         {
285           if (tmp == index)
286             {
287               return *j;
288             }
289           tmp++;
290         }
291     }
292   index -= m_networkRoutes.size ();
293   tmp = 0;
294   for (ASExternalRoutesCI k = m_ASexternalRoutes.begin ();
295        k != m_ASexternalRoutes.end ();
296        k++)
297     {
298       if (tmp == index)
299         {
300           return *k;
301         }
302       tmp++;
303     }
304   NS_ASSERT (false);
305   // quiet compiler.
306   return 0;
307 }
308 void
RemoveRoute(uint32_t index)309 Ipv4GlobalRouting::RemoveRoute (uint32_t index)
310 {
311   NS_LOG_FUNCTION (this << index);
312   if (index < m_hostRoutes.size ())
313     {
314       uint32_t tmp = 0;
315       for (HostRoutesI i = m_hostRoutes.begin ();
316            i != m_hostRoutes.end ();
317            i++)
318         {
319           if (tmp  == index)
320             {
321               NS_LOG_LOGIC ("Removing route " << index << "; size = " << m_hostRoutes.size ());
322               delete *i;
323               m_hostRoutes.erase (i);
324               NS_LOG_LOGIC ("Done removing host route " << index << "; host route remaining size = " << m_hostRoutes.size ());
325               return;
326             }
327           tmp++;
328         }
329     }
330   index -= m_hostRoutes.size ();
331   uint32_t tmp = 0;
332   for (NetworkRoutesI j = m_networkRoutes.begin ();
333        j != m_networkRoutes.end ();
334        j++)
335     {
336       if (tmp == index)
337         {
338           NS_LOG_LOGIC ("Removing route " << index << "; size = " << m_networkRoutes.size ());
339           delete *j;
340           m_networkRoutes.erase (j);
341           NS_LOG_LOGIC ("Done removing network route " << index << "; network route remaining size = " << m_networkRoutes.size ());
342           return;
343         }
344       tmp++;
345     }
346   index -= m_networkRoutes.size ();
347   tmp = 0;
348   for (ASExternalRoutesI k = m_ASexternalRoutes.begin ();
349        k != m_ASexternalRoutes.end ();
350        k++)
351     {
352       if (tmp == index)
353         {
354           NS_LOG_LOGIC ("Removing route " << index << "; size = " << m_ASexternalRoutes.size ());
355           delete *k;
356           m_ASexternalRoutes.erase (k);
357           NS_LOG_LOGIC ("Done removing network route " << index << "; network route remaining size = " << m_networkRoutes.size ());
358           return;
359         }
360       tmp++;
361     }
362   NS_ASSERT (false);
363 }
364 
365 int64_t
AssignStreams(int64_t stream)366 Ipv4GlobalRouting::AssignStreams (int64_t stream)
367 {
368   NS_LOG_FUNCTION (this << stream);
369   m_rand->SetStream (stream);
370   return 1;
371 }
372 
373 void
DoDispose(void)374 Ipv4GlobalRouting::DoDispose (void)
375 {
376   NS_LOG_FUNCTION (this);
377   for (HostRoutesI i = m_hostRoutes.begin ();
378        i != m_hostRoutes.end ();
379        i = m_hostRoutes.erase (i))
380     {
381       delete (*i);
382     }
383   for (NetworkRoutesI j = m_networkRoutes.begin ();
384        j != m_networkRoutes.end ();
385        j = m_networkRoutes.erase (j))
386     {
387       delete (*j);
388     }
389   for (ASExternalRoutesI l = m_ASexternalRoutes.begin ();
390        l != m_ASexternalRoutes.end ();
391        l = m_ASexternalRoutes.erase (l))
392     {
393       delete (*l);
394     }
395 
396   Ipv4RoutingProtocol::DoDispose ();
397 }
398 
399 // Formatted like output of "route -n" command
400 void
PrintRoutingTable(Ptr<OutputStreamWrapper> stream,Time::Unit unit) const401 Ipv4GlobalRouting::PrintRoutingTable (Ptr<OutputStreamWrapper> stream, Time::Unit unit) const
402 {
403   NS_LOG_FUNCTION (this << stream);
404   std::ostream* os = stream->GetStream ();
405   // Copy the current ostream state
406   std::ios oldState (nullptr);
407   oldState.copyfmt (*os);
408 
409   *os << std::resetiosflags (std::ios::adjustfield) << std::setiosflags (std::ios::left);
410 
411   *os << "Node: " << m_ipv4->GetObject<Node> ()->GetId ()
412       << ", Time: " << Now().As (unit)
413       << ", Local time: " << m_ipv4->GetObject<Node> ()->GetLocalTime ().As (unit)
414       << ", Ipv4GlobalRouting table" << std::endl;
415 
416   if (GetNRoutes () > 0)
417     {
418       *os << "Destination     Gateway         Genmask         Flags Metric Ref    Use Iface" << std::endl;
419       for (uint32_t j = 0; j < GetNRoutes (); j++)
420         {
421           std::ostringstream dest, gw, mask, flags;
422           Ipv4RoutingTableEntry route = GetRoute (j);
423           dest << route.GetDest ();
424           *os << std::setw (16) << dest.str ();
425           gw << route.GetGateway ();
426           *os << std::setw (16) << gw.str ();
427           mask << route.GetDestNetworkMask ();
428           *os << std::setw (16) << mask.str ();
429           flags << "U";
430           if (route.IsHost ())
431             {
432               flags << "H";
433             }
434           else if (route.IsGateway ())
435             {
436               flags << "G";
437             }
438           *os << std::setw (6) << flags.str ();
439           // Metric not implemented
440           *os << "-" << "      ";
441           // Ref ct not implemented
442           *os << "-" << "      ";
443           // Use not implemented
444           *os << "-" << "   ";
445           if (Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ())) != "")
446             {
447               *os << Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ()));
448             }
449           else
450             {
451               *os << route.GetInterface ();
452             }
453           *os << std::endl;
454         }
455     }
456   *os << std::endl;
457   // Restore the previous ostream state
458   (*os).copyfmt (oldState);
459 }
460 
461 Ptr<Ipv4Route>
RouteOutput(Ptr<Packet> p,const Ipv4Header & header,Ptr<NetDevice> oif,Socket::SocketErrno & sockerr)462 Ipv4GlobalRouting::RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
463 {
464   NS_LOG_FUNCTION (this << p << &header << oif << &sockerr);
465 //
466 // First, see if this is a multicast packet we have a route for.  If we
467 // have a route, then send the packet down each of the specified interfaces.
468 //
469   if (header.GetDestination ().IsMulticast ())
470     {
471       NS_LOG_LOGIC ("Multicast destination-- returning false");
472       return 0; // Let other routing protocols try to handle this
473     }
474 //
475 // See if this is a unicast packet we have a route for.
476 //
477   NS_LOG_LOGIC ("Unicast destination- looking up");
478   Ptr<Ipv4Route> rtentry = LookupGlobal (header.GetDestination (), oif);
479   if (rtentry)
480     {
481       sockerr = Socket::ERROR_NOTERROR;
482     }
483   else
484     {
485       sockerr = Socket::ERROR_NOROUTETOHOST;
486     }
487   return rtentry;
488 }
489 
490 bool
RouteInput(Ptr<const Packet> p,const Ipv4Header & header,Ptr<const NetDevice> idev,UnicastForwardCallback ucb,MulticastForwardCallback mcb,LocalDeliverCallback lcb,ErrorCallback ecb)491 Ipv4GlobalRouting::RouteInput  (Ptr<const Packet> p, const Ipv4Header &header, Ptr<const NetDevice> idev,                             UnicastForwardCallback ucb, MulticastForwardCallback mcb,
492                                 LocalDeliverCallback lcb, ErrorCallback ecb)
493 {
494   NS_LOG_FUNCTION (this << p << header << header.GetSource () << header.GetDestination () << idev << &lcb << &ecb);
495   // Check if input device supports IP
496   NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
497   uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
498 
499   if (m_ipv4->IsDestinationAddress (header.GetDestination (), iif))
500     {
501       if (!lcb.IsNull ())
502         {
503           NS_LOG_LOGIC ("Local delivery to " << header.GetDestination ());
504           lcb (p, header, iif);
505           return true;
506         }
507       else
508         {
509           // The local delivery callback is null.  This may be a multicast
510           // or broadcast packet, so return false so that another
511           // multicast routing protocol can handle it.  It should be possible
512           // to extend this to explicitly check whether it is a unicast
513           // packet, and invoke the error callback if so
514           return false;
515         }
516     }
517 
518   // Check if input device supports IP forwarding
519   if (m_ipv4->IsForwarding (iif) == false)
520     {
521       NS_LOG_LOGIC ("Forwarding disabled for this interface");
522       ecb (p, header, Socket::ERROR_NOROUTETOHOST);
523       return true;
524     }
525   // Next, try to find a route
526   NS_LOG_LOGIC ("Unicast destination- looking up global route");
527   Ptr<Ipv4Route> rtentry = LookupGlobal (header.GetDestination ());
528   if (rtentry != 0)
529     {
530       NS_LOG_LOGIC ("Found unicast destination- calling unicast callback");
531       ucb (rtentry, p, header);
532       return true;
533     }
534   else
535     {
536       NS_LOG_LOGIC ("Did not find unicast destination- returning false");
537       return false; // Let other routing protocols try to handle this
538                     // route request.
539     }
540 }
541 void
NotifyInterfaceUp(uint32_t i)542 Ipv4GlobalRouting::NotifyInterfaceUp (uint32_t i)
543 {
544   NS_LOG_FUNCTION (this << i);
545   if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0)  // avoid startup events
546     {
547       GlobalRouteManager::DeleteGlobalRoutes ();
548       GlobalRouteManager::BuildGlobalRoutingDatabase ();
549       GlobalRouteManager::InitializeRoutes ();
550     }
551 }
552 
553 void
NotifyInterfaceDown(uint32_t i)554 Ipv4GlobalRouting::NotifyInterfaceDown (uint32_t i)
555 {
556   NS_LOG_FUNCTION (this << i);
557   if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0)  // avoid startup events
558     {
559       GlobalRouteManager::DeleteGlobalRoutes ();
560       GlobalRouteManager::BuildGlobalRoutingDatabase ();
561       GlobalRouteManager::InitializeRoutes ();
562     }
563 }
564 
565 void
NotifyAddAddress(uint32_t interface,Ipv4InterfaceAddress address)566 Ipv4GlobalRouting::NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address)
567 {
568   NS_LOG_FUNCTION (this << interface << address);
569   if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0)  // avoid startup events
570     {
571       GlobalRouteManager::DeleteGlobalRoutes ();
572       GlobalRouteManager::BuildGlobalRoutingDatabase ();
573       GlobalRouteManager::InitializeRoutes ();
574     }
575 }
576 
577 void
NotifyRemoveAddress(uint32_t interface,Ipv4InterfaceAddress address)578 Ipv4GlobalRouting::NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address)
579 {
580   NS_LOG_FUNCTION (this << interface << address);
581   if (m_respondToInterfaceEvents && Simulator::Now ().GetSeconds () > 0)  // avoid startup events
582     {
583       GlobalRouteManager::DeleteGlobalRoutes ();
584       GlobalRouteManager::BuildGlobalRoutingDatabase ();
585       GlobalRouteManager::InitializeRoutes ();
586     }
587 }
588 
589 void
SetIpv4(Ptr<Ipv4> ipv4)590 Ipv4GlobalRouting::SetIpv4 (Ptr<Ipv4> ipv4)
591 {
592   NS_LOG_FUNCTION (this << ipv4);
593   NS_ASSERT (m_ipv4 == 0 && ipv4 != 0);
594   m_ipv4 = ipv4;
595 }
596 
597 
598 } // namespace ns3
599