Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usbipd: add usbipd service with autobind #348301

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions maintainers/maintainer-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3756,6 +3756,12 @@
matrix = "@cedric:cbarrete.com";
name = "Cédric Barreteau";
};
cbingman = {
name = "Christian Bingman";
email = "[email protected]";
github = "ChristianBingman";
githubId = 42191425;
};
cbleslie = {
email = "[email protected]";
github = "cbleslie";
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@
./services/hardware/udisks2.nix
./services/hardware/undervolt.nix
./services/hardware/upower.nix
./services/hardware/usbipd.nix
./services/hardware/usbmuxd.nix
./services/hardware/usbrelayd.nix
./services/hardware/vdr.nix
Expand Down
99 changes: 99 additions & 0 deletions nixos/modules/services/hardware/usbipd.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.usbipd;
device = lib.types.submodule {
options = {
productid = lib.mkOption {
type = lib.types.str;
description = "The product id of the device";
};
vendorid = lib.mkOption {
type = lib.types.str;
description = "The vendor id of the device";
};
};
};
in
{
options.services.usbipd = {
enable = lib.mkEnableOption "usbip server";
kernelPackage = lib.mkPackageOption pkgs.linuxPackages_latest "usbip" { };
devices = lib.mkOption {
type = lib.types.listOf device;
default = [ ];
description = "List of USB devices to watch and automatically export.";
example = [
{
productid = "xxxx";
vendorid = "xxxx";
}
];
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Open port 3240 for usbipd";
example = false;
};
};

config = lib.mkIf cfg.enable {
boot.extraModulePackages = [ cfg.kernelPackage ];
boot.kernelModules = [
"usbip-core"
"usbip-host"
];
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 3240 ];
services.udev.extraRules = lib.strings.concatLines (
(map (
dev:
"ACTION==\"add\", SUBSYSTEM==\"usb\", ATTRS{idProduct}==\"${dev.productid}\", ATTRS{idVendor}==\"${dev.vendorid}\", RUN+=\"${pkgs.systemd}/bin/systemctl restart usbip-${dev.vendorid}:${dev.productid}.service\""
) cfg.devices)
);

systemd.services =
(builtins.listToAttrs (
map (dev: {
name = "usbip-${dev.vendorid}:${dev.productid}";
value = {
after = [ "usbipd.service" ];
script = ''
set +e
devices=$(${cfg.kernelPackage}/bin/usbip list -l | grep -E "^.*- busid.*(${dev.vendorid}:${dev.productid})" )
echo $devices | while read device; do
output=$(${cfg.kernelPackage}/bin/usbip -d bind -b $(echo $device | ${pkgs.gawk}/bin/awk '{ print $3 }') 2>&1)
code=$?

echo $output
if [[ $output =~ "already bound" ]] || [ $code -eq 0 ]; then
continue
else
exit $code
fi
done
'';
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
restartTriggers = [ "usbipd.service" ];
};
}) cfg.devices
))
// {
usbipd = {
wantedBy = [ "multi-user.target" ];
script = ''
${lib.getExe' pkgs.kmod "modprobe"} usbip-host usbip-core
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done via boot.kernelModules already, I think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not, e.g. rke2 does this and several others.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rke2 does not set boot.kernelModules. My understanding is that putting something in boot.kernelModules is almost equivalent to a modprobe call at boot time.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I could get confirmation, I am happy to remove it. Though when I initially tested this case the module was not loaded until after reboot, so that is why I added it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at kernel.nix it seems like it is supposed to autoload, but in my experience it didn’t and the wording seems to indicate otherwise “The set of kernel modules to be loaded in the second stage of the boot process”. In any case I will remove it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though when I initially tested this case the module was not loaded until after reboot, so that is why I added it.

That is correct. It will not work with a simple nixos-rebuild switch, only a reboot will apply a change to boot.kernelModules.

exec ${lib.getExe' cfg.kernelPackage "usbipd"} -D
'';
serviceConfig.Type = "forking";
};
};
};
meta.maintainers = with lib.maintainers; [ cbingman ];
meta.buildDocsInSandbox = false;
}
Loading