qdisc.go 7.2 KB

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