123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- package netlink
- import (
- "fmt"
- "math"
- )
- const (
- HANDLE_NONE = 0
- HANDLE_INGRESS = 0xFFFFFFF1
- HANDLE_ROOT = 0xFFFFFFFF
- PRIORITY_MAP_LEN = 16
- )
- type Qdisc interface {
- Attrs() *QdiscAttrs
- Type() string
- }
- // Qdisc represents a netlink qdisc. A qdisc is associated with a link,
- // has a handle, a parent and a refcnt. The root qdisc of a device should
- // have parent == HANDLE_ROOT.
- type QdiscAttrs struct {
- LinkIndex int
- Handle uint32
- Parent uint32
- Refcnt uint32 // read only
- }
- func (q QdiscAttrs) String() string {
- return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
- }
- func MakeHandle(major, minor uint16) uint32 {
- return (uint32(major) << 16) | uint32(minor)
- }
- 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))
- }
- // 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"
- }
- // 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"
- }
- // 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(
- "{Latency: %d, Limit: %d, Loss: %d, Gap: %d, Duplicate: %d, 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
- var loss_corr, delay_corr, duplicate_corr uint32
- var reorder_prob, reorder_corr uint32
- var corrupt_prob, corrupt_corr uint32
- latency := nattrs.Latency
- loss := Percentage2u32(nattrs.Loss)
- gap := nattrs.Gap
- duplicate := Percentage2u32(nattrs.Duplicate)
- jitter := nattrs.Jitter
- // Correlation
- if latency > 0 && jitter > 0 {
- delay_corr = Percentage2u32(nattrs.DelayCorr)
- }
- if loss > 0 {
- loss_corr = Percentage2u32(nattrs.LossCorr)
- }
- if duplicate > 0 {
- duplicate_corr = 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)
- }
- reorder_prob = Percentage2u32(nattrs.ReorderProb)
- reorder_corr = Percentage2u32(nattrs.ReorderCorr)
- if reorder_prob > 0 {
- // ERROR if lantency == 0
- if gap == 0 {
- gap = 1
- }
- }
- corrupt_prob = Percentage2u32(nattrs.CorruptProb)
- corrupt_corr = Percentage2u32(nattrs.CorruptCorr)
- return &Netem{
- QdiscAttrs: attrs,
- Latency: latency,
- DelayCorr: delay_corr,
- Limit: limit,
- Loss: loss,
- LossCorr: loss_corr,
- Gap: gap,
- Duplicate: duplicate,
- DuplicateCorr: duplicate_corr,
- Jitter: jitter,
- ReorderProb: reorder_prob,
- ReorderCorr: reorder_corr,
- CorruptProb: corrupt_prob,
- CorruptCorr: corrupt_corr,
- }
- }
- func (qdisc *Netem) Attrs() *QdiscAttrs {
- return &qdisc.QdiscAttrs
- }
- func (qdisc *Netem) Type() string {
- return "netem"
- }
- // Tbf is a classless qdisc that rate limits based on tokens
- type Tbf struct {
- QdiscAttrs
- // TODO: handle 64bit rate properly
- Rate uint64
- Limit uint32
- Buffer uint32
- // TODO: handle other settings
- }
- func (qdisc *Tbf) Attrs() *QdiscAttrs {
- return &qdisc.QdiscAttrs
- }
- func (qdisc *Tbf) Type() string {
- return "tbf"
- }
- // 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"
- }
- // 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
- }
|