A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ipv4-static-routing.cc
Go to the documentation of this file.
1 // -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*-
2 //
3 // Copyright (c) 2006 Georgia Tech Research Corporation
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: George F. Riley<riley@ece.gatech.edu>
19 // Gustavo Carneiro <gjc@inescporto.pt>
20 
21 #define NS_LOG_APPEND_CONTEXT \
22  if (m_ipv4 && m_ipv4->GetObject<Node> ()) { \
23  std::clog << Simulator::Now ().GetSeconds () \
24  << " [node " << m_ipv4->GetObject<Node> ()->GetId () << "] "; }
25 
26 #include <iomanip>
27 #include "ns3/log.h"
28 #include "ns3/names.h"
29 #include "ns3/packet.h"
30 #include "ns3/node.h"
31 #include "ns3/simulator.h"
32 #include "ns3/ipv4-route.h"
33 #include "ns3/output-stream-wrapper.h"
34 #include "ipv4-static-routing.h"
36 
37 NS_LOG_COMPONENT_DEFINE ("Ipv4StaticRouting");
38 
39 using std::make_pair;
40 
41 namespace ns3 {
42 
43 NS_OBJECT_ENSURE_REGISTERED (Ipv4StaticRouting);
44 
45 TypeId
47 {
48  static TypeId tid = TypeId ("ns3::Ipv4StaticRouting")
50  .AddConstructor<Ipv4StaticRouting> ()
51  ;
52  return tid;
53 }
54 
56  : m_ipv4 (0)
57 {
58  NS_LOG_FUNCTION (this);
59 }
60 
61 void
63  Ipv4Mask networkMask,
64  Ipv4Address nextHop,
65  uint32_t interface,
66  uint32_t metric)
67 {
68  NS_LOG_FUNCTION (this << network << " " << networkMask << " " << nextHop << " " << interface << " " << metric);
71  networkMask,
72  nextHop,
73  interface);
74  m_networkRoutes.push_back (make_pair (route,metric));
75 }
76 
77 void
79  Ipv4Mask networkMask,
80  uint32_t interface,
81  uint32_t metric)
82 {
83  NS_LOG_FUNCTION (this << network << " " << networkMask << " " << interface << " " << metric);
86  networkMask,
87  interface);
88  m_networkRoutes.push_back (make_pair (route,metric));
89 }
90 
91 void
93  Ipv4Address nextHop,
94  uint32_t interface,
95  uint32_t metric)
96 {
97  NS_LOG_FUNCTION (this << dest << " " << nextHop << " " << interface << " " << metric);
98  AddNetworkRouteTo (dest, Ipv4Mask::GetOnes (), nextHop, interface, metric);
99 }
100 
101 void
103  uint32_t interface,
104  uint32_t metric)
105 {
106  NS_LOG_FUNCTION (this << dest << " " << interface << " " << metric);
107  AddNetworkRouteTo (dest, Ipv4Mask::GetOnes (), interface, metric);
108 }
109 
110 void
112  uint32_t interface,
113  uint32_t metric)
114 {
115  NS_LOG_FUNCTION (this << nextHop << " " << interface << " " << metric);
116  AddNetworkRouteTo (Ipv4Address ("0.0.0.0"), Ipv4Mask::GetZero (), nextHop, interface, metric);
117 }
118 
119 void
122  uint32_t inputInterface,
123  std::vector<uint32_t> outputInterfaces)
124 {
125  NS_LOG_FUNCTION (this << origin << " " << group << " " << inputInterface);
128  inputInterface, outputInterfaces);
129  m_multicastRoutes.push_back (route);
130 }
131 
132 // default multicast routes are stored as a network route
133 // these routes are _not_ consulted in the forwarding process-- only
134 // for originating packets
135 void
137 {
138  NS_LOG_FUNCTION (this << outputInterface);
140  Ipv4Address network = Ipv4Address ("224.0.0.0");
141  Ipv4Mask networkMask = Ipv4Mask ("240.0.0.0");
143  networkMask,
144  outputInterface);
145  m_networkRoutes.push_back (make_pair (route,0));
146 }
147 
148 uint32_t
150 {
151  NS_LOG_FUNCTION (this);
152  return m_multicastRoutes.size ();
153 }
154 
157 {
158  NS_LOG_FUNCTION (this << index);
159  NS_ASSERT_MSG (index < m_multicastRoutes.size (),
160  "Ipv4StaticRouting::GetMulticastRoute (): Index out of range");
161 
162  if (index < m_multicastRoutes.size ())
163  {
164  uint32_t tmp = 0;
165  for (MulticastRoutesCI i = m_multicastRoutes.begin ();
166  i != m_multicastRoutes.end ();
167  i++)
168  {
169  if (tmp == index)
170  {
171  return *i;
172  }
173  tmp++;
174  }
175  }
176  return 0;
177 }
178 
179 bool
182  uint32_t inputInterface)
183 {
184  NS_LOG_FUNCTION (this << origin << " " << group << " " << inputInterface);
185  for (MulticastRoutesI i = m_multicastRoutes.begin ();
186  i != m_multicastRoutes.end ();
187  i++)
188  {
189  Ipv4MulticastRoutingTableEntry *route = *i;
190  if (origin == route->GetOrigin () &&
191  group == route->GetGroup () &&
192  inputInterface == route->GetInputInterface ())
193  {
194  delete *i;
195  m_multicastRoutes.erase (i);
196  return true;
197  }
198  }
199  return false;
200 }
201 
202 void
204 {
205  NS_LOG_FUNCTION (this << index);
206  uint32_t tmp = 0;
207  for (MulticastRoutesI i = m_multicastRoutes.begin ();
208  i != m_multicastRoutes.end ();
209  i++)
210  {
211  if (tmp == index)
212  {
213  delete *i;
214  m_multicastRoutes.erase (i);
215  return;
216  }
217  tmp++;
218  }
219 }
220 
223 {
224  NS_LOG_FUNCTION (this << dest << " " << oif);
225  Ptr<Ipv4Route> rtentry = 0;
226  uint16_t longest_mask = 0;
227  uint32_t shortest_metric = 0xffffffff;
228  /* when sending on local multicast, there have to be interface specified */
229  if (dest.IsLocalMulticast ())
230  {
231  NS_ASSERT_MSG (oif, "Try to send on link-local multicast address, and no interface index is given!");
232 
233  rtentry = Create<Ipv4Route> ();
234  rtentry->SetDestination (dest);
235  rtentry->SetGateway (Ipv4Address::GetZero ());
236  rtentry->SetOutputDevice (oif);
237  rtentry->SetSource (m_ipv4->GetAddress (oif->GetIfIndex (), 0).GetLocal ());
238  return rtentry;
239  }
240 
241 
242  for (NetworkRoutesI i = m_networkRoutes.begin ();
243  i != m_networkRoutes.end ();
244  i++)
245  {
246  Ipv4RoutingTableEntry *j=i->first;
247  uint32_t metric =i->second;
248  Ipv4Mask mask = (j)->GetDestNetworkMask ();
249  uint16_t masklen = mask.GetPrefixLength ();
250  Ipv4Address entry = (j)->GetDestNetwork ();
251  NS_LOG_LOGIC ("Searching for route to " << dest << ", checking against route to " << entry << "/" << masklen);
252  if (mask.IsMatch (dest, entry))
253  {
254  NS_LOG_LOGIC ("Found global network route " << j << ", mask length " << masklen << ", metric " << metric);
255  if (oif != 0)
256  {
257  if (oif != m_ipv4->GetNetDevice (j->GetInterface ()))
258  {
259  NS_LOG_LOGIC ("Not on requested interface, skipping");
260  continue;
261  }
262  }
263  if (masklen < longest_mask) // Not interested if got shorter mask
264  {
265  NS_LOG_LOGIC ("Previous match longer, skipping");
266  continue;
267  }
268  if (masklen > longest_mask) // Reset metric if longer masklen
269  {
270  shortest_metric = 0xffffffff;
271  }
272  longest_mask = masklen;
273  if (metric > shortest_metric)
274  {
275  NS_LOG_LOGIC ("Equal mask length, but previous metric shorter, skipping");
276  continue;
277  }
278  shortest_metric = metric;
279  Ipv4RoutingTableEntry* route = (j);
280  uint32_t interfaceIdx = route->GetInterface ();
281  rtentry = Create<Ipv4Route> ();
282  rtentry->SetDestination (route->GetDest ());
283  rtentry->SetSource (SourceAddressSelection (interfaceIdx, route->GetDest ()));
284  rtentry->SetGateway (route->GetGateway ());
285  rtentry->SetOutputDevice (m_ipv4->GetNetDevice (interfaceIdx));
286  }
287  }
288  if (rtentry != 0)
289  {
290  NS_LOG_LOGIC ("Matching route via " << rtentry->GetGateway () << " at the end");
291  }
292  else
293  {
294  NS_LOG_LOGIC ("No matching route to " << dest << " found");
295  }
296  return rtentry;
297 }
298 
301  Ipv4Address origin,
303  uint32_t interface)
304 {
305  NS_LOG_FUNCTION (this << origin << " " << group << " " << interface);
306  Ptr<Ipv4MulticastRoute> mrtentry = 0;
307 
308  for (MulticastRoutesI i = m_multicastRoutes.begin ();
309  i != m_multicastRoutes.end ();
310  i++)
311  {
312  Ipv4MulticastRoutingTableEntry *route = *i;
313 //
314 // We've been passed an origin address, a multicast group address and an
315 // interface index. We have to decide if the current route in the list is
316 // a match.
317 //
318 // The first case is the restrictive case where the origin, group and index
319 // matches.
320 //
321  if (origin == route->GetOrigin () && group == route->GetGroup ())
322  {
323  // Skipping this case (SSM) for now
324  NS_LOG_LOGIC ("Found multicast source specific route" << *i);
325  }
326  if (group == route->GetGroup ())
327  {
328  if (interface == Ipv4::IF_ANY ||
329  interface == route->GetInputInterface ())
330  {
331  NS_LOG_LOGIC ("Found multicast route" << *i);
332  mrtentry = Create<Ipv4MulticastRoute> ();
333  mrtentry->SetGroup (route->GetGroup ());
334  mrtentry->SetOrigin (route->GetOrigin ());
335  mrtentry->SetParent (route->GetInputInterface ());
336  for (uint32_t j = 0; j < route->GetNOutputInterfaces (); j++)
337  {
338  if (route->GetOutputInterface (j))
339  {
340  NS_LOG_LOGIC ("Setting output interface index " << route->GetOutputInterface (j));
341  mrtentry->SetOutputTtl (route->GetOutputInterface (j), Ipv4MulticastRoute::MAX_TTL - 1);
342  }
343  }
344  return mrtentry;
345  }
346  }
347  }
348  return mrtentry;
349 }
350 
351 uint32_t
353 {
354  NS_LOG_FUNCTION (this);
355  return m_networkRoutes.size ();;
356 }
357 
360 {
361  NS_LOG_FUNCTION (this);
362  // Basically a repeat of LookupStatic, retained for backward compatibility
363  Ipv4Address dest ("0.0.0.0");
364  uint32_t shortest_metric = 0xffffffff;
365  Ipv4RoutingTableEntry *result = 0;
366  for (NetworkRoutesI i = m_networkRoutes.begin ();
367  i != m_networkRoutes.end ();
368  i++)
369  {
370  Ipv4RoutingTableEntry *j = i->first;
371  uint32_t metric = i->second;
372  Ipv4Mask mask = (j)->GetDestNetworkMask ();
373  uint16_t masklen = mask.GetPrefixLength ();
374  if (masklen != 0)
375  {
376  continue;
377  }
378  if (metric > shortest_metric)
379  {
380  continue;
381  }
382  shortest_metric = metric;
383  result = j;
384  }
385  if (result)
386  {
387  return result;
388  }
389  else
390  {
391  return Ipv4RoutingTableEntry ();
392  }
393 }
394 
396 Ipv4StaticRouting::GetRoute (uint32_t index) const
397 {
398  NS_LOG_FUNCTION (this << index);
399  uint32_t tmp = 0;
400  for (NetworkRoutesCI j = m_networkRoutes.begin ();
401  j != m_networkRoutes.end ();
402  j++)
403  {
404  if (tmp == index)
405  {
406  return j->first;
407  }
408  tmp++;
409  }
410  NS_ASSERT (false);
411  // quiet compiler.
412  return 0;
413 }
414 
415 uint32_t
416 Ipv4StaticRouting::GetMetric (uint32_t index) const
417 {
418  NS_LOG_FUNCTION (this << index);
419  uint32_t tmp = 0;
420  for (NetworkRoutesCI j = m_networkRoutes.begin ();
421  j != m_networkRoutes.end ();
422  j++)
423  {
424  if (tmp == index)
425  {
426  return j->second;
427  }
428  tmp++;
429  }
430  NS_ASSERT (false);
431  // quiet compiler.
432  return 0;
433 }
434 void
436 {
437  NS_LOG_FUNCTION (this << index);
438  uint32_t tmp = 0;
439  for (NetworkRoutesI j = m_networkRoutes.begin ();
440  j != m_networkRoutes.end ();
441  j++)
442  {
443  if (tmp == index)
444  {
445  delete j->first;
446  m_networkRoutes.erase (j);
447  return;
448  }
449  tmp++;
450  }
451  NS_ASSERT (false);
452 }
453 
456 {
457  NS_LOG_FUNCTION (this << header << oif);
458  Ipv4Address destination = header.GetDestination ();
459  Ptr<Ipv4Route> rtentry = 0;
460 
461  // Multicast goes here
462  if (destination.IsMulticast ())
463  {
464  // Note: Multicast routes for outbound packets are stored in the
465  // normal unicast table. An implication of this is that it is not
466  // possible to source multicast datagrams on multiple interfaces.
467  // This is a well-known property of sockets implementation on
468  // many Unix variants.
469  // So, we just log it and fall through to LookupStatic ()
470  NS_LOG_LOGIC ("RouteOutput()::Multicast destination");
471  }
472  rtentry = LookupStatic (destination, oif);
473  if (rtentry)
474  {
475  sockerr = Socket::ERROR_NOTERROR;
476  }
477  else
478  {
479  sockerr = Socket::ERROR_NOROUTETOHOST;
480  }
481  return rtentry;
482 }
483 
484 bool
488 {
489  NS_LOG_FUNCTION (this << p << ipHeader << ipHeader.GetSource () << ipHeader.GetDestination () << idev);
490 
491  NS_ASSERT (m_ipv4 != 0);
492  // Check if input device supports IP
493  NS_ASSERT (m_ipv4->GetInterfaceForDevice (idev) >= 0);
494  uint32_t iif = m_ipv4->GetInterfaceForDevice (idev);
495 
496  // Multicast recognition; handle local delivery here
497  //
498  if (ipHeader.GetDestination ().IsMulticast ())
499  {
500  NS_LOG_LOGIC ("Multicast destination");
501  Ptr<Ipv4MulticastRoute> mrtentry = LookupStatic (ipHeader.GetSource (),
502  ipHeader.GetDestination (), m_ipv4->GetInterfaceForDevice (idev));
503 
504  if (mrtentry)
505  {
506  NS_LOG_LOGIC ("Multicast route found");
507  mcb (mrtentry, p, ipHeader); // multicast forwarding callback
508  return true;
509  }
510  else
511  {
512  NS_LOG_LOGIC ("Multicast route not found");
513  return false; // Let other routing protocols try to handle this
514  }
515  }
516  if (ipHeader.GetDestination ().IsBroadcast ())
517  {
518  NS_LOG_LOGIC ("For me (Ipv4Addr broadcast address)");
519  // TODO: Local Deliver for broadcast
520  // TODO: Forward broadcast
521  }
522 
523  NS_LOG_LOGIC ("Unicast destination");
524  // TODO: Configurable option to enable RFC 1222 Strong End System Model
525  // Right now, we will be permissive and allow a source to send us
526  // a packet to one of our other interface addresses; that is, the
527  // destination unicast address does not match one of the iif addresses,
528  // but we check our other interfaces. This could be an option
529  // (to remove the outer loop immediately below and just check iif).
530  for (uint32_t j = 0; j < m_ipv4->GetNInterfaces (); j++)
531  {
532  for (uint32_t i = 0; i < m_ipv4->GetNAddresses (j); i++)
533  {
534  Ipv4InterfaceAddress iaddr = m_ipv4->GetAddress (j, i);
535  Ipv4Address addr = iaddr.GetLocal ();
536  if (addr.IsEqual (ipHeader.GetDestination ()))
537  {
538  if (j == iif)
539  {
540  NS_LOG_LOGIC ("For me (destination " << addr << " match)");
541  }
542  else
543  {
544  NS_LOG_LOGIC ("For me (destination " << addr << " match) on another interface " << ipHeader.GetDestination ());
545  }
546  lcb (p, ipHeader, iif);
547  return true;
548  }
549  if (ipHeader.GetDestination ().IsEqual (iaddr.GetBroadcast ()))
550  {
551  NS_LOG_LOGIC ("For me (interface broadcast address)");
552  lcb (p, ipHeader, iif);
553  return true;
554  }
555  NS_LOG_LOGIC ("Address "<< addr << " not a match");
556  }
557  }
558  // Check if input device supports IP forwarding
559  if (m_ipv4->IsForwarding (iif) == false)
560  {
561  NS_LOG_LOGIC ("Forwarding disabled for this interface");
562  ecb (p, ipHeader, Socket::ERROR_NOROUTETOHOST);
563  return false;
564  }
565  // Next, try to find a route
566  Ptr<Ipv4Route> rtentry = LookupStatic (ipHeader.GetDestination ());
567  if (rtentry != 0)
568  {
569  NS_LOG_LOGIC ("Found unicast destination- calling unicast callback");
570  ucb (rtentry, p, ipHeader); // unicast forwarding callback
571  return true;
572  }
573  else
574  {
575  NS_LOG_LOGIC ("Did not find unicast destination- returning false");
576  return false; // Let other routing protocols try to handle this
577  }
578 }
579 
581 {
582 }
583 
584 void
586 {
587  for (NetworkRoutesI j = m_networkRoutes.begin ();
588  j != m_networkRoutes.end ();
589  j = m_networkRoutes.erase (j))
590  {
591  delete (j->first);
592  }
593  for (MulticastRoutesI i = m_multicastRoutes.begin ();
594  i != m_multicastRoutes.end ();
595  i = m_multicastRoutes.erase (i))
596  {
597  delete (*i);
598  }
599  m_ipv4 = 0;
601 }
602 
603 void
605 {
606  NS_LOG_FUNCTION (this << i);
607  // If interface address and network mask have been set, add a route
608  // to the network of the interface (like e.g. ifconfig does on a
609  // Linux box)
610  for (uint32_t j = 0; j < m_ipv4->GetNAddresses (i); j++)
611  {
612  if (m_ipv4->GetAddress (i,j).GetLocal () != Ipv4Address () &&
613  m_ipv4->GetAddress (i,j).GetMask () != Ipv4Mask () &&
614  m_ipv4->GetAddress (i,j).GetMask () != Ipv4Mask::GetOnes ())
615  {
617  m_ipv4->GetAddress (i,j).GetMask (), i);
618  }
619  }
620 }
621 
622 void
624 {
625  NS_LOG_FUNCTION (this << i);
626  // Remove all static routes that are going through this interface
627  uint32_t j = 0;
628  while (j < GetNRoutes ())
629  {
630  Ipv4RoutingTableEntry route = GetRoute (j);
631  if (route.GetInterface () == i)
632  {
633  RemoveRoute (j);
634  }
635  else
636  {
637  j++;
638  }
639  }
640 }
641 
642 void
644 {
645  NS_LOG_FUNCTION (this << interface << " " << address.GetLocal ());
646  if (!m_ipv4->IsUp (interface))
647  {
648  return;
649  }
650 
651  Ipv4Address networkAddress = address.GetLocal ().CombineMask (address.GetMask ());
652  Ipv4Mask networkMask = address.GetMask ();
653  if (address.GetLocal () != Ipv4Address () &&
654  address.GetMask () != Ipv4Mask ())
655  {
656  AddNetworkRouteTo (networkAddress,
657  networkMask, interface);
658  }
659 }
660 void
662 {
663  NS_LOG_FUNCTION (this << interface << " " << address.GetLocal ());
664  if (!m_ipv4->IsUp (interface))
665  {
666  return;
667  }
668  Ipv4Address networkAddress = address.GetLocal ().CombineMask (address.GetMask ());
669  Ipv4Mask networkMask = address.GetMask ();
670  // Remove all static routes that are going through this interface
671  // which reference this network
672  for (uint32_t j = 0; j < GetNRoutes (); j++)
673  {
674  Ipv4RoutingTableEntry route = GetRoute (j);
675  if (route.GetInterface () == interface &&
676  route.IsNetwork () &&
677  route.GetDestNetwork () == networkAddress &&
678  route.GetDestNetworkMask () == networkMask)
679  {
680  RemoveRoute (j);
681  }
682  }
683 }
684 
685 void
687 {
688  NS_LOG_FUNCTION (this << ipv4);
689  NS_ASSERT (m_ipv4 == 0 && ipv4 != 0);
690  m_ipv4 = ipv4;
691  for (uint32_t i = 0; i < m_ipv4->GetNInterfaces (); i++)
692  {
693  if (m_ipv4->IsUp (i))
694  {
695  NotifyInterfaceUp (i);
696  }
697  else
698  {
700  }
701  }
702 }
703 // Formatted like output of "route -n" command
704 void
706 {
707  std::ostream* os = stream->GetStream ();
708  if (GetNRoutes () > 0)
709  {
710  *os << "Destination Gateway Genmask Flags Metric Ref Use Iface" << std::endl;
711  for (uint32_t j = 0; j < GetNRoutes (); j++)
712  {
713  std::ostringstream dest, gw, mask, flags;
714  Ipv4RoutingTableEntry route = GetRoute (j);
715  dest << route.GetDest ();
716  *os << std::setiosflags (std::ios::left) << std::setw (16) << dest.str ();
717  gw << route.GetGateway ();
718  *os << std::setiosflags (std::ios::left) << std::setw (16) << gw.str ();
719  mask << route.GetDestNetworkMask ();
720  *os << std::setiosflags (std::ios::left) << std::setw (16) << mask.str ();
721  flags << "U";
722  if (route.IsHost ())
723  {
724  flags << "HS";
725  }
726  else if (route.IsGateway ())
727  {
728  flags << "GS";
729  }
730  *os << std::setiosflags (std::ios::left) << std::setw (6) << flags.str ();
731  *os << std::setiosflags (std::ios::left) << std::setw (7) << GetMetric (j);
732  // Ref ct not implemented
733  *os << "-" << " ";
734  // Use not implemented
735  *os << "-" << " ";
736  if (Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ())) != "")
737  {
738  *os << Names::FindName (m_ipv4->GetNetDevice (route.GetInterface ()));
739  }
740  else
741  {
742  *os << route.GetInterface ();
743  }
744  *os << std::endl;
745  }
746  }
747 }
750 {
751  NS_LOG_FUNCTION (this << interfaceIdx << " " << dest);
752  if (m_ipv4->GetNAddresses (interfaceIdx) == 1) // common case
753  {
754  return m_ipv4->GetAddress (interfaceIdx, 0).GetLocal ();
755  }
756  // no way to determine the scope of the destination, so adopt the
757  // following rule: pick the first available address (index 0) unless
758  // a subsequent address is on link (in which case, pick the primary
759  // address if there are multiple)
760  Ipv4Address candidate = m_ipv4->GetAddress (interfaceIdx, 0).GetLocal ();
761  for (uint32_t i = 0; i < m_ipv4->GetNAddresses (interfaceIdx); i++)
762  {
763  Ipv4InterfaceAddress test = m_ipv4->GetAddress (interfaceIdx, i);
764  if (test.GetLocal ().CombineMask (test.GetMask ()) == dest.CombineMask (test.GetMask ()))
765  {
766  if (test.IsSecondary () == false)
767  {
768  return test.GetLocal ();
769  }
770  }
771  }
772  return candidate;
773 }
774 
775 } // namespace ns3