Skip to content

Added GetParam for Network Statistics #5119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ These parameters are accessed by calling [GetParam](./api/GetParam.md) or [SetPa
| `QUIC_PARAM_CONN_STATISTICS_V2_PLAT`<br> 23 | QUIC_STATISTICS_V2 | Get-only | Connection-level statistics with platform-specific time format, version 2. |
| `QUIC_PARAM_CONN_ORIG_DEST_CID` <br> 24 | uint8_t[] | Get-only | The original destination connection ID used by the client to connect to the server. |
| `QUIC_PARAM_CONN_SEND_DSCP` <br> 25 | uint8_t | Both | The DiffServ Code Point put in the DiffServ field (formerly TypeOfService/TrafficClass) on packets sent from this connection. |
| `QUIC_PARAM_CONN_NETWORK_STATISTICS` <br> 20 | QUIC_NETWORK_STATISTICS | Get-only | Returns Connection level network statistics |

### QUIC_PARAM_CONN_STATISTICS_V2

Expand Down
11 changes: 2 additions & 9 deletions docs/api/QUIC_CONNECTION_EVENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,7 @@ typedef struct QUIC_CONNECTION_EVENT {
BOOLEAN SendNegotiated; // TRUE if sending one-way delay timestamps is negotiated.
BOOLEAN ReceiveNegotiated; // TRUE if receiving one-way delay timestamps is negotiated.
} ONE_WAY_DELAY_NEGOTIATED;
struct {
uint32_t BytesInFlight; // Bytes that were sent on the wire, but not yet acked
uint64_t PostedBytes; // Total bytes queued, but not yet acked. These may contain sent bytes that may have potentially lost too.
uint64_t IdealBytes; // Ideal number of bytes required to be available to avoid limiting throughput
uint64_t SmoothedRTT; // Smoothed RTT value
uint32_t CongestionWindow; // Congestion Window
uint64_t Bandwidth; // Estimated bandwidth
} NETWORK_STATISTICS;
QUIC_NETWORK_STATISTICS NETWORK_STATISTICS;
#endif

};
Expand Down Expand Up @@ -450,7 +443,7 @@ This event is only indicated if QUIC_SETTINGS.EnableNetStatsEvent is TRUE. This

### NETWORK_STATISTICS

Detailed networking statistics are passed in the `NETWORK_STATISTICS` struct/union.
Detailed networking statistics are passed in the `QUIC_NETWORK_STATISTICS` struct/union.

`BytesInFlight`

Expand Down
30 changes: 22 additions & 8 deletions src/core/bbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,23 +299,36 @@ QuicConnLogBbr(
BbrCongestionControlIsAppLimited(Cc));
}

_IRQL_requires_max_(DISPATCH_LEVEL)
void
BbrCongestionControlGetNetworkStatistics(
_In_ const QUIC_CONNECTION* const Connection,
_In_ const QUIC_CONGESTION_CONTROL* const Cc,
_Out_ QUIC_NETWORK_STATISTICS* NetworkStatistics
)
{
const QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr;
const QUIC_PATH* Path = &Connection->Paths[0];

NetworkStatistics->BytesInFlight = Bbr->BytesInFlight;
NetworkStatistics->PostedBytes = Connection->SendBuffer.PostedBytes;
NetworkStatistics->IdealBytes = Connection->SendBuffer.IdealBytes;
NetworkStatistics->SmoothedRTT = Path->SmoothedRtt;
NetworkStatistics->CongestionWindow = BbrCongestionControlGetCongestionWindow(Cc);
NetworkStatistics->Bandwidth = BbrCongestionControlGetBandwidth(Cc) / BW_UNIT;
}

