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