1 /*
2  * Copyright (c) 2019 Fastly, Janardhan Iyengar
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 
23 /* Interface definition for quicly's congestion controller.
24  */
25 
26 #ifndef quicly_cc_h
27 #define quicly_cc_h
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 #include <assert.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include "quicly/constants.h"
37 #include "quicly/loss.h"
38 
39 #define QUICLY_MIN_CWND 2
40 #define QUICLY_RENO_BETA 0.7
41 
42 /**
43  * Holds pointers to concrete congestion control implementation functions.
44  */
45 typedef const struct st_quicly_cc_type_t quicly_cc_type_t;
46 
47 typedef struct st_quicly_cc_t {
48     /**
49      * Congestion controller type.
50      */
51     quicly_cc_type_t *type;
52     /**
53      * Current congestion window.
54      */
55     uint32_t cwnd;
56     /**
57      * Current slow start threshold.
58      */
59     uint32_t ssthresh;
60     /**
61      * Packet number indicating end of recovery period, if in recovery.
62      */
63     uint64_t recovery_end;
64     /**
65      * State information specific to the congestion controller implementation.
66      */
67     union {
68         /**
69          * State information for Reno congestion control.
70          */
71         struct {
72             /**
73              * Stash of acknowledged bytes, used during congestion avoidance.
74              */
75             uint32_t stash;
76         } reno;
77         /**
78          * State information for Pico.
79          */
80         struct {
81             /**
82              * Stash of acknowledged bytes, used during congestion avoidance.
83              */
84             uint32_t stash;
85             /**
86              * Number of bytes required to be acked in order to increase CWND by 1 MTU.
87              */
88             uint32_t bytes_per_mtu_increase;
89         } pico;
90         /**
91          * State information for CUBIC congestion control.
92          */
93         struct {
94             /**
95              * Time offset from the latest congestion event until cwnd reaches W_max again.
96              */
97             double k;
98             /**
99              * Last cwnd value before the latest congestion event.
100              */
101             uint32_t w_max;
102             /**
103              * W_max value from the previous congestion event.
104              */
105             uint32_t w_last_max;
106             /**
107              * Timestamp of the latest congestion event.
108              */
109             int64_t avoidance_start;
110             /**
111              * Timestamp of the most recent send operation.
112              */
113             int64_t last_sent_time;
114         } cubic;
115     } state;
116     /**
117      * Initial congestion window.
118      */
119     uint32_t cwnd_initial;
120     /**
121      * Congestion window at the end of slow start.
122      */
123     uint32_t cwnd_exiting_slow_start;
124     /**
125      * Minimum congestion window during the connection.
126      */
127     uint32_t cwnd_minimum;
128     /**
129      * Maximum congestion window during the connection.
130      */
131     uint32_t cwnd_maximum;
132     /**
133      * Total number of number of loss episodes (congestion window reductions).
134      */
135     uint32_t num_loss_episodes;
136 } quicly_cc_t;
137 
138 struct st_quicly_cc_type_t {
139     /**
140      * name (e.g., "reno")
141      */
142     const char *name;
143     /**
144      * Corresponding default init_cc.
145      */
146     struct st_quicly_init_cc_t *cc_init;
147     /**
148      * Called when a packet is newly acknowledged.
149      */
150     void (*cc_on_acked)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight,
151                         uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size);
152     /**
153      * Called when a packet is detected as lost. |next_pn| is the next unsent packet number,
154      * used for setting the recovery window.
155      */
156     void (*cc_on_lost)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn, int64_t now,
157                        uint32_t max_udp_payload_size);
158     /**
159      * Called when persistent congestion is observed.
160      */
161     void (*cc_on_persistent_congestion)(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now);
162     /**
163      * Called after a packet is sent.
164      */
165     void (*cc_on_sent)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now);
166     /**
167      * Switches the underlying algorithm of `cc` to that of `cc_switch`, returning a boolean if the operation was successful.
168      */
169     int (*cc_switch)(quicly_cc_t *cc);
170 };
171 
172 /**
173  * The type objects for each CC. These can be used for testing the type of each `quicly_cc_t`.
174  */
175 extern quicly_cc_type_t quicly_cc_type_reno, quicly_cc_type_cubic, quicly_cc_type_pico;
176 /**
177  * The factory methods for each CC.
178  */
179 extern struct st_quicly_init_cc_t quicly_cc_reno_init, quicly_cc_cubic_init, quicly_cc_pico_init;
180 
181 /**
182  * A null-terminated list of all CC types.
183  */
184 extern quicly_cc_type_t *quicly_cc_all_types[];
185 
186 /**
187  * Calculates the initial congestion window size given the maximum UDP payload size.
188  */
189 uint32_t quicly_cc_calc_initial_cwnd(uint32_t max_packets, uint16_t max_udp_payload_size);
190 
191 void quicly_cc_reno_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t lost_pn, uint64_t next_pn,
192                             int64_t now, uint32_t max_udp_payload_size);
193 void quicly_cc_reno_on_persistent_congestion(quicly_cc_t *cc, const quicly_loss_t *loss, int64_t now);
194 void quicly_cc_reno_on_sent(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, int64_t now);
195 
196 #ifdef __cplusplus
197 }
198 #endif
199 
200 #endif
201