This adds support for testing host PCI device hotplug/unplug in
libvirt drivers. This requires that the host have a usable
IOMMU & hardware virt, and that the device in question can be
reset safely.
Since the TCK can't assume there are any host PCI devices that
can be safely messed around with, the person running the test
suite must first list one or more devices in the config file.
If no devices are listed, the test will automatically skip
all parts, rather than failing.
* conf/default.cfg: Config entry to specify PCI devices that the
TCK can mess around with
* lib/Sys/Virt/TCK.pm: API for getting a host PCI device from
the config
* scripts/domain/250-pci-host-hotplug.t: Test case for PCI
device hotplug/unplug.
---
conf/default.cfg | 15 ++++
lib/Sys/Virt/TCK.pm | 18 +++++
scripts/domain/250-pci-host-hotplug.t | 117 +++++++++++++++++++++++++++++++++
3 files changed, 150 insertions(+), 0 deletions(-)
create mode 100644 scripts/domain/250-pci-host-hotplug.t
diff --git a/conf/default.cfg b/conf/default.cfg
index f9c2b5c..5b85cbc 100644
--- a/conf/default.cfg
+++ b/conf/default.cfg
@@ -112,3 +112,18 @@ host_usb_devices = (
# }
# Can list more than one USB device if many are available
)
+
+
+# Host PCI devices that the test suite can safely mess around with
+# without risk of breaking the host OS. Using a NIC device is the
+# most reliable option. Definitely don't try listing a VGA device.
+host_pci_devices = (
+# Slot is only required entry, all others default to 0
+# {
+# domain = 0000
+# bus = 00
+# slot = 07
+# function = 0
+# }
+# Can list more than one PCI device if many are available
+)
diff --git a/lib/Sys/Virt/TCK.pm b/lib/Sys/Virt/TCK.pm
index ce03935..f101937 100644
--- a/lib/Sys/Virt/TCK.pm
+++ b/lib/Sys/Virt/TCK.pm
@@ -787,4 +787,22 @@ sub get_host_usb_device {
return ($bus, $device, $vendor, $product);
}
+sub get_host_pci_device {
+ my $self = shift;
+ my $devindex = @_ ? shift : 0;
+
+ my $devs = $self->config("host_pci_devices", []);
+
+ if ($devindex > $#{$devs}) {
+ return ();
+ }
+
+ my $domain = $self->config("host_pci_devices/[$devindex]/domain", 0);
+ my $bus = $self->config("host_pci_devices/[$devindex]/bus", 0);
+ my $slot = $self->config("host_pci_devices/[$devindex]/slot");
+ my $function = $self->config("host_pci_devices/[$devindex]/function",
0);
+
+ return ($domain, $bus, $slot, $function);
+}
+
1;
diff --git a/scripts/domain/250-pci-host-hotplug.t
b/scripts/domain/250-pci-host-hotplug.t
new file mode 100644
index 0000000..9ccd036
--- /dev/null
+++ b/scripts/domain/250-pci-host-hotplug.t
@@ -0,0 +1,117 @@
+# -*- perl -*-
+#
+# Copyright (C) 2009 Red Hat
+# Copyright (C) 2009 Daniel P. Berrange
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+domain/250-pci-host-hotplug.t - verify hot plug & unplug of a host PCI device
+
+=head1 DESCRIPTION
+
+The test case validates that it is possible to hotplug a pci
+host device to a running domain, and then unplug it again.
+This requires that the TCK configuration file have at least
+one host PCI device listed.
+
+This first searches for the node device, then detachs it from
+the host OS. Next it performs a reset. Then does the hotplug
+and unplug, before finally reattaching to the host.
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 10;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+
+my $xml = $tck->generic_domain("tck")->as_xml;
+
+diag "Creating a new transient domain";
+my $dom;
+ok_domain(sub { $dom = $conn->create_domain($xml) }, "created transient domain
object");
+
+
+my ($domain, $bus, $slot, $function) = $tck->get_host_pci_device();
+
+SKIP: {
+ # Must have one item be non-zero
+ unless ($domain || $bus || $slot || $function) {
+ skip "No host pci device available in configuration file", 9;
+ }
+
+ my $nodedev;
+ my @devs = $conn->list_node_devices("pci");
+ foreach my $dev (@devs) {
+ my $thisxml = $dev->get_xml_description();
+
+ my $xp = XML::XPath->new(xml => $thisxml);
+
+ #warn $thisxml;
+ my $ndomain =
$xp->find("string(/device/capability[\@type='pci']/domain[text()])")->value();
+ my $nbus =
$xp->find("string(/device/capability[\@type='pci']/bus[text()])")->value();
+ my $nslot =
$xp->find("string(/device/capability[\@type='pci']/slot[text()])")->value();
+ my $nfunction =
$xp->find("string(/device/capability[\@type='pci']/function[text()])")->value();
+
+ if ($ndomain == $domain &&
+ $nbus == $bus &&
+ $nslot == $slot &&
+ $nfunction == $function) {
+ $nodedev = $dev;
+ last;
+ }
+ }
+
+ ok(defined $nodedev, "found PCI device $domain:$bus:$slot.$function on
host");
+
+ lives_ok(sub { $nodedev->dettach() }, "detached device from host OS");
+ lives_ok(sub { $nodedev->reset() }, "reset the host PCI device");
+
+ my $devxml =
+ "<hostdev mode='subsystem' type='pci'
managed='no'>\n" .
+ " <source>\n" .
+ " <address domain='$domain' bus='$bus' slot='$slot'
function='$function'/>\n" .
+ " </source>\n" .
+ "</hostdev>\n";
+
+ my $initialxml = $dom->get_xml_description;
+
+ diag "Attaching the new dev $devxml";
+ lives_ok(sub { $dom->attach_device($devxml); }, "PCI dev has been
attached");
+
+ my $newxml = $dom->get_xml_description;
+ ok($newxml =~ m|<hostdev|, "new XML has extra PCI dev present");
+
+ diag "Detaching the new dev $devxml";
+ lives_ok(sub { $dom->detach_device($devxml); }, "PCI dev has been
detached");
+
+ lives_ok(sub { $nodedev->reset() }, "reset the host PCI device");
+ lives_ok(sub { $nodedev->reattach() }, "reattached device to host OS");
+
+ my $finalxml = $dom->get_xml_description;
+
+ is($initialxml, $finalxml, "final XML has removed the disk")
+}
+
--
1.6.5.2