2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
11 #include <openssl/ssl.h>
12 #include "internal/quic_ackm.h"
13 #include "internal/quic_cc.h"
15 static OSSL_TIME fake_time
= {0};
17 #define TIME_BASE (ossl_ticks2time(123 * OSSL_TIME_SECOND))
19 static OSSL_TIME
fake_now(void *arg
)
25 OSSL_ACKM_TX_PKT
*pkt
;
26 int lost
, acked
, discarded
;
29 static void on_lost(void *arg
)
31 struct pkt_info
*info
= arg
;
35 static void on_acked(void *arg
)
37 struct pkt_info
*info
= arg
;
41 static void on_discarded(void *arg
)
43 struct pkt_info
*info
= arg
;
49 struct pkt_info
*pkts
;
56 static void helper_destroy(struct helper
*h
)
60 if (h
->ackm
!= NULL
) {
61 ossl_ackm_free(h
->ackm
);
65 if (h
->ccdata
!= NULL
) {
66 ossl_cc_dummy_method
.free(h
->ccdata
);
71 ossl_statm_destroy(&h
->statm
);
75 if (h
->pkts
!= NULL
) {
76 for (i
= 0; i
< h
->num_pkts
; ++i
) {
77 OPENSSL_free(h
->pkts
[i
].pkt
);
78 h
->pkts
[i
].pkt
= NULL
;
81 OPENSSL_free(h
->pkts
);
86 static int helper_init(struct helper
*h
, size_t num_pkts
)
90 memset(h
, 0, sizeof(*h
));
92 fake_time
= TIME_BASE
;
94 /* Initialise statistics tracker. */
95 if (!TEST_int_eq(ossl_statm_init(&h
->statm
), 1))
100 /* Initialise congestion controller. */
101 h
->ccdata
= ossl_cc_dummy_method
.new(fake_now
, NULL
);
102 if (!TEST_ptr(h
->ccdata
))
105 /* Initialise ACK manager. */
106 h
->ackm
= ossl_ackm_new(fake_now
, NULL
, &h
->statm
,
107 &ossl_cc_dummy_method
, h
->ccdata
);
108 if (!TEST_ptr(h
->ackm
))
111 /* Allocate our array of packet information. */
112 h
->num_pkts
= num_pkts
;
114 h
->pkts
= OPENSSL_zalloc(sizeof(struct pkt_info
) * num_pkts
);
115 if (!TEST_ptr(h
->pkts
))
129 static const QUIC_PN linear_20
[] = {
130 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
133 static const QUIC_PN high_linear_20
[] = {
134 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008,
135 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017,
140 * TX ACK (Packet Threshold) Test Cases
141 * ******************************************************************
143 struct tx_ack_test_case
{
144 const QUIC_PN
*pn_table
;
146 const OSSL_QUIC_ACK_RANGE
*ack_ranges
;
147 size_t num_ack_ranges
;
148 const char *expect_ack
; /* 1=ack, 2=lost, 4=discarded */
151 #define DEFINE_TX_ACK_CASE(n, pntable) \
152 static const struct tx_ack_test_case tx_ack_case_##n = { \
153 (pntable), OSSL_NELEM(pntable), \
154 tx_ack_range_##n, OSSL_NELEM(tx_ack_range_##n), \
158 /* One range, partial coverage of space */
159 static const OSSL_QUIC_ACK_RANGE tx_ack_range_1
[] = {
162 static const char tx_ack_expect_1
[] = {
163 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
165 DEFINE_TX_ACK_CASE(1, linear_20
);
167 /* Two ranges, partial coverage of space, overlapping by 1 */
168 static const OSSL_QUIC_ACK_RANGE tx_ack_range_2
[] = {
171 static const char tx_ack_expect_2
[] = {
172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
174 DEFINE_TX_ACK_CASE(2, linear_20
);
176 /* Two ranges, partial coverage of space, together contiguous */
177 static const OSSL_QUIC_ACK_RANGE tx_ack_range_3
[] = {
180 static const char tx_ack_expect_3
[] = {
181 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
183 DEFINE_TX_ACK_CASE(3, linear_20
);
186 * Two ranges, partial coverage of space, non-contiguous by 1
187 * Causes inferred loss due to packet threshold being exceeded.
189 static const OSSL_QUIC_ACK_RANGE tx_ack_range_4
[] = {
192 static const char tx_ack_expect_4
[] = {
193 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
195 DEFINE_TX_ACK_CASE(4, linear_20
);
198 * Two ranges, partial coverage of space, non-contiguous by 2
199 * Causes inferred loss due to packet threshold being exceeded.
201 static const OSSL_QUIC_ACK_RANGE tx_ack_range_5
[] = {
204 static const char tx_ack_expect_5
[] = {
205 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
207 DEFINE_TX_ACK_CASE(5, linear_20
);
209 /* One range, covering entire space */
210 static const OSSL_QUIC_ACK_RANGE tx_ack_range_6
[] = {
213 static const char tx_ack_expect_6
[] = {
214 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
216 DEFINE_TX_ACK_CASE(6, linear_20
);
218 /* One range, covering more space than exists */
219 static const OSSL_QUIC_ACK_RANGE tx_ack_range_7
[] = {
222 static const char tx_ack_expect_7
[] = {
223 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
225 DEFINE_TX_ACK_CASE(7, linear_20
);
227 /* One range, covering nothing (too high) */
228 static const OSSL_QUIC_ACK_RANGE tx_ack_range_8
[] = {
231 static const char tx_ack_expect_8
[] = {
232 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
234 DEFINE_TX_ACK_CASE(8, linear_20
);
236 /* One range, covering nothing (too low) */
237 static const OSSL_QUIC_ACK_RANGE tx_ack_range_9
[] = {
240 static const char tx_ack_expect_9
[] = {
241 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
243 DEFINE_TX_ACK_CASE(9, high_linear_20
);
245 /* One single packet at start of PN set */
246 static const OSSL_QUIC_ACK_RANGE tx_ack_range_10
[] = {
249 static const char tx_ack_expect_10
[] = {
250 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
252 DEFINE_TX_ACK_CASE(10, linear_20
);
255 * One single packet in middle of PN set
256 * Causes inferred loss of one packet due to packet threshold being exceeded,
257 * but several other previous packets survive as they are under the threshold.
259 static const OSSL_QUIC_ACK_RANGE tx_ack_range_11
[] = {
262 static const char tx_ack_expect_11
[] = {
263 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
265 DEFINE_TX_ACK_CASE(11, linear_20
);
268 * One single packet at end of PN set
269 * Causes inferred loss due to packet threshold being exceeded.
271 static const OSSL_QUIC_ACK_RANGE tx_ack_range_12
[] = {
274 static const char tx_ack_expect_12
[] = {
275 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1
277 DEFINE_TX_ACK_CASE(12, linear_20
);
281 * Causes inferred loss due to packet threshold being exceeded.
283 static const OSSL_QUIC_ACK_RANGE tx_ack_range_13
[] = {
284 { 1008, 1008 }, { 1004, 1005 }, { 1001, 1002 }
286 static const char tx_ack_expect_13
[] = {
287 2, 1, 1, 2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
289 DEFINE_TX_ACK_CASE(13, high_linear_20
);
291 static const struct tx_ack_test_case
*const tx_ack_cases
[] = {
308 MODE_ACK
, MODE_DISCARD
, MODE_PTO
, MODE_NUM
311 static int test_probe_counts(const OSSL_ACKM_PROBE_INFO
*p
,
312 uint32_t anti_deadlock_handshake
,
313 uint32_t anti_deadlock_initial
,
314 uint32_t pto_initial
,
315 uint32_t pto_handshake
,
318 if (!TEST_uint_eq(p
->anti_deadlock_handshake
, anti_deadlock_handshake
))
320 if (!TEST_uint_eq(p
->anti_deadlock_initial
, anti_deadlock_initial
))
322 if (!TEST_uint_eq(p
->pto
[QUIC_PN_SPACE_INITIAL
], pto_initial
))
324 if (!TEST_uint_eq(p
->pto
[QUIC_PN_SPACE_HANDSHAKE
], pto_handshake
))
326 if (!TEST_uint_eq(p
->pto
[QUIC_PN_SPACE_APP
], pto_app
))
331 static void on_loss_detection_deadline_callback(OSSL_TIME deadline
, void *arg
)
333 *(OSSL_TIME
*)arg
= deadline
;
336 static int test_tx_ack_case_actual(int tidx
, int space
, int mode
)
341 OSSL_ACKM_TX_PKT
*tx
;
342 const struct tx_ack_test_case
*c
= tx_ack_cases
[tidx
];
343 OSSL_QUIC_FRAME_ACK ack
= {0};
344 OSSL_TIME loss_detection_deadline
= ossl_time_zero();
346 /* Cannot discard app space, so skip this */
347 if (mode
== MODE_DISCARD
&& space
== QUIC_PN_SPACE_APP
) {
348 TEST_skip("skipping test for app space");
352 if (!TEST_int_eq(helper_init(&h
, c
->pn_table_len
), 1))
356 ossl_ackm_set_loss_detection_deadline_callback(h
.ackm
,
357 on_loss_detection_deadline_callback
,
358 &loss_detection_deadline
);
360 /* Allocate TX packet structures. */
361 for (i
= 0; i
< c
->pn_table_len
; ++i
) {
362 h
.pkts
[i
].pkt
= tx
= OPENSSL_zalloc(sizeof(*tx
));
366 tx
->pkt_num
= c
->pn_table
[i
];
367 tx
->pkt_space
= space
;
369 tx
->is_ack_eliciting
= 1;
371 tx
->largest_acked
= QUIC_PN_INVALID
;
372 tx
->on_lost
= on_lost
;
373 tx
->on_acked
= on_acked
;
374 tx
->on_discarded
= on_discarded
;
375 tx
->cb_arg
= &h
.pkts
[i
];
377 tx
->time
= fake_time
;
379 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h
.ackm
, tx
), 1))
383 if (mode
== MODE_DISCARD
) {
384 /* Try discarding. */
385 if (!TEST_int_eq(ossl_ackm_on_pkt_space_discarded(h
.ackm
, space
), 1))
388 /* Check all discard callbacks were called. */
389 for (i
= 0; i
< c
->pn_table_len
; ++i
) {
390 if (!TEST_int_eq(h
.pkts
[i
].acked
, 0))
392 if (!TEST_int_eq(h
.pkts
[i
].lost
, 0))
394 if (!TEST_int_eq(h
.pkts
[i
].discarded
, 1))
397 } else if (mode
== MODE_ACK
) {
398 /* Try acknowledging. */
399 ack
.ack_ranges
= (OSSL_QUIC_ACK_RANGE
*)c
->ack_ranges
;
400 ack
.num_ack_ranges
= c
->num_ack_ranges
;
401 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h
.ackm
, &ack
, space
, fake_time
), 1))
404 /* Check correct ranges were acknowledged. */
405 for (i
= 0; i
< c
->pn_table_len
; ++i
) {
406 if (!TEST_int_eq(h
.pkts
[i
].acked
,
407 (c
->expect_ack
[i
] & 1) != 0 ? 1 : 0))
409 if (!TEST_int_eq(h
.pkts
[i
].lost
,
410 (c
->expect_ack
[i
] & 2) != 0 ? 1 : 0))
412 if (!TEST_int_eq(h
.pkts
[i
].discarded
,
413 (c
->expect_ack
[i
] & 4) != 0 ? 1 : 0))
416 } else if (mode
== MODE_PTO
) {
417 OSSL_TIME deadline
= ossl_ackm_get_loss_detection_deadline(h
.ackm
);
418 OSSL_ACKM_PROBE_INFO probe
;
420 if (!TEST_int_eq(ossl_time_compare(deadline
, loss_detection_deadline
), 0))
423 /* We should have a PTO deadline. */
424 if (!TEST_int_gt(ossl_time_compare(deadline
, fake_time
), 0))
427 /* Should not have any probe requests yet. */
428 probe
= *ossl_ackm_get0_probe_request(h
.ackm
);
429 if (!TEST_int_eq(test_probe_counts(&probe
, 0, 0, 0, 0, 0), 1))
433 * If in app space, confirm handshake, as this is necessary to enable
434 * app space PTO probe requests.
436 if (space
== QUIC_PN_SPACE_APP
)
437 if (!TEST_int_eq(ossl_ackm_on_handshake_confirmed(h
.ackm
), 1))
440 /* Advance to the PTO deadline. */
441 fake_time
= ossl_time_add(deadline
, ossl_ticks2time(1));
443 if (!TEST_int_eq(ossl_ackm_on_timeout(h
.ackm
), 1))
446 /* Should have a probe request. Not cleared by first call. */
447 for (i
= 0; i
< 3; ++i
) {
448 probe
= *ossl_ackm_get0_probe_request(h
.ackm
);
450 memset(ossl_ackm_get0_probe_request(h
.ackm
), 0, sizeof(probe
));
453 if (!TEST_int_eq(test_probe_counts(&probe
, 0, 0, 0, 0, 0), 1))
456 if (!TEST_int_eq(test_probe_counts(&probe
, 0, 0,
457 space
== QUIC_PN_SPACE_INITIAL
,
458 space
== QUIC_PN_SPACE_HANDSHAKE
,
459 space
== QUIC_PN_SPACE_APP
), 1))
474 * TX ACK (Time Threshold) Test
475 * ******************************************************************
479 TX_ACK_TIME_OP_PKT
, /* TX packets */
480 TX_ACK_TIME_OP_ACK
, /* Synthesise incoming ACK of single PN range */
481 TX_ACK_TIME_OP_EXPECT
/* Ack/loss assertion */
484 struct tx_ack_time_op
{
486 uint64_t time_advance
; /* all ops */
487 QUIC_PN pn
; /* PKT, ACK */
488 size_t num_pn
; /* PKT, ACK */
489 const char *expect
; /* 1=ack, 2=lost, 4=discarded */
492 #define TX_OP_PKT(advance, pn, num_pn) \
493 { TX_ACK_TIME_OP_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL },
494 #define TX_OP_ACK(advance, pn, num_pn) \
495 { TX_ACK_TIME_OP_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), NULL },
496 #define TX_OP_EXPECT(expect) \
497 { TX_ACK_TIME_OP_EXPECT, 0, 0, 0, (expect) },
498 #define TX_OP_END { TX_ACK_TIME_OP_END }
500 static const char tx_ack_time_script_1_expect
[] = {
504 static const struct tx_ack_time_op tx_ack_time_script_1
[] = {
506 TX_OP_PKT (3600000, 1, 1)
507 TX_OP_ACK ( 1000, 1, 1)
508 TX_OP_EXPECT(tx_ack_time_script_1_expect
)
512 static const struct tx_ack_time_op
*const tx_ack_time_scripts
[] = {
513 tx_ack_time_script_1
,
516 static int test_tx_ack_time_script(int tidx
)
520 OSSL_ACKM_TX_PKT
*tx
= NULL
;
521 OSSL_QUIC_FRAME_ACK ack
= {0};
522 OSSL_QUIC_ACK_RANGE ack_range
= {0};
523 size_t i
, num_pkts
= 0, pkt_idx
= 0;
524 const struct tx_ack_time_op
*script
= tx_ack_time_scripts
[tidx
], *s
;
526 /* Calculate number of packets. */
527 for (s
= script
; s
->kind
!= TX_ACK_TIME_OP_END
; ++s
)
528 if (s
->kind
== TX_ACK_TIME_OP_PKT
)
529 num_pkts
+= s
->num_pn
;
531 /* Initialise ACK manager and packet structures. */
532 if (!TEST_int_eq(helper_init(&h
, num_pkts
), 1))
535 for (i
= 0; i
< num_pkts
; ++i
) {
536 h
.pkts
[i
].pkt
= tx
= OPENSSL_zalloc(sizeof(*tx
));
542 for (s
= script
; s
->kind
!= TX_ACK_TIME_OP_END
; ++s
)
544 case TX_ACK_TIME_OP_PKT
:
545 for (i
= 0; i
< s
->num_pn
; ++i
) {
546 tx
= h
.pkts
[pkt_idx
+ i
].pkt
;
548 tx
->pkt_num
= s
->pn
+ i
;
549 tx
->pkt_space
= QUIC_PN_SPACE_INITIAL
;
551 tx
->largest_acked
= QUIC_PN_INVALID
;
553 tx
->is_ack_eliciting
= 1;
554 tx
->on_lost
= on_lost
;
555 tx
->on_acked
= on_acked
;
556 tx
->on_discarded
= on_discarded
;
557 tx
->cb_arg
= &h
.pkts
[pkt_idx
+ i
];
559 fake_time
= ossl_time_add(fake_time
,
560 ossl_ticks2time(s
->time_advance
));
561 tx
->time
= fake_time
;
563 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h
.ackm
, tx
), 1))
567 pkt_idx
+= s
->num_pn
;
570 case TX_ACK_TIME_OP_ACK
:
571 ack
.ack_ranges
= &ack_range
;
572 ack
.num_ack_ranges
= 1;
574 ack_range
.start
= s
->pn
;
575 ack_range
.end
= s
->pn
+ s
->num_pn
;
577 fake_time
= ossl_time_add(fake_time
,
578 ossl_ticks2time(s
->time_advance
));
580 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h
.ackm
, &ack
,
581 QUIC_PN_SPACE_INITIAL
,
587 case TX_ACK_TIME_OP_EXPECT
:
588 for (i
= 0; i
< num_pkts
; ++i
) {
589 if (!TEST_int_eq(h
.pkts
[i
].acked
,
590 (s
->expect
[i
] & 1) != 0 ? 1 : 0))
592 if (!TEST_int_eq(h
.pkts
[i
].lost
,
593 (s
->expect
[i
] & 2) != 0 ? 1 : 0))
595 if (!TEST_int_eq(h
.pkts
[i
].discarded
,
596 (s
->expect
[i
] & 4) != 0 ? 1 : 0))
611 * ******************************************************************
615 RX_OPK_PKT
, /* RX packet */
616 RX_OPK_CHECK_UNPROC
, /* check PNs unprocessable */
617 RX_OPK_CHECK_PROC
, /* check PNs processable */
618 RX_OPK_CHECK_STATE
, /* check is_desired/deadline */
619 RX_OPK_CHECK_ACKS
, /* check ACK ranges */
620 RX_OPK_TX
, /* TX packet */
621 RX_OPK_RX_ACK
/* RX ACK frame */
626 uint64_t time_advance
;
628 QUIC_PN pn
; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */
629 size_t num_pn
; /* PKT, CHECK_(UN)PROC, TX, RX_ACK */
631 char expect_desired
; /* CHECK_STATE */
632 char expect_deadline
; /* CHECK_STATE */
634 const OSSL_QUIC_ACK_RANGE
*ack_ranges
; /* CHECK_ACKS */
635 size_t num_ack_ranges
; /* CHECK_ACKS */
637 QUIC_PN largest_acked
; /* TX */
640 #define RX_OP_PKT(advance, pn, num_pn) \
642 RX_OPK_PKT, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
646 #define RX_OP_CHECK_UNPROC(advance, pn, num_pn) \
648 RX_OPK_CHECK_UNPROC, (advance) * OSSL_TIME_MS, (pn), (num_pn),\
652 #define RX_OP_CHECK_PROC(advance, pn, num_pn) \
654 RX_OPK_CHECK_PROC, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
658 #define RX_OP_CHECK_STATE(advance, expect_desired, expect_deadline) \
660 RX_OPK_CHECK_STATE, (advance) * OSSL_TIME_MS, 0, 0, \
661 (expect_desired), (expect_deadline), NULL, 0, 0 \
664 #define RX_OP_CHECK_ACKS(advance, ack_ranges) \
666 RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0, \
667 0, 0, (ack_ranges), OSSL_NELEM(ack_ranges), 0 \
670 #define RX_OP_CHECK_NO_ACKS(advance) \
672 RX_OPK_CHECK_ACKS, (advance) * OSSL_TIME_MS, 0, 0, \
676 #define RX_OP_TX(advance, pn, largest_acked) \
678 RX_OPK_TX, (advance) * OSSL_TIME_MS, (pn), 1, \
679 0, 0, NULL, 0, (largest_acked) \
682 #define RX_OP_RX_ACK(advance, pn, num_pn) \
684 RX_OPK_RX_ACK, (advance) * OSSL_TIME_MS, (pn), (num_pn), \
691 /* RX 1. Simple Test with ACK Desired (Packet Threshold, Exactly) */
692 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_1a
[] = {
696 static const struct rx_test_op rx_script_1
[] = {
697 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
698 RX_OP_CHECK_PROC (0, 0, 3)
700 RX_OP_PKT (0, 0, 2) /* two packets, threshold */
701 RX_OP_CHECK_UNPROC (0, 0, 2)
702 RX_OP_CHECK_PROC (0, 2, 1)
703 RX_OP_CHECK_STATE (0, 1, 0) /* threshold met, immediate */
704 RX_OP_CHECK_ACKS (0, rx_ack_ranges_1a
)
706 /* At this point we would generate e.g. a packet with an ACK. */
707 RX_OP_TX (0, 0, 1) /* ACKs both */
708 RX_OP_CHECK_ACKS (0, rx_ack_ranges_1a
) /* not provably ACKed yet */
709 RX_OP_RX_ACK (0, 0, 1) /* TX'd packet is ACK'd */
711 RX_OP_CHECK_NO_ACKS (0) /* nothing more to ACK */
712 RX_OP_CHECK_UNPROC (0, 0, 2) /* still unprocessable */
713 RX_OP_CHECK_PROC (0, 2, 1) /* still processable */
718 /* RX 2. Simple Test with ACK Not Yet Desired (Packet Threshold) */
719 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2a
[] = {
723 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_2b
[] = {
727 static const struct rx_test_op rx_script_2
[] = {
728 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
729 RX_OP_CHECK_PROC (0, 0, 3)
731 /* First packet always generates an ACK so get it out of the way. */
733 RX_OP_CHECK_UNPROC (0, 0, 1)
734 RX_OP_CHECK_PROC (0, 1, 1)
735 RX_OP_CHECK_STATE (0, 1, 0) /* first packet always causes ACK */
736 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2a
) /* clears packet counter */
737 RX_OP_CHECK_STATE (0, 0, 0) /* desired state should have been cleared */
739 /* Second packet should not cause ACK-desired state */
740 RX_OP_PKT (0, 1, 1) /* just one packet, threshold is 2 */
741 RX_OP_CHECK_UNPROC (0, 0, 2)
742 RX_OP_CHECK_PROC (0, 2, 1)
743 RX_OP_CHECK_STATE (0, 0, 1) /* threshold not yet met, so deadline */
744 /* Don't check ACKs here, as it would reset our threshold counter. */
746 /* Now receive a second packet, triggering the threshold */
747 RX_OP_PKT (0, 2, 1) /* second packet meets threshold */
748 RX_OP_CHECK_UNPROC (0, 0, 3)
749 RX_OP_CHECK_PROC (0, 3, 1)
750 RX_OP_CHECK_STATE (0, 1, 0) /* desired immediately */
751 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2b
)
753 /* At this point we would generate e.g. a packet with an ACK. */
754 RX_OP_TX (0, 0, 2) /* ACKs all */
755 RX_OP_CHECK_ACKS (0, rx_ack_ranges_2b
) /* not provably ACKed yet */
756 RX_OP_RX_ACK (0, 0, 1) /* TX'd packet is ACK'd */
758 RX_OP_CHECK_NO_ACKS (0) /* nothing more to ACK */
759 RX_OP_CHECK_UNPROC (0, 0, 3) /* still unprocessable */
760 RX_OP_CHECK_PROC (0, 3, 1) /* still processable */
765 /* RX 3. Simple Test with ACK Desired (Packet Threshold, Multiple Watermarks) */
766 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3a
[] = {
770 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3b
[] = {
774 static const OSSL_QUIC_ACK_RANGE rx_ack_ranges_3c
[] = {
778 static const struct rx_test_op rx_script_3
[] = {
779 RX_OP_CHECK_STATE (0, 0, 0) /* no threshold yet */
780 RX_OP_CHECK_PROC (0, 0, 11)
782 /* First packet always generates an ACK so get it out of the way. */
784 RX_OP_CHECK_UNPROC (0, 0, 1)
785 RX_OP_CHECK_PROC (0, 1, 1)
786 RX_OP_CHECK_STATE (0, 1, 0) /* first packet always causes ACK */
787 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3a
) /* clears packet counter */
788 RX_OP_CHECK_STATE (0, 0, 0) /* desired state should have been cleared */
790 /* Generate ten packets, exceeding the threshold. */
791 RX_OP_PKT (0, 1, 10) /* ten packets, threshold is 2 */
792 RX_OP_CHECK_UNPROC (0, 0, 11)
793 RX_OP_CHECK_PROC (0, 11, 1)
794 RX_OP_CHECK_STATE (0, 1, 0) /* threshold met, immediate */
795 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3b
)
798 * Test TX'ing a packet which doesn't ACK anything.
800 RX_OP_TX (0, 0, QUIC_PN_INVALID
)
801 RX_OP_RX_ACK (0, 0, 1)
804 * At this point we would generate a packet with an ACK immediately.
805 * TX a packet which when ACKed makes [0,5] provably ACKed.
808 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3b
) /* not provably ACKed yet */
809 RX_OP_RX_ACK (0, 1, 1)
811 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3c
) /* provably ACKed now gone */
812 RX_OP_CHECK_UNPROC (0, 0, 11) /* still unprocessable */
813 RX_OP_CHECK_PROC (0, 11, 1) /* still processable */
816 * Now TX another packet which provably ACKs the rest when ACKed.
819 RX_OP_CHECK_ACKS (0, rx_ack_ranges_3c
) /* not provably ACKed yet */
820 RX_OP_RX_ACK (0, 2, 1)
822 RX_OP_CHECK_NO_ACKS (0) /* provably ACKed now gone */
823 RX_OP_CHECK_UNPROC (0, 0, 11) /* still unprocessable */
824 RX_OP_CHECK_PROC (0, 11, 1) /* still processable */
829 static const struct rx_test_op
*const rx_test_scripts
[] = {
835 static void on_ack_deadline_callback(OSSL_TIME deadline
,
836 int pkt_space
, void *arg
)
838 ((OSSL_TIME
*)arg
)[pkt_space
] = deadline
;
841 static int test_rx_ack_actual(int tidx
, int space
)
845 const struct rx_test_op
*script
= rx_test_scripts
[tidx
], *s
;
846 size_t i
, num_tx
= 0, txi
= 0;
847 const OSSL_QUIC_FRAME_ACK
*ack
;
848 OSSL_QUIC_FRAME_ACK rx_ack
= {0};
849 OSSL_QUIC_ACK_RANGE rx_ack_range
= {0};
850 struct pkt_info
*pkts
= NULL
;
851 OSSL_ACKM_TX_PKT
*txs
= NULL
, *tx
;
852 OSSL_TIME ack_deadline
[QUIC_PN_SPACE_NUM
];
854 for (i
= 0; i
< QUIC_PN_SPACE_NUM
; ++i
)
855 ack_deadline
[i
] = ossl_time_infinite();
857 /* Initialise ACK manager. */
858 if (!TEST_int_eq(helper_init(&h
, 0), 1))
861 /* Arm callback for testing. */
862 ossl_ackm_set_ack_deadline_callback(h
.ackm
, on_ack_deadline_callback
,
866 * Determine how many packets we are TXing, and therefore how many packet
867 * structures we need.
869 for (s
= script
; s
->kind
!= RX_OPK_END
; ++s
)
870 if (s
->kind
== RX_OPK_TX
)
873 /* Allocate packet information structures. */
874 txs
= OPENSSL_zalloc(sizeof(*txs
) * num_tx
);
878 pkts
= OPENSSL_zalloc(sizeof(*pkts
) * num_tx
);
883 for (s
= script
; s
->kind
!= RX_OPK_END
; ++s
) {
884 fake_time
= ossl_time_add(fake_time
,
885 ossl_ticks2time(s
->time_advance
));
888 for (i
= 0; i
< s
->num_pn
; ++i
) {
889 OSSL_ACKM_RX_PKT pkt
= {0};
891 pkt
.pkt_num
= s
->pn
+ i
;
892 pkt
.time
= fake_time
;
893 pkt
.pkt_space
= space
;
894 pkt
.is_ack_eliciting
= 1;
896 /* The packet should be processable before we feed it. */
897 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h
.ackm
,
902 if (!TEST_int_eq(ossl_ackm_on_rx_packet(h
.ackm
, &pkt
), 1))
908 case RX_OPK_CHECK_UNPROC
:
909 case RX_OPK_CHECK_PROC
:
910 for (i
= 0; i
< s
->num_pn
; ++i
)
911 if (!TEST_int_eq(ossl_ackm_is_rx_pn_processable(h
.ackm
,
913 (s
->kind
== RX_OPK_CHECK_PROC
)))
918 case RX_OPK_CHECK_STATE
:
919 if (!TEST_int_eq(ossl_ackm_is_ack_desired(h
.ackm
, space
),
923 if (!TEST_int_eq(!ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h
.ackm
, space
))
924 && !ossl_time_is_zero(ossl_ackm_get_ack_deadline(h
.ackm
, space
)),
928 for (i
= 0; i
< QUIC_PN_SPACE_NUM
; ++i
) {
929 if (i
!= (size_t)space
930 && !TEST_true(ossl_time_is_infinite(ossl_ackm_get_ack_deadline(h
.ackm
, i
))))
933 if (!TEST_int_eq(ossl_time_compare(ossl_ackm_get_ack_deadline(h
.ackm
, i
),
934 ack_deadline
[i
]), 0))
940 case RX_OPK_CHECK_ACKS
:
941 ack
= ossl_ackm_get_ack_frame(h
.ackm
, space
);
943 /* Should always be able to get an ACK frame. */
947 if (!TEST_size_t_eq(ack
->num_ack_ranges
, s
->num_ack_ranges
))
950 for (i
= 0; i
< ack
->num_ack_ranges
; ++i
) {
951 if (!TEST_uint64_t_eq(ack
->ack_ranges
[i
].start
,
952 s
->ack_ranges
[i
].start
))
954 if (!TEST_uint64_t_eq(ack
->ack_ranges
[i
].end
,
955 s
->ack_ranges
[i
].end
))
962 pkts
[txi
].pkt
= tx
= &txs
[txi
];
965 tx
->pkt_space
= space
;
967 tx
->largest_acked
= s
->largest_acked
;
969 tx
->is_ack_eliciting
= 1;
970 tx
->on_lost
= on_lost
;
971 tx
->on_acked
= on_acked
;
972 tx
->on_discarded
= on_discarded
;
973 tx
->cb_arg
= &pkts
[txi
];
974 tx
->time
= fake_time
;
976 if (!TEST_int_eq(ossl_ackm_on_tx_packet(h
.ackm
, tx
), 1))
983 rx_ack
.ack_ranges
= &rx_ack_range
;
984 rx_ack
.num_ack_ranges
= 1;
986 rx_ack_range
.start
= s
->pn
;
987 rx_ack_range
.end
= s
->pn
+ s
->num_pn
- 1;
989 if (!TEST_int_eq(ossl_ackm_on_rx_ack_frame(h
.ackm
, &rx_ack
,
990 space
, fake_time
), 1))
1010 * ******************************************************************
1012 static int test_tx_ack_case(int idx
)
1016 tidx
= idx
% OSSL_NELEM(tx_ack_cases
);
1017 idx
/= OSSL_NELEM(tx_ack_cases
);
1019 space
= idx
% QUIC_PN_SPACE_NUM
;
1020 idx
/= QUIC_PN_SPACE_NUM
;
1022 return test_tx_ack_case_actual(tidx
, space
, idx
);
1025 static int test_rx_ack(int idx
)
1029 tidx
= idx
% OSSL_NELEM(rx_test_scripts
);
1030 idx
/= OSSL_NELEM(rx_test_scripts
);
1032 return test_rx_ack_actual(tidx
, idx
);
1035 int setup_tests(void)
1037 ADD_ALL_TESTS(test_tx_ack_case
,
1038 OSSL_NELEM(tx_ack_cases
) * MODE_NUM
* QUIC_PN_SPACE_NUM
);
1039 ADD_ALL_TESTS(test_tx_ack_time_script
, OSSL_NELEM(tx_ack_time_scripts
));
1040 ADD_ALL_TESTS(test_rx_ack
, OSSL_NELEM(rx_test_scripts
) * QUIC_PN_SPACE_NUM
);