1 package netlink
2
3 import (
4 "fmt"
5 "io/ioutil"
6 "strconv"
7 "strings"
8 "sync"
9 "syscall"
10
11 "github.com/vishvananda/netlink/nl"
12 "golang.org/x/sys/unix"
13 )
14
15
16 func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
17 var limit uint32 = 1000
18 var lossCorr, delayCorr, duplicateCorr uint32
19 var reorderProb, reorderCorr uint32
20 var corruptProb, corruptCorr uint32
21 var rate64 uint64
22
23 latency := nattrs.Latency
24 loss := Percentage2u32(nattrs.Loss)
25 gap := nattrs.Gap
26 duplicate := Percentage2u32(nattrs.Duplicate)
27 jitter := nattrs.Jitter
28
29
30 if latency > 0 && jitter > 0 {
31 delayCorr = Percentage2u32(nattrs.DelayCorr)
32 }
33 if loss > 0 {
34 lossCorr = Percentage2u32(nattrs.LossCorr)
35 }
36 if duplicate > 0 {
37 duplicateCorr = Percentage2u32(nattrs.DuplicateCorr)
38 }
39
40 latency = time2Tick(latency)
41
42 if nattrs.Limit != 0 {
43 limit = nattrs.Limit
44 }
45
46 if latency > 0 {
47 jitter = time2Tick(jitter)
48 }
49
50 reorderProb = Percentage2u32(nattrs.ReorderProb)
51 reorderCorr = Percentage2u32(nattrs.ReorderCorr)
52
53 if reorderProb > 0 {
54
55 if gap == 0 {
56 gap = 1
57 }
58 }
59
60 corruptProb = Percentage2u32(nattrs.CorruptProb)
61 corruptCorr = Percentage2u32(nattrs.CorruptCorr)
62 rate64 = nattrs.Rate64
63
64 return &Netem{
65 QdiscAttrs: attrs,
66 Latency: latency,
67 DelayCorr: delayCorr,
68 Limit: limit,
69 Loss: loss,
70 LossCorr: lossCorr,
71 Gap: gap,
72 Duplicate: duplicate,
73 DuplicateCorr: duplicateCorr,
74 Jitter: jitter,
75 ReorderProb: reorderProb,
76 ReorderCorr: reorderCorr,
77 CorruptProb: corruptProb,
78 CorruptCorr: corruptCorr,
79 Rate64: rate64,
80 }
81 }
82
83
84
85 func QdiscDel(qdisc Qdisc) error {
86 return pkgHandle.QdiscDel(qdisc)
87 }
88
89
90
91 func (h *Handle) QdiscDel(qdisc Qdisc) error {
92 return h.qdiscModify(unix.RTM_DELQDISC, 0, qdisc)
93 }
94
95
96
97
98 func QdiscChange(qdisc Qdisc) error {
99 return pkgHandle.QdiscChange(qdisc)
100 }
101
102
103
104
105 func (h *Handle) QdiscChange(qdisc Qdisc) error {
106 return h.qdiscModify(unix.RTM_NEWQDISC, 0, qdisc)
107 }
108
109
110
111
112 func QdiscReplace(qdisc Qdisc) error {
113 return pkgHandle.QdiscReplace(qdisc)
114 }
115
116
117
118
119 func (h *Handle) QdiscReplace(qdisc Qdisc) error {
120 return h.qdiscModify(
121 unix.RTM_NEWQDISC,
122 unix.NLM_F_CREATE|unix.NLM_F_REPLACE,
123 qdisc)
124 }
125
126
127
128 func QdiscAdd(qdisc Qdisc) error {
129 return pkgHandle.QdiscAdd(qdisc)
130 }
131
132
133
134 func (h *Handle) QdiscAdd(qdisc Qdisc) error {
135 return h.qdiscModify(
136 unix.RTM_NEWQDISC,
137 unix.NLM_F_CREATE|unix.NLM_F_EXCL,
138 qdisc)
139 }
140
141 func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
142 req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
143 base := qdisc.Attrs()
144 msg := &nl.TcMsg{
145 Family: nl.FAMILY_ALL,
146 Ifindex: int32(base.LinkIndex),
147 Handle: base.Handle,
148 Parent: base.Parent,
149 }
150 req.AddData(msg)
151
152
153 if cmd != unix.RTM_DELQDISC {
154 if err := qdiscPayload(req, qdisc); err != nil {
155 return err
156 }
157 }
158
159 _, err := req.Execute(unix.NETLINK_ROUTE, 0)
160 return err
161 }
162
163 func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
164
165 req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(qdisc.Type())))
166 if qdisc.Attrs().IngressBlock != nil {
167 req.AddData(nl.NewRtAttr(nl.TCA_INGRESS_BLOCK, nl.Uint32Attr(*qdisc.Attrs().IngressBlock)))
168 }
169
170 options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
171
172 switch qdisc := qdisc.(type) {
173 case *Prio:
174 tcmap := nl.TcPrioMap{
175 Bands: int32(qdisc.Bands),
176 Priomap: qdisc.PriorityMap,
177 }
178 options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize())
179 case *Tbf:
180 opt := nl.TcTbfQopt{}
181 opt.Rate.Rate = uint32(qdisc.Rate)
182 opt.Peakrate.Rate = uint32(qdisc.Peakrate)
183 opt.Limit = qdisc.Limit
184 opt.Buffer = qdisc.Buffer
185 options.AddRtAttr(nl.TCA_TBF_PARMS, opt.Serialize())
186 if qdisc.Rate >= uint64(1<<32) {
187 options.AddRtAttr(nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
188 }
189 if qdisc.Peakrate >= uint64(1<<32) {
190 options.AddRtAttr(nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
191 }
192 if qdisc.Peakrate > 0 {
193 options.AddRtAttr(nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
194 }
195 case *Htb:
196 opt := nl.TcHtbGlob{}
197 opt.Version = qdisc.Version
198 opt.Rate2Quantum = qdisc.Rate2Quantum
199 opt.Defcls = qdisc.Defcls
200
201 opt.Debug = qdisc.Debug
202 opt.DirectPkts = qdisc.DirectPkts
203 options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize())
204 if qdisc.DirectQlen != nil {
205 options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, nl.Uint32Attr(*qdisc.DirectQlen))
206 }
207 case *Hfsc:
208 opt := nl.TcHfscOpt{}
209 opt.Defcls = qdisc.Defcls
210 options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
211 case *Netem:
212 opt := nl.TcNetemQopt{}
213 opt.Latency = qdisc.Latency
214 opt.Limit = qdisc.Limit
215 opt.Loss = qdisc.Loss
216 opt.Gap = qdisc.Gap
217 opt.Duplicate = qdisc.Duplicate
218 opt.Jitter = qdisc.Jitter
219 options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
220
221 corr := nl.TcNetemCorr{}
222 corr.DelayCorr = qdisc.DelayCorr
223 corr.LossCorr = qdisc.LossCorr
224 corr.DupCorr = qdisc.DuplicateCorr
225
226 if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 {
227 options.AddRtAttr(nl.TCA_NETEM_CORR, corr.Serialize())
228 }
229
230 corruption := nl.TcNetemCorrupt{}
231 corruption.Probability = qdisc.CorruptProb
232 corruption.Correlation = qdisc.CorruptCorr
233 if corruption.Probability > 0 {
234 options.AddRtAttr(nl.TCA_NETEM_CORRUPT, corruption.Serialize())
235 }
236
237 reorder := nl.TcNetemReorder{}
238 reorder.Probability = qdisc.ReorderProb
239 reorder.Correlation = qdisc.ReorderCorr
240 if reorder.Probability > 0 {
241 options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize())
242 }
243
244 if qdisc.Rate64 > 0 {
245 rate := nl.TcNetemRate{}
246 if qdisc.Rate64 >= uint64(1<<32) {
247 options.AddRtAttr(nl.TCA_NETEM_RATE64, nl.Uint64Attr(qdisc.Rate64))
248 rate.Rate = ^uint32(0)
249 } else {
250 rate.Rate = uint32(qdisc.Rate64)
251 }
252 options.AddRtAttr(nl.TCA_NETEM_RATE, rate.Serialize())
253 }
254 case *Clsact:
255 options = nil
256 case *Ingress:
257
258 if qdisc.Attrs().Parent != HANDLE_INGRESS {
259 return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
260 }
261 case *FqCodel:
262 options.AddRtAttr(nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
263 if qdisc.Limit > 0 {
264 options.AddRtAttr(nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
265 }
266 if qdisc.Interval > 0 {
267 options.AddRtAttr(nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
268 }
269 if qdisc.Flows > 0 {
270 options.AddRtAttr(nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
271 }
272 if qdisc.Quantum > 0 {
273 options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
274 }
275 if qdisc.CEThreshold > 0 {
276 options.AddRtAttr(nl.TCA_FQ_CODEL_CE_THRESHOLD, nl.Uint32Attr(qdisc.CEThreshold))
277 }
278 if qdisc.DropBatchSize > 0 {
279 options.AddRtAttr(nl.TCA_FQ_CODEL_DROP_BATCH_SIZE, nl.Uint32Attr(qdisc.DropBatchSize))
280 }
281 if qdisc.MemoryLimit > 0 {
282 options.AddRtAttr(nl.TCA_FQ_CODEL_MEMORY_LIMIT, nl.Uint32Attr(qdisc.MemoryLimit))
283 }
284 case *Fq:
285 options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
286
287 if qdisc.Buckets > 0 {
288 options.AddRtAttr(nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
289 }
290 if qdisc.PacketLimit > 0 {
291 options.AddRtAttr(nl.TCA_FQ_PLIMIT, nl.Uint32Attr((uint32(qdisc.PacketLimit))))
292 }
293 if qdisc.LowRateThreshold > 0 {
294 options.AddRtAttr(nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
295 }
296 if qdisc.Quantum > 0 {
297 options.AddRtAttr(nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
298 }
299 if qdisc.InitialQuantum > 0 {
300 options.AddRtAttr(nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
301 }
302 if qdisc.FlowRefillDelay > 0 {
303 options.AddRtAttr(nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
304 }
305 if qdisc.FlowPacketLimit > 0 {
306 options.AddRtAttr(nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
307 }
308 if qdisc.FlowMaxRate > 0 {
309 options.AddRtAttr(nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
310 }
311 if qdisc.FlowDefaultRate > 0 {
312 options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
313 }
314 if qdisc.Horizon > 0 {
315 options.AddRtAttr(nl.TCA_FQ_HORIZON, nl.Uint32Attr(qdisc.Horizon))
316 }
317 if qdisc.HorizonDropPolicy != HORIZON_DROP_POLICY_DEFAULT {
318 options.AddRtAttr(nl.TCA_FQ_HORIZON_DROP, nl.Uint8Attr(qdisc.HorizonDropPolicy))
319 }
320 case *Sfq:
321 opt := nl.TcSfqQoptV1{}
322 opt.TcSfqQopt.Quantum = qdisc.Quantum
323 opt.TcSfqQopt.Perturb = int32(qdisc.Perturb)
324 opt.TcSfqQopt.Limit = qdisc.Limit
325 opt.TcSfqQopt.Divisor = qdisc.Divisor
326
327 options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
328 default:
329 options = nil
330 }
331
332 if options != nil {
333 req.AddData(options)
334 }
335 return nil
336 }
337
338
339
340
341 func QdiscList(link Link) ([]Qdisc, error) {
342 return pkgHandle.QdiscList(link)
343 }
344
345
346
347
348 func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
349 req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
350 index := int32(0)
351 if link != nil {
352 base := link.Attrs()
353 h.ensureIndex(base)
354 index = int32(base.Index)
355 }
356 msg := &nl.TcMsg{
357 Family: nl.FAMILY_ALL,
358 Ifindex: index,
359 }
360 req.AddData(msg)
361
362 msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
363 if err != nil {
364 return nil, err
365 }
366
367 var res []Qdisc
368 for _, m := range msgs {
369 msg := nl.DeserializeTcMsg(m)
370
371 attrs, err := nl.ParseRouteAttr(m[msg.Len():])
372 if err != nil {
373 return nil, err
374 }
375
376
377 if link != nil && msg.Ifindex != index {
378 continue
379 }
380
381 base := QdiscAttrs{
382 LinkIndex: int(msg.Ifindex),
383 Handle: msg.Handle,
384 Parent: msg.Parent,
385 Refcnt: msg.Info,
386 }
387 var qdisc Qdisc
388 qdiscType := ""
389 for _, attr := range attrs {
390 switch attr.Attr.Type {
391 case nl.TCA_KIND:
392 qdiscType = string(attr.Value[:len(attr.Value)-1])
393 switch qdiscType {
394 case "pfifo_fast":
395 qdisc = &PfifoFast{}
396 case "prio":
397 qdisc = &Prio{}
398 case "tbf":
399 qdisc = &Tbf{}
400 case "ingress":
401 qdisc = &Ingress{}
402 case "htb":
403 qdisc = &Htb{}
404 case "fq":
405 qdisc = &Fq{}
406 case "hfsc":
407 qdisc = &Hfsc{}
408 case "fq_codel":
409 qdisc = &FqCodel{}
410 case "netem":
411 qdisc = &Netem{}
412 case "sfq":
413 qdisc = &Sfq{}
414 case "clsact":
415 qdisc = &Clsact{}
416 default:
417 qdisc = &GenericQdisc{QdiscType: qdiscType}
418 }
419 case nl.TCA_OPTIONS:
420 switch qdiscType {
421 case "pfifo_fast":
422
423 if err := parsePfifoFastData(qdisc, attr.Value); err != nil {
424 return nil, err
425 }
426 case "prio":
427
428 if err := parsePrioData(qdisc, attr.Value); err != nil {
429 return nil, err
430 }
431 case "tbf":
432 data, err := nl.ParseRouteAttr(attr.Value)
433 if err != nil {
434 return nil, err
435 }
436 if err := parseTbfData(qdisc, data); err != nil {
437 return nil, err
438 }
439 case "hfsc":
440 if err := parseHfscData(qdisc, attr.Value); err != nil {
441 return nil, err
442 }
443 case "htb":
444 data, err := nl.ParseRouteAttr(attr.Value)
445 if err != nil {
446 return nil, err
447 }
448 if err := parseHtbData(qdisc, data); err != nil {
449 return nil, err
450 }
451 case "fq":
452 data, err := nl.ParseRouteAttr(attr.Value)
453 if err != nil {
454 return nil, err
455 }
456 if err := parseFqData(qdisc, data); err != nil {
457 return nil, err
458 }
459 case "fq_codel":
460 data, err := nl.ParseRouteAttr(attr.Value)
461 if err != nil {
462 return nil, err
463 }
464 if err := parseFqCodelData(qdisc, data); err != nil {
465 return nil, err
466 }
467 case "netem":
468 if err := parseNetemData(qdisc, attr.Value); err != nil {
469 return nil, err
470 }
471 case "sfq":
472 if err := parseSfqData(qdisc, attr.Value); err != nil {
473 return nil, err
474 }
475
476
477 }
478 case nl.TCA_INGRESS_BLOCK:
479 ingressBlock := new(uint32)
480 *ingressBlock = native.Uint32(attr.Value)
481 base.IngressBlock = ingressBlock
482 case nl.TCA_STATS:
483 s, err := parseTcStats(attr.Value)
484 if err != nil {
485 return nil, err
486 }
487 base.Statistics = (*QdiscStatistics)(s)
488 case nl.TCA_STATS2:
489 s, err := parseTcStats2(attr.Value)
490 if err != nil {
491 return nil, err
492 }
493 base.Statistics = (*QdiscStatistics)(s)
494 }
495 }
496 *qdisc.Attrs() = base
497 res = append(res, qdisc)
498 }
499
500 return res, nil
501 }
502
503 func parsePfifoFastData(qdisc Qdisc, value []byte) error {
504 pfifo := qdisc.(*PfifoFast)
505 tcmap := nl.DeserializeTcPrioMap(value)
506 pfifo.PriorityMap = tcmap.Priomap
507 pfifo.Bands = uint8(tcmap.Bands)
508 return nil
509 }
510
511 func parsePrioData(qdisc Qdisc, value []byte) error {
512 prio := qdisc.(*Prio)
513 tcmap := nl.DeserializeTcPrioMap(value)
514 prio.PriorityMap = tcmap.Priomap
515 prio.Bands = uint8(tcmap.Bands)
516 return nil
517 }
518
519 func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
520 htb := qdisc.(*Htb)
521 for _, datum := range data {
522 switch datum.Attr.Type {
523 case nl.TCA_HTB_INIT:
524 opt := nl.DeserializeTcHtbGlob(datum.Value)
525 htb.Version = opt.Version
526 htb.Rate2Quantum = opt.Rate2Quantum
527 htb.Defcls = opt.Defcls
528 htb.Debug = opt.Debug
529 htb.DirectPkts = opt.DirectPkts
530 case nl.TCA_HTB_DIRECT_QLEN:
531 directQlen := native.Uint32(datum.Value)
532 htb.DirectQlen = &directQlen
533 }
534 }
535 return nil
536 }
537
538 func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
539 fqCodel := qdisc.(*FqCodel)
540 for _, datum := range data {
541
542 switch datum.Attr.Type {
543 case nl.TCA_FQ_CODEL_TARGET:
544 fqCodel.Target = native.Uint32(datum.Value)
545 case nl.TCA_FQ_CODEL_LIMIT:
546 fqCodel.Limit = native.Uint32(datum.Value)
547 case nl.TCA_FQ_CODEL_INTERVAL:
548 fqCodel.Interval = native.Uint32(datum.Value)
549 case nl.TCA_FQ_CODEL_ECN:
550 fqCodel.ECN = native.Uint32(datum.Value)
551 case nl.TCA_FQ_CODEL_FLOWS:
552 fqCodel.Flows = native.Uint32(datum.Value)
553 case nl.TCA_FQ_CODEL_QUANTUM:
554 fqCodel.Quantum = native.Uint32(datum.Value)
555 case nl.TCA_FQ_CODEL_CE_THRESHOLD:
556 fqCodel.CEThreshold = native.Uint32(datum.Value)
557 case nl.TCA_FQ_CODEL_DROP_BATCH_SIZE:
558 fqCodel.DropBatchSize = native.Uint32(datum.Value)
559 case nl.TCA_FQ_CODEL_MEMORY_LIMIT:
560 fqCodel.MemoryLimit = native.Uint32(datum.Value)
561 }
562 }
563 return nil
564 }
565
566 func parseHfscData(qdisc Qdisc, data []byte) error {
567 Hfsc := qdisc.(*Hfsc)
568 Hfsc.Defcls = native.Uint16(data)
569 return nil
570 }
571
572 func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
573 fq := qdisc.(*Fq)
574 for _, datum := range data {
575 switch datum.Attr.Type {
576 case nl.TCA_FQ_BUCKETS_LOG:
577 fq.Buckets = native.Uint32(datum.Value)
578 case nl.TCA_FQ_LOW_RATE_THRESHOLD:
579 fq.LowRateThreshold = native.Uint32(datum.Value)
580 case nl.TCA_FQ_QUANTUM:
581 fq.Quantum = native.Uint32(datum.Value)
582 case nl.TCA_FQ_RATE_ENABLE:
583 fq.Pacing = native.Uint32(datum.Value)
584 case nl.TCA_FQ_INITIAL_QUANTUM:
585 fq.InitialQuantum = native.Uint32(datum.Value)
586 case nl.TCA_FQ_ORPHAN_MASK:
587
588 case nl.TCA_FQ_FLOW_REFILL_DELAY:
589 fq.FlowRefillDelay = native.Uint32(datum.Value)
590 case nl.TCA_FQ_FLOW_PLIMIT:
591 fq.FlowPacketLimit = native.Uint32(datum.Value)
592 case nl.TCA_FQ_PLIMIT:
593 fq.PacketLimit = native.Uint32(datum.Value)
594 case nl.TCA_FQ_FLOW_MAX_RATE:
595 fq.FlowMaxRate = native.Uint32(datum.Value)
596 case nl.TCA_FQ_FLOW_DEFAULT_RATE:
597 fq.FlowDefaultRate = native.Uint32(datum.Value)
598 case nl.TCA_FQ_HORIZON:
599 fq.Horizon = native.Uint32(datum.Value)
600 case nl.TCA_FQ_HORIZON_DROP:
601 fq.HorizonDropPolicy = datum.Value[0]
602
603 }
604 }
605 return nil
606 }
607
608 func parseNetemData(qdisc Qdisc, value []byte) error {
609 netem := qdisc.(*Netem)
610 opt := nl.DeserializeTcNetemQopt(value)
611 netem.Latency = opt.Latency
612 netem.Limit = opt.Limit
613 netem.Loss = opt.Loss
614 netem.Gap = opt.Gap
615 netem.Duplicate = opt.Duplicate
616 netem.Jitter = opt.Jitter
617 data, err := nl.ParseRouteAttr(value[nl.SizeofTcNetemQopt:])
618 if err != nil {
619 return err
620 }
621 var rate *nl.TcNetemRate
622 var rate64 uint64
623 for _, datum := range data {
624 switch datum.Attr.Type {
625 case nl.TCA_NETEM_CORR:
626 opt := nl.DeserializeTcNetemCorr(datum.Value)
627 netem.DelayCorr = opt.DelayCorr
628 netem.LossCorr = opt.LossCorr
629 netem.DuplicateCorr = opt.DupCorr
630 case nl.TCA_NETEM_CORRUPT:
631 opt := nl.DeserializeTcNetemCorrupt(datum.Value)
632 netem.CorruptProb = opt.Probability
633 netem.CorruptCorr = opt.Correlation
634 case nl.TCA_NETEM_REORDER:
635 opt := nl.DeserializeTcNetemReorder(datum.Value)
636 netem.ReorderProb = opt.Probability
637 netem.ReorderCorr = opt.Correlation
638 case nl.TCA_NETEM_RATE:
639 rate = nl.DeserializeTcNetemRate(datum.Value)
640 case nl.TCA_NETEM_RATE64:
641 rate64 = native.Uint64(datum.Value)
642 }
643 }
644 if rate != nil {
645 netem.Rate64 = uint64(rate.Rate)
646 if rate64 > 0 {
647 netem.Rate64 = rate64
648 }
649 }
650
651 return nil
652 }
653
654 func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
655 tbf := qdisc.(*Tbf)
656 for _, datum := range data {
657 switch datum.Attr.Type {
658 case nl.TCA_TBF_PARMS:
659 opt := nl.DeserializeTcTbfQopt(datum.Value)
660 tbf.Rate = uint64(opt.Rate.Rate)
661 tbf.Peakrate = uint64(opt.Peakrate.Rate)
662 tbf.Limit = opt.Limit
663 tbf.Buffer = opt.Buffer
664 case nl.TCA_TBF_RATE64:
665 tbf.Rate = native.Uint64(datum.Value[0:8])
666 case nl.TCA_TBF_PRATE64:
667 tbf.Peakrate = native.Uint64(datum.Value[0:8])
668 case nl.TCA_TBF_PBURST:
669 tbf.Minburst = native.Uint32(datum.Value[0:4])
670 }
671 }
672 return nil
673 }
674
675 func parseSfqData(qdisc Qdisc, value []byte) error {
676 sfq := qdisc.(*Sfq)
677 opt := nl.DeserializeTcSfqQoptV1(value)
678 sfq.Quantum = opt.TcSfqQopt.Quantum
679 sfq.Perturb = uint8(opt.TcSfqQopt.Perturb)
680 sfq.Limit = opt.TcSfqQopt.Limit
681 sfq.Divisor = opt.TcSfqQopt.Divisor
682
683 return nil
684 }
685
686 const (
687 TIME_UNITS_PER_SEC = 1000000
688 )
689
690 var (
691 tickInUsec float64
692 clockFactor float64
693 hz float64
694
695
696 initClockMutex sync.Mutex
697 )
698
699 func initClock() {
700 data, err := ioutil.ReadFile("/proc/net/psched")
701 if err != nil {
702 return
703 }
704 parts := strings.Split(strings.TrimSpace(string(data)), " ")
705 if len(parts) < 4 {
706 return
707 }
708 var vals [4]uint64
709 for i := range vals {
710 val, err := strconv.ParseUint(parts[i], 16, 32)
711 if err != nil {
712 return
713 }
714 vals[i] = val
715 }
716
717 if vals[2] == 1000000000 {
718 vals[0] = vals[1]
719 }
720 clockFactor = float64(vals[2]) / TIME_UNITS_PER_SEC
721 tickInUsec = float64(vals[0]) / float64(vals[1]) * clockFactor
722 if vals[2] == 1000000 {
723
724 hz = float64(vals[3])
725 } else {
726 hz = 100
727 }
728 }
729
730 func TickInUsec() float64 {
731 initClockMutex.Lock()
732 defer initClockMutex.Unlock()
733 if tickInUsec == 0.0 {
734 initClock()
735 }
736 return tickInUsec
737 }
738
739 func ClockFactor() float64 {
740 initClockMutex.Lock()
741 defer initClockMutex.Unlock()
742 if clockFactor == 0.0 {
743 initClock()
744 }
745 return clockFactor
746 }
747
748 func Hz() float64 {
749 initClockMutex.Lock()
750 defer initClockMutex.Unlock()
751 if hz == 0.0 {
752 initClock()
753 }
754 return hz
755 }
756
757 func time2Tick(time uint32) uint32 {
758 return uint32(float64(time) * TickInUsec())
759 }
760
761 func tick2Time(tick uint32) uint32 {
762 return uint32(float64(tick) / TickInUsec())
763 }
764
765 func time2Ktime(time uint32) uint32 {
766 return uint32(float64(time) * ClockFactor())
767 }
768
769 func ktime2Time(ktime uint32) uint32 {
770 return uint32(float64(ktime) / ClockFactor())
771 }
772
773 func burst(rate uint64, buffer uint32) uint32 {
774 return uint32(float64(rate) * float64(tick2Time(buffer)) / TIME_UNITS_PER_SEC)
775 }
776
777 func latency(rate uint64, limit, buffer uint32) float64 {
778 return TIME_UNITS_PER_SEC*(float64(limit)/float64(rate)) - float64(tick2Time(buffer))
779 }
780
781 func Xmittime(rate uint64, size uint32) uint32 {
782
783 return time2Tick(uint32(TIME_UNITS_PER_SEC * (float64(size) / float64(rate))))
784 }
785
786 func Xmitsize(rate uint64, ticks uint32) uint32 {
787 return uint32((float64(rate) * float64(tick2Time(ticks))) / TIME_UNITS_PER_SEC)
788 }
789
View as plain text