Investigating MAC Address Conflict Resolution in libvirt: Log
Analysis and Code Location Inquiry
by Xuda Zhang
Dear Team,
I am reaching out regarding an issue I encountered with libvirt and MAC
address conflicts. Below is a summary of the situation:
1. Initially, the vNIC's MAC address was different from the target VM's
MAC address.
2. After modifying the vNIC's MAC address to match the VM's MAC address,
the network was interrupted.
3. After rebooting the VM, the vNIC's MAC address was automatically
modified again.
I have observed the following kernel logs during this process:
Dec 24 16:59:40 zstack-manager kernel: br_enp2s0: port 14(vnic43.0)
entered disabled stateDec 24 16:59:40 zstack-manager kernel: device
vnic43.0 left promiscuous modeDec 24 16:59:40 zstack-manager kernel:
br_enp2s0: port 14(vnic43.0) entered disabled stateDec 24 17:00:11
zstack-manager kernel: br_enp2s0: port 14(vnic43.0) entered blocking
stateDec 24 17:00:11 zstack-manager kernel: br_enp2s0: port
14(vnic43.0) entered disabled stateDec 24 17:00:11 zstack-manager
kernel: device vnic43.0 entered promiscuous modeDec 24 17:00:11
zstack-manager kernel: br_enp2s0: port 14(vnic43.0) entered blocking
stateDec 24 17:00:11 zstack-manager kernel: br_enp2s0: port
14(vnic43.0) entered forwarding state
I am looking to understand the underlying code that handles the automatic
modification of the vNIC's MAC address after the conflict and how the
network interruption occurs. Can you help direct me to the relevant code
segment or provide any insights into this behavior?
Thank you for your assistance.
Best regards,
4 hours, 19 minutes
[PATCH v3 00/17] hw/microblaze: Allow running cross-endian vCPUs
by Philippe Mathieu-Daudé
Missing review: 4 (new) & 10
Since v2:
- Addressed Richard's review comments
Since v1:
- Make device endianness configurable (Edgar)
- Convert more Xilinx devices
- Avoid preprocessor #if (Richard)
- Add R-b tags
Make machines endianness-agnostic, allowing to run a big-endian vCPU
on the little-endian 'qemu-system-microblazeel' binary, and a little
endian one on the big-endian 'qemu-system-microblaze' binary.
Tests added, following combinations covered:
- little-endian vCPU using little-endian binary (in-tree)
- little-endian vCPU using big-endian binary (new)
- big-endian vCPU using little-endian binary (new)
- big-endian vCPU using big-endian binary (in-tree)
To make a target endian-agnostic we need to remove the MO_TE uses.
In order to do that, we propagate the MemOp from earlier in the
call stack, or we extract it from the vCPU env (on MicroBlaze the
CPU endianness is exposed by the 'ENDI' bit).
Next step: Look at unifying binaries.
Please review,
Phil.
Philippe Mathieu-Daudé (17):
hw/microblaze: Restrict MemoryRegionOps are implemented as 32-bit
hw/microblaze: Propagate CPU endianness to microblaze_load_kernel()
hw/intc/xilinx_intc: Make device endianness configurable
RFC hw/net/xilinx_ethlite: Simplify by having configurable endianness
RFC hw/timer/xilinx_timer: Allow down to 8-bit memory access
hw/timer/xilinx_timer: Make device endianness configurable
hw/char/xilinx_uartlite: Make device endianness configurable
hw/ssi/xilinx_spi: Make device endianness configurable
hw/ssi/xilinx_spips: Make device endianness configurable
hw/arm/xlnx-zynqmp: Use &error_abort for programming errors
target/microblaze: Explode MO_TExx -> MO_TE | MO_xx
target/microblaze: Set MO_TE once in do_load() / do_store()
target/microblaze: Introduce mo_endian() helper
target/microblaze: Consider endianness while translating code
hw/microblaze: Support various endianness for s3adsp1800 machines
tests/functional: Explicit endianness of microblaze assets
tests/functional: Add microblaze cross-endianness tests
hw/microblaze/boot.h | 4 +-
include/hw/ssi/xilinx_spips.h | 1 +
target/microblaze/cpu.h | 7 +++
hw/arm/xilinx_zynq.c | 1 +
hw/arm/xlnx-zynqmp.c | 40 +++++--------
hw/char/xilinx_uartlite.c | 31 ++++++----
hw/intc/xilinx_intc.c | 50 ++++++++++++----
hw/microblaze/boot.c | 8 +--
hw/microblaze/petalogix_ml605_mmu.c | 4 +-
hw/microblaze/petalogix_s3adsp1800_mmu.c | 58 ++++++++++++++++---
hw/microblaze/xlnx-zynqmp-pmu.c | 2 +-
hw/net/xilinx_ethlite.c | 42 +++++++++-----
hw/ppc/virtex_ml507.c | 1 +
hw/ssi/xilinx_spi.c | 24 +++++---
hw/ssi/xilinx_spips.c | 36 +++++++-----
hw/timer/xilinx_timer.c | 33 +++++++----
target/microblaze/translate.c | 49 ++++++++++------
.../functional/test_microblaze_s3adsp1800.py | 27 ++++++++-
.../test_microblazeel_s3adsp1800.py | 25 +++++++-
19 files changed, 309 insertions(+), 134 deletions(-)
--
2.45.2
10 hours, 38 minutes
[PATCH 00/26] integrate auto-shutdown of VMs with daemons
by Daniel P. Berrangé
This series starts the work needed to obsolete the libvirt-guests.sh
script which has grown a surprisingly large amount of functionality.
Currently the virt daemons will acquire inhibitors to delay OS shutdown
when VMs are running. The libvirt-guests.service unit can be used to
call libvirt-guests.sh to shutdown running VMs on system shutdown.
This split is a bad architecture because libvirt-guests.service will
only run once the system has decided to initiate the shutdown sequence.
When the user requests as shutdown while inhibitors are present, logind
will emit a "PrepareForShutdown" signal over dbus. Applications are
supposed to respond to this by preserving state & releasing their
inhibitors, which in turns allows shutdown to be initiated.
The remote daemon already has support for listening for the
"PrepareForShutdown" signal, but only does this for session instances,
not system instances.
This series essentially takes that logic and expands it to run in the
system instances too, thus conceptually making libvirt-guests.service
obsolete.
It is slightly more complicated than that though for many reasons...
Saving running VMs can take a very long time. The inhibitor delay
can be as low as 5 seconds, and when killing a service, systemd may
not wait very long for it to terminate. libvirt-guests.service deals
with this by setting TimeoutStopSecs=0 to make systemd wait forever.
This is undesirable to set in libvirtd.service though, as we would
like systemd to kill the daemon aggressively if it hangs. The series
thus uses the notification protocol to request systemd give it more
time to shutdown, as long as we're in the phase of saving running
VMs. A bug in this code will still result in systemd waiting forever,
which is no different from libvirt-guests.service, but a bug in any
other part of the libvirt daemon shutdown code will result in systemd
killing us.
The existing logic for saving VMs in the session daemons had many
feature gaps compared to libvirt-guests.sh. Thus there is code to
add support
* Requesting graceful OS shutdown if managed save failed
* Force poweroff of VMs if no other action worked
* Optionally enabling/disabling use of managed save,
graceful shutdown and force poweroff, which is more flexible
than ON_SHUTDOWN=nnn, as we can try the whole sequence of
options
* Ability to bypass cache in managed save
* Support for one-time autostart of VMs as an official API
To aid in testing this logic, virt-admin gains a new command
'virt-admin daemon-shutdown --preserve'
All this new functionality is wired up into the QEMU driver, and is
made easily accessible to other hypervisor drivers, so would easily
be extendable to Xen, CH, LXC drivers, but this is not done in this
series. IOW, libvirt-guests.service is not yet fully obsolete.
The new functionality is also not enabled by default for the system
daemon, it requires explicit admin changes to /etc/libvirt/qemu.conf
to enable it. This is because it would clash with execution of the
libvirt-guests.service if both were enabled.
It is highly desirable that we enable this by default though, so we
need to figure out a upgrade story wrt libvirt-guests.service.
The only libvirt-guests.sh features not implemented are:
* PARALLEL_SHUTDOWN=nn.
When doing a graceful shutdown we initiate it on every single VM
at once, and then monitor progress of all of them in parallel.
* SYNC_TIME=nn
When make not attempt to sync guest time when restoring from
managed save. This ought to be fixed
Daniel P. Berrangé (26):
util: add APIs for more systemd notifications
remote: notify systemd when reloading config
hypervisor: introduce helper for autostart
src: convert drivers over to use new autostart helper
hypervisor: add support for delay interval during autostart
qemu: add 'auto_start_delay' configuration parameter
hypervisor: move support for auto-shutdown out of QEMU driver
remote: always invoke virStateStop for all daemons
hypervisor: expand available shutdown actions
hypervisor: custom shutdown actions for transient vs persistent VMs
qemu: support automatic VM managed save in system daemon
qemu: improve shutdown defaults for session daemon
qemu: configurable delay for shutdown before poweroff
hypervisor: support bypassing cache for managed save
qemu: add config parameter to control auto-save bypass cache
src: add new APIs for marking a domain to autostart once
conf: implement support for autostart once feature
hypervisor: wire up support for auto restore of running domains
qemu: wire up support for once only autostart
qemu: add config to control if auto-shutdown VMs are restored
rpc: move state stop into virNetDaemon class
rpc: don't unconditionally quit after preserving state
rpc: fix shutdown sequence when preserving state
admin: add 'daemon-shutdown' command
rpc: don't let systemd shutdown daemon while saving VMs
hypervisor: send systemd status messages while saving
include/libvirt/libvirt-admin.h | 13 ++
include/libvirt/libvirt-domain.h | 4 +
src/admin/admin_protocol.x | 11 +-
src/admin/admin_server_dispatch.c | 13 ++
src/admin/libvirt-admin.c | 33 ++++
src/admin/libvirt_admin_public.syms | 5 +
src/bhyve/bhyve_driver.c | 53 ++----
src/conf/domain_conf.c | 6 +-
src/conf/domain_conf.h | 1 +
src/conf/virdomainobjlist.c | 7 +-
src/driver-hypervisor.h | 10 ++
src/hypervisor/domain_driver.c | 250 ++++++++++++++++++++++++++++
src/hypervisor/domain_driver.h | 42 +++++
src/libvirt-domain.c | 87 ++++++++++
src/libvirt_private.syms | 10 +-
src/libvirt_public.syms | 6 +
src/libvirt_remote.syms | 2 +-
src/libxl/libxl_driver.c | 36 ++--
src/lxc/lxc_driver.c | 13 +-
src/lxc/lxc_process.c | 18 +-
src/lxc/lxc_process.h | 2 +
src/qemu/libvirtd_qemu.aug | 7 +
src/qemu/qemu.conf.in | 59 +++++++
src/qemu/qemu_conf.c | 63 +++++++
src/qemu/qemu_conf.h | 7 +
src/qemu/qemu_driver.c | 203 +++++++++++++---------
src/qemu/test_libvirtd_qemu.aug.in | 7 +
src/remote/libvirtd.service.in | 2 +-
src/remote/remote_daemon.c | 78 +++------
src/remote/remote_driver.c | 2 +
src/remote/remote_protocol.x | 30 +++-
src/remote_protocol-structs | 12 ++
src/rpc/gendispatch.pl | 4 +-
src/rpc/virnetdaemon.c | 212 +++++++++++++++++++----
src/rpc/virnetdaemon.h | 20 ++-
src/util/virsystemd.c | 41 ++++-
src/util/virsystemd.h | 6 +-
src/virtd.service.in | 2 +-
tools/virsh-domain-monitor.c | 5 +
tools/virsh-domain.c | 39 ++++-
tools/virt-admin.c | 41 +++++
41 files changed, 1181 insertions(+), 281 deletions(-)
--
2.47.1
1 day, 17 hours
[PATCH v5 00/18] *** qemu: block: Support block disk along with throttle filters ***
by Harikumar R
*** BLURB HERE ***
Chun Feng Wu (17):
schema: Add new domain elements to support multiple throttle groups
schema: Add new domain elements to support multiple throttle filters
config: Introduce ThrottleGroup and corresponding XML parsing
config: Introduce ThrottleFilter and corresponding XML parsing
qemu: monitor: Add support for ThrottleGroup operations
tests: Test qemuMonitorJSONGetThrottleGroup and
qemuMonitorJSONUpdateThrottleGroup
remote: New APIs for ThrottleGroup lifecycle management
qemu: Refactor qemuDomainSetBlockIoTune to extract common methods
qemu: Implement qemu driver for throttle API
qemu: helper: throttle filter nodename and preparation processing
qemu: block: Support block disk along with throttle filters
config: validate: Verify iotune, throttle group and filter
qemuxmlconftest: Add 'throttlefilter' tests
test_driver: Test throttle group lifecycle APIs
virsh: Refactor iotune options for re-use
virsh: Add support for throttle group operations
virsh: Add option "throttle-groups" to "attach_disk"
Harikumar Rajkumar (1):
tests: Test qemuxmlactivetestThrottleGroup
docs/formatdomain.rst | 47 ++
docs/manpages/virsh.rst | 135 +++-
include/libvirt/libvirt-domain.h | 21 +
src/conf/domain_conf.c | 398 ++++++++++
src/conf/domain_conf.h | 45 ++
src/conf/domain_validate.c | 119 ++-
src/conf/schemas/domaincommon.rng | 293 ++++----
src/conf/virconftypes.h | 4 +
src/driver-hypervisor.h | 22 +
src/libvirt-domain.c | 174 +++++
src/libvirt_private.syms | 8 +
src/libvirt_public.syms | 7 +
src/qemu/qemu_block.c | 136 ++++
src/qemu/qemu_block.h | 49 ++
src/qemu/qemu_command.c | 180 +++++
src/qemu/qemu_command.h | 6 +
src/qemu/qemu_domain.c | 73 +-
src/qemu/qemu_driver.c | 619 +++++++++++++---
src/qemu/qemu_hotplug.c | 33 +
src/qemu/qemu_monitor.c | 34 +
src/qemu/qemu_monitor.h | 14 +
src/qemu/qemu_monitor_json.c | 134 ++++
src/qemu/qemu_monitor_json.h | 14 +
src/remote/remote_daemon_dispatch.c | 44 ++
src/remote/remote_driver.c | 40 ++
src/remote/remote_protocol.x | 48 +-
src/remote_protocol-structs | 28 +
src/test/test_driver.c | 452 ++++++++----
tests/qemumonitorjsontest.c | 86 +++
.../throttlefilter-in.xml | 392 ++++++++++
.../throttlefilter-out.xml | 393 ++++++++++
tests/qemuxmlactivetest.c | 1 +
.../throttlefilter-invalid.x86_64-latest.err | 1 +
.../throttlefilter-invalid.xml | 89 +++
.../throttlefilter.x86_64-latest.args | 55 ++
.../throttlefilter.x86_64-latest.xml | 105 +++
tests/qemuxmlconfdata/throttlefilter.xml | 95 +++
tests/qemuxmlconftest.c | 2 +
tools/virsh-completer-domain.c | 82 +++
tools/virsh-completer-domain.h | 16 +
tools/virsh-domain.c | 680 ++++++++++++++----
41 files changed, 4649 insertions(+), 525 deletions(-)
create mode 100644 tests/qemustatusxml2xmldata/throttlefilter-in.xml
create mode 100644 tests/qemustatusxml2xmldata/throttlefilter-out.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter-invalid.x86_64-latest.err
create mode 100644 tests/qemuxmlconfdata/throttlefilter-invalid.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter.x86_64-latest.args
create mode 100644 tests/qemuxmlconfdata/throttlefilter.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/throttlefilter.xml
--
2.39.5 (Apple Git-154)
2 days
[PATCH 1/3] [bhyve] list pci devices on host
by Alexander Shursha
Linux gets the list via sysfs. FreeBSD can get the list through
ioctl
Sponsored by: Future Crew, LLC
Signed-off-by: Alexander Shursha <kekek2(a)ya.ru>
---
src/bhyve/bhyve_capabilities.c | 2 +-
src/conf/node_device_conf.c | 2 +-
src/node_device/node_device_driver.c | 2 +-
src/util/virmdev.c | 2 +-
src/util/virpci.c | 400 ++++++++++++++++++++++++++-
5 files changed, 399 insertions(+), 9 deletions(-)
diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c
index b065256cf0..fcef91c435 100644
--- a/src/bhyve/bhyve_capabilities.c
+++ b/src/bhyve/bhyve_capabilities.c
@@ -108,7 +108,7 @@ virBhyveDomainCapsFill(virDomainCaps *caps,
VIR_DOMAIN_CAPS_ENUM_SET(caps->video.modelType, VIR_DOMAIN_VIDEO_TYPE_GOP);
}
- caps->hostdev.supported = VIR_TRISTATE_BOOL_NO;
+ caps->hostdev.supported = VIR_TRISTATE_BOOL_YES;
caps->features[VIR_DOMAIN_CAPS_FEATURE_IOTHREADS] = VIR_TRISTATE_BOOL_NO;
caps->features[VIR_DOMAIN_CAPS_FEATURE_VMCOREINFO] = VIR_TRISTATE_BOOL_NO;
caps->features[VIR_DOMAIN_CAPS_FEATURE_GENID] = VIR_TRISTATE_BOOL_NO;
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 08a89942ba..39e6b78f3d 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -2836,7 +2836,7 @@ virNodeDeviceSyncMdevActiveConfig(virNodeDeviceDef *def)
}
}
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
int
virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHost *scsi_host)
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index fa5db0d5d5..282af02724 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -111,7 +111,7 @@ int nodeConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
return 1;
}
-#if defined (__linux__) && defined(WITH_UDEV)
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(WITH_UDEV)
/* NB: It was previously believed that changes in driver name were
* relayed to libvirt as "change" events by udev, and the udev event
* notification is setup to recognize such events and effectively
diff --git a/src/util/virmdev.c b/src/util/virmdev.c
index 6ecdbdf0ab..3a07ba75f2 100644
--- a/src/util/virmdev.c
+++ b/src/util/virmdev.c
@@ -565,7 +565,7 @@ virMediatedDeviceParentGetAddress(const char *sysfspath,
return -1;
}
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
ssize_t
virMediatedDeviceGetMdevTypes(const char *sysfspath,
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 90617e69c6..f954ce4df2 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -30,6 +30,13 @@
#include <sys/stat.h>
#include <unistd.h>
+#ifdef __FreeBSD__
+# ifdef WITH_BHYVE
+# include <libudev.h>
+# endif
+# include <sys/pciio.h>
+#endif
+
#ifdef __linux__
# include <sys/utsname.h>
#endif
@@ -72,7 +79,11 @@ struct _virPCIDevice {
char *name; /* domain:bus:slot.function */
char id[PCI_ID_LEN]; /* product vendor */
+#ifndef __FreeBSD__
char *path;
+#else
+ struct pci_match_conf patterns[1];
+#endif
/* The driver:domain which uses the device */
char *used_by_drvname;
@@ -99,6 +110,9 @@ struct _virPCIDevice {
bool unbind_from_stub;
bool remove_slot;
bool reprobe;
+#ifdef __FreeBSD__
+ u_int8_t pc_hdr; /* PCI header type */
+#endif
};
struct _virPCIDeviceList {
@@ -359,6 +373,7 @@ virPCIDeviceGetCurrentDriverNameAndType(virPCIDevice *dev,
}
+#ifndef __FreeBSD__
static int
virPCIDeviceConfigOpenInternal(virPCIDevice *dev, bool readonly, bool fatal)
{
@@ -429,6 +444,7 @@ virPCIDeviceRead(virPCIDevice *dev,
return 0;
}
+#endif
/**
* virPCIDeviceReadN:
@@ -450,6 +466,7 @@ virPCIDeviceRead(virPCIDevice *dev,
* and the return value is 0, then the config file really does contain
* the value 0 at @pos.
*/
+#ifndef __FreeBSD__
static uint8_t
virPCIDeviceRead8(virPCIDevice *dev, int cfgfd, unsigned int pos)
{
@@ -473,7 +490,56 @@ virPCIDeviceRead32(virPCIDevice *dev, int cfgfd, unsigned int pos)
virPCIDeviceRead(dev, cfgfd, pos, &buf[0], sizeof(buf));
return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}
+#else
+static int
+virPCIDeviceRead(virPCIDevice *dev, int pi_reg, int pi_width, u_int32_t *pi_data)
+{
+ struct pci_io pc;
+ int fd;
+
+ bzero(&pc, sizeof(struct pci_io));
+ pc.pi_sel.pc_domain = dev->address.domain;
+ pc.pi_sel.pc_bus = dev->address.bus;
+ pc.pi_sel.pc_dev = dev->address.slot;
+ pc.pi_sel.pc_func = dev->address.function;
+ pc.pi_reg = pi_reg;
+ pc.pi_width = pi_width;
+
+ fd = open("/dev/pci", O_RDWR, 0);
+ errno = 0;
+ if (ioctl(fd, PCIOCREAD, &pc) == -1) {
+ VIR_FORCE_CLOSE(fd);
+ VIR_WARN("Failed to read from '%s' : %s", dev->name, g_strerror(errno));
+ return -1;
+ }
+ VIR_FORCE_CLOSE(fd);
+ *pi_data = pc.pi_data;
+ return 0;
+}
+static uint8_t
+virPCIDeviceRead8(virPCIDevice *dev, int pi_reg)
+{
+ u_int32_t pi_data;
+ virPCIDeviceRead(dev, pi_reg, 1, &pi_data);
+ return pi_data & 0xff;
+}
+static uint16_t
+virPCIDeviceRead16(virPCIDevice *dev, int pi_reg)
+{
+ u_int32_t pi_data;
+ virPCIDeviceRead(dev, pi_reg, 2, &pi_data);
+ return pi_data & 0xffff;
+}
+
+static uint32_t
+virPCIDeviceRead32(virPCIDevice *dev, int pi_reg)
+{
+ u_int32_t pi_data;
+ virPCIDeviceRead(dev, pi_reg, 4, &pi_data);
+ return pi_data;
+}
+#endif
static int
virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class)
{
@@ -499,6 +565,7 @@ virPCIDeviceReadClass(virPCIDevice *dev, uint16_t *device_class)
return 0;
}
+#ifndef __FreeBSD__
static int
virPCIDeviceWrite(virPCIDevice *dev,
int cfgfd,
@@ -528,6 +595,44 @@ virPCIDeviceWrite32(virPCIDevice *dev, int cfgfd, unsigned int pos, uint32_t val
uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 24) };
virPCIDeviceWrite(dev, cfgfd, pos, &buf[0], sizeof(buf));
}
+#else
+static int
+virPCIDeviceWrite(virPCIDevice *dev, int pi_reg, int pi_width, u_int32_t pi_data)
+{
+ struct pci_io pc;
+ int fd;
+
+ bzero(&pc, sizeof(struct pci_io));
+ pc.pi_sel.pc_domain = dev->address.domain;
+ pc.pi_sel.pc_bus = dev->address.bus;
+ pc.pi_sel.pc_dev = dev->address.slot;
+ pc.pi_sel.pc_func = dev->address.function;
+ pc.pi_reg = pi_reg;
+ pc.pi_width = pi_width;
+ pc.pi_data = pi_data;
+
+ fd = open("/dev/pci", O_RDWR, 0);
+ errno = 0;
+ if (ioctl(fd, PCIOCWRITE, &pc) == -1) {
+ VIR_FORCE_CLOSE(fd);
+ VIR_WARN("Failed to write to '%s' : %s", dev->name, g_strerror(errno));
+ return -1;
+ }
+ VIR_FORCE_CLOSE(fd);
+ return 0;
+}
+static void
+virPCIDeviceWrite16(virPCIDevice *dev, int pi_reg, u_int16_t val)
+{
+ virPCIDeviceWrite(dev, pi_reg, 2, val);
+}
+
+static void
+virPCIDeviceWrite32(virPCIDevice *dev, int pi_reg, uint32_t val)
+{
+ virPCIDeviceWrite(dev, pi_reg, 4, val);
+}
+#endif
typedef int (*virPCIDeviceIterPredicate)(virPCIDevice *, virPCIDevice *,
void *);
@@ -610,7 +715,9 @@ virPCIDeviceIterDevices(virPCIDeviceIterPredicate predicate,
*/
static int
virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
+#ifndef __FreeBSD__
int cfgfd,
+#endif
unsigned int capability,
unsigned int *offset)
{
@@ -619,11 +726,19 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
*offset = 0; /* assume failure (*nothing* can be at offset 0) */
+#ifndef __FreeBSD__
status = virPCIDeviceRead16(dev, cfgfd, PCI_STATUS);
+#else
+ status = virPCIDeviceRead16(dev, PCI_STATUS);
+#endif
if (errno != 0 || !(status & PCI_STATUS_CAP_LIST))
goto error;
+#ifndef __FreeBSD__
pos = virPCIDeviceRead8(dev, cfgfd, PCI_CAPABILITY_LIST);
+#else
+ pos = virPCIDeviceRead8(dev, PCI_CAPABILITY_LIST);
+#endif
if (errno != 0)
goto error;
@@ -635,7 +750,11 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
* capabilities here.
*/
while (pos >= PCI_CONF_HEADER_LEN && pos != 0xff) {
+#ifndef __FreeBSD__
uint8_t capid = virPCIDeviceRead8(dev, cfgfd, pos);
+#else
+ uint8_t capid = virPCIDeviceRead8(dev, pos);
+#endif
if (errno != 0)
goto error;
@@ -646,7 +765,11 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
return 0;
}
+#ifndef __FreeBSD__
pos = virPCIDeviceRead8(dev, cfgfd, pos + 1);
+#else
+ pos = virPCIDeviceRead8(dev, pos + 1);
+#endif
if (errno != 0)
goto error;
}
@@ -665,7 +788,9 @@ virPCIDeviceFindCapabilityOffset(virPCIDevice *dev,
static unsigned int
virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
+#ifndef __FreeBSD__
int cfgfd,
+#endif
unsigned int capability)
{
int ttl;
@@ -677,7 +802,11 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
pos = PCI_EXT_CAP_BASE;
while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) {
+#ifndef __FreeBSD__
header = virPCIDeviceRead32(dev, cfgfd, pos);
+#else
+ header = virPCIDeviceRead32(dev, pos);
+#endif
if ((header & PCI_EXT_CAP_ID_MASK) == capability)
return pos;
@@ -693,7 +822,11 @@ virPCIDeviceFindExtendedCapabilityOffset(virPCIDevice *dev,
* not have FLR, 1 if it does, and -1 on error
*/
static bool
+#ifndef __FreeBSD__
virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
+#else
+virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev)
+#endif
{
uint32_t caps;
unsigned int pos;
@@ -707,7 +840,11 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
* on SR-IOV NICs at the moment.
*/
if (dev->pcie_cap_pos) {
+#ifndef __FreeBSD__
caps = virPCIDeviceRead32(dev, cfgfd, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
+#else
+ caps = virPCIDeviceRead32(dev, dev->pcie_cap_pos + PCI_EXP_DEVCAP);
+#endif
if (caps & PCI_EXP_DEVCAP_FLR) {
VIR_DEBUG("%s %s: detected PCIe FLR capability", dev->id, dev->name);
return true;
@@ -718,11 +855,19 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
* the same thing, except for conventional PCI
* devices. This is not common yet.
*/
+#ifndef __FreeBSD__
if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_AF, &pos) < 0)
+#else
+ if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_AF, &pos) < 0)
+#endif
goto error;
if (pos) {
+#ifndef __FreeBSD__
caps = virPCIDeviceRead16(dev, cfgfd, pos + PCI_AF_CAP);
+#else
+ caps = virPCIDeviceRead16(dev, pos + PCI_AF_CAP);
+#endif
if (caps & PCI_AF_CAP_FLR) {
VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name);
return true;
@@ -754,13 +899,21 @@ virPCIDeviceDetectFunctionLevelReset(virPCIDevice *dev, int cfgfd)
* internal reset, not just a soft reset.
*/
static bool
+#ifndef __FreeBSD__
virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev, int cfgfd)
+#else
+virPCIDeviceDetectPowerManagementReset(virPCIDevice *dev)
+#endif
{
if (dev->pci_pm_cap_pos) {
uint32_t ctl;
/* require the NO_SOFT_RESET bit is clear */
+#ifndef __FreeBSD__
ctl = virPCIDeviceRead32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+#else
+ ctl = virPCIDeviceRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+#endif
if (!(ctl & PCI_PM_CTRL_NO_SOFT_RESET)) {
VIR_DEBUG("%s %s: detected PM reset capability", dev->id, dev->name);
return true;
@@ -811,13 +964,17 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
uint8_t header_type, secondary, subordinate;
virPCIDevice **best = data;
int ret = 0;
+#ifndef __FreeBSD__
int fd;
+#endif
if (dev->address.domain != check->address.domain)
return 0;
+#ifndef __FreeBSD__
if ((fd = virPCIDeviceConfigOpenTry(check)) < 0)
return 0;
+#endif
/* Is it a bridge? */
ret = virPCIDeviceReadClass(check, &device_class);
@@ -825,12 +982,21 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
goto cleanup;
/* Is it a plane? */
+#ifndef __FreeBSD__
header_type = virPCIDeviceRead8(check, fd, PCI_HEADER_TYPE);
+#else
+ header_type = virPCIDeviceRead8(check, PCI_HEADER_TYPE);
+#endif
if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
goto cleanup;
+#ifndef __FreeBSD__
secondary = virPCIDeviceRead8(check, fd, PCI_SECONDARY_BUS);
subordinate = virPCIDeviceRead8(check, fd, PCI_SUBORDINATE_BUS);
+#else
+ secondary = virPCIDeviceRead8(check, PCI_SECONDARY_BUS);
+ subordinate = virPCIDeviceRead8(check, PCI_SUBORDINATE_BUS);
+#endif
VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name);
@@ -858,13 +1024,19 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
* parent. See if the current device is more restrictive than the
* best, and if so, make it the new best
*/
+#ifndef __FreeBSD__
int bestfd;
+#endif
uint8_t best_secondary;
+#ifndef __FreeBSD__
if ((bestfd = virPCIDeviceConfigOpenTry(*best)) < 0)
goto cleanup;
best_secondary = virPCIDeviceRead8(*best, bestfd, PCI_SECONDARY_BUS);
virPCIDeviceConfigClose(*best, bestfd);
+#else
+ best_secondary = virPCIDeviceRead8(*best, PCI_SECONDARY_BUS);
+#endif
if (secondary > best_secondary) {
virPCIDeviceFree(*best);
@@ -878,7 +1050,9 @@ virPCIDeviceIsParent(virPCIDevice *dev, virPCIDevice *check, void *data)
}
cleanup:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(check, fd);
+#endif
return ret;
}
@@ -902,7 +1076,9 @@ virPCIDeviceGetParent(virPCIDevice *dev, virPCIDevice **parent)
*/
static int
virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
+#ifndef __FreeBSD__
int cfgfd,
+#endif
virPCIDeviceList *inactiveDevs)
{
g_autoptr(virPCIDevice) parent = NULL;
@@ -910,7 +1086,9 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
uint8_t config_space[PCI_CONF_LEN];
uint16_t ctl;
int ret = -1;
+#ifndef __FreeBSD__
int parentfd;
+#endif
/* Refuse to do a secondary bus reset if there are other
* devices/functions behind the bus are used by the host
@@ -932,8 +1110,11 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
dev->name);
return -1;
}
+
+#ifndef __FreeBSD__
if ((parentfd = virPCIDeviceConfigOpenWrite(parent)) < 0)
goto out;
+#endif
VIR_DEBUG("%s %s: doing a secondary bus reset", dev->id, dev->name);
@@ -941,7 +1122,11 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
* for the supplied device since we refuse to do a reset if there
* are multiple devices/functions
*/
+#ifndef __FreeBSD__
if (virPCIDeviceRead(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
+#else
+ if (virPCIDeviceRead(dev, 0, PCI_CONF_LEN, (u_int32_t *) config_space) < 0) {
+#endif
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to read PCI config space for %1$s"),
dev->name);
@@ -951,6 +1136,7 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
/* Read the control register, set the reset flag, wait 200ms,
* unset the reset flag and wait 200ms.
*/
+#ifndef __FreeBSD__
ctl = virPCIDeviceRead16(dev, parentfd, PCI_BRIDGE_CONTROL);
virPCIDeviceWrite16(parent, parentfd, PCI_BRIDGE_CONTROL,
@@ -963,6 +1149,20 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
g_usleep(200 * 1000); /* sleep 200ms */
if (virPCIDeviceWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) {
+#else
+ ctl = virPCIDeviceRead16(parent, PCI_BRIDGE_CONTROL);
+
+ virPCIDeviceWrite16(parent, PCI_BRIDGE_CONTROL,
+ ctl | PCI_BRIDGE_CTL_RESET);
+
+ g_usleep(200 * 1000); /* sleep 200ms */
+
+ virPCIDeviceWrite16(parent, PCI_BRIDGE_CONTROL, ctl);
+
+ g_usleep(200 * 1000); /* sleep 200ms */
+
+ if (virPCIDeviceWrite(dev, 0, PCI_CONF_LEN, (config_space[0] << 0) | (config_space[1] << 8) | (config_space[2] << 16) | (config_space[3] << 24)) < 0) {
+#endif
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to restore PCI config space for %1$s"),
dev->name);
@@ -971,7 +1171,9 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
ret = 0;
out:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(parent, parentfd);
+#endif
return ret;
}
@@ -980,7 +1182,11 @@ virPCIDeviceTrySecondaryBusReset(virPCIDevice *dev,
* above we require the device supports a full internal reset.
*/
static int
+#ifndef __FreeBSD__
virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
+#else
+virPCIDeviceTryPowerManagementReset(virPCIDevice *dev)
+#endif
{
uint8_t config_space[PCI_CONF_LEN];
uint32_t ctl;
@@ -989,6 +1195,7 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
return -1;
/* Save and restore the device's config space. */
+#ifndef __FreeBSD__
if (virPCIDeviceRead(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to read PCI config space for %1$s"),
@@ -1012,6 +1219,31 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
g_usleep(10 * 1000); /* sleep 10ms */
if (virPCIDeviceWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+#else
+ if (virPCIDeviceRead(dev, 0, PCI_CONF_LEN, (u_int32_t *) config_space) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to read PCI config space for %1$s"),
+ dev->name);
+ return -1;
+ }
+
+ VIR_DEBUG("%s %s: doing a power management reset", dev->id, dev->name);
+
+ ctl = virPCIDeviceRead32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL);
+ ctl &= ~PCI_PM_CTRL_STATE_MASK;
+
+ virPCIDeviceWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL,
+ ctl | PCI_PM_CTRL_STATE_D3hot);
+
+ g_usleep(10 * 1000); /* sleep 10ms */
+
+ virPCIDeviceWrite32(dev, dev->pci_pm_cap_pos + PCI_PM_CTRL,
+ ctl | PCI_PM_CTRL_STATE_D0);
+
+ g_usleep(10 * 1000); /* sleep 10ms */
+
+ if (virPCIDeviceWrite(dev, 0, PCI_CONF_LEN, (config_space[0] << 0) | (config_space[1] << 8) | (config_space[2] << 16) | (config_space[3] << 24)) < 0) {
+#endif
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to restore PCI config space for %1$s"),
dev->name);
@@ -1046,10 +1278,18 @@ virPCIDeviceTryPowerManagementReset(virPCIDevice *dev, int cfgfd)
* Always returns success (0) (for now)
*/
static int
+#ifndef __FreeBSD__
virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
+#else
+virPCIDeviceInit(virPCIDevice *dev)
+#endif
{
dev->is_pcie = false;
+#ifndef __FreeBSD__
if (virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) {
+#else
+ if (virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_EXP, &dev->pcie_cap_pos) < 0) {
+#endif
/* an unprivileged process is unable to read *all* of a
* device's PCI config (it can only read the first 64
* bytes, which isn't enough for see the Express
@@ -1065,6 +1305,7 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
* -1), then we blindly assume the most likely outcome -
* PCIe.
*/
+#ifndef __FreeBSD__
off_t configLen = virFileLength(virPCIDeviceGetConfigPath(dev), -1);
if (configLen != 256)
@@ -1077,6 +1318,16 @@ virPCIDeviceInit(virPCIDevice *dev, int cfgfd)
virPCIDeviceFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos);
dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev, cfgfd);
dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev, cfgfd);
+#else
+
+ } else {
+ dev->is_pcie = (dev->pcie_cap_pos != 0);
+ }
+
+ virPCIDeviceFindCapabilityOffset(dev, PCI_CAP_ID_PM, &dev->pci_pm_cap_pos);
+ dev->has_flr = virPCIDeviceDetectFunctionLevelReset(dev);
+ dev->has_pm_reset = virPCIDeviceDetectPowerManagementReset(dev);
+#endif
return 0;
}
@@ -1089,7 +1340,9 @@ virPCIDeviceReset(virPCIDevice *dev,
g_autofree char *drvName = NULL;
virPCIStubDriver drvType;
int ret = -1;
+#ifndef __FreeBSD__
int fd = -1;
+#endif
int hdrType = -1;
if (virPCIGetHeaderType(dev, &hdrType) < 0)
@@ -1125,10 +1378,14 @@ virPCIDeviceReset(virPCIDevice *dev,
VIR_DEBUG("Resetting device %s", dev->name);
+#ifndef __FreeBSD__
if ((fd = virPCIDeviceConfigOpenWrite(dev)) < 0)
goto cleanup;
if (virPCIDeviceInit(dev, fd) < 0)
+#else
+ if (virPCIDeviceInit(dev) < 0)
+#endif
goto cleanup;
/* KVM will perform FLR when starting and stopping
@@ -1144,11 +1401,19 @@ virPCIDeviceReset(virPCIDevice *dev,
* the function, not the whole device.
*/
if (dev->has_pm_reset)
+#ifndef __FreeBSD__
ret = virPCIDeviceTryPowerManagementReset(dev, fd);
+#else
+ ret = virPCIDeviceTryPowerManagementReset(dev);
+#endif
/* Bus reset is not an option with the root bus */
if (ret < 0 && dev->address.bus != 0)
+#ifndef __FreeBSD__
ret = virPCIDeviceTrySecondaryBusReset(dev, fd, inactiveDevs);
+#else
+ ret = virPCIDeviceTrySecondaryBusReset(dev, inactiveDevs);
+#endif
if (ret < 0) {
virErrorPtr err = virGetLastError();
@@ -1160,7 +1425,9 @@ virPCIDeviceReset(virPCIDevice *dev,
}
cleanup:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(dev, fd);
+#endif
return ret;
}
@@ -1868,6 +2135,12 @@ virPCIDeviceNew(const virPCIDeviceAddress *address)
g_autoptr(virPCIDevice) dev = NULL;
g_autofree char *vendor = NULL;
g_autofree char *product = NULL;
+#ifdef __FreeBSD__
+ struct pci_conf_io pc;
+ struct pci_match_conf patterns[1];
+ struct pci_conf conf[1];
+ int fd;
+#endif
dev = g_new0(virPCIDevice, 1);
@@ -1875,6 +2148,7 @@ virPCIDeviceNew(const virPCIDeviceAddress *address)
dev->name = virPCIDeviceAddressAsString(&dev->address);
+#ifndef __FreeBSD__
dev->path = g_strdup_printf(PCI_SYSFS "devices/%s/config", dev->name);
if (!virFileExists(dev->path)) {
@@ -1902,6 +2176,52 @@ virPCIDeviceNew(const virPCIDeviceAddress *address)
&vendor[2], &product[2]);
return NULL;
}
+#else
+ fd = open("/dev/pci", O_RDONLY, 0);
+ if (fd < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Error open /dev/pci: %1$d"), errno);
+ return NULL;
+ }
+
+ bzero(&pc, sizeof(struct pci_conf_io));
+ pc.match_buf_len = sizeof(conf);
+ pc.matches = conf;
+
+ bzero(patterns, sizeof(patterns));
+ patterns[0].pc_sel.pc_domain = address->domain;
+ patterns[0].pc_sel.pc_bus = address->bus;
+ patterns[0].pc_sel.pc_dev = address->slot;
+ patterns[0].pc_sel.pc_func = address->function;
+
+ patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
+ pc.num_patterns = 1;
+ pc.pat_buf_len = sizeof(patterns);
+ pc.patterns = patterns;
+
+ if (ioctl(fd, PCIOCGETCONF, &pc) == -1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("ioctl(PCIOCGETCONF) eroor: %1$d"), errno);
+ return NULL;
+ }
+ if (pc.status != PCI_GETCONF_LAST_DEVICE && pc.status != PCI_GETCONF_MORE_DEVS) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("error returned from PCIOCGETCONF ioctl: %1$d"), pc.status);
+ return NULL;
+ }
+ VIR_FORCE_CLOSE(fd);
+ if (pc.num_matches == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("Device not found: %1$d"), pc.num_matches);
+ return NULL;
+ }
+
+ /* strings contain '0x' prefix */
+ if (g_snprintf(dev->id, sizeof(dev->id), "%x %x", pc.matches->pc_vendor,
+ pc.matches->pc_device) >= sizeof(dev->id)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("dev->id buffer overflow: %1$x %2$x"),
+ pc.matches->pc_vendor, pc.matches->pc_device);
+ return NULL;
+ }
+ dev->pc_hdr = pc.matches->pc_hdr;
+#endif
VIR_DEBUG("%s %s: initialized", dev->id, dev->name);
@@ -1918,10 +2238,12 @@ virPCIDeviceCopy(virPCIDevice *dev)
/* shallow copy to take care of most attributes */
*copy = *dev;
+#ifndef __FreeBSD__
copy->path = NULL;
+ copy->path = g_strdup(dev->path);
+#endif
copy->used_by_drvname = copy->used_by_domname = NULL;
copy->name = g_strdup(dev->name);
- copy->path = g_strdup(dev->path);
copy->used_by_drvname = g_strdup(dev->used_by_drvname);
copy->used_by_domname = g_strdup(dev->used_by_domname);
copy->stubDriverName = g_strdup(dev->stubDriverName);
@@ -1936,7 +2258,9 @@ virPCIDeviceFree(virPCIDevice *dev)
return;
VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
g_free(dev->name);
+#ifndef __FreeBSD__
g_free(dev->path);
+#endif
g_free(dev->used_by_drvname);
g_free(dev->used_by_domname);
g_free(dev->stubDriverName);
@@ -1970,11 +2294,19 @@ virPCIDeviceGetName(virPCIDevice *dev)
* Returns a pointer to a string containing the path of @dev's PCI
* config file.
*/
+#ifndef __FreeBSD__
const char *
virPCIDeviceGetConfigPath(virPCIDevice *dev)
{
return dev->path;
}
+#else
+const char *
+virPCIDeviceGetConfigPath(virPCIDevice *dev G_GNUC_UNUSED)
+{
+ return NULL;
+}
+#endif
void virPCIDeviceSetManaged(virPCIDevice *dev, bool managed)
{
@@ -2484,14 +2816,20 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev)
uint16_t flags;
uint16_t ctrl;
unsigned int pos;
+#ifndef __FreeBSD__
int fd;
+#endif
int ret = 0;
uint16_t device_class;
+#ifndef __FreeBSD__
if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
return -1;
if (virPCIDeviceInit(dev, fd) < 0) {
+#else
+ if (virPCIDeviceInit(dev) < 0) {
+#endif
ret = -1;
goto cleanup;
}
@@ -2503,18 +2841,30 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev)
if (!pos || device_class != PCI_CLASS_BRIDGE_PCI)
goto cleanup;
+#ifndef __FreeBSD__
flags = virPCIDeviceRead16(dev, fd, pos + PCI_EXP_FLAGS);
+#else
+ flags = virPCIDeviceRead16(dev, pos + PCI_EXP_FLAGS);
+#endif
if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM)
goto cleanup;
+#ifndef __FreeBSD__
pos = virPCIDeviceFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS);
+#else
+ pos = virPCIDeviceFindExtendedCapabilityOffset(dev, PCI_EXT_CAP_ID_ACS);
+#endif
if (!pos) {
VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name);
ret = 1;
goto cleanup;
}
+#ifndef __FreeBSD__
ctrl = virPCIDeviceRead16(dev, fd, pos + PCI_EXT_ACS_CTRL);
+#else
+ ctrl = virPCIDeviceRead16(dev, pos + PCI_EXT_ACS_CTRL);
+#endif
if ((ctrl & PCI_EXT_CAP_ACS_ENABLED) != PCI_EXT_CAP_ACS_ENABLED) {
VIR_DEBUG("%s %s: downstream port has ACS disabled",
dev->id, dev->name);
@@ -2523,7 +2873,9 @@ virPCIDeviceDownstreamLacksACS(virPCIDevice *dev)
}
cleanup:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(dev, fd);
+#endif
return ret;
}
@@ -2689,7 +3041,7 @@ virPCIGetVirtualFunctions(const char *sysfs_path,
}
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
virPCIDeviceAddress *
virPCIGetDeviceAddressFromSysfsLink(const char *device_link)
@@ -3189,33 +3541,43 @@ virPCIDeviceGetVPD(virPCIDevice *dev G_GNUC_UNUSED)
int
virPCIDeviceIsPCIExpress(virPCIDevice *dev)
{
+int ret = -1;
+#ifndef __FreeBSD__
int fd;
- int ret = -1;
if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
return ret;
if (virPCIDeviceInit(dev, fd) < 0)
+#else
+ if (virPCIDeviceInit(dev) < 0)
+#endif
goto cleanup;
ret = dev->is_pcie;
cleanup:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(dev, fd);
+#endif
return ret;
}
int
virPCIDeviceHasPCIExpressLink(virPCIDevice *dev)
{
- int fd;
int ret = -1;
uint16_t cap, type;
+#ifndef __FreeBSD__
+ int fd;
if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
return ret;
if (virPCIDeviceInit(dev, fd) < 0)
+#else
+ if (virPCIDeviceInit(dev) < 0)
+#endif
goto cleanup;
if (dev->pcie_cap_pos == 0) {
@@ -3223,13 +3585,19 @@ virPCIDeviceHasPCIExpressLink(virPCIDevice *dev)
goto cleanup;
}
+#ifndef __FreeBSD__
cap = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_CAP_FLAGS);
+#else
+ cap = virPCIDeviceRead16(dev, dev->pcie_cap_pos + PCI_CAP_FLAGS);
+#endif
type = (cap & PCI_EXP_FLAGS_TYPE) >> 4;
ret = type != PCI_EXP_TYPE_ROOT_INT_EP && type != PCI_EXP_TYPE_ROOT_EC;
cleanup:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(dev, fd);
+#endif
return ret;
}
@@ -3242,13 +3610,17 @@ virPCIDeviceGetLinkCapSta(virPCIDevice *dev,
unsigned int *sta_width)
{
uint32_t t;
- int fd;
int ret = -1;
+#ifndef __FreeBSD__
+ int fd;
if ((fd = virPCIDeviceConfigOpen(dev)) < 0)
return ret;
if (virPCIDeviceInit(dev, fd) < 0)
+#else
+ if (virPCIDeviceInit(dev) < 0)
+#endif
goto cleanup;
if (!dev->pcie_cap_pos) {
@@ -3258,26 +3630,37 @@ virPCIDeviceGetLinkCapSta(virPCIDevice *dev,
goto cleanup;
}
+#ifndef __FreeBSD__
t = virPCIDeviceRead32(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKCAP);
+#else
+ t = virPCIDeviceRead32(dev, dev->pcie_cap_pos + PCI_EXP_LNKCAP);
+#endif
*cap_port = t >> 24;
*cap_speed = t & PCI_EXP_LNKCAP_SPEED;
*cap_width = (t & PCI_EXP_LNKCAP_WIDTH) >> 4;
+#ifndef __FreeBSD__
t = virPCIDeviceRead16(dev, fd, dev->pcie_cap_pos + PCI_EXP_LNKSTA);
+#else
+ t = virPCIDeviceRead16(dev, dev->pcie_cap_pos + PCI_EXP_LNKSTA);
+#endif
*sta_speed = t & PCI_EXP_LNKSTA_SPEED;
*sta_width = (t & PCI_EXP_LNKSTA_WIDTH) >> 4;
ret = 0;
cleanup:
+#ifndef __FreeBSD__
virPCIDeviceConfigClose(dev, fd);
+#endif
return ret;
}
int virPCIGetHeaderType(virPCIDevice *dev, int *hdrType)
{
+#ifndef __FreeBSD__
int fd;
uint8_t type;
@@ -3289,6 +3672,13 @@ int virPCIGetHeaderType(virPCIDevice *dev, int *hdrType)
type = virPCIDeviceRead8(dev, fd, PCI_HEADER_TYPE);
virPCIDeviceConfigClose(dev, fd);
+#else
+ uint8_t type = dev->pc_hdr;
+
+ *hdrType = -1;
+
+ type = virPCIDeviceRead8(dev, PCI_HEADER_TYPE);
+#endif
type &= PCI_HEADER_TYPE_MASK;
if (type >= VIR_PCI_HEADER_LAST) {
--
2.47.1
2 days, 1 hour
[PATCH] qemu: introduce load qemu.conf for "virt-qemu-run"
by Adam Julis
Adding a new option --config (or -c) for specifying a custom
qemu.conf file.
Previously, virt-qemu-run loaded default configuration values for
QEMU via qemuStateInitialize(). The configuration was loaded from
a temporary ../etc/ directory using virQEMUDriverConfigLoadFile(),
and any qemu.conf file present in that directory was also loaded
automatically.
This patch allows users to specify a custom configuration file,
which is copied into the temporary directory (or a permanent
folder if the -r option is used) before loading the
configuration. If an existing qemu.conf is present, it is
properly backed up and restored in case of a permanent folder.
The custom qemu.conf is always removed when the program exits.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/723
Signed-off-by: Adam Julis <ajulis(a)redhat.com>
---
docs/manpages/virt-qemu-run.rst | 9 +++
src/qemu/qemu_shim.c | 121 +++++++++++++++++++++++++++++++-
2 files changed, 129 insertions(+), 1 deletion(-)
diff --git a/docs/manpages/virt-qemu-run.rst b/docs/manpages/virt-qemu-run.rst
index 4d546ff8cc..ba1c90b52a 100644
--- a/docs/manpages/virt-qemu-run.rst
+++ b/docs/manpages/virt-qemu-run.rst
@@ -72,6 +72,15 @@ whose UUID should match a secret referenced in the guest domain XML.
Display verbose information about startup.
+``-c`` *QEMU-CONF-FILE*,
+``--config``\ =\ *QEMU-CONF-FILE*
+
+Specify the QEMU configuration file to be used for starting the VM.
+*QEMU-CONF-FILE* is the full path to the QEMU configuration file.
+
+If this parameter is omitted, the default configuration values will
+be used.
+
``-h``, ``--help``
Display the command line help.
diff --git a/src/qemu/qemu_shim.c b/src/qemu/qemu_shim.c
index 7fdd69b538..64c87ab264 100644
--- a/src/qemu/qemu_shim.c
+++ b/src/qemu/qemu_shim.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
+#include <fcntl.h>
#include "virfile.h"
#include "virgettext.h"
@@ -132,6 +133,100 @@ qemuShimQuench(void *userData G_GNUC_UNUSED,
{
}
+/* Load specific QEMU config file, is the -c option is used */
+static int
+qemuAddConfigFile(const char *source_file, const char *root, bool *config_to_delete, long long deltams)
+{
+ int ret = -1;
+ struct stat st;
+ VIR_AUTOCLOSE srcFD = -1;
+ VIR_AUTOCLOSE dstFD = -1;
+ g_autofree char *config_dir = NULL;
+ g_autofree char *source_file_real = NULL;
+ g_autofree char *config_path_file = NULL;
+ g_autofree char *config_path_file_real = NULL;
+
+ if ((srcFD = open(source_file, O_RDONLY)) < 0) {
+ g_printerr("Couldn't open specific config file\n");
+ goto cleanup;
+ }
+
+ if (fstat(srcFD, &st) != 0) {
+ g_printerr("Specific config file does not exist\n");
+ goto cleanup;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ g_printerr("Specific config is not a regular file\n");
+ goto cleanup;
+ }
+
+ /* Since source file exists, make the destination path or
+ * validate that it already exists */
+ config_dir = g_strdup_printf("%s/etc/", root);
+
+ if (g_mkdir_with_parents(config_dir, 0777) < 0) {
+ g_printerr("Couldn't make the directory for specific config file\n");
+ goto cleanup;
+ }
+
+ config_path_file = g_strdup_printf("%sqemu.conf", config_dir);
+
+ /* If the source file is same as the destination file, no action needed */
+ if ((source_file_real = realpath(source_file, NULL)) &&
+ (config_path_file_real = realpath(config_path_file, NULL))) {
+ if (STREQ(source_file_real, config_path_file_real)) {
+ ret = 0;
+ goto cleanup;
+ }
+ }
+
+ /* Check already existing qemu.conf in the subfolder, if so, renamed
+ * (appended via deltams constant - should be unique). Final cleanup
+ * at main() will revert this change */
+ if (access(config_path_file, R_OK) == 0) {
+ if (rename(config_path_file, g_strdup_printf("%sqemu_old_%lld.conf",
+ config_dir, deltams)) != 0) {
+ g_printerr("Couldn't rename old config file, try delete it\n");
+ goto cleanup;
+ }
+ }
+
+ if ((dstFD = open(config_path_file, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
+ g_printerr("Couldn't open file for define specific config\n");
+ goto cleanup;
+ }
+
+ /* Set the flag for deleting the new/modified config in main() cleanup,
+ * for ensure that behaviour without the user config will be always
+ * consistent and take default value */
+ *config_to_delete = true;
+
+ do {
+ char buffer[1024];
+ ssize_t readed = 0;
+
+ readed = saferead(srcFD, buffer, 1024);
+
+ if (readed < 0) {
+ g_printerr("Couldn't read from specific config\n");
+ goto cleanup;
+ } else if (readed == 0) {
+ break;
+ } else {
+ ssize_t writed = safewrite(dstFD, buffer, readed);
+ if (writed != readed) {
+ g_printerr("Couldn't write to file for define specific config\n");
+ goto cleanup;
+ }
+ }
+ } while (1);
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
int main(int argc, char **argv)
{
g_autoptr(virIdentity) sysident = NULL;
@@ -142,8 +237,11 @@ int main(int argc, char **argv)
g_autofree char *uri = NULL;
g_autofree char *suri = NULL;
const char *root = NULL;
+ const char *config = NULL;
+ long long delta_ms = 0;
g_autofree char *escaped = NULL;
bool tmproot = false;
+ bool config_to_delete = false;
int ret = 1;
g_autoptr(GError) error = NULL;
g_auto(GStrv) secrets = NULL;
@@ -156,6 +254,7 @@ int main(int argc, char **argv)
{ "root", 'r', 0, G_OPTION_ARG_STRING, &root, "Root directory", "DIR" },
{ "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Debug output", NULL },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", NULL },
+ { "config", 'c', 0, G_OPTION_ARG_STRING, &config, "Load specific QEMU configuration file", "QEMU-CONF-FILE"},
{ 0 }
};
int quitfd[2] = {-1, -1};
@@ -172,7 +271,7 @@ int main(int argc, char **argv)
return 1;
}
- if (argc != 2) {
+ if (argc != 2 && argc != 3) {
g_autofree char *help = g_option_context_get_help(ctx, TRUE, NULL);
g_printerr("%s", help);
return 1;
@@ -234,6 +333,10 @@ int main(int argc, char **argv)
goto cleanup;
}
+ delta_ms = deltams();
+ if (config && (qemuAddConfigFile(config, root, &config_to_delete, delta_ms) < 0))
+ g_printerr("Specific config file was not loaded, default was used\n");
+
escaped = g_uri_escape_string(root, NULL, true);
virFileActivateDirOverrideForProg(argv[0]);
@@ -402,6 +505,22 @@ int main(int argc, char **argv)
VIR_FORCE_CLOSE(quitfd[0]);
VIR_FORCE_CLOSE(quitfd[1]);
+ if (config_to_delete) {
+ g_autofree char *possible_old_file = g_strdup_printf("%s/etc/qemu_old_%lld.conf",
+ root, delta_ms);
+ g_autofree char *to_delete = g_strdup_printf("%s/etc/qemu.conf", root);
+
+ if (remove(to_delete) != 0)
+ g_printerr("Deleting specific config failed, located in: %s\n",
+ to_delete);
+
+ if (access(possible_old_file, R_OK) == 0) {
+ if (rename(possible_old_file, to_delete) != 0)
+ g_printerr("Renaming your old qemu.conf failed, ups, located in %s\n",
+ possible_old_file);
+ }
+ }
+
if (dom != NULL)
virDomainFree(dom);
if (sconn != NULL)
--
2.47.1
4 days, 21 hours
[PATCH 0/5] Drop support for VirtualBox-6.1
by Michal Privoznik
This was initiated by the following issue:
https://gitlab.com/libvirt/libvirt/-/issues/681
and I tried to add support for VBOX-7.1 but unfortunately got hit by a
bug in VBOX which renders the way we initialize C bindings useless. I've
reported the bug here:
https://www.virtualbox.org/ticket/22224
but it didn't get any attention.
Michal Prívozník (5):
vbox: Use g_autofree in tryLoadOne()
vbox: Report an error when VBox CAPI initialization fails
vbox: Drop support for VirtualBox-6.1.x
vbox: Drop code supporting old VBox version
NEWS: Document VBOX-6.1 removal
NEWS.rst | 5 +
src/vbox/meson.build | 1 -
src/vbox/vbox_CAPI_v6_1.h | 32896 --------------------------------
src/vbox/vbox_V6_1.c | 13 -
src/vbox/vbox_XPCOMCGlue.c | 5 +-
src/vbox/vbox_XPCOMCGlue.h | 2 +-
src/vbox/vbox_common.h | 4 +-
src/vbox/vbox_storage.c | 4 +-
src/vbox/vbox_tmpl.c | 30 +-
src/vbox/vbox_uniformed_api.h | 1 -
10 files changed, 16 insertions(+), 32945 deletions(-)
delete mode 100644 src/vbox/vbox_CAPI_v6_1.h
delete mode 100644 src/vbox/vbox_V6_1.c
--
2.45.2
5 days, 1 hour
[PATCH V2 0/3] qemu: Improve opening and verifying save images
by Jim Fehlig
V2 of https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/message/D...
Changes in V2:
* Move unlinking corrupt save images from qemuSaveImageOpen to the only
caller using that functionality
* Add a function to read save image header
* Correctly position file pointer of save image for QEMU
Jim Fehlig (3):
qemu: Move unlinking corrupt save image file to caller
qemu: Decompose qemuSaveImageOpen
qemu: Check for valid save image format when verifying image header
src/qemu/qemu_driver.c | 46 ++++---
src/qemu/qemu_saveimage.c | 268 +++++++++++++++++++++++---------------
src/qemu/qemu_saveimage.h | 21 ++-
src/qemu/qemu_snapshot.c | 9 +-
4 files changed, 207 insertions(+), 137 deletions(-)
--
2.43.0
5 days, 3 hours
[PATCH 0/2] qemu: Improve opening and verifying save images
by Jim Fehlig
qemuSaveImageOpen does a lot of stuff. When bypass-cache is specified,
it creates a virFileWrapperFd, which is not cleaned up in the subsequent
failure paths. This results in errors from the iohelper, which can
overwrite the actual error. E.g. consider libvirt attempting to restore
an image saved in an unknown format
# virsh restore --bypass-cache /data/test.sav.sparse
error: Failed to restore domain from /data/test.sav.sparse
error: internal error: Child process (LIBVIRT_LOG_OUTPUTS=1:stderr /usr/lib64/libvirt/libvirt_iohelper /data/test.sav.sparse 0) unexpected fatal signal 13
When not using the iohelper, and not creating a virFileWrapperFd, we see
the real error:
# virsh restore /data/test.sav.sparse
error: Failed to restore domain from /data/test.sav.sparse
error: operation failed: Invalid compressed save format 6
Although that error highlights a spot I missed when removing the
"compression" implications around the 'foo_image_format' settings in
qemu.conf with commit bd6d7ebf622 :-). IMO, the error message would be
best fixed by checking for valid values when reading the save image
metadata.
Patch 1 decomposes qemuSaveImageOpen to allow for better error handling
and more flexibility. Patch 2 checks for a valid format when checking the
other header fields.
Jim Fehlig (2):
qemu: Decompose qemuSaveImageOpen
qemu: Check for valid save image format when verifying image header
src/qemu/qemu_driver.c | 37 +++++++--------
src/qemu/qemu_saveimage.c | 95 +++++++++++++++++++++++++--------------
src/qemu/qemu_saveimage.h | 16 ++++---
src/qemu/qemu_snapshot.c | 9 ++--
4 files changed, 95 insertions(+), 62 deletions(-)
--
2.43.0
5 days, 8 hours
[PATCH 00/19] Add qemu RDP server support
by marcandre.lureau@redhat.com
From: Marc-André Lureau <marcandre.lureau(a)redhat.com>
Hi,
This patch series offers an out-of-process Remote Desktop Protocol (RDP)
server solution utilizing QEMU's -display dbus interface, offering improved
modularity and potential security benefits compared to built-in server.
This initiative was spearheaded by Mihnea Buzatu during the QEMU Summer of Code
2023. The project's goal was to develop an out-of-process RDP server using the
-display dbus interface, implemented in Rust. Given that the IronRDP crate
lacked some server support at the time, investments in IronRDP were required.
I finally released an initial v0.1 version of qemu-rdp on crates.io
(https://crates.io/crates/qemu-rdp). That should allow more people to review and
evaluate the state of this work.
On unix systems, with cargo/rust toolchain installed, it should be as easy as
running "cargo install qemu-rdp", apply this patch series for libvirt, set the
"rdp_tls_x509_cert_dir" location for your TLS certificates, and configure a VM
with both dbus & rdp graphics (run "virsh domdisplay DOMAIN" to get the display
connection details).
Thanks for the reviews & feedback!
Marc-André Lureau (19):
build-sys: drop -Winline
build: fix -Werror=maybe-uninitialized
qemu-slirp: drop unneeded check for OOM
util: add conn != NULL precondition in virGDBusCallMethod()
qemu: report an error for unsupported graphics
qemu: add rdp state directory
qemu: add qemu RDP configuration
conf: parse optional RDP username & password
conf: generalize virDomainDefHasSpiceGraphics
qemu: use virDomainDefHasGraphics
qemu: add RDP ports range allocator
qemu: limit to one <graphics type='rdp'>
qemu/dbus: keep a connection to the VM D-Bus
qemu/dbus: log daemon stdout/err
qemu: validate RDP configuration
qemu: if -display dbus capability is supported, accept rdp
qemu: add qemu-rdp helper unit
qemu: add RDP support
tests: add qemu <graphics type='rdp'/> test
docs/formatdomain.rst | 25 +-
meson.build | 1 -
po/POTFILES | 1 +
src/conf/domain_conf.c | 28 +-
src/conf/domain_conf.h | 5 +-
src/conf/schemas/domaincommon.rng | 10 +
src/libvirt_private.syms | 2 +-
src/qemu/libvirtd_qemu.aug | 7 +
src/qemu/meson.build | 1 +
src/qemu/qemu.conf.in | 31 ++
src/qemu/qemu_capabilities.c | 7 +-
src/qemu/qemu_command.c | 11 +-
src/qemu/qemu_conf.c | 47 ++
src/qemu/qemu_conf.h | 13 +
src/qemu/qemu_dbus.c | 83 +++-
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 4 +
src/qemu/qemu_driver.c | 20 +
src/qemu/qemu_extdevice.c | 46 +-
src/qemu/qemu_hotplug.c | 49 +-
src/qemu/qemu_hotplug.h | 1 +
src/qemu/qemu_process.c | 167 ++++++-
src/qemu/qemu_rdp.c | 427 ++++++++++++++++++
src/qemu/qemu_rdp.h | 71 +++
src/qemu/qemu_slirp.c | 6 -
src/qemu/qemu_validate.c | 45 +-
src/qemu/test_libvirtd_qemu.aug.in | 5 +
src/util/virgdbus.c | 4 +
tests/domaincapsdata/qemu_10.0.0.s390x.xml | 1 +
.../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 1 +
.../qemu_7.2.0-hvf.x86_64+hvf.xml | 1 +
.../domaincapsdata/qemu_7.2.0-q35.x86_64.xml | 1 +
.../qemu_7.2.0-tcg.x86_64+hvf.xml | 1 +
.../domaincapsdata/qemu_7.2.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_7.2.0.ppc.xml | 1 +
tests/domaincapsdata/qemu_7.2.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.0.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_8.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.1.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.1.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_8.1.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_8.1.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_8.2.0-q35.x86_64.xml | 1 +
.../qemu_8.2.0-tcg-virt.loongarch64.xml | 1 +
.../domaincapsdata/qemu_8.2.0-tcg.x86_64.xml | 1 +
.../qemu_8.2.0-virt.aarch64.xml | 1 +
.../qemu_8.2.0-virt.loongarch64.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.aarch64.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.armv7l.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_8.2.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.0.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.0.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_9.0.0.sparc.xml | 1 +
tests/domaincapsdata/qemu_9.0.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.1.0-q35.x86_64.xml | 1 +
.../qemu_9.1.0-tcg-virt.riscv64.xml | 1 +
.../domaincapsdata/qemu_9.1.0-tcg.x86_64.xml | 1 +
.../qemu_9.1.0-virt.riscv64.xml | 1 +
tests/domaincapsdata/qemu_9.1.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_9.1.0.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.2.0-q35.x86_64.xml | 1 +
.../domaincapsdata/qemu_9.2.0-tcg.x86_64.xml | 1 +
tests/domaincapsdata/qemu_9.2.0.s390x.xml | 1 +
tests/domaincapsdata/qemu_9.2.0.x86_64.xml | 1 +
.../graphics-rdp.x86_64-latest.args | 35 ++
.../graphics-rdp.x86_64-latest.xml | 1 +
tests/qemuxmlconfdata/graphics-rdp.xml | 43 ++
tests/qemuxmlconftest.c | 2 +
tests/testutilsqemu.c | 4 +
tools/nss/libvirt_nss_leases.c | 2 +-
tools/nss/libvirt_nss_macs.c | 2 +-
78 files changed, 1172 insertions(+), 78 deletions(-)
create mode 100644 src/qemu/qemu_rdp.c
create mode 100644 src/qemu/qemu_rdp.h
create mode 100644 tests/qemuxmlconfdata/graphics-rdp.x86_64-latest.args
create mode 120000 tests/qemuxmlconfdata/graphics-rdp.x86_64-latest.xml
create mode 100644 tests/qemuxmlconfdata/graphics-rdp.xml
--
2.47.0
5 days, 11 hours