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