| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- package netlink
- import (
- "errors"
- "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`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- 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, executeErr
- }
- // dump all devices if dev is nil
- //
- // If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- devs := make([]*VDPADev, 0, len(messages))
- for _, m := range messages {
- d := &VDPADev{}
- d.parseAttributes(m)
- devs = append(devs, d)
- }
- return devs, executeErr
- }
- // dump all devices if dev is nil
- //
- // If dev is nil, and the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- cfgs := make([]*VDPADevConfig, 0, len(messages))
- for _, m := range messages {
- cfg := &VDPADevConfig{}
- cfg.parseAttributes(m)
- cfgs = append(cfgs, cfg)
- }
- return cfgs, executeErr
- }
- // dump all devices if dev is nil
- //
- // If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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, executeErr := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs)
- if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
- return nil, executeErr
- }
- cfgs := make([]*VDPAMGMTDev, 0, len(messages))
- for _, m := range messages {
- cfg := &VDPAMGMTDev{}
- cfg.parseAttributes(m)
- cfgs = append(cfgs, cfg)
- }
- return cfgs, executeErr
- }
- // 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`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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`
- //
- // If the returned error is [ErrDumpInterrupted], results may be inconsistent
- // or incomplete.
- 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
- }
|