1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014 Universita' di Firenze, Italy
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: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19  */
20 
21 #include <iomanip>
22 #include "ripng.h"
23 #include "ns3/log.h"
24 #include "ns3/abort.h"
25 #include "ns3/assert.h"
26 #include "ns3/unused.h"
27 #include "ns3/random-variable-stream.h"
28 #include "ns3/ipv6-route.h"
29 #include "ns3/node.h"
30 #include "ns3/names.h"
31 #include "ns3/ripng-header.h"
32 #include "ns3/udp-header.h"
33 #include "ns3/enum.h"
34 #include "ns3/uinteger.h"
35 #include "ns3/ipv6-packet-info-tag.h"
36 #include "ns3/simulator.h"
37 
38 #define RIPNG_ALL_NODE "ff02::9"
39 #define RIPNG_PORT 521
40 
41 namespace ns3 {
42 
43 NS_LOG_COMPONENT_DEFINE ("RipNg");
44 
45 NS_OBJECT_ENSURE_REGISTERED (RipNg);
46 
RipNg()47 RipNg::RipNg ()
48   : m_ipv6 (0), m_splitHorizonStrategy (RipNg::POISON_REVERSE), m_initialized (false)
49 {
50   m_rng = CreateObject<UniformRandomVariable> ();
51 }
52 
~RipNg()53 RipNg::~RipNg ()
54 {
55 }
56 
57 TypeId
GetTypeId(void)58 RipNg::GetTypeId (void)
59 {
60   static TypeId tid = TypeId ("ns3::RipNg")
61     .SetParent<Ipv6RoutingProtocol> ()
62     .SetGroupName ("Internet")
63     .AddConstructor<RipNg> ()
64     .AddAttribute ("UnsolicitedRoutingUpdate", "The time between two Unsolicited Routing Updates.",
65                    TimeValue (Seconds(30)),
66                    MakeTimeAccessor (&RipNg::m_unsolicitedUpdate),
67                    MakeTimeChecker ())
68     .AddAttribute ("StartupDelay", "Maximum random delay for protocol startup (send route requests).",
69                    TimeValue (Seconds(1)),
70                    MakeTimeAccessor (&RipNg::m_startupDelay),
71                    MakeTimeChecker ())
72     .AddAttribute ("TimeoutDelay", "The delay to invalidate a route.",
73                    TimeValue (Seconds(180)),
74                    MakeTimeAccessor (&RipNg::m_timeoutDelay),
75                    MakeTimeChecker ())
76     .AddAttribute ("GarbageCollectionDelay", "The delay to delete an expired route.",
77                    TimeValue (Seconds(120)),
78                    MakeTimeAccessor (&RipNg::m_garbageCollectionDelay),
79                    MakeTimeChecker ())
80     .AddAttribute ("MinTriggeredCooldown", "Min cooldown delay after a Triggered Update.",
81                    TimeValue (Seconds(1)),
82                    MakeTimeAccessor (&RipNg::m_minTriggeredUpdateDelay),
83                    MakeTimeChecker ())
84     .AddAttribute ("MaxTriggeredCooldown", "Max cooldown delay after a Triggered Update.",
85                    TimeValue (Seconds(5)),
86                    MakeTimeAccessor (&RipNg::m_maxTriggeredUpdateDelay),
87                    MakeTimeChecker ())
88     .AddAttribute ("SplitHorizon", "Split Horizon strategy.",
89                    EnumValue (RipNg::POISON_REVERSE),
90                    MakeEnumAccessor (&RipNg::m_splitHorizonStrategy),
91                    MakeEnumChecker (RipNg::NO_SPLIT_HORIZON, "NoSplitHorizon",
92                                     RipNg::SPLIT_HORIZON, "SplitHorizon",
93                                     RipNg::POISON_REVERSE, "PoisonReverse"))
94     .AddAttribute ("LinkDownValue", "Value for link down in count to infinity.",
95                    UintegerValue (16),
96                    MakeUintegerAccessor (&RipNg::m_linkDown),
97                    MakeUintegerChecker<uint8_t> ())
98     ;
99   return tid;
100 }
101 
AssignStreams(int64_t stream)102 int64_t RipNg::AssignStreams (int64_t stream)
103 {
104   NS_LOG_FUNCTION (this << stream);
105 
106   m_rng->SetStream (stream);
107   return 1;
108 }
109 
DoInitialize()110 void RipNg::DoInitialize ()
111 {
112   NS_LOG_FUNCTION (this);
113 
114   bool addedGlobal = false;
115 
116   m_initialized = true;
117 
118   Time delay = m_unsolicitedUpdate + Seconds (m_rng->GetValue (0, 0.5*m_unsolicitedUpdate.GetSeconds ()) );
119   m_nextUnsolicitedUpdate = Simulator::Schedule (delay, &RipNg::SendUnsolicitedRouteUpdate, this);
120 
121 
122   for (uint32_t i = 0 ; i < m_ipv6->GetNInterfaces (); i++)
123     {
124       bool activeInterface = false;
125       if (m_interfaceExclusions.find (i) == m_interfaceExclusions.end ())
126         {
127           activeInterface = true;
128           m_ipv6->SetForwarding (i, true);
129         }
130 
131       for (uint32_t j = 0; j < m_ipv6->GetNAddresses (i); j++)
132         {
133           Ipv6InterfaceAddress address = m_ipv6->GetAddress (i, j);
134           if (address.GetScope() == Ipv6InterfaceAddress::LINKLOCAL && activeInterface == true)
135             {
136               NS_LOG_LOGIC ("RIPng: adding socket to " << address.GetAddress ());
137               TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
138               Ptr<Node> theNode = GetObject<Node> ();
139               Ptr<Socket> socket = Socket::CreateSocket (theNode, tid);
140               Inet6SocketAddress local = Inet6SocketAddress (address.GetAddress (), RIPNG_PORT);
141               socket->BindToNetDevice (m_ipv6->GetNetDevice (i));
142               int ret = socket->Bind (local);
143               NS_ASSERT_MSG (ret == 0, "Bind unsuccessful");
144               socket->SetRecvCallback (MakeCallback (&RipNg::Receive, this));
145               socket->SetIpv6RecvHopLimit (true);
146               socket->SetRecvPktInfo (true);
147               m_unicastSocketList[socket] = i;
148             }
149           else if (m_ipv6->GetAddress (i, j).GetScope() == Ipv6InterfaceAddress::GLOBAL)
150             {
151               addedGlobal = true;
152             }
153         }
154     }
155 
156   if (!m_multicastRecvSocket)
157     {
158       NS_LOG_LOGIC ("RIPng: adding receiving socket");
159       TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
160       Ptr<Node> theNode = GetObject<Node> ();
161       m_multicastRecvSocket = Socket::CreateSocket (theNode, tid);
162       Inet6SocketAddress local = Inet6SocketAddress (RIPNG_ALL_NODE, RIPNG_PORT);
163       m_multicastRecvSocket->Bind (local);
164       m_multicastRecvSocket->SetRecvCallback (MakeCallback (&RipNg::Receive, this));
165       m_multicastRecvSocket->SetIpv6RecvHopLimit (true);
166       m_multicastRecvSocket->SetRecvPktInfo (true);
167     }
168 
169 
170   if (addedGlobal)
171     {
172       Time delay = Seconds (m_rng->GetValue (m_minTriggeredUpdateDelay.GetSeconds (), m_maxTriggeredUpdateDelay.GetSeconds ()));
173       m_nextTriggeredUpdate = Simulator::Schedule (delay, &RipNg::DoSendRouteUpdate, this, false);
174     }
175 
176   delay = Seconds (m_rng->GetValue (0.01, m_startupDelay.GetSeconds ()));
177   m_nextTriggeredUpdate = Simulator::Schedule (delay, &RipNg::SendRouteRequest, this);
178 
179   Ipv6RoutingProtocol::DoInitialize ();
180 }
181 
RouteOutput(Ptr<Packet> p,const Ipv6Header & header,Ptr<NetDevice> oif,Socket::SocketErrno & sockerr)182 Ptr<Ipv6Route> RipNg::RouteOutput (Ptr<Packet> p, const Ipv6Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr)
183 {
184   NS_LOG_FUNCTION (this << header << oif);
185 
186   Ipv6Address destination = header.GetDestination ();
187   Ptr<Ipv6Route> rtentry = 0;
188 
189   if (destination.IsMulticast ())
190     {
191       // Note:  Multicast routes for outbound packets are stored in the
192       // normal unicast table.  An implication of this is that it is not
193       // possible to source multicast datagrams on multiple interfaces.
194       // This is a well-known property of sockets implementation on
195       // many Unix variants.
196       // So, we just log it and fall through to LookupStatic ()
197       NS_LOG_LOGIC ("RouteOutput (): Multicast destination");
198     }
199 
200   rtentry = Lookup (destination, oif);
201   if (rtentry)
202     {
203       sockerr = Socket::ERROR_NOTERROR;
204     }
205   else
206     {
207       sockerr = Socket::ERROR_NOROUTETOHOST;
208     }
209   return rtentry;
210 }
211 
RouteInput(Ptr<const Packet> p,const Ipv6Header & header,Ptr<const NetDevice> idev,UnicastForwardCallback ucb,MulticastForwardCallback mcb,LocalDeliverCallback lcb,ErrorCallback ecb)212 bool RipNg::RouteInput (Ptr<const Packet> p, const Ipv6Header &header, Ptr<const NetDevice> idev,
213                         UnicastForwardCallback ucb, MulticastForwardCallback mcb,
214                         LocalDeliverCallback lcb, ErrorCallback ecb)
215 {
216   NS_LOG_FUNCTION (this << p << header << header.GetSource () << header.GetDestination () << idev);
217 
218   NS_ASSERT (m_ipv6 != 0);
219   // Check if input device supports IP
220   NS_ASSERT (m_ipv6->GetInterfaceForDevice (idev) >= 0);
221   uint32_t iif = m_ipv6->GetInterfaceForDevice (idev);
222   Ipv6Address dst = header.GetDestination ();
223 
224   if (dst.IsMulticast ())
225     {
226       NS_LOG_LOGIC ("Multicast route not supported by RIPng");
227       return false; // Let other routing protocols try to handle this
228     }
229 
230   if (header.GetDestination ().IsLinkLocal () ||
231       header.GetSource ().IsLinkLocal ())
232     {
233       NS_LOG_LOGIC ("Dropping packet not for me and with src or dst LinkLocal");
234       if (!ecb.IsNull ())
235         {
236           ecb (p, header, Socket::ERROR_NOROUTETOHOST);
237         }
238       return false;
239     }
240 
241   // Check if input device supports IP forwarding
242   if (m_ipv6->IsForwarding (iif) == false)
243     {
244       NS_LOG_LOGIC ("Forwarding disabled for this interface");
245       if (!ecb.IsNull ())
246         {
247           ecb (p, header, Socket::ERROR_NOROUTETOHOST);
248         }
249       return true;
250     }
251   // Next, try to find a route
252   NS_LOG_LOGIC ("Unicast destination");
253   Ptr<Ipv6Route> rtentry = Lookup (header.GetDestination ());
254 
255   if (rtentry != 0)
256     {
257       NS_LOG_LOGIC ("Found unicast destination - calling unicast callback");
258       ucb (idev, rtentry, p, header);  // unicast forwarding callback
259       return true;
260     }
261   else
262     {
263       NS_LOG_LOGIC ("Did not find unicast destination - returning false");
264       return false; // Let other routing protocols try to handle this
265     }
266 }
267 
NotifyInterfaceUp(uint32_t i)268 void RipNg::NotifyInterfaceUp (uint32_t i)
269 {
270   NS_LOG_FUNCTION (this << i);
271 
272   for (uint32_t j = 0; j < m_ipv6->GetNAddresses (i); j++)
273     {
274       Ipv6InterfaceAddress address = m_ipv6->GetAddress (i, j);
275       Ipv6Prefix networkMask = address.GetPrefix ();
276       Ipv6Address networkAddress = address.GetAddress ().CombinePrefix (networkMask);
277 
278       if (address.GetScope () == Ipv6InterfaceAddress::GLOBAL)
279         {
280           AddNetworkRouteTo (networkAddress, networkMask, i);
281         }
282     }
283 
284   if (!m_initialized)
285     {
286       return;
287     }
288 
289 
290   bool sendSocketFound = false;
291   for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
292     {
293       if (iter->second == i)
294         {
295           sendSocketFound = true;
296           break;
297         }
298     }
299 
300   bool activeInterface = false;
301   if (m_interfaceExclusions.find (i) == m_interfaceExclusions.end ())
302     {
303       activeInterface = true;
304       m_ipv6->SetForwarding (i, true);
305     }
306 
307   for (uint32_t j = 0; j < m_ipv6->GetNAddresses (i); j++)
308     {
309       Ipv6InterfaceAddress address = m_ipv6->GetAddress (i, j);
310 
311       if (address.GetScope() == Ipv6InterfaceAddress::LINKLOCAL && sendSocketFound == false && activeInterface == true)
312         {
313           NS_LOG_LOGIC ("RIPng: adding sending socket to " << address.GetAddress ());
314           TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
315           Ptr<Node> theNode = GetObject<Node> ();
316           Ptr<Socket> socket = Socket::CreateSocket (theNode, tid);
317           Inet6SocketAddress local = Inet6SocketAddress (address.GetAddress (), RIPNG_PORT);
318           socket->BindToNetDevice (m_ipv6->GetNetDevice (i));
319           socket->Bind (local);
320           socket->SetRecvCallback (MakeCallback (&RipNg::Receive, this));
321           socket->SetIpv6RecvHopLimit (true);
322           socket->SetRecvPktInfo (true);
323           m_unicastSocketList[socket] = i;
324         }
325       else if (address.GetScope() == Ipv6InterfaceAddress::GLOBAL)
326         {
327           SendTriggeredRouteUpdate ();
328         }
329     }
330 
331   if (!m_multicastRecvSocket)
332     {
333       NS_LOG_LOGIC ("RIPng: adding receiving socket");
334       TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
335       Ptr<Node> theNode = GetObject<Node> ();
336       m_multicastRecvSocket = Socket::CreateSocket (theNode, tid);
337       Inet6SocketAddress local = Inet6SocketAddress (RIPNG_ALL_NODE, RIPNG_PORT);
338       m_multicastRecvSocket->Bind (local);
339       m_multicastRecvSocket->SetRecvCallback (MakeCallback (&RipNg::Receive, this));
340       m_multicastRecvSocket->SetIpv6RecvHopLimit (true);
341       m_multicastRecvSocket->SetRecvPktInfo (true);
342     }
343 }
344 
NotifyInterfaceDown(uint32_t interface)345 void RipNg::NotifyInterfaceDown (uint32_t interface)
346 {
347   NS_LOG_FUNCTION (this << interface);
348 
349   /* remove all routes that are going through this interface */
350   for (RoutesI it = m_routes.begin (); it != m_routes.end (); it++)
351     {
352       if (it->first->GetInterface () == interface)
353         {
354           InvalidateRoute (it->first);
355         }
356     }
357 
358   for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
359     {
360       NS_LOG_INFO ("Checking socket for interface " << interface);
361       if (iter->second == interface)
362         {
363           NS_LOG_INFO ("Removed socket for interface " << interface);
364           iter->first->Close ();
365           m_unicastSocketList.erase (iter);
366           break;
367         }
368     }
369 
370   if (m_interfaceExclusions.find (interface) == m_interfaceExclusions.end ())
371     {
372       SendTriggeredRouteUpdate ();
373     }
374 }
375 
NotifyAddAddress(uint32_t interface,Ipv6InterfaceAddress address)376 void RipNg::NotifyAddAddress (uint32_t interface, Ipv6InterfaceAddress address)
377 {
378   NS_LOG_FUNCTION (this << interface << address);
379 
380   if (!m_ipv6->IsUp (interface))
381     {
382       return;
383     }
384 
385   if (m_interfaceExclusions.find (interface) != m_interfaceExclusions.end ())
386     {
387       return;
388     }
389 
390   Ipv6Address networkAddress = address.GetAddress ().CombinePrefix (address.GetPrefix ());
391   Ipv6Prefix networkMask = address.GetPrefix ();
392 
393   if (address.GetScope () == Ipv6InterfaceAddress::GLOBAL)
394     {
395       AddNetworkRouteTo (networkAddress, networkMask, interface);
396     }
397 
398   SendTriggeredRouteUpdate ();
399 }
400 
NotifyRemoveAddress(uint32_t interface,Ipv6InterfaceAddress address)401 void RipNg::NotifyRemoveAddress (uint32_t interface, Ipv6InterfaceAddress address)
402 {
403   NS_LOG_FUNCTION (this << interface << address);
404 
405   if (!m_ipv6->IsUp (interface))
406     {
407       return;
408     }
409 
410   if (address.GetScope() != Ipv6InterfaceAddress::GLOBAL)
411     {
412       return;
413     }
414 
415   Ipv6Address networkAddress = address.GetAddress ().CombinePrefix (address.GetPrefix ());
416   Ipv6Prefix networkMask = address.GetPrefix ();
417 
418   // Remove all routes that are going through this interface
419   // which reference this network
420   for (RoutesI it = m_routes.begin (); it != m_routes.end (); it++)
421     {
422       if (it->first->GetInterface () == interface
423           && it->first->IsNetwork ()
424           && it->first->GetDestNetwork () == networkAddress
425           && it->first->GetDestNetworkPrefix () == networkMask)
426         {
427           InvalidateRoute (it->first);
428         }
429     }
430 
431   if (m_interfaceExclusions.find (interface) == m_interfaceExclusions.end ())
432     {
433       SendTriggeredRouteUpdate ();
434     }
435 
436 }
437 
NotifyAddRoute(Ipv6Address dst,Ipv6Prefix mask,Ipv6Address nextHop,uint32_t interface,Ipv6Address prefixToUse)438 void RipNg::NotifyAddRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
439 {
440   NS_LOG_INFO (this << dst << mask << nextHop << interface << prefixToUse);
441   // \todo this can be used to add delegate routes
442 }
443 
NotifyRemoveRoute(Ipv6Address dst,Ipv6Prefix mask,Ipv6Address nextHop,uint32_t interface,Ipv6Address prefixToUse)444 void RipNg::NotifyRemoveRoute (Ipv6Address dst, Ipv6Prefix mask, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
445 {
446   NS_LOG_FUNCTION (this << dst << mask << nextHop << interface);
447   // \todo this can be used to delete delegate routes
448 }
449 
SetIpv6(Ptr<Ipv6> ipv6)450 void RipNg::SetIpv6 (Ptr<Ipv6> ipv6)
451 {
452   NS_LOG_FUNCTION (this << ipv6);
453 
454   NS_ASSERT (m_ipv6 == 0 && ipv6 != 0);
455   uint32_t i = 0;
456   m_ipv6 = ipv6;
457 
458   for (i = 0; i < m_ipv6->GetNInterfaces (); i++)
459     {
460       if (m_ipv6->IsUp (i))
461         {
462           NotifyInterfaceUp (i);
463         }
464       else
465         {
466           NotifyInterfaceDown (i);
467         }
468     }
469 }
470 
PrintRoutingTable(Ptr<OutputStreamWrapper> stream,Time::Unit unit) const471 void RipNg::PrintRoutingTable (Ptr<OutputStreamWrapper> stream, Time::Unit unit) const
472 {
473   NS_LOG_FUNCTION (this << stream);
474 
475   std::ostream* os = stream->GetStream ();
476   *os << std::resetiosflags (std::ios::adjustfield) << std::setiosflags (std::ios::left);
477 
478   *os << "Node: " << m_ipv6->GetObject<Node> ()->GetId ()
479       << ", Time: " << Now().As (unit)
480       << ", Local time: " << m_ipv6->GetObject<Node> ()->GetLocalTime ().As (unit)
481       << ", IPv6 RIPng table" << std::endl;
482 
483   if (!m_routes.empty ())
484     {
485       *os << "Destination                    Next Hop                   Flag Met Ref Use If" << std::endl;
486       for (RoutesCI it = m_routes.begin (); it != m_routes.end (); it++)
487         {
488           RipNgRoutingTableEntry* route = it->first;
489           RipNgRoutingTableEntry::Status_e status = route->GetRouteStatus();
490 
491           if (status == RipNgRoutingTableEntry::RIPNG_VALID)
492             {
493               std::ostringstream dest, gw, mask, flags;
494 
495               dest << route->GetDest () << "/" << int(route->GetDestNetworkPrefix ().GetPrefixLength ());
496               *os << std::setw (31) << dest.str ();
497               gw << route->GetGateway ();
498               *os << std::setw (27) << gw.str ();
499               flags << "U";
500               if (route->IsHost ())
501                 {
502                   flags << "H";
503                 }
504               else if (route->IsGateway ())
505                 {
506                   flags << "G";
507                 }
508               *os << std::setw (5) << flags.str ();
509               *os << std::setw (4) << int(route->GetRouteMetric ());
510               // Ref ct not implemented
511               *os << "-" << "   ";
512               // Use not implemented
513               *os << "-" << "   ";
514               if (Names::FindName (m_ipv6->GetNetDevice (route->GetInterface ())) != "")
515                 {
516                   *os << Names::FindName (m_ipv6->GetNetDevice (route->GetInterface ()));
517                 }
518               else
519                 {
520                   *os << route->GetInterface ();
521                 }
522               *os << std::endl;
523             }
524         }
525     }
526   *os << std::endl;
527 }
528 
DoDispose()529 void RipNg::DoDispose ()
530 {
531   NS_LOG_FUNCTION (this);
532 
533   for (RoutesI j = m_routes.begin ();  j != m_routes.end (); j = m_routes.erase (j))
534     {
535       delete j->first;
536     }
537   m_routes.clear ();
538 
539   m_nextTriggeredUpdate.Cancel ();
540   m_nextUnsolicitedUpdate.Cancel ();
541   m_nextTriggeredUpdate = EventId ();
542   m_nextUnsolicitedUpdate = EventId ();
543 
544   for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
545     {
546       iter->first->Close ();
547     }
548   m_unicastSocketList.clear ();
549 
550   m_multicastRecvSocket->Close ();
551   m_multicastRecvSocket = 0;
552 
553   m_ipv6 = 0;
554 
555   Ipv6RoutingProtocol::DoDispose ();
556 }
557 
558 
Lookup(Ipv6Address dst,Ptr<NetDevice> interface)559 Ptr<Ipv6Route> RipNg::Lookup (Ipv6Address dst, Ptr<NetDevice> interface)
560 {
561   NS_LOG_FUNCTION (this << dst << interface);
562 
563   Ptr<Ipv6Route> rtentry = 0;
564   uint16_t longestMask = 0;
565 
566   /* when sending on link-local multicast, there have to be interface specified */
567   if (dst.IsLinkLocalMulticast ())
568     {
569       NS_ASSERT_MSG (interface, "Try to send on link-local multicast address, and no interface index is given!");
570       rtentry = Create<Ipv6Route> ();
571       rtentry->SetSource (m_ipv6->SourceAddressSelection (m_ipv6->GetInterfaceForDevice (interface), dst));
572       rtentry->SetDestination (dst);
573       rtentry->SetGateway (Ipv6Address::GetZero ());
574       rtentry->SetOutputDevice (interface);
575       return rtentry;
576     }
577 
578   for (RoutesI it = m_routes.begin (); it != m_routes.end (); it++)
579     {
580       RipNgRoutingTableEntry* j = it->first;
581 
582       if (j->GetRouteStatus () == RipNgRoutingTableEntry::RIPNG_VALID)
583         {
584           Ipv6Prefix mask = j->GetDestNetworkPrefix ();
585           uint16_t maskLen = mask.GetPrefixLength ();
586           Ipv6Address entry = j->GetDestNetwork ();
587 
588           NS_LOG_LOGIC ("Searching for route to " << dst << ", mask length " << maskLen);
589 
590           if (mask.IsMatch (dst, entry))
591             {
592               NS_LOG_LOGIC ("Found global network route " << j << ", mask length " << maskLen);
593 
594               /* if interface is given, check the route will output on this interface */
595               if (!interface || interface == m_ipv6->GetNetDevice (j->GetInterface ()))
596                 {
597                   if (maskLen < longestMask)
598                     {
599                       NS_LOG_LOGIC ("Previous match longer, skipping");
600                       continue;
601                     }
602 
603                   longestMask = maskLen;
604 
605                   Ipv6RoutingTableEntry* route = j;
606                   uint32_t interfaceIdx = route->GetInterface ();
607                   rtentry = Create<Ipv6Route> ();
608 
609                   if (route->GetGateway ().IsAny ())
610                     {
611                       rtentry->SetSource (m_ipv6->SourceAddressSelection (interfaceIdx, route->GetDest ()));
612                     }
613                   else if (route->GetDest ().IsAny ()) /* default route */
614                     {
615                       rtentry->SetSource (m_ipv6->SourceAddressSelection (interfaceIdx, route->GetPrefixToUse ().IsAny () ? dst : route->GetPrefixToUse ()));
616                     }
617                   else
618                     {
619                       rtentry->SetSource (m_ipv6->SourceAddressSelection (interfaceIdx, route->GetDest ()));
620                     }
621 
622                   rtentry->SetDestination (route->GetDest ());
623                   rtentry->SetGateway (route->GetGateway ());
624                   rtentry->SetOutputDevice (m_ipv6->GetNetDevice (interfaceIdx));
625                 }
626             }
627         }
628     }
629 
630   if (rtentry)
631     {
632       NS_LOG_LOGIC ("Matching route via " << rtentry->GetDestination () << " (through " << rtentry->GetGateway () << ") at the end");
633     }
634   return rtentry;
635 }
636 
AddNetworkRouteTo(Ipv6Address network,Ipv6Prefix networkPrefix,Ipv6Address nextHop,uint32_t interface,Ipv6Address prefixToUse)637 void RipNg::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
638 {
639   NS_LOG_FUNCTION (this << network << networkPrefix << nextHop << interface << prefixToUse);
640 
641   if (nextHop.IsLinkLocal())
642     {
643       NS_LOG_WARN ("Ripng::AddNetworkRouteTo - Next hop should be link-local");
644     }
645 
646   RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (network, networkPrefix, nextHop, interface, prefixToUse);
647   route->SetRouteMetric (1);
648   route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
649   route->SetRouteChanged (true);
650 
651   m_routes.push_back (std::make_pair (route, EventId ()));
652 }
653 
AddNetworkRouteTo(Ipv6Address network,Ipv6Prefix networkPrefix,uint32_t interface)654 void RipNg::AddNetworkRouteTo (Ipv6Address network, Ipv6Prefix networkPrefix, uint32_t interface)
655 {
656   NS_LOG_FUNCTION (this << network << networkPrefix << interface);
657 
658   RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (network, networkPrefix, interface);
659   route->SetRouteMetric (1);
660   route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
661   route->SetRouteChanged (true);
662 
663   m_routes.push_back (std::make_pair (route, EventId ()));
664 }
665 
InvalidateRoute(RipNgRoutingTableEntry * route)666 void RipNg::InvalidateRoute (RipNgRoutingTableEntry *route)
667 {
668   NS_LOG_FUNCTION (this << *route);
669 
670   for (RoutesI it = m_routes.begin (); it != m_routes.end (); it++)
671     {
672       if (it->first == route)
673         {
674           route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_INVALID);
675           route->SetRouteMetric (m_linkDown);
676           route->SetRouteChanged (true);
677           if (it->second.IsRunning ())
678             {
679               it->second.Cancel ();
680             }
681           it->second = Simulator::Schedule (m_garbageCollectionDelay, &RipNg::DeleteRoute, this, route);
682           return;
683         }
684     }
685   NS_ABORT_MSG ("Ripng::InvalidateRoute - cannot find the route to update");
686 }
687 
DeleteRoute(RipNgRoutingTableEntry * route)688 void RipNg::DeleteRoute (RipNgRoutingTableEntry *route)
689 {
690   NS_LOG_FUNCTION (this << *route);
691 
692   for (RoutesI it = m_routes.begin (); it != m_routes.end (); it++)
693     {
694       if (it->first == route)
695         {
696           delete route;
697           m_routes.erase (it);
698           return;
699         }
700     }
701   NS_ABORT_MSG ("Ripng::DeleteRoute - cannot find the route to delete");
702 }
703 
704 
Receive(Ptr<Socket> socket)705 void RipNg::Receive (Ptr<Socket> socket)
706 {
707   NS_LOG_FUNCTION (this << socket);
708 
709   Address sender;
710   Ptr<Packet> packet = socket->RecvFrom (sender);
711   Inet6SocketAddress senderAddr = Inet6SocketAddress::ConvertFrom (sender);
712   NS_LOG_INFO ("Received " << *packet << " from " << senderAddr);
713 
714   Ipv6Address senderAddress = senderAddr.GetIpv6 ();
715   uint16_t senderPort = senderAddr.GetPort ();
716 
717   Ipv6PacketInfoTag interfaceInfo;
718   if (!packet->RemovePacketTag (interfaceInfo))
719     {
720       NS_ABORT_MSG ("No incoming interface on RIPng message, aborting.");
721     }
722   uint32_t incomingIf = interfaceInfo.GetRecvIf ();
723   Ptr<Node> node = this->GetObject<Node> ();
724   Ptr<NetDevice> dev = node->GetDevice (incomingIf);
725   uint32_t ipInterfaceIndex = m_ipv6->GetInterfaceForDevice (dev);
726 
727   SocketIpv6HopLimitTag hoplimitTag;
728   if (!packet->RemovePacketTag (hoplimitTag))
729     {
730       NS_ABORT_MSG ("No incoming Hop Count on RIPng message, aborting.");
731     }
732   uint8_t hopLimit = hoplimitTag.GetHopLimit ();
733 
734   int32_t interfaceForAddress = m_ipv6->GetInterfaceForAddress (senderAddress);
735   if (interfaceForAddress != -1)
736     {
737       NS_LOG_LOGIC ("Ignoring a packet sent by myself.");
738       return;
739     }
740 
741   RipNgHeader hdr;
742   packet->RemoveHeader (hdr);
743 
744   if (hdr.GetCommand () == RipNgHeader::RESPONSE)
745     {
746       HandleResponses (hdr, senderAddress, ipInterfaceIndex, hopLimit);
747     }
748   else if (hdr.GetCommand () == RipNgHeader::REQUEST)
749     {
750       HandleRequests (hdr, senderAddress, senderPort, ipInterfaceIndex, hopLimit);
751     }
752   else
753     {
754       NS_LOG_LOGIC ("Ignoring message with unknown command: " << int (hdr.GetCommand ()));
755     }
756   return;
757 }
758 
HandleRequests(RipNgHeader requestHdr,Ipv6Address senderAddress,uint16_t senderPort,uint32_t incomingInterface,uint8_t hopLimit)759 void RipNg::HandleRequests (RipNgHeader requestHdr, Ipv6Address senderAddress, uint16_t senderPort, uint32_t incomingInterface, uint8_t hopLimit)
760 {
761   NS_LOG_FUNCTION (this << senderAddress << int (senderPort) << incomingInterface << int (hopLimit) << requestHdr);
762 
763   std::list<RipNgRte> rtes = requestHdr.GetRteList ();
764 
765   if (rtes.empty ())
766     {
767       return;
768     }
769 
770   // check if it's a request for the full table from a neighbor
771   if (rtes.size () == 1 && senderAddress.IsLinkLocal ())
772     {
773       if (rtes.begin ()->GetPrefix () == Ipv6Address::GetAny () &&
774           rtes.begin ()->GetPrefixLen () == 0 &&
775           rtes.begin ()->GetRouteMetric () == m_linkDown)
776         {
777           // Output whole thing. Use Split Horizon
778           if (m_interfaceExclusions.find (incomingInterface) == m_interfaceExclusions.end ())
779             {
780               // we use one of the sending sockets, as they're bound to the right interface
781               // and the local address might be used on different interfaces.
782               Ptr<Socket> sendingSocket;
783               for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
784                 {
785                   if (iter->second == incomingInterface)
786                     {
787                       sendingSocket = iter->first;
788                     }
789                 }
790               NS_ASSERT_MSG (sendingSocket, "HandleRequest - Impossible to find a socket to send the reply");
791 
792               uint16_t mtu = m_ipv6->GetMtu (incomingInterface);
793               uint16_t maxRte = (mtu - Ipv6Header ().GetSerializedSize () - UdpHeader ().GetSerializedSize () - RipNgHeader ().GetSerializedSize ()) / RipNgRte ().GetSerializedSize ();
794 
795               Ptr<Packet> p = Create<Packet> ();
796               SocketIpv6HopLimitTag tag;
797               p->RemovePacketTag (tag);
798               tag.SetHopLimit (255);
799               p->AddPacketTag (tag);
800 
801               RipNgHeader hdr;
802               hdr.SetCommand (RipNgHeader::RESPONSE);
803 
804               for (RoutesI rtIter = m_routes.begin (); rtIter != m_routes.end (); rtIter++)
805                 {
806                   bool splitHorizoning = (rtIter->first->GetInterface () == incomingInterface);
807 
808                   Ipv6InterfaceAddress rtDestAddr = Ipv6InterfaceAddress (rtIter->first->GetDestNetwork (), rtIter->first->GetDestNetworkPrefix ());
809 
810                   bool isGlobal = (rtDestAddr.GetScope () == Ipv6InterfaceAddress::GLOBAL);
811                   bool isDefaultRoute = ((rtIter->first->GetDestNetwork () == Ipv6Address::GetAny ()) &&
812                       (rtIter->first->GetDestNetworkPrefix () == Ipv6Prefix::GetZero ()) &&
813                       (rtIter->first->GetInterface () != incomingInterface));
814 
815                   if ((isGlobal || isDefaultRoute) &&
816                       (rtIter->first->GetRouteStatus () == RipNgRoutingTableEntry::RIPNG_VALID) )
817                     {
818                       RipNgRte rte;
819                       rte.SetPrefix (rtIter->first->GetDestNetwork ());
820                       rte.SetPrefixLen (rtIter->first->GetDestNetworkPrefix ().GetPrefixLength ());
821                       if (m_splitHorizonStrategy == POISON_REVERSE && splitHorizoning)
822                         {
823                           rte.SetRouteMetric (m_linkDown);
824                         }
825                       else
826                         {
827                           rte.SetRouteMetric (rtIter->first->GetRouteMetric ());
828                         }
829                       rte.SetRouteTag (rtIter->first->GetRouteTag ());
830                       if ((m_splitHorizonStrategy != SPLIT_HORIZON) ||
831                           (m_splitHorizonStrategy == SPLIT_HORIZON && !splitHorizoning))
832                         {
833                           hdr.AddRte (rte);
834                         }
835                     }
836                   if (hdr.GetRteNumber () == maxRte)
837                     {
838                       p->AddHeader (hdr);
839                       NS_LOG_DEBUG ("SendTo: " << *p);
840                       sendingSocket->SendTo (p, 0, Inet6SocketAddress (senderAddress, RIPNG_PORT));
841                       p->RemoveHeader (hdr);
842                       hdr.ClearRtes ();
843                     }
844                 }
845               if (hdr.GetRteNumber () > 0)
846                 {
847                   p->AddHeader (hdr);
848                   NS_LOG_DEBUG ("SendTo: " << *p);
849                   sendingSocket->SendTo (p, 0, Inet6SocketAddress (senderAddress, RIPNG_PORT));
850                 }
851             }
852         }
853     }
854   else
855     {
856       // note: we got the request as a single packet, so no check is necessary for MTU limit
857 
858       // we use one of the sending sockets, as they're bound to the right interface
859       // and the local address might be used on different interfaces.
860       Ptr<Socket> sendingSocket;
861       if (senderAddress.IsLinkLocal ())
862         {
863           for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
864             {
865               if (iter->second == incomingInterface)
866                 {
867                   sendingSocket = iter->first;
868                 }
869             }
870         }
871       else
872         {
873           sendingSocket = m_multicastRecvSocket;
874         }
875 
876       Ptr<Packet> p = Create<Packet> ();
877       SocketIpv6HopLimitTag tag;
878       p->RemovePacketTag (tag);
879       tag.SetHopLimit (255);
880       p->AddPacketTag (tag);
881 
882       RipNgHeader hdr;
883       hdr.SetCommand (RipNgHeader::RESPONSE);
884 
885       for (std::list<RipNgRte>::iterator iter = rtes.begin ();
886           iter != rtes.end (); iter++)
887         {
888           bool found = false;
889           for (RoutesI rtIter = m_routes.begin (); rtIter != m_routes.end (); rtIter++)
890             {
891               Ipv6InterfaceAddress rtDestAddr = Ipv6InterfaceAddress(rtIter->first->GetDestNetwork (), rtIter->first->GetDestNetworkPrefix ());
892               if ((rtDestAddr.GetScope () == Ipv6InterfaceAddress::GLOBAL) &&
893                   (rtIter->first->GetRouteStatus () == RipNgRoutingTableEntry::RIPNG_VALID))
894                 {
895                   Ipv6Address requestedAddress = iter->GetPrefix ();
896                   requestedAddress.CombinePrefix (Ipv6Prefix (iter->GetPrefixLen ()));
897                   Ipv6Address rtAddress = rtIter->first->GetDestNetwork ();
898                   rtAddress.CombinePrefix (rtIter->first->GetDestNetworkPrefix ());
899 
900                   if (requestedAddress == rtAddress)
901                     {
902                       iter->SetRouteMetric (rtIter->first->GetRouteMetric ());
903                       iter->SetRouteTag (rtIter->first->GetRouteTag ());
904                       hdr.AddRte (*iter);
905                       found = true;
906                       break;
907                     }
908                 }
909             }
910           if (!found)
911             {
912               iter->SetRouteMetric (m_linkDown);
913               iter->SetRouteTag (0);
914               hdr.AddRte (*iter);
915             }
916         }
917       p->AddHeader (hdr);
918       NS_LOG_DEBUG ("SendTo: " << *p);
919       sendingSocket->SendTo (p, 0, Inet6SocketAddress (senderAddress, senderPort));
920     }
921 
922 }
923 
HandleResponses(RipNgHeader hdr,Ipv6Address senderAddress,uint32_t incomingInterface,uint8_t hopLimit)924 void RipNg::HandleResponses (RipNgHeader hdr, Ipv6Address senderAddress, uint32_t incomingInterface, uint8_t hopLimit)
925 {
926   NS_LOG_FUNCTION (this << senderAddress << incomingInterface << int (hopLimit) << hdr);
927 
928   if (m_interfaceExclusions.find (incomingInterface) != m_interfaceExclusions.end ())
929     {
930       NS_LOG_LOGIC ("Ignoring an update message from an excluded interface: " << incomingInterface);
931       return;
932     }
933 
934   if (!senderAddress.IsLinkLocal ())
935     {
936       NS_LOG_LOGIC ("Ignoring an update message from a non-link-local source: " << senderAddress);
937       return;
938     }
939 
940   if (hopLimit != 255)
941     {
942       NS_LOG_LOGIC ("Ignoring an update message with suspicious hop count: " << int (hopLimit));
943       return;
944     }
945 
946   std::list<RipNgRte> rtes = hdr.GetRteList ();
947 
948   // validate the RTEs before processing
949   for (std::list<RipNgRte>::iterator iter = rtes.begin ();
950       iter != rtes.end (); iter++)
951     {
952       if (iter->GetRouteMetric () == 0 || iter->GetRouteMetric () > m_linkDown)
953         {
954           NS_LOG_LOGIC ("Ignoring an update message with malformed metric: " << int (iter->GetRouteMetric ()));
955           return;
956         }
957       if (iter->GetPrefixLen () > 128)
958         {
959           NS_LOG_LOGIC ("Ignoring an update message with malformed prefix length: " << int (iter->GetPrefixLen ()));
960           return;
961         }
962       if (iter->GetPrefix ().IsLocalhost () ||
963           iter->GetPrefix ().IsLinkLocal () ||
964           iter->GetPrefix ().IsMulticast ())
965         {
966           NS_LOG_LOGIC ("Ignoring an update message with wrong prefixes: " << iter->GetPrefix ());
967           return;
968         }
969     }
970 
971   bool changed = false;
972 
973   for (std::list<RipNgRte>::iterator iter = rtes.begin ();
974       iter != rtes.end (); iter++)
975     {
976       Ipv6Prefix rtePrefix = Ipv6Prefix (iter->GetPrefixLen ());
977       Ipv6Address rteAddr = iter->GetPrefix ().CombinePrefix (rtePrefix);
978 
979       NS_LOG_LOGIC ("Processing RTE " << *iter);
980 
981       uint8_t interfaceMetric = 1;
982       if (m_interfaceMetrics.find (incomingInterface) != m_interfaceMetrics.end ())
983         {
984           interfaceMetric = m_interfaceMetrics[incomingInterface];
985         }
986       uint16_t rteMetric = iter->GetRouteMetric () + interfaceMetric;
987       if (rteMetric > m_linkDown)
988         {
989           rteMetric = m_linkDown;
990         }
991       RoutesI it;
992       bool found = false;
993       for (it = m_routes.begin (); it != m_routes.end (); it++)
994         {
995           if (it->first->GetDestNetwork () == rteAddr &&
996               it->first->GetDestNetworkPrefix () == rtePrefix)
997             {
998               found = true;
999               if (rteMetric < it->first->GetRouteMetric ())
1000                 {
1001                   if (senderAddress != it->first->GetGateway ())
1002                     {
1003                       RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (rteAddr, rtePrefix, senderAddress, incomingInterface, Ipv6Address::GetAny ());
1004                       delete it->first;
1005                       it->first = route;
1006                     }
1007                   it->first->SetRouteMetric (rteMetric);
1008                   it->first->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
1009                   it->first->SetRouteTag (iter->GetRouteTag ());
1010                   it->first->SetRouteChanged (true);
1011                   it->second.Cancel ();
1012                   it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, it->first);
1013                   changed = true;
1014                 }
1015               else if (rteMetric == it->first->GetRouteMetric ())
1016                 {
1017                   if (senderAddress == it->first->GetGateway ())
1018                     {
1019                       it->second.Cancel ();
1020                       it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, it->first);
1021                     }
1022                   else
1023                     {
1024                       if (Simulator::GetDelayLeft (it->second) < m_timeoutDelay/2)
1025                         {
1026                           RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (rteAddr, rtePrefix, senderAddress, incomingInterface, Ipv6Address::GetAny ());
1027                           route->SetRouteMetric (rteMetric);
1028                           route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
1029                           route->SetRouteTag (iter->GetRouteTag ());
1030                           route->SetRouteChanged (true);
1031                           delete it->first;
1032                           it->first = route;
1033                           it->second.Cancel ();
1034                           it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, route);
1035                           changed = true;
1036                         }
1037                     }
1038                 }
1039               else if (rteMetric > it->first->GetRouteMetric () && senderAddress == it->first->GetGateway ())
1040                 {
1041                   it->second.Cancel ();
1042                   if (rteMetric < m_linkDown)
1043                     {
1044                       it->first->SetRouteMetric (rteMetric);
1045                       it->first->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
1046                       it->first->SetRouteTag (iter->GetRouteTag ());
1047                       it->first->SetRouteChanged (true);
1048                       it->second.Cancel ();
1049                       it->second = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, it->first);
1050                     }
1051                   else
1052                     {
1053                       InvalidateRoute (it->first);
1054                     }
1055                   changed = true;
1056                 }
1057             }
1058         }
1059       if (!found && rteMetric != m_linkDown)
1060         {
1061           NS_LOG_LOGIC ("Received a RTE with new route, adding.");
1062 
1063           RipNgRoutingTableEntry* route = new RipNgRoutingTableEntry (rteAddr, rtePrefix, senderAddress, incomingInterface, Ipv6Address::GetAny ());
1064           route->SetRouteMetric (rteMetric);
1065           route->SetRouteStatus (RipNgRoutingTableEntry::RIPNG_VALID);
1066           route->SetRouteChanged (true);
1067           m_routes.push_front (std::make_pair (route, EventId ()));
1068           EventId invalidateEvent = Simulator::Schedule (m_timeoutDelay, &RipNg::InvalidateRoute, this, route);
1069           (m_routes.begin ())->second = invalidateEvent;
1070           changed = true;
1071         }
1072     }
1073 
1074   if (changed)
1075     {
1076       SendTriggeredRouteUpdate ();
1077     }
1078 }
1079 
DoSendRouteUpdate(bool periodic)1080 void RipNg::DoSendRouteUpdate (bool periodic)
1081 {
1082   NS_LOG_FUNCTION (this << (periodic ? " periodic" : " triggered"));
1083 
1084   for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
1085     {
1086       uint32_t interface = iter->second;
1087 
1088       if (m_interfaceExclusions.find (interface) == m_interfaceExclusions.end ())
1089         {
1090           uint16_t mtu = m_ipv6->GetMtu (interface);
1091           uint16_t maxRte = (mtu - Ipv6Header ().GetSerializedSize () - UdpHeader ().GetSerializedSize () - RipNgHeader ().GetSerializedSize ()) / RipNgRte ().GetSerializedSize ();
1092 
1093           Ptr<Packet> p = Create<Packet> ();
1094           SocketIpv6HopLimitTag tag;
1095           tag.SetHopLimit (255);
1096           p->AddPacketTag (tag);
1097 
1098           RipNgHeader hdr;
1099           hdr.SetCommand (RipNgHeader::RESPONSE);
1100 
1101           for (RoutesI rtIter = m_routes.begin (); rtIter != m_routes.end (); rtIter++)
1102             {
1103               bool splitHorizoning = (rtIter->first->GetInterface () == interface);
1104               Ipv6InterfaceAddress rtDestAddr = Ipv6InterfaceAddress(rtIter->first->GetDestNetwork (), rtIter->first->GetDestNetworkPrefix ());
1105 
1106               NS_LOG_DEBUG ("Processing RT " << rtDestAddr << " " << int(rtIter->first->IsRouteChanged ()));
1107 
1108               bool isGlobal = (rtDestAddr.GetScope () == Ipv6InterfaceAddress::GLOBAL);
1109               bool isDefaultRoute = ((rtIter->first->GetDestNetwork () == Ipv6Address::GetAny ()) &&
1110                   (rtIter->first->GetDestNetworkPrefix () == Ipv6Prefix::GetZero ()) &&
1111                   (rtIter->first->GetInterface () != interface));
1112 
1113               if ((isGlobal || isDefaultRoute) &&
1114                   (periodic || rtIter->first->IsRouteChanged ()))
1115                 {
1116                   RipNgRte rte;
1117                   rte.SetPrefix (rtIter->first->GetDestNetwork ());
1118                   rte.SetPrefixLen (rtIter->first->GetDestNetworkPrefix ().GetPrefixLength ());
1119                   if (m_splitHorizonStrategy == POISON_REVERSE && splitHorizoning)
1120                     {
1121                       rte.SetRouteMetric (m_linkDown);
1122                     }
1123                   else
1124                     {
1125                       rte.SetRouteMetric (rtIter->first->GetRouteMetric ());
1126                     }
1127                   rte.SetRouteTag (rtIter->first->GetRouteTag ());
1128                   if (m_splitHorizonStrategy == SPLIT_HORIZON && !splitHorizoning)
1129                     {
1130                       hdr.AddRte (rte);
1131                     }
1132                   else if (m_splitHorizonStrategy != SPLIT_HORIZON)
1133                     {
1134                       hdr.AddRte (rte);
1135                     }
1136                 }
1137               if (hdr.GetRteNumber () == maxRte)
1138                 {
1139                   p->AddHeader (hdr);
1140                   NS_LOG_DEBUG ("SendTo: " << *p);
1141                   iter->first->SendTo (p, 0, Inet6SocketAddress (RIPNG_ALL_NODE, RIPNG_PORT));
1142                   p->RemoveHeader (hdr);
1143                   hdr.ClearRtes ();
1144                 }
1145             }
1146           if (hdr.GetRteNumber () > 0)
1147             {
1148               p->AddHeader (hdr);
1149               NS_LOG_DEBUG ("SendTo: " << *p);
1150               iter->first->SendTo (p, 0, Inet6SocketAddress (RIPNG_ALL_NODE, RIPNG_PORT));
1151             }
1152         }
1153     }
1154   for (RoutesI rtIter = m_routes.begin (); rtIter != m_routes.end (); rtIter++)
1155     {
1156       rtIter->first->SetRouteChanged (false);
1157     }
1158 }
1159 
SendTriggeredRouteUpdate()1160 void RipNg::SendTriggeredRouteUpdate ()
1161 {
1162   NS_LOG_FUNCTION (this);
1163 
1164   if (m_nextTriggeredUpdate.IsRunning())
1165     {
1166       NS_LOG_LOGIC ("Skipping Triggered Update due to cooldown");
1167       return;
1168     }
1169 
1170   // DoSendRouteUpdate (false);
1171 
1172   // note: The RFC states:
1173   //     After a triggered
1174   //     update is sent, a timer should be set for a random interval between 1
1175   //     and 5 seconds.  If other changes that would trigger updates occur
1176   //     before the timer expires, a single update is triggered when the timer
1177   //     expires.  The timer is then reset to another random value between 1
1178   //     and 5 seconds.  Triggered updates may be suppressed if a regular
1179   //     update is due by the time the triggered update would be sent.
1180   // Here we rely on this:
1181   // When an update occurs (either Triggered or Periodic) the "IsChanged ()"
1182   // route field will be cleared.
1183   // Hence, the following Triggered Update will be fired, but will not send
1184   // any route update.
1185 
1186   Time delay = Seconds (m_rng->GetValue (m_minTriggeredUpdateDelay.GetSeconds (), m_maxTriggeredUpdateDelay.GetSeconds ()));
1187   m_nextTriggeredUpdate = Simulator::Schedule (delay, &RipNg::DoSendRouteUpdate, this, false);
1188 }
1189 
SendUnsolicitedRouteUpdate()1190 void RipNg::SendUnsolicitedRouteUpdate ()
1191 {
1192   NS_LOG_FUNCTION (this);
1193 
1194   if (m_nextTriggeredUpdate.IsRunning())
1195     {
1196       m_nextTriggeredUpdate.Cancel ();
1197     }
1198 
1199   DoSendRouteUpdate (true);
1200 
1201   Time delay = m_unsolicitedUpdate + Seconds (m_rng->GetValue (0, 0.5*m_unsolicitedUpdate.GetSeconds ()) );
1202   m_nextUnsolicitedUpdate = Simulator::Schedule (delay, &RipNg::SendUnsolicitedRouteUpdate, this);
1203 }
1204 
GetInterfaceExclusions() const1205 std::set<uint32_t> RipNg::GetInterfaceExclusions () const
1206 {
1207   return m_interfaceExclusions;
1208 }
1209 
SetInterfaceExclusions(std::set<uint32_t> exceptions)1210 void RipNg::SetInterfaceExclusions (std::set<uint32_t> exceptions)
1211 {
1212   NS_LOG_FUNCTION (this);
1213 
1214   m_interfaceExclusions = exceptions;
1215 }
1216 
GetInterfaceMetric(uint32_t interface) const1217 uint8_t RipNg::GetInterfaceMetric (uint32_t interface) const
1218 {
1219   NS_LOG_FUNCTION (this << interface);
1220 
1221   std::map<uint32_t, uint8_t>::const_iterator iter = m_interfaceMetrics.find (interface);
1222   if (iter != m_interfaceMetrics.end ())
1223     {
1224       return iter->second;
1225     }
1226   return 1;
1227 }
1228 
SetInterfaceMetric(uint32_t interface,uint8_t metric)1229 void RipNg::SetInterfaceMetric (uint32_t interface, uint8_t metric)
1230 {
1231   NS_LOG_FUNCTION (this << interface << int (metric));
1232 
1233   if (metric < m_linkDown)
1234     {
1235       m_interfaceMetrics[interface] = metric;
1236     }
1237 }
1238 
SendRouteRequest()1239 void RipNg::SendRouteRequest ()
1240 {
1241   NS_LOG_FUNCTION (this);
1242 
1243   Ptr<Packet> p = Create<Packet> ();
1244   SocketIpv6HopLimitTag tag;
1245   p->RemovePacketTag (tag);
1246   tag.SetHopLimit (255);
1247   p->AddPacketTag (tag);
1248 
1249   RipNgHeader hdr;
1250   hdr.SetCommand (RipNgHeader::REQUEST);
1251 
1252   RipNgRte rte;
1253   rte.SetPrefix (Ipv6Address::GetAny ());
1254   rte.SetPrefixLen (0);
1255   rte.SetRouteMetric (m_linkDown);
1256 
1257   hdr.AddRte (rte);
1258   p->AddHeader (hdr);
1259 
1260   for (SocketListI iter = m_unicastSocketList.begin (); iter != m_unicastSocketList.end (); iter++ )
1261     {
1262       uint32_t interface = iter->second;
1263 
1264       if (m_interfaceExclusions.find (interface) == m_interfaceExclusions.end ())
1265         {
1266           NS_LOG_DEBUG ("SendTo: " << *p);
1267           iter->first->SendTo (p, 0, Inet6SocketAddress (RIPNG_ALL_NODE, RIPNG_PORT));
1268         }
1269     }
1270 }
1271 
AddDefaultRouteTo(Ipv6Address nextHop,uint32_t interface)1272 void RipNg::AddDefaultRouteTo (Ipv6Address nextHop, uint32_t interface)
1273 {
1274   NS_LOG_FUNCTION (this << interface);
1275 
1276   AddNetworkRouteTo (Ipv6Address ("::"), Ipv6Prefix::GetZero (), nextHop, interface, Ipv6Address ("::"));
1277 }
1278 
1279 
1280 /*
1281  * RipNgRoutingTableEntry
1282  */
1283 
RipNgRoutingTableEntry()1284 RipNgRoutingTableEntry::RipNgRoutingTableEntry ()
1285   : m_tag (0), m_metric (0), m_status (RIPNG_INVALID), m_changed (false)
1286 {
1287 }
1288 
RipNgRoutingTableEntry(Ipv6Address network,Ipv6Prefix networkPrefix,Ipv6Address nextHop,uint32_t interface,Ipv6Address prefixToUse)1289 RipNgRoutingTableEntry::RipNgRoutingTableEntry (Ipv6Address network, Ipv6Prefix networkPrefix, Ipv6Address nextHop, uint32_t interface, Ipv6Address prefixToUse)
1290   : Ipv6RoutingTableEntry ( RipNgRoutingTableEntry::CreateNetworkRouteTo (network, networkPrefix, nextHop, interface, prefixToUse) ),
1291     m_tag (0), m_metric (0), m_status (RIPNG_INVALID), m_changed (false)
1292 {
1293 }
1294 
RipNgRoutingTableEntry(Ipv6Address network,Ipv6Prefix networkPrefix,uint32_t interface)1295 RipNgRoutingTableEntry::RipNgRoutingTableEntry (Ipv6Address network, Ipv6Prefix networkPrefix, uint32_t interface)
1296   : Ipv6RoutingTableEntry ( Ipv6RoutingTableEntry::CreateNetworkRouteTo (network, networkPrefix, interface) ),
1297     m_tag (0), m_metric (0), m_status (RIPNG_INVALID), m_changed (false)
1298 {
1299 }
1300 
~RipNgRoutingTableEntry()1301 RipNgRoutingTableEntry::~RipNgRoutingTableEntry ()
1302 {
1303 }
1304 
1305 
SetRouteTag(uint16_t routeTag)1306 void RipNgRoutingTableEntry::SetRouteTag (uint16_t routeTag)
1307 {
1308   if (m_tag != routeTag)
1309     {
1310       m_tag = routeTag;
1311       m_changed = true;
1312     }
1313 }
1314 
GetRouteTag() const1315 uint16_t RipNgRoutingTableEntry::GetRouteTag () const
1316 {
1317   return m_tag;
1318 }
1319 
SetRouteMetric(uint8_t routeMetric)1320 void RipNgRoutingTableEntry::SetRouteMetric (uint8_t routeMetric)
1321 {
1322   if (m_metric != routeMetric)
1323     {
1324       m_metric = routeMetric;
1325       m_changed = true;
1326     }
1327 }
1328 
GetRouteMetric() const1329 uint8_t RipNgRoutingTableEntry::GetRouteMetric () const
1330 {
1331   return m_metric;
1332 }
1333 
SetRouteStatus(Status_e status)1334 void RipNgRoutingTableEntry::SetRouteStatus (Status_e status)
1335 {
1336   if (m_status != status)
1337     {
1338       m_status = status;
1339       m_changed = true;
1340     }
1341 }
1342 
GetRouteStatus(void) const1343 RipNgRoutingTableEntry::Status_e RipNgRoutingTableEntry::GetRouteStatus (void) const
1344 {
1345   return m_status;
1346 }
1347 
SetRouteChanged(bool changed)1348 void RipNgRoutingTableEntry::SetRouteChanged (bool changed)
1349 {
1350   m_changed = changed;
1351 }
1352 
IsRouteChanged(void) const1353 bool RipNgRoutingTableEntry::IsRouteChanged (void) const
1354 {
1355   return m_changed;
1356 }
1357 
1358 
operator <<(std::ostream & os,const RipNgRoutingTableEntry & rte)1359 std::ostream & operator << (std::ostream& os, const RipNgRoutingTableEntry& rte)
1360 {
1361   os << static_cast<const Ipv6RoutingTableEntry &>(rte);
1362   os << ", metric: " << int (rte.GetRouteMetric ()) << ", tag: " << int (rte.GetRouteTag ());
1363 
1364   return os;
1365 }
1366 
1367 
1368 }
1369 
1370