blob: d4f9582fb78a65975ec570da5adee9e5a2e81599 [file] [log] [blame]
Eric Newberry185ab292017-03-28 06:45:39 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberry7b0071e2017-07-03 17:33:31 +00002/*
Davide Pesavento91c15c82024-01-15 17:14:23 -05003 * Copyright (c) 2014-2024, Regents of the University of California,
Eric Newberry185ab292017-03-28 06:45:39 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#ifndef NFD_DAEMON_FACE_LP_RELIABILITY_HPP
27#define NFD_DAEMON_FACE_LP_RELIABILITY_HPP
28
Eric Newberry5ab4cf82020-02-03 15:40:16 -080029#include "face-common.hpp"
Eric Newberry185ab292017-03-28 06:45:39 +000030
Eric Newberry185ab292017-03-28 06:45:39 +000031#include <ndn-cxx/lp/packet.hpp>
32#include <ndn-cxx/lp/sequence.hpp>
Davide Pesaventof190cfa2019-07-17 20:14:11 -040033#include <ndn-cxx/util/rtt-estimator.hpp>
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -050034#include <ndn-cxx/util/scheduler.hpp>
Eric Newberry185ab292017-03-28 06:45:39 +000035
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -050036#include <map>
Eric Newberry185ab292017-03-28 06:45:39 +000037#include <queue>
38
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040039namespace nfd::face {
Eric Newberry185ab292017-03-28 06:45:39 +000040
41class GenericLinkService;
42
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040043/**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040044 * \brief Provides for reliable sending and receiving of link-layer packets.
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040045 * \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
Eric Newberry185ab292017-03-28 06:45:39 +000046 */
47class LpReliability : noncopyable
48{
49public:
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040050 /// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
51 static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
52 tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
53 sizeof(lp::Sequence);
54
Eric Newberry185ab292017-03-28 06:45:39 +000055 struct Options
56 {
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040057 /** \brief Enables link-layer reliability.
Eric Newberry185ab292017-03-28 06:45:39 +000058 */
59 bool isEnabled = false;
60
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040061 /** \brief Maximum number of retransmissions for an LpPacket.
Eric Newberry185ab292017-03-28 06:45:39 +000062 */
63 size_t maxRetx = 3;
64
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040065 /** \brief Period between sending pending Acks in an IDLE packet.
Eric Newberry185ab292017-03-28 06:45:39 +000066 */
Davide Pesaventoe4b22382018-06-10 14:37:24 -040067 time::nanoseconds idleAckTimerPeriod = 5_ms;
Eric Newberry185ab292017-03-28 06:45:39 +000068
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040069 /** \brief A fragment is considered lost if this number of fragments with greater sequence
70 * numbers are acknowledged.
Eric Newberry185ab292017-03-28 06:45:39 +000071 */
72 size_t seqNumLossThreshold = 3;
73 };
74
75 LpReliability(const Options& options, GenericLinkService* linkService);
76
Davide Pesaventoe0b67df2024-02-17 19:14:24 -050077 /**
78 * \brief Called when an Interest is dropped for exceeding the allowed number of retransmissions.
Eric Newberry41aba102017-11-01 16:42:13 -070079 */
80 signal::Signal<LpReliability, Interest> onDroppedInterest;
81
Davide Pesaventoe0b67df2024-02-17 19:14:24 -050082 /**
83 * \brief Set options for reliability.
Eric Newberry185ab292017-03-28 06:45:39 +000084 */
85 void
86 setOptions(const Options& options);
87
Davide Pesaventoe0b67df2024-02-17 19:14:24 -050088 /**
89 * \brief Returns the GenericLinkService that owns this instance.
Eric Newberry185ab292017-03-28 06:45:39 +000090 *
Davide Pesaventoe0b67df2024-02-17 19:14:24 -050091 * This is only used for logging, and may be nullptr.
Eric Newberry185ab292017-03-28 06:45:39 +000092 */
93 const GenericLinkService*
Davide Pesaventoe0b67df2024-02-17 19:14:24 -050094 getLinkService() const noexcept
95 {
96 return m_linkService;
97 }
Eric Newberry185ab292017-03-28 06:45:39 +000098
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040099 /** \brief Observe outgoing fragment(s) of a network packet and store for potential retransmission.
Eric Newberry185ab292017-03-28 06:45:39 +0000100 * \param frags fragments of network packet
Eric Newberry41aba102017-11-01 16:42:13 -0700101 * \param pkt encapsulated network packet
102 * \param isInterest whether the network packet is an Interest
Eric Newberry185ab292017-03-28 06:45:39 +0000103 */
104 void
Eric Newberry41aba102017-11-01 16:42:13 -0700105 handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest);
Eric Newberry185ab292017-03-28 06:45:39 +0000106
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400107 /** \brief Extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue.
Eric Newberry185ab292017-03-28 06:45:39 +0000108 * \param pkt incoming LpPacket
Eric Newberry32f7eac2020-02-07 14:40:17 -0800109 * \return whether incoming LpPacket is new and not a duplicate
Eric Newberry185ab292017-03-28 06:45:39 +0000110 */
Eric Newberry32f7eac2020-02-07 14:40:17 -0800111 bool
Eric Newberry185ab292017-03-28 06:45:39 +0000112 processIncomingPacket(const lp::Packet& pkt);
113
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400114 /** \brief Called by GenericLinkService to attach Acks onto an outgoing LpPacket.
Eric Newberry185ab292017-03-28 06:45:39 +0000115 * \param pkt outgoing LpPacket to attach Acks to
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400116 * \param mtu MTU of the transport
Eric Newberry185ab292017-03-28 06:45:39 +0000117 */
118 void
119 piggyback(lp::Packet& pkt, ssize_t mtu);
120
Davide Pesavento264af772021-02-09 21:48:24 -0500121NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000122 class UnackedFrag;
123 class NetPkt;
124 using UnackedFrags = std::map<lp::Sequence, UnackedFrag>;
125
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400126 /** \brief Assign TxSequence number to a fragment.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000127 * \param frag fragment to assign TxSequence to
128 * \return assigned TxSequence number
129 * \throw std::length_error assigned TxSequence is equal to the start of the existing window
130 */
131 lp::Sequence
132 assignTxSequence(lp::Packet& frag);
133
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400134 /** \brief Start the idle Ack timer.
Eric Newberry185ab292017-03-28 06:45:39 +0000135 *
136 * This timer requests an IDLE packet to acknowledge pending fragments not already piggybacked.
137 * It is called regularly on a period configured in Options::idleAckTimerPeriod. This allows Acks
138 * to be returned to the sender, even if the link goes idle.
139 */
140 void
141 startIdleAckTimer();
142
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400143 /** \brief Find and mark as lost fragments where a configurable number of Acks
144 * (Options::seqNumLossThreshold) have been received for greater TxSequence numbers.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000145 * \param ackIt iterator pointing to acknowledged fragment
Eric Newberry971d9622018-03-30 23:29:26 -0700146 * \return vector containing TxSequences of fragments marked lost by this mechanism
Eric Newberry185ab292017-03-28 06:45:39 +0000147 */
Eric Newberry971d9622018-03-30 23:29:26 -0700148 std::vector<lp::Sequence>
Eric Newberry7b0071e2017-07-03 17:33:31 +0000149 findLostLpPackets(UnackedFrags::iterator ackIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000150
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400151 /** \brief Resend (or give up on) a lost fragment.
Eric Newberry971d9622018-03-30 23:29:26 -0700152 * \return vector of the TxSequences of fragments removed due to a network packet being removed
Eric Newberry185ab292017-03-28 06:45:39 +0000153 */
Eric Newberry971d9622018-03-30 23:29:26 -0700154 std::vector<lp::Sequence>
Eric Newberry32f7eac2020-02-07 14:40:17 -0800155 onLpPacketLost(lp::Sequence txSeq, bool isTimeout);
Eric Newberry185ab292017-03-28 06:45:39 +0000156
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400157 /** \brief Remove the fragment with the given sequence number from the map of unacknowledged
158 * fragments, as well as its associated network packet (if any).
Eric Newberry7b0071e2017-07-03 17:33:31 +0000159 * \param fragIt iterator to acknowledged fragment
Eric Newberry185ab292017-03-28 06:45:39 +0000160 *
Eric Newberry7b0071e2017-07-03 17:33:31 +0000161 * If the given TxSequence marks the beginning of the send window, the window will be incremented.
Eric Newberry185ab292017-03-28 06:45:39 +0000162 * If the associated network packet has been fully transmitted, it will be removed.
163 */
164 void
Eric Newberry7b0071e2017-07-03 17:33:31 +0000165 onLpPacketAcknowledged(UnackedFrags::iterator fragIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000166
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400167 /** \brief Delete a fragment from UnackedFrags and advance acknowledge window if necessary.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000168 * \param fragIt iterator to an UnackedFrag, must be dereferencable
169 * \post fragIt is not in m_unackedFrags
170 * \post if was equal to m_firstUnackedFrag,
171 * m_firstUnackedFrag is set to the UnackedFrag after fragIt with consideration of
172 * TxSequence number wraparound, or set to m_unackedFrags.end() if m_unackedFrags is empty
173 */
174 void
175 deleteUnackedFrag(UnackedFrags::iterator fragIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000176
Davide Pesavento264af772021-02-09 21:48:24 -0500177NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400178 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400179 * \brief Contains a sent fragment that has not been acknowledged and associated data.
Eric Newberry185ab292017-03-28 06:45:39 +0000180 */
181 class UnackedFrag
182 {
183 public:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000184 explicit
Davide Pesavento91c15c82024-01-15 17:14:23 -0500185 UnackedFrag(lp::Packet p)
186 : pkt(std::move(p))
187 {
188 }
Eric Newberry185ab292017-03-28 06:45:39 +0000189
190 public:
191 lp::Packet pkt;
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500192 ndn::scheduler::ScopedEventId rtoTimer;
Davide Pesavento91c15c82024-01-15 17:14:23 -0500193 time::steady_clock::time_point sendTime = time::steady_clock::now();
194 size_t retxCount = 0;
195 size_t nGreaterSeqAcks = 0; ///< Number of Acks received for sequences greater than this fragment
Eric Newberry7b0071e2017-07-03 17:33:31 +0000196 shared_ptr<NetPkt> netPkt;
Eric Newberry185ab292017-03-28 06:45:39 +0000197 };
198
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400199 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400200 * \brief Contains a network-layer packet with unacknowledged fragments.
Eric Newberry185ab292017-03-28 06:45:39 +0000201 */
202 class NetPkt
203 {
204 public:
Davide Pesavento91c15c82024-01-15 17:14:23 -0500205 NetPkt(lp::Packet&& p, bool isInterest)
206 : pkt(std::move(p))
207 , isInterest(isInterest)
208 {
209 }
Eric Newberry41aba102017-11-01 16:42:13 -0700210
211 public:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000212 std::vector<UnackedFrags::iterator> unackedFrags;
Eric Newberry41aba102017-11-01 16:42:13 -0700213 lp::Packet pkt;
214 bool isInterest;
Davide Pesavento91c15c82024-01-15 17:14:23 -0500215 bool didRetx = false;
Eric Newberry185ab292017-03-28 06:45:39 +0000216 };
217
Eric Newberry185ab292017-03-28 06:45:39 +0000218 Options m_options;
Davide Pesavento91c15c82024-01-15 17:14:23 -0500219 GenericLinkService* m_linkService = nullptr;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000220 UnackedFrags m_unackedFrags;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400221 // An iterator that points to the first unacknowledged fragment in the current window. The window
222 // can wrap around so that the beginning of the window is at a TxSequence greater than other
223 // fragments in the window. When the window is moved past the last item in the iterator, the
224 // first fragment in the map will become the start of the window.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000225 UnackedFrags::iterator m_firstUnackedFrag;
Eric Newberry185ab292017-03-28 06:45:39 +0000226 std::queue<lp::Sequence> m_ackQueue;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400227 std::map<lp::Sequence, time::steady_clock::time_point> m_recentRecvSeqs;
Eric Newberry32f7eac2020-02-07 14:40:17 -0800228 std::queue<lp::Sequence> m_recentRecvSeqsQueue;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000229 lp::Sequence m_lastTxSeqNo;
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500230 ndn::scheduler::ScopedEventId m_idleAckTimer;
Davide Pesaventof190cfa2019-07-17 20:14:11 -0400231 ndn::util::RttEstimator m_rttEst;
Eric Newberry185ab292017-03-28 06:45:39 +0000232};
233
Eric Newberry5ab4cf82020-02-03 15:40:16 -0800234std::ostream&
235operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh);
236
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400237} // namespace nfd::face
Eric Newberry185ab292017-03-28 06:45:39 +0000238
239#endif // NFD_DAEMON_FACE_LP_RELIABILITY_HPP