Skip to content

Commit e34576b

Browse files
podocarpesselius
authored andcommitted
Darwin support
1 parent 9694139 commit e34576b

File tree

5 files changed

+117
-82
lines changed

5 files changed

+117
-82
lines changed

lib/default.nix

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,49 +29,6 @@ rec {
2929
lib.drop offset lib.strings.lowerChars
3030
));
3131

32-
createVolumesScript = pkgs: volumes:
33-
lib.optionalString (volumes != []) (
34-
lib.optionalString (lib.any (v: v.autoCreate) volumes) ''
35-
PATH=$PATH:${with pkgs.buildPackages; lib.makeBinPath [ coreutils util-linux e2fsprogs xfsprogs dosfstools btrfs-progs ]}
36-
'' +
37-
pkgs.lib.concatMapStringsSep "\n" (
38-
{ image
39-
, label
40-
, size ? throw "Specify a size for volume ${image} or use autoCreate = false"
41-
, mkfsExtraArgs
42-
, fsType ? defaultFsType
43-
, autoCreate ? true
44-
, ...
45-
}: pkgs.lib.warnIf
46-
(label != null && !autoCreate) "Volume is not automatically labeled unless autoCreate is true. Volume has to be labeled manually, otherwise it will not be identified"
47-
(let labelOption =
48-
if autoCreate then
49-
(if builtins.elem fsType ["ext2" "ext3" "ext4" "xfs" "btrfs"] then "-L"
50-
else if fsType == "vfat" then "-n"
51-
else (pkgs.lib.warnIf (label != null)
52-
"Will not label volume ${label} with filesystem type ${fsType}. Open an issue on the microvm.nix project to request a fix."
53-
null))
54-
else null;
55-
labelArgument =
56-
if (labelOption != null && label != null) then "${labelOption} '${label}'"
57-
else "";
58-
mkfsExtraArgsString =
59-
if mkfsExtraArgs != null
60-
then lib.escapeShellArgs mkfsExtraArgs
61-
else " ";
62-
in (lib.optionalString autoCreate ''
63-
64-
if [ ! -e '${image}' ]; then
65-
touch '${image}'
66-
# Mark NOCOW
67-
chattr +C '${image}' || true
68-
truncate -s ${toString size}M '${image}'
69-
mkfs.${fsType} ${labelArgument} ${mkfsExtraArgsString} '${image}'
70-
fi
71-
''))
72-
) volumes
73-
);
74-
7532
buildRunner = import ./runner.nix;
7633

7734
makeMacvtap = { microvmConfig, hypervisorConfig }:

lib/runner.nix

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
let
77
inherit (pkgs) lib;
88

9-
inherit (microvmConfig) hostName;
9+
inherit (microvmConfig) hostName vmHostPackages;
1010

11-
inherit (import ./. { inherit lib; }) createVolumesScript makeMacvtap withDriveLetters extractOptValues extractParamValue;
11+
inherit (import ./. { inherit lib; }) makeMacvtap withDriveLetters extractOptValues extractParamValue;
12+
inherit (import ./volumes.nix { inherit lib microvmConfig; }) createVolumesScript;
1213
inherit (makeMacvtap {
1314
inherit microvmConfig hypervisorConfig;
1415
}) openMacvtapFds macvtapFds;
@@ -26,22 +27,12 @@ let
2627
execArg = lib.optionalString microvmConfig.prettyProcnames
2728
''-a "microvm@${hostName}"'';
2829

29-
vmHostPackages =
30-
if microvmConfig.cpu == null
31-
then
32-
# When cross-compiling for a target host, select packages for
33-
# the target:
34-
pkgs
35-
else
36-
# When cross-compiling for CPU emulation in qemu, select
37-
# packages for the host:
38-
pkgs.buildPackages;
3930

4031
binScripts = microvmConfig.binScripts // {
4132
microvm-run = ''
4233
set -eou pipefail
4334
${preStart}
44-
${createVolumesScript vmHostPackages microvmConfig.volumes}
35+
${createVolumesScript microvmConfig.volumes}
4536
${lib.optionalString (hypervisorConfig.requiresMacvtapAsFds or false) openMacvtapFds}
4637
4738
exec ${execArg} ${command}
@@ -63,11 +54,11 @@ let
6354
};
6455

6556
binScriptPkgs = lib.mapAttrs (scriptName: lines:
66-
pkgs.writeShellScript "microvm-${hostName}-${scriptName}" lines
57+
vmHostPackages.writeShellScript "microvm-${hostName}-${scriptName}" lines
6758
) binScripts;
6859
in
6960

