github.com/vishvananda/netlink@v1.3.1/vdpa_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"syscall"
     8  
     9  	"golang.org/x/sys/unix"
    10  
    11  	"github.com/vishvananda/netlink/nl"
    12  )
    13  
    14  type vdpaDevID struct {
    15  	Name string
    16  	ID   uint32
    17  }
    18  
    19  // VDPADev contains info about VDPA device
    20  type VDPADev struct {
    21  	vdpaDevID
    22  	VendorID  uint32
    23  	MaxVQS    uint32
    24  	MaxVQSize uint16
    25  	MinVQSize uint16
    26  }
    27  
    28  // VDPADevConfig contains configuration of the VDPA device
    29  type VDPADevConfig struct {
    30  	vdpaDevID
    31  	Features           uint64
    32  	NegotiatedFeatures uint64
    33  	Net                VDPADevConfigNet
    34  }
    35  
    36  // VDPADevVStats conatins vStats for the VDPA device
    37  type VDPADevVStats struct {
    38  	vdpaDevID
    39  	QueueIndex         uint32
    40  	Vendor             []VDPADevVStatsVendor
    41  	NegotiatedFeatures uint64
    42  }
    43  
    44  // VDPADevVStatsVendor conatins name and value for vendor specific vstat option
    45  type VDPADevVStatsVendor struct {
    46  	Name  string
    47  	Value uint64
    48  }
    49  
    50  // VDPADevConfigNet conatins status and net config for the VDPA device
    51  type VDPADevConfigNet struct {
    52  	Status VDPADevConfigNetStatus
    53  	Cfg    VDPADevConfigNetCfg
    54  }
    55  
    56  // VDPADevConfigNetStatus contains info about net status
    57  type VDPADevConfigNetStatus struct {
    58  	LinkUp   bool
    59  	Announce bool
    60  }
    61  
    62  // VDPADevConfigNetCfg contains net config for the VDPA device
    63  type VDPADevConfigNetCfg struct {
    64  	MACAddr net.HardwareAddr
    65  	MaxVQP  uint16
    66  	MTU     uint16
    67  }
    68  
    69  // VDPAMGMTDev conatins info about VDPA management device
    70  type VDPAMGMTDev struct {
    71  	BusName           string
    72  	DevName           string
    73  	SupportedClasses  uint64
    74  	SupportedFeatures uint64
    75  	MaxVQS            uint32
    76  }
    77  
    78  // VDPANewDevParams contains parameters for new VDPA device
    79  // use SetBits to configure requried features for the device
    80  // example:
    81  //
    82  //	VDPANewDevParams{Features: SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)}
    83  type VDPANewDevParams struct {
    84  	MACAddr  net.HardwareAddr
    85  	MaxVQP   uint16
    86  	MTU      uint16
    87  	Features uint64
    88  }
    89  
    90  // SetBits set provided bits in the uint64 input value
    91  // usage example:
    92  // features := SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)
    93  func SetBits(input uint64, pos ...int) uint64 {
    94  	for _, p := range pos {
    95  		input |= 1 << uint64(p)
    96  	}
    97  	return input
    98  }
    99  
   100  // IsBitSet check if specific bit is set in the uint64 input value
   101  // usage example:
   102  // hasNetClass := IsBitSet(mgmtDev, VIRTIO_ID_NET)
   103  func IsBitSet(input uint64, pos int) bool {
   104  	val := input & (1 << uint64(pos))
   105  	return val > 0
   106  }
   107  
   108  // VDPANewDev adds new VDPA device
   109  // Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]`
   110  func VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error {
   111  	return pkgHandle.VDPANewDev(name, mgmtBus, mgmtName, params)
   112  }
   113  
   114  // VDPADelDev removes VDPA device
   115  // Equivalent to: `vdpa dev del <name>`
   116  func VDPADelDev(name string) error {
   117  	return pkgHandle.VDPADelDev(name)
   118  }
   119  
   120  // VDPAGetDevList returns list of VDPA devices
   121  // Equivalent to: `vdpa dev show`
   122  //
   123  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   124  // or incomplete.
   125  func VDPAGetDevList() ([]*VDPADev, error) {
   126  	return pkgHandle.VDPAGetDevList()
   127  }
   128  
   129  // VDPAGetDevByName returns VDPA device selected by name
   130  // Equivalent to: `vdpa dev show <name>`
   131  func VDPAGetDevByName(name string) (*VDPADev, error) {
   132  	return pkgHandle.VDPAGetDevByName(name)
   133  }
   134  
   135  // VDPAGetDevConfigList returns list of VDPA devices configurations
   136  // Equivalent to: `vdpa dev config show`
   137  //
   138  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   139  // or incomplete.
   140  func VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
   141  	return pkgHandle.VDPAGetDevConfigList()
   142  }
   143  
   144  // VDPAGetDevConfigByName returns VDPA device configuration selected by name
   145  // Equivalent to: `vdpa dev config show <name>`
   146  func VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) {
   147  	return pkgHandle.VDPAGetDevConfigByName(name)
   148  }
   149  
   150  // VDPAGetDevVStats returns vstats for VDPA device
   151  // Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>`
   152  func VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
   153  	return pkgHandle.VDPAGetDevVStats(name, queueIndex)
   154  }
   155  
   156  // VDPAGetMGMTDevList returns list of mgmt devices
   157  // Equivalent to: `vdpa mgmtdev show`
   158  //
   159  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   160  // or incomplete.
   161  func VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
   162  	return pkgHandle.VDPAGetMGMTDevList()
   163  }
   164  
   165  // VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name
   166  // Equivalent to: `vdpa mgmtdev show <bus>/<name>`
   167  func VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) {
   168  	return pkgHandle.VDPAGetMGMTDevByBusAndName(bus, name)
   169  }
   170  
   171  type vdpaNetlinkMessage []syscall.NetlinkRouteAttr
   172  
   173  func (id *vdpaDevID) parseIDAttribute(attr syscall.NetlinkRouteAttr) {
   174  	switch attr.Attr.Type {
   175  	case nl.VDPA_ATTR_DEV_NAME:
   176  		id.Name = nl.BytesToString(attr.Value)
   177  	case nl.VDPA_ATTR_DEV_ID:
   178  		id.ID = native.Uint32(attr.Value)
   179  	}
   180  }
   181  
   182  func (netStatus *VDPADevConfigNetStatus) parseStatusAttribute(value []byte) {
   183  	a := native.Uint16(value)
   184  	netStatus.Announce = (a & VIRTIO_NET_S_ANNOUNCE) > 0
   185  	netStatus.LinkUp = (a & VIRTIO_NET_S_LINK_UP) > 0
   186  }
   187  
   188  func (d *VDPADev) parseAttributes(attrs vdpaNetlinkMessage) {
   189  	for _, a := range attrs {
   190  		d.parseIDAttribute(a)
   191  		switch a.Attr.Type {
   192  		case nl.VDPA_ATTR_DEV_VENDOR_ID:
   193  			d.VendorID = native.Uint32(a.Value)
   194  		case nl.VDPA_ATTR_DEV_MAX_VQS:
   195  			d.MaxVQS = native.Uint32(a.Value)
   196  		case nl.VDPA_ATTR_DEV_MAX_VQ_SIZE:
   197  			d.MaxVQSize = native.Uint16(a.Value)
   198  		case nl.VDPA_ATTR_DEV_MIN_VQ_SIZE:
   199  			d.MinVQSize = native.Uint16(a.Value)
   200  		}
   201  	}
   202  }
   203  
   204  func (c *VDPADevConfig) parseAttributes(attrs vdpaNetlinkMessage) {
   205  	for _, a := range attrs {
   206  		c.parseIDAttribute(a)
   207  		switch a.Attr.Type {
   208  		case nl.VDPA_ATTR_DEV_NET_CFG_MACADDR:
   209  			c.Net.Cfg.MACAddr = a.Value
   210  		case nl.VDPA_ATTR_DEV_NET_STATUS:
   211  			c.Net.Status.parseStatusAttribute(a.Value)
   212  		case nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP:
   213  			c.Net.Cfg.MaxVQP = native.Uint16(a.Value)
   214  		case nl.VDPA_ATTR_DEV_NET_CFG_MTU:
   215  			c.Net.Cfg.MTU = native.Uint16(a.Value)
   216  		case nl.VDPA_ATTR_DEV_FEATURES:
   217  			c.Features = native.Uint64(a.Value)
   218  		case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES:
   219  			c.NegotiatedFeatures = native.Uint64(a.Value)
   220  		}
   221  	}
   222  }
   223  
   224  func (s *VDPADevVStats) parseAttributes(attrs vdpaNetlinkMessage) {
   225  	for _, a := range attrs {
   226  		s.parseIDAttribute(a)
   227  		switch a.Attr.Type {
   228  		case nl.VDPA_ATTR_DEV_QUEUE_INDEX:
   229  			s.QueueIndex = native.Uint32(a.Value)
   230  		case nl.VDPA_ATTR_DEV_VENDOR_ATTR_NAME:
   231  			s.Vendor = append(s.Vendor, VDPADevVStatsVendor{Name: nl.BytesToString(a.Value)})
   232  		case nl.VDPA_ATTR_DEV_VENDOR_ATTR_VALUE:
   233  			if len(s.Vendor) == 0 {
   234  				break
   235  			}
   236  			s.Vendor[len(s.Vendor)-1].Value = native.Uint64(a.Value)
   237  		case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES:
   238  			s.NegotiatedFeatures = native.Uint64(a.Value)
   239  		}
   240  	}
   241  }
   242  
   243  func (d *VDPAMGMTDev) parseAttributes(attrs vdpaNetlinkMessage) {
   244  	for _, a := range attrs {
   245  		switch a.Attr.Type {
   246  		case nl.VDPA_ATTR_MGMTDEV_BUS_NAME:
   247  			d.BusName = nl.BytesToString(a.Value)
   248  		case nl.VDPA_ATTR_MGMTDEV_DEV_NAME:
   249  			d.DevName = nl.BytesToString(a.Value)
   250  		case nl.VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES:
   251  			d.SupportedClasses = native.Uint64(a.Value)
   252  		case nl.VDPA_ATTR_DEV_SUPPORTED_FEATURES:
   253  			d.SupportedFeatures = native.Uint64(a.Value)
   254  		case nl.VDPA_ATTR_DEV_MGMTDEV_MAX_VQS:
   255  			d.MaxVQS = native.Uint32(a.Value)
   256  		}
   257  	}
   258  }
   259  
   260  func (h *Handle) vdpaRequest(command uint8, extraFlags int, attrs []*nl.RtAttr) ([]vdpaNetlinkMessage, error) {
   261  	f, err := h.GenlFamilyGet(nl.VDPA_GENL_NAME)
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_ACK|extraFlags)
   266  	req.AddData(&nl.Genlmsg{
   267  		Command: command,
   268  		Version: nl.VDPA_GENL_VERSION,
   269  	})
   270  	for _, a := range attrs {
   271  		req.AddData(a)
   272  	}
   273  
   274  	resp, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
   275  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   276  		return nil, executeErr
   277  	}
   278  	messages := make([]vdpaNetlinkMessage, 0, len(resp))
   279  	for _, m := range resp {
   280  		attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
   281  		if err != nil {
   282  			return nil, err
   283  		}
   284  		messages = append(messages, attrs)
   285  	}
   286  	return messages, executeErr
   287  }
   288  
   289  // dump all devices if dev is nil
   290  //
   291  // If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
   292  // or incomplete.
   293  func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) {
   294  	var extraFlags int
   295  	var attrs []*nl.RtAttr
   296  	if dev != nil {
   297  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev)))
   298  	} else {
   299  		extraFlags = extraFlags | unix.NLM_F_DUMP
   300  	}
   301  	messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs)
   302  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   303  		return nil, executeErr
   304  	}
   305  	devs := make([]*VDPADev, 0, len(messages))
   306  	for _, m := range messages {
   307  		d := &VDPADev{}
   308  		d.parseAttributes(m)
   309  		devs = append(devs, d)
   310  	}
   311  	return devs, executeErr
   312  }
   313  
   314  // dump all devices if dev is nil
   315  //
   316  // If dev is nil, and the returned error is [ErrDumpInterrupted], results may be inconsistent
   317  // or incomplete.
   318  func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) {
   319  	var extraFlags int
   320  	var attrs []*nl.RtAttr
   321  	if dev != nil {
   322  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev)))
   323  	} else {
   324  		extraFlags = extraFlags | unix.NLM_F_DUMP
   325  	}
   326  	messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs)
   327  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   328  		return nil, executeErr
   329  	}
   330  	cfgs := make([]*VDPADevConfig, 0, len(messages))
   331  	for _, m := range messages {
   332  		cfg := &VDPADevConfig{}
   333  		cfg.parseAttributes(m)
   334  		cfgs = append(cfgs, cfg)
   335  	}
   336  	return cfgs, executeErr
   337  }
   338  
   339  // dump all devices if dev is nil
   340  //
   341  // If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
   342  // or incomplete.
   343  func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) {
   344  	var extraFlags int
   345  	var attrs []*nl.RtAttr
   346  	if dev != nil {
   347  		attrs = append(attrs,
   348  			nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(*dev)),
   349  		)
   350  		if bus != nil {
   351  			attrs = append(attrs,
   352  				nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(*bus)),
   353  			)
   354  		}
   355  	} else {
   356  		extraFlags = extraFlags | unix.NLM_F_DUMP
   357  	}
   358  	messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs)
   359  	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
   360  		return nil, executeErr
   361  	}
   362  	cfgs := make([]*VDPAMGMTDev, 0, len(messages))
   363  	for _, m := range messages {
   364  		cfg := &VDPAMGMTDev{}
   365  		cfg.parseAttributes(m)
   366  		cfgs = append(cfgs, cfg)
   367  	}
   368  	return cfgs, executeErr
   369  }
   370  
   371  // VDPANewDev adds new VDPA device
   372  // Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]`
   373  func (h *Handle) VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error {
   374  	attrs := []*nl.RtAttr{
   375  		nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)),
   376  		nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(mgmtName)),
   377  	}
   378  	if mgmtBus != "" {
   379  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(mgmtBus)))
   380  	}
   381  	if len(params.MACAddr) != 0 {
   382  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MACADDR, params.MACAddr))
   383  	}
   384  	if params.MaxVQP > 0 {
   385  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP, nl.Uint16Attr(params.MaxVQP)))
   386  	}
   387  	if params.MTU > 0 {
   388  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MTU, nl.Uint16Attr(params.MTU)))
   389  	}
   390  	if params.Features > 0 {
   391  		attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_FEATURES, nl.Uint64Attr(params.Features)))
   392  	}
   393  	_, err := h.vdpaRequest(nl.VDPA_CMD_DEV_NEW, 0, attrs)
   394  	return err
   395  }
   396  
   397  // VDPADelDev removes VDPA device
   398  // Equivalent to: `vdpa dev del <name>`
   399  func (h *Handle) VDPADelDev(name string) error {
   400  	_, err := h.vdpaRequest(nl.VDPA_CMD_DEV_DEL, 0, []*nl.RtAttr{
   401  		nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name))})
   402  	return err
   403  }
   404  
   405  // VDPAGetDevList returns list of VDPA devices
   406  // Equivalent to: `vdpa dev show`
   407  //
   408  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   409  // or incomplete.
   410  func (h *Handle) VDPAGetDevList() ([]*VDPADev, error) {
   411  	return h.vdpaDevGet(nil)
   412  }
   413  
   414  // VDPAGetDevByName returns VDPA device selected by name
   415  // Equivalent to: `vdpa dev show <name>`
   416  func (h *Handle) VDPAGetDevByName(name string) (*VDPADev, error) {
   417  	devs, err := h.vdpaDevGet(&name)
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  	if len(devs) == 0 {
   422  		return nil, fmt.Errorf("device not found")
   423  	}
   424  	return devs[0], nil
   425  }
   426  
   427  // VDPAGetDevConfigList returns list of VDPA devices configurations
   428  // Equivalent to: `vdpa dev config show`
   429  //
   430  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   431  // or incomplete.
   432  func (h *Handle) VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
   433  	return h.vdpaDevConfigGet(nil)
   434  }
   435  
   436  // VDPAGetDevConfigByName returns VDPA device configuration selected by name
   437  // Equivalent to: `vdpa dev config show <name>`
   438  func (h *Handle) VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) {
   439  	cfgs, err := h.vdpaDevConfigGet(&name)
   440  	if err != nil {
   441  		return nil, err
   442  	}
   443  	if len(cfgs) == 0 {
   444  		return nil, fmt.Errorf("configuration not found")
   445  	}
   446  	return cfgs[0], nil
   447  }
   448  
   449  // VDPAGetDevVStats returns vstats for VDPA device
   450  // Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>`
   451  func (h *Handle) VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
   452  	messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_VSTATS_GET, 0, []*nl.RtAttr{
   453  		nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)),
   454  		nl.NewRtAttr(nl.VDPA_ATTR_DEV_QUEUE_INDEX, nl.Uint32Attr(queueIndex)),
   455  	})
   456  	if err != nil {
   457  		return nil, err
   458  	}
   459  	if len(messages) == 0 {
   460  		return nil, fmt.Errorf("stats not found")
   461  	}
   462  	stats := &VDPADevVStats{}
   463  	stats.parseAttributes(messages[0])
   464  	return stats, nil
   465  }
   466  
   467  // VDPAGetMGMTDevList returns list of mgmt devices
   468  // Equivalent to: `vdpa mgmtdev show`
   469  //
   470  // If the returned error is [ErrDumpInterrupted], results may be inconsistent
   471  // or incomplete.
   472  func (h *Handle) VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
   473  	return h.vdpaMGMTDevGet(nil, nil)
   474  }
   475  
   476  // VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name
   477  // Equivalent to: `vdpa mgmtdev show <bus>/<name>`
   478  func (h *Handle) VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) {
   479  	var busPtr *string
   480  	if bus != "" {
   481  		busPtr = &bus
   482  	}
   483  	devs, err := h.vdpaMGMTDevGet(busPtr, &name)
   484  	if err != nil {
   485  		return nil, err
   486  	}
   487  	if len(devs) == 0 {
   488  		return nil, fmt.Errorf("mgmtdev not found")
   489  	}
   490  	return devs[0], nil
   491  }