1QUIC ACK Manager
2================
3
4![(Overview block diagram.)](images/ackm.png "QUIC ACK Manager Block Diagram")
5
6The QUIC ACK manager is responsible for, on the TX side:
7
8  - Handling received ACK frames
9  - Generating notifications that a packet we sent was delivered successfully
10  - Generating notifications that a packet we sent was lost
11  - Generating requests for probe transmission
12  - Providing information on the largest unacked packet number so that packet
13    numbers in packet headers can be encoded and decoded correctly
14
15On the RX side, it is responsible for:
16
17  - Generating ACK frames for later transmission in response to packets we
18    received
19  - Providing information on whether a given RX packet number is potentially
20    duplicate and should not be processed
21
22In order to allow it to perform these tasks, the ACK manager must:
23
24  - be notified of all transmitted packets
25  - be notified of all received datagrams
26  - be notified of all received packets
27  - be notified of all received ACK frames
28  - be notified when a packet number space is discarded
29  - be notified when its loss detection deadline arrives
30
31The ACK manager consumes:
32
33  - an arbitrary function which returns the current time;
34  - a RTT statistics tracker;
35  - a congestion controller.
36
37The ACK manager provides the following outputs:
38
39  - It indicates the current deadline by which the loss detection
40    event should be invoked.
41
42  - It indicates when probes should be generated.
43
44  - It indicates what ACK frames should be generated.
45
46  - It indicates the current deadline by which new ACK frames
47    will be generated, if any.
48
49  - It indicates the largest unacknowledged packet number
50    for a given packet number space.
51
52  - It calls a callback for each transmitted packet it is notified
53    of, specifying whether the packet was successfully acknowledged by the peer,
54    lost or discarded.
55
56  - It may communicate with a congestion controller, causing the
57    congestion controller to update its state.
58
59  - It may communicate with a RTT statistics tracker, causing it
60    to update its state.
61
62In this document, “the caller” refers to the system which makes use of the ACK
63manager.
64
65Utility Definitions
66-------------------
67
68There are three QUIC packet number spaces: Initial, Handshake and Application
69Data.
70
71```c
72/* QUIC packet number spaces. */
73#define QUIC_PN_SPACE_INITIAL       0
74#define QUIC_PN_SPACE_HANDSHAKE     1
75#define QUIC_PN_SPACE_APP           2
76#define QUIC_PN_SPACE_NUM           3
77```
78
79Packet numbers are 62-bit values represented herein by `QUIC_PN`.
80`QUIC_PN_INFINITE` evaluates to an invalid QUIC packet number value.
81
82```c
83/* QUIC packet number representation. */
84typedef uint64_t QUIC_PN;
85#define QUIC_PN_INFINITE            UINT64_MAX
86```
87
88Instantiation
89-------------
90
91The QUIC ACK manager is instantiated as follows:
92
93```c
94typedef struct ossl_ackm_st OSSL_ACKM;
95
96OSSL_ACKM *ossl_ackm_new(OSSL_TIME (*now)(void *arg),
97                         void *now_arg,
98                         QUIC_STATM *statm,
99                         OSSL_CC_METHOD *cc_method,
100                         OSSL_CC_DATA *cc_data);
101
102void ossl_ackm_free(OSSL_ACKM *ackm);
103```
104
105The function pointer `now` is invoked by the ACK manager to obtain the current
106time. `now_arg` is passed as the argument. The congestion controller method and
107instance passed are used by the ACK manager instance. `statm` points to a
108[Statistics Manager tracker instance](quic-statm.md).
109
110Events
111------
112
113The ACK manager state is evolved in response to events provided to the ACK
114manager by the caller.
115
116### On TX Packet
117
118This must be called when a packet is transmitted. It does not provide the
119payload of the packet, but provides metadata about the packet which is relevant
120to the loss detection and acknowledgement process.
121
122The caller is responsible for the allocation of the structure and the structure
123must remain allocated until one of the callbacks is called or the ACK manager is
124freed. It is expected this structure will usually be freed (or returned to a
125pool) in the implementation of either callback passed by the caller.
126
127Only exactly one of the callbacks in the structure will be called over the
128lifetime of a `OSSL_ACKM_TX_PKT`, and only once.
129
130Returns 1 on success.
131
132```c
133typedef struct ossl_ackm_tx_pkt_st {
134    /* The packet number of the transmitted packet. */
135    QUIC_PN pkt_num;
136
137    /* The number of bytes in the packet which was sent. */
138    size_t num_bytes;
139
140    /* The time at which the packet was sent. */
141    OSSL_TIME time;
142
143    /*
144     * If the packet being described by this structure contains an ACK frame,
145     * this must be set to the largest PN ACK'd by that frame.
146     *
147     * Otherwise, it should be set to QUIC_PN_INVALID.
148     *
149     * This is necessary to bound the number of PNs we have to keep track of on
150     * the RX side (RFC 9000 s. 13.2.4). It allows older PN tracking information
151     * on the RX side to be discarded.
152     */
153    QUIC_PN largest_acked;
154
155    /*
156     * One of the QUIC_PN_SPACE_* values. This qualifies the pkt_num field
157     * into a packet number space.
158     */
159    unsigned int pkt_space :2;
160
161    /* 1 if the packet is in flight. */
162    unsigned int is_inflight :1;
163
164    /* 1 if the packet has one or more ACK-eliciting frames. */
165    unsigned int is_ack_eliciting :1;
166
167    /* 1 if the packet is a PTO probe. */
168    unsigned int is_pto_probe :1;
169
170    /* 1 if the packet is an MTU probe. */
171    unsigned int is_mtu_probe :1;
172
173    /* Callback called if frames in this packet are lost. arg is cb_arg. */
174    void (*on_lost)(void *arg);
175
176    /* Callback called if frames in this packet are acked. arg is cb_arg. */
177    void (*on_acked)(void *arg);
178
179    /*
180     * Callback called if frames in this packet are neither acked nor lost. arg
181     * is cb_arg.
182     */
183    void (*on_discarded)(void *arg);
184    void  *cb_arg;
185
186    /* (Internal use fields are appended here and must be zero-initialized.) */
187} OSSL_ACKM_TX_PKT;
188
189int ossl_ackm_on_tx_packet(OSSL_ACKM *ackm, const OSSL_ACKM_TX_PKT *pkt);
190```
191
192### On RX Datagram
193
194This must be called whenever a datagram is received. A datagram may contain
195multiple packets, and this function should be called before the calls to
196`ossl_ackm_on_rx_packet`.
197
198The primary use of this function is to inform the ACK manager of new credit to
199the anti-amplification budget. Packet and ACK-frame related logic are handled
200separately in the subsequent calls to `ossl_ackm_on_rx_packet` and
201`ossl_ackm_on_rx_ack_frame`, respectively.
202
203Returns 1 on success.
204
205```c
206int ossl_ackm_on_rx_datagram(OSSL_ACKM *ackm, size_t num_bytes);
207```
208
209### On RX Packet
210
211This must be called whenever a packet is received. It should be called after
212`ossl_ackm_on_rx_datagram` was called for the datagram containing the packet.
213
214Returns 1 on success.
215
216```c
217#define OSSL_ACKM_ECN_NONE      0
218#define OSSL_ACKM_ECN_ECT1      1
219#define OSSL_ACKM_ECN_ECT0      2
220#define OSSL_ACKM_ECN_ECNCE     3
221
222typedef struct ossl_ackm_rx_pkt_st {
223    /* The packet number of the received packet. */
224    QUIC_PN pkt_num;
225
226    /* The time at which the packet was received. */
227    OSSL_TIME time;
228
229    /*
230     * One of the QUIC_PN_SPACE_* values. This qualifies the pkt_num field
231     * into a packet number space.
232     */
233    unsigned int pkt_space :2;
234
235    /* 1 if the packet has one or more ACK-eliciting frames. */
236    unsigned int is_ack_eliciting :1;
237
238    /*
239     * One of the OSSL_ACKM_ECN_* values. This is the ECN labelling applied
240     * to the received packet. If unknown, use OSSL_ACKM_ECN_NONE.
241     */
242    unsigned int ecn :2;
243} OSSL_ACKM_RX_PKT;
244
245int ossl_ackm_on_rx_packet(OSSL_ACKM *ackm, const OSSL_ACKM_RX_PKT *pkt);
246```
247
248### On RX ACK Frame
249
250This must be called whenever an ACK frame is received. It should be called
251after any call to `ossl_ackm_on_rx_packet`.
252
253The ranges of packet numbers being acknowledged are passed as an argument.
254`pkt_space` is one of the `QUIC_PN_SPACE_*` values, specifying the packet number
255space of the containing packet. `rx_time` is the time the frame was
256received.
257
258This function causes `on_acked` callbacks to be invoked on applicable packets.
259
260Returns 1 on success.
261
262```c
263typedef struct ossl_ackm_ack_range_st {
264    /*
265     * Represents an inclusive range of packet numbers [start, end].
266     * start must be <= end.
267     */
268    QUIC_PN start, end;
269} OSSL_ACKM_ACK_RANGE;
270
271typedef struct ossl_ackm_ack {
272    /*
273     * A sequence of packet number ranges [[start, end]...].
274     *
275     * The ranges must be sorted in descending order, for example:
276     *      [ 95, 100]
277     *      [ 90,  92]
278     *      etc.
279     *
280     * As such, ack_ranges[0].end is always the highest packet number
281     * being acknowledged and ack_ranges[num_ack_ranges-1].start is
282     * always the lowest packet number being acknowledged.
283     *
284     * num_ack_ranges must be greater than zero, as an ACK frame must
285     * acknowledge at least one packet number.
286     */
287    const OSSL_ACKM_ACK_RANGE  *ack_ranges;
288    size_t                      num_ack_ranges;
289
290    OSSL_TIME                   delay_time;
291    uint64_t                    ect0, ect1, ecnce;
292    /* 1 if the ect0, ect1 and ecnce fields are valid */
293    char                        ecn_present;
294} OSSL_ACKM_ACK;
295
296int ossl_ackm_on_rx_ack_frame(OSSL_ACKM *ackm, const OSSL_ACKM_ACK *ack,
297                              int pkt_space, OSSL_TIME rx_time);
298```
299
300### On Packet Space Discarded
301
302This must be called whenever a packet number space is discarded. ACK-tracking
303information for the number space is thrown away. Any previously provided
304`OSSL_ACKM_TX_PKT` structures have their `on_discarded` callback invoked,
305providing an opportunity for them to be freed.
306
307Returns 1 on success.
308
309```c
310int ossl_ackm_on_pkt_space_discarded(OSSL_ACKM *ackm, int pkt_space);
311```
312
313### On Handshake Confirmed
314
315This should be called by the caller when the QUIC handshake is confirmed. The
316Probe Timeout (PTO) algorithm behaves differently depending on whether the QUIC
317handshake is confirmed yet.
318
319Returns 1 on success.
320
321```c
322int ossl_ackm_on_handshake_confirmed(OSSL_ACKM *ackm);
323```
324
325### On Timeout
326
327This must be called whenever the loss detection deadline expires.
328
329```c
330int ossl_ackm_on_timeout(OSSL_ACKM *ackm);
331```
332
333Queries
334-------
335
336These functions allow information about the status of the ACK manager to be
337obtained.
338
339### Get Loss Detection Deadline
340
341This returns a deadline after which `ossl_ackm_on_timeout` should be called.
342
343If it is `OSSL_TIME_INFINITY`, no timeout is currently active.
344
345The value returned by this function may change after any call to any of the
346event functions above is made.
347
348```c
349OSSL_TIME ossl_ackm_get_loss_detection_deadline(OSSL_ACKM *ackm);
350```
351
352### Get ACK Frame
353
354This returns a pointer to a `OSSL_ACKM_ACK` structure representing the
355information which should be packed into an ACK frame and transmitted.
356
357This generates an ACK frame regardless of whether the ACK manager thinks one
358should currently be sent. To determine if the ACK manager thinks an ACK frame
359should be sent, use `ossl_ackm_is_ack_desired`, discussed below.
360
361If no new ACK frame is currently needed, returns NULL. After calling this
362function, calling the function immediately again will return NULL.
363
364The structure pointed to by the returned pointer, and the referenced ACK range
365structures, are guaranteed to remain valid until the next call to any
366`OSSL_ACKM` function. After such a call is made, all fields become undefined.
367
368This function is used to provide ACK frames for acknowledging packets which have
369been received and notified to the ACK manager via `ossl_ackm_on_rx_packet`.
370
371Calling this function clears the flag returned by `ossl_ackm_is_ack_desired` and
372the deadline returned by `ossl_ackm_get_ack_deadline`.
373
374```c
375const OSSL_ACKM_ACK *ossl_ackm_get_ack_frame(OSSL_ACKM *ackm, int pkt_space);
376```
377
378### Is ACK Desired
379
380This returns 1 if the ACK manager thinks an ACK frame ought to be generated and
381sent at this time. `ossl_ackm_get_ack_frame` will always provide an ACK frame
382whether or not this returns 1, so it is suggested that you call this function
383first to determine whether you need to generate an ACK frame.
384
385The return value of this function can change based on calls to
386`ossl_ackm_on_rx_packet` and based on the passage of time (see
387`ossl_ackm_get_ack_deadline`).
388
389```c
390int ossl_ackm_is_ack_desired(OSSL_ACKM *ackm, int pkt_space);
391```
392
393### Get ACK Deadline
394
395The ACK manager may defer generation of ACK frames to optimize performance. For
396example, after a packet requiring acknowledgement is received, it may decide to
397wait until a few more packets are received before generating an ACK frame, so
398that a single ACK frame can acknowledge all of them. However, if further
399packets do not arrive, an ACK frame must be generated anyway within a certain
400amount of time.
401
402This function returns the deadline at which the return value of
403`ossl_ackm_is_ack_desired` will change to 1, or `OSSL_TIME_INFINITY`, which
404means that no deadline is currently applicable. If the deadline has already
405passed, it may either return that deadline or `OSSL_TIME_ZERO`.
406
407```c
408OSSL_TIME ossl_ackm_get_ack_deadline(OSSL_ACKM *ackm, int pkt_space);
409```
410
411### Is RX PN Processable
412
413Returns 1 if the given RX packet number is “processable”. A processable PN is
414one that is not either
415
416  - duplicate, meaning that we have already been passed such a PN in a call
417    to `ossl_ackm_on_rx_packet`; or
418
419  - written off, meaning that the PN is so old that we have stopped tracking
420    state for it (meaning we cannot tell whether it is a duplicate and cannot
421    process it safely).
422
423This should be called for a packet before attempting to process its contents.
424Failure to do so may may result in processing a duplicated packet in violation
425of the RFC.
426
427The returrn value of this function transitions from 1 to 0 for a given PN once
428that PN is passed to ossl_ackm_on_rx_packet, thus this functiion must be used
429before calling `ossl_ackm_on_rx_packet`.
430
431```c
432int ossl_ackm_is_rx_pn_processable(OSSL_ACKM *ackm, QUIC_PN pn, int pkt_space);
433```
434
435### Get Probe Packet
436
437This determines if the ACK manager is requesting any probe packets to be
438transmitted.
439
440The user calls `ossl_ackm_get_probe_request`. The structure pointed
441to by `info` is filled and the function returns 1 on success.
442
443The fields of `OSSL_ACKM_PROBE_INFO` record the number of probe requests
444of each type which are outstanding. In short:
445
446  - `handshake` designates the number of ACK-eliciting Handshake
447    packets being requested. This is equivalent to
448    `SendOneAckElicitingHandshakePacket()` in RFC 9002.
449
450  - `padded_initial` designates the number of ACK-eliciting
451    padded Initial packets being requested. This is equivalent to
452    `SendOneAckElicitingPaddedInitialPacket()` in RFC 9002.
453
454  - `pto` designates the number of ACK-eliciting outstanding probe events
455    corresponding to each packet number space. This is equivalent to
456    `SendOneOrTwoAckElicitingPackets(pn_space)` in RFC 9002.
457
458Once the caller has processed these requests, the caller must clear these
459outstanding requests by calling `ossl_ackm_get_probe_request` with `clear` set
460to 1. If `clear` is non-zero, the current values are returned and then zeroed,
461so that the next call to `ossl_ackm_get_probe_request` (if made immediately)
462will return zero values for all fields.
463
464```c
465typedef struct ossl_ackm_probe_info_st {
466    uint32_t handshake;
467    uint32_t padded_initial;
468    uint32_t pto[QUIC_PN_SPACE_NUM];
469} OSSL_ACKM_PROBE_INFO;
470
471int ossl_ackm_get_probe_request(OSSL_ACKM *ackm, int clear,
472                                OSSL_ACKM_PROBE_INFO *info);
473```
474
475### Get Largest Unacked Packet Number
476
477This gets the largest unacknowledged packet number in the given packet number
478space. The packet number is written to `*pn`. Returns 1 on success.
479
480This is needed so that packet encoders can determine with what length to encode
481the abridged packet number in the packet header.
482
483```c
484int ossl_ackm_get_largest_unacked(OSSL_ACKM *ackm, int pkt_space, QUIC_PN *pn);
485```
486
487Callback Functionality
488----------------------
489
490The ACK manager supports optional callback functionality when its deadlines
491are updated. By default, the callback functionality is not enabled. To use
492the callback functionality, call either or both of the following functions
493with a non-NULL function pointer:
494
495```c
496void ossl_ackm_set_loss_detection_deadline_callback(OSSL_ACKM *ackm,
497                                                    void (*fn)(OSSL_TIME deadline,
498                                                               void *arg),
499                                                    void *arg);
500
501void ossl_ackm_set_ack_deadline_callback(OSSL_ACKM *ackm,
502                                         void (*fn)(OSSL_TIME deadline,
503                                                    int pkt_space,
504                                                    void *arg),
505                                         void *arg);
506```
507
508Callbacks can be subsequently disabled by calling these functions with a NULL
509function pointer. The callbacks are not called at the time that they are set,
510therefore it is recommended to call them immediately after the call to
511`ossl_ackm_new`.
512
513The loss detection deadline callback is called whenever the value returned
514by `ossl_ackm_get_loss_detection_deadline` changes.
515
516The ACK deadline callback is called whenever the value returned by
517`ossl_ackm_get_ack_deadline` changes for a given packet space.
518
519The `deadline` argument reflects the value which will be newly returned by the
520corresponding function. If the configured callback calls either of these
521functions, the returned value will reflect the new deadline.
522