--- node_device.go | 310 +++++++++++++++++++++++++++++++++++++++++++++++ node_device_test.go | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 647 insertions(+) create mode 100644 node_device.go create mode 100644 node_device_test.go diff --git a/node_device.go b/node_device.go new file mode 100644 index 0000000..cc40451 --- /dev/null +++ b/node_device.go @@ -0,0 +1,310 @@ +/* + * This file is part of the libvirt-go-xml project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Copyright (C) 2017 Red Hat, Inc. + * + */ + +package libvirtxml + +import ( + "encoding/xml" +) + +type NodeDevice struct { + Name string `xml:"name"` + Path string `xml:"path,omitempty"` + Parent string `xml:"parent,omitempty"` + Driver string `xml:"driver>name,omitempty"` + Capability interface{} `xml:"capability"` +} + +type NodeDeviceVendor struct { + ID string `xml:"id,attr,omitempty"` + Name string `xml:",chardata"` +} +type NodeDeviceProduct struct { + ID string `xml:"id,attr,omitempty"` + Name string `xml:",chardata"` +} + +type NodeDevicePciExpress struct { + Links []NodeDevicePciExpressLink `xml:"link"` +} + +type NodeDevicePciExpressLink struct { + Validity string `xml:"validity,attr,omitempty"` + Speed float64 `xml:"speed,attr,omitempty"` + Port int `xml:"port,attr,omitempty"` + Width int `xml:"width,attr,omitempty"` +} + +type NodeDeviceIOMMUGroup struct { + Number int `xml:"number,attr"` +} + +type NodeDeviceNUMA struct { + Node int `xml:"node,attr"` +} + +type NodeDevicePCIAddress struct { + Domain string `xml:"domain,attr"` + Bus string `xml:"bus,attr"` + Slot string `xml:"slot,attr"` + Function string `xml:"function,attr"` +} + +type NodeDeviceSystemHardware struct { + Vendor string `xml:"vendor"` + Version string `xml:"version"` + Serial string `xml:"serial"` + UUID string `xml:"uuid"` +} + +type NodeDeviceSystemFirmware struct { + Vendor string `xml:"vendor"` + Version string `xml:"version"` + ReleaseDate string `xml:"release_date"` +} + +type NodeDeviceNetOffloadFeatures struct { + Name string `xml:"name,attr"` +} + +type NodeDeviceNetLink struct { + State string `xml:"state,attr"` + Speed string `xml:"speed,attr,omitempty"` +} + +type NodeDevicePciCapability struct { + Domain int `xml:"domain,omitempty"` + Bus int `xml:"bus,omitempty"` + Slot int `xml:"slot,omitempty"` + Function int `xml:"function,omitempty"` + Product *NodeDeviceProduct `xml:"product,omitempty"` + Vendor *NodeDeviceVendor `xml:"vendor,omitempty"` + IommuGroup *NodeDeviceIOMMUGroup `xml:"iommuGroup,omitempty"` + Numa *NodeDeviceNUMA `xml:"numa,omitempty"` + PciExpress *NodeDevicePciExpress `xml:"pci-express,omitempty"` + Capability []NodeDeviceNestedPciCapability `xml:"capability,omitempty"` +} + +type NodeDeviceNestedPciCapability struct { + Type string `xml:"type,attr"` + Address []NodeDevicePCIAddress `xml:"address,omitempty"` + MaxCount int `xml:"maxCount,attr,omitempty"` +} + +type NodeDeviceSystemCapability struct { + Product string `xml:"product"` + Hardware *NodeDeviceSystemHardware `xml:"hardware"` + Firmware *NodeDeviceSystemFirmware `xml:"firmware"` +} + +type NodeDeviceUSBDeviceCapability struct { + Bus int `xml:"bus"` + Device int `xml:"device"` + Product *NodeDeviceProduct `xml:"product,omitempty"` + Vendor *NodeDeviceVendor `xml:"vendor,omitempty"` +} + +type NodeDeviceUSBCapability struct { + Number int `xml:"number"` + Class int `xml:"class"` + Subclass int `xml:"subclass"` + Protocol int `xml:"protocol"` + Description string `xml:"description,omitempty"` +} + +type NodeDeviceNetCapability struct { + Interface string `xml:"interface"` + Address string `xml:"address"` + Link *NodeDeviceNetLink `xml:"link"` + Features []NodeDeviceNetOffloadFeatures `xml:"feature,omitempty"` + Capability *NodeDeviceNestedNetCapability `xml:"capability"` +} + +type NodeDeviceNestedNetCapability struct { + Type string `xml:"type,attr"` +} + +type NodeDeviceSCSIHostCapability struct { + Host int `xml:"host"` + UniqueID int `xml:"unique_id"` + Capability []NodeDeviceNestedSCSIHostCapability `xml:"capability"` +} + +type NodeDeviceNestedSCSIHostCapability struct { + Type string `xml:"type,attr"` + Vports int `xml:"vports,omitempty"` + MaxVports int `xml:"maxvports,,omitempty"` + WWNN string `xml:"wwnn,omitempty"` + WWPN string `xml:"wwpn,omitempty"` + FabricWWN string `xml:"fabric_wwn,omitempty"` +} + +type NodeDeviceSCSICapability struct { + Host int `xml:"host"` + Bus int `xml:"bus"` + Target int `xml:"target"` + Lun int `xml:"lun"` + Type string `xml:"type"` +} + +type NodeDeviceNestedStorageCapability struct { + Type string `xml:"type,attr"` + MediaAvailable int `xml:"media_available,omitempty"` + MediaSize int `xml:"media_size,omitempty"` + MediaLable int `xml:"media_label,omitempty"` +} + +type NodeDeviceStorageCapability struct { + Block string `xml:"block"` + Bus string `xml:"bus"` + DriverType string `xml:"drive_type"` + Model string `xml:"model"` + Vendor string `xml:"vendor"` + Serial string `xml:"serial,omitempty"` + Size int `xml:"size,omitempty"` + Capability *NodeDeviceNestedStorageCapability `xml:"capability,omitempty"` +} + +type NodeDeviceDRMCapability struct { + Type string `xml:"type"` +} + +func (c *NodeDevice) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + + for { + t, err := d.Token() + if err != nil { + return err + } + switch token := t.(type) { + case xml.StartElement: + switch token.Name.Local { + case "name": + var content string + if err := d.DecodeElement(&content, &start); err != nil { + return err + } + c.Name = content + case "path": + var content string + if err := d.DecodeElement(&content, &start); err != nil { + return err + } + c.Path = content + case "parent": + var content string + if err := d.DecodeElement(&content, &start); err != nil { + return err + } + c.Parent = content + case "driver": + tmp := struct { + Name string `xml:"name"` + }{} + if err := d.DecodeElement(&tmp, &token); err != nil { + return err + } + c.Driver = tmp.Name + case "capability": + for _, attr := range token.Attr { + if attr.Name.Local == "type" { + switch attr.Value { + case "pci": + var pciCaps NodeDevicePciCapability + if err := d.DecodeElement(&pciCaps, &token); err != nil { + return err + } + c.Capability = pciCaps + case "system": + var systemCaps NodeDeviceSystemCapability + if err := d.DecodeElement(&systemCaps, &token); err != nil { + return err + } + c.Capability = systemCaps + case "usb_device": + var usbdevCaps NodeDeviceUSBDeviceCapability + if err := d.DecodeElement(&usbdevCaps, &token); err != nil { + return err + } + c.Capability = usbdevCaps + case "usb": + var usbCaps NodeDeviceUSBCapability + if err := d.DecodeElement(&usbCaps, &token); err != nil { + return err + } + c.Capability = usbCaps + case "net": + var netCaps NodeDeviceNetCapability + if err := d.DecodeElement(&netCaps, &token); err != nil { + return err + } + c.Capability = netCaps + case "scsi_host": + var scsiHostCaps NodeDeviceSCSIHostCapability + if err := d.DecodeElement(&scsiHostCaps, &token); err != nil { + return err + } + c.Capability = scsiHostCaps + case "scsi": + var scsiCaps NodeDeviceSCSICapability + if err := d.DecodeElement(&scsiCaps, &token); err != nil { + return err + } + c.Capability = scsiCaps + case "storage": + var storageCaps NodeDeviceStorageCapability + if err := d.DecodeElement(&storageCaps, &token); err != nil { + return err + } + c.Capability = storageCaps + case "drm": + var drmCaps NodeDeviceDRMCapability + if err := d.DecodeElement(&drmCaps, &token); err != nil { + return err + } + c.Capability = drmCaps + } + } + } + } + case xml.EndElement: + return nil + } + } + + return nil +} + +func (c *NodeDevice) Unmarshal(doc string) error { + return xml.Unmarshal([]byte(doc), c) +} + +func (c *NodeDevice) Marshal() (string, error) { + doc, err := xml.MarshalIndent(c, "", " ") + if err != nil { + return "", err + } + return string(doc), nil +} diff --git a/node_device_test.go b/node_device_test.go new file mode 100644 index 0000000..a9f939e --- /dev/null +++ b/node_device_test.go @@ -0,0 +1,337 @@ +/* + * This file is part of the libvirt-go-xml project + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Copyright (C) 2017 Red Hat, Inc. + * + */ + +package libvirtxml + +import ( + "reflect" + "strings" + "testing" +) + +var NodeDeviceTestData = []struct { + Object *NodeDevice + XML []string +}{ + { + Object: &NodeDevice{ + Name: "pci_0000_81_00_0", + Parent: "pci_0000_80_01_0", + Driver: "ixgbe", + Capability: NodeDevicePciCapability{ + Domain: 1, + Bus: 21, + Slot: 10, + Function: 50, + Product: &NodeDeviceProduct{ + ID: "0x1528", + Name: "Ethernet Controller 10-Gigabit X540-AT2", + }, + Vendor: &NodeDeviceVendor{ + ID: "0x8086", + Name: "Intel Corporation", + }, + IommuGroup: &NodeDeviceIOMMUGroup{ + Number: 3, + }, + Numa: &NodeDeviceNUMA{ + Node: 1, + }, + Capability: []NodeDeviceNestedPciCapability{ + NodeDeviceNestedPciCapability{ + Type: "virt_functions", + Address: []NodeDevicePCIAddress{ + NodeDevicePCIAddress{ + Domain: "0x0000", + Bus: "0x81", + Slot: "0x10", + Function: "0x1", + }, + NodeDevicePCIAddress{ + Domain: "0x0000", + Bus: "0x81", + Slot: "0x10", + Function: "0x3", + }, + }, + MaxCount: 63, + }, + }, + }, + }, + XML: []string{ + `<device>`, + ` <name>pci_0000_81_00_0</name>`, + ` <parent>pci_0000_80_01_0</parent>`, + ` <driver>`, + ` <name>ixgbe</name>`, + ` </driver>`, + ` <capability type='pci'>`, + ` <domain>1</domain>`, + ` <bus>21</bus>`, + ` <slot>10</slot>`, + ` <function>50</function>`, + ` <product id='0x1528'>Ethernet Controller 10-Gigabit X540-AT2</product>`, + ` <vendor id='0x8086'>Intel Corporation</vendor>`, + ` <capability type='virt_functions' maxCount='63'>`, + ` <address domain='0x0000' bus='0x81' slot='0x10' function='0x1'/>`, + ` <address domain='0x0000' bus='0x81' slot='0x10' function='0x3'/>`, + ` </capability>`, + ` <iommuGroup number='3'>`, + ` <address domain='0x0000' bus='0x15' slot='0x00' function='0x4'/>`, + ` </iommuGroup>`, + ` <numa node='1'/>`, + ` </capability>`, + `</device>`, + }, + }, + { + Object: &NodeDevice{ + Name: "pci_10df_fe00_0_scsi_host", + Parent: "pci_10df_fe00_0", + Capability: NodeDeviceSCSIHostCapability{ + Host: 4, + Capability: []NodeDeviceNestedSCSIHostCapability{ + NodeDeviceNestedSCSIHostCapability{ + Type: "fc_host", + WWNN: "20000000c9848141", + WWPN: "10000000c9848141", + }, + NodeDeviceNestedSCSIHostCapability{ + Type: "vport_ops", + }, + }, + }, + }, + XML: []string{ + `<device>`, + ` <name>pci_10df_fe00_0_scsi_host</name>`, + ` <parent>pci_10df_fe00_0</parent>`, + ` <capability type='scsi_host'>`, + ` <host>4</host>`, + ` <capability type='fc_host'>`, + ` <wwnn>20000000c9848141</wwnn>`, + ` <wwpn>10000000c9848141</wwpn>`, + ` </capability>`, + ` <capability type='vport_ops' />`, + ` </capability>`, + `</device>`, + }, + }, + { + Object: &NodeDevice{ + Name: "computer", + Capability: NodeDeviceSystemCapability{ + Hardware: &NodeDeviceSystemHardware{ + Vendor: "LENOVO", + Version: "ThinkPad T61", + Serial: "L3B2616", + UUID: "97e80381-494f-11cb-8e0e-cbc168f7d753", + }, + Firmware: &NodeDeviceSystemFirmware{ + Vendor: "LENOVO", + Version: "7LET51WW (1.21 )", + ReleaseDate: "08/22/2007", + }, + }, + }, + XML: []string{ + `<device>`, + ` <name>computer</name>`, + ` <capability type='system'>`, + ` <hardware>`, + ` <vendor>LENOVO</vendor>`, + ` <version>ThinkPad T61</version>`, + ` <serial>L3B2616</serial>`, + ` <uuid>97e80381-494f-11cb-8e0e-cbc168f7d753</uuid>`, + ` </hardware>`, + ` <firmware>`, + ` <vendor>LENOVO</vendor>`, + ` <version>7LET51WW (1.21 )</version>`, + ` <release_date>08/22/2007</release_date>`, + ` </firmware>`, + ` </capability>`, + `</device>`, + }, + }, + { + Object: &NodeDevice{ + Name: "usb_device_1d6b_1_0000_00_1a_0", + Parent: "pci_8086_2834", + Driver: "usb", + Capability: NodeDeviceUSBDeviceCapability{ + Bus: 3, + Device: 1, + Product: &NodeDeviceProduct{ + ID: "0x0001", + Name: "1.1 root hub", + }, + Vendor: &NodeDeviceVendor{ + ID: "0x1d6b", + Name: "Linux Foundation", + }, + }, + }, + XML: []string{ + `<device>`, + ` <name>usb_device_1d6b_1_0000_00_1a_0</name>`, + ` <parent>pci_8086_2834</parent>`, + ` <driver>`, + ` <name>usb</name>`, + ` </driver>`, + ` <capability type='usb_device'>`, + ` <bus>3</bus>`, + ` <device>1</device>`, + ` <product id='0x0001'>1.1 root hub</product>`, + ` <vendor id='0x1d6b'>Linux Foundation</vendor>`, + ` </capability>`, + `</device>`, + }, + }, + { + Object: &NodeDevice{ + Name: "usb_device_1d6b_1_0000_00_1a_0_if0", + Parent: "usb_device_1d6b_1_0000_00_1a_0", + Driver: "hub", + Capability: NodeDeviceUSBCapability{ + Number: 0, + Class: 9, + Subclass:0, + Protocol: 0, + }, + }, + XML: []string{ + `<device>`, + ` <name>usb_device_1d6b_1_0000_00_1a_0_if0</name>`, + ` <parent>usb_device_1d6b_1_0000_00_1a_0</parent>`, + ` <driver>`, + ` <name>hub</name>`, + ` </driver>`, + ` <capability type='usb'>`, + ` <number>0</number>`, + ` <class>9</class>`, + ` <subclass>0</subclass>`, + ` <protocol>0</protocol>`, + ` </capability>`, + `</device>`, + }, + }, + { + Object: &NodeDevice{ + Name: "net_wlp3s0_4c_eb_42_aa_aa_82", + Path: "/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0", + Parent: "pci_0000_03_00_0", + Capability: NodeDeviceNetCapability{ + Interface: "wlp3s0", + Address: "4c:eb:42:aa:aa:82", + Link: &NodeDeviceNetLink{ + State: "up", + }, + Features: []NodeDeviceNetOffloadFeatures{ + NodeDeviceNetOffloadFeatures{ + Name: "sg", + }, + NodeDeviceNetOffloadFeatures{ + Name: "gso", + }, + NodeDeviceNetOffloadFeatures{ + Name: "gro", + }, + }, + Capability: &NodeDeviceNestedNetCapability{ + Type: "80211", + }, + }, + }, + XML: []string{ + `<device>`, + ` <name>net_wlp3s0_4c_eb_42_aa_aa_82</name>`, + ` <path>/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0</path>`, + ` <parent>pci_0000_03_00_0</parent>`, + ` <capability type='net'>`, + ` <interface>wlp3s0</interface>`, + ` <address>4c:eb:42:aa:aa:82</address>`, + ` <link state='up'/>`, + ` <feature name='sg'/>`, + ` <feature name='gso'/>`, + ` <feature name='gro'/>`, + ` <capability type='80211'/>`, + ` </capability>`, + `</device>`, + }, + }, + { + Object: &NodeDevice{ + Name: "storage_model_DVDRAM_GSA_U10N", + Parent: "pci_8086_2850_scsi_host_scsi_device_lun0", + Capability: NodeDeviceStorageCapability{ + Block: "/dev/sr1", + Bus: "pci", + DriverType: "cdrom", + Model:"DVDRAM GSA-U10N", + Vendor: "HL-DT-ST", + Capability: &NodeDeviceNestedStorageCapability{ + Type: "removable", + MediaAvailable: 0, + MediaSize: 0, + }, + }, + }, + XML: []string{ + `<device>`, + ` <name>storage_model_DVDRAM_GSA_U10N</name>`, + ` <parent>pci_8086_2850_scsi_host_scsi_device_lun0</parent>`, + ` <capability type='storage'>`, + ` <block>/dev/sr1</block>`, + ` <bus>pci</bus>`, + ` <drive_type>cdrom</drive_type>`, + ` <model>DVDRAM GSA-U10N</model>`, + ` <vendor>HL-DT-ST</vendor>`, + ` <capability type='removable'>`, + ` <media_available>0</media_available>`, + ` <media_size>0</media_size>`, + ` </capability>`, + ` </capability>`, + `</device>`, + }, + }, + +} + +func TestNodeDevice(t *testing.T) { + for _, test := range NodeDeviceTestData { + xmlDoc := strings.Join(test.XML, "\n") + nodeDevice := NodeDevice{} + err := nodeDevice.Unmarshal(xmlDoc) + if err != nil { + t.Fatal(err) + } + + res := reflect.DeepEqual(&nodeDevice, test.Object) + if !res { + t.Fatal("Bad NodeDevice object creation.", "\nExpected: ", test.Object, "\nActual: ", nodeDevice) + } + } +} -- 2.9.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list