From 60449cfbaac31a92c122501b5f1b7b3ad4a23912 Mon Sep 17 00:00:00 2001 From: Tommaso Pecorella Date: Mon, 20 Jun 2022 22:06:24 -0500 Subject: [PATCH] internet: (fixes #400) Adds RS retransmission if no reply --- CHANGES.md | 1 + RELEASE_NOTES.md | 2 + src/internet/model/icmpv6-l4-protocol.cc | 103 ++++++++++++++++++++++- src/internet/model/icmpv6-l4-protocol.h | 77 +++++++++++++++-- src/internet/model/ipv6-interface.cc | 2 +- 5 files changed, 174 insertions(+), 11 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a235674cb..dab795547 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,6 +28,7 @@ Changes from ns-3.36 to ns-3.37 * Adds supporting structures used by **LrWpanMac** (PAN descriptor, Command Payload Header, Capability Field). * Mac(8|16|48|64)Address address allocation pool is now reset between consecutive runs. * Adds support for **LrWpanMac** energy detection (ED) scan. +* IPv6 Router Solicitations (RS) are now retrnamitted up to 4 times, following RFC 5779. ### Changes to build system diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3ddc04e30..da0658d5a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -18,6 +18,8 @@ Release 3-dev - (lr-wpan) Adds PAN descriptor, CommandPayload Header and Capability Field - (wifi) !984 - MultiUserScheduler can request channel access periodically - (lr-wpan) !991 - Adds MAC ED scan support +- (internet) !996 - IPv6 Router Solicitations (RS) are now retrnamitted up to 4 times, following RFC 5779. + ### Bugs fixed diff --git a/src/internet/model/icmpv6-l4-protocol.cc b/src/internet/model/icmpv6-l4-protocol.cc index e9fe3088d..5a5c4ce4b 100644 --- a/src/internet/model/icmpv6-l4-protocol.cc +++ b/src/internet/model/icmpv6-l4-protocol.cc @@ -31,6 +31,8 @@ #include "ns3/pointer.h" #include "ns3/string.h" #include "ns3/integer.h" +#include "ns3/uinteger.h" +#include "ns3/double.h" #include "ipv6-l3-protocol.h" #include "ipv6-interface.h" @@ -94,6 +96,33 @@ TypeId Icmpv6L4Protocol::GetTypeId () TimeValue (Seconds (5)), MakeTimeAccessor (&Icmpv6L4Protocol::m_delayFirstProbe), MakeTimeChecker ()) + .AddAttribute ("DadTimeout", "Duplicate Address Detection (DAD) timeout", + TimeValue (Seconds (1)), + MakeTimeAccessor (&Icmpv6L4Protocol::m_dadTimeout), + MakeTimeChecker ()) + .AddAttribute ("RsRetransmissionJitter", "Multicast RS retransmission randomization quantity", + StringValue ("ns3::UniformRandomVariable[Min=-0.1|Max=0.1]"), + MakePointerAccessor (&Icmpv6L4Protocol::m_rsRetransmissionJitter), + MakePointerChecker ()) + .AddAttribute ("RsInitialRetransmissionTime", "Multicast RS initial retransmission time.", + TimeValue (Seconds (4)), + MakeTimeAccessor (&Icmpv6L4Protocol::m_rsInitialRetransmissionTime), + MakeTimeChecker ()) + .AddAttribute ("RsMaxRetransmissionTime", "Multicast RS maximum retransmission time (0 means unbound).", + TimeValue (Seconds (3600)), + MakeTimeAccessor (&Icmpv6L4Protocol::m_rsMaxRetransmissionTime), + MakeTimeChecker ()) + .AddAttribute ("RsMaxRetransmissionCount", + "Multicast RS maximum retransmission count (0 means unbound). " + "Note: RFC 7559 suggest a zero value (infinite). The default is 4 to avoid " + "non-terminating simulations.", + UintegerValue (4), + MakeUintegerAccessor (&Icmpv6L4Protocol::m_rsMaxRetransmissionCount), + MakeUintegerChecker ()) + .AddAttribute ("RsMaxRetransmissionDuration", "Multicast RS maximum retransmission duration (0 means unbound).", + TimeValue (Seconds (0)), + MakeTimeAccessor (&Icmpv6L4Protocol::m_rsMaxRetransmissionDuration), + MakeTimeChecker ()) ; return tid; } @@ -135,7 +164,8 @@ int64_t Icmpv6L4Protocol::AssignStreams (int64_t stream) { NS_LOG_FUNCTION (this << stream); m_solicitationJitter->SetStream (stream); - return 1; + m_rsRetransmissionJitter->SetStream (stream+1); + return 2; } void Icmpv6L4Protocol::NotifyNewAggregate () @@ -325,6 +355,14 @@ void Icmpv6L4Protocol::HandleEchoRequest (Ptr packet, Ipv6Address const void Icmpv6L4Protocol::HandleRA (Ptr packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr interface) { NS_LOG_FUNCTION (this << packet << src << dst << interface); + + if (m_handleRsTimeoutEvent.IsRunning ()) + { + m_handleRsTimeoutEvent.Cancel (); + // We need to update this in case we need to restart RS retransmissions. + m_rsRetransmissionCount = 0; + } + Ptr p = packet->Copy (); Icmpv6RA raHeader; Ptr ipv6 = m_node->GetObject (); @@ -1074,7 +1112,7 @@ void Icmpv6L4Protocol::SendNS (Ipv6Address src, Ipv6Address dst, Ipv6Address tar } } -void Icmpv6L4Protocol::SendRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress) +void Icmpv6L4Protocol::SendRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress) { NS_LOG_FUNCTION (this << src << dst << hardwareAddress); Ptr p = Create (); @@ -1100,10 +1138,60 @@ void Icmpv6L4Protocol::SendRS (Ipv6Address src, Ipv6Address dst, Address hardwa else { NS_LOG_LOGIC ("Destination is Multicast, using DelayedSendMessage"); - Simulator::Schedule (Time (MilliSeconds (m_solicitationJitter->GetValue ())), &Icmpv6L4Protocol::DelayedSendMessage, this, p, src, dst, 255); + Time rsDelay = Time (0); + Time rsTimeout = Time (0); + + if (m_rsRetransmissionCount == 0) + { + // First RS transmission - also add some jitter to desynchronize nodes. + m_rsInitialRetransmissionTime = Simulator::Now (); + rsTimeout = m_rsInitialRetransmissionTime * (1 + m_rsRetransmissionJitter->GetValue ()); + rsDelay = Time (MilliSeconds (m_solicitationJitter->GetValue ())); + } + else + { + // Following RS transmission - adding further jitter is unnecesary. + rsTimeout = m_rsPrevRetransmissionTimeout * (2 + m_rsRetransmissionJitter->GetValue ()); + if (rsTimeout > m_rsMaxRetransmissionTime) + { + rsTimeout = m_rsMaxRetransmissionTime * (1 + m_rsRetransmissionJitter->GetValue ()); + } + } + m_rsPrevRetransmissionTimeout = rsTimeout; + Simulator::Schedule (rsDelay, &Icmpv6L4Protocol::DelayedSendMessage, this, p, src, dst, 255); + m_handleRsTimeoutEvent = Simulator::Schedule (rsDelay+m_rsPrevRetransmissionTimeout, &Icmpv6L4Protocol::HandleRsTimeout, this, src, dst, hardwareAddress); } } +void Icmpv6L4Protocol::HandleRsTimeout (Ipv6Address src, Ipv6Address dst, Address hardwareAddress) +{ + NS_LOG_FUNCTION (this << src << dst << hardwareAddress); + + if (m_rsMaxRetransmissionCount == 0) + { + // Unbound number of retransmissions - just add one to signal that we're in retransmission mode. + m_rsRetransmissionCount = 1; + } + else + { + m_rsRetransmissionCount ++; + if (m_rsRetransmissionCount > m_rsMaxRetransmissionCount) + { + NS_LOG_LOGIC ("Maximum number of multicast RS reached, giving up."); + return; + } + } + + if (m_rsMaxRetransmissionDuration != Time (0) && + Simulator::Now () - m_rsInitialRetransmissionTime > m_rsMaxRetransmissionDuration) + { + NS_LOG_LOGIC ("Maximum RS retransmission time reached, giving up."); + return; + } + + SendRS (src, dst, hardwareAddress); +} + void Icmpv6L4Protocol::SendErrorDestinationUnreachable (Ptr malformedPacket, Ipv6Address dst, uint8_t code) { NS_LOG_FUNCTION (this << malformedPacket << dst << (uint32_t)code); @@ -1490,7 +1578,8 @@ void Icmpv6L4Protocol::FunctionDadTimeout (Ipv6Interface* interface, Ipv6Address /* \todo Add random delays before sending RS * because all nodes start at the same time, there will be many of RS around 1 second of simulation time */ - NS_LOG_LOGIC ("Scheduled a Router Solicitation"); + NS_LOG_LOGIC ("Scheduled a first Router Solicitation"); + m_rsRetransmissionCount = 0; Simulator::Schedule (Seconds (0.0), &Icmpv6L4Protocol::SendRS, this, ifaddr.GetAddress (), Ipv6Address::GetAllRoutersMulticast (), interface->GetDevice ()->GetAddress ()); } else @@ -1557,6 +1646,12 @@ Icmpv6L4Protocol::GetDelayFirstProbe () const return m_delayFirstProbe; } +Time +Icmpv6L4Protocol::GetDadTimeout () const +{ + return m_dadTimeout; +} + } /* namespace ns3 */ diff --git a/src/internet/model/icmpv6-l4-protocol.h b/src/internet/model/icmpv6-l4-protocol.h index 056cde766..0d748f5a5 100644 --- a/src/internet/model/icmpv6-l4-protocol.h +++ b/src/internet/model/icmpv6-l4-protocol.h @@ -127,7 +127,7 @@ public: * by setting the node in the ICMPv6 stack and adding ICMPv6 factory to * IPv6 stack connected to the node. */ - void NotifyNewAggregate (); + virtual void NotifyNewAggregate (); /** * \brief Get the protocol number. @@ -319,7 +319,7 @@ public: * \param interface the interface * \param addr the IPv6 address */ - void FunctionDadTimeout (Ipv6Interface* interface, Ipv6Address addr); + virtual void FunctionDadTimeout (Ipv6Interface* interface, Ipv6Address addr); /** * \brief Lookup in the ND cache for the IPv6 address @@ -332,7 +332,7 @@ public: * \param hardwareDestination hardware address * \return true if the address is in the ND cache, the hardwareDestination is updated. */ - bool Lookup (Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination); + virtual bool Lookup (Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination); /** * \brief Lookup in the ND cache for the IPv6 address (similar as ARP protocol). @@ -346,12 +346,12 @@ public: * \param hardwareDestination hardware address * \return true if the address is in the ND cache, the hardwareDestination is updated. */ - bool Lookup (Ptr p, const Ipv6Header & ipHeader, Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination); + virtual bool Lookup (Ptr p, const Ipv6Header & ipHeader, Ipv6Address dst, Ptr device, Ptr cache, Address* hardwareDestination); /** * \brief Send a Router Solicitation. * \param src link-local source address - * \param dst destination address (usually ff02::2 i.e all-routers) + * \param dst destination address (usually ff02::2 i.e., all-routers) * \param hardwareAddress link-layer address (SHOULD be included if src is not ::) */ void SendRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress); @@ -380,6 +380,12 @@ public: */ int64_t AssignStreams (int64_t stream); + /** + * Get the DAD timeout + * \return the DAD timeout + */ + Time GetDadTimeout () const; + protected: /** * \brief Dispose this object. @@ -418,6 +424,14 @@ protected: */ void HandleRS (Ptr p, Ipv6Address const &src, Ipv6Address const &dst, Ptr interface); + /** + * \brief Router Solicitation Timeout handler. + * \param src link-local source address + * \param dst destination address (usually ff02::2 i.e all-routers) + * \param hardwareAddress link-layer address (SHOULD be included if src is not ::) + */ + virtual void HandleRsTimeout (Ipv6Address src, Ipv6Address dst, Address hardwareAddress); + /** * \brief Receive Router Advertisement method. * \param p the packet @@ -523,7 +537,6 @@ protected: */ CacheList m_cacheList; -private: /** * \brief Neighbor Discovery node constants: max multicast solicitations. */ @@ -534,6 +547,43 @@ private: */ uint8_t m_maxUnicastSolicit; + /** + * \brief Initial multicast RS retransmission time [\RFC{7559}]. + */ + Time m_rsInitialRetransmissionTime; + + /** + * \brief Maximum time between multicast RS retransmissions [\RFC{7559}]. Zero means unbound. + */ + Time m_rsMaxRetransmissionTime; + + /** + * \brief Maximum number of multicast RS retransmissions [\RFC{7559}]. Zero means unbound. + */ + uint32_t m_rsMaxRetransmissionCount; + + /** + * \brief Maximum duration of multicast RS retransmissions [\RFC{7559}]. Zero means unbound. + */ + Time m_rsMaxRetransmissionDuration; + + /** + * \brief Multicast RS retransmissions counter [\RFC{7559}]. + * + * Zero indicate a first transmission, greater than zero means retranmsisisons. + */ + uint32_t m_rsRetransmissionCount {0}; + + /** + * \brief Previous multicast RS retransmissions timeout [\RFC{7559}]. + */ + Time m_rsPrevRetransmissionTimeout; + + /** + * \brief First multicast RS transmissions [\RFC{7559}]. + */ + Time m_rsFirstTransmissionTime; + /** * \brief Neighbor Discovery node constants: reachable time. */ @@ -559,6 +609,21 @@ private: */ Ptr m_solicitationJitter; + /** + * \brief Random jitter for RS retransmissions + */ + Ptr m_rsRetransmissionJitter; + + /** + * \brief DAD timeout + */ + Time m_dadTimeout; + + /** + * RS timeout handler event + */ + EventId m_handleRsTimeoutEvent; + IpL4Protocol::DownTargetCallback6 m_downTarget; //!< callback to Ipv6::Send }; diff --git a/src/internet/model/ipv6-interface.cc b/src/internet/model/ipv6-interface.cc index a99390175..64dc5362c 100644 --- a/src/internet/model/ipv6-interface.cc +++ b/src/internet/model/ipv6-interface.cc @@ -222,7 +222,7 @@ bool Ipv6Interface::AddAddress (Ipv6InterfaceAddress iface) if (icmpv6->IsAlwaysDad ()) { Simulator::Schedule (Seconds (0.), &Icmpv6L4Protocol::DoDAD, icmpv6, addr, this); - Simulator::Schedule (Seconds (1.), &Icmpv6L4Protocol::FunctionDadTimeout, icmpv6, this, addr); + Simulator::Schedule (icmpv6->GetDadTimeout (), &Icmpv6L4Protocol::FunctionDadTimeout, icmpv6, this, addr); } else {