diff --git a/cmd/kvdpa-cli/kvdpa-cli.go b/cmd/kvdpa-cli/kvdpa-cli.go index 12729a1..44c3d27 100644 --- a/cmd/kvdpa-cli/kvdpa-cli.go +++ b/cmd/kvdpa-cli/kvdpa-cli.go @@ -3,7 +3,6 @@ package main import ( "fmt" "os" - "strings" "text/template" vdpa "github.com/k8snetworkplumbingwg/govdpa/pkg/kvdpa" @@ -26,26 +25,14 @@ const deviceTemplate = ` - Name: {{ .Name }} func listAction(c *cli.Context) error { var devs []vdpa.VdpaDevice var err error - if c.String("mgmtdev") != "" { - var bus, name string - nameParts := strings.Split(c.String("mgmtdev"), "/") - if len(nameParts) == 1 { - name = nameParts[0] - } else if len(nameParts) == 2 { - bus = nameParts[0] - name = nameParts[1] - } else { - return fmt.Errorf("Invalid management device name %s", c.String("mgmtdev")) - } - devs, err = vdpa.GetVdpaDevicesByMgmtDev(bus, name) - if err != nil { - return err - } + var mgmtDev = c.String("mgmtdev") + if mgmtDev != "" { + devs, err = vdpa.GetVdpaDevicesByPciAddress(mgmtDev) } else { devs, err = vdpa.ListVdpaDevices() - if err != nil { - fmt.Println(err) - } + } + if err != nil { + return err } tmpl := template.Must(template.New("device").Parse(deviceTemplate)) diff --git a/go.mod b/go.mod index 431bee4..a6eb55c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/stretchr/testify v1.7.0 github.com/urfave/cli/v2 v2.2.0 github.com/vishvananda/netlink v1.1.0 - golang.org/x/sys v0.1.0 + golang.org/x/sys v0.12.0 ) require ( @@ -17,5 +17,7 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/stretchr/objx v0.1.0 // indirect github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/tools v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/go.sum b/go.sum index 8bb04c5..1e94140 100644 --- a/go.sum +++ b/go.sum @@ -20,9 +20,26 @@ github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/kvdpa/device.go b/pkg/kvdpa/device.go index 120b495..fd080fa 100644 --- a/pkg/kvdpa/device.go +++ b/pkg/kvdpa/device.go @@ -185,7 +185,8 @@ func GetVdpaDevice(name string) (VdpaDevice, error) { return nil, err } - vdpaDevs, err := parseDevLinkVdpaDevList(msgs) + // No filters, expecting to parse attributes for the device with the given name + vdpaDevs, err := parseDevLinkVdpaDevList("", "", msgs) if err != nil { return nil, err } @@ -197,38 +198,32 @@ GetVdpaDevicesByMgmtDev returns the VdpaDevice objects whose MgmtDev has the given bus and device names. */ func GetVdpaDevicesByMgmtDev(busName, devName string) ([]VdpaDevice, error) { - result := []VdpaDevice{} - devices, err := ListVdpaDevices() - if err != nil { - return nil, err - } - for _, device := range devices { - if device.MgmtDev() != nil && - device.MgmtDev().BusName() == busName && - device.MgmtDev().DevName() == devName { - result = append(result, device) - } - } - if len(result) == 0 { - return nil, syscall.ENODEV - } - return result, nil + return listVdpaDevicesWithBusDevName(busName, devName) } /*ListVdpaDevices returns a list of all available vdpa devices */ func ListVdpaDevices() ([]VdpaDevice, error) { + return listVdpaDevices() +} + +func listVdpaDevicesWithBusDevName(busName, devName string) ([]VdpaDevice, error) { msgs, err := GetNetlinkOps().RunVdpaNetlinkCmd(VdpaCmdDevGet, syscall.NLM_F_DUMP, nil) if err != nil { return nil, err } - vdpaDevs, err := parseDevLinkVdpaDevList(msgs) + vdpaDevs, err := parseDevLinkVdpaDevList(busName, devName, msgs) if err != nil { return nil, err } return vdpaDevs, nil } +func listVdpaDevices() ([]VdpaDevice, error) { + // no filters, returns all the objects + return listVdpaDevicesWithBusDevName("", "") +} + func extractBusNameAndMgmtDeviceName(fullMgmtDeviceName string) (busName string, mgmtDeviceName string, err error) { numSlashes := strings.Count(fullMgmtDeviceName, "/") if numSlashes > 1 { @@ -317,7 +312,7 @@ func DeleteVdpaDevice(vdpaDeviceName string) error { return nil } -func parseDevLinkVdpaDevList(msgs [][]byte) ([]VdpaDevice, error) { +func parseDevLinkVdpaDevList(busName string, mgmtDeviceName string, msgs [][]byte) ([]VdpaDevice, error) { devices := make([]VdpaDevice, 0, len(msgs)) for _, m := range msgs { @@ -329,6 +324,15 @@ func parseDevLinkVdpaDevList(msgs [][]byte) ([]VdpaDevice, error) { if err = dev.parseAttributes(attrs); err != nil { return nil, err } + + if busName != "" && busName != dev.mgmtDev.busName { + continue + } + + if mgmtDeviceName != "" && mgmtDeviceName != dev.mgmtDev.devName { + continue + } + if err = dev.getBusInfo(); err != nil { return nil, err } diff --git a/pkg/kvdpa/device_test.go b/pkg/kvdpa/device_test.go index aaa0668..b584105 100644 --- a/pkg/kvdpa/device_test.go +++ b/pkg/kvdpa/device_test.go @@ -128,6 +128,98 @@ func TestVdpaDevList(t *testing.T) { } } +func TestVdpaDevListWithFilter(t *testing.T) { + tests := []struct { + name string + err bool + response []VdpaDevice + }{ + { + name: "Multiple SR-IOV and SF devices", + err: false, + response: []VdpaDevice{ + &vdpaDev{ + name: "vdpa0", + mgmtDev: &mgmtDev{ + devName: "0000:01:01", + }, + }, + &vdpaDev{ + name: "vdpa1", + mgmtDev: &mgmtDev{ + busName: "pci", + devName: "0000:01:02", + }, + }, + &vdpaDev{ + name: "vdpa2", + mgmtDev: &mgmtDev{ + busName: "pci", + devName: "0000:01:02", + }, + }, + &vdpaDev{ + name: "vdpa3", + mgmtDev: &mgmtDev{ + busName: "pci", + devName: "0000:01:03", + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(fmt.Sprintf("%s_%s", "TestVdpaDevListWithFilter", tt.name), func(t *testing.T) { + netLinkMock := &mocks.NetlinkOps{} + SetNetlinkOps(netLinkMock) + netLinkMock.On("RunVdpaNetlinkCmd", + VdpaCmdDevGet, + mock.MatchedBy(func(flags int) bool { + return (flags|syscall.NLM_F_DUMP != 0) + }), + mock.AnythingOfType("[]*nl.RtAttr")). + Return(vdpaDevToNlMessage(t, tt.response...), nil) + // no filters, all devices are returned + devs, err := ListVdpaDevices() + if tt.err { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.Equal(t, tt.response, devs) + } + // mgmtdev: 0000:01:01 + devs, err = GetVdpaDevicesByPciAddress("0000:01:01") + if tt.err { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.Equal(t, len(devs), 1) + assert.Equal(t, tt.response[0], devs[0]) + } + // mgmtdev: pci/0000:01:02 + devs, err = GetVdpaDevicesByPciAddress("pci/0000:01:02") + if tt.err { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.Equal(t, len(devs), 2) + assert.Equal(t, tt.response[1], devs[0]) + assert.Equal(t, tt.response[2], devs[1]) + } + // mgmtdev: pci/0000:01:03 + devs, err = GetVdpaDevicesByPciAddress("pci/0000:01:03") + if tt.err { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.Equal(t, len(devs), 1) + assert.Equal(t, tt.response[3], devs[0]) + } + }) + } +} + func TestVdpaDevGet(t *testing.T) { tests := []struct { name string @@ -304,7 +396,7 @@ func TestVdpaDevGetByMgmt(t *testing.T) { }, { name: "Wrong", - err: syscall.ENODEV, + response: []VdpaDevice{}, mgmtDevName: "noDev", mgmtBusName: "wrongBus", },