diff --git a/CHANGELOG b/CHANGELOG index f583389a8..831c49697 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +2020-12-09 + - 2.26.0 + - [OPTIMIZATION] Adjust packet reordering threshold when spurious losses + are detected. + - [API] Pass pointer to local sockaddr to ea_get_ssl_ctx() callback. + 2020-12-04 - 2.25.0 - [API, FEATURE] Add es_delay_onclose option to delay on_close until all diff --git a/bin/prog.c b/bin/prog.c index af662941a..c197fd6af 100644 --- a/bin/prog.c +++ b/bin/prog.c @@ -39,7 +39,7 @@ static int prog_stopped; -static SSL_CTX * get_ssl_ctx (void *); +static SSL_CTX * get_ssl_ctx (void *, const struct sockaddr *); static const struct lsquic_packout_mem_if pmi = { .pmi_allocate = pba_allocate, @@ -417,7 +417,7 @@ prog_init_client (struct prog *prog) static SSL_CTX * -get_ssl_ctx (void *peer_ctx) +get_ssl_ctx (void *peer_ctx, const struct sockaddr *unused) { const struct service_port *const sport = peer_ctx; return sport->sp_prog->prog_ssl_ctx; diff --git a/docs/apiref.rst b/docs/apiref.rst index 1c55db6d2..f9330f76b 100644 --- a/docs/apiref.rst +++ b/docs/apiref.rst @@ -257,10 +257,10 @@ optional members. Look up certificate. Mandatory in server mode. - .. member:: struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx) + .. member:: struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx, const struct sockaddr *local) Get SSL_CTX associated with a peer context. Mandatory in server - mode. This is use for default values for SSL instantiation. + mode. This is used for default values for SSL instantiation. .. member:: const struct lsquic_hset_if *ea_hsi_if .. member:: void *ea_hsi_ctx diff --git a/docs/conf.py b/docs/conf.py index f142c15d8..9d37bd03b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -24,9 +24,9 @@ author = u'LiteSpeed Technologies' # The short X.Y version -version = u'2.25' +version = u'2.26' # The full version, including alpha/beta/rc tags -release = u'2.25.0' +release = u'2.26.0' # -- General configuration --------------------------------------------------- diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 08b508030..296cc9afb 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -863,7 +863,8 @@ The server requires SSL callbacks to be present. The basic required callback is struct lsquic_engine_api { lsquic_lookup_cert_f ea_lookup_cert; void *ea_cert_lu_ctx; - struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx); + struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx, + const struct sockaddr *local); /* (Other members of the struct are not shown) */ }; diff --git a/include/lsquic.h b/include/lsquic.h index 75bcdbda0..1612d45d5 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -24,7 +24,7 @@ extern "C" { #endif #define LSQUIC_MAJOR_VERSION 2 -#define LSQUIC_MINOR_VERSION 25 +#define LSQUIC_MINOR_VERSION 26 #define LSQUIC_PATCH_VERSION 0 /** @@ -1274,7 +1274,8 @@ struct lsquic_engine_api lsquic_lookup_cert_f ea_lookup_cert; void *ea_cert_lu_ctx; /** Mandatory callback for server, optional for client. */ - struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx); + struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx, + const struct sockaddr *local); /** * Shared hash interface is optional. If set to zero, performance of * multiple LSQUIC instances will be degraded. diff --git a/src/liblsquic/lsquic_enc_sess_ietf.c b/src/liblsquic/lsquic_enc_sess_ietf.c index 354bf6da9..71ca6f21f 100644 --- a/src/liblsquic/lsquic_enc_sess_ietf.c +++ b/src/liblsquic/lsquic_enc_sess_ietf.c @@ -888,11 +888,20 @@ iquic_esfi_create_client (const char *hostname, enc_sess->esi_alpn = am->alpn; } - if (enc_sess->esi_enpub->enp_get_ssl_ctx - && (ssl_ctx = enc_sess->esi_enpub->enp_get_ssl_ctx(peer_ctx))) - set_app_ctx = 1; + if (enc_sess->esi_enpub->enp_get_ssl_ctx) + { + struct network_path *const path = + enc_sess->esi_conn->cn_if->ci_get_path(enc_sess->esi_conn, NULL); + ssl_ctx = enc_sess->esi_enpub->enp_get_ssl_ctx(peer_ctx, + NP_LOCAL_SA(path)); + if (ssl_ctx) + set_app_ctx = 1; + else + goto create_new_ssl_ctx; + } else { + create_new_ssl_ctx: LSQ_DEBUG("Create new SSL_CTX"); ssl_ctx = SSL_CTX_new(TLS_method()); if (!ssl_ctx) @@ -1363,6 +1372,7 @@ static int iquic_esfi_init_server (enc_session_t *enc_session_p) { struct enc_sess_iquic *const enc_sess = enc_session_p; + struct network_path *path; const struct alpn_map *am; unsigned quic_ctx_idx; int transpa_len; @@ -1390,8 +1400,9 @@ iquic_esfi_init_server (enc_session_t *enc_session_p) ok: enc_sess->esi_alpn = am->alpn; } - ssl_ctx = enc_sess->esi_enpub->enp_get_ssl_ctx( - lsquic_conn_get_peer_ctx(enc_sess->esi_conn, NULL)); + path = enc_sess->esi_conn->cn_if->ci_get_path(enc_sess->esi_conn, NULL); + ssl_ctx = enc_sess->esi_enpub->enp_get_ssl_ctx(path->np_peer_ctx, + NP_LOCAL_SA(path)); if (!ssl_ctx) { LSQ_ERROR("fetching SSL context associated with peer context failed"); diff --git a/src/liblsquic/lsquic_engine_public.h b/src/liblsquic/lsquic_engine_public.h index 179ca1b1a..4a2f79852 100644 --- a/src/liblsquic/lsquic_engine_public.h +++ b/src/liblsquic/lsquic_engine_public.h @@ -20,6 +20,7 @@ struct ssl_ctx_st; struct crand; struct evp_aead_ctx_st; struct lsquic_server_config; +struct sockaddr; enum warning_type { @@ -37,7 +38,8 @@ struct lsquic_engine_public { struct token_generator *enp_tokgen; lsquic_lookup_cert_f enp_lookup_cert; void *enp_cert_lu_ctx; - struct ssl_ctx_st * (*enp_get_ssl_ctx)(void *peer_ctx); + struct ssl_ctx_st * (*enp_get_ssl_ctx)(void *peer_ctx, + const struct sockaddr *); const struct lsquic_shared_hash_if *enp_shi; void *enp_shi_ctx; diff --git a/src/liblsquic/lsquic_packet_out.h b/src/liblsquic/lsquic_packet_out.h index 9e9806b3d..f5c692c1a 100644 --- a/src/liblsquic/lsquic_packet_out.h +++ b/src/liblsquic/lsquic_packet_out.h @@ -166,6 +166,7 @@ typedef struct lsquic_packet_out POL_HEADER_PROT = 1 << 9, /* Header protection applied */ #endif POL_LIMITED = 1 << 10, /* Used to credit sc_next_limit if needed. */ + POL_FACKED = 1 << 11, /* Lost due to FACK check */ } po_lflags:16; unsigned char *po_data; diff --git a/src/liblsquic/lsquic_send_ctl.c b/src/liblsquic/lsquic_send_ctl.c index 4bd784ca6..db7881e95 100644 --- a/src/liblsquic/lsquic_send_ctl.c +++ b/src/liblsquic/lsquic_send_ctl.c @@ -417,6 +417,13 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset, ctl->sc_can_send = send_ctl_can_send_pre_hsk; else ctl->sc_can_send = send_ctl_can_send; + ctl->sc_reord_thresh = N_NACKS_BEFORE_RETX; +#if LSQUIC_DEVEL + const char *s; + s = getenv("LSQUIC_DYN_PTHRESH"); + if (s == NULL || atoi(s)) + ctl->sc_flags |= SC_DYN_PTHRESH; +#endif } @@ -884,7 +891,7 @@ send_ctl_destroy_chain (struct lsquic_send_ctl *ctl, } -static void +static struct lsquic_packet_out * send_ctl_record_loss (struct lsquic_send_ctl *ctl, struct lsquic_packet_out *packet_out) { @@ -909,16 +916,21 @@ send_ctl_record_loss (struct lsquic_send_ctl *ctl, * remove from the list: */ TAILQ_INSERT_BEFORE(packet_out, loss_record, po_next); + return loss_record; } else + { LSQ_INFO("cannot allocate memory for loss record"); + return NULL; + } } -static int +static struct lsquic_packet_out * send_ctl_handle_regular_lost_packet (struct lsquic_send_ctl *ctl, lsquic_packet_out_t *packet_out, struct lsquic_packet_out **next) { + struct lsquic_packet_out *loss_record; unsigned packet_sz; assert(ctl->sc_n_in_flight_all); @@ -952,11 +964,11 @@ send_ctl_handle_regular_lost_packet (struct lsquic_send_ctl *ctl, { LSQ_DEBUG("lost retransmittable packet %"PRIu64, packet_out->po_packno); - send_ctl_record_loss(ctl, packet_out); + loss_record = send_ctl_record_loss(ctl, packet_out); send_ctl_unacked_remove(ctl, packet_out, packet_sz); TAILQ_INSERT_TAIL(&ctl->sc_lost_packets, packet_out, po_next); packet_out->po_flags |= PO_LOST; - return 1; + return loss_record; } else { @@ -965,7 +977,7 @@ send_ctl_handle_regular_lost_packet (struct lsquic_send_ctl *ctl, send_ctl_unacked_remove(ctl, packet_out, packet_sz); send_ctl_destroy_chain(ctl, packet_out, next); send_ctl_destroy_packet(ctl, packet_out); - return 0; + return NULL; } } @@ -993,7 +1005,7 @@ send_ctl_handle_lost_packet (struct lsquic_send_ctl *ctl, struct lsquic_packet_out *packet_out, struct lsquic_packet_out **next) { if (0 == (packet_out->po_flags & PO_MTU_PROBE)) - return send_ctl_handle_regular_lost_packet(ctl, packet_out, next); + return send_ctl_handle_regular_lost_packet(ctl, packet_out, next) != NULL; else return send_ctl_handle_lost_mtu_probe(ctl, packet_out); } @@ -1031,7 +1043,7 @@ static int send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns, lsquic_time_t time) { - lsquic_packet_out_t *packet_out, *next; + struct lsquic_packet_out *packet_out, *next, *loss_record; lsquic_packno_t largest_retx_packno, largest_lost_packno; largest_retx_packno = largest_retx_packet_number(ctl, pns); @@ -1047,14 +1059,22 @@ send_ctl_detect_losses (struct lsquic_send_ctl *ctl, enum packnum_space pns, if (packet_out->po_flags & (PO_LOSS_REC|PO_POISON)) continue; - if (packet_out->po_packno + N_NACKS_BEFORE_RETX < + if (packet_out->po_packno + ctl->sc_reord_thresh < ctl->sc_largest_acked_packno) { - LSQ_DEBUG("loss by FACK detected, packet %"PRIu64, + LSQ_DEBUG("loss by FACK detected (dist: %"PRIu64"), packet %"PRIu64, + ctl->sc_largest_acked_packno - packet_out->po_packno, packet_out->po_packno); if (0 == (packet_out->po_flags & PO_MTU_PROBE)) + { largest_lost_packno = packet_out->po_packno; - (void) send_ctl_handle_lost_packet(ctl, packet_out, &next); + loss_record = send_ctl_handle_regular_lost_packet(ctl, + packet_out, &next); + if (loss_record) + loss_record->po_lflags |= POL_FACKED; + } + else + send_ctl_handle_lost_mtu_probe(ctl, packet_out); continue; } @@ -1120,6 +1140,26 @@ send_ctl_mtu_probe_acked (struct lsquic_send_ctl *ctl, } +static void +send_ctl_maybe_increase_reord_thresh (struct lsquic_send_ctl *ctl, + const struct lsquic_packet_out *loss_record, + lsquic_packno_t prev_largest_acked) +{ +#if LSQUIC_DEVEL + if (ctl->sc_flags & SC_DYN_PTHRESH) +#endif + if ((loss_record->po_lflags & POL_FACKED) + && loss_record->po_packno + ctl->sc_reord_thresh + < prev_largest_acked) + { + ctl->sc_reord_thresh = prev_largest_acked - loss_record->po_packno; + LSQ_DEBUG("packet %"PRIu64" was a spurious loss by FACK, increase " + "reordering threshold to %u", loss_record->po_packno, + ctl->sc_reord_thresh); + } +} + + int lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl, const struct ack_info *acki, @@ -1129,6 +1169,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl, &acki->ranges[ acki->n_ranges - 1 ]; lsquic_packet_out_t *packet_out, *next; lsquic_packno_t smallest_unacked; + lsquic_packno_t prev_largest_acked; lsquic_packno_t ack2ed[2]; unsigned packet_sz; int app_limited, losses_detected; @@ -1190,6 +1231,7 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl, ctl->sc_cur_rt_end = lsquic_senhist_largest(&ctl->sc_senhist); } + prev_largest_acked = ctl->sc_largest_acked_packno; do_rtt = 0, skip_checks = 0; app_limited = -1; do @@ -1234,6 +1276,8 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl, po_next); LSQ_DEBUG("acking via loss record %"PRIu64, packet_out->po_packno); + send_ctl_maybe_increase_reord_thresh(ctl, packet_out, + prev_largest_acked); #if LSQUIC_CONN_STATS ++ctl->sc_conn_pub->conn_stats->out.acked_via_loss; #endif diff --git a/src/liblsquic/lsquic_send_ctl.h b/src/liblsquic/lsquic_send_ctl.h index 9e4fbd5ed..73df97448 100644 --- a/src/liblsquic/lsquic_send_ctl.h +++ b/src/liblsquic/lsquic_send_ctl.h @@ -54,6 +54,9 @@ enum send_ctl_flags { SC_ACK_RECV_HSK = SC_ACK_RECV_INIT << PNS_HSK, SC_ACK_RECV_APP = SC_ACK_RECV_INIT << PNS_APP, SC_ROUGH_RTT = 1 << 22, +#if LSQUIC_DEVEL + SC_DYN_PTHRESH = 1 << 31u, /* dynamic packet threshold enabled */ +#endif }; typedef struct lsquic_send_ctl { @@ -110,6 +113,9 @@ typedef struct lsquic_send_ctl { * This information is used to drop stale ACK frames from packets in * buffered queues. */ + /* XXX We have both sc_largest_acked_packno and sc_largest_acked. Rename + * the latter to make the code more readable. + */ lsquic_packno_t sc_largest_acked; lsquic_time_t sc_loss_to; uint64_t sc_ecn_total_acked[N_PNS]; @@ -137,6 +143,7 @@ typedef struct lsquic_send_ctl { lsquic_packno_t sc_gap; unsigned sc_loss_count; /* Used to set loss bit */ unsigned sc_square_count;/* Used to set square bit */ + unsigned sc_reord_thresh; signed char sc_cidlen; /* For debug purposes */ } lsquic_send_ctl_t;