|  | // Copyright (c) 2019 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/core/quic_mtu_discovery.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h" | 
|  |  | 
|  | namespace quic { | 
|  |  | 
|  | QuicConnectionMtuDiscoverer::QuicConnectionMtuDiscoverer( | 
|  | QuicPacketCount packets_between_probes_base, | 
|  | QuicPacketNumber next_probe_at) | 
|  | : packets_between_probes_(packets_between_probes_base), | 
|  | next_probe_at_(next_probe_at) {} | 
|  |  | 
|  | void QuicConnectionMtuDiscoverer::Enable( | 
|  | QuicByteCount max_packet_length, | 
|  | QuicByteCount target_max_packet_length) { | 
|  | DCHECK(!IsEnabled()); | 
|  |  | 
|  | if (target_max_packet_length <= max_packet_length) { | 
|  | QUIC_DVLOG(1) << "MtuDiscoverer not enabled. target_max_packet_length:" | 
|  | << target_max_packet_length | 
|  | << " <= max_packet_length:" << max_packet_length; | 
|  | return; | 
|  | } | 
|  |  | 
|  | min_probe_length_ = max_packet_length; | 
|  | max_probe_length_ = target_max_packet_length; | 
|  | DCHECK(IsEnabled()); | 
|  |  | 
|  | QUIC_DVLOG(1) << "MtuDiscoverer enabled. min:" << min_probe_length_ | 
|  | << ", max:" << max_probe_length_ | 
|  | << ", next:" << next_probe_packet_length(); | 
|  | } | 
|  |  | 
|  | void QuicConnectionMtuDiscoverer::Disable() { | 
|  | *this = QuicConnectionMtuDiscoverer(packets_between_probes_, next_probe_at_); | 
|  | } | 
|  |  | 
|  | bool QuicConnectionMtuDiscoverer::IsEnabled() const { | 
|  | return min_probe_length_ < max_probe_length_; | 
|  | } | 
|  |  | 
|  | bool QuicConnectionMtuDiscoverer::ShouldProbeMtu( | 
|  | QuicPacketNumber largest_sent_packet) const { | 
|  | if (!IsEnabled()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (remaining_probe_count_ == 0) { | 
|  | QUIC_DVLOG(1) | 
|  | << "ShouldProbeMtu returns false because max probe count reached"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (largest_sent_packet < next_probe_at_) { | 
|  | QUIC_DVLOG(1) << "ShouldProbeMtu returns false because not enough packets " | 
|  | "sent since last probe. largest_sent_packet:" | 
|  | << largest_sent_packet | 
|  | << ", next_probe_at_:" << next_probe_at_; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | QUIC_DVLOG(1) << "ShouldProbeMtu returns true. largest_sent_packet:" | 
|  | << largest_sent_packet; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | QuicPacketLength QuicConnectionMtuDiscoverer::GetUpdatedMtuProbeSize( | 
|  | QuicPacketNumber largest_sent_packet) { | 
|  | DCHECK(ShouldProbeMtu(largest_sent_packet)); | 
|  |  | 
|  | QuicPacketLength probe_packet_length = next_probe_packet_length(); | 
|  | if (probe_packet_length == last_probe_length_) { | 
|  | // The next probe packet is as big as the previous one. Assuming the | 
|  | // previous one exceeded MTU, we need to decrease the probe packet length. | 
|  | max_probe_length_ = probe_packet_length; | 
|  | QUIC_RELOADABLE_FLAG_COUNT_N(quic_mtu_discovery_v2, 1, 3); | 
|  | } else { | 
|  | DCHECK_GT(probe_packet_length, last_probe_length_); | 
|  | QUIC_RELOADABLE_FLAG_COUNT_N(quic_mtu_discovery_v2, 2, 3); | 
|  | } | 
|  | last_probe_length_ = next_probe_packet_length(); | 
|  |  | 
|  | packets_between_probes_ *= 2; | 
|  | next_probe_at_ = largest_sent_packet + packets_between_probes_ + 1; | 
|  | if (remaining_probe_count_ > 0) { | 
|  | --remaining_probe_count_; | 
|  | } | 
|  |  | 
|  | QUIC_DVLOG(1) << "GetUpdatedMtuProbeSize: probe_packet_length:" | 
|  | << last_probe_length_ | 
|  | << ", New packets_between_probes_:" << packets_between_probes_ | 
|  | << ", next_probe_at_:" << next_probe_at_ | 
|  | << ", remaining_probe_count_:" << remaining_probe_count_; | 
|  | DCHECK(!ShouldProbeMtu(largest_sent_packet)); | 
|  | return last_probe_length_; | 
|  | } | 
|  |  | 
|  | QuicPacketLength QuicConnectionMtuDiscoverer::next_probe_packet_length() const { | 
|  | DCHECK_NE(min_probe_length_, 0); | 
|  | DCHECK_NE(max_probe_length_, 0); | 
|  | DCHECK_GE(max_probe_length_, min_probe_length_); | 
|  |  | 
|  | const QuicPacketLength normal_next_probe_length = | 
|  | (min_probe_length_ + max_probe_length_ + 1) / 2; | 
|  |  | 
|  | if (remaining_probe_count_ == 1 && | 
|  | normal_next_probe_length > last_probe_length_) { | 
|  | // If the previous probe succeeded, and there is only one last probe to | 
|  | // send, use |max_probe_length_| for the last probe. | 
|  | return max_probe_length_; | 
|  | } | 
|  | return normal_next_probe_length; | 
|  | } | 
|  |  | 
|  | void QuicConnectionMtuDiscoverer::OnMaxPacketLengthUpdated( | 
|  | QuicByteCount old_value, | 
|  | QuicByteCount new_value) { | 
|  | if (!IsEnabled() || new_value <= old_value) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | DCHECK_EQ(old_value, min_probe_length_); | 
|  | min_probe_length_ = new_value; | 
|  | QUIC_RELOADABLE_FLAG_COUNT_N(quic_mtu_discovery_v2, 3, 3); | 
|  | } | 
|  |  | 
|  | std::ostream& operator<<(std::ostream& os, | 
|  | const QuicConnectionMtuDiscoverer& d) { | 
|  | os << "{ min_probe_length_:" << d.min_probe_length_ | 
|  | << " max_probe_length_:" << d.max_probe_length_ | 
|  | << " last_probe_length_:" << d.last_probe_length_ | 
|  | << " remaining_probe_count_:" << d.remaining_probe_count_ | 
|  | << " packets_between_probes_:" << d.packets_between_probes_ | 
|  | << " next_probe_at_:" << d.next_probe_at_ << " }"; | 
|  | return os; | 
|  | } | 
|  |  | 
|  | }  // namespace quic |