]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vmspawn: add nic configuration
authorSam Leonard <sam.leonard@codethink.co.uk>
Fri, 10 Nov 2023 17:32:25 +0000 (17:32 +0000)
committerSam Leonard <sam.leonard@codethink.co.uk>
Fri, 9 Feb 2024 12:46:43 +0000 (12:46 +0000)
man/systemd-vmspawn.xml
src/vmspawn/vmspawn-util.c
src/vmspawn/vmspawn-util.h
src/vmspawn/vmspawn.c

index a9011d910623de60cdc89c1d4240336680255c3d..38f5e3c93e73e5f81247f63eeaf0371e239a3757 100644 (file)
         <xi:include href="version-info.xml" xpointer="v255"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>-n</option></term>
+        <term><option>--network-tap</option></term>
+
+        <listitem>
+          <para>Create a TAP device to network with the virtual machine.</para>
+          <para>
+            Note: root privileges are required to use TAP networking.
+            Additionally requires a correctly setup
+            <citerefentry><refentrytitle>systemd-networkd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+            to be running on the host to ensure the host interface is correctly configured.
+            The relevant <literal>.network</literal> file can be found at <filename>/usr/lib/systemd/network/80-vm-vt.network</filename>.
+          </para>
+          <xi:include href="version-info.xml" xpointer="v255"/>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--network-user-mode</option></term>
+
+        <listitem><para>Use user mode networking with QEMU.</para>
+
+        <xi:include href="version-info.xml" xpointer="v255"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--firmware=</option><replaceable>PATH</replaceable></term>
 
index 79e1e5399a2d8448af646123f4667f236061626d..822b10291217e44fbb7b40d7e5da5b54c777db66 100644 (file)
@@ -20,6 +20,7 @@
 #include "siphash24.h"
 #include "socket-util.h"
 #include "sort-util.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "vmspawn-util.h"
@@ -35,6 +36,8 @@ OvmfConfig* ovmf_config_free(OvmfConfig *config) {
         return mfree(config);
 }
 
+DEFINE_STRING_TABLE_LOOKUP(qemu_network_stack, QemuNetworkStack);
+
 int qemu_check_kvm_support(void) {
         if (access("/dev/kvm", F_OK) >= 0)
                 return true;
index c3dbdf205b1a02af21d81e416d06a9435d8d0707..9c9b1867d38c82144f5dd63622c13c2a7fa53f57 100644 (file)
@@ -45,6 +45,23 @@ static inline const char *ovmf_config_vars_format(const OvmfConfig *c) {
 OvmfConfig* ovmf_config_free(OvmfConfig *ovmf_config);
 DEFINE_TRIVIAL_CLEANUP_FUNC(OvmfConfig*, ovmf_config_free);
 
+typedef enum QemuNetworkStack {
+        QEMU_NET_TAP,
+        QEMU_NET_USER,
+        QEMU_NET_NONE,
+        _QEMU_NET_MAX,
+        _QEMU_NET_INVALID = -EINVAL,
+} QemuNetworkStack;
+
+static const char* const qemu_network_stack_table[_QEMU_NET_MAX] = {
+        [QEMU_NET_TAP]  = "tap",
+        [QEMU_NET_USER] = "user",
+        [QEMU_NET_NONE] = "none",
+};
+
+const char* qemu_network_stack_to_string(QemuNetworkStack type) _const_;
+QemuNetworkStack qemu_network_stack_from_string(const char *s) _pure_;
+
 int qemu_check_kvm_support(void);
 int qemu_check_vsock_support(void);
 int list_ovmf_config(char ***ret);
index 5e5139d574200ba81cc6981b0149c8e3b1b75a2d..37c354f0b077a76de6b8b59434d80de5caa7114d 100644 (file)
@@ -61,6 +61,7 @@ static int arg_tpm = -1;
 static char *arg_linux = NULL;
 static char *arg_initrd = NULL;
 static bool arg_qemu_gui = false;
+static QemuNetworkStack arg_network_stack = QEMU_NET_NONE;
 static int arg_secure_boot = -1;
 static MachineCredentialContext arg_credentials = {};
 static SettingsMask arg_settings_mask = 0;
@@ -109,6 +110,8 @@ static int help(void) {
                "     --linux=PATH           Specify the linux kernel for direct kernel boot\n"
                "     --initrd=PATH          Specify the initrd for direct kernel boot\n"
                "     --qemu-gui             Start QEMU in graphical mode\n"
+               "  -n --network-tap          Create a TAP device for networking with QEMU.\n"
+               "     --network-user-mode    Use user mode networking with QEMU.\n"
                "     --secure-boot=BOOL     Configure whether to search for firmware which\n"
                "                            supports Secure Boot\n"
                "     --firmware=PATH|list   Select firmware definition file (or list available)\n"
@@ -145,6 +148,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_LINUX,
                 ARG_INITRD,
                 ARG_QEMU_GUI,
+                ARG_NETWORK_USER_MODE,
                 ARG_SECURE_BOOT,
                 ARG_SET_CREDENTIAL,
                 ARG_LOAD_CREDENTIAL,
@@ -152,25 +156,27 @@ static int parse_argv(int argc, char *argv[]) {
         };
 
         static const struct option options[] = {
-                { "help",            no_argument,       NULL, 'h'                 },
-                { "version",         no_argument,       NULL, ARG_VERSION         },
-                { "quiet",           no_argument,       NULL, 'q'                 },
-                { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
-                { "image",           required_argument, NULL, 'i'                 },
-                { "machine",         required_argument, NULL, 'M'                 },
-                { "qemu-smp",        required_argument, NULL, ARG_QEMU_SMP        },
-                { "qemu-mem",        required_argument, NULL, ARG_QEMU_MEM        },
-                { "qemu-kvm",        required_argument, NULL, ARG_QEMU_KVM        },
-                { "qemu-vsock",      required_argument, NULL, ARG_QEMU_VSOCK      },
-                { "vsock-cid",       required_argument, NULL, ARG_VSOCK_CID       },
-                { "tpm",             required_argument, NULL, ARG_TPM             },
-                { "linux",           required_argument, NULL, ARG_LINUX           },
-                { "initrd",          required_argument, NULL, ARG_INITRD          },
-                { "qemu-gui",        no_argument,       NULL, ARG_QEMU_GUI        },
-                { "secure-boot",     required_argument, NULL, ARG_SECURE_BOOT     },
-                { "set-credential",  required_argument, NULL, ARG_SET_CREDENTIAL  },
-                { "load-credential", required_argument, NULL, ARG_LOAD_CREDENTIAL },
-                { "firmware",        required_argument, NULL, ARG_FIRMWARE        },
+                { "help",              no_argument,       NULL, 'h'                   },
+                { "version",           no_argument,       NULL, ARG_VERSION           },
+                { "quiet",             no_argument,       NULL, 'q'                   },
+                { "no-pager",          no_argument,       NULL, ARG_NO_PAGER          },
+                { "image",             required_argument, NULL, 'i'                   },
+                { "machine",           required_argument, NULL, 'M'                   },
+                { "qemu-smp",          required_argument, NULL, ARG_QEMU_SMP          },
+                { "qemu-mem",          required_argument, NULL, ARG_QEMU_MEM          },
+                { "qemu-kvm",          required_argument, NULL, ARG_QEMU_KVM          },
+                { "qemu-vsock",        required_argument, NULL, ARG_QEMU_VSOCK        },
+                { "vsock-cid",         required_argument, NULL, ARG_VSOCK_CID         },
+                { "tpm",               required_argument, NULL, ARG_TPM               },
+                { "linux",             required_argument, NULL, ARG_LINUX             },
+                { "initrd",            required_argument, NULL, ARG_INITRD            },
+                { "qemu-gui",          no_argument,       NULL, ARG_QEMU_GUI          },
+                { "network-tap",       no_argument,       NULL, 'n'                   },
+                { "network-user-mode", no_argument,       NULL, ARG_NETWORK_USER_MODE },
+                { "secure-boot",       required_argument, NULL, ARG_SECURE_BOOT       },
+                { "set-credential",    required_argument, NULL, ARG_SET_CREDENTIAL    },
+                { "load-credential",   required_argument, NULL, ARG_LOAD_CREDENTIAL   },
+                { "firmware",          required_argument, NULL, ARG_FIRMWARE          },
                 {}
         };
 
@@ -180,7 +186,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argv);
 
         optind = 0;
-        while ((c = getopt_long(argc, argv, "+hi:M:q", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "+hi:M:nq", options, NULL)) >= 0)
                 switch (c) {
                 case 'h':
                         return help();
@@ -281,6 +287,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_qemu_gui = true;
                         break;
 
+                case 'n':
+                        arg_network_stack = QEMU_NET_TAP;
+                        break;
+
+                case ARG_NETWORK_USER_MODE:
+                        arg_network_stack = QEMU_NET_USER;
+                        break;
+
                 case ARG_SECURE_BOOT:
                         r = parse_tristate(optarg, &arg_secure_boot);
                         if (r < 0)
@@ -702,8 +716,7 @@ static int run_virtual_machine(void) {
                 "-smp", arg_qemu_smp ?: "1",
                 "-m", mem,
                 "-object", "rng-random,filename=/dev/urandom,id=rng0",
-                "-device", "virtio-rng-pci,rng=rng0,id=rng-device0",
-                "-nic", "user,model=virtio-net-pci"
+                "-device", "virtio-rng-pci,rng=rng0,id=rng-device0"
         );
         if (!cmdline)
                 return log_oom();
@@ -722,6 +735,15 @@ static int run_virtual_machine(void) {
                 }
         }
 
+        if (arg_network_stack == QEMU_NET_TAP)
+                r = strv_extend_many(&cmdline, "-nic", "tap,script=no,model=virtio-net-pci");
+        else if (arg_network_stack == QEMU_NET_USER)
+                r = strv_extend_many(&cmdline, "-nic", "user,model=virtio-net-pci");
+        else
+                r = strv_extend_many(&cmdline, "-nic", "none");
+        if (r < 0)
+                return log_oom();
+
         bool use_vsock = arg_qemu_vsock > 0 && ARCHITECTURE_SUPPORTS_SMBIOS;
         if (arg_qemu_vsock < 0) {
                 r = qemu_check_vsock_support();
@@ -1062,6 +1084,13 @@ static int determine_names(void) {
         return 0;
 }
 
+static int verify_arguments(void) {
+        if (arg_network_stack == QEMU_NET_TAP && !arg_privileged)
+                return log_error_errno(SYNTHETIC_ERRNO(EPERM), "--network-tap requires root privileges, refusing.");
+
+        return 0;
+}
+
 static int run(int argc, char *argv[]) {
         int r;
 
@@ -1077,6 +1106,10 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
+        r = verify_arguments();
+        if (r < 0)
+                return r;
+
         if (!arg_quiet) {
                 _cleanup_free_ char *u = NULL;
                 (void) terminal_urlify_path(arg_image, arg_image, &u);