1 /** @file
2  *
3  *  A brief file description
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #pragma once
25 
26 // TODO Using STL Map because ts/Map lacks remove method
27 #include <map>
28 #include <set>
29 
30 #include "I_EventSystem.h"
31 #include "I_Action.h"
32 #include "tscore/ink_hrtime.h"
33 #include "I_VConnection.h"
34 #include "QUICTypes.h"
35 #include "QUICPacket.h"
36 #include "QUICFrame.h"
37 #include "QUICFrameHandler.h"
38 #include "QUICConnection.h"
39 #include "QUICContext.h"
40 #include "QUICCongestionController.h"
41 
42 class QUICPadder;
43 class QUICPinger;
44 class QUICLossDetector;
45 class QUICRTTMeasure;
46 
47 using QUICPacketInfoUPtr = std::unique_ptr<QUICPacketInfo>;
48 
49 class QUICRTTProvider
50 {
51 public:
52   virtual ink_hrtime smoothed_rtt() const = 0;
53   virtual ink_hrtime rttvar() const       = 0;
54   virtual ink_hrtime latest_rtt() const   = 0;
55 
56   virtual ink_hrtime congestion_period(uint32_t threshold) const = 0;
57 };
58 
59 class QUICNewRenoCongestionController : public QUICCongestionController
60 {
61 public:
62   QUICNewRenoCongestionController(QUICCCContext &context);
~QUICNewRenoCongestionController()63   virtual ~QUICNewRenoCongestionController() {}
64   void on_packet_sent(size_t bytes_sent) override;
65   void on_packet_acked(const QUICPacketInfo &acked_packet) override;
66   virtual void on_packets_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &packets) override;
67   void process_ecn(const QUICPacketInfo &acked_largest_packet, const QUICAckFrame::EcnSection *ecn_section) override;
68   bool check_credit() const;
69   uint32_t credit() const override;
70   void reset() override;
71   bool is_app_limited();
72 
73   // Debug
74   uint32_t bytes_in_flight() const;
75   uint32_t congestion_window() const;
76   uint32_t current_ssthresh() const;
77 
78   void add_extra_credit() override;
79 
80 private:
81   Ptr<ProxyMutex> _cc_mutex;
82 
83   void _congestion_event(ink_hrtime sent_time);
84   bool _in_persistent_congestion(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets,
85                                  QUICPacketInfo *largest_lost_packet);
86   bool _in_window_lost(const std::map<QUICPacketNumber, QUICPacketInfo *> &lost_packets, QUICPacketInfo *largest_lost_packet,
87                        ink_hrtime period) const;
88 
89   uint32_t _extra_packets_count = 0;
90 
91   // [draft-17 recovery] 7.9.1. Constants of interest
92   // Values will be loaded from records.config via QUICConfig at constructor
93   uint32_t _k_max_datagram_size               = 0;
94   uint32_t _k_initial_window                  = 0;
95   uint32_t _k_minimum_window                  = 0;
96   float _k_loss_reduction_factor              = 0.0;
97   uint32_t _k_persistent_congestion_threshold = 3;
98 
99   // [draft-17 recovery] 7.9.2. Variables of interest
100   uint32_t _ecn_ce_counter                   = 0;
101   uint32_t _bytes_in_flight                  = 0;
102   uint32_t _congestion_window                = 0;
103   ink_hrtime _congestion_recovery_start_time = 0;
104   uint32_t _ssthresh                         = UINT32_MAX;
105 
106   bool _in_congestion_recovery(ink_hrtime sent_time);
107 
108   QUICCCContext &_context;
109 };
110 
111 class QUICLossDetector : public Continuation, public QUICFrameHandler
112 {
113 public:
114   QUICLossDetector(QUICLDContext &context, QUICCongestionController *cc, QUICRTTMeasure *rtt_measure, QUICPinger *pinger,
115                    QUICPadder *padder);
116   ~QUICLossDetector();
117 
118   int event_handler(int event, Event *edata);
119 
120   std::vector<QUICFrameType> interests() override;
121   virtual QUICConnectionErrorUPtr handle_frame(QUICEncryptionLevel level, const QUICFrame &frame) override;
122   void on_packet_sent(QUICPacketInfoUPtr packet_info, bool in_flight = true);
123   QUICPacketNumber largest_acked_packet_number(QUICPacketNumberSpace pn_space);
124   void update_ack_delay_exponent(uint8_t ack_delay_exponent);
125   void reset();
126 
127 private:
128   Ptr<ProxyMutex> _loss_detection_mutex;
129 
130   uint8_t _ack_delay_exponent = 3;
131 
132   // [draft-17 recovery] 6.4.1.  Constants of interest
133   // Values will be loaded from records.config via QUICConfig at constructor
134   uint32_t _k_packet_threshold = 0;
135   float _k_time_threshold      = 0.0;
136 
137   // [draft-11 recovery] 3.5.2.  Variables of interest
138   // Keep the order as the same as the spec so that we can see the difference easily.
139   Action *_loss_detection_timer                              = nullptr;
140   ink_hrtime _time_of_last_sent_ack_eliciting_packet         = 0;
141   ink_hrtime _time_of_last_sent_crypto_packet                = 0;
142   ink_hrtime _loss_time[kPacketNumberSpace]                  = {0};
143   QUICPacketNumber _largest_acked_packet[kPacketNumberSpace] = {0};
144   std::map<QUICPacketNumber, QUICPacketInfoUPtr> _sent_packets[kPacketNumberSpace];
145 
146   // These are not defined on the spec but expected to be count
147   // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions.
148   std::atomic<uint32_t> _crypto_outstanding;
149   std::atomic<uint32_t> _ack_eliciting_outstanding;
150   void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr<QUICPacketInfo> packet_info);
151   void _remove_from_sent_packet_list(QUICPacketNumber packet_number, QUICPacketNumberSpace pn_space);
152   std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator _remove_from_sent_packet_list(
153     std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator it, QUICPacketNumberSpace pn_space);
154   void _decrement_outstanding_counters(std::map<QUICPacketNumber, QUICPacketInfoUPtr>::iterator it, QUICPacketNumberSpace pn_space);
155 
156   /*
157    * Because this alarm will be reset on every packet transmission, to reduce number of events,
158    * Loss Detector uses schedule_every() and checks if it has to be triggered.
159    */
160   ink_hrtime _loss_detection_alarm_at = 0;
161 
162   void _on_ack_received(const QUICAckFrame &ack_frame, QUICPacketNumberSpace pn_space);
163   void _on_packet_acked(const QUICPacketInfo &acked_packet);
164   void _detect_lost_packets(QUICPacketNumberSpace pn_space);
165   void _set_loss_detection_timer();
166   void _on_loss_detection_timeout();
167   void _retransmit_lost_packet(QUICPacketInfo &packet_info);
168 
169   ink_hrtime _get_earliest_loss_time(QUICPacketNumberSpace &pn_space);
170 
171   std::vector<QUICPacketInfo *> _determine_newly_acked_packets(const QUICAckFrame &ack_frame, int pn_space);
172   bool _include_ack_eliciting(const std::vector<QUICPacketInfo *> &acked_packets, int index) const;
173 
174   void _retransmit_all_unacked_crypto_data();
175   void _send_one_or_two_packet();
176   void _send_one_handshake_packets();
177   void _send_one_padded_packets();
178 
179   void _send_packet(QUICEncryptionLevel level, bool padded = false);
180 
181   bool _is_client_without_one_rtt_key() const;
182 
183   QUICRTTMeasure *_rtt_measure  = nullptr;
184   QUICPinger *_pinger           = nullptr;
185   QUICPadder *_padder           = nullptr;
186   QUICCongestionController *_cc = nullptr;
187 
188   QUICLDContext &_context;
189 };
190 
191 class QUICRTTMeasure : public QUICRTTProvider
192 {
193 public:
194   // use `friend` so ld can acesss RTTMeasure.
195   // friend QUICLossDetector;
196 
197   QUICRTTMeasure(const QUICLDConfig &ld_config);
198   QUICRTTMeasure() = default;
199 
200   void init(const QUICLDConfig &ld_config);
201 
202   // period
203   ink_hrtime handshake_retransmit_timeout() const;
204   ink_hrtime current_pto_period() const;
205   ink_hrtime congestion_period(uint32_t threshold) const override;
206 
207   // get members
208   ink_hrtime smoothed_rtt() const override;
209   ink_hrtime rttvar() const override;
210   ink_hrtime latest_rtt() const override;
211 
212   uint32_t pto_count() const;
213   uint32_t crypto_count() const;
214 
215   void set_crypto_count(uint32_t count);
216   void set_pto_count(uint32_t count);
217 
218   void update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay);
219   void reset();
220 
221   ink_hrtime k_granularity() const;
222 
223 private:
224   // related to rtt calculate
225   uint32_t _crypto_count = 0;
226   uint32_t _pto_count    = 0;
227   // FIXME should be set by transport parameters
228   ink_hrtime _max_ack_delay = HRTIME_MSECONDS(25);
229 
230   // rtt vars
231   ink_hrtime _latest_rtt   = 0;
232   ink_hrtime _smoothed_rtt = 0;
233   ink_hrtime _rttvar       = 0;
234   ink_hrtime _min_rtt      = INT64_MAX;
235 
236   // config
237   ink_hrtime _k_granularity = 0;
238   ink_hrtime _k_initial_rtt = HRTIME_MSECONDS(500);
239 };
240