class_linux.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package netlink
  2. import (
  3. "errors"
  4. "syscall"
  5. "github.com/vishvananda/netlink/nl"
  6. )
  7. // NOTE: function is in here because it uses other linux functions
  8. func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
  9. mtu := 1600
  10. rate := cattrs.Rate / 8
  11. ceil := cattrs.Ceil / 8
  12. buffer := cattrs.Buffer
  13. cbuffer := cattrs.Cbuffer
  14. if ceil == 0 {
  15. ceil = rate
  16. }
  17. if buffer == 0 {
  18. buffer = uint32(float64(rate)/Hz() + float64(mtu))
  19. }
  20. buffer = uint32(Xmittime(rate, buffer))
  21. if cbuffer == 0 {
  22. cbuffer = uint32(float64(ceil)/Hz() + float64(mtu))
  23. }
  24. cbuffer = uint32(Xmittime(ceil, cbuffer))
  25. return &HtbClass{
  26. ClassAttrs: attrs,
  27. Rate: rate,
  28. Ceil: ceil,
  29. Buffer: buffer,
  30. Cbuffer: cbuffer,
  31. Quantum: 10,
  32. Level: 0,
  33. Prio: 0,
  34. }
  35. }
  36. // ClassDel will delete a class from the system.
  37. // Equivalent to: `tc class del $class`
  38. func ClassDel(class Class) error {
  39. return pkgHandle.ClassDel(class)
  40. }
  41. // ClassDel will delete a class from the system.
  42. // Equivalent to: `tc class del $class`
  43. func (h *Handle) ClassDel(class Class) error {
  44. return h.classModify(syscall.RTM_DELTCLASS, 0, class)
  45. }
  46. // ClassChange will change a class in place
  47. // Equivalent to: `tc class change $class`
  48. // The parent and handle MUST NOT be changed.
  49. func ClassChange(class Class) error {
  50. return pkgHandle.ClassChange(class)
  51. }
  52. // ClassChange will change a class in place
  53. // Equivalent to: `tc class change $class`
  54. // The parent and handle MUST NOT be changed.
  55. func (h *Handle) ClassChange(class Class) error {
  56. return h.classModify(syscall.RTM_NEWTCLASS, 0, class)
  57. }
  58. // ClassReplace will replace a class to the system.
  59. // quivalent to: `tc class replace $class`
  60. // The handle MAY be changed.
  61. // If a class already exist with this parent/handle pair, the class is changed.
  62. // If a class does not already exist with this parent/handle, a new class is created.
  63. func ClassReplace(class Class) error {
  64. return pkgHandle.ClassReplace(class)
  65. }
  66. // ClassReplace will replace a class to the system.
  67. // quivalent to: `tc class replace $class`
  68. // The handle MAY be changed.
  69. // If a class already exist with this parent/handle pair, the class is changed.
  70. // If a class does not already exist with this parent/handle, a new class is created.
  71. func (h *Handle) ClassReplace(class Class) error {
  72. return h.classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class)
  73. }
  74. // ClassAdd will add a class to the system.
  75. // Equivalent to: `tc class add $class`
  76. func ClassAdd(class Class) error {
  77. return pkgHandle.ClassAdd(class)
  78. }
  79. // ClassAdd will add a class to the system.
  80. // Equivalent to: `tc class add $class`
  81. func (h *Handle) ClassAdd(class Class) error {
  82. return h.classModify(
  83. syscall.RTM_NEWTCLASS,
  84. syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
  85. class,
  86. )
  87. }
  88. func (h *Handle) classModify(cmd, flags int, class Class) error {
  89. req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
  90. base := class.Attrs()
  91. msg := &nl.TcMsg{
  92. Family: nl.FAMILY_ALL,
  93. Ifindex: int32(base.LinkIndex),
  94. Handle: base.Handle,
  95. Parent: base.Parent,
  96. }
  97. req.AddData(msg)
  98. if cmd != syscall.RTM_DELTCLASS {
  99. if err := classPayload(req, class); err != nil {
  100. return err
  101. }
  102. }
  103. _, err := req.Execute(syscall.NETLINK_ROUTE, 0)
  104. return err
  105. }
  106. func classPayload(req *nl.NetlinkRequest, class Class) error {
  107. req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type())))
  108. options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
  109. if htb, ok := class.(*HtbClass); ok {
  110. opt := nl.TcHtbCopt{}
  111. opt.Buffer = htb.Buffer
  112. opt.Cbuffer = htb.Cbuffer
  113. opt.Quantum = htb.Quantum
  114. opt.Level = htb.Level
  115. opt.Prio = htb.Prio
  116. // TODO: Handle Debug properly. For now default to 0
  117. /* Calculate {R,C}Tab and set Rate and Ceil */
  118. cellLog := -1
  119. ccellLog := -1
  120. linklayer := nl.LINKLAYER_ETHERNET
  121. mtu := 1600
  122. var rtab [256]uint32
  123. var ctab [256]uint32
  124. tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
  125. if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 {
  126. return errors.New("HTB: failed to calculate rate table")
  127. }
  128. opt.Rate = tcrate
  129. tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
  130. if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 {
  131. return errors.New("HTB: failed to calculate ceil rate table")
  132. }
  133. opt.Ceil = tcceil
  134. nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
  135. nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
  136. nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
  137. }
  138. req.AddData(options)
  139. return nil
  140. }
  141. // ClassList gets a list of classes in the system.
  142. // Equivalent to: `tc class show`.
  143. // Generally returns nothing if link and parent are not specified.
  144. func ClassList(link Link, parent uint32) ([]Class, error) {
  145. return pkgHandle.ClassList(link, parent)
  146. }
  147. // ClassList gets a list of classes in the system.
  148. // Equivalent to: `tc class show`.
  149. // Generally returns nothing if link and parent are not specified.
  150. func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
  151. req := h.newNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP)
  152. msg := &nl.TcMsg{
  153. Family: nl.FAMILY_ALL,
  154. Parent: parent,
  155. }
  156. if link != nil {
  157. base := link.Attrs()
  158. h.ensureIndex(base)
  159. msg.Ifindex = int32(base.Index)
  160. }
  161. req.AddData(msg)
  162. msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWTCLASS)
  163. if err != nil {
  164. return nil, err
  165. }
  166. var res []Class
  167. for _, m := range msgs {
  168. msg := nl.DeserializeTcMsg(m)
  169. attrs, err := nl.ParseRouteAttr(m[msg.Len():])
  170. if err != nil {
  171. return nil, err
  172. }
  173. base := ClassAttrs{
  174. LinkIndex: int(msg.Ifindex),
  175. Handle: msg.Handle,
  176. Parent: msg.Parent,
  177. }
  178. var class Class
  179. classType := ""
  180. for _, attr := range attrs {
  181. switch attr.Attr.Type {
  182. case nl.TCA_KIND:
  183. classType = string(attr.Value[:len(attr.Value)-1])
  184. switch classType {
  185. case "htb":
  186. class = &HtbClass{}
  187. default:
  188. class = &GenericClass{ClassType: classType}
  189. }
  190. case nl.TCA_OPTIONS:
  191. switch classType {
  192. case "htb":
  193. data, err := nl.ParseRouteAttr(attr.Value)
  194. if err != nil {
  195. return nil, err
  196. }
  197. _, err = parseHtbClassData(class, data)
  198. if err != nil {
  199. return nil, err
  200. }
  201. }
  202. }
  203. }
  204. *class.Attrs() = base
  205. res = append(res, class)
  206. }
  207. return res, nil
  208. }
  209. func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
  210. htb := class.(*HtbClass)
  211. detailed := false
  212. for _, datum := range data {
  213. switch datum.Attr.Type {
  214. case nl.TCA_HTB_PARMS:
  215. opt := nl.DeserializeTcHtbCopt(datum.Value)
  216. htb.Rate = uint64(opt.Rate.Rate)
  217. htb.Ceil = uint64(opt.Ceil.Rate)
  218. htb.Buffer = opt.Buffer
  219. htb.Cbuffer = opt.Cbuffer
  220. htb.Quantum = opt.Quantum
  221. htb.Level = opt.Level
  222. htb.Prio = opt.Prio
  223. }
  224. }
  225. return detailed, nil
  226. }