mirror of
https://github.com/vishvananda/netlink.git
synced 2025-09-27 04:05:59 +08:00
Add FQ Codel
This commit is contained in:

committed by
Alessandro Boch

parent
465b5fef28
commit
a2af46a09c
@@ -695,3 +695,16 @@ const (
|
|||||||
TCA_FQ_ORPHAN_MASK // mask applied to orphaned skb hashes
|
TCA_FQ_ORPHAN_MASK // mask applied to orphaned skb hashes
|
||||||
TCA_FQ_LOW_RATE_THRESHOLD // per packet delay under this rate
|
TCA_FQ_LOW_RATE_THRESHOLD // per packet delay under this rate
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TCA_FQ_CODEL_UNSPEC = iota
|
||||||
|
TCA_FQ_CODEL_TARGET
|
||||||
|
TCA_FQ_CODEL_LIMIT
|
||||||
|
TCA_FQ_CODEL_INTERVAL
|
||||||
|
TCA_FQ_CODEL_ECN
|
||||||
|
TCA_FQ_CODEL_FLOWS
|
||||||
|
TCA_FQ_CODEL_QUANTUM
|
||||||
|
TCA_FQ_CODEL_CE_THRESHOLD
|
||||||
|
TCA_FQ_CODEL_DROP_BATCH_SIZE
|
||||||
|
TCA_FQ_CODEL_MEMORY_LIMIT
|
||||||
|
)
|
||||||
|
27
qdisc.go
27
qdisc.go
@@ -263,3 +263,30 @@ func (qdisc *Fq) Attrs() *QdiscAttrs {
|
|||||||
func (qdisc *Fq) Type() string {
|
func (qdisc *Fq) Type() string {
|
||||||
return "fq"
|
return "fq"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme.
|
||||||
|
type FqCodel struct {
|
||||||
|
QdiscAttrs
|
||||||
|
Target uint32
|
||||||
|
Limit uint32
|
||||||
|
Interval uint32
|
||||||
|
ECN uint32
|
||||||
|
Flows uint32
|
||||||
|
Quantum uint32
|
||||||
|
// There are some more attributes here, but support for them seems not ubiquitous
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFqCodel(attrs QdiscAttrs) *FqCodel {
|
||||||
|
return &FqCodel{
|
||||||
|
QdiscAttrs: attrs,
|
||||||
|
ECN: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qdisc *FqCodel) Attrs() *QdiscAttrs {
|
||||||
|
return &qdisc.QdiscAttrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qdisc *FqCodel) Type() string {
|
||||||
|
return "fq_codel"
|
||||||
|
}
|
||||||
|
@@ -232,6 +232,21 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
|
|||||||
if qdisc.Attrs().Parent != HANDLE_INGRESS {
|
if qdisc.Attrs().Parent != HANDLE_INGRESS {
|
||||||
return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
|
return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
|
||||||
}
|
}
|
||||||
|
case *FqCodel:
|
||||||
|
nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
|
||||||
|
if qdisc.Limit > 0 {
|
||||||
|
nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
|
||||||
|
}
|
||||||
|
if qdisc.Interval > 0 {
|
||||||
|
nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
|
||||||
|
}
|
||||||
|
if qdisc.Flows > 0 {
|
||||||
|
nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
|
||||||
|
}
|
||||||
|
if qdisc.Quantum > 0 {
|
||||||
|
nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
|
||||||
|
}
|
||||||
|
|
||||||
case *Fq:
|
case *Fq:
|
||||||
nl.NewRtAttrChild(options, nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
|
nl.NewRtAttrChild(options, nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
|
||||||
|
|
||||||
@@ -333,6 +348,8 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
|
|||||||
qdisc = &Htb{}
|
qdisc = &Htb{}
|
||||||
case "fq":
|
case "fq":
|
||||||
qdisc = &Fq{}
|
qdisc = &Fq{}
|
||||||
|
case "fq_codel":
|
||||||
|
qdisc = &FqCodel{}
|
||||||
case "netem":
|
case "netem":
|
||||||
qdisc = &Netem{}
|
qdisc = &Netem{}
|
||||||
default:
|
default:
|
||||||
@@ -374,6 +391,14 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
|
|||||||
if err := parseFqData(qdisc, data); err != nil {
|
if err := parseFqData(qdisc, data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
case "fq_codel":
|
||||||
|
data, err := nl.ParseRouteAttr(attr.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := parseFqCodelData(qdisc, data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
case "netem":
|
case "netem":
|
||||||
if err := parseNetemData(qdisc, attr.Value); err != nil {
|
if err := parseNetemData(qdisc, attr.Value); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -426,6 +451,29 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
|
||||||
|
native = nl.NativeEndian()
|
||||||
|
fqCodel := qdisc.(*FqCodel)
|
||||||
|
for _, datum := range data {
|
||||||
|
|
||||||
|
switch datum.Attr.Type {
|
||||||
|
case nl.TCA_FQ_CODEL_TARGET:
|
||||||
|
fqCodel.Target = native.Uint32(datum.Value)
|
||||||
|
case nl.TCA_FQ_CODEL_LIMIT:
|
||||||
|
fqCodel.Limit = native.Uint32(datum.Value)
|
||||||
|
case nl.TCA_FQ_CODEL_INTERVAL:
|
||||||
|
fqCodel.Interval = native.Uint32(datum.Value)
|
||||||
|
case nl.TCA_FQ_CODEL_ECN:
|
||||||
|
fqCodel.ECN = native.Uint32(datum.Value)
|
||||||
|
case nl.TCA_FQ_CODEL_FLOWS:
|
||||||
|
fqCodel.Flows = native.Uint32(datum.Value)
|
||||||
|
case nl.TCA_FQ_CODEL_QUANTUM:
|
||||||
|
fqCodel.Quantum = native.Uint32(datum.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
|
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
|
||||||
native = nl.NativeEndian()
|
native = nl.NativeEndian()
|
||||||
fq := qdisc.(*Fq)
|
fq := qdisc.(*Fq)
|
||||||
|
@@ -402,3 +402,57 @@ func TestFqAddChangeDel(t *testing.T) {
|
|||||||
t.Fatal("Failed to remove qdisc")
|
t.Fatal("Failed to remove qdisc")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFqCodelAddChangeDel(t *testing.T) {
|
||||||
|
minKernelRequired(t, 3, 4)
|
||||||
|
|
||||||
|
tearDown := setUpNetlinkTest(t)
|
||||||
|
defer tearDown()
|
||||||
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
link, err := LinkByName("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := LinkSetUp(link); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdisc := &FqCodel{
|
||||||
|
QdiscAttrs: QdiscAttrs{
|
||||||
|
LinkIndex: link.Attrs().Index,
|
||||||
|
Handle: MakeHandle(1, 0),
|
||||||
|
Parent: HANDLE_ROOT,
|
||||||
|
},
|
||||||
|
ECN: 1,
|
||||||
|
Quantum: 9000,
|
||||||
|
}
|
||||||
|
if err := QdiscAdd(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err := SafeQdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 1 {
|
||||||
|
t.Fatal("Failed to add qdisc")
|
||||||
|
}
|
||||||
|
fqcodel, ok := qdiscs[0].(*FqCodel)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("Qdisc is the wrong type")
|
||||||
|
}
|
||||||
|
if fqcodel.Quantum != qdisc.Quantum {
|
||||||
|
t.Fatal("Quantum does not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := QdiscDel(qdisc); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
qdiscs, err = SafeQdiscList(link)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(qdiscs) != 0 {
|
||||||
|
t.Fatal("Failed to remove qdisc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user