github.com/vishvananda/netlink@v1.3.0/vdpa_linux.go (about) 1 package netlink 2 3 import ( 4 "fmt" 5 "net" 6 "syscall" 7 8 "golang.org/x/sys/unix" 9 10 "github.com/vishvananda/netlink/nl" 11 ) 12 13 type vdpaDevID struct { 14 Name string 15 ID uint32 16 } 17 18 // VDPADev contains info about VDPA device 19 type VDPADev struct { 20 vdpaDevID 21 VendorID uint32 22 MaxVQS uint32 23 MaxVQSize uint16 24 MinVQSize uint16 25 } 26 27 // VDPADevConfig contains configuration of the VDPA device 28 type VDPADevConfig struct { 29 vdpaDevID 30 Features uint64 31 NegotiatedFeatures uint64 32 Net VDPADevConfigNet 33 } 34 35 // VDPADevVStats conatins vStats for the VDPA device 36 type VDPADevVStats struct { 37 vdpaDevID 38 QueueIndex uint32 39 Vendor []VDPADevVStatsVendor 40 NegotiatedFeatures uint64 41 } 42 43 // VDPADevVStatsVendor conatins name and value for vendor specific vstat option 44 type VDPADevVStatsVendor struct { 45 Name string 46 Value uint64 47 } 48 49 // VDPADevConfigNet conatins status and net config for the VDPA device 50 type VDPADevConfigNet struct { 51 Status VDPADevConfigNetStatus 52 Cfg VDPADevConfigNetCfg 53 } 54 55 // VDPADevConfigNetStatus contains info about net status 56 type VDPADevConfigNetStatus struct { 57 LinkUp bool 58 Announce bool 59 } 60 61 // VDPADevConfigNetCfg contains net config for the VDPA device 62 type VDPADevConfigNetCfg struct { 63 MACAddr net.HardwareAddr 64 MaxVQP uint16 65 MTU uint16 66 } 67 68 // VDPAMGMTDev conatins info about VDPA management device 69 type VDPAMGMTDev struct { 70 BusName string 71 DevName string 72 SupportedClasses uint64 73 SupportedFeatures uint64 74 MaxVQS uint32 75 } 76 77 // VDPANewDevParams contains parameters for new VDPA device 78 // use SetBits to configure requried features for the device 79 // example: 80 // 81 // VDPANewDevParams{Features: SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)} 82 type VDPANewDevParams struct { 83 MACAddr net.HardwareAddr 84 MaxVQP uint16 85 MTU uint16 86 Features uint64 87 } 88 89 // SetBits set provided bits in the uint64 input value 90 // usage example: 91 // features := SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR) 92 func SetBits(input uint64, pos ...int) uint64 { 93 for _, p := range pos { 94 input |= 1 << uint64(p) 95 } 96 return input 97 } 98 99 // IsBitSet check if specific bit is set in the uint64 input value 100 // usage example: 101 // hasNetClass := IsBitSet(mgmtDev, VIRTIO_ID_NET) 102 func IsBitSet(input uint64, pos int) bool { 103 val := input & (1 << uint64(pos)) 104 return val > 0 105 } 106 107 // VDPANewDev adds new VDPA device 108 // Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]` 109 func VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error { 110 return pkgHandle.VDPANewDev(name, mgmtBus, mgmtName, params) 111 } 112 113 // VDPADelDev removes VDPA device 114 // Equivalent to: `vdpa dev del <name>` 115 func VDPADelDev(name string) error { 116 return pkgHandle.VDPADelDev(name) 117 } 118 119 // VDPAGetDevList returns list of VDPA devices 120 // Equivalent to: `vdpa dev show` 121 func VDPAGetDevList() ([]*VDPADev, error) { 122 return pkgHandle.VDPAGetDevList() 123 } 124 125 // VDPAGetDevByName returns VDPA device selected by name 126 // Equivalent to: `vdpa dev show <name>` 127 func VDPAGetDevByName(name string) (*VDPADev, error) { 128 return pkgHandle.VDPAGetDevByName(name) 129 } 130 131 // VDPAGetDevConfigList returns list of VDPA devices configurations 132 // Equivalent to: `vdpa dev config show` 133 func VDPAGetDevConfigList() ([]*VDPADevConfig, error) { 134 return pkgHandle.VDPAGetDevConfigList() 135 } 136 137 // VDPAGetDevConfigByName returns VDPA device configuration selected by name 138 // Equivalent to: `vdpa dev config show <name>` 139 func VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) { 140 return pkgHandle.VDPAGetDevConfigByName(name) 141 } 142 143 // VDPAGetDevVStats returns vstats for VDPA device 144 // Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>` 145 func VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) { 146 return pkgHandle.VDPAGetDevVStats(name, queueIndex) 147 } 148 149 // VDPAGetMGMTDevList returns list of mgmt devices 150 // Equivalent to: `vdpa mgmtdev show` 151 func VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) { 152 return pkgHandle.VDPAGetMGMTDevList() 153 } 154 155 // VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name 156 // Equivalent to: `vdpa mgmtdev show <bus>/<name>` 157 func VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) { 158 return pkgHandle.VDPAGetMGMTDevByBusAndName(bus, name) 159 } 160 161 type vdpaNetlinkMessage []syscall.NetlinkRouteAttr 162 163 func (id *vdpaDevID) parseIDAttribute(attr syscall.NetlinkRouteAttr) { 164 switch attr.Attr.Type { 165 case nl.VDPA_ATTR_DEV_NAME: 166 id.Name = nl.BytesToString(attr.Value) 167 case nl.VDPA_ATTR_DEV_ID: 168 id.ID = native.Uint32(attr.Value) 169 } 170 } 171 172 func (netStatus *VDPADevConfigNetStatus) parseStatusAttribute(value []byte) { 173 a := native.Uint16(value) 174 netStatus.Announce = (a & VIRTIO_NET_S_ANNOUNCE) > 0 175 netStatus.LinkUp = (a & VIRTIO_NET_S_LINK_UP) > 0 176 } 177 178 func (d *VDPADev) parseAttributes(attrs vdpaNetlinkMessage) { 179 for _, a := range attrs { 180 d.parseIDAttribute(a) 181 switch a.Attr.Type { 182 case nl.VDPA_ATTR_DEV_VENDOR_ID: 183 d.VendorID = native.Uint32(a.Value) 184 case nl.VDPA_ATTR_DEV_MAX_VQS: 185 d.MaxVQS = native.Uint32(a.Value) 186 case nl.VDPA_ATTR_DEV_MAX_VQ_SIZE: 187 d.MaxVQSize = native.Uint16(a.Value) 188 case nl.VDPA_ATTR_DEV_MIN_VQ_SIZE: 189 d.MinVQSize = native.Uint16(a.Value) 190 } 191 } 192 } 193 194 func (c *VDPADevConfig) parseAttributes(attrs vdpaNetlinkMessage) { 195 for _, a := range attrs { 196 c.parseIDAttribute(a) 197 switch a.Attr.Type { 198 case nl.VDPA_ATTR_DEV_NET_CFG_MACADDR: 199 c.Net.Cfg.MACAddr = a.Value 200 case nl.VDPA_ATTR_DEV_NET_STATUS: 201 c.Net.Status.parseStatusAttribute(a.Value) 202 case nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP: 203 c.Net.Cfg.MaxVQP = native.Uint16(a.Value) 204 case nl.VDPA_ATTR_DEV_NET_CFG_MTU: 205 c.Net.Cfg.MTU = native.Uint16(a.Value) 206 case nl.VDPA_ATTR_DEV_FEATURES: 207 c.Features = native.Uint64(a.Value) 208 case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES: 209 c.NegotiatedFeatures = native.Uint64(a.Value) 210 } 211 } 212 } 213 214 func (s *VDPADevVStats) parseAttributes(attrs vdpaNetlinkMessage) { 215 for _, a := range attrs { 216 s.parseIDAttribute(a) 217 switch a.Attr.Type { 218 case nl.VDPA_ATTR_DEV_QUEUE_INDEX: 219 s.QueueIndex = native.Uint32(a.Value) 220 case nl.VDPA_ATTR_DEV_VENDOR_ATTR_NAME: 221 s.Vendor = append(s.Vendor, VDPADevVStatsVendor{Name: nl.BytesToString(a.Value)}) 222 case nl.VDPA_ATTR_DEV_VENDOR_ATTR_VALUE: 223 if len(s.Vendor) == 0 { 224 break 225 } 226 s.Vendor[len(s.Vendor)-1].Value = native.Uint64(a.Value) 227 case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES: 228 s.NegotiatedFeatures = native.Uint64(a.Value) 229 } 230 } 231 } 232 233 func (d *VDPAMGMTDev) parseAttributes(attrs vdpaNetlinkMessage) { 234 for _, a := range attrs { 235 switch a.Attr.Type { 236 case nl.VDPA_ATTR_MGMTDEV_BUS_NAME: 237 d.BusName = nl.BytesToString(a.Value) 238 case nl.VDPA_ATTR_MGMTDEV_DEV_NAME: 239 d.DevName = nl.BytesToString(a.Value) 240 case nl.VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES: 241 d.SupportedClasses = native.Uint64(a.Value) 242 case nl.VDPA_ATTR_DEV_SUPPORTED_FEATURES: 243 d.SupportedFeatures = native.Uint64(a.Value) 244 case nl.VDPA_ATTR_DEV_MGMTDEV_MAX_VQS: 245 d.MaxVQS = native.Uint32(a.Value) 246 } 247 } 248 } 249 250 func (h *Handle) vdpaRequest(command uint8, extraFlags int, attrs []*nl.RtAttr) ([]vdpaNetlinkMessage, error) { 251 f, err := h.GenlFamilyGet(nl.VDPA_GENL_NAME) 252 if err != nil { 253 return nil, err 254 } 255 req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_ACK|extraFlags) 256 req.AddData(&nl.Genlmsg{ 257 Command: command, 258 Version: nl.VDPA_GENL_VERSION, 259 }) 260 for _, a := range attrs { 261 req.AddData(a) 262 } 263 264 resp, err := req.Execute(unix.NETLINK_GENERIC, 0) 265 if err != nil { 266 return nil, err 267 } 268 messages := make([]vdpaNetlinkMessage, 0, len(resp)) 269 for _, m := range resp { 270 attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) 271 if err != nil { 272 return nil, err 273 } 274 messages = append(messages, attrs) 275 } 276 return messages, nil 277 } 278 279 // dump all devices if dev is nil 280 func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) { 281 var extraFlags int 282 var attrs []*nl.RtAttr 283 if dev != nil { 284 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev))) 285 } else { 286 extraFlags = extraFlags | unix.NLM_F_DUMP 287 } 288 messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs) 289 if err != nil { 290 return nil, err 291 } 292 devs := make([]*VDPADev, 0, len(messages)) 293 for _, m := range messages { 294 d := &VDPADev{} 295 d.parseAttributes(m) 296 devs = append(devs, d) 297 } 298 return devs, nil 299 } 300 301 // dump all devices if dev is nil 302 func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) { 303 var extraFlags int 304 var attrs []*nl.RtAttr 305 if dev != nil { 306 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev))) 307 } else { 308 extraFlags = extraFlags | unix.NLM_F_DUMP 309 } 310 messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs) 311 if err != nil { 312 return nil, err 313 } 314 cfgs := make([]*VDPADevConfig, 0, len(messages)) 315 for _, m := range messages { 316 cfg := &VDPADevConfig{} 317 cfg.parseAttributes(m) 318 cfgs = append(cfgs, cfg) 319 } 320 return cfgs, nil 321 } 322 323 // dump all devices if dev is nil 324 func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) { 325 var extraFlags int 326 var attrs []*nl.RtAttr 327 if dev != nil { 328 attrs = append(attrs, 329 nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(*dev)), 330 ) 331 if bus != nil { 332 attrs = append(attrs, 333 nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(*bus)), 334 ) 335 } 336 } else { 337 extraFlags = extraFlags | unix.NLM_F_DUMP 338 } 339 messages, err := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs) 340 if err != nil { 341 return nil, err 342 } 343 cfgs := make([]*VDPAMGMTDev, 0, len(messages)) 344 for _, m := range messages { 345 cfg := &VDPAMGMTDev{} 346 cfg.parseAttributes(m) 347 cfgs = append(cfgs, cfg) 348 } 349 return cfgs, nil 350 } 351 352 // VDPANewDev adds new VDPA device 353 // Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]` 354 func (h *Handle) VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error { 355 attrs := []*nl.RtAttr{ 356 nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)), 357 nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(mgmtName)), 358 } 359 if mgmtBus != "" { 360 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(mgmtBus))) 361 } 362 if len(params.MACAddr) != 0 { 363 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MACADDR, params.MACAddr)) 364 } 365 if params.MaxVQP > 0 { 366 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP, nl.Uint16Attr(params.MaxVQP))) 367 } 368 if params.MTU > 0 { 369 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MTU, nl.Uint16Attr(params.MTU))) 370 } 371 if params.Features > 0 { 372 attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_FEATURES, nl.Uint64Attr(params.Features))) 373 } 374 _, err := h.vdpaRequest(nl.VDPA_CMD_DEV_NEW, 0, attrs) 375 return err 376 } 377 378 // VDPADelDev removes VDPA device 379 // Equivalent to: `vdpa dev del <name>` 380 func (h *Handle) VDPADelDev(name string) error { 381 _, err := h.vdpaRequest(nl.VDPA_CMD_DEV_DEL, 0, []*nl.RtAttr{ 382 nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name))}) 383 return err 384 } 385 386 // VDPAGetDevList returns list of VDPA devices 387 // Equivalent to: `vdpa dev show` 388 func (h *Handle) VDPAGetDevList() ([]*VDPADev, error) { 389 return h.vdpaDevGet(nil) 390 } 391 392 // VDPAGetDevByName returns VDPA device selected by name 393 // Equivalent to: `vdpa dev show <name>` 394 func (h *Handle) VDPAGetDevByName(name string) (*VDPADev, error) { 395 devs, err := h.vdpaDevGet(&name) 396 if err != nil { 397 return nil, err 398 } 399 if len(devs) == 0 { 400 return nil, fmt.Errorf("device not found") 401 } 402 return devs[0], nil 403 } 404 405 // VDPAGetDevConfigList returns list of VDPA devices configurations 406 // Equivalent to: `vdpa dev config show` 407 func (h *Handle) VDPAGetDevConfigList() ([]*VDPADevConfig, error) { 408 return h.vdpaDevConfigGet(nil) 409 } 410 411 // VDPAGetDevConfigByName returns VDPA device configuration selected by name 412 // Equivalent to: `vdpa dev config show <name>` 413 func (h *Handle) VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) { 414 cfgs, err := h.vdpaDevConfigGet(&name) 415 if err != nil { 416 return nil, err 417 } 418 if len(cfgs) == 0 { 419 return nil, fmt.Errorf("configuration not found") 420 } 421 return cfgs[0], nil 422 } 423 424 // VDPAGetDevVStats returns vstats for VDPA device 425 // Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>` 426 func (h *Handle) VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) { 427 messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_VSTATS_GET, 0, []*nl.RtAttr{ 428 nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)), 429 nl.NewRtAttr(nl.VDPA_ATTR_DEV_QUEUE_INDEX, nl.Uint32Attr(queueIndex)), 430 }) 431 if err != nil { 432 return nil, err 433 } 434 if len(messages) == 0 { 435 return nil, fmt.Errorf("stats not found") 436 } 437 stats := &VDPADevVStats{} 438 stats.parseAttributes(messages[0]) 439 return stats, nil 440 } 441 442 // VDPAGetMGMTDevList returns list of mgmt devices 443 // Equivalent to: `vdpa mgmtdev show` 444 func (h *Handle) VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) { 445 return h.vdpaMGMTDevGet(nil, nil) 446 } 447 448 // VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name 449 // Equivalent to: `vdpa mgmtdev show <bus>/<name>` 450 func (h *Handle) VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) { 451 var busPtr *string 452 if bus != "" { 453 busPtr = &bus 454 } 455 devs, err := h.vdpaMGMTDevGet(busPtr, &name) 456 if err != nil { 457 return nil, err 458 } 459 if len(devs) == 0 { 460 return nil, fmt.Errorf("mgmtdev not found") 461 } 462 return devs[0], nil 463 }