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 {
|
func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||||
skipUnlessRoot(t)
|
skipUnlessRoot(t)
|
||||||
|
|
||||||
|
@ -159,22 +181,7 @@ func setUpSEG6NetlinkTest(t *testing.T) tearDownNetlinkTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUpNetlinkTestWithKModule(t *testing.T, name string) tearDownNetlinkTest {
|
func setUpNetlinkTestWithKModule(t *testing.T, name string) tearDownNetlinkTest {
|
||||||
file, err := ioutil.ReadFile("/proc/modules")
|
skipUnlessKModuleLoaded(t, name)
|
||||||
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)
|
|
||||||
}
|
|
||||||
return setUpNetlinkTest(t)
|
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