From 6765a4402e6d9fd1ca5d0785cbe32c5ec40d6a6f Mon Sep 17 00:00:00 2001 From: Byoungchan Lee Date: Wed, 26 Jul 2023 14:31:56 +0900 Subject: [PATCH] Add support for TCA_NETEM_RATE64 in Netem qdisc - `Rate64` field added to the `Netem` struct in `qdisc.go` - Implemented serialization and deserialization methods for `Rate64` - Modify `TestClassAddDel` test to validate Rate64 changes --- class_test.go | 4 ++++ nl/tc_linux.go | 21 +++++++++++++++++++++ qdisc.go | 2 ++ qdisc_linux.go | 27 +++++++++++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/class_test.go b/class_test.go index d913883..9f0bf5d 100644 --- a/class_test.go +++ b/class_test.go @@ -154,6 +154,7 @@ func TestClassAddDel(t *testing.T) { ReorderProb: 23.4, CorruptProb: 10.0, CorruptCorr: 10, + Rate64: 10 * 1024 * 1024, } qdiscnetem := NewNetem(qattrs, nattrs) if err := QdiscAdd(qdiscnetem); err != nil { @@ -195,6 +196,9 @@ func TestClassAddDel(t *testing.T) { if netem.DuplicateCorr != qdiscnetem.DuplicateCorr { t.Fatal("DuplicateCorr does not match") } + if netem.Rate64 != qdiscnetem.Rate64 { + t.Fatalf("Rate64 does not match. Expected %d, got %d", netem.Rate64, qdiscnetem.Rate64) + } // Deletion // automatically removes netem qdisc diff --git a/nl/tc_linux.go b/nl/tc_linux.go index e9ce190..0720729 100644 --- a/nl/tc_linux.go +++ b/nl/tc_linux.go @@ -105,6 +105,7 @@ const ( SizeofTcNetemCorr = 0x0c SizeofTcNetemReorder = 0x08 SizeofTcNetemCorrupt = 0x08 + SizeOfTcNetemRate = 0x10 SizeofTcTbfQopt = 2*SizeofTcRateSpec + 0x0c SizeofTcHtbCopt = 2*SizeofTcRateSpec + 0x14 SizeofTcHtbGlob = 0x14 @@ -372,6 +373,26 @@ func (x *TcNetemCorrupt) Serialize() []byte { return (*(*[SizeofTcNetemCorrupt]byte)(unsafe.Pointer(x)))[:] } +// TcNetemRate is a struct that represents the rate of a netem qdisc +type TcNetemRate struct { + Rate uint32 + PacketOverhead int32 + CellSize uint32 + CellOverhead int32 +} + +func (msg *TcNetemRate) Len() int { + return SizeofTcRateSpec +} + +func DeserializeTcNetemRate(b []byte) *TcNetemRate { + return (*TcNetemRate)(unsafe.Pointer(&b[0:SizeofTcRateSpec][0])) +} + +func (msg *TcNetemRate) Serialize() []byte { + return (*(*[SizeOfTcNetemRate]byte)(unsafe.Pointer(msg)))[:] +} + // struct tc_tbf_qopt { // struct tc_ratespec rate; // struct tc_ratespec peakrate; diff --git a/qdisc.go b/qdisc.go index 906856e..6f5d6df 100644 --- a/qdisc.go +++ b/qdisc.go @@ -160,6 +160,7 @@ type NetemQdiscAttrs struct { ReorderCorr float32 // in % CorruptProb float32 // in % CorruptCorr float32 // in % + Rate64 uint64 } func (q NetemQdiscAttrs) String() string { @@ -184,6 +185,7 @@ type Netem struct { ReorderCorr uint32 CorruptProb uint32 CorruptCorr uint32 + Rate64 uint64 } func (netem *Netem) String() string { diff --git a/qdisc_linux.go b/qdisc_linux.go index 670d663..3c3780d 100644 --- a/qdisc_linux.go +++ b/qdisc_linux.go @@ -17,6 +17,7 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { var lossCorr, delayCorr, duplicateCorr uint32 var reorderProb, reorderCorr uint32 var corruptProb, corruptCorr uint32 + var rate64 uint64 latency := nattrs.Latency loss := Percentage2u32(nattrs.Loss) @@ -57,6 +58,7 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { corruptProb = Percentage2u32(nattrs.CorruptProb) corruptCorr = Percentage2u32(nattrs.CorruptCorr) + rate64 = nattrs.Rate64 return &Netem{ QdiscAttrs: attrs, @@ -73,6 +75,7 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem { ReorderCorr: reorderCorr, CorruptProb: corruptProb, CorruptCorr: corruptCorr, + Rate64: rate64, } } @@ -234,6 +237,17 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { if reorder.Probability > 0 { options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize()) } + // Rate + if qdisc.Rate64 > 0 { + rate := nl.TcNetemRate{} + if qdisc.Rate64 >= uint64(1<<32) { + options.AddRtAttr(nl.TCA_NETEM_RATE64, nl.Uint64Attr(qdisc.Rate64)) + rate.Rate = ^uint32(0) + } else { + rate.Rate = uint32(qdisc.Rate64) + } + options.AddRtAttr(nl.TCA_NETEM_RATE, rate.Serialize()) + } case *Clsact: options = nil case *Ingress: @@ -601,6 +615,8 @@ func parseNetemData(qdisc Qdisc, value []byte) error { if err != nil { return err } + var rate *nl.TcNetemRate + var rate64 uint64 for _, datum := range data { switch datum.Attr.Type { case nl.TCA_NETEM_CORR: @@ -616,8 +632,19 @@ func parseNetemData(qdisc Qdisc, value []byte) error { opt := nl.DeserializeTcNetemReorder(datum.Value) netem.ReorderProb = opt.Probability netem.ReorderCorr = opt.Correlation + case nl.TCA_NETEM_RATE: + rate = nl.DeserializeTcNetemRate(datum.Value) + case nl.TCA_NETEM_RATE64: + rate64 = native.Uint64(datum.Value) } } + if rate != nil { + netem.Rate64 = uint64(rate.Rate) + if rate64 > 0 { + netem.Rate64 = rate64 + } + } + return nil }