mirror of
				https://github.com/vishvananda/netlink.git
				synced 2025-10-31 19:22:34 +08:00 
			
		
		
		
	Add FQ Codel
This commit is contained in:
		 Sargun Dhillon
					Sargun Dhillon
				
			
				
					committed by
					
						 Alessandro Boch
						Alessandro Boch
					
				
			
			
				
	
			
			
			 Alessandro Boch
						Alessandro Boch
					
				
			
						parent
						
							465b5fef28
						
					
				
				
					commit
					a2af46a09c
				
			| @@ -695,3 +695,16 @@ const ( | ||||
| 	TCA_FQ_ORPHAN_MASK        // mask applied to orphaned skb hashes | ||||
| 	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 { | ||||
| 	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 { | ||||
| 			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: | ||||
| 		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{} | ||||
| 				case "fq": | ||||
| 					qdisc = &Fq{} | ||||
| 				case "fq_codel": | ||||
| 					qdisc = &FqCodel{} | ||||
| 				case "netem": | ||||
| 					qdisc = &Netem{} | ||||
| 				default: | ||||
| @@ -374,6 +391,14 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) { | ||||
| 					if err := parseFqData(qdisc, data); err != nil { | ||||
| 						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": | ||||
| 					if err := parseNetemData(qdisc, attr.Value); err != nil { | ||||
| 						return nil, err | ||||
| @@ -426,6 +451,29 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { | ||||
| 	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 { | ||||
| 	native = nl.NativeEndian() | ||||
| 	fq := qdisc.(*Fq) | ||||
|   | ||||
| @@ -402,3 +402,57 @@ func TestFqAddChangeDel(t *testing.T) { | ||||
| 		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