Home | History | Annotate | Line # | Download | only in quic-design
      1 QUIC ACK Manager
      2 ================
      3 
      4 ![(Overview block diagram.)](images/ackm.png "QUIC ACK Manager Block Diagram")
      5 
      6 The 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 
     15 On 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 
     22 In 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 
     31 The ACK manager consumes:
     32 
     33   - an arbitrary function which returns the current time;
     34   - a RTT statistics tracker;
     35   - a congestion controller.
     36 
     37 The 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 
     62 In this document, the caller refers to the system which makes use of the ACK
     63 manager.
     64 
     65 Utility Definitions
     66 -------------------
     67 
     68 There are three QUIC packet number spaces: Initial, Handshake and Application
     69 Data.
     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 
     79 Packet 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. */
     84 typedef uint64_t QUIC_PN;
     85 #define QUIC_PN_INFINITE            UINT64_MAX
     86 ```
     87 
     88 Instantiation
     89 -------------
     90 
     91 The QUIC ACK manager is instantiated as follows:
     92 
     93 ```c
     94 typedef struct ossl_ackm_st OSSL_ACKM;
     95 
     96 OSSL_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 
    102 void ossl_ackm_free(OSSL_ACKM *ackm);
    103 ```
    104 
    105 The function pointer `now` is invoked by the ACK manager to obtain the current
    106 time. `now_arg` is passed as the argument. The congestion controller method and
    107 instance passed are used by the ACK manager instance. `statm` points to a
    108 [Statistics Manager tracker instance](quic-statm.md).
    109 
    110 Events
    111 ------
    112 
    113 The ACK manager state is evolved in response to events provided to the ACK
    114 manager by the caller.
    115 
    116 ### On TX Packet
    117 
    118 This must be called when a packet is transmitted. It does not provide the
    119 payload of the packet, but provides metadata about the packet which is relevant
    120 to the loss detection and acknowledgement process.
    121 
    122 The caller is responsible for the allocation of the structure and the structure
    123 must remain allocated until one of the callbacks is called or the ACK manager is
    124 freed. It is expected this structure will usually be freed (or returned to a
    125 pool) in the implementation of either callback passed by the caller.
    126 
    127 Only exactly one of the callbacks in the structure will be called over the
    128 lifetime of a `OSSL_ACKM_TX_PKT`, and only once.
    129 
    130 Returns 1 on success.
    131 
    132 ```c
    133 typedef 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 
    189 int ossl_ackm_on_tx_packet(OSSL_ACKM *ackm, const OSSL_ACKM_TX_PKT *pkt);
    190 ```
    191 
    192 ### On RX Datagram
    193 
    194 This must be called whenever a datagram is received. A datagram may contain
    195 multiple packets, and this function should be called before the calls to
    196 `ossl_ackm_on_rx_packet`.
    197 
    198 The primary use of this function is to inform the ACK manager of new credit to
    199 the anti-amplification budget. Packet and ACK-frame related logic are handled
    200 separately in the subsequent calls to `ossl_ackm_on_rx_packet` and
    201 `ossl_ackm_on_rx_ack_frame`, respectively.
    202 
    203 Returns 1 on success.
    204 
    205 ```c
    206 int ossl_ackm_on_rx_datagram(OSSL_ACKM *ackm, size_t num_bytes);
    207 ```
    208 
    209 ### On RX Packet
    210 
    211 This 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 
    214 Returns 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 
    222 typedef 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 
    245 int ossl_ackm_on_rx_packet(OSSL_ACKM *ackm, const OSSL_ACKM_RX_PKT *pkt);
    246 ```
    247 
    248 ### On RX ACK Frame
    249 
    250 This must be called whenever an ACK frame is received. It should be called
    251 after any call to `ossl_ackm_on_rx_packet`.
    252 
    253 The 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
    255 space of the containing packet. `rx_time` is the time the frame was
    256 received.
    257 
    258 This function causes `on_acked` callbacks to be invoked on applicable packets.
    259 
    260 Returns 1 on success.
    261 
    262 ```c
    263 typedef 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 
    271 typedef 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 
    296 int 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 
    302 This must be called whenever a packet number space is discarded. ACK-tracking
    303 information for the number space is thrown away. Any previously provided
    304 `OSSL_ACKM_TX_PKT` structures have their `on_discarded` callback invoked,
    305 providing an opportunity for them to be freed.
    306 
    307 Returns 1 on success.
    308 
    309 ```c
    310 int ossl_ackm_on_pkt_space_discarded(OSSL_ACKM *ackm, int pkt_space);
    311 ```
    312 
    313 ### On Handshake Confirmed
    314 
    315 This should be called by the caller when the QUIC handshake is confirmed. The
    316 Probe Timeout (PTO) algorithm behaves differently depending on whether the QUIC
    317 handshake is confirmed yet.
    318 
    319 Returns 1 on success.
    320 
    321 ```c
    322 int ossl_ackm_on_handshake_confirmed(OSSL_ACKM *ackm);
    323 ```
    324 
    325 ### On Timeout
    326 
    327 This must be called whenever the loss detection deadline expires.
    328 
    329 ```c
    330 int ossl_ackm_on_timeout(OSSL_ACKM *ackm);
    331 ```
    332 
    333 Queries
    334 -------
    335 
    336 These functions allow information about the status of the ACK manager to be
    337 obtained.
    338 
    339 ### Get Loss Detection Deadline
    340 
    341 This returns a deadline after which `ossl_ackm_on_timeout` should be called.
    342 
    343 If it is `OSSL_TIME_INFINITY`, no timeout is currently active.
    344 
    345 The value returned by this function may change after any call to any of the
    346 event functions above is made.
    347 
    348 ```c
    349 OSSL_TIME ossl_ackm_get_loss_detection_deadline(OSSL_ACKM *ackm);
    350 ```
    351 
    352 ### Get ACK Frame
    353 
    354 This returns a pointer to a `OSSL_ACKM_ACK` structure representing the
    355 information which should be packed into an ACK frame and transmitted.
    356 
    357 This generates an ACK frame regardless of whether the ACK manager thinks one
    358 should currently be sent. To determine if the ACK manager thinks an ACK frame
    359 should be sent, use `ossl_ackm_is_ack_desired`, discussed below.
    360 
    361 If no new ACK frame is currently needed, returns NULL. After calling this
    362 function, calling the function immediately again will return NULL.
    363 
    364 The structure pointed to by the returned pointer, and the referenced ACK range
    365 structures, 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 
    368 This function is used to provide ACK frames for acknowledging packets which have
    369 been received and notified to the ACK manager via `ossl_ackm_on_rx_packet`.
    370 
    371 Calling this function clears the flag returned by `ossl_ackm_is_ack_desired` and
    372 the deadline returned by `ossl_ackm_get_ack_deadline`.
    373 
    374 ```c
    375 const OSSL_ACKM_ACK *ossl_ackm_get_ack_frame(OSSL_ACKM *ackm, int pkt_space);
    376 ```
    377 
    378 ### Is ACK Desired
    379 
    380 This returns 1 if the ACK manager thinks an ACK frame ought to be generated and
    381 sent at this time. `ossl_ackm_get_ack_frame` will always provide an ACK frame
    382 whether or not this returns 1, so it is suggested that you call this function
    383 first to determine whether you need to generate an ACK frame.
    384 
    385 The 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
    390 int ossl_ackm_is_ack_desired(OSSL_ACKM *ackm, int pkt_space);
    391 ```
    392 
    393 ### Get ACK Deadline
    394 
    395 The ACK manager may defer generation of ACK frames to optimize performance. For
    396 example, after a packet requiring acknowledgement is received, it may decide to
    397 wait until a few more packets are received before generating an ACK frame, so
    398 that a single ACK frame can acknowledge all of them. However, if further
    399 packets do not arrive, an ACK frame must be generated anyway within a certain
    400 amount of time.
    401 
    402 This 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
    404 means that no deadline is currently applicable. If the deadline has already
    405 passed, it may either return that deadline or `OSSL_TIME_ZERO`.
    406 
    407 ```c
    408 OSSL_TIME ossl_ackm_get_ack_deadline(OSSL_ACKM *ackm, int pkt_space);
    409 ```
    410 
    411 ### Is RX PN Processable
    412 
    413 Returns 1 if the given RX packet number is processable. A processable PN is
    414 one 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 
    423 This should be called for a packet before attempting to process its contents.
    424 Failure to do so may may result in processing a duplicated packet in violation
    425 of the RFC.
    426 
    427 The returrn value of this function transitions from 1 to 0 for a given PN once
    428 that PN is passed to ossl_ackm_on_rx_packet, thus this function must be used
    429 before calling `ossl_ackm_on_rx_packet`.
    430 
    431 ```c
    432 int ossl_ackm_is_rx_pn_processable(OSSL_ACKM *ackm, QUIC_PN pn, int pkt_space);
    433 ```
    434 
    435 ### Get Probe Packet
    436 
    437 This determines if the ACK manager is requesting any probe packets to be
    438 transmitted.
    439 
    440 The user calls `ossl_ackm_get_probe_request`. The structure pointed
    441 to by `info` is filled and the function returns 1 on success.
    442 
    443 The fields of `OSSL_ACKM_PROBE_INFO` record the number of probe requests
    444 of 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 
    458 Once the caller has processed these requests, the caller must clear these
    459 outstanding requests by calling `ossl_ackm_get_probe_request` with `clear` set
    460 to 1. If `clear` is non-zero, the current values are returned and then zeroed,
    461 so that the next call to `ossl_ackm_get_probe_request` (if made immediately)
    462 will return zero values for all fields.
    463 
    464 ```c
    465 typedef 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 
    471 int 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 
    477 This gets the largest unacknowledged packet number in the given packet number
    478 space. The packet number is written to `*pn`. Returns 1 on success.
    479 
    480 This is needed so that packet encoders can determine with what length to encode
    481 the abridged packet number in the packet header.
    482 
    483 ```c
    484 int ossl_ackm_get_largest_unacked(OSSL_ACKM *ackm, int pkt_space, QUIC_PN *pn);
    485 ```
    486 
    487 Callback Functionality
    488 ----------------------
    489 
    490 The ACK manager supports optional callback functionality when its deadlines
    491 are updated. By default, the callback functionality is not enabled. To use
    492 the callback functionality, call either or both of the following functions
    493 with a non-NULL function pointer:
    494 
    495 ```c
    496 void ossl_ackm_set_loss_detection_deadline_callback(OSSL_ACKM *ackm,
    497                                                     void (*fn)(OSSL_TIME deadline,
    498                                                                void *arg),
    499                                                     void *arg);
    500 
    501 void 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 
    508 Callbacks can be subsequently disabled by calling these functions with a NULL
    509 function pointer. The callbacks are not called at the time that they are set,
    510 therefore it is recommended to call them immediately after the call to
    511 `ossl_ackm_new`.
    512 
    513 The loss detection deadline callback is called whenever the value returned
    514 by `ossl_ackm_get_loss_detection_deadline` changes.
    515 
    516 The ACK deadline callback is called whenever the value returned by
    517 `ossl_ackm_get_ack_deadline` changes for a given packet space.
    518 
    519 The `deadline` argument reflects the value which will be newly returned by the
    520 corresponding function. If the configured callback calls either of these
    521 functions, the returned value will reflect the new deadline.
    522