From c4bbdd7db2aaa9f227c2ce0613cbc7711cb31b56 Mon Sep 17 00:00:00 2001 From: Kangjie Xu Date: Tue, 4 Jun 2024 20:37:44 -0700 Subject: [PATCH] qdisc: add TCA_XSTATS stats for fq qdisc. When using fq, we rely on xstats useful metrics to check fq behavior and diangosis, it is what can be seen from iproute2 tools, `tc -s qdisc show` as well. It exposes metrics as: https://github.com/iproute2/iproute2/blob/main/include/uapi/linux/pkt_sched.h#L847 Signed-off-by: Kangjie Xu --- class_linux.go | 10 ++++++++++ qdisc.go | 4 ++++ qdisc_linux.go | 10 ++++++++++ qdisc_test.go | 4 ++++ 4 files changed, 28 insertions(+) diff --git a/class_linux.go b/class_linux.go index a82eb09d..18d3bba5 100644 --- a/class_linux.go +++ b/class_linux.go @@ -398,3 +398,13 @@ func parseTcStats2(data []byte) (*ClassStatistics, error) { return stats, nil } + +func parseTcFqXStats(data []byte) (*nl.TcFqQdStats, error) { + buf := &bytes.Buffer{} + buf.Write(data) + stats := &nl.TcFqQdStats{} + if err := binary.Read(buf, native, stats); err != nil { + return nil, err + } + return stats, nil +} diff --git a/qdisc.go b/qdisc.go index 6f5d6df4..f27d4b94 100644 --- a/qdisc.go +++ b/qdisc.go @@ -3,6 +3,8 @@ package netlink import ( "fmt" "math" + + "github.com/vishvananda/netlink/nl" ) const ( @@ -308,6 +310,8 @@ type Fq struct { LowRateThreshold uint32 Horizon uint32 HorizonDropPolicy uint8 + + Stats *nl.TcFqQdStats } func (fq *Fq) String() string { diff --git a/qdisc_linux.go b/qdisc_linux.go index 3c3780d3..98df7e4e 100644 --- a/qdisc_linux.go +++ b/qdisc_linux.go @@ -488,6 +488,16 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) { return nil, err } base.Statistics = (*QdiscStatistics)(s) + case nl.TCA_XSTATS: + switch qdisc.Type() { + case "fq": + fq := qdisc.(*Fq) + s, err := parseTcFqXStats(attr.Value) + if err != nil { + return nil, err + } + fq.Stats = s + } } } *qdisc.Attrs() = base diff --git a/qdisc_test.go b/qdisc_test.go index 24307484..870478b4 100644 --- a/qdisc_test.go +++ b/qdisc_test.go @@ -515,6 +515,10 @@ func TestFqHorizon(t *testing.T) { t.Fatal("HorizonDropPolicy does not match") } + if fq.Stats.GcFlows != 0 || fq.Stats.ThrottledFlows != 0 || fq.Stats.HorizonDrops != 0 { + t.Fatal("Stats is not zero") + } + if err := QdiscDel(qdisc); err != nil { t.Fatal(err) }