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