github.com/vishvananda/netlink@v1.3.0/rdma_link_linux.go (about)

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