_IRQL_requires_max_(DISPATCH_LEVEL)
void
BbrCongestionControlIndicateConnectionEvent(
_In_ QUIC_CONNECTION* const Connection,
_In_ const QUIC_CONGESTION_CONTROL* Cc
)
{
const QUIC_CONGESTION_CONTROL_BBR* Bbr = &Cc->Bbr;
const QUIC_PATH* Path = &Connection->Paths[0];
QUIC_CONNECTION_EVENT Event;
Event.Type = QUIC_CONNECTION_EVENT_NETWORK_STATISTICS;
Event.NETWORK_STATISTICS.BytesInFlight = Bbr->BytesInFlight;
Event.NETWORK_STATISTICS.PostedBytes = Connection->SendBuffer.PostedBytes;
Event.NETWORK_STATISTICS.IdealBytes = Connection->SendBuffer.IdealBytes;
Event.NETWORK_STATISTICS.SmoothedRTT = Path->SmoothedRtt;
Event.NETWORK_STATISTICS.CongestionWindow = BbrCongestionControlGetCongestionWindow(Cc);
Event.NETWORK_STATISTICS.Bandwidth = BbrCongestionControlGetBandwidth(Cc) / BW_UNIT;

BbrCongestionControlGetNetworkStatistics(Connection, Cc, &Event.NETWORK_STATISTICS);

QuicTraceLogConnVerbose(
IndicateDataAcked,
Expand Down Expand Up @@ -1068,6 +1081,7 @@ static const QUIC_CONGESTION_CONTROL QuicCongestionControlBbr = {
.QuicCongestionControlGetBytesInFlightMax = BbrCongestionControlGetBytesInFlightMax,
.QuicCongestionControlIsAppLimited = BbrCongestionControlIsAppLimited,
.QuicCongestionControlSetAppLimited = BbrCongestionControlSetAppLimited,
.QuicCongestionControlGetNetworkStatistics = BbrCongestionControlGetNetworkStatistics
};

_IRQL_requires_max_(DISPATCH_LEVEL)
Expand Down
6 changes: 6 additions & 0 deletions src/core/congestion_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ typedef struct QUIC_CONGESTION_CONTROL {
_In_ struct QUIC_CONGESTION_CONTROL* Cc
);

void (*QuicCongestionControlGetNetworkStatistics)(
_In_ const QUIC_CONNECTION* const Connection,
_In_ const struct QUIC_CONGESTION_CONTROL* const Cc,
_Out_ struct QUIC_NETWORK_STATISTICS* NetworkStatistics
);

//
// Algorithm specific state.
//
Expand Down
32 changes: 32 additions & 0 deletions src/core/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -6902,6 +6902,33 @@ QuicConnGetV2Statistics(
return QUIC_STATUS_SUCCESS;
}

_IRQL_requires_max_(PASSIVE_LEVEL)
static
QUIC_STATUS
QuicConnGetNetworkStatistics(
_In_ const QUIC_CONNECTION* Connection,
_Inout_ uint32_t* StatsLength,
_Out_writes_bytes_opt_(*StatsLength)
QUIC_NETWORK_STATISTICS* Stats
)
{
if (*StatsLength < sizeof(QUIC_NETWORK_STATISTICS)) {
*StatsLength = sizeof(QUIC_NETWORK_STATISTICS);
return QUIC_STATUS_BUFFER_TOO_SMALL;
}

if (Stats == NULL) {
return QUIC_STATUS_INVALID_PARAMETER;
}

CxPlatZeroMemory(Stats, sizeof(QUIC_NETWORK_STATISTICS));

Connection->CongestionControl.QuicCongestionControlGetNetworkStatistics(
Connection, &Connection->CongestionControl, Stats);

return QUIC_STATUS_SUCCESS;
}

_IRQL_requires_max_(PASSIVE_LEVEL)
QUIC_STATUS
QuicConnParamGet(
Expand Down Expand Up @@ -7320,6 +7347,11 @@ QuicConnParamGet(
Status = QUIC_STATUS_SUCCESS;
break;

case QUIC_PARAM_CONN_NETWORK_STATISTICS:
Status =
QuicConnGetNetworkStatistics(Connection, BufferLength, (QUIC_NETWORK_STATISTICS *)Buffer);
break;

default:
Status = QUIC_STATUS_INVALID_PARAMETER;
break;
Expand Down
20 changes: 20 additions & 0 deletions src/core/cubic.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,25 @@ CubicCongestionControlOnDataInvalidated(
return CubicCongestionControlUpdateBlockedState(Cc, PreviousCanSendState);
}

_IRQL_requires_max_(DISPATCH_LEVEL)
void
CubicCongestionControlGetNetworkStatistics(
_In_ const QUIC_CONNECTION* const Connection,
_In_ const QUIC_CONGESTION_CONTROL* const Cc,
_Out_ QUIC_NETWORK_STATISTICS* NetworkStatistics
)
{
const QUIC_CONGESTION_CONTROL_CUBIC* Cubic = &Cc->Cubic;
const QUIC_PATH* Path = &Connection->Paths[0];

NetworkStatistics->BytesInFlight = Cubic->BytesInFlight;
NetworkStatistics->PostedBytes = Connection->SendBuffer.PostedBytes;
NetworkStatistics->IdealBytes = Connection->SendBuffer.IdealBytes;
NetworkStatistics->SmoothedRTT = Path->SmoothedRtt;
NetworkStatistics->CongestionWindow = Cubic->CongestionWindow;
NetworkStatistics->Bandwidth = Cubic->CongestionWindow / Path->SmoothedRtt;
}

_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
CubicCongestionControlOnDataAcknowledged(
Expand Down Expand Up @@ -888,6 +907,7 @@ static const QUIC_CONGESTION_CONTROL QuicCongestionControlCubic = {
.QuicCongestionControlIsAppLimited = CubicCongestionControlIsAppLimited,
.QuicCongestionControlSetAppLimited = CubicCongestionControlSetAppLimited,
.QuicCongestionControlGetCongestionWindow = CubicCongestionControlGetCongestionWindow,
.QuicCongestionControlGetNetworkStatistics = CubicCongestionControlGetNetworkStatistics
};

_IRQL_requires_max_(DISPATCH_LEVEL)
Expand Down
50 changes: 26 additions & 24 deletions src/cs/lib/msquic_generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,27 @@ internal uint RESERVED
internal uint RttVariance;
}

internal partial struct QUIC_NETWORK_STATISTICS
{
[NativeTypeName("uint32_t")]
internal uint BytesInFlight;

[NativeTypeName("uint64_t")]
internal ulong PostedBytes;

[NativeTypeName("uint64_t")]
internal ulong IdealBytes;

[NativeTypeName("uint64_t")]
internal ulong SmoothedRTT;

[NativeTypeName("uint32_t")]
internal uint CongestionWindow;

[NativeTypeName("uint64_t")]
internal ulong Bandwidth;
}

internal partial struct QUIC_LISTENER_STATISTICS
{
[NativeTypeName("uint64_t")]
Expand Down Expand Up @@ -2762,7 +2783,7 @@ internal ref _Anonymous_e__Union._ONE_WAY_DELAY_NEGOTIATED_e__Struct ONE_WAY_DEL
}
}

internal ref _Anonymous_e__Union._NETWORK_STATISTICS_e__Struct NETWORK_STATISTICS
internal ref QUIC_NETWORK_STATISTICS NETWORK_STATISTICS
{
get
{
Expand Down Expand Up @@ -2846,8 +2867,7 @@ internal partial struct _Anonymous_e__Union
internal _ONE_WAY_DELAY_NEGOTIATED_e__Struct ONE_WAY_DELAY_NEGOTIATED;

[FieldOffset(0)]
[NativeTypeName("struct (anonymous struct)")]
internal _NETWORK_STATISTICS_e__Struct NETWORK_STATISTICS;
internal QUIC_NETWORK_STATISTICS NETWORK_STATISTICS;

internal unsafe partial struct _CONNECTED_e__Struct
{
Expand Down Expand Up @@ -3038,27 +3058,6 @@ internal partial struct _ONE_WAY_DELAY_NEGOTIATED_e__Struct
[NativeTypeName("BOOLEAN")]
internal byte ReceiveNegotiated;
}

internal partial struct _NETWORK_STATISTICS_e__Struct
{
[NativeTypeName("uint32_t")]
internal uint BytesInFlight;

[NativeTypeName("uint64_t")]
internal ulong PostedBytes;

[NativeTypeName("uint64_t")]
internal ulong IdealBytes;

[NativeTypeName("uint64_t")]
internal ulong SmoothedRTT;

[NativeTypeName("uint32_t")]
internal uint CongestionWindow;

[NativeTypeName("uint64_t")]
internal ulong Bandwidth;
}
}
}

Expand Down Expand Up @@ -3717,6 +3716,9 @@ internal static unsafe partial class MsQuic
[NativeTypeName("#define QUIC_PARAM_CONN_SEND_DSCP 0x05000019")]
internal const uint QUIC_PARAM_CONN_SEND_DSCP = 0x05000019;

[NativeTypeName("#define QUIC_PARAM_CONN_NETWORK_STATISTICS 0x05000020")]
internal const uint QUIC_PARAM_CONN_NETWORK_STATISTICS = 0x05000020;

[NativeTypeName("#define QUIC_PARAM_TLS_HANDSHAKE_INFO 0x06000000")]
internal const uint QUIC_PARAM_TLS_HANDSHAKE_INFO = 0x06000000;

Expand Down
23 changes: 15 additions & 8 deletions src/inc/msquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,17 @@ typedef struct QUIC_STATISTICS_V2 {

} QUIC_STATISTICS_V2;

typedef struct QUIC_NETWORK_STATISTICS
{
uint32_t BytesInFlight; // Bytes that were sent on the wire, but not yet acked
uint64_t PostedBytes; // Total bytes queued, but not yet acked. These may contain sent bytes that may have potentially lost too.
uint64_t IdealBytes; // Ideal number of bytes required to be available to avoid limiting throughput
uint64_t SmoothedRTT; // Smoothed RTT value
uint32_t CongestionWindow; // Congestion Window
uint64_t Bandwidth; // Estimated bandwidth

} QUIC_NETWORK_STATISTICS;

#define QUIC_STRUCT_SIZE_THRU_FIELD(Struct, Field) \
(FIELD_OFFSET(Struct, Field) + sizeof(((Struct*)0)->Field))

Expand Down Expand Up @@ -1011,6 +1022,9 @@ typedef struct QUIC_SCHANNEL_CREDENTIAL_ATTRIBUTE_W {
#define QUIC_PARAM_CONN_STATISTICS_V2_PLAT 0x05000017 // QUIC_STATISTICS_V2
#define QUIC_PARAM_CONN_ORIG_DEST_CID 0x05000018 // uint8_t[]
#define QUIC_PARAM_CONN_SEND_DSCP 0x05000019 // uint8_t
#ifdef QUIC_API_ENABLE_PREVIEW_FEATURES
#define QUIC_PARAM_CONN_NETWORK_STATISTICS 0x05000020 // struct QUIC_NETWORK_STATISTICS
#endif

//
// Parameters for TLS.
Expand Down Expand Up @@ -1360,14 +1374,7 @@ typedef struct QUIC_CONNECTION_EVENT {
BOOLEAN SendNegotiated; // TRUE if sending one-way delay timestamps is negotiated.
BOOLEAN ReceiveNegotiated; // TRUE if receiving one-way delay timestamps is negotiated.
} ONE_WAY_DELAY_NEGOTIATED;
struct {
uint32_t BytesInFlight; // Bytes that were sent on the wire, but not yet acked
uint64_t PostedBytes; // Total bytes queued, but not yet acked. These may contain sent bytes that may have potentially lost too.
uint64_t IdealBytes; // Ideal number of bytes required to be available to avoid limiting throughput
uint64_t SmoothedRTT; // Smoothed RTT value
uint32_t CongestionWindow; // Congestion Window
uint64_t Bandwidth; // Estimated bandwidth
} NETWORK_STATISTICS;
QUIC_NETWORK_STATISTICS NETWORK_STATISTICS;
#endif
};
} QUIC_CONNECTION_EVENT;
Expand Down
Loading
Loading