[libvirt PATCH 0/4] remote: switch to modular daemons by default

This series first improves driver probing when using modular daemons. Currently when URI is NULL, we connect to virtproxyd and it looks at which UNIX sockets exist and what binaries exist, to decide which modular hypervisor daemon to connect to. This means the common case results in all traffic going via virtproxyd. Moving the logic out of virtproxyd into the remote client means we can avoid using virtproxyd by default. With this, we can now switch to the modular daemons by default. The latter change primarily impacts how autostart works When running as root we simply connect to whatever UNIX socket exists and rely on systemd to autostart if needed. Whether the UNIX sockets are for the modular daemon or libvirt doesn't matter - we'll look for both. Defaults are dependent on the distros' systemd presets. I intend to get Fedora / RHEL-9 presets changed to use the modular daemons. When running as non-root, we again try to connect to whatever UNIX socket exists, whethe a modular daemon or libvirtd. When no socket exists though, we need to pick a daemon to start and that's where the meson default setting toggle comes into effect, so we prefer spawning modular daemons now and don't spawn libvirtd. Daniel P. Berrangé (4): remote: extract logic for probing for modular daemons remote: add support for probing drivers with modular daemons remote: remove probing logic from virtproxyd dispatcher remote: switch to auto-spawn modular daemons by default meson.build | 6 +- meson_options.txt | 2 +- src/libvirt_remote.syms | 5 + src/remote/remote_daemon_dispatch.c | 130 +------------------ src/remote/remote_sockets.c | 192 ++++++++++++++++++++++++++-- src/remote/remote_sockets.h | 7 + 6 files changed, 202 insertions(+), 140 deletions(-) -- 2.31.1

