We generate the <interface type="user"> element on libvirt 3.8.0+
already.
For selecting passt rather than SLIRP, we only need to insert the child
element <backend type='passt'>. Make that child element conditional on
libvirt 9.0.0+, plus "passt --help" being executable.
For the latter, place the new helper function guestfs_int_passt_runnable()
in "lib/launch.c" -- we're going to use the same function for the direct
backend as well.
This change exposes a number of (perceived) shortcomings in libvirt; I've
filed <
https://bugzilla.redhat.com/show_bug.cgi?id=2222766> about those.
Bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=2184967
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
Reviewed-by: Richard W.M. Jones <rjones(a)redhat.com>
---
Notes:
v2:
- redirect "passt --help" stdout+stderr to /dev/null unless verbose
[Rich]
- pick up Rich's R-b
lib/guestfs-internal.h | 1 +
lib/launch-libvirt.c | 11 +++++++
lib/launch.c | 31 ++++++++++++++++++++
3 files changed, 43 insertions(+)
diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h
index 4be351e3d3cc..a6c4266ad3fe 100644
--- a/lib/guestfs-internal.h
+++ b/lib/guestfs-internal.h
@@ -703,6 +703,7 @@ extern void guestfs_int_unblock_sigterm (void);
extern int guestfs_int_create_socketname (guestfs_h *g, const char *filename, char
(*sockname)[UNIX_PATH_MAX]);
extern void guestfs_int_register_backend (const char *name, const struct backend_ops *);
extern int guestfs_int_set_backend (guestfs_h *g, const char *method);
+extern bool guestfs_int_passt_runnable (guestfs_h *g);
/* Close all file descriptors matching the condition. */
#define close_file_descriptors(cond) do { \
diff --git a/lib/launch-libvirt.c b/lib/launch-libvirt.c
index d4bf1a8ff242..994909a35f2d 100644
--- a/lib/launch-libvirt.c
+++ b/lib/launch-libvirt.c
@@ -1414,6 +1414,17 @@ construct_libvirt_xml_devices (guestfs_h *g,
guestfs_int_version_ge (¶ms->data->libvirt_version, 3, 8, 0)) {
start_element ("interface") {
attribute ("type", "user");
+ /* If libvirt is 9.0.0+ and "passt" is available, ask for passt rather
+ * than SLIRP (RHBZ#2184967). Note that this causes some
+ * appliance-visible changes (although network connectivity is certainly
+ * functional); refer to RHBZ#2222766 about those.
+ */
+ if (guestfs_int_version_ge (¶ms->data->libvirt_version, 9, 0, 0)
&&
+ guestfs_int_passt_runnable (g)) {
+ start_element ("backend") {
+ attribute ("type", "passt");
+ } end_element ();
+ }
start_element ("model") {
attribute ("type", "virtio");
} end_element ();
diff --git a/lib/launch.c b/lib/launch.c
index 6e08b12006da..87fb10e75a6c 100644
--- a/lib/launch.c
+++ b/lib/launch.c
@@ -36,6 +36,7 @@
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <errno.h>
#include <assert.h>
#include <libintl.h>
@@ -414,6 +415,36 @@ guestfs_int_set_backend (guestfs_h *g, const char *method)
return 0;
}
+/**
+ * Return C<true> if we can call S<C<passt --help>>, and it exits with
status
+ * C<0> or C<1>.
+ *
+ * (At least C<passt-0^20230222.g4ddbcb9-2.el9_2.x86_64> terminates with status
+ * C<1> in response to "--help", which is arguably wrong, and
potentially
+ * subject to change, but it doesn't really matter.)
+ */
+bool
+guestfs_int_passt_runnable (guestfs_h *g)
+{
+ CLEANUP_CMD_CLOSE struct command *cmd = NULL;
+ int r, ex;
+
+ cmd = guestfs_int_new_command (g);
+ if (cmd == NULL)
+ return false;
+
+ guestfs_int_cmd_add_string_unquoted (cmd, "passt --help");
+ if (!g->verbose)
+ guestfs_int_cmd_add_string_unquoted (cmd, " >/dev/null 2>&1");
+
+ r = guestfs_int_cmd_run (cmd);
+ if (r == -1 || !WIFEXITED (r))
+ return false;
+
+ ex = WEXITSTATUS (r);
+ return ex == 0 || ex == 1;
+}
+
/* This hack is only required to make static linking work. See:
*
https://stackoverflow.com/questions/1202494/why-doesnt-attribute-construc...
*/