github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/qdisc.go (about)

     1  package netlink
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  )
     7  
     8  const (
     9  	HANDLE_NONE      = 0
    10  	HANDLE_INGRESS   = 0xFFFFFFF1
    11  	HANDLE_CLSACT    = HANDLE_INGRESS
    12  	HANDLE_ROOT      = 0xFFFFFFFF
    13  	PRIORITY_MAP_LEN = 16
    14  )
    15  const (
    16  	HANDLE_MIN_INGRESS = 0xFFFFFFF2
    17  	HANDLE_MIN_EGRESS  = 0xFFFFFFF3
    18  )
    19  
    20  const (
    21  	HORIZON_DROP_POLICY_CAP     = 0
    22  	HORIZON_DROP_POLICY_DROP    = 1
    23  	HORIZON_DROP_POLICY_DEFAULT = 255
    24  )
    25  
    26  type Qdisc interface {
    27  	Attrs() *QdiscAttrs
    28  	Type() string
    29  }
    30  
    31  // QdiscAttrs represents a netlink qdisc. A qdisc is associated with a link,
    32  // has a handle, a parent and a refcnt. The root qdisc of a device should
    33  // have parent == HANDLE_ROOT.
    34  type QdiscAttrs struct {
    35  	LinkIndex int
    36  	Handle    uint32
    37  	Parent    uint32
    38  	Refcnt    uint32 // read only
    39  }
    40  
    41  func (q QdiscAttrs) String() string {
    42  	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
    43  }
    44  
    45  func MakeHandle(major, minor uint16) uint32 {
    46  	return (uint32(major) << 16) | uint32(minor)
    47  }
    48  
    49  func MajorMinor(handle uint32) (uint16, uint16) {
    50  	return uint16((handle & 0xFFFF0000) >> 16), uint16(handle & 0x0000FFFFF)
    51  }
    52  
    53  func HandleStr(handle uint32) string {
    54  	switch handle {
    55  	case HANDLE_NONE:
    56  		return "none"
    57  	case HANDLE_INGRESS:
    58  		return "ingress"
    59  	case HANDLE_ROOT:
    60  		return "root"
    61  	default:
    62  		major, minor := MajorMinor(handle)
    63  		return fmt.Sprintf("%x:%x", major, minor)
    64  	}
    65  }
    66  
    67  func Percentage2u32(percentage float32) uint32 {
    68  	// FIXME this is most likely not the best way to convert from % to uint32
    69  	if percentage == 100 {
    70  		return math.MaxUint32
    71  	}
    72  	return uint32(math.MaxUint32 * (percentage / 100))
    73  }
    74  
    75  // PfifoFast is the default qdisc created by the kernel if one has not
    76  // been defined for the interface
    77  type PfifoFast struct {
    78  	QdiscAttrs
    79  	Bands       uint8
    80  	PriorityMap [PRIORITY_MAP_LEN]uint8
    81  }
    82  
    83  func (qdisc *PfifoFast) Attrs() *QdiscAttrs {
    84  	return &qdisc.QdiscAttrs
    85  }
    86  
    87  func (qdisc *PfifoFast) Type() string {
    88  	return "pfifo_fast"
    89  }
    90  
    91  // Prio is a basic qdisc that works just like PfifoFast
    92  type Prio struct {
    93  	QdiscAttrs
    94  	Bands       uint8
    95  	PriorityMap [PRIORITY_MAP_LEN]uint8
    96  }
    97  
    98  func NewPrio(attrs QdiscAttrs) *Prio {
    99  	return &Prio{
   100  		QdiscAttrs:  attrs,
   101  		Bands:       3,
   102  		PriorityMap: [PRIORITY_MAP_LEN]uint8{1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
   103  	}
   104  }
   105  
   106  func (qdisc *Prio) Attrs() *QdiscAttrs {
   107  	return &qdisc.QdiscAttrs
   108  }
   109  
   110  func (qdisc *Prio) Type() string {
   111  	return "prio"
   112  }
   113  
   114  // Htb is a classful qdisc that rate limits based on tokens
   115  type Htb struct {
   116  	QdiscAttrs
   117  	Version      uint32
   118  	Rate2Quantum uint32
   119  	Defcls       uint32
   120  	Debug        uint32
   121  	DirectPkts   uint32
   122  }
   123  
   124  func NewHtb(attrs QdiscAttrs) *Htb {
   125  	return &Htb{
   126  		QdiscAttrs:   attrs,
   127  		Version:      3,
   128  		Defcls:       0,
   129  		Rate2Quantum: 10,
   130  		Debug:        0,
   131  		DirectPkts:   0,
   132  	}
   133  }
   134  
   135  func (qdisc *Htb) Attrs() *QdiscAttrs {
   136  	return &qdisc.QdiscAttrs
   137  }
   138  
   139  func (qdisc *Htb) Type() string {
   140  	return "htb"
   141  }
   142  
   143  // Netem is a classless qdisc that rate limits based on tokens
   144  
   145  type NetemQdiscAttrs struct {
   146  	Latency       uint32  // in us
   147  	DelayCorr     float32 // in %
   148  	Limit         uint32
   149  	Loss          float32 // in %
   150  	LossCorr      float32 // in %
   151  	Gap           uint32
   152  	Duplicate     float32 // in %
   153  	DuplicateCorr float32 // in %
   154  	Jitter        uint32  // in us
   155  	ReorderProb   float32 // in %
   156  	ReorderCorr   float32 // in %
   157  	CorruptProb   float32 // in %
   158  	CorruptCorr   float32 // in %
   159  }
   160  
   161  func (q NetemQdiscAttrs) String() string {
   162  	return fmt.Sprintf(
   163  		"{Latency: %d, Limit: %d, Loss: %f, Gap: %d, Duplicate: %f, Jitter: %d}",
   164  		q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter,
   165  	)
   166  }
   167  
   168  type Netem struct {
   169  	QdiscAttrs
   170  	Latency       uint32
   171  	DelayCorr     uint32
   172  	Limit         uint32
   173  	Loss          uint32
   174  	LossCorr      uint32
   175  	Gap           uint32
   176  	Duplicate     uint32
   177  	DuplicateCorr uint32
   178  	Jitter        uint32
   179  	ReorderProb   uint32
   180  	ReorderCorr   uint32
   181  	CorruptProb   uint32
   182  	CorruptCorr   uint32
   183  }
   184  
   185  func (netem *Netem) String() string {
   186  	return fmt.Sprintf(
   187  		"{Latency: %v, Limit: %v, Loss: %v, Gap: %v, Duplicate: %v, Jitter: %v}",
   188  		netem.Latency, netem.Limit, netem.Loss, netem.Gap, netem.Duplicate, netem.Jitter,
   189  	)
   190  }
   191  
   192  func (qdisc *Netem) Attrs() *QdiscAttrs {
   193  	return &qdisc.QdiscAttrs
   194  }
   195  
   196  func (qdisc *Netem) Type() string {
   197  	return "netem"
   198  }
   199  
   200  // Tbf is a classless qdisc that rate limits based on tokens
   201  type Tbf struct {
   202  	QdiscAttrs
   203  	Rate     uint64
   204  	Limit    uint32
   205  	Buffer   uint32
   206  	Peakrate uint64
   207  	Minburst uint32
   208  	// TODO: handle other settings
   209  }
   210  
   211  func (qdisc *Tbf) Attrs() *QdiscAttrs {
   212  	return &qdisc.QdiscAttrs
   213  }
   214  
   215  func (qdisc *Tbf) Type() string {
   216  	return "tbf"
   217  }
   218  
   219  // Ingress is a qdisc for adding ingress filters
   220  type Ingress struct {
   221  	QdiscAttrs
   222  }
   223  
   224  func (qdisc *Ingress) Attrs() *QdiscAttrs {
   225  	return &qdisc.QdiscAttrs
   226  }
   227  
   228  func (qdisc *Ingress) Type() string {
   229  	return "ingress"
   230  }
   231  
   232  // GenericQdisc qdiscs represent types that are not currently understood
   233  // by this netlink library.
   234  type GenericQdisc struct {
   235  	QdiscAttrs
   236  	QdiscType string
   237  }
   238  
   239  func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
   240  	return &qdisc.QdiscAttrs
   241  }
   242  
   243  func (qdisc *GenericQdisc) Type() string {
   244  	return qdisc.QdiscType
   245  }
   246  
   247  type Hfsc struct {
   248  	QdiscAttrs
   249  	Defcls uint16
   250  }
   251  
   252  func NewHfsc(attrs QdiscAttrs) *Hfsc {
   253  	return &Hfsc{
   254  		QdiscAttrs: attrs,
   255  		Defcls:     1,
   256  	}
   257  }
   258  
   259  func (hfsc *Hfsc) Attrs() *QdiscAttrs {
   260  	return &hfsc.QdiscAttrs
   261  }
   262  
   263  func (hfsc *Hfsc) Type() string {
   264  	return "hfsc"
   265  }
   266  
   267  func (hfsc *Hfsc) String() string {
   268  	return fmt.Sprintf(
   269  		"{%v -- default: %d}",
   270  		hfsc.Attrs(), hfsc.Defcls,
   271  	)
   272  }
   273  
   274  // Fq is a classless packet scheduler meant to be mostly used for locally generated traffic.
   275  type Fq struct {
   276  	QdiscAttrs
   277  	PacketLimit     uint32
   278  	FlowPacketLimit uint32
   279  	// In bytes
   280  	Quantum        uint32
   281  	InitialQuantum uint32
   282  	// called RateEnable under the hood
   283  	Pacing          uint32
   284  	FlowDefaultRate uint32
   285  	FlowMaxRate     uint32
   286  	// called BucketsLog under the hood
   287  	Buckets           uint32
   288  	FlowRefillDelay   uint32
   289  	LowRateThreshold  uint32
   290  	Horizon           uint32
   291  	HorizonDropPolicy uint8
   292  }
   293  
   294  func (fq *Fq) String() string {
   295  	return fmt.Sprintf(
   296  		"{PacketLimit: %v, FlowPacketLimit: %v, Quantum: %v, InitialQuantum: %v, Pacing: %v, FlowDefaultRate: %v, FlowMaxRate: %v, Buckets: %v, FlowRefillDelay: %v,  LowRateThreshold: %v, Horizon: %v, HorizonDropPolicy: %v}",
   297  		fq.PacketLimit, fq.FlowPacketLimit, fq.Quantum, fq.InitialQuantum, fq.Pacing, fq.FlowDefaultRate, fq.FlowMaxRate, fq.Buckets, fq.FlowRefillDelay, fq.LowRateThreshold, fq.Horizon, fq.HorizonDropPolicy,
   298  	)
   299  }
   300  
   301  func NewFq(attrs QdiscAttrs) *Fq {
   302  	return &Fq{
   303  		QdiscAttrs:        attrs,
   304  		Pacing:            1,
   305  		HorizonDropPolicy: HORIZON_DROP_POLICY_DEFAULT,
   306  	}
   307  }
   308  
   309  func (qdisc *Fq) Attrs() *QdiscAttrs {
   310  	return &qdisc.QdiscAttrs
   311  }
   312  
   313  func (qdisc *Fq) Type() string {
   314  	return "fq"
   315  }
   316  
   317  // FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme.
   318  type FqCodel struct {
   319  	QdiscAttrs
   320  	Target        uint32
   321  	Limit         uint32
   322  	Interval      uint32
   323  	ECN           uint32
   324  	Flows         uint32
   325  	Quantum       uint32
   326  	CEThreshold   uint32
   327  	DropBatchSize uint32
   328  	MemoryLimit   uint32
   329  }
   330  
   331  func (fqcodel *FqCodel) String() string {
   332  	return fmt.Sprintf(
   333  		"{%v -- Target: %v, Limit: %v, Interval: %v, ECM: %v, Flows: %v, Quantum: %v}",
   334  		fqcodel.Attrs(), fqcodel.Target, fqcodel.Limit, fqcodel.Interval, fqcodel.ECN, fqcodel.Flows, fqcodel.Quantum,
   335  	)
   336  }
   337  
   338  func NewFqCodel(attrs QdiscAttrs) *FqCodel {
   339  	return &FqCodel{
   340  		QdiscAttrs: attrs,
   341  		ECN:        1,
   342  	}
   343  }
   344  
   345  func (qdisc *FqCodel) Attrs() *QdiscAttrs {
   346  	return &qdisc.QdiscAttrs
   347  }
   348  
   349  func (qdisc *FqCodel) Type() string {
   350  	return "fq_codel"
   351  }
   352  
   353  type Sfq struct {
   354  	QdiscAttrs
   355  	// TODO: Only the simplified options for SFQ are handled here. Support for the extended one can be added later.
   356  	Quantum uint8
   357  	Perturb uint8
   358  	Limit   uint32
   359  	Divisor uint8
   360  }
   361  
   362  func (sfq *Sfq) String() string {
   363  	return fmt.Sprintf(
   364  		"{%v -- Quantum: %v, Perturb: %v, Limit: %v, Divisor: %v}",
   365  		sfq.Attrs(), sfq.Quantum, sfq.Perturb, sfq.Limit, sfq.Divisor,
   366  	)
   367  }
   368  
   369  func (qdisc *Sfq) Attrs() *QdiscAttrs {
   370  	return &qdisc.QdiscAttrs
   371  }
   372  
   373  func (qdisc *Sfq) Type() string {
   374  	return "sfq"
   375  }