Skip to content

Commit 65a6e30

Browse files
nesteroffbrianmcgillion
authored andcommitted
Implement PCI device management via vhotplug
Signed-off-by: Yuri Nesterov <yuriy.nesterov@unikie.com>
1 parent 5e9c171 commit 65a6e30

File tree

14 files changed

+477
-329
lines changed

14 files changed

+477
-329
lines changed

flake.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,16 @@
180180
inputs.nixpkgs.follows = "nixpkgs";
181181
};
182182

183+
# Hot-plugging USB devices into virtual machines
184+
vhotplug = {
185+
url = "github:tiiuae/vhotplug";
186+
inputs = {
187+
nixpkgs.follows = "nixpkgs";
188+
flake-parts.follows = "flake-parts";
189+
treefmt-nix.follows = "treefmt-nix";
190+
};
191+
};
192+
183193
# A UI for the one true VPN: Wireguard
184194
wireguard-gui = {
185195
url = "github:tiiuae/wireguard-gui";

modules/common/services/killswitch.nix

Lines changed: 38 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,22 @@ let
1111
mkOption
1212
mkIf
1313
types
14-
flatten
15-
concatMapStringsSep
1614
;
1715
cfg = config.ghaf.services.kill-switch;
1816

19-
netvmName = "net-vm";
20-
audiovmName = "audio-vm";
21-
inherit (config.microvm) stateDir;
2217
supportedDevices = [
2318
"mic"
2419
"net"
2520
"cam"
2621
];
2722

28-
# Flatten the list of devices
2923
audioPciDevices =
3024
if config.ghaf.virtualization.microvm.audiovm.enable then
31-
flatten (map (device: "${device.vendorId}:${device.productId}") config.ghaf.common.hardware.audio)
25+
config.ghaf.common.hardware.audio
3226
else
3327
[ ];
3428
netPciDevices =
35-
if config.ghaf.virtualization.microvm.netvm.enable then
36-
flatten (map (device: "${device.vendorId}:${device.productId}") config.ghaf.common.hardware.nics)
37-
else
38-
[ ];
29+
if config.ghaf.virtualization.microvm.netvm.enable then config.ghaf.common.hardware.nics else [ ];
3930
camUsbDevices = builtins.filter (
4031
d: lib.hasPrefix "cam" d.name
4132
) config.ghaf.hardware.definition.usb.devices;
@@ -44,7 +35,6 @@ let
4435
name = "ghaf-killswitch";
4536
runtimeInputs = with pkgs; [
4637
coreutils
47-
hotplug
4838
vhotplug
4939
];
5040

@@ -95,28 +85,25 @@ let
9585
fi
9686
fi
9787
98-
find_vm_devices() {
99-
100-
case "$device" in
101-
mic)
102-
vm_name="${audiovmName}"
103-
${concatMapStringsSep "\n" (pciDevice: ''
104-
devices+=("${pciDevice}")
105-
'') audioPciDevices}
106-
;;
107-
net)
108-
vm_name="${netvmName}"
109-
${concatMapStringsSep "\n" (pciDevice: ''
110-
devices+=("${pciDevice}")
111-
'') netPciDevices}
112-
;;
113-
esac
114-
}
115-
11688
block_devices() {
117-
if [[ "$device" == "net" || "$device" == "mic" ]]; then
118-
echo "Blocking $device device ..."
119-
hotplug --detach-pci "''${devices[@]}" --data-path "$state_path" --socket-path "$socket_path"
89+
if [[ "$device" == "net" ]]; then
90+
echo "Blocking net device ..."
91+
${lib.concatStringsSep "\n" (
92+
map (d: ''
93+
vhotplugcli pci detach \
94+
${if d.vendorId == null then "" else "--vid ${d.vendorId}"} \
95+
${if d.productId == null then "" else "--did ${d.productId}"}
96+
'') netPciDevices
97+
)}
98+
elif [[ "$device" == "mic" ]]; then
99+
echo "Blocking mic device ..."
100+
${lib.concatStringsSep "\n" (
101+
map (d: ''
102+
vhotplugcli pci detach \
103+
${if d.vendorId == null then "" else "--vid ${d.vendorId}"} \
104+
${if d.productId == null then "" else "--did ${d.productId}"}
105+
'') audioPciDevices
106+
)}
120107
else
121108
${lib.concatStringsSep "\n" (
122109
map (d: ''
@@ -135,14 +122,24 @@ let
135122
}
136123
137124
unblock_devices() {
138-
if [[ "$device" == "net" || "$device" == "mic" ]]; then
139-
echo "Unblocking $device device ..."
140-
if ! hotplug --attach-pci --data-path "$state_path" --socket-path "$socket_path"; then
141-
echo "Failed to attach PCI devices. Check systemctl status microvm@$vm_name.service"
142-
# Recovery from failed attach; restart the VM
143-
echo "Fallback: restarting $vm_name..."
144-
systemctl restart microvm@"$vm_name".service
145-
fi
125+
if [[ "$device" == "net" ]]; then
126+
echo "Unblocking net device ..."
127+
${lib.concatStringsSep "\n" (
128+
map (d: ''
129+
vhotplugcli pci attach \
130+
${if d.vendorId == null then "" else "--vid ${d.vendorId}"} \
131+
${if d.productId == null then "" else "--did ${d.productId}"}
132+
'') netPciDevices
133+
)}
134+
elif [[ "$device" == "mic" ]]; then
135+
echo "Unblocking mic device ..."
136+
${lib.concatStringsSep "\n" (
137+
map (d: ''
138+
vhotplugcli pci attach \
139+
${if d.vendorId == null then "" else "--vid ${d.vendorId}"} \
140+
${if d.productId == null then "" else "--did ${d.productId}"}
141+
'') audioPciDevices
142+
)}
146143
else
147144
${lib.concatStringsSep "\n" (
148145
map (d: ''
@@ -168,15 +165,6 @@ let
168165
echo "$device is not supported"
169166
exit 1
170167
fi
171-
172-
# Find VM name and the devices
173-
vm_name=""
174-
declare -a devices
175-
find_vm_devices
176-
177-
# Set socket and state path
178-
socket_path="${stateDir}/$vm_name/$vm_name.sock"
179-
state_path="${stateDir}/$vm_name/state"
180168
fi
181169
182170
case "$cmd" in

modules/common/services/power.nix

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@ let
3737
# is used to determine suspend actions for PCI devices at runtime
3838
pciDevices = flatten (
3939
map (device: "${device.vendorId}:${device.productId}") (
40-
config.ghaf.common.hardware.nics ++ config.ghaf.common.hardware.audio
40+
lib.filter (d: d.vendorId != null && d.productId != null) (
41+
config.ghaf.common.hardware.nics ++ config.ghaf.common.hardware.audio
42+
)
4143
)
44+
4245
);
4346

4447
# List of VMs that are running a fake suspend
@@ -82,7 +85,7 @@ let
8285
pkgs.systemd
8386
pkgs.coreutils
8487
pkgs.grpcurl
85-
pkgs.hotplug
88+
pkgs.vhotplug
8689
pkgs.wait-for-unit
8790
];
8891
text = ''
@@ -141,21 +144,15 @@ let
141144
;;
142145
143146
pci-suspend)
144-
socket_path="${config.microvm.stateDir}/$vm_name/$vm_name.sock"
145-
state_path="${config.microvm.stateDir}/$vm_name/pci-state"
146147
case "$action" in
147148
suspend)
148-
declare -a pci_devices
149-
${concatMapStringsSep "\n" (pciDevice: ''
150-
pci_devices+=("${pciDevice}")
151-
'') pciDevices}
152-
153149
echo "Suspending PCI devices for $vm_name..."
154-
hotplug --detach-pci "''${pci_devices[@]}" --data-path "$state_path" --socket-path "$socket_path"
150+
vhotplugcli pci suspend --vm "$vm_name"
151+
155152
;;
156153
resume)
157154
echo "Resuming PCI devices for $vm_name..."
158-
if ! hotplug --attach-pci --data-path "$state_path" --socket-path "$socket_path"; then
155+
if ! vhotplugcli pci resume --vm "$vm_name"; then
159156
echo "Failed to attach PCI devices for $vm_name. Please check the logs."
160157
# Recovery from failed attach; restart the VM
161158
echo "Fallback: restarting $vm_name..."

modules/hardware/common/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{
44
imports = [
55
./usb/external-devices.nix
6+
./usb/internal-devices.nix
67
./usb/vhotplug.nix
78
./usb/quirks.nix
89
./devices.nix

0 commit comments

Comments
 (0)