quic/congestion_control/QuicCCP.h (54 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 <quic/QuicException.h> #include <quic/congestion_control/Bandwidth.h> #include <quic/congestion_control/CongestionController.h> #include <quic/congestion_control/QuicCubic.h> #include <quic/server/state/ServerStateMachine.h> #include <quic/state/AckEvent.h> #include <quic/state/StateData.h> #ifdef CCP_ENABLED #include <ccp/ccp.h> #endif #include <limits> namespace quic { /** * The class defines CCP as a congestion control "algorithm", but it really acts * as a proxy layer between the datapath (mvfst) and CCP. Each instance of this * class corresponds to a separate connection that is using CCP for congestion * control. * * From the perspective of this class, the behavior is very simple: * - On each ack or loss, it updates some statistics about the connection (rtt * etc.) * - Once in a while, after updating it will batch the last few updates and send * them to CCP (via IPC). * - Asynchronously, at any time CCP may send a message (via IPC) telling this * connection to use a new cwnd or rate. CCPReader receives these messages, * looks up the correct instance of QuicCCP for that connection, and calls * setCongestionWindow or setPacingRate. This class does not contain any logic * for updating the cwnd (or rate) directly, they only change when directed by * CCP. * * The low-level functionality, such as batching updates, serializing them, * sending IPC, etc. is handled by libccp, which is a helper library provided by * the CCP authors. * * If, for whatever reason, mvfst has not received any responses from CCP for a * while, we go into "fallback" mode and use cubic instead, by simply proxying * the acks, losses, and cwnd updates to an internal instance of QuicCubic. If * connection is re-established with CCP, we leave fallback mode and pick up the * cwnd where cubic left off. * */ class CCP : public CongestionController { public: explicit CCP(QuicConnectionStateBase& conn); ~CCP() override; void onRemoveBytesFromInflight(uint64_t) override; void onPacketSent(const OutstandingPacket& packet) override; void onPacketAckOrLoss( const AckEvent* FOLLY_NULLABLE, const LossEvent* FOLLY_NULLABLE) override; void onPacketAckOrLoss( folly::Optional<AckEvent> ack, folly::Optional<LossEvent> loss) { onPacketAckOrLoss(ack.get_pointer(), loss.get_pointer()); } FOLLY_NODISCARD uint64_t getWritableBytes() const noexcept override; FOLLY_NODISCARD uint64_t getCongestionWindow() const noexcept override; // Called (indirectly) by CCP when it wants to update the cwnd for this // connection. void setCongestionWindow(uint64_t cwnd) noexcept; void setAppIdle(bool, TimePoint) noexcept override; void setAppLimited() override; FOLLY_NODISCARD CongestionControlType type() const noexcept override; FOLLY_NODISCARD uint64_t getBytesInFlight() const noexcept; // Called indirectly by CCP when it wants to update the pacing rate for this // connection. void setPacingRate(uint64_t rate) noexcept; FOLLY_NODISCARD bool isAppLimited() const noexcept override; void getStats(CongestionControllerStats& /*stats*/) const override {} private: void onLossEvent(const LossEvent&); void onAckEvent(const AckEvent&); // Fallback to in-datapath congestion control impl (eg. because ccp not // responding) void fallback(); // Go back to using CCP after a period of fallback void restoreAfterFallback(); private: QuicServerConnectionState& conn_; // The current cwnd for this connection when we are not in fallback mode. // When we are in fallback mode, we instead use // fallbackCC_->getCongestionWindow(). uint64_t cwndBytes_; // The current pacing rate for this connection when we are not in fallback // mode. When we are in fallback mode, the pacing rate is set by fallbackCC_. uint64_t pacingRate_{0}; // The per-connection state needed by libccp, initialized by calling // libccp::ccp_connection_start in the constructor. struct ccp_connection* ccp_conn_{nullptr}; // The global (per QuicServerWorker) state needed by libccp, retrieved from // the connection's corresponding QuicServerConnectionState. struct ccp_datapath* datapath_{nullptr}; // Used to help ensure we don't count the same loss event multiple times. folly::Optional<TimePoint> endOfRecovery_; // Current estimate of the send and ack rate, two of the basic statistics sent // to CCP. Bandwidth sendRate_, ackRate_; // Whether or not we are in fallback mode. bool inFallback_; // An instance of QuicCubic to use during fallback mode. Cubic fallbackCC_; }; } // namespace quic