quic/state/QuicTransportStatsCallback.h (192 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <folly/Optional.h> #include <folly/functional/Invoke.h> #include <folly/io/async/EventBase.h> #include <string> #include <quic/QuicConstants.h> #include <quic/QuicException.h> namespace quic { /* Interface for Transport level stats per VIP (server) * Quic Transport expects applications to instantiate this per thread (and * do necessary aggregation at the application level). * * NOTE: since several of these methods are called for every single packets, * and every single connection, it is extremely important to not do any * blocking call in any of the implementation of these methods. */ class QuicTransportStatsCallback { public: enum class PacketDropReason : uint8_t { NONE, CONNECTION_NOT_FOUND, DECRYPTION_ERROR, INVALID_PACKET, PARSE_ERROR, PEER_ADDRESS_CHANGE, PROTOCOL_VIOLATION, ROUTING_ERROR_WRONG_HOST, SERVER_STATE_CLOSED, TRANSPORT_PARAMETER_ERROR, WORKER_NOT_INITIALIZED, SERVER_SHUTDOWN, INITIAL_CONNID_SMALL, CANNOT_MAKE_TRANSPORT, UDP_TRUNCATED, CLIENT_STATE_CLOSED, CLIENT_SHUTDOWN, INVALID_SRC_PORT, // NOTE: MAX should always be at the end MAX }; enum class SocketErrorType : uint8_t { AGAIN, INVAL, MSGSIZE, NOBUFS, NOMEM, OTHER, MAX }; virtual ~QuicTransportStatsCallback() = default; // packet level metrics virtual void onPacketReceived() = 0; virtual void onDuplicatedPacketReceived() = 0; virtual void onOutOfOrderPacketReceived() = 0; virtual void onPacketProcessed() = 0; virtual void onPacketSent() = 0; virtual void onDSRPacketSent(size_t pktSize) = 0; virtual void onPacketRetransmission() = 0; virtual void onPacketLoss() = 0; virtual void onPacketSpuriousLoss() = 0; virtual void onPersistentCongestion() = 0; virtual void onPacketDropped(PacketDropReason reason) = 0; virtual void onPacketForwarded() = 0; virtual void onForwardedPacketReceived() = 0; virtual void onForwardedPacketProcessed() = 0; virtual void onClientInitialReceived(QuicVersion version) = 0; virtual void onConnectionRateLimited() = 0; virtual void onNewTokenReceived() = 0; virtual void onNewTokenIssued() = 0; virtual void onTokenDecryptFailure() = 0; // connection level metrics: virtual void onNewConnection() = 0; virtual void onConnectionClose( folly::Optional<QuicErrorCode> code = folly::none) = 0; virtual void onConnectionCloseZeroBytesWritten() = 0; // stream level metrics virtual void onNewQuicStream() = 0; virtual void onQuicStreamClosed() = 0; virtual void onQuicStreamReset(QuicErrorCode code) = 0; // flow control / congestion control / loss recovery related metrics virtual void onConnFlowControlUpdate() = 0; virtual void onConnFlowControlBlocked() = 0; virtual void onStatelessReset() = 0; virtual void onStreamFlowControlUpdate() = 0; virtual void onStreamFlowControlBlocked() = 0; virtual void onCwndBlocked() = 0; virtual void onNewCongestionController(CongestionControlType type) = 0; // retransmission timeout counter virtual void onPTO() = 0; // metrics to track bytes read from / written to wire virtual void onRead(size_t bufSize) = 0; virtual void onWrite(size_t bufSize) = 0; virtual void onUDPSocketWriteError(SocketErrorType errorType) = 0; virtual void onConnectionD6DStarted() = 0; virtual void onConnectionPMTURaised() = 0; virtual void onConnectionPMTUBlackholeDetected() = 0; virtual void onConnectionPMTUUpperBoundDetected() = 0; virtual void onTransportKnobApplied(TransportKnobParamId knobType) = 0; virtual void onTransportKnobError(TransportKnobParamId knobType) = 0; virtual void onServerUnfinishedHandshake() = 0; virtual void onZeroRttBuffered() = 0; virtual void onZeroRttBufferedPruned() = 0; virtual void onZeroRttAccepted() = 0; virtual void onZeroRttRejected() = 0; virtual void onDatagramRead(size_t datagramSize) = 0; virtual void onDatagramWrite(size_t datagramSize) = 0; virtual void onDatagramDroppedOnWrite() = 0; virtual void onDatagramDroppedOnRead() = 0; virtual void onShortHeaderPadding(size_t padSize) = 0; virtual void onPacerTimerLagged() = 0; static const char* toString(PacketDropReason reason) { switch (reason) { case PacketDropReason::NONE: return "NONE"; case PacketDropReason::CONNECTION_NOT_FOUND: return "CONNECTION_NOT_FOUND"; case PacketDropReason::DECRYPTION_ERROR: return "DECRYPTION_ERROR"; case PacketDropReason::INVALID_PACKET: return "INVALID_PACKET"; case PacketDropReason::PARSE_ERROR: return "PARSE_ERROR"; case PacketDropReason::PEER_ADDRESS_CHANGE: return "PEER_ADDRESS_CHANGE"; case PacketDropReason::PROTOCOL_VIOLATION: return "PROTOCOL_VIOLATION"; case PacketDropReason::ROUTING_ERROR_WRONG_HOST: return "ROUTING_ERROR_WRONG_HOST"; case PacketDropReason::SERVER_STATE_CLOSED: return "SERVER_STATE_CLOSED"; case PacketDropReason::TRANSPORT_PARAMETER_ERROR: return "TRANSPORT_PARAMETER_ERROR"; case PacketDropReason::WORKER_NOT_INITIALIZED: return "WORKER_NOT_INITIALIZED"; case PacketDropReason::SERVER_SHUTDOWN: return "SERVER_SHUTDOWN"; case PacketDropReason::INITIAL_CONNID_SMALL: return "INITIAL_CONNID_SMALL"; case PacketDropReason::CANNOT_MAKE_TRANSPORT: return "CANNOT_MAKE_TRANSPORT"; case PacketDropReason::UDP_TRUNCATED: return "UDP_TRUNCATED"; case PacketDropReason::CLIENT_STATE_CLOSED: return "CLIENT_STATE_CLOSED"; case PacketDropReason::CLIENT_SHUTDOWN: return "CLIENT_SHUTDOWN"; case PacketDropReason::INVALID_SRC_PORT: return "INVALID_SRC_PORT"; case PacketDropReason::MAX: return "MAX"; default: throw std::runtime_error("Undefined PacketDropReason passed"); } } static const char* toString(SocketErrorType errorType) { switch (errorType) { case SocketErrorType::AGAIN: return "AGAIN"; case SocketErrorType::INVAL: return "INVAL"; case SocketErrorType::MSGSIZE: return "MSGSIZE"; case SocketErrorType::NOBUFS: return "NOBUFS"; case SocketErrorType::NOMEM: return "NOMEM"; case SocketErrorType::OTHER: return "Other"; default: throw std::runtime_error("Undefined SocketErrorType"); } } static SocketErrorType errnoToSocketErrorType(int err) { switch (err) { case EAGAIN: return SocketErrorType::AGAIN; case EINVAL: return SocketErrorType::INVAL; case EMSGSIZE: return SocketErrorType::MSGSIZE; case ENOBUFS: return SocketErrorType::NOBUFS; case ENOMEM: return SocketErrorType::NOMEM; default: return SocketErrorType::OTHER; } } }; /** * Interface to create QuicTransportStatsCallback instance. * If application supplies the implementation of this factory, the transport * calls 'make' during its initialization _for each worker_. * Further, 'make' is called from the worker's eventbase so that it is * convenient for application to specify actions such as scheduling per thread * aggregation */ class QuicTransportStatsCallbackFactory { public: virtual ~QuicTransportStatsCallbackFactory() = default; virtual std::unique_ptr<QuicTransportStatsCallback> make() = 0; }; #define QUIC_STATS(statsCallback, method, ...) \ if (statsCallback) { \ folly::invoke( \ &QuicTransportStatsCallback::method, statsCallback, ##__VA_ARGS__); \ } #define QUIC_STATS_FOR_EACH(iterBegin, iterEnd, statsCallback, method, ...) \ if (statsCallback) { \ std::for_each(iterBegin, iterEnd, [&](const auto&) { \ folly::invoke( \ &QuicTransportStatsCallback::method, statsCallback, ##__VA_ARGS__); \ }); \ } } // namespace quic