rdma_link_linux.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. package netlink
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "fmt"
  6. "net"
  7. "github.com/vishvananda/netlink/nl"
  8. "golang.org/x/sys/unix"
  9. )
  10. // LinkAttrs represents data shared by most link types
  11. type RdmaLinkAttrs struct {
  12. Index uint32
  13. Name string
  14. FirmwareVersion string
  15. NodeGuid string
  16. SysImageGuid string
  17. }
  18. // Link represents a rdma device from netlink.
  19. type RdmaLink struct {
  20. Attrs RdmaLinkAttrs
  21. }
  22. func getProtoField(clientType int, op int) int {
  23. return ((clientType << nl.RDMA_NL_GET_CLIENT_SHIFT) | op)
  24. }
  25. func uint64ToGuidString(guid uint64) string {
  26. //Convert to byte array
  27. sysGuidBytes := new(bytes.Buffer)
  28. binary.Write(sysGuidBytes, binary.LittleEndian, guid)
  29. //Convert to HardwareAddr
  30. sysGuidNet := net.HardwareAddr(sysGuidBytes.Bytes())
  31. //Get the String
  32. return sysGuidNet.String()
  33. }
  34. func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
  35. link := RdmaLink{}
  36. reader := bytes.NewReader(data)
  37. for reader.Len() >= 4 {
  38. _, attrType, len, value := parseNfAttrTLV(reader)
  39. switch attrType {
  40. case nl.RDMA_NLDEV_ATTR_DEV_INDEX:
  41. var Index uint32
  42. r := bytes.NewReader(value)
  43. binary.Read(r, nl.NativeEndian(), &Index)
  44. link.Attrs.Index = Index
  45. case nl.RDMA_NLDEV_ATTR_DEV_NAME:
  46. link.Attrs.Name = string(value[0 : len-1])
  47. case nl.RDMA_NLDEV_ATTR_FW_VERSION:
  48. link.Attrs.FirmwareVersion = string(value[0 : len-1])
  49. case nl.RDMA_NLDEV_ATTR_NODE_GUID:
  50. var guid uint64
  51. r := bytes.NewReader(value)
  52. binary.Read(r, nl.NativeEndian(), &guid)
  53. link.Attrs.NodeGuid = uint64ToGuidString(guid)
  54. case nl.RDMA_NLDEV_ATTR_SYS_IMAGE_GUID:
  55. var sysGuid uint64
  56. r := bytes.NewReader(value)
  57. binary.Read(r, nl.NativeEndian(), &sysGuid)
  58. link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid)
  59. }
  60. if (len % 4) != 0 {
  61. // Skip pad bytes
  62. reader.Seek(int64(4-(len%4)), seekCurrent)
  63. }
  64. }
  65. return &link, nil
  66. }
  67. func execRdmaSetLink(req *nl.NetlinkRequest) error {
  68. _, err := req.Execute(unix.NETLINK_RDMA, 0)
  69. return err
  70. }
  71. // RdmaLinkList gets a list of RDMA link devices.
  72. // Equivalent to: `rdma dev show`
  73. func RdmaLinkList() ([]*RdmaLink, error) {
  74. return pkgHandle.RdmaLinkList()
  75. }
  76. // RdmaLinkList gets a list of RDMA link devices.
  77. // Equivalent to: `rdma dev show`
  78. func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
  79. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
  80. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
  81. msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
  82. if err != nil {
  83. return nil, err
  84. }
  85. var res []*RdmaLink
  86. for _, m := range msgs {
  87. link, err := executeOneGetRdmaLink(m)
  88. if err != nil {
  89. return nil, err
  90. }
  91. res = append(res, link)
  92. }
  93. return res, nil
  94. }
  95. // RdmaLinkByName finds a link by name and returns a pointer to the object if
  96. // found and nil error, otherwise returns error code.
  97. func RdmaLinkByName(name string) (*RdmaLink, error) {
  98. return pkgHandle.RdmaLinkByName(name)
  99. }
  100. // RdmaLinkByName finds a link by name and returns a pointer to the object if
  101. // found and nil error, otherwise returns error code.
  102. func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
  103. links, err := h.RdmaLinkList()
  104. if err != nil {
  105. return nil, err
  106. }
  107. for _, link := range links {
  108. if link.Attrs.Name == name {
  109. return link, nil
  110. }
  111. }
  112. return nil, fmt.Errorf("Rdma device %v not found", name)
  113. }
  114. // RdmaLinkSetName sets the name of the rdma link device. Return nil on success
  115. // or error otherwise.
  116. // Equivalent to: `rdma dev set $old_devname name $name`
  117. func RdmaLinkSetName(link *RdmaLink, name string) error {
  118. return pkgHandle.RdmaLinkSetName(link, name)
  119. }
  120. // RdmaLinkSetName sets the name of the rdma link device. Return nil on success
  121. // or error otherwise.
  122. // Equivalent to: `rdma dev set $old_devname name $name`
  123. func (h *Handle) RdmaLinkSetName(link *RdmaLink, name string) error {
  124. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
  125. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
  126. b := make([]byte, 4)
  127. native.PutUint32(b, uint32(link.Attrs.Index))
  128. data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b)
  129. req.AddData(data)
  130. b = make([]byte, len(name)+1)
  131. copy(b, name)
  132. data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, b)
  133. req.AddData(data)
  134. return execRdmaSetLink(req)
  135. }
  136. func netnsModeToString(mode uint8) string {
  137. switch mode {
  138. case 0:
  139. return "exclusive"
  140. case 1:
  141. return "shared"
  142. default:
  143. return "unknown"
  144. }
  145. }
  146. func executeOneGetRdmaNetnsMode(data []byte) (string, error) {
  147. reader := bytes.NewReader(data)
  148. for reader.Len() >= 4 {
  149. _, attrType, len, value := parseNfAttrTLV(reader)
  150. switch attrType {
  151. case nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE:
  152. var mode uint8
  153. r := bytes.NewReader(value)
  154. binary.Read(r, nl.NativeEndian(), &mode)
  155. return netnsModeToString(mode), nil
  156. }
  157. if (len % 4) != 0 {
  158. // Skip pad bytes
  159. reader.Seek(int64(4-(len%4)), seekCurrent)
  160. }
  161. }
  162. return "", fmt.Errorf("Invalid netns mode")
  163. }
  164. // RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem
  165. // Returns mode string and error status as nil on success or returns error
  166. // otherwise.
  167. // Equivalent to: `rdma system show netns'
  168. func RdmaSystemGetNetnsMode() (string, error) {
  169. return pkgHandle.RdmaSystemGetNetnsMode()
  170. }
  171. // RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem
  172. // Returns mode string and error status as nil on success or returns error
  173. // otherwise.
  174. // Equivalent to: `rdma system show netns'
  175. func (h *Handle) RdmaSystemGetNetnsMode() (string, error) {
  176. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_GET)
  177. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
  178. msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
  179. if err != nil {
  180. return "", err
  181. }
  182. if len(msgs) == 0 {
  183. return "", fmt.Errorf("No valid response from kernel")
  184. }
  185. return executeOneGetRdmaNetnsMode(msgs[0])
  186. }
  187. func netnsModeStringToUint8(mode string) (uint8, error) {
  188. switch mode {
  189. case "exclusive":
  190. return 0, nil
  191. case "shared":
  192. return 1, nil
  193. default:
  194. return 0, fmt.Errorf("Invalid mode; %q", mode)
  195. }
  196. }
  197. // RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem
  198. // Returns nil on success or appropriate error code.
  199. // Equivalent to: `rdma system set netns { shared | exclusive }'
  200. func RdmaSystemSetNetnsMode(NewMode string) error {
  201. return pkgHandle.RdmaSystemSetNetnsMode(NewMode)
  202. }
  203. // RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem
  204. // Returns nil on success or appropriate error code.
  205. // Equivalent to: `rdma system set netns { shared | exclusive }'
  206. func (h *Handle) RdmaSystemSetNetnsMode(NewMode string) error {
  207. value, err := netnsModeStringToUint8(NewMode)
  208. if err != nil {
  209. return err
  210. }
  211. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_SET)
  212. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
  213. data := nl.NewRtAttr(nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE, []byte{value})
  214. req.AddData(data)
  215. _, err = req.Execute(unix.NETLINK_RDMA, 0)
  216. return err
  217. }
  218. // RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The
  219. // fd must be an open file descriptor to a network namespace.
  220. // Similar to: `rdma dev set $dev netns $ns`
  221. func RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
  222. return pkgHandle.RdmaLinkSetNsFd(link, fd)
  223. }
  224. // RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The
  225. // fd must be an open file descriptor to a network namespace.
  226. // Similar to: `rdma dev set $dev netns $ns`
  227. func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
  228. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
  229. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
  230. data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX,
  231. nl.Uint32Attr(link.Attrs.Index))
  232. req.AddData(data)
  233. data = nl.NewRtAttr(nl.RDMA_NLDEV_NET_NS_FD, nl.Uint32Attr(fd))
  234. req.AddData(data)
  235. return execRdmaSetLink(req)
  236. }
  237. // RdmaLinkDel deletes an rdma link
  238. //
  239. // Similar to: rdma link delete NAME
  240. // REF: https://man7.org/linux/man-pages/man8/rdma-link.8.html
  241. func RdmaLinkDel(name string) error {
  242. return pkgHandle.RdmaLinkDel(name)
  243. }
  244. // RdmaLinkDel deletes an rdma link.
  245. func (h *Handle) RdmaLinkDel(name string) error {
  246. link, err := h.RdmaLinkByName(name)
  247. if err != nil {
  248. return err
  249. }
  250. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_DELLINK)
  251. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
  252. b := make([]byte, 4)
  253. native.PutUint32(b, link.Attrs.Index)
  254. req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b))
  255. _, err = req.Execute(unix.NETLINK_RDMA, 0)
  256. return err
  257. }
  258. // RdmaLinkAdd adds an rdma link for the specified type to the network device.
  259. // Similar to: rdma link add NAME type TYPE netdev NETDEV
  260. // NAME - specifies the new name of the rdma link to add
  261. // TYPE - specifies which rdma type to use. Link types:
  262. // rxe - Soft RoCE driver
  263. // siw - Soft iWARP driver
  264. // NETDEV - specifies the network device to which the link is bound
  265. //
  266. // REF: https://man7.org/linux/man-pages/man8/rdma-link.8.html
  267. func RdmaLinkAdd(linkName, linkType, netdev string) error {
  268. return pkgHandle.RdmaLinkAdd(linkName, linkType, netdev)
  269. }
  270. // RdmaLinkAdd adds an rdma link for the specified type to the network device.
  271. func (h *Handle) RdmaLinkAdd(linkName string, linkType string, netdev string) error {
  272. proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_NEWLINK)
  273. req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
  274. req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, nl.ZeroTerminated(linkName)))
  275. req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_LINK_TYPE, nl.ZeroTerminated(linkType)))
  276. req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_NDEV_NAME, nl.ZeroTerminated(netdev)))
  277. _, err := req.Execute(unix.NETLINK_RDMA, 0)
  278. return err
  279. }