mirror of https://github.com/vishvananda/netlink
Add support for VDPA devices management
Current implementation support following functions: - VDPANewDev - VDPADelDev - VDPAGetDevList - VDPAGetDevByName - VDPAGetDevConfigList - VDPAGetDevConfigByName - VDPAGetDevVStats - VDPAGetMGMTDevList - VDPAGetMGMTDevByBusAndName Signed-off-by: Yury Kulazhenkov <ykulazhenkov@nvidia.com>
This commit is contained in:
parent
06219cde3e
commit
857968af11
|
@ -31,6 +31,28 @@ func skipUnlessRoot(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func skipUnlessKModuleLoaded(t *testing.T, module ...string) {
|
||||
t.Helper()
|
||||
file, err := ioutil.ReadFile("/proc/modules")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open /proc/modules", err)
|
||||
}
|
||||
for _, mod := range module {
|
||||
found := false
|
||||
for _, line := range strings.Split(string(file), "\n") {
|
||||
n := strings.Split(line, " ")[0]
|
||||
if n == mod {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
if !found {
|
||||
t.Skipf("Test requires kmodule %q.", mod)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||
skipUnlessRoot(t)
|
||||
|
||||
|
@ -159,22 +181,7 @@ func setUpSEG6NetlinkTest(t *testing.T) tearDownNetlinkTest {
|
|||
}
|
||||
|
||||
func setUpNetlinkTestWithKModule(t *testing.T, name string) tearDownNetlinkTest {
|
||||
file, err := ioutil.ReadFile("/proc/modules")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open /proc/modules", err)
|
||||
}
|
||||
found := false
|
||||
for _, line := range strings.Split(string(file), "\n") {
|
||||
n := strings.Split(line, " ")[0]
|
||||
if n == name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
if !found {
|
||||
t.Skipf("Test requires kmodule %q.", name)
|
||||
}
|
||||
skipUnlessKModuleLoaded(t, name)
|
||||
return setUpNetlinkTest(t)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package nl
|
||||
|
||||
const (
|
||||
VDPA_GENL_NAME = "vdpa"
|
||||
VDPA_GENL_VERSION = 0x1
|
||||
)
|
||||
|
||||
const (
|
||||
VDPA_CMD_UNSPEC = iota
|
||||
VDPA_CMD_MGMTDEV_NEW
|
||||
VDPA_CMD_MGMTDEV_GET /* can dump */
|
||||
VDPA_CMD_DEV_NEW
|
||||
VDPA_CMD_DEV_DEL
|
||||
VDPA_CMD_DEV_GET /* can dump */
|
||||
VDPA_CMD_DEV_CONFIG_GET /* can dump */
|
||||
VDPA_CMD_DEV_VSTATS_GET
|
||||
)
|
||||
|
||||
const (
|
||||
VDPA_ATTR_UNSPEC = iota
|
||||
VDPA_ATTR_MGMTDEV_BUS_NAME
|
||||
VDPA_ATTR_MGMTDEV_DEV_NAME
|
||||
VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES
|
||||
VDPA_ATTR_DEV_NAME
|
||||
VDPA_ATTR_DEV_ID
|
||||
VDPA_ATTR_DEV_VENDOR_ID
|
||||
VDPA_ATTR_DEV_MAX_VQS
|
||||
VDPA_ATTR_DEV_MAX_VQ_SIZE
|
||||
VDPA_ATTR_DEV_MIN_VQ_SIZE
|
||||
VDPA_ATTR_DEV_NET_CFG_MACADDR
|
||||
VDPA_ATTR_DEV_NET_STATUS
|
||||
VDPA_ATTR_DEV_NET_CFG_MAX_VQP
|
||||
VDPA_ATTR_DEV_NET_CFG_MTU
|
||||
VDPA_ATTR_DEV_NEGOTIATED_FEATURES
|
||||
VDPA_ATTR_DEV_MGMTDEV_MAX_VQS
|
||||
VDPA_ATTR_DEV_SUPPORTED_FEATURES
|
||||
VDPA_ATTR_DEV_QUEUE_INDEX
|
||||
VDPA_ATTR_DEV_VENDOR_ATTR_NAME
|
||||
VDPA_ATTR_DEV_VENDOR_ATTR_VALUE
|
||||
VDPA_ATTR_DEV_FEATURES
|
||||
)
|
|
@ -0,0 +1,463 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
type vdpaDevID struct {
|
||||
Name string
|
||||
ID uint32
|
||||
}
|
||||
|
||||
// VDPADev contains info about VDPA device
|
||||
type VDPADev struct {
|
||||
vdpaDevID
|
||||
VendorID uint32
|
||||
MaxVQS uint32
|
||||
MaxVQSize uint16
|
||||
MinVQSize uint16
|
||||
}
|
||||
|
||||
// VDPADevConfig contains configuration of the VDPA device
|
||||
type VDPADevConfig struct {
|
||||
vdpaDevID
|
||||
Features uint64
|
||||
NegotiatedFeatures uint64
|
||||
Net VDPADevConfigNet
|
||||
}
|
||||
|
||||
// VDPADevVStats conatins vStats for the VDPA device
|
||||
type VDPADevVStats struct {
|
||||
vdpaDevID
|
||||
QueueIndex uint32
|
||||
Vendor []VDPADevVStatsVendor
|
||||
NegotiatedFeatures uint64
|
||||
}
|
||||
|
||||
// VDPADevVStatsVendor conatins name and value for vendor specific vstat option
|
||||
type VDPADevVStatsVendor struct {
|
||||
Name string
|
||||
Value uint64
|
||||
}
|
||||
|
||||
// VDPADevConfigNet conatins status and net config for the VDPA device
|
||||
type VDPADevConfigNet struct {
|
||||
Status VDPADevConfigNetStatus
|
||||
Cfg VDPADevConfigNetCfg
|
||||
}
|
||||
|
||||
// VDPADevConfigNetStatus contains info about net status
|
||||
type VDPADevConfigNetStatus struct {
|
||||
LinkUp bool
|
||||
Announce bool
|
||||
}
|
||||
|
||||
// VDPADevConfigNetCfg contains net config for the VDPA device
|
||||
type VDPADevConfigNetCfg struct {
|
||||
MACAddr net.HardwareAddr
|
||||
MaxVQP uint16
|
||||
MTU uint16
|
||||
}
|
||||
|
||||
// VDPAMGMTDev conatins info about VDPA management device
|
||||
type VDPAMGMTDev struct {
|
||||
BusName string
|
||||
DevName string
|
||||
SupportedClasses uint64
|
||||
SupportedFeatures uint64
|
||||
MaxVQS uint32
|
||||
}
|
||||
|
||||
// VDPANewDevParams contains parameters for new VDPA device
|
||||
// use SetBits to configure requried features for the device
|
||||
// example:
|
||||
//
|
||||
// VDPANewDevParams{Features: SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)}
|
||||
type VDPANewDevParams struct {
|
||||
MACAddr net.HardwareAddr
|
||||
MaxVQP uint16
|
||||
MTU uint16
|
||||
Features uint64
|
||||
}
|
||||
|
||||
// SetBits set provided bits in the uint64 input value
|
||||
// usage example:
|
||||
// features := SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)
|
||||
func SetBits(input uint64, pos ...int) uint64 {
|
||||
for _, p := range pos {
|
||||
input |= 1 << uint64(p)
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
// IsBitSet check if specific bit is set in the uint64 input value
|
||||
// usage example:
|
||||
// hasNetClass := IsBitSet(mgmtDev, VIRTIO_ID_NET)
|
||||
func IsBitSet(input uint64, pos int) bool {
|
||||
val := input & (1 << uint64(pos))
|
||||
return val > 0
|
||||
}
|
||||
|
||||
// VDPANewDev adds new VDPA device
|
||||
// Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]`
|
||||
func VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error {
|
||||
return pkgHandle.VDPANewDev(name, mgmtBus, mgmtName, params)
|
||||
}
|
||||
|
||||
// VDPADelDev removes VDPA device
|
||||
// Equivalent to: `vdpa dev del <name>`
|
||||
func VDPADelDev(name string) error {
|
||||
return pkgHandle.VDPADelDev(name)
|
||||
}
|
||||
|
||||
// VDPAGetDevList returns list of VDPA devices
|
||||
// Equivalent to: `vdpa dev show`
|
||||
func VDPAGetDevList() ([]*VDPADev, error) {
|
||||
return pkgHandle.VDPAGetDevList()
|
||||
}
|
||||
|
||||
// VDPAGetDevByName returns VDPA device selected by name
|
||||
// Equivalent to: `vdpa dev show <name>`
|
||||
func VDPAGetDevByName(name string) (*VDPADev, error) {
|
||||
return pkgHandle.VDPAGetDevByName(name)
|
||||
}
|
||||
|
||||
// VDPAGetDevConfigList returns list of VDPA devices configurations
|
||||
// Equivalent to: `vdpa dev config show`
|
||||
func VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
|
||||
return pkgHandle.VDPAGetDevConfigList()
|
||||
}
|
||||
|
||||
// VDPAGetDevConfigByName returns VDPA device configuration selected by name
|
||||
// Equivalent to: `vdpa dev config show <name>`
|
||||
func VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) {
|
||||
return pkgHandle.VDPAGetDevConfigByName(name)
|
||||
}
|
||||
|
||||
// VDPAGetDevVStats returns vstats for VDPA device
|
||||
// Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>`
|
||||
func VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
|
||||
return pkgHandle.VDPAGetDevVStats(name, queueIndex)
|
||||
}
|
||||
|
||||
// VDPAGetMGMTDevList returns list of mgmt devices
|
||||
// Equivalent to: `vdpa mgmtdev show`
|
||||
func VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
|
||||
return pkgHandle.VDPAGetMGMTDevList()
|
||||
}
|
||||
|
||||
// VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name
|
||||
// Equivalent to: `vdpa mgmtdev show <bus>/<name>`
|
||||
func VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) {
|
||||
return pkgHandle.VDPAGetMGMTDevByBusAndName(bus, name)
|
||||
}
|
||||
|
||||
type vdpaNetlinkMessage []syscall.NetlinkRouteAttr
|
||||
|
||||
func (id *vdpaDevID) parseIDAttribute(attr syscall.NetlinkRouteAttr) {
|
||||
switch attr.Attr.Type {
|
||||
case nl.VDPA_ATTR_DEV_NAME:
|
||||
id.Name = nl.BytesToString(attr.Value)
|
||||
case nl.VDPA_ATTR_DEV_ID:
|
||||
id.ID = native.Uint32(attr.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (netStatus *VDPADevConfigNetStatus) parseStatusAttribute(value []byte) {
|
||||
a := native.Uint16(value)
|
||||
netStatus.Announce = (a & VIRTIO_NET_S_ANNOUNCE) > 0
|
||||
netStatus.LinkUp = (a & VIRTIO_NET_S_LINK_UP) > 0
|
||||
}
|
||||
|
||||
func (d *VDPADev) parseAttributes(attrs vdpaNetlinkMessage) {
|
||||
for _, a := range attrs {
|
||||
d.parseIDAttribute(a)
|
||||
switch a.Attr.Type {
|
||||
case nl.VDPA_ATTR_DEV_VENDOR_ID:
|
||||
d.VendorID = native.Uint32(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_MAX_VQS:
|
||||
d.MaxVQS = native.Uint32(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_MAX_VQ_SIZE:
|
||||
d.MaxVQSize = native.Uint16(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_MIN_VQ_SIZE:
|
||||
d.MinVQSize = native.Uint16(a.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *VDPADevConfig) parseAttributes(attrs vdpaNetlinkMessage) {
|
||||
for _, a := range attrs {
|
||||
c.parseIDAttribute(a)
|
||||
switch a.Attr.Type {
|
||||
case nl.VDPA_ATTR_DEV_NET_CFG_MACADDR:
|
||||
c.Net.Cfg.MACAddr = a.Value
|
||||
case nl.VDPA_ATTR_DEV_NET_STATUS:
|
||||
c.Net.Status.parseStatusAttribute(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP:
|
||||
c.Net.Cfg.MaxVQP = native.Uint16(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_NET_CFG_MTU:
|
||||
c.Net.Cfg.MTU = native.Uint16(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_FEATURES:
|
||||
c.Features = native.Uint64(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES:
|
||||
c.NegotiatedFeatures = native.Uint64(a.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *VDPADevVStats) parseAttributes(attrs vdpaNetlinkMessage) {
|
||||
for _, a := range attrs {
|
||||
s.parseIDAttribute(a)
|
||||
switch a.Attr.Type {
|
||||
case nl.VDPA_ATTR_DEV_QUEUE_INDEX:
|
||||
s.QueueIndex = native.Uint32(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_VENDOR_ATTR_NAME:
|
||||
s.Vendor = append(s.Vendor, VDPADevVStatsVendor{Name: nl.BytesToString(a.Value)})
|
||||
case nl.VDPA_ATTR_DEV_VENDOR_ATTR_VALUE:
|
||||
if len(s.Vendor) == 0 {
|
||||
break
|
||||
}
|
||||
s.Vendor[len(s.Vendor)-1].Value = native.Uint64(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES:
|
||||
s.NegotiatedFeatures = native.Uint64(a.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *VDPAMGMTDev) parseAttributes(attrs vdpaNetlinkMessage) {
|
||||
for _, a := range attrs {
|
||||
switch a.Attr.Type {
|
||||
case nl.VDPA_ATTR_MGMTDEV_BUS_NAME:
|
||||
d.BusName = nl.BytesToString(a.Value)
|
||||
case nl.VDPA_ATTR_MGMTDEV_DEV_NAME:
|
||||
d.DevName = nl.BytesToString(a.Value)
|
||||
case nl.VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES:
|
||||
d.SupportedClasses = native.Uint64(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_SUPPORTED_FEATURES:
|
||||
d.SupportedFeatures = native.Uint64(a.Value)
|
||||
case nl.VDPA_ATTR_DEV_MGMTDEV_MAX_VQS:
|
||||
d.MaxVQS = native.Uint32(a.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handle) vdpaRequest(command uint8, extraFlags int, attrs []*nl.RtAttr) ([]vdpaNetlinkMessage, error) {
|
||||
f, err := h.GenlFamilyGet(nl.VDPA_GENL_NAME)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_ACK|extraFlags)
|
||||
req.AddData(&nl.Genlmsg{
|
||||
Command: command,
|
||||
Version: nl.VDPA_GENL_VERSION,
|
||||
})
|
||||
for _, a := range attrs {
|
||||
req.AddData(a)
|
||||
}
|
||||
|
||||
resp, err := req.Execute(unix.NETLINK_GENERIC, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages := make([]vdpaNetlinkMessage, 0, len(resp))
|
||||
for _, m := range resp {
|
||||
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages = append(messages, attrs)
|
||||
}
|
||||
return messages, nil
|
||||
}
|
||||
|
||||
// dump all devices if dev is nil
|
||||
func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) {
|
||||
var extraFlags int
|
||||
var attrs []*nl.RtAttr
|
||||
if dev != nil {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev)))
|
||||
} else {
|
||||
extraFlags = extraFlags | unix.NLM_F_DUMP
|
||||
}
|
||||
messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
devs := make([]*VDPADev, 0, len(messages))
|
||||
for _, m := range messages {
|
||||
d := &VDPADev{}
|
||||
d.parseAttributes(m)
|
||||
devs = append(devs, d)
|
||||
}
|
||||
return devs, nil
|
||||
}
|
||||
|
||||
// dump all devices if dev is nil
|
||||
func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) {
|
||||
var extraFlags int
|
||||
var attrs []*nl.RtAttr
|
||||
if dev != nil {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev)))
|
||||
} else {
|
||||
extraFlags = extraFlags | unix.NLM_F_DUMP
|
||||
}
|
||||
messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgs := make([]*VDPADevConfig, 0, len(messages))
|
||||
for _, m := range messages {
|
||||
cfg := &VDPADevConfig{}
|
||||
cfg.parseAttributes(m)
|
||||
cfgs = append(cfgs, cfg)
|
||||
}
|
||||
return cfgs, nil
|
||||
}
|
||||
|
||||
// dump all devices if dev is nil
|
||||
func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) {
|
||||
var extraFlags int
|
||||
var attrs []*nl.RtAttr
|
||||
if dev != nil {
|
||||
attrs = append(attrs,
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(*dev)),
|
||||
)
|
||||
if bus != nil {
|
||||
attrs = append(attrs,
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(*bus)),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
extraFlags = extraFlags | unix.NLM_F_DUMP
|
||||
}
|
||||
messages, err := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgs := make([]*VDPAMGMTDev, 0, len(messages))
|
||||
for _, m := range messages {
|
||||
cfg := &VDPAMGMTDev{}
|
||||
cfg.parseAttributes(m)
|
||||
cfgs = append(cfgs, cfg)
|
||||
}
|
||||
return cfgs, nil
|
||||
}
|
||||
|
||||
// VDPANewDev adds new VDPA device
|
||||
// Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]`
|
||||
func (h *Handle) VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error {
|
||||
attrs := []*nl.RtAttr{
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)),
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(mgmtName)),
|
||||
}
|
||||
if mgmtBus != "" {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(mgmtBus)))
|
||||
}
|
||||
if len(params.MACAddr) != 0 {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MACADDR, params.MACAddr))
|
||||
}
|
||||
if params.MaxVQP > 0 {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP, nl.Uint16Attr(params.MaxVQP)))
|
||||
}
|
||||
if params.MTU > 0 {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MTU, nl.Uint16Attr(params.MTU)))
|
||||
}
|
||||
if params.Features > 0 {
|
||||
attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_FEATURES, nl.Uint64Attr(params.Features)))
|
||||
}
|
||||
_, err := h.vdpaRequest(nl.VDPA_CMD_DEV_NEW, 0, attrs)
|
||||
return err
|
||||
}
|
||||
|
||||
// VDPADelDev removes VDPA device
|
||||
// Equivalent to: `vdpa dev del <name>`
|
||||
func (h *Handle) VDPADelDev(name string) error {
|
||||
_, err := h.vdpaRequest(nl.VDPA_CMD_DEV_DEL, 0, []*nl.RtAttr{
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name))})
|
||||
return err
|
||||
}
|
||||
|
||||
// VDPAGetDevList returns list of VDPA devices
|
||||
// Equivalent to: `vdpa dev show`
|
||||
func (h *Handle) VDPAGetDevList() ([]*VDPADev, error) {
|
||||
return h.vdpaDevGet(nil)
|
||||
}
|
||||
|
||||
// VDPAGetDevByName returns VDPA device selected by name
|
||||
// Equivalent to: `vdpa dev show <name>`
|
||||
func (h *Handle) VDPAGetDevByName(name string) (*VDPADev, error) {
|
||||
devs, err := h.vdpaDevGet(&name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(devs) == 0 {
|
||||
return nil, fmt.Errorf("device not found")
|
||||
}
|
||||
return devs[0], nil
|
||||
}
|
||||
|
||||
// VDPAGetDevConfigList returns list of VDPA devices configurations
|
||||
// Equivalent to: `vdpa dev config show`
|
||||
func (h *Handle) VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
|
||||
return h.vdpaDevConfigGet(nil)
|
||||
}
|
||||
|
||||
// VDPAGetDevConfigByName returns VDPA device configuration selected by name
|
||||
// Equivalent to: `vdpa dev config show <name>`
|
||||
func (h *Handle) VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) {
|
||||
cfgs, err := h.vdpaDevConfigGet(&name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cfgs) == 0 {
|
||||
return nil, fmt.Errorf("configuration not found")
|
||||
}
|
||||
return cfgs[0], nil
|
||||
}
|
||||
|
||||
// VDPAGetDevVStats returns vstats for VDPA device
|
||||
// Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>`
|
||||
func (h *Handle) VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
|
||||
messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_VSTATS_GET, 0, []*nl.RtAttr{
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)),
|
||||
nl.NewRtAttr(nl.VDPA_ATTR_DEV_QUEUE_INDEX, nl.Uint32Attr(queueIndex)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(messages) == 0 {
|
||||
return nil, fmt.Errorf("stats not found")
|
||||
}
|
||||
stats := &VDPADevVStats{}
|
||||
stats.parseAttributes(messages[0])
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// VDPAGetMGMTDevList returns list of mgmt devices
|
||||
// Equivalent to: `vdpa mgmtdev show`
|
||||
func (h *Handle) VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
|
||||
return h.vdpaMGMTDevGet(nil, nil)
|
||||
}
|
||||
|
||||
// VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name
|
||||
// Equivalent to: `vdpa mgmtdev show <bus>/<name>`
|
||||
func (h *Handle) VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) {
|
||||
var busPtr *string
|
||||
if bus != "" {
|
||||
busPtr = &bus
|
||||
}
|
||||
devs, err := h.vdpaMGMTDevGet(busPtr, &name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(devs) == 0 {
|
||||
return nil, fmt.Errorf("mgmtdev not found")
|
||||
}
|
||||
return devs[0], nil
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
// tests in this package require following modules: vdpa, vdpa_sim, vdpa_sim_net
|
||||
// The vpda_sim_net module creates virtual VDPA mgmt device with name vdpasim_net.
|
||||
|
||||
const (
|
||||
vdpaSimMGMTDev = "vdpasim_net"
|
||||
vdpaTestDeviceName = "__nl_test_dev"
|
||||
)
|
||||
|
||||
var (
|
||||
vdapTestReqModules = []string{"vdpa", "vdpa_sim", "vdpa_sim_net"}
|
||||
)
|
||||
|
||||
func setupVDPATest(t *testing.T, reqCommands ...int) func() {
|
||||
t.Helper()
|
||||
skipUnlessRoot(t)
|
||||
skipUnlessKModuleLoaded(t, vdapTestReqModules...)
|
||||
gFam, err := GenlFamilyGet(nl.VDPA_GENL_NAME)
|
||||
if err != nil {
|
||||
t.Skip("can't check for supported VDPA commands")
|
||||
}
|
||||
for _, c := range reqCommands {
|
||||
found := false
|
||||
for _, supportedOpt := range gFam.Ops {
|
||||
if supportedOpt.ID == uint32(c) {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Skip("host doesn't support required VDPA command for the test")
|
||||
}
|
||||
}
|
||||
return func() {
|
||||
_ = VDPADelDev(vdpaTestDeviceName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetMGMTDevList(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_MGMTDEV_GET)()
|
||||
mgmtDevs, err := VDPAGetMGMTDevList()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to list VDPA mgmt devs: %v", err)
|
||||
}
|
||||
simMGMTFound := false
|
||||
for _, d := range mgmtDevs {
|
||||
if d.DevName != vdpaSimMGMTDev || d.BusName != "" {
|
||||
continue
|
||||
}
|
||||
simMGMTFound = true
|
||||
checkVDPAMGMTDev(t, d)
|
||||
}
|
||||
if !simMGMTFound {
|
||||
t.Fatal("VDPA vdpasim_net MGMT device not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetMGMTDevByBusAndName(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_MGMTDEV_GET)()
|
||||
mgmtDev, err := VDPAGetMGMTDevByBusAndName("", vdpaSimMGMTDev)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get VDPA sim mgmt dev: %v", err)
|
||||
}
|
||||
checkVDPAMGMTDev(t, mgmtDev)
|
||||
if mgmtDev.DevName != vdpaSimMGMTDev || mgmtDev.BusName != "" {
|
||||
t.Fatalf("Invalid device received for Get call, expected: %s, actual: %s", vdpaSimMGMTDev, mgmtDev.DevName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetMGMTDevByBusAndName_Unknown_Device(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_MGMTDEV_GET)()
|
||||
_, err := VDPAGetMGMTDevByBusAndName("pci", "__should_not_exist")
|
||||
if !errors.Is(err, syscall.ENODEV) {
|
||||
t.Fatal("VDPAGetMGMTDevByBusAndName returns unexpected error for unknown device")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPANewDev(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_NEW)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
_, err := VDPAGetDevByName(vdpaTestDeviceName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get created VDPA devvice: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPANewDev_Already_Exist(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_NEW)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
err := createVDPATestDev()
|
||||
if !errors.Is(err, syscall.EEXIST) {
|
||||
t.Fatal("VDPANewDev returns unexpected error for device which is already exist")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPANewDev_Unknown_MGMT_DEV(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_NEW)()
|
||||
err := VDPANewDev(vdpaTestDeviceName, "", "__should_not_exist", VDPANewDevParams{})
|
||||
if !errors.Is(err, syscall.ENODEV) {
|
||||
t.Fatal("VDPANewDev returns unexpected error for unknown mgmt device")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPADelDev(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_DEL, nl.VDPA_CMD_DEV_NEW)()
|
||||
defer setupVDPATest(t)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
if err := VDPADelDev(vdpaTestDeviceName); err != nil {
|
||||
t.Fatalf("VDPADelDev failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPADelDev_Unknown_Device(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_DEL)()
|
||||
err := VDPADelDev("__should_not_exist")
|
||||
if !errors.Is(err, syscall.ENODEV) {
|
||||
t.Fatal("VDPADelDev returns unexpected error for unknown device")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetDevList(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_NEW)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
devs, err := VDPAGetDevList()
|
||||
if err != nil {
|
||||
t.Fatalf("VDPAGetDevList failed: %v", err)
|
||||
}
|
||||
testDevFound := false
|
||||
for _, d := range devs {
|
||||
if d.Name != vdpaTestDeviceName {
|
||||
continue
|
||||
}
|
||||
testDevFound = true
|
||||
checkVDPADev(t, d)
|
||||
}
|
||||
if !testDevFound {
|
||||
t.Fatal("VDPA test device not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetDevByName(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_NEW)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
dev, err := VDPAGetDevByName(vdpaTestDeviceName)
|
||||
if err != nil {
|
||||
t.Fatalf("VDPAGetDevByName failed: %v", err)
|
||||
}
|
||||
checkVDPADev(t, dev)
|
||||
if dev.Name != vdpaTestDeviceName {
|
||||
t.Fatalf("Invalid device received for Get call, expected: %s, actual: %s", vdpaTestDeviceName, dev.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetDevByName_Unknown(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET)()
|
||||
_, err := VDPAGetDevByName("__should_not_exist")
|
||||
if !errors.Is(err, syscall.ENODEV) {
|
||||
t.Fatal("VDPAGetDevByName returns unexpected error for unknown device")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetDevConfigList(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_CONFIG_GET)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
devConfs, err := VDPAGetDevConfigList()
|
||||
if err != nil {
|
||||
t.Fatalf("VDPAGetDevConfigList failed: %v", err)
|
||||
}
|
||||
testDevConfFound := false
|
||||
for _, d := range devConfs {
|
||||
if d.Name != vdpaTestDeviceName {
|
||||
continue
|
||||
}
|
||||
testDevConfFound = true
|
||||
checkVDPADevConf(t, d)
|
||||
}
|
||||
if !testDevConfFound {
|
||||
t.Fatal("VDPA test device config not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetDevConfigByName(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_CONFIG_GET)()
|
||||
if err := createVDPATestDev(); err != nil {
|
||||
t.Fatalf("failed to create VDPA device: %v", err)
|
||||
}
|
||||
dev, err := VDPAGetDevConfigByName(vdpaTestDeviceName)
|
||||
if err != nil {
|
||||
t.Fatalf("VDPAGetDevConfigByName failed: %v", err)
|
||||
}
|
||||
checkVDPADevConf(t, dev)
|
||||
if dev.Name != vdpaTestDeviceName {
|
||||
t.Fatalf("Invalid device received for Get call, expected: %s, actual: %s", vdpaTestDeviceName, dev.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVDPAGetDevConfigByName_Unknowm(t *testing.T) {
|
||||
defer setupVDPATest(t, nl.VDPA_CMD_DEV_GET, nl.VDPA_CMD_DEV_CONFIG_GET)()
|
||||
_, err := VDPAGetDevConfigByName("__should_not_exist")
|
||||
if !errors.Is(err, syscall.ENODEV) {
|
||||
t.Fatal("VDPAGetDevConfigByName returns unexpected error for unknown device")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetBits(t *testing.T) {
|
||||
features := SetBits(0, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_MQ)
|
||||
if !IsBitSet(features, VIRTIO_NET_F_CSUM) || !IsBitSet(features, VIRTIO_NET_F_MQ) {
|
||||
t.Fatal("BitSet test failed")
|
||||
}
|
||||
if IsBitSet(features, VIRTIO_NET_F_STATUS) {
|
||||
t.Fatal("unexpected bit is set")
|
||||
}
|
||||
}
|
||||
|
||||
func createVDPATestDev() error {
|
||||
return VDPANewDev(vdpaTestDeviceName, "", vdpaSimMGMTDev, VDPANewDevParams{})
|
||||
}
|
||||
|
||||
func checkVDPAMGMTDev(t *testing.T, d *VDPAMGMTDev) {
|
||||
if d == nil {
|
||||
t.Fatal("VDPA MGMT dev is nil")
|
||||
}
|
||||
if d.DevName == "" {
|
||||
t.Fatal("VDPA MGMT dev name is not set")
|
||||
}
|
||||
}
|
||||
|
||||
func checkVDPADev(t *testing.T, d *VDPADev) {
|
||||
if d == nil {
|
||||
t.Fatal("VDPA dev is nil")
|
||||
}
|
||||
if d.Name == "" {
|
||||
t.Fatal("VDPA dev name is not set")
|
||||
}
|
||||
if d.ID == 0 {
|
||||
t.Fatal("VDPA dev ID is not set")
|
||||
}
|
||||
}
|
||||
|
||||
func checkVDPADevConf(t *testing.T, d *VDPADevConfig) {
|
||||
if d == nil {
|
||||
t.Fatal("VDPA dev config is nil")
|
||||
}
|
||||
if d.Name == "" {
|
||||
t.Fatal("VDPA dev name is not set")
|
||||
}
|
||||
if d.ID == 0 {
|
||||
t.Fatal("VDPA dev ID is not set")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package netlink
|
||||
|
||||
// features for virtio net
|
||||
const (
|
||||
VIRTIO_NET_F_CSUM = 0 // Host handles pkts w/ partial csum
|
||||
VIRTIO_NET_F_GUEST_CSUM = 1 // Guest handles pkts w/ partial csum
|
||||
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS = 2 // Dynamic offload configuration.
|
||||
VIRTIO_NET_F_MTU = 3 // Initial MTU advice
|
||||
VIRTIO_NET_F_MAC = 5 // Host has given MAC address.
|
||||
VIRTIO_NET_F_GUEST_TSO4 = 7 // Guest can handle TSOv4 in.
|
||||
VIRTIO_NET_F_GUEST_TSO6 = 8 // Guest can handle TSOv6 in.
|
||||
VIRTIO_NET_F_GUEST_ECN = 9 // Guest can handle TSO[6] w/ ECN in.
|
||||
VIRTIO_NET_F_GUEST_UFO = 10 // Guest can handle UFO in.
|
||||
VIRTIO_NET_F_HOST_TSO4 = 11 // Host can handle TSOv4 in.
|
||||
VIRTIO_NET_F_HOST_TSO6 = 12 // Host can handle TSOv6 in.
|
||||
VIRTIO_NET_F_HOST_ECN = 13 // Host can handle TSO[6] w/ ECN in.
|
||||
VIRTIO_NET_F_HOST_UFO = 14 // Host can handle UFO in.
|
||||
VIRTIO_NET_F_MRG_RXBUF = 15 // Host can merge receive buffers.
|
||||
VIRTIO_NET_F_STATUS = 16 // virtio_net_config.status available
|
||||
VIRTIO_NET_F_CTRL_VQ = 17 // Control channel available
|
||||
VIRTIO_NET_F_CTRL_RX = 18 // Control channel RX mode support
|
||||
VIRTIO_NET_F_CTRL_VLAN = 19 // Control channel VLAN filtering
|
||||
VIRTIO_NET_F_CTRL_RX_EXTRA = 20 // Extra RX mode control support
|
||||
VIRTIO_NET_F_GUEST_ANNOUNCE = 21 // Guest can announce device on the* network
|
||||
VIRTIO_NET_F_MQ = 22 // Device supports Receive Flow Steering
|
||||
VIRTIO_NET_F_CTRL_MAC_ADDR = 23 // Set MAC address
|
||||
VIRTIO_NET_F_VQ_NOTF_COAL = 52 // Device supports virtqueue notification coalescing
|
||||
VIRTIO_NET_F_NOTF_COAL = 53 // Device supports notifications coalescing
|
||||
VIRTIO_NET_F_GUEST_USO4 = 54 // Guest can handle USOv4 in.
|
||||
VIRTIO_NET_F_GUEST_USO6 = 55 // Guest can handle USOv6 in.
|
||||
VIRTIO_NET_F_HOST_USO = 56 // Host can handle USO in.
|
||||
VIRTIO_NET_F_HASH_REPORT = 57 // Supports hash report
|
||||
VIRTIO_NET_F_GUEST_HDRLEN = 59 // Guest provides the exact hdr_len value.
|
||||
VIRTIO_NET_F_RSS = 60 // Supports RSS RX steering
|
||||
VIRTIO_NET_F_RSC_EXT = 61 // extended coalescing info
|
||||
VIRTIO_NET_F_STANDBY = 62 // Act as standby for another device with the same MAC.
|
||||
VIRTIO_NET_F_SPEED_DUPLEX = 63 // Device set linkspeed and duplex
|
||||
VIRTIO_NET_F_GSO = 6 // Host handles pkts any GSO type
|
||||
)
|
||||
|
||||
// virtio net status
|
||||
const (
|
||||
VIRTIO_NET_S_LINK_UP = 1 // Link is up
|
||||
VIRTIO_NET_S_ANNOUNCE = 2 // Announcement is needed
|
||||
)
|
||||
|
||||
// virtio config
|
||||
const (
|
||||
// Do we get callbacks when the ring is completely used, even if we've
|
||||
// suppressed them?
|
||||
VIRTIO_F_NOTIFY_ON_EMPTY = 24
|
||||
// Can the device handle any descriptor layout?
|
||||
VIRTIO_F_ANY_LAYOUT = 27
|
||||
// v1.0 compliant
|
||||
VIRTIO_F_VERSION_1 = 32
|
||||
// If clear - device has the platform DMA (e.g. IOMMU) bypass quirk feature.
|
||||
// If set - use platform DMA tools to access the memory.
|
||||
// Note the reverse polarity (compared to most other features),
|
||||
// this is for compatibility with legacy systems.
|
||||
VIRTIO_F_ACCESS_PLATFORM = 33
|
||||
// Legacy name for VIRTIO_F_ACCESS_PLATFORM (for compatibility with old userspace)
|
||||
VIRTIO_F_IOMMU_PLATFORM = VIRTIO_F_ACCESS_PLATFORM
|
||||
// This feature indicates support for the packed virtqueue layout.
|
||||
VIRTIO_F_RING_PACKED = 34
|
||||
// Inorder feature indicates that all buffers are used by the device
|
||||
// in the same order in which they have been made available.
|
||||
VIRTIO_F_IN_ORDER = 35
|
||||
// This feature indicates that memory accesses by the driver and the
|
||||
// device are ordered in a way described by the platform.
|
||||
VIRTIO_F_ORDER_PLATFORM = 36
|
||||
// Does the device support Single Root I/O Virtualization?
|
||||
VIRTIO_F_SR_IOV = 37
|
||||
// This feature indicates that the driver passes extra data (besides
|
||||
// identifying the virtqueue) in its device notifications.
|
||||
VIRTIO_F_NOTIFICATION_DATA = 38
|
||||
// This feature indicates that the driver uses the data provided by the device
|
||||
// as a virtqueue identifier in available buffer notifications.
|
||||
VIRTIO_F_NOTIF_CONFIG_DATA = 39
|
||||
// This feature indicates that the driver can reset a queue individually.
|
||||
VIRTIO_F_RING_RESET = 40
|
||||
)
|
||||
|
||||
// virtio device ids
|
||||
const (
|
||||
VIRTIO_ID_NET = 1 // virtio net
|
||||
VIRTIO_ID_BLOCK = 2 // virtio block
|
||||
VIRTIO_ID_CONSOLE = 3 // virtio console
|
||||
VIRTIO_ID_RNG = 4 // virtio rng
|
||||
VIRTIO_ID_BALLOON = 5 // virtio balloon
|
||||
VIRTIO_ID_IOMEM = 6 // virtio ioMemory
|
||||
VIRTIO_ID_RPMSG = 7 // virtio remote processor messaging
|
||||
VIRTIO_ID_SCSI = 8 // virtio scsi
|
||||
VIRTIO_ID_9P = 9 // 9p virtio console
|
||||
VIRTIO_ID_MAC80211_WLAN = 10 // virtio WLAN MAC
|
||||
VIRTIO_ID_RPROC_SERIAL = 11 // virtio remoteproc serial link
|
||||
VIRTIO_ID_CAIF = 12 // Virtio caif
|
||||
VIRTIO_ID_MEMORY_BALLOON = 13 // virtio memory balloon
|
||||
VIRTIO_ID_GPU = 16 // virtio GPU
|
||||
VIRTIO_ID_CLOCK = 17 // virtio clock/timer
|
||||
VIRTIO_ID_INPUT = 18 // virtio input
|
||||
VIRTIO_ID_VSOCK = 19 // virtio vsock transport
|
||||
VIRTIO_ID_CRYPTO = 20 // virtio crypto
|
||||
VIRTIO_ID_SIGNAL_DIST = 21 // virtio signal distribution device
|
||||
VIRTIO_ID_PSTORE = 22 // virtio pstore device
|
||||
VIRTIO_ID_IOMMU = 23 // virtio IOMMU
|
||||
VIRTIO_ID_MEM = 24 // virtio mem
|
||||
VIRTIO_ID_SOUND = 25 // virtio sound
|
||||
VIRTIO_ID_FS = 26 // virtio filesystem
|
||||
VIRTIO_ID_PMEM = 27 // virtio pmem
|
||||
VIRTIO_ID_RPMB = 28 // virtio rpmb
|
||||
VIRTIO_ID_MAC80211_HWSIM = 29 // virtio mac80211-hwsim
|
||||
VIRTIO_ID_VIDEO_ENCODER = 30 // virtio video encoder
|
||||
VIRTIO_ID_VIDEO_DECODER = 31 // virtio video decoder
|
||||
VIRTIO_ID_SCMI = 32 // virtio SCMI
|
||||
VIRTIO_ID_NITRO_SEC_MOD = 33 // virtio nitro secure module
|
||||
VIRTIO_ID_I2C_ADAPTER = 34 // virtio i2c adapter
|
||||
VIRTIO_ID_WATCHDOG = 35 // virtio watchdog
|
||||
VIRTIO_ID_CAN = 36 // virtio can
|
||||
VIRTIO_ID_DMABUF = 37 // virtio dmabuf
|
||||
VIRTIO_ID_PARAM_SERV = 38 // virtio parameter server
|
||||
VIRTIO_ID_AUDIO_POLICY = 39 // virtio audio policy
|
||||
VIRTIO_ID_BT = 40 // virtio bluetooth
|
||||
VIRTIO_ID_GPIO = 41 // virtio gpio
|
||||
// Virtio Transitional IDs
|
||||
VIRTIO_TRANS_ID_NET = 0x1000 // transitional virtio net
|
||||
VIRTIO_TRANS_ID_BLOCK = 0x1001 // transitional virtio block
|
||||
VIRTIO_TRANS_ID_BALLOON = 0x1002 // transitional virtio balloon
|
||||
VIRTIO_TRANS_ID_CONSOLE = 0x1003 // transitional virtio console
|
||||
VIRTIO_TRANS_ID_SCSI = 0x1004 // transitional virtio SCSI
|
||||
VIRTIO_TRANS_ID_RNG = 0x1005 // transitional virtio rng
|
||||
VIRTIO_TRANS_ID_9P = 0x1009 // transitional virtio 9p console
|
||||
)
|
Loading…
Reference in New Issue