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