Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE YET] add options for testing retransmission behavior #498

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/quicly.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,21 @@ struct st_quicly_context_t {
* will request the peer to send one ACK every 1/8 RTT (or CWND). 0 disables the use of the delayed-ack extension.
*/
uint16_t ack_frequency;
/**
* destroy the packet being sent at given ratio (xorshift with given seed is used for each connection)
*/
struct {
uint16_t ratio;
uint64_t seed;
} destroy_packet;
/**
* expand client hello so that it does not fit into one datagram
*/
unsigned expand_client_hello : 1;
/**
* intentionally fragment stream payload; this is useful for testing retransmission
*/
unsigned fragment_payload : 1;
/**
*
*/
Expand Down
5 changes: 5 additions & 0 deletions lib/defaults.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define DEFAULT_MAX_CRYPTO_BYTES 65536
#define DEFAULT_INITCWND_PACKETS 10
#define DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT 3
#define DEFAULT_DESTROY_PACKET_SEED 88172645463325252

/* profile that employs IETF specified values */
const quicly_context_t quicly_spec_context = {NULL, /* tls */
Expand All @@ -45,7 +46,9 @@ const quicly_context_t quicly_spec_context = {NULL,
QUICLY_PROTOCOL_VERSION_1,
DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT,
0, /* ack_frequency */
{0, DEFAULT_DESTROY_PACKET_SEED}, /* destroy_packet */
0, /* enlarge_client_hello */
0, /* fragment_payload */
NULL,
NULL, /* on_stream_open */
&quicly_default_stream_scheduler,
Expand Down Expand Up @@ -73,7 +76,9 @@ const quicly_context_t quicly_performant_context = {NULL,
QUICLY_PROTOCOL_VERSION_1,
DEFAULT_PRE_VALIDATION_AMPLIFICATION_LIMIT,
0, /* ack_frequency */
{0, DEFAULT_DESTROY_PACKET_SEED}, /* destroy_packet */
0, /* enlarge_client_hello */
0, /* fragment_payload */
NULL,
NULL, /* on_stream_open */
&quicly_default_stream_scheduler,
Expand Down
32 changes: 32 additions & 0 deletions lib/quicly.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ struct st_quicly_conn_t {
* next PN to be skipped
*/
uint64_t next_pn_to_skip;
/**
* RNG used to determine if packet should be destroyed
*/
uint64_t destroy_packet_rng;
/**
*
*/
Expand Down Expand Up @@ -454,6 +458,12 @@ static const quicly_transport_parameters_t default_transport_params = {.max_udp_
.active_connection_id_limit =
QUICLY_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT};

static void xorshift64(uint64_t *x)
{
*x = *x ^ (*x << 7);
*x = *x ^ (*x >> 9);
}

static const struct st_ptls_salt_t *get_salt(uint32_t protocol_version)
{
static const struct st_ptls_salt_t
Expand Down Expand Up @@ -2115,6 +2125,7 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol
&conn->super.remote.transport_params.max_ack_delay, &conn->super.remote.transport_params.ack_delay_exponent);
conn->egress.next_pn_to_skip =
calc_next_pn_to_skip(conn->super.ctx->tls, 0, initcwnd, conn->super.ctx->initial_egress_max_udp_payload_size);
conn->egress.destroy_packet_rng = conn->super.ctx->destroy_packet.seed;
conn->egress.max_udp_payload_size = conn->super.ctx->initial_egress_max_udp_payload_size;
init_max_streams(&conn->egress.max_streams.uni);
init_max_streams(&conn->egress.max_streams.bidi);
Expand Down Expand Up @@ -3111,6 +3122,13 @@ static int commit_send_packet(quicly_conn_t *conn, quicly_send_context_t *s, int
s->dst_payload_from - s->payload_buf.datagram, conn->egress.packet_number,
coalesced);

/* packet drill: intentionally destroy the packet at given ratio */
if (conn->super.ctx->destroy_packet.ratio > 0) {
xorshift64(&conn->egress.destroy_packet_rng);
if (conn->egress.destroy_packet_rng % 1024 < conn->super.ctx->destroy_packet.ratio)
s->dst[-1] ^= 1;
}

/* update CC, commit sentmap */
if (s->target.ack_eliciting) {
packet_bytes_in_flight = s->dst - s->target.first_byte_at;
Expand Down Expand Up @@ -3665,8 +3683,22 @@ int quicly_send_stream(quicly_stream_t *stream, quicly_send_context_t *s)
}
assert(len != 0);

/* [fragment] trim output to cause fragmentation at the receiver */
if (stream->conn->super.ctx->fragment_payload) {
size_t new_len = len < 4 ? 1 : len / 4;
if (new_len < len)
wrote_all = 0;
len = new_len;
}

adjust_stream_frame_layout(&s->dst, s->dst_end, &len, &wrote_all, &frame_type_at);

/* [fragment] append PADDING to prevent more frames from getting added to the same packet */
if (stream->conn->super.ctx->fragment_payload && s->dst < s->dst_end) {
memset(s->dst, QUICLY_FRAME_TYPE_PADDING, s->dst_end - s->dst);
s->dst = s->dst_end;
}

/* determine if the frame incorporates FIN */
if (off + len == stream->sendstate.final_size) {
assert(!quicly_sendstate_is_open(&stream->sendstate));
Expand Down
16 changes: 15 additions & 1 deletion src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,7 @@ static void usage(const char *cmd)
" -E expand Client Hello (sends multiple client Initials)\n"
" -f fraction increases the induced ack frequency to specified\n"
" fraction of CWND (default: 0)\n"
" -F introduce fragmentation\n"
" -G enable UDP generic segmentation offload\n"
" -i interval interval to reissue requests (in milliseconds)\n"
" -I timeout idle timeout (in milliseconds; default: 600,000)\n"
Expand Down Expand Up @@ -1051,6 +1052,8 @@ static void usage(const char *cmd)
" -x named-group named group to be used (default: secp256r1)\n"
" -X max bidirectional stream count (default: 100)\n"
" -y cipher-suite cipher-suite to be used (default: all)\n"
" -Y ratio destroy the packet being sent at given ratio\n"
" (default: 0)\n"
" -h print this help\n"
"\n",
cmd);
Expand Down Expand Up @@ -1094,7 +1097,7 @@ int main(int argc, char **argv)
address_token_aead.dec = ptls_aead_new(&ptls_openssl_aes128gcm, &ptls_openssl_sha256, 0, secret, "");
}

while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:f:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:y:h")) != -1) {
while ((ch = getopt(argc, argv, "a:b:B:c:C:Dd:k:Ee:Ff:Gi:I:K:l:M:m:NnOp:P:Rr:S:s:u:U:Vvw:W:x:X:Y:y:h")) != -1) {
switch (ch) {
case 'a':
assert(negotiated_protocols.count < PTLS_ELEMENTSOF(negotiated_protocols.list));
Expand Down Expand Up @@ -1156,6 +1159,9 @@ int main(int argc, char **argv)
}
setvbuf(quicly_trace_fp, NULL, _IONBF, 0);
break;
case 'F':
ctx.fragment_payload = 1;
break;
case 'f': {
double fraction;
if (sscanf(optarg, "%lf", &fraction) != 1) {
Expand Down Expand Up @@ -1291,6 +1297,14 @@ int main(int argc, char **argv)
exit(1);
}
break;
case 'Y': {
double ratio;
if (sscanf(optarg, "%lf", &ratio) != 1 || !(0 <= ratio && ratio <= 1)) {
fprintf(stderr, "failed to parse packet destroy ratio (-Y): %s\n", optarg);
exit(1);
}
ctx.destroy_packet.ratio = (uint16_t)(ratio * 1024);
} break;
case 'y': {
size_t i;
for (i = 0; cipher_suites[i] != NULL; ++i)
Expand Down