When virtproxyd gets a NULL URI, it needs to implement probing logic similar to that found in virConnectOpen. The latter can't be used directly since it relied on directly calling into the internal drivers in libvirtd. virtproxyd approximates this behaviour by looking to see what modular daemon sockets exist, or what daemon binaries are installed. This same logic is also going to be needed when the regular libvirt remote client switches to prefer modular daemons by default, as we don't want to continue spawning libvirtd going forward. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/libvirt_remote.syms | 5 + src/remote/remote_daemon_dispatch.c | 98 +++++--------------- src/remote/remote_sockets.c | 139 ++++++++++++++++++++++++++++ src/remote/remote_sockets.h | 7 ++ 4 files changed, 173 insertions(+), 76 deletions(-) diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms index 11c9e2cb73..b4265adf2e 100644 --- a/src/libvirt_remote.syms +++ b/src/libvirt_remote.syms @@ -14,6 +14,11 @@ xdr_*; xdr_virNetMessageError; +# remote/remote_sockets.h +remoteProbeSessionDriverFromBinary; +remoteProbeSessionDriverFromSocket; +remoteProbeSystemDriverFromSocket; + # rpc/virnetclient.h virNetClientAddProgram; virNetClientAddStream; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 838f4a925f..36d4d00b79 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -24,6 +24,7 @@ #include "remote_daemon_dispatch.h" #include "remote_daemon.h" +#include "remote_sockets.h" #include "libvirt_internal.h" #include "datatypes.h" #include "viralloc.h" @@ -1968,6 +1969,8 @@ static int remoteDispatchProbeURI(bool readonly, char **probeduri) { + g_autofree char *driver = NULL; + const char *suffix; *probeduri = NULL; VIR_DEBUG("Probing for driver daemon sockets"); @@ -1976,94 +1979,37 @@ remoteDispatchProbeURI(bool readonly, * exists, or we're using socket activation so the socket exists * too. * - * If running non-root, chances are that the daemon won't be - * running, nor any socket activation is used. We need to - * be able to auto-spawn the daemon. We thus just check to - * see what daemons are installed. This is not a big deal as - * only QEMU & VBox run as non-root, anyway. + * If running non-root, the daemon may or may not already be + * running, and socket activation probably isn't relevant. + * So if no viable socket exists, we need to check which daemons + * are actually installed. This is not a big deal as only QEMU & + * VBox run as non-root, anyway. */ if (geteuid() != 0) { - /* Order these the same as virDriverLoadModule - * calls in daemonInitialize */ - const char *drivers[] = { -# ifdef WITH_QEMU - "qemu", -# endif -# ifdef WITH_VBOX - "vbox", -# endif - }; - ssize_t i; - - for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers) && !*probeduri; i++) { - g_autofree char *daemonname = NULL; - g_autofree char *daemonpath = NULL; - - daemonname = g_strdup_printf("virt%sd", drivers[i]); - - if (!(daemonpath = virFileFindResource(daemonname, - abs_top_builddir "/src", - SBINDIR))) - return -1; - - if (!virFileExists(daemonpath)) { - VIR_DEBUG("Missing daemon %s for driver %s", daemonpath, drivers[i]); - continue; - } + if (remoteProbeSessionDriverFromSocket(false, &driver) < 0) + return -1; - *probeduri = g_strdup_printf("%s:///session", drivers[i]); + if (driver == NULL && + remoteProbeSessionDriverFromBinary(&driver) < 0) + return -1; - VIR_DEBUG("Probed URI %s via daemon %s", *probeduri, daemonpath); - return 0; - } + suffix = "session"; } else { - /* Order these the same as virDriverLoadModule - * calls in daemonInitialize */ - const char *drivers[] = { -# ifdef WITH_LIBXL - "libxl", -# endif -# ifdef WITH_QEMU - "qemu", -# endif -# ifdef WITH_LXC - "lxc", -# endif -# ifdef WITH_VBOX - "vbox", -# endif -# ifdef WITH_BHYVE - "bhyve", -# endif -# ifdef WITH_VZ - "vz", -# endif - }; - ssize_t i; - - for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers) && !*probeduri; i++) { - g_autofree char *sockname = NULL; - - sockname = g_strdup_printf("%s/libvirt/virt%sd-%s", RUNSTATEDIR, - drivers[i], readonly ? "sock-ro" : "sock"); - - if (!virFileExists(sockname)) { - VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); - continue; - } - - *probeduri = g_strdup_printf("%s:///system", drivers[i]); + if (remoteProbeSystemDriverFromSocket(readonly, &driver) < 0) + return -1; - VIR_DEBUG("Probed URI %s via sock %s", *probeduri, sockname); - return 0; - } + suffix = "system"; } /* Even if we didn't probe any socket, we won't * return error. Just let virConnectOpen's normal * logic run which will likely return an error anyway */ - VIR_DEBUG("No driver sock exists"); + if (!driver) + return 0; + + *probeduri = g_strdup_printf("%s:///%s", driver, suffix); + VIR_DEBUG("Probed URI %s for driver %s", *probeduri, driver); return 0; } #endif /* VIRTPROXYD */ diff --git a/src/remote/remote_sockets.c b/src/remote/remote_sockets.c index 0f85b999fd..dd28c9dd5e 100644 --- a/src/remote/remote_sockets.c +++ b/src/remote/remote_sockets.c @@ -146,6 +146,145 @@ remoteGetUNIXSocketHelper(remoteDriverTransport transport, return sockname; } +/* + * Determine which driver is probably usable based on + * which modular daemon binaries are installed. + */ +int +remoteProbeSessionDriverFromBinary(char **driver) +{ + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize, so we replicate + * probing order that virConnectOpen would use + * if running inside libvirtd */ + const char *drivers[] = { +#ifdef WITH_QEMU + "qemu", +#endif +#ifdef WITH_VBOX + "vbox", +#endif + }; + ssize_t i; + + VIR_DEBUG("Probing for driver from daemon binaries"); + + *driver = NULL; + + for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) { + g_autofree char *daemonname = NULL; + g_autofree char *daemonpath = NULL; + + daemonname = g_strdup_printf("virt%sd", drivers[i]); + VIR_DEBUG("Probing driver '%s' via daemon %s", drivers[i], daemonpath); + + if (!(daemonpath = virFileFindResource(daemonname, + abs_top_builddir "/src", + SBINDIR))) + return -1; + + if (virFileExists(daemonpath)) { + VIR_DEBUG("Found driver '%s' via daemon %s", drivers[i], daemonpath); + *driver = g_strdup(drivers[i]); + return 0; + } + + VIR_DEBUG("Missing daemon %s for driver %s", daemonpath, drivers[i]); + } + + VIR_DEBUG("No more drivers to probe for"); + return 0; +} + + +int +remoteProbeSystemDriverFromSocket(bool readonly, char **driver) +{ + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize, so we replicate + * probing order that virConnectOpen would use + * if running inside libvirtd */ + const char *drivers[] = { +#ifdef WITH_LIBXL + "libxl", +#endif +#ifdef WITH_QEMU + "qemu", +#endif +#ifdef WITH_LXC + "lxc", +#endif +#ifdef WITH_VBOX + "vbox", +#endif +#ifdef WITH_BHYVE + "bhyve", +#endif +#ifdef WITH_VZ + "vz", +#endif + }; + ssize_t i; + + for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) { + g_autofree char *sockname = + g_strdup_printf("%s/libvirt/virt%sd-%s", RUNSTATEDIR, + drivers[i], readonly ? "sock-ro" : "sock"); + + if (virFileExists(sockname)) { + VIR_DEBUG("Probed driver '%s' via sock '%s'", drivers[i], sockname); + *driver = g_strdup(drivers[i]); + return 0; + } + + VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); + } + + /* Even if we didn't probe any socket, we won't + * return error. Just let virConnectOpen's normal + * logic run which will likely return an error anyway + */ + VIR_DEBUG("No more drivers to probe for"); + return 0; +} + +int +remoteProbeSessionDriverFromSocket(bool readonly, char **driver) +{ + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize */ + const char *drivers[] = { +#ifdef WITH_QEMU + "qemu", +#endif +#ifdef WITH_VBOX + "vbox", +#endif + }; + ssize_t i; + + for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) { + g_autofree char *userdir = virGetUserRuntimeDirectory(); + g_autofree char *sockname = + g_strdup_printf("%s/virt%sd-%s", + userdir, drivers[i], readonly ? "sock-ro" : "sock"); + + if (virFileExists(sockname)) { + VIR_DEBUG("Probed driver '%s' via sock '%s'", drivers[i], sockname); + *driver = g_strdup(drivers[i]); + return 0; + } + + VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); + } + + /* Even if we didn't probe any socket, we won't + * return error. Just let virConnectOpen's normal + * logic run which will likely return an error anyway + */ + VIR_DEBUG("No more drivers to probe for"); + return 0; +} char * remoteGetUNIXSocket(remoteDriverTransport transport, diff --git a/src/remote/remote_sockets.h b/src/remote/remote_sockets.h index 11934dbf70..00e654d46c 100644 --- a/src/remote/remote_sockets.h +++ b/src/remote/remote_sockets.h @@ -62,6 +62,13 @@ remoteSplitURIScheme(virURI *uri, char **driver, remoteDriverTransport *transport); +int +remoteProbeSessionDriverFromBinary(char **driver); +int +remoteProbeSystemDriverFromSocket(bool readonly, char **driver); +int +remoteProbeSessionDriverFromSocket(bool readonly, char **driver); + char * remoteGetUNIXSocket(remoteDriverTransport transport, remoteDriverMode mode, -- 2.31.1

On 6/10/21 7:43 AM, Daniel P. Berrangé wrote:
When virtproxyd gets a NULL URI, it needs to implement probing logic similar to that found in virConnectOpen. The latter can't be used directly since it relied on directly calling into the internal drivers in libvirtd. virtproxyd approximates this behaviour by looking to see what modular daemon sockets exist, or what daemon binaries are installed.
This same logic is also going to be needed when the regular libvirt remote client switches to prefer modular daemons by default, as we don't want to continue spawning libvirtd going forward.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/libvirt_remote.syms | 5 + src/remote/remote_daemon_dispatch.c | 98 +++++--------------- src/remote/remote_sockets.c | 139 ++++++++++++++++++++++++++++ src/remote/remote_sockets.h | 7 ++ 4 files changed, 173 insertions(+), 76 deletions(-)
diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms index 11c9e2cb73..b4265adf2e 100644 --- a/src/libvirt_remote.syms +++ b/src/libvirt_remote.syms @@ -14,6 +14,11 @@ xdr_*; xdr_virNetMessageError;
+# remote/remote_sockets.h +remoteProbeSessionDriverFromBinary; +remoteProbeSessionDriverFromSocket; +remoteProbeSystemDriverFromSocket; + # rpc/virnetclient.h virNetClientAddProgram; virNetClientAddStream; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 838f4a925f..36d4d00b79 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -24,6 +24,7 @@
#include "remote_daemon_dispatch.h" #include "remote_daemon.h" +#include "remote_sockets.h" #include "libvirt_internal.h" #include "datatypes.h" #include "viralloc.h" @@ -1968,6 +1969,8 @@ static int remoteDispatchProbeURI(bool readonly, char **probeduri) { + g_autofree char *driver = NULL; + const char *suffix; *probeduri = NULL; VIR_DEBUG("Probing for driver daemon sockets");
@@ -1976,94 +1979,37 @@ remoteDispatchProbeURI(bool readonly, * exists, or we're using socket activation so the socket exists * too. * - * If running non-root, chances are that the daemon won't be - * running, nor any socket activation is used. We need to - * be able to auto-spawn the daemon. We thus just check to - * see what daemons are installed. This is not a big deal as - * only QEMU & VBox run as non-root, anyway. + * If running non-root, the daemon may or may not already be + * running, and socket activation probably isn't relevant. + * So if no viable socket exists, we need to check which daemons + * are actually installed. This is not a big deal as only QEMU & + * VBox run as non-root, anyway. */ if (geteuid() != 0) { - /* Order these the same as virDriverLoadModule - * calls in daemonInitialize */ - const char *drivers[] = { -# ifdef WITH_QEMU - "qemu", -# endif -# ifdef WITH_VBOX - "vbox", -# endif - }; - ssize_t i; - - for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers) && !*probeduri; i++) { - g_autofree char *daemonname = NULL; - g_autofree char *daemonpath = NULL; - - daemonname = g_strdup_printf("virt%sd", drivers[i]); - - if (!(daemonpath = virFileFindResource(daemonname, - abs_top_builddir "/src", - SBINDIR))) - return -1; - - if (!virFileExists(daemonpath)) { - VIR_DEBUG("Missing daemon %s for driver %s", daemonpath, drivers[i]); - continue; - } + if (remoteProbeSessionDriverFromSocket(false, &driver) < 0) + return -1;
- *probeduri = g_strdup_printf("%s:///session", drivers[i]); + if (driver == NULL && + remoteProbeSessionDriverFromBinary(&driver) < 0) + return -1;
- VIR_DEBUG("Probed URI %s via daemon %s", *probeduri, daemonpath); - return 0; - } + suffix = "session"; } else { - /* Order these the same as virDriverLoadModule - * calls in daemonInitialize */ - const char *drivers[] = { -# ifdef WITH_LIBXL - "libxl", -# endif -# ifdef WITH_QEMU - "qemu", -# endif -# ifdef WITH_LXC - "lxc", -# endif -# ifdef WITH_VBOX - "vbox", -# endif -# ifdef WITH_BHYVE - "bhyve", -# endif -# ifdef WITH_VZ - "vz", -# endif - }; - ssize_t i; - - for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers) && !*probeduri; i++) { - g_autofree char *sockname = NULL; - - sockname = g_strdup_printf("%s/libvirt/virt%sd-%s", RUNSTATEDIR, - drivers[i], readonly ? "sock-ro" : "sock"); - - if (!virFileExists(sockname)) { - VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); - continue; - } - - *probeduri = g_strdup_printf("%s:///system", drivers[i]); + if (remoteProbeSystemDriverFromSocket(readonly, &driver) < 0) + return -1;
- VIR_DEBUG("Probed URI %s via sock %s", *probeduri, sockname); - return 0; - } + suffix = "system"; }
/* Even if we didn't probe any socket, we won't * return error. Just let virConnectOpen's normal * logic run which will likely return an error anyway */ - VIR_DEBUG("No driver sock exists"); + if (!driver) + return 0; + + *probeduri = g_strdup_printf("%s:///%s", driver, suffix); + VIR_DEBUG("Probed URI %s for driver %s", *probeduri, driver); return 0; } #endif /* VIRTPROXYD */ diff --git a/src/remote/remote_sockets.c b/src/remote/remote_sockets.c index 0f85b999fd..dd28c9dd5e 100644 --- a/src/remote/remote_sockets.c +++ b/src/remote/remote_sockets.c @@ -146,6 +146,145 @@ remoteGetUNIXSocketHelper(remoteDriverTransport transport, return sockname; }
+/* + * Determine which driver is probably usable based on + * which modular daemon binaries are installed. + */ +int +remoteProbeSessionDriverFromBinary(char **driver) +{ + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize, so we replicate + * probing order that virConnectOpen would use + * if running inside libvirtd */ + const char *drivers[] = { +#ifdef WITH_QEMU + "qemu", +#endif +#ifdef WITH_VBOX + "vbox", +#endif + }; + ssize_t i; + + VIR_DEBUG("Probing for driver from daemon binaries"); + + *driver = NULL; + + for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) { + g_autofree char *daemonname = NULL; + g_autofree char *daemonpath = NULL; + + daemonname = g_strdup_printf("virt%sd", drivers[i]); + VIR_DEBUG("Probing driver '%s' via daemon %s", drivers[i], daemonpath); + + if (!(daemonpath = virFileFindResource(daemonname, + abs_top_builddir "/src", + SBINDIR))) + return -1; + + if (virFileExists(daemonpath)) { + VIR_DEBUG("Found driver '%s' via daemon %s", drivers[i], daemonpath); + *driver = g_strdup(drivers[i]); + return 0; + } + + VIR_DEBUG("Missing daemon %s for driver %s", daemonpath, drivers[i]); + } + + VIR_DEBUG("No more drivers to probe for"); + return 0; +} + + +int +remoteProbeSystemDriverFromSocket(bool readonly, char **driver) +{ + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize, so we replicate + * probing order that virConnectOpen would use + * if running inside libvirtd */ + const char *drivers[] = { +#ifdef WITH_LIBXL + "libxl",
Pre-existing bug due to libxl vs xen naming fiasco, but here it should be "xen". Regards, Jim
+#endif +#ifdef WITH_QEMU + "qemu", +#endif +#ifdef WITH_LXC + "lxc", +#endif +#ifdef WITH_VBOX + "vbox", +#endif +#ifdef WITH_BHYVE + "bhyve", +#endif +#ifdef WITH_VZ + "vz", +#endif + }; + ssize_t i; + + for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) { + g_autofree char *sockname = + g_strdup_printf("%s/libvirt/virt%sd-%s", RUNSTATEDIR, + drivers[i], readonly ? "sock-ro" : "sock"); + + if (virFileExists(sockname)) { + VIR_DEBUG("Probed driver '%s' via sock '%s'", drivers[i], sockname); + *driver = g_strdup(drivers[i]); + return 0; + } + + VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); + } + + /* Even if we didn't probe any socket, we won't + * return error. Just let virConnectOpen's normal + * logic run which will likely return an error anyway + */ + VIR_DEBUG("No more drivers to probe for"); + return 0; +} + +int +remoteProbeSessionDriverFromSocket(bool readonly, char **driver) +{ + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize */ + const char *drivers[] = { +#ifdef WITH_QEMU + "qemu", +#endif +#ifdef WITH_VBOX + "vbox", +#endif + }; + ssize_t i; + + for (i = 0; i < (ssize_t) G_N_ELEMENTS(drivers); i++) { + g_autofree char *userdir = virGetUserRuntimeDirectory(); + g_autofree char *sockname = + g_strdup_printf("%s/virt%sd-%s", + userdir, drivers[i], readonly ? "sock-ro" : "sock"); + + if (virFileExists(sockname)) { + VIR_DEBUG("Probed driver '%s' via sock '%s'", drivers[i], sockname); + *driver = g_strdup(drivers[i]); + return 0; + } + + VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); + } + + /* Even if we didn't probe any socket, we won't + * return error. Just let virConnectOpen's normal + * logic run which will likely return an error anyway + */ + VIR_DEBUG("No more drivers to probe for"); + return 0; +}
char * remoteGetUNIXSocket(remoteDriverTransport transport, diff --git a/src/remote/remote_sockets.h b/src/remote/remote_sockets.h index 11934dbf70..00e654d46c 100644 --- a/src/remote/remote_sockets.h +++ b/src/remote/remote_sockets.h @@ -62,6 +62,13 @@ remoteSplitURIScheme(virURI *uri, char **driver, remoteDriverTransport *transport);
+int +remoteProbeSessionDriverFromBinary(char **driver); +int +remoteProbeSystemDriverFromSocket(bool readonly, char **driver); +int +remoteProbeSessionDriverFromSocket(bool readonly, char **driver); + char * remoteGetUNIXSocket(remoteDriverTransport transport, remoteDriverMode mode,

With the traditional libvirtd, the virConnectOpen call will probe active drivers server side to find which one to use when the URI is NULL/empty. With the modular daemons though, the remote client does not know which daemon to connect in the first place, so we can't rely on virConnectOpen probing. Currently the virtproxyd daemon has code to probe for a possible driver by looking at which sockets are listening or which binaries are installed. The remote client can thus connect to virtproxyd which in turn can connect to a real hypervisor driver. The virtproxyd probing code though isn't something that needs to live in virtproxyd. By moving it into the remote client we can get probing client side in all scenarios and avoid the extra trip via virtproxyd in the common case. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- meson.build | 6 +++-- src/remote/remote_sockets.c | 53 +++++++++++++++++++++++++++++++------ 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/meson.build b/meson.build index 40e99fec0c..91d51492a4 100644 --- a/meson.build +++ b/meson.build @@ -1415,8 +1415,10 @@ if not get_option('driver_remote').disabled() endif endif -remote_default_mode = get_option('remote_default_mode').to_upper() -conf.set('REMOTE_DRIVER_MODE_DEFAULT', 'REMOTE_DRIVER_MODE_@0@'.format(remote_default_mode)) +remote_default_mode = get_option('remote_default_mode') +if remote_default_mode == 'direct' + conf.set('REMOTE_DRIVER_AUTOSTART_DIRECT', '1') +endif if not get_option('driver_libvirtd').disabled() use_libvirtd = true diff --git a/src/remote/remote_sockets.c b/src/remote/remote_sockets.c index dd28c9dd5e..506e267201 100644 --- a/src/remote/remote_sockets.c +++ b/src/remote/remote_sockets.c @@ -299,6 +299,9 @@ remoteGetUNIXSocket(remoteDriverTransport transport, g_autofree char *daemon_name = NULL; g_autofree char *direct_sock_name = NULL; g_autofree char *legacy_sock_name = NULL; +#ifdef REMOTE_DRIVER_AUTOSTART_DIRECT + g_autofree char *guessdriver = NULL; +#endif #ifndef WIN32 const char *env_name = remoteGetDaemonPathEnv(); #else @@ -310,12 +313,35 @@ remoteGetUNIXSocket(remoteDriverTransport transport, remoteDriverModeTypeToString(mode), driver, flags); +#ifdef REMOTE_DRIVER_AUTOSTART_DIRECT + if (!driver && mode != REMOTE_DRIVER_MODE_LEGACY) { + VIR_DEBUG("Client side modular daemon probe"); + /* + * If we don't have a driver (because URI is empty) + * in the direct case, we don't know which daemon + * to connect to. This logic attempts to be a rough + * equivalent of auto-probing from virConnectOpen + * in the libvirtd days. + */ + if (geteuid() != 0) { + if (remoteProbeSessionDriverFromSocket(false, &guessdriver) < 0) + return NULL; + + if (guessdriver == NULL && + remoteProbeSessionDriverFromBinary(&guessdriver) < 0) + return NULL; + } else { + if (remoteProbeSystemDriverFromSocket(flags & REMOTE_DRIVER_OPEN_RO, + &guessdriver) < 0) + return NULL; + } + driver = guessdriver; + } +#endif + if (driver) { direct_daemon = g_strdup_printf("virt%sd", driver); direct_sock_name = remoteGetUNIXSocketHelper(transport, direct_daemon, flags); - } else { - direct_daemon = g_strdup("virtproxyd"); - direct_sock_name = remoteGetUNIXSocketHelper(transport, "libvirt", flags); } legacy_daemon = g_strdup("libvirtd"); @@ -323,18 +349,29 @@ remoteGetUNIXSocket(remoteDriverTransport transport, if (mode == REMOTE_DRIVER_MODE_AUTO) { if (transport == REMOTE_DRIVER_TRANSPORT_UNIX) { + /* + * When locally accessing libvirtd, we pick legacy or + * modular daemons depending on which sockets we see + * existing. + */ if (direct_sock_name && virFileExists(direct_sock_name)) { mode = REMOTE_DRIVER_MODE_DIRECT; } else if (virFileExists(legacy_sock_name)) { mode = REMOTE_DRIVER_MODE_LEGACY; } else { - /* - * This constant comes from the configure script and - * maps to either the direct or legacy mode constant - */ - mode = REMOTE_DRIVER_MODE_DEFAULT; +#ifdef REMOTE_DRIVER_AUTOSTART_DIRECT + mode = REMOTE_DRIVER_MODE_DIRECT; +#else + mode = REMOTE_DRIVER_MODE_LEGACY; +#endif } } else { + /* + * When remotely accessing libvirtd, we always default to a legacy socket + * path, as there's no way for us to probe what's configured. This does + * not matter, since 'virt-ssh-helper' will be used if it is available + * and thus probe from context of the remote host + */ mode = REMOTE_DRIVER_MODE_LEGACY; } } -- 2.31.1

Now that the remote driver itself can probe for listening sockets / running daemons, virtproxyd doesn't need to probe URIs itself. Instead it can just delegate to the remote driver. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- src/remote/remote_daemon_dispatch.c | 74 ----------------------------- 1 file changed, 74 deletions(-) diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 36d4d00b79..8cec0a2a01 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -1948,73 +1948,6 @@ void *remoteClientNew(virNetServerClient *client, /*----- Functions. -----*/ -#ifdef VIRTPROXYD -/* - * When running in virtproxyd regular auto-probing of drivers - * does not work as we don't have any drivers present (except - * stateless ones inside libvirt.so). All the interesting - * drivers are in separate daemons. Thus when we get a NULL - * URI we need to simulate probing that virConnectOpen would - * previously do. We use the existence of the UNIX domain - * socket as our hook for probing. - * - * This assumes no stale sockets left over from a now dead - * daemon, but that's reasonable since libvirtd unlinks - * sockets it creates on shutdown, or uses systemd activation - * - * We only try to probe for primary hypervisor drivers, - * not the secondary drivers. - */ -static int -remoteDispatchProbeURI(bool readonly, - char **probeduri) -{ - g_autofree char *driver = NULL; - const char *suffix; - *probeduri = NULL; - VIR_DEBUG("Probing for driver daemon sockets"); - - /* - * If running root, either the daemon is running and the socket - * exists, or we're using socket activation so the socket exists - * too. - * - * If running non-root, the daemon may or may not already be - * running, and socket activation probably isn't relevant. - * So if no viable socket exists, we need to check which daemons - * are actually installed. This is not a big deal as only QEMU & - * VBox run as non-root, anyway. - */ - if (geteuid() != 0) { - if (remoteProbeSessionDriverFromSocket(false, &driver) < 0) - return -1; - - if (driver == NULL && - remoteProbeSessionDriverFromBinary(&driver) < 0) - return -1; - - suffix = "session"; - } else { - if (remoteProbeSystemDriverFromSocket(readonly, &driver) < 0) - return -1; - - suffix = "system"; - } - - /* Even if we didn't probe any socket, we won't - * return error. Just let virConnectOpen's normal - * logic run which will likely return an error anyway - */ - if (!driver) - return 0; - - *probeduri = g_strdup_printf("%s:///%s", driver, suffix); - VIR_DEBUG("Probed URI %s for driver %s", *probeduri, driver); - return 0; -} -#endif /* VIRTPROXYD */ - - static int remoteDispatchConnectOpen(virNetServer *server G_GNUC_UNUSED, virNetServerClient *client, @@ -2054,13 +1987,6 @@ remoteDispatchConnectOpen(virNetServer *server G_GNUC_UNUSED, priv->readonly = flags & VIR_CONNECT_RO; #ifdef VIRTPROXYD - if (!name || STREQ(name, "")) { - if (remoteDispatchProbeURI(priv->readonly, &probeduri) < 0) - goto cleanup; - - name = probeduri; - } - preserveIdentity = true; #endif /* VIRTPROXYD */ -- 2.31.1

When determining what socket path to connect to for a given URI we will - Connect to the driver specific daemon if its UNIX socket exists - Connect to libvirtd if its UNIX socket exists - If non-root, auto-spawn a daemon based on the default mode Historically the last point would result in spawning libvirtd, but with this change we now spawn a modular daemon. Remote client probing logic will pick a specific hypervisor daemon to connect to when the URI is NULL. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> --- meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index d0f84dbfa6..859ed36b8f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -63,7 +63,7 @@ option('qemu_user', type: 'string', value: '', description: 'username to run QEM option('qemu_group', type: 'string', value: '', description: 'groupname to run QEMU system instance as') option('qemu_moddir', type: 'string', value: '', description: 'set the directory where QEMU modules are located') option('driver_remote', type: 'feature', value: 'auto', description: 'remote driver') -option('remote_default_mode', type: 'combo', choices: ['legacy', 'direct'], value: 'legacy', description: 'remote driver default mode') +option('remote_default_mode', type: 'combo', choices: ['legacy', 'direct'], value: 'direct', description: 'remote driver default mode') option('driver_secrets', type: 'feature', value: 'auto', description: 'local secrets management driver') option('driver_test', type: 'feature', value: 'auto', description: 'test driver') option('driver_vbox', type: 'feature', value: 'auto', description: 'VirtualBox XPCOMC driver') -- 2.31.1

On 6/10/21 7:43 AM, Daniel P. Berrangé wrote:
This series first improves driver probing when using modular daemons.
Currently when URI is NULL, we connect to virtproxyd and it looks at which UNIX sockets exist and what binaries exist, to decide which modular hypervisor daemon to connect to.
This means the common case results in all traffic going via virtproxyd. Moving the logic out of virtproxyd into the remote client means we can avoid using virtproxyd by default.
With this, we can now switch to the modular daemons by default. The latter change primarily impacts how autostart works
When running as root we simply connect to whatever UNIX socket exists and rely on systemd to autostart if needed. Whether the UNIX sockets are for the modular daemon or libvirt doesn't matter - we'll look for both. Defaults are dependent on the distros' systemd presets. I intend to get Fedora / RHEL-9 presets changed to use the modular daemons.
I'll need to do the same for the SUSE presets, along with adjusting zypper patterns that include libvirtd, and other downstream tweaks. Additional testing may uncover other issues I haven't considered. I don't _think_ apparmor will prevent things from working since there are no profiles for the modular daemons. But yes, I'll need to work on some profiles :-). Regards, Jim

On Mon, Jun 14, 2021 at 05:22:22PM -0600, Jim Fehlig wrote:
On 6/10/21 7:43 AM, Daniel P. Berrangé wrote:
This series first improves driver probing when using modular daemons.
Currently when URI is NULL, we connect to virtproxyd and it looks at which UNIX sockets exist and what binaries exist, to decide which modular hypervisor daemon to connect to.
This means the common case results in all traffic going via virtproxyd. Moving the logic out of virtproxyd into the remote client means we can avoid using virtproxyd by default.
With this, we can now switch to the modular daemons by default. The latter change primarily impacts how autostart works
When running as root we simply connect to whatever UNIX socket exists and rely on systemd to autostart if needed. Whether the UNIX sockets are for the modular daemon or libvirt doesn't matter - we'll look for both. Defaults are dependent on the distros' systemd presets. I intend to get Fedora / RHEL-9 presets changed to use the modular daemons.
I'll need to do the same for the SUSE presets, along with adjusting zypper patterns that include libvirtd, and other downstream tweaks. Additional testing may uncover other issues I haven't considered. I don't _think_ apparmor will prevent things from working since there are no profiles for the modular daemons. But yes, I'll need to work on some profiles :-).
FWIW, with SELinux we have just copied the existing libvirtd profile to the modular daemons. That is not optimal of course, but it is as least no worse than current system. Over time we can refine the profile to be more strict. Also note if you're not ready to switch SUSE, you can just pass the -Dremote_default_mode=legacy option to meson, which will retain current behaviour when autostarting. 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 :|

On 6/15/21 2:42 AM, Daniel P. Berrangé wrote:
On Mon, Jun 14, 2021 at 05:22:22PM -0600, Jim Fehlig wrote:
On 6/10/21 7:43 AM, Daniel P. Berrangé wrote:
This series first improves driver probing when using modular daemons.
Currently when URI is NULL, we connect to virtproxyd and it looks at which UNIX sockets exist and what binaries exist, to decide which modular hypervisor daemon to connect to.
This means the common case results in all traffic going via virtproxyd. Moving the logic out of virtproxyd into the remote client means we can avoid using virtproxyd by default.
With this, we can now switch to the modular daemons by default. The latter change primarily impacts how autostart works
When running as root we simply connect to whatever UNIX socket exists and rely on systemd to autostart if needed. Whether the UNIX sockets are for the modular daemon or libvirt doesn't matter - we'll look for both. Defaults are dependent on the distros' systemd presets. I intend to get Fedora / RHEL-9 presets changed to use the modular daemons.
I'll need to do the same for the SUSE presets, along with adjusting zypper patterns that include libvirtd, and other downstream tweaks. Additional testing may uncover other issues I haven't considered. I don't _think_ apparmor will prevent things from working since there are no profiles for the modular daemons. But yes, I'll need to work on some profiles :-).
FWIW, with SELinux we have just copied the existing libvirtd profile to the modular daemons. That is not optimal of course, but it is as least no worse than current system. Over time we can refine the profile to be more strict.
I started with the approach of copying the libvirtd profile to virt{lxc,qemu,xen}d and removing the obvious stuff from each https://listman.redhat.com/archives/libvir-list/2021-June/msg00456.html The xen one in particular can be further reduced. I'm working on that and addressing other comments for V2.
Also note if you're not ready to switch SUSE, you can just pass the -Dremote_default_mode=legacy option to meson, which will retain current behaviour when autostarting.
Nod. I'll make the change after gaining more confidence at the packaging level, e.g. upgrades, etc. BTW, I've been testing the apparmor work on top of this series and haven't noticed any problems beyond the s/libxl/xen/ issue you already fixed. I didn't review the changes thoroughly but can certainly give a Tested-by: Jim Fehlig <jfehlig@suse.com> Regards, Jim

On 6/10/21 3:43 PM, Daniel P. Berrangé wrote:
This series first improves driver probing when using modular daemons.
Currently when URI is NULL, we connect to virtproxyd and it looks at which UNIX sockets exist and what binaries exist, to decide which modular hypervisor daemon to connect to.
This means the common case results in all traffic going via virtproxyd. Moving the logic out of virtproxyd into the remote client means we can avoid using virtproxyd by default.
With this, we can now switch to the modular daemons by default. The latter change primarily impacts how autostart works
When running as root we simply connect to whatever UNIX socket exists and rely on systemd to autostart if needed. Whether the UNIX sockets are for the modular daemon or libvirt doesn't matter - we'll look for both. Defaults are dependent on the distros' systemd presets. I intend to get Fedora / RHEL-9 presets changed to use the modular daemons.
When running as non-root, we again try to connect to whatever UNIX socket exists, whethe a modular daemon or libvirtd. When no socket exists though, we need to pick a daemon to start and that's where the meson default setting toggle comes into effect, so we prefer spawning modular daemons now and don't spawn libvirtd.
Daniel P. Berrangé (4): remote: extract logic for probing for modular daemons remote: add support for probing drivers with modular daemons remote: remove probing logic from virtproxyd dispatcher remote: switch to auto-spawn modular daemons by default
meson.build | 6 +- meson_options.txt | 2 +- src/libvirt_remote.syms | 5 + src/remote/remote_daemon_dispatch.c | 130 +------------------ src/remote/remote_sockets.c | 192 ++++++++++++++++++++++++++-- src/remote/remote_sockets.h | 7 + 6 files changed, 202 insertions(+), 140 deletions(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (3)
-
Daniel P. Berrangé
-
Jim Fehlig
-
Michal Prívozník