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

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