2020-04-24 23:36:52 +00:00
# Xen hypervisor (Dom0) support.
2024-09-19 14:19:46 +00:00
{
config ,
lib ,
pkgs ,
. . .
} :
2020-04-24 23:36:52 +00:00
let
cfg = config . virtualisation . xen ;
2024-09-19 14:19:46 +00:00
xenBootBuilder = pkgs . writeShellApplication {
name = " x e n B o o t B u i l d e r " ;
runtimeInputs =
( with pkgs ; [
binutils
coreutils
findutils
gawk
gnugrep
gnused
jq
] )
++ lib . lists . optionals ( cfg . efi . bootBuilderVerbosity == " i n f o " ) (
with pkgs ;
[
bat
diffutils
]
) ;
runtimeEnv = {
efiMountPoint = config . boot . loader . efi . efiSysMountPoint ;
} ;
2024-09-26 11:04:55 +00:00
# We disable SC2016 because we don't want to expand the regexes in the sed commands.
excludeShellChecks = [ " S C 2 0 1 6 " ] ;
2024-09-19 14:19:46 +00:00
text = builtins . readFile ./xen-boot-builder.sh ;
} ;
2020-04-24 23:36:52 +00:00
in
{
2024-09-19 14:19:46 +00:00
imports = with lib . modules ; [
( mkRemovedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" b r i d g e "
" n a m e "
]
" T h e X e n N e t w o r k B r i d g e o p t i o n s a r e c u r r e n t l y u n a v a i l a b l e . P l e a s e s e t u p y o u r o w n b r i d g e m a n u a l l y . "
)
( mkRemovedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" b r i d g e "
" a d d r e s s "
]
" T h e X e n N e t w o r k B r i d g e o p t i o n s a r e c u r r e n t l y u n a v a i l a b l e . P l e a s e s e t u p y o u r o w n b r i d g e m a n u a l l y . "
)
( mkRemovedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" b r i d g e "
" p r e f i x L e n g t h "
]
" T h e X e n N e t w o r k B r i d g e o p t i o n s a r e c u r r e n t l y u n a v a i l a b l e . P l e a s e s e t u p y o u r o w n b r i d g e m a n u a l l y . "
)
( mkRemovedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" b r i d g e "
" f o r w a r d D n s "
]
" T h e X e n N e t w o r k B r i d g e o p t i o n s a r e c u r r e n t l y u n a v a i l a b l e . P l e a s e s e t u p y o u r o w n b r i d g e m a n u a l l y . "
)
( mkRenamedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" q e m u - p a c k a g e "
]
[
" v i r t u a l i s a t i o n "
" x e n "
" q e m u "
" p a c k a g e "
]
)
( mkRenamedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" p a c k a g e - q e m u "
]
[
" v i r t u a l i s a t i o n "
" x e n "
" q e m u "
" p a c k a g e "
]
)
( mkRenamedOptionModule
[
" v i r t u a l i s a t i o n "
" x e n "
" s t o r e d "
]
[
" v i r t u a l i s a t i o n "
" x e n "
" s t o r e "
" p a t h "
]
)
2020-04-24 23:36:52 +00:00
] ;
2024-09-19 14:19:46 +00:00
## Interface ##
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
options . virtualisation . xen = {
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
enable = lib . options . mkEnableOption " t h e X e n H y p e r v i s o r , a v i r t u a l i s a t i o n t e c h n o l o g y d e f i n e d a s a * t y p e - 1 h y p e r v i s o r * , w h i c h a l l o w s m u l t i p l e v i r t u a l m a c h i n e s , k n o w n a s * d o m a i n s * , t o r u n c o n c u r r e n t l y o n t h e p h y s i c a l m a c h i n e . N i x O S r u n s a s t h e p r i v i l e g e d * D o m a i n 0 * . T h i s o p t i o n r e q u i r e s a r e b o o t i n t o a X e n k e r n e l t o t a k e e f f e c t " ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
debug = lib . options . mkEnableOption " X e n d e b u g f e a t u r e s f o r D o m a i n 0 . T h i s o p t i o n e n a b l e s s o m e h i d d e n d e b u g g i n g t e s t s a n d f e a t u r e s , a n d s h o u l d n o t b e u s e d i n p r o d u c t i o n " ;
trace = lib . options . mkOption {
type = lib . types . bool ;
default = cfg . debug ;
defaultText = lib . options . literalExpression " f a l s e " ;
example = true ;
description = " W h e t h e r t o e n a b l e X e n d e b u g t r a c i n g a n d l o g g i n g f o r D o m a i n 0 . " ;
2020-04-24 23:36:52 +00:00
} ;
2024-09-19 14:19:46 +00:00
package = lib . options . mkOption {
type = lib . types . package ;
default = pkgs . xen ;
defaultText = lib . options . literalExpression " p k g s . x e n " ;
example = lib . options . literalExpression " p k g s . x e n - s l i m " ;
2024-04-21 15:54:59 +00:00
description = ''
2024-09-19 14:19:46 +00:00
The package used for Xen Hypervisor .
2020-04-24 23:36:52 +00:00
'' ;
2024-09-19 14:19:46 +00:00
relatedPackages = [
" x e n "
" x e n - s l i m "
] ;
2020-04-24 23:36:52 +00:00
} ;
2024-09-19 14:19:46 +00:00
qemu = {
package = lib . options . mkOption {
type = lib . types . package ;
default = pkgs . xen ;
defaultText = lib . options . literalExpression " p k g s . x e n " ;
example = lib . options . literalExpression " p k g s . q e m u _ x e n " ;
description = ''
The package with QEMU binaries that runs in Domain 0
and virtualises the unprivileged domains .
'' ;
relatedPackages = [
" x e n "
{
name = " q e m u _ x e n " ;
comment = " F o r u s e w i t h ` p k g s . x e n - s l i m ` . " ;
}
] ;
2020-04-24 23:36:52 +00:00
} ;
2024-09-19 14:19:46 +00:00
pidFile = lib . options . mkOption {
type = lib . types . path ;
default = " / r u n / x e n / q e m u - d o m 0 . p i d " ;
example = " / v a r / r u n / x e n / q e m u - d o m 0 . p i d " ;
description = " P a t h t o t h e Q E M U P I D f i l e . " ;
2020-04-24 23:36:52 +00:00
} ;
2024-09-19 14:19:46 +00:00
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
bootParams = lib . options . mkOption {
default = [ ] ;
example = ''
[
" i o m m u = f o r c e : t r u e , q i n v a l : t r u e , d e b u g : t r u e "
" n o r e b o o t = t r u e "
" v g a = a s k "
]
'' ;
type = lib . types . listOf lib . types . str ;
description = ''
Xen Command Line parameters passed to Domain 0 at boot time .
Note : these are different from ` boot . kernelParams ` . See
the [ Xen documentation ] ( https://xenbits.xenproject.org/docs/unstable/misc/xen-command-line.html ) for more information .
'' ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
efi = {
bootBuilderVerbosity = lib . options . mkOption {
type = lib . types . enum [
" d e f a u l t "
" i n f o "
" d e b u g "
" q u i e t "
] ;
default = " d e f a u l t " ;
example = " i n f o " ;
description = ''
The EFI boot entry builder script should be called with exactly one of the following arguments in order to specify its verbosity :
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
- ` quiet ` supresses all messages .
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
- ` default ` adds a simple " I n s t a l l i n g X e n H y p e r v i s o r b o o t e n t r i e s . . . d o n e . " message to the script .
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
- ` info ` is the same as ` default ` , but it also prints a diff with information on which generations were altered .
- This option adds two extra dependencies to the script : ` diffutils ` and ` bat ` .
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
- ` debug ` prints information messages for every single step of the script .
This option does not alter the actual functionality of the script , just the number of messages printed when rebuilding the system .
'' ;
2020-04-24 23:36:52 +00:00
} ;
2024-09-19 14:19:46 +00:00
path = lib . options . mkOption {
type = lib . types . path ;
default = " ${ cfg . package . boot } / ${ cfg . package . efi } " ;
defaultText = lib . options . literalExpression " \$ { c o n f i g . v i r t u a l i s a t i o n . x e n . p a c k a g e . b o o t } / \$ { c o n f i g . v i r t u a l i s a t i o n . x e n . p a c k a g e . e f i } " ;
example = lib . options . literalExpression " \$ { c o n f i g . v i r t u a l i s a t i o n . x e n . p a c k a g e } / b o o t / e f i / e f i / n i x o s / x e n - \$ { c o n f i g . v i r t u a l i s a t i o n . x e n . p a c k a g e . v e r s i o n } . e f i " ;
description = ''
Path to xen . efi . ` pkgs . xen ` is patched to install the xen . efi file
on ` $ boot/boot/xen.efi ` , but an unpatched Xen build may install it
somewhere else , such as ` $ out/boot/efi/efi/nixos/xen.efi ` . Unless
you're building your own Xen derivation , you should leave this
option as the default value .
'' ;
2020-04-24 23:36:52 +00:00
} ;
2024-09-19 14:19:46 +00:00
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
dom0Resources = {
maxVCPUs = lib . options . mkOption {
default = 0 ;
example = 4 ;
type = lib . types . ints . unsigned ;
description = ''
Amount of virtual CPU cores allocated to Domain 0 on boot .
If set to 0 , all cores are assigned to Domain 0 , and
unprivileged domains will compete with Domain 0 for CPU time .
'' ;
} ;
2020-05-03 17:38:23 +00:00
2024-09-19 14:19:46 +00:00
memory = lib . options . mkOption {
default = 0 ;
example = 512 ;
type = lib . types . ints . unsigned ;
description = ''
Amount of memory ( in MiB ) allocated to Domain 0 on boot .
If set to 0 , all memory is assigned to Domain 0 , and
unprivileged domains will compete with Domain 0 for free RAM .
'' ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
maxMemory = lib . options . mkOption {
default = cfg . dom0Resources . memory ;
defaultText = lib . options . literalExpression " c o n f i g . v i r t u a l i s a t i o n . x e n . d o m 0 R e s o u r c e s . m e m o r y " ;
example = 1024 ;
type = lib . types . ints . unsigned ;
description = ''
Maximum amount of memory ( in MiB ) that Domain 0 can
dynamically allocate to itself . Does nothing if set
to the same amount as virtualisation . xen . memory , or
if that option is set to 0 .
'' ;
} ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
domains = {
extraConfig = lib . options . mkOption {
type = lib . types . lines ;
default = " " ;
example = ''
XENDOMAINS_SAVE = /persist/xen/save
XENDOMAINS_RESTORE = false
XENDOMAINS_CREATE_USLEEP = 10000000
'' ;
description = ''
Options defined here will override the defaults for xendomains .
The default options can be seen in the file included from
/etc/default/xendomains.
'' ;
} ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
store = {
path = lib . options . mkOption {
type = lib . types . path ;
default = " ${ cfg . package } / b i n / o x e n s t o r e d " ;
defaultText = lib . options . literalExpression " \$ { c o n f i g . v i r t u a l i s a t i o n . x e n . p a c k a g e } / b i n / o x e n s t o r e d " ;
example = lib . options . literalExpression " \$ { c o n f i g . v i r t u a l i s a t i o n . x e n . p a c k a g e } / b i n / x e n s t o r e d " ;
description = ''
Path to the Xen Store Daemon . This option is useful to
switch between the legacy C-based Xen Store Daemon , and
the newer OCaml-based Xen Store Daemon , ` oxenstored ` .
'' ;
} ;
type = lib . options . mkOption {
type = lib . types . enum [
" c "
" o c a m l "
] ;
default = if ( lib . strings . hasSuffix " o x e n s t o r e d " cfg . store . path ) then " o c a m l " else " c " ;
internal = true ;
readOnly = true ;
description = " H e l p e r i n t e r n a l o p t i o n t h a t d e t e r m i n e s t h e t y p e o f t h e X e n S t o r e D a e m o n b a s e d o n c f g . s t o r e . p a t h . " ;
} ;
settings = lib . options . mkOption {
default = { } ;
example = {
enableMerge = false ;
quota . maxWatchEvents = 2048 ;
quota . enable = true ;
conflict . maxHistorySeconds = 0 .12 ;
conflict . burstLimit = 15 .0 ;
xenstored . log . file = " / d e v / n u l l " ;
xenstored . log . level = " i n f o " ;
} ;
description = ''
The OCaml-based Xen Store Daemon configuration . This
option does nothing with the C-based ` xenstored ` .
'' ;
type = lib . types . submodule {
options = {
pidFile = lib . options . mkOption {
default = " / r u n / x e n / x e n s t o r e d . p i d " ;
example = " / v a r / r u n / x e n / x e n s t o r e d . p i d " ;
type = lib . types . path ;
description = " P a t h t o t h e X e n S t o r e D a e m o n P I D f i l e . " ;
} ;
testEAGAIN = lib . options . mkOption {
default = cfg . debug ;
defaultText = lib . options . literalExpression " c o n f i g . v i r t u a l i s a t i o n . x e n . d e b u g " ;
example = true ;
type = lib . types . bool ;
visible = false ;
description = " R a n d o m l y f a i l a t r a n s a c t i o n w i t h E A G A I N . T h i s o p t i o n i s u s e d f o r d e b u g g i n g p u r p o s e s o n l y . " ;
} ;
enableMerge = lib . options . mkOption {
default = true ;
example = false ;
type = lib . types . bool ;
description = " W h e t h e r t o e n a b l e t r a n s a c t i o n m e r g e s u p p o r t . " ;
} ;
conflict = {
burstLimit = lib . options . mkOption {
default = 5 .0 ;
example = 15 .0 ;
type = lib . types . addCheck (
lib . types . float
// {
name = " n o n n e g a t i v e F l o a t " ;
description = " n o n n e g a t i v e f l o a t i n g p o i n t n u m b e r , m e a n i n g > = 0 " ;
descriptionClass = " n o n R e s t r i c t i v e C l a u s e " ;
}
) ( n : n >= 0 ) ;
description = ''
Limits applied to domains whose writes cause other domains' transaction
commits to fail . Must include decimal point .
The burst limit is the number of conflicts a domain can cause to
fail in a short period ; this value is used for both the initial and
the maximum value of each domain's conflict-credit , which falls by
one point for each conflict caused , and when it reaches zero the
domain's requests are ignored .
'' ;
} ;
maxHistorySeconds = lib . options . mkOption {
default = 5 .0e-2 ;
example = 1 .0 ;
type = lib . types . addCheck (
lib . types . float // { description = " n o n n e g a t i v e f l o a t i n g p o i n t n u m b e r , m e a n i n g > = 0 " ; }
) ( n : n >= 0 ) ;
description = ''
Limits applied to domains whose writes cause other domains' transaction
commits to fail . Must include decimal point .
The conflict-credit is replenished over time :
one point is issued after each conflict . maxHistorySeconds , so this
is the minimum pause-time during which a domain will be ignored .
'' ;
} ;
rateLimitIsAggregate = lib . options . mkOption {
default = true ;
example = false ;
type = lib . types . bool ;
description = ''
If the conflict . rateLimitIsAggregate option is ` true ` , then after each
tick one point of conflict-credit is given to just one domain : the
one at the front of the queue . If ` false ` , then after each tick each
domain gets a point of conflict-credit .
In environments where it is known that every transaction will
involve a set of nodes that is writable by at most one other domain ,
then it is safe to set this aggregate limit flag to ` false ` for better
performance . ( This can be determined by considering the layout of
the xenstore tree and permissions , together with the content of the
transactions that require protection . )
A transaction which involves a set of nodes which can be modified by
multiple other domains can suffer conflicts caused by any of those
domains , so the flag must be set to ` true ` .
'' ;
} ;
} ;
perms = {
enable = lib . options . mkOption {
default = true ;
example = false ;
type = lib . types . bool ;
description = " W h e t h e r t o e n a b l e t h e n o d e p e r m i s s i o n s y s t e m . " ;
} ;
enableWatch = lib . options . mkOption {
default = true ;
example = false ;
type = lib . types . bool ;
description = ''
Whether to enable the watch permission system .
When this is set to ` true ` , unprivileged guests can only get watch events
for xenstore entries that they would've been able to read .
When this is set to ` false ` , unprivileged guests may get watch events
for xenstore entries that they cannot read . The watch event contains
only the entry name , not the value .
This restores behaviour prior to [ XSA-115 ] ( https://xenbits.xenproject.org/xsa/advisory-115.html ) .
'' ;
} ;
} ;
quota = {
enable = lib . options . mkOption {
default = true ;
example = false ;
type = lib . types . bool ;
description = " W h e t h e r t o e n a b l e t h e q u o t a s y s t e m . " ;
} ;
maxEntity = lib . options . mkOption {
default = 1000 ;
example = 1024 ;
type = lib . types . ints . positive ;
description = " E n t i t y l i m i t f o r t r a n s a c t i o n s . " ;
} ;
maxSize = lib . options . mkOption {
default = 2048 ;
example = 4096 ;
type = lib . types . ints . positive ;
description = " S i z e l i m i t f o r t r a n s a c t i o n s . " ;
} ;
maxWatch = lib . options . mkOption {
default = 100 ;
example = 256 ;
type = lib . types . ints . positive ;
description = " M a x i m u m n u m b e r o f w a t c h e s b y t h e X e n s t o r e W a t c h d o g . " ;
} ;
transaction = lib . options . mkOption {
default = 10 ;
example = 50 ;
type = lib . types . ints . positive ;
description = " M a x i m u m n u m b e r o f t r a n s a c t i o n s . " ;
} ;
maxRequests = lib . options . mkOption {
default = 1024 ;
example = 1024 ;
type = lib . types . ints . positive ;
description = " M a x i m u m n u m b e r o f r e q u e s t s p e r t r a n s a c t i o n . " ;
} ;
maxPath = lib . options . mkOption {
default = 1024 ;
example = 1024 ;
type = lib . types . ints . positive ;
description = " P a t h l i m i t f o r t h e q u o t a s y s t e m . " ;
} ;
maxOutstanding = lib . options . mkOption {
default = 1024 ;
example = 1024 ;
type = lib . types . ints . positive ;
description = " M a x i m u m o u t s t a n d i n g r e q u e s t s , i . e . i n - f l i g h t r e q u e s t s / d o m a i n . " ;
} ;
maxWatchEvents = lib . options . mkOption {
default = 1024 ;
example = 2048 ;
type = lib . types . ints . positive ;
description = " M a x i m u m n u m b e r o f o u t s t a n d i n g w a t c h e v e n t s p e r w a t c h . " ;
} ;
} ;
persistent = lib . options . mkOption {
default = false ;
example = true ;
type = lib . types . bool ;
description = " W h e t h e r t o a c t i v a t e t h e f i l e d b a s e b a c k e n d . " ;
} ;
xenstored = {
log = {
file = lib . options . mkOption {
default = " / v a r / l o g / x e n / x e n s t o r e d . l o g " ;
example = " / d e v / n u l l " ;
type = lib . types . path ;
description = " P a t h t o t h e X e n S t o r e l o g f i l e . " ;
} ;
level = lib . options . mkOption {
default = if cfg . trace then " d e b u g " else null ;
defaultText = lib . options . literalExpression " i f ( c o n f i g . v i r t u a l i s a t i o n . x e n . t r a c e = = t r u e ) t h e n \" d e b u g \" e l s e n u l l " ;
example = " e r r o r " ;
type = lib . types . nullOr (
lib . types . enum [
" d e b u g "
" i n f o "
" w a r n "
" e r r o r "
]
) ;
description = " L o g g i n g l e v e l f o r t h e X e n S t o r e . " ;
} ;
# The hidden options below have no upstream documentation whatsoever.
# The nb* options appear to alter the log rotation behaviour, and
# the specialOps option appears to affect the Xenbus logging logic.
nbFiles = lib . options . mkOption {
default = 10 ;
example = 16 ;
type = lib . types . int ;
visible = false ;
description = " S e t ` x e n s t o r e d - l o g - n b - f i l e s ` . " ;
} ;
} ;
accessLog = {
file = lib . options . mkOption {
default = " / v a r / l o g / x e n / x e n s t o r e d - a c c e s s . l o g " ;
example = " / v a r / l o g / s e c u r i t y / x e n s t o r e d - a c c e s s . l o g " ;
type = lib . types . path ;
description = " P a t h t o t h e X e n S t o r e a c c e s s l o g f i l e . " ;
} ;
nbLines = lib . options . mkOption {
default = 13215 ;
example = 16384 ;
type = lib . types . int ;
visible = false ;
description = " S e t ` a c c e s s - l o g - n b - l i n e s ` . " ;
} ;
nbChars = lib . options . mkOption {
default = 180 ;
example = 256 ;
type = lib . types . int ;
visible = false ;
description = " S e t ` a c e s s s - l o g - n b - c h a r s ` . " ;
} ;
specialOps = lib . options . mkOption {
default = false ;
example = true ;
type = lib . types . bool ;
visible = false ;
description = " S e t ` a c c e s s - l o g - s p e c i a l - o p s ` . " ;
} ;
} ;
xenfs = {
kva = lib . options . mkOption {
default = " / p r o c / x e n / x s d _ k v a " ;
example = cfg . store . settings . xenstored . xenfs . kva ;
type = lib . types . path ;
visible = false ;
description = ''
Path to the Xen Store Daemon KVA location inside the XenFS pseudo-filesystem .
While it is possible to alter this value , some drivers may be hardcoded to follow the default paths .
'' ;
} ;
port = lib . options . mkOption {
default = " / p r o c / x e n / x s d _ p o r t " ;
example = cfg . store . settings . xenstored . xenfs . port ;
type = lib . types . path ;
visible = false ;
description = ''
Path to the Xen Store Daemon userspace port inside the XenFS pseudo-filesystem .
While it is possible to alter this value , some drivers may be hardcoded to follow the default paths .
'' ;
} ;
} ;
} ;
ringScanInterval = lib . options . mkOption {
default = 20 ;
example = 30 ;
type = lib . types . addCheck (
lib . types . int
// {
name = " n o n z e r o I n t " ;
description = " n o n z e r o s i g n e d i n t e g e r , m e a n i n g ! = 0 " ;
descriptionClass = " n o n R e s t r i c t i v e C l a u s e " ;
}
) ( n : n != 0 ) ;
description = ''
Perodic scanning for all the rings as a safenet for lazy clients .
Define the interval in seconds ; set to a negative integer to disable .
'' ;
} ;
} ;
} ;
} ;
} ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
## Implementation ##
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
config = lib . modules . mkIf cfg . enable {
assertions = [
{
2024-09-26 11:04:55 +00:00
assertion = pkgs . stdenv . hostPlatform . isx86_64 ;
2024-09-19 14:19:46 +00:00
message = " X e n i s c u r r e n t l y n o t s u p p o r t e d o n ${ pkgs . stdenv . hostPlatform . system } . " ;
}
{
assertion =
config . boot . loader . systemd-boot . enable
|| ( config . boot ? lanzaboote ) && config . boot . lanzaboote . enable ;
message = " X e n o n l y s u p p o r t s b o o t i n g o n s y s t e m d - b o o t o r L a n z a b o o t e . " ;
}
{
assertion = config . boot . initrd . systemd . enable ;
message = " X e n d o e s n o t s u p p o r t t h e l e g a c y s c r i p t - b a s e d S t a g e 1 i n i t r d . " ;
}
{
assertion = cfg . dom0Resources . maxMemory >= cfg . dom0Resources . memory ;
message = ''
You have allocated more memory to dom0 than virtualisation . xen . dom0Resources . maxMemory
allows for . Please increase the maximum memory limit , or decrease the default memory allocation .
'' ;
}
{
assertion = cfg . debug -> cfg . trace ;
message = " X e n ' s d e b u g g i n g f e a t u r e s a r e e n a b l e d , b u t l o g g i n g i s d i s a b l e d . T h i s i s m o s t l i k e l y n o t w h a t y o u w a n t . " ;
}
{
assertion = cfg . store . settings . quota . maxWatchEvents >= cfg . store . settings . quota . maxOutstanding ;
message = ''
Upstream Xen recommends that maxWatchEvents be equal to or greater than maxOutstanding ,
in order to mitigate denial of service attacks from malicious frontends .
'' ;
}
] ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
virtualisation . xen . bootParams =
lib . lists . optionals cfg . trace [
" l o g l v l = a l l "
" g u e s t _ l o g l v l = a l l "
]
++
lib . lists . optional ( cfg . dom0Resources . memory != 0 )
" d o m 0 _ m e m = ${ toString cfg . dom0Resources . memory } M ${
lib . strings . optionalString (
cfg . dom0Resources . memory != cfg . dom0Resources . maxMemory
) " , m a x : ${ toString cfg . dom0Resources . maxMemory } M "
} "
++ lib . lists . optional (
cfg . dom0Resources . maxVCPUs != 0
) " d o m 0 _ m a x _ v c p u s = ${ toString cfg . dom0Resources . maxVCPUs } " ;
boot = {
kernelModules = [
" x e n - e v t c h n "
" x e n - g n t d e v "
" x e n - g n t a l l o c "
" x e n - b l k b a c k "
" x e n - n e t b a c k "
" x e n - p c i b a c k "
" e v t c h n "
" g n t d e v "
" n e t b k "
" b l k b k "
" x e n - s c s i b k "
" u s b b k "
" p c i b a c k "
" x e n - a c p i - p r o c e s s o r "
" b l k t a p 2 "
" t u n "
" n e t x e n _ n i c "
" x e n _ w d t "
" x e n - a c p i - p r o c e s s o r "
" x e n - p r i v c m d "
" x e n - s c s i b a c k "
2020-04-24 23:36:52 +00:00
" x e n f s "
] ;
2024-09-19 14:19:46 +00:00
# The xenfs module is needed to mount /proc/xen.
initrd . kernelModules = [ " x e n f s " ] ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
# Increase the number of loopback devices from the default (8),
# which is way too small because every VM virtual disk requires a
# loopback device.
extraModprobeConfig = ''
2020-04-24 23:36:52 +00:00
options loop max_loop = 64
'' ;
2024-09-19 14:19:46 +00:00
# Xen Bootspec extension. This extension allows NixOS bootloaders to
# fetch the `xen.efi` path and access the `cfg.bootParams` option.
bootspec . extensions = {
" o r g . x e n p r o j e c t . b o o t s p e c . v 1 " = {
xen = cfg . efi . path ;
xenParams = cfg . bootParams ;
} ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
# See the `xenBootBuilder` script in the main `let...in` statement of this file.
loader . systemd-boot . extraInstallCommands = ''
$ { lib . meta . getExe xenBootBuilder } $ { cfg . efi . bootBuilderVerbosity }
2020-04-24 23:36:52 +00:00
'' ;
2024-09-19 14:19:46 +00:00
} ;
2020-04-24 23:36:52 +00:00
# Domain 0 requires a pvops-enabled kernel.
2024-09-19 14:19:46 +00:00
# All NixOS kernels come with this enabled by default; this is merely a sanity check.
system . requiredKernelConfig = with config . lib . kernelConfig ; [
( isYes " X E N " )
( isYes " X 8 6 _ I O _ A P I C " )
( isYes " A C P I " )
( isYes " X E N _ D O M 0 " )
( isYes " P C I _ X E N " )
( isYes " X E N _ D E V _ E V T C H N " )
( isYes " X E N F S " )
( isYes " X E N _ C O M P A T _ X E N F S " )
( isYes " X E N _ S Y S _ H Y P E R V I S O R " )
( isYes " X E N _ G N T D E V " )
( isYes " X E N _ B A C K E N D " )
( isModule " X E N _ N E T D E V _ B A C K E N D " )
( isModule " X E N _ B L K D E V _ B A C K E N D " )
( isModule " X E N _ P C I D E V _ B A C K E N D " )
( isYes " X E N _ B A L L O O N " )
( isYes " X E N _ S C R U B _ P A G E S " )
] ;
environment = {
systemPackages = [
cfg . package
cfg . qemu . package
2020-04-24 23:36:52 +00:00
] ;
2024-09-19 14:19:46 +00:00
etc =
# Set up Xen Domain 0 configuration files.
{
" x e n / x l . c o n f " . source = " ${ cfg . package } / e t c / x e n / x l . c o n f " ; # 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.
" x e n / s c r i p t s - x e n " = {
source = " ${ cfg . package } / e t c / x e n / s c r i p t s / * " ;
target = " x e n / s c r i p t s " ;
} ;
" d e f a u l t / x e n c o m m o n s " . text = ''
source $ { cfg . package } /etc/default/xencommons
XENSTORED = " ${ cfg . store . path } "
QEMU_XEN = " ${ cfg . qemu . package } / ${ cfg . qemu . package . qemu-system-i386 } "
$ { lib . strings . optionalString cfg . trace ''
XENSTORED_TRACE = yes
XENCONSOLED_TRACE = all
'' }
'' ;
" d e f a u l t / x e n d o m a i n s " . text = ''
source $ { cfg . package } /etc/default/xendomains
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
$ { cfg . domains . extraConfig }
'' ;
}
# The OCaml-based Xen Store Daemon requires /etc/xen/oxenstored.conf to start.
// lib . attrsets . optionalAttrs ( cfg . store . type == " o c a m l " ) {
" x e n / o x e n s t o r e d . c o n f " . text = ''
pid-file = $ { cfg . store . settings . pidFile }
test-eagain = $ { lib . trivial . boolToString cfg . store . settings . testEAGAIN }
merge-activate = $ { toString cfg . store . settings . enableMerge }
conflict-burst-limit = $ { toString cfg . store . settings . conflict . burstLimit }
conflict-max-history-seconds = $ { toString cfg . store . settings . conflict . maxHistorySeconds }
conflict-rate-limit-is-aggregate = $ { toString cfg . store . settings . conflict . rateLimitIsAggregate }
perms-activate = $ { toString cfg . store . settings . perms . enable }
perms-watch-activate = $ { toString cfg . store . settings . perms . enableWatch }
quota-activate = $ { toString cfg . store . settings . quota . enable }
quota-maxentity = $ { toString cfg . store . settings . quota . maxEntity }
quota-maxsize = $ { toString cfg . store . settings . quota . maxSize }
quota-maxwatch = $ { toString cfg . store . settings . quota . maxWatch }
quota-transaction = $ { toString cfg . store . settings . quota . transaction }
quota-maxrequests = $ { toString cfg . store . settings . quota . maxRequests }
quota-path-max = $ { toString cfg . store . settings . quota . maxPath }
quota-maxoutstanding = $ { toString cfg . store . settings . quota . maxOutstanding }
quota-maxwatchevents = $ { toString cfg . store . settings . quota . maxWatchEvents }
persistent = $ { lib . trivial . boolToString cfg . store . settings . persistent }
xenstored-log-file = $ { cfg . store . settings . xenstored . log . file }
xenstored-log-level = $ {
if isNull cfg . store . settings . xenstored . log . level then
" n u l l "
else
cfg . store . settings . xenstored . log . level
}
xenstored-log-nb-files = $ { toString cfg . store . settings . xenstored . log . nbFiles }
access-log-file = $ { cfg . store . settings . xenstored . accessLog . file }
access-log-nb-lines = $ { toString cfg . store . settings . xenstored . accessLog . nbLines }
acesss-log-nb-chars = $ { toString cfg . store . settings . xenstored . accessLog . nbChars }
access-log-special-ops = $ { lib . trivial . boolToString cfg . store . settings . xenstored . accessLog . specialOps }
ring-scan-interval = $ { toString cfg . store . settings . ringScanInterval }
xenstored-kva = $ { cfg . store . settings . xenstored . xenfs . kva }
xenstored-port = $ { cfg . store . settings . xenstored . xenfs . port }
'' ;
} ;
} ;
2020-04-24 23:36:52 +00:00
# Xen provides udev rules.
services . udev . packages = [ cfg . package ] ;
2024-09-19 14:19:46 +00:00
systemd = {
# Xen provides systemd units.
packages = [ cfg . package ] ;
mounts = [
{
description = " M o u n t / p r o c / x e n f i l e s " ;
what = " x e n f s " ;
where = " / p r o c / x e n " ;
type = " x e n f s " ;
unitConfig = {
ConditionPathExists = " / p r o c / x e n " ;
RefuseManualStop = " t r u e " ;
} ;
}
] ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
services = {
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
# While this service is installed by the `xen` package, it shouldn't be used in dom0.
xendriverdomain . enable = false ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
xenstored = {
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
preStart = ''
export XENSTORED_ROOTDIR = " / v a r / l i b / x e n s t o r e d "
rm - f " $ X E N S T O R E D _ R O O T D I R " /tdb * & > /dev/null
mkdir - p /var / { run , log , lib } /xen
2020-04-24 23:36:52 +00:00
'' ;
2024-09-19 14:19:46 +00:00
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
xen-init-dom0 = {
restartIfChanged = false ;
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
xen-qemu-dom0-disk-backend = {
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
serviceConfig = {
PIDFile = cfg . qemu . pidFile ;
ExecStart = ''
$ { cfg . qemu . package } / $ { cfg . qemu . package . qemu-system-i386 } \
- xen-domid 0 - xen-attach - name dom0 - nographic - M xenpv \
- daemonize - monitor /dev/null - serial /dev/null - parallel \
/dev/null - nodefaults - no-user-config - pidfile \
$ { cfg . qemu . pidFile }
'' ;
} ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
xenconsoled . wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
xen-watchdog = {
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
serviceConfig = {
RestartSec = " 1 " ;
Restart = " o n - f a i l u r e " ;
} ;
} ;
2020-04-24 23:36:52 +00:00
2024-09-19 14:19:46 +00:00
xendomains = {
restartIfChanged = false ;
path = [
cfg . package
cfg . qemu . package
] ;
preStart = " m k d i r - p / v a r / l o c k / s u b s y s - m 7 5 5 " ;
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
} ;
} ;
2020-04-24 23:36:52 +00:00
} ;
} ;
2024-09-19 14:19:46 +00:00
meta . maintainers = with lib . maintainers ; [ sigmasquadron ] ;
2020-04-24 23:36:52 +00:00
}