virtualization.scm 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  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,2021 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  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.
  12. ;;;
  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.
  17. ;;;
  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/>.
  20. (define-module (gnu services virtualization)
  21. #:use-module (gnu bootloader)
  22. #:use-module (gnu bootloader grub)
  23. #:use-module (gnu image)
  24. #:use-module (gnu packages admin)
  25. #:use-module (gnu packages gdb)
  26. #:use-module (gnu packages package-management)
  27. #:use-module (gnu packages ssh)
  28. #:use-module (gnu packages virtualization)
  29. #:use-module (gnu services base)
  30. #:use-module (gnu services configuration)
  31. #:use-module (gnu services dbus)
  32. #:use-module (gnu services shepherd)
  33. #:use-module (gnu services ssh)
  34. #:use-module (gnu services)
  35. #:use-module (gnu system file-systems)
  36. #:use-module (gnu system hurd)
  37. #:use-module (gnu system image)
  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)
  48. #:use-module (srfi srfi-9)
  49. #:use-module (srfi srfi-26)
  50. #:use-module (rnrs bytevectors)
  51. #:use-module (ice-9 match)
  52. #:export (%hurd-vm-operating-system
  53. hurd-vm-configuration
  54. hurd-vm-configuration?
  55. hurd-vm-configuration-os
  56. hurd-vm-configuration-qemu
  57. hurd-vm-configuration-image
  58. hurd-vm-configuration-disk-size
  59. hurd-vm-configuration-memory-size
  60. hurd-vm-configuration-options
  61. hurd-vm-configuration-id
  62. hurd-vm-configuration-net-options
  63. hurd-vm-configuration-secrets
  64. hurd-vm-disk-image
  65. hurd-vm-port
  66. hurd-vm-net-options
  67. hurd-vm-service-type
  68. libvirt-configuration
  69. libvirt-service-type
  70. virtlog-configuration
  71. virtlog-service-type
  72. %qemu-platforms
  73. lookup-qemu-platforms
  74. qemu-platform?
  75. qemu-platform-name
  76. qemu-binfmt-configuration
  77. qemu-binfmt-configuration?
  78. qemu-binfmt-service-type))
  79. (define (uglify-field-name field-name)
  80. (let ((str (symbol->string field-name)))
  81. (string-join
  82. (string-split (string-delete #\? str) #\-)
  83. "_")))
  84. (define (quote-val val)
  85. (string-append "\"" val "\""))
  86. (define (serialize-field field-name val)
  87. (format #t "~a = ~a\n" (uglify-field-name field-name) val))
  88. (define (serialize-string field-name val)
  89. (serialize-field field-name (quote-val val)))
  90. (define (serialize-boolean field-name val)
  91. (serialize-field field-name (if val 1 0)))
  92. (define (serialize-integer field-name val)
  93. (serialize-field field-name val))
  94. (define (build-opt-list val)
  95. (string-append
  96. "["
  97. (string-join (map quote-val val) ",")
  98. "]"))
  99. (define optional-list? list?)
  100. (define optional-string? string?)
  101. (define (serialize-list field-name val)
  102. (serialize-field field-name (build-opt-list val)))
  103. (define (serialize-optional-list field-name val)
  104. (if (null? val)
  105. (format #t "# ~a = []\n" (uglify-field-name field-name))
  106. (serialize-list field-name val)))
  107. (define (serialize-optional-string field-name val)
  108. (if (string-null? val)
  109. (format #t "# ~a = \"\"\n" (uglify-field-name field-name))
  110. (serialize-string field-name val)))
  111. (define-configuration libvirt-configuration
  112. (libvirt
  113. (package libvirt)
  114. "Libvirt package.")
  115. (listen-tls?
  116. (boolean #t)
  117. "Flag listening for secure TLS connections on the public TCP/IP port.
  118. must set @code{listen} for this to have any effect.
  119. It is necessary to setup a CA and issue server certificates before
  120. using this capability.")
  121. (listen-tcp?
  122. (boolean #f)
  123. "Listen for unencrypted TCP connections on the public TCP/IP port.
  124. must set @code{listen} for this to have any effect.
  125. Using the TCP socket requires SASL authentication by default. Only
  126. SASL mechanisms which support data encryption are allowed. This is
  127. DIGEST_MD5 and GSSAPI (Kerberos5)")
  128. (tls-port
  129. (string "16514")
  130. "Port for accepting secure TLS connections This can be a port number,
  131. or service name")
  132. (tcp-port
  133. (string "16509")
  134. "Port for accepting insecure TCP connections This can be a port number,
  135. or service name")
  136. (listen-addr
  137. (string "0.0.0.0")
  138. "IP address or hostname used for client connections.")
  139. (mdns-adv?
  140. (boolean #f)
  141. "Flag toggling mDNS advertisement of the libvirt service.
  142. Alternatively can disable for all services on a host by
  143. stopping the Avahi daemon.")
  144. (mdns-name
  145. (string (string-append "Virtualization Host " (gethostname)))
  146. "Default mDNS advertisement name. This must be unique on the
  147. immediate broadcast network.")
  148. (unix-sock-group
  149. (string "root")
  150. "UNIX domain socket group ownership. This can be used to
  151. allow a 'trusted' set of users access to management capabilities
  152. without becoming root.")
  153. (unix-sock-ro-perms
  154. (string "0777")
  155. "UNIX socket permissions for the R/O socket. This is used
  156. for monitoring VM status only.")
  157. (unix-sock-rw-perms
  158. (string "0770")
  159. "UNIX socket permissions for the R/W socket. Default allows
  160. only root. If PolicyKit is enabled on the socket, the default
  161. will change to allow everyone (eg, 0777)")
  162. (unix-sock-admin-perms
  163. (string "0777")
  164. "UNIX socket permissions for the admin socket. Default allows
  165. only owner (root), do not change it unless you are sure to whom
  166. you are exposing the access to.")
  167. (unix-sock-dir
  168. (string "/var/run/libvirt")
  169. "The directory in which sockets will be found/created.")
  170. (auth-unix-ro
  171. (string "polkit")
  172. "Authentication scheme for UNIX read-only sockets. By default
  173. socket permissions allow anyone to connect")
  174. (auth-unix-rw
  175. (string "polkit")
  176. "Authentication scheme for UNIX read-write sockets. By default
  177. socket permissions only allow root. If PolicyKit support was compiled
  178. into libvirt, the default will be to use 'polkit' auth.")
  179. (auth-tcp
  180. (string "sasl")
  181. "Authentication scheme for TCP sockets. If you don't enable SASL,
  182. then all TCP traffic is cleartext. Don't do this outside of a dev/test
  183. scenario.")
  184. (auth-tls
  185. (string "none")
  186. "Authentication scheme for TLS sockets. TLS sockets already have
  187. encryption provided by the TLS layer, and limited authentication is
  188. done by certificates.
  189. It is possible to make use of any SASL authentication mechanism as
  190. well, by using 'sasl' for this option")
  191. (access-drivers
  192. (optional-list '())
  193. "API access control scheme.
  194. By default an authenticated user is allowed access to all APIs. Access
  195. drivers can place restrictions on this.")
  196. (key-file
  197. (string "")
  198. "Server key file path. If set to an empty string, then no private key
  199. is loaded.")
  200. (cert-file
  201. (string "")
  202. "Server key file path. If set to an empty string, then no certificate
  203. is loaded.")
  204. (ca-file
  205. (string "")
  206. "Server key file path. If set to an empty string, then no CA certificate
  207. is loaded.")
  208. (crl-file
  209. (string "")
  210. "Certificate revocation list path. If set to an empty string, then no
  211. CRL is loaded.")
  212. (tls-no-sanity-cert
  213. (boolean #f)
  214. "Disable verification of our own server certificates.
  215. When libvirtd starts it performs some sanity checks against its own
  216. certificates.")
  217. (tls-no-verify-cert
  218. (boolean #f)
  219. "Disable verification of client certificates.
  220. Client certificate verification is the primary authentication mechanism.
  221. Any client which does not present a certificate signed by the CA
  222. will be rejected.")
  223. (tls-allowed-dn-list
  224. (optional-list '())
  225. "Whitelist of allowed x509 Distinguished Name.")
  226. (sasl-allowed-usernames
  227. (optional-list '())
  228. "Whitelist of allowed SASL usernames. The format for username
  229. depends on the SASL authentication mechanism.")
  230. (tls-priority
  231. (string "NORMAL")
  232. "Override the compile time default TLS priority string. The
  233. default is usually \"NORMAL\" unless overridden at build time.
  234. Only set this is it is desired for libvirt to deviate from
  235. the global default settings.")
  236. (max-clients
  237. (integer 5000)
  238. "Maximum number of concurrent client connections to allow
  239. over all sockets combined.")
  240. (max-queued-clients
  241. (integer 1000)
  242. "Maximum length of queue of connections waiting to be
  243. accepted by the daemon. Note, that some protocols supporting
  244. retransmission may obey this so that a later reattempt at
  245. connection succeeds.")
  246. (max-anonymous-clients
  247. (integer 20)
  248. "Maximum length of queue of accepted but not yet authenticated
  249. clients. Set this to zero to turn this feature off")
  250. (min-workers
  251. (integer 5)
  252. "Number of workers to start up initially.")
  253. (max-workers
  254. (integer 20)
  255. "Maximum number of worker threads.
  256. If the number of active clients exceeds @code{min-workers},
  257. then more threads are spawned, up to max_workers limit.
  258. Typically you'd want max_workers to equal maximum number
  259. of clients allowed.")
  260. (prio-workers
  261. (integer 5)
  262. "Number of priority workers. If all workers from above
  263. pool are stuck, some calls marked as high priority
  264. (notably domainDestroy) can be executed in this pool.")
  265. (max-requests
  266. (integer 20)
  267. "Total global limit on concurrent RPC calls.")
  268. (max-client-requests
  269. (integer 5)
  270. "Limit on concurrent requests from a single client
  271. connection. To avoid one client monopolizing the server
  272. this should be a small fraction of the global max_requests
  273. and max_workers parameter.")
  274. (admin-min-workers
  275. (integer 1)
  276. "Same as @code{min-workers} but for the admin interface.")
  277. (admin-max-workers
  278. (integer 5)
  279. "Same as @code{max-workers} but for the admin interface.")
  280. (admin-max-clients
  281. (integer 5)
  282. "Same as @code{max-clients} but for the admin interface.")
  283. (admin-max-queued-clients
  284. (integer 5)
  285. "Same as @code{max-queued-clients} but for the admin interface.")
  286. (admin-max-client-requests
  287. (integer 5)
  288. "Same as @code{max-client-requests} but for the admin interface.")
  289. (log-level
  290. (integer 3)
  291. "Logging level. 4 errors, 3 warnings, 2 information, 1 debug.")
  292. (log-filters
  293. (string "3:remote 4:event")
  294. "Logging filters.
  295. A filter allows selecting a different logging level for a given category
  296. of logs
  297. The format for a filter is one of:
  298. @itemize
  299. @item x:name
  300. @item x:+name
  301. @end itemize
  302. where @code{name} is a string which is matched against the category
  303. given in the @code{VIR_LOG_INIT()} at the top of each libvirt source
  304. file, e.g., \"remote\", \"qemu\", or \"util.json\" (the name in the
  305. filter can be a substring of the full category name, in order
  306. to match multiple similar categories), the optional \"+\" prefix
  307. tells libvirt to log stack trace for each message matching
  308. name, and @code{x} is the minimal level where matching messages should
  309. be logged:
  310. @itemize
  311. @item 1: DEBUG
  312. @item 2: INFO
  313. @item 3: WARNING
  314. @item 4: ERROR
  315. @end itemize
  316. Multiple filters can be defined in a single filters statement, they just
  317. need to be separated by spaces.")
  318. (log-outputs
  319. (string "3:syslog:libvirtd")
  320. "Logging outputs.
  321. An output is one of the places to save logging information
  322. The format for an output can be:
  323. @table @code
  324. @item x:stderr
  325. output goes to stderr
  326. @item x:syslog:name
  327. use syslog for the output and use the given name as the ident
  328. @item x:file:file_path
  329. output to a file, with the given filepath
  330. @item x:journald
  331. output to journald logging system
  332. @end table
  333. In all case the x prefix is the minimal level, acting as a filter
  334. @itemize
  335. @item 1: DEBUG
  336. @item 2: INFO
  337. @item 3: WARNING
  338. @item 4: ERROR
  339. @end itemize
  340. Multiple outputs can be defined, they just need to be separated by spaces.")
  341. (audit-level
  342. (integer 1)
  343. "Allows usage of the auditing subsystem to be altered
  344. @itemize
  345. @item 0: disable all auditing
  346. @item 1: enable auditing, only if enabled on host
  347. @item 2: enable auditing, and exit if disabled on host.
  348. @end itemize
  349. ")
  350. (audit-logging
  351. (boolean #f)
  352. "Send audit messages via libvirt logging infrastructure.")
  353. (host-uuid
  354. (optional-string "")
  355. "Host UUID. UUID must not have all digits be the same.")
  356. (host-uuid-source
  357. (string "smbios")
  358. "Source to read host UUID.
  359. @itemize
  360. @item @code{smbios}: fetch the UUID from @code{dmidecode -s system-uuid}
  361. @item @code{machine-id}: fetch the UUID from @code{/etc/machine-id}
  362. @end itemize
  363. If @code{dmidecode} does not provide a valid UUID a temporary UUID
  364. will be generated.")
  365. (keepalive-interval
  366. (integer 5)
  367. "A keepalive message is sent to a client after
  368. @code{keepalive_interval} seconds of inactivity to check if
  369. the client is still responding. If set to -1, libvirtd will
  370. never send keepalive requests; however clients can still send
  371. them and the daemon will send responses.")
  372. (keepalive-count
  373. (integer 5)
  374. "Maximum number of keepalive messages that are allowed to be sent
  375. to the client without getting any response before the connection is
  376. considered broken.
  377. In other words, the connection is automatically
  378. closed approximately after
  379. @code{keepalive_interval * (keepalive_count + 1)} seconds since the last
  380. message received from the client. When @code{keepalive-count} is
  381. set to 0, connections will be automatically closed after
  382. @code{keepalive-interval} seconds of inactivity without sending any
  383. keepalive messages.")
  384. (admin-keepalive-interval
  385. (integer 5)
  386. "Same as above but for admin interface.")
  387. (admin-keepalive-count
  388. (integer 5)
  389. "Same as above but for admin interface.")
  390. (ovs-timeout
  391. (integer 5)
  392. "Timeout for Open vSwitch calls.
  393. The @code{ovs-vsctl} utility is used for the configuration and
  394. its timeout option is set by default to 5 seconds to avoid
  395. potential infinite waits blocking libvirt."))
  396. (define* (libvirt-conf-file config)
  397. "Return a libvirtd config file."
  398. (plain-file "libvirtd.conf"
  399. (with-output-to-string
  400. (lambda ()
  401. (serialize-configuration config libvirt-configuration-fields)))))
  402. (define %libvirt-accounts
  403. (list (user-group (name "libvirt") (system? #t))))
  404. (define (%libvirt-activation config)
  405. (let ((sock-dir (libvirt-configuration-unix-sock-dir config)))
  406. #~(begin
  407. (use-modules (guix build utils))
  408. (mkdir-p #$sock-dir))))
  409. (define (libvirt-shepherd-service config)
  410. (let* ((config-file (libvirt-conf-file config))
  411. (libvirt (libvirt-configuration-libvirt config)))
  412. (list (shepherd-service
  413. (documentation "Run the libvirt daemon.")
  414. (provision '(libvirtd))
  415. (start #~(make-forkexec-constructor
  416. (list (string-append #$libvirt "/sbin/libvirtd")
  417. "-f" #$config-file)
  418. ;; For finding qemu and ip binaries.
  419. #:environment-variables
  420. (list (string-append
  421. "PATH=/run/current-system/profile/bin:"
  422. "/run/current-system/profile/sbin"))))
  423. (stop #~(make-kill-destructor))))))
  424. (define libvirt-service-type
  425. (service-type (name 'libvirt)
  426. (extensions
  427. (list
  428. (service-extension polkit-service-type
  429. (compose list libvirt-configuration-libvirt))
  430. (service-extension profile-service-type
  431. (lambda (config)
  432. (list
  433. (libvirt-configuration-libvirt config)
  434. qemu)))
  435. (service-extension activation-service-type
  436. %libvirt-activation)
  437. (service-extension shepherd-root-service-type
  438. libvirt-shepherd-service)
  439. (service-extension account-service-type
  440. (const %libvirt-accounts))))
  441. (default-value (libvirt-configuration))))
  442. (define-record-type* <virtlog-configuration>
  443. virtlog-configuration make-virtlog-configuration
  444. virtlog-configuration?
  445. (libvirt virtlog-configuration-libvirt
  446. (default libvirt))
  447. (log-level virtlog-configuration-log-level
  448. (default 3))
  449. (log-filters virtlog-configuration-log-filters
  450. (default "3:remote 4:event"))
  451. (log-outputs virtlog-configuration-log-outputs
  452. (default "3:syslog:virtlogd"))
  453. (max-clients virtlog-configuration-max-clients
  454. (default 1024))
  455. (max-size virtlog-configuration-max-size
  456. (default 2097152)) ;; 2MB
  457. (max-backups virtlog-configuration-max-backups
  458. (default 3)))
  459. (define* (virtlogd-conf-file config)
  460. "Return a virtlogd config file."
  461. (plain-file "virtlogd.conf"
  462. (string-append
  463. "log_level = " (number->string (virtlog-configuration-log-level config)) "\n"
  464. "log_filters = \"" (virtlog-configuration-log-filters config) "\"\n"
  465. "log_outputs = \"" (virtlog-configuration-log-outputs config) "\"\n"
  466. "max_clients = " (number->string (virtlog-configuration-max-clients config)) "\n"
  467. "max_size = " (number->string (virtlog-configuration-max-size config)) "\n"
  468. "max_backups = " (number->string (virtlog-configuration-max-backups config)) "\n")))
  469. (define (virtlogd-shepherd-service config)
  470. (let* ((config-file (virtlogd-conf-file config))
  471. (libvirt (virtlog-configuration-libvirt config)))
  472. (list (shepherd-service
  473. (documentation "Run the virtlog daemon.")
  474. (provision '(virtlogd))
  475. (start #~(make-forkexec-constructor
  476. (list (string-append #$libvirt "/sbin/virtlogd")
  477. "-f" #$config-file)))
  478. (stop #~(make-kill-destructor))))))
  479. (define virtlog-service-type
  480. (service-type (name 'virtlogd)
  481. (extensions
  482. (list
  483. (service-extension shepherd-root-service-type
  484. virtlogd-shepherd-service)))
  485. (default-value (virtlog-configuration))))
  486. (define (generate-libvirt-documentation)
  487. (generate-documentation
  488. `((libvirt-configuration ,libvirt-configuration-fields))
  489. 'libvirt-configuration))
  490. ;;;
  491. ;;; Transparent QEMU emulation via binfmt_misc.
  492. ;;;
  493. ;; Platforms that QEMU can emulate.
  494. (define-record-type* <qemu-platform>
  495. qemu-platform make-qemu-platform
  496. qemu-platform?
  497. (name qemu-platform-name) ;string
  498. (family qemu-platform-family) ;string
  499. (magic qemu-platform-magic) ;bytevector
  500. (mask qemu-platform-mask) ;bytevector
  501. (flags qemu-platform-flags (default "F"))) ;string
  502. (define-syntax bv
  503. (lambda (s)
  504. "Expand the given string into a bytevector."
  505. (syntax-case s ()
  506. ((_ str)
  507. (string? (syntax->datum #'str))
  508. (let ((bv (u8-list->bytevector
  509. (map char->integer
  510. (string->list (syntax->datum #'str))))))
  511. bv)))))
  512. ;;; The platform descriptions below are taken from
  513. ;;; 'scripts/qemu-binfmt-conf.sh' in QEMU.
  514. (define %i386
  515. (qemu-platform
  516. (name "i386")
  517. (family "i386")
  518. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00"))
  519. (mask (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  520. (define %i486
  521. (qemu-platform
  522. (name "i486")
  523. (family "i386")
  524. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00"))
  525. (mask (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  526. (define %alpha
  527. (qemu-platform
  528. (name "alpha")
  529. (family "alpha")
  530. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90"))
  531. (mask (bv "\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  532. (define %arm
  533. (qemu-platform
  534. (name "arm")
  535. (family "arm")
  536. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00"))
  537. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  538. (define %armeb
  539. (qemu-platform
  540. (name "armeb")
  541. (family "arm")
  542. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28"))
  543. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  544. (define %sparc
  545. (qemu-platform
  546. (name "sparc")
  547. (family "sparc")
  548. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02"))
  549. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  550. (define %sparc32plus
  551. (qemu-platform
  552. (name "sparc32plus")
  553. (family "sparc")
  554. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12"))
  555. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  556. (define %ppc
  557. (qemu-platform
  558. (name "ppc")
  559. (family "ppc")
  560. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14"))
  561. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  562. (define %ppc64
  563. (qemu-platform
  564. (name "ppc64")
  565. (family "ppc")
  566. (magic (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15"))
  567. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  568. (define %ppc64le
  569. (qemu-platform
  570. (name "ppc64le")
  571. (family "ppcle")
  572. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00"))
  573. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00"))))
  574. (define %m68k
  575. (qemu-platform
  576. (name "m68k")
  577. (family "m68k")
  578. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04"))
  579. (mask (bv "\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  580. ;; XXX: We could use the other endianness on a MIPS host.
  581. (define %mips
  582. (qemu-platform
  583. (name "mips")
  584. (family "mips")
  585. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"))
  586. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  587. (define %mipsel
  588. (qemu-platform
  589. (name "mipsel")
  590. (family "mips")
  591. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00"))
  592. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  593. (define %mipsn32
  594. (qemu-platform
  595. (name "mipsn32")
  596. (family "mips")
  597. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"))
  598. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  599. (define %mipsn32el
  600. (qemu-platform
  601. (name "mipsn32el")
  602. (family "mips")
  603. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00"))
  604. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  605. (define %mips64
  606. (qemu-platform
  607. (name "mips64")
  608. (family "mips")
  609. (magic (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08"))
  610. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  611. (define %mips64el
  612. (qemu-platform
  613. (name "mips64el")
  614. (family "mips")
  615. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00"))
  616. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  617. (define %riscv32
  618. (qemu-platform
  619. (name "riscv32")
  620. (family "riscv")
  621. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00"))
  622. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  623. (define %riscv64
  624. (qemu-platform
  625. (name "riscv64")
  626. (family "riscv")
  627. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00"))
  628. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  629. (define %sh4
  630. (qemu-platform
  631. (name "sh4")
  632. (family "sh4")
  633. (magic (bv "\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a\x00"))
  634. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  635. (define %sh4eb
  636. (qemu-platform
  637. (name "sh4eb")
  638. (family "sh4")
  639. (magic (bv "\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x2a"))
  640. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  641. (define %s390x
  642. (qemu-platform
  643. (name "s390x")
  644. (family "s390x")
  645. (magic (bv "\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16"))
  646. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  647. (define %aarch64
  648. (qemu-platform
  649. (name "aarch64")
  650. (family "arm")
  651. (magic (bv "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00"))
  652. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"))))
  653. (define %hppa
  654. (qemu-platform
  655. (name "hppa")
  656. (family "hppa")
  657. (magic (bv "\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f"))
  658. (mask (bv "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff"))))
  659. (define %qemu-platforms
  660. (list %i386 %i486 %alpha %arm %sparc32plus %ppc %ppc64 %ppc64le %m68k
  661. %mips %mipsel %mipsn32 %mipsn32el %mips64 %mips64el
  662. %riscv32 %riscv64 %sh4 %sh4eb %s390x %aarch64 %hppa))
  663. (define (lookup-qemu-platforms . names)
  664. "Return the list of QEMU platforms that match NAMES--a list of names such as
  665. \"arm\", \"hppa\", etc."
  666. (filter (lambda (platform)
  667. (member (qemu-platform-name platform) names))
  668. %qemu-platforms))
  669. (define-record-type* <qemu-binfmt-configuration>
  670. qemu-binfmt-configuration make-qemu-binfmt-configuration
  671. qemu-binfmt-configuration?
  672. (qemu qemu-binfmt-configuration-qemu
  673. (default qemu))
  674. (platforms qemu-binfmt-configuration-platforms
  675. (default '()))) ;safest default
  676. (define (qemu-platform->binfmt qemu platform)
  677. "Return a gexp that evaluates to a binfmt string for PLATFORM, using the
  678. given QEMU package."
  679. (define (bytevector->binfmt-string bv)
  680. ;; Return a binfmt-friendly string representing BV. Hex-encode every
  681. ;; character, in particular because the doc notes "that you must escape
  682. ;; any NUL bytes; parsing halts at the first one".
  683. (string-concatenate
  684. (map (lambda (n)
  685. (string-append "\\x"
  686. (string-pad (number->string n 16) 2 #\0)))
  687. (bytevector->u8-list bv))))
  688. (match platform
  689. (($ <qemu-platform> name family magic mask flags)
  690. ;; See 'Documentation/binfmt_misc.txt' in the kernel.
  691. #~(string-append ":qemu-" #$name ":M::"
  692. #$(bytevector->binfmt-string magic)
  693. ":" #$(bytevector->binfmt-string mask)
  694. ":" #$qemu:static "/bin/qemu-" #$name
  695. ":" #$flags))))
  696. (define %binfmt-mount-point
  697. (file-system-mount-point %binary-format-file-system))
  698. (define %binfmt-register-file
  699. (string-append %binfmt-mount-point "/register"))
  700. (define qemu-binfmt-shepherd-services
  701. (match-lambda
  702. (($ <qemu-binfmt-configuration> qemu platforms)
  703. (list (shepherd-service
  704. (provision '(qemu-binfmt))
  705. (documentation "Install binfmt_misc handlers for QEMU.")
  706. (requirement '(file-system-/proc/sys/fs/binfmt_misc))
  707. (start #~(lambda ()
  708. ;; Register the handlers for all of PLATFORMS.
  709. (for-each (lambda (str)
  710. (call-with-output-file
  711. #$%binfmt-register-file
  712. (lambda (port)
  713. (display str port))))
  714. (list
  715. #$@(map (cut qemu-platform->binfmt qemu
  716. <>)
  717. platforms)))
  718. #t))
  719. (stop #~(lambda (_)
  720. ;; Unregister the handlers.
  721. (for-each (lambda (name)
  722. (let ((file (string-append
  723. #$%binfmt-mount-point
  724. "/qemu-" name)))
  725. (call-with-output-file file
  726. (lambda (port)
  727. (display "-1" port)))))
  728. '#$(map qemu-platform-name platforms))
  729. #f)))))))
  730. (define qemu-binfmt-service-type
  731. ;; TODO: Make a separate binfmt_misc service out of this?
  732. (service-type (name 'qemu-binfmt)
  733. (extensions
  734. (list (service-extension file-system-service-type
  735. (const
  736. (list %binary-format-file-system)))
  737. (service-extension shepherd-root-service-type
  738. qemu-binfmt-shepherd-services)))
  739. (default-value (qemu-binfmt-configuration))
  740. (description
  741. "This service supports transparent emulation of binaries
  742. compiled for other architectures using QEMU and the @code{binfmt_misc}
  743. functionality of the kernel Linux.")))
  744. ;;;
  745. ;;; Secrets for guest VMs.
  746. ;;;
  747. (define (secret-service-activation port)
  748. "Return an activation snippet that fetches sensitive material at local PORT,
  749. over TCP. Reboot upon failure."
  750. (with-imported-modules '((gnu build secret-service)
  751. (guix build utils))
  752. #~(begin
  753. (use-modules (gnu build secret-service))
  754. (let ((sent (secret-service-receive-secrets #$port)))
  755. (unless sent
  756. (sleep 3)
  757. (reboot))))))
  758. (define secret-service-type
  759. (service-type
  760. (name 'secret-service)
  761. (extensions (list (service-extension activation-service-type
  762. secret-service-activation)))
  763. (description
  764. "This service fetches secret key and other sensitive material over TCP at
  765. boot time. This service is meant to be used by virtual machines (VMs) that
  766. can only be accessed by their host.")))
  767. (define (secret-service-operating-system os)
  768. "Return an operating system based on OS that includes the secret-service,
  769. that will be listening to receive secret keys on port 1004, TCP."
  770. (operating-system
  771. (inherit os)
  772. ;; Arrange so that the secret service activation snippet shows up before
  773. ;; the OpenSSH and Guix activation snippets. That way, we receive OpenSSH
  774. ;; and Guix keys before the activation snippets try to generate fresh keys
  775. ;; for nothing.
  776. (services (append (operating-system-user-services os)
  777. (list (service secret-service-type 1004))))))
  778. ;;;
  779. ;;; The Hurd in VM service: a Childhurd.
  780. ;;;
  781. (define %hurd-vm-operating-system
  782. (operating-system
  783. (inherit %hurd-default-operating-system)
  784. (host-name "childhurd")
  785. (timezone "Europe/Amsterdam")
  786. (bootloader (bootloader-configuration
  787. (bootloader grub-minimal-bootloader)
  788. (target "/dev/vda")
  789. (timeout 0)))
  790. (packages (cons* gdb-minimal
  791. (operating-system-packages
  792. %hurd-default-operating-system)))
  793. (services (cons*
  794. (service openssh-service-type
  795. (openssh-configuration
  796. (openssh openssh-sans-x)
  797. (use-pam? #f)
  798. (port-number 2222)
  799. (permit-root-login #t)
  800. (allow-empty-passwords? #t)
  801. (password-authentication? #t)))
  802. ;; By default, the secret service introduces a pre-initialized
  803. ;; /etc/guix/acl file in the childhurd. Thus, clear
  804. ;; 'authorize-key?' so that it's not overridden at activation
  805. ;; time.
  806. (modify-services %base-services/hurd
  807. (guix-service-type config =>
  808. (guix-configuration
  809. (inherit config)
  810. (authorize-key? #f))))))))
  811. (define-record-type* <hurd-vm-configuration>
  812. hurd-vm-configuration make-hurd-vm-configuration
  813. hurd-vm-configuration?
  814. (os hurd-vm-configuration-os ;<operating-system>
  815. (default %hurd-vm-operating-system))
  816. (qemu hurd-vm-configuration-qemu ;<package>
  817. (default qemu-minimal))
  818. (image hurd-vm-configuration-image ;string
  819. (thunked)
  820. (default (hurd-vm-disk-image this-record)))
  821. (disk-size hurd-vm-configuration-disk-size ;number or 'guess
  822. (default 'guess))
  823. (memory-size hurd-vm-configuration-memory-size ;number
  824. (default 512))
  825. (options hurd-vm-configuration-options ;list of string
  826. (default `("--snapshot")))
  827. (id hurd-vm-configuration-id ;#f or integer [1..]
  828. (default #f))
  829. (net-options hurd-vm-configuration-net-options ;list of string
  830. (thunked)
  831. (default (hurd-vm-net-options this-record)))
  832. (secret-root hurd-vm-configuration-secret-root ;string
  833. (default "/etc/childhurd")))
  834. (define (hurd-vm-disk-image config)
  835. "Return a disk-image for the Hurd according to CONFIG. The secret-service
  836. is added to the OS specified in CONFIG."
  837. (let* ((os (secret-service-operating-system
  838. (hurd-vm-configuration-os config)))
  839. (disk-size (hurd-vm-configuration-disk-size config))
  840. (type (lookup-image-type-by-name 'hurd-qcow2))
  841. (os->image (image-type-constructor type)))
  842. (system-image
  843. (image (inherit (os->image os))
  844. (size disk-size)))))
  845. (define (hurd-vm-port config base)
  846. "Return the forwarded vm port for this childhurd config."
  847. (let ((id (or (hurd-vm-configuration-id config) 0)))
  848. (+ base (* 1000 id))))
  849. (define %hurd-vm-secrets-port 11004)
  850. (define %hurd-vm-ssh-port 10022)
  851. (define %hurd-vm-vnc-port 15900)
  852. (define (hurd-vm-net-options config)
  853. `("--device" "rtl8139,netdev=net0"
  854. "--netdev"
  855. ,(string-append "user,id=net0"
  856. ",hostfwd=tcp:127.0.0.1:"
  857. (number->string (hurd-vm-port config %hurd-vm-secrets-port))
  858. "-:1004"
  859. ",hostfwd=tcp:127.0.0.1:"
  860. (number->string (hurd-vm-port config %hurd-vm-ssh-port))
  861. "-:2222"
  862. ",hostfwd=tcp:127.0.0.1:"
  863. (number->string (hurd-vm-port config %hurd-vm-vnc-port))
  864. "-:5900")))
  865. (define (hurd-vm-shepherd-service config)
  866. "Return a <shepherd-service> for a Hurd in a Virtual Machine with CONFIG."
  867. (let ((image (hurd-vm-configuration-image config))
  868. (qemu (hurd-vm-configuration-qemu config))
  869. (memory-size (hurd-vm-configuration-memory-size config))
  870. (options (hurd-vm-configuration-options config))
  871. (id (hurd-vm-configuration-id config))
  872. (net-options (hurd-vm-configuration-net-options config))
  873. (provisions '(hurd-vm childhurd)))
  874. (define vm-command
  875. #~(append (list #$(file-append qemu "/bin/qemu-system-i386")
  876. "-m" (number->string #$memory-size)
  877. #$@net-options
  878. #$@options
  879. "--hda" #+image
  880. ;; Cause the service to be respawned if the guest
  881. ;; reboots (it can reboot for instance if it did not
  882. ;; receive valid secrets, or if it crashed.)
  883. "--no-reboot")
  884. (if (file-exists? "/dev/kvm")
  885. '("--enable-kvm")
  886. '())))
  887. (list
  888. (shepherd-service
  889. (documentation "Run the Hurd in a Virtual Machine: a Childhurd.")
  890. (provision (if id
  891. (map
  892. (cute symbol-append <>
  893. (string->symbol (number->string id)))
  894. provisions)
  895. provisions))
  896. (requirement '(loopback networking user-processes))
  897. (start
  898. (with-imported-modules
  899. (source-module-closure '((gnu build secret-service)
  900. (guix build utils)))
  901. #~(lambda ()
  902. (let ((pid (fork+exec-command #$vm-command
  903. #:user "childhurd"
  904. ;; XXX TODO: use "childhurd" after
  905. ;; updating Shepherd
  906. #:group "kvm"
  907. #:environment-variables
  908. ;; QEMU tries to write to /var/tmp
  909. ;; by default.
  910. '("TMPDIR=/tmp")))
  911. (port #$(hurd-vm-port config %hurd-vm-secrets-port))
  912. (root #$(hurd-vm-configuration-secret-root config)))
  913. (catch #t
  914. (lambda _
  915. ;; XXX: 'secret-service-send-secrets' won't complete until
  916. ;; the guest has booted and its secret service server is
  917. ;; running, which could take 20+ seconds during which PID 1
  918. ;; is stuck waiting.
  919. (if (secret-service-send-secrets port root)
  920. pid
  921. (begin
  922. (kill (- pid) SIGTERM)
  923. #f)))
  924. (lambda (key . args)
  925. (kill (- pid) SIGTERM)
  926. (apply throw key args)))))))
  927. (modules `((gnu build secret-service)
  928. (guix build utils)
  929. ,@%default-modules))
  930. (stop #~(make-kill-destructor))))))
  931. (define %hurd-vm-accounts
  932. (list (user-group (name "childhurd") (system? #t))
  933. (user-account
  934. (name "childhurd")
  935. (group "childhurd")
  936. (supplementary-groups '("kvm"))
  937. (comment "Privilege separation user for the childhurd")
  938. (home-directory "/var/empty")
  939. (shell (file-append shadow "/sbin/nologin"))
  940. (system? #t))))
  941. (define (initialize-hurd-vm-substitutes)
  942. "Initialize the Hurd VM's key pair and ACL and store it on the host."
  943. (define run
  944. (with-imported-modules '((guix build utils))
  945. #~(begin
  946. (use-modules (guix build utils)
  947. (ice-9 match))
  948. (define host-key
  949. "/etc/guix/signing-key.pub")
  950. (define host-acl
  951. "/etc/guix/acl")
  952. (match (command-line)
  953. ((_ guest-config-directory)
  954. (setenv "GUIX_CONFIGURATION_DIRECTORY"
  955. guest-config-directory)
  956. (invoke #+(file-append guix "/bin/guix") "archive"
  957. "--generate-key")
  958. (when (file-exists? host-acl)
  959. ;; Copy the host ACL.
  960. (copy-file host-acl
  961. (string-append guest-config-directory
  962. "/acl")))
  963. (when (file-exists? host-key)
  964. ;; Add the host key to the childhurd's ACL.
  965. (let ((key (open-fdes host-key O_RDONLY)))
  966. (close-fdes 0)
  967. (dup2 key 0)
  968. (execl #+(file-append guix "/bin/guix")
  969. "guix" "archive" "--authorize"))))))))
  970. (program-file "initialize-hurd-vm-substitutes" run))
  971. (define (hurd-vm-activation config)
  972. "Return a gexp to activate the Hurd VM according to CONFIG."
  973. (with-imported-modules '((guix build utils))
  974. #~(begin
  975. (use-modules (guix build utils))
  976. (define secret-directory
  977. #$(hurd-vm-configuration-secret-root config))
  978. (define ssh-directory
  979. (string-append secret-directory "/etc/ssh"))
  980. (define guix-directory
  981. (string-append secret-directory "/etc/guix"))
  982. (unless (file-exists? ssh-directory)
  983. ;; Generate SSH host keys under SSH-DIRECTORY.
  984. (mkdir-p ssh-directory)
  985. (invoke #$(file-append openssh "/bin/ssh-keygen")
  986. "-A" "-f" secret-directory))
  987. (unless (file-exists? guix-directory)
  988. (invoke #$(initialize-hurd-vm-substitutes)
  989. guix-directory)))))
  990. (define hurd-vm-service-type
  991. (service-type
  992. (name 'hurd-vm)
  993. (extensions (list (service-extension shepherd-root-service-type
  994. hurd-vm-shepherd-service)
  995. (service-extension account-service-type
  996. (const %hurd-vm-accounts))
  997. (service-extension activation-service-type
  998. hurd-vm-activation)))
  999. (default-value (hurd-vm-configuration))
  1000. (description
  1001. "Provide a virtual machine (VM) running GNU/Hurd, also known as a
  1002. @dfn{childhurd}.")))