Skip to content

Commit

Permalink
Add support for USB hot plugging
Browse files Browse the repository at this point in the history
Signed-off-by: Yuri Nesterov <[email protected]>
  • Loading branch information
nesteroff authored and brianmcgillion committed Aug 28, 2024
1 parent 3105ca4 commit 4c568da
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 4 deletions.
1 change: 1 addition & 0 deletions modules/hardware/common/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
imports = [
./usb/internal.nix
./usb/external.nix
./usb/vhotplug.nix
./devices.nix
./kernel.nix
./qemu.nix
Expand Down
6 changes: 5 additions & 1 deletion modules/hardware/common/qemu.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ in
"acad"
]
++ optionals (hasAttr "yubikey" config.ghaf.hardware.usb.external.qemuExtraArgs) config.ghaf.hardware.usb.external.qemuExtraArgs.yubikey
++ optionals (hasAttr "fpr0" config.ghaf.hardware.usb.internal.qemuExtraArgs) config.ghaf.hardware.usb.internal.qemuExtraArgs.fpr0;
++ optionals (hasAttr "fpr0" config.ghaf.hardware.usb.internal.qemuExtraArgs) config.ghaf.hardware.usb.internal.qemuExtraArgs.fpr0
++ optionals config.ghaf.hardware.usb.vhotplug.enableEvdevPassthrough builtins.concatMap (n: [
"-device"
"pcie-root-port,bus=pcie.0,id=${config.ghaf.hardware.usb.vhotplug.pcieBusPrefix}${toString n},chassis=${toString n}"
]) (lib.range 1 config.ghaf.hardware.usb.vhotplug.pciePortCount);
};
};
}
192 changes: 192 additions & 0 deletions modules/hardware/common/usb/vhotplug.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
config,
lib,
pkgs,
...
}:
let
cfg = config.ghaf.hardware.usb.vhotplug;
inherit (lib)
mkEnableOption
mkOption
types
mkIf
literalExpression
;

vhotplug = pkgs.callPackage ../../../../packages/vhotplug { };
defaultRules = [
{
name = "GUIVM";
qmpSocket = "/var/lib/microvms/gui-vm/gui-vm.sock";
usbPassthrough = [
{
class = 3;
protocol = 1;
description = "HID Keyboard";
}
{
class = 3;
protocol = 2;
description = "HID Mouse";
}
{
class = 11;
description = "Chip/SmartCard (e.g. YubiKey)";
}
{
class = 224;
subclass = 1;
protocol = 1;
description = "Bluetooth";
disable = true;
}
{
# Currently disabled to leave USB drives connected to the host
class = 8;
sublass = 6;
description = "Mass Storage - SCSI (USB drives)";
disable = true;
}
];
evdevPassthrough = {
enable = cfg.enableEvdevPassthrough;
inherit (cfg) pcieBusPrefix;
};
}
{
name = "NetVM";
qmpSocket = "/var/lib/microvms/net-vm/net-vm.sock";
usbPassthrough = [
{
# Currently disabled to avoid breaking remote nixos-rebuild,
# which requires an Ethernet adapter connected to the host
class = 2;
sublass = 6;
description = "Communications - Ethernet Networking";
disable = true;
}
];
}
{
name = "ChromiumVM";
qmpSocket = "/var/lib/microvms/chromium-vm/chromium-vm.sock";
usbPassthrough = [
{
class = 14;
description = "Video (USB Webcams)";
}
];
}
{
name = "AudioVM";
qmpSocket = "/var/lib/microvms/audio-vm/audio-vm.sock";
usbPassthrough = [
{
class = 1;
description = "Audio";
}
];
}
];
in
{
options.ghaf.hardware.usb.vhotplug = {
enable = mkEnableOption "Enable hot plugging of USB devices";

rules = mkOption {
type = types.listOf types.attrs;
default = defaultRules;
description = ''
List of virtual machines with USB hot plugging rules.
'';
example = literalExpression ''
[
{
name = "GUIVM";
qmpSocket = "/var/lib/microvms/gui-vm/gui-vm.sock";
usbPassthrough = [
{
class = 3;
protocol = 1;
description = "HID Keyboard";
ignore = [
{
vendorId = "046d";
productId = "c52b";
description = "Logitech, Inc. Unifying Receiver";
}
];
}
{
vendorId = "067b";
productId = "23a3";
description = "Prolific Technology, Inc. USB-Serial Controller";
disable = true;
}
];
}
{
name = "NetVM";
qmpSocket = "/var/lib/microvms/net-vm/net-vm.sock";
usbPassthrough = [
{
productName = ".*ethernet.*";
description = "Ethernet devices";
}
];
}
];
'';
};

enableEvdevPassthrough = mkOption {
description = ''
Enable passthrough of non-USB input devices on startup using QEMU virtio-input-host-pci device.
'';
type = types.bool;
default = true;
};

pcieBusPrefix = mkOption {
type = types.nullOr types.str;
default = "rp";
description = ''
PCIe bus prefix used for the pcie-root-port QEMU device when evdev passthrough is enabled.
'';
};

pciePortCount = lib.mkOption {
type = lib.types.int;
default = 5;
description = ''
The number of PCIe ports used for hot-plugging virtio-input-host-pci devices.
'';
};
};

config = mkIf cfg.enable {
services.udev.extraRules = ''
SUBSYSTEM=="usb", GROUP="kvm"
KERNEL=="event*", GROUP="kvm"
'';

environment.etc."vhotplug.conf".text = builtins.toJSON { vms = cfg.rules; };

systemd.services.vhotplug = {
enable = true;
description = "vhotplug";
wantedBy = [ "microvms.target" ];
after = [ "microvms.target" ];
serviceConfig = {
Type = "simple";
Restart = "always";
RestartSec = "1";
ExecStart = "${vhotplug}/bin/vhotplug -a -c /etc/vhotplug.conf";
};
startLimitIntervalSec = 0;
};
};
}
9 changes: 7 additions & 2 deletions modules/microvm/virtualization/microvm/audiovm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ let
pkgs.pulseaudio
pkgs.pamixer
pkgs.pipewire
];
] ++ lib.optional config.ghaf.development.debug.tools.enable pkgs.alsa-utils;
};

