blob: 9d18843e89ab47c6540ad732c5ee7f568618969c [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
QUICHE team173c48f2019-11-19 16:34:44 -08009#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050010
11namespace quic {
12
13quic_trace::EncryptionLevel EncryptionLevelToProto(EncryptionLevel level) {
14 switch (level) {
QUICHE team6987b4a2019-03-15 16:23:04 -070015 case ENCRYPTION_INITIAL:
QUICHE teama6ef0a62019-03-07 20:34:33 -050016 return quic_trace::ENCRYPTION_INITIAL;
QUICHE team88ea0082019-03-15 10:05:26 -070017 case ENCRYPTION_HANDSHAKE:
18 return quic_trace::ENCRYPTION_HANDSHAKE;
QUICHE teama6ef0a62019-03-07 20:34:33 -050019 case ENCRYPTION_ZERO_RTT:
20 return quic_trace::ENCRYPTION_0RTT;
21 case ENCRYPTION_FORWARD_SECURE:
22 return quic_trace::ENCRYPTION_1RTT;
23 case NUM_ENCRYPTION_LEVELS:
24 QUIC_BUG << "Invalid encryption level specified";
25 return quic_trace::ENCRYPTION_UNKNOWN;
26 }
27}
28
29QuicTraceVisitor::QuicTraceVisitor(const QuicConnection* connection)
30 : connection_(connection),
31 start_time_(connection_->clock()->ApproximateNow()) {
vasilvvc48c8712019-03-11 13:38:16 -070032 std::string binary_connection_id(connection->connection_id().data(),
33 connection->connection_id().length());
QUICHE teama6ef0a62019-03-07 20:34:33 -050034 // We assume that the connection ID in gQUIC is equivalent to the
35 // server-chosen client-selected ID.
36 switch (connection->perspective()) {
37 case Perspective::IS_CLIENT:
38 trace_.set_destination_connection_id(binary_connection_id);
39 break;
40 case Perspective::IS_SERVER:
41 trace_.set_source_connection_id(binary_connection_id);
42 break;
43 }
44}
45
46void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet,
QUICHE teama6ef0a62019-03-07 20:34:33 -050047 TransmissionType /*transmission_type*/,
48 QuicTime sent_time) {
49 quic_trace::Event* event = trace_.add_events();
50 event->set_event_type(quic_trace::PACKET_SENT);
51 event->set_time_us(ConvertTimestampToRecordedFormat(sent_time));
52 event->set_packet_number(serialized_packet.packet_number.ToUint64());
53 event->set_packet_size(serialized_packet.encrypted_length);
54 event->set_encryption_level(
55 EncryptionLevelToProto(serialized_packet.encryption_level));
56
57 for (const QuicFrame& frame : serialized_packet.retransmittable_frames) {
58 switch (frame.type) {
59 case STREAM_FRAME:
60 case RST_STREAM_FRAME:
61 case CONNECTION_CLOSE_FRAME:
62 case WINDOW_UPDATE_FRAME:
63 case BLOCKED_FRAME:
64 case PING_FRAME:
fayang01062942020-01-22 07:23:23 -080065 case HANDSHAKE_DONE_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -050066 PopulateFrameInfo(frame, event->add_frames());
67 break;
68
69 case PADDING_FRAME:
70 case MTU_DISCOVERY_FRAME:
71 case STOP_WAITING_FRAME:
72 case ACK_FRAME:
73 QUIC_BUG
74 << "Frames of type are not retransmittable and are not supposed "
75 "to be in retransmittable_frames";
76 break;
77
78 // New IETF frames, not used in current gQUIC version.
QUICHE teama6ef0a62019-03-07 20:34:33 -050079 case NEW_CONNECTION_ID_FRAME:
80 case RETIRE_CONNECTION_ID_FRAME:
fkastenholz3c4eabf2019-04-22 07:49:59 -070081 case MAX_STREAMS_FRAME:
82 case STREAMS_BLOCKED_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -050083 case PATH_RESPONSE_FRAME:
84 case PATH_CHALLENGE_FRAME:
85 case STOP_SENDING_FRAME:
86 case MESSAGE_FRAME:
87 case CRYPTO_FRAME:
88 case NEW_TOKEN_FRAME:
89 break;
90
91 // Ignore gQUIC-specific frames.
92 case GOAWAY_FRAME:
93 break;
94
95 case NUM_FRAME_TYPES:
96 QUIC_BUG << "Unknown frame type encountered";
97 break;
98 }
99 }
100
101 // Output PCC DebugState on packet sent for analysis.
102 if (connection_->sent_packet_manager()
103 .GetSendAlgorithm()
104 ->GetCongestionControlType() == kPCC) {
105 PopulateTransportState(event->mutable_transport_state());
106 }
107}
108
109void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame,
110 quic_trace::Frame* frame_record) {
111 switch (frame.type) {
112 case STREAM_FRAME: {
113 frame_record->set_frame_type(quic_trace::STREAM);
114
115 quic_trace::StreamFrameInfo* info =
116 frame_record->mutable_stream_frame_info();
117 info->set_stream_id(frame.stream_frame.stream_id);
118 info->set_fin(frame.stream_frame.fin);
119 info->set_offset(frame.stream_frame.offset);
120 info->set_length(frame.stream_frame.data_length);
121 break;
122 }
123
124 case ACK_FRAME: {
125 frame_record->set_frame_type(quic_trace::ACK);
126
127 quic_trace::AckInfo* info = frame_record->mutable_ack_info();
128 info->set_ack_delay_us(frame.ack_frame->ack_delay_time.ToMicroseconds());
129 for (const auto& interval : frame.ack_frame->packets) {
130 quic_trace::AckBlock* block = info->add_acked_packets();
131 // We record intervals as [a, b], whereas the in-memory representation
132 // we currently use is [a, b).
133 block->set_first_packet(interval.min().ToUint64());
134 block->set_last_packet(interval.max().ToUint64() - 1);
135 }
136 break;
137 }
138
139 case RST_STREAM_FRAME: {
140 frame_record->set_frame_type(quic_trace::RESET_STREAM);
141
142 quic_trace::ResetStreamInfo* info =
143 frame_record->mutable_reset_stream_info();
144 info->set_stream_id(frame.rst_stream_frame->stream_id);
145 info->set_final_offset(frame.rst_stream_frame->byte_offset);
146 info->set_application_error_code(frame.rst_stream_frame->error_code);
147 break;
148 }
149
150 case CONNECTION_CLOSE_FRAME: {
151 frame_record->set_frame_type(quic_trace::CONNECTION_CLOSE);
152
153 quic_trace::CloseInfo* info = frame_record->mutable_close_info();
fkastenholze9d71a82019-04-09 05:12:13 -0700154 info->set_error_code(frame.connection_close_frame->quic_error_code);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155 info->set_reason_phrase(frame.connection_close_frame->error_details);
fkastenholz72f509b2019-04-10 09:17:49 -0700156 info->set_close_type(static_cast<quic_trace::CloseType>(
157 frame.connection_close_frame->close_type));
158 info->set_transport_close_frame_type(
159 frame.connection_close_frame->transport_close_frame_type);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500160 break;
161 }
162
163 case GOAWAY_FRAME:
164 // Do not bother logging this since the frame in question is
165 // gQUIC-specific.
166 break;
167
168 case WINDOW_UPDATE_FRAME: {
169 bool is_connection = frame.window_update_frame->stream_id == 0;
170 frame_record->set_frame_type(is_connection ? quic_trace::MAX_DATA
171 : quic_trace::MAX_STREAM_DATA);
172
173 quic_trace::FlowControlInfo* info =
174 frame_record->mutable_flow_control_info();
renjietangd088eab2019-11-21 14:54:41 -0800175 info->set_max_data(frame.window_update_frame->max_data);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500176 if (!is_connection) {
177 info->set_stream_id(frame.window_update_frame->stream_id);
178 }
179 break;
180 }
181
182 case BLOCKED_FRAME: {
183 bool is_connection = frame.blocked_frame->stream_id == 0;
184 frame_record->set_frame_type(is_connection ? quic_trace::BLOCKED
185 : quic_trace::STREAM_BLOCKED);
186
187 quic_trace::FlowControlInfo* info =
188 frame_record->mutable_flow_control_info();
189 if (!is_connection) {
190 info->set_stream_id(frame.window_update_frame->stream_id);
191 }
192 break;
193 }
194
195 case PING_FRAME:
196 case MTU_DISCOVERY_FRAME:
fayang01062942020-01-22 07:23:23 -0800197 case HANDSHAKE_DONE_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500198 frame_record->set_frame_type(quic_trace::PING);
199 break;
200
201 case PADDING_FRAME:
202 frame_record->set_frame_type(quic_trace::PADDING);
203 break;
204
205 case STOP_WAITING_FRAME:
206 // We're going to pretend those do not exist.
207 break;
208
209 // New IETF frames, not used in current gQUIC version.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500210 case NEW_CONNECTION_ID_FRAME:
211 case RETIRE_CONNECTION_ID_FRAME:
fkastenholz3c4eabf2019-04-22 07:49:59 -0700212 case MAX_STREAMS_FRAME:
213 case STREAMS_BLOCKED_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500214 case PATH_RESPONSE_FRAME:
215 case PATH_CHALLENGE_FRAME:
216 case STOP_SENDING_FRAME:
217 case MESSAGE_FRAME:
218 case CRYPTO_FRAME:
219 case NEW_TOKEN_FRAME:
220 break;
221
222 case NUM_FRAME_TYPES:
223 QUIC_BUG << "Unknown frame type encountered";
224 break;
225 }
226}
227
228void QuicTraceVisitor::OnIncomingAck(
fayangf8e918b2019-07-16 13:03:16 -0700229 QuicPacketNumber /*ack_packet_number*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500230 const QuicAckFrame& ack_frame,
231 QuicTime ack_receive_time,
232 QuicPacketNumber /*largest_observed*/,
233 bool /*rtt_updated*/,
234 QuicPacketNumber /*least_unacked_sent_packet*/) {
235 quic_trace::Event* event = trace_.add_events();
236 event->set_time_us(ConvertTimestampToRecordedFormat(ack_receive_time));
QUICHE team1f3de242019-03-20 07:24:48 -0700237 event->set_packet_number(connection_->GetLargestReceivedPacket().ToUint64());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500238 event->set_event_type(quic_trace::PACKET_RECEIVED);
239
240 // TODO(vasilvv): consider removing this copy.
241 QuicAckFrame copy_of_ack = ack_frame;
242 PopulateFrameInfo(QuicFrame(&copy_of_ack), event->add_frames());
243 PopulateTransportState(event->mutable_transport_state());
244}
245
246void QuicTraceVisitor::OnPacketLoss(QuicPacketNumber lost_packet_number,
dschinazi17d42422019-06-18 16:35:07 -0700247 TransmissionType /*transmission_type*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500248 QuicTime detection_time) {
249 quic_trace::Event* event = trace_.add_events();
250 event->set_time_us(ConvertTimestampToRecordedFormat(detection_time));
251 event->set_event_type(quic_trace::PACKET_LOST);
252 event->set_packet_number(lost_packet_number.ToUint64());
253 PopulateTransportState(event->mutable_transport_state());
254}
255
256void QuicTraceVisitor::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
257 const QuicTime& receive_time) {
258 quic_trace::Event* event = trace_.add_events();
259 event->set_time_us(ConvertTimestampToRecordedFormat(receive_time));
260 event->set_event_type(quic_trace::PACKET_RECEIVED);
QUICHE team1f3de242019-03-20 07:24:48 -0700261 event->set_packet_number(connection_->GetLargestReceivedPacket().ToUint64());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500262
263 // TODO(vasilvv): consider removing this copy.
264 QuicWindowUpdateFrame copy_of_update = frame;
265 PopulateFrameInfo(QuicFrame(&copy_of_update), event->add_frames());
266}
267
268void QuicTraceVisitor::OnSuccessfulVersionNegotiation(
269 const ParsedQuicVersion& version) {
QUICHE team173c48f2019-11-19 16:34:44 -0800270 uint32_t tag =
271 quiche::QuicheEndian::HostToNet32(CreateQuicVersionLabel(version));
vasilvvc48c8712019-03-11 13:38:16 -0700272 std::string binary_tag(reinterpret_cast<const char*>(&tag), sizeof(tag));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273 trace_.set_protocol_version(binary_tag);
274}
275
276void QuicTraceVisitor::OnApplicationLimited() {
277 quic_trace::Event* event = trace_.add_events();
278 event->set_time_us(
279 ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow()));
280 event->set_event_type(quic_trace::APPLICATION_LIMITED);
281}
282
283void QuicTraceVisitor::OnAdjustNetworkParameters(QuicBandwidth bandwidth,
fayangbe83ecd2019-04-26 13:58:09 -0700284 QuicTime::Delta rtt,
dschinazi17d42422019-06-18 16:35:07 -0700285 QuicByteCount /*old_cwnd*/,
286 QuicByteCount /*new_cwnd*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500287 quic_trace::Event* event = trace_.add_events();
288 event->set_time_us(
289 ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow()));
290 event->set_event_type(quic_trace::EXTERNAL_PARAMETERS);
291
292 quic_trace::ExternalNetworkParameters* parameters =
293 event->mutable_external_network_parameters();
294 if (!bandwidth.IsZero()) {
295 parameters->set_bandwidth_bps(bandwidth.ToBitsPerSecond());
296 }
297 if (!rtt.IsZero()) {
298 parameters->set_rtt_us(rtt.ToMicroseconds());
299 }
300}
301
302uint64_t QuicTraceVisitor::ConvertTimestampToRecordedFormat(
303 QuicTime timestamp) {
304 if (timestamp < start_time_) {
305 QUIC_BUG << "Timestamp went back in time while recording a trace";
306 return 0;
307 }
308
309 return (timestamp - start_time_).ToMicroseconds();
310}
311
312void QuicTraceVisitor::PopulateTransportState(
313 quic_trace::TransportState* state) {
314 const RttStats* rtt_stats = connection_->sent_packet_manager().GetRttStats();
315 state->set_min_rtt_us(rtt_stats->min_rtt().ToMicroseconds());
316 state->set_smoothed_rtt_us(rtt_stats->smoothed_rtt().ToMicroseconds());
317 state->set_last_rtt_us(rtt_stats->latest_rtt().ToMicroseconds());
318
319 state->set_cwnd_bytes(
320 connection_->sent_packet_manager().GetCongestionWindowInBytes());
321 QuicByteCount in_flight =
322 connection_->sent_packet_manager().GetBytesInFlight();
323 state->set_in_flight_bytes(in_flight);
324 state->set_pacing_rate_bps(connection_->sent_packet_manager()
325 .GetSendAlgorithm()
326 ->PacingRate(in_flight)
327 .ToBitsPerSecond());
328
329 if (connection_->sent_packet_manager()
330 .GetSendAlgorithm()
331 ->GetCongestionControlType() == kPCC) {
332 state->set_congestion_control_state(
333 connection_->sent_packet_manager().GetSendAlgorithm()->GetDebugState());
334 }
335}
336
337} // namespace quic