70-
pkgs.buildPackages.runCommand "microvm-${microvmConfig.hypervisor}-${hostName}"
61+
vmHostPackages.buildPackages.runCommand "microvm-${microvmConfig.hypervisor}-${hostName}"
7162
{
7263
# for `nix run`
7364
meta.mainProgram = "microvm-run";

lib/runners/qemu.nix

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
let
99
inherit (pkgs) lib;
1010
inherit (pkgs.stdenv) system;
11+
inherit (microvmConfig) vmHostPackages;
1112

1213
enableLibusb = pkg: pkg.overrideAttrs (oa: {
1314
configureFlags = oa.configureFlags ++ [
@@ -38,16 +39,11 @@ let
3839
++ lib.optional microvmConfig.optimize.enable minimizeQemuClosureSize
3940
);
4041

41-
qemuPkg =
42-
if microvmConfig.cpu == null
43-
then
44-
# When cross-compiling for a target host, select qemu for the target:
45-
pkgs.qemu_kvm
46-
else
47-
# When cross-compiling for CPU emulation, select qemu for the host:
48-
pkgs.buildPackages.qemu;
42+
qemu = overrideQemu vmHostPackages.qemu;
4943

50-
qemu = overrideQemu qemuPkg;
44+
aioEngine = if vmHostPackages.stdenv.hostPlatform.isLinux
45+
then "io_uring"
46+
else "threads";
5147

5248
inherit (microvmConfig) hostName vcpu mem balloon initialBalloonMem deflateOnOOM hotplugMem hotpluggedMem user interfaces shares socket forwardPorts devices vsock graphics storeOnDisk kernel initrdPath storeDisk credentialFiles;
5349
inherit (microvmConfig.qemu) machine extraArgs serialConsole;
@@ -72,10 +68,10 @@ let
7268
else "host"
7369
) ];
7470

75-
accel =
76-
if microvmConfig.cpu == null
77-
then "kvm:tcg"
78-
else "tcg";
71+
accel = if vmHostPackages.stdenv.hostPlatform.isLinux
72+
then "kvm:tcg" else
73+
if vmHostPackages.stdenv.hostPlatform.isDarwin
74+
then "hvf:tcg" else "tcg";
7975

8076
# PCI required by vfio-pci for PCI passthrough
8177
pciInDevices = lib.any ({ bus, ... }: bus == "pci") devices;
@@ -104,6 +100,9 @@ let
104100
inherit accel;
105101
gic-version = "max";
106102
};
103+
aarch64-darwin = {
104+
inherit accel;
105+
};
107106
}.${system};
108107

