Skip to content

Commit a27e9ff

Browse files
committed
incusd/ip/vdpa: Switch to vishvananda/netlink library instead of doing netlink ourselves (incomplete)
Signed-off-by: Gwendolyn <[email protected]>
1 parent 0a9355d commit a27e9ff

File tree

1 file changed

+41
-265
lines changed

1 file changed

+41
-265
lines changed

internal/server/ip/vdpa.go

+41-265
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,13 @@
11
package ip
22

33
import (
4-
"encoding/binary"
54
"fmt"
65
"os"
76
"path/filepath"
87
"strings"
98
"syscall"
109

1110
"github.com/vishvananda/netlink"
12-
"github.com/vishvananda/netlink/nl"
13-
)
14-
15-
// vDPA Netlink name.
16-
const (
17-
vDPAGenlName = "vdpa"
18-
)
19-
20-
// vDPA Netlink command.
21-
const (
22-
_ uint8 = iota
23-
_
24-
vDPACmdMgmtDevGet
25-
vDPACmdDevNew
26-
vDPACmdDevDel
27-
vDPACmdDevGet
28-
_
29-
)
30-
31-
// vDPA Netlink Attributes.
32-
const (
33-
_ = iota
34-
35-
// bus name (optional) + dev name together make the parent device handle.
36-
vDPAAttrMgmtDevBusName // string
37-
vDPAAttrMgmtDevDevName // string
38-
vDPAAttrMgmtDevSupportedClasses // u64
39-
40-
vDPAAttrDevName // string
41-
vDPAAttrDevID // u32
42-
vDPAAttrDevVendorID // u32
43-
vDPAAttrDevMaxVqs // u32
44-
vDPAAttrDevMaxVqSize // u16
45-
vDPAAttrDevMinVqSize // u16
46-
47-
vDPAAttrDevNetCfgMacAddr // binary
48-
vDPAAttrDevNetStatus // u8
49-
vDPAAttrDevNetCfgMaxVqp // u16
50-
vDPAAttrGetNetCfgMTU // u16
5111
)
5212

5313
// Base flags passed to all Netlink requests.
@@ -66,7 +26,7 @@ const (
6626
vdpaVhostDevDir = "/dev"
6727
)
6828

