netlink/qdisc.go

296 lines
6.2 KiB
Go
Raw Normal View History

2015-08-18 10:16:54 +00:00
package netlink
import (
"fmt"
"math"
2015-08-18 10:16:54 +00:00
)
const (
HANDLE_NONE = 0
HANDLE_INGRESS = 0xFFFFFFF1
HANDLE_CLSACT = HANDLE_INGRESS
2015-08-18 10:16:54 +00:00
HANDLE_ROOT = 0xFFFFFFFF
PRIORITY_MAP_LEN = 16
)
const (
HANDLE_MIN_INGRESS = 0xFFFFFFF2
HANDLE_MIN_EGRESS = 0xFFFFFFF3
)
2015-08-18 10:16:54 +00:00
type Qdisc interface {
Attrs() *QdiscAttrs
Type() string
}
2016-03-20 00:12:26 +00:00
// QdiscAttrs represents a netlink qdisc. A qdisc is associated with a link,
2015-08-19 23:02:04 +00:00
// has a handle, a parent and a refcnt. The root qdisc of a device should
// have parent == HANDLE_ROOT.
2015-08-18 10:16:54 +00:00
type QdiscAttrs struct {
LinkIndex int
Handle uint32
Parent uint32
2015-08-19 23:02:04 +00:00
Refcnt uint32 // read only
2015-08-18 10:16:54 +00:00
}
func (q QdiscAttrs) String() string {
2016-03-20 00:12:26 +00:00
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
2015-08-18 10:16:54 +00:00
}
func MakeHandle(major, minor uint16) uint32 {
2015-08-18 21:07:01 +00:00
return (uint32(major) << 16) | uint32(minor)
2015-08-18 10:16:54 +00:00
}
func MajorMinor(handle uint32) (uint16, uint16) {
return uint16((handle & 0xFFFF0000) >> 16), uint16(handle & 0x0000FFFFF)
}
func HandleStr(handle uint32) string {
switch handle {
case HANDLE_NONE:
return "none"
case HANDLE_INGRESS:
return "ingress"
case HANDLE_ROOT:
return "root"
default:
major, minor := MajorMinor(handle)
return fmt.Sprintf("%x:%x", major, minor)
}
}
func Percentage2u32(percentage float32) uint32 {
// FIXME this is most likely not the best way to convert from % to uint32
if percentage == 100 {
return math.MaxUint32
}
return uint32(math.MaxUint32 * (percentage / 100))
}
2015-08-18 10:16:54 +00:00
// PfifoFast is the default qdisc created by the kernel if one has not
// been defined for the interface
type PfifoFast struct {
QdiscAttrs
Bands uint8
PriorityMap [PRIORITY_MAP_LEN]uint8
}
func (qdisc *PfifoFast) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *PfifoFast) Type() string {
return "pfifo_fast"
}
2015-08-20 01:22:02 +00:00
// Prio is a basic qdisc that works just like PfifoFast
type Prio struct {
QdiscAttrs
Bands uint8
PriorityMap [PRIORITY_MAP_LEN]uint8
}
func NewPrio(attrs QdiscAttrs) *Prio {
return &Prio{
QdiscAttrs: attrs,
Bands: 3,
PriorityMap: [PRIORITY_MAP_LEN]uint8{1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
}
}
func (qdisc *Prio) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *Prio) Type() string {
return "prio"
}
2015-09-05 07:13:17 +00:00
// Htb is a classful qdisc that rate limits based on tokens
type Htb struct {
QdiscAttrs
Version uint32
Rate2Quantum uint32
Defcls uint32
Debug uint32
DirectPkts uint32
}
func NewHtb(attrs QdiscAttrs) *Htb {
return &Htb{
QdiscAttrs: attrs,
Version: 3,
Defcls: 0,
Rate2Quantum: 10,
Debug: 0,
DirectPkts: 0,
}
}
func (qdisc *Htb) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *Htb) Type() string {
return "htb"
}
// Netem is a classless qdisc that rate limits based on tokens
type NetemQdiscAttrs struct {
Latency uint32 // in us
DelayCorr float32 // in %
Limit uint32
Loss float32 // in %
LossCorr float32 // in %
Gap uint32
Duplicate float32 // in %
DuplicateCorr float32 // in %
Jitter uint32 // in us
ReorderProb float32 // in %
ReorderCorr float32 // in %
CorruptProb float32 // in %
CorruptCorr float32 // in %
}
func (q NetemQdiscAttrs) String() string {
return fmt.Sprintf(
2016-03-20 00:12:26 +00:00
"{Latency: %d, Limit: %d, Loss: %f, Gap: %d, Duplicate: %f, Jitter: %d}",
q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter,
)
}
type Netem struct {
QdiscAttrs
Latency uint32
DelayCorr uint32
Limit uint32
Loss uint32
LossCorr uint32
Gap uint32
Duplicate uint32
DuplicateCorr uint32
Jitter uint32
ReorderProb uint32
ReorderCorr uint32
CorruptProb uint32
CorruptCorr uint32
}
func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
var limit uint32 = 1000
2016-03-20 00:12:26 +00:00
var lossCorr, delayCorr, duplicateCorr uint32
var reorderProb, reorderCorr uint32
var corruptProb, corruptCorr uint32
latency := nattrs.Latency
loss := Percentage2u32(nattrs.Loss)
gap := nattrs.Gap
duplicate := Percentage2u32(nattrs.Duplicate)
jitter := nattrs.Jitter
// Correlation
if latency > 0 && jitter > 0 {
2016-03-20 00:12:26 +00:00
delayCorr = Percentage2u32(nattrs.DelayCorr)
}
if loss > 0 {
2016-03-20 00:12:26 +00:00
lossCorr = Percentage2u32(nattrs.LossCorr)
}
if duplicate > 0 {
2016-03-20 00:12:26 +00:00
duplicateCorr = Percentage2u32(nattrs.DuplicateCorr)
}
// FIXME should validate values(like loss/duplicate are percentages...)
latency = time2Tick(latency)
if nattrs.Limit != 0 {
limit = nattrs.Limit
}
// Jitter is only value if latency is > 0
if latency > 0 {
jitter = time2Tick(jitter)
}
2016-03-20 00:12:26 +00:00
reorderProb = Percentage2u32(nattrs.ReorderProb)
reorderCorr = Percentage2u32(nattrs.ReorderCorr)
2016-03-20 00:12:26 +00:00
if reorderProb > 0 {
// ERROR if lantency == 0
if gap == 0 {
gap = 1
}
}
2016-03-20 00:12:26 +00:00
corruptProb = Percentage2u32(nattrs.CorruptProb)
corruptCorr = Percentage2u32(nattrs.CorruptCorr)
return &Netem{
QdiscAttrs: attrs,
Latency: latency,
2016-03-20 00:12:26 +00:00
DelayCorr: delayCorr,
Limit: limit,
Loss: loss,
2016-03-20 00:12:26 +00:00
LossCorr: lossCorr,
Gap: gap,
Duplicate: duplicate,
2016-03-20 00:12:26 +00:00
DuplicateCorr: duplicateCorr,
Jitter: jitter,
2016-03-20 00:12:26 +00:00
ReorderProb: reorderProb,
ReorderCorr: reorderCorr,
CorruptProb: corruptProb,
CorruptCorr: corruptCorr,
}
}
func (qdisc *Netem) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *Netem) Type() string {
return "netem"
}
2015-09-05 07:13:17 +00:00
// Tbf is a classless qdisc that rate limits based on tokens
2015-08-19 23:02:04 +00:00
type Tbf struct {
2015-08-18 10:16:54 +00:00
QdiscAttrs
2015-08-18 21:07:01 +00:00
// TODO: handle 64bit rate properly
Rate uint64
Limit uint32
Buffer uint32
// TODO: handle other settings
2015-08-18 10:16:54 +00:00
}
2015-08-19 23:02:04 +00:00
func (qdisc *Tbf) Attrs() *QdiscAttrs {
2015-08-18 10:16:54 +00:00
return &qdisc.QdiscAttrs
}
2015-08-19 23:02:04 +00:00
func (qdisc *Tbf) Type() string {
2015-08-18 10:16:54 +00:00
return "tbf"
}
2015-08-19 23:02:04 +00:00
// Ingress is a qdisc for adding ingress filters
type Ingress struct {
QdiscAttrs
}
func (qdisc *Ingress) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *Ingress) Type() string {
return "ingress"
}
2015-08-18 10:16:54 +00:00
// GenericQdisc qdiscs represent types that are not currently understood
// by this netlink library.
type GenericQdisc struct {
QdiscAttrs
QdiscType string
}
func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
func (qdisc *GenericQdisc) Type() string {
return qdisc.QdiscType
}