]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
creds: import 'vmm.notify_socket' and use it to set
authorLuca Boccassi <bluca@debian.org>
Tue, 3 Jan 2023 17:11:04 +0000 (18:11 +0100)
committerLuca Boccassi <bluca@debian.org>
Thu, 5 Jan 2023 22:07:16 +0000 (23:07 +0100)
This is intended to be used with VSOCK, to notify the hypervisor/VMM, eg on the host:

qemu <...> -smbios type=11,value=io.systemd.credential:vmm.notify_socket=vsock:2:1234 -device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=42

(vsock:2:1234 -> send to host on vsock port 1234, default is to send to 0 which is
the hypervisor itself)

Also on the host:

$ socat - VSOCK-LISTEN:1234,socktype=5
READY=1
STATUS=Ready.

docs/CREDENTIALS.md
man/systemd.system-credentials.xml
src/core/import-creds.c

index 9e16dd3ba4f7d3d6dcd8d1dfae8dc04b7a755d8a..debe0a714f4c1d71df207a276602c19ba7810a0b 100644 (file)
@@ -330,6 +330,18 @@ systemd-run -p LoadCredential=mycred -P --wait systemd-creds cat mycred
 
 Various services shipped with `systemd` consume credentials for tweaking behaviour:
 
+* [`systemd(1)`](https://www.freedesktop.org/software/systemd/man/systemd.html)
+  (I.E.: PID1, the system manager) will look for the credential `vmm.notify_socket`
+  and will use it to send a `READY=1` datagram when the system has finished
+  booting. This is useful for hypervisors/VMMs or other processes on the host
+  to receive a notification via VSOCK when a virtual machine has finished booting.
+  Note that in case the hypervisor does not support `SOCK_DGRAM` over `AF_VSOCK`,
+  `SOCK_SEQPACKET` will be tried instead. The credential payload should be in the
+  form: `vsock:<CID>:<PORT>`, where `<CID>` is optional and if omitted will
+  default to talking to the hypervisor (`0`). Also note that this requires
+  support for VHOST to be built-in both the guest and the host kernels, and the
+  kernel modules to be loaded.
+
 * [`systemd-sysusers(8)`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html)
   will look for the credentials `passwd.hashed-password.<username>`,
   `passwd.plaintext-password.<username>` and `passwd.shell.<username>` to
@@ -382,7 +394,8 @@ qemu-system-x86_64 \
 ```
 
 This boots the specified disk image via qemu, provisioning public key SSH access
-for the root user from the caller's key:
+for the root user from the caller's key, and sends a notification when booting
+has finished to a process on the host:
 
 ```
 qemu-system-x86_64 \
@@ -396,8 +409,18 @@ qemu-system-x86_64 \
         -drive if=none,id=hd,file=test.raw,format=raw \
         -device virtio-scsi-pci,id=scsi \
         -device scsi-hd,drive=hd,bootindex=1 \
+        -device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=42 \
+        -smbios type=11,value=io.systemd.credential:vmm.notify_socket=vsock:2:1234 \
         -smbios type=11,value=io.systemd.credential.binary:tmpfiles.extra=$(echo "f~ /root/.ssh/authorized_keys 700 root root - $(ssh-add -L | base64 -w 0)" | base64 -w 0)
 ```
+
+A process on the host can listen for the notification, for example:
+
+```
+$ socat - VSOCK-LISTEN:1234,socktype=5
+READY=1
+```
+
 ## Relevant Paths
 
 From *service* perspective the runtime path to find loaded credentials in is
index 3eadf9b9852cf2b850d36a926d82453427804721..2a87139a1163008e2785b45127e9f578ca4943ec 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>vmm.notify_socket</varname></term>
+        <listitem>
+          <para>This credential is parsed looking for an <constant>AF_VSOCK</constant> or
+          <constant>AF_UNIX</constant> address where to send a <constant>READY=1</constant>
+          notification datagram when the system has finished booting. See:
+          <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+          This is useful for hypervisors/VMMs or other processes on the host
+          to receive a notification via VSOCK when a virtual machine has finished booting.
+          Note that in case the hypervisor does not support <constant>SOCK_DGRAM</constant>
+          over <constant>AF_VSOCK</constant>, <constant>SOCK_SEQPACKET</constant> will be
+          tried instead. The credential payload for <constant>AF_VSOCK</constant> should be
+          in the form: <literal>vsock:CID:PORT</literal>, where <literal>CID</literal> is
+          optional and if omitted will default to talking to the hypervisor
+          (<constant>0</constant>).</para>
+        </listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
index 1f5a15f73b40cac3b5f84f249c0e5f8bf34376a5..ade509be348c11031465626b6171c2c0961cc9a0 100644 (file)
@@ -713,5 +713,18 @@ int import_credentials(void) {
                         r = q;
         }
 
+        if (r >= 0) {
+                _cleanup_free_ char *address = NULL;
+
+                r = read_credential("vmm.notify_socket", (void **)&address, /* ret_size= */ NULL);
+                if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
+                        log_warning_errno(r, "Failed to read 'vmm.notify_socket' credential, ignoring: %m");
+                else if (r >= 0 && !isempty(address)) {
+                        r = setenv("NOTIFY_SOCKET", address, /* replace= */ 1);
+                        if (r < 0)
+                                log_warning_errno(errno, "Failed to set $NOTIFY_SOCKET environment variable, ignoring: %m");
+                }
+        }
+
         return r;
 }