qdisc.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package netlink
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. const (
  7. HANDLE_NONE = 0
  8. HANDLE_INGRESS = 0xFFFFFFF1
  9. HANDLE_ROOT = 0xFFFFFFFF
  10. PRIORITY_MAP_LEN = 16
  11. )
  12. type Qdisc interface {
  13. Attrs() *QdiscAttrs
  14. Type() string
  15. }
  16. // Qdisc represents a netlink qdisc. A qdisc is associated with a link,
  17. // has a handle, a parent and a refcnt. The root qdisc of a device should
  18. // have parent == HANDLE_ROOT.
  19. type QdiscAttrs struct {
  20. LinkIndex int
  21. Handle uint32
  22. Parent uint32
  23. Refcnt uint32 // read only
  24. }
  25. func (q QdiscAttrs) String() string {
  26. return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
  27. }
  28. func MakeHandle(major, minor uint16) uint32 {
  29. return (uint32(major) << 16) | uint32(minor)
  30. }
  31. func MajorMinor(handle uint32) (uint16, uint16) {
  32. return uint16((handle & 0xFFFF0000) >> 16), uint16(handle & 0x0000FFFFF)
  33. }
  34. func HandleStr(handle uint32) string {
  35. switch handle {
  36. case HANDLE_NONE:
  37. return "none"
  38. case HANDLE_INGRESS:
  39. return "ingress"
  40. case HANDLE_ROOT:
  41. return "root"
  42. default:
  43. major, minor := MajorMinor(handle)
  44. return fmt.Sprintf("%x:%x", major, minor)
  45. }
  46. }
  47. func Percentage2u32(percentage float32) uint32 {
  48. // FIXME this is most likely not the best way to convert from % to uint32
  49. if percentage == 100 {
  50. return math.MaxUint32
  51. }
  52. return uint32(math.MaxUint32 * (percentage / 100))
  53. }
  54. // PfifoFast is the default qdisc created by the kernel if one has not
  55. // been defined for the interface
  56. type PfifoFast struct {
  57. QdiscAttrs
  58. Bands uint8
  59. PriorityMap [PRIORITY_MAP_LEN]uint8
  60. }
  61. func (qdisc *PfifoFast) Attrs() *QdiscAttrs {
  62. return &qdisc.QdiscAttrs
  63. }
  64. func (qdisc *PfifoFast) Type() string {
  65. return "pfifo_fast"
  66. }
  67. // Prio is a basic qdisc that works just like PfifoFast
  68. type Prio struct {
  69. QdiscAttrs
  70. Bands uint8
  71. PriorityMap [PRIORITY_MAP_LEN]uint8
  72. }
  73. func NewPrio(attrs QdiscAttrs) *Prio {
  74. return &Prio{
  75. QdiscAttrs: attrs,
  76. Bands: 3,
  77. PriorityMap: [PRIORITY_MAP_LEN]uint8{1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
  78. }
  79. }
  80. func (qdisc *Prio) Attrs() *QdiscAttrs {
  81. return &qdisc.QdiscAttrs
  82. }
  83. func (qdisc *Prio) Type() string {
  84. return "prio"
  85. }
  86. // Htb is a classful qdisc that rate limits based on tokens
  87. type Htb struct {
  88. QdiscAttrs
  89. Version uint32
  90. Rate2Quantum uint32
  91. Defcls uint32
  92. Debug uint32
  93. DirectPkts uint32
  94. }
  95. func NewHtb(attrs QdiscAttrs) *Htb {
  96. return &Htb{
  97. QdiscAttrs: attrs,
  98. Version: 3,
  99. Defcls: 0,
  100. Rate2Quantum: 10,
  101. Debug: 0,
  102. DirectPkts: 0,
  103. }
  104. }
  105. func (qdisc *Htb) Attrs() *QdiscAttrs {
  106. return &qdisc.QdiscAttrs
  107. }
  108. func (qdisc *Htb) Type() string {
  109. return "htb"
  110. }
  111. // Netem is a classless qdisc that rate limits based on tokens
  112. type NetemQdiscAttrs struct {
  113. Latency uint32 // in us
  114. DelayCorr float32 // in %
  115. Limit uint32
  116. Loss float32 // in %
  117. LossCorr float32 // in %
  118. Gap uint32
  119. Duplicate float32 // in %
  120. DuplicateCorr float32 // in %
  121. Jitter uint32 // in us
  122. ReorderProb float32 // in %
  123. ReorderCorr float32 // in %
  124. CorruptProb float32 // in %
  125. CorruptCorr float32 // in %
  126. }
  127. func (q NetemQdiscAttrs) String() string {
  128. return fmt.Sprintf(
  129. "{Latency: %d, Limit: %d, Loss: %d, Gap: %d, Duplicate: %d, Jitter: %d}",
  130. q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter,
  131. )
  132. }
  133. type Netem struct {
  134. QdiscAttrs
  135. Latency uint32
  136. DelayCorr uint32
  137. Limit uint32
  138. Loss uint32
  139. LossCorr uint32
  140. Gap uint32
  141. Duplicate uint32
  142. DuplicateCorr uint32
  143. Jitter uint32
  144. ReorderProb uint32
  145. ReorderCorr uint32
  146. CorruptProb uint32
  147. CorruptCorr uint32
  148. }
  149. func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
  150. var limit uint32 = 1000
  151. var loss_corr, delay_corr, duplicate_corr uint32
  152. var reorder_prob, reorder_corr uint32
  153. var corrupt_prob, corrupt_corr uint32
  154. latency := nattrs.Latency
  155. loss := Percentage2u32(nattrs.Loss)
  156. gap := nattrs.Gap
  157. duplicate := Percentage2u32(nattrs.Duplicate)
  158. jitter := nattrs.Jitter
  159. // Correlation
  160. if latency > 0 && jitter > 0 {
  161. delay_corr = Percentage2u32(nattrs.DelayCorr)
  162. }
  163. if loss > 0 {
  164. loss_corr = Percentage2u32(nattrs.LossCorr)
  165. }
  166. if duplicate > 0 {
  167. duplicate_corr = Percentage2u32(nattrs.DuplicateCorr)
  168. }
  169. // FIXME should validate values(like loss/duplicate are percentages...)
  170. latency = time2Tick(latency)
  171. if nattrs.Limit != 0 {
  172. limit = nattrs.Limit
  173. }
  174. // Jitter is only value if latency is > 0
  175. if latency > 0 {
  176. jitter = time2Tick(jitter)
  177. }
  178. reorder_prob = Percentage2u32(nattrs.ReorderProb)
  179. reorder_corr = Percentage2u32(nattrs.ReorderCorr)
  180. if reorder_prob > 0 {
  181. // ERROR if lantency == 0
  182. if gap == 0 {
  183. gap = 1
  184. }
  185. }
  186. corrupt_prob = Percentage2u32(nattrs.CorruptProb)
  187. corrupt_corr = Percentage2u32(nattrs.CorruptCorr)
  188. return &Netem{
  189. QdiscAttrs: attrs,
  190. Latency: latency,
  191. DelayCorr: delay_corr,
  192. Limit: limit,
  193. Loss: loss,
  194. LossCorr: loss_corr,
  195. Gap: gap,
  196. Duplicate: duplicate,
  197. DuplicateCorr: duplicate_corr,
  198. Jitter: jitter,
  199. ReorderProb: reorder_prob,
  200. ReorderCorr: reorder_corr,
  201. CorruptProb: corrupt_prob,
  202. CorruptCorr: corrupt_corr,
  203. }
  204. }
  205. func (qdisc *Netem) Attrs() *QdiscAttrs {
  206. return &qdisc.QdiscAttrs
  207. }
  208. func (qdisc *Netem) Type() string {
  209. return "netem"
  210. }
  211. // Tbf is a classless qdisc that rate limits based on tokens
  212. type Tbf struct {
  213. QdiscAttrs
  214. // TODO: handle 64bit rate properly
  215. Rate uint64
  216. Limit uint32
  217. Buffer uint32
  218. // TODO: handle other settings
  219. }
  220. func (qdisc *Tbf) Attrs() *QdiscAttrs {
  221. return &qdisc.QdiscAttrs
  222. }
  223. func (qdisc *Tbf) Type() string {
  224. return "tbf"
  225. }
  226. // Ingress is a qdisc for adding ingress filters
  227. type Ingress struct {
  228. QdiscAttrs
  229. }
  230. func (qdisc *Ingress) Attrs() *QdiscAttrs {
  231. return &qdisc.QdiscAttrs
  232. }
  233. func (qdisc *Ingress) Type() string {
  234. return "ingress"
  235. }
  236. // GenericQdisc qdiscs represent types that are not currently understood
  237. // by this netlink library.
  238. type GenericQdisc struct {
  239. QdiscAttrs
  240. QdiscType string
  241. }
  242. func (qdisc *GenericQdisc) Attrs() *QdiscAttrs {
  243. return &qdisc.QdiscAttrs
  244. }
  245. func (qdisc *GenericQdisc) Type() string {
  246. return qdisc.QdiscType
  247. }