blob: 415a06d46f0d9b6a1aa7b977719c36050a671d09 [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 Pesaventoa3a7a4e2022-05-29 16:06:22 -04003 * Copyright (c) 2014-2022, 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>
Eric Newberry185ab292017-03-28 06:45:39 +000034
35#include <queue>
36
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040037namespace nfd::face {
Eric Newberry185ab292017-03-28 06:45:39 +000038
39class GenericLinkService;
40
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040041/**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040042 * \brief Provides for reliable sending and receiving of link-layer packets.
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040043 * \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
Eric Newberry185ab292017-03-28 06:45:39 +000044 */
45class LpReliability : noncopyable
46{
47public:
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040048 /// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
49 static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
50 tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
51 sizeof(lp::Sequence);
52
Eric Newberry185ab292017-03-28 06:45:39 +000053 struct Options
54 {
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040055 /** \brief Enables link-layer reliability.
Eric Newberry185ab292017-03-28 06:45:39 +000056 */
57 bool isEnabled = false;
58
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040059 /** \brief Maximum number of retransmissions for an LpPacket.
Eric Newberry185ab292017-03-28 06:45:39 +000060 */
61 size_t maxRetx = 3;
62
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040063 /** \brief Period between sending pending Acks in an IDLE packet.
Eric Newberry185ab292017-03-28 06:45:39 +000064 */
Davide Pesaventoe4b22382018-06-10 14:37:24 -040065 time::nanoseconds idleAckTimerPeriod = 5_ms;
Eric Newberry185ab292017-03-28 06:45:39 +000066
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040067 /** \brief A fragment is considered lost if this number of fragments with greater sequence
68 * numbers are acknowledged.
Eric Newberry185ab292017-03-28 06:45:39 +000069 */
70 size_t seqNumLossThreshold = 3;
71 };
72
73 LpReliability(const Options& options, GenericLinkService* linkService);
74
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040075 /** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
Eric Newberry41aba102017-11-01 16:42:13 -070076 */
77 signal::Signal<LpReliability, Interest> onDroppedInterest;
78
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040079 /** \brief Set options for reliability.
Eric Newberry185ab292017-03-28 06:45:39 +000080 */
81 void
82 setOptions(const Options& options);
83
84 /** \return GenericLinkService that owns this instance
85 *
86 * This is only used for logging, and may be nullptr.
87 */
88 const GenericLinkService*
89 getLinkService() const;
90
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040091 /** \brief Observe outgoing fragment(s) of a network packet and store for potential retransmission.
Eric Newberry185ab292017-03-28 06:45:39 +000092 * \param frags fragments of network packet
Eric Newberry41aba102017-11-01 16:42:13 -070093 * \param pkt encapsulated network packet
94 * \param isInterest whether the network packet is an Interest
Eric Newberry185ab292017-03-28 06:45:39 +000095 */
96 void
Eric Newberry41aba102017-11-01 16:42:13 -070097 handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest);
Eric Newberry185ab292017-03-28 06:45:39 +000098
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040099 /** \brief Extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue.
Eric Newberry185ab292017-03-28 06:45:39 +0000100 * \param pkt incoming LpPacket
Eric Newberry32f7eac2020-02-07 14:40:17 -0800101 * \return whether incoming LpPacket is new and not a duplicate
Eric Newberry185ab292017-03-28 06:45:39 +0000102 */
Eric Newberry32f7eac2020-02-07 14:40:17 -0800103 bool
Eric Newberry185ab292017-03-28 06:45:39 +0000104 processIncomingPacket(const lp::Packet& pkt);
105
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400106 /** \brief Called by GenericLinkService to attach Acks onto an outgoing LpPacket.
Eric Newberry185ab292017-03-28 06:45:39 +0000107 * \param pkt outgoing LpPacket to attach Acks to
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400108 * \param mtu MTU of the transport
Eric Newberry185ab292017-03-28 06:45:39 +0000109 */
110 void
111 piggyback(lp::Packet& pkt, ssize_t mtu);
112
Davide Pesavento264af772021-02-09 21:48:24 -0500113NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000114 class UnackedFrag;
115 class NetPkt;
116 using UnackedFrags = std::map<lp::Sequence, UnackedFrag>;
117
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400118 /** \brief Assign TxSequence number to a fragment.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000119 * \param frag fragment to assign TxSequence to
120 * \return assigned TxSequence number
121 * \throw std::length_error assigned TxSequence is equal to the start of the existing window
122 */
123 lp::Sequence
124 assignTxSequence(lp::Packet& frag);
125
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400126 /** \brief Start the idle Ack timer.
Eric Newberry185ab292017-03-28 06:45:39 +0000127 *
128 * This timer requests an IDLE packet to acknowledge pending fragments not already piggybacked.
129 * It is called regularly on a period configured in Options::idleAckTimerPeriod. This allows Acks
130 * to be returned to the sender, even if the link goes idle.
131 */
132 void
133 startIdleAckTimer();
134
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400135 /** \brief Find and mark as lost fragments where a configurable number of Acks
136 * (Options::seqNumLossThreshold) have been received for greater TxSequence numbers.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000137 * \param ackIt iterator pointing to acknowledged fragment
Eric Newberry971d9622018-03-30 23:29:26 -0700138 * \return vector containing TxSequences of fragments marked lost by this mechanism
Eric Newberry185ab292017-03-28 06:45:39 +0000139 */
Eric Newberry971d9622018-03-30 23:29:26 -0700140 std::vector<lp::Sequence>
Eric Newberry7b0071e2017-07-03 17:33:31 +0000141 findLostLpPackets(UnackedFrags::iterator ackIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000142
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400143 /** \brief Resend (or give up on) a lost fragment.
Eric Newberry971d9622018-03-30 23:29:26 -0700144 * \return vector of the TxSequences of fragments removed due to a network packet being removed
Eric Newberry185ab292017-03-28 06:45:39 +0000145 */
Eric Newberry971d9622018-03-30 23:29:26 -0700146 std::vector<lp::Sequence>
Eric Newberry32f7eac2020-02-07 14:40:17 -0800147 onLpPacketLost(lp::Sequence txSeq, bool isTimeout);
Eric Newberry185ab292017-03-28 06:45:39 +0000148
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400149 /** \brief Remove the fragment with the given sequence number from the map of unacknowledged
150 * fragments, as well as its associated network packet (if any).
Eric Newberry7b0071e2017-07-03 17:33:31 +0000151 * \param fragIt iterator to acknowledged fragment
Eric Newberry185ab292017-03-28 06:45:39 +0000152 *
Eric Newberry7b0071e2017-07-03 17:33:31 +0000153 * If the given TxSequence marks the beginning of the send window, the window will be incremented.
Eric Newberry185ab292017-03-28 06:45:39 +0000154 * If the associated network packet has been fully transmitted, it will be removed.
155 */
156 void
Eric Newberry7b0071e2017-07-03 17:33:31 +0000157 onLpPacketAcknowledged(UnackedFrags::iterator fragIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000158
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400159 /** \brief Delete a fragment from UnackedFrags and advance acknowledge window if necessary.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000160 * \param fragIt iterator to an UnackedFrag, must be dereferencable
161 * \post fragIt is not in m_unackedFrags
162 * \post if was equal to m_firstUnackedFrag,
163 * m_firstUnackedFrag is set to the UnackedFrag after fragIt with consideration of
164 * TxSequence number wraparound, or set to m_unackedFrags.end() if m_unackedFrags is empty
165 */
166 void
167 deleteUnackedFrag(UnackedFrags::iterator fragIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000168
Davide Pesavento264af772021-02-09 21:48:24 -0500169NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400170 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400171 * \brief Contains a sent fragment that has not been acknowledged and associated data.
Eric Newberry185ab292017-03-28 06:45:39 +0000172 */
173 class UnackedFrag
174 {
175 public:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000176 explicit
Eric Newberry185ab292017-03-28 06:45:39 +0000177 UnackedFrag(lp::Packet pkt);
178
179 public:
180 lp::Packet pkt;
181 scheduler::ScopedEventId rtoTimer;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400182 time::steady_clock::time_point sendTime;
Eric Newberry185ab292017-03-28 06:45:39 +0000183 size_t retxCount;
184 size_t nGreaterSeqAcks; //!< number of Acks received for sequences greater than this fragment
Eric Newberry7b0071e2017-07-03 17:33:31 +0000185 shared_ptr<NetPkt> netPkt;
Eric Newberry185ab292017-03-28 06:45:39 +0000186 };
187
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400188 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400189 * \brief Contains a network-layer packet with unacknowledged fragments.
Eric Newberry185ab292017-03-28 06:45:39 +0000190 */
191 class NetPkt
192 {
193 public:
Eric Newberry41aba102017-11-01 16:42:13 -0700194 NetPkt(lp::Packet&& pkt, bool isInterest);
195
196 public:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000197 std::vector<UnackedFrags::iterator> unackedFrags;
Eric Newberry41aba102017-11-01 16:42:13 -0700198 lp::Packet pkt;
199 bool isInterest;
200 bool didRetx;
Eric Newberry185ab292017-03-28 06:45:39 +0000201 };
202
Eric Newberry185ab292017-03-28 06:45:39 +0000203 Options m_options;
204 GenericLinkService* m_linkService;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000205 UnackedFrags m_unackedFrags;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400206 // An iterator that points to the first unacknowledged fragment in the current window. The window
207 // can wrap around so that the beginning of the window is at a TxSequence greater than other
208 // fragments in the window. When the window is moved past the last item in the iterator, the
209 // first fragment in the map will become the start of the window.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000210 UnackedFrags::iterator m_firstUnackedFrag;
Eric Newberry185ab292017-03-28 06:45:39 +0000211 std::queue<lp::Sequence> m_ackQueue;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400212 std::map<lp::Sequence, time::steady_clock::time_point> m_recentRecvSeqs;
Eric Newberry32f7eac2020-02-07 14:40:17 -0800213 std::queue<lp::Sequence> m_recentRecvSeqsQueue;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000214 lp::Sequence m_lastTxSeqNo;
Eric Newberry185ab292017-03-28 06:45:39 +0000215 scheduler::ScopedEventId m_idleAckTimer;
Davide Pesaventof190cfa2019-07-17 20:14:11 -0400216 ndn::util::RttEstimator m_rttEst;
Eric Newberry185ab292017-03-28 06:45:39 +0000217};
218
Eric Newberry5ab4cf82020-02-03 15:40:16 -0800219std::ostream&
220operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh);
221
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400222} // namespace nfd::face
Eric Newberry185ab292017-03-28 06:45:39 +0000223
224#endif // NFD_DAEMON_FACE_LP_RELIABILITY_HPP