at master 33 kB view raw
1# Xen Project Hypervisor (Dom0) support. 2 3{ 4 config, 5 lib, 6 pkgs, 7 ... 8}: 9 10let 11 inherit (builtins) readFile; 12 inherit (lib.meta) hiPrio; 13 inherit (lib.modules) mkRemovedOptionModule mkRenamedOptionModule mkIf; 14 inherit (lib.options) 15 mkOption 16 mkEnableOption 17 literalExpression 18 mkPackageOption 19 ; 20 inherit (lib.types) 21 listOf 22 str 23 ints 24 lines 25 enum 26 path 27 submodule 28 addCheck 29 float 30 bool 31 int 32 nullOr 33 ; 34 inherit (lib.lists) optional optionals; 35 inherit (lib.strings) hasSuffix optionalString; 36 inherit (lib.meta) getExe; 37 inherit (lib.attrsets) optionalAttrs; 38 inherit (lib.trivial) boolToString; 39 inherit (lib.teams.xen) members; 40 41 cfg = config.virtualisation.xen; 42 43 xenBootBuilder = pkgs.writeShellApplication { 44 name = "xenBootBuilder"; 45 runtimeInputs = 46 (with pkgs; [ 47 binutils 48 coreutils 49 findutils 50 gawk 51 gnugrep 52 gnused 53 jq 54 ]) 55 ++ optionals (cfg.boot.builderVerbosity == "info") ( 56 with pkgs; 57 [ 58 bat 59 diffutils 60 ] 61 ); 62 runtimeEnv = { 63 efiMountPoint = config.boot.loader.efi.efiSysMountPoint; 64 }; 65 66 # We disable SC2016 because we don't want to expand the regexes in the sed commands. 67 excludeShellChecks = [ "SC2016" ]; 68 69 text = readFile ./xen-boot-builder.sh; 70 }; 71in 72 73{ 74 imports = [ 75 (mkRemovedOptionModule 76 [ 77 "virtualisation" 78 "xen" 79 "bridge" 80 "name" 81 ] 82 "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually." 83 ) 84 (mkRemovedOptionModule 85 [ 86 "virtualisation" 87 "xen" 88 "bridge" 89 "address" 90 ] 91 "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually." 92 ) 93 (mkRemovedOptionModule 94 [ 95 "virtualisation" 96 "xen" 97 "bridge" 98 "prefixLength" 99 ] 100 "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually." 101 ) 102 (mkRemovedOptionModule 103 [ 104 "virtualisation" 105 "xen" 106 "bridge" 107 "forwardDns" 108 ] 109 "The Xen Network Bridge options are currently unavailable. Please set up your own bridge manually." 110 ) 111 (mkRenamedOptionModule 112 [ 113 "virtualisation" 114 "xen" 115 "qemu-package" 116 ] 117 [ 118 "virtualisation" 119 "xen" 120 "qemu" 121 "package" 122 ] 123 ) 124 (mkRenamedOptionModule 125 [ 126 "virtualisation" 127 "xen" 128 "package-qemu" 129 ] 130 [ 131 "virtualisation" 132 "xen" 133 "qemu" 134 "package" 135 ] 136 ) 137 (mkRenamedOptionModule 138 [ 139 "virtualisation" 140 "xen" 141 "stored" 142 ] 143 [ 144 "virtualisation" 145 "xen" 146 "store" 147 "path" 148 ] 149 ) 150 (mkRenamedOptionModule 151 [ 152 "virtualisation" 153 "xen" 154 "efi" 155 "bootBuilderVerbosity" 156 ] 157 [ 158 "virtualisation" 159 "xen" 160 "boot" 161 "builderVerbosity" 162 ] 163 ) 164 (mkRenamedOptionModule 165 [ 166 "virtualisation" 167 "xen" 168 "bootParams" 169 ] 170 [ 171 "virtualisation" 172 "xen" 173 "boot" 174 "params" 175 ] 176 ) 177 (mkRenamedOptionModule 178 [ 179 "virtualisation" 180 "xen" 181 "efi" 182 "path" 183 ] 184 [ 185 "virtualisation" 186 "xen" 187 "boot" 188 "efi" 189 "path" 190 ] 191 ) 192 ]; 193 194 ## Interface ## 195 196 options.virtualisation.xen = { 197 198 enable = mkEnableOption "the Xen Project Hypervisor, a virtualisation technology defined as a *type-1 hypervisor*, which allows multiple virtual machines, known as *domains*, to run concurrently on the physical machine. NixOS runs as the privileged *Domain 0*. This option requires a reboot into a Xen kernel to take effect"; 199 200 debug = mkEnableOption "Xen debug features for Domain 0. This option enables some hidden debugging tests and features, and should not be used in production"; 201 202 trace = mkOption { 203 type = bool; 204 default = cfg.debug; 205 defaultText = literalExpression "false"; 206 example = true; 207 description = "Whether to enable Xen debug tracing and logging for Domain 0."; 208 }; 209 210 package = mkPackageOption pkgs "Xen Hypervisor" { default = [ "xen" ]; }; 211 212 qemu = { 213 package = mkPackageOption pkgs "QEMU (with Xen Hypervisor support)" { 214 default = [ "qemu_xen" ]; 215 }; 216 pidFile = mkOption { 217 type = path; 218 default = "/run/xen/qemu-dom0.pid"; 219 example = "/var/run/xen/qemu-dom0.pid"; 220 description = "Path to the QEMU PID file."; 221 }; 222 }; 223 224 boot = { 225 params = mkOption { 226 default = [ ]; 227 example = '' 228 [ 229 "iommu=force:true,qinval:true,debug:true" 230 "noreboot=true" 231 "vga=ask" 232 ] 233 ''; 234 type = listOf str; 235 description = '' 236 Xen Command Line parameters passed to Domain 0 at boot time. 237 Note: these are different from `boot.kernelParams`. See 238 the [Xen documentation](https://xenbits.xenproject.org/docs/unstable/misc/xen-command-line.html) for more information. 239 ''; 240 }; 241 builderVerbosity = mkOption { 242 type = enum [ 243 "default" 244 "info" 245 "debug" 246 "quiet" 247 ]; 248 default = "default"; 249 example = "info"; 250 description = '' 251 The boot entry builder script should be called with exactly one of the following arguments in order to specify its verbosity: 252 253 - `quiet` supresses all messages. 254 255 - `default` adds a simple "Installing Xen Project Hypervisor boot entries...done." message to the script. 256 257 - `info` is the same as `default`, but it also prints a diff with information on which generations were altered. 258 - This option adds two extra dependencies to the script: `diffutils` and `bat`. 259 260 - `debug` prints information messages for every single step of the script. 261 262 This option does not alter the actual functionality of the script, just the number of messages printed when rebuilding the system. 263 ''; 264 }; 265 bios = { 266 path = mkOption { 267 type = path; 268 default = "${cfg.package.boot}/${cfg.package.multiboot}"; 269 defaultText = literalExpression "\${config.virtualisation.xen.package.boot}/\${config.virtualisation.xen.package.multiboot}"; 270 example = literalExpression "\${config.virtualisation.xen.package}/boot/xen-\${config.virtualisation.xen.package.version}"; 271 description = '' 272 Path to the Xen `multiboot` binary used for BIOS booting. 273 Unless you're building your own Xen derivation, you should leave this 274 option as the default value. 275 ''; 276 }; 277 }; 278 efi = { 279 path = mkOption { 280 type = path; 281 default = "${cfg.package.boot}/${cfg.package.efi}"; 282 defaultText = literalExpression "\${config.virtualisation.xen.package.boot}/\${config.virtualisation.xen.package.efi}"; 283 example = literalExpression "\${config.virtualisation.xen.package}/boot/efi/efi/nixos/xen-\${config.virtualisation.xen.package.version}.efi"; 284 description = '' 285 Path to xen.efi. `pkgs.xen` is patched to install the xen.efi file 286 on `$boot/boot/xen.efi`, but an unpatched Xen build may install it 287 somewhere else, such as `$out/boot/efi/efi/nixos/xen.efi`. Unless 288 you're building your own Xen derivation, you should leave this 289 option as the default value. 290 ''; 291 }; 292 }; 293 }; 294 295 dom0Resources = { 296 maxVCPUs = mkOption { 297 default = 0; 298 example = 4; 299 type = ints.unsigned; 300 description = '' 301 Amount of virtual CPU cores allocated to Domain 0 on boot. 302 If set to 0, all cores are assigned to Domain 0, and 303 unprivileged domains will compete with Domain 0 for CPU time. 304 ''; 305 }; 306 307 memory = mkOption { 308 default = 0; 309 example = 512; 310 type = ints.unsigned; 311 description = '' 312 Amount of memory (in MiB) allocated to Domain 0 on boot. 313 If set to 0, all memory is assigned to Domain 0, and 314 unprivileged domains will compete with Domain 0 for free RAM. 315 ''; 316 }; 317 318 maxMemory = mkOption { 319 default = cfg.dom0Resources.memory; 320 defaultText = literalExpression "config.virtualisation.xen.dom0Resources.memory"; 321 example = 1024; 322 type = ints.unsigned; 323 description = '' 324 Maximum amount of memory (in MiB) that Domain 0 can 325 dynamically allocate to itself. Does nothing if set 326 to the same amount as virtualisation.xen.memory, or 327 if that option is set to 0. 328 ''; 329 }; 330 }; 331 332 domains = { 333 extraConfig = mkOption { 334 type = lines; 335 default = ""; 336 example = '' 337 XENDOMAINS_SAVE=/persist/xen/save 338 XENDOMAINS_RESTORE=false 339 XENDOMAINS_CREATE_USLEEP=10000000 340 ''; 341 description = '' 342 Options defined here will override the defaults for xendomains. 343 The default options can be seen in the file included from 344 /etc/default/xendomains. 345 ''; 346 }; 347 }; 348 349 store = { 350 path = mkOption { 351 type = path; 352 default = "${cfg.package}/bin/oxenstored"; 353 defaultText = literalExpression "\${config.virtualisation.xen.package}/bin/oxenstored"; 354 example = literalExpression "\${config.virtualisation.xen.package}/bin/xenstored"; 355 description = '' 356 Path to the Xen Store Daemon. This option is useful to 357 switch between the legacy C-based Xen Store Daemon, and 358 the newer OCaml-based Xen Store Daemon, `oxenstored`. 359 ''; 360 }; 361 type = mkOption { 362 type = enum [ 363 "c" 364 "ocaml" 365 ]; 366 default = if (hasSuffix "oxenstored" cfg.store.path) then "ocaml" else "c"; 367 internal = true; 368 readOnly = true; 369 description = "Helper internal option that determines the type of the Xen Store Daemon based on cfg.store.path."; 370 }; 371 settings = mkOption { 372 default = { }; 373 example = { 374 enableMerge = false; 375 quota.maxWatchEvents = 2048; 376 quota.enable = true; 377 conflict.maxHistorySeconds = 0.12; 378 conflict.burstLimit = 15.0; 379 xenstored.log.file = "/dev/null"; 380 xenstored.log.level = "info"; 381 }; 382 description = '' 383 The OCaml-based Xen Store Daemon configuration. This 384 option does nothing with the C-based `xenstored`. 385 ''; 386 type = submodule { 387 options = { 388 pidFile = mkOption { 389 default = "/run/xen/xenstored.pid"; 390 example = "/var/run/xen/xenstored.pid"; 391 type = path; 392 description = "Path to the Xen Store Daemon PID file."; 393 }; 394 testEAGAIN = mkOption { 395 default = cfg.debug; 396 defaultText = literalExpression "config.virtualisation.xen.debug"; 397 example = true; 398 type = bool; 399 visible = false; 400 description = "Randomly fail a transaction with EAGAIN. This option is used for debugging purposes only."; 401 }; 402 enableMerge = mkOption { 403 default = true; 404 example = false; 405 type = bool; 406 description = "Whether to enable transaction merge support."; 407 }; 408 conflict = { 409 burstLimit = mkOption { 410 default = 5.0; 411 example = 15.0; 412 type = addCheck ( 413 float 414 // { 415 name = "nonnegativeFloat"; 416 description = "nonnegative floating point number, meaning >=0"; 417 descriptionClass = "nonRestrictiveClause"; 418 } 419 ) (n: n >= 0); 420 description = '' 421 Limits applied to domains whose writes cause other domains' transaction 422 commits to fail. Must include decimal point. 423 424 The burst limit is the number of conflicts a domain can cause to 425 fail in a short period; this value is used for both the initial and 426 the maximum value of each domain's conflict-credit, which falls by 427 one point for each conflict caused, and when it reaches zero the 428 domain's requests are ignored. 429 ''; 430 }; 431 maxHistorySeconds = mkOption { 432 default = 5.0e-2; 433 example = 1.0; 434 type = addCheck (float // { description = "nonnegative floating point number, meaning >=0"; }) ( 435 n: n >= 0 436 ); 437 description = '' 438 Limits applied to domains whose writes cause other domains' transaction 439 commits to fail. Must include decimal point. 440 441 The conflict-credit is replenished over time: 442 one point is issued after each conflict.maxHistorySeconds, so this 443 is the minimum pause-time during which a domain will be ignored. 444 ''; 445 }; 446 rateLimitIsAggregate = mkOption { 447 default = true; 448 example = false; 449 type = bool; 450 description = '' 451 If the conflict.rateLimitIsAggregate option is `true`, then after each 452 tick one point of conflict-credit is given to just one domain: the 453 one at the front of the queue. If `false`, then after each tick each 454 domain gets a point of conflict-credit. 455 456 In environments where it is known that every transaction will 457 involve a set of nodes that is writable by at most one other domain, 458 then it is safe to set this aggregate limit flag to `false` for better 459 performance. (This can be determined by considering the layout of 460 the xenstore tree and permissions, together with the content of the 461 transactions that require protection.) 462 463 A transaction which involves a set of nodes which can be modified by 464 multiple other domains can suffer conflicts caused by any of those 465 domains, so the flag must be set to `true`. 466 ''; 467 }; 468 }; 469 perms = { 470 enable = mkOption { 471 default = true; 472 example = false; 473 type = bool; 474 description = "Whether to enable the node permission system."; 475 }; 476 enableWatch = mkOption { 477 default = true; 478 example = false; 479 type = bool; 480 description = '' 481 Whether to enable the watch permission system. 482 483 When this is set to `true`, unprivileged guests can only get watch events 484 for xenstore entries that they would've been able to read. 485 486 When this is set to `false`, unprivileged guests may get watch events 487 for xenstore entries that they cannot read. The watch event contains 488 only the entry name, not the value. 489 This restores behaviour prior to [XSA-115](https://xenbits.xenproject.org/xsa/advisory-115.html). 490 ''; 491 }; 492 }; 493 quota = { 494 enable = mkOption { 495 default = true; 496 example = false; 497 type = bool; 498 description = "Whether to enable the quota system."; 499 }; 500 maxEntity = mkOption { 501 default = 1000; 502 example = 1024; 503 type = ints.positive; 504 description = "Entity limit for transactions."; 505 }; 506 maxSize = mkOption { 507 default = 2048; 508 example = 4096; 509 type = ints.positive; 510 description = "Size limit for transactions."; 511 }; 512 maxWatch = mkOption { 513 default = 100; 514 example = 256; 515 type = ints.positive; 516 description = "Maximum number of watches by the Xenstore Watchdog."; 517 }; 518 transaction = mkOption { 519 default = 10; 520 example = 50; 521 type = ints.positive; 522 description = "Maximum number of transactions."; 523 }; 524 maxRequests = mkOption { 525 default = 1024; 526 example = 1024; 527 type = ints.positive; 528 description = "Maximum number of requests per transaction."; 529 }; 530 maxPath = mkOption { 531 default = 1024; 532 example = 1024; 533 type = ints.positive; 534 description = "Path limit for the quota system."; 535 }; 536 maxOutstanding = mkOption { 537 default = 1024; 538 example = 1024; 539 type = ints.positive; 540 description = "Maximum outstanding requests, i.e. in-flight requests / domain."; 541 }; 542 maxWatchEvents = mkOption { 543 default = 1024; 544 example = 2048; 545 type = ints.positive; 546 description = "Maximum number of outstanding watch events per watch."; 547 }; 548 }; 549 persistent = mkOption { 550 default = false; 551 example = true; 552 type = bool; 553 description = "Whether to activate the filed base backend."; 554 }; 555 xenstored = { 556 log = { 557 file = mkOption { 558 default = "/var/log/xen/xenstored.log"; 559 example = "/dev/null"; 560 type = path; 561 description = "Path to the Xen Store log file."; 562 }; 563 level = mkOption { 564 default = if cfg.trace then "debug" else null; 565 defaultText = literalExpression "if (config.virtualisation.xen.trace == true) then \"debug\" else null"; 566 example = "error"; 567 type = nullOr (enum [ 568 "debug" 569 "info" 570 "warn" 571 "error" 572 ]); 573 description = "Logging level for the Xen Store."; 574 }; 575 # The hidden options below have no upstream documentation whatsoever. 576 # The nb* options appear to alter the log rotation behaviour, and 577 # the specialOps option appears to affect the Xenbus logging logic. 578 nbFiles = mkOption { 579 default = 10; 580 example = 16; 581 type = int; 582 visible = false; 583 description = "Set `xenstored-log-nb-files`."; 584 }; 585 }; 586 accessLog = { 587 file = mkOption { 588 default = "/var/log/xen/xenstored-access.log"; 589 example = "/var/log/security/xenstored-access.log"; 590 type = path; 591 description = "Path to the Xen Store access log file."; 592 }; 593 nbLines = mkOption { 594 default = 13215; 595 example = 16384; 596 type = int; 597 visible = false; 598 description = "Set `access-log-nb-lines`."; 599 }; 600 nbChars = mkOption { 601 default = 180; 602 example = 256; 603 type = int; 604 visible = false; 605 description = "Set `acesss-log-nb-chars`."; 606 }; 607 specialOps = mkOption { 608 default = false; 609 example = true; 610 type = bool; 611 visible = false; 612 description = "Set `access-log-special-ops`."; 613 }; 614 }; 615 xenfs = { 616 kva = mkOption { 617 default = "/proc/xen/xsd_kva"; 618 example = cfg.store.settings.xenstored.xenfs.kva; 619 type = path; 620 visible = false; 621 description = '' 622 Path to the Xen Store Daemon KVA location inside the XenFS pseudo-filesystem. 623 While it is possible to alter this value, some drivers may be hardcoded to follow the default paths. 624 ''; 625 }; 626 port = mkOption { 627 default = "/proc/xen/xsd_port"; 628 example = cfg.store.settings.xenstored.xenfs.port; 629 type = path; 630 visible = false; 631 description = '' 632 Path to the Xen Store Daemon userspace port inside the XenFS pseudo-filesystem. 633 While it is possible to alter this value, some drivers may be hardcoded to follow the default paths. 634 ''; 635 }; 636 }; 637 }; 638 ringScanInterval = mkOption { 639 default = 20; 640 example = 30; 641 type = addCheck ( 642 int 643 // { 644 name = "nonzeroInt"; 645 description = "nonzero signed integer, meaning !=0"; 646 descriptionClass = "nonRestrictiveClause"; 647 } 648 ) (n: n != 0); 649 description = '' 650 Perodic scanning for all the rings as a safenet for lazy clients. 651 Define the interval in seconds; set to a negative integer to disable. 652 ''; 653 }; 654 }; 655 }; 656 }; 657 }; 658 }; 659 660 ## Implementation ## 661 662 config = mkIf cfg.enable { 663 assertions = [ 664 { 665 assertion = pkgs.stdenv.hostPlatform.isx86_64; 666 message = "Xen is currently not supported on ${pkgs.stdenv.hostPlatform.system}."; 667 } 668 { 669 assertion = 670 config.boot.loader.systemd-boot.enable 671 || (config.boot ? lanzaboote) && config.boot.lanzaboote.enable 672 || config.boot.loader.limine.enable; 673 message = "Xen only supports booting on systemd-boot, Lanzaboote or Limine."; 674 } 675 { 676 assertion = config.boot.initrd.systemd.enable; 677 message = "Xen does not support the legacy script-based Stage 1 initrd."; 678 } 679 { 680 assertion = cfg.dom0Resources.maxMemory >= cfg.dom0Resources.memory; 681 message = '' 682 You have allocated more memory to dom0 than virtualisation.xen.dom0Resources.maxMemory 683 allows for. Please increase the maximum memory limit, or decrease the default memory allocation. 684 ''; 685 } 686 { 687 assertion = cfg.debug -> cfg.trace; 688 message = "Xen's debugging features are enabled, but logging is disabled. This is most likely not what you want."; 689 } 690 { 691 assertion = cfg.store.settings.quota.maxWatchEvents >= cfg.store.settings.quota.maxOutstanding; 692 message = '' 693 Upstream Xen recommends that maxWatchEvents be equal to or greater than maxOutstanding, 694 in order to mitigate denial of service attacks from malicious frontends. 695 ''; 696 } 697 ]; 698 699 virtualisation.xen.boot.params = 700 optionals cfg.trace [ 701 "loglvl=all" 702 "guest_loglvl=all" 703 ] 704 ++ 705 optional (cfg.dom0Resources.memory != 0) 706 "dom0_mem=${toString cfg.dom0Resources.memory}M${ 707 optionalString ( 708 cfg.dom0Resources.memory != cfg.dom0Resources.maxMemory 709 ) ",max:${toString cfg.dom0Resources.maxMemory}M" 710 }" 711 ++ optional ( 712 cfg.dom0Resources.maxVCPUs != 0 713 ) "dom0_max_vcpus=${toString cfg.dom0Resources.maxVCPUs}"; 714 715 boot = { 716 kernelModules = [ 717 "xen-evtchn" 718 "xen-gntdev" 719 "xen-gntalloc" 720 "xen-blkback" 721 "xen-netback" 722 "xen-pciback" 723 "evtchn" 724 "gntdev" 725 "netbk" 726 "blkbk" 727 "xen-scsibk" 728 "usbbk" 729 "pciback" 730 "xen-acpi-processor" 731 "blktap2" 732 "tun" 733 "netxen_nic" 734 "xen_wdt" 735 "xen-acpi-processor" 736 "xen-privcmd" 737 "xen-scsiback" 738 "xenfs" 739 ]; 740 741 # The xenfs module is needed to mount /proc/xen. 742 initrd.kernelModules = [ "xenfs" ]; 743 744 # Increase the number of loopback devices from the default (8), 745 # which is way too small because every VM virtual disk requires a 746 # loopback device. 747 extraModprobeConfig = '' 748 options loop max_loop=64 749 ''; 750 751 # Xen Bootspec extension. This extension allows NixOS bootloaders to 752 # fetch the dom0 kernel paths and access the `cfg.boot.params` option. 753 bootspec.extensions = { 754 # Bootspec extension v1 is deprecated, and will be removed in 26.05 755 # It is present for backwards compatibility 756 "org.xenproject.bootspec.v1" = { 757 xen = cfg.boot.efi.path; 758 xenParams = cfg.boot.params; 759 }; 760 # Bootspec extension v2 includes more detail, 761 # including supporting multiboot, and is the current supported 762 # bootspec extension 763 "org.xenproject.bootspec.v2" = { 764 efiPath = cfg.boot.efi.path; 765 multibootPath = cfg.boot.bios.path; 766 version = cfg.package.version; 767 params = cfg.boot.params; 768 }; 769 }; 770 771 # See the `xenBootBuilder` script in the main `let...in` statement of this file. 772 loader.systemd-boot.extraInstallCommands = '' 773 ${getExe xenBootBuilder} ${cfg.boot.builderVerbosity} 774 ''; 775 }; 776 777 # Domain 0 requires a pvops-enabled kernel. 778 # All NixOS kernels come with this enabled by default; this is merely a sanity check. 779 system.requiredKernelConfig = with config.lib.kernelConfig; [ 780 (isYes "XEN") 781 (isYes "X86_IO_APIC") 782 (isYes "ACPI") 783 (isYes "XEN_DOM0") 784 (isYes "PCI_XEN") 785 (isYes "XEN_DEV_EVTCHN") 786 (isYes "XENFS") 787 (isYes "XEN_COMPAT_XENFS") 788 (isYes "XEN_SYS_HYPERVISOR") 789 (isYes "XEN_GNTDEV") 790 (isYes "XEN_BACKEND") 791 (isModule "XEN_NETDEV_BACKEND") 792 (isModule "XEN_BLKDEV_BACKEND") 793 (isModule "XEN_PCIDEV_BACKEND") 794 (isYes "XEN_BALLOON") 795 (isYes "XEN_SCRUB_PAGES") 796 ]; 797 798 environment = { 799 systemPackages = [ 800 cfg.package 801 (hiPrio cfg.qemu.package) 802 ]; 803 etc = 804 # Set up Xen Domain 0 configuration files. 805 { 806 "xen/xl.conf".source = "${cfg.package}/etc/xen/xl.conf"; # TODO: Add options to configure xl.conf declaratively. It's worth considering making a new "xl value" type, as it could be reused to produce xl.cfg (domain definition) files. 807 "xen/scripts-xen" = { 808 source = "${cfg.package}/etc/xen/scripts/*"; 809 target = "xen/scripts"; 810 }; 811 "default/xencommons".text = '' 812 source ${cfg.package}/etc/default/xencommons 813 814 XENSTORED="${cfg.store.path}" 815 QEMU_XEN="${cfg.qemu.package}/${cfg.qemu.package.qemu-system-i386}" 816 ${optionalString cfg.trace '' 817 XENSTORED_TRACE=yes 818 XENCONSOLED_TRACE=all 819 ''} 820 ''; 821 "default/xendomains".text = '' 822 source ${cfg.package}/etc/default/xendomains 823 824 ${cfg.domains.extraConfig} 825 ''; 826 } 827 # The OCaml-based Xen Store Daemon requires /etc/xen/oxenstored.conf to start. 828 // optionalAttrs (cfg.store.type == "ocaml") { 829 "xen/oxenstored.conf".text = '' 830 pid-file = ${cfg.store.settings.pidFile} 831 test-eagain = ${boolToString cfg.store.settings.testEAGAIN} 832 merge-activate = ${toString cfg.store.settings.enableMerge} 833 conflict-burst-limit = ${toString cfg.store.settings.conflict.burstLimit} 834 conflict-max-history-seconds = ${toString cfg.store.settings.conflict.maxHistorySeconds} 835 conflict-rate-limit-is-aggregate = ${toString cfg.store.settings.conflict.rateLimitIsAggregate} 836 perms-activate = ${toString cfg.store.settings.perms.enable} 837 perms-watch-activate = ${toString cfg.store.settings.perms.enableWatch} 838 quota-activate = ${toString cfg.store.settings.quota.enable} 839 quota-maxentity = ${toString cfg.store.settings.quota.maxEntity} 840 quota-maxsize = ${toString cfg.store.settings.quota.maxSize} 841 quota-maxwatch = ${toString cfg.store.settings.quota.maxWatch} 842 quota-transaction = ${toString cfg.store.settings.quota.transaction} 843 quota-maxrequests = ${toString cfg.store.settings.quota.maxRequests} 844 quota-path-max = ${toString cfg.store.settings.quota.maxPath} 845 quota-maxoutstanding = ${toString cfg.store.settings.quota.maxOutstanding} 846 quota-maxwatchevents = ${toString cfg.store.settings.quota.maxWatchEvents} 847 persistent = ${boolToString cfg.store.settings.persistent} 848 xenstored-log-file = ${cfg.store.settings.xenstored.log.file} 849 xenstored-log-level = ${ 850 if isNull cfg.store.settings.xenstored.log.level then 851 "null" 852 else 853 cfg.store.settings.xenstored.log.level 854 } 855 xenstored-log-nb-files = ${toString cfg.store.settings.xenstored.log.nbFiles} 856 access-log-file = ${cfg.store.settings.xenstored.accessLog.file} 857 access-log-nb-lines = ${toString cfg.store.settings.xenstored.accessLog.nbLines} 858 acesss-log-nb-chars = ${toString cfg.store.settings.xenstored.accessLog.nbChars} 859 access-log-special-ops = ${boolToString cfg.store.settings.xenstored.accessLog.specialOps} 860 ring-scan-interval = ${toString cfg.store.settings.ringScanInterval} 861 xenstored-kva = ${cfg.store.settings.xenstored.xenfs.kva} 862 xenstored-port = ${cfg.store.settings.xenstored.xenfs.port} 863 ''; 864 }; 865 }; 866 867 # Xen provides udev rules. 868 services.udev.packages = [ cfg.package ]; 869 870 systemd = { 871 # Xen provides systemd units. 872 packages = [ cfg.package ]; 873 874 mounts = [ 875 { 876 description = "Mount /proc/xen files"; 877 what = "xenfs"; 878 where = "/proc/xen"; 879 type = "xenfs"; 880 unitConfig = { 881 ConditionPathExists = "/proc/xen"; 882 RefuseManualStop = "true"; 883 }; 884 } 885 ]; 886 887 services = { 888 889 # While this service is installed by the `xen` package, it shouldn't be used in dom0. 890 xendriverdomain.enable = false; 891 892 xenstored = { 893 wantedBy = [ "multi-user.target" ]; 894 preStart = '' 895 export XENSTORED_ROOTDIR="/var/lib/xenstored" 896 rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null 897 mkdir -p /var/{run,log,lib}/xen 898 ''; 899 }; 900 901 xen-init-dom0 = { 902 restartIfChanged = false; 903 wantedBy = [ "multi-user.target" ]; 904 }; 905 906 xen-qemu-dom0-disk-backend = { 907 wantedBy = [ "multi-user.target" ]; 908 serviceConfig = { 909 PIDFile = cfg.qemu.pidFile; 910 ExecStart = '' 911 ${cfg.qemu.package}/${cfg.qemu.package.qemu-system-i386} \ 912 -xen-domid 0 -xen-attach -name dom0 -nographic -M xenpv \ 913 -daemonize -monitor /dev/null -serial /dev/null -parallel \ 914 /dev/null -nodefaults -no-user-config -pidfile \ 915 ${cfg.qemu.pidFile} 916 ''; 917 }; 918 }; 919 920 xenconsoled.wantedBy = [ "multi-user.target" ]; 921 922 xen-watchdog = { 923 wantedBy = [ "multi-user.target" ]; 924 serviceConfig = { 925 RestartSec = "1"; 926 Restart = "on-failure"; 927 }; 928 }; 929 930 xendomains = { 931 restartIfChanged = false; 932 path = [ 933 cfg.package 934 cfg.qemu.package 935 ]; 936 preStart = "mkdir -p /var/lock/subsys -m 755"; 937 wantedBy = [ "multi-user.target" ]; 938 }; 939 }; 940 }; 941 }; 942 meta.maintainers = members; 943}