69-
// VhostVdpa is the vhost-vdpa device information.
29+
// VhostVDPA is the vhost-vdpa device information.
7030
type VhostVDPA struct {
7131
Name string
7232
Path string
@@ -90,19 +50,6 @@ type VDPADev struct {
9050
VhostVDPA *VhostVDPA
9151
}
9252

93-
// ParseAttributes parses the attributes of a netlink message for a vDPA management device.
94-
func (d *MgmtVDPADev) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
95-
for _, attr := range attrs {
96-
switch attr.Attr.Type {
97-
case vDPAAttrMgmtDevBusName:
98-
d.BusName = string(attr.Value[:len(attr.Value)-1])
99-
case vDPAAttrMgmtDevDevName:
100-
d.DevName = string(attr.Value[:len(attr.Value)-1])
101-
}
102-
}
103-
return nil
104-
}
105-
10653
// getVhostVDPADevInPath returns the VhostVDPA found in the provided parent device's path.
10754
func getVhostVDPADevInPath(parentPath string) (*VhostVDPA, error) {
10855
fd, err := os.Open(parentPath)
@@ -139,211 +86,61 @@ func getVhostVDPADevInPath(parentPath string) (*VhostVDPA, error) {
13986
return nil, fmt.Errorf("No vhost-vdpa device found in %s", parentPath)
14087
}
14188

142-
// ParseAttributes parses the attributes of a netlink message for a vDPA device.
143-
func (d *VDPADev) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
144-
d.MgmtDev = &MgmtVDPADev{}
145-
for _, attr := range attrs {
146-
switch attr.Attr.Type {
147-
case vDPAAttrDevName:
148-
d.Name = string(attr.Value[:len(attr.Value)-1])
149-
case vDPAAttrDevMaxVqs:
150-
d.MaxVQs = binary.LittleEndian.Uint32(attr.Value[:len(attr.Value)])
151-
case vDPAAttrMgmtDevBusName:
152-
d.MgmtDev.BusName = string(attr.Value[:len(attr.Value)-1])
153-
case vDPAAttrMgmtDevDevName:
154-
d.MgmtDev.DevName = string(attr.Value[:len(attr.Value)-1])
155-
}
156-
}
157-
158-
// Get the vhost-vdpa device associated with the vDPA device.
159-
vhostVDPA, err := getVhostVDPADevInPath(filepath.Join(vdpaBusDevDir, d.Name))
160-
if err != nil {
161-
return err
162-
}
163-
164-
d.VhostVDPA = vhostVDPA
165-
return nil
166-
}
167-
168-
// runVDPANetlinkCmd executes a vDPA netlink command and returns the response.
169-
func runVDPANetlinkCmd(command uint8, flags int, data []*nl.RtAttr) ([][]byte, error) {
170-
f, err := netlink.GenlFamilyGet(vDPAGenlName)
171-
if err != nil {
172-
return nil, fmt.Errorf("Could not get the vDPA Netlink family : %v", err)
173-
}
174-
175-
msg := &nl.Genlmsg{
176-
Command: command,
177-
Version: nl.GENL_CTRL_VERSION,
178-
}
179-
180-
req := nl.NewNetlinkRequest(int(f.ID), commonNLFlags|flags)
181-
// Pass the data into the request header
182-
req.AddData(msg)
183-
for _, d := range data {
184-
req.AddData(d)
185-
}
186-
187-
// Execute the request
188-
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
189-
if err != nil {
190-
return nil, fmt.Errorf("Could not execute vDPA Netlink request : %v", err)
191-
}
192-
193-
return msgs, nil
194-
}
195-
196-
// newNetlinkAttribute creates a new netlink attribute based on the attribute type and data.
197-
func newNetlinkAttribute(attrType int, data any) (*nl.RtAttr, error) {
198-
switch attrType {
199-
case vDPAAttrMgmtDevBusName, vDPAAttrMgmtDevDevName, vDPAAttrDevName:
200-
strData, ok := data.(string)
201-
if !ok {
202-
return nil, fmt.Errorf("Netlink attribute type %d requires string data", attrType)
203-
}
204-
205-
bytes := make([]byte, len(strData)+1)
206-
copy(bytes, strData)
207-
return nl.NewRtAttr(attrType, bytes), nil
208-
case vDPAAttrMgmtDevSupportedClasses:
209-
u64Data, ok := data.(uint64)
210-
if !ok {
211-
return nil, fmt.Errorf("Netlink attribute type %d requires uint64 data", attrType)
212-
}
213-
214-
return nl.NewRtAttr(attrType, nl.Uint64Attr(u64Data)), nil
215-
case vDPAAttrDevID, vDPAAttrDevVendorID, vDPAAttrDevMaxVqs:
216-
u32Data, ok := data.(uint32)
217-
if !ok {
218-
return nil, fmt.Errorf("Netlink attribute type %d requires uint32 data", attrType)
219-
}
220-
221-
return nl.NewRtAttr(attrType, nl.Uint32Attr(u32Data)), nil
222-
case vDPAAttrDevMaxVqSize, vDPAAttrDevMinVqSize, vDPAAttrDevNetCfgMaxVqp, vDPAAttrGetNetCfgMTU:
223-
u16Data, ok := data.(uint16)
224-
if !ok {
225-
return nil, fmt.Errorf("Netlink attribute type %d requires uint16 data", attrType)
226-
}
227-
228-
return nl.NewRtAttr(attrType, nl.Uint16Attr(u16Data)), nil
229-
case vDPAAttrDevNetStatus:
230-
u8Data, ok := data.(uint8)
231-
if !ok {
232-
return nil, fmt.Errorf("Netlink attribute type %d requires uint8 data", attrType)
233-
}
234-
235-
return nl.NewRtAttr(attrType, nl.Uint8Attr(u8Data)), nil
236-
case vDPAAttrDevNetCfgMacAddr:
237-
binData, ok := data.([]byte)
238-
if !ok {
239-
return nil, fmt.Errorf("Netlink attribute type %d requires []byte data", attrType)
240-
}
241-
242-
return nl.NewRtAttr(attrType, binData), nil
243-
default:
244-
return nil, fmt.Errorf("Unknown netlink attribute type %d", attrType)
245-
}
246-
}
247-
248-
// parseMgmtVDPADevList parses a list of vDPA management device netlink messages.
249-
func parseMgmtVDPADevList(msgs [][]byte) ([]*MgmtVDPADev, error) {
250-
devices := make([]*MgmtVDPADev, 0, len(msgs))
251-
for _, m := range msgs {
252-
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
253-
if err != nil {
254-
return nil, fmt.Errorf("Could not parse Netlink vDPA management device route attributes : %v", err)
255-
}
256-
257-
dev := &MgmtVDPADev{}
258-
if err = dev.parseAttributes(attrs); err != nil {
259-
return nil, err
260-
}
261-
262-
devices = append(devices, dev)
263-
}
264-
265-
return devices, nil
266-
}
267-
268-
// parseVDPADevList parses a list of vDPA device netlink messages.
269-
func parseVDPADevList(msgs [][]byte) ([]*VDPADev, error) {
270-
devices := make([]*VDPADev, 0, len(msgs))
271-
for _, m := range msgs {
272-
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
273-
if err != nil {
274-
return nil, fmt.Errorf("Could not parse Netlink vDPA device route attributes : %v", err)
275-
}
276-
277-
dev := &VDPADev{}
278-
if err = dev.parseAttributes(attrs); err != nil {
279-
return nil, err
280-
}
281-
282-
devices = append(devices, dev)
283-
}
284-
285-
return devices, nil
286-
}
287-
28889
// ListVDPAMgmtDevices returns the list of all vDPA management devices.
28990
func ListVDPAMgmtDevices() ([]*MgmtVDPADev, error) {
290-
resp, err := runVDPANetlinkCmd(vDPACmdMgmtDevGet, syscall.NLM_F_DUMP, nil)
91+
netlinkDevices, err := netlink.VDPAGetMGMTDevList()
29192
if err != nil {
29293
return nil, err
29394
}
29495

295-
mgtmDevs, err := parseMgmtVDPADevList(resp)
296-
if err != nil {
297-
return nil, err
96+
devices := make([]*MgmtVDPADev, 0, len(netlinkDevices))
97+
for _, dev := range netlinkDevices {
98+
devices = append(devices, &MgmtVDPADev{
99+
BusName: dev.BusName,
100+
DevName: dev.DevName,
101+
})
298102
}
299103

300-
return mgtmDevs, nil
104+
return devices, nil
301105
}
302106

303107
// ListVDPADevices returns the list of all vDPA devices.
304108
func ListVDPADevices() ([]*VDPADev, error) {
305-
resp, err := runVDPANetlinkCmd(vDPACmdDevGet, syscall.NLM_F_DUMP, nil)
109+
netlinkDevices, err := netlink.VDPAGetDevList()
306110
if err != nil {
307111
return nil, err
308112
}
309113

310-
devices, err := parseVDPADevList(resp)
311-
if err != nil {
312-
return nil, err
114+
devices := make([]*VDPADev, 0, len(netlinkDevices))
115+
for _, dev := range netlinkDevices {
116+
vhostVDPA, err := getVhostVDPADevInPath(filepath.Join(vdpaBusDevDir, dev.Name))
117+
if err != nil {
118+
return nil, err
119+
}
120+
121+
devices = append(devices, &VDPADev{
122+
Name: dev.Name,
123+
MaxVQs: dev.MaxVQS,
124+
MgmtDev: nil, // TODO: the netlink library does not expose the associated management device information
125+
VhostVDPA: vhostVDPA,
126+
})
313127
}
314128

315129
return devices, nil
316130
}
317131

318132
// AddVDPADevice adds a new vDPA device.
319133
func AddVDPADevice(pciDevSlotName string, volatile map[string]string) (*VDPADev, error) {
320-
// List existing vDPA devices
321-
vdpaDevs, err := ListVDPADevices()
134+
existingDevices, err := netlink.VDPAGetDevList()
322135
if err != nil {
323136
return nil, err
324137
}
325138

326139
existingVDPADevNames := make(map[string]struct{})
327-
for _, vdpaDev := range vdpaDevs {
328-
existingVDPADevNames[vdpaDev.Name] = struct{}{}
329-
}
330-
331-
// Create the netlink attributes
332-
header := []*nl.RtAttr{}
333-
busName, err := newNetlinkAttribute(vDPAAttrMgmtDevBusName, "pci")
334-
if err != nil {
335-
return nil, fmt.Errorf("Failed creating vDPA `busName` netlink attr : %v", err)
336-
}
337-
338-
header = append(header, busName)
339-
340-
mgmtDevDevName, err := newNetlinkAttribute(vDPAAttrMgmtDevDevName, pciDevSlotName)
341-
if err != nil {
342-
return nil, fmt.Errorf("Failed creating vDPA `pciDevSlotName` netlink attr : %v", err)
140+
for _, device := range existingDevices {
141+
existingVDPADevNames[device.Name] = struct{}{}
343142
}
344143

345-
header = append(header, mgmtDevDevName)
346-
347144
// Generate a unique attribute name for the vDPA device (i.e, vdpa0, vdpa1, etc.)
348145
baseVDPAName, idx, generatedVDPADevName := "vdpa", 0, ""
349146
for {
@@ -356,56 +153,35 @@ func AddVDPADevice(pciDevSlotName string, volatile map[string]string) (*VDPADev,
356153
idx++
357154
}
358155

359-
devName, err := newNetlinkAttribute(vDPAAttrDevName, generatedVDPADevName)
156+
err = netlink.VDPANewDev(generatedVDPADevName, "pci", pciDevSlotName, netlink.VDPANewDevParams{
157+
MaxVQP: vDPAMaxVQP,
158+
})
360159
if err != nil {
361-
return nil, fmt.Errorf("Failed creating vDPA `generatedVDPADevName` netlink attr : %v", err)
362-
}
363-
364-
header = append(header, devName)
365-
366-
maxVQP, err := newNetlinkAttribute(vDPAAttrDevNetCfgMaxVqp, vDPAMaxVQP)
367-
if err != nil {
368-
return nil, fmt.Errorf("Failed creating vDPA `maxVQP` netlink attr : %v", err)
369-
}
370-
371-
header = append(header, maxVQP)
372-
373-
_, err = runVDPANetlinkCmd(vDPACmdDevNew, 0, header)
374-
if err != nil {
375-
return nil, fmt.Errorf("Failed creating vDPA device : %v", err)
160+
return nil, err
376161
}
377162

378-
// Now that the vDPA device has been created in the kernel, return the VDPADev struct
379-
msgs, err := runVDPANetlinkCmd(vDPACmdDevGet, 0, []*nl.RtAttr{devName})
163+
dev, err := netlink.VDPAGetDevByName(generatedVDPADevName)
380164
if err != nil {
381-
return nil, fmt.Errorf("Failed getting vDPA device : %v", err)
165+
return nil, err
382166
}
383167

384-
vdpaDevs, err = parseVDPADevList(msgs)
168+
vhostVDPA, err := getVhostVDPADevInPath(filepath.Join(vdpaBusDevDir, dev.Name))
385169
if err != nil {
386-
return nil, fmt.Errorf("Failed parsing vDPA device : %v", err)
170+
return nil, err
387171
}
388172

389173
// Update the volatile map
390174
volatile["last_state.vdpa.name"] = generatedVDPADevName
391175

392-
return vdpaDevs[0], nil
176+
return &VDPADev{
177+
Name: dev.Name,
178+
MaxVQs: dev.MaxVQS,
179+
MgmtDev: nil, // TODO: the netlink library does not expose the associated management device information
180+
VhostVDPA: vhostVDPA,
181+
}, nil
393182
}
394183

395184
// DeleteVDPADevice deletes a vDPA management device.
396185
func DeleteVDPADevice(vDPADevName string) error {
397-
header := []*nl.RtAttr{}
398-
devName, err := newNetlinkAttribute(vDPAAttrDevName, vDPADevName)
399-
if err != nil {
400-
return fmt.Errorf("Failed creating vDPA `vDPADevName` netlink attr : %v", err)
401-
}
402-
403-
header = append(header, devName)
404-
405-
_, err = runVDPANetlinkCmd(vDPACmdDevDel, 0, header)
406-
if err != nil {
407-
return fmt.Errorf("Cannot delete VDPA dev: %v", err)
408-
}
409-
410-
return nil
186+
return netlink.VDPADelDev(vDPADevName)
411187
}

0 commit comments

Comments
 (0)