time.timeZone = config.time.timeZone;
Expand All @@ -73,7 +73,8 @@ let
services.openssh = config.ghaf.security.sshKeys.sshAuthorizedKeysCommand;

microvm = {
optimize.enable = true;
# Optimize is disabled because when it is enabled, qemu is built without libusb
optimize.enable = false;
vcpu = 1;
mem = 256;
hypervisor = "qemu";
Expand Down Expand Up @@ -102,6 +103,10 @@ let
aarch64-linux = "virt";
}
.${configHost.nixpkgs.hostPlatform.system};
extraArgs = [
"-device"
"qemu-xhci"
];
};
};

Expand Down
7 changes: 6 additions & 1 deletion modules/microvm/virtualization/microvm/netvm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ let
'';

microvm = {
optimize.enable = true;
# Optimize is disabled because when it is enabled, qemu is built without libusb
optimize.enable = false;
hypervisor = "qemu";
shares =
[
Expand Down Expand Up @@ -122,6 +123,10 @@ let
aarch64-linux = "virt";
}
.${config.nixpkgs.hostPlatform.system};
extraArgs = [
"-device"
"qemu-xhci"
];
};
};

Expand Down
1 change: 1 addition & 0 deletions modules/reference/profiles/laptop-x86.nix
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ in
tpm2.enable = true;
usb.internal.enable = true;
usb.external.enable = true;
usb.vhotplug.enable = true;
};

# Virtualization options
Expand Down
26 changes: 26 additions & 0 deletions packages/qemuqmp/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
python3Packages,
fetchPypi,
lib,
}:
python3Packages.buildPythonPackage rec {
pname = "qemu.qmp";
version = "0.0.3";

src = fetchPypi {
inherit pname version;
sha256 = "sha256-y8iPvMEV7pQ9hER9FyxkLaEgIgRRQWwvYhrPM98eEBA=";
};

pyproject = true;

nativeBuildInputs = [ python3Packages.setuptools-scm ];

meta = {
homepage = "https://www.qemu.org/";
description = "QEMU Monitor Protocol library";
license = lib.licenses.lgpl2Plus;
};
}
29 changes: 29 additions & 0 deletions packages/vhotplug/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
python3Packages,
pkgs,
fetchFromGitHub,
}:
let
qemuqmp = pkgs.callPackage ../qemuqmp { };
in
python3Packages.buildPythonApplication rec {
pname = "vhotplug";
version = "0.1";

propagatedBuildInputs = [
python3Packages.pyudev
python3Packages.psutil
qemuqmp
];

doCheck = false;

src = fetchFromGitHub {
owner = "tiiuae";
repo = "vhotplug";
rev = "fd05361ed893d06cdb5ac4a538c171e4a86b6f5a";
hash = "sha256-6fl5xeSpcIIBKn3dZUAEHiNRRpn9LbYC4Imap5KBH2M=";
};
}

0 comments on commit 4c568da

Please sign in to comment.