Files
MoShiro/backend/shared/MoShiro.Protocol/Catalog/Kinds/Kinds.cs
T
justme 0fd38b2367
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful
fix: prevent QUIC heartbeat stalls and isolate TCP retransmission counters [CI] [SKIP TESTS]
2026-10-20 18:23:31 +08:00

163 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace MoShiro.Protocol;
/// <summary>
/// Kind 目录。新增一种采集方法 = 在这里加一个静态字段并放进 <see cref="All"/>;
/// 参数一律用 <see cref="P"/> 声明默认值和上下限。
/// </summary>
public static class Kinds
{
private static readonly string[] s_directions = ["fwd", "rev", "bidir"];
private static readonly StreamSpec s_echoMsg = new(
"msg",
[
Col.Seq("seq"), Col.U16("size"),
Col.TsProbe("t1"), Col.TsAgent("t2", nullable: true), Col.TsAgent("t3", nullable: true), Col.TsProbe("t4", nullable: true),
],
Side.Probe,
"seq");
private static readonly StreamSpec s_tcpInfo = new(
"tcp_info",
[
Col.TsLocal("ts"), Col.U8("side"), Col.U32("srtt_us"), Col.U32("rttvar_us"), Col.U32("cwnd"),
Col.U32("retrans_total"), Col.U32("segs_out"), Col.U64("bytes_acked"),
new ColumnSpec("conn", ColumnType.U64, ColumnEnc.Plain, true),
],
Union: true);
public static readonly KindSpec UdpEcho = new(
"udp_echo",
"QUIC Datagram echo",
"Fixed-rate QUIC Datagram echo with four timestamps per packet.",
Scope.Line,
new BlockSet("quic_datagram", "fixed", "fixed", "echo", []),
[
P.Int("rate_hz", 10, 1, 200, "Hz"),
P.Int("size", 64, 44, 1400, "B"),
P.Int("port", 7443, 1, 65535),
],
[s_echoMsg],
p => Bandwidth.UdpEcho(p.GetInt("rate_hz"), p.GetInt("size")));
public static readonly KindSpec UdpTrain = new(
"udp_train",
"QUIC Datagram train",
"Fixed-rate or laddered one-way QUIC Datagram stream (Agent to Probe) for loss and delay variation under load.",
Scope.Line,
new BlockSet("quic_datagram", "ladder", "fixed", "sink", []),
[
P.Number("mbps", 10, 0.1, 1000, "Mbit/s"),
P.Int("size", 1250, 200, 1400, "B"),
P.Int("duration_s", 10, 1, 120, "s"),
P.Enum("direction", "rev", s_directions),
P.Int("port", 7443, 1, 65535),
],
[
new StreamSpec("pkt", [Col.Seq("seq"), Col.U16("size"), Col.TsAgent("t_send"), Col.TsProbe("t_recv", nullable: true)], Side.Agent, "seq"),
new StreamSpec("step", [Col.U16("index"), Col.U32("mbps"), Col.TsProbe("start_ts"), Col.TsProbe("end_ts")]),
],
p => (long)(p.GetNumber("mbps") * 1_000_000));
public static readonly KindSpec TcpEcho = new(
"tcp_echo",
"TCP echo",
"Small TCP messages echoed with four timestamps, plus periodic kernel tcp_info samples.",
Scope.Line,
new BlockSet("tcp", "fixed", "uniform", "echo", ["tcp_info"]),
[
P.Int("rate_hz", 20, 1, 200, "Hz"),
P.Int("min", 32, 16, 1400, "B"),
P.Int("max", 64, 16, 1400, "B"),
P.Int("tcp_info_ms", 100, 10, 1000, "ms"),
P.Int("port", 7444, 1, 65535),
P.Bool("tls", false),
],
[s_echoMsg, s_tcpInfo],
p => Bandwidth.TcpEcho(p.GetInt("rate_hz"), p.GetInt("max")));
public static readonly KindSpec TcpBulk = new(
"tcp_bulk",
"TCP bulk",
"Bulk TCP transfer on several streams with periodic byte counters and tcp_info.",
Scope.Line,
new BlockSet("tcp", "fixed", "fixed", "source", ["tcp_info"]),
[
P.Int("streams", 4, 1, 16),
P.Int("duration_s", 4, 1, 120, "s"),
P.Enum("direction", "rev", s_directions),
P.Int("sample_ms", 100, 20, 1000, "ms"),
P.Int("port", 7444, 1, 65535),
P.Bool("tls", true),
],
[
new StreamSpec("bytes", [Col.TsProbe("ts"), Col.U8("conn"), Col.U64("bytes")]),
s_tcpInfo,
],
_ => 0);
public static readonly KindSpec Connect = new(
"connect",
"Connect",
"Repeated TCP and TLS connection establishment with per-phase timings and outcome.",
Scope.Line | Scope.Target,
new BlockSet("tcp", "fixed", "fixed", "connect", []),
[
P.Int("per_minute", 6, 1, 60),
P.Bool("tls", true),
P.Int("timeout_ms", 5000, 500, 30000, "ms"),
P.Int("port", 7444, 1, 65535),
],
[
new StreamSpec(
"conn",
[Col.Seq("attempt"), Col.TsProbe("ts"), Col.U32("tcp_us", nullable: true), Col.U32("tls_us", nullable: true), Col.U8("outcome")]),
],
p => p.GetInt("per_minute") * 4000 / 60);
public static readonly KindSpec Hold = new(
"hold",
"Hold",
"A long-lived TLS connection with periodic heartbeats; records resets and lifetime.",
Scope.Line,
new BlockSet("tls", "fixed", "fixed", "hold", []),
[
P.Int("heartbeat_s", 30, 5, 300, "s"),
P.Int("port", 7444, 1, 65535),
],
[
new StreamSpec("hold", [Col.TsProbe("ts"), Col.U8("event"), Col.U32("lifetime_ms")]),
],
p => 2000 / Math.Max(1, p.GetInt("heartbeat_s")) * 8);
public static readonly KindSpec IcmpEcho = new(
"icmp_echo",
"ICMP echo",
"Probe or Agent side ICMP echo to a target address.",
Scope.Target,
new BlockSet("icmp", "fixed", "fixed", "echo", []),
[
P.Int("rate_hz", 1, 1, 20, "Hz"),
P.Int("size", 64, 44, 1400, "B"),
],
[
new StreamSpec("msg", [Col.Seq("seq"), Col.U16("size"), Col.TsLocal("t1"), new ColumnSpec("t4", ColumnType.I64, ColumnEnc.Delta, true, ColumnRole.TsLocal)]),
],
p => Bandwidth.UdpEcho(p.GetInt("rate_hz"), p.GetInt("size")));
public static readonly IReadOnlyList<KindSpec> All = [UdpEcho, UdpTrain, TcpEcho, TcpBulk, Connect, Hold, IcmpEcho];
public static KindSpec? Find(string id)
{
foreach (KindSpec kind in All)
{
if (kind.Id == id)
{
return kind;
}
}
return null;
}
}