---
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