109108
machineConfig = builtins.concatStringsSep "," (
@@ -129,9 +128,10 @@ let
129128

130129
canSandbox =
131130
# Don't let qemu sandbox itself if it is going to call qemu-bridge-helper
132-
! lib.any ({ type, ... }:
131+
(! lib.any ({ type, ... }:
133132
type == "bridge"
134-
) microvmConfig.interfaces;
133+
) microvmConfig.interfaces) &&
134+
(builtins.elem "--enable-seccomp" (qemu.configureFlags or []));
135135

136136
tapMultiQueue = vcpu > 1;
137137

@@ -196,7 +196,7 @@ lib.warnIf (mem == 2048) ''
196196
lib.optionals serialConsole [
197197
"-serial" "chardev:stdio"
198198
] ++
199-
lib.optionals (microvmConfig.cpu == null) [
199+
lib.optionals (vmHostPackages.stdenv.hostPlatform.isLinux && microvmConfig.cpu == null) [
200200
"-enable-kvm"
201201
] ++
202202
cpuArgs ++
@@ -209,7 +209,7 @@ lib.warnIf (mem == 2048) ''
209209
"-append" "${kernelConsole} reboot=t panic=-1 ${builtins.unsafeDiscardStringContext (toString microvmConfig.kernelParams)}"
210210
] ++
211211
lib.optionals storeOnDisk [
212-
"-drive" "id=store,format=raw,read-only=on,file=${storeDisk},if=none,aio=io_uring"
212+
"-drive" "id=store,format=raw,read-only=on,file=${storeDisk},if=none,aio=${aioEngine}"
213213
"-device" "virtio-blk-${devType},drive=store${lib.optionalString (devType == "pci") ",disable-legacy=on"}"
214214
] ++
215215
(if graphics.enable
@@ -233,7 +233,7 @@ lib.warnIf (mem == 2048) ''
233233
] ++
234234
builtins.concatMap ({ image, letter, serial, direct, readOnly, ... }:
235235
[ "-drive"
236-
"id=vd${letter},format=raw,file=${image},if=none,aio=io_uring,discard=unmap${
236+
"id=vd${letter},format=raw,file=${image},if=none,aio=${aioEngine},discard=unmap${
237237
lib.optionalString (direct != null) ",cache=none"
238238
},read-only=${if readOnly then "on" else "off"}"
239239
"-device"
@@ -243,10 +243,10 @@ lib.warnIf (mem == 2048) ''
243243
]
244244
) volumes ++
245245
lib.optionals (shares != []) (
246-
[
247-
"-object" "memory-backend-memfd,id=mem,size=${toString mem}M,share=on"
246+
(lib.optionals vmHostPackages.stdenv.hostPlatform.isLinux [
248247
"-numa" "node,memdev=mem"
249-
] ++
248+
"-object" "memory-backend-memfd,id=mem,size=${toString mem}M,share=on"
249+
]) ++
250250
builtins.concatMap ({ proto, index, socket, source, tag, securityModel, ... }: {
251251
"virtiofs" = [
252252
"-chardev" "socket,id=fs${toString index},path=${socket}"
@@ -372,7 +372,7 @@ lib.warnIf (mem == 2048) ''
372372
# wait for exit
373373
cat
374374
) | \
375-
${pkgs.socat}/bin/socat STDIO UNIX:${socket},shut-none
375+
${vmHostPackages.socat}/bin/socat STDIO UNIX:${socket},shut-none
376376
''
377377
else throw "Cannot shutdown without socket";
378378

@@ -384,9 +384,9 @@ lib.warnIf (mem == 2048) ''
384384
${writeQmp { execute = "qmp_capabilities"; }}
385385
${writeQmp { execute = "balloon"; arguments.value = 987; }}
386386
) | sed -e s/987/$VALUE/ | \
387-
${pkgs.socat}/bin/socat STDIO UNIX:${socket},shut-none | \
387+
${vmHostPackages.socat}/bin/socat STDIO UNIX:${socket},shut-none | \
388388
tail -n 1 | \
389-
${pkgs.jq}/bin/jq -r .data.actual \
389+
${vmHostPackages.jq}/bin/jq -r .data.actual \
390390
)
391391
echo $(( $SIZE / 1024 / 1024 ))
392392
''

lib/volumes.nix

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{ lib, microvmConfig }:
2+
let
3+
inherit (microvmConfig) vmHostPackages;
4+
inherit (import ../../lib {
5+
inherit lib;
6+
}) defaultFsType;
7+
8+
fsTypeToUtil = fs: with vmHostPackages; {
9+
"ext2" = e2fsprogs;
10+
"ext3" = e2fsprogs;
11+
"ext4" = e2fsprogs;
12+
"xfs" = xfsprogs;
13+
"btrfs" = btrfs-progs;
14+
"vfat" = dosfstools;
15+
}.${fs} or (throw "Do not know how to handle ${fs}");
16+
collectFsTypes = volumes: map (v: v.fsType) volumes;
17+
collectFsUtils = volumes: map (fsType: fsTypeToUtil fsType) (collectFsTypes volumes);
18+
in
19+
{
20+
createVolumesScript =
21+
volumes:
22+
lib.optionalString (volumes != [ ]) (
23+
lib.optionalString (lib.any (v: v.autoCreate) volumes) ''
24+
PATH=$PATH:${lib.makeBinPath ([ vmHostPackages.coreutils ] ++ (collectFsUtils volumes))}
25+
''
26+
+ lib.concatMapStringsSep "\n" (
27+
{
28+
image,
29+
label,
30+
size ? throw "Specify a size for volume ${image} or use autoCreate = false",
31+
mkfsExtraArgs,
32+
fsType ? defaultFsType,
33+
autoCreate ? true,
34+
...
35+
}:
36+
lib.warnIf (label != null && !autoCreate)
37+
"Volume is not automatically labeled unless autoCreate is true. Volume has to be labeled manually, otherwise it will not be identified"
38+
(
39+
let
40+
labelOption =
41+
if autoCreate then
42+
(
43+
if
44+
builtins.elem fsType [
45+
"ext2"
46+
"ext3"
47+
"ext4"
48+
"xfs"
49+
"btrfs"
50+
]
51+
then
52+
"-L"
53+
else if fsType == "vfat" then
54+
"-n"
55+
else
56+
(lib.warnIf (label != null)
57+
"Will not label volume ${label} with filesystem type ${fsType}. Open an issue on the microvm.nix project to request a fix."
58+
null
59+
)
60+
)
61+
else
62+
null;
63+
labelArgument = lib.optionalString (labelOption != null && label != null) then "${labelOption} '${label}'";
64+
mkfsExtraArgsString = if mkfsExtraArgs != null then lib.escapeShellArgs mkfsExtraArgs else " ";
65+
in
66+
(lib.optionalString autoCreate ''
67+
68+
if [ ! -e '${image}' ]; then
69+
touch '${image}'
70+
# Mark NOCOW
71+
chattr +C '${image}' || true
72+
truncate -s ${toString size}M '${image}'
73+
mkfs.${fsType} ${labelArgument} ${mkfsExtraArgsString} '${image}'
74+
fi
75+
'')
76+
)
77+
) volumes
78+
);
79+
}

nixos-modules/microvm/options.nix

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ let
44
inherit lib;
55
};
66

7+
cfg = config.microvm;
78
hostName = config.networking.hostName or "$HOSTNAME";
89
kernelAtLeast = lib.versionAtLeast config.boot.kernelPackages.kernel.version;
910
in
@@ -483,6 +484,13 @@ in
483484
'';
484485
};
485486

487+
vmHostPackages = mkOption {
488+
description = "If set, overrides the default host package.";
489+
example = "nixpkgs.legacyPackages.aarch64-darwin.pkgs";
490+
type = types.nullOr types.pkgs;
491+
default = if cfg.cpu == null then pkgs else pkgs.buildPackages;
492+
};
493+
486494
qemu.machine = mkOption {
487495
type = types.str;
488496
description = ''

0 commit comments

Comments
 (0)