blob: eeaf297c1caeb062443532f73fcfb86d0d7b2a03 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2018 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 "net/third_party/quiche/src/quic/core/quic_trace_visitor.h"
6
vasilvv872e7a32019-03-12 16:42:44 -07007#include <string>
8
vasilvv923b6d22020-03-23 11:17:58 -07009#include "net/third_party/quiche/src/quic/core/quic_types.h"
QUICHE team173c48f2019-11-19 16:34:44 -080010#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050011
12namespace quic {
13
14quic_trace::EncryptionLevel EncryptionLevelToProto(EncryptionLevel level) {
15 switch (level) {
QUICHE team6987b4a2019-03-15 16:23:04 -070016 case ENCRYPTION_INITIAL:
QUICHE teama6ef0a62019-03-07 20:34:33 -050017 return quic_trace::ENCRYPTION_INITIAL;
QUICHE team88ea0082019-03-15 10:05:26 -070018 case ENCRYPTION_HANDSHAKE:
19 return quic_trace::ENCRYPTION_HANDSHAKE;
QUICHE teama6ef0a62019-03-07 20:34:33 -050020 case ENCRYPTION_ZERO_RTT:
21 return quic_trace::ENCRYPTION_0RTT;
22 case ENCRYPTION_FORWARD_SECURE:
23 return quic_trace::ENCRYPTION_1RTT;
24 case NUM_ENCRYPTION_LEVELS:
25 QUIC_BUG << "Invalid encryption level specified";
26 return quic_trace::ENCRYPTION_UNKNOWN;
27 }
28}
29
30QuicTraceVisitor::QuicTraceVisitor(const QuicConnection* connection)
31 : connection_(connection),
32 start_time_(connection_->clock()->ApproximateNow()) {
vasilvvc48c8712019-03-11 13:38:16 -070033 std::string binary_connection_id(connection->connection_id().data(),
34 connection->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -050035 // We assume that the connection ID in gQUIC is equivalent to the
36 // server-chosen client-selected ID.
37 switch (connection->perspective()) {
38 case Perspective::IS_CLIENT:
39 trace_.set_destination_connection_id(binary_connection_id);
40 break;
41 case Perspective::IS_SERVER:
42 trace_.set_source_connection_id(binary_connection_id);
43 break;
44 }
45}
46
47void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet,
QUICHE teama6ef0a62019-03-07 20:34:33 -050048 TransmissionType /*transmission_type*/,
49 QuicTime sent_time) {
50 quic_trace::Event* event = trace_.add_events();
51 event->set_event_type(quic_trace::PACKET_SENT);
52 event->set_time_us(ConvertTimestampToRecordedFormat(sent_time));
53 event->set_packet_number(serialized_packet.packet_number.ToUint64());
54 event->set_packet_size(serialized_packet.encrypted_length);
55 event->set_encryption_level(
56 EncryptionLevelToProto(serialized_packet.encryption_level));
57
58 for (const QuicFrame& frame : serialized_packet.retransmittable_frames) {
59 switch (frame.type) {
60 case STREAM_FRAME:
61 case RST_STREAM_FRAME:
62 case CONNECTION_CLOSE_FRAME:
63 case WINDOW_UPDATE_FRAME:
64 case BLOCKED_FRAME:
65 case PING_FRAME:
fayang01062942020-01-22 07:23:23 -080066 case HANDSHAKE_DONE_FRAME:
haoyuewang6a6a0ff2020-06-23 16:32:26 -070067 case ACK_FREQUENCY_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -050068 PopulateFrameInfo(frame, event->add_frames());
69 break;
70
71 case PADDING_FRAME:
72 case MTU_DISCOVERY_FRAME:
73 case STOP_WAITING_FRAME:
74 case ACK_FRAME:
75 QUIC_BUG
76 << "Frames of type are not retransmittable and are not supposed "
77 "to be in retransmittable_frames";
78 break;
79
80 // New IETF frames, not used in current gQUIC version.
QUICHE teama6ef0a62019-03-07 20:34:33 -050081 case NEW_CONNECTION_ID_FRAME:
82 case RETIRE_CONNECTION_ID_FRAME:
fkastenholz3c4eabf2019-04-22 07:49:59 -070083 case MAX_STREAMS_FRAME:
84 case STREAMS_BLOCKED_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -050085 case PATH_RESPONSE_FRAME:
86 case PATH_CHALLENGE_FRAME:
87 case STOP_SENDING_FRAME:
88 case MESSAGE_FRAME:
89 case CRYPTO_FRAME:
90 case NEW_TOKEN_FRAME:
91 break;
92
93 // Ignore gQUIC-specific frames.
94 case GOAWAY_FRAME:
95 break;
96
97 case NUM_FRAME_TYPES:
98 QUIC_BUG << "Unknown frame type encountered";
99 break;
100 }
101 }
102
103 // Output PCC DebugState on packet sent for analysis.
104 if (connection_->sent_packet_manager()
105 .GetSendAlgorithm()
106 ->GetCongestionControlType() == kPCC) {
107 PopulateTransportState(event->mutable_transport_state());
108 }
109}
110
111void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame,
112 quic_trace::Frame* frame_record) {
113 switch (frame.type) {
114 case STREAM_FRAME: {
115 frame_record->set_frame_type(quic_trace::STREAM);
116
117 quic_trace::StreamFrameInfo* info =
118 frame_record->mutable_stream_frame_info();
119 info->set_stream_id(frame.stream_frame.stream_id);
120 info->set_fin(frame.stream_frame.fin);
121 info->set_offset(frame.stream_frame.offset);
122 info->set_length(frame.stream_frame.data_length);
123 break;
124 }
125
126 case ACK_FRAME: {
127 frame_record->set_frame_type(quic_trace::ACK);
128
129 quic_trace::AckInfo* info = frame_record->mutable_ack_info();
130 info->set_ack_delay_us(frame.ack_frame->ack_delay_time.ToMicroseconds());
131 for (const auto& interval : frame.ack_frame->packets) {
132 quic_trace::AckBlock* block = info->add_acked_packets();
133 // We record intervals as [a, b], whereas the in-memory representation
134 // we currently use is [a, b).
135 block->set_first_packet(interval.min().ToUint64());
136 block->set_last_packet(interval.max().ToUint64() - 1);
137 }
138 break;
139 }
140
141 case RST_STREAM_FRAME: {
142 frame_record->set_frame_type(quic_trace::RESET_STREAM);
143
144 quic_trace::ResetStreamInfo* info =
145 frame_record->mutable_reset_stream_info();
146 info->set_stream_id(frame.rst_stream_frame->stream_id);
147 info->set_final_offset(frame.rst_stream_frame->byte_offset);
148 info->set_application_error_code(frame.rst_stream_frame->error_code);
149 break;
150 }
151
152 case CONNECTION_CLOSE_FRAME: {
153 frame_record->set_frame_type(quic_trace::CONNECTION_CLOSE);
154
155 quic_trace::CloseInfo* info = frame_record->mutable_close_info();
fkastenholze9d71a82019-04-09 05:12:13 -0700156 info->set_error_code(frame.connection_close_frame->quic_error_code);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157 info->set_reason_phrase(frame.connection_close_frame->error_details);
fkastenholz72f509b2019-04-10 09:17:49 -0700158 info->set_close_type(static_cast<quic_trace::CloseType>(
159 frame.connection_close_frame->close_type));
160 info->set_transport_close_frame_type(
161 frame.connection_close_frame->transport_close_frame_type);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500162 break;
163 }
164
165 case GOAWAY_FRAME:
166 // Do not bother logging this since the frame in question is
167 // gQUIC-specific.
168 break;
169
170 case WINDOW_UPDATE_FRAME: {
171 bool is_connection = frame.window_update_frame->stream_id == 0;
172 frame_record->set_frame_type(is_connection ? quic_trace::MAX_DATA
173 : quic_trace::MAX_STREAM_DATA);
174
175 quic_trace::FlowControlInfo* info =
176 frame_record->mutable_flow_control_info();
renjietangd088eab2019-11-21 14:54:41 -0800177 info->set_max_data(frame.window_update_frame->max_data);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 if (!is_connection) {
179 info->set_stream_id(frame.window_update_frame->stream_id);
180 }
181 break;
182 }
183
184 case BLOCKED_FRAME: {
185 bool is_connection = frame.blocked_frame->stream_id == 0;
186 frame_record->set_frame_type(is_connection ? quic_trace::BLOCKED
187 : quic_trace::STREAM_BLOCKED);
188
189 quic_trace::FlowControlInfo* info =
190 frame_record->mutable_flow_control_info();
191 if (!is_connection) {
192 info->set_stream_id(frame.window_update_frame->stream_id);
193 }
194 break;
195 }
196
197 case PING_FRAME:
198 case MTU_DISCOVERY_FRAME:
fayang01062942020-01-22 07:23:23 -0800199 case HANDSHAKE_DONE_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500200 frame_record->set_frame_type(quic_trace::PING);
201 break;
202
203 case PADDING_FRAME:
204 frame_record->set_frame_type(quic_trace::PADDING);
205 break;
206
207 case STOP_WAITING_FRAME:
208 // We're going to pretend those do not exist.
209 break;
210
211 // New IETF frames, not used in current gQUIC version.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500212 case NEW_CONNECTION_ID_FRAME:
213 case RETIRE_CONNECTION_ID_FRAME:
fkastenholz3c4eabf2019-04-22 07:49:59 -0700214 case MAX_STREAMS_FRAME:
215 case STREAMS_BLOCKED_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500216 case PATH_RESPONSE_FRAME:
217 case PATH_CHALLENGE_FRAME:
218 case STOP_SENDING_FRAME:
219 case MESSAGE_FRAME:
220 case CRYPTO_FRAME:
221 case NEW_TOKEN_FRAME:
haoyuewang6a6a0ff2020-06-23 16:32:26 -0700222 case ACK_FREQUENCY_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500223 break;
224
225 case NUM_FRAME_TYPES:
226 QUIC_BUG << "Unknown frame type encountered";
227 break;
228 }
229}
230
231void QuicTraceVisitor::OnIncomingAck(
fayangf8e918b2019-07-16 13:03:16 -0700232 QuicPacketNumber /*ack_packet_number*/,
vasilvv923b6d22020-03-23 11:17:58 -0700233 EncryptionLevel ack_decrypted_level,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500234 const QuicAckFrame& ack_frame,
235 QuicTime ack_receive_time,
236 QuicPacketNumber /*largest_observed*/,
237 bool /*rtt_updated*/,
238 QuicPacketNumber /*least_unacked_sent_packet*/) {
239 quic_trace::Event* event = trace_.add_events();
240 event->set_time_us(ConvertTimestampToRecordedFormat(ack_receive_time));
QUICHE team1f3de242019-03-20 07:24:48 -0700241 event->set_packet_number(connection_->GetLargestReceivedPacket().ToUint64());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500242 event->set_event_type(quic_trace::PACKET_RECEIVED);
vasilvv923b6d22020-03-23 11:17:58 -0700243 event->set_encryption_level(EncryptionLevelToProto(ack_decrypted_level));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500244
245 // TODO(vasilvv): consider removing this copy.
246 QuicAckFrame copy_of_ack = ack_frame;
247 PopulateFrameInfo(QuicFrame(&copy_of_ack), event->add_frames());
248 PopulateTransportState(event->mutable_transport_state());
249}
250
251void QuicTraceVisitor::OnPacketLoss(QuicPacketNumber lost_packet_number,
vasilvv923b6d22020-03-23 11:17:58 -0700252 EncryptionLevel encryption_level,
dschinazi17d42422019-06-18 16:35:07 -0700253 TransmissionType /*transmission_type*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500254 QuicTime detection_time) {
255 quic_trace::Event* event = trace_.add_events();
256 event->set_time_us(ConvertTimestampToRecordedFormat(detection_time));
257 event->set_event_type(quic_trace::PACKET_LOST);
258 event->set_packet_number(lost_packet_number.ToUint64());
259 PopulateTransportState(event->mutable_transport_state());
vasilvv923b6d22020-03-23 11:17:58 -0700260 event->set_encryption_level(EncryptionLevelToProto(encryption_level));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500261}
262
263void QuicTraceVisitor::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
264 const QuicTime& receive_time) {
265 quic_trace::Event* event = trace_.add_events();
266 event->set_time_us(ConvertTimestampToRecordedFormat(receive_time));
267 event->set_event_type(quic_trace::PACKET_RECEIVED);
QUICHE team1f3de242019-03-20 07:24:48 -0700268 event->set_packet_number(connection_->GetLargestReceivedPacket().ToUint64());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500269
270 // TODO(vasilvv): consider removing this copy.
271 QuicWindowUpdateFrame copy_of_update = frame;
272 PopulateFrameInfo(QuicFrame(&copy_of_update), event->add_frames());
273}
274
275void QuicTraceVisitor::OnSuccessfulVersionNegotiation(
276 const ParsedQuicVersion& version) {
QUICHE team173c48f2019-11-19 16:34:44 -0800277 uint32_t tag =
278 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version));
vasilvvc48c8712019-03-11 13:38:16 -0700279 std::string binary_tag(reinterpret_cast<const char*>(&tag), sizeof(tag));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500280 trace_.set_protocol_version(binary_tag);
281}
282
283void QuicTraceVisitor::OnApplicationLimited() {
284 quic_trace::Event* event = trace_.add_events();
285 event->set_time_us(
286 ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow()));
287 event->set_event_type(quic_trace::APPLICATION_LIMITED);
288}
289
290void QuicTraceVisitor::OnAdjustNetworkParameters(QuicBandwidth bandwidth,
fayangbe83ecd2019-04-26 13:58:09 -0700291 QuicTime::Delta rtt,
dschinazi17d42422019-06-18 16:35:07 -0700292 QuicByteCount /*old_cwnd*/,
293 QuicByteCount /*new_cwnd*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500294 quic_trace::Event* event = trace_.add_events();
295 event->set_time_us(
296 ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow()));
297 event->set_event_type(quic_trace::EXTERNAL_PARAMETERS);
298
299 quic_trace::ExternalNetworkParameters* parameters =
300 event->mutable_external_network_parameters();
301 if (!bandwidth.IsZero()) {
302 parameters->set_bandwidth_bps(bandwidth.ToBitsPerSecond());
303 }
304 if (!rtt.IsZero()) {
305 parameters->set_rtt_us(rtt.ToMicroseconds());
306 }
307}
308
309uint64_t QuicTraceVisitor::ConvertTimestampToRecordedFormat(
310 QuicTime timestamp) {
311 if (timestamp < start_time_) {
312 QUIC_BUG << "Timestamp went back in time while recording a trace";
313 return 0;
314 }
315
316 return (timestamp - start_time_).ToMicroseconds();
317}
318
319void QuicTraceVisitor::PopulateTransportState(
320 quic_trace::TransportState* state) {
321 const RttStats* rtt_stats = connection_->sent_packet_manager().GetRttStats();
322 state->set_min_rtt_us(rtt_stats->min_rtt().ToMicroseconds());
323 state->set_smoothed_rtt_us(rtt_stats->smoothed_rtt().ToMicroseconds());
324 state->set_last_rtt_us(rtt_stats->latest_rtt().ToMicroseconds());
325
326 state->set_cwnd_bytes(
327 connection_->sent_packet_manager().GetCongestionWindowInBytes());
328 QuicByteCount in_flight =
329 connection_->sent_packet_manager().GetBytesInFlight();
330 state->set_in_flight_bytes(in_flight);
331 state->set_pacing_rate_bps(connection_->sent_packet_manager()
332 .GetSendAlgorithm()
333 ->PacingRate(in_flight)
334 .ToBitsPerSecond());
335
336 if (connection_->sent_packet_manager()
337 .GetSendAlgorithm()
338 ->GetCongestionControlType() == kPCC) {
339 state->set_congestion_control_state(
340 connection_->sent_packet_manager().GetSendAlgorithm()->GetDebugState());
341 }
342}
343
344} // namespace quic