qdisc_linux.go 21 KB

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