devlink_linux.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. package netlink
  2. import (
  3. "syscall"
  4. "fmt"
  5. "github.com/vishvananda/netlink/nl"
  6. "golang.org/x/sys/unix"
  7. )
  8. // DevlinkDevEswitchAttr represents device's eswitch attributes
  9. type DevlinkDevEswitchAttr struct {
  10. Mode string
  11. InlineMode string
  12. EncapMode string
  13. }
  14. // DevlinkDevAttrs represents device attributes
  15. type DevlinkDevAttrs struct {
  16. Eswitch DevlinkDevEswitchAttr
  17. }
  18. // DevlinkDevice represents device and its attributes
  19. type DevlinkDevice struct {
  20. BusName string
  21. DeviceName string
  22. Attrs DevlinkDevAttrs
  23. }
  24. // DevlinkPort represents port and its attributes
  25. type DevlinkPort struct {
  26. BusName string
  27. DeviceName string
  28. PortIndex uint32
  29. PortType uint16
  30. NetdeviceName string
  31. NetdevIfIndex uint32
  32. RdmaDeviceName string
  33. PortFlavour uint16
  34. }
  35. func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
  36. devices := make([]*DevlinkDevice, 0, len(msgs))
  37. for _, m := range msgs {
  38. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  39. if err != nil {
  40. return nil, err
  41. }
  42. dev := &DevlinkDevice{}
  43. if err = dev.parseAttributes(attrs); err != nil {
  44. return nil, err
  45. }
  46. devices = append(devices, dev)
  47. }
  48. return devices, nil
  49. }
  50. func eswitchStringToMode(modeName string) (uint16, error) {
  51. if modeName == "legacy" {
  52. return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
  53. } else if modeName == "switchdev" {
  54. return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
  55. } else {
  56. return 0xffff, fmt.Errorf("invalid switchdev mode")
  57. }
  58. }
  59. func parseEswitchMode(mode uint16) string {
  60. var eswitchMode = map[uint16]string{
  61. nl.DEVLINK_ESWITCH_MODE_LEGACY: "legacy",
  62. nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
  63. }
  64. if eswitchMode[mode] == "" {
  65. return "unknown"
  66. } else {
  67. return eswitchMode[mode]
  68. }
  69. }
  70. func parseEswitchInlineMode(inlinemode uint8) string {
  71. var eswitchInlineMode = map[uint8]string{
  72. nl.DEVLINK_ESWITCH_INLINE_MODE_NONE: "none",
  73. nl.DEVLINK_ESWITCH_INLINE_MODE_LINK: "link",
  74. nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK: "network",
  75. nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
  76. }
  77. if eswitchInlineMode[inlinemode] == "" {
  78. return "unknown"
  79. } else {
  80. return eswitchInlineMode[inlinemode]
  81. }
  82. }
  83. func parseEswitchEncapMode(encapmode uint8) string {
  84. var eswitchEncapMode = map[uint8]string{
  85. nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE: "disable",
  86. nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
  87. }
  88. if eswitchEncapMode[encapmode] == "" {
  89. return "unknown"
  90. } else {
  91. return eswitchEncapMode[encapmode]
  92. }
  93. }
  94. func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  95. for _, a := range attrs {
  96. switch a.Attr.Type {
  97. case nl.DEVLINK_ATTR_BUS_NAME:
  98. d.BusName = string(a.Value)
  99. case nl.DEVLINK_ATTR_DEV_NAME:
  100. d.DeviceName = string(a.Value)
  101. case nl.DEVLINK_ATTR_ESWITCH_MODE:
  102. d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
  103. case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
  104. d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
  105. case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
  106. d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
  107. }
  108. }
  109. return nil
  110. }
  111. func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
  112. m := msgs[0]
  113. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  114. if err != nil {
  115. return
  116. }
  117. dev.parseAttributes(attrs)
  118. }
  119. func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
  120. msg := &nl.Genlmsg{
  121. Command: nl.DEVLINK_CMD_ESWITCH_GET,
  122. Version: nl.GENL_DEVLINK_VERSION,
  123. }
  124. req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  125. req.AddData(msg)
  126. b := make([]byte, len(dev.BusName))
  127. copy(b, dev.BusName)
  128. data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
  129. req.AddData(data)
  130. b = make([]byte, len(dev.DeviceName))
  131. copy(b, dev.DeviceName)
  132. data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
  133. req.AddData(data)
  134. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  135. if err != nil {
  136. return
  137. }
  138. dev.parseEswitchAttrs(msgs)
  139. }
  140. // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
  141. // otherwise returns an error code.
  142. func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
  143. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  144. if err != nil {
  145. return nil, err
  146. }
  147. msg := &nl.Genlmsg{
  148. Command: nl.DEVLINK_CMD_GET,
  149. Version: nl.GENL_DEVLINK_VERSION,
  150. }
  151. req := h.newNetlinkRequest(int(f.ID),
  152. unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
  153. req.AddData(msg)
  154. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  155. if err != nil {
  156. return nil, err
  157. }
  158. devices, err := parseDevLinkDeviceList(msgs)
  159. if err != nil {
  160. return nil, err
  161. }
  162. for _, d := range devices {
  163. h.getEswitchAttrs(f, d)
  164. }
  165. return devices, nil
  166. }
  167. // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
  168. // otherwise returns an error code.
  169. func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
  170. return pkgHandle.DevLinkGetDeviceList()
  171. }
  172. func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
  173. m := msgs[0]
  174. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  175. if err != nil {
  176. return nil, err
  177. }
  178. dev := &DevlinkDevice{}
  179. if err = dev.parseAttributes(attrs); err != nil {
  180. return nil, err
  181. }
  182. return dev, nil
  183. }
  184. func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
  185. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  186. if err != nil {
  187. return nil, nil, err
  188. }
  189. msg := &nl.Genlmsg{
  190. Command: cmd,
  191. Version: nl.GENL_DEVLINK_VERSION,
  192. }
  193. req := h.newNetlinkRequest(int(f.ID),
  194. unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  195. req.AddData(msg)
  196. b := make([]byte, len(bus)+1)
  197. copy(b, bus)
  198. data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
  199. req.AddData(data)
  200. b = make([]byte, len(device)+1)
  201. copy(b, device)
  202. data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
  203. req.AddData(data)
  204. return f, req, nil
  205. }
  206. // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
  207. // otherwise returns an error code.
  208. func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
  209. f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
  210. if err != nil {
  211. return nil, err
  212. }
  213. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  214. if err != nil {
  215. return nil, err
  216. }
  217. dev, err := parseDevlinkDevice(respmsg)
  218. if err == nil {
  219. h.getEswitchAttrs(f, dev)
  220. }
  221. return dev, err
  222. }
  223. // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
  224. // otherwise returns an error code.
  225. func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
  226. return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
  227. }
  228. // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
  229. // returns an error code.
  230. // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
  231. // Equivalent to: `devlink dev eswitch set $dev mode legacy`
  232. func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
  233. mode, err := eswitchStringToMode(NewMode)
  234. if err != nil {
  235. return err
  236. }
  237. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
  238. if err != nil {
  239. return err
  240. }
  241. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
  242. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  243. return err
  244. }
  245. // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
  246. // returns an error code.
  247. // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
  248. // Equivalent to: `devlink dev eswitch set $dev mode legacy`
  249. func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
  250. return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
  251. }
  252. func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  253. for _, a := range attrs {
  254. switch a.Attr.Type {
  255. case nl.DEVLINK_ATTR_BUS_NAME:
  256. port.BusName = string(a.Value)
  257. case nl.DEVLINK_ATTR_DEV_NAME:
  258. port.DeviceName = string(a.Value)
  259. case nl.DEVLINK_ATTR_PORT_INDEX:
  260. port.PortIndex = native.Uint32(a.Value)
  261. case nl.DEVLINK_ATTR_PORT_TYPE:
  262. port.PortType = native.Uint16(a.Value)
  263. case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
  264. port.NetdeviceName = string(a.Value)
  265. case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
  266. port.NetdevIfIndex = native.Uint32(a.Value)
  267. case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
  268. port.RdmaDeviceName = string(a.Value)
  269. case nl.DEVLINK_ATTR_PORT_FLAVOUR:
  270. port.PortFlavour = native.Uint16(a.Value)
  271. }
  272. }
  273. return nil
  274. }
  275. func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
  276. ports := make([]*DevlinkPort, 0, len(msgs))
  277. for _, m := range msgs {
  278. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  279. if err != nil {
  280. return nil, err
  281. }
  282. port := &DevlinkPort{}
  283. if err = port.parseAttributes(attrs); err != nil {
  284. return nil, err
  285. }
  286. ports = append(ports, port)
  287. }
  288. return ports, nil
  289. }
  290. // DevLinkGetPortList provides a pointer to devlink ports and nil error,
  291. // otherwise returns an error code.
  292. func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
  293. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  294. if err != nil {
  295. return nil, err
  296. }
  297. msg := &nl.Genlmsg{
  298. Command: nl.DEVLINK_CMD_PORT_GET,
  299. Version: nl.GENL_DEVLINK_VERSION,
  300. }
  301. req := h.newNetlinkRequest(int(f.ID),
  302. unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
  303. req.AddData(msg)
  304. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  305. if err != nil {
  306. return nil, err
  307. }
  308. ports, err := parseDevLinkAllPortList(msgs)
  309. if err != nil {
  310. return nil, err
  311. }
  312. return ports, nil
  313. }
  314. // DevLinkGetPortList provides a pointer to devlink ports and nil error,
  315. // otherwise returns an error code.
  316. func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
  317. return pkgHandle.DevLinkGetAllPortList()
  318. }
  319. func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
  320. m := msgs[0]
  321. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  322. if err != nil {
  323. return nil, err
  324. }
  325. port := &DevlinkPort{}
  326. if err = port.parseAttributes(attrs); err != nil {
  327. return nil, err
  328. }
  329. return port, nil
  330. }
  331. // DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
  332. // otherwise returns an error code.
  333. func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
  334. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
  335. if err != nil {
  336. return nil, err
  337. }
  338. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  339. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  340. if err != nil {
  341. return nil, err
  342. }
  343. port, err := parseDevlinkPortMsg(respmsg)
  344. return port, err
  345. }
  346. // DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
  347. // otherwise returns an error code.
  348. func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
  349. return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
  350. }