1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2017 Ryan Moe <ryan.moe@gmail.com>
3 ;;; Copyright © 2018, 2020 Ludovic Courtès <ludo@gnu.org>
4 ;;; Copyright © 2020 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
6 ;;; This file is part of GNU Guix.
8 ;;; GNU Guix is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
13 ;;; GNU Guix is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
21 (define-module (gnu services virtualization)
22 #:use-module (gnu bootloader)
23 #:use-module (gnu bootloader grub)
24 #:use-module (gnu image)
25 #:use-module (gnu packages admin)
26 #:use-module (gnu packages ssh)
27 #:use-module (gnu packages virtualization)
28 #:use-module (gnu services base)
29 #:use-module (gnu services configuration)
30 #:use-module (gnu services dbus)
31 #:use-module (gnu services shepherd)
32 #:use-module (gnu services ssh)
33 #:use-module (gnu services)
34 #:use-module (gnu system file-systems)
35 #:use-module (gnu system hurd)
36 #:use-module (gnu system image)
37 #:use-module (gnu system images hurd)
38 #:use-module (gnu system shadow)
39 #:use-module (gnu system)
40 #:use-module (guix derivations)
41 #:use-module (guix gexp)
42 #:use-module (guix modules)
43 #:use-module (guix monads)
44 #:use-module (guix packages)
45 #:use-module (guix records)
46 #:use-module (guix store)
47 #:use-module (guix utils)
49 #:use-module (srfi srfi-9)
50 #:use-module (srfi srfi-26)
51 #:use-module (rnrs bytevectors)
52 #:use-module (ice-9 match)
54 #:export (%hurd-vm-operating-system
56 hurd-vm-configuration?
57 hurd-vm-configuration-os
58 hurd-vm-configuration-qemu
59 hurd-vm-configuration-image
60 hurd-vm-configuration-disk-size
61 hurd-vm-configuration-memory-size
62 hurd-vm-configuration-options
63 hurd-vm-configuration-id
64 hurd-vm-configuration-net-options
65 hurd-vm-configuration-secrets
82 qemu-binfmt-configuration
83 qemu-binfmt-configuration?
84 qemu-binfmt-service-type))
86 (define (uglify-field-name field-name)
87 (let ((str (symbol->string field-name)))
89 (string-split (string-delete #\? str) #\-)
92 (define (quote-val val)
93 (string-append "\"" val "\""))
95 (define (serialize-field field-name val)
96 (format #t "~a = ~a\n" (uglify-field-name field-name) val))
98 (define (serialize-string field-name val)
99 (serialize-field field-name (quote-val val)))
101 (define (serialize-boolean field-name val)
102 (serialize-field field-name (if val 1 0)))
104 (define (serialize-integer field-name val)
105 (serialize-field field-name val))
107 (define (build-opt-list val)
110 (string-join (map quote-val val) ",")
113 (define optional-list? list?)
114 (define optional-string? string?)
116 (define (serialize-list field-name val)
117 (serialize-field field-name (build-opt-list val)))
119 (define (serialize-optional-list field-name val)
121 (format #t "# ~a = []\n" (uglify-field-name field-name))
122 (serialize-list field-name val)))
124 (define (serialize-optional-string field-name val)
125 (if (string-null? val)
126 (format #t "# ~a = \"\"\n" (uglify-field-name field-name))
127 (serialize-string field-name val)))
129 (define-configuration libvirt-configuration
135 "Flag listening for secure TLS connections on the public TCP/IP port.
136 must set @code{listen} for this to have any effect.
138 It is necessary to setup a CA and issue server certificates before
139 using this capability.")
142 "Listen for unencrypted TCP connections on the public TCP/IP port.
143 must set @code{listen} for this to have any effect.
145 Using the TCP socket requires SASL authentication by default. Only
146 SASL mechanisms which support data encryption are allowed. This is
147 DIGEST_MD5 and GSSAPI (Kerberos5)")
150 "Port for accepting secure TLS connections This can be a port number,
154 "Port for accepting insecure TCP connections This can be a port number,
158 "IP address or hostname used for client connections.")
161 "Flag toggling mDNS advertisement of the libvirt service.
163 Alternatively can disable for all services on a host by
164 stopping the Avahi daemon.")
166 (string (string-append "Virtualization Host " (gethostname)))
167 "Default mDNS advertisement name. This must be unique on the
168 immediate broadcast network.")
171 "UNIX domain socket group ownership. This can be used to
172 allow a 'trusted' set of users access to management capabilities
173 without becoming root.")
176 "UNIX socket permissions for the R/O socket. This is used
177 for monitoring VM status only.")
180 "UNIX socket permissions for the R/W socket. Default allows
181 only root. If PolicyKit is enabled on the socket, the default
182 will change to allow everyone (eg, 0777)")
183 (unix-sock-admin-perms
185 "UNIX socket permissions for the admin socket. Default allows
186 only owner (root), do not change it unless you are sure to whom
187 you are exposing the access to.")
189 (string "/var/run/libvirt")
190 "The directory in which sockets will be found/created.")
193 "Authentication scheme for UNIX read-only sockets. By default
194 socket permissions allow anyone to connect")
197 "Authentication scheme for UNIX read-write sockets. By default
198 socket permissions only allow root. If PolicyKit support was compiled
199 into libvirt, the default will be to use 'polkit' auth.")
202 "Authentication scheme for TCP sockets. If you don't enable SASL,
203 then all TCP traffic is cleartext. Don't do this outside of a dev/test
207 "Authentication scheme for TLS sockets. TLS sockets already have
208 encryption provided by the TLS layer, and limited authentication is
209 done by certificates.
211 It is possible to make use of any SASL authentication mechanism as
212 well, by using 'sasl' for this option")
215 "API access control scheme.
217 By default an authenticated user is allowed access to all APIs. Access
218 drivers can place restrictions on this.")
221 "Server key file path. If set to an empty string, then no private key
225 "Server key file path. If set to an empty string, then no certificate
229 "Server key file path. If set to an empty string, then no CA certificate
233 "Certificate revocation list path. If set to an empty string, then no
237 "Disable verification of our own server certificates.
239 When libvirtd starts it performs some sanity checks against its own
243 "Disable verification of client certificates.
245 Client certificate verification is the primary authentication mechanism.
246 Any client which does not present a certificate signed by the CA
250 "Whitelist of allowed x509 Distinguished Name.")
251 (sasl-allowed-usernames
253 "Whitelist of allowed SASL usernames. The format for username
254 depends on the SASL authentication mechanism.")
257 "Override the compile time default TLS priority string. The
258 default is usually \"NORMAL\" unless overridden at build time.
259 Only set this is it is desired for libvirt to deviate from
260 the global default settings.")
263 "Maximum number of concurrent client connections to allow
264 over all sockets combined.")
267 "Maximum length of queue of connections waiting to be
268 accepted by the daemon. Note, that some protocols supporting
269 retransmission may obey this so that a later reattempt at
270 connection succeeds.")
271 (max-anonymous-clients
273 "Maximum length of queue of accepted but not yet authenticated
274 clients. Set this to zero to turn this feature off")
277 "Number of workers to start up initially.")
280 "Maximum number of worker threads.
282 If the number of active clients exceeds @code{min-workers},
283 then more threads are spawned, up to max_workers limit.
284 Typically you'd want max_workers to equal maximum number
285 of clients allowed.")
288 "Number of priority workers. If all workers from above
289 pool are stuck, some calls marked as high priority
290 (notably domainDestroy) can be executed in this pool.")
293 "Total global limit on concurrent RPC calls.")
296 "Limit on concurrent requests from a single client
297 connection. To avoid one client monopolizing the server
298 this should be a small fraction of the global max_requests
299 and max_workers parameter.")
302 "Same as @code{min-workers} but for the admin interface.")
305 "Same as @code{max-workers} but for the admin interface.")
308 "Same as @code{max-clients} but for the admin interface.")
309 (admin-max-queued-clients
311 "Same as @code{max-queued-clients} but for the admin interface.")
312 (admin-max-client-requests
314 "Same as @code{max-client-requests} but for the admin interface.")
317 "Logging level. 4 errors, 3 warnings, 2 information, 1 debug.")
319 (string "3:remote 4:event")
322 A filter allows selecting a different logging level for a given category
324 The format for a filter is one of:
331 where @code{name} is a string which is matched against the category
332 given in the @code{VIR_LOG_INIT()} at the top of each libvirt source
333 file, e.g., \"remote\", \"qemu\", or \"util.json\" (the name in the
334 filter can be a substring of the full category name, in order
335 to match multiple similar categories), the optional \"+\" prefix
336 tells libvirt to log stack trace for each message matching
337 name, and @code{x} is the minimal level where matching messages should
347 Multiple filters can be defined in a single filters statement, they just
348 need to be separated by spaces.")
350 (string "3:syslog:libvirtd")
353 An output is one of the places to save logging information
354 The format for an output can be:
358 output goes to stderr
361 use syslog for the output and use the given name as the ident
363 @item x:file:file_path
364 output to a file, with the given filepath
367 output to journald logging system
370 In all case the x prefix is the minimal level, acting as a filter
379 Multiple outputs can be defined, they just need to be separated by spaces.")
382 "Allows usage of the auditing subsystem to be altered
385 @item 0: disable all auditing
386 @item 1: enable auditing, only if enabled on host
387 @item 2: enable auditing, and exit if disabled on host.
392 "Send audit messages via libvirt logging infrastructure.")
395 "Host UUID. UUID must not have all digits be the same.")
398 "Source to read host UUID.
402 @item @code{smbios}: fetch the UUID from @code{dmidecode -s system-uuid}
404 @item @code{machine-id}: fetch the UUID from @code{/etc/machine-id}
408 If @code{dmidecode} does not provide a valid UUID a temporary UUID
412 "A keepalive message is sent to a client after
413 @code{keepalive_interval} seconds of inactivity to check if
414 the client is still responding. If set to -1, libvirtd will
415 never send keepalive requests; however clients can still send
416 them and the daemon will send responses.")
419 "Maximum number of keepalive messages that are allowed to be sent
420 to the client without getting any response before the connection is
423 In other words, the connection is automatically
424 closed approximately after
425 @code{keepalive_interval * (keepalive_count + 1)} seconds since the last
426 message received from the client. When @code{keepalive-count} is
427 set to 0, connections will be automatically closed after
428 @code{keepalive-interval} seconds of inactivity without sending any
429 keepalive messages.")
430 (admin-keepalive-interval
432 "Same as above but for admin interface.")
433 (admin-keepalive-count
435 "Same as above but for admin interface.")
438 "Timeout for Open vSwitch calls.
440 The @code{ovs-vsctl} utility is used for the configuration and
441 its timeout option is set by default to 5 seconds to avoid
442 potential infinite waits blocking libvirt."))
444 (define* (libvirt-conf-file config)
445 "Return a libvirtd config file."
446 (plain-file "libvirtd.conf"
447 (with-output-to-string
449 (serialize-configuration config libvirt-configuration-fields)))))
451 (define %libvirt-accounts
452 (list (user-group (name "libvirt") (system? #t))))
454 (define (%libvirt-activation config)
455 (let ((sock-dir (libvirt-configuration-unix-sock-dir config)))
457 (use-modules (guix build utils))
458 (mkdir-p #$sock-dir))))
461 (define (libvirt-shepherd-service config)
462 (let* ((config-file (libvirt-conf-file config))
463 (libvirt (libvirt-configuration-libvirt config)))
464 (list (shepherd-service
465 (documentation "Run the libvirt daemon.")
466 (provision '(libvirtd))
467 (start #~(make-forkexec-constructor
468 (list (string-append #$libvirt "/sbin/libvirtd")
470 ;; For finding qemu and ip binaries.
471 #:environment-variables
473 "PATH=/run/current-system/profile/bin:"
474 "/run/current-system/profile/sbin"))))
475 (stop #~(make-kill-destructor))))))
477 (define libvirt-service-type
478 (service-type (name 'libvirt)
481 (service-extension polkit-service-type
482 (compose list libvirt-configuration-libvirt))
483 (service-extension profile-service-type
486 (libvirt-configuration-libvirt config)
488 (service-extension activation-service-type
490 (service-extension shepherd-root-service-type
491 libvirt-shepherd-service)
492 (service-extension account-service-type
493 (const %libvirt-accounts))))
494 (default-value (libvirt-configuration))))
497 (define-record-type* <virtlog-configuration>
498 virtlog-configuration make-virtlog-configuration
499 virtlog-configuration?
500 (libvirt virtlog-configuration-libvirt
502 (log-level virtlog-configuration-log-level
504 (log-filters virtlog-configuration-log-filters
505 (default "3:remote 4:event"))
506 (log-outputs virtlog-configuration-log-outputs
507 (default "3:syslog:virtlogd"))
508 (max-clients virtlog-configuration-max-clients
510 (max-size virtlog-configuration-max-size
511 (default 2097152)) ;; 2MB
512 (max-backups virtlog-configuration-max-backups
515 (define* (virtlogd-conf-file config)
516 "Return a virtlogd config file."
517 (plain-file "virtlogd.conf"
519 "log_level = " (number->string (virtlog-configuration-log-level config)) "\n"
520 "log_filters = \"" (virtlog-configuration-log-filters config) "\"\n"
521 "log_outputs = \"" (virtlog-configuration-log-outputs config) "\"\n"
522 "max_clients = " (number->string (virtlog-configuration-max-clients config)) "\n"
523 "max_size = " (number->string (virtlog-configuration-max-size config)) "\n"
524 "max_backups = " (number->string (virtlog-configuration-max-backups config)) "\n")))
526 (define (virtlogd-shepherd-service config)
527 (let* ((config-file (virtlogd-conf-file config))
528 (libvirt (virtlog-configuration-libvirt config)))
529 (list (shepherd-service
530 (documentation "Run the virtlog daemon.")
531 (provision '(virtlogd))
532 (start #~(make-forkexec-constructor
533 (list (string-append #$libvirt "/sbin/virtlogd")
534 "-f" #$config-file)))
535 (stop #~(make-kill-destructor))))))
537 (define virtlog-service-type
538 (service-type (name 'virtlogd)
541 (service-extension shepherd-root-service-type
542 virtlogd-shepherd-service)))
543 (default-value (virtlog-configuration))))
545 (define (generate-libvirt-documentation)
546 (generate-documentation
547 `((libvirt-configuration ,libvirt-configuration-fields))
548 'libvirt-configuration))
552 ;;; Transparent QEMU emulation via binfmt_misc.
555 ;; Platforms that QEMU can emulate.
556 (define-record-type <qemu-platform>
557 (qemu-platform name family magic mask)
559 (name qemu-platform-name) ;string
560 (family qemu-platform-family) ;string
561 (magic qemu-platform-magic) ;bytevector
562 (mask qemu-platform-mask)) ;bytevector
566 "Expand the given string into a bytevector."
569 (string? (syntax->datum #'str))
570 (let ((bv (u8-list->bytevector
572 (string->list (syntax->datum #'str))))))
575 ;;; The platform descriptions below are taken from
576 ;;; 'scripts/qemu-binfmt-conf.sh' in QEMU.
579 (qemu-platform "i386" "i386"
580 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00")
581 (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
584 (qemu-platform "i486" "i386"
585 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00")
586 (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
589 (qemu-platform "alpha" "alpha"
590 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90")
591 (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
594 (qemu-platform "arm" "arm"
595 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00")
596 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
599 (qemu-platform "armeb" "arm"
600 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28")
601 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
604 (qemu-platform "sparc" "sparc"
605 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02")
606 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
609 (qemu-platform "sparc32plus" "sparc"
610 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12")
611 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
614 (qemu-platform "ppc" "ppc"
615 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14")
616 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
619 (qemu-platform "ppc64" "ppc"
620 (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15")
621 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
624 (qemu-platform "ppc64le" "ppcle"
625 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00")
626 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00")))
629 (qemu-platform "m68k" "m68k"
630 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04")
631 (bv "\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
633 ;; XXX: We could use the other endianness on a MIPS host.
635 (qemu-platform "mips" "mips"
636 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
637 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
640 (qemu-platform "mipsel" "mips"
641 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
642 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
645 (qemu-platform "mipsn32" "mips"
646 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
647 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
650 (qemu-platform "mipsn32el" "mips"
651 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
652 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
655 (qemu-platform "mips64" "mips"
656 (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08")
657 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
660 (qemu-platform "mips64el" "mips"
661 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00")
662 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
665 (qemu-platform "riscv32" "riscv"
666 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00")
667 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
670 (qemu-platform "riscv64" "riscv"
671 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00")
672 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
675 (qemu-platform "sh4" "sh4"
676 (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00")
677 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
680 (qemu-platform "sh4eb" "sh4"
681 (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a")
682 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
685 (qemu-platform "s390x" "s390x"
686 (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16")
687 (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
690 (qemu-platform "aarch64" "arm"
691 (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00")
692 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff")))
695 (qemu-platform "hppa" "hppa"
696 (bv "\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f")
697 (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff")))
699 (define %qemu-platforms
700 (list %i386 %i486 %alpha %arm %sparc32plus %ppc %ppc64 %ppc64le %m68k
701 %mips %mipsel %mipsn32 %mipsn32el %mips64 %mips64el
702 %riscv32 %riscv64 %sh4 %sh4eb %s390x %aarch64 %hppa))
704 (define (lookup-qemu-platforms . names)
705 "Return the list of QEMU platforms that match NAMES--a list of names such as
706 \"arm\", \"hppa\", etc."
707 (filter (lambda (platform)
708 (member (qemu-platform-name platform) names))
711 (define-record-type* <qemu-binfmt-configuration>
712 qemu-binfmt-configuration make-qemu-binfmt-configuration
713 qemu-binfmt-configuration?
714 (qemu qemu-binfmt-configuration-qemu
716 (platforms qemu-binfmt-configuration-platforms
717 (default '())) ;safest default
718 (guix-support? qemu-binfmt-configuration-guix-support?
721 (define (qemu-platform->binfmt qemu platform)
722 "Return a gexp that evaluates to a binfmt string for PLATFORM, using the
724 (define (bytevector->binfmt-string bv)
725 ;; Return a binfmt-friendly string representing BV. Hex-encode every
726 ;; character, in particular because the doc notes "that you must escape
727 ;; any NUL bytes; parsing halts at the first one".
731 (string-pad (number->string n 16) 2 #\0)))
732 (bytevector->u8-list bv))))
735 (($ <qemu-platform> name family magic mask)
736 ;; See 'Documentation/binfmt_misc.txt' in the kernel.
737 #~(string-append ":qemu-" #$name ":M::"
738 #$(bytevector->binfmt-string magic)
739 ":" #$(bytevector->binfmt-string mask)
740 ":" #$(file-append qemu "/bin/qemu-" name)
744 (define %binfmt-mount-point
745 (file-system-mount-point %binary-format-file-system))
747 (define %binfmt-register-file
748 (string-append %binfmt-mount-point "/register"))
750 (define qemu-binfmt-shepherd-services
752 (($ <qemu-binfmt-configuration> qemu platforms)
753 (list (shepherd-service
754 (provision '(qemu-binfmt))
755 (documentation "Install binfmt_misc handlers for QEMU.")
756 (requirement '(file-system-/proc/sys/fs/binfmt_misc))
758 ;; Register the handlers for all of PLATFORMS.
759 (for-each (lambda (str)
760 (call-with-output-file
761 #$%binfmt-register-file
763 (display str port))))
765 #$@(map (cut qemu-platform->binfmt qemu
770 ;; Unregister the handlers.
771 (for-each (lambda (name)
772 (let ((file (string-append
773 #$%binfmt-mount-point
775 (call-with-output-file file
777 (display "-1" port)))))
778 '#$(map qemu-platform-name platforms))
781 (define qemu-binfmt-guix-chroot
783 ;; Add QEMU and its dependencies to the guix-daemon chroot so that our
784 ;; binfmt_misc handlers work in the chroot (otherwise 'execve' would fail
787 ;; The 'F' flag of binfmt_misc is meant to address this problem by loading
788 ;; the interpreter upfront rather than lazily, but apparently that is
789 ;; insufficient (perhaps it loads the 'qemu-ARCH' binary upfront but looks
790 ;; up its dependencies lazily?).
791 (($ <qemu-binfmt-configuration> qemu platforms guix?)
792 (if guix? (list qemu) '()))))
794 (define qemu-binfmt-service-type
795 ;; TODO: Make a separate binfmt_misc service out of this?
796 (service-type (name 'qemu-binfmt)
798 (list (service-extension file-system-service-type
800 (list %binary-format-file-system)))
801 (service-extension shepherd-root-service-type
802 qemu-binfmt-shepherd-services)
803 (service-extension guix-service-type
804 qemu-binfmt-guix-chroot)))
805 (default-value (qemu-binfmt-configuration))
807 "This service supports transparent emulation of binaries
808 compiled for other architectures using QEMU and the @code{binfmt_misc}
809 functionality of the kernel Linux.")))
813 ;;; Secrets for guest VMs.
816 (define (secret-service-activation port)
817 "Return an activation snippet that fetches sensitive material at local PORT,
818 over TCP. Reboot upon failure."
819 (with-imported-modules '((gnu build secret-service)
822 (use-modules (gnu build secret-service))
823 (let ((sent (secret-service-receive-secrets #$port)))
828 (define secret-service-type
830 (name 'secret-service)
831 (extensions (list (service-extension activation-service-type
832 secret-service-activation)))
834 "This service fetches secret key and other sensitive material over TCP at
835 boot time. This service is meant to be used by virtual machines (VMs) that
836 can only be accessed by their host.")))
838 (define (secret-service-operating-system os)
839 "Return an operating system based on OS that includes the secret-service,
840 that will be listening to receive secret keys on port 1004, TCP."
843 (services (cons (service secret-service-type 1004)
844 (operating-system-user-services os)))))
848 ;;; The Hurd in VM service: a Childhurd.
851 (define %hurd-vm-operating-system
853 (inherit %hurd-default-operating-system)
854 (host-name "childhurd")
855 (timezone "Europe/Amsterdam")
856 (bootloader (bootloader-configuration
857 (bootloader grub-minimal-bootloader)
861 (service openssh-service-type
862 (openssh-configuration
863 (openssh openssh-sans-x)
866 (permit-root-login #t)
867 (allow-empty-passwords? #t)
868 (password-authentication? #t)))
869 %base-services/hurd))))
871 (define-record-type* <hurd-vm-configuration>
872 hurd-vm-configuration make-hurd-vm-configuration
873 hurd-vm-configuration?
874 (os hurd-vm-configuration-os ;<operating-system>
875 (default %hurd-vm-operating-system))
876 (qemu hurd-vm-configuration-qemu ;<package>
877 (default qemu-minimal))
878 (image hurd-vm-configuration-image ;string
880 (default (hurd-vm-disk-image this-record)))
881 (disk-size hurd-vm-configuration-disk-size ;number or 'guess
883 (memory-size hurd-vm-configuration-memory-size ;number
885 (options hurd-vm-configuration-options ;list of string
886 (default `("--snapshot")))
887 (id hurd-vm-configuration-id ;#f or integer [1..]
889 (net-options hurd-vm-configuration-net-options ;list of string
891 (default (hurd-vm-net-options this-record)))
892 (secret-root hurd-vm-configuration-secret-root ;string
893 (default "/etc/childhurd")))
895 (define (hurd-vm-disk-image config)
896 "Return a disk-image for the Hurd according to CONFIG. The secret-service
897 is added to the OS specified in CONFIG."
898 (let ((os (secret-service-operating-system (hurd-vm-configuration-os config)))
899 (disk-size (hurd-vm-configuration-disk-size config)))
902 (inherit hurd-disk-image)
904 (operating-system os)))))
906 (define (hurd-vm-port config base)
907 "Return the forwarded vm port for this childhurd config."
908 (let ((id (or (hurd-vm-configuration-id config) 0)))
909 (+ base (* 1000 id))))
910 (define %hurd-vm-secrets-port 11004)
911 (define %hurd-vm-ssh-port 10022)
912 (define %hurd-vm-vnc-port 15900)
914 (define (hurd-vm-net-options config)
915 `("--device" "rtl8139,netdev=net0"
917 ,(string-append "user,id=net0"
918 ",hostfwd=tcp:127.0.0.1:"
919 (number->string (hurd-vm-port config %hurd-vm-secrets-port))
921 ",hostfwd=tcp:127.0.0.1:"
922 (number->string (hurd-vm-port config %hurd-vm-ssh-port))
924 ",hostfwd=tcp:127.0.0.1:"
925 (number->string (hurd-vm-port config %hurd-vm-vnc-port))
928 (define (hurd-vm-shepherd-service config)
929 "Return a <shepherd-service> for a Hurd in a Virtual Machine with CONFIG."
931 (let ((image (hurd-vm-configuration-image config))
932 (qemu (hurd-vm-configuration-qemu config))
933 (memory-size (hurd-vm-configuration-memory-size config))
934 (options (hurd-vm-configuration-options config))
935 (id (hurd-vm-configuration-id config))
936 (net-options (hurd-vm-configuration-net-options config))
937 (provisions '(hurd-vm childhurd)))
941 (string-append #$qemu "/bin/qemu-system-i386")
942 #$@(if (file-exists? "/dev/kvm") '("--enable-kvm") '())
943 "-m" (number->string #$memory-size)
950 (documentation "Run the Hurd in a Virtual Machine: a Childhurd.")
953 (cute symbol-append <>
954 (string->symbol (number->string id)))
957 (requirement '(loopback networking user-processes))
959 (with-imported-modules
960 (source-module-closure '((gnu build secret-service)
962 #~(let ((spawn (make-forkexec-constructor #$vm-command)))
965 (port #$(hurd-vm-port config %hurd-vm-secrets-port))
966 (root #$(hurd-vm-configuration-secret-root config)))
969 (secret-service-send-secrets port root))
971 (kill (- pid) SIGTERM)
972 (apply throw key args)))
974 (modules `((gnu build secret-service)
977 (stop #~(make-kill-destructor))))))
979 (define hurd-vm-service-type
982 (extensions (list (service-extension shepherd-root-service-type
983 hurd-vm-shepherd-service)))
984 (default-value (hurd-vm-configuration))
986 "Provide a Virtual Machine running the GNU/Hurd.")))