quic/congestion_control/CongestionController.h (85 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/QuicConstants.h>
#include <quic/state/OutstandingPacket.h>
#include <quic/state/PacketEvent.h>
namespace quic {
struct AckEvent;
struct BbrStats {
uint8_t state;
};
struct CopaStats {
double deltaParam;
bool useRttStanding;
};
struct CubicStats {
uint8_t state;
uint64_t ssthresh;
};
union CongestionControllerStats {
struct BbrStats bbrStats;
struct CopaStats copaStats;
struct CubicStats cubicStats;
};
struct CongestionController {
public:
using AckEvent = quic::AckEvent;
struct State {
uint64_t writableBytes{0};
uint64_t congestionWindowBytes{0};
};
// Helper struct to group multiple lost packets into one event
struct LossEvent {
folly::Optional<PacketNum> largestLostPacketNum;
std::vector<PacketNum> lostPacketNumbers;
uint64_t lostBytes{0};
uint32_t lostPackets{0};
const TimePoint lossTime;
// The packet sent time of the lost packet with largest packet sent time in
// this LossEvent
folly::Optional<TimePoint> largestLostSentTime;
// The packet sent time of the lost packet with smallest packet sent time in
// the LossEvent
folly::Optional<TimePoint> smallestLostSentTime;
// Whether this LossEvent also indicates persistent congestion
bool persistentCongestion{false};
explicit LossEvent(TimePoint time = Clock::now()) : lossTime(time) {}
void addLostPacket(const OutstandingPacket& packet) {
if (std::numeric_limits<uint64_t>::max() - lostBytes <
packet.metadata.encodedSize) {
throw QuicInternalException(
"LossEvent: lostBytes overflow",
LocalErrorCode::LOST_BYTES_OVERFLOW);
}
PacketNum packetNum = packet.packet.header.getPacketSequenceNum();
largestLostPacketNum =
std::max(packetNum, largestLostPacketNum.value_or(packetNum));
lostPacketNumbers.push_back(packetNum);
lostBytes += packet.metadata.encodedSize;
lostPackets++;
largestLostSentTime = std::max(
packet.metadata.time,
largestLostSentTime.value_or(packet.metadata.time));
smallestLostSentTime = std::min(
packet.metadata.time,
smallestLostSentTime.value_or(packet.metadata.time));
}
};
virtual ~CongestionController() = default;
/**
* Take bytes out of flight without mutating other states of the controller
*/
virtual void onRemoveBytesFromInflight(uint64_t) = 0;
virtual void onPacketSent(const OutstandingPacket& packet) = 0;
virtual void onPacketAckOrLoss(
const AckEvent* FOLLY_NULLABLE ackEvent,
const LossEvent* FOLLY_NULLABLE lossEvent) = 0;
/**
* Return the number of bytes that the congestion controller
* will allow you to write.
*/
FOLLY_NODISCARD virtual uint64_t getWritableBytes() const = 0;
/**
* Return the number of bytes of cwnd of the congestion
* controller.
*/
FOLLY_NODISCARD virtual uint64_t getCongestionWindow() const = 0;
/**
* Notify congestion controller that the connection has become idle or active
* in the sense that there are active non-control streams.
* idle: true if the connection has become app-idle, false if the
* connection has become not app-idle.
* eventTime: the time point when the app-idle state changed.
*/
virtual void setAppIdle(bool idle, TimePoint eventTime) = 0;
/**
* Notify congestion controller that the connection has become app-limited or
* not app-limited.
*/
virtual void setAppLimited() = 0;
FOLLY_NODISCARD virtual CongestionControlType type() const = 0;
/**
* Set the congestion controller to use only a fraction of the available
* bandwidth (best-effort for implementations that support it)
* bandwidthUtilizationFactor:
* < 1.0 indicates backgrounded flow
* = 1.0 indicates normal operation.
* > 1.0 maps to =1.0
*/
virtual void setBandwidthUtilizationFactor(
float bandwidthUtilizationFactor) noexcept = 0;
/**
* Whether the congestion controller is making use of all of the available
* bandwidth. Returns true if bandwidthUtilizationFactor < 1.0.
*/
FOLLY_NODISCARD virtual bool isInBackgroundMode() const = 0;
/**
* Whether the congestion controller thinks it's currently in app-limited
* state.
*/
FOLLY_NODISCARD virtual bool isAppLimited() const = 0;
virtual void getStats(CongestionControllerStats& stats) const = 0;
/**
* Get current state of congestion controller.
*/
FOLLY_NODISCARD State getState() const {
State state;
state.congestionWindowBytes = getCongestionWindow();
state.writableBytes = getWritableBytes();
return state;
}
/**
* Enable experimental settings of the congestion controller
*/
virtual void setExperimental(bool /*experimental*/) {}
};
} // namespace quic