[libvirt PATCH v3 00/18] Use nbdkit for http/ftp/ssh network drives in libvirt
by Jonathon Jongsma
This is the third version of this patch series. See
https://bugzilla.redhat.com/show_bug.cgi?id=2016527 for more information about
the goal, but the summary is that RHEL does not want to ship the qemu storage
plugins for curl and ssh. Handling them outside of the qemu process provides
several advantages such as reduced attack surface and stability.
A quick summary of the code:
- at startup I query to see whether nbdkit exists on the host and if
so, I query which plugins/filters are installed. These capabilities
are cached and stored in the qemu driver
- When the driver prepares the domain, we go through each disk source
and determine whether the nbdkit capabilities allow us to support
this disk via nbdkit, and if so, we allocate a qemuNbdkitProcess
object and stash it in the private data of the virStorageSource.
- The presence or absence of this qemuNbdkitProcess data then indicates
whether this disk will be served to qemu indirectly via nbdkit or
directly
- When we launch the qemuProcess, as part of the "external device
start" step, I launch a ndkit process for each disk that is supported
by nbdkit.
- for devices which are served by an intermediate ndkit process, I
change the qemu commandline in the following ways:
- I no longer pass auth/cookie secrets to qemu (those are handled by
nbdkit)
- I replace the actual network URL of the remote disk source with the
path to the nbdkit unix socket
- We create a 'monitor' for the nbdkit process that watches to see whether the
process exits. If it does, we pause the domain, attempt to restart nbdkit,
and then resume the domain.
Open questions
- I think selinux will work once we add a policy for the /usr/sbin/nbdkit
binary to allow it to be executed by libvirt, but for now it fails to
execute nbdkit in enforcing mode. The current context for nbdkit (on fedora)
is "system_u:object_r:bin_t:s0". When I temporarily change the context to
something like qemu_exec_t, I am able to start nbdkit and the domain
launches.
Known shortcomings
- creating disks (in ssh) still isn't supported.
Changes in v3:
- Various formatting fixes
- Don't kill process in qemuNbdkitProcessFree() since we want the nbdkit
daemon to continue running even if libvirt restarts.
- Better detection and error reporting when starting the nbdkit process
- Add monitoring for nbdkit process so that it can be restarted if if ever
exits unexpectedly.
Changes in v2:
- split into multiple patches
- added a build option for nbdkit_moddir
- don't instantiate any secret / cookie props for disks that are being served
by nbdkit since we don't send secrets to qemu anymore
- ensure that nbdkit processes are started/stopped for the entire backing
chain
- switch to virFileCache-based capabilities for nbdkit so that we don't need
to requery every time
- switch to using pipes for communicating sensitive data to nbdkit
- use pidfile support built into virCommand rather than nbdkit's --pidfile
argument
- added significantly more tests
Jonathon Jongsma (18):
schema: allow 'ssh' as a protocol for network disks
qemu: Add functions for determining nbdkit availability
qemu: expand nbdkit capabilities
util: Allow virFileCache data to be any GObject
qemu: implement basic virFileCache for nbdkit caps
qemu: implement persistent file cache for nbdkit caps
qemu: use file cache for nbdkit caps
qemu: Add qemuNbdkitProcess
qemu: add functions to start and stop nbdkit
tests: add ability to test various nbdkit capabilities
qemu: split qemuDomainSecretStorageSourcePrepare
qemu: include nbdkit state in private xml
qemu: use nbdkit to serve network disks if available
tests: add tests for nbdkit invocation
util: make virCommandSetSendBuffer testable
qemu: pass sensitive data to nbdkit via pipe
qemu: add test for authenticating a https network disk
qemu: Monitor nbdkit process for exit
build-aux/syntax-check.mk | 4 +-
meson.build | 9 +
meson_options.txt | 1 +
po/POTFILES | 1 +
src/conf/schemas/domaincommon.rng | 1 +
src/libvirt_private.syms | 1 +
src/qemu/meson.build | 1 +
src/qemu/qemu_block.c | 162 ++-
src/qemu/qemu_conf.c | 23 +
src/qemu/qemu_conf.h | 7 +
src/qemu/qemu_domain.c | 180 ++-
src/qemu/qemu_domain.h | 4 +
src/qemu/qemu_driver.c | 4 +
src/qemu/qemu_extdevice.c | 48 +
src/qemu/qemu_nbdkit.c | 1243 +++++++++++++++++
src/qemu/qemu_nbdkit.h | 120 ++
src/qemu/qemu_nbdkitpriv.h | 31 +
src/qemu/qemu_process.c | 13 +
src/util/vircommand.c | 19 +-
src/util/vircommand.h | 8 +
src/util/vircommandpriv.h | 4 +
src/util/virfilecache.c | 14 +-
src/util/virfilecache.h | 2 +-
src/util/virutil.h | 2 +-
tests/meson.build | 1 +
.../disk-cdrom-network.args.disk0 | 7 +
.../disk-cdrom-network.args.disk1 | 9 +
.../disk-cdrom-network.args.disk1.pipe.1778 | 1 +
.../disk-cdrom-network.args.disk2 | 9 +
.../disk-cdrom-network.args.disk2.pipe.1780 | 1 +
.../disk-network-http.args.disk0 | 7 +
.../disk-network-http.args.disk1 | 6 +
.../disk-network-http.args.disk2 | 7 +
.../disk-network-http.args.disk2.pipe.1778 | 1 +
.../disk-network-http.args.disk3 | 8 +
.../disk-network-http.args.disk3.pipe.1780 | 1 +
...work-source-curl-nbdkit-backing.args.disk0 | 8 +
...e-curl-nbdkit-backing.args.disk0.pipe.1778 | 1 +
.../disk-network-source-curl.args.1.pipe.1 | 1 +
.../disk-network-source-curl.args.disk0 | 8 +
...k-network-source-curl.args.disk0.pipe.1778 | 1 +
.../disk-network-source-curl.args.disk1 | 10 +
...k-network-source-curl.args.disk1.pipe.1780 | 1 +
...k-network-source-curl.args.disk1.pipe.1782 | 1 +
...isk-network-source-curl.args.disk1.pipe.49 | 1 +
.../disk-network-source-curl.args.disk2 | 8 +
...k-network-source-curl.args.disk2.pipe.1782 | 1 +
...k-network-source-curl.args.disk2.pipe.1784 | 1 +
...isk-network-source-curl.args.disk2.pipe.51 | 1 +
.../disk-network-source-curl.args.disk3 | 7 +
.../disk-network-source-curl.args.disk4 | 7 +
.../disk-network-ssh.args.disk0 | 7 +
tests/qemunbdkittest.c | 294 ++++
...sk-cdrom-network-nbdkit.x86_64-latest.args | 42 +
.../disk-cdrom-network-nbdkit.xml | 1 +
...isk-network-http-nbdkit.x86_64-latest.args | 45 +
.../disk-network-http-nbdkit.xml | 1 +
...rce-curl-nbdkit-backing.x86_64-latest.args | 38 +
...isk-network-source-curl-nbdkit-backing.xml | 45 +
...work-source-curl-nbdkit.x86_64-latest.args | 50 +
.../disk-network-source-curl-nbdkit.xml | 1 +
...isk-network-source-curl.x86_64-latest.args | 54 +
.../disk-network-source-curl.xml | 74 +
...disk-network-ssh-nbdkit.x86_64-latest.args | 36 +
.../disk-network-ssh-nbdkit.xml | 1 +
.../disk-network-ssh.x86_64-latest.args | 36 +
tests/qemuxml2argvdata/disk-network-ssh.xml | 31 +
tests/qemuxml2argvtest.c | 18 +
tests/testutilsqemu.c | 27 +
tests/testutilsqemu.h | 5 +
70 files changed, 2707 insertions(+), 116 deletions(-)
create mode 100644 src/qemu/qemu_nbdkit.c
create mode 100644 src/qemu/qemu_nbdkit.h
create mode 100644 src/qemu/qemu_nbdkitpriv.h
create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk0
create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk1
create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk1.pipe.1778
create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk2
create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk2.pipe.1780
create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk0
create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk1
create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk2
create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk2.pipe.1778
create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk3
create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk3.pipe.1780
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0.pipe.1778
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.1.pipe.1
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk0
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk0.pipe.1778
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk1
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.1780
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.1782
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.49
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk2
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.1782
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.1784
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.51
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk3
create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk4
create mode 100644 tests/qemunbdkitdata/disk-network-ssh.args.disk0
create mode 100644 tests/qemunbdkittest.c
create mode 100644 tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.x86_64-latest.args
create mode 120000 tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.xml
create mode 100644 tests/qemuxml2argvdata/disk-network-http-nbdkit.x86_64-latest.args
create mode 120000 tests/qemuxml2argvdata/disk-network-http-nbdkit.xml
create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl-nbdkit-backing.x86_64-latest.args
create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl-nbdkit-backing.xml
create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.x86_64-latest.args
create mode 120000 tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.xml
create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl.x86_64-latest.args
create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl.xml
create mode 100644 tests/qemuxml2argvdata/disk-network-ssh-nbdkit.x86_64-latest.args
create mode 120000 tests/qemuxml2argvdata/disk-network-ssh-nbdkit.xml
create mode 100644 tests/qemuxml2argvdata/disk-network-ssh.x86_64-latest.args
create mode 100644 tests/qemuxml2argvdata/disk-network-ssh.xml
--
2.37.3
1 year, 11 months
[libvirt PATCH v3] tools: add virt-qemu-qmp-proxy for proxying QMP via libvirt QEMU guests
by Daniel P. Berrangé
Libvirt provides QMP passthrough APIs for the QEMU driver and these are
exposed in virsh. It is not especially pleasant, however, using the raw
QMP JSON syntax. QEMU has a tool 'qmp-shell' which can speak QMP and
exposes a human friendly interactive shell. It is not possible to use
this with libvirt managed guest, however, since only one client can
attach to the QMP socket at any point in time. While it would be
possible to configure a second QMP socket for a VM, it may not be
an known requirement at the time the guest is provisioned.
The virt-qmp-proxy tool aims to solve this problem. It opens a UNIX
socket and listens for incoming client connections, speaking QMP on
the connected socket. It will forward any QMP commands received onto
the running libvirt QEMU guest, and forward any replies back to the
QMP client. It will also forward back events.
$ virsh start demo
$ virt-qmp-proxy demo demo.qmp &
$ qmp-shell demo.qmp
Welcome to the QMP low-level shell!
Connected to QEMU 6.2.0
(QEMU) query-kvm
{
"return": {
"enabled": true,
"present": true
}
}
Note this tool of course has the same risks as the raw libvirt
QMP passthrough. It is safe to run query commands to fetch information
but commands which change the QEMU state risk disrupting libvirt's
management of QEMU, potentially resulting in data loss/corruption in
the worst case. Any use of this tool will cause the guest to be marked
as tainted as an warning that it could be in an unexpected state.
Since this tool introduces a python dependency it is not desirable
to include it in any of the existing RPMs in libvirt. This tool is
also QEMU specific, so isn't appropriate to bundle with the generic
tools. Thus a new RPM is introduced 'libvirt-clients-qemu', to
contain additional QEMU specific tools, with extra external deps.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
In v3:
- Added to libvirt-clients-qemu RPM
- Renamed to virt-qemu-qmp-proxy
docs/manpages/meson.build | 1 +
docs/manpages/virt-qemu-qmp-proxy.rst | 120 +++++++++
libvirt.spec.in | 15 ++
tools/meson.build | 5 +
tools/virt-qemu-qmp-proxy | 360 ++++++++++++++++++++++++++
5 files changed, 501 insertions(+)
create mode 100644 docs/manpages/virt-qemu-qmp-proxy.rst
create mode 100755 tools/virt-qemu-qmp-proxy
diff --git a/docs/manpages/meson.build b/docs/manpages/meson.build
index ba673cf472..83933227d9 100644
--- a/docs/manpages/meson.build
+++ b/docs/manpages/meson.build
@@ -18,6 +18,7 @@ docs_man_files = [
{ 'name': 'virt-pki-query-dn', 'section': '1', 'install': true },
{ 'name': 'virt-pki-validate', 'section': '1', 'install': true },
{ 'name': 'virt-qemu-run', 'section': '1', 'install': conf.has('WITH_QEMU') },
+ { 'name': 'virt-qemu-qmp-proxy', 'section': '1', 'install': conf.has('WITH_QEMU') },
{ 'name': 'virt-xml-validate', 'section': '1', 'install': true },
{ 'name': 'libvirt-guests', 'section': '8', 'install': conf.has('WITH_LIBVIRTD') },
diff --git a/docs/manpages/virt-qemu-qmp-proxy.rst b/docs/manpages/virt-qemu-qmp-proxy.rst
new file mode 100644
index 0000000000..b387474b19
--- /dev/null
+++ b/docs/manpages/virt-qemu-qmp-proxy.rst
@@ -0,0 +1,120 @@
+===================
+virt-qemu-qmp-proxy
+===================
+
+--------------------------------------------------
+Expose a QMP proxy server for a libvirt QEMU guest
+--------------------------------------------------
+
+:Manual section: 1
+:Manual group: Virtualization Support
+
+.. contents::
+
+
+SYNOPSIS
+========
+
+``virt-qemu-qmp-proxy`` [*OPTION*]... *DOMAIN* *QMP-SOCKET-PATH*
+
+
+DESCRIPTION
+===========
+
+This tool provides a way to expose a QMP proxy server that communicates
+with a QEMU guest managed by libvirt. This enables standard QMP client
+tools to interact with libvirt managed guests.
+
+**NOTE: use of this tool will result in the running QEMU guest being
+marked as tainted.** It is strongly recommended that this tool *only be
+used to send commands which query information* about the running guest.
+If this tool is used to make changes to the state of the guest, this
+may have negative interactions with the QEMU driver, resulting in an
+inability to manage the guest operation thereafter, and in the worst
+case **potentially lead to data loss or corruption**.
+
+The ``virt-qemu-qmp-proxy`` program will listen on a UNIX socket for incoming
+client connections, and run the QMP protocol over the connection. Any
+commands received will be sent to the running libvirt guest, and replies
+sent back.
+
+The ``virt-qemu-qmp-proxy`` program may be interrupted (eg Ctrl-C) when it
+is no longer required. The libvirt QEMU guest will continue running.
+
+
+OPTIONS
+=======
+
+*DOMAIN*
+
+The ID or UUID or Name of the libvirt QEMU guest.
+
+*QMP-SOCKET-PATH*
+
+The filesystem path at which to run the QMP server, listening for
+incoming connections.
+
+``-c`` *CONNECTION-URI*
+``--connect``\ =\ *CONNECTION-URI*
+
+The URI for the connection to the libvirt QEMU driver. If omitted,
+a URI will be auto-detected.
+
+``-v``, ``--verbose``
+
+Run in verbose mode, printing all QMP commands and replies that
+are handled.
+
+``-h``, ``--help``
+
+Display the command line help.
+
+
+EXIT STATUS
+===========
+
+Upon successful shutdown, an exit status of 0 will be set. Upon
+failure a non-zero status will be set.
+
+
+AUTHOR
+======
+
+Daniel P. Berrangé
+
+
+BUGS
+====
+
+Please report all bugs you discover. This should be done via either:
+
+#. the mailing list
+
+ `https://libvirt.org/contact.html <https://libvirt.org/contact.html>`_
+
+#. the bug tracker
+
+ `https://libvirt.org/bugs.html <https://libvirt.org/bugs.html>`_
+
+Alternatively, you may report bugs to your software distributor / vendor.
+
+COPYRIGHT
+=========
+
+Copyright (C) 2022 by Red Hat, Inc.
+
+
+LICENSE
+=======
+
+``virt-qemu-qmp-proxy`` is distributed under the terms of the GNU LGPL v2+.
+This is free software; see the source for copying conditions. There
+is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE
+
+
+SEE ALSO
+========
+
+virsh(1), `https://libvirt.org/ <https://libvirt.org/>`_,
+`QMP reference <https://www.qemu.org/docs/master/interop/qemu-qmp-ref.html>`_
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 950c5a3b6d..3082285dc0 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -899,6 +899,15 @@ Obsoletes: libvirt-bash-completion < 7.3.0
The client binaries needed to access the virtualization
capabilities of recent versions of Linux (and other OSes).
+%package client-qemu
+Summary: Additional client side utilities for QEMU
+Requires: %{name}-libs = %{version}-%{release}
+Requires: python3-libvirt >= %{version}-%{release}
+
+%description client-qemu
+The additional client binaries are used to interact
+with some QEMU specific features of libvirt.
+
%package libs
Summary: Client side libraries
# So remote clients can access libvirt over SSH tunnel
@@ -2159,6 +2168,12 @@ exit 0
%{_datadir}/bash-completion/completions/virsh
+%if %{with_qemu}
+%files client-qemu
+%{_mandir}/man1/virt-qemu-qmp-proxy.1*
+%{_bindir}/virt-qemu-qmp-proxy
+%endif
+
%files libs -f %{name}.lang
%license COPYING COPYING.LESSER
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/
diff --git a/tools/meson.build b/tools/meson.build
index bb28a904dc..20509906af 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -320,6 +320,11 @@ if conf.has('WITH_LIBVIRTD')
endif
endif
+if conf.has('WITH_QEMU')
+ install_data('virt-qemu-qmp-proxy',
+ install_dir: bindir)
+endif
+
if bash_completion_dep.found()
subdir('bash-completion')
endif
diff --git a/tools/virt-qemu-qmp-proxy b/tools/virt-qemu-qmp-proxy
new file mode 100755
index 0000000000..d85342bd2b
--- /dev/null
+++ b/tools/virt-qemu-qmp-proxy
@@ -0,0 +1,360 @@
+#!/usr/bin/env python3
+
+import argparse
+import array
+import libvirt
+import libvirt_qemu
+import os
+import re
+import socket
+import sys
+import traceback
+import json
+import fcntl
+
+
+debug = False
+
+def get_domain(uri, domstr):
+ conn = libvirt.open(uri)
+
+ dom = None
+ saveex = None
+
+ def try_lookup(cb):
+ try:
+ return cb()
+ except libvirt.libvirtError as ex:
+ nonlocal saveex
+ if saveex is None:
+ saveex = ex
+
+ if re.match(r'^\d+$', domstr):
+ dom = try_lookup(lambda: conn.lookupByID(int(domstr)))
+
+ if dom is None and re.match(r'^[-a-f0-9]{36}|[a-f0-9]{32}$', domstr):
+ dom = try_lookup(lambda: conn.lookupByUUIDString(domstr))
+
+ if dom is None:
+ dom = try_lookup(lambda: conn.lookupByName(domstr))
+
+ if dom is None:
+ raise saveex
+
+ if not dom.isActive():
+ raise Exception("Domain must be running to use QMP")
+
+ return conn, dom
+
+
+class QMPProxy(object):
+
+ def __init__(self, conn, dom, serversock, verbose):
+ self.conn = conn
+ self.dom = dom
+ self.verbose = verbose
+
+ self.serversock = serversock
+ self.serverwatch = 0
+
+ self.clientsock = None
+ self.clientwatch = 0
+
+ self.api2sock = bytes([])
+ self.api2sockfds = []
+
+ self.sock2api = bytes([])
+ self.sock2apifds = []
+
+ self.serverwatch = libvirt.virEventAddHandle(
+ self.serversock.fileno(), libvirt.VIR_EVENT_HANDLE_READABLE,
+ self.handle_server_io, self)
+
+ libvirt_qemu.qemuMonitorEventRegister(self.conn, self.dom,
+ None,
+ self.handle_qmp_event,
+ self)
+
+
+ @staticmethod
+ def handle_qmp_event(conn, dom, event, secs, usecs, details, self):
+ evdoc = {
+ "event": event,
+ "timestamp": {"seconds": secs, "microseconds": usecs }
+ }
+ if details is not None:
+ evdoc["data"] = details
+
+ ev = json.dumps(evdoc)
+ if self.verbose:
+ print(ev)
+ ev += "\r\n"
+ self.api2sock += ev.encode("utf-8")
+ self.update_client_events()
+
+
+ def recv_with_fds(self):
+ # Match VIR_NET_MESSAGE_NUM_FDS_MAX in virnetprotocol.x
+ maxfds = 32
+ fds = array.array('i')
+ cmsgdatalen = socket.CMSG_LEN(maxfds * fds.itemsize)
+
+ data, cmsgdata, flags, addr = self.clientsock.recvmsg(1024,
+ cmsgdatalen)
+ for cmsg_level, cmsg_type, cmsg_data in cmsgdata:
+ if (cmsg_level == socket.SOL_SOCKET and
+ cmsg_type == socket.SCM_RIGHTS):
+ fds.frombytes(cmsg_data[:len(cmsg_data) -
+ (len(cmsg_data) % fds.itemsize)])
+ else:
+ raise Exception("Unexpected CMSGDATA level %d type %d" % (
+ cmsg_level, cmsg_type))
+
+ return data, [self.make_file(fd) for fd in fds]
+
+
+ def send_with_fds(self, data, fds):
+ cfds = [fd.fileno() for fd in fds]
+
+ cmsgdata = [(socket.SOL_SOCKET, socket.SCM_RIGHTS,
+ array.array("i", cfds))]
+
+ return self.clientsock.sendmsg([data], cmsgdata)
+
+
+ @staticmethod
+ def make_file(fd):
+ flags = fcntl.fcntl(fd, fcntl.F_GETFL)
+
+ mask = os.O_RDONLY | os.O_WRONLY | os.O_RDWR | os.O_APPEND
+ flags = flags & mask
+ mode = ""
+ if flags == os.O_RDONLY:
+ mode = "rb"
+ elif flags == os.O_WRONLY:
+ mode = "wb"
+ elif flags == os.O_RDWR:
+ mode = "r+b"
+ elif flags == (os.O_WRONLY | os.O_APPEND):
+ mode = "ab"
+ elif flags == (os.O_RDWR | os.O_APPEND):
+ mode = "a+b"
+
+ return os.fdopen(fd, mode)
+
+
+ def add_client(self, sock):
+ ver = self.conn.getVersion()
+ major = int(ver / 1000000) % 1000
+ minor = int(ver / 1000) % 1000
+ micro = ver % 1000
+
+ greetingobj = {
+ "QMP": {
+ "version": {
+ "qemu": {
+ "major": major,
+ "minor": minor,
+ "micro": micro,
+ },
+ "package": f"qemu-{major}.{minor}.{micro}",
+ },
+ "capabilities": [
+ "oob"
+ ],
+ }
+ }
+ greeting = json.dumps(greetingobj)
+ if self.verbose:
+ print(greeting)
+ greeting += "\r\n"
+
+ self.clientsock = sock
+ self.clientwatch = libvirt.virEventAddHandle(
+ self.clientsock.fileno(), libvirt.VIR_EVENT_HANDLE_WRITABLE,
+ self.handle_client_io, self)
+ self.api2sock += greeting.encode("utf-8")
+ self.update_server_events()
+
+
+ def remove_client(self):
+ libvirt.virEventRemoveHandle(self.clientwatch)
+ self.clientsock.close()
+ self.clientsock = None
+ self.clientwatch = 0
+ self.update_server_events()
+
+ self.api2sock = bytes([])
+ self.api2sockfds = []
+
+ self.sock2api = bytes([])
+ self.sock2apifds = []
+
+
+ def update_client_events(self):
+ # For simplicity of tracking distinct QMP cmds and their passed FDs
+ # we don't try to support "pipelining", only a single cmd may be
+ # inflight
+ if len(self.api2sock) > 0:
+ events = libvirt.VIR_EVENT_HANDLE_WRITABLE
+ else:
+ events = libvirt.VIR_EVENT_HANDLE_READABLE
+
+ libvirt.virEventUpdateHandle(self.clientwatch, events)
+
+
+ def update_server_events(self):
+ if self.clientsock is not None:
+ libvirt.virEventUpdateHandle(self.serverwatch, 0)
+ else:
+ libvirt.virEventUpdateHandle(self.serverwatch,
+ libvirt.VIR_EVENT_HANDLE_READABLE)
+
+
+ def try_command(self):
+ try:
+ cmdstr = self.sock2api.decode("utf-8")
+ cmd = json.loads(cmdstr)
+
+ if self.verbose:
+ cmdstr = cmdstr.strip()
+ print(cmdstr)
+ except Exception as ex:
+ if debug:
+ print("Incomplete %s: %s" % ( self.sock2api, ex))
+ return
+
+ id = None
+ if "id" in cmd:
+ id = cmd["id"]
+ del cmd["id"]
+
+ if cmd.get("execute", "") == "qmp_capabilities":
+ resobj = {
+ "return": {},
+ }
+ resfds = []
+ else:
+ if hasattr(libvirt_qemu, "qemuMonitorCommandWithFiles"):
+ res, resfds = libvirt_qemu.qemuMonitorCommandWithFiles(
+ self.dom, json.dumps(cmd), [f.fileno() for f in self.sock2apifds])
+ resobj = json.loads(res)
+ else:
+ if len(self.sock2apifds) > 0:
+ raise Exception("FD passing not supported")
+ res = libvirt_qemu.qemuMonitorCommand(
+ self.dom, json.dumps(cmd))
+ resfds = []
+ resobj = json.loads(res)
+
+ if "id" in resobj:
+ del resobj["id"]
+ if id is not None:
+ resobj["id"] = id
+
+ res = json.dumps(resobj)
+ if self.verbose:
+ print(res)
+ res += "\r\n"
+
+ self.sock2api = bytes([])
+ self.sock2apifds = []
+ self.api2sock += res.encode("utf-8")
+ self.api2sockfds = resfds
+
+
+ @staticmethod
+ def handle_client_io(watch, fd, events, self):
+ error = False
+ try:
+ if events & libvirt.VIR_EVENT_HANDLE_WRITABLE:
+ done = self.send_with_fds(self.api2sock, self.api2sockfds)
+ if done > 0:
+ self.api2sock = self.api2sock[done:]
+ self.api2sockfds = []
+ elif events & libvirt.VIR_EVENT_HANDLE_READABLE:
+ data, fds = self.recv_with_fds()
+ if len(data) == 0:
+ error = True
+ else:
+ self.sock2api += data
+ if len(fds):
+ self.sock2apifds += fds
+
+ self.try_command()
+ else:
+ error = True
+ except Exception as e:
+ global debug
+ if debug:
+ print("%s: %s" % (sys.argv[0], str(e)))
+ print(traceback.format_exc())
+ error = True
+
+ if error:
+ self.remove_client()
+ else:
+ self.update_client_events()
+
+
+ @staticmethod
+ def handle_server_io(watch, fd, events, self):
+ if self.clientsock is None:
+ sock, addr = self.serversock.accept()
+ self.add_client(sock)
+ else:
+ self.update_server_events()
+
+
+def parse_commandline():
+ parser = argparse.ArgumentParser(description="Libvirt QMP proxy")
+ parser.add_argument("--connect", "-c",
+ help="Libvirt QEMU driver connection URI")
+ parser.add_argument("--debug", "-d", action='store_true',
+ help="Display debugging information")
+ parser.add_argument("--verbose", "-v", action='store_true',
+ help="Display QMP traffic")
+ parser.add_argument("domain", metavar="DOMAIN",
+ help="Libvirt guest domain ID/UUID/Name")
+ parser.add_argument("sockpath", metavar="QMP-SOCK-PATH",
+ help="UNIX socket path for QMP server")
+
+ return parser.parse_args()
+
+
+def main():
+ args = parse_commandline()
+ global debug
+ debug = args.debug
+
+ if not debug:
+ libvirt.registerErrorHandler(lambda opaque, error: None, None)
+
+ libvirt.virEventRegisterDefaultImpl()
+
+ conn, dom = get_domain(args.connect, args.domain)
+
+ if conn.getType() != "QEMU":
+ raise Exception("QMP proxy requires a QEMU driver connection not %s" %
+ conn.getType())
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ if os.path.exists(args.sockpath):
+ os.unlink(args.sockpath)
+ sock.bind(args.sockpath)
+ sock.listen(1)
+
+ proxy = QMPProxy(conn, dom, sock, args.verbose)
+
+ while True:
+ libvirt.virEventRunDefaultImpl()
+
+
+try:
+ main()
+ sys.exit(0)
+except Exception as e:
+ print("%s: %s" % (sys.argv[0], str(e)))
+ if debug:
+ print(traceback.format_exc())
+ sys.exit(1)
--
2.37.3
1 year, 12 months
[PATCH v4 0/7] qemu: tpm: Add support for migration across shared storage
by Stefan Berger
This series of patches adds support for migrating vTPMs across hosts whose
storage has been set up to share the directory structure holding the state
of the TPM (swtpm). The existence of share storage influences the
management of the directory structure holding the TPM state, which for
example is only removed when a domain is undefined and not when a VM is
removed on the migration source host. Further, when shared storage is used
then security labeling on the destination side is skipped assuming that the
labeling was already done on the source side.
I have tested this with an NFS setup where I had to turn SELinux off on
the hosts since the SELinux MLS range labeling is not supported by NFS.
For shared storage support to work properly both sides of the migration
need to be clients of the shared storage setup, meaning that they both have
to have /var/lib/libvirt/swtpm mounted as shared storage, because other-
wise the virFileIsSharedFS() may not detect shared storage and in the
worst case may cause the TPM emulator (swtpm) to malfunction if for
example the source side removed the TPM state directory structure.
Shared storage migration requires (upcoming) swtpm v0.8.
Stefan
v4:
- Fixed long-standing bug regarding offline migration that now blocks if
no shared storage is set up
- Addressed Michal's concerns
v3:
- Relying entirely on virFileIsSharedFS() on migration source and
destination sides to detect whether shared storage is set up between
hosts; no more hint about shared storage from user via flag
- Added support for virDomainTPMPrivate structure to store and persist
TPM-related private data
Stefan Berger (7):
util: Add parsing support for swtpm's cmdarg-migration capability
qemu: tpm: Allow offline migration with TPM_EMULATOR only with shared
storage
qemu: tpm: Conditionally create storage on incoming migration
qemu: tpm: Add support for storing private TPM-related data
qemu: tpm: Pass --migration option to swtpm if supported and needed
qemu: tpm: Avoid security labels on incoming migration with shared
storage
qemu: tpm: Never remove state on outgoing migration and shared storage
src/conf/domain_conf.c | 63 ++++++++++++++++++--
src/conf/domain_conf.h | 9 +++
src/qemu/qemu_domain.c | 85 ++++++++++++++++++++++++--
src/qemu/qemu_domain.h | 17 +++++-
src/qemu/qemu_driver.c | 20 +++----
src/qemu/qemu_extdevice.c | 10 ++--
src/qemu/qemu_extdevice.h | 6 +-
src/qemu/qemu_migration.c | 28 +++++++--
src/qemu/qemu_process.c | 9 ++-
src/qemu/qemu_snapshot.c | 4 +-
src/qemu/qemu_tpm.c | 122 ++++++++++++++++++++++++++++++++++----
src/qemu/qemu_tpm.h | 14 ++++-
src/util/virtpm.c | 1 +
src/util/virtpm.h | 1 +
14 files changed, 339 insertions(+), 50 deletions(-)
--
2.37.3
2 years
[libvirt PATCH v2] Add basically RISC-V support
by Yu Gu
This patch provides basic support for the RISC-V architecture, so
libvirt can run in RISC-V machine.
Signed-off-by: Yu Gu <guyu2876(a)gmail.com>
---
po/POTFILES | 1 +
src/cpu/cpu.c | 2 +
src/cpu/cpu.h | 2 +
src/cpu/cpu_riscv64.c | 118 +++++++++++++++++++++++++++++++
src/cpu/cpu_riscv64.h | 28 ++++++++
src/cpu/cpu_riscv64_data.h | 40 +++++++++++
src/cpu/meson.build | 1 +
src/cpu_map/index.xml | 4 ++
src/cpu_map/meson.build | 1 +
src/cpu_map/riscv64_vendors.xml | 3 +
src/util/virarch.c | 2 +
src/util/virhostcpu.c | 2 +-
src/util/virsysinfo.c | 121 ++++++++++++++++++++++++++++++++
13 files changed, 324 insertions(+), 1 deletion(-)
create mode 100644 src/cpu/cpu_riscv64.c
create mode 100644 src/cpu/cpu_riscv64.h
create mode 100644 src/cpu/cpu_riscv64_data.h
create mode 100644 src/cpu_map/riscv64_vendors.xml
diff --git a/po/POTFILES b/po/POTFILES
index 169e2a41dc..a52795e7c1 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -72,6 +72,7 @@ src/cpu/cpu_map.c
src/cpu/cpu_ppc64.c
src/cpu/cpu_s390.c
src/cpu/cpu_x86.c
+src/cpu/cpu_riscv64.c
src/datatypes.c
src/driver.c
src/esx/esx_driver.c
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index d97ef5e873..8fdc42e719 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -27,6 +27,7 @@
#include "cpu_ppc64.h"
#include "cpu_s390.h"
#include "cpu_arm.h"
+#include "cpu_riscv64.h"
#include "capabilities.h"
@@ -39,6 +40,7 @@ static struct cpuArchDriver *drivers[] = {
&cpuDriverPPC64,
&cpuDriverS390,
&cpuDriverArm,
+ &cpuDriverRISCV64,
};
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index 41a62ce486..6e0a06fce4 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -27,6 +27,7 @@
#include "cpu_x86_data.h"
#include "cpu_ppc64_data.h"
#include "cpu_arm_data.h"
+#include "cpu_riscv64_data.h"
typedef struct _virCPUData virCPUData;
@@ -36,6 +37,7 @@ struct _virCPUData {
virCPUx86Data x86;
virCPUppc64Data ppc64;
virCPUarmData arm;
+ virCPUriscv64Data riscv64;
/* generic driver needs no data */
} data;
};
diff --git a/src/cpu/cpu_riscv64.c b/src/cpu/cpu_riscv64.c
new file mode 100644
index 0000000000..21f7178cc2
--- /dev/null
+++ b/src/cpu/cpu_riscv64.c
@@ -0,0 +1,118 @@
+/*
+ * cpu_riscv64.c: CPU driver for riscv64(x) CPUs
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "cpu.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_CPU
+
+static const virArch archs[] = { VIR_ARCH_RISCV64 };
+
+static virCPUCompareResult
+virCPUriscv64Compare(virCPUDef *host G_GNUC_UNUSED,
+ virCPUDef *cpu G_GNUC_UNUSED,
+ bool failMessages G_GNUC_UNUSED)
+{
+ /* riscv64 relies on QEMU to perform all runability checking. Return
+ * VIR_CPU_COMPARE_IDENTICAL to bypass Libvirt checking.
+ */
+ return VIR_CPU_COMPARE_IDENTICAL;
+}
+
+static int
+virCPUriscv64Update(virCPUDef *guest,
+ const virCPUDef *host,
+ bool relative)
+{
+ g_autoptr(virCPUDef) updated = NULL;
+ size_t i;
+
+ if (!relative)
+ return 0;
+
+ if (guest->mode == VIR_CPU_MODE_CUSTOM) {
+ if (guest->match == VIR_CPU_MATCH_MINIMUM) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("match mode %s not supported"),
+ virCPUMatchTypeToString(guest->match));
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("optional CPU features are not supported"));
+ }
+ return -1;
+ }
+
+ if (!host) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("unknown host CPU model"));
+ return -1;
+ }
+
+ if (!(updated = virCPUDefCopyWithoutModel(guest)))
+ return -1;
+
+ updated->mode = VIR_CPU_MODE_CUSTOM;
+ if (virCPUDefCopyModel(updated, host, true) < 0)
+ return -1;
+
+ for (i = 0; i < guest->nfeatures; i++) {
+ if (virCPUDefUpdateFeature(updated,
+ guest->features[i].name,
+ guest->features[i].policy) < 0)
+ return -1;
+ }
+
+ virCPUDefStealModel(guest, updated, false);
+ guest->mode = VIR_CPU_MODE_CUSTOM;
+ guest->match = VIR_CPU_MATCH_EXACT;
+
+ return 0;
+}
+
+
+static int
+virCPUriscv64ValidateFeatures(virCPUDef *cpu)
+{
+ size_t i;
+
+ for (i = 0; i < cpu->nfeatures; i++) {
+ if (cpu->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("only cpu feature policies 'require' and "
+ "'disable' are supported for %s"),
+ cpu->features[i].name);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+struct cpuArchDriver cpuDriverRISCV64 = {
+ .name = "riscv64",
+ .arch = archs,
+ .narch = G_N_ELEMENTS(archs),
+ .compare = virCPUriscv64Compare,
+ .decode = NULL,
+ .encode = NULL,
+ .baseline = NULL,
+ .update = virCPUriscv64Update,
+ .validateFeatures = virCPUriscv64ValidateFeatures,
+};
diff --git a/src/cpu/cpu_riscv64.h b/src/cpu/cpu_riscv64.h
new file mode 100644
index 0000000000..67528415fe
--- /dev/null
+++ b/src/cpu/cpu_riscv64.h
@@ -0,0 +1,28 @@
+/*
+ * cpu_riscv64.h: CPU driver for 64-bit RISC-V CPUs
+ *
+ * Copyright (C) Copyright (C) IBM Corporation, 2010
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VIR_CPU_RISCV64_H__
+# define __VIR_CPU_RISCV64_H__
+
+# include "cpu.h"
+
+extern struct cpuArchDriver cpuDriverRISCV64;
+
+#endif
diff --git a/src/cpu/cpu_riscv64_data.h b/src/cpu/cpu_riscv64_data.h
new file mode 100644
index 0000000000..819b9e8fde
--- /dev/null
+++ b/src/cpu/cpu_riscv64_data.h
@@ -0,0 +1,40 @@
+/*
+ * cpu_riscv64_data.h: 64-bit riscv64 CPU specific data
+ *
+ * Copyright (C) 2012 IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VIR_CPU_RISCV64_DATA_H__
+# define __VIR_CPU_RISCV64_DATA_H__
+
+# include <stdint.h>
+
+typedef struct _virCPUriscv64Prid virCPUriscv64Prid;
+struct _virCPUriscv64Prid {
+ uint32_t value;
+ uint32_t mask;
+};
+
+# define VIR_CPU_riscv64_DATA_INIT { 0 }
+
+typedef struct _virCPUriscv64Data virCPUriscv64Data;
+struct _virCPUriscv64Data {
+ size_t len;
+ virCPUriscv64Prid *prid;
+};
+
+#endif
diff --git a/src/cpu/meson.build b/src/cpu/meson.build
index b4ad95e46d..eba1d45743 100644
--- a/src/cpu/meson.build
+++ b/src/cpu/meson.build
@@ -5,6 +5,7 @@ cpu_sources = [
'cpu_ppc64.c',
'cpu_s390.c',
'cpu_x86.c',
+ 'cpu_riscv64.c',
]
cpu_lib = static_library(
diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml
index d533a28865..f2c4b1c62a 100644
--- a/src/cpu_map/index.xml
+++ b/src/cpu_map/index.xml
@@ -89,6 +89,10 @@
<include filename='ppc64_POWERPC_e6500.xml'/>
</arch>
+ <arch name='riscv64'>
+ <include filename='riscv64_vendors.xml'/>
+ </arch>
+
<arch name='arm'>
<include filename='arm_vendors.xml'/>
<include filename='arm_features.xml'/>
diff --git a/src/cpu_map/meson.build b/src/cpu_map/meson.build
index 99264289e2..1a02df8268 100644
--- a/src/cpu_map/meson.build
+++ b/src/cpu_map/meson.build
@@ -19,6 +19,7 @@ cpumap_data = [
'ppc64_POWERPC_e5500.xml',
'ppc64_POWERPC_e6500.xml',
'ppc64_vendors.xml',
+ 'riscv64_vendors.xml',
'x86_486.xml',
'x86_athlon.xml',
'x86_Broadwell-IBRS.xml',
diff --git a/src/cpu_map/riscv64_vendors.xml b/src/cpu_map/riscv64_vendors.xml
new file mode 100644
index 0000000000..478a23a467
--- /dev/null
+++ b/src/cpu_map/riscv64_vendors.xml
@@ -0,0 +1,3 @@
+<cpus>
+ <vendor name='RISC-V'/>
+</cpus>
\ No newline at end of file
diff --git a/src/util/virarch.c b/src/util/virarch.c
index 2134dd6a9d..3d14ecd193 100644
--- a/src/util/virarch.c
+++ b/src/util/virarch.c
@@ -190,6 +190,8 @@ virArch virArchFromHost(void)
return VIR_ARCH_ALPHA;
case PROCESSOR_ARCHITECTURE_PPC:
return VIR_ARCH_PPC;
+ case PROCESSOR_ARCHITECTURE_RISCV:
+ return VIR_ARCH_RISCV64;
case PROCESSOR_ARCHITECTURE_SHX:
return VIR_ARCH_SH4;
case PROCESSOR_ARCHITECTURE_ARM:
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
index c1e8dc8078..08c2290f00 100644
--- a/src/util/virhostcpu.c
+++ b/src/util/virhostcpu.c
@@ -544,7 +544,7 @@ virHostCPUParseFrequency(FILE *cpuinfo,
char line[1024];
/* No sensible way to retrieve CPU frequency */
- if (ARCH_IS_ARM(arch))
+ if (ARCH_IS_ARM(arch) || ARCH_IS_RISCV(arch))
return 0;
if (ARCH_IS_X86(arch))
diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c
index 376d5d4816..e281d928c7 100644
--- a/src/util/virsysinfo.c
+++ b/src/util/virsysinfo.c
@@ -623,6 +623,125 @@ virSysinfoReadS390(void)
return g_steal_pointer(&ret);
}
+#if 0
+static int
+virSysinfoParseRISCVSystem(const char *base, virSysinfoSystemDef **sysdef)
+{
+ int ret = -1;
+ virSysinfoSystemDef *def;
+
+ def = g_new0(virSysinfoSystemDef, 1);
+
+#if 0
+ if (!virSysinfoParseS390Line(base, "Manufacturer", &def->manufacturer))
+ goto cleanup;
+
+ if (!virSysinfoParseS390Line(base, "Type", &def->family))
+ goto cleanup;
+#endif
+ def->manufacturer = g_strndup("Virt-RISC-V", sizeof("Virt RISC-V"));
+
+ if (!def->manufacturer && !def->product && !def->version &&
+ !def->serial && !def->uuid && !def->sku && !def->family) {
+ g_clear_pointer(&def, virSysinfoSystemDefFree);
+ }
+
+ *sysdef = g_steal_pointer(&def);
+ ret = 0;
+ cleanup:
+ virSysinfoSystemDefFree(def);
+ return ret;
+}
+#endif
+
+static int
+virSysinfoParseRISCVProcessor(const char *base, virSysinfoDef *ret)
+{
+ const char *tmp_base;
+ char *manufacturer = NULL;
+ char *procline = NULL;
+ char *ncpu = NULL;
+ int result = -1;
+ virSysinfoProcessorDef *processor;
+
+ if (!(tmp_base = virSysinfoParseS390Line(base, "uarch", &manufacturer)))
+ goto error;
+
+ /* Find processor N: line and gather the processor manufacturer,
+ version, serial number, and family */
+ while ((tmp_base = strstr(tmp_base, "processor "))
+ && (tmp_base = virSysinfoParseS390Line(tmp_base, "processor ",
+ &procline))) {
+ VIR_EXPAND_N(ret->processor, ret->nprocessor, 1);
+ processor = &ret->processor[ret->nprocessor - 1];
+ processor->processor_manufacturer = g_strdup(manufacturer);
+
+ VIR_FREE(procline);
+ }
+
+ /* now, for each processor found, extract the frequency information */
+ tmp_base = base;
+
+ while ((tmp_base = strstr(tmp_base, "hart")) &&
+ (tmp_base = virSysinfoParseS390Line(tmp_base, "hart", &ncpu))) {
+ unsigned int n;
+ char *mhz = NULL;
+
+ if (virStrToLong_uip(ncpu, NULL, 10, &n) < 0)
+ goto error;
+
+ if (n >= ret->nprocessor) {
+ VIR_DEBUG("CPU number '%u' out of range", n);
+ goto cleanup;
+ }
+
+ VIR_FREE(ncpu);
+ }
+
+ cleanup:
+ result = 0;
+
+ error:
+ VIR_FREE(manufacturer);
+ VIR_FREE(procline);
+ VIR_FREE(ncpu);
+ return result;
+}
+
+virSysinfoDef *
+virSysinfoReadRISCV(void)
+{
+ g_autoptr(virSysinfoDef) ret = NULL;
+ g_autofree char *outbuf = NULL;
+
+ ret = g_new0(virSysinfoDef, 1);
+
+ /* Gather info from /proc/cpuinfo */
+ if (virFileReadAll(CPUINFO, CPUINFO_FILE_LEN, &outbuf) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to open %s"), CPUINFO);
+ return NULL;
+ }
+
+ if (virSysinfoParseRISCVProcessor(outbuf, ret) < 0)
+ return NULL;
+
+ /* Free buffer before reading next file */
+ VIR_FREE(outbuf);
+
+#if 0
+ /* Gather info from /proc/sysinfo */
+ if (virFileReadAll(SYSINFO, 8192, &outbuf) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to open %s"), SYSINFO);
+ return NULL;
+ }
+
+ if (virSysinfoParseRISCVSystem(outbuf, &ret->system) < 0)
+ return NULL;
+#endif
+ return g_steal_pointer(&ret);
+}
static int
virSysinfoParseBIOS(const char *base, virSysinfoBIOSDef **bios)
@@ -1243,6 +1362,8 @@ virSysinfoRead(void)
return virSysinfoReadPPC();
#elif defined(__arm__) || defined(__aarch64__)
return virSysinfoReadARM();
+#elif defined(__riscv) && __riscv_xlen == 64
+ return virSysinfoReadRISCV();
#elif defined(__s390__) || defined(__s390x__)
return virSysinfoReadS390();
#elif !defined(WIN32) && \
--
2.37.3
2 years
questions regarding modular daemons
by Jim Fehlig
Hi All,
I've procrastinated long enough and finally decided to switch to modular daemons
in openSUSE Factory libvirt package. For the most part, the Factory spec file
mimics the upstream one. I enabled with_modular_daemons and would like to
confirm the results of my testing.
When upgrading an existing installation running the monolithic daemon, the
monolithic daemon is still enabled after the upgrade. I suppose this behavior is
expected, and fine IMO.
However, when installing the "modularized" packages on a system with no prior
installation, the monolithic daemon is still installed and potentially enabled
in posttrans. Having both the monolithic and modular daemons installed, along
with all associated systemd socket and service files, is a bit confusing to
users IMO. E.g. should one enable libvirtd sockets, virtqemud sockets, both?
Is the intention, over time, to remove the monolithic daemon? Perhaps we could
start by isolating the monolithic daemon in the libvirt-daemon subpackage and
moving the other daemons (virtproxyd, virtlogd, virtlockd, etc) to a new
subpackage? The modular daemons could then drop the libvirt-daemon dependency,
allowing installation without the monolithic daemon.
TIA for your comments.
Regards,
Jim
2 years
[libvirt][PATCH v16 1/9] domain_capabilities: Define SGX capabilities structs
by Lin Yang
From: Haibin Huang <haibin.huang(a)intel.com>
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
Signed-off-by: Haibin Huang <haibin.huang(a)intel.com>
---
src/conf/domain_capabilities.c | 11 +++++++++++
src/conf/domain_capabilities.h | 22 ++++++++++++++++++++++
src/libvirt_private.syms | 1 +
3 files changed, 34 insertions(+)
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index 653123f293..869b5d68e6 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -76,6 +76,17 @@ virSEVCapabilitiesFree(virSEVCapability *cap)
}
+void
+virSGXCapabilitiesFree(virSGXCapability *cap)
+{
+ if (!cap)
+ return;
+
+ g_free(cap->sgxSections);
+ g_free(cap);
+}
+
+
static void
virDomainCapsDispose(void *obj)
{
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index a526969cda..3c9fd7f7de 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -193,6 +193,22 @@ struct _virSEVCapability {
unsigned int max_es_guests;
};
+typedef struct _virSGXSection virSGXSection;
+struct _virSGXSection {
+ unsigned long long size;
+ unsigned int node;
+};
+
+typedef struct _virSGXCapability virSGXCapability;
+struct _virSGXCapability {
+ bool flc;
+ bool sgx1;
+ bool sgx2;
+ unsigned long long section_size;
+ size_t nSgxSections;
+ virSGXSection *sgxSections;
+};
+
typedef enum {
VIR_DOMAIN_CAPS_FEATURE_IOTHREADS = 0,
VIR_DOMAIN_CAPS_FEATURE_VMCOREINFO,
@@ -229,6 +245,7 @@ struct _virDomainCaps {
virDomainCapsFeatureGIC gic;
virSEVCapability *sev;
+ virSGXCapability *sgx;
/* add new domain features here */
virTristateBool features[VIR_DOMAIN_CAPS_FEATURE_LAST];
@@ -277,3 +294,8 @@ void
virSEVCapabilitiesFree(virSEVCapability *capabilities);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSEVCapability, virSEVCapabilitiesFree);
+
+void
+virSGXCapabilitiesFree(virSGXCapability *capabilities);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 00cb07709d..97b019d00a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -218,6 +218,7 @@ virDomainCapsEnumSet;
virDomainCapsFormat;
virDomainCapsNew;
virSEVCapabilitiesFree;
+virSGXCapabilitiesFree;
# conf/domain_conf.h
--
2.25.1
2 years
[PATCH] cpu_map: Add cpu feature amx
by Lin Yang
AMX was introduced in QEMU commit 1f16764f7d4515bfd5e4ae0aae814fa280a7d0c8
and following commits.
---
src/cpu_map/sync_qemu_i386.py | 3 +++
src/cpu_map/x86_features.xml | 9 +++++++++
2 files changed, 12 insertions(+)
diff --git a/src/cpu_map/sync_qemu_i386.py b/src/cpu_map/sync_qemu_i386.py
index 4dd9f3b84d..6a46f87cff 100755
--- a/src/cpu_map/sync_qemu_i386.py
+++ b/src/cpu_map/sync_qemu_i386.py
@@ -72,6 +72,9 @@ def translate_feature(name):
"CPUID_7_0_EDX_SPEC_CTRL": "spec-ctrl",
"CPUID_7_0_EDX_SPEC_CTRL_SSBD": "ssbd",
"CPUID_7_0_EDX_STIBP": "stibp",
+ "CPUID_7_0_EDX_AMX_BF16": "amx-bf16",
+ "CPUID_7_0_EDX_AMX_TILE": "amx-tile",
+ "CPUID_7_0_EDX_AMX_INT8": "amx-int8",
"CPUID_7_1_EAX_AVX512_BF16": "avx512-bf16",
"CPUID_7_1_EAX_AVX_VNNI": "avx-vnni",
"CPUID_8000_0008_EBX_AMD_SSBD": "amd-ssbd",
diff --git a/src/cpu_map/x86_features.xml b/src/cpu_map/x86_features.xml
index 4cf3ff0804..102d39f626 100644
--- a/src/cpu_map/x86_features.xml
+++ b/src/cpu_map/x86_features.xml
@@ -347,6 +347,15 @@
<feature name='pconfig'>
<cpuid eax_in='0x07' ecx_in='0x00' edx='0x00040000'/>
</feature>
+ <feature name='amx-bf16'>
+ <cpuid eax_in='0x07' ecx_in='0x00' edx='0x00400000'/>
+ </feature>
+ <feature name='amx-tile'>
+ <cpuid eax_in='0x07' ecx_in='0x00' edx='0x01000000'/>
+ </feature>
+ <feature name='amx-int8'>
+ <cpuid eax_in='0x07' ecx_in='0x00' edx='0x02000000'/>
+ </feature>
<feature name='spec-ctrl'>
<cpuid eax_in='0x07' ecx_in='0x00' edx='0x04000000'/>
</feature>
--
2.34.1
2 years, 1 month
[libvirt PATCH v2 00/24] Synchronize x86 cpu features from qemu
by Tim Wiederhake
V1: https://listman.redhat.com/archives/libvir-list/2022-October/235007.html
Changes since V1:
* Fixed register for features "sgx1" and "sgx2". Double checked all other
features, just to be sure.
* Addes missing help message in sync_qemu_i386_features.py.
* Merged all eax=0x12 ecx=0x01 features (sgx-...).
Thanks Jiri for the review.
> I'm not sure about the "for now" part here [patch #2, "cpu_x86: Ignore
> alias names"]. Do you think we can do something clever with them while
> still not accepting them in domain XML (accepting aliases in the XML
> would just make such XMLs unnecessarily incompatible with older libvirt
> releases)?
I am planning on using this information in virQEMUCapsCPUFeatureTranslate.
Would be nice if we could deduplicate the information of how to translate
qemu feature names into libvirt names. I agree that we should not accept
the alias names in XML.
Tim Wiederhake (24):
cpu-data.py: Allow for more than child in feature nodes
cpu_x86: Ignore alias names
cpu: make x86 feature alias names machine readable
cpu_map: Add script to sync from QEMU i386 cpu features
cpu_map: Rename sync_qemu_i386.py
cpu_map: Add missing x86 feature alias names
cpu_map: Add missing x86 feature "sgx"
cpu_map: Add missing x86 feature "sgxlc"
cpu_map: Add missing x86 feature "sgx-exinfo"
cpu_map: Add missing x86 feature "sgx1"
cpu_map: Add missing x86 feature "sgx2"
cpu_map: Add missing x86 features "sgx-..."
cpu_map: Add missing x86 feature "bus-lock-detect"
cpu_map: Add missing x86 feature "pks"
cpu_map: Add missing x86 feature "avx512-vp2intersect"
cpu_map: Add missing x86 feature "avx512-fp16"
cpu_map: Add missing x86 feature "serialize"
cpu_map: Add missing x86 feature "tsx-ldtrk"
cpu_map: Add missing x86 feature "arch-lbr"
cpu_map: Add missing x86 feature "xfd"
cpu_map: Add missing x86 feature "intel-pt-lip"
cpu_map: Add missing x86 feature "avic"
cpu_map: Add missing x86 feature "v-vmsave-vmload"
cpu_map: Add missing x86 feature "vgif"
src/cpu/cpu_x86.c | 10 +-
src/cpu_map/sync_qemu_features_i386.py | 278 ++++++++++++++++++
..._qemu_i386.py => sync_qemu_models_i386.py} | 0
src/cpu_map/x86_features.xml | 133 +++++++--
tests/cputestdata/cpu-data.py | 11 +-
.../x86_64-cpuid-Atom-P5362-disabled.xml | 1 +
.../x86_64-cpuid-Atom-P5362-guest.xml | 1 +
.../x86_64-cpuid-Atom-P5362-host.xml | 1 +
.../x86_64-cpuid-Core-i7-7600U-disabled.xml | 2 +-
.../x86_64-cpuid-Core-i7-7600U-guest.xml | 1 +
.../x86_64-cpuid-Core-i7-7600U-host.xml | 1 +
.../x86_64-cpuid-Core-i7-7700-disabled.xml | 2 +-
.../x86_64-cpuid-Core-i7-7700-guest.xml | 1 +
.../x86_64-cpuid-Core-i7-7700-host.xml | 1 +
.../x86_64-cpuid-Core-i7-8550U-disabled.xml | 2 +-
.../x86_64-cpuid-Core-i7-8550U-guest.xml | 1 +
.../x86_64-cpuid-Core-i7-8550U-host.xml | 1 +
.../x86_64-cpuid-Core-i7-8700-disabled.xml | 2 +-
.../x86_64-cpuid-Core-i7-8700-guest.xml | 2 +
.../x86_64-cpuid-Core-i7-8700-host.xml | 2 +
...86_64-cpuid-EPYC-7502-32-Core-disabled.xml | 2 +-
.../x86_64-cpuid-EPYC-7502-32-Core-guest.xml | 3 +
.../x86_64-cpuid-EPYC-7502-32-Core-host.xml | 3 +
...86_64-cpuid-EPYC-7601-32-Core-disabled.xml | 2 +-
.../x86_64-cpuid-EPYC-7601-32-Core-guest.xml | 3 +
.../x86_64-cpuid-EPYC-7601-32-Core-host.xml | 3 +
...-cpuid-EPYC-7601-32-Core-ibpb-disabled.xml | 2 +-
..._64-cpuid-EPYC-7601-32-Core-ibpb-guest.xml | 3 +
...6_64-cpuid-EPYC-7601-32-Core-ibpb-host.xml | 3 +
...-cpuid-Hygon-C86-7185-32-core-disabled.xml | 2 +-
..._64-cpuid-Hygon-C86-7185-32-core-guest.xml | 3 +
...6_64-cpuid-Hygon-C86-7185-32-core-host.xml | 3 +
.../x86_64-cpuid-Ice-Lake-Server-disabled.xml | 2 +-
.../x86_64-cpuid-Ice-Lake-Server-guest.xml | 2 +
.../x86_64-cpuid-Ice-Lake-Server-host.xml | 2 +
...puid-Ryzen-7-1800X-Eight-Core-disabled.xml | 2 +-
...4-cpuid-Ryzen-7-1800X-Eight-Core-guest.xml | 3 +
...64-cpuid-Ryzen-7-1800X-Eight-Core-host.xml | 3 +
...4-cpuid-Ryzen-9-3900X-12-Core-disabled.xml | 2 +-
...6_64-cpuid-Ryzen-9-3900X-12-Core-guest.xml | 3 +
...86_64-cpuid-Ryzen-9-3900X-12-Core-host.xml | 3 +
.../x86_64-cpuid-Xeon-E3-1225-v5-disabled.xml | 2 +-
.../x86_64-cpuid-Xeon-E3-1225-v5-guest.xml | 1 +
.../x86_64-cpuid-Xeon-E3-1225-v5-host.xml | 1 +
.../x86_64-cpuid-Xeon-E3-1245-v5-disabled.xml | 2 +-
.../x86_64-cpuid-Xeon-E3-1245-v5-guest.xml | 1 +
.../x86_64-cpuid-Xeon-E3-1245-v5-host.xml | 1 +
.../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 1 +
.../domaincapsdata/qemu_6.1.0-tcg.x86_64.xml | 1 +
.../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 2 +
.../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 2 +
.../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 2 +
52 files changed, 487 insertions(+), 36 deletions(-)
create mode 100755 src/cpu_map/sync_qemu_features_i386.py
rename src/cpu_map/{sync_qemu_i386.py => sync_qemu_models_i386.py} (100%)
--
2.36.1
2 years, 1 month
[PATCH 00/43] Remove XPath parser functions using 'long' type
by Peter Krempa
Clean up the XML parser functions to avoid use of the long type.
Peter Krempa (43):
util: xml: Remove unused virXPathNumber
util: xml: Unexport virXMLXPathContextNew
util: xml: Ensure proper header style in virxml.c
util: xml: Use consistent naming for RNG validation error handling
functions
util: xml: Remove unused 'virXPathLongHex'
virNodeDevCapsDefParseULong: Use virXPathUInt instead of virXPathULong
conf: node_device: Rename virNodeDevCapsDefParseULong to
virNodeDevCapsDefParseUInt
virNodeDeviceCapPCIDefFormat: Use %u for unsigned values
conf: Always use 'string()' conversion with virXPath(U)LongLong
util: xml: Extract XPath evaluation for strings
util: xml: Remove double->(u)ll conversion in virXPath(U)LongLong
util: xml: Disallow aliasing of negative numbers in virXPathULongLong
conf: node_device: Use 'string()' in XPath expressions for
virNodeDevCapsDefParseUInt
conf: node_device: Convert rest of virXPathUInt XPath expressions to
number
conf: node_device: Use 'string()' in XPath expressions for
virNodeDevCapsDefParseIntOptional
conf: numa: Don't fetch XML node count in virDomainNumatuneParseXML
conf: cpu: Extract and refactor parsing of cache from
virCPUDefParseXML
util: xml: Reimplement virXPath(U)Int via virXPathEvalString
util: xml: Introduce virXPathU(Int|LongLong)Base
virNodeDevCapsDefParseHexId: Use 'virXPathUIntBase'
util: xml: Disallow aliasing of negative numbers in virXPathUInt
testParseNodeInfo: Rewrite to virXPathU(Int|LongLong)
conf: domain: Convert from virXPathLong
util: xml: Remove virXPathLong
virQEMUCapsLoadCache: Use 'virXMLPropUInt' instead of 'virXPathULong'
virNetDevIPRouteParseXML: Refactor to use 'virXMLProp*' instead of
XPath
virNetworkIPDefParseXML: Use virXMLPropUInt instead of virXPathULong
virInterfaceDefParseMtu: Use virXPathUInt instead of virXPathULong
virNetDevVlanParse: Use virXMLProp* helpers instead of XPath lookups
virDomainTimerCatchupDef: Change members to 'unsigned long long'
virDomainTimerDefParseXML: Refactor cleanup
virDomainTimerDef: Convert 'name' field to proper enum type
virDomainTimerDef: Convert 'tickpolicy' field to proper enum type
virDomainTimerDef: Convert 'track' field to proper enum type
virDomainTimerDef: Convert 'mode' field to proper enum type
virDomainTimerDefParseXML: Use virXMLProp instead of virXPath
virDomainNetDef: Change type of 'tune.sndbuf'
virDomainSEVDefParseXML: Use virXPathUIntBase instead of
virXPathULongHex
ppc64ModelParse: Switch to virXMLPropUInt from virXPathULongHex
qemuDomainObjPrivateXMLParseBlockjobData: Use virXMLPropUInt instead
of virXPathULongHex
virDomainJobObj: Use 'unsigned int' instead of 'unsigned long' for
'apiFlags' field
cpu_arm: Avoid use of 'unsigned long'
util: xml: Remove unused virXPathULong*
src/conf/cpu_conf.c | 58 +--
src/conf/domain_conf.c | 153 +++-----
src/conf/domain_conf.h | 16 +-
src/conf/interface_conf.c | 14 +-
src/conf/netdev_vlan_conf.c | 39 +-
src/conf/network_conf.c | 25 +-
src/conf/networkcommon_conf.c | 61 +--
src/conf/networkcommon_conf.h | 3 +-
src/conf/node_device_conf.c | 160 ++++----
src/conf/numa_conf.c | 7 +-
src/conf/storage_conf.c | 4 +-
src/conf/virdomainjob.c | 4 +-
src/conf/virdomainjob.h | 4 +-
src/cpu/cpu_arm.c | 37 +-
src/cpu/cpu_arm_data.h | 4 +-
src/cpu/cpu_ppc64.c | 19 +-
src/libvirt_private.syms | 8 +-
src/libxl/libxl_conf.c | 6 +-
src/libxl/xen_common.c | 6 +-
src/qemu/qemu_capabilities.c | 7 +-
src/qemu/qemu_command.c | 7 +
src/qemu/qemu_domain.c | 5 +-
src/qemu/qemu_domainjob.c | 7 +-
src/qemu/qemu_migration.c | 2 +-
src/qemu/qemu_migration_params.c | 8 +-
src/qemu/qemu_migration_params.h | 4 +-
src/qemu/qemu_process.c | 2 +-
src/qemu/qemu_process.h | 2 +-
src/qemu/qemu_validate.c | 8 +
src/test/test_driver.c | 51 +--
src/util/virxml.c | 370 ++++++------------
src/util/virxml.h | 32 +-
.../pci_0000_00_02_0_header_type.xml | 2 +-
33 files changed, 432 insertions(+), 703 deletions(-)
--
2.37.3
2 years, 1 month
[PATCH 0/6] Implement XML validation feature for node devices and storage volumes
by Peter Krempa
In the last round of adding support for built-in validation the node
device APIs and storage volume creation were not covered.
Note that due to the close freeze date I've already marked the APIs for
v8.10.
Peter Krempa (6):
conf: node_device: Add 'validate' argument to virNodeDeviceDefParse
nodedev: Add VIR_NODE_DEVICE_(CREATE|DEFINE)_XML_VALIDATE flags
nodedev|test: Implement support for validating node device XMLs
conf: storage: Add support for validating storage vol XML to
virStorageVolDefParse
storage: Add VIR_STORAGE_VOL_CREATE_VALIDATE flag
storage|test|vbox: Implement support for validating storage volume
XMLs
docs/manpages/virsh.rst | 19 +++++++++++++++----
include/libvirt/libvirt-nodedev.h | 19 +++++++++++++++++++
include/libvirt/libvirt-storage.h | 1 +
src/conf/node_device_conf.c | 5 +++--
src/conf/node_device_conf.h | 3 ++-
src/conf/storage_conf.c | 3 ++-
src/conf/storage_conf.h | 2 ++
src/hypervisor/domain_driver.c | 6 +++---
src/libvirt-nodedev.c | 4 ++--
src/node_device/node_device_driver.c | 10 ++++++----
src/storage/storage_driver.c | 18 ++++++++++++++----
src/test/test_driver.c | 24 +++++++++++++++++-------
src/vbox/vbox_storage.c | 8 ++++++--
tests/nodedevmdevctltest.c | 4 ++--
tests/nodedevxml2xmltest.c | 3 ++-
tools/virsh-nodedev.c | 20 ++++++++++++++++++--
tools/virsh-volume.c | 14 ++++++++++++++
17 files changed, 128 insertions(+), 35 deletions(-)
--
2.37.3
2 years, 1 month