1
1
package ip
2
2
3
3
import (
4
- "encoding/binary"
5
4
"fmt"
6
5
"os"
7
6
"path/filepath"
8
7
"strings"
9
8
"syscall"
10
9
11
10
"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
51
11
)
52
12
53
13
// Base flags passed to all Netlink requests.
@@ -66,7 +26,7 @@ const (
66
26
vdpaVhostDevDir = "/dev"
67
27
)
68
28
69
- // VhostVdpa is the vhost-vdpa device information.
29
+ // VhostVDPA is the vhost-vdpa device information.
70
30
type VhostVDPA struct {
71
31
Name string
72
32
Path string
@@ -90,19 +50,6 @@ type VDPADev struct {
90
50
VhostVDPA * VhostVDPA
91
51
}
92
52
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
-
106
53
// getVhostVDPADevInPath returns the VhostVDPA found in the provided parent device's path.
107
54
func getVhostVDPADevInPath (parentPath string ) (* VhostVDPA , error ) {
108
55
fd , err := os .Open (parentPath )
@@ -139,211 +86,61 @@ func getVhostVDPADevInPath(parentPath string) (*VhostVDPA, error) {
139
86
return nil , fmt .Errorf ("No vhost-vdpa device found in %s" , parentPath )
140
87
}
141
88
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
-
288
89
// ListVDPAMgmtDevices returns the list of all vDPA management devices.
289
90
func ListVDPAMgmtDevices () ([]* MgmtVDPADev , error ) {
290
- resp , err := runVDPANetlinkCmd ( vDPACmdMgmtDevGet , syscall . NLM_F_DUMP , nil )
91
+ netlinkDevices , err := netlink . VDPAGetMGMTDevList ( )
291
92
if err != nil {
292
93
return nil , err
293
94
}
294
95
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
+ })
298
102
}
299
103
300
- return mgtmDevs , nil
104
+ return devices , nil
301
105
}
302
106
303
107
// ListVDPADevices returns the list of all vDPA devices.
304
108
func ListVDPADevices () ([]* VDPADev , error ) {
305
- resp , err := runVDPANetlinkCmd ( vDPACmdDevGet , syscall . NLM_F_DUMP , nil )
109
+ netlinkDevices , err := netlink . VDPAGetDevList ( )
306
110
if err != nil {
307
111
return nil , err
308
112
}
309
113
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
+ })
313
127
}
314
128
315
129
return devices , nil
316
130
}
317
131
318
132
// AddVDPADevice adds a new vDPA device.
319
133
func AddVDPADevice (pciDevSlotName string , volatile map [string ]string ) (* VDPADev , error ) {
320
- // List existing vDPA devices
321
- vdpaDevs , err := ListVDPADevices ()
134
+ existingDevices , err := netlink .VDPAGetDevList ()
322
135
if err != nil {
323
136
return nil , err
324
137
}
325
138
326
139
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 {}{}
343
142
}
344
143
345
- header = append (header , mgmtDevDevName )
346
-
347
144
// Generate a unique attribute name for the vDPA device (i.e, vdpa0, vdpa1, etc.)
348
145
baseVDPAName , idx , generatedVDPADevName := "vdpa" , 0 , ""
349
146
for {
@@ -356,56 +153,35 @@ func AddVDPADevice(pciDevSlotName string, volatile map[string]string) (*VDPADev,
356
153
idx ++
357
154
}
358
155
359
- devName , err := newNetlinkAttribute (vDPAAttrDevName , generatedVDPADevName )
156
+ err = netlink .VDPANewDev (generatedVDPADevName , "pci" , pciDevSlotName , netlink.VDPANewDevParams {
157
+ MaxVQP : vDPAMaxVQP ,
158
+ })
360
159
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
376
161
}
377
162
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 )
380
164
if err != nil {
381
- return nil , fmt . Errorf ( "Failed getting vDPA device : %v" , err )
165
+ return nil , err
382
166
}
383
167
384
- vdpaDevs , err = parseVDPADevList ( msgs )
168
+ vhostVDPA , err := getVhostVDPADevInPath ( filepath . Join ( vdpaBusDevDir , dev . Name ) )
385
169
if err != nil {
386
- return nil , fmt . Errorf ( "Failed parsing vDPA device : %v" , err )
170
+ return nil , err
387
171
}
388
172
389
173
// Update the volatile map
390
174
volatile ["last_state.vdpa.name" ] = generatedVDPADevName
391
175
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
393
182
}
394
183
395
184
// DeleteVDPADevice deletes a vDPA management device.
396
185
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 )
411
187
}
0 commit comments