qdisc.go 8.4 KB

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