[PATCH] util: Add phys_port_name support on virPCIGetNetName
by Dmytro Linkin
Current virPCIGetNetName() logic is to get net device name by checking
it's phys_port_id, if caller provide it, or by it's index (eg, by it's
position at sysfs net directory). This approach worked fine up until
linux kernel version 5.8, where NVIDIA Mellanox driver implemented
linking of VFs' representors to PCI device in switchdev mode. This mean
that device's sysfs net directory will hold multiple net devices. Ex.:
$ ls '/sys/bus/pci/devices/0000:82:00.0/net'
ens1f0 eth0 eth1
Most switch devices support phys_port_name instead of phys_port_id, so
virPCIGetNetName() will try to get PF name by it's index - 0. The
problem here is that the PF nedev entry may not be the first.
To fix that, for switch devices, we introduce a new logic to select the
PF uplink netdev according to the content of phys_port_name. Extend
virPCIGetNetName() with physPortNameRegex variable to get proper device
by it's phys_port_name scheme, for ex., "p[0-9]+$" to get PF,
"pf[0-9]+vf[0-9]+$" to get VF or "p1$" to get exact net device. So now
virPCIGetNetName() logic work in following sequence:
- filter by phys_port_id, if it's provided,
or
- filter by phys_port_name, if it's regex provided,
or
- get net device by it's index (position) in sysfs net directory.
Also, make getting content of iface sysfs files more generic.
Signed-off-by: Dmytro Linkin <dlinkin(a)nvidia.com>
Reviewed-by: Adrian Chiris <adrianc(a)nvidia.com>
---
src/hypervisor/virhostdev.c | 2 +-
src/util/virnetdev.c | 74 ++++++++++++++++++++++++++++++++++++---------
src/util/virnetdev.h | 4 +++
src/util/virpci.c | 63 ++++++++++++++++++++++++++++++++++++--
src/util/virpci.h | 6 ++++
5 files changed, 130 insertions(+), 19 deletions(-)
diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c
index 69102b8..1f5c347 100644
--- a/src/hypervisor/virhostdev.c
+++ b/src/hypervisor/virhostdev.c
@@ -333,7 +333,7 @@ virHostdevNetDevice(virDomainHostdevDefPtr hostdev,
* type='hostdev'>, and it is only those devices that should
* end up calling this function.
*/
- if (virPCIGetNetName(sysfs_path, 0, NULL, linkdev) < 0)
+ if (virPCIGetNetName(sysfs_path, 0, NULL, NULL, linkdev) < 0)
return -1;
if (!(*linkdev)) {
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index b42fa86..99e3b35 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -1112,6 +1112,29 @@ virNetDevGetPCIDevice(const char *devName)
}
+/* A wrapper to get content of file from ifname SYSFS_NET_DIR
+ */
+static int
+virNetDevGetSysfsFileValue(const char *ifname,
+ const char *fileName,
+ char **sysfsFileData)
+{
+ g_autofree char *sysfsFile = NULL;
+
+ *sysfsFileData = NULL;
+
+ if (virNetDevSysfsFile(&sysfsFile, ifname, fileName) < 0)
+ return -1;
+
+ /* a failure to read just means the driver doesn't support
+ * <fileName>, so set success now and ignore the return from
+ * virFileReadAllQuiet().
+ */
+
+ ignore_value(virFileReadAllQuiet(sysfsFile, 1024, sysfsFileData));
+ return 0;
+}
+
/**
* virNetDevGetPhysPortID:
*
@@ -1130,20 +1153,29 @@ int
virNetDevGetPhysPortID(const char *ifname,
char **physPortID)
{
- g_autofree char *physPortIDFile = NULL;
-
- *physPortID = NULL;
-
- if (virNetDevSysfsFile(&physPortIDFile, ifname, "phys_port_id") < 0)
- return -1;
+ return virNetDevGetSysfsFileValue(ifname, "phys_port_id", physPortID);
+}
- /* a failure to read just means the driver doesn't support
- * phys_port_id, so set success now and ignore the return from
- * virFileReadAllQuiet().
- */
- ignore_value(virFileReadAllQuiet(physPortIDFile, 1024, physPortID));
- return 0;
+/**
+ * virNetDevGetPhysPortName:
+ *
+ * @ifname: name of a netdev
+ *
+ * @physPortName: pointer to char* that will receive @ifname's
+ * phys_port_name from sysfs (null terminated
+ * string). Could be NULL if @ifname's net driver doesn't
+ * support phys_port_name (most netdev drivers
+ * don't). Caller is responsible for freeing the string
+ * when finished.
+ *
+ * Returns 0 on success or -1 on failure.
+ */
+int
+virNetDevGetPhysPortName(const char *ifname,
+ char **physPortName)
+{
+ return virNetDevGetSysfsFileValue(ifname, "phys_port_name", physPortName);
}
@@ -1200,7 +1232,7 @@ virNetDevGetVirtualFunctions(const char *pfname,
}
if (virPCIGetNetName(pci_sysfs_device_link, 0,
- pfPhysPortID, &((*vfname)[i])) < 0) {
+ pfPhysPortID, NULL, &((*vfname)[i])) < 0) {
goto cleanup;
}
@@ -1295,7 +1327,8 @@ virNetDevGetPhysicalFunction(const char *ifname, char **pfname)
return -1;
if (virPCIGetNetName(physfn_sysfs_path, 0,
- vfPhysPortID, pfname) < 0) {
+ vfPhysPortID,
+ VIR_PF_PHYS_PORT_NAME_REGEX, pfname) < 0) {
return -1;
}
@@ -1358,7 +1391,7 @@ virNetDevPFGetVF(const char *pfname, int vf, char **vfname)
* isn't bound to a netdev driver, it won't have a netdev name,
* and vfname will be NULL).
*/
- return virPCIGetNetName(virtfnSysfsPath, 0, pfPhysPortID, vfname);
+ return virPCIGetNetName(virtfnSysfsPath, 0, pfPhysPortID, NULL, vfname);
}
@@ -1403,6 +1436,17 @@ virNetDevGetPhysPortID(const char *ifname G_GNUC_UNUSED,
}
int
+virNetDevGetPhysPortName(const char *ifname G_GNUC_UNUSED,
+ char **physPortName)
+{
+ /* this actually should never be called, and is just here to
+ * satisfy the linker.
+ */
+ *physPortName = NULL;
+ return 0;
+}
+
+int
virNetDevGetVirtualFunctions(const char *pfname G_GNUC_UNUSED,
char ***vfname G_GNUC_UNUSED,
virPCIDeviceAddressPtr **virt_fns G_GNUC_UNUSED,
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index 55e3948..712421d 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -229,6 +229,10 @@ int virNetDevGetPhysPortID(const char *ifname,
char **physPortID)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
G_GNUC_WARN_UNUSED_RESULT;
+int virNetDevGetPhysPortName(const char *ifname,
+ char **physPortName)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ G_GNUC_WARN_UNUSED_RESULT;
int virNetDevGetVirtualFunctions(const char *pfname,
char ***vfname,
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 47c671d..18b3f66 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -2409,8 +2409,10 @@ virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
* virPCIGetNetName:
* @device_link_sysfs_path: sysfs path to the PCI device
* @idx: used to choose which netdev when there are several
- * (ignored if physPortID is set)
+ * (ignored if physPortID or physPortNameRegex is set)
* @physPortID: match this string in the netdev's phys_port_id
+ * (or NULL to ignore and use phys_port_name or idx instead)
+ * @physPortNameRegex: match this regex with netdev's phys_port_name
* (or NULL to ignore and use idx instead)
* @netname: used to return the name of the netdev
* (set to NULL (but returns success) if there is no netdev)
@@ -2421,11 +2423,13 @@ int
virPCIGetNetName(const char *device_link_sysfs_path,
size_t idx,
char *physPortID,
+ char *physPortNameRegex,
char **netname)
{
g_autofree char *pcidev_sysfs_net_path = NULL;
g_autofree char *firstEntryName = NULL;
g_autofree char *thisPhysPortID = NULL;
+ g_autofree char *thisPhysPortName = NULL;
int ret = -1;
DIR *dir = NULL;
struct dirent *entry = NULL;
@@ -2466,6 +2470,41 @@ virPCIGetNetName(const char *device_link_sysfs_path,
continue;
}
+ } else if (physPortNameRegex) {
+ /* Most switch devices use phys_port_name instead of
+ * phys_port_id.
+ * NOTE: VFs' representors net devices can be linked to PF's PCI
+ * device, which mean that there'll be multiple net devices
+ * instances and to get a proper net device need to match on
+ * specific regex.
+ * To get PF netdev, for ex., used following regex:
+ * "(p[0-9]+$)|(p[0-9]+s[0-9]+$)"
+ * or to get exact VF's netdev next regex is used:
+ * "pf0vf1$"
+ */
+ if (virNetDevGetPhysPortName(entry->d_name, &thisPhysPortName) < 0)
+ goto cleanup;
+
+ if (thisPhysPortName) {
+ /* if this one doesn't match, keep looking */
+ if (!virStringMatch(thisPhysPortName, physPortNameRegex)) {
+ VIR_FREE(thisPhysPortName);
+ /* Save the first entry we find to use as a failsafe
+ * in case we fail to match on regex.
+ */
+ if (!firstEntryName)
+ firstEntryName = g_strdup(entry->d_name);
+
+ continue;
+ }
+ } else {
+ /* Save the first entry we find to use as a failsafe in case
+ * phys_port_name is not supported.
+ */
+ if (!firstEntryName)
+ firstEntryName = g_strdup(entry->d_name);
+ continue;
+ }
} else {
if (i++ < idx)
continue;
@@ -2494,6 +2533,22 @@ virPCIGetNetName(const char *device_link_sysfs_path,
"phys_port_id '%s' under PCI device at %s"),
physPortID, device_link_sysfs_path);
}
+ } else if (physPortNameRegex) {
+ if (firstEntryName) {
+ /* We didn't match the provided phys_port_name regex, probably
+ * because kernel or NIC driver doesn't support it, so just
+ * return first netname we found.
+ */
+ *netname = firstEntryName;
+ firstEntryName = NULL;
+ ret = 0;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not find network device with "
+ "phys_port_name matching regex '%s' "
+ "under PCI device at %s"),
+ physPortNameRegex, device_link_sysfs_path);
+ }
} else {
ret = 0; /* no netdev at the given index is *not* an error */
}
@@ -2539,7 +2594,7 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path,
* correct.
*/
if (pfNetDevIdx == -1) {
- if (virPCIGetNetName(vf_sysfs_device_path, 0, NULL, &vfname) < 0)
+ if (virPCIGetNetName(vf_sysfs_device_path, 0, NULL, NULL, &vfname) < 0)
goto cleanup;
if (vfname) {
@@ -2550,7 +2605,8 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path,
}
if (virPCIGetNetName(pf_sysfs_device_path,
- pfNetDevIdx, vfPhysPortID, pfname) < 0) {
+ pfNetDevIdx, vfPhysPortID,
+ VIR_PF_PHYS_PORT_NAME_REGEX, pfname) < 0) {
goto cleanup;
}
@@ -2688,6 +2744,7 @@ int
virPCIGetNetName(const char *device_link_sysfs_path G_GNUC_UNUSED,
size_t idx G_GNUC_UNUSED,
char *physPortID G_GNUC_UNUSED,
+ char *physPortNameScheme G_GNUC_UNUSED,
char **netname G_GNUC_UNUSED)
{
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported));
diff --git a/src/util/virpci.h b/src/util/virpci.h
index b3322ba..6ea0873 100644
--- a/src/util/virpci.h
+++ b/src/util/virpci.h
@@ -55,6 +55,11 @@ struct _virZPCIDeviceAddress {
#define VIR_PCI_DEVICE_ADDRESS_FMT "%04x:%02x:%02x.%d"
+/* Represents format of PF's phys_port_name in switchdev mode:
+ * 'p%u' or 'p%us%u'. New line checked since value is readed from sysfs file.
+ */
+# define VIR_PF_PHYS_PORT_NAME_REGEX ((char *)"(p[0-9]+$)|(p[0-9]+s[0-9]+$)")
+
struct _virPCIDeviceAddress {
unsigned int domain;
unsigned int bus;
@@ -232,6 +237,7 @@ int virPCIDeviceAddressGetSysfsFile(virPCIDeviceAddressPtr addr,
int virPCIGetNetName(const char *device_link_sysfs_path,
size_t idx,
char *physPortID,
+ char *physPortNameRegex,
char **netname);
int virPCIGetSysfsFile(char *virPCIDeviceName,
--
1.8.3.1
4 years, 3 months
[libvirt][RFC PATCH] add a new 'default' option for attribute mode in numatune
by Luyao Zhong
Hi Libvirt experts,
I would like enhence the numatune snippet configuration. Given a example snippet:
<domain>
...
<numatune>
<memory mode="strict" nodeset="1-4,^3"/>
<memnode cellid="0" mode="strict" nodeset="1"/>
<memnode cellid="2" mode="preferred" nodeset="2"/>
</numatune>
...
</domain>
Currently, attribute mode is either 'interleave', 'strict', or 'preferred',
I propose to add a new 'default' option. I give the reason as following.
Presume we are using cgroups v1, Libvirt sets cpuset.mems for all vcpu threads
according to 'nodeset' in memory element. And translate the memnode element to
qemu config options (--object memory-backend-ram) for per numa cell, which
invoking mbind() system call at the end.[1]
But what if we want using default memory policy and request each guest numa cell
pinned to different host memory nodes? We can't use mbind via qemu config options,
because (I quoto here) "For MPOL_DEFAULT, the nodemask and maxnode arguments must
be specify the empty set of nodes." [2]
So my solution is introducing a new 'default' option for attribute mode. e.g.
<domain>
...
<numatune>
<memory mode="default" nodeset="1-2"/>
<memnode cellid="0" mode="default" nodeset="1"/>
<memnode cellid="1" mode="default" nodeset="2"/>
</numatune>
...
</domain>
If the mode is 'default', libvirt should avoid generating qemu command line
'--object memory-backend-ram', and invokes cgroups to set cpuset.mems for per guest numa
combining with numa topology config. Presume the numa topology is :
<cpu>
...
<numa>
<cell id='0' cpus='0-3' memory='512000' unit='KiB' />
<cell id='1' cpus='4-7' memory='512000' unit='KiB' />
</numa>
...
</cpu>
Then libvirt should set cpuset.mems to '1' for vcpus 0-3, and '2' for vcpus 4-7.
Is this reasonable and feasible? Welcome any comments.
Regards,
Luyao
[1]https://github.com/qemu/qemu/blob/f2a1cf9180f63e88bb38ff21c169da97c3f2b...
[2]https://man7.org/linux/man-pages/man2/mbind.2.html
--
2.25.1
4 years, 4 months
Races / crashes in shutdown of libvirtd daemon
by Daniel P. Berrangé
We got a new BZ filed about a libvirtd crash in shutdown
https://bugzilla.redhat.com/show_bug.cgi?id=1828207
We can see from the stack trace that the "interface" driver is in
the middle of servicing an RPC call for virConnectListAllInterfaces()
Meanwhile the libvirtd daemon is doing virObjectUnref(dmn) on the
virNetDaemonPtr object.
The fact that it is doing this unref, means that it must have already
call virStateCleanup(), given the code sequence:
/* Run event loop. */
virNetDaemonRun(dmn);
ret = 0;
virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_SHUTDOWN,
0, "shutdown", NULL, NULL);
cleanup:
/* Keep cleanup order in inverse order of startup */
virNetDaemonClose(dmn);
virNetlinkEventServiceStopAll();
if (driversInitialized) {
/* NB: Possible issue with timing window between driversInitialized
* setting if virNetlinkEventServerStart fails */
driversInitialized = false;
virStateCleanup();
}
virObjectUnref(adminProgram);
virObjectUnref(srvAdm);
virObjectUnref(qemuProgram);
virObjectUnref(lxcProgram);
virObjectUnref(remoteProgram);
virObjectUnref(srv);
virObjectUnref(dmn);
Unless I'm missing something non-obvious, this cleanup code path is
inherantly broken & racy. When virNetDaemonRun() returns the RPC
worker threads are all still active. They are all liable to still
be executing RPC calls, which means any of the drivers may be in
use. So calling virStateCleanup() is an inherantly dangerous
thing to do. There is the further complication that once we have
exitted the main loop we may prevent the RPC calls from ever
completing, as they may be waiting on an event to be dispatched.
I know we're had various patch proposals in the past to improve the
robustness of shutdown cleanup but I can't remember the outcome of the
reviews. Hopefully people involved in those threads can jump in here...
IMHO the key problem here is the virNetDeamonRun() method which just
looks at the "quit" flag and immediately returns if it is set.
This needs to be changed so that when it sees quit == true, it takes
the following actions
1. Call virNetDaemonClose() to drop all RPC clients and thus prevent
new RPC calls arriving
2. Flush any RPC calls which are queued but not yet assigned to a
worker thread
3. Tell worker threads to exit after finishing their current job
4. Wait for all worker threads to exit
5. Now virNetDaemonRun may return
At this point we can call virStateCleanup and the various other
things, as we know no drivers are still active in RPC calls.
Having said that, there could be background threads in the the
drivers which are doing work that uses the event loop thread.
So we probably need a virStateClose() method that we call from
virNetDaemonRun, *after* all worker threads are gone, which would
cleanup any background threads while the event loop is still
running.
The issue is that step 4 above ("Wait for all worker threads to exit")
may take too long, or indeed never complete. To deal with this, it
will need a timeout. In the remote_daemon.c cleanup code path, if
there are still worker threads present, then we need to skip all
cleanup and simply call _exit(0) to terminate the process with no
attempt at cleanup, since it would be unsafe to try anything else.
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
4 years, 4 months
[libvirt PATCH v2 00/16] Add support for persistent mediated devices
by Jonathon Jongsma
This patch series follows the previously-merged series which added support for
transient mediated devices. This series expands mdev support to include
persistent device definitions. Again, it relies on mdevctl as the backend.
It follows the common libvirt pattern of APIs by adding the following new APIs
for node devices:
- virNodeDeviceDefineXML() - defines a persistent device
- virNodeDeviceUndefine() - undefines a persistent device
- virNodeDeviceCreate() - starts a previously-defined device
It also adds virsh commands mapping to these new APIs: nodedev-define,
nodedev-undefine, and nodedev-start.
The method of staying up-to-date with devices defined by mdevctl is currently=
a
little bit crude due to the fact that mdevctl does not emit any events when n=
ew
devices are added or removed. As a workaround, we create a file monitor for t=
he
mdevctl config directory and re-query mdevctl when we detect changes within
that directory. In the future, mdevctl may introduce a more elegant solution.
Changes in v2:
- rebase to latest git master
Jonathon Jongsma (16):
tests: remove extra trailing semicolon
nodedev: introduce concept of 'active' node devices
nodedev: Add ability to filter by active state
virsh: Add --active, --inactive, --all to nodedev-list
nodedev: add ability to list and parse defined mdevs
nodedev: add STOPPED/STARTED lifecycle events
nodedev: add mdevctl devices to node device list
nodedev: handle mdevs that disappear from mdevctl
nodedev: add an mdevctl thread
api: add virNodeDeviceDefineXML()
virsh: add nodedev-define command
api: add virNodeDeviceUndefine()
virsh: Factor out function to find node device
virsh: add nodedev-undefine command
api: add virNodeDeviceCreate()
virsh: add "nodedev-start" command
examples/c/misc/event-test.c | 4 +
include/libvirt/libvirt-nodedev.h | 19 +-
src/conf/node_device_conf.h | 9 +
src/conf/virnodedeviceobj.c | 24 +
src/conf/virnodedeviceobj.h | 7 +
src/driver-nodedev.h | 14 +
src/libvirt-nodedev.c | 115 ++++
src/libvirt_private.syms | 2 +
src/libvirt_public.syms | 6 +
src/node_device/node_device_driver.c | 525 +++++++++++++++++-
src/node_device/node_device_driver.h | 38 ++
src/node_device/node_device_udev.c | 275 ++++++++-
src/remote/remote_driver.c | 3 +
src/remote/remote_protocol.x | 40 +-
src/remote_protocol-structs | 16 +
src/rpc/gendispatch.pl | 1 +
...19_36ea_4111_8f0a_8c9a70e21366-define.argv | 1 +
...19_36ea_4111_8f0a_8c9a70e21366-define.json | 1 +
...39_495e_4243_ad9f_beb3f14c23d9-define.argv | 1 +
...39_495e_4243_ad9f_beb3f14c23d9-define.json | 1 +
...16_1ca8_49ac_b176_871d16c13076-define.argv | 1 +
...16_1ca8_49ac_b176_871d16c13076-define.json | 1 +
tests/nodedevmdevctldata/mdevctl-create.argv | 1 +
.../mdevctl-list-defined.argv | 1 +
.../mdevctl-list-multiple-parents.json | 59 ++
.../mdevctl-list-multiple-parents.out.xml | 39 ++
.../mdevctl-list-multiple.json | 59 ++
.../mdevctl-list-multiple.out.xml | 39 ++
.../mdevctl-list-single-noattr.json | 11 +
.../mdevctl-list-single-noattr.out.xml | 8 +
.../mdevctl-list-single.json | 31 ++
.../mdevctl-list-single.out.xml | 14 +
.../nodedevmdevctldata/mdevctl-undefine.argv | 1 +
tests/nodedevmdevctltest.c | 227 +++++++-
tools/virsh-nodedev.c | 281 ++++++++--
35 files changed, 1787 insertions(+), 88 deletions(-)
create mode 100644 tests/nodedevmdevctldata/mdev_d069d019_36ea_4111_8f0a_8c9=
a70e21366-define.argv
create mode 100644 tests/nodedevmdevctldata/mdev_d069d019_36ea_4111_8f0a_8c9=
a70e21366-define.json
create mode 100644 tests/nodedevmdevctldata/mdev_d2441d39_495e_4243_ad9f_beb=
3f14c23d9-define.argv
create mode 100644 tests/nodedevmdevctldata/mdev_d2441d39_495e_4243_ad9f_beb=
3f14c23d9-define.json
create mode 100644 tests/nodedevmdevctldata/mdev_fedc4916_1ca8_49ac_b176_871=
d16c13076-define.argv
create mode 100644 tests/nodedevmdevctldata/mdev_fedc4916_1ca8_49ac_b176_871=
d16c13076-define.json
create mode 100644 tests/nodedevmdevctldata/mdevctl-create.argv
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-defined.argv
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple-parents.js=
on
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple-parents.ou=
t.xml
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple.json
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-multiple.out.xml
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single-noattr.json
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single-noattr.out.x=
ml
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single.json
create mode 100644 tests/nodedevmdevctldata/mdevctl-list-single.out.xml
create mode 100644 tests/nodedevmdevctldata/mdevctl-undefine.argv
--=20
2.26.2
4 years, 4 months
[PATCH 0/2] qemu: migration corner case fix and cleanup
by Nikolay Shirokovskiy
Nikolay Shirokovskiy (2):
qemu: fix qemuMigrationSrcCleanup to use qemuMigrationJobFinish
qemu: don't needlessly unset close callback during perform phase
src/qemu/qemu_migration.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
--
1.8.3.1
4 years, 5 months
[libvirt PATCH v2 00/10] remote: introduce a custom netcat impl for ssh tunnelling
by Daniel P. Berrangé
We have long had a problem with use of netcat for ssh tunnelling because
there's no guarantee the UNIX socket path the client builds will match
the UNIX socket path the remote host uses. We don't even allow session
mode SSH tunnelling for this reason. We also can't easily auto-spawn
libvirtd in session mode.
With the introduction of modular daemons we also have potential for two
completely different UNIX socket paths even for system mode, and the
client can't know which to use.
The solution to all these problems is to introduce a custom netcat impl.
Instead passing the UNIX socket path, we pass the libvirt driver URI.
The custom netcat then decides which socket path to use based on the
remote build host environment.
We still have to support netcat for interoperability with legacy libvirt
versions, but we can default to the new virt-nc.
Daniel P. Berrangé (10):
rpc: merge logic for generating remote SSH shell script
remote: push logic for default netcat binary into common helper
remote: split off enums into separate source file
remote: split out function for parsing URI scheme
remote: parse the remote transport string earlier
remote: split out function for constructing socket path
remote: extract logic for determining daemon to connect to
remote: introduce virt-ssh-helper binary
rpc: switch order of args in virNetClientNewSSH
rpc: use new virt-ssh-helper binary for remote tunnelling
build-aux/syntax-check.mk | 2 +-
docs/uri.html.in | 24 +-
libvirt.spec.in | 2 +
po/POTFILES.in | 2 +
src/libvirt_remote.syms | 1 +
src/remote/Makefile.inc.am | 33 +++
src/remote/remote_driver.c | 323 ++++---------------------
src/remote/remote_sockets.c | 277 +++++++++++++++++++++
src/remote/remote_sockets.h | 70 ++++++
src/remote/remote_ssh_helper.c | 425 +++++++++++++++++++++++++++++++++
src/rpc/virnetclient.c | 166 ++++++++-----
src/rpc/virnetclient.h | 29 ++-
src/rpc/virnetsocket.c | 37 +--
src/rpc/virnetsocket.h | 4 +-
tests/virnetsockettest.c | 12 +-
15 files changed, 1035 insertions(+), 372 deletions(-)
create mode 100644 src/remote/remote_sockets.c
create mode 100644 src/remote/remote_sockets.h
create mode 100644 src/remote/remote_ssh_helper.c
--
2.26.2
4 years, 5 months
[PATCH] qemu.conf: Re-word the description for *_tls_x509_verify
by Fangge Jin
The original descirption for *_tls_x509_verify is a little misleading
by saying that "Enabling this option will reject any client who does
not have a ca-cert.pem certificate".
Signed-off-by: Fangge Jin <fjin(a)redhat.com>
---
src/qemu/qemu.conf | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index a96bedb114..b1bd3cecbd 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -109,9 +109,8 @@
# issuing an x509 certificate to every client who needs to connect.
#
# Enabling this option will reject any client that does not have a
-# ca-cert.pem certificate signed by the CA in the vnc_tls_x509_cert_dir
-# (or default_tls_x509_cert_dir) as well as the corresponding client-*.pem
-# files described in default_tls_x509_cert_dir.
+# certificate(as described in default_tls_x509_verify) signed by the
+# CA in the vnc_tls_x509_cert_dir (or default_tls_x509_cert_dir).
#
# If this option is not supplied, it will be set to the value of
# "default_tls_x509_verify".
@@ -248,9 +247,8 @@
# issuing an x509 certificate to every client who needs to connect.
#
# Enabling this option will reject any client that does not have a
-# ca-cert.pem certificate signed by the CA in the chardev_tls_x509_cert_dir
-# (or default_tls_x509_cert_dir) as well as the corresponding client-*.pem
-# files described in default_tls_x509_cert_dir.
+# certificate(as described in default_tls_x509_verify) signed by the
+# CA in the chardev_tls_x509_cert_dir (or default_tls_x509_cert_dir).
#
# If this option is not supplied, it will be set to the value of
# "default_tls_x509_verify".
@@ -375,9 +373,8 @@
# issuing an x509 certificate to every client who needs to connect.
#
# Enabling this option will reject any client that does not have a
-# ca-cert.pem certificate signed by the CA in the migrate_tls_x509_cert_dir
-# (or default_tls_x509_cert_dir) as well as the corresponding client-*.pem
-# files described in default_tls_x509_cert_dir.
+# certificate(as described in default_tls_x509_verify) signed by the
+# CA in the migrate_tls_x509_cert_dir (or default_tls_x509_cert_dir).
#
# If this option is not supplied, it will be set to the value of
# "default_tls_x509_verify".
@@ -412,9 +409,8 @@
# issuing an x509 certificate to every client who needs to connect.
#
# Enabling this option will reject any client that does not have a
-# ca-cert.pem certificate signed by the CA in the backup_tls_x509_cert_dir
-# (or default_tls_x509_cert_dir) as well as the corresponding client-*.pem
-# files described in default_tls_x509_cert_dir.
+# certificate(as described in default_tls_x509_verify) signed by the
+# CA in the backup_tls_x509_cert_dir (or default_tls_x509_cert_dir).
#
# If this option is not supplied, it will be set to the value of
# "default_tls_x509_verify".
--
2.20.1
4 years, 6 months
[PATCH] qemu: clear residual QMP caps processes during QEMU driver initialization
by Bihong Yu
>From c328ff62b11d58553fd2032a85fd3295e009b3d3 Mon Sep 17 00:00:00 2001
From: Bihong Yu <yubihong(a)huawei.com>
Date: Fri, 17 Jul 2020 16:55:12 +0800
Subject: [PATCH] qemu: clear residual QMP caps processes during QEMU driver
initialization
In some cases, the QMP capabilities processes possible residue. So we need to
clear the residual QMP caps processes during starting libvirt.
Signed-off-by:Bihong Yu <yubihong(a)huawei.com>
---
src/qemu/qemu_driver.c | 2 ++
src/qemu/qemu_process.c | 40 ++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_process.h | 2 ++
3 files changed, 44 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d185666..d627fd7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -889,6 +889,8 @@ qemuStateInitialize(bool privileged,
run_gid = cfg->group;
}
+ qemuProcessQMPClear(cfg->libDir);
+
qemu_driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
cfg->cacheDir,
run_uid,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 70fc24b..d545e3e 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -8312,6 +8312,46 @@ static qemuMonitorCallbacks callbacks = {
};
+/**
+ * qemuProcessQMPClear
+ *
+ * Try to kill residual QMP caps processes
+ */
+void
+qemuProcessQMPClear(const char *libDir)
+{
+ virErrorPtr orig_err;
+ DIR *dirp = NULL;
+ struct dirent *dp;
+
+ if (!virFileExists(libDir))
+ return;
+
+ if (virDirOpen(&dirp, libDir) < 0)
+ return;
+
+ virErrorPreserveLast(&orig_err);
+ while (virDirRead(dirp, &dp, libDir) > 0) {
+ g_autofree char *qmp_uniqDir = NULL;
+ g_autofree char *qmp_pidfile = NULL;
+
+ if (!STRPREFIX(dp->d_name, "qmp-"))
+ continue;
+
+ qmp_uniqDir = g_strdup_printf("%s/%s", libDir, dp->d_name);
+ qmp_pidfile = g_strdup_printf("%s/%s", qmp_uniqDir, "qmp.pid");
+
+ ignore_value(virPidFileForceCleanupPath(qmp_pidfile));
+
+ if (qmp_uniqDir)
+ rmdir(qmp_uniqDir);
+ }
+ virErrorRestore(&orig_err);
+
+ VIR_DIR_CLOSE(dirp);
+}
+
+
static void
qemuProcessQMPStop(qemuProcessQMPPtr proc)
{
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index 15e67b9..b039e6c 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -233,6 +233,8 @@ qemuProcessQMPPtr qemuProcessQMPNew(const char *binary,
gid_t runGid,
bool forceTCG);
+void qemuProcessQMPClear(const char *libDir);
+
void qemuProcessQMPFree(qemuProcessQMPPtr proc);
int qemuProcessQMPStart(qemuProcessQMPPtr proc);
--
1.8.3.1
4 years, 6 months
[libvirt PATCH v4 00/11] remote: introduce a custom netcat impl for ssh tunnelling
by Daniel P. Berrangé
We have long had a problem with use of netcat for ssh tunnelling because
there's no guarantee the UNIX socket path the client builds will match
the UNIX socket path the remote host uses. We don't even allow session
mode SSH tunnelling for this reason. We also can't easily auto-spawn
libvirtd in session mode.
With the introduction of modular daemons we also have potential for two
completely different UNIX socket paths even for system mode, and the
client can't know which to use.
The solution to all these problems is to introduce a custom netcat impl.
Instead passing the UNIX socket path, we pass the libvirt driver URI.
The custom netcat then decides which socket path to use based on the
remote build host environment.
We still have to support netcat for interoperability with legacy libvirt
versions, but we can default to the new virt-nc.
v4: Now with many fixed bugs to make it actually work
v3: Now with more meson and less autotools !
Daniel P. Berrangé (11):
rpc: merge logic for generating remote SSH shell script
remote: push logic for default netcat binary into common helper
remote: split off enums into separate source file
remote: split out function for parsing URI scheme
remote: parse the remote transport string earlier
remote: split out function for constructing socket path
remote: extract logic for determining daemon to connect to
remote: introduce virt-ssh-helper binary
rpc: switch order of args in virNetClientNewSSH
rpc: use new virt-ssh-helper binary for remote tunnelling
remote: fix error reporting for invalid daemon mode
build-aux/syntax-check.mk | 2 +-
docs/uri.html.in | 24 +-
libvirt.spec.in | 2 +
po/POTFILES.in | 2 +
src/libvirt_remote.syms | 1 +
src/remote/meson.build | 18 ++
src/remote/remote_driver.c | 331 +++++--------------------
src/remote/remote_sockets.c | 277 +++++++++++++++++++++
src/remote/remote_sockets.h | 70 ++++++
src/remote/remote_ssh_helper.c | 425 +++++++++++++++++++++++++++++++++
src/rpc/virnetclient.c | 167 +++++++++----
src/rpc/virnetclient.h | 29 ++-
src/rpc/virnetsocket.c | 37 +--
src/rpc/virnetsocket.h | 4 +-
tests/virnetsockettest.c | 12 +-
15 files changed, 1030 insertions(+), 371 deletions(-)
create mode 100644 src/remote/remote_sockets.c
create mode 100644 src/remote/remote_sockets.h
create mode 100644 src/remote/remote_ssh_helper.c
--
2.26.2
4 years, 6 months