blob: 03243043f494df93aca594897da33aa06d64a5f4 [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 Pesaventoaa9e3b22022-10-21 17:00:07 -040077 /** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
Eric Newberry41aba102017-11-01 16:42:13 -070078 */
79 signal::Signal<LpReliability, Interest> onDroppedInterest;
80
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040081 /** \brief Set options for reliability.
Eric Newberry185ab292017-03-28 06:45:39 +000082 */
83 void
84 setOptions(const Options& options);
85
86 /** \return GenericLinkService that owns this instance
87 *
88 * This is only used for logging, and may be nullptr.
89 */
90 const GenericLinkService*
91 getLinkService() const;
92
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040093 /** \brief Observe outgoing fragment(s) of a network packet and store for potential retransmission.
Eric Newberry185ab292017-03-28 06:45:39 +000094 * \param frags fragments of network packet
Eric Newberry41aba102017-11-01 16:42:13 -070095 * \param pkt encapsulated network packet
96 * \param isInterest whether the network packet is an Interest
Eric Newberry185ab292017-03-28 06:45:39 +000097 */
98 void
Eric Newberry41aba102017-11-01 16:42:13 -070099 handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest);
Eric Newberry185ab292017-03-28 06:45:39 +0000100
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400101 /** \brief Extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue.
Eric Newberry185ab292017-03-28 06:45:39 +0000102 * \param pkt incoming LpPacket
Eric Newberry32f7eac2020-02-07 14:40:17 -0800103 * \return whether incoming LpPacket is new and not a duplicate
Eric Newberry185ab292017-03-28 06:45:39 +0000104 */
Eric Newberry32f7eac2020-02-07 14:40:17 -0800105 bool
Eric Newberry185ab292017-03-28 06:45:39 +0000106 processIncomingPacket(const lp::Packet& pkt);
107
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400108 /** \brief Called by GenericLinkService to attach Acks onto an outgoing LpPacket.
Eric Newberry185ab292017-03-28 06:45:39 +0000109 * \param pkt outgoing LpPacket to attach Acks to
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400110 * \param mtu MTU of the transport
Eric Newberry185ab292017-03-28 06:45:39 +0000111 */
112 void
113 piggyback(lp::Packet& pkt, ssize_t mtu);
114
Davide Pesavento264af772021-02-09 21:48:24 -0500115NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000116 class UnackedFrag;
117 class NetPkt;
118 using UnackedFrags = std::map<lp::Sequence, UnackedFrag>;
119
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400120 /** \brief Assign TxSequence number to a fragment.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000121 * \param frag fragment to assign TxSequence to
122 * \return assigned TxSequence number
123 * \throw std::length_error assigned TxSequence is equal to the start of the existing window
124 */
125 lp::Sequence
126 assignTxSequence(lp::Packet& frag);
127
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400128 /** \brief Start the idle Ack timer.
Eric Newberry185ab292017-03-28 06:45:39 +0000129 *
130 * This timer requests an IDLE packet to acknowledge pending fragments not already piggybacked.
131 * It is called regularly on a period configured in Options::idleAckTimerPeriod. This allows Acks
132 * to be returned to the sender, even if the link goes idle.
133 */
134 void
135 startIdleAckTimer();
136
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400137 /** \brief Find and mark as lost fragments where a configurable number of Acks
138 * (Options::seqNumLossThreshold) have been received for greater TxSequence numbers.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000139 * \param ackIt iterator pointing to acknowledged fragment
Eric Newberry971d9622018-03-30 23:29:26 -0700140 * \return vector containing TxSequences of fragments marked lost by this mechanism
Eric Newberry185ab292017-03-28 06:45:39 +0000141 */
Eric Newberry971d9622018-03-30 23:29:26 -0700142 std::vector<lp::Sequence>
Eric Newberry7b0071e2017-07-03 17:33:31 +0000143 findLostLpPackets(UnackedFrags::iterator ackIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000144
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400145 /** \brief Resend (or give up on) a lost fragment.
Eric Newberry971d9622018-03-30 23:29:26 -0700146 * \return vector of the TxSequences of fragments removed due to a network packet being removed
Eric Newberry185ab292017-03-28 06:45:39 +0000147 */
Eric Newberry971d9622018-03-30 23:29:26 -0700148 std::vector<lp::Sequence>
Eric Newberry32f7eac2020-02-07 14:40:17 -0800149 onLpPacketLost(lp::Sequence txSeq, bool isTimeout);
Eric Newberry185ab292017-03-28 06:45:39 +0000150
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400151 /** \brief Remove the fragment with the given sequence number from the map of unacknowledged
152 * fragments, as well as its associated network packet (if any).
Eric Newberry7b0071e2017-07-03 17:33:31 +0000153 * \param fragIt iterator to acknowledged fragment
Eric Newberry185ab292017-03-28 06:45:39 +0000154 *
Eric Newberry7b0071e2017-07-03 17:33:31 +0000155 * If the given TxSequence marks the beginning of the send window, the window will be incremented.
Eric Newberry185ab292017-03-28 06:45:39 +0000156 * If the associated network packet has been fully transmitted, it will be removed.
157 */
158 void
Eric Newberry7b0071e2017-07-03 17:33:31 +0000159 onLpPacketAcknowledged(UnackedFrags::iterator fragIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000160
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400161 /** \brief Delete a fragment from UnackedFrags and advance acknowledge window if necessary.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000162 * \param fragIt iterator to an UnackedFrag, must be dereferencable
163 * \post fragIt is not in m_unackedFrags
164 * \post if was equal to m_firstUnackedFrag,
165 * m_firstUnackedFrag is set to the UnackedFrag after fragIt with consideration of
166 * TxSequence number wraparound, or set to m_unackedFrags.end() if m_unackedFrags is empty
167 */
168 void
169 deleteUnackedFrag(UnackedFrags::iterator fragIt);
Eric Newberry185ab292017-03-28 06:45:39 +0000170
Davide Pesavento264af772021-02-09 21:48:24 -0500171NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400172 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400173 * \brief Contains a sent fragment that has not been acknowledged and associated data.
Eric Newberry185ab292017-03-28 06:45:39 +0000174 */
175 class UnackedFrag
176 {
177 public:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000178 explicit
Davide Pesavento91c15c82024-01-15 17:14:23 -0500179 UnackedFrag(lp::Packet p)
180 : pkt(std::move(p))
181 {
182 }
Eric Newberry185ab292017-03-28 06:45:39 +0000183
184 public:
185 lp::Packet pkt;
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500186 ndn::scheduler::ScopedEventId rtoTimer;
Davide Pesavento91c15c82024-01-15 17:14:23 -0500187 time::steady_clock::time_point sendTime = time::steady_clock::now();
188 size_t retxCount = 0;
189 size_t nGreaterSeqAcks = 0; ///< Number of Acks received for sequences greater than this fragment
Eric Newberry7b0071e2017-07-03 17:33:31 +0000190 shared_ptr<NetPkt> netPkt;
Eric Newberry185ab292017-03-28 06:45:39 +0000191 };
192
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -0400193 /**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400194 * \brief Contains a network-layer packet with unacknowledged fragments.
Eric Newberry185ab292017-03-28 06:45:39 +0000195 */
196 class NetPkt
197 {
198 public:
Davide Pesavento91c15c82024-01-15 17:14:23 -0500199 NetPkt(lp::Packet&& p, bool isInterest)
200 : pkt(std::move(p))
201 , isInterest(isInterest)
202 {
203 }
Eric Newberry41aba102017-11-01 16:42:13 -0700204
205 public:
Eric Newberry7b0071e2017-07-03 17:33:31 +0000206 std::vector<UnackedFrags::iterator> unackedFrags;
Eric Newberry41aba102017-11-01 16:42:13 -0700207 lp::Packet pkt;
208 bool isInterest;
Davide Pesavento91c15c82024-01-15 17:14:23 -0500209 bool didRetx = false;
Eric Newberry185ab292017-03-28 06:45:39 +0000210 };
211
Eric Newberry185ab292017-03-28 06:45:39 +0000212 Options m_options;
Davide Pesavento91c15c82024-01-15 17:14:23 -0500213 GenericLinkService* m_linkService = nullptr;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000214 UnackedFrags m_unackedFrags;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400215 // An iterator that points to the first unacknowledged fragment in the current window. The window
216 // can wrap around so that the beginning of the window is at a TxSequence greater than other
217 // fragments in the window. When the window is moved past the last item in the iterator, the
218 // first fragment in the map will become the start of the window.
Eric Newberry7b0071e2017-07-03 17:33:31 +0000219 UnackedFrags::iterator m_firstUnackedFrag;
Eric Newberry185ab292017-03-28 06:45:39 +0000220 std::queue<lp::Sequence> m_ackQueue;
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400221 std::map<lp::Sequence, time::steady_clock::time_point> m_recentRecvSeqs;
Eric Newberry32f7eac2020-02-07 14:40:17 -0800222 std::queue<lp::Sequence> m_recentRecvSeqsQueue;
Eric Newberry7b0071e2017-07-03 17:33:31 +0000223 lp::Sequence m_lastTxSeqNo;
Davide Pesavento2c9d2ca2024-01-27 16:36:51 -0500224 ndn::scheduler::ScopedEventId m_idleAckTimer;
Davide Pesaventof190cfa2019-07-17 20:14:11 -0400225 ndn::util::RttEstimator m_rttEst;
Eric Newberry185ab292017-03-28 06:45:39 +0000226};
227
Eric Newberry5ab4cf82020-02-03 15:40:16 -0800228std::ostream&
229operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh);
230
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400231} // namespace nfd::face
Eric Newberry185ab292017-03-28 06:45:39 +0000232
233#endif // NFD_DAEMON_FACE_LP_RELIABILITY_HPP