1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 */ 8 9 #pragma once 10 11 #include <folly/Optional.h> 12 #include <folly/functional/Invoke.h> 13 #include <folly/io/async/EventBase.h> 14 #include <string> 15 16 #include <quic/QuicConstants.h> 17 #include <quic/QuicException.h> 18 19 namespace quic { 20 21 /* Interface for Transport level stats per VIP (server) 22 * Quic Transport expects applications to instantiate this per thread (and 23 * do necessary aggregation at the application level). 24 * 25 * NOTE: since several of these methods are called for every single packets, 26 * and every single connection, it is extremely important to not do any 27 * blocking call in any of the implementation of these methods. 28 */ 29 class QuicTransportStatsCallback { 30 public: 31 enum class PacketDropReason : uint8_t { 32 NONE, 33 CONNECTION_NOT_FOUND, 34 DECRYPTION_ERROR, 35 INVALID_PACKET, 36 PARSE_ERROR, 37 PEER_ADDRESS_CHANGE, 38 PROTOCOL_VIOLATION, 39 ROUTING_ERROR_WRONG_HOST, 40 SERVER_STATE_CLOSED, 41 TRANSPORT_PARAMETER_ERROR, 42 WORKER_NOT_INITIALIZED, 43 SERVER_SHUTDOWN, 44 INITIAL_CONNID_SMALL, 45 CANNOT_MAKE_TRANSPORT, 46 UDP_TRUNCATED, 47 CLIENT_STATE_CLOSED, 48 CLIENT_SHUTDOWN, 49 INVALID_SRC_PORT, 50 // NOTE: MAX should always be at the end 51 MAX 52 }; 53 54 enum class SocketErrorType : uint8_t { 55 AGAIN, 56 INVAL, 57 MSGSIZE, 58 NOBUFS, 59 NOMEM, 60 OTHER, 61 MAX 62 }; 63 64 enum class TransportKnobType : uint8_t { 65 ZERO_PMTU_BLACKHOLE, 66 FORCIBLY_SET_UDP_PAYLOAD_SIZE, 67 UNKNOWN, 68 MAX 69 }; 70 71 virtual ~QuicTransportStatsCallback() = default; 72 73 // packet level metrics 74 virtual void onPacketReceived() = 0; 75 76 virtual void onDuplicatedPacketReceived() = 0; 77 78 virtual void onOutOfOrderPacketReceived() = 0; 79 80 virtual void onPacketProcessed() = 0; 81 82 virtual void onPacketSent() = 0; 83 84 virtual void onPacketRetransmission() = 0; 85 86 virtual void onPacketLoss() = 0; 87 88 virtual void onPacketSpuriousLoss() = 0; 89 90 virtual void onPersistentCongestion() = 0; 91 92 virtual void onPacketDropped(PacketDropReason reason) = 0; 93 94 virtual void onPacketForwarded() = 0; 95 96 virtual void onForwardedPacketReceived() = 0; 97 98 virtual void onForwardedPacketProcessed() = 0; 99 100 virtual void onClientInitialReceived(QuicVersion version) = 0; 101 102 virtual void onConnectionRateLimited() = 0; 103 104 // connection level metrics: 105 virtual void onNewConnection() = 0; 106 107 virtual void onConnectionClose( 108 folly::Optional<QuicErrorCode> code = folly::none) = 0; 109 110 // stream level metrics 111 virtual void onNewQuicStream() = 0; 112 113 virtual void onQuicStreamClosed() = 0; 114 115 virtual void onQuicStreamReset(QuicErrorCode code) = 0; 116 117 // flow control / congestion control / loss recovery related metrics 118 virtual void onConnFlowControlUpdate() = 0; 119 120 virtual void onConnFlowControlBlocked() = 0; 121 122 virtual void onStatelessReset() = 0; 123 124 virtual void onStreamFlowControlUpdate() = 0; 125 126 virtual void onStreamFlowControlBlocked() = 0; 127 128 virtual void onCwndBlocked() = 0; 129 130 virtual void onNewCongestionController(CongestionControlType type) = 0; 131 132 // retransmission timeout counter 133 virtual void onPTO() = 0; 134 135 // metrics to track bytes read from / written to wire 136 virtual void onRead(size_t bufSize) = 0; 137 138 virtual void onWrite(size_t bufSize) = 0; 139 140 virtual void onUDPSocketWriteError(SocketErrorType errorType) = 0; 141 142 virtual void onConnectionD6DStarted() = 0; 143 144 virtual void onConnectionPMTURaised() = 0; 145 146 virtual void onConnectionPMTUBlackholeDetected() = 0; 147 148 virtual void onConnectionPMTUUpperBoundDetected() = 0; 149 150 virtual void onTransportKnobApplied(TransportKnobType knobType) = 0; 151 152 virtual void onTransportKnobError(TransportKnobType knobType) = 0; 153 154 virtual void onServerUnfinishedHandshake() = 0; 155 156 virtual void onZeroRttBuffered() = 0; 157 158 virtual void onZeroRttBufferedPruned() = 0; 159 160 virtual void onZeroRttAccepted() = 0; 161 162 virtual void onZeroRttRejected() = 0; 163 toString(PacketDropReason reason)164 static const char* toString(PacketDropReason reason) { 165 switch (reason) { 166 case PacketDropReason::NONE: 167 return "NONE"; 168 case PacketDropReason::CONNECTION_NOT_FOUND: 169 return "CONNECTION_NOT_FOUND"; 170 case PacketDropReason::DECRYPTION_ERROR: 171 return "DECRYPTION_ERROR"; 172 case PacketDropReason::INVALID_PACKET: 173 return "INVALID_PACKET"; 174 case PacketDropReason::PARSE_ERROR: 175 return "PARSE_ERROR"; 176 case PacketDropReason::PEER_ADDRESS_CHANGE: 177 return "PEER_ADDRESS_CHANGE"; 178 case PacketDropReason::PROTOCOL_VIOLATION: 179 return "PROTOCOL_VIOLATION"; 180 case PacketDropReason::ROUTING_ERROR_WRONG_HOST: 181 return "ROUTING_ERROR_WRONG_HOST"; 182 case PacketDropReason::SERVER_STATE_CLOSED: 183 return "SERVER_STATE_CLOSED"; 184 case PacketDropReason::TRANSPORT_PARAMETER_ERROR: 185 return "TRANSPORT_PARAMETER_ERROR"; 186 case PacketDropReason::WORKER_NOT_INITIALIZED: 187 return "WORKER_NOT_INITIALIZED"; 188 case PacketDropReason::SERVER_SHUTDOWN: 189 return "SERVER_SHUTDOWN"; 190 case PacketDropReason::INITIAL_CONNID_SMALL: 191 return "INITIAL_CONNID_SMALL"; 192 case PacketDropReason::CANNOT_MAKE_TRANSPORT: 193 return "CANNOT_MAKE_TRANSPORT"; 194 case PacketDropReason::UDP_TRUNCATED: 195 return "UDP_TRUNCATED"; 196 case PacketDropReason::CLIENT_STATE_CLOSED: 197 return "CLIENT_STATE_CLOSED"; 198 case PacketDropReason::CLIENT_SHUTDOWN: 199 return "CLIENT_SHUTDOWN"; 200 case PacketDropReason::INVALID_SRC_PORT: 201 return "INVALID_SRC_PORT"; 202 case PacketDropReason::MAX: 203 return "MAX"; 204 default: 205 throw std::runtime_error("Undefined PacketDropReason passed"); 206 } 207 } 208 toString(SocketErrorType errorType)209 static const char* toString(SocketErrorType errorType) { 210 switch (errorType) { 211 case SocketErrorType::AGAIN: 212 return "AGAIN"; 213 case SocketErrorType::INVAL: 214 return "INVAL"; 215 case SocketErrorType::MSGSIZE: 216 return "MSGSIZE"; 217 case SocketErrorType::NOBUFS: 218 return "NOBUFS"; 219 case SocketErrorType::NOMEM: 220 return "NOMEM"; 221 case SocketErrorType::OTHER: 222 return "Other"; 223 default: 224 throw std::runtime_error("Undefined SocketErrorType"); 225 } 226 } 227 errnoToSocketErrorType(int err)228 static SocketErrorType errnoToSocketErrorType(int err) { 229 switch (err) { 230 case EAGAIN: 231 return SocketErrorType::AGAIN; 232 case EINVAL: 233 return SocketErrorType::INVAL; 234 case EMSGSIZE: 235 return SocketErrorType::MSGSIZE; 236 case ENOBUFS: 237 return SocketErrorType::NOBUFS; 238 case ENOMEM: 239 return SocketErrorType::NOMEM; 240 default: 241 return SocketErrorType::OTHER; 242 } 243 } 244 toString(TransportKnobType knobType)245 static const char* toString(TransportKnobType knobType) { 246 switch (knobType) { 247 case TransportKnobType::ZERO_PMTU_BLACKHOLE: 248 return "ZERO_PMTU_BLACKHOLE"; 249 case TransportKnobType::FORCIBLY_SET_UDP_PAYLOAD_SIZE: 250 return "FORCIBLY_SET_UDP_PAYLOAD_SIZE"; 251 case TransportKnobType::UNKNOWN: 252 return "UNKNOWN"; 253 case TransportKnobType::MAX: 254 return "MAX"; 255 default: 256 throw std::runtime_error("Undefined TransportKnobType passed"); 257 } 258 } 259 paramIdToTransportKnobType(uint64_t paramId)260 static TransportKnobType paramIdToTransportKnobType(uint64_t paramId) { 261 switch (paramId) { 262 case static_cast<uint64_t>( 263 TransportKnobParamId::ZERO_PMTU_BLACKHOLE_DETECTION): 264 return TransportKnobType::ZERO_PMTU_BLACKHOLE; 265 case static_cast<uint64_t>( 266 TransportKnobParamId::FORCIBLY_SET_UDP_PAYLOAD_SIZE): 267 return TransportKnobType::FORCIBLY_SET_UDP_PAYLOAD_SIZE; 268 default: 269 return TransportKnobType::UNKNOWN; 270 } 271 } 272 }; 273 274 /** 275 * Interface to create QuicTransportStatsCallback instance. 276 * If application supplies the implementation of this factory, the transport 277 * calls 'make' during its initialization _for each worker_. 278 * Further, 'make' is called from the worker's eventbase so that it is 279 * convenient for application to specify actions such as scheduling per thread 280 * aggregation 281 */ 282 class QuicTransportStatsCallbackFactory { 283 public: 284 virtual ~QuicTransportStatsCallbackFactory() = default; 285 286 virtual std::unique_ptr<QuicTransportStatsCallback> make() = 0; 287 }; 288 289 #define QUIC_STATS(statsCallback, method, ...) \ 290 if (statsCallback) { \ 291 folly::invoke( \ 292 &QuicTransportStatsCallback::method, statsCallback, ##__VA_ARGS__); \ 293 } 294 295 #define QUIC_STATS_FOR_EACH(iterBegin, iterEnd, statsCallback, method, ...) \ 296 if (statsCallback) { \ 297 std::for_each(iterBegin, iterEnd, [&](const auto&) { \ 298 folly::invoke( \ 299 &QuicTransportStatsCallback::method, statsCallback, ##__VA_ARGS__); \ 300 }); \ 301 } 302 } // namespace quic 303