1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/quic_mtu_discovery.h"
6
7 #include "quiche/quic/platform/api/quic_flag_utils.h"
8 #include "quiche/quic/platform/api/quic_stack_trace.h"
9
10 namespace quic {
11
QuicConnectionMtuDiscoverer(QuicPacketCount packets_between_probes_base,QuicPacketNumber next_probe_at)12 QuicConnectionMtuDiscoverer::QuicConnectionMtuDiscoverer(
13 QuicPacketCount packets_between_probes_base, QuicPacketNumber next_probe_at)
14 : packets_between_probes_(packets_between_probes_base),
15 next_probe_at_(next_probe_at) {}
16
Enable(QuicByteCount max_packet_length,QuicByteCount target_max_packet_length)17 void QuicConnectionMtuDiscoverer::Enable(
18 QuicByteCount max_packet_length, QuicByteCount target_max_packet_length) {
19 QUICHE_DCHECK(!IsEnabled());
20
21 if (target_max_packet_length <= max_packet_length) {
22 QUIC_DVLOG(1) << "MtuDiscoverer not enabled. target_max_packet_length:"
23 << target_max_packet_length
24 << " <= max_packet_length:" << max_packet_length;
25 return;
26 }
27
28 min_probe_length_ = max_packet_length;
29 max_probe_length_ = target_max_packet_length;
30 QUICHE_DCHECK(IsEnabled());
31
32 QUIC_DVLOG(1) << "MtuDiscoverer enabled. min:" << min_probe_length_
33 << ", max:" << max_probe_length_
34 << ", next:" << next_probe_packet_length();
35 }
36
Disable()37 void QuicConnectionMtuDiscoverer::Disable() {
38 *this = QuicConnectionMtuDiscoverer(packets_between_probes_, next_probe_at_);
39 }
40
IsEnabled() const41 bool QuicConnectionMtuDiscoverer::IsEnabled() const {
42 return min_probe_length_ < max_probe_length_;
43 }
44
ShouldProbeMtu(QuicPacketNumber largest_sent_packet) const45 bool QuicConnectionMtuDiscoverer::ShouldProbeMtu(
46 QuicPacketNumber largest_sent_packet) const {
47 if (!IsEnabled()) {
48 return false;
49 }
50
51 if (remaining_probe_count_ == 0) {
52 QUIC_DVLOG(1)
53 << "ShouldProbeMtu returns false because max probe count reached";
54 return false;
55 }
56
57 if (largest_sent_packet < next_probe_at_) {
58 QUIC_DVLOG(1) << "ShouldProbeMtu returns false because not enough packets "
59 "sent since last probe. largest_sent_packet:"
60 << largest_sent_packet
61 << ", next_probe_at_:" << next_probe_at_;
62 return false;
63 }
64
65 QUIC_DVLOG(1) << "ShouldProbeMtu returns true. largest_sent_packet:"
66 << largest_sent_packet;
67 return true;
68 }
69
GetUpdatedMtuProbeSize(QuicPacketNumber largest_sent_packet)70 QuicPacketLength QuicConnectionMtuDiscoverer::GetUpdatedMtuProbeSize(
71 QuicPacketNumber largest_sent_packet) {
72 QUICHE_DCHECK(ShouldProbeMtu(largest_sent_packet));
73
74 QuicPacketLength probe_packet_length = next_probe_packet_length();
75 if (probe_packet_length == last_probe_length_) {
76 // The next probe packet is as big as the previous one. Assuming the
77 // previous one exceeded MTU, we need to decrease the probe packet length.
78 max_probe_length_ = probe_packet_length;
79 } else {
80 QUICHE_DCHECK_GT(probe_packet_length, last_probe_length_);
81 }
82 last_probe_length_ = next_probe_packet_length();
83
84 packets_between_probes_ *= 2;
85 next_probe_at_ = largest_sent_packet + packets_between_probes_ + 1;
86 if (remaining_probe_count_ > 0) {
87 --remaining_probe_count_;
88 }
89
90 QUIC_DVLOG(1) << "GetUpdatedMtuProbeSize: probe_packet_length:"
91 << last_probe_length_
92 << ", New packets_between_probes_:" << packets_between_probes_
93 << ", next_probe_at_:" << next_probe_at_
94 << ", remaining_probe_count_:" << remaining_probe_count_;
95 QUICHE_DCHECK(!ShouldProbeMtu(largest_sent_packet));
96 return last_probe_length_;
97 }
98
next_probe_packet_length() const99 QuicPacketLength QuicConnectionMtuDiscoverer::next_probe_packet_length() const {
100 QUICHE_DCHECK_NE(min_probe_length_, 0);
101 QUICHE_DCHECK_NE(max_probe_length_, 0);
102 QUICHE_DCHECK_GE(max_probe_length_, min_probe_length_);
103
104 const QuicPacketLength normal_next_probe_length =
105 (min_probe_length_ + max_probe_length_ + 1) / 2;
106
107 if (remaining_probe_count_ == 1 &&
108 normal_next_probe_length > last_probe_length_) {
109 // If the previous probe succeeded, and there is only one last probe to
110 // send, use |max_probe_length_| for the last probe.
111 return max_probe_length_;
112 }
113 return normal_next_probe_length;
114 }
115
OnMaxPacketLengthUpdated(QuicByteCount old_value,QuicByteCount new_value)116 void QuicConnectionMtuDiscoverer::OnMaxPacketLengthUpdated(
117 QuicByteCount old_value, QuicByteCount new_value) {
118 if (!IsEnabled() || new_value <= old_value) {
119 return;
120 }
121
122 QUICHE_DCHECK_EQ(old_value, min_probe_length_);
123 min_probe_length_ = new_value;
124 }
125
operator <<(std::ostream & os,const QuicConnectionMtuDiscoverer & d)126 std::ostream& operator<<(std::ostream& os,
127 const QuicConnectionMtuDiscoverer& d) {
128 os << "{ min_probe_length_:" << d.min_probe_length_
129 << " max_probe_length_:" << d.max_probe_length_
130 << " last_probe_length_:" << d.last_probe_length_
131 << " remaining_probe_count_:" << d.remaining_probe_count_
132 << " packets_between_probes_:" << d.packets_between_probes_
133 << " next_probe_at_:" << d.next_probe_at_ << " }";
134 return os;
135 }
136
137 } // namespace quic
138