src/transport/xqc_send_ctl.h (163 lines of code) (raw):

/** * @copyright Copyright (c) 2022, Alibaba Group Holding Limited */ #ifndef _XQC_SEND_CTL_H_INCLUDED_ #define _XQC_SEND_CTL_H_INCLUDED_ #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_conn.h" #include "src/transport/xqc_pacing.h" #include "src/congestion_control/xqc_sample.h" #include "src/transport/xqc_send_queue.h" #include "src/transport/xqc_timer.h" #include "src/transport/xqc_multipath.h" #include <math.h> #define XQC_kPacketThreshold 3 #define XQC_kTimeThresholdShift 3 #define XQC_kPersistentCongestionThreshold 3 #define XQC_CONSECUTIVE_PTO_THRESH 2 /* * Timer granularity. This is a system-dependent value. * However, implementations SHOULD use a value no smaller than 1ms. */ #define XQC_kGranularity 2 #define XQC_kInitialRtt_us 250000 /* 2^n */ #define xqc_send_ctl_pow(n) (1 << n) #define xqc_send_ctl_pow_x(x, n) (fabs(x - 2) < 1e-7) ? xqc_send_ctl_pow(n) : pow(x, n) #define XQC_DEFAULT_RECORD_INTERVAL (100000) /* 100ms record interval */ #define XQC_DEFAULT_RTT_CHANGE_THRESHOLD (50 * 1000) /* 50ms */ #define XQC_DEFAULT_BW_CHANGE_THRESHOLD (50) /* percentage of bandwidth change */ typedef struct { xqc_usec_t last_record_time; /* last periodic record time */ xqc_usec_t last_rtt_time; /* last time the rtt was drastically changed */ xqc_usec_t last_lost_time; /* last time a packet loss was recorded */ xqc_usec_t last_bw_time; /* last time the bandwidth was drastically changed */ uint64_t record_interval; /* all types of records are recorded only once in the interval */ uint64_t rtt_change_threshold; /* threshold of rtt change */ uint64_t bw_change_threshold; /* threshold of bandwidth change */ uint64_t last_lost_count; /* number of packets lost in the last record */ uint64_t last_send_count; /* number of packets sent in the last record */ }xqc_send_ctl_info_t; typedef struct xqc_pn_ctl_s { xqc_packet_number_t ctl_packet_number[XQC_PNS_N]; /* maximum value of Largest Acknowledged in the packet_out that sent ACK and was ACKed * ensures that the ACK has been received by the peer, * so that the sender can no longer generate ACKs smaller than that value */ xqc_packet_number_t ctl_largest_acked_ack[XQC_PNS_N]; /* largest packet number of the packets sent */ xqc_packet_number_t ctl_largest_sent[XQC_PNS_N]; /* record received pkt number range in a list */ xqc_recv_record_t ctl_recv_record[XQC_PNS_N]; /* record ack sent */ xqc_ack_sent_record_t ack_sent_record[XQC_PNS_N]; /* fields are used for detecting optimistic ack attacks */ /* we skip pn in [ctl_skipped_pn_low, ctl_skipped_pn_high] */ xqc_packet_number_t ctl_skipped_pn_low; xqc_packet_number_t ctl_skipped_pn_high; xqc_usec_t ctl_next_skip_chance; } xqc_pn_ctl_t; typedef struct xqc_send_ctl_s { xqc_connection_t *ctl_conn; xqc_path_ctx_t *ctl_path; /* largest packet number of the acked packets in packet_out */ xqc_packet_number_t ctl_largest_acked[XQC_PNS_N]; /* sending time of largest packet */ xqc_usec_t ctl_largest_acked_sent_time[XQC_PNS_N]; /* largest packet number of the received packets in packet_in */ xqc_packet_number_t ctl_largest_received[XQC_PNS_N]; /* received time of largest packet */ xqc_usec_t ctl_largest_recv_time[XQC_PNS_N]; /* Ack-eliciting Packets received since last ack sent */ uint32_t ctl_ack_eliciting_pkt[XQC_PNS_N]; xqc_usec_t ctl_loss_time[XQC_PNS_N]; xqc_usec_t ctl_last_inflight_pkt_sent_time; xqc_usec_t ctl_time_of_last_sent_ack_eliciting_packet[XQC_PNS_N]; xqc_packet_number_t ctl_last_sent_ack_eliciting_packet_number[XQC_PNS_N]; xqc_usec_t ctl_srtt, ctl_rttvar, ctl_minrtt, ctl_latest_rtt; xqc_usec_t ctl_first_rtt_sample_time; /* The time when the conn gets the first RTT sample. */ /* data record - latest rtt */ uint32_t ctl_update_latest_rtt_count; xqc_msec_t ctl_latest_rtt_sum; xqc_msec_t ctl_latest_rtt_square_sum; xqc_timer_manager_t path_timer_manager; unsigned ctl_pto_count; unsigned ctl_send_count; unsigned ctl_lost_count; unsigned ctl_tlp_count; unsigned ctl_spurious_loss_count; unsigned ctl_lost_dgram_cnt; /* record time for last three cwnd limitation and rtt mutation*/ xqc_msec_t ctl_recent_cwnd_limitation_time[3]; uint8_t ctl_cwndlim_update_idx; unsigned ctl_recv_count; /* for QUIC datagrams */ uint32_t ctl_dgram_send_count; uint32_t ctl_dgram_recv_count; uint32_t ctl_reinj_dgram_send_count; uint32_t ctl_reinj_dgram_recv_count; uint32_t ctl_max_bytes_in_flight; uint8_t ctl_is_cwnd_limited; unsigned ctl_bytes_in_flight; uint32_t ctl_bytes_ack_eliciting_inflight[XQC_PNS_N]; unsigned ctl_prior_bytes_in_flight; uint64_t ctl_bytes_send; uint64_t ctl_bytes_recv; /* only accounts for stream and datagram packets */ uint64_t ctl_app_bytes_send; uint64_t ctl_app_bytes_recv; const xqc_cong_ctrl_callback_t *ctl_cong_callback; void *ctl_cong; xqc_pacing_t ctl_pacing; uint64_t ctl_prior_delivered; /* the amount of data delivered in the last call of on_ack_received*/ uint64_t ctl_delivered; /* the amount of data that has been marked as sent at the current ack moment */ uint64_t ctl_app_limited; /* The index of the last transmitted packet marked as application-limited, * or 0 if the connection is not currently application-limited. */ xqc_usec_t ctl_delivered_time; /* time when the current packet was acked */ xqc_usec_t ctl_first_sent_time; /* Send time of the first packet in the current sampling period */ uint32_t ctl_lost_pkts_number; /* how many packets have been lost so far */ xqc_packet_number_t ctl_reordering_packet_threshold; int32_t ctl_reordering_time_threshold_shift; xqc_sample_t sampler; xqc_send_ctl_info_t ctl_info; unsigned ctl_recent_send_count[2]; unsigned ctl_recent_lost_count[2]; xqc_usec_t ctl_recent_stats_timestamp; uint64_t ctl_ack_sent_cnt; } xqc_send_ctl_t; static inline xqc_usec_t xqc_send_ctl_calc_pto(xqc_send_ctl_t *send_ctl) { return send_ctl->ctl_srtt + xqc_max(4 * send_ctl->ctl_rttvar, XQC_kGranularity * 1000) + send_ctl->ctl_conn->local_settings.max_ack_delay * 1000; } void xqc_send_ctl_on_dgram_dropped(xqc_connection_t *conn, xqc_packet_out_t *po); int xqc_send_ctl_may_remove_unacked_dgram(xqc_connection_t *conn, xqc_packet_out_t *po); int xqc_send_ctl_indirectly_ack_or_drop_po(xqc_connection_t *conn, xqc_packet_out_t *po); xqc_send_ctl_t *xqc_send_ctl_create(xqc_path_ctx_t *path); void xqc_send_ctl_destroy(xqc_send_ctl_t *send_ctl); void xqc_send_ctl_reset(xqc_send_ctl_t *send_ctl); xqc_pn_ctl_t *xqc_pn_ctl_create(xqc_connection_t *conn); void xqc_pn_ctl_destroy(xqc_pn_ctl_t *pn_ctl); xqc_pn_ctl_t *xqc_get_pn_ctl(xqc_connection_t *conn, xqc_path_ctx_t *path); int xqc_send_ctl_can_send(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes); xqc_bool_t xqc_send_packet_cwnd_allows(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now); xqc_bool_t xqc_send_packet_pacer_allows(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now); xqc_bool_t xqc_send_packet_check_cc(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now); void xqc_send_ctl_increase_inflight(xqc_connection_t *conn, xqc_packet_out_t *packet_out); void xqc_send_ctl_decrease_inflight(xqc_connection_t *conn, xqc_packet_out_t *packet_out); void xqc_send_ctl_on_pns_discard(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns); void xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_packet_out_t *packet_out, xqc_usec_t now); int xqc_send_ctl_on_ack_received (xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_send_queue_t *send_queue, xqc_ack_info_t *const ack_info, xqc_usec_t ack_recv_time, xqc_bool_t ack_on_same_path); void xqc_send_ctl_on_dgram_received(xqc_send_ctl_t *send_ctl, size_t dgram_size); void xqc_send_ctl_update_rtt(xqc_send_ctl_t *send_ctl, xqc_usec_t *latest_rtt, xqc_usec_t ack_delay); void xqc_send_ctl_on_spurious_loss_detected(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns, xqc_usec_t ack_recv_time, xqc_packet_number_t largest_ack, xqc_packet_number_t spurious_loss_pktnum, xqc_usec_t spurious_loss_sent_time); void xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, xqc_pkt_num_space_t pns, xqc_usec_t now); xqc_bool_t xqc_send_ctl_in_persistent_congestion(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *largest_lost, xqc_usec_t now); void xqc_send_ctl_congestion_event(xqc_send_ctl_t *send_ctl, xqc_usec_t sent_time); int xqc_send_ctl_in_recovery(xqc_send_ctl_t *send_ctl, xqc_usec_t sent_time); int xqc_send_ctl_is_app_limited(xqc_send_ctl_t *send_ctl); int xqc_send_ctl_is_cwnd_limited(xqc_send_ctl_t *send_ctl); void xqc_send_ctl_cc_on_ack(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *acked_packet, xqc_usec_t now); void xqc_send_ctl_on_packet_acked(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *acked_packet, xqc_usec_t now, int do_cc); void xqc_send_queue_maybe_remove_unacked(xqc_packet_out_t *packet_out, xqc_send_queue_t *send_queue, xqc_path_ctx_t *path); xqc_usec_t xqc_send_ctl_get_pto_time_and_space(xqc_send_ctl_t *send_ctl, xqc_usec_t now, xqc_pkt_num_space_t *pns_ret); void xqc_send_ctl_set_loss_detection_timer(xqc_send_ctl_t *send_ctl); xqc_usec_t xqc_send_ctl_get_earliest_loss_time(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t *pns_ret); xqc_usec_t xqc_send_ctl_get_srtt(xqc_send_ctl_t *send_ctl); float xqc_send_ctl_get_retrans_rate(xqc_send_ctl_t *send_ctl); float xqc_send_ctl_get_spurious_loss_rate(xqc_send_ctl_t *send_ctl); /** * check amplification limit state * @param send_bytes input 0 to check if server is at limit now, input non-zero to * check if this byte count will trigger amplification limit * @return XQC_FALSE: not at amplification limit, XQC_TRUE: at amplification limit */ xqc_bool_t xqc_send_ctl_check_anti_amplification(xqc_send_ctl_t *send_ctl, size_t send_bytes); void xqc_send_ctl_rearm_ld_timer(xqc_send_ctl_t *send_ctl); xqc_bool_t xqc_send_ctl_ack_received_in_pns(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns); xqc_packet_number_t xqc_send_ctl_get_lost_sent_pn(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns); xqc_packet_number_t xqc_send_ctl_get_pkt_num_gap(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns, xqc_packet_number_t front, xqc_packet_number_t back); /* bytes per second */ uint64_t xqc_send_ctl_get_est_bw(xqc_send_ctl_t *send_ctl); uint64_t xqc_send_ctl_get_pacing_rate(xqc_send_ctl_t *send_ctl); xqc_int_t xqc_send_ctl_detect_optimistic_ack_attack(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ack_info_t *const ack_info, xqc_usec_t ack_recv_time); void xqc_send_ctl_set_next_pn_for_packet(xqc_connection_t *conn, xqc_pn_ctl_t *pn_ctl, xqc_packet_out_t *packet_out, xqc_usec_t current_time); #endif /* _XQC_SEND_CTL_H_INCLUDED_ */