blob: 42ee003966d37df7fd816e42b11cb73d891da95f [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 teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/platform/api/quic_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,
47 QuicPacketNumber /*original_packet_number*/,
48 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:
66 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();
175 info->set_max_data(frame.window_update_frame->byte_offset);
176 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:
197 frame_record->set_frame_type(quic_trace::PING);
198 break;
199
200 case PADDING_FRAME:
201 frame_record->set_frame_type(quic_trace::PADDING);
202 break;
203
204 case STOP_WAITING_FRAME:
205 // We're going to pretend those do not exist.
206 break;
207
208 // New IETF frames, not used in current gQUIC version.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500209 case NEW_CONNECTION_ID_FRAME:
210 case RETIRE_CONNECTION_ID_FRAME:
fkastenholz3c4eabf2019-04-22 07:49:59 -0700211 case MAX_STREAMS_FRAME:
212 case STREAMS_BLOCKED_FRAME:
QUICHE teama6ef0a62019-03-07 20:34:33 -0500213 case PATH_RESPONSE_FRAME:
214 case PATH_CHALLENGE_FRAME:
215 case STOP_SENDING_FRAME:
216 case MESSAGE_FRAME:
217 case CRYPTO_FRAME:
218 case NEW_TOKEN_FRAME:
219 break;
220
221 case NUM_FRAME_TYPES:
222 QUIC_BUG << "Unknown frame type encountered";
223 break;
224 }
225}
226
227void QuicTraceVisitor::OnIncomingAck(
fayangf8e918b2019-07-16 13:03:16 -0700228 QuicPacketNumber /*ack_packet_number*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500229 const QuicAckFrame& ack_frame,
230 QuicTime ack_receive_time,
231 QuicPacketNumber /*largest_observed*/,
232 bool /*rtt_updated*/,
233 QuicPacketNumber /*least_unacked_sent_packet*/) {
234 quic_trace::Event* event = trace_.add_events();
235 event->set_time_us(ConvertTimestampToRecordedFormat(ack_receive_time));
QUICHE team1f3de242019-03-20 07:24:48 -0700236 event->set_packet_number(connection_->GetLargestReceivedPacket().ToUint64());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500237 event->set_event_type(quic_trace::PACKET_RECEIVED);
238
239 // TODO(vasilvv): consider removing this copy.
240 QuicAckFrame copy_of_ack = ack_frame;
241 PopulateFrameInfo(QuicFrame(&copy_of_ack), event->add_frames());
242 PopulateTransportState(event->mutable_transport_state());
243}
244
245void QuicTraceVisitor::OnPacketLoss(QuicPacketNumber lost_packet_number,
dschinazi17d42422019-06-18 16:35:07 -0700246 TransmissionType /*transmission_type*/,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500247 QuicTime detection_time) {
248 quic_trace::Event* event = trace_.add_events();
249 event->set_time_us(ConvertTimestampToRecordedFormat(detection_time));
250 event->set_event_type(quic_trace::PACKET_LOST);
251 event->set_packet_number(lost_packet_number.ToUint64());
252 PopulateTransportState(event->mutable_transport_state());
253}
254
255void QuicTraceVisitor::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
256 const QuicTime& receive_time) {
257 quic_trace::Event* event = trace_.add_events();
258 event->set_time_us(ConvertTimestampToRecordedFormat(receive_time));
259 event->set_event_type(quic_trace::PACKET_RECEIVED);
QUICHE team1f3de242019-03-20 07:24:48 -0700260 event->set_packet_number(connection_->GetLargestReceivedPacket().ToUint64());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500261
262 // TODO(vasilvv): consider removing this copy.
263 QuicWindowUpdateFrame copy_of_update = frame;
264 PopulateFrameInfo(QuicFrame(&copy_of_update), event->add_frames());
265}
266
267void QuicTraceVisitor::OnSuccessfulVersionNegotiation(
268 const ParsedQuicVersion& version) {
269 uint32_t tag = QuicEndian::HostToNet32(CreateQuicVersionLabel(version));
vasilvvc48c8712019-03-11 13:38:16 -0700270 std::string binary_tag(reinterpret_cast<const char*>(&tag), sizeof(tag));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500271 trace_.set_protocol_version(binary_tag);
272}
273
274void QuicTraceVisitor::OnApplicationLimited() {
275 quic_trace::Event* event = trace_.add_events();
276 event->set_time_us(
277 ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow()));
278 event->set_event_type(quic_trace::APPLICATION_LIMITED);
279}
280
281void QuicTraceVisitor::OnAdjustNetworkParameters(QuicBandwidth bandwidth,
fayangbe83ecd2019-04-26 13:58:09 -0700282 QuicTime::Delta rtt,
dschinazi17d42422019-06-18 16:35:07 -0700283 QuicByteCount /*old_cwnd*/,
284 QuicByteCount /*new_cwnd*/) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500285 quic_trace::Event* event = trace_.add_events();
286 event->set_time_us(
287 ConvertTimestampToRecordedFormat(connection_->clock()->ApproximateNow()));
288 event->set_event_type(quic_trace::EXTERNAL_PARAMETERS);
289
290 quic_trace::ExternalNetworkParameters* parameters =
291 event->mutable_external_network_parameters();
292 if (!bandwidth.IsZero()) {
293 parameters->set_bandwidth_bps(bandwidth.ToBitsPerSecond());
294 }
295 if (!rtt.IsZero()) {
296 parameters->set_rtt_us(rtt.ToMicroseconds());
297 }
298}
299
300uint64_t QuicTraceVisitor::ConvertTimestampToRecordedFormat(
301 QuicTime timestamp) {
302 if (timestamp < start_time_) {
303 QUIC_BUG << "Timestamp went back in time while recording a trace";
304 return 0;
305 }
306
307 return (timestamp - start_time_).ToMicroseconds();
308}
309
310void QuicTraceVisitor::PopulateTransportState(
311 quic_trace::TransportState* state) {
312 const RttStats* rtt_stats = connection_->sent_packet_manager().GetRttStats();
313 state->set_min_rtt_us(rtt_stats->min_rtt().ToMicroseconds());
314 state->set_smoothed_rtt_us(rtt_stats->smoothed_rtt().ToMicroseconds());
315 state->set_last_rtt_us(rtt_stats->latest_rtt().ToMicroseconds());
316
317 state->set_cwnd_bytes(
318 connection_->sent_packet_manager().GetCongestionWindowInBytes());
319 QuicByteCount in_flight =
320 connection_->sent_packet_manager().GetBytesInFlight();
321 state->set_in_flight_bytes(in_flight);
322 state->set_pacing_rate_bps(connection_->sent_packet_manager()
323 .GetSendAlgorithm()
324 ->PacingRate(in_flight)
325 .ToBitsPerSecond());
326
327 if (connection_->sent_packet_manager()
328 .GetSendAlgorithm()
329 ->GetCongestionControlType() == kPCC) {
330 state->set_congestion_control_state(
331 connection_->sent_packet_manager().GetSendAlgorithm()->GetDebugState());
332 }
333}
334
335} // namespace quic