class_linux.go 6.6 KB

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