qdisc_linux.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. package netlink
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "strconv"
  6. "strings"
  7. "syscall"
  8. "github.com/vishvananda/netlink/nl"
  9. "golang.org/x/sys/unix"
  10. )
  11. // NOTE function is here because it uses other linux functions
  12. func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
  13. var limit uint32 = 1000
  14. var lossCorr, delayCorr, duplicateCorr uint32
  15. var reorderProb, reorderCorr uint32
  16. var corruptProb, corruptCorr uint32
  17. latency := nattrs.Latency
  18. loss := Percentage2u32(nattrs.Loss)
  19. gap := nattrs.Gap
  20. duplicate := Percentage2u32(nattrs.Duplicate)
  21. jitter := nattrs.Jitter
  22. // Correlation
  23. if latency > 0 && jitter > 0 {
  24. delayCorr = Percentage2u32(nattrs.DelayCorr)
  25. }
  26. if loss > 0 {
  27. lossCorr = Percentage2u32(nattrs.LossCorr)
  28. }
  29. if duplicate > 0 {
  30. duplicateCorr = Percentage2u32(nattrs.DuplicateCorr)
  31. }
  32. // FIXME should validate values(like loss/duplicate are percentages...)
  33. latency = time2Tick(latency)
  34. if nattrs.Limit != 0 {
  35. limit = nattrs.Limit
  36. }
  37. // Jitter is only value if latency is > 0
  38. if latency > 0 {
  39. jitter = time2Tick(jitter)
  40. }
  41. reorderProb = Percentage2u32(nattrs.ReorderProb)
  42. reorderCorr = Percentage2u32(nattrs.ReorderCorr)
  43. if reorderProb > 0 {
  44. // ERROR if lantency == 0
  45. if gap == 0 {
  46. gap = 1
  47. }
  48. }
  49. corruptProb = Percentage2u32(nattrs.CorruptProb)
  50. corruptCorr = Percentage2u32(nattrs.CorruptCorr)
  51. return &Netem{
  52. QdiscAttrs: attrs,
  53. Latency: latency,
  54. DelayCorr: delayCorr,
  55. Limit: limit,
  56. Loss: loss,
  57. LossCorr: lossCorr,
  58. Gap: gap,
  59. Duplicate: duplicate,
  60. DuplicateCorr: duplicateCorr,
  61. Jitter: jitter,
  62. ReorderProb: reorderProb,
  63. ReorderCorr: reorderCorr,
  64. CorruptProb: corruptProb,
  65. CorruptCorr: corruptCorr,
  66. }
  67. }
  68. // QdiscDel will delete a qdisc from the system.
  69. // Equivalent to: `tc qdisc del $qdisc`
  70. func QdiscDel(qdisc Qdisc) error {
  71. return pkgHandle.QdiscDel(qdisc)
  72. }
  73. // QdiscDel will delete a qdisc from the system.
  74. // Equivalent to: `tc qdisc del $qdisc`
  75. func (h *Handle) QdiscDel(qdisc Qdisc) error {
  76. return h.qdiscModify(unix.RTM_DELQDISC, 0, qdisc)
  77. }
  78. // QdiscChange will change a qdisc in place
  79. // Equivalent to: `tc qdisc change $qdisc`
  80. // The parent and handle MUST NOT be changed.
  81. func QdiscChange(qdisc Qdisc) error {
  82. return pkgHandle.QdiscChange(qdisc)
  83. }
  84. // QdiscChange will change a qdisc in place
  85. // Equivalent to: `tc qdisc change $qdisc`
  86. // The parent and handle MUST NOT be changed.
  87. func (h *Handle) QdiscChange(qdisc Qdisc) error {
  88. return h.qdiscModify(unix.RTM_NEWQDISC, 0, qdisc)
  89. }
  90. // QdiscReplace will replace a qdisc to the system.
  91. // Equivalent to: `tc qdisc replace $qdisc`
  92. // The handle MUST change.
  93. func QdiscReplace(qdisc Qdisc) error {
  94. return pkgHandle.QdiscReplace(qdisc)
  95. }
  96. // QdiscReplace will replace a qdisc to the system.
  97. // Equivalent to: `tc qdisc replace $qdisc`
  98. // The handle MUST change.
  99. func (h *Handle) QdiscReplace(qdisc Qdisc) error {
  100. return h.qdiscModify(
  101. unix.RTM_NEWQDISC,
  102. unix.NLM_F_CREATE|unix.NLM_F_REPLACE,
  103. qdisc)
  104. }
  105. // QdiscAdd will add a qdisc to the system.
  106. // Equivalent to: `tc qdisc add $qdisc`
  107. func QdiscAdd(qdisc Qdisc) error {
  108. return pkgHandle.QdiscAdd(qdisc)
  109. }
  110. // QdiscAdd will add a qdisc to the system.
  111. // Equivalent to: `tc qdisc add $qdisc`
  112. func (h *Handle) QdiscAdd(qdisc Qdisc) error {
  113. return h.qdiscModify(
  114. unix.RTM_NEWQDISC,
  115. unix.NLM_F_CREATE|unix.NLM_F_EXCL,
  116. qdisc)
  117. }
  118. func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
  119. req := h.newNetlinkRequest(cmd, flags|unix.NLM_F_ACK)
  120. base := qdisc.Attrs()
  121. msg := &nl.TcMsg{
  122. Family: nl.FAMILY_ALL,
  123. Ifindex: int32(base.LinkIndex),
  124. Handle: base.Handle,
  125. Parent: base.Parent,
  126. }
  127. req.AddData(msg)
  128. // When deleting don't bother building the rest of the netlink payload
  129. if cmd != unix.RTM_DELQDISC {
  130. if err := qdiscPayload(req, qdisc); err != nil {
  131. return err
  132. }
  133. }
  134. _, err := req.Execute(unix.NETLINK_ROUTE, 0)
  135. return err
  136. }
  137. func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
  138. req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(qdisc.Type())))
  139. options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
  140. switch qdisc := qdisc.(type) {
  141. case *Prio:
  142. tcmap := nl.TcPrioMap{
  143. Bands: int32(qdisc.Bands),
  144. Priomap: qdisc.PriorityMap,
  145. }
  146. options = nl.NewRtAttr(nl.TCA_OPTIONS, tcmap.Serialize())
  147. case *Tbf:
  148. opt := nl.TcTbfQopt{}
  149. opt.Rate.Rate = uint32(qdisc.Rate)
  150. opt.Peakrate.Rate = uint32(qdisc.Peakrate)
  151. opt.Limit = qdisc.Limit
  152. opt.Buffer = qdisc.Buffer
  153. options.AddRtAttr(nl.TCA_TBF_PARMS, opt.Serialize())
  154. if qdisc.Rate >= uint64(1<<32) {
  155. options.AddRtAttr(nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
  156. }
  157. if qdisc.Peakrate >= uint64(1<<32) {
  158. options.AddRtAttr(nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
  159. }
  160. if qdisc.Peakrate > 0 {
  161. options.AddRtAttr(nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
  162. }
  163. case *Htb:
  164. opt := nl.TcHtbGlob{}
  165. opt.Version = qdisc.Version
  166. opt.Rate2Quantum = qdisc.Rate2Quantum
  167. opt.Defcls = qdisc.Defcls
  168. // TODO: Handle Debug properly. For now default to 0
  169. opt.Debug = qdisc.Debug
  170. opt.DirectPkts = qdisc.DirectPkts
  171. options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize())
  172. // options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
  173. case *Hfsc:
  174. opt := nl.TcHfscOpt{}
  175. opt.Defcls = qdisc.Defcls
  176. options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
  177. case *Netem:
  178. opt := nl.TcNetemQopt{}
  179. opt.Latency = qdisc.Latency
  180. opt.Limit = qdisc.Limit
  181. opt.Loss = qdisc.Loss
  182. opt.Gap = qdisc.Gap
  183. opt.Duplicate = qdisc.Duplicate
  184. opt.Jitter = qdisc.Jitter
  185. options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
  186. // Correlation
  187. corr := nl.TcNetemCorr{}
  188. corr.DelayCorr = qdisc.DelayCorr
  189. corr.LossCorr = qdisc.LossCorr
  190. corr.DupCorr = qdisc.DuplicateCorr
  191. if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 {
  192. options.AddRtAttr(nl.TCA_NETEM_CORR, corr.Serialize())
  193. }
  194. // Corruption
  195. corruption := nl.TcNetemCorrupt{}
  196. corruption.Probability = qdisc.CorruptProb
  197. corruption.Correlation = qdisc.CorruptCorr
  198. if corruption.Probability > 0 {
  199. options.AddRtAttr(nl.TCA_NETEM_CORRUPT, corruption.Serialize())
  200. }
  201. // Reorder
  202. reorder := nl.TcNetemReorder{}
  203. reorder.Probability = qdisc.ReorderProb
  204. reorder.Correlation = qdisc.ReorderCorr
  205. if reorder.Probability > 0 {
  206. options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize())
  207. }
  208. case *Ingress:
  209. // ingress filters must use the proper handle
  210. if qdisc.Attrs().Parent != HANDLE_INGRESS {
  211. return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
  212. }
  213. case *FqCodel:
  214. options.AddRtAttr(nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
  215. if qdisc.Limit > 0 {
  216. options.AddRtAttr(nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
  217. }
  218. if qdisc.Interval > 0 {
  219. options.AddRtAttr(nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
  220. }
  221. if qdisc.Flows > 0 {
  222. options.AddRtAttr(nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
  223. }
  224. if qdisc.Quantum > 0 {
  225. options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
  226. }
  227. if qdisc.CEThreshold > 0 {
  228. options.AddRtAttr(nl.TCA_FQ_CODEL_CE_THRESHOLD, nl.Uint32Attr(qdisc.CEThreshold))
  229. }
  230. if qdisc.DropBatchSize > 0 {
  231. options.AddRtAttr(nl.TCA_FQ_CODEL_DROP_BATCH_SIZE, nl.Uint32Attr(qdisc.DropBatchSize))
  232. }
  233. if qdisc.MemoryLimit > 0 {
  234. options.AddRtAttr(nl.TCA_FQ_CODEL_MEMORY_LIMIT, nl.Uint32Attr(qdisc.MemoryLimit))
  235. }
  236. case *Fq:
  237. options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
  238. if qdisc.Buckets > 0 {
  239. options.AddRtAttr(nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
  240. }
  241. if qdisc.LowRateThreshold > 0 {
  242. options.AddRtAttr(nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
  243. }
  244. if qdisc.Quantum > 0 {
  245. options.AddRtAttr(nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
  246. }
  247. if qdisc.InitialQuantum > 0 {
  248. options.AddRtAttr(nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
  249. }
  250. if qdisc.FlowRefillDelay > 0 {
  251. options.AddRtAttr(nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
  252. }
  253. if qdisc.FlowPacketLimit > 0 {
  254. options.AddRtAttr(nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
  255. }
  256. if qdisc.FlowMaxRate > 0 {
  257. options.AddRtAttr(nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
  258. }
  259. if qdisc.FlowDefaultRate > 0 {
  260. options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
  261. }
  262. case *Sfq:
  263. opt := nl.TcSfqQoptV1{}
  264. opt.TcSfqQopt.Quantum = qdisc.Quantum
  265. opt.TcSfqQopt.Perturb = int32(qdisc.Perturb)
  266. opt.TcSfqQopt.Limit = qdisc.Limit
  267. opt.TcSfqQopt.Divisor = qdisc.Divisor
  268. options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
  269. default:
  270. options = nil
  271. }
  272. if options != nil {
  273. req.AddData(options)
  274. }
  275. return nil
  276. }
  277. // QdiscList gets a list of qdiscs in the system.
  278. // Equivalent to: `tc qdisc show`.
  279. // The list can be filtered by link.
  280. func QdiscList(link Link) ([]Qdisc, error) {
  281. return pkgHandle.QdiscList(link)
  282. }
  283. // QdiscList gets a list of qdiscs in the system.
  284. // Equivalent to: `tc qdisc show`.
  285. // The list can be filtered by link.
  286. func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
  287. req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
  288. index := int32(0)
  289. if link != nil {
  290. base := link.Attrs()
  291. h.ensureIndex(base)
  292. index = int32(base.Index)
  293. }
  294. msg := &nl.TcMsg{
  295. Family: nl.FAMILY_ALL,
  296. Ifindex: index,
  297. }
  298. req.AddData(msg)
  299. msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
  300. if err != nil {
  301. return nil, err
  302. }
  303. var res []Qdisc
  304. for _, m := range msgs {
  305. msg := nl.DeserializeTcMsg(m)
  306. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  307. if err != nil {
  308. return nil, err
  309. }
  310. // skip qdiscs from other interfaces
  311. if link != nil && msg.Ifindex != index {
  312. continue
  313. }
  314. base := QdiscAttrs{
  315. LinkIndex: int(msg.Ifindex),
  316. Handle: msg.Handle,
  317. Parent: msg.Parent,
  318. Refcnt: msg.Info,
  319. }
  320. var qdisc Qdisc
  321. qdiscType := ""
  322. for _, attr := range attrs {
  323. switch attr.Attr.Type {
  324. case nl.TCA_KIND:
  325. qdiscType = string(attr.Value[:len(attr.Value)-1])
  326. switch qdiscType {
  327. case "pfifo_fast":
  328. qdisc = &PfifoFast{}
  329. case "prio":
  330. qdisc = &Prio{}
  331. case "tbf":
  332. qdisc = &Tbf{}
  333. case "ingress":
  334. qdisc = &Ingress{}
  335. case "htb":
  336. qdisc = &Htb{}
  337. case "fq":
  338. qdisc = &Fq{}
  339. case "hfsc":
  340. qdisc = &Hfsc{}
  341. case "fq_codel":
  342. qdisc = &FqCodel{}
  343. case "netem":
  344. qdisc = &Netem{}
  345. case "sfq":
  346. qdisc = &Sfq{}
  347. default:
  348. qdisc = &GenericQdisc{QdiscType: qdiscType}
  349. }
  350. case nl.TCA_OPTIONS:
  351. switch qdiscType {
  352. case "pfifo_fast":
  353. // pfifo returns TcPrioMap directly without wrapping it in rtattr
  354. if err := parsePfifoFastData(qdisc, attr.Value); err != nil {
  355. return nil, err
  356. }
  357. case "prio":
  358. // prio returns TcPrioMap directly without wrapping it in rtattr
  359. if err := parsePrioData(qdisc, attr.Value); err != nil {
  360. return nil, err
  361. }
  362. case "tbf":
  363. data, err := nl.ParseRouteAttr(attr.Value)
  364. if err != nil {
  365. return nil, err
  366. }
  367. if err := parseTbfData(qdisc, data); err != nil {
  368. return nil, err
  369. }
  370. case "hfsc":
  371. if err := parseHfscData(qdisc, attr.Value); err != nil {
  372. return nil, err
  373. }
  374. case "htb":
  375. data, err := nl.ParseRouteAttr(attr.Value)
  376. if err != nil {
  377. return nil, err
  378. }
  379. if err := parseHtbData(qdisc, data); err != nil {
  380. return nil, err
  381. }
  382. case "fq":
  383. data, err := nl.ParseRouteAttr(attr.Value)
  384. if err != nil {
  385. return nil, err
  386. }
  387. if err := parseFqData(qdisc, data); err != nil {
  388. return nil, err
  389. }
  390. case "fq_codel":
  391. data, err := nl.ParseRouteAttr(attr.Value)
  392. if err != nil {
  393. return nil, err
  394. }
  395. if err := parseFqCodelData(qdisc, data); err != nil {
  396. return nil, err
  397. }
  398. case "netem":
  399. if err := parseNetemData(qdisc, attr.Value); err != nil {
  400. return nil, err
  401. }
  402. case "sfq":
  403. if err := parseSfqData(qdisc, attr.Value); err != nil {
  404. return nil, err
  405. }
  406. // no options for ingress
  407. }
  408. }
  409. }
  410. *qdisc.Attrs() = base
  411. res = append(res, qdisc)
  412. }
  413. return res, nil
  414. }
  415. func parsePfifoFastData(qdisc Qdisc, value []byte) error {
  416. pfifo := qdisc.(*PfifoFast)
  417. tcmap := nl.DeserializeTcPrioMap(value)
  418. pfifo.PriorityMap = tcmap.Priomap
  419. pfifo.Bands = uint8(tcmap.Bands)
  420. return nil
  421. }
  422. func parsePrioData(qdisc Qdisc, value []byte) error {
  423. prio := qdisc.(*Prio)
  424. tcmap := nl.DeserializeTcPrioMap(value)
  425. prio.PriorityMap = tcmap.Priomap
  426. prio.Bands = uint8(tcmap.Bands)
  427. return nil
  428. }
  429. func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
  430. htb := qdisc.(*Htb)
  431. for _, datum := range data {
  432. switch datum.Attr.Type {
  433. case nl.TCA_HTB_INIT:
  434. opt := nl.DeserializeTcHtbGlob(datum.Value)
  435. htb.Version = opt.Version
  436. htb.Rate2Quantum = opt.Rate2Quantum
  437. htb.Defcls = opt.Defcls
  438. htb.Debug = opt.Debug
  439. htb.DirectPkts = opt.DirectPkts
  440. case nl.TCA_HTB_DIRECT_QLEN:
  441. // TODO
  442. //htb.DirectQlen = native.uint32(datum.Value)
  443. }
  444. }
  445. return nil
  446. }
  447. func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
  448. fqCodel := qdisc.(*FqCodel)
  449. for _, datum := range data {
  450. switch datum.Attr.Type {
  451. case nl.TCA_FQ_CODEL_TARGET:
  452. fqCodel.Target = native.Uint32(datum.Value)
  453. case nl.TCA_FQ_CODEL_LIMIT:
  454. fqCodel.Limit = native.Uint32(datum.Value)
  455. case nl.TCA_FQ_CODEL_INTERVAL:
  456. fqCodel.Interval = native.Uint32(datum.Value)
  457. case nl.TCA_FQ_CODEL_ECN:
  458. fqCodel.ECN = native.Uint32(datum.Value)
  459. case nl.TCA_FQ_CODEL_FLOWS:
  460. fqCodel.Flows = native.Uint32(datum.Value)
  461. case nl.TCA_FQ_CODEL_QUANTUM:
  462. fqCodel.Quantum = native.Uint32(datum.Value)
  463. case nl.TCA_FQ_CODEL_CE_THRESHOLD:
  464. fqCodel.CEThreshold = native.Uint32(datum.Value)
  465. case nl.TCA_FQ_CODEL_DROP_BATCH_SIZE:
  466. fqCodel.DropBatchSize = native.Uint32(datum.Value)
  467. case nl.TCA_FQ_CODEL_MEMORY_LIMIT:
  468. fqCodel.MemoryLimit = native.Uint32(datum.Value)
  469. }
  470. }
  471. return nil
  472. }
  473. func parseHfscData(qdisc Qdisc, data []byte) error {
  474. Hfsc := qdisc.(*Hfsc)
  475. Hfsc.Defcls = native.Uint16(data)
  476. return nil
  477. }
  478. func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
  479. fq := qdisc.(*Fq)
  480. for _, datum := range data {
  481. switch datum.Attr.Type {
  482. case nl.TCA_FQ_BUCKETS_LOG:
  483. fq.Buckets = native.Uint32(datum.Value)
  484. case nl.TCA_FQ_LOW_RATE_THRESHOLD:
  485. fq.LowRateThreshold = native.Uint32(datum.Value)
  486. case nl.TCA_FQ_QUANTUM:
  487. fq.Quantum = native.Uint32(datum.Value)
  488. case nl.TCA_FQ_RATE_ENABLE:
  489. fq.Pacing = native.Uint32(datum.Value)
  490. case nl.TCA_FQ_INITIAL_QUANTUM:
  491. fq.InitialQuantum = native.Uint32(datum.Value)
  492. case nl.TCA_FQ_ORPHAN_MASK:
  493. // TODO
  494. case nl.TCA_FQ_FLOW_REFILL_DELAY:
  495. fq.FlowRefillDelay = native.Uint32(datum.Value)
  496. case nl.TCA_FQ_FLOW_PLIMIT:
  497. fq.FlowPacketLimit = native.Uint32(datum.Value)
  498. case nl.TCA_FQ_PLIMIT:
  499. fq.PacketLimit = native.Uint32(datum.Value)
  500. case nl.TCA_FQ_FLOW_MAX_RATE:
  501. fq.FlowMaxRate = native.Uint32(datum.Value)
  502. case nl.TCA_FQ_FLOW_DEFAULT_RATE:
  503. fq.FlowDefaultRate = native.Uint32(datum.Value)
  504. }
  505. }
  506. return nil
  507. }
  508. func parseNetemData(qdisc Qdisc, value []byte) error {
  509. netem := qdisc.(*Netem)
  510. opt := nl.DeserializeTcNetemQopt(value)
  511. netem.Latency = opt.Latency
  512. netem.Limit = opt.Limit
  513. netem.Loss = opt.Loss
  514. netem.Gap = opt.Gap
  515. netem.Duplicate = opt.Duplicate
  516. netem.Jitter = opt.Jitter
  517. data, err := nl.ParseRouteAttr(value[nl.SizeofTcNetemQopt:])
  518. if err != nil {
  519. return err
  520. }
  521. for _, datum := range data {
  522. switch datum.Attr.Type {
  523. case nl.TCA_NETEM_CORR:
  524. opt := nl.DeserializeTcNetemCorr(datum.Value)
  525. netem.DelayCorr = opt.DelayCorr
  526. netem.LossCorr = opt.LossCorr
  527. netem.DuplicateCorr = opt.DupCorr
  528. case nl.TCA_NETEM_CORRUPT:
  529. opt := nl.DeserializeTcNetemCorrupt(datum.Value)
  530. netem.CorruptProb = opt.Probability
  531. netem.CorruptCorr = opt.Correlation
  532. case nl.TCA_NETEM_REORDER:
  533. opt := nl.DeserializeTcNetemReorder(datum.Value)
  534. netem.ReorderProb = opt.Probability
  535. netem.ReorderCorr = opt.Correlation
  536. }
  537. }
  538. return nil
  539. }
  540. func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
  541. tbf := qdisc.(*Tbf)
  542. for _, datum := range data {
  543. switch datum.Attr.Type {
  544. case nl.TCA_TBF_PARMS:
  545. opt := nl.DeserializeTcTbfQopt(datum.Value)
  546. tbf.Rate = uint64(opt.Rate.Rate)
  547. tbf.Peakrate = uint64(opt.Peakrate.Rate)
  548. tbf.Limit = opt.Limit
  549. tbf.Buffer = opt.Buffer
  550. case nl.TCA_TBF_RATE64:
  551. tbf.Rate = native.Uint64(datum.Value[0:8])
  552. case nl.TCA_TBF_PRATE64:
  553. tbf.Peakrate = native.Uint64(datum.Value[0:8])
  554. case nl.TCA_TBF_PBURST:
  555. tbf.Minburst = native.Uint32(datum.Value[0:4])
  556. }
  557. }
  558. return nil
  559. }
  560. func parseSfqData(qdisc Qdisc, value []byte) error {
  561. sfq := qdisc.(*Sfq)
  562. opt := nl.DeserializeTcSfqQoptV1(value)
  563. sfq.Quantum = opt.TcSfqQopt.Quantum
  564. sfq.Perturb = uint8(opt.TcSfqQopt.Perturb)
  565. sfq.Limit = opt.TcSfqQopt.Limit
  566. sfq.Divisor = opt.TcSfqQopt.Divisor
  567. return nil
  568. }
  569. const (
  570. TIME_UNITS_PER_SEC = 1000000
  571. )
  572. var (
  573. tickInUsec float64
  574. clockFactor float64
  575. hz float64
  576. )
  577. func initClock() {
  578. data, err := ioutil.ReadFile("/proc/net/psched")
  579. if err != nil {
  580. return
  581. }
  582. parts := strings.Split(strings.TrimSpace(string(data)), " ")
  583. if len(parts) < 4 {
  584. return
  585. }
  586. var vals [4]uint64
  587. for i := range vals {
  588. val, err := strconv.ParseUint(parts[i], 16, 32)
  589. if err != nil {
  590. return
  591. }
  592. vals[i] = val
  593. }
  594. // compatibility
  595. if vals[2] == 1000000000 {
  596. vals[0] = vals[1]
  597. }
  598. clockFactor = float64(vals[2]) / TIME_UNITS_PER_SEC
  599. tickInUsec = float64(vals[0]) / float64(vals[1]) * clockFactor
  600. if vals[2] == 1000000 {
  601. // ref https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/lib/utils.c#n963
  602. hz = float64(vals[3])
  603. } else {
  604. hz = 100
  605. }
  606. }
  607. func TickInUsec() float64 {
  608. if tickInUsec == 0.0 {
  609. initClock()
  610. }
  611. return tickInUsec
  612. }
  613. func ClockFactor() float64 {
  614. if clockFactor == 0.0 {
  615. initClock()
  616. }
  617. return clockFactor
  618. }
  619. func Hz() float64 {
  620. if hz == 0.0 {
  621. initClock()
  622. }
  623. return hz
  624. }
  625. func time2Tick(time uint32) uint32 {
  626. return uint32(float64(time) * TickInUsec())
  627. }
  628. func tick2Time(tick uint32) uint32 {
  629. return uint32(float64(tick) / TickInUsec())
  630. }
  631. func time2Ktime(time uint32) uint32 {
  632. return uint32(float64(time) * ClockFactor())
  633. }
  634. func ktime2Time(ktime uint32) uint32 {
  635. return uint32(float64(ktime) / ClockFactor())
  636. }
  637. func burst(rate uint64, buffer uint32) uint32 {
  638. return uint32(float64(rate) * float64(tick2Time(buffer)) / TIME_UNITS_PER_SEC)
  639. }
  640. func latency(rate uint64, limit, buffer uint32) float64 {
  641. return TIME_UNITS_PER_SEC*(float64(limit)/float64(rate)) - float64(tick2Time(buffer))
  642. }
  643. func Xmittime(rate uint64, size uint32) uint32 {
  644. // https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/tc/tc_core.c#n62
  645. return time2Tick(uint32(TIME_UNITS_PER_SEC * (float64(size) / float64(rate))))
  646. }
  647. func Xmitsize(rate uint64, ticks uint32) uint32 {
  648. return uint32((float64(rate) * float64(tick2Time(ticks))) / TIME_UNITS_PER_SEC